aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2012-11-27 04:58:09 -0500
committerPablo Neira Ayuso <pablo@netfilter.org>2012-12-03 08:36:08 -0500
commit9076aea76538556224e7d73ab718f8841330818a (patch)
tree50d4a6413f9c5dd7d65e9da485179af2e9b824de /net/netfilter
parent60e476d02129acb1f863a9b4932358678ee6a355 (diff)
netfilter: ipset: Increase the number of maximal sets automatically
The max number of sets was hardcoded at kernel cofiguration time and could only be modified via a module parameter. The patch adds the support of increasing the max number of sets automatically, as needed. The array of sets is incremented by 64 new slots if we run out of empty slots. The absolute limit for the maximal number of sets is limited by 65534. Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/ipset/ip_set_core.c243
1 files changed, 160 insertions, 83 deletions
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
index fed899f600b2..6d6d8f2b033e 100644
--- a/net/netfilter/ipset/ip_set_core.c
+++ b/net/netfilter/ipset/ip_set_core.c
@@ -28,9 +28,10 @@ static LIST_HEAD(ip_set_type_list); /* all registered set types */
28static DEFINE_MUTEX(ip_set_type_mutex); /* protects ip_set_type_list */ 28static DEFINE_MUTEX(ip_set_type_mutex); /* protects ip_set_type_list */
29static DEFINE_RWLOCK(ip_set_ref_lock); /* protects the set refs */ 29static DEFINE_RWLOCK(ip_set_ref_lock); /* protects the set refs */
30 30
31static struct ip_set **ip_set_list; /* all individual sets */ 31static struct ip_set * __rcu *ip_set_list; /* all individual sets */
32static ip_set_id_t ip_set_max = CONFIG_IP_SET_MAX; /* max number of sets */ 32static ip_set_id_t ip_set_max = CONFIG_IP_SET_MAX; /* max number of sets */
33 33
34#define IP_SET_INC 64
34#define STREQ(a, b) (strncmp(a, b, IPSET_MAXNAMELEN) == 0) 35#define STREQ(a, b) (strncmp(a, b, IPSET_MAXNAMELEN) == 0)
35 36
36static unsigned int max_sets; 37static unsigned int max_sets;
@@ -42,6 +43,12 @@ MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
42MODULE_DESCRIPTION("core IP set support"); 43MODULE_DESCRIPTION("core IP set support");
43MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET); 44MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET);
44 45
46/* When the nfnl mutex is held: */
47#define nfnl_dereference(p) \
48 rcu_dereference_protected(p, 1)
49#define nfnl_set(id) \
50 nfnl_dereference(ip_set_list)[id]
51
45/* 52/*
46 * The set types are implemented in modules and registered set types 53 * The set types are implemented in modules and registered set types
47 * can be found in ip_set_type_list. Adding/deleting types is 54 * can be found in ip_set_type_list. Adding/deleting types is
@@ -321,19 +328,19 @@ EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6);
321 */ 328 */
322 329
323static inline void 330static inline void
324__ip_set_get(ip_set_id_t index) 331__ip_set_get(struct ip_set *set)
325{ 332{
326 write_lock_bh(&ip_set_ref_lock); 333 write_lock_bh(&ip_set_ref_lock);
327 ip_set_list[index]->ref++; 334 set->ref++;
328 write_unlock_bh(&ip_set_ref_lock); 335 write_unlock_bh(&ip_set_ref_lock);
329} 336}
330 337
331static inline void 338static inline void
332__ip_set_put(ip_set_id_t index) 339__ip_set_put(struct ip_set *set)
333{ 340{
334 write_lock_bh(&ip_set_ref_lock); 341 write_lock_bh(&ip_set_ref_lock);
335 BUG_ON(ip_set_list[index]->ref == 0); 342 BUG_ON(set->ref == 0);
336 ip_set_list[index]->ref--; 343 set->ref--;
337 write_unlock_bh(&ip_set_ref_lock); 344 write_unlock_bh(&ip_set_ref_lock);
338} 345}
339 346
@@ -344,12 +351,25 @@ __ip_set_put(ip_set_id_t index)
344 * so it can't be destroyed (or changed) under our foot. 351 * so it can't be destroyed (or changed) under our foot.
345 */ 352 */
346 353
354static inline struct ip_set *
355ip_set_rcu_get(ip_set_id_t index)
356{
357 struct ip_set *set;
358
359 rcu_read_lock();
360 /* ip_set_list itself needs to be protected */
361 set = rcu_dereference(ip_set_list)[index];
362 rcu_read_unlock();
363
364 return set;
365}
366
347int 367int
348ip_set_test(ip_set_id_t index, const struct sk_buff *skb, 368ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
349 const struct xt_action_param *par, 369 const struct xt_action_param *par,
350 const struct ip_set_adt_opt *opt) 370 const struct ip_set_adt_opt *opt)
351{ 371{
352 struct ip_set *set = ip_set_list[index]; 372 struct ip_set *set = ip_set_rcu_get(index);
353 int ret = 0; 373 int ret = 0;
354 374
355 BUG_ON(set == NULL); 375 BUG_ON(set == NULL);
@@ -388,7 +408,7 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
388 const struct xt_action_param *par, 408 const struct xt_action_param *par,
389 const struct ip_set_adt_opt *opt) 409 const struct ip_set_adt_opt *opt)
390{ 410{
391 struct ip_set *set = ip_set_list[index]; 411 struct ip_set *set = ip_set_rcu_get(index);
392 int ret; 412 int ret;
393 413
394 BUG_ON(set == NULL); 414 BUG_ON(set == NULL);
@@ -411,7 +431,7 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
411 const struct xt_action_param *par, 431 const struct xt_action_param *par,
412 const struct ip_set_adt_opt *opt) 432 const struct ip_set_adt_opt *opt)
413{ 433{
414 struct ip_set *set = ip_set_list[index]; 434 struct ip_set *set = ip_set_rcu_get(index);
415 int ret = 0; 435 int ret = 0;
416 436
417 BUG_ON(set == NULL); 437 BUG_ON(set == NULL);
@@ -440,14 +460,17 @@ ip_set_get_byname(const char *name, struct ip_set **set)
440 ip_set_id_t i, index = IPSET_INVALID_ID; 460 ip_set_id_t i, index = IPSET_INVALID_ID;
441 struct ip_set *s; 461 struct ip_set *s;
442 462
463 rcu_read_lock();
443 for (i = 0; i < ip_set_max; i++) { 464 for (i = 0; i < ip_set_max; i++) {
444 s = ip_set_list[i]; 465 s = rcu_dereference(ip_set_list)[i];
445 if (s != NULL && STREQ(s->name, name)) { 466 if (s != NULL && STREQ(s->name, name)) {
446 __ip_set_get(i); 467 __ip_set_get(s);
447 index = i; 468 index = i;
448 *set = s; 469 *set = s;
470 break;
449 } 471 }
450 } 472 }
473 rcu_read_unlock();
451 474
452 return index; 475 return index;
453} 476}
@@ -462,8 +485,13 @@ EXPORT_SYMBOL_GPL(ip_set_get_byname);
462void 485void
463ip_set_put_byindex(ip_set_id_t index) 486ip_set_put_byindex(ip_set_id_t index)
464{ 487{
465 if (ip_set_list[index] != NULL) 488 struct ip_set *set;
466 __ip_set_put(index); 489
490 rcu_read_lock();
491 set = rcu_dereference(ip_set_list)[index];
492 if (set != NULL)
493 __ip_set_put(set);
494 rcu_read_unlock();
467} 495}
468EXPORT_SYMBOL_GPL(ip_set_put_byindex); 496EXPORT_SYMBOL_GPL(ip_set_put_byindex);
469 497
@@ -477,7 +505,7 @@ EXPORT_SYMBOL_GPL(ip_set_put_byindex);
477const char * 505const char *
478ip_set_name_byindex(ip_set_id_t index) 506ip_set_name_byindex(ip_set_id_t index)
479{ 507{
480 const struct ip_set *set = ip_set_list[index]; 508 const struct ip_set *set = ip_set_rcu_get(index);
481 509
482 BUG_ON(set == NULL); 510 BUG_ON(set == NULL);
483 BUG_ON(set->ref == 0); 511 BUG_ON(set->ref == 0);
@@ -501,11 +529,18 @@ EXPORT_SYMBOL_GPL(ip_set_name_byindex);
501ip_set_id_t 529ip_set_id_t
502ip_set_nfnl_get(const char *name) 530ip_set_nfnl_get(const char *name)
503{ 531{
532 ip_set_id_t i, index = IPSET_INVALID_ID;
504 struct ip_set *s; 533 struct ip_set *s;
505 ip_set_id_t index;
506 534
507 nfnl_lock(); 535 nfnl_lock();
508 index = ip_set_get_byname(name, &s); 536 for (i = 0; i < ip_set_max; i++) {
537 s = nfnl_set(i);
538 if (s != NULL && STREQ(s->name, name)) {
539 __ip_set_get(s);
540 index = i;
541 break;
542 }
543 }
509 nfnl_unlock(); 544 nfnl_unlock();
510 545
511 return index; 546 return index;
@@ -521,12 +556,15 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_get);
521ip_set_id_t 556ip_set_id_t
522ip_set_nfnl_get_byindex(ip_set_id_t index) 557ip_set_nfnl_get_byindex(ip_set_id_t index)
523{ 558{
559 struct ip_set *set;
560
524 if (index > ip_set_max) 561 if (index > ip_set_max)
525 return IPSET_INVALID_ID; 562 return IPSET_INVALID_ID;
526 563
527 nfnl_lock(); 564 nfnl_lock();
528 if (ip_set_list[index]) 565 set = nfnl_set(index);
529 __ip_set_get(index); 566 if (set)
567 __ip_set_get(set);
530 else 568 else
531 index = IPSET_INVALID_ID; 569 index = IPSET_INVALID_ID;
532 nfnl_unlock(); 570 nfnl_unlock();
@@ -545,8 +583,11 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_get_byindex);
545void 583void
546ip_set_nfnl_put(ip_set_id_t index) 584ip_set_nfnl_put(ip_set_id_t index)
547{ 585{
586 struct ip_set *set;
548 nfnl_lock(); 587 nfnl_lock();
549 ip_set_put_byindex(index); 588 set = nfnl_set(index);
589 if (set != NULL)
590 __ip_set_put(set);
550 nfnl_unlock(); 591 nfnl_unlock();
551} 592}
552EXPORT_SYMBOL_GPL(ip_set_nfnl_put); 593EXPORT_SYMBOL_GPL(ip_set_nfnl_put);
@@ -603,41 +644,46 @@ static const struct nla_policy ip_set_create_policy[IPSET_ATTR_CMD_MAX + 1] = {
603 [IPSET_ATTR_DATA] = { .type = NLA_NESTED }, 644 [IPSET_ATTR_DATA] = { .type = NLA_NESTED },
604}; 645};
605 646
606static ip_set_id_t 647static struct ip_set *
607find_set_id(const char *name) 648find_set_and_id(const char *name, ip_set_id_t *id)
608{ 649{
609 ip_set_id_t i, index = IPSET_INVALID_ID; 650 struct ip_set *set = NULL;
610 const struct ip_set *set; 651 ip_set_id_t i;
611 652
612 for (i = 0; index == IPSET_INVALID_ID && i < ip_set_max; i++) { 653 *id = IPSET_INVALID_ID;
613 set = ip_set_list[i]; 654 for (i = 0; i < ip_set_max; i++) {
614 if (set != NULL && STREQ(set->name, name)) 655 set = nfnl_set(i);
615 index = i; 656 if (set != NULL && STREQ(set->name, name)) {
657 *id = i;
658 break;
659 }
616 } 660 }
617 return index; 661 return (*id == IPSET_INVALID_ID ? NULL : set);
618} 662}
619 663
620static inline struct ip_set * 664static inline struct ip_set *
621find_set(const char *name) 665find_set(const char *name)
622{ 666{
623 ip_set_id_t index = find_set_id(name); 667 ip_set_id_t id;
624 668
625 return index == IPSET_INVALID_ID ? NULL : ip_set_list[index]; 669 return find_set_and_id(name, &id);
626} 670}
627 671
628static int 672static int
629find_free_id(const char *name, ip_set_id_t *index, struct ip_set **set) 673find_free_id(const char *name, ip_set_id_t *index, struct ip_set **set)
630{ 674{
675 struct ip_set *s;
631 ip_set_id_t i; 676 ip_set_id_t i;
632 677
633 *index = IPSET_INVALID_ID; 678 *index = IPSET_INVALID_ID;
634 for (i = 0; i < ip_set_max; i++) { 679 for (i = 0; i < ip_set_max; i++) {
635 if (ip_set_list[i] == NULL) { 680 s = nfnl_set(i);
681 if (s == NULL) {
636 if (*index == IPSET_INVALID_ID) 682 if (*index == IPSET_INVALID_ID)
637 *index = i; 683 *index = i;
638 } else if (STREQ(name, ip_set_list[i]->name)) { 684 } else if (STREQ(name, s->name)) {
639 /* Name clash */ 685 /* Name clash */
640 *set = ip_set_list[i]; 686 *set = s;
641 return -EEXIST; 687 return -EEXIST;
642 } 688 }
643 } 689 }
@@ -730,10 +776,9 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
730 * and check clashing. 776 * and check clashing.
731 */ 777 */
732 ret = find_free_id(set->name, &index, &clash); 778 ret = find_free_id(set->name, &index, &clash);
733 if (ret != 0) { 779 if (ret == -EEXIST) {
734 /* If this is the same set and requested, ignore error */ 780 /* If this is the same set and requested, ignore error */
735 if (ret == -EEXIST && 781 if ((flags & IPSET_FLAG_EXIST) &&
736 (flags & IPSET_FLAG_EXIST) &&
737 STREQ(set->type->name, clash->type->name) && 782 STREQ(set->type->name, clash->type->name) &&
738 set->type->family == clash->type->family && 783 set->type->family == clash->type->family &&
739 set->type->revision_min == clash->type->revision_min && 784 set->type->revision_min == clash->type->revision_min &&
@@ -741,13 +786,36 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
741 set->variant->same_set(set, clash)) 786 set->variant->same_set(set, clash))
742 ret = 0; 787 ret = 0;
743 goto cleanup; 788 goto cleanup;
744 } 789 } else if (ret == -IPSET_ERR_MAX_SETS) {
790 struct ip_set **list, **tmp;
791 ip_set_id_t i = ip_set_max + IP_SET_INC;
792
793 if (i < ip_set_max || i == IPSET_INVALID_ID)
794 /* Wraparound */
795 goto cleanup;
796
797 list = kzalloc(sizeof(struct ip_set *) * i, GFP_KERNEL);
798 if (!list)
799 goto cleanup;
800 /* nfnl mutex is held, both lists are valid */
801 tmp = nfnl_dereference(ip_set_list);
802 memcpy(list, tmp, sizeof(struct ip_set *) * ip_set_max);
803 rcu_assign_pointer(ip_set_list, list);
804 /* Make sure all current packets have passed through */
805 synchronize_net();
806 /* Use new list */
807 index = ip_set_max;
808 ip_set_max = i;
809 kfree(tmp);
810 ret = 0;
811 } else if (ret)
812 goto cleanup;
745 813
746 /* 814 /*
747 * Finally! Add our shiny new set to the list, and be done. 815 * Finally! Add our shiny new set to the list, and be done.
748 */ 816 */
749 pr_debug("create: '%s' created with index %u!\n", set->name, index); 817 pr_debug("create: '%s' created with index %u!\n", set->name, index);
750 ip_set_list[index] = set; 818 nfnl_set(index) = set;
751 819
752 return ret; 820 return ret;
753 821
@@ -772,10 +840,10 @@ ip_set_setname_policy[IPSET_ATTR_CMD_MAX + 1] = {
772static void 840static void
773ip_set_destroy_set(ip_set_id_t index) 841ip_set_destroy_set(ip_set_id_t index)
774{ 842{
775 struct ip_set *set = ip_set_list[index]; 843 struct ip_set *set = nfnl_set(index);
776 844
777 pr_debug("set: %s\n", set->name); 845 pr_debug("set: %s\n", set->name);
778 ip_set_list[index] = NULL; 846 nfnl_set(index) = NULL;
779 847
780 /* Must call it without holding any lock */ 848 /* Must call it without holding any lock */
781 set->variant->destroy(set); 849 set->variant->destroy(set);
@@ -788,6 +856,7 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
788 const struct nlmsghdr *nlh, 856 const struct nlmsghdr *nlh,
789 const struct nlattr * const attr[]) 857 const struct nlattr * const attr[])
790{ 858{
859 struct ip_set *s;
791 ip_set_id_t i; 860 ip_set_id_t i;
792 int ret = 0; 861 int ret = 0;
793 862
@@ -807,22 +876,24 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
807 read_lock_bh(&ip_set_ref_lock); 876 read_lock_bh(&ip_set_ref_lock);
808 if (!attr[IPSET_ATTR_SETNAME]) { 877 if (!attr[IPSET_ATTR_SETNAME]) {
809 for (i = 0; i < ip_set_max; i++) { 878 for (i = 0; i < ip_set_max; i++) {
810 if (ip_set_list[i] != NULL && ip_set_list[i]->ref) { 879 s = nfnl_set(i);
880 if (s != NULL && s->ref) {
811 ret = -IPSET_ERR_BUSY; 881 ret = -IPSET_ERR_BUSY;
812 goto out; 882 goto out;
813 } 883 }
814 } 884 }
815 read_unlock_bh(&ip_set_ref_lock); 885 read_unlock_bh(&ip_set_ref_lock);
816 for (i = 0; i < ip_set_max; i++) { 886 for (i = 0; i < ip_set_max; i++) {
817 if (ip_set_list[i] != NULL) 887 s = nfnl_set(i);
888 if (s != NULL)
818 ip_set_destroy_set(i); 889 ip_set_destroy_set(i);
819 } 890 }
820 } else { 891 } else {
821 i = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); 892 s = find_set_and_id(nla_data(attr[IPSET_ATTR_SETNAME]), &i);
822 if (i == IPSET_INVALID_ID) { 893 if (s == NULL) {
823 ret = -ENOENT; 894 ret = -ENOENT;
824 goto out; 895 goto out;
825 } else if (ip_set_list[i]->ref) { 896 } else if (s->ref) {
826 ret = -IPSET_ERR_BUSY; 897 ret = -IPSET_ERR_BUSY;
827 goto out; 898 goto out;
828 } 899 }
@@ -853,21 +924,24 @@ ip_set_flush(struct sock *ctnl, struct sk_buff *skb,
853 const struct nlmsghdr *nlh, 924 const struct nlmsghdr *nlh,
854 const struct nlattr * const attr[]) 925 const struct nlattr * const attr[])
855{ 926{
927 struct ip_set *s;
856 ip_set_id_t i; 928 ip_set_id_t i;
857 929
858 if (unlikely(protocol_failed(attr))) 930 if (unlikely(protocol_failed(attr)))
859 return -IPSET_ERR_PROTOCOL; 931 return -IPSET_ERR_PROTOCOL;
860 932
861 if (!attr[IPSET_ATTR_SETNAME]) { 933 if (!attr[IPSET_ATTR_SETNAME]) {
862 for (i = 0; i < ip_set_max; i++) 934 for (i = 0; i < ip_set_max; i++) {
863 if (ip_set_list[i] != NULL) 935 s = nfnl_set(i);
864 ip_set_flush_set(ip_set_list[i]); 936 if (s != NULL)
937 ip_set_flush_set(s);
938 }
865 } else { 939 } else {
866 i = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); 940 s = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
867 if (i == IPSET_INVALID_ID) 941 if (s == NULL)
868 return -ENOENT; 942 return -ENOENT;
869 943
870 ip_set_flush_set(ip_set_list[i]); 944 ip_set_flush_set(s);
871 } 945 }
872 946
873 return 0; 947 return 0;
@@ -889,7 +963,7 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb,
889 const struct nlmsghdr *nlh, 963 const struct nlmsghdr *nlh,
890 const struct nlattr * const attr[]) 964 const struct nlattr * const attr[])
891{ 965{
892 struct ip_set *set; 966 struct ip_set *set, *s;
893 const char *name2; 967 const char *name2;
894 ip_set_id_t i; 968 ip_set_id_t i;
895 int ret = 0; 969 int ret = 0;
@@ -911,8 +985,8 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb,
911 985
912 name2 = nla_data(attr[IPSET_ATTR_SETNAME2]); 986 name2 = nla_data(attr[IPSET_ATTR_SETNAME2]);
913 for (i = 0; i < ip_set_max; i++) { 987 for (i = 0; i < ip_set_max; i++) {
914 if (ip_set_list[i] != NULL && 988 s = nfnl_set(i);
915 STREQ(ip_set_list[i]->name, name2)) { 989 if (s != NULL && STREQ(s->name, name2)) {
916 ret = -IPSET_ERR_EXIST_SETNAME2; 990 ret = -IPSET_ERR_EXIST_SETNAME2;
917 goto out; 991 goto out;
918 } 992 }
@@ -947,17 +1021,14 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
947 attr[IPSET_ATTR_SETNAME2] == NULL)) 1021 attr[IPSET_ATTR_SETNAME2] == NULL))
948 return -IPSET_ERR_PROTOCOL; 1022 return -IPSET_ERR_PROTOCOL;
949 1023
950 from_id = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); 1024 from = find_set_and_id(nla_data(attr[IPSET_ATTR_SETNAME]), &from_id);
951 if (from_id == IPSET_INVALID_ID) 1025 if (from == NULL)
952 return -ENOENT; 1026 return -ENOENT;
953 1027
954 to_id = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME2])); 1028 to = find_set_and_id(nla_data(attr[IPSET_ATTR_SETNAME2]), &to_id);
955 if (to_id == IPSET_INVALID_ID) 1029 if (to == NULL)
956 return -IPSET_ERR_EXIST_SETNAME2; 1030 return -IPSET_ERR_EXIST_SETNAME2;
957 1031
958 from = ip_set_list[from_id];
959 to = ip_set_list[to_id];
960
961 /* Features must not change. 1032 /* Features must not change.
962 * Not an artificial restriction anymore, as we must prevent 1033 * Not an artificial restriction anymore, as we must prevent
963 * possible loops created by swapping in setlist type of sets. */ 1034 * possible loops created by swapping in setlist type of sets. */
@@ -971,8 +1042,8 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
971 1042
972 write_lock_bh(&ip_set_ref_lock); 1043 write_lock_bh(&ip_set_ref_lock);
973 swap(from->ref, to->ref); 1044 swap(from->ref, to->ref);
974 ip_set_list[from_id] = to; 1045 nfnl_set(from_id) = to;
975 ip_set_list[to_id] = from; 1046 nfnl_set(to_id) = from;
976 write_unlock_bh(&ip_set_ref_lock); 1047 write_unlock_bh(&ip_set_ref_lock);
977 1048
978 return 0; 1049 return 0;
@@ -992,7 +1063,7 @@ static int
992ip_set_dump_done(struct netlink_callback *cb) 1063ip_set_dump_done(struct netlink_callback *cb)
993{ 1064{
994 if (cb->args[2]) { 1065 if (cb->args[2]) {
995 pr_debug("release set %s\n", ip_set_list[cb->args[1]]->name); 1066 pr_debug("release set %s\n", nfnl_set(cb->args[1])->name);
996 ip_set_put_byindex((ip_set_id_t) cb->args[1]); 1067 ip_set_put_byindex((ip_set_id_t) cb->args[1]);
997 } 1068 }
998 return 0; 1069 return 0;
@@ -1030,8 +1101,11 @@ dump_init(struct netlink_callback *cb)
1030 */ 1101 */
1031 1102
1032 if (cda[IPSET_ATTR_SETNAME]) { 1103 if (cda[IPSET_ATTR_SETNAME]) {
1033 index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME])); 1104 struct ip_set *set;
1034 if (index == IPSET_INVALID_ID) 1105
1106 set = find_set_and_id(nla_data(cda[IPSET_ATTR_SETNAME]),
1107 &index);
1108 if (set == NULL)
1035 return -ENOENT; 1109 return -ENOENT;
1036 1110
1037 dump_type = DUMP_ONE; 1111 dump_type = DUMP_ONE;
@@ -1081,7 +1155,7 @@ dump_last:
1081 dump_type, dump_flags, cb->args[1]); 1155 dump_type, dump_flags, cb->args[1]);
1082 for (; cb->args[1] < max; cb->args[1]++) { 1156 for (; cb->args[1] < max; cb->args[1]++) {
1083 index = (ip_set_id_t) cb->args[1]; 1157 index = (ip_set_id_t) cb->args[1];
1084 set = ip_set_list[index]; 1158 set = nfnl_set(index);
1085 if (set == NULL) { 1159 if (set == NULL) {
1086 if (dump_type == DUMP_ONE) { 1160 if (dump_type == DUMP_ONE) {
1087 ret = -ENOENT; 1161 ret = -ENOENT;
@@ -1100,7 +1174,7 @@ dump_last:
1100 if (!cb->args[2]) { 1174 if (!cb->args[2]) {
1101 /* Start listing: make sure set won't be destroyed */ 1175 /* Start listing: make sure set won't be destroyed */
1102 pr_debug("reference set\n"); 1176 pr_debug("reference set\n");
1103 __ip_set_get(index); 1177 __ip_set_get(set);
1104 } 1178 }
1105 nlh = start_msg(skb, NETLINK_CB(cb->skb).portid, 1179 nlh = start_msg(skb, NETLINK_CB(cb->skb).portid,
1106 cb->nlh->nlmsg_seq, flags, 1180 cb->nlh->nlmsg_seq, flags,
@@ -1159,7 +1233,7 @@ next_set:
1159release_refcount: 1233release_refcount:
1160 /* If there was an error or set is done, release set */ 1234 /* If there was an error or set is done, release set */
1161 if (ret || !cb->args[2]) { 1235 if (ret || !cb->args[2]) {
1162 pr_debug("release set %s\n", ip_set_list[index]->name); 1236 pr_debug("release set %s\n", nfnl_set(index)->name);
1163 ip_set_put_byindex(index); 1237 ip_set_put_byindex(index);
1164 cb->args[2] = 0; 1238 cb->args[2] = 0;
1165 } 1239 }
@@ -1409,17 +1483,15 @@ ip_set_header(struct sock *ctnl, struct sk_buff *skb,
1409 const struct ip_set *set; 1483 const struct ip_set *set;
1410 struct sk_buff *skb2; 1484 struct sk_buff *skb2;
1411 struct nlmsghdr *nlh2; 1485 struct nlmsghdr *nlh2;
1412 ip_set_id_t index;
1413 int ret = 0; 1486 int ret = 0;
1414 1487
1415 if (unlikely(protocol_failed(attr) || 1488 if (unlikely(protocol_failed(attr) ||
1416 attr[IPSET_ATTR_SETNAME] == NULL)) 1489 attr[IPSET_ATTR_SETNAME] == NULL))
1417 return -IPSET_ERR_PROTOCOL; 1490 return -IPSET_ERR_PROTOCOL;
1418 1491
1419 index = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); 1492 set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
1420 if (index == IPSET_INVALID_ID) 1493 if (set == NULL)
1421 return -ENOENT; 1494 return -ENOENT;
1422 set = ip_set_list[index];
1423 1495
1424 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 1496 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1425 if (skb2 == NULL) 1497 if (skb2 == NULL)
@@ -1684,6 +1756,7 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
1684 } 1756 }
1685 case IP_SET_OP_GET_BYNAME: { 1757 case IP_SET_OP_GET_BYNAME: {
1686 struct ip_set_req_get_set *req_get = data; 1758 struct ip_set_req_get_set *req_get = data;
1759 ip_set_id_t id;
1687 1760
1688 if (*len != sizeof(struct ip_set_req_get_set)) { 1761 if (*len != sizeof(struct ip_set_req_get_set)) {
1689 ret = -EINVAL; 1762 ret = -EINVAL;
@@ -1691,12 +1764,14 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
1691 } 1764 }
1692 req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0'; 1765 req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0';
1693 nfnl_lock(); 1766 nfnl_lock();
1694 req_get->set.index = find_set_id(req_get->set.name); 1767 find_set_and_id(req_get->set.name, &id);
1768 req_get->set.index = id;
1695 nfnl_unlock(); 1769 nfnl_unlock();
1696 goto copy; 1770 goto copy;
1697 } 1771 }
1698 case IP_SET_OP_GET_BYINDEX: { 1772 case IP_SET_OP_GET_BYINDEX: {
1699 struct ip_set_req_get_set *req_get = data; 1773 struct ip_set_req_get_set *req_get = data;
1774 struct ip_set *set;
1700 1775
1701 if (*len != sizeof(struct ip_set_req_get_set) || 1776 if (*len != sizeof(struct ip_set_req_get_set) ||
1702 req_get->set.index >= ip_set_max) { 1777 req_get->set.index >= ip_set_max) {
@@ -1704,9 +1779,8 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
1704 goto done; 1779 goto done;
1705 } 1780 }
1706 nfnl_lock(); 1781 nfnl_lock();
1707 strncpy(req_get->set.name, 1782 set = nfnl_set(req_get->set.index);
1708 ip_set_list[req_get->set.index] 1783 strncpy(req_get->set.name, set ? set->name : "",
1709 ? ip_set_list[req_get->set.index]->name : "",
1710 IPSET_MAXNAMELEN); 1784 IPSET_MAXNAMELEN);
1711 nfnl_unlock(); 1785 nfnl_unlock();
1712 goto copy; 1786 goto copy;
@@ -1737,6 +1811,7 @@ static struct nf_sockopt_ops so_set __read_mostly = {
1737static int __init 1811static int __init
1738ip_set_init(void) 1812ip_set_init(void)
1739{ 1813{
1814 struct ip_set **list;
1740 int ret; 1815 int ret;
1741 1816
1742 if (max_sets) 1817 if (max_sets)
@@ -1744,22 +1819,22 @@ ip_set_init(void)
1744 if (ip_set_max >= IPSET_INVALID_ID) 1819 if (ip_set_max >= IPSET_INVALID_ID)
1745 ip_set_max = IPSET_INVALID_ID - 1; 1820 ip_set_max = IPSET_INVALID_ID - 1;
1746 1821
1747 ip_set_list = kzalloc(sizeof(struct ip_set *) * ip_set_max, 1822 list = kzalloc(sizeof(struct ip_set *) * ip_set_max, GFP_KERNEL);
1748 GFP_KERNEL); 1823 if (!list)
1749 if (!ip_set_list)
1750 return -ENOMEM; 1824 return -ENOMEM;
1751 1825
1826 rcu_assign_pointer(ip_set_list, list);
1752 ret = nfnetlink_subsys_register(&ip_set_netlink_subsys); 1827 ret = nfnetlink_subsys_register(&ip_set_netlink_subsys);
1753 if (ret != 0) { 1828 if (ret != 0) {
1754 pr_err("ip_set: cannot register with nfnetlink.\n"); 1829 pr_err("ip_set: cannot register with nfnetlink.\n");
1755 kfree(ip_set_list); 1830 kfree(list);
1756 return ret; 1831 return ret;
1757 } 1832 }
1758 ret = nf_register_sockopt(&so_set); 1833 ret = nf_register_sockopt(&so_set);
1759 if (ret != 0) { 1834 if (ret != 0) {
1760 pr_err("SO_SET registry failed: %d\n", ret); 1835 pr_err("SO_SET registry failed: %d\n", ret);
1761 nfnetlink_subsys_unregister(&ip_set_netlink_subsys); 1836 nfnetlink_subsys_unregister(&ip_set_netlink_subsys);
1762 kfree(ip_set_list); 1837 kfree(list);
1763 return ret; 1838 return ret;
1764 } 1839 }
1765 1840
@@ -1770,10 +1845,12 @@ ip_set_init(void)
1770static void __exit 1845static void __exit
1771ip_set_fini(void) 1846ip_set_fini(void)
1772{ 1847{
1848 struct ip_set **list = rcu_dereference_protected(ip_set_list, 1);
1849
1773 /* There can't be any existing set */ 1850 /* There can't be any existing set */
1774 nf_unregister_sockopt(&so_set); 1851 nf_unregister_sockopt(&so_set);
1775 nfnetlink_subsys_unregister(&ip_set_netlink_subsys); 1852 nfnetlink_subsys_unregister(&ip_set_netlink_subsys);
1776 kfree(ip_set_list); 1853 kfree(list);
1777 pr_debug("these are the famous last words\n"); 1854 pr_debug("these are the famous last words\n");
1778} 1855}
1779 1856