Skip to content

Commit 9bf24f5

Browse files
chaudrondavem330
authored andcommitted
net: openvswitch: make masks cache size configurable
This patch makes the masks cache size configurable, or with a size of 0, disable it. Reviewed-by: Paolo Abeni <[email protected]> Reviewed-by: Tonghao Zhang <[email protected]> Signed-off-by: Eelco Chaudron <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 9d2f627 commit 9bf24f5

File tree

4 files changed

+115
-14
lines changed

4 files changed

+115
-14
lines changed

include/uapi/linux/openvswitch.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ enum ovs_datapath_attr {
8686
OVS_DP_ATTR_MEGAFLOW_STATS, /* struct ovs_dp_megaflow_stats */
8787
OVS_DP_ATTR_USER_FEATURES, /* OVS_DP_F_* */
8888
OVS_DP_ATTR_PAD,
89+
OVS_DP_ATTR_MASKS_CACHE_SIZE,
8990
__OVS_DP_ATTR_MAX
9091
};
9192

net/openvswitch/datapath.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1498,6 +1498,7 @@ static size_t ovs_dp_cmd_msg_size(void)
14981498
msgsize += nla_total_size_64bit(sizeof(struct ovs_dp_stats));
14991499
msgsize += nla_total_size_64bit(sizeof(struct ovs_dp_megaflow_stats));
15001500
msgsize += nla_total_size(sizeof(u32)); /* OVS_DP_ATTR_USER_FEATURES */
1501+
msgsize += nla_total_size(sizeof(u32)); /* OVS_DP_ATTR_MASKS_CACHE_SIZE */
15011502

15021503
return msgsize;
15031504
}
@@ -1535,6 +1536,10 @@ static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb,
15351536
if (nla_put_u32(skb, OVS_DP_ATTR_USER_FEATURES, dp->user_features))
15361537
goto nla_put_failure;
15371538

1539+
if (nla_put_u32(skb, OVS_DP_ATTR_MASKS_CACHE_SIZE,
1540+
ovs_flow_tbl_masks_cache_size(&dp->table)))
1541+
goto nla_put_failure;
1542+
15381543
genlmsg_end(skb, ovs_header);
15391544
return 0;
15401545

@@ -1599,6 +1604,16 @@ static int ovs_dp_change(struct datapath *dp, struct nlattr *a[])
15991604
#endif
16001605
}
16011606

1607+
if (a[OVS_DP_ATTR_MASKS_CACHE_SIZE]) {
1608+
int err;
1609+
u32 cache_size;
1610+
1611+
cache_size = nla_get_u32(a[OVS_DP_ATTR_MASKS_CACHE_SIZE]);
1612+
err = ovs_flow_tbl_masks_cache_resize(&dp->table, cache_size);
1613+
if (err)
1614+
return err;
1615+
}
1616+
16021617
dp->user_features = user_features;
16031618

16041619
if (dp->user_features & OVS_DP_F_TC_RECIRC_SHARING)
@@ -1887,6 +1902,8 @@ static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = {
18871902
[OVS_DP_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
18881903
[OVS_DP_ATTR_UPCALL_PID] = { .type = NLA_U32 },
18891904
[OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 },
1905+
[OVS_DP_ATTR_MASKS_CACHE_SIZE] = NLA_POLICY_RANGE(NLA_U32, 0,
1906+
PCPU_MIN_UNIT_SIZE / sizeof(struct mask_cache_entry)),
18901907
};
18911908

18921909
static const struct genl_ops dp_datapath_genl_ops[] = {

net/openvswitch/flow_table.c

Lines changed: 88 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@
3838
#define MASK_ARRAY_SIZE_MIN 16
3939
#define REHASH_INTERVAL (10 * 60 * HZ)
4040

41+
#define MC_DEFAULT_HASH_ENTRIES 256
4142
#define MC_HASH_SHIFT 8
42-
#define MC_HASH_ENTRIES (1u << MC_HASH_SHIFT)
4343
#define MC_HASH_SEGS ((sizeof(uint32_t) * 8) / MC_HASH_SHIFT)
4444

4545
static struct kmem_cache *flow_cache;
@@ -341,15 +341,79 @@ static void flow_mask_remove(struct flow_table *tbl, struct sw_flow_mask *mask)
341341
}
342342
}
343343

344+
static void __mask_cache_destroy(struct mask_cache *mc)
345+
{
346+
free_percpu(mc->mask_cache);
347+
kfree(mc);
348+
}
349+
350+
static void mask_cache_rcu_cb(struct rcu_head *rcu)
351+
{
352+
struct mask_cache *mc = container_of(rcu, struct mask_cache, rcu);
353+
354+
__mask_cache_destroy(mc);
355+
}
356+
357+
static struct mask_cache *tbl_mask_cache_alloc(u32 size)
358+
{
359+
struct mask_cache_entry __percpu *cache = NULL;
360+
struct mask_cache *new;
361+
362+
/* Only allow size to be 0, or a power of 2, and does not exceed
363+
* percpu allocation size.
364+
*/
365+
if ((!is_power_of_2(size) && size != 0) ||
366+
(size * sizeof(struct mask_cache_entry)) > PCPU_MIN_UNIT_SIZE)
367+
return NULL;
368+
369+
new = kzalloc(sizeof(*new), GFP_KERNEL);
370+
if (!new)
371+
return NULL;
372+
373+
new->cache_size = size;
374+
if (new->cache_size > 0) {
375+
cache = __alloc_percpu(array_size(sizeof(struct mask_cache_entry),
376+
new->cache_size),
377+
__alignof__(struct mask_cache_entry));
378+
if (!cache) {
379+
kfree(new);
380+
return NULL;
381+
}
382+
}
383+
384+
new->mask_cache = cache;
385+
return new;
386+
}
387+
int ovs_flow_tbl_masks_cache_resize(struct flow_table *table, u32 size)
388+
{
389+
struct mask_cache *mc = rcu_dereference(table->mask_cache);
390+
struct mask_cache *new;
391+
392+
if (size == mc->cache_size)
393+
return 0;
394+
395+
if ((!is_power_of_2(size) && size != 0) ||
396+
(size * sizeof(struct mask_cache_entry)) > PCPU_MIN_UNIT_SIZE)
397+
return -EINVAL;
398+
399+
new = tbl_mask_cache_alloc(size);
400+
if (!new)
401+
return -ENOMEM;
402+
403+
rcu_assign_pointer(table->mask_cache, new);
404+
call_rcu(&mc->rcu, mask_cache_rcu_cb);
405+
406+
return 0;
407+
}
408+
344409
int ovs_flow_tbl_init(struct flow_table *table)
345410
{
346411
struct table_instance *ti, *ufid_ti;
412+
struct mask_cache *mc;
347413
struct mask_array *ma;
348414

349-
table->mask_cache = __alloc_percpu(sizeof(struct mask_cache_entry) *
350-
MC_HASH_ENTRIES,
351-
__alignof__(struct mask_cache_entry));
352-
if (!table->mask_cache)
415+
mc = tbl_mask_cache_alloc(MC_DEFAULT_HASH_ENTRIES);
416+
if (!mc)
353417
return -ENOMEM;
354418

355419
ma = tbl_mask_array_alloc(MASK_ARRAY_SIZE_MIN);
@@ -367,6 +431,7 @@ int ovs_flow_tbl_init(struct flow_table *table)
367431
rcu_assign_pointer(table->ti, ti);
368432
rcu_assign_pointer(table->ufid_ti, ufid_ti);
369433
rcu_assign_pointer(table->mask_array, ma);
434+
rcu_assign_pointer(table->mask_cache, mc);
370435
table->last_rehash = jiffies;
371436
table->count = 0;
372437
table->ufid_count = 0;
@@ -377,7 +442,7 @@ int ovs_flow_tbl_init(struct flow_table *table)
377442
free_mask_array:
378443
__mask_array_destroy(ma);
379444
free_mask_cache:
380-
free_percpu(table->mask_cache);
445+
__mask_cache_destroy(mc);
381446
return -ENOMEM;
382447
}
383448

@@ -453,9 +518,11 @@ void ovs_flow_tbl_destroy(struct flow_table *table)
453518
{
454519
struct table_instance *ti = rcu_dereference_raw(table->ti);
455520
struct table_instance *ufid_ti = rcu_dereference_raw(table->ufid_ti);
521+
struct mask_cache *mc = rcu_dereference(table->mask_cache);
522+
struct mask_array *ma = rcu_dereference_ovsl(table->mask_array);
456523

457-
free_percpu(table->mask_cache);
458-
call_rcu(&table->mask_array->rcu, mask_array_rcu_cb);
524+
call_rcu(&mc->rcu, mask_cache_rcu_cb);
525+
call_rcu(&ma->rcu, mask_array_rcu_cb);
459526
table_instance_destroy(table, ti, ufid_ti, false);
460527
}
461528

@@ -724,6 +791,7 @@ struct sw_flow *ovs_flow_tbl_lookup_stats(struct flow_table *tbl,
724791
u32 *n_mask_hit,
725792
u32 *n_cache_hit)
726793
{
794+
struct mask_cache *mc = rcu_dereference(tbl->mask_cache);
727795
struct mask_array *ma = rcu_dereference(tbl->mask_array);
728796
struct table_instance *ti = rcu_dereference(tbl->ti);
729797
struct mask_cache_entry *entries, *ce;
@@ -733,7 +801,7 @@ struct sw_flow *ovs_flow_tbl_lookup_stats(struct flow_table *tbl,
733801

734802
*n_mask_hit = 0;
735803
*n_cache_hit = 0;
736-
if (unlikely(!skb_hash)) {
804+
if (unlikely(!skb_hash || mc->cache_size == 0)) {
737805
u32 mask_index = 0;
738806
u32 cache = 0;
739807

@@ -749,11 +817,11 @@ struct sw_flow *ovs_flow_tbl_lookup_stats(struct flow_table *tbl,
749817

750818
ce = NULL;
751819
hash = skb_hash;
752-
entries = this_cpu_ptr(tbl->mask_cache);
820+
entries = this_cpu_ptr(mc->mask_cache);
753821

754822
/* Find the cache entry 'ce' to operate on. */
755823
for (seg = 0; seg < MC_HASH_SEGS; seg++) {
756-
int index = hash & (MC_HASH_ENTRIES - 1);
824+
int index = hash & (mc->cache_size - 1);
757825
struct mask_cache_entry *e;
758826

759827
e = &entries[index];
@@ -867,6 +935,13 @@ int ovs_flow_tbl_num_masks(const struct flow_table *table)
867935
return READ_ONCE(ma->count);
868936
}
869937

938+
u32 ovs_flow_tbl_masks_cache_size(const struct flow_table *table)
939+
{
940+
struct mask_cache *mc = rcu_dereference(table->mask_cache);
941+
942+
return READ_ONCE(mc->cache_size);
943+
}
944+
870945
static struct table_instance *table_instance_expand(struct table_instance *ti,
871946
bool ufid)
872947
{
@@ -1095,8 +1170,8 @@ void ovs_flow_masks_rebalance(struct flow_table *table)
10951170
for (i = 0; i < masks_entries; i++) {
10961171
int index = masks_and_count[i].index;
10971172

1098-
new->masks[new->count++] =
1099-
rcu_dereference_ovsl(ma->masks[index]);
1173+
if (ovsl_dereference(ma->masks[index]))
1174+
new->masks[new->count++] = ma->masks[index];
11001175
}
11011176

11021177
rcu_assign_pointer(table->mask_array, new);

net/openvswitch/flow_table.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ struct mask_cache_entry {
2727
u32 mask_index;
2828
};
2929

30+
struct mask_cache {
31+
struct rcu_head rcu;
32+
u32 cache_size; /* Must be ^2 value. */
33+
struct mask_cache_entry __percpu *mask_cache;
34+
};
35+
3036
struct mask_count {
3137
int index;
3238
u64 counter;
@@ -53,7 +59,7 @@ struct table_instance {
5359
struct flow_table {
5460
struct table_instance __rcu *ti;
5561
struct table_instance __rcu *ufid_ti;
56-
struct mask_cache_entry __percpu *mask_cache;
62+
struct mask_cache __rcu *mask_cache;
5763
struct mask_array __rcu *mask_array;
5864
unsigned long last_rehash;
5965
unsigned int count;
@@ -77,6 +83,8 @@ int ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow,
7783
const struct sw_flow_mask *mask);
7884
void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow);
7985
int ovs_flow_tbl_num_masks(const struct flow_table *table);
86+
u32 ovs_flow_tbl_masks_cache_size(const struct flow_table *table);
87+
int ovs_flow_tbl_masks_cache_resize(struct flow_table *table, u32 size);
8088
struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *table,
8189
u32 *bucket, u32 *idx);
8290
struct sw_flow *ovs_flow_tbl_lookup_stats(struct flow_table *,

0 commit comments

Comments
 (0)