CRIU needs OVS_DP_ATTR_PER_CPU_PIDS to checkpoint/restore newest
openvswitch versions.
Add pids to generic datapath reply. Adjust reply allocation to reserve
memory for pids and move it under ovs_lock() to ensure than number of
pids is unchanged while we adding them to nlmsg.

Signed-off-by: Andrey Zhadchenko <andrey.zhadche...@virtuozzo.com>
---
 net/openvswitch/datapath.c | 88 +++++++++++++++++++++++---------------
 1 file changed, 53 insertions(+), 35 deletions(-)

diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 20c9964b74cc..865c848a041b 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -1506,9 +1506,11 @@ static struct genl_family dp_flow_genl_family 
__ro_after_init = {
        .module = THIS_MODULE,
 };
 
-static size_t ovs_dp_cmd_msg_size(void)
+static size_t ovs_dp_cmd_msg_size(struct datapath *dp)
 {
        size_t msgsize = NLMSG_ALIGN(sizeof(struct ovs_header));
+       struct dp_nlsk_pids *pids = ovsl_dereference(dp->upcall_portids);
+
 
        msgsize += nla_total_size(IFNAMSIZ);
        msgsize += nla_total_size_64bit(sizeof(struct ovs_dp_stats));
@@ -1516,6 +1518,9 @@ static size_t ovs_dp_cmd_msg_size(void)
        msgsize += nla_total_size(sizeof(u32)); /* OVS_DP_ATTR_USER_FEATURES */
        msgsize += nla_total_size(sizeof(u32)); /* OVS_DP_ATTR_MASKS_CACHE_SIZE 
*/
 
+       if (dp->user_features & OVS_DP_F_DISPATCH_UPCALL_PER_CPU && pids)
+               msgsize += nla_total_size_64bit(sizeof(u32) * pids->n_pids);
+
        return msgsize;
 }
 
@@ -1527,6 +1532,7 @@ static int ovs_dp_cmd_fill_info(struct datapath *dp, 
struct sk_buff *skb,
        struct ovs_dp_stats dp_stats;
        struct ovs_dp_megaflow_stats dp_megaflow_stats;
        int err;
+       struct dp_nlsk_pids *pids = ovsl_dereference(dp->upcall_portids);
 
        ovs_header = genlmsg_put(skb, portid, seq, &dp_datapath_genl_family,
                                 flags, cmd);
@@ -1556,6 +1562,11 @@ static int ovs_dp_cmd_fill_info(struct datapath *dp, 
struct sk_buff *skb,
                        ovs_flow_tbl_masks_cache_size(&dp->table)))
                goto nla_put_failure;
 
+       if (dp->user_features & OVS_DP_F_DISPATCH_UPCALL_PER_CPU && pids &&
+           nla_put_64bit(skb, OVS_DP_ATTR_PER_CPU_PIDS, sizeof(u32) * 
pids->n_pids,
+                         &pids->pids, OVS_DP_ATTR_PAD))
+               goto nla_put_failure;
+
        genlmsg_end(skb, ovs_header);
        return 0;
 
@@ -1565,9 +1576,9 @@ static int ovs_dp_cmd_fill_info(struct datapath *dp, 
struct sk_buff *skb,
        return -EMSGSIZE;
 }
 
-static struct sk_buff *ovs_dp_cmd_alloc_info(void)
+static struct sk_buff *ovs_dp_cmd_alloc_info(struct datapath *dp)
 {
-       return genlmsg_new(ovs_dp_cmd_msg_size(), GFP_KERNEL);
+       return genlmsg_new(ovs_dp_cmd_msg_size(dp), GFP_KERNEL);
 }
 
 /* Called with rcu_read_lock or ovs_mutex. */
@@ -1745,14 +1756,9 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct 
genl_info *info)
        if (!a[OVS_DP_ATTR_NAME] || !a[OVS_DP_ATTR_UPCALL_PID])
                goto err;
 
-       reply = ovs_dp_cmd_alloc_info();
-       if (!reply)
-               return -ENOMEM;
-
-       err = -ENOMEM;
        dp = kzalloc(sizeof(*dp), GFP_KERNEL);
        if (dp == NULL)
-               goto err_destroy_reply;
+               return -ENOMEM;
 
        ovs_dp_set_net(dp, sock_net(skb->sk));
 
@@ -1785,9 +1791,15 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct 
genl_info *info)
        /* So far only local changes have been made, now need the lock. */
        ovs_lock();
 
-       err = ovs_dp_change(dp, a);
-       if (err)
+       reply = ovs_dp_cmd_alloc_info(dp);
+       if (!reply) {
+               err = -ENOMEM;
                goto err_unlock_and_destroy_meters;
+       }
+
+       err = ovs_dp_change(dp, a);
+       if (err)
+               goto err_destroy_reply;
 
        vport = new_vport(&parms);
        if (IS_ERR(vport)) {
@@ -1822,6 +1834,8 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct 
genl_info *info)
 err_destroy_pids:
        if (rcu_dereference_raw(dp->upcall_portids))
                kfree(rcu_dereference_raw(dp->upcall_portids));
+err_destroy_reply:
+       kfree_skb(reply);
 err_unlock_and_destroy_meters:
        ovs_unlock();
        ovs_meters_exit(dp);
@@ -1833,8 +1847,6 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct 
genl_info *info)
        ovs_flow_tbl_destroy(&dp->table);
 err_destroy_dp:
        kfree(dp);
-err_destroy_reply:
-       kfree_skb(reply);
 err:
        return err;
 }
@@ -1881,15 +1893,17 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct 
genl_info *info)
        struct datapath *dp;
        int err;
 
-       reply = ovs_dp_cmd_alloc_info();
-       if (!reply)
-               return -ENOMEM;
-
        ovs_lock();
        dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
        err = PTR_ERR(dp);
        if (IS_ERR(dp))
-               goto err_unlock_free;
+               goto err_unlock;
+
+       reply = ovs_dp_cmd_alloc_info(dp);
+       if (!reply) {
+               err = -ENOMEM;
+               goto err_unlock;
+       }
 
        err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
                                   info->snd_seq, 0, OVS_DP_CMD_DEL);
@@ -1902,9 +1916,8 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct 
genl_info *info)
 
        return 0;
 
-err_unlock_free:
+err_unlock:
        ovs_unlock();
-       kfree_skb(reply);
        return err;
 }
 
@@ -1914,19 +1927,21 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct 
genl_info *info)
        struct datapath *dp;
        int err;
 
-       reply = ovs_dp_cmd_alloc_info();
-       if (!reply)
-               return -ENOMEM;
-
        ovs_lock();
        dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
        err = PTR_ERR(dp);
        if (IS_ERR(dp))
-               goto err_unlock_free;
+               goto err_unlock;
+
+       reply = ovs_dp_cmd_alloc_info(dp);
+       if (!reply) {
+               err = -ENOMEM;
+               goto err_unlock;
+       }
 
        err = ovs_dp_change(dp, info->attrs);
        if (err)
-               goto err_unlock_free;
+               goto err_free;
 
        err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
                                   info->snd_seq, 0, OVS_DP_CMD_SET);
@@ -1937,9 +1952,10 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct 
genl_info *info)
 
        return 0;
 
-err_unlock_free:
-       ovs_unlock();
+err_free:
        kfree_skb(reply);
+err_unlock:
+       ovs_unlock();
        return err;
 }
 
@@ -1949,16 +1965,19 @@ static int ovs_dp_cmd_get(struct sk_buff *skb, struct 
genl_info *info)
        struct datapath *dp;
        int err;
 
-       reply = ovs_dp_cmd_alloc_info();
-       if (!reply)
-               return -ENOMEM;
-
        ovs_lock();
        dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
        if (IS_ERR(dp)) {
                err = PTR_ERR(dp);
-               goto err_unlock_free;
+               goto err_unlock;
        }
+
+       reply = ovs_dp_cmd_alloc_info(dp);
+       if (!reply) {
+               err = -ENOMEM;
+               goto err_unlock;
+       }
+
        err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
                                   info->snd_seq, 0, OVS_DP_CMD_GET);
        BUG_ON(err < 0);
@@ -1966,9 +1985,8 @@ static int ovs_dp_cmd_get(struct sk_buff *skb, struct 
genl_info *info)
 
        return genlmsg_reply(reply, info);
 
-err_unlock_free:
+err_unlock:
        ovs_unlock();
-       kfree_skb(reply);
        return err;
 }
 
-- 
2.31.1

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to