mirror of
https://github.com/openvswitch/ovs
synced 2025-08-31 14:25:26 +00:00
dpif-netdev: Conditional EMC insert
Unconditional insertion of EMC entries results in EMC thrashing at high numbers of parallel flows. When this occurs, the performance of the EMC often falls below that of the dpcls classifier, rendering the EMC practically useless. Instead of unconditionally inserting entries into the EMC when a miss occurs, use a 1% probability of insertion. This ensures that the most frequent flows have the highest chance of creating an entry in the EMC, and the probability of thrashing the EMC is also greatly reduced. The probability of insertion is configurable, via the other_config:emc-insert-inv-prob option. This value sets the average probability of insertion to 1/emc-insert-inv-prob. For example the following command changes the insertion probability to (on average) 1 in every 20 packets ie. 1/20 ie. 5%. ovs-vsctl set Open_vSwitch . other_config:emc-insert-inv-prob=20 Signed-off-by: Ciara Loftus <ciara.loftus@intel.com> Signed-off-by: Georg Schmuecking <georg.schmuecking@ericsson.com> Co-authored-by: Georg Schmuecking <georg.schmuecking@ericsson.com> Acked-by: Kevin Traynor <ktraynor@redhat.com> Signed-off-by: Daniele Di Proietto <diproiettod@vmware.com>
This commit is contained in:
committed by
Daniele Di Proietto
parent
878b54d783
commit
4c30b24602
@@ -144,6 +144,11 @@ struct netdev_flow_key {
|
||||
#define EM_FLOW_HASH_MASK (EM_FLOW_HASH_ENTRIES - 1)
|
||||
#define EM_FLOW_HASH_SEGS 2
|
||||
|
||||
/* Default EMC insert probability is 1 / DEFAULT_EM_FLOW_INSERT_INV_PROB */
|
||||
#define DEFAULT_EM_FLOW_INSERT_INV_PROB 100
|
||||
#define DEFAULT_EM_FLOW_INSERT_MIN (UINT32_MAX / \
|
||||
DEFAULT_EM_FLOW_INSERT_INV_PROB)
|
||||
|
||||
struct emc_entry {
|
||||
struct dp_netdev_flow *flow;
|
||||
struct netdev_flow_key key; /* key.hash used for emc hash value. */
|
||||
@@ -254,6 +259,9 @@ struct dp_netdev {
|
||||
uint64_t last_tnl_conf_seq;
|
||||
|
||||
struct conntrack conntrack;
|
||||
|
||||
/* Probability of EMC insertions is a factor of 'emc_insert_min'.*/
|
||||
OVS_ALIGNED_VAR(CACHE_LINE_SIZE) atomic_uint32_t emc_insert_min;
|
||||
};
|
||||
|
||||
static struct dp_netdev_port *dp_netdev_lookup_port(const struct dp_netdev *dp,
|
||||
@@ -1066,6 +1074,8 @@ create_dp_netdev(const char *name, const struct dpif_class *class,
|
||||
|
||||
conntrack_init(&dp->conntrack);
|
||||
|
||||
atomic_init(&dp->emc_insert_min, DEFAULT_EM_FLOW_INSERT_MIN);
|
||||
|
||||
cmap_init(&dp->poll_threads);
|
||||
ovs_mutex_init_recursive(&dp->non_pmd_mutex);
|
||||
ovsthread_key_create(&dp->per_pmd_key, NULL);
|
||||
@@ -1943,6 +1953,27 @@ emc_insert(struct emc_cache *cache, const struct netdev_flow_key *key,
|
||||
emc_change_entry(to_be_replaced, flow, key);
|
||||
}
|
||||
|
||||
static inline void
|
||||
emc_probabilistic_insert(struct dp_netdev_pmd_thread *pmd,
|
||||
const struct netdev_flow_key *key,
|
||||
struct dp_netdev_flow *flow)
|
||||
{
|
||||
/* Insert an entry into the EMC based on probability value 'min'. By
|
||||
* default the value is UINT32_MAX / 100 which yields an insertion
|
||||
* probability of 1/100 ie. 1% */
|
||||
|
||||
uint32_t min;
|
||||
atomic_read_relaxed(&pmd->dp->emc_insert_min, &min);
|
||||
|
||||
#ifdef DPDK_NETDEV
|
||||
if (min && (key->hash ^ (uint32_t) pmd->last_cycles) <= min) {
|
||||
#else
|
||||
if (min && (key->hash ^ random_uint32()) <= min) {
|
||||
#endif
|
||||
emc_insert(&pmd->flow_cache, key, flow);
|
||||
}
|
||||
}
|
||||
|
||||
static inline struct dp_netdev_flow *
|
||||
emc_lookup(struct emc_cache *cache, const struct netdev_flow_key *key)
|
||||
{
|
||||
@@ -2731,6 +2762,10 @@ dpif_netdev_set_config(struct dpif *dpif, const struct smap *other_config)
|
||||
{
|
||||
struct dp_netdev *dp = get_dp_netdev(dpif);
|
||||
const char *cmask = smap_get(other_config, "pmd-cpu-mask");
|
||||
unsigned long long insert_prob =
|
||||
smap_get_ullong(other_config, "emc-insert-inv-prob",
|
||||
DEFAULT_EM_FLOW_INSERT_INV_PROB);
|
||||
uint32_t insert_min, cur_min;
|
||||
|
||||
if (!nullable_string_is_equal(dp->pmd_cmask, cmask)) {
|
||||
free(dp->pmd_cmask);
|
||||
@@ -2738,6 +2773,24 @@ dpif_netdev_set_config(struct dpif *dpif, const struct smap *other_config)
|
||||
dp_netdev_request_reconfigure(dp);
|
||||
}
|
||||
|
||||
atomic_read_relaxed(&dp->emc_insert_min, &cur_min);
|
||||
if (insert_prob <= UINT32_MAX) {
|
||||
insert_min = insert_prob == 0 ? 0 : UINT32_MAX / insert_prob;
|
||||
} else {
|
||||
insert_min = DEFAULT_EM_FLOW_INSERT_MIN;
|
||||
insert_prob = DEFAULT_EM_FLOW_INSERT_INV_PROB;
|
||||
}
|
||||
|
||||
if (insert_min != cur_min) {
|
||||
atomic_store_relaxed(&dp->emc_insert_min, insert_min);
|
||||
if (insert_min == 0) {
|
||||
VLOG_INFO("EMC has been disabled");
|
||||
} else {
|
||||
VLOG_INFO("EMC insertion probability changed to 1/%llu (~%.2f%%)",
|
||||
insert_prob, (100 / (float)insert_prob));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4193,8 +4246,7 @@ handle_packet_upcall(struct dp_netdev_pmd_thread *pmd, struct dp_packet *packet,
|
||||
add_actions->size);
|
||||
}
|
||||
ovs_mutex_unlock(&pmd->flow_mutex);
|
||||
|
||||
emc_insert(&pmd->flow_cache, key, netdev_flow);
|
||||
emc_probabilistic_insert(pmd, key, netdev_flow);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4217,7 +4269,6 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd,
|
||||
struct dpcls *cls;
|
||||
struct dpcls_rule *rules[PKT_ARRAY_SIZE];
|
||||
struct dp_netdev *dp = pmd->dp;
|
||||
struct emc_cache *flow_cache = &pmd->flow_cache;
|
||||
int miss_cnt = 0, lost_cnt = 0;
|
||||
int lookup_cnt = 0, add_lookup_cnt;
|
||||
bool any_miss;
|
||||
@@ -4288,7 +4339,7 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd,
|
||||
|
||||
flow = dp_netdev_flow_cast(rules[i]);
|
||||
|
||||
emc_insert(flow_cache, &keys[i], flow);
|
||||
emc_probabilistic_insert(pmd, &keys[i], flow);
|
||||
dp_netdev_queue_batches(packet, flow, &keys[i].mf, batches, n_batches);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user