aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-05-31 03:02:30 -0400
committerDavid S. Miller <davem@davemloft.net>2015-05-31 03:02:30 -0400
commit583d3f5af2a6dfa7866715d9e062dbfb3b66a6f0 (patch)
tree77e7c8514031b67d74bb5ce415074dd098b108ac
parent5289e4a03fb9ba79f0ad065c26024afe379c3d35 (diff)
parented6c4136f1571bd6ab362afc3410905a8a69ca42 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
Pablo Neira Ayuso says: ==================== Netfilter updates for net-next The following patchset contains Netfilter updates for net-next, they are: 1) default CONFIG_NETFILTER_INGRESS to y for easier compile-testing of all options. 2) Allow to bind a table to net_device. This introduces the internal NFT_AF_NEEDS_DEV flag to perform a mandatory check for this binding. This is required by the next patch. 3) Add the 'netdev' table family, this new table allows you to create ingress filter basechains. This provides access to the existing nf_tables features from ingress. 4) Kill unused argument from compat_find_calc_{match,target} in ip_tables and ip6_tables, from Florian Westphal. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/netfilter/nf_tables.h8
-rw-r--r--include/net/netns/nftables.h1
-rw-r--r--include/uapi/linux/netfilter/nf_tables.h2
-rw-r--r--net/ipv4/netfilter/ip_tables.c4
-rw-r--r--net/ipv6/netfilter/ip6_tables.c4
-rw-r--r--net/netfilter/Kconfig6
-rw-r--r--net/netfilter/Makefile1
-rw-r--r--net/netfilter/nf_tables_api.c46
-rw-r--r--net/netfilter/nf_tables_netdev.c183
9 files changed, 244 insertions, 11 deletions
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index e6bcf55dcf20..3d6f48ca40a7 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -819,6 +819,7 @@ unsigned int nft_do_chain(struct nft_pktinfo *pkt,
819 * @use: number of chain references to this table 819 * @use: number of chain references to this table
820 * @flags: table flag (see enum nft_table_flags) 820 * @flags: table flag (see enum nft_table_flags)
821 * @name: name of the table 821 * @name: name of the table
822 * @dev: this table is bound to this device (if any)
822 */ 823 */
823struct nft_table { 824struct nft_table {
824 struct list_head list; 825 struct list_head list;
@@ -828,6 +829,11 @@ struct nft_table {
828 u32 use; 829 u32 use;
829 u16 flags; 830 u16 flags;
830 char name[NFT_TABLE_MAXNAMELEN]; 831 char name[NFT_TABLE_MAXNAMELEN];
832 struct net_device *dev;
833};
834
835enum nft_af_flags {
836 NFT_AF_NEEDS_DEV = (1 << 0),
831}; 837};
832 838
833/** 839/**
@@ -838,6 +844,7 @@ struct nft_table {
838 * @nhooks: number of hooks in this family 844 * @nhooks: number of hooks in this family
839 * @owner: module owner 845 * @owner: module owner
840 * @tables: used internally 846 * @tables: used internally
847 * @flags: family flags
841 * @nops: number of hook ops in this family 848 * @nops: number of hook ops in this family
842 * @hook_ops_init: initialization function for chain hook ops 849 * @hook_ops_init: initialization function for chain hook ops
843 * @hooks: hookfn overrides for packet validation 850 * @hooks: hookfn overrides for packet validation
@@ -848,6 +855,7 @@ struct nft_af_info {
848 unsigned int nhooks; 855 unsigned int nhooks;
849 struct module *owner; 856 struct module *owner;
850 struct list_head tables; 857 struct list_head tables;
858 u32 flags;
851 unsigned int nops; 859 unsigned int nops;
852 void (*hook_ops_init)(struct nf_hook_ops *, 860 void (*hook_ops_init)(struct nf_hook_ops *,
853 unsigned int); 861 unsigned int);
diff --git a/include/net/netns/nftables.h b/include/net/netns/nftables.h
index eee608b12cc9..c80781146019 100644
--- a/include/net/netns/nftables.h
+++ b/include/net/netns/nftables.h
@@ -13,6 +13,7 @@ struct netns_nftables {
13 struct nft_af_info *inet; 13 struct nft_af_info *inet;
14 struct nft_af_info *arp; 14 struct nft_af_info *arp;
15 struct nft_af_info *bridge; 15 struct nft_af_info *bridge;
16 struct nft_af_info *netdev;
16 unsigned int base_seq; 17 unsigned int base_seq;
17 u8 gencursor; 18 u8 gencursor;
18}; 19};
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 5fa1cd04762e..89a671e0f5e7 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -146,12 +146,14 @@ enum nft_table_flags {
146 * @NFTA_TABLE_NAME: name of the table (NLA_STRING) 146 * @NFTA_TABLE_NAME: name of the table (NLA_STRING)
147 * @NFTA_TABLE_FLAGS: bitmask of enum nft_table_flags (NLA_U32) 147 * @NFTA_TABLE_FLAGS: bitmask of enum nft_table_flags (NLA_U32)
148 * @NFTA_TABLE_USE: number of chains in this table (NLA_U32) 148 * @NFTA_TABLE_USE: number of chains in this table (NLA_U32)
149 * @NFTA_TABLE_DEV: net device name (NLA_STRING)
149 */ 150 */
150enum nft_table_attributes { 151enum nft_table_attributes {
151 NFTA_TABLE_UNSPEC, 152 NFTA_TABLE_UNSPEC,
152 NFTA_TABLE_NAME, 153 NFTA_TABLE_NAME,
153 NFTA_TABLE_FLAGS, 154 NFTA_TABLE_FLAGS,
154 NFTA_TABLE_USE, 155 NFTA_TABLE_USE,
156 NFTA_TABLE_DEV,
155 __NFTA_TABLE_MAX 157 __NFTA_TABLE_MAX
156}; 158};
157#define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1) 159#define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1)
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 2d0e265fef6e..e7abf5145edc 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -1444,7 +1444,6 @@ static int
1444compat_find_calc_match(struct xt_entry_match *m, 1444compat_find_calc_match(struct xt_entry_match *m,
1445 const char *name, 1445 const char *name,
1446 const struct ipt_ip *ip, 1446 const struct ipt_ip *ip,
1447 unsigned int hookmask,
1448 int *size) 1447 int *size)
1449{ 1448{
1450 struct xt_match *match; 1449 struct xt_match *match;
@@ -1513,8 +1512,7 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e,
1513 entry_offset = (void *)e - (void *)base; 1512 entry_offset = (void *)e - (void *)base;
1514 j = 0; 1513 j = 0;
1515 xt_ematch_foreach(ematch, e) { 1514 xt_ematch_foreach(ematch, e) {
1516 ret = compat_find_calc_match(ematch, name, 1515 ret = compat_find_calc_match(ematch, name, &e->ip, &off);
1517 &e->ip, e->comefrom, &off);
1518 if (ret != 0) 1516 if (ret != 0)
1519 goto release_matches; 1517 goto release_matches;
1520 ++j; 1518 ++j;
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 62f5b0d0bc9b..cdd085f8b770 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -1459,7 +1459,6 @@ static int
1459compat_find_calc_match(struct xt_entry_match *m, 1459compat_find_calc_match(struct xt_entry_match *m,
1460 const char *name, 1460 const char *name,
1461 const struct ip6t_ip6 *ipv6, 1461 const struct ip6t_ip6 *ipv6,
1462 unsigned int hookmask,
1463 int *size) 1462 int *size)
1464{ 1463{
1465 struct xt_match *match; 1464 struct xt_match *match;
@@ -1528,8 +1527,7 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
1528 entry_offset = (void *)e - (void *)base; 1527 entry_offset = (void *)e - (void *)base;
1529 j = 0; 1528 j = 0;
1530 xt_ematch_foreach(ematch, e) { 1529 xt_ematch_foreach(ematch, e) {
1531 ret = compat_find_calc_match(ematch, name, 1530 ret = compat_find_calc_match(ematch, name, &e->ipv6, &off);
1532 &e->ipv6, e->comefrom, &off);
1533 if (ret != 0) 1531 if (ret != 0)
1534 goto release_matches; 1532 goto release_matches;
1535 ++j; 1533 ++j;
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 1c78d7fb1da7..fbc8d15c7fda 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -3,6 +3,7 @@ menu "Core Netfilter Configuration"
3 3
4config NETFILTER_INGRESS 4config NETFILTER_INGRESS
5 bool "Netfilter ingress support" 5 bool "Netfilter ingress support"
6 default y
6 select NET_INGRESS 7 select NET_INGRESS
7 help 8 help
8 This allows you to classify packets from ingress using the Netfilter 9 This allows you to classify packets from ingress using the Netfilter
@@ -455,6 +456,11 @@ config NF_TABLES_INET
455 help 456 help
456 This option enables support for a mixed IPv4/IPv6 "inet" table. 457 This option enables support for a mixed IPv4/IPv6 "inet" table.
457 458
459config NF_TABLES_NETDEV
460 tristate "Netfilter nf_tables netdev tables support"
461 help
462 This option enables support for the "netdev" table.
463
458config NFT_EXTHDR 464config NFT_EXTHDR
459 tristate "Netfilter nf_tables IPv6 exthdr module" 465 tristate "Netfilter nf_tables IPv6 exthdr module"
460 help 466 help
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index a87d8b8ec730..70d026d46fe7 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -75,6 +75,7 @@ nf_tables-objs += nft_bitwise.o nft_byteorder.o nft_payload.o
75 75
76obj-$(CONFIG_NF_TABLES) += nf_tables.o 76obj-$(CONFIG_NF_TABLES) += nf_tables.o
77obj-$(CONFIG_NF_TABLES_INET) += nf_tables_inet.o 77obj-$(CONFIG_NF_TABLES_INET) += nf_tables_inet.o
78obj-$(CONFIG_NF_TABLES_NETDEV) += nf_tables_netdev.o
78obj-$(CONFIG_NFT_COMPAT) += nft_compat.o 79obj-$(CONFIG_NFT_COMPAT) += nft_compat.o
79obj-$(CONFIG_NFT_EXTHDR) += nft_exthdr.o 80obj-$(CONFIG_NFT_EXTHDR) += nft_exthdr.o
80obj-$(CONFIG_NFT_META) += nft_meta.o 81obj-$(CONFIG_NFT_META) += nft_meta.o
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 34ded09317e7..4528f122bcd2 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -399,6 +399,8 @@ static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = {
399 [NFTA_TABLE_NAME] = { .type = NLA_STRING, 399 [NFTA_TABLE_NAME] = { .type = NLA_STRING,
400 .len = NFT_TABLE_MAXNAMELEN - 1 }, 400 .len = NFT_TABLE_MAXNAMELEN - 1 },
401 [NFTA_TABLE_FLAGS] = { .type = NLA_U32 }, 401 [NFTA_TABLE_FLAGS] = { .type = NLA_U32 },
402 [NFTA_TABLE_DEV] = { .type = NLA_STRING,
403 .len = IFNAMSIZ - 1 },
402}; 404};
403 405
404static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net, 406static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
@@ -423,6 +425,10 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
423 nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use))) 425 nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)))
424 goto nla_put_failure; 426 goto nla_put_failure;
425 427
428 if (table->dev &&
429 nla_put_string(skb, NFTA_TABLE_DEV, table->dev->name))
430 goto nla_put_failure;
431
426 nlmsg_end(skb, nlh); 432 nlmsg_end(skb, nlh);
427 return 0; 433 return 0;
428 434
@@ -608,6 +614,11 @@ static int nf_tables_updtable(struct nft_ctx *ctx)
608 if (flags == ctx->table->flags) 614 if (flags == ctx->table->flags)
609 return 0; 615 return 0;
610 616
617 if ((ctx->afi->flags & NFT_AF_NEEDS_DEV) &&
618 ctx->nla[NFTA_TABLE_DEV] &&
619 nla_strcmp(ctx->nla[NFTA_TABLE_DEV], ctx->table->dev->name))
620 return -EOPNOTSUPP;
621
611 trans = nft_trans_alloc(ctx, NFT_MSG_NEWTABLE, 622 trans = nft_trans_alloc(ctx, NFT_MSG_NEWTABLE,
612 sizeof(struct nft_trans_table)); 623 sizeof(struct nft_trans_table));
613 if (trans == NULL) 624 if (trans == NULL)
@@ -645,6 +656,7 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
645 struct nft_table *table; 656 struct nft_table *table;
646 struct net *net = sock_net(skb->sk); 657 struct net *net = sock_net(skb->sk);
647 int family = nfmsg->nfgen_family; 658 int family = nfmsg->nfgen_family;
659 struct net_device *dev = NULL;
648 u32 flags = 0; 660 u32 flags = 0;
649 struct nft_ctx ctx; 661 struct nft_ctx ctx;
650 int err; 662 int err;
@@ -679,30 +691,50 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
679 return -EINVAL; 691 return -EINVAL;
680 } 692 }
681 693
694 if (afi->flags & NFT_AF_NEEDS_DEV) {
695 char ifname[IFNAMSIZ];
696
697 if (!nla[NFTA_TABLE_DEV])
698 return -EOPNOTSUPP;
699
700 nla_strlcpy(ifname, nla[NFTA_TABLE_DEV], IFNAMSIZ);
701 dev = dev_get_by_name(net, ifname);
702 if (!dev)
703 return -ENOENT;
704 } else if (nla[NFTA_TABLE_DEV]) {
705 return -EOPNOTSUPP;
706 }
707
708 err = -EAFNOSUPPORT;
682 if (!try_module_get(afi->owner)) 709 if (!try_module_get(afi->owner))
683 return -EAFNOSUPPORT; 710 goto err1;
684 711
685 err = -ENOMEM; 712 err = -ENOMEM;
686 table = kzalloc(sizeof(*table), GFP_KERNEL); 713 table = kzalloc(sizeof(*table), GFP_KERNEL);
687 if (table == NULL) 714 if (table == NULL)
688 goto err1; 715 goto err2;
689 716
690 nla_strlcpy(table->name, name, NFT_TABLE_MAXNAMELEN); 717 nla_strlcpy(table->name, name, NFT_TABLE_MAXNAMELEN);
691 INIT_LIST_HEAD(&table->chains); 718 INIT_LIST_HEAD(&table->chains);
692 INIT_LIST_HEAD(&table->sets); 719 INIT_LIST_HEAD(&table->sets);
693 table->flags = flags; 720 table->flags = flags;
721 table->dev = dev;
694 722
695 nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla); 723 nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
696 err = nft_trans_table_add(&ctx, NFT_MSG_NEWTABLE); 724 err = nft_trans_table_add(&ctx, NFT_MSG_NEWTABLE);
697 if (err < 0) 725 if (err < 0)
698 goto err2; 726 goto err3;
699 727
700 list_add_tail_rcu(&table->list, &afi->tables); 728 list_add_tail_rcu(&table->list, &afi->tables);
701 return 0; 729 return 0;
702err2: 730err3:
703 kfree(table); 731 kfree(table);
704err1: 732err2:
705 module_put(afi->owner); 733 module_put(afi->owner);
734err1:
735 if (dev != NULL)
736 dev_put(dev);
737
706 return err; 738 return err;
707} 739}
708 740
@@ -806,6 +838,9 @@ static void nf_tables_table_destroy(struct nft_ctx *ctx)
806{ 838{
807 BUG_ON(ctx->table->use > 0); 839 BUG_ON(ctx->table->use > 0);
808 840
841 if (ctx->table->dev)
842 dev_put(ctx->table->dev);
843
809 kfree(ctx->table); 844 kfree(ctx->table);
810 module_put(ctx->afi->owner); 845 module_put(ctx->afi->owner);
811} 846}
@@ -1361,6 +1396,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
1361 ops->priority = priority; 1396 ops->priority = priority;
1362 ops->priv = chain; 1397 ops->priv = chain;
1363 ops->hook = afi->hooks[ops->hooknum]; 1398 ops->hook = afi->hooks[ops->hooknum];
1399 ops->dev = table->dev;
1364 if (hookfn) 1400 if (hookfn)
1365 ops->hook = hookfn; 1401 ops->hook = hookfn;
1366 if (afi->hook_ops_init) 1402 if (afi->hook_ops_init)
diff --git a/net/netfilter/nf_tables_netdev.c b/net/netfilter/nf_tables_netdev.c
new file mode 100644
index 000000000000..04cb17057f46
--- /dev/null
+++ b/net/netfilter/nf_tables_netdev.c
@@ -0,0 +1,183 @@
1/*
2 * Copyright (c) 2015 Pablo Neira Ayuso <pablo@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/init.h>
10#include <linux/module.h>
11#include <net/netfilter/nf_tables.h>
12#include <linux/ip.h>
13#include <linux/ipv6.h>
14#include <net/netfilter/nf_tables_ipv4.h>
15#include <net/netfilter/nf_tables_ipv6.h>
16
17static inline void
18nft_netdev_set_pktinfo_ipv4(struct nft_pktinfo *pkt,
19 const struct nf_hook_ops *ops, struct sk_buff *skb,
20 const struct nf_hook_state *state)
21{
22 struct iphdr *iph, _iph;
23 u32 len, thoff;
24
25 nft_set_pktinfo(pkt, ops, skb, state);
26
27 iph = skb_header_pointer(skb, skb_network_offset(skb), sizeof(*iph),
28 &_iph);
29 if (!iph)
30 return;
31
32 iph = ip_hdr(skb);
33 if (iph->ihl < 5 || iph->version != 4)
34 return;
35
36 len = ntohs(iph->tot_len);
37 thoff = iph->ihl * 4;
38 if (skb->len < len)
39 return;
40 else if (len < thoff)
41 return;
42
43 pkt->tprot = iph->protocol;
44 pkt->xt.thoff = thoff;
45 pkt->xt.fragoff = ntohs(iph->frag_off) & IP_OFFSET;
46}
47
48static inline void
49__nft_netdev_set_pktinfo_ipv6(struct nft_pktinfo *pkt,
50 const struct nf_hook_ops *ops,
51 struct sk_buff *skb,
52 const struct nf_hook_state *state)
53{
54#if IS_ENABLED(CONFIG_IPV6)
55 struct ipv6hdr *ip6h, _ip6h;
56 unsigned int thoff = 0;
57 unsigned short frag_off;
58 int protohdr;
59 u32 pkt_len;
60
61 ip6h = skb_header_pointer(skb, skb_network_offset(skb), sizeof(*ip6h),
62 &_ip6h);
63 if (!ip6h)
64 return;
65
66 if (ip6h->version != 6)
67 return;
68
69 pkt_len = ntohs(ip6h->payload_len);
70 if (pkt_len + sizeof(*ip6h) > skb->len)
71 return;
72
73 protohdr = ipv6_find_hdr(pkt->skb, &thoff, -1, &frag_off, NULL);
74 if (protohdr < 0)
75 return;
76
77 pkt->tprot = protohdr;
78 pkt->xt.thoff = thoff;
79 pkt->xt.fragoff = frag_off;
80#endif
81}
82
83static inline void nft_netdev_set_pktinfo_ipv6(struct nft_pktinfo *pkt,
84 const struct nf_hook_ops *ops,
85 struct sk_buff *skb,
86 const struct nf_hook_state *state)
87{
88 nft_set_pktinfo(pkt, ops, skb, state);
89 __nft_netdev_set_pktinfo_ipv6(pkt, ops, skb, state);
90}
91
92static unsigned int
93nft_do_chain_netdev(const struct nf_hook_ops *ops, struct sk_buff *skb,
94 const struct nf_hook_state *state)
95{
96 struct nft_pktinfo pkt;
97
98 switch (eth_hdr(skb)->h_proto) {
99 case htons(ETH_P_IP):
100 nft_netdev_set_pktinfo_ipv4(&pkt, ops, skb, state);
101 break;
102 case htons(ETH_P_IPV6):
103 nft_netdev_set_pktinfo_ipv6(&pkt, ops, skb, state);
104 break;
105 default:
106 nft_set_pktinfo(&pkt, ops, skb, state);
107 break;
108 }
109
110 return nft_do_chain(&pkt, ops);
111}
112
113static struct nft_af_info nft_af_netdev __read_mostly = {
114 .family = NFPROTO_NETDEV,
115 .nhooks = NF_NETDEV_NUMHOOKS,
116 .owner = THIS_MODULE,
117 .flags = NFT_AF_NEEDS_DEV,
118 .nops = 1,
119 .hooks = {
120 [NF_NETDEV_INGRESS] = nft_do_chain_netdev,
121 },
122};
123
124static int nf_tables_netdev_init_net(struct net *net)
125{
126 net->nft.netdev = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
127 if (net->nft.netdev == NULL)
128 return -ENOMEM;
129
130 memcpy(net->nft.netdev, &nft_af_netdev, sizeof(nft_af_netdev));
131
132 if (nft_register_afinfo(net, net->nft.netdev) < 0)
133 goto err;
134
135 return 0;
136err:
137 kfree(net->nft.netdev);
138 return -ENOMEM;
139}
140
141static void nf_tables_netdev_exit_net(struct net *net)
142{
143 nft_unregister_afinfo(net->nft.netdev);
144 kfree(net->nft.netdev);
145}
146
147static struct pernet_operations nf_tables_netdev_net_ops = {
148 .init = nf_tables_netdev_init_net,
149 .exit = nf_tables_netdev_exit_net,
150};
151
152static const struct nf_chain_type nft_filter_chain_netdev = {
153 .name = "filter",
154 .type = NFT_CHAIN_T_DEFAULT,
155 .family = NFPROTO_NETDEV,
156 .owner = THIS_MODULE,
157 .hook_mask = (1 << NF_NETDEV_INGRESS),
158};
159
160static int __init nf_tables_netdev_init(void)
161{
162 int ret;
163
164 nft_register_chain_type(&nft_filter_chain_netdev);
165 ret = register_pernet_subsys(&nf_tables_netdev_net_ops);
166 if (ret < 0)
167 nft_unregister_chain_type(&nft_filter_chain_netdev);
168
169 return ret;
170}
171
172static void __exit nf_tables_netdev_exit(void)
173{
174 unregister_pernet_subsys(&nf_tables_netdev_net_ops);
175 nft_unregister_chain_type(&nft_filter_chain_netdev);
176}
177
178module_init(nf_tables_netdev_init);
179module_exit(nf_tables_netdev_exit);
180
181MODULE_LICENSE("GPL");
182MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
183MODULE_ALIAS_NFT_FAMILY(5); /* NFPROTO_NETDEV */