openvswitch: allow specifying ifindex of new interfaces
authorAndrey Zhadchenko <andrey.zhadchenko@virtuozzo.com>
Thu, 25 Aug 2022 02:04:49 +0000 (05:04 +0300)
committerJakub Kicinski <kuba@kernel.org>
Sat, 27 Aug 2022 02:31:20 +0000 (19:31 -0700)
CRIU is preserving ifindexes of net devices after restoration. However,
current Open vSwitch API does not allow to target ifindex, so we cannot
correctly restore OVS configuration.

Add new OVS_DP_ATTR_IFINDEX for OVS_DP_CMD_NEW and use it as desired
ifindex.
Use OVS_VPORT_ATTR_IFINDEX during OVS_VPORT_CMD_NEW to specify new netdev
ifindex.

Signed-off-by: Andrey Zhadchenko <andrey.zhadchenko@virtuozzo.com>
Acked-by: Christian Brauner (Microsoft) <brauner@kernel.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/uapi/linux/openvswitch.h
net/openvswitch/datapath.c
net/openvswitch/vport-internal_dev.c
net/openvswitch/vport.h

index ce3e173..94066f8 100644 (file)
@@ -76,6 +76,8 @@ enum ovs_datapath_cmd {
  * datapath.  Always present in notifications.
  * @OVS_DP_ATTR_MEGAFLOW_STATS: Statistics about mega flow masks usage for the
  * datapath. Always present in notifications.
+ * @OVS_DP_ATTR_IFINDEX: Interface index for a new datapath netdev. Only
+ * valid for %OVS_DP_CMD_NEW requests.
  *
  * These attributes follow the &struct ovs_header within the Generic Netlink
  * payload for %OVS_DP_* commands.
@@ -92,6 +94,7 @@ enum ovs_datapath_attr {
        OVS_DP_ATTR_PER_CPU_PIDS,   /* Netlink PIDS to receive upcalls in
                                     * per-cpu dispatch mode
                                     */
+       OVS_DP_ATTR_IFINDEX,
        __OVS_DP_ATTR_MAX
 };
 
index 45f9a7b..1ad771d 100644 (file)
@@ -1787,6 +1787,8 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
        parms.dp = dp;
        parms.port_no = OVSP_LOCAL;
        parms.upcall_portids = a[OVS_DP_ATTR_UPCALL_PID];
+       parms.desired_ifindex = a[OVS_DP_ATTR_IFINDEX]
+               ? nla_get_u32(a[OVS_DP_ATTR_IFINDEX]) : 0;
 
        /* So far only local changes have been made, now need the lock. */
        ovs_lock();
@@ -2004,6 +2006,7 @@ static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = {
        [OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 },
        [OVS_DP_ATTR_MASKS_CACHE_SIZE] =  NLA_POLICY_RANGE(NLA_U32, 0,
                PCPU_MIN_UNIT_SIZE / sizeof(struct mask_cache_entry)),
+       [OVS_DP_ATTR_IFINDEX] = {.type = NLA_U32 },
 };
 
 static const struct genl_small_ops dp_datapath_genl_ops[] = {
@@ -2207,7 +2210,10 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
        if (!a[OVS_VPORT_ATTR_NAME] || !a[OVS_VPORT_ATTR_TYPE] ||
            !a[OVS_VPORT_ATTR_UPCALL_PID])
                return -EINVAL;
-       if (a[OVS_VPORT_ATTR_IFINDEX])
+
+       parms.type = nla_get_u32(a[OVS_VPORT_ATTR_TYPE]);
+
+       if (a[OVS_VPORT_ATTR_IFINDEX] && parms.type != OVS_VPORT_TYPE_INTERNAL)
                return -EOPNOTSUPP;
 
        port_no = a[OVS_VPORT_ATTR_PORT_NO]
@@ -2244,11 +2250,12 @@ restart:
        }
 
        parms.name = nla_data(a[OVS_VPORT_ATTR_NAME]);
-       parms.type = nla_get_u32(a[OVS_VPORT_ATTR_TYPE]);
        parms.options = a[OVS_VPORT_ATTR_OPTIONS];
        parms.dp = dp;
        parms.port_no = port_no;
        parms.upcall_portids = a[OVS_VPORT_ATTR_UPCALL_PID];
+       parms.desired_ifindex = a[OVS_VPORT_ATTR_IFINDEX]
+               ? nla_get_u32(a[OVS_VPORT_ATTR_IFINDEX]) : 0;
 
        vport = new_vport(&parms);
        err = PTR_ERR(vport);
index 134bc85..35f42c9 100644 (file)
@@ -147,6 +147,7 @@ static struct vport *internal_dev_create(const struct vport_parms *parms)
        }
 
        dev_net_set(vport->dev, ovs_dp_get_net(vport->dp));
+       dev->ifindex = parms->desired_ifindex;
        internal_dev = internal_dev_priv(vport->dev);
        internal_dev->vport = vport;
 
index 9de5030..7d276f6 100644 (file)
@@ -90,12 +90,14 @@ struct vport {
  * @type: New vport's type.
  * @options: %OVS_VPORT_ATTR_OPTIONS attribute from Netlink message, %NULL if
  * none was supplied.
+ * @desired_ifindex: New vport's ifindex.
  * @dp: New vport's datapath.
  * @port_no: New vport's port number.
  */
 struct vport_parms {
        const char *name;
        enum ovs_vport_type type;
+       int desired_ifindex;
        struct nlattr *options;
 
        /* For ovs_vport_alloc(). */