2
0
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:
Ethan Jackson
2013-09-24 13:39:56 -07:00
parent 1b84927316
commit e79a6c833e
15 changed files with 978 additions and 2511 deletions

4
NEWS
View File

@@ -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

View File

@@ -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 \

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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 */

View File

@@ -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

View File

@@ -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 *,

View File

@@ -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])

View File

@@ -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)
])

View File

@@ -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)
])

View File

@@ -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"));

View File

@@ -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