netfilter: nf_tables: add flowtable offload control plane
authorPablo Neira Ayuso <pablo@netfilter.org>
Mon, 11 Nov 2019 23:29:55 +0000 (00:29 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 13 Nov 2019 03:42:26 +0000 (19:42 -0800)
This patch adds the NFTA_FLOWTABLE_FLAGS attribute that allows users to
specify the NF_FLOWTABLE_HW_OFFLOAD flag. This patch also adds a new
setup interface for the flowtable type to perform the flowtable offload
block callback configuration.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/netfilter/nf_flow_table.h
include/uapi/linux/netfilter/nf_tables.h
net/ipv4/netfilter/nf_flow_table_ipv4.c
net/ipv6/netfilter/nf_flow_table_ipv6.c
net/netfilter/nf_flow_table_inet.c
net/netfilter/nf_tables_api.c

index f000e89174871744b437b9c4e8117d0467605518..ece09d36c7a6aa18fefb51ac78408a344676310a 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/rcupdate.h>
 #include <linux/netfilter.h>
 #include <linux/netfilter/nf_conntrack_tuple_common.h>
+#include <net/flow_offload.h>
 #include <net/dst.h>
 
 struct nf_flowtable;
@@ -16,17 +17,27 @@ struct nf_flowtable_type {
        struct list_head                list;
        int                             family;
        int                             (*init)(struct nf_flowtable *ft);
+       int                             (*setup)(struct nf_flowtable *ft,
+                                                struct net_device *dev,
+                                                enum flow_block_command cmd);
        void                            (*free)(struct nf_flowtable *ft);
        nf_hookfn                       *hook;
        struct module                   *owner;
 };
 
+enum nf_flowtable_flags {
+       NF_FLOWTABLE_HW_OFFLOAD         = 0x1,
+};
+
 struct nf_flowtable {
        struct list_head                list;
        struct rhashtable               rhashtable;
        int                             priority;
        const struct nf_flowtable_type  *type;
        struct delayed_work             gc_work;
+       unsigned int                    flags;
+       struct flow_block               flow_block;
+       possible_net_t                  net;
 };
 
 enum flow_offload_tuple_dir {
@@ -131,4 +142,11 @@ unsigned int nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
 #define MODULE_ALIAS_NF_FLOWTABLE(family)      \
        MODULE_ALIAS("nf-flowtable-" __stringify(family))
 
+static inline int nf_flow_table_offload_setup(struct nf_flowtable *flowtable,
+                                             struct net_device *dev,
+                                             enum flow_block_command cmd)
+{
+       return 0;
+}
+
 #endif /* _NF_FLOW_TABLE_H */
index 81fed16fe2b2a0d6762794ee6f29d7e78c21127c..bb9b049310dffbebbaf84113aaee5737bbf94190 100644 (file)
@@ -1518,6 +1518,7 @@ enum nft_object_attributes {
  * @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32)
  * @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32)
  * @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64)
+ * @NFTA_FLOWTABLE_FLAGS: flags (NLA_U32)
  */
 enum nft_flowtable_attributes {
        NFTA_FLOWTABLE_UNSPEC,
@@ -1527,6 +1528,7 @@ enum nft_flowtable_attributes {
        NFTA_FLOWTABLE_USE,
        NFTA_FLOWTABLE_HANDLE,
        NFTA_FLOWTABLE_PAD,
+       NFTA_FLOWTABLE_FLAGS,
        __NFTA_FLOWTABLE_MAX
 };
 #define NFTA_FLOWTABLE_MAX     (__NFTA_FLOWTABLE_MAX - 1)
index 012c4047c788a0d5c51399b864824a756fb54f98..f3befddb5fdd25ad20efb5819d7801f8a699fcbe 100644 (file)
@@ -9,6 +9,7 @@
 static struct nf_flowtable_type flowtable_ipv4 = {
        .family         = NFPROTO_IPV4,
        .init           = nf_flow_table_init,
+       .setup          = nf_flow_table_offload_setup,
        .free           = nf_flow_table_free,
        .hook           = nf_flow_offload_ip_hook,
        .owner          = THIS_MODULE,
index f6d9a48c7a2aa4b1b5223b9c16b48ab3e6436899..1c47f05eabd63a473fd583ea4b9c2efffd1b03ae 100644 (file)
@@ -10,6 +10,7 @@
 static struct nf_flowtable_type flowtable_ipv6 = {
        .family         = NFPROTO_IPV6,
        .init           = nf_flow_table_init,
+       .setup          = nf_flow_table_offload_setup,
        .free           = nf_flow_table_free,
        .hook           = nf_flow_offload_ipv6_hook,
        .owner          = THIS_MODULE,
index 593357aedb3635b6d687b32f3fa518d2bf503ab8..1e70fd504da3585ef58cfbacedba01c0763acef8 100644 (file)
@@ -24,6 +24,7 @@ nf_flow_offload_inet_hook(void *priv, struct sk_buff *skb,
 static struct nf_flowtable_type flowtable_inet = {
        .family         = NFPROTO_INET,
        .init           = nf_flow_table_init,
+       .setup          = nf_flow_table_offload_setup,
        .free           = nf_flow_table_free,
        .hook           = nf_flow_offload_inet_hook,
        .owner          = THIS_MODULE,
index 0d2243945f1d057ad557da28b7e8c9319de6338d..2dc636faa322c497cefb4f96b227dbe7ec033852 100644 (file)
@@ -5835,6 +5835,7 @@ static const struct nla_policy nft_flowtable_policy[NFTA_FLOWTABLE_MAX + 1] = {
                                            .len = NFT_NAME_MAXLEN - 1 },
        [NFTA_FLOWTABLE_HOOK]           = { .type = NLA_NESTED },
        [NFTA_FLOWTABLE_HANDLE]         = { .type = NLA_U64 },
+       [NFTA_FLOWTABLE_FLAGS]          = { .type = NLA_U32 },
 };
 
 struct nft_flowtable *nft_flowtable_lookup(const struct nft_table *table,
@@ -5968,8 +5969,11 @@ static void nft_unregister_flowtable_net_hooks(struct net *net,
 {
        struct nft_hook *hook;
 
-       list_for_each_entry(hook, &flowtable->hook_list, list)
+       list_for_each_entry(hook, &flowtable->hook_list, list) {
                nf_unregister_net_hook(net, &hook->ops);
+               flowtable->data.type->setup(&flowtable->data, hook->ops.dev,
+                                           FLOW_BLOCK_UNBIND);
+       }
 }
 
 static int nft_register_flowtable_net_hooks(struct net *net,
@@ -5991,6 +5995,8 @@ static int nft_register_flowtable_net_hooks(struct net *net,
                        }
                }
 
+               flowtable->data.type->setup(&flowtable->data, hook->ops.dev,
+                                           FLOW_BLOCK_BIND);
                err = nf_register_net_hook(net, &hook->ops);
                if (err < 0)
                        goto err_unregister_net_hooks;
@@ -6006,6 +6012,8 @@ err_unregister_net_hooks:
                        break;
 
                nf_unregister_net_hook(net, &hook->ops);
+               flowtable->data.type->setup(&flowtable->data, hook->ops.dev,
+                                           FLOW_BLOCK_UNBIND);
                list_del_rcu(&hook->list);
                kfree_rcu(hook, rcu);
        }
@@ -6080,6 +6088,14 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
                goto err2;
        }
 
+       if (nla[NFTA_FLOWTABLE_FLAGS]) {
+               flowtable->data.flags =
+                       ntohl(nla_get_be32(nla[NFTA_FLOWTABLE_FLAGS]));
+               if (flowtable->data.flags & ~NF_FLOWTABLE_HW_OFFLOAD)
+                       goto err3;
+       }
+
+       write_pnet(&flowtable->data.net, net);
        flowtable->data.type = type;
        err = type->init(&flowtable->data);
        if (err < 0)
@@ -6191,7 +6207,8 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
            nla_put_string(skb, NFTA_FLOWTABLE_NAME, flowtable->name) ||
            nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use)) ||
            nla_put_be64(skb, NFTA_FLOWTABLE_HANDLE, cpu_to_be64(flowtable->handle),
-                        NFTA_FLOWTABLE_PAD))
+                        NFTA_FLOWTABLE_PAD) ||
+           nla_put_be32(skb, NFTA_FLOWTABLE_FLAGS, htonl(flowtable->data.flags)))
                goto nla_put_failure;
 
        nest = nla_nest_start_noflag(skb, NFTA_FLOWTABLE_HOOK);