net: openvswitch: Set OvS recirc_id from tc chain index
authorPaul Blakey <paulb@mellanox.com>
Wed, 4 Sep 2019 13:56:37 +0000 (16:56 +0300)
committerDavid S. Miller <davem@davemloft.net>
Fri, 6 Sep 2019 12:59:18 +0000 (14:59 +0200)
Offloaded OvS datapath rules are translated one to one to tc rules,
for example the following simplified OvS rule:

recirc_id(0),in_port(dev1),eth_type(0x0800),ct_state(-trk) actions:ct(),recirc(2)

Will be translated to the following tc rule:

$ tc filter add dev dev1 ingress \
    prio 1 chain 0 proto ip \
flower tcp ct_state -trk \
action ct pipe \
action goto chain 2

Received packets will first travel though tc, and if they aren't stolen
by it, like in the above rule, they will continue to OvS datapath.
Since we already did some actions (action ct in this case) which might
modify the packets, and updated action stats, we would like to continue
the proccessing with the correct recirc_id in OvS (here recirc_id(2))
where we left off.

To support this, introduce a new skb extension for tc, which
will be used for translating tc chain to ovs recirc_id to
handle these miss cases. Last tc chain index will be set
by tc goto chain action and read by OvS datapath.

Signed-off-by: Paul Blakey <paulb@mellanox.com>
Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Acked-by: Pravin B Shelar <pshelar@ovn.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/skbuff.h
include/uapi/linux/openvswitch.h
net/core/skbuff.c
net/openvswitch/datapath.c
net/openvswitch/datapath.h
net/openvswitch/flow.c
net/sched/Kconfig
net/sched/cls_api.c

index 77c6dc88e95dde78e32dd5e4c9909f2a088b75ed..028e684fa974668b058b1f2243ab4477e5600975 100644 (file)
@@ -279,6 +279,16 @@ struct nf_bridge_info {
 };
 #endif
 
+#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
+/* Chain in tc_skb_ext will be used to share the tc chain with
+ * ovs recirc_id. It will be set to the current chain by tc
+ * and read by ovs to recirc_id.
+ */
+struct tc_skb_ext {
+       __u32 chain;
+};
+#endif
+
 struct sk_buff_head {
        /* These two members must be first. */
        struct sk_buff  *next;
@@ -4057,6 +4067,9 @@ enum skb_ext_id {
 #endif
 #ifdef CONFIG_XFRM
        SKB_EXT_SEC_PATH,
+#endif
+#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
+       TC_SKB_EXT,
 #endif
        SKB_EXT_NUM, /* must be last */
 };
index f271f1ec50aed08cb8f0e52fdd9ae8752b8c3b83..1887a451c388ffd7653c3a211422afe94e1c4e9c 100644 (file)
@@ -123,6 +123,9 @@ struct ovs_vport_stats {
 /* Allow datapath to associate multiple Netlink PIDs to each vport */
 #define OVS_DP_F_VPORT_PIDS    (1 << 1)
 
+/* Allow tc offload recirc sharing */
+#define OVS_DP_F_TC_RECIRC_SHARING     (1 << 2)
+
 /* Fixed logical ports. */
 #define OVSP_LOCAL      ((__u32)0)
 
index ea8e8d332d85064e241bc716231991cb07a8dc40..2b40b5a9425ba22ebdec389b15a75007b8ba7157 100644 (file)
@@ -4087,6 +4087,9 @@ static const u8 skb_ext_type_len[] = {
 #ifdef CONFIG_XFRM
        [SKB_EXT_SEC_PATH] = SKB_EXT_CHUNKSIZEOF(struct sec_path),
 #endif
+#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
+       [TC_SKB_EXT] = SKB_EXT_CHUNKSIZEOF(struct tc_skb_ext),
+#endif
 };
 
 static __always_inline unsigned int skb_ext_total_length(void)
@@ -4097,6 +4100,9 @@ static __always_inline unsigned int skb_ext_total_length(void)
 #endif
 #ifdef CONFIG_XFRM
                skb_ext_type_len[SKB_EXT_SEC_PATH] +
+#endif
+#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
+               skb_ext_type_len[TC_SKB_EXT] +
 #endif
                0;
 }
index 65122bbccd27ab94f57e6ce7c2c2569497b2e166..dde9d762edee90ab223ccffe28b529b24811de74 100644 (file)
@@ -1545,10 +1545,34 @@ static void ovs_dp_reset_user_features(struct sk_buff *skb, struct genl_info *in
        dp->user_features = 0;
 }
 
-static void ovs_dp_change(struct datapath *dp, struct nlattr *a[])
+DEFINE_STATIC_KEY_FALSE(tc_recirc_sharing_support);
+
+static int ovs_dp_change(struct datapath *dp, struct nlattr *a[])
 {
-       if (a[OVS_DP_ATTR_USER_FEATURES])
-               dp->user_features = nla_get_u32(a[OVS_DP_ATTR_USER_FEATURES]);
+       u32 user_features = 0;
+
+       if (a[OVS_DP_ATTR_USER_FEATURES]) {
+               user_features = nla_get_u32(a[OVS_DP_ATTR_USER_FEATURES]);
+
+               if (user_features & ~(OVS_DP_F_VPORT_PIDS |
+                                     OVS_DP_F_UNALIGNED |
+                                     OVS_DP_F_TC_RECIRC_SHARING))
+                       return -EOPNOTSUPP;
+
+#if !IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
+               if (user_features & OVS_DP_F_TC_RECIRC_SHARING)
+                       return -EOPNOTSUPP;
+#endif
+       }
+
+       dp->user_features = user_features;
+
+       if (dp->user_features & OVS_DP_F_TC_RECIRC_SHARING)
+               static_branch_enable(&tc_recirc_sharing_support);
+       else
+               static_branch_disable(&tc_recirc_sharing_support);
+
+       return 0;
 }
 
 static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
@@ -1610,7 +1634,9 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
        parms.port_no = OVSP_LOCAL;
        parms.upcall_portids = a[OVS_DP_ATTR_UPCALL_PID];
 
-       ovs_dp_change(dp, a);
+       err = ovs_dp_change(dp, a);
+       if (err)
+               goto err_destroy_meters;
 
        /* So far only local changes have been made, now need the lock. */
        ovs_lock();
@@ -1736,7 +1762,9 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
        if (IS_ERR(dp))
                goto err_unlock_free;
 
-       ovs_dp_change(dp, info->attrs);
+       err = ovs_dp_change(dp, info->attrs);
+       if (err)
+               goto err_unlock_free;
 
        err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
                                   info->snd_seq, 0, OVS_DP_CMD_SET);
index 751d34accdf9afa467bfb63b1b92bde745f41a20..81e85dde8217a1ff871c9ae134fdd3fcc6fd8ac4 100644 (file)
@@ -218,6 +218,8 @@ static inline struct datapath *get_dp(struct net *net, int dp_ifindex)
 extern struct notifier_block ovs_dp_device_notifier;
 extern struct genl_family dp_vport_genl_family;
 
+DECLARE_STATIC_KEY_FALSE(tc_recirc_sharing_support);
+
 void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key);
 void ovs_dp_detach_port(struct vport *);
 int ovs_dp_upcall(struct datapath *, struct sk_buff *,
index 9d81d2c7bf8212e5d50063634e8ab064b2005040..38147e6a20f534a1d28eb8bd2ed2701c060c6efe 100644 (file)
@@ -842,6 +842,9 @@ static int key_extract_mac_proto(struct sk_buff *skb)
 int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
                         struct sk_buff *skb, struct sw_flow_key *key)
 {
+#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
+       struct tc_skb_ext *tc_ext;
+#endif
        int res, err;
 
        /* Extract metadata from packet. */
@@ -874,7 +877,17 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
        if (res < 0)
                return res;
        key->mac_proto = res;
+
+#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
+       if (static_branch_unlikely(&tc_recirc_sharing_support)) {
+               tc_ext = skb_ext_find(skb, TC_SKB_EXT);
+               key->recirc_id = tc_ext ? tc_ext->chain : 0;
+       } else {
+               key->recirc_id = 0;
+       }
+#else
        key->recirc_id = 0;
+#endif
 
        err = key_extract(skb, key);
        if (!err)
index afd2ba157a132d1189b39c3307da093db0dd39f4..b3faafeafab98739a88467d70bb205ce416cc332 100644 (file)
@@ -963,6 +963,19 @@ config NET_IFE_SKBTCINDEX
         tristate "Support to encoding decoding skb tcindex on IFE action"
         depends on NET_ACT_IFE
 
+config NET_TC_SKB_EXT
+       bool "TC recirculation support"
+       depends on NET_CLS_ACT
+       default y if NET_CLS_ACT
+       select SKB_EXTENSIONS
+
+       help
+         Say Y here to allow tc chain misses to continue in OvS datapath in
+         the correct recirc_id, and hardware chain misses to continue in
+         the correct chain in tc software datapath.
+
+         Say N here if you won't be using tc<->ovs offload or tc chains offload.
+
 endif # NET_SCHED
 
 config NET_SCH_FIFO
index 671ca905dbb5d0743370fe50d0e6eca41ab5e344..05c4fe1c3ca28c3f05fde784af04cf16b1c867b0 100644 (file)
@@ -1514,6 +1514,18 @@ reclassify:
                        goto reset;
                } else if (unlikely(TC_ACT_EXT_CMP(err, TC_ACT_GOTO_CHAIN))) {
                        first_tp = res->goto_tp;
+
+#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
+                       {
+                               struct tc_skb_ext *ext;
+
+                               ext = skb_ext_add(skb, TC_SKB_EXT);
+                               if (WARN_ON_ONCE(!ext))
+                                       return TC_ACT_SHOT;
+
+                               ext->chain = err & TC_ACT_EXT_VAL_MASK;
+                       }
+#endif
                        goto reset;
                }
 #endif