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