net: extract nf_ct_handle_fragments to nf_conntrack_ovs
authorXin Long <lucien.xin@gmail.com>
Tue, 7 Feb 2023 22:52:10 +0000 (17:52 -0500)
committerJakub Kicinski <kuba@kernel.org>
Sat, 11 Feb 2023 00:23:03 +0000 (16:23 -0800)
Now handle_fragments() in OVS and TC have the similar code, and
this patch removes the duplicate code by moving the function
to nf_conntrack_ovs.

Note that skb_clear_hash(skb) or skb->ignore_df = 1 should be
done only when defrag returns 0, as it does in other places
in kernel.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Reviewed-by: Aaron Conole <aconole@redhat.com>
Acked-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/net/netfilter/nf_conntrack.h
net/netfilter/nf_conntrack_ovs.c
net/openvswitch/conntrack.c
net/sched/act_ct.c

index a6e89d7..7bbab8f 100644 (file)
@@ -363,6 +363,8 @@ static inline struct nf_conntrack_net *nf_ct_pernet(const struct net *net)
 }
 
 int nf_ct_skb_network_trim(struct sk_buff *skb, int family);
+int nf_ct_handle_fragments(struct net *net, struct sk_buff *skb,
+                          u16 zone, u8 family, u8 *proto, u16 *mru);
 
 #define NF_CT_STAT_INC(net, count)       __this_cpu_inc((net)->ct.stat->count)
 #define NF_CT_STAT_INC_ATOMIC(net, count) this_cpu_inc((net)->ct.stat->count)
index c60ef71..52b776b 100644 (file)
@@ -3,6 +3,8 @@
 
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_seqadj.h>
+#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
+#include <net/ipv6_frag.h>
 #include <net/ip.h>
 
 /* 'skb' should already be pulled to nh_ofs. */
@@ -128,3 +130,49 @@ int nf_ct_skb_network_trim(struct sk_buff *skb, int family)
        return pskb_trim_rcsum(skb, len);
 }
 EXPORT_SYMBOL_GPL(nf_ct_skb_network_trim);
+
+/* Returns 0 on success, -EINPROGRESS if 'skb' is stolen, or other nonzero
+ * value if 'skb' is freed.
+ */
+int nf_ct_handle_fragments(struct net *net, struct sk_buff *skb,
+                          u16 zone, u8 family, u8 *proto, u16 *mru)
+{
+       int err;
+
+       if (family == NFPROTO_IPV4) {
+               enum ip_defrag_users user = IP_DEFRAG_CONNTRACK_IN + zone;
+
+               memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
+               local_bh_disable();
+               err = ip_defrag(net, skb, user);
+               local_bh_enable();
+               if (err)
+                       return err;
+
+               *mru = IPCB(skb)->frag_max_size;
+#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
+       } else if (family == NFPROTO_IPV6) {
+               enum ip6_defrag_users user = IP6_DEFRAG_CONNTRACK_IN + zone;
+
+               memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm));
+               err = nf_ct_frag6_gather(net, skb, user);
+               if (err) {
+                       if (err != -EINPROGRESS)
+                               kfree_skb(skb);
+                       return err;
+               }
+
+               *proto = ipv6_hdr(skb)->nexthdr;
+               *mru = IP6CB(skb)->frag_max_size;
+#endif
+       } else {
+               kfree_skb(skb);
+               return -EPFNOSUPPORT;
+       }
+
+       skb_clear_hash(skb);
+       skb->ignore_df = 1;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(nf_ct_handle_fragments);
index 211e058..331730f 100644 (file)
@@ -435,56 +435,13 @@ static int ovs_ct_set_labels(struct nf_conn *ct, struct sw_flow_key *key,
        return 0;
 }
 
-/* Returns 0 on success, -EINPROGRESS if 'skb' is stolen, or other nonzero
- * value if 'skb' is freed.
- */
-static int handle_fragments(struct net *net, struct sk_buff *skb,
-                           u16 zone, u8 family, u8 *proto, u16 *mru)
-{
-       int err;
-
-       if (family == NFPROTO_IPV4) {
-               enum ip_defrag_users user = IP_DEFRAG_CONNTRACK_IN + zone;
-
-               memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
-               err = ip_defrag(net, skb, user);
-               if (err)
-                       return err;
-
-               *mru = IPCB(skb)->frag_max_size;
-#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
-       } else if (family == NFPROTO_IPV6) {
-               enum ip6_defrag_users user = IP6_DEFRAG_CONNTRACK_IN + zone;
-
-               memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm));
-               err = nf_ct_frag6_gather(net, skb, user);
-               if (err) {
-                       if (err != -EINPROGRESS)
-                               kfree_skb(skb);
-                       return err;
-               }
-
-               *proto = ipv6_hdr(skb)->nexthdr;
-               *mru = IP6CB(skb)->frag_max_size;
-#endif
-       } else {
-               kfree_skb(skb);
-               return -EPFNOSUPPORT;
-       }
-
-       skb_clear_hash(skb);
-       skb->ignore_df = 1;
-
-       return 0;
-}
-
 static int ovs_ct_handle_fragments(struct net *net, struct sw_flow_key *key,
                                   u16 zone, int family, struct sk_buff *skb)
 {
        struct ovs_skb_cb ovs_cb = *OVS_CB(skb);
        int err;
 
-       err = handle_fragments(net, skb, zone, family, &key->ip.proto, &ovs_cb.mru);
+       err = nf_ct_handle_fragments(net, skb, zone, family, &key->ip.proto, &ovs_cb.mru);
        if (err)
                return err;
 
index 9f133ed..9cc0bc7 100644 (file)
@@ -778,49 +778,6 @@ static int tcf_ct_ipv6_is_fragment(struct sk_buff *skb, bool *frag)
        return 0;
 }
 
-static int handle_fragments(struct net *net, struct sk_buff *skb,
-                           u16 zone, u8 family, u16 *mru)
-{
-       int err;
-
-       if (family == NFPROTO_IPV4) {
-               enum ip_defrag_users user = IP_DEFRAG_CONNTRACK_IN + zone;
-
-               memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
-               local_bh_disable();
-               err = ip_defrag(net, skb, user);
-               local_bh_enable();
-               if (err && err != -EINPROGRESS)
-                       return err;
-
-               if (!err)
-                       *mru = IPCB(skb)->frag_max_size;
-       } else { /* NFPROTO_IPV6 */
-#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
-               enum ip6_defrag_users user = IP6_DEFRAG_CONNTRACK_IN + zone;
-
-               memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm));
-               err = nf_ct_frag6_gather(net, skb, user);
-               if (err && err != -EINPROGRESS)
-                       goto out_free;
-
-               if (!err)
-                       *mru = IP6CB(skb)->frag_max_size;
-#else
-               err = -EOPNOTSUPP;
-               goto out_free;
-#endif
-       }
-
-       skb_clear_hash(skb);
-       skb->ignore_df = 1;
-       return err;
-
-out_free:
-       kfree_skb(skb);
-       return err;
-}
-
 static int tcf_ct_handle_fragments(struct net *net, struct sk_buff *skb,
                                   u8 family, u16 zone, bool *defrag)
 {
@@ -828,6 +785,7 @@ static int tcf_ct_handle_fragments(struct net *net, struct sk_buff *skb,
        struct nf_conn *ct;
        int err = 0;
        bool frag;
+       u8 proto;
        u16 mru;
 
        /* Previously seen (loopback)? Ignore. */
@@ -843,7 +801,7 @@ static int tcf_ct_handle_fragments(struct net *net, struct sk_buff *skb,
                return err;
 
        skb_get(skb);
-       err = handle_fragments(net, skb, zone, family, &mru);
+       err = nf_ct_handle_fragments(net, skb, zone, family, &proto, &mru);
        if (err)
                return err;