]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - net/netfilter/nft_ct.c
netfilter: nft_ct: prepare for key-dependent error unwind
[mirror_ubuntu-bionic-kernel.git] / net / netfilter / nft_ct.c
CommitLineData
96518518 1/*
ef1f7df9 2 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
25443261 3 * Copyright (c) 2016 Pablo Neira Ayuso <pablo@netfilter.org>
96518518
PM
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Development of this code funded by Astaro AG (http://www.astaro.com/)
10 */
11
12#include <linux/kernel.h>
13#include <linux/init.h>
14#include <linux/module.h>
15#include <linux/netlink.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter/nf_tables.h>
18#include <net/netfilter/nf_tables.h>
19#include <net/netfilter/nf_conntrack.h>
48f66c90 20#include <net/netfilter/nf_conntrack_acct.h>
96518518
PM
21#include <net/netfilter/nf_conntrack_tuple.h>
22#include <net/netfilter/nf_conntrack_helper.h>
c4ede3d3 23#include <net/netfilter/nf_conntrack_ecache.h>
d2bf2f34 24#include <net/netfilter/nf_conntrack_labels.h>
96518518
PM
25
26struct nft_ct {
27 enum nft_ct_keys key:8;
28 enum ip_conntrack_dir dir:8;
d46f2cd2 29 union {
c4ede3d3
KE
30 enum nft_registers dreg:8;
31 enum nft_registers sreg:8;
32 };
96518518
PM
33};
34
48f66c90
FW
35static u64 nft_ct_get_eval_counter(const struct nf_conn_counter *c,
36 enum nft_ct_keys k,
37 enum ip_conntrack_dir d)
38{
39 if (d < IP_CT_DIR_MAX)
40 return k == NFT_CT_BYTES ? atomic64_read(&c[d].bytes) :
41 atomic64_read(&c[d].packets);
42
43 return nft_ct_get_eval_counter(c, k, IP_CT_DIR_ORIGINAL) +
44 nft_ct_get_eval_counter(c, k, IP_CT_DIR_REPLY);
45}
46
c4ede3d3 47static void nft_ct_get_eval(const struct nft_expr *expr,
a55e22e9 48 struct nft_regs *regs,
c4ede3d3 49 const struct nft_pktinfo *pkt)
96518518
PM
50{
51 const struct nft_ct *priv = nft_expr_priv(expr);
49499c3e 52 u32 *dest = &regs->data[priv->dreg];
96518518
PM
53 enum ip_conntrack_info ctinfo;
54 const struct nf_conn *ct;
55 const struct nf_conn_help *help;
56 const struct nf_conntrack_tuple *tuple;
57 const struct nf_conntrack_helper *helper;
96518518
PM
58 unsigned int state;
59
60 ct = nf_ct_get(pkt->skb, &ctinfo);
61
62 switch (priv->key) {
63 case NFT_CT_STATE:
64 if (ct == NULL)
65 state = NF_CT_STATE_INVALID_BIT;
66 else if (nf_ct_is_untracked(ct))
67 state = NF_CT_STATE_UNTRACKED_BIT;
68 else
69 state = NF_CT_STATE_BIT(ctinfo);
fad136ea 70 *dest = state;
96518518 71 return;
c1f86676
DM
72 default:
73 break;
96518518
PM
74 }
75
76 if (ct == NULL)
77 goto err;
78
79 switch (priv->key) {
80 case NFT_CT_DIRECTION:
fad136ea 81 *dest = CTINFO2DIR(ctinfo);
96518518
PM
82 return;
83 case NFT_CT_STATUS:
fad136ea 84 *dest = ct->status;
96518518
PM
85 return;
86#ifdef CONFIG_NF_CONNTRACK_MARK
87 case NFT_CT_MARK:
fad136ea 88 *dest = ct->mark;
96518518
PM
89 return;
90#endif
91#ifdef CONFIG_NF_CONNTRACK_SECMARK
92 case NFT_CT_SECMARK:
fad136ea 93 *dest = ct->secmark;
96518518
PM
94 return;
95#endif
96 case NFT_CT_EXPIRATION:
c8607e02 97 *dest = jiffies_to_msecs(nf_ct_expires(ct));
96518518
PM
98 return;
99 case NFT_CT_HELPER:
100 if (ct->master == NULL)
101 goto err;
102 help = nfct_help(ct->master);
103 if (help == NULL)
104 goto err;
105 helper = rcu_dereference(help->helper);
106 if (helper == NULL)
107 goto err;
fad136ea 108 strncpy((char *)dest, helper->name, NF_CT_HELPER_NAME_LEN);
96518518 109 return;
d2bf2f34
FW
110#ifdef CONFIG_NF_CONNTRACK_LABELS
111 case NFT_CT_LABELS: {
112 struct nf_conn_labels *labels = nf_ct_labels_find(ct);
d2bf2f34 113
23014011
FW
114 if (labels)
115 memcpy(dest, labels->bits, NF_CT_LABELS_MAX_SIZE);
116 else
fad136ea 117 memset(dest, 0, NF_CT_LABELS_MAX_SIZE);
d2bf2f34
FW
118 return;
119 }
efaea94a 120#endif
48f66c90
FW
121 case NFT_CT_BYTES: /* fallthrough */
122 case NFT_CT_PKTS: {
123 const struct nf_conn_acct *acct = nf_conn_acct_find(ct);
124 u64 count = 0;
125
126 if (acct)
127 count = nft_ct_get_eval_counter(acct->counter,
128 priv->key, priv->dir);
129 memcpy(dest, &count, sizeof(count));
130 return;
131 }
949a3584
LZ
132 case NFT_CT_AVGPKT: {
133 const struct nf_conn_acct *acct = nf_conn_acct_find(ct);
134 u64 avgcnt = 0, bcnt = 0, pcnt = 0;
135
136 if (acct) {
137 pcnt = nft_ct_get_eval_counter(acct->counter,
138 NFT_CT_PKTS, priv->dir);
139 bcnt = nft_ct_get_eval_counter(acct->counter,
140 NFT_CT_BYTES, priv->dir);
141 if (pcnt != 0)
142 avgcnt = div64_u64(bcnt, pcnt);
143 }
144
145 memcpy(dest, &avgcnt, sizeof(avgcnt));
146 return;
147 }
d767ff2c
LZ
148 case NFT_CT_L3PROTOCOL:
149 *dest = nf_ct_l3num(ct);
150 return;
151 case NFT_CT_PROTOCOL:
152 *dest = nf_ct_protonum(ct);
153 return;
ab23821f
FW
154#ifdef CONFIG_NF_CONNTRACK_ZONES
155 case NFT_CT_ZONE: {
156 const struct nf_conntrack_zone *zone = nf_ct_zone(ct);
157
158 if (priv->dir < IP_CT_DIR_MAX)
159 *dest = nf_ct_zone_id(zone, priv->dir);
160 else
161 *dest = zone->id;
162
163 return;
164 }
165#endif
c1f86676
DM
166 default:
167 break;
96518518
PM
168 }
169
170 tuple = &ct->tuplehash[priv->dir].tuple;
171 switch (priv->key) {
96518518 172 case NFT_CT_SRC:
fad136ea 173 memcpy(dest, tuple->src.u3.all,
96518518
PM
174 nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
175 return;
176 case NFT_CT_DST:
fad136ea 177 memcpy(dest, tuple->dst.u3.all,
96518518
PM
178 nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
179 return;
96518518 180 case NFT_CT_PROTO_SRC:
fad136ea 181 *dest = (__force __u16)tuple->src.u.all;
96518518
PM
182 return;
183 case NFT_CT_PROTO_DST:
fad136ea 184 *dest = (__force __u16)tuple->dst.u.all;
96518518 185 return;
c1f86676
DM
186 default:
187 break;
96518518
PM
188 }
189 return;
190err:
a55e22e9 191 regs->verdict.code = NFT_BREAK;
96518518
PM
192}
193
c4ede3d3 194static void nft_ct_set_eval(const struct nft_expr *expr,
a55e22e9 195 struct nft_regs *regs,
c4ede3d3
KE
196 const struct nft_pktinfo *pkt)
197{
198 const struct nft_ct *priv = nft_expr_priv(expr);
199 struct sk_buff *skb = pkt->skb;
847c8e29 200#ifdef CONFIG_NF_CONNTRACK_MARK
49499c3e 201 u32 value = regs->data[priv->sreg];
847c8e29 202#endif
c4ede3d3
KE
203 enum ip_conntrack_info ctinfo;
204 struct nf_conn *ct;
205
206 ct = nf_ct_get(skb, &ctinfo);
207 if (ct == NULL)
208 return;
209
210 switch (priv->key) {
211#ifdef CONFIG_NF_CONNTRACK_MARK
212 case NFT_CT_MARK:
213 if (ct->mark != value) {
214 ct->mark = value;
215 nf_conntrack_event_cache(IPCT_MARK, ct);
216 }
217 break;
1ad8f48d
FW
218#endif
219#ifdef CONFIG_NF_CONNTRACK_LABELS
220 case NFT_CT_LABELS:
221 nf_connlabels_replace(ct,
222 &regs->data[priv->sreg],
223 &regs->data[priv->sreg],
224 NF_CT_LABELS_MAX_SIZE / sizeof(u32));
225 break;
c4ede3d3 226#endif
c1f86676
DM
227 default:
228 break;
c4ede3d3
KE
229 }
230}
231
96518518
PM
232static const struct nla_policy nft_ct_policy[NFTA_CT_MAX + 1] = {
233 [NFTA_CT_DREG] = { .type = NLA_U32 },
234 [NFTA_CT_KEY] = { .type = NLA_U32 },
235 [NFTA_CT_DIRECTION] = { .type = NLA_U8 },
c4ede3d3 236 [NFTA_CT_SREG] = { .type = NLA_U32 },
96518518
PM
237};
238
ecb2421b 239static int nft_ct_netns_get(struct net *net, uint8_t family)
9638f33e
PM
240{
241 int err;
242
243 if (family == NFPROTO_INET) {
ecb2421b 244 err = nf_ct_netns_get(net, NFPROTO_IPV4);
9638f33e
PM
245 if (err < 0)
246 goto err1;
ecb2421b 247 err = nf_ct_netns_get(net, NFPROTO_IPV6);
9638f33e
PM
248 if (err < 0)
249 goto err2;
250 } else {
ecb2421b 251 err = nf_ct_netns_get(net, family);
9638f33e
PM
252 if (err < 0)
253 goto err1;
254 }
255 return 0;
256
257err2:
ecb2421b 258 nf_ct_netns_put(net, NFPROTO_IPV4);
9638f33e
PM
259err1:
260 return err;
261}
262
ecb2421b 263static void nft_ct_netns_put(struct net *net, uint8_t family)
9638f33e
PM
264{
265 if (family == NFPROTO_INET) {
ecb2421b
FW
266 nf_ct_netns_put(net, NFPROTO_IPV4);
267 nf_ct_netns_put(net, NFPROTO_IPV6);
9638f33e 268 } else
ecb2421b 269 nf_ct_netns_put(net, family);
9638f33e
PM
270}
271
fe92ca45
PM
272static int nft_ct_get_init(const struct nft_ctx *ctx,
273 const struct nft_expr *expr,
274 const struct nlattr * const tb[])
96518518
PM
275{
276 struct nft_ct *priv = nft_expr_priv(expr);
45d9bcda 277 unsigned int len;
fe92ca45 278 int err;
96518518 279
fe92ca45 280 priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
ab23821f 281 priv->dir = IP_CT_DIR_MAX;
96518518 282 switch (priv->key) {
96518518 283 case NFT_CT_DIRECTION:
45d9bcda
PM
284 if (tb[NFTA_CT_DIRECTION] != NULL)
285 return -EINVAL;
286 len = sizeof(u8);
287 break;
288 case NFT_CT_STATE:
96518518
PM
289 case NFT_CT_STATUS:
290#ifdef CONFIG_NF_CONNTRACK_MARK
291 case NFT_CT_MARK:
292#endif
293#ifdef CONFIG_NF_CONNTRACK_SECMARK
294 case NFT_CT_SECMARK:
d2bf2f34 295#endif
45d9bcda
PM
296 case NFT_CT_EXPIRATION:
297 if (tb[NFTA_CT_DIRECTION] != NULL)
298 return -EINVAL;
299 len = sizeof(u32);
300 break;
d2bf2f34
FW
301#ifdef CONFIG_NF_CONNTRACK_LABELS
302 case NFT_CT_LABELS:
45d9bcda
PM
303 if (tb[NFTA_CT_DIRECTION] != NULL)
304 return -EINVAL;
305 len = NF_CT_LABELS_MAX_SIZE;
306 break;
96518518 307#endif
96518518
PM
308 case NFT_CT_HELPER:
309 if (tb[NFTA_CT_DIRECTION] != NULL)
310 return -EINVAL;
45d9bcda 311 len = NF_CT_HELPER_NAME_LEN;
96518518 312 break;
45d9bcda 313
51292c07 314 case NFT_CT_L3PROTOCOL:
96518518 315 case NFT_CT_PROTOCOL:
d767ff2c
LZ
316 /* For compatibility, do not report error if NFTA_CT_DIRECTION
317 * attribute is specified.
318 */
45d9bcda
PM
319 len = sizeof(u8);
320 break;
96518518
PM
321 case NFT_CT_SRC:
322 case NFT_CT_DST:
45d9bcda
PM
323 if (tb[NFTA_CT_DIRECTION] == NULL)
324 return -EINVAL;
325
326 switch (ctx->afi->family) {
327 case NFPROTO_IPV4:
328 len = FIELD_SIZEOF(struct nf_conntrack_tuple,
329 src.u3.ip);
330 break;
331 case NFPROTO_IPV6:
332 case NFPROTO_INET:
333 len = FIELD_SIZEOF(struct nf_conntrack_tuple,
334 src.u3.ip6);
335 break;
336 default:
337 return -EAFNOSUPPORT;
338 }
339 break;
96518518
PM
340 case NFT_CT_PROTO_SRC:
341 case NFT_CT_PROTO_DST:
342 if (tb[NFTA_CT_DIRECTION] == NULL)
343 return -EINVAL;
45d9bcda 344 len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u.all);
96518518 345 break;
48f66c90
FW
346 case NFT_CT_BYTES:
347 case NFT_CT_PKTS:
949a3584 348 case NFT_CT_AVGPKT:
48f66c90
FW
349 len = sizeof(u64);
350 break;
ab23821f
FW
351#ifdef CONFIG_NF_CONNTRACK_ZONES
352 case NFT_CT_ZONE:
353 len = sizeof(u16);
354 break;
355#endif
96518518
PM
356 default:
357 return -EOPNOTSUPP;
358 }
359
fe92ca45
PM
360 if (tb[NFTA_CT_DIRECTION] != NULL) {
361 priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]);
362 switch (priv->dir) {
363 case IP_CT_DIR_ORIGINAL:
364 case IP_CT_DIR_REPLY:
365 break;
366 default:
367 return -EINVAL;
368 }
369 }
370
b1c96ed3 371 priv->dreg = nft_parse_register(tb[NFTA_CT_DREG]);
1ec10212
PM
372 err = nft_validate_register_store(ctx, priv->dreg, NULL,
373 NFT_DATA_VALUE, len);
fe92ca45
PM
374 if (err < 0)
375 return err;
376
ecb2421b 377 err = nft_ct_netns_get(ctx->net, ctx->afi->family);
fe92ca45
PM
378 if (err < 0)
379 return err;
380
949a3584
LZ
381 if (priv->key == NFT_CT_BYTES ||
382 priv->key == NFT_CT_PKTS ||
383 priv->key == NFT_CT_AVGPKT)
3f8b61b7
LZ
384 nf_ct_set_acct(ctx->net, true);
385
c4ede3d3
KE
386 return 0;
387}
388
5c178d81
FW
389static void __nft_ct_set_destroy(const struct nft_ctx *ctx, struct nft_ct *priv)
390{
391 switch (priv->key) {
392#ifdef CONFIG_NF_CONNTRACK_LABELS
393 case NFT_CT_LABELS:
394 nf_connlabels_put(ctx->net);
395 break;
396#endif
397 default:
398 break;
399 }
400}
401
fe92ca45
PM
402static int nft_ct_set_init(const struct nft_ctx *ctx,
403 const struct nft_expr *expr,
404 const struct nlattr * const tb[])
c4ede3d3 405{
fe92ca45 406 struct nft_ct *priv = nft_expr_priv(expr);
d07db988 407 unsigned int len;
fe92ca45
PM
408 int err;
409
410 priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
411 switch (priv->key) {
e88e514e 412#ifdef CONFIG_NF_CONNTRACK_MARK
c4ede3d3 413 case NFT_CT_MARK:
7bfdde70
LZ
414 if (tb[NFTA_CT_DIRECTION])
415 return -EINVAL;
d07db988 416 len = FIELD_SIZEOF(struct nf_conn, mark);
c4ede3d3 417 break;
1ad8f48d
FW
418#endif
419#ifdef CONFIG_NF_CONNTRACK_LABELS
420 case NFT_CT_LABELS:
421 if (tb[NFTA_CT_DIRECTION])
422 return -EINVAL;
423 len = NF_CT_LABELS_MAX_SIZE;
424 err = nf_connlabels_get(ctx->net, (len * BITS_PER_BYTE) - 1);
425 if (err)
426 return err;
427 break;
e88e514e 428#endif
c4ede3d3
KE
429 default:
430 return -EOPNOTSUPP;
431 }
432
b1c96ed3 433 priv->sreg = nft_parse_register(tb[NFTA_CT_SREG]);
d07db988 434 err = nft_validate_register_load(priv->sreg, len);
fe92ca45 435 if (err < 0)
590025a2 436 goto err1;
c4ede3d3 437
ecb2421b 438 err = nft_ct_netns_get(ctx->net, ctx->afi->family);
96518518 439 if (err < 0)
590025a2 440 goto err1;
96518518 441
96518518 442 return 0;
590025a2
LZ
443
444err1:
5c178d81 445 __nft_ct_set_destroy(ctx, priv);
590025a2
LZ
446 return err;
447}
448
449static void nft_ct_get_destroy(const struct nft_ctx *ctx,
450 const struct nft_expr *expr)
451{
ecb2421b 452 nf_ct_netns_put(ctx->net, ctx->afi->family);
96518518
PM
453}
454
590025a2
LZ
455static void nft_ct_set_destroy(const struct nft_ctx *ctx,
456 const struct nft_expr *expr)
96518518 457{
1ad8f48d
FW
458 struct nft_ct *priv = nft_expr_priv(expr);
459
5c178d81 460 __nft_ct_set_destroy(ctx, priv);
ecb2421b 461 nft_ct_netns_put(ctx->net, ctx->afi->family);
96518518
PM
462}
463
c4ede3d3 464static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr)
96518518
PM
465{
466 const struct nft_ct *priv = nft_expr_priv(expr);
467
b1c96ed3 468 if (nft_dump_register(skb, NFTA_CT_DREG, priv->dreg))
96518518
PM
469 goto nla_put_failure;
470 if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
471 goto nla_put_failure;
2a53bfb3
AB
472
473 switch (priv->key) {
2a53bfb3
AB
474 case NFT_CT_SRC:
475 case NFT_CT_DST:
476 case NFT_CT_PROTO_SRC:
477 case NFT_CT_PROTO_DST:
478 if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
479 goto nla_put_failure;
48f66c90
FW
480 break;
481 case NFT_CT_BYTES:
482 case NFT_CT_PKTS:
949a3584 483 case NFT_CT_AVGPKT:
ab23821f 484 case NFT_CT_ZONE:
48f66c90
FW
485 if (priv->dir < IP_CT_DIR_MAX &&
486 nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
487 goto nla_put_failure;
488 break;
2a53bfb3
AB
489 default:
490 break;
491 }
492
96518518
PM
493 return 0;
494
495nla_put_failure:
496 return -1;
497}
498
c4ede3d3
KE
499static int nft_ct_set_dump(struct sk_buff *skb, const struct nft_expr *expr)
500{
501 const struct nft_ct *priv = nft_expr_priv(expr);
502
b1c96ed3 503 if (nft_dump_register(skb, NFTA_CT_SREG, priv->sreg))
c4ede3d3
KE
504 goto nla_put_failure;
505 if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
506 goto nla_put_failure;
507 return 0;
508
509nla_put_failure:
510 return -1;
511}
512
ef1f7df9 513static struct nft_expr_type nft_ct_type;
c4ede3d3 514static const struct nft_expr_ops nft_ct_get_ops = {
ef1f7df9 515 .type = &nft_ct_type,
96518518 516 .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
c4ede3d3 517 .eval = nft_ct_get_eval,
fe92ca45 518 .init = nft_ct_get_init,
590025a2 519 .destroy = nft_ct_get_destroy,
c4ede3d3 520 .dump = nft_ct_get_dump,
ef1f7df9
PM
521};
522
c4ede3d3
KE
523static const struct nft_expr_ops nft_ct_set_ops = {
524 .type = &nft_ct_type,
525 .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
526 .eval = nft_ct_set_eval,
fe92ca45 527 .init = nft_ct_set_init,
590025a2 528 .destroy = nft_ct_set_destroy,
c4ede3d3
KE
529 .dump = nft_ct_set_dump,
530};
531
532static const struct nft_expr_ops *
533nft_ct_select_ops(const struct nft_ctx *ctx,
534 const struct nlattr * const tb[])
535{
536 if (tb[NFTA_CT_KEY] == NULL)
537 return ERR_PTR(-EINVAL);
538
539 if (tb[NFTA_CT_DREG] && tb[NFTA_CT_SREG])
540 return ERR_PTR(-EINVAL);
541
542 if (tb[NFTA_CT_DREG])
543 return &nft_ct_get_ops;
544
545 if (tb[NFTA_CT_SREG])
546 return &nft_ct_set_ops;
547
548 return ERR_PTR(-EINVAL);
549}
550
ef1f7df9
PM
551static struct nft_expr_type nft_ct_type __read_mostly = {
552 .name = "ct",
c4ede3d3 553 .select_ops = &nft_ct_select_ops,
96518518
PM
554 .policy = nft_ct_policy,
555 .maxattr = NFTA_CT_MAX,
ef1f7df9 556 .owner = THIS_MODULE,
96518518
PM
557};
558
25443261
PNA
559static void nft_notrack_eval(const struct nft_expr *expr,
560 struct nft_regs *regs,
561 const struct nft_pktinfo *pkt)
562{
563 struct sk_buff *skb = pkt->skb;
564 enum ip_conntrack_info ctinfo;
565 struct nf_conn *ct;
566
567 ct = nf_ct_get(pkt->skb, &ctinfo);
568 /* Previously seen (loopback or untracked)? Ignore. */
569 if (ct)
570 return;
571
572 ct = nf_ct_untracked_get();
573 atomic_inc(&ct->ct_general.use);
c74454fa 574 nf_ct_set(skb, ct, IP_CT_NEW);
25443261
PNA
575}
576
577static struct nft_expr_type nft_notrack_type;
578static const struct nft_expr_ops nft_notrack_ops = {
579 .type = &nft_notrack_type,
580 .size = NFT_EXPR_SIZE(0),
581 .eval = nft_notrack_eval,
582};
583
584static struct nft_expr_type nft_notrack_type __read_mostly = {
585 .name = "notrack",
586 .ops = &nft_notrack_ops,
587 .owner = THIS_MODULE,
588};
589
96518518
PM
590static int __init nft_ct_module_init(void)
591{
25443261
PNA
592 int err;
593
adff6c65
FW
594 BUILD_BUG_ON(NF_CT_LABELS_MAX_SIZE > NFT_REG_SIZE);
595
25443261
PNA
596 err = nft_register_expr(&nft_ct_type);
597 if (err < 0)
598 return err;
599
600 err = nft_register_expr(&nft_notrack_type);
601 if (err < 0)
602 goto err1;
603
604 return 0;
605err1:
606 nft_unregister_expr(&nft_ct_type);
607 return err;
96518518
PM
608}
609
610static void __exit nft_ct_module_exit(void)
611{
25443261 612 nft_unregister_expr(&nft_notrack_type);
ef1f7df9 613 nft_unregister_expr(&nft_ct_type);
96518518
PM
614}
615
616module_init(nft_ct_module_init);
617module_exit(nft_ct_module_exit);
618
619MODULE_LICENSE("GPL");
620MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
621MODULE_ALIAS_NFT_EXPR("ct");
25443261 622MODULE_ALIAS_NFT_EXPR("notrack");