Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.12-rc2 655 lines 17 kB view raw
1/* 2 * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org> 3 * (C) 2012 by Vyatta Inc. <http://www.vyatta.com> 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 (or any later at your option). 8 */ 9#include <linux/init.h> 10#include <linux/module.h> 11#include <linux/kernel.h> 12#include <linux/rculist.h> 13#include <linux/rculist_nulls.h> 14#include <linux/types.h> 15#include <linux/timer.h> 16#include <linux/security.h> 17#include <linux/skbuff.h> 18#include <linux/errno.h> 19#include <linux/netlink.h> 20#include <linux/spinlock.h> 21#include <linux/interrupt.h> 22#include <linux/slab.h> 23 24#include <linux/netfilter.h> 25#include <net/netlink.h> 26#include <net/sock.h> 27#include <net/netfilter/nf_conntrack.h> 28#include <net/netfilter/nf_conntrack_core.h> 29#include <net/netfilter/nf_conntrack_l3proto.h> 30#include <net/netfilter/nf_conntrack_l4proto.h> 31#include <net/netfilter/nf_conntrack_tuple.h> 32#include <net/netfilter/nf_conntrack_timeout.h> 33 34#include <linux/netfilter/nfnetlink.h> 35#include <linux/netfilter/nfnetlink_cttimeout.h> 36 37MODULE_LICENSE("GPL"); 38MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); 39MODULE_DESCRIPTION("cttimeout: Extended Netfilter Connection Tracking timeout tuning"); 40 41static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = { 42 [CTA_TIMEOUT_NAME] = { .type = NLA_NUL_STRING, 43 .len = CTNL_TIMEOUT_NAME_MAX - 1}, 44 [CTA_TIMEOUT_L3PROTO] = { .type = NLA_U16 }, 45 [CTA_TIMEOUT_L4PROTO] = { .type = NLA_U8 }, 46 [CTA_TIMEOUT_DATA] = { .type = NLA_NESTED }, 47}; 48 49static int 50ctnl_timeout_parse_policy(void *timeouts, struct nf_conntrack_l4proto *l4proto, 51 struct net *net, const struct nlattr *attr) 52{ 53 int ret = 0; 54 55 if (likely(l4proto->ctnl_timeout.nlattr_to_obj)) { 56 struct nlattr *tb[l4proto->ctnl_timeout.nlattr_max+1]; 57 58 ret = nla_parse_nested(tb, l4proto->ctnl_timeout.nlattr_max, 59 attr, l4proto->ctnl_timeout.nla_policy, 60 NULL); 61 if (ret < 0) 62 return ret; 63 64 ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net, timeouts); 65 } 66 return ret; 67} 68 69static int cttimeout_new_timeout(struct net *net, struct sock *ctnl, 70 struct sk_buff *skb, 71 const struct nlmsghdr *nlh, 72 const struct nlattr * const cda[]) 73{ 74 __u16 l3num; 75 __u8 l4num; 76 struct nf_conntrack_l4proto *l4proto; 77 struct ctnl_timeout *timeout, *matching = NULL; 78 char *name; 79 int ret; 80 81 if (!cda[CTA_TIMEOUT_NAME] || 82 !cda[CTA_TIMEOUT_L3PROTO] || 83 !cda[CTA_TIMEOUT_L4PROTO] || 84 !cda[CTA_TIMEOUT_DATA]) 85 return -EINVAL; 86 87 name = nla_data(cda[CTA_TIMEOUT_NAME]); 88 l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO])); 89 l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]); 90 91 list_for_each_entry(timeout, &net->nfct_timeout_list, head) { 92 if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) 93 continue; 94 95 if (nlh->nlmsg_flags & NLM_F_EXCL) 96 return -EEXIST; 97 98 matching = timeout; 99 break; 100 } 101 102 if (matching) { 103 if (nlh->nlmsg_flags & NLM_F_REPLACE) { 104 /* You cannot replace one timeout policy by another of 105 * different kind, sorry. 106 */ 107 if (matching->l3num != l3num || 108 matching->l4proto->l4proto != l4num) 109 return -EINVAL; 110 111 return ctnl_timeout_parse_policy(&matching->data, 112 matching->l4proto, net, 113 cda[CTA_TIMEOUT_DATA]); 114 } 115 116 return -EBUSY; 117 } 118 119 l4proto = nf_ct_l4proto_find_get(l3num, l4num); 120 121 /* This protocol is not supportted, skip. */ 122 if (l4proto->l4proto != l4num) { 123 ret = -EOPNOTSUPP; 124 goto err_proto_put; 125 } 126 127 timeout = kzalloc(sizeof(struct ctnl_timeout) + 128 l4proto->ctnl_timeout.obj_size, GFP_KERNEL); 129 if (timeout == NULL) { 130 ret = -ENOMEM; 131 goto err_proto_put; 132 } 133 134 ret = ctnl_timeout_parse_policy(&timeout->data, l4proto, net, 135 cda[CTA_TIMEOUT_DATA]); 136 if (ret < 0) 137 goto err; 138 139 strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME])); 140 timeout->l3num = l3num; 141 timeout->l4proto = l4proto; 142 refcount_set(&timeout->refcnt, 1); 143 list_add_tail_rcu(&timeout->head, &net->nfct_timeout_list); 144 145 return 0; 146err: 147 kfree(timeout); 148err_proto_put: 149 nf_ct_l4proto_put(l4proto); 150 return ret; 151} 152 153static int 154ctnl_timeout_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, 155 int event, struct ctnl_timeout *timeout) 156{ 157 struct nlmsghdr *nlh; 158 struct nfgenmsg *nfmsg; 159 unsigned int flags = portid ? NLM_F_MULTI : 0; 160 struct nf_conntrack_l4proto *l4proto = timeout->l4proto; 161 162 event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_TIMEOUT, event); 163 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags); 164 if (nlh == NULL) 165 goto nlmsg_failure; 166 167 nfmsg = nlmsg_data(nlh); 168 nfmsg->nfgen_family = AF_UNSPEC; 169 nfmsg->version = NFNETLINK_V0; 170 nfmsg->res_id = 0; 171 172 if (nla_put_string(skb, CTA_TIMEOUT_NAME, timeout->name) || 173 nla_put_be16(skb, CTA_TIMEOUT_L3PROTO, htons(timeout->l3num)) || 174 nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4proto->l4proto) || 175 nla_put_be32(skb, CTA_TIMEOUT_USE, 176 htonl(refcount_read(&timeout->refcnt)))) 177 goto nla_put_failure; 178 179 if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) { 180 struct nlattr *nest_parms; 181 int ret; 182 183 nest_parms = nla_nest_start(skb, 184 CTA_TIMEOUT_DATA | NLA_F_NESTED); 185 if (!nest_parms) 186 goto nla_put_failure; 187 188 ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, &timeout->data); 189 if (ret < 0) 190 goto nla_put_failure; 191 192 nla_nest_end(skb, nest_parms); 193 } 194 195 nlmsg_end(skb, nlh); 196 return skb->len; 197 198nlmsg_failure: 199nla_put_failure: 200 nlmsg_cancel(skb, nlh); 201 return -1; 202} 203 204static int 205ctnl_timeout_dump(struct sk_buff *skb, struct netlink_callback *cb) 206{ 207 struct net *net = sock_net(skb->sk); 208 struct ctnl_timeout *cur, *last; 209 210 if (cb->args[2]) 211 return 0; 212 213 last = (struct ctnl_timeout *)cb->args[1]; 214 if (cb->args[1]) 215 cb->args[1] = 0; 216 217 rcu_read_lock(); 218 list_for_each_entry_rcu(cur, &net->nfct_timeout_list, head) { 219 if (last) { 220 if (cur != last) 221 continue; 222 223 last = NULL; 224 } 225 if (ctnl_timeout_fill_info(skb, NETLINK_CB(cb->skb).portid, 226 cb->nlh->nlmsg_seq, 227 NFNL_MSG_TYPE(cb->nlh->nlmsg_type), 228 IPCTNL_MSG_TIMEOUT_NEW, cur) < 0) { 229 cb->args[1] = (unsigned long)cur; 230 break; 231 } 232 } 233 if (!cb->args[1]) 234 cb->args[2] = 1; 235 rcu_read_unlock(); 236 return skb->len; 237} 238 239static int cttimeout_get_timeout(struct net *net, struct sock *ctnl, 240 struct sk_buff *skb, 241 const struct nlmsghdr *nlh, 242 const struct nlattr * const cda[]) 243{ 244 int ret = -ENOENT; 245 char *name; 246 struct ctnl_timeout *cur; 247 248 if (nlh->nlmsg_flags & NLM_F_DUMP) { 249 struct netlink_dump_control c = { 250 .dump = ctnl_timeout_dump, 251 }; 252 return netlink_dump_start(ctnl, skb, nlh, &c); 253 } 254 255 if (!cda[CTA_TIMEOUT_NAME]) 256 return -EINVAL; 257 name = nla_data(cda[CTA_TIMEOUT_NAME]); 258 259 list_for_each_entry(cur, &net->nfct_timeout_list, head) { 260 struct sk_buff *skb2; 261 262 if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) 263 continue; 264 265 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 266 if (skb2 == NULL) { 267 ret = -ENOMEM; 268 break; 269 } 270 271 ret = ctnl_timeout_fill_info(skb2, NETLINK_CB(skb).portid, 272 nlh->nlmsg_seq, 273 NFNL_MSG_TYPE(nlh->nlmsg_type), 274 IPCTNL_MSG_TIMEOUT_NEW, cur); 275 if (ret <= 0) { 276 kfree_skb(skb2); 277 break; 278 } 279 ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, 280 MSG_DONTWAIT); 281 if (ret > 0) 282 ret = 0; 283 284 /* this avoids a loop in nfnetlink. */ 285 return ret == -EAGAIN ? -ENOBUFS : ret; 286 } 287 return ret; 288} 289 290static void untimeout(struct nf_conntrack_tuple_hash *i, 291 struct ctnl_timeout *timeout) 292{ 293 struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(i); 294 struct nf_conn_timeout *timeout_ext = nf_ct_timeout_find(ct); 295 296 if (timeout_ext && (!timeout || timeout_ext->timeout == timeout)) 297 RCU_INIT_POINTER(timeout_ext->timeout, NULL); 298} 299 300static void ctnl_untimeout(struct net *net, struct ctnl_timeout *timeout) 301{ 302 struct nf_conntrack_tuple_hash *h; 303 const struct hlist_nulls_node *nn; 304 unsigned int last_hsize; 305 spinlock_t *lock; 306 int i, cpu; 307 308 for_each_possible_cpu(cpu) { 309 struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu); 310 311 spin_lock_bh(&pcpu->lock); 312 hlist_nulls_for_each_entry(h, nn, &pcpu->unconfirmed, hnnode) 313 untimeout(h, timeout); 314 spin_unlock_bh(&pcpu->lock); 315 } 316 317 local_bh_disable(); 318restart: 319 last_hsize = nf_conntrack_htable_size; 320 for (i = 0; i < last_hsize; i++) { 321 lock = &nf_conntrack_locks[i % CONNTRACK_LOCKS]; 322 nf_conntrack_lock(lock); 323 if (last_hsize != nf_conntrack_htable_size) { 324 spin_unlock(lock); 325 goto restart; 326 } 327 328 hlist_nulls_for_each_entry(h, nn, &nf_conntrack_hash[i], hnnode) 329 untimeout(h, timeout); 330 spin_unlock(lock); 331 } 332 local_bh_enable(); 333} 334 335/* try to delete object, fail if it is still in use. */ 336static int ctnl_timeout_try_del(struct net *net, struct ctnl_timeout *timeout) 337{ 338 int ret = 0; 339 340 /* We want to avoid races with ctnl_timeout_put. So only when the 341 * current refcnt is 1, we decrease it to 0. 342 */ 343 if (refcount_dec_if_one(&timeout->refcnt)) { 344 /* We are protected by nfnl mutex. */ 345 list_del_rcu(&timeout->head); 346 nf_ct_l4proto_put(timeout->l4proto); 347 ctnl_untimeout(net, timeout); 348 kfree_rcu(timeout, rcu_head); 349 } else { 350 ret = -EBUSY; 351 } 352 return ret; 353} 354 355static int cttimeout_del_timeout(struct net *net, struct sock *ctnl, 356 struct sk_buff *skb, 357 const struct nlmsghdr *nlh, 358 const struct nlattr * const cda[]) 359{ 360 struct ctnl_timeout *cur, *tmp; 361 int ret = -ENOENT; 362 char *name; 363 364 if (!cda[CTA_TIMEOUT_NAME]) { 365 list_for_each_entry_safe(cur, tmp, &net->nfct_timeout_list, 366 head) 367 ctnl_timeout_try_del(net, cur); 368 369 return 0; 370 } 371 name = nla_data(cda[CTA_TIMEOUT_NAME]); 372 373 list_for_each_entry(cur, &net->nfct_timeout_list, head) { 374 if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) 375 continue; 376 377 ret = ctnl_timeout_try_del(net, cur); 378 if (ret < 0) 379 return ret; 380 381 break; 382 } 383 return ret; 384} 385 386static int cttimeout_default_set(struct net *net, struct sock *ctnl, 387 struct sk_buff *skb, 388 const struct nlmsghdr *nlh, 389 const struct nlattr * const cda[]) 390{ 391 __u16 l3num; 392 __u8 l4num; 393 struct nf_conntrack_l4proto *l4proto; 394 unsigned int *timeouts; 395 int ret; 396 397 if (!cda[CTA_TIMEOUT_L3PROTO] || 398 !cda[CTA_TIMEOUT_L4PROTO] || 399 !cda[CTA_TIMEOUT_DATA]) 400 return -EINVAL; 401 402 l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO])); 403 l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]); 404 l4proto = nf_ct_l4proto_find_get(l3num, l4num); 405 406 /* This protocol is not supported, skip. */ 407 if (l4proto->l4proto != l4num) { 408 ret = -EOPNOTSUPP; 409 goto err; 410 } 411 412 timeouts = l4proto->get_timeouts(net); 413 414 ret = ctnl_timeout_parse_policy(timeouts, l4proto, net, 415 cda[CTA_TIMEOUT_DATA]); 416 if (ret < 0) 417 goto err; 418 419 nf_ct_l4proto_put(l4proto); 420 return 0; 421err: 422 nf_ct_l4proto_put(l4proto); 423 return ret; 424} 425 426static int 427cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid, 428 u32 seq, u32 type, int event, 429 struct nf_conntrack_l4proto *l4proto) 430{ 431 struct nlmsghdr *nlh; 432 struct nfgenmsg *nfmsg; 433 unsigned int flags = portid ? NLM_F_MULTI : 0; 434 435 event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_TIMEOUT, event); 436 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags); 437 if (nlh == NULL) 438 goto nlmsg_failure; 439 440 nfmsg = nlmsg_data(nlh); 441 nfmsg->nfgen_family = AF_UNSPEC; 442 nfmsg->version = NFNETLINK_V0; 443 nfmsg->res_id = 0; 444 445 if (nla_put_be16(skb, CTA_TIMEOUT_L3PROTO, htons(l4proto->l3proto)) || 446 nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, l4proto->l4proto)) 447 goto nla_put_failure; 448 449 if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) { 450 struct nlattr *nest_parms; 451 unsigned int *timeouts = l4proto->get_timeouts(net); 452 int ret; 453 454 nest_parms = nla_nest_start(skb, 455 CTA_TIMEOUT_DATA | NLA_F_NESTED); 456 if (!nest_parms) 457 goto nla_put_failure; 458 459 ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, timeouts); 460 if (ret < 0) 461 goto nla_put_failure; 462 463 nla_nest_end(skb, nest_parms); 464 } 465 466 nlmsg_end(skb, nlh); 467 return skb->len; 468 469nlmsg_failure: 470nla_put_failure: 471 nlmsg_cancel(skb, nlh); 472 return -1; 473} 474 475static int cttimeout_default_get(struct net *net, struct sock *ctnl, 476 struct sk_buff *skb, 477 const struct nlmsghdr *nlh, 478 const struct nlattr * const cda[]) 479{ 480 __u16 l3num; 481 __u8 l4num; 482 struct nf_conntrack_l4proto *l4proto; 483 struct sk_buff *skb2; 484 int ret, err; 485 486 if (!cda[CTA_TIMEOUT_L3PROTO] || !cda[CTA_TIMEOUT_L4PROTO]) 487 return -EINVAL; 488 489 l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO])); 490 l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]); 491 l4proto = nf_ct_l4proto_find_get(l3num, l4num); 492 493 /* This protocol is not supported, skip. */ 494 if (l4proto->l4proto != l4num) { 495 err = -EOPNOTSUPP; 496 goto err; 497 } 498 499 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 500 if (skb2 == NULL) { 501 err = -ENOMEM; 502 goto err; 503 } 504 505 ret = cttimeout_default_fill_info(net, skb2, NETLINK_CB(skb).portid, 506 nlh->nlmsg_seq, 507 NFNL_MSG_TYPE(nlh->nlmsg_type), 508 IPCTNL_MSG_TIMEOUT_DEFAULT_SET, 509 l4proto); 510 if (ret <= 0) { 511 kfree_skb(skb2); 512 err = -ENOMEM; 513 goto err; 514 } 515 ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT); 516 if (ret > 0) 517 ret = 0; 518 519 /* this avoids a loop in nfnetlink. */ 520 return ret == -EAGAIN ? -ENOBUFS : ret; 521err: 522 nf_ct_l4proto_put(l4proto); 523 return err; 524} 525 526#ifdef CONFIG_NF_CONNTRACK_TIMEOUT 527static struct ctnl_timeout * 528ctnl_timeout_find_get(struct net *net, const char *name) 529{ 530 struct ctnl_timeout *timeout, *matching = NULL; 531 532 rcu_read_lock(); 533 list_for_each_entry_rcu(timeout, &net->nfct_timeout_list, head) { 534 if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) 535 continue; 536 537 if (!try_module_get(THIS_MODULE)) 538 goto err; 539 540 if (!refcount_inc_not_zero(&timeout->refcnt)) { 541 module_put(THIS_MODULE); 542 goto err; 543 } 544 matching = timeout; 545 break; 546 } 547err: 548 rcu_read_unlock(); 549 return matching; 550} 551 552static void ctnl_timeout_put(struct ctnl_timeout *timeout) 553{ 554 if (refcount_dec_and_test(&timeout->refcnt)) 555 kfree_rcu(timeout, rcu_head); 556 557 module_put(THIS_MODULE); 558} 559#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ 560 561static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = { 562 [IPCTNL_MSG_TIMEOUT_NEW] = { .call = cttimeout_new_timeout, 563 .attr_count = CTA_TIMEOUT_MAX, 564 .policy = cttimeout_nla_policy }, 565 [IPCTNL_MSG_TIMEOUT_GET] = { .call = cttimeout_get_timeout, 566 .attr_count = CTA_TIMEOUT_MAX, 567 .policy = cttimeout_nla_policy }, 568 [IPCTNL_MSG_TIMEOUT_DELETE] = { .call = cttimeout_del_timeout, 569 .attr_count = CTA_TIMEOUT_MAX, 570 .policy = cttimeout_nla_policy }, 571 [IPCTNL_MSG_TIMEOUT_DEFAULT_SET]= { .call = cttimeout_default_set, 572 .attr_count = CTA_TIMEOUT_MAX, 573 .policy = cttimeout_nla_policy }, 574 [IPCTNL_MSG_TIMEOUT_DEFAULT_GET]= { .call = cttimeout_default_get, 575 .attr_count = CTA_TIMEOUT_MAX, 576 .policy = cttimeout_nla_policy }, 577}; 578 579static const struct nfnetlink_subsystem cttimeout_subsys = { 580 .name = "conntrack_timeout", 581 .subsys_id = NFNL_SUBSYS_CTNETLINK_TIMEOUT, 582 .cb_count = IPCTNL_MSG_TIMEOUT_MAX, 583 .cb = cttimeout_cb, 584}; 585 586MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_TIMEOUT); 587 588static int __net_init cttimeout_net_init(struct net *net) 589{ 590 INIT_LIST_HEAD(&net->nfct_timeout_list); 591 592 return 0; 593} 594 595static void __net_exit cttimeout_net_exit(struct net *net) 596{ 597 struct ctnl_timeout *cur, *tmp; 598 599 ctnl_untimeout(net, NULL); 600 601 list_for_each_entry_safe(cur, tmp, &net->nfct_timeout_list, head) { 602 list_del_rcu(&cur->head); 603 nf_ct_l4proto_put(cur->l4proto); 604 605 if (refcount_dec_and_test(&cur->refcnt)) 606 kfree_rcu(cur, rcu_head); 607 } 608} 609 610static struct pernet_operations cttimeout_ops = { 611 .init = cttimeout_net_init, 612 .exit = cttimeout_net_exit, 613}; 614 615static int __init cttimeout_init(void) 616{ 617 int ret; 618 619 ret = register_pernet_subsys(&cttimeout_ops); 620 if (ret < 0) 621 return ret; 622 623 ret = nfnetlink_subsys_register(&cttimeout_subsys); 624 if (ret < 0) { 625 pr_err("cttimeout_init: cannot register cttimeout with " 626 "nfnetlink.\n"); 627 goto err_out; 628 } 629#ifdef CONFIG_NF_CONNTRACK_TIMEOUT 630 RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, ctnl_timeout_find_get); 631 RCU_INIT_POINTER(nf_ct_timeout_put_hook, ctnl_timeout_put); 632#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ 633 return 0; 634 635err_out: 636 unregister_pernet_subsys(&cttimeout_ops); 637 return ret; 638} 639 640static void __exit cttimeout_exit(void) 641{ 642 pr_info("cttimeout: unregistering from nfnetlink.\n"); 643 644 nfnetlink_subsys_unregister(&cttimeout_subsys); 645 646 unregister_pernet_subsys(&cttimeout_ops); 647#ifdef CONFIG_NF_CONNTRACK_TIMEOUT 648 RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, NULL); 649 RCU_INIT_POINTER(nf_ct_timeout_put_hook, NULL); 650 synchronize_rcu(); 651#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ 652} 653 654module_init(cttimeout_init); 655module_exit(cttimeout_exit);