f2210259e8ddbcd2eca2df8c77ac9f484d6bb994
[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 @@ -897,8 +897,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 @@ -910,7 +908,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 @@ -971,8 +969,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 @@ -982,9 +978,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 @@ -624,8 +621,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 @@ -642,8 +638,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 @@ -1055,7 +1050,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 @@ -1283,8 +1278,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 @@ -1380,7 +1375,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 @@ -1419,21 +1413,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 @@ -1451,7 +1442,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 @@ -1465,7 +1456,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 @@ -1478,14 +1469,13 @@ 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         const struct nlattr *name;
240         struct nf_hook_ops *ops;
241         struct nft_trans *trans;
242 -       int err, i;
243 +       int err;
244  
245         if (nla[NFTA_CHAIN_HOOK]) {
246                 if (!nft_is_base_chain(chain))
247 @@ -1502,14 +1492,12 @@ static int nf_tables_updchain(struct nft
248                         return -EBUSY;
249                 }
250  
251 -               for (i = 0; i < afi->nops; i++) {
252 -                       ops = &basechain->ops[i];
253 -                       if (ops->hooknum != hook.num ||
254 -                           ops->priority != hook.priority ||
255 -                           ops->dev != hook.dev) {
256 -                               nft_chain_release_hook(&hook);
257 -                               return -EBUSY;
258 -                       }
259 +               ops = &basechain->ops;
260 +               if (ops->hooknum != hook.num ||
261 +                   ops->priority != hook.priority ||
262 +                   ops->dev != hook.dev) {
263 +                       nft_chain_release_hook(&hook);
264 +                       return -EBUSY;
265                 }
266                 nft_chain_release_hook(&hook);
267         }
268 @@ -5112,10 +5100,9 @@ static int nf_tables_commit(struct net *
269                 case NFT_MSG_DELCHAIN:
270                         list_del_rcu(&trans->ctx.chain->list);
271                         nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN);
272 -                       nf_tables_unregister_hooks(trans->ctx.net,
273 -                                                  trans->ctx.table,
274 -                                                  trans->ctx.chain,
275 -                                                  trans->ctx.afi->nops);
276 +                       nf_tables_unregister_hook(trans->ctx.net,
277 +                                                 trans->ctx.table,
278 +                                                 trans->ctx.chain);
279                         break;
280                 case NFT_MSG_NEWRULE:
281                         nft_clear(trans->ctx.net, nft_trans_rule(trans));
282 @@ -5252,10 +5239,9 @@ static int nf_tables_abort(struct net *n
283                         } else {
284                                 trans->ctx.table->use--;
285                                 list_del_rcu(&trans->ctx.chain->list);
286 -                               nf_tables_unregister_hooks(trans->ctx.net,
287 -                                                          trans->ctx.table,
288 -                                                          trans->ctx.chain,
289 -                                                          trans->ctx.afi->nops);
290 +                               nf_tables_unregister_hook(trans->ctx.net,
291 +                                                         trans->ctx.table,
292 +                                                         trans->ctx.chain);
293                         }
294                         break;
295                 case NFT_MSG_DELCHAIN:
296 @@ -5358,7 +5344,7 @@ int nft_chain_validate_hooks(const struc
297         if (nft_is_base_chain(chain)) {
298                 basechain = nft_base_chain(chain);
299  
300 -               if ((1 << basechain->ops[0].hooknum) & hook_flags)
301 +               if ((1 << basechain->ops.hooknum) & hook_flags)
302                         return 0;
303  
304                 return -EOPNOTSUPP;
305 @@ -5840,8 +5826,7 @@ int __nft_release_basechain(struct nft_c
306  
307         BUG_ON(!nft_is_base_chain(ctx->chain));
308  
309 -       nf_tables_unregister_hooks(ctx->net, ctx->chain->table, ctx->chain,
310 -                                  ctx->afi->nops);
311 +       nf_tables_unregister_hook(ctx->net, ctx->chain->table, ctx->chain);
312         list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) {
313                 list_del(&rule->list);
314                 ctx->chain->use--;
315 @@ -5870,8 +5855,7 @@ static void __nft_release_afinfo(struct
316  
317         list_for_each_entry_safe(table, nt, &afi->tables, list) {
318                 list_for_each_entry(chain, &table->chains, list)
319 -                       nf_tables_unregister_hooks(net, table, chain,
320 -                                                  afi->nops);
321 +                       nf_tables_unregister_hook(net, table, chain);
322                 /* No packets are walking on these chains anymore. */
323                 ctx.table = table;
324                 list_for_each_entry(chain, &table->chains, list) {
325 --- a/net/netfilter/nf_tables_inet.c
326 +++ b/net/netfilter/nf_tables_inet.c
327 @@ -74,7 +74,6 @@ static struct nft_af_info nft_af_inet __
328         .family         = NFPROTO_INET,
329         .nhooks         = NF_INET_NUMHOOKS,
330         .owner          = THIS_MODULE,
331 -       .nops           = 1,
332         .hooks          = {
333                 [NF_INET_LOCAL_IN]      = nft_do_chain_inet,
334                 [NF_INET_LOCAL_OUT]     = nft_inet_output,
335 --- a/net/netfilter/nf_tables_netdev.c
336 +++ b/net/netfilter/nf_tables_netdev.c
337 @@ -43,7 +43,6 @@ static struct nft_af_info nft_af_netdev
338         .nhooks         = NF_NETDEV_NUMHOOKS,
339         .owner          = THIS_MODULE,
340         .flags          = NFT_AF_NEEDS_DEV,
341 -       .nops           = 1,
342         .hooks          = {
343                 [NF_NETDEV_INGRESS]     = nft_do_chain_netdev,
344         },
345 @@ -98,7 +97,7 @@ static void nft_netdev_event(unsigned lo
346                 __nft_release_basechain(ctx);
347                 break;
348         case NETDEV_CHANGENAME:
349 -               if (dev->ifindex != basechain->ops[0].dev->ifindex)
350 +               if (dev->ifindex != basechain->ops.dev->ifindex)
351                         return;
352  
353                 strncpy(basechain->dev_name, dev->name, IFNAMSIZ);
354 --- a/net/netfilter/nft_compat.c
355 +++ b/net/netfilter/nft_compat.c
356 @@ -186,7 +186,7 @@ nft_target_set_tgchk_param(struct xt_tgc
357         if (nft_is_base_chain(ctx->chain)) {
358                 const struct nft_base_chain *basechain =
359                                                 nft_base_chain(ctx->chain);
360 -               const struct nf_hook_ops *ops = &basechain->ops[0];
361 +               const struct nf_hook_ops *ops = &basechain->ops;
362  
363                 par->hook_mask = 1 << ops->hooknum;
364         } else {
365 @@ -317,7 +317,7 @@ static int nft_target_validate(const str
366         if (nft_is_base_chain(ctx->chain)) {
367                 const struct nft_base_chain *basechain =
368                                                 nft_base_chain(ctx->chain);
369 -               const struct nf_hook_ops *ops = &basechain->ops[0];
370 +               const struct nf_hook_ops *ops = &basechain->ops;
371  
372                 hook_mask = 1 << ops->hooknum;
373                 if (target->hooks && !(hook_mask & target->hooks))
374 @@ -414,7 +414,7 @@ nft_match_set_mtchk_param(struct xt_mtch
375         if (nft_is_base_chain(ctx->chain)) {
376                 const struct nft_base_chain *basechain =
377                                                 nft_base_chain(ctx->chain);
378 -               const struct nf_hook_ops *ops = &basechain->ops[0];
379 +               const struct nf_hook_ops *ops = &basechain->ops;
380  
381                 par->hook_mask = 1 << ops->hooknum;
382         } else {
383 @@ -564,7 +564,7 @@ static int nft_match_validate(const stru
384         if (nft_is_base_chain(ctx->chain)) {
385                 const struct nft_base_chain *basechain =
386                                                 nft_base_chain(ctx->chain);
387 -               const struct nf_hook_ops *ops = &basechain->ops[0];
388 +               const struct nf_hook_ops *ops = &basechain->ops;
389  
390                 hook_mask = 1 << ops->hooknum;
391                 if (match->hooks && !(hook_mask & match->hooks))