[PATCH net backport to 5.5 - 5.8.3 v2] net: openvswitch: introduce common code for flushing flows

2020-08-27 Thread xiangxia . m . yue
From: Tonghao Zhang 

[ Upstream commit 1f3a090b9033f69de380c03db3ea1a1015c850cf ]

Backport this commit to 5.5 - 5.8.3.

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: 50b0e61b32ee ("net: openvswitch: fix possible memleak on destroy 
flow-table")
Reported-by: Johan Knöös 
Reported-at: 
https://mail.openvswitch.org/pipermail/ovs-discuss/2020-August/050489.html
Signed-off-by: Tonghao Zhang 
Reviewed-by: Cong Wang 
Signed-off-by: David S. Miller 
---
 net/openvswitch/datapath.c   | 10 +-
 net/openvswitch/flow_table.c | 35 +++
 net/openvswitch/flow_table.h |  3 +++
 3 files changed, 27 insertions(+), 21 deletions(-)

diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index e3a37d22539c..15615cae4c89 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -1737,6 +1737,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct 
genl_info *info)
 /* Called with ovs_mutex. */
 static void __dp_destroy(struct datapath *dp)
 {
+   struct flow_table *table = >table;
int i;
 
for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
@@ -1755,7 +1756,14 @@ static void __dp_destroy(struct datapath *dp)
 */
ovs_dp_detach_port(ovs_vport_ovsl(dp, OVSP_LOCAL));
 
-   /* RCU destroy the flow table */
+   /* Flush sw_flow in the tables. RCU cb only releases resource
+* such as dp, ports and tables. That may avoid some issues
+* such as RCU usage warning.
+*/
+   table_instance_flow_flush(table, ovsl_dereference(table->ti),
+ ovsl_dereference(table->ufid_ti));
+
+   /* RCU destroy the ports, meters and flow tables. */
call_rcu(>rcu, destroy_dp_rcu);
 }
 
diff --git a/net/openvswitch/flow_table.c b/net/openvswitch/flow_table.c
index 5904e93e5765..1c4fbac53fbd 100644
--- a/net/openvswitch/flow_table.c
+++ b/net/openvswitch/flow_table.c
@@ -345,19 +345,15 @@ static void table_instance_flow_free(struct flow_table 
*table,
flow_mask_remove(table, flow->mask);
 }
 
-static void table_instance_destroy(struct flow_table *table,
-  struct table_instance *ti,
-  struct table_instance *ufid_ti,
-  bool deferred)
+/* Must be called with OVS mutex held. */
+void table_instance_flow_flush(struct flow_table *table,
+  struct table_instance *ti,
+  struct table_instance *ufid_ti)
 {
int i;
 
-   if (!ti)
-   return;
-
-   BUG_ON(!ufid_ti);
if (ti->keep_flows)
-   goto skip_flows;
+   return;
 
for (i = 0; i < ti->n_buckets; i++) {
struct sw_flow *flow;
@@ -369,18 +365,16 @@ static void table_instance_destroy(struct flow_table 
*table,
 
table_instance_flow_free(table, ti, ufid_ti,
 flow, false);
-   ovs_flow_free(flow, deferred);
+   ovs_flow_free(flow, true);
}
}
+}
 
-skip_flows:
-   if (deferred) {
-   call_rcu(>rcu, flow_tbl_destroy_rcu_cb);
-   call_rcu(_ti->rcu, flow_tbl_destroy_rcu_cb);
-   } else {
-   __table_instance_destroy(ti);
-   __table_instance_destroy(ufid_ti);
-   }
+static void table_instance_destroy(struct table_instance *ti,
+  struct table_instance *ufid_ti)
+{
+   call_rcu(>rcu, flow_tbl_destroy_rcu_cb);
+   call_rcu(_ti->rcu, flow_tbl_destroy_rcu_cb);
 }
 
 /* No need for locking this function is called from RCU callback or
@@ -393,7 +387,7 @@ void ovs_flow_tbl_destroy(struct flow_table *table)
 
free_percpu(table->mask_cache);
kfree_rcu(rcu_dereference_raw(table->mask_array), rcu);
-   table_instance_destroy(table, ti, ufid_ti, false);
+   table_instance_destroy(ti, ufid_ti);
 }
 
 struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *ti,
@@ -509,7 +503,8 @@ int ovs_flow_tbl_flush(struct flow_table *flow_table)
flow_table->count = 0;
flow_table->ufid_count = 0;
 
-   table_instance_destroy(flow_table, old_ti, old_ufid_ti, true);
+   table_instance_flow_flush(flow_table, old_ti, old_ufid_ti);
+   table_instance_destroy(old_ti, old_ufid_ti);
return 0;
 
 err_free_ti:
diff --git a/net/openvswitch/flow_table.h b/net/openvswitch/flow_table.h
index 8a5cea6ae111..8ea8fc957377 100644
--- a/net/openvswitch/flow_table.h
+++ b/net/openvswitch/flow_table.h
@@ -86,4 +86,7 @@ bool ovs_flow_cmp(const struct sw_flow *, const struct 
sw_flow_match *);
 
 void ovs_flow_mask_key(struct sw_flow_key *dst, 

[PATCH net backport 5.6.14-5.8.3 v1] net: openvswitch: introduce common code for flushing flows

2020-08-24 Thread xiangxia . m . yue
From: Tonghao Zhang 

[ Upstream commit 77b981c82c1df7c7ad32a046f17f007450b46954 ]

Backport this commit to 5.6.14 - 5.8.3.

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: 50b0e61b32ee ("net: openvswitch: fix possible memleak on destroy 
flow-table")
Reported-by: Johan Knöös 
Reported-at: 
https://mail.openvswitch.org/pipermail/ovs-discuss/2020-August/050489.html
Signed-off-by: Tonghao Zhang 
Reviewed-by: Cong Wang 
Signed-off-by: David S. Miller 
---
 net/openvswitch/datapath.c   | 10 +-
 net/openvswitch/flow_table.c | 35 +++
 net/openvswitch/flow_table.h |  3 +++
 3 files changed, 27 insertions(+), 21 deletions(-)

diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 94b024534987..03b81aa99975 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -1736,6 +1736,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct 
genl_info *info)
 /* Called with ovs_mutex. */
 static void __dp_destroy(struct datapath *dp)
 {
+   struct flow_table *table = >table;
int i;
 
for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
@@ -1754,7 +1755,14 @@ static void __dp_destroy(struct datapath *dp)
 */
ovs_dp_detach_port(ovs_vport_ovsl(dp, OVSP_LOCAL));
 
-   /* RCU destroy the flow table */
+   /* Flush sw_flow in the tables. RCU cb only releases resource
+* such as dp, ports and tables. That may avoid some issues
+* such as RCU usage warning.
+*/
+   table_instance_flow_flush(table, ovsl_dereference(table->ti),
+ ovsl_dereference(table->ufid_ti));
+
+   /* RCU destroy the ports, meters and flow tables. */
call_rcu(>rcu, destroy_dp_rcu);
 }
 
diff --git a/net/openvswitch/flow_table.c b/net/openvswitch/flow_table.c
index 2398d7238300..f198bbb0c517 100644
--- a/net/openvswitch/flow_table.c
+++ b/net/openvswitch/flow_table.c
@@ -345,19 +345,15 @@ static void table_instance_flow_free(struct flow_table 
*table,
flow_mask_remove(table, flow->mask);
 }
 
-static void table_instance_destroy(struct flow_table *table,
-  struct table_instance *ti,
-  struct table_instance *ufid_ti,
-  bool deferred)
+/* Must be called with OVS mutex held. */
+void table_instance_flow_flush(struct flow_table *table,
+  struct table_instance *ti,
+  struct table_instance *ufid_ti)
 {
int i;
 
-   if (!ti)
-   return;
-
-   BUG_ON(!ufid_ti);
if (ti->keep_flows)
-   goto skip_flows;
+   return;
 
for (i = 0; i < ti->n_buckets; i++) {
struct sw_flow *flow;
@@ -369,18 +365,16 @@ static void table_instance_destroy(struct flow_table 
*table,
 
table_instance_flow_free(table, ti, ufid_ti,
 flow, false);
-   ovs_flow_free(flow, deferred);
+   ovs_flow_free(flow, true);
}
}
+}
 
-skip_flows:
-   if (deferred) {
-   call_rcu(>rcu, flow_tbl_destroy_rcu_cb);
-   call_rcu(_ti->rcu, flow_tbl_destroy_rcu_cb);
-   } else {
-   __table_instance_destroy(ti);
-   __table_instance_destroy(ufid_ti);
-   }
+static void table_instance_destroy(struct table_instance *ti,
+  struct table_instance *ufid_ti)
+{
+   call_rcu(>rcu, flow_tbl_destroy_rcu_cb);
+   call_rcu(_ti->rcu, flow_tbl_destroy_rcu_cb);
 }
 
 /* No need for locking this function is called from RCU callback or
@@ -393,7 +387,7 @@ void ovs_flow_tbl_destroy(struct flow_table *table)
 
free_percpu(table->mask_cache);
kfree_rcu(rcu_dereference_raw(table->mask_array), rcu);
-   table_instance_destroy(table, ti, ufid_ti, false);
+   table_instance_destroy(ti, ufid_ti);
 }
 
 struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *ti,
@@ -511,7 +505,8 @@ int ovs_flow_tbl_flush(struct flow_table *flow_table)
flow_table->count = 0;
flow_table->ufid_count = 0;
 
-   table_instance_destroy(flow_table, old_ti, old_ufid_ti, true);
+   table_instance_flow_flush(flow_table, old_ti, old_ufid_ti);
+   table_instance_destroy(old_ti, old_ufid_ti);
return 0;
 
 err_free_ti:
diff --git a/net/openvswitch/flow_table.h b/net/openvswitch/flow_table.h
index 8a5cea6ae111..8ea8fc957377 100644
--- a/net/openvswitch/flow_table.h
+++ b/net/openvswitch/flow_table.h
@@ -86,4 +86,7 @@ bool ovs_flow_cmp(const struct sw_flow *, const struct 
sw_flow_match *);
 
 void ovs_flow_mask_key(struct sw_flow_key 

[PATCH] net: openvswitch: silence suspicious RCU usage warning

2020-08-05 Thread xiangxia . m . yue
From: Tonghao Zhang 

ovs_flow_tbl_destroy always is called from RCU callback
or error path. It is no need to check if rcu_read_lock
or lockdep_ovsl_is_held was held.

ovs_dp_cmd_fill_info always is called with ovs_mutex,
So use the rcu_dereference_ovsl instead of rcu_dereference
in ovs_flow_tbl_masks_cache_size.

Fixes: 9bf24f594c6a ("net: openvswitch: make masks cache size configurable")
Cc: Eelco Chaudron 
Reported-by: syzbot+c0eb9e7cdde04e4eb...@syzkaller.appspotmail.com
Reported-by: syzbot+f612c02823acb02ff...@syzkaller.appspotmail.com
Signed-off-by: Tonghao Zhang 
---
 net/openvswitch/flow_table.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/net/openvswitch/flow_table.c b/net/openvswitch/flow_table.c
index 6527d84c3ea6..8c12675cbb67 100644
--- a/net/openvswitch/flow_table.c
+++ b/net/openvswitch/flow_table.c
@@ -518,8 +518,8 @@ void ovs_flow_tbl_destroy(struct flow_table *table)
 {
struct table_instance *ti = rcu_dereference_raw(table->ti);
struct table_instance *ufid_ti = rcu_dereference_raw(table->ufid_ti);
-   struct mask_cache *mc = rcu_dereference(table->mask_cache);
-   struct mask_array *ma = rcu_dereference_ovsl(table->mask_array);
+   struct mask_cache *mc = rcu_dereference_raw(table->mask_cache);
+   struct mask_array *ma = rcu_dereference_raw(table->mask_array);
 
call_rcu(>rcu, mask_cache_rcu_cb);
call_rcu(>rcu, mask_array_rcu_cb);
@@ -937,7 +937,7 @@ int ovs_flow_tbl_num_masks(const struct flow_table *table)
 
 u32 ovs_flow_tbl_masks_cache_size(const struct flow_table *table)
 {
-   struct mask_cache *mc = rcu_dereference(table->mask_cache);
+   struct mask_cache *mc = rcu_dereference_ovsl(table->mask_cache);
 
return READ_ONCE(mc->cache_size);
 }
-- 
2.26.1