Allow the user space to query what features are supported by the openvswitch
module. This will be used to allow or disallow certain configurations and/or
switch between newer and older APIs depending on what the kernel supports.

Two features are reported as supported by this patch: lwtunnel and IPv6
tunneling support. Theoretically, we could merge these two, as any of them
implies the other with this patch applied, but it's better to keep them
separate: kernel 4.3 supports lwtunnels but not IPv6 for ovs, and the
separation of the two flags allows us to backport a version of this patch
to 4.3 should the need arise.

Signed-off-by: Jiri Benc <jb...@redhat.com>
---
This is intentionally submitted to net-next. Kernel 4.3 will be fine without
this feature (but despite that, I'd like to keep the two flags separate).
---
 include/uapi/linux/openvswitch.h | 12 ++++++++++++
 net/openvswitch/datapath.c       | 21 ++++++++++++++++++---
 2 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h
index 32e07d8cbaf4..3d8d00b6e55d 100644
--- a/include/uapi/linux/openvswitch.h
+++ b/include/uapi/linux/openvswitch.h
@@ -73,6 +73,10 @@ 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_KERNEL_FEATURES: Bitmask of features that the datapath
+ * supports.  When creating a datapath, this is a minimal feature set
+ * requested, the request will fail if it cannot be honored.  On get
+ * operations, this contains all features supported by the datapath.
  *
  * These attributes follow the &struct ovs_header within the Generic Netlink
  * payload for %OVS_DP_* commands.
@@ -84,6 +88,7 @@ enum ovs_datapath_attr {
        OVS_DP_ATTR_STATS,              /* struct ovs_dp_stats */
        OVS_DP_ATTR_MEGAFLOW_STATS,     /* struct ovs_dp_megaflow_stats */
        OVS_DP_ATTR_USER_FEATURES,      /* OVS_DP_F_*  */
+       OVS_DP_ATTR_KERNEL_FEATURES,    /* OVS_DP_KF_* */
        __OVS_DP_ATTR_MAX
 };
 
@@ -121,6 +126,13 @@ struct ovs_vport_stats {
 /* Allow datapath to associate multiple Netlink PIDs to each vport */
 #define OVS_DP_F_VPORT_PIDS    (1 << 1)
 
+/* Datapath features */
+#define OVS_DP_KF_LWTUNNEL     (1ULL << 0)  /* lwtunnel interface supported */
+#define OVS_DP_KF_IPV6_TUNNEL  (1ULL << 1)  /* IPv6 tunneling supported */
+
+#define OVS_DP_KF_ALL          (OVS_DP_KF_LWTUNNEL | \
+                                OVS_DP_KF_IPV6_TUNNEL)
+
 /* Fixed logical ports. */
 #define OVSP_LOCAL      ((__u32)0)
 
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index a75828091e21..896435779fc8 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -1439,6 +1439,7 @@ static size_t ovs_dp_cmd_msg_size(void)
        msgsize += nla_total_size(sizeof(struct ovs_dp_stats));
        msgsize += nla_total_size(sizeof(struct ovs_dp_megaflow_stats));
        msgsize += nla_total_size(sizeof(u32)); /* OVS_DP_ATTR_USER_FEATURES */
+       msgsize += nla_total_size(sizeof(u64)); /* OVS_DP_ATTR_KERNEL_FEATURES 
*/
 
        return msgsize;
 }
@@ -1476,6 +1477,9 @@ static int ovs_dp_cmd_fill_info(struct datapath *dp, 
struct sk_buff *skb,
        if (nla_put_u32(skb, OVS_DP_ATTR_USER_FEATURES, dp->user_features))
                goto nla_put_failure;
 
+       if (nla_put_u64(skb, OVS_DP_ATTR_KERNEL_FEATURES, OVS_DP_KF_ALL))
+               goto nla_put_failure;
+
        genlmsg_end(skb, ovs_header);
        return 0;
 
@@ -1526,6 +1530,13 @@ static void ovs_dp_change(struct datapath *dp, struct 
nlattr *a[])
                dp->user_features = nla_get_u32(a[OVS_DP_ATTR_USER_FEATURES]);
 }
 
+static bool ovs_dp_kernel_features_ok(struct nlattr *a[])
+{
+       if (!a[OVS_DP_ATTR_KERNEL_FEATURES])
+               return true;
+       return !(nla_get_u64(a[OVS_DP_ATTR_KERNEL_FEATURES]) & ~OVS_DP_KF_ALL);
+}
+
 static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
 {
        struct nlattr **a = info->attrs;
@@ -1536,9 +1547,10 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct 
genl_info *info)
        struct ovs_net *ovs_net;
        int err, i;
 
-       err = -EINVAL;
        if (!a[OVS_DP_ATTR_NAME] || !a[OVS_DP_ATTR_UPCALL_PID])
-               goto err;
+               return -EINVAL;
+       if (!ovs_dp_kernel_features_ok(a))
+               return -EOPNOTSUPP;
 
        reply = ovs_dp_cmd_alloc_info(info);
        if (!reply)
@@ -1626,7 +1638,6 @@ err_free_dp:
        kfree(dp);
 err_free_reply:
        kfree_skb(reply);
-err:
        return err;
 }
 
@@ -1694,6 +1705,9 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct 
genl_info *info)
        struct datapath *dp;
        int err;
 
+       if (!ovs_dp_kernel_features_ok(info->attrs))
+               return -EOPNOTSUPP;
+
        reply = ovs_dp_cmd_alloc_info(info);
        if (!reply)
                return -ENOMEM;
@@ -1777,6 +1791,7 @@ static const struct nla_policy 
datapath_policy[OVS_DP_ATTR_MAX + 1] = {
        [OVS_DP_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
        [OVS_DP_ATTR_UPCALL_PID] = { .type = NLA_U32 },
        [OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 },
+       [OVS_DP_ATTR_KERNEL_FEATURES] = { .type = NLA_U64 },
 };
 
 static const struct genl_ops dp_datapath_genl_ops[] = {
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to