Skip to content

Commit 1f3a090

Browse files
hao022davem330
authored andcommitted
net: openvswitch: introduce common code for flushing flows
To avoid some issues, for example RCU usage warning and double free, we should flush the flows under ovs_lock. This patch refactors table_instance_destroy and introduces table_instance_flow_flush which can be invoked by __dp_destroy or ovs_flow_tbl_flush. Fixes: 50b0e61 ("net: openvswitch: fix possible memleak on destroy flow-table") Reported-by: Johan Knöös <[email protected]> Reported-at: https://mail.openvswitch.org/pipermail/ovs-discuss/2020-August/050489.html Signed-off-by: Tonghao Zhang <[email protected]> Reviewed-by: Cong Wang <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 88fd1cb commit 1f3a090

File tree

3 files changed

+27
-21
lines changed

3 files changed

+27
-21
lines changed

net/openvswitch/datapath.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1756,6 +1756,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
17561756
/* Called with ovs_mutex. */
17571757
static void __dp_destroy(struct datapath *dp)
17581758
{
1759+
struct flow_table *table = &dp->table;
17591760
int i;
17601761

17611762
for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
@@ -1774,7 +1775,14 @@ static void __dp_destroy(struct datapath *dp)
17741775
*/
17751776
ovs_dp_detach_port(ovs_vport_ovsl(dp, OVSP_LOCAL));
17761777

1777-
/* RCU destroy the flow table */
1778+
/* Flush sw_flow in the tables. RCU cb only releases resource
1779+
* such as dp, ports and tables. That may avoid some issues
1780+
* such as RCU usage warning.
1781+
*/
1782+
table_instance_flow_flush(table, ovsl_dereference(table->ti),
1783+
ovsl_dereference(table->ufid_ti));
1784+
1785+
/* RCU destroy the ports, meters and flow tables. */
17781786
call_rcu(&dp->rcu, destroy_dp_rcu);
17791787
}
17801788

net/openvswitch/flow_table.c

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -473,19 +473,15 @@ static void table_instance_flow_free(struct flow_table *table,
473473
flow_mask_remove(table, flow->mask);
474474
}
475475

476-
static void table_instance_destroy(struct flow_table *table,
477-
struct table_instance *ti,
478-
struct table_instance *ufid_ti,
479-
bool deferred)
476+
/* Must be called with OVS mutex held. */
477+
void table_instance_flow_flush(struct flow_table *table,
478+
struct table_instance *ti,
479+
struct table_instance *ufid_ti)
480480
{
481481
int i;
482482

483-
if (!ti)
484-
return;
485-
486-
BUG_ON(!ufid_ti);
487483
if (ti->keep_flows)
488-
goto skip_flows;
484+
return;
489485

490486
for (i = 0; i < ti->n_buckets; i++) {
491487
struct sw_flow *flow;
@@ -497,18 +493,16 @@ static void table_instance_destroy(struct flow_table *table,
497493

498494
table_instance_flow_free(table, ti, ufid_ti,
499495
flow, false);
500-
ovs_flow_free(flow, deferred);
496+
ovs_flow_free(flow, true);
501497
}
502498
}
499+
}
503500

504-
skip_flows:
505-
if (deferred) {
506-
call_rcu(&ti->rcu, flow_tbl_destroy_rcu_cb);
507-
call_rcu(&ufid_ti->rcu, flow_tbl_destroy_rcu_cb);
508-
} else {
509-
__table_instance_destroy(ti);
510-
__table_instance_destroy(ufid_ti);
511-
}
501+
static void table_instance_destroy(struct table_instance *ti,
502+
struct table_instance *ufid_ti)
503+
{
504+
call_rcu(&ti->rcu, flow_tbl_destroy_rcu_cb);
505+
call_rcu(&ufid_ti->rcu, flow_tbl_destroy_rcu_cb);
512506
}
513507

514508
/* No need for locking this function is called from RCU callback or
@@ -523,7 +517,7 @@ void ovs_flow_tbl_destroy(struct flow_table *table)
523517

524518
call_rcu(&mc->rcu, mask_cache_rcu_cb);
525519
call_rcu(&ma->rcu, mask_array_rcu_cb);
526-
table_instance_destroy(table, ti, ufid_ti, false);
520+
table_instance_destroy(ti, ufid_ti);
527521
}
528522

529523
struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *ti,
@@ -641,7 +635,8 @@ int ovs_flow_tbl_flush(struct flow_table *flow_table)
641635
flow_table->count = 0;
642636
flow_table->ufid_count = 0;
643637

644-
table_instance_destroy(flow_table, old_ti, old_ufid_ti, true);
638+
table_instance_flow_flush(flow_table, old_ti, old_ufid_ti);
639+
table_instance_destroy(old_ti, old_ufid_ti);
645640
return 0;
646641

647642
err_free_ti:

net/openvswitch/flow_table.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,5 +105,8 @@ void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src,
105105
bool full, const struct sw_flow_mask *mask);
106106

107107
void ovs_flow_masks_rebalance(struct flow_table *table);
108+
void table_instance_flow_flush(struct flow_table *table,
109+
struct table_instance *ti,
110+
struct table_instance *ufid_ti);
108111

109112
#endif /* flow_table.h */

0 commit comments

Comments
 (0)