mirror of
https://github.com/openvswitch/ovs
synced 2025-08-31 22:35:15 +00:00
ofproto: Handle flow installation and eviction in upcall.
This patch moves flow installation and eviction from ofproto-dpif and the main thread, into ofproto-dpif-upcall. This performs significantly better (approximately 2x TCP_CRR improvement), and allows ovs-vswitchd to maintain significantly larger datapath flow tables. On top of that, it significantly simplifies the code, retiring "struct facet" and friends. Signed-off-by: Ethan Jackson <ethan@nicira.com> Acked-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
4
NEWS
4
NEWS
@@ -54,6 +54,10 @@ Post-v2.0.0
|
||||
- ovsdb-client:
|
||||
* The "monitor" command can now monitor all tables in a database,
|
||||
instead of being limited to a single table.
|
||||
- The flow-eviction-threshold has been replaced by the flow-limit which is a
|
||||
hard limit on the number of flows in the datapath. It defaults to 200,000
|
||||
flows. OVS automatically adjusts this number depending on network
|
||||
conditions.
|
||||
|
||||
|
||||
v2.0.0 - 15 Oct 2013
|
||||
|
@@ -25,8 +25,6 @@ ofproto_libofproto_la_SOURCES = \
|
||||
ofproto/ofproto.h \
|
||||
ofproto/ofproto-dpif.c \
|
||||
ofproto/ofproto-dpif.h \
|
||||
ofproto/ofproto-dpif-governor.c \
|
||||
ofproto/ofproto-dpif-governor.h \
|
||||
ofproto/ofproto-dpif-ipfix.c \
|
||||
ofproto/ofproto-dpif-ipfix.h \
|
||||
ofproto/ofproto-dpif-mirror.c \
|
||||
|
@@ -1,211 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Nicira, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "ofproto-dpif-governor.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "coverage.h"
|
||||
#include "poll-loop.h"
|
||||
#include "random.h"
|
||||
#include "timeval.h"
|
||||
#include "util.h"
|
||||
#include "valgrind.h"
|
||||
#include "vlog.h"
|
||||
|
||||
VLOG_DEFINE_THIS_MODULE(ofproto_dpif_governor);
|
||||
|
||||
/* Minimum number of observed packets before setting up a flow.
|
||||
*
|
||||
* This value seems OK empirically. */
|
||||
#define FLOW_SETUP_THRESHOLD 5
|
||||
BUILD_ASSERT_DECL(FLOW_SETUP_THRESHOLD > 1);
|
||||
BUILD_ASSERT_DECL(FLOW_SETUP_THRESHOLD < 16);
|
||||
|
||||
/* Minimum and maximum size of a governor, in bytes. */
|
||||
enum { MIN_SIZE = 16 * 1024 };
|
||||
enum { MAX_SIZE = 256 * 1024 };
|
||||
BUILD_ASSERT_DECL(IS_POW2(MIN_SIZE));
|
||||
BUILD_ASSERT_DECL(IS_POW2(MAX_SIZE));
|
||||
|
||||
/* Minimum and maximum time to process the number of packets that make up a
|
||||
* given generation. If a generation completes faster than the minimum time,
|
||||
* we double the table size (but no more than MAX_SIZE). If a generation take
|
||||
* more than the maximum time to complete, we halve the table size (but no
|
||||
* smaller than MIN_SIZE). */
|
||||
enum { MIN_ELAPSED = 1000 }; /* In milliseconds. */
|
||||
enum { MAX_ELAPSED = 5000 }; /* In milliseconds. */
|
||||
|
||||
static void governor_new_generation(struct governor *, unsigned int size);
|
||||
|
||||
/* Creates and returns a new governor. */
|
||||
struct governor *
|
||||
governor_create(void)
|
||||
{
|
||||
struct governor *g = xzalloc(sizeof *g);
|
||||
governor_new_generation(g, MIN_SIZE);
|
||||
return g;
|
||||
}
|
||||
|
||||
/* Destroys 'g'. */
|
||||
void
|
||||
governor_destroy(struct governor *g)
|
||||
{
|
||||
if (g) {
|
||||
VLOG_INFO("disengaging");
|
||||
free(g->table);
|
||||
free(g);
|
||||
}
|
||||
}
|
||||
|
||||
/* Performs periodic maintenance work on 'g'. */
|
||||
void
|
||||
governor_run(struct governor *g)
|
||||
{
|
||||
if (time_msec() - g->start > MAX_ELAPSED) {
|
||||
if (g->size > MIN_SIZE) {
|
||||
governor_new_generation(g, g->size / 2);
|
||||
} else {
|
||||
/* Don't start a new generation (we'd never go idle). */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Arranges for the poll loop to wake up when 'g' needs to do some work. */
|
||||
void
|
||||
governor_wait(struct governor *g)
|
||||
{
|
||||
if (g->size > MIN_SIZE) {
|
||||
poll_timer_wait_until(g->start + MAX_ELAPSED);
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns true if 'g' has been doing only a minimal amount of work and thus
|
||||
* the client should consider getting rid of it entirely. */
|
||||
bool
|
||||
governor_is_idle(struct governor *g)
|
||||
{
|
||||
return g->size == MIN_SIZE && time_msec() - g->start > MAX_ELAPSED;
|
||||
}
|
||||
|
||||
/* Tests whether a flow whose hash is 'hash' and for which 'n' packets have
|
||||
* just arrived should be set up in the datapath or just processed on a
|
||||
* packet-by-packet basis. Returns true to set up a datapath flow, false to
|
||||
* process the packets individually.
|
||||
*
|
||||
* One would expect 'n' to ordinarily be 1, if batching leads multiple packets
|
||||
* to be processed at a time then it could be greater. */
|
||||
bool
|
||||
governor_should_install_flow(struct governor *g, uint32_t hash, int n)
|
||||
{
|
||||
int old_count, new_count;
|
||||
bool install_flow;
|
||||
uint8_t *e;
|
||||
|
||||
ovs_assert(n > 0);
|
||||
|
||||
/* Count these packets and begin a new generation if necessary. */
|
||||
g->n_packets += n;
|
||||
if (g->n_packets >= g->size / 4) {
|
||||
unsigned int new_size;
|
||||
long long elapsed;
|
||||
|
||||
elapsed = time_msec() - g->start;
|
||||
new_size = (elapsed < MIN_ELAPSED && g->size < MAX_SIZE ? g->size * 2
|
||||
: elapsed > MAX_ELAPSED && g->size > MIN_SIZE ? g->size / 2
|
||||
: g->size);
|
||||
governor_new_generation(g, new_size);
|
||||
}
|
||||
|
||||
/* If we've set up most of the flows we've seen, then we're wasting time
|
||||
* handling most packets one at a time, so in this case instead set up most
|
||||
* flows directly and use the remaining flows as a sample set to adjust our
|
||||
* criteria later.
|
||||
*
|
||||
* The definition of "most" is conservative, but the sample size is tuned
|
||||
* based on a few experiments with TCP_CRR mode in netperf. */
|
||||
if (g->n_setups >= g->n_flows - g->n_flows / 16
|
||||
&& g->n_flows >= 64
|
||||
&& hash & 0x3f) {
|
||||
g->n_shortcuts++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Do hash table processing.
|
||||
*
|
||||
* Even-numbered hash values use high-order nibbles.
|
||||
* Odd-numbered hash values use low-order nibbles. */
|
||||
e = &g->table[(hash >> 1) & (g->size - 1)];
|
||||
old_count = (hash & 1 ? *e >> 4 : *e & 0x0f);
|
||||
if (!old_count) {
|
||||
g->n_flows++;
|
||||
}
|
||||
new_count = n + old_count;
|
||||
if (new_count >= FLOW_SETUP_THRESHOLD) {
|
||||
g->n_setups++;
|
||||
install_flow = true;
|
||||
new_count = 0;
|
||||
} else {
|
||||
install_flow = false;
|
||||
}
|
||||
*e = hash & 1 ? (new_count << 4) | (*e & 0x0f) : (*e & 0xf0) | new_count;
|
||||
|
||||
return install_flow;
|
||||
}
|
||||
|
||||
/* Starts a new generation in 'g' with a table size of 'size' bytes. 'size'
|
||||
* must be a power of two between MIN_SIZE and MAX_SIZE, inclusive. */
|
||||
static void
|
||||
governor_new_generation(struct governor *g, unsigned int size)
|
||||
{
|
||||
ovs_assert(size >= MIN_SIZE && size <= MAX_SIZE);
|
||||
ovs_assert(is_pow2(size));
|
||||
|
||||
/* Allocate new table, if necessary. */
|
||||
if (g->size != size) {
|
||||
if (!g->size) {
|
||||
VLOG_INFO("engaging governor with %u kB hash table", size / 1024);
|
||||
} else {
|
||||
VLOG_INFO("processed %u packets in %.2f s, "
|
||||
"%s hash table to %u kB "
|
||||
"(%u hashes, %u setups, %u shortcuts)",
|
||||
g->n_packets,
|
||||
(time_msec() - g->start) / 1000.0,
|
||||
size > g->size ? "enlarging" : "shrinking",
|
||||
size / 1024,
|
||||
g->n_flows, g->n_setups, g->n_shortcuts);
|
||||
}
|
||||
|
||||
free(g->table);
|
||||
g->table = xmalloc(size * sizeof *g->table);
|
||||
g->size = size;
|
||||
} else {
|
||||
VLOG_DBG("processed %u packets in %.2f s with %u kB hash table "
|
||||
"(%u hashes, %u setups, %u shortcuts)",
|
||||
g->n_packets, (time_msec() - g->start) / 1000.0,
|
||||
size / 1024, g->n_flows, g->n_setups, g->n_shortcuts);
|
||||
}
|
||||
|
||||
/* Clear data for next generation. */
|
||||
memset(g->table, 0, size * sizeof *g->table);
|
||||
g->start = time_msec();
|
||||
g->n_packets = 0;
|
||||
g->n_flows /= 2;
|
||||
g->n_setups /= 2;
|
||||
g->n_shortcuts = 0;
|
||||
}
|
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Nicira, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef OFPROTO_DPIF_GOVERNOR_H
|
||||
#define OFPROTO_DPIF_GOVERNOR_H 1
|
||||
|
||||
/* Flow setup rate limiter.
|
||||
*
|
||||
* A governor in an engine limits a vehicle's speed. This governor limits the
|
||||
* rate at which flows are set up in the datapath. The client provides as
|
||||
* input the hashes of observed packets. The governor keeps track of hashes
|
||||
* seen multiple times. When a given hash is seen often enough, the governor
|
||||
* indicates to its client that it should set up a facet and a subfacet and a
|
||||
* datapath flow for that flow.
|
||||
*
|
||||
* The same tracking could be done in terms of facets and subfacets directly,
|
||||
* but the governor code uses much less time and space to do the same job. */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct governor {
|
||||
char *name; /* Name, for log messages. */
|
||||
uint8_t *table; /* Table of counters, two per byte. */
|
||||
unsigned int size; /* Table size in bytes. */
|
||||
long long int start; /* Time when the table was last cleared. */
|
||||
unsigned int n_packets; /* Number of packets processed. */
|
||||
|
||||
/* Statistics for skipping counters when most flows get set up. */
|
||||
unsigned int n_flows; /* Number of unique flows seen. */
|
||||
unsigned int n_setups; /* Number of flows set up based on counters. */
|
||||
unsigned int n_shortcuts; /* Number of flows set up based on history. */
|
||||
};
|
||||
|
||||
struct governor *governor_create(void);
|
||||
void governor_destroy(struct governor *);
|
||||
|
||||
void governor_run(struct governor *);
|
||||
void governor_wait(struct governor *);
|
||||
|
||||
bool governor_is_idle(struct governor *);
|
||||
|
||||
bool governor_should_install_flow(struct governor *, uint32_t hash, int n);
|
||||
|
||||
#endif /* ofproto/ofproto-dpif-governor.h */
|
File diff suppressed because it is too large
Load Diff
@@ -15,90 +15,24 @@
|
||||
#ifndef OFPROTO_DPIF_UPCALL_H
|
||||
#define OFPROTO_DPIF_UPCALL_H
|
||||
|
||||
#define FLOW_MISS_MAX_BATCH 50
|
||||
|
||||
#include "dpif.h"
|
||||
#include "flow.h"
|
||||
#include "hmap.h"
|
||||
#include "list.h"
|
||||
#include "odp-util.h"
|
||||
#include "ofpbuf.h"
|
||||
#include "ofproto-dpif-xlate.h"
|
||||
#include <stddef.h>
|
||||
|
||||
struct dpif;
|
||||
struct dpif_backer;
|
||||
struct seq;
|
||||
struct simap;
|
||||
|
||||
/* udif is responsible for retrieving upcalls from the kernel, processing miss
|
||||
* upcalls, and handing more complex ones up to the main ofproto-dpif
|
||||
* module. */
|
||||
/* Udif is responsible for retrieving upcalls from the kernel and processing
|
||||
* them. Additionally, it's responsible for maintaining the datapath flow
|
||||
* table. */
|
||||
|
||||
struct udpif *udpif_create(struct dpif_backer *, struct dpif *);
|
||||
void udpif_set_threads(struct udpif *, size_t n_handlers);
|
||||
void udpif_set_threads(struct udpif *, size_t n_handlers,
|
||||
size_t n_revalidators);
|
||||
void udpif_destroy(struct udpif *);
|
||||
|
||||
void udpif_wait(struct udpif *);
|
||||
|
||||
void udpif_revalidate(struct udpif *);
|
||||
|
||||
void udpif_get_memory_usage(struct udpif *, struct simap *usage);
|
||||
|
||||
/* udpif figures out how to forward packets, and does forward them, but it
|
||||
* can't set up datapath flows on its own. This interface passes packet
|
||||
* forwarding data from udpif to the higher level ofproto_dpif to allow the
|
||||
* latter to set up datapath flows. */
|
||||
|
||||
/* Flow miss batching.
|
||||
*
|
||||
* Some dpifs implement operations faster when you hand them off in a batch.
|
||||
* To allow batching, "struct flow_miss" queues the dpif-related work needed
|
||||
* for a given flow. Each "struct flow_miss" corresponds to sending one or
|
||||
* more packets, plus possibly installing the flow in the dpif. */
|
||||
struct flow_miss {
|
||||
struct hmap_node hmap_node;
|
||||
struct ofproto_dpif *ofproto;
|
||||
|
||||
struct flow flow;
|
||||
enum odp_key_fitness key_fitness;
|
||||
const struct nlattr *key;
|
||||
size_t key_len;
|
||||
enum dpif_upcall_type upcall_type;
|
||||
struct dpif_flow_stats stats;
|
||||
|
||||
struct xlate_out xout;
|
||||
};
|
||||
|
||||
struct flow_miss_batch {
|
||||
struct list list_node;
|
||||
|
||||
struct flow_miss miss_buf[FLOW_MISS_MAX_BATCH];
|
||||
struct hmap misses;
|
||||
|
||||
unsigned int reval_seq;
|
||||
|
||||
/* Flow misses refer to the memory held by "struct upcall"s,
|
||||
* so we need to keep track of the upcalls to be able to
|
||||
* free them when done. */
|
||||
struct list upcalls; /* Contains "struct upcall"s. */
|
||||
};
|
||||
|
||||
struct flow_miss_batch *flow_miss_batch_next(struct udpif *);
|
||||
void flow_miss_batch_destroy(struct flow_miss_batch *);
|
||||
|
||||
/* Drop keys are odp flow keys which have drop flows installed in the kernel.
|
||||
* These are datapath flows which have no associated ofproto, if they did we
|
||||
* would use facets.
|
||||
*
|
||||
* udpif can't install drop flows by itself. This interfaces allows udpif to
|
||||
* pass the drop flows up to ofproto_dpif to get it to install them. */
|
||||
struct drop_key {
|
||||
struct hmap_node hmap_node;
|
||||
struct list list_node;
|
||||
struct nlattr *key;
|
||||
size_t key_len;
|
||||
};
|
||||
|
||||
struct drop_key *drop_key_next(struct udpif *);
|
||||
void drop_key_destroy(struct drop_key *);
|
||||
void udpif_drop_key_clear(struct udpif *);
|
||||
struct seq *udpif_dump_seq(struct udpif *);
|
||||
void udpif_flush(void);
|
||||
|
||||
#endif /* ofproto-dpif-upcall.h */
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -455,13 +455,13 @@ void rule_collection_ref(struct rule_collection *) OVS_REQUIRES(ofproto_mutex);
|
||||
void rule_collection_unref(struct rule_collection *);
|
||||
void rule_collection_destroy(struct rule_collection *);
|
||||
|
||||
/* Threshold at which to begin flow table eviction. Only affects the
|
||||
* ofproto-dpif implementation */
|
||||
extern unsigned flow_eviction_threshold;
|
||||
/* Limits the number of flows allowed in the datapath. Only affects the
|
||||
* ofproto-dpif implementation. */
|
||||
extern unsigned ofproto_flow_limit;
|
||||
|
||||
/* Number of upcall handler threads. Only affects the ofproto-dpif
|
||||
* implementation. */
|
||||
extern size_t n_handlers;
|
||||
/* Number of upcall handler and revalidator threads. Only affects the
|
||||
* ofproto-dpif implementation. */
|
||||
extern size_t n_handlers, n_revalidators;
|
||||
|
||||
/* Determines which model to use for handling misses in the ofproto-dpif
|
||||
* implementation */
|
||||
|
@@ -306,10 +306,10 @@ static size_t allocated_ofproto_classes;
|
||||
/* Global lock that protects all flow table operations. */
|
||||
struct ovs_mutex ofproto_mutex = OVS_MUTEX_INITIALIZER;
|
||||
|
||||
unsigned flow_eviction_threshold = OFPROTO_FLOW_EVICTION_THRESHOLD_DEFAULT;
|
||||
unsigned ofproto_flow_limit = OFPROTO_FLOW_LIMIT_DEFAULT;
|
||||
enum ofproto_flow_miss_model flow_miss_model = OFPROTO_HANDLE_MISS_AUTO;
|
||||
|
||||
size_t n_handlers;
|
||||
size_t n_handlers, n_revalidators;
|
||||
|
||||
/* Map from datapath name to struct ofproto, for use by unixctl commands. */
|
||||
static struct hmap all_ofprotos = HMAP_INITIALIZER(&all_ofprotos);
|
||||
@@ -693,10 +693,9 @@ ofproto_set_in_band_queue(struct ofproto *ofproto, int queue_id)
|
||||
/* Sets the number of flows at which eviction from the kernel flow table
|
||||
* will occur. */
|
||||
void
|
||||
ofproto_set_flow_eviction_threshold(unsigned threshold)
|
||||
ofproto_set_flow_limit(unsigned limit)
|
||||
{
|
||||
flow_eviction_threshold = MAX(OFPROTO_FLOW_EVICTION_THRESHOLD_MIN,
|
||||
threshold);
|
||||
ofproto_flow_limit = limit;
|
||||
}
|
||||
|
||||
/* Sets the path for handling flow misses. */
|
||||
@@ -734,13 +733,23 @@ ofproto_set_mac_table_config(struct ofproto *ofproto, unsigned idle_time,
|
||||
}
|
||||
}
|
||||
|
||||
/* Sets number of upcall handler threads. The default is
|
||||
* (number of online cores - 2). */
|
||||
void
|
||||
ofproto_set_threads(size_t n_handlers_)
|
||||
ofproto_set_threads(size_t n_handlers_, size_t n_revalidators_)
|
||||
{
|
||||
int threads = MAX(count_cpu_cores() - 2, 1);
|
||||
n_handlers = n_handlers_ ? n_handlers_ : threads;
|
||||
int threads = MAX(count_cpu_cores(), 2);
|
||||
|
||||
n_revalidators = n_revalidators_;
|
||||
n_handlers = n_handlers_;
|
||||
|
||||
if (!n_revalidators) {
|
||||
n_revalidators = n_handlers
|
||||
? MAX(threads - (int) n_handlers, 1)
|
||||
: threads / 4 + 1;
|
||||
}
|
||||
|
||||
if (!n_handlers) {
|
||||
n_handlers = MAX(threads - (int) n_revalidators, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -213,8 +213,7 @@ int ofproto_port_dump_done(struct ofproto_port_dump *);
|
||||
: (ofproto_port_dump_done(DUMP), false)); \
|
||||
)
|
||||
|
||||
#define OFPROTO_FLOW_EVICTION_THRESHOLD_DEFAULT 2500
|
||||
#define OFPROTO_FLOW_EVICTION_THRESHOLD_MIN 100
|
||||
#define OFPROTO_FLOW_LIMIT_DEFAULT 200000
|
||||
|
||||
/* How flow misses should be handled in ofproto-dpif */
|
||||
enum ofproto_flow_miss_model {
|
||||
@@ -243,12 +242,12 @@ void ofproto_reconnect_controllers(struct ofproto *);
|
||||
void ofproto_set_extra_in_band_remotes(struct ofproto *,
|
||||
const struct sockaddr_in *, size_t n);
|
||||
void ofproto_set_in_band_queue(struct ofproto *, int queue_id);
|
||||
void ofproto_set_flow_eviction_threshold(unsigned threshold);
|
||||
void ofproto_set_flow_limit(unsigned limit);
|
||||
void ofproto_set_flow_miss_model(unsigned model);
|
||||
void ofproto_set_forward_bpdu(struct ofproto *, bool forward_bpdu);
|
||||
void ofproto_set_mac_table_config(struct ofproto *, unsigned idle_time,
|
||||
size_t max_entries);
|
||||
void ofproto_set_threads(size_t n_handlers);
|
||||
void ofproto_set_threads(size_t n_handlers, size_t n_revalidators);
|
||||
void ofproto_set_dp_desc(struct ofproto *, const char *dp_desc);
|
||||
int ofproto_set_snoops(struct ofproto *, const struct sset *snoops);
|
||||
int ofproto_set_netflow(struct ofproto *,
|
||||
|
@@ -2100,22 +2100,23 @@ for delay in 1000 30000; do
|
||||
ovs-appctl time/warp $delay
|
||||
done
|
||||
|
||||
ovs-appctl time/warp 6000
|
||||
sleep 1
|
||||
OVS_VSWITCHD_STOP
|
||||
ovs-appctl -t test-netflow exit
|
||||
|
||||
AT_CHECK([[sed -e 's/, uptime [0-9]*//
|
||||
s/, now [0-9.]*//
|
||||
s/time \([0-9]*\)\.\.\.\1$/time <moment>/
|
||||
s/time [0-9]*\.\.\.[0-9]*/time <range>/
|
||||
' netflow.log | sort]], [0],
|
||||
[
|
||||
header: v5, seq 0, engine 2,1
|
||||
header: v5, seq 1, engine 2,1
|
||||
seq 0: 192.168.0.1 > 192.168.0.2, if 1 > 65535, 1 pkts, 60 bytes, ICMP 8:0, time <moment>
|
||||
seq 1: 192.168.0.1 > 192.168.0.2, if 1 > 2, 1 pkts, 60 bytes, ICMP 8:0, time <moment>
|
||||
seq 1: 192.168.0.2 > 192.168.0.1, if 2 > 1, 2 pkts, 120 bytes, ICMP 0:0, time <range>
|
||||
])
|
||||
AT_CHECK([grep "192.168.0.1 > 192.168.0.2, if 1 > 65535, 1 pkts, 60 bytes, ICMP 8:0" netflow.log | wc -l], [0], [dnl
|
||||
1
|
||||
], [ignore])
|
||||
|
||||
AT_CHECK([grep "192.168.0.1 > 192.168.0.2, if 1 > 2, 1 pkts, 60 bytes, ICMP 8:0" netflow.log | wc -l], [0], [dnl
|
||||
1
|
||||
], [ignore])
|
||||
|
||||
combined=`grep "192.168.0.2 > 192.168.0.1, if 2 > 1, 2 pkts, 120 bytes, ICMP 0:0" netflow.log | wc -l`
|
||||
separate=`grep "192.168.0.2 > 192.168.0.1, if 2 > 1, 1 pkts, 60 bytes, ICMP 0:0" netflow.log | wc -l`
|
||||
AT_CHECK([test $separate = 2 || test $combined = 1], [0])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
dnl Test that basic NetFlow reports active expirations correctly.
|
||||
@@ -2192,12 +2193,6 @@ done < netflow.log
|
||||
AT_CHECK([echo $n_learn $n_in $n_out $n_other], [0], [1 59 60 0
|
||||
])
|
||||
|
||||
# There should be 1 expiration for MAC learning,
|
||||
# at least 5 active and a final expiration in one direction,
|
||||
# and at least 5 active and a final expiration in the other direction.
|
||||
echo $n_recs
|
||||
AT_CHECK([test $n_recs -ge 13])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([idle_age and hard_age increase over time])
|
||||
@@ -2347,12 +2342,11 @@ ADD_OF_PORTS([br1], [3])
|
||||
|
||||
AT_CHECK([ovs-appctl dpif/show], [0], [dnl
|
||||
dummy@ovs-dummy: hit:0 missed:0
|
||||
flows: cur: 0, avg: 0, max: 0
|
||||
br0: hit:0 missed:0
|
||||
br0:
|
||||
br0 65534/100: (dummy)
|
||||
p1 1/1: (dummy)
|
||||
p2 2/2: (dummy)
|
||||
br1: hit:0 missed:0
|
||||
br1:
|
||||
br1 65534/101: (dummy)
|
||||
p3 3/3: (dummy)
|
||||
])
|
||||
@@ -2409,12 +2403,11 @@ warped
|
||||
|
||||
AT_CHECK([ovs-appctl dpif/show], [0], [dnl
|
||||
dummy@ovs-dummy: hit:13 missed:2
|
||||
flows: cur: 2, avg: 1, max: 2
|
||||
br0: hit:9 missed:1
|
||||
br0:
|
||||
br0 65534/100: (dummy)
|
||||
p2 2/2: (dummy)
|
||||
pbr0 1/none: (patch: peer=pbr1)
|
||||
br1: hit:4 missed:1
|
||||
br1:
|
||||
br1 65534/101: (dummy)
|
||||
p3 3/3: (dummy)
|
||||
pbr1 1/none: (patch: peer=pbr0)
|
||||
@@ -2442,34 +2435,6 @@ OFPST_PORT reply (xid=0x4): 1 ports
|
||||
OVS_VSWITCHD_STOP
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([ofproto-dpif - ovs-appctl dpif/show rates])
|
||||
OVS_VSWITCHD_START([set Bridge br0 fail-mode=secure])
|
||||
ADD_OF_PORTS([br0], 1, 2)
|
||||
|
||||
AT_CHECK([ovs-appctl time/stop])
|
||||
AT_CHECK([ovs-ofctl add-flow br0 actions=LOCAL,output:1,output:2])
|
||||
|
||||
for i in $(seq 1 61); do
|
||||
ovs-appctl netdev-dummy/receive br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
|
||||
ovs-appctl time/warp 10000
|
||||
ovs-appctl time/warp 50000
|
||||
done
|
||||
|
||||
AT_CHECK([ovs-appctl time/warp 10000], [0], [warped
|
||||
])
|
||||
|
||||
AT_CHECK([ovs-appctl dpif/show | sed 's/ 10[[0-9]]\{3\}(ms)$/ 10000(ms)/'], [0], [dnl
|
||||
dummy@ovs-dummy: hit:0 missed:61
|
||||
flows: cur: 0, avg: 0, max: 1
|
||||
br0: hit:0 missed:61
|
||||
br0 65534/100: (dummy)
|
||||
p1 1/1: (dummy)
|
||||
p2 2/2: (dummy)
|
||||
])
|
||||
|
||||
OVS_VSWITCHD_STOP
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([ofproto-dpif - port duration])
|
||||
OVS_VSWITCHD_START([set Bridge br0 protocols=OpenFlow13])
|
||||
ADD_OF_PORTS([br0], 1, 2)
|
||||
@@ -2949,7 +2914,7 @@ AT_DATA([flows.txt], [dnl
|
||||
table=0 in_port=1,ip,nw_dst=10.0.0.1 actions=output(2)
|
||||
table=0 in_port=1,ip,nw_dst=10.0.0.3 actions=drop
|
||||
])
|
||||
AT_CHECK([ovs-appctl dpif/disable-megaflows], [0], [megaflows disabled
|
||||
AT_CHECK([ovs-appctl upcall/disable-megaflows], [0], [megaflows disabled
|
||||
], [])
|
||||
AT_CHECK([ovs-appctl vlog/set dpif_netdev:dbg], [0], [], [])
|
||||
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
|
||||
|
@@ -2485,7 +2485,7 @@ AT_CHECK([ovs-ofctl add-flow br0 "tcp,tcp_flags=+ack-ack,action="], [1], [],
|
||||
[ovs-ofctl: ack: Each TCP flag can be specified only once
|
||||
])
|
||||
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +5], [0], [dnl
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +4], [0], [dnl
|
||||
p1 1/1: (dummy)
|
||||
p2 2/2: (dummy)
|
||||
])
|
||||
|
@@ -14,7 +14,7 @@ actions=IN_PORT
|
||||
|
||||
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
|
||||
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +4], [0], [dnl
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
|
||||
br0 65534/100: (dummy)
|
||||
p1 1/1: (gre: remote_ip=1.1.1.1)
|
||||
p2 2/1: (gre: local_ip=2.2.2.2, remote_ip=1.1.1.1)
|
||||
@@ -37,7 +37,7 @@ dnl reconfigure, local_ip, remote_ip
|
||||
AT_CHECK([ovs-vsctl set Interface p2 type=gre options:local_ip=2.2.2.3 \
|
||||
options:df_default=false options:ttl=1 options:csum=true \
|
||||
-- set Interface p3 type=gre64])
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +4], [0], [dnl
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
|
||||
br0 65534/100: (dummy)
|
||||
p1 1/1: (gre: remote_ip=1.1.1.1)
|
||||
p2 2/1: (gre: csum=true, df_default=false, local_ip=2.2.2.3, remote_ip=1.1.1.1, ttl=1)
|
||||
@@ -72,7 +72,7 @@ actions=2
|
||||
|
||||
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
|
||||
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +4], [0], [dnl
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
|
||||
br0 65534/100: (dummy)
|
||||
p1 1/1: (gre: remote_ip=1.1.1.1)
|
||||
p2 2/2: (dummy)
|
||||
@@ -116,7 +116,7 @@ actions=output:1
|
||||
|
||||
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
|
||||
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +4], [0], [dnl
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
|
||||
br0 65534/100: (dummy)
|
||||
p1 1/1: (gre: key=5, local_ip=2.2.2.2, remote_ip=1.1.1.1)
|
||||
p2 2/2: (dummy)
|
||||
@@ -148,7 +148,7 @@ actions=output:1
|
||||
|
||||
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
|
||||
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +4], [0], [dnl
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
|
||||
br0 65534/100: (dummy)
|
||||
p1 1/1: (gre: remote_ip=1.1.1.1, tos=inherit, ttl=inherit)
|
||||
p2 2/2: (dummy)
|
||||
@@ -190,7 +190,7 @@ actions=set_tunnel:1,output:1,set_tunnel:2,output:2,set_tunnel:3,output:3,set_tu
|
||||
|
||||
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
|
||||
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +4], [0], [dnl
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
|
||||
br0 65534/100: (dummy)
|
||||
p1 1/1: (gre: key=flow, remote_ip=1.1.1.1)
|
||||
p2 2/1: (gre: key=flow, remote_ip=2.2.2.2)
|
||||
@@ -222,7 +222,7 @@ actions=IN_PORT,output:1,output:2,output:3
|
||||
|
||||
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
|
||||
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +4], [0], [dnl
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
|
||||
br0 65534/100: (dummy)
|
||||
p1 1/1: (gre: key=1, remote_ip=1.1.1.1)
|
||||
p2 2/1: (gre: in_key=2, out_key=3, remote_ip=1.1.1.1)
|
||||
@@ -274,7 +274,7 @@ tun_id=4,actions=output:5
|
||||
|
||||
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
|
||||
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +4], [0], [dnl
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
|
||||
br0 65534/100: (dummy)
|
||||
p1 1/1: (gre: key=flow, remote_ip=1.1.1.1)
|
||||
p2 2/1: (gre: key=3, remote_ip=3.3.3.3)
|
||||
@@ -310,7 +310,7 @@ AT_SETUP([tunnel - VXLAN])
|
||||
OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=vxlan \
|
||||
options:remote_ip=1.1.1.1 ofport_request=1])
|
||||
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +4], [0], [dnl
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
|
||||
br0 65534/100: (dummy)
|
||||
p1 1/1: (vxlan: remote_ip=1.1.1.1)
|
||||
])
|
||||
@@ -322,7 +322,7 @@ AT_SETUP([tunnel - LISP])
|
||||
OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=lisp \
|
||||
options:remote_ip=1.1.1.1 ofport_request=1])
|
||||
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +4], [0], [dnl
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
|
||||
br0 65534/100: (dummy)
|
||||
p1 1/1: (lisp: remote_ip=1.1.1.1)
|
||||
])
|
||||
@@ -334,7 +334,7 @@ AT_SETUP([tunnel - different VXLAN UDP port])
|
||||
OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=vxlan \
|
||||
options:remote_ip=1.1.1.1 ofport_request=1 options:dst_port=4341])
|
||||
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +4], [0], [dnl
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
|
||||
br0 65534/100: (dummy)
|
||||
p1 1/1: (vxlan: dst_port=4341, remote_ip=1.1.1.1)
|
||||
])
|
||||
@@ -343,7 +343,7 @@ dnl change UDP port
|
||||
|
||||
AT_CHECK([ovs-vsctl -- set Interface p1 options:dst_port=5000])
|
||||
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +4], [0], [dnl
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
|
||||
br0 65534/100: (dummy)
|
||||
p1 1/2: (vxlan: dst_port=5000, remote_ip=1.1.1.1)
|
||||
])
|
||||
@@ -352,7 +352,7 @@ dnl change UDP port to default
|
||||
|
||||
AT_CHECK([ovs-vsctl -- set Interface p1 options:dst_port=4789])
|
||||
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +4], [0], [dnl
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
|
||||
br0 65534/100: (dummy)
|
||||
p1 1/1: (vxlan: remote_ip=1.1.1.1)
|
||||
])
|
||||
|
@@ -493,12 +493,12 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
|
||||
|
||||
COVERAGE_INC(bridge_reconfigure);
|
||||
|
||||
ofproto_set_flow_eviction_threshold(
|
||||
smap_get_int(&ovs_cfg->other_config, "flow-eviction-threshold",
|
||||
OFPROTO_FLOW_EVICTION_THRESHOLD_DEFAULT));
|
||||
ofproto_set_flow_limit(smap_get_int(&ovs_cfg->other_config, "flow-limit",
|
||||
OFPROTO_FLOW_LIMIT_DEFAULT));
|
||||
|
||||
ofproto_set_threads(
|
||||
smap_get_int(&ovs_cfg->other_config, "n-handler-threads", 0));
|
||||
smap_get_int(&ovs_cfg->other_config, "n-handler-threads", 0),
|
||||
smap_get_int(&ovs_cfg->other_config, "n-revalidator-threads", 0));
|
||||
|
||||
bridge_configure_flow_miss_model(smap_get(&ovs_cfg->other_config,
|
||||
"force-miss-model"));
|
||||
|
@@ -123,17 +123,16 @@
|
||||
</p>
|
||||
</column>
|
||||
|
||||
<column name="other_config" key="flow-eviction-threshold"
|
||||
<column name="other_config" key="flow-limit"
|
||||
type='{"type": "integer", "minInteger": 0}'>
|
||||
<p>
|
||||
A number of flows as a nonnegative integer. This sets number of
|
||||
flows at which eviction from the datapath flow table will be
|
||||
triggered. If there are a large number of flows then increasing this
|
||||
value to around the number of flows present can result in reduced CPU
|
||||
usage and packet loss.
|
||||
The maximum
|
||||
number of flows allowed in the datapath flow table. Internally OVS
|
||||
will choose a flow limit which will likely be lower than this number,
|
||||
based on real time network conditions.
|
||||
</p>
|
||||
<p>
|
||||
The default is 2500. Values below 100 will be rounded up to 100.
|
||||
The default is 200000.
|
||||
</p>
|
||||
</column>
|
||||
|
||||
@@ -163,8 +162,28 @@
|
||||
type='{"type": "integer", "minInteger": 1}'>
|
||||
<p>
|
||||
Specifies the number of threads for software datapaths to use for
|
||||
handling new flows. The default is two less than the number of
|
||||
online CPU cores (but at least 1).
|
||||
handling new flows. The default the number of online CPU cores minus
|
||||
the number of revalidators.
|
||||
</p>
|
||||
<p>
|
||||
This configuration is per datapath. If you have more than one
|
||||
software datapath (e.g. some <code>system</code> bridges and some
|
||||
<code>netdev</code> bridges), then the total number of threads is
|
||||
<code>n-handler-threads</code> times the number of software
|
||||
datapaths.
|
||||
</p>
|
||||
</column>
|
||||
|
||||
<column name="other_config" key="n-revalidator-threads"
|
||||
type='{"type": "integer", "minInteger": 1}'>
|
||||
<p>
|
||||
Specifies the number of threads for software datapaths to use for
|
||||
revalidating flows in the datapath. Typically, there is a direct
|
||||
correlation between the number of revalidator threads, and the number
|
||||
of flows allowed in the datapath. The default is the number of cpu
|
||||
cores divided by four plus one. If <code>n-handler-threads</code> is
|
||||
set, the default changes to the number of cpu cores minus the number
|
||||
of handler threads.
|
||||
</p>
|
||||
<p>
|
||||
This configuration is per datapath. If you have more than one
|
||||
|
Reference in New Issue
Block a user