ed33b2fc5f8b232ff390dd3694059a44224891c7
[oweals/openwrt.git] /
1 From: Pablo Neira Ayuso <pablo@netfilter.org>
2 Date: Sat, 9 Dec 2017 15:40:25 +0100
3 Subject: [PATCH] netfilter: nf_tables: remove multihook chains and families
4
5 Since NFPROTO_INET is handled from the core, we don't need to maintain
6 extra infrastructure in nf_tables to handle the double hook
7 registration, one for IPv4 and another for IPv6.
8
9 Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
10 ---
11
12 --- a/include/net/netfilter/nf_tables.h
13 +++ b/include/net/netfilter/nf_tables.h
14 @@ -898,8 +898,6 @@ struct nft_stats {
15         struct u64_stats_sync   syncp;
16  };
17  
18 -#define NFT_HOOK_OPS_MAX               2
19 -
20  /**
21   *     struct nft_base_chain - nf_tables base chain
22   *
23 @@ -911,7 +909,7 @@ struct nft_stats {
24   *     @dev_name: device name that this base chain is attached to (if any)
25   */
26  struct nft_base_chain {
27 -       struct nf_hook_ops              ops[NFT_HOOK_OPS_MAX];
28 +       struct nf_hook_ops              ops;
29         const struct nf_chain_type      *type;
30         u8                              policy;
31         u8                              flags;
32 @@ -972,8 +970,6 @@ enum nft_af_flags {
33   *     @owner: module owner
34   *     @tables: used internally
35   *     @flags: family flags
36 - *     @nops: number of hook ops in this family
37 - *     @hook_ops_init: initialization function for chain hook ops
38   *     @hooks: hookfn overrides for packet validation
39   */
40  struct nft_af_info {
41 @@ -983,9 +979,6 @@ struct nft_af_info {
42         struct module                   *owner;
43         struct list_head                tables;
44         u32                             flags;
45 -       unsigned int                    nops;
46 -       void                            (*hook_ops_init)(struct nf_hook_ops *,
47 -                                                        unsigned int);
48         nf_hookfn                       *hooks[NF_MAX_HOOKS];
49  };
50  
51 --- a/net/bridge/netfilter/nf_tables_bridge.c
52 +++ b/net/bridge/netfilter/nf_tables_bridge.c
53 @@ -46,7 +46,6 @@ static struct nft_af_info nft_af_bridge
54         .family         = NFPROTO_BRIDGE,
55         .nhooks         = NF_BR_NUMHOOKS,
56         .owner          = THIS_MODULE,
57 -       .nops           = 1,
58         .hooks          = {
59                 [NF_BR_PRE_ROUTING]     = nft_do_chain_bridge,
60                 [NF_BR_LOCAL_IN]        = nft_do_chain_bridge,
61 --- a/net/ipv4/netfilter/nf_tables_arp.c
62 +++ b/net/ipv4/netfilter/nf_tables_arp.c
63 @@ -31,7 +31,6 @@ static struct nft_af_info nft_af_arp __r
64         .family         = NFPROTO_ARP,
65         .nhooks         = NF_ARP_NUMHOOKS,
66         .owner          = THIS_MODULE,
67 -       .nops           = 1,
68         .hooks          = {
69                 [NF_ARP_IN]             = nft_do_chain_arp,
70                 [NF_ARP_OUT]            = nft_do_chain_arp,
71 --- a/net/ipv4/netfilter/nf_tables_ipv4.c
72 +++ b/net/ipv4/netfilter/nf_tables_ipv4.c
73 @@ -49,7 +49,6 @@ static struct nft_af_info nft_af_ipv4 __
74         .family         = NFPROTO_IPV4,
75         .nhooks         = NF_INET_NUMHOOKS,
76         .owner          = THIS_MODULE,
77 -       .nops           = 1,
78         .hooks          = {
79                 [NF_INET_LOCAL_IN]      = nft_do_chain_ipv4,
80                 [NF_INET_LOCAL_OUT]     = nft_ipv4_output,
81 --- a/net/ipv6/netfilter/nf_tables_ipv6.c
82 +++ b/net/ipv6/netfilter/nf_tables_ipv6.c
83 @@ -46,7 +46,6 @@ static struct nft_af_info nft_af_ipv6 __
84         .family         = NFPROTO_IPV6,
85         .nhooks         = NF_INET_NUMHOOKS,
86         .owner          = THIS_MODULE,
87 -       .nops           = 1,
88         .hooks          = {
89                 [NF_INET_LOCAL_IN]      = nft_do_chain_ipv6,
90                 [NF_INET_LOCAL_OUT]     = nft_ipv6_output,
91 --- a/net/netfilter/nf_tables_api.c
92 +++ b/net/netfilter/nf_tables_api.c
93 @@ -139,29 +139,26 @@ static void nft_trans_destroy(struct nft
94         kfree(trans);
95  }
96  
97 -static int nf_tables_register_hooks(struct net *net,
98 -                                   const struct nft_table *table,
99 -                                   struct nft_chain *chain,
100 -                                   unsigned int hook_nops)
101 +static int nf_tables_register_hook(struct net *net,
102 +                                  const struct nft_table *table,
103 +                                  struct nft_chain *chain)
104  {
105         if (table->flags & NFT_TABLE_F_DORMANT ||
106             !nft_is_base_chain(chain))
107                 return 0;
108  
109 -       return nf_register_net_hooks(net, nft_base_chain(chain)->ops,
110 -                                    hook_nops);
111 +       return nf_register_net_hook(net, &nft_base_chain(chain)->ops);
112  }
113  
114 -static void nf_tables_unregister_hooks(struct net *net,
115 -                                      const struct nft_table *table,
116 -                                      struct nft_chain *chain,
117 -                                      unsigned int hook_nops)
118 +static void nf_tables_unregister_hook(struct net *net,
119 +                                     const struct nft_table *table,
120 +                                     struct nft_chain *chain)
121  {
122         if (table->flags & NFT_TABLE_F_DORMANT ||
123             !nft_is_base_chain(chain))
124                 return;
125  
126 -       nf_unregister_net_hooks(net, nft_base_chain(chain)->ops, hook_nops);
127 +       nf_unregister_net_hook(net, &nft_base_chain(chain)->ops);
128  }
129  
130  static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type)
131 @@ -639,8 +636,7 @@ static void _nf_tables_table_disable(str
132                 if (cnt && i++ == cnt)
133                         break;
134  
135 -               nf_unregister_net_hooks(net, nft_base_chain(chain)->ops,
136 -                                       afi->nops);
137 +               nf_unregister_net_hook(net, &nft_base_chain(chain)->ops);
138         }
139  }
140  
141 @@ -657,8 +653,7 @@ static int nf_tables_table_enable(struct
142                 if (!nft_is_base_chain(chain))
143                         continue;
144  
145 -               err = nf_register_net_hooks(net, nft_base_chain(chain)->ops,
146 -                                           afi->nops);
147 +               err = nf_register_net_hook(net, &nft_base_chain(chain)->ops);
148                 if (err < 0)
149                         goto err;
150  
151 @@ -1070,7 +1065,7 @@ static int nf_tables_fill_chain_info(str
152  
153         if (nft_is_base_chain(chain)) {
154                 const struct nft_base_chain *basechain = nft_base_chain(chain);
155 -               const struct nf_hook_ops *ops = &basechain->ops[0];
156 +               const struct nf_hook_ops *ops = &basechain->ops;
157                 struct nlattr *nest;
158  
159                 nest = nla_nest_start(skb, NFTA_CHAIN_HOOK);
160 @@ -1298,8 +1293,8 @@ static void nf_tables_chain_destroy(stru
161                 free_percpu(basechain->stats);
162                 if (basechain->stats)
163                         static_branch_dec(&nft_counters_enabled);
164 -               if (basechain->ops[0].dev != NULL)
165 -                       dev_put(basechain->ops[0].dev);
166 +               if (basechain->ops.dev != NULL)
167 +                       dev_put(basechain->ops.dev);
168                 kfree(chain->name);
169                 kfree(basechain);
170         } else {
171 @@ -1395,7 +1390,6 @@ static int nf_tables_addchain(struct nft
172         struct nft_stats __percpu *stats;
173         struct net *net = ctx->net;
174         struct nft_chain *chain;
175 -       unsigned int i;
176         int err;
177  
178         if (table->use == UINT_MAX)
179 @@ -1434,21 +1428,18 @@ static int nf_tables_addchain(struct nft
180                 basechain->type = hook.type;
181                 chain = &basechain->chain;
182  
183 -               for (i = 0; i < afi->nops; i++) {
184 -                       ops = &basechain->ops[i];
185 -                       ops->pf         = family;
186 -                       ops->hooknum    = hook.num;
187 -                       ops->priority   = hook.priority;
188 -                       ops->priv       = chain;
189 -                       ops->hook       = afi->hooks[ops->hooknum];
190 -                       ops->dev        = hook.dev;
191 -                       if (hookfn)
192 -                               ops->hook = hookfn;
193 -                       if (afi->hook_ops_init)
194 -                               afi->hook_ops_init(ops, i);
195 -                       if (basechain->type->type == NFT_CHAIN_T_NAT)
196 -                               ops->nat_hook = true;
197 -               }
198 +               ops             = &basechain->ops;
199 +               ops->pf         = family;
200 +               ops->hooknum    = hook.num;
201 +               ops->priority   = hook.priority;
202 +               ops->priv       = chain;
203 +               ops->hook       = afi->hooks[ops->hooknum];
204 +               ops->dev        = hook.dev;
205 +               if (hookfn)
206 +                       ops->hook = hookfn;
207 +
208 +               if (basechain->type->type == NFT_CHAIN_T_NAT)
209 +                       ops->nat_hook = true;
210  
211                 chain->flags |= NFT_BASE_CHAIN;
212                 basechain->policy = policy;
213 @@ -1466,7 +1457,7 @@ static int nf_tables_addchain(struct nft
214                 goto err1;
215         }
216  
217 -       err = nf_tables_register_hooks(net, table, chain, afi->nops);
218 +       err = nf_tables_register_hook(net, table, chain);
219         if (err < 0)
220                 goto err1;
221  
222 @@ -1480,7 +1471,7 @@ static int nf_tables_addchain(struct nft
223  
224         return 0;
225  err2:
226 -       nf_tables_unregister_hooks(net, table, chain, afi->nops);
227 +       nf_tables_unregister_hook(net, table, chain);
228  err1:
229         nf_tables_chain_destroy(chain);
230  
231 @@ -1493,13 +1484,12 @@ static int nf_tables_updchain(struct nft
232         const struct nlattr * const *nla = ctx->nla;
233         struct nft_table *table = ctx->table;
234         struct nft_chain *chain = ctx->chain;
235 -       struct nft_af_info *afi = ctx->afi;
236         struct nft_base_chain *basechain;
237         struct nft_stats *stats = NULL;
238         struct nft_chain_hook hook;
239         struct nf_hook_ops *ops;
240         struct nft_trans *trans;
241 -       int err, i;
242 +       int err;
243  
244         if (nla[NFTA_CHAIN_HOOK]) {
245                 if (!nft_is_base_chain(chain))
246 @@ -1516,14 +1506,12 @@ static int nf_tables_updchain(struct nft
247                         return -EBUSY;
248                 }
249  
250 -               for (i = 0; i < afi->nops; i++) {
251 -                       ops = &basechain->ops[i];
252 -                       if (ops->hooknum != hook.num ||
253 -                           ops->priority != hook.priority ||
254 -                           ops->dev != hook.dev) {
255 -                               nft_chain_release_hook(&hook);
256 -                               return -EBUSY;
257 -                       }
258 +               ops = &basechain->ops;
259 +               if (ops->hooknum != hook.num ||
260 +                   ops->priority != hook.priority ||
261 +                   ops->dev != hook.dev) {
262 +                       nft_chain_release_hook(&hook);
263 +                       return -EBUSY;
264                 }
265                 nft_chain_release_hook(&hook);
266         }
267 @@ -5156,10 +5144,9 @@ static int nf_tables_commit(struct net *
268                 case NFT_MSG_DELCHAIN:
269                         list_del_rcu(&trans->ctx.chain->list);
270                         nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN);
271 -                       nf_tables_unregister_hooks(trans->ctx.net,
272 -                                                  trans->ctx.table,
273 -                                                  trans->ctx.chain,
274 -                                                  trans->ctx.afi->nops);
275 +                       nf_tables_unregister_hook(trans->ctx.net,
276 +                                                 trans->ctx.table,
277 +                                                 trans->ctx.chain);
278                         break;
279                 case NFT_MSG_NEWRULE:
280                         nft_clear(trans->ctx.net, nft_trans_rule(trans));
281 @@ -5296,10 +5283,9 @@ static int nf_tables_abort(struct net *n
282                         } else {
283                                 trans->ctx.table->use--;
284                                 list_del_rcu(&trans->ctx.chain->list);
285 -                               nf_tables_unregister_hooks(trans->ctx.net,
286 -                                                          trans->ctx.table,
287 -                                                          trans->ctx.chain,
288 -                                                          trans->ctx.afi->nops);
289 +                               nf_tables_unregister_hook(trans->ctx.net,
290 +                                                         trans->ctx.table,
291 +                                                         trans->ctx.chain);
292                         }
293                         break;
294                 case NFT_MSG_DELCHAIN:
295 @@ -5402,7 +5388,7 @@ int nft_chain_validate_hooks(const struc
296         if (nft_is_base_chain(chain)) {
297                 basechain = nft_base_chain(chain);
298  
299 -               if ((1 << basechain->ops[0].hooknum) & hook_flags)
300 +               if ((1 << basechain->ops.hooknum) & hook_flags)
301                         return 0;
302  
303                 return -EOPNOTSUPP;
304 @@ -5884,8 +5870,7 @@ int __nft_release_basechain(struct nft_c
305  
306         BUG_ON(!nft_is_base_chain(ctx->chain));
307  
308 -       nf_tables_unregister_hooks(ctx->net, ctx->chain->table, ctx->chain,
309 -                                  ctx->afi->nops);
310 +       nf_tables_unregister_hook(ctx->net, ctx->chain->table, ctx->chain);
311         list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) {
312                 list_del(&rule->list);
313                 ctx->chain->use--;
314 @@ -5914,8 +5899,7 @@ static void __nft_release_afinfo(struct
315  
316         list_for_each_entry_safe(table, nt, &afi->tables, list) {
317                 list_for_each_entry(chain, &table->chains, list)
318 -                       nf_tables_unregister_hooks(net, table, chain,
319 -                                                  afi->nops);
320 +                       nf_tables_unregister_hook(net, table, chain);
321                 /* No packets are walking on these chains anymore. */
322                 ctx.table = table;
323                 list_for_each_entry(chain, &table->chains, list) {
324 --- a/net/netfilter/nf_tables_inet.c
325 +++ b/net/netfilter/nf_tables_inet.c
326 @@ -74,7 +74,6 @@ static struct nft_af_info nft_af_inet __
327         .family         = NFPROTO_INET,
328         .nhooks         = NF_INET_NUMHOOKS,
329         .owner          = THIS_MODULE,
330 -       .nops           = 1,
331         .hooks          = {
332                 [NF_INET_LOCAL_IN]      = nft_do_chain_inet,
333                 [NF_INET_LOCAL_OUT]     = nft_inet_output,
334 --- a/net/netfilter/nf_tables_netdev.c
335 +++ b/net/netfilter/nf_tables_netdev.c
336 @@ -43,7 +43,6 @@ static struct nft_af_info nft_af_netdev
337         .nhooks         = NF_NETDEV_NUMHOOKS,
338         .owner          = THIS_MODULE,
339         .flags          = NFT_AF_NEEDS_DEV,
340 -       .nops           = 1,
341         .hooks          = {
342                 [NF_NETDEV_INGRESS]     = nft_do_chain_netdev,
343         },
344 @@ -98,7 +97,7 @@ static void nft_netdev_event(unsigned lo
345                 __nft_release_basechain(ctx);
346                 break;
347         case NETDEV_CHANGENAME:
348 -               if (dev->ifindex != basechain->ops[0].dev->ifindex)
349 +               if (dev->ifindex != basechain->ops.dev->ifindex)
350                         return;
351  
352                 strncpy(basechain->dev_name, dev->name, IFNAMSIZ);
353 --- a/net/netfilter/nft_compat.c
354 +++ b/net/netfilter/nft_compat.c
355 @@ -186,7 +186,7 @@ nft_target_set_tgchk_param(struct xt_tgc
356         if (nft_is_base_chain(ctx->chain)) {
357                 const struct nft_base_chain *basechain =
358                                                 nft_base_chain(ctx->chain);
359 -               const struct nf_hook_ops *ops = &basechain->ops[0];
360 +               const struct nf_hook_ops *ops = &basechain->ops;
361  
362                 par->hook_mask = 1 << ops->hooknum;
363         } else {
364 @@ -318,7 +318,7 @@ static int nft_target_validate(const str
365         if (nft_is_base_chain(ctx->chain)) {
366                 const struct nft_base_chain *basechain =
367                                                 nft_base_chain(ctx->chain);
368 -               const struct nf_hook_ops *ops = &basechain->ops[0];
369 +               const struct nf_hook_ops *ops = &basechain->ops;
370  
371                 hook_mask = 1 << ops->hooknum;
372                 if (target->hooks && !(hook_mask & target->hooks))
373 @@ -415,7 +415,7 @@ nft_match_set_mtchk_param(struct xt_mtch
374         if (nft_is_base_chain(ctx->chain)) {
375                 const struct nft_base_chain *basechain =
376                                                 nft_base_chain(ctx->chain);
377 -               const struct nf_hook_ops *ops = &basechain->ops[0];
378 +               const struct nf_hook_ops *ops = &basechain->ops;
379  
380                 par->hook_mask = 1 << ops->hooknum;
381         } else {
382 @@ -566,7 +566,7 @@ static int nft_match_validate(const stru
383         if (nft_is_base_chain(ctx->chain)) {
384                 const struct nft_base_chain *basechain =
385                                                 nft_base_chain(ctx->chain);
386 -               const struct nf_hook_ops *ops = &basechain->ops[0];
387 +               const struct nf_hook_ops *ops = &basechain->ops;
388  
389                 hook_mask = 1 << ops->hooknum;
390                 if (match->hooks && !(hook_mask & match->hooks))