diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/nfnetlink_log.c | 177 |
1 files changed, 117 insertions, 60 deletions
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index b593fd1f8cab..8e7bf641e096 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <net/sock.h> | 33 | #include <net/sock.h> |
34 | #include <net/netfilter/nf_log.h> | 34 | #include <net/netfilter/nf_log.h> |
35 | #include <net/netns/generic.h> | ||
35 | #include <net/netfilter/nfnetlink_log.h> | 36 | #include <net/netfilter/nfnetlink_log.h> |
36 | 37 | ||
37 | #include <linux/atomic.h> | 38 | #include <linux/atomic.h> |
@@ -56,6 +57,7 @@ struct nfulnl_instance { | |||
56 | unsigned int qlen; /* number of nlmsgs in skb */ | 57 | unsigned int qlen; /* number of nlmsgs in skb */ |
57 | struct sk_buff *skb; /* pre-allocatd skb */ | 58 | struct sk_buff *skb; /* pre-allocatd skb */ |
58 | struct timer_list timer; | 59 | struct timer_list timer; |
60 | struct net *net; | ||
59 | struct user_namespace *peer_user_ns; /* User namespace of the peer process */ | 61 | struct user_namespace *peer_user_ns; /* User namespace of the peer process */ |
60 | int peer_portid; /* PORTID of the peer process */ | 62 | int peer_portid; /* PORTID of the peer process */ |
61 | 63 | ||
@@ -71,25 +73,34 @@ struct nfulnl_instance { | |||
71 | struct rcu_head rcu; | 73 | struct rcu_head rcu; |
72 | }; | 74 | }; |
73 | 75 | ||
74 | static DEFINE_SPINLOCK(instances_lock); | ||
75 | static atomic_t global_seq; | ||
76 | |||
77 | #define INSTANCE_BUCKETS 16 | 76 | #define INSTANCE_BUCKETS 16 |
78 | static struct hlist_head instance_table[INSTANCE_BUCKETS]; | ||
79 | static unsigned int hash_init; | 77 | static unsigned int hash_init; |
80 | 78 | ||
79 | static int nfnl_log_net_id __read_mostly; | ||
80 | |||
81 | struct nfnl_log_net { | ||
82 | spinlock_t instances_lock; | ||
83 | struct hlist_head instance_table[INSTANCE_BUCKETS]; | ||
84 | atomic_t global_seq; | ||
85 | }; | ||
86 | |||
87 | static struct nfnl_log_net *nfnl_log_pernet(struct net *net) | ||
88 | { | ||
89 | return net_generic(net, nfnl_log_net_id); | ||
90 | } | ||
91 | |||
81 | static inline u_int8_t instance_hashfn(u_int16_t group_num) | 92 | static inline u_int8_t instance_hashfn(u_int16_t group_num) |
82 | { | 93 | { |
83 | return ((group_num & 0xff) % INSTANCE_BUCKETS); | 94 | return ((group_num & 0xff) % INSTANCE_BUCKETS); |
84 | } | 95 | } |
85 | 96 | ||
86 | static struct nfulnl_instance * | 97 | static struct nfulnl_instance * |
87 | __instance_lookup(u_int16_t group_num) | 98 | __instance_lookup(struct nfnl_log_net *log, u_int16_t group_num) |
88 | { | 99 | { |
89 | struct hlist_head *head; | 100 | struct hlist_head *head; |
90 | struct nfulnl_instance *inst; | 101 | struct nfulnl_instance *inst; |
91 | 102 | ||
92 | head = &instance_table[instance_hashfn(group_num)]; | 103 | head = &log->instance_table[instance_hashfn(group_num)]; |
93 | hlist_for_each_entry_rcu(inst, head, hlist) { | 104 | hlist_for_each_entry_rcu(inst, head, hlist) { |
94 | if (inst->group_num == group_num) | 105 | if (inst->group_num == group_num) |
95 | return inst; | 106 | return inst; |
@@ -104,12 +115,12 @@ instance_get(struct nfulnl_instance *inst) | |||
104 | } | 115 | } |
105 | 116 | ||
106 | static struct nfulnl_instance * | 117 | static struct nfulnl_instance * |
107 | instance_lookup_get(u_int16_t group_num) | 118 | instance_lookup_get(struct nfnl_log_net *log, u_int16_t group_num) |
108 | { | 119 | { |
109 | struct nfulnl_instance *inst; | 120 | struct nfulnl_instance *inst; |
110 | 121 | ||
111 | rcu_read_lock_bh(); | 122 | rcu_read_lock_bh(); |
112 | inst = __instance_lookup(group_num); | 123 | inst = __instance_lookup(log, group_num); |
113 | if (inst && !atomic_inc_not_zero(&inst->use)) | 124 | if (inst && !atomic_inc_not_zero(&inst->use)) |
114 | inst = NULL; | 125 | inst = NULL; |
115 | rcu_read_unlock_bh(); | 126 | rcu_read_unlock_bh(); |
@@ -119,7 +130,11 @@ instance_lookup_get(u_int16_t group_num) | |||
119 | 130 | ||
120 | static void nfulnl_instance_free_rcu(struct rcu_head *head) | 131 | static void nfulnl_instance_free_rcu(struct rcu_head *head) |
121 | { | 132 | { |
122 | kfree(container_of(head, struct nfulnl_instance, rcu)); | 133 | struct nfulnl_instance *inst = |
134 | container_of(head, struct nfulnl_instance, rcu); | ||
135 | |||
136 | put_net(inst->net); | ||
137 | kfree(inst); | ||
123 | module_put(THIS_MODULE); | 138 | module_put(THIS_MODULE); |
124 | } | 139 | } |
125 | 140 | ||
@@ -133,13 +148,15 @@ instance_put(struct nfulnl_instance *inst) | |||
133 | static void nfulnl_timer(unsigned long data); | 148 | static void nfulnl_timer(unsigned long data); |
134 | 149 | ||
135 | static struct nfulnl_instance * | 150 | static struct nfulnl_instance * |
136 | instance_create(u_int16_t group_num, int portid, struct user_namespace *user_ns) | 151 | instance_create(struct net *net, u_int16_t group_num, |
152 | int portid, struct user_namespace *user_ns) | ||
137 | { | 153 | { |
138 | struct nfulnl_instance *inst; | 154 | struct nfulnl_instance *inst; |
155 | struct nfnl_log_net *log = nfnl_log_pernet(net); | ||
139 | int err; | 156 | int err; |
140 | 157 | ||
141 | spin_lock_bh(&instances_lock); | 158 | spin_lock_bh(&log->instances_lock); |
142 | if (__instance_lookup(group_num)) { | 159 | if (__instance_lookup(log, group_num)) { |
143 | err = -EEXIST; | 160 | err = -EEXIST; |
144 | goto out_unlock; | 161 | goto out_unlock; |
145 | } | 162 | } |
@@ -163,6 +180,7 @@ instance_create(u_int16_t group_num, int portid, struct user_namespace *user_ns) | |||
163 | 180 | ||
164 | setup_timer(&inst->timer, nfulnl_timer, (unsigned long)inst); | 181 | setup_timer(&inst->timer, nfulnl_timer, (unsigned long)inst); |
165 | 182 | ||
183 | inst->net = get_net(net); | ||
166 | inst->peer_user_ns = user_ns; | 184 | inst->peer_user_ns = user_ns; |
167 | inst->peer_portid = portid; | 185 | inst->peer_portid = portid; |
168 | inst->group_num = group_num; | 186 | inst->group_num = group_num; |
@@ -174,14 +192,15 @@ instance_create(u_int16_t group_num, int portid, struct user_namespace *user_ns) | |||
174 | inst->copy_range = NFULNL_COPY_RANGE_MAX; | 192 | inst->copy_range = NFULNL_COPY_RANGE_MAX; |
175 | 193 | ||
176 | hlist_add_head_rcu(&inst->hlist, | 194 | hlist_add_head_rcu(&inst->hlist, |
177 | &instance_table[instance_hashfn(group_num)]); | 195 | &log->instance_table[instance_hashfn(group_num)]); |
196 | |||
178 | 197 | ||
179 | spin_unlock_bh(&instances_lock); | 198 | spin_unlock_bh(&log->instances_lock); |
180 | 199 | ||
181 | return inst; | 200 | return inst; |
182 | 201 | ||
183 | out_unlock: | 202 | out_unlock: |
184 | spin_unlock_bh(&instances_lock); | 203 | spin_unlock_bh(&log->instances_lock); |
185 | return ERR_PTR(err); | 204 | return ERR_PTR(err); |
186 | } | 205 | } |
187 | 206 | ||
@@ -210,11 +229,12 @@ __instance_destroy(struct nfulnl_instance *inst) | |||
210 | } | 229 | } |
211 | 230 | ||
212 | static inline void | 231 | static inline void |
213 | instance_destroy(struct nfulnl_instance *inst) | 232 | instance_destroy(struct nfnl_log_net *log, |
233 | struct nfulnl_instance *inst) | ||
214 | { | 234 | { |
215 | spin_lock_bh(&instances_lock); | 235 | spin_lock_bh(&log->instances_lock); |
216 | __instance_destroy(inst); | 236 | __instance_destroy(inst); |
217 | spin_unlock_bh(&instances_lock); | 237 | spin_unlock_bh(&log->instances_lock); |
218 | } | 238 | } |
219 | 239 | ||
220 | static int | 240 | static int |
@@ -336,7 +356,7 @@ __nfulnl_send(struct nfulnl_instance *inst) | |||
336 | if (!nlh) | 356 | if (!nlh) |
337 | goto out; | 357 | goto out; |
338 | } | 358 | } |
339 | status = nfnetlink_unicast(inst->skb, &init_net, inst->peer_portid, | 359 | status = nfnetlink_unicast(inst->skb, inst->net, inst->peer_portid, |
340 | MSG_DONTWAIT); | 360 | MSG_DONTWAIT); |
341 | 361 | ||
342 | inst->qlen = 0; | 362 | inst->qlen = 0; |
@@ -370,7 +390,8 @@ nfulnl_timer(unsigned long data) | |||
370 | /* This is an inline function, we don't really care about a long | 390 | /* This is an inline function, we don't really care about a long |
371 | * list of arguments */ | 391 | * list of arguments */ |
372 | static inline int | 392 | static inline int |
373 | __build_packet_message(struct nfulnl_instance *inst, | 393 | __build_packet_message(struct nfnl_log_net *log, |
394 | struct nfulnl_instance *inst, | ||
374 | const struct sk_buff *skb, | 395 | const struct sk_buff *skb, |
375 | unsigned int data_len, | 396 | unsigned int data_len, |
376 | u_int8_t pf, | 397 | u_int8_t pf, |
@@ -536,7 +557,7 @@ __build_packet_message(struct nfulnl_instance *inst, | |||
536 | /* global sequence number */ | 557 | /* global sequence number */ |
537 | if ((inst->flags & NFULNL_CFG_F_SEQ_GLOBAL) && | 558 | if ((inst->flags & NFULNL_CFG_F_SEQ_GLOBAL) && |
538 | nla_put_be32(inst->skb, NFULA_SEQ_GLOBAL, | 559 | nla_put_be32(inst->skb, NFULA_SEQ_GLOBAL, |
539 | htonl(atomic_inc_return(&global_seq)))) | 560 | htonl(atomic_inc_return(&log->global_seq)))) |
540 | goto nla_put_failure; | 561 | goto nla_put_failure; |
541 | 562 | ||
542 | if (data_len) { | 563 | if (data_len) { |
@@ -592,13 +613,15 @@ nfulnl_log_packet(u_int8_t pf, | |||
592 | const struct nf_loginfo *li; | 613 | const struct nf_loginfo *li; |
593 | unsigned int qthreshold; | 614 | unsigned int qthreshold; |
594 | unsigned int plen; | 615 | unsigned int plen; |
616 | struct net *net = dev_net(in ? in : out); | ||
617 | struct nfnl_log_net *log = nfnl_log_pernet(net); | ||
595 | 618 | ||
596 | if (li_user && li_user->type == NF_LOG_TYPE_ULOG) | 619 | if (li_user && li_user->type == NF_LOG_TYPE_ULOG) |
597 | li = li_user; | 620 | li = li_user; |
598 | else | 621 | else |
599 | li = &default_loginfo; | 622 | li = &default_loginfo; |
600 | 623 | ||
601 | inst = instance_lookup_get(li->u.ulog.group); | 624 | inst = instance_lookup_get(log, li->u.ulog.group); |
602 | if (!inst) | 625 | if (!inst) |
603 | return; | 626 | return; |
604 | 627 | ||
@@ -680,7 +703,7 @@ nfulnl_log_packet(u_int8_t pf, | |||
680 | 703 | ||
681 | inst->qlen++; | 704 | inst->qlen++; |
682 | 705 | ||
683 | __build_packet_message(inst, skb, data_len, pf, | 706 | __build_packet_message(log, inst, skb, data_len, pf, |
684 | hooknum, in, out, prefix, plen); | 707 | hooknum, in, out, prefix, plen); |
685 | 708 | ||
686 | if (inst->qlen >= qthreshold) | 709 | if (inst->qlen >= qthreshold) |
@@ -709,24 +732,24 @@ nfulnl_rcv_nl_event(struct notifier_block *this, | |||
709 | unsigned long event, void *ptr) | 732 | unsigned long event, void *ptr) |
710 | { | 733 | { |
711 | struct netlink_notify *n = ptr; | 734 | struct netlink_notify *n = ptr; |
735 | struct nfnl_log_net *log = nfnl_log_pernet(n->net); | ||
712 | 736 | ||
713 | if (event == NETLINK_URELEASE && n->protocol == NETLINK_NETFILTER) { | 737 | if (event == NETLINK_URELEASE && n->protocol == NETLINK_NETFILTER) { |
714 | int i; | 738 | int i; |
715 | 739 | ||
716 | /* destroy all instances for this portid */ | 740 | /* destroy all instances for this portid */ |
717 | spin_lock_bh(&instances_lock); | 741 | spin_lock_bh(&log->instances_lock); |
718 | for (i = 0; i < INSTANCE_BUCKETS; i++) { | 742 | for (i = 0; i < INSTANCE_BUCKETS; i++) { |
719 | struct hlist_node *t2; | 743 | struct hlist_node *t2; |
720 | struct nfulnl_instance *inst; | 744 | struct nfulnl_instance *inst; |
721 | struct hlist_head *head = &instance_table[i]; | 745 | struct hlist_head *head = &log->instance_table[i]; |
722 | 746 | ||
723 | hlist_for_each_entry_safe(inst, t2, head, hlist) { | 747 | hlist_for_each_entry_safe(inst, t2, head, hlist) { |
724 | if ((net_eq(n->net, &init_net)) && | 748 | if (n->portid == inst->peer_portid) |
725 | (n->portid == inst->peer_portid)) | ||
726 | __instance_destroy(inst); | 749 | __instance_destroy(inst); |
727 | } | 750 | } |
728 | } | 751 | } |
729 | spin_unlock_bh(&instances_lock); | 752 | spin_unlock_bh(&log->instances_lock); |
730 | } | 753 | } |
731 | return NOTIFY_DONE; | 754 | return NOTIFY_DONE; |
732 | } | 755 | } |
@@ -768,6 +791,7 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, | |||
768 | struct nfulnl_instance *inst; | 791 | struct nfulnl_instance *inst; |
769 | struct nfulnl_msg_config_cmd *cmd = NULL; | 792 | struct nfulnl_msg_config_cmd *cmd = NULL; |
770 | struct net *net = sock_net(ctnl); | 793 | struct net *net = sock_net(ctnl); |
794 | struct nfnl_log_net *log = nfnl_log_pernet(net); | ||
771 | int ret = 0; | 795 | int ret = 0; |
772 | 796 | ||
773 | if (nfula[NFULA_CFG_CMD]) { | 797 | if (nfula[NFULA_CFG_CMD]) { |
@@ -784,7 +808,7 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, | |||
784 | } | 808 | } |
785 | } | 809 | } |
786 | 810 | ||
787 | inst = instance_lookup_get(group_num); | 811 | inst = instance_lookup_get(log, group_num); |
788 | if (inst && inst->peer_portid != NETLINK_CB(skb).portid) { | 812 | if (inst && inst->peer_portid != NETLINK_CB(skb).portid) { |
789 | ret = -EPERM; | 813 | ret = -EPERM; |
790 | goto out_put; | 814 | goto out_put; |
@@ -798,7 +822,7 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, | |||
798 | goto out_put; | 822 | goto out_put; |
799 | } | 823 | } |
800 | 824 | ||
801 | inst = instance_create(group_num, | 825 | inst = instance_create(net, group_num, |
802 | NETLINK_CB(skb).portid, | 826 | NETLINK_CB(skb).portid, |
803 | sk_user_ns(NETLINK_CB(skb).ssk)); | 827 | sk_user_ns(NETLINK_CB(skb).ssk)); |
804 | if (IS_ERR(inst)) { | 828 | if (IS_ERR(inst)) { |
@@ -812,7 +836,7 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, | |||
812 | goto out; | 836 | goto out; |
813 | } | 837 | } |
814 | 838 | ||
815 | instance_destroy(inst); | 839 | instance_destroy(log, inst); |
816 | goto out_put; | 840 | goto out_put; |
817 | default: | 841 | default: |
818 | ret = -ENOTSUPP; | 842 | ret = -ENOTSUPP; |
@@ -895,55 +919,68 @@ static const struct nfnetlink_subsystem nfulnl_subsys = { | |||
895 | 919 | ||
896 | #ifdef CONFIG_PROC_FS | 920 | #ifdef CONFIG_PROC_FS |
897 | struct iter_state { | 921 | struct iter_state { |
922 | struct seq_net_private p; | ||
898 | unsigned int bucket; | 923 | unsigned int bucket; |
899 | }; | 924 | }; |
900 | 925 | ||
901 | static struct hlist_node *get_first(struct iter_state *st) | 926 | static struct hlist_node *get_first(struct net *net, struct iter_state *st) |
902 | { | 927 | { |
928 | struct nfnl_log_net *log; | ||
903 | if (!st) | 929 | if (!st) |
904 | return NULL; | 930 | return NULL; |
905 | 931 | ||
932 | log = nfnl_log_pernet(net); | ||
933 | |||
906 | for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) { | 934 | for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) { |
907 | if (!hlist_empty(&instance_table[st->bucket])) | 935 | struct hlist_head *head = &log->instance_table[st->bucket]; |
908 | return rcu_dereference_bh(hlist_first_rcu(&instance_table[st->bucket])); | 936 | |
937 | if (!hlist_empty(head)) | ||
938 | return rcu_dereference_bh(hlist_first_rcu(head)); | ||
909 | } | 939 | } |
910 | return NULL; | 940 | return NULL; |
911 | } | 941 | } |
912 | 942 | ||
913 | static struct hlist_node *get_next(struct iter_state *st, struct hlist_node *h) | 943 | static struct hlist_node *get_next(struct net *net, struct iter_state *st, |
944 | struct hlist_node *h) | ||
914 | { | 945 | { |
915 | h = rcu_dereference_bh(hlist_next_rcu(h)); | 946 | h = rcu_dereference_bh(hlist_next_rcu(h)); |
916 | while (!h) { | 947 | while (!h) { |
948 | struct nfnl_log_net *log; | ||
949 | struct hlist_head *head; | ||
950 | |||
917 | if (++st->bucket >= INSTANCE_BUCKETS) | 951 | if (++st->bucket >= INSTANCE_BUCKETS) |
918 | return NULL; | 952 | return NULL; |
919 | 953 | ||
920 | h = rcu_dereference_bh(hlist_first_rcu(&instance_table[st->bucket])); | 954 | log = nfnl_log_pernet(net); |
955 | head = &log->instance_table[st->bucket]; | ||
956 | h = rcu_dereference_bh(hlist_first_rcu(head)); | ||
921 | } | 957 | } |
922 | return h; | 958 | return h; |
923 | } | 959 | } |
924 | 960 | ||
925 | static struct hlist_node *get_idx(struct iter_state *st, loff_t pos) | 961 | static struct hlist_node *get_idx(struct net *net, struct iter_state *st, |
962 | loff_t pos) | ||
926 | { | 963 | { |
927 | struct hlist_node *head; | 964 | struct hlist_node *head; |
928 | head = get_first(st); | 965 | head = get_first(net, st); |
929 | 966 | ||
930 | if (head) | 967 | if (head) |
931 | while (pos && (head = get_next(st, head))) | 968 | while (pos && (head = get_next(net, st, head))) |
932 | pos--; | 969 | pos--; |
933 | return pos ? NULL : head; | 970 | return pos ? NULL : head; |
934 | } | 971 | } |
935 | 972 | ||
936 | static void *seq_start(struct seq_file *seq, loff_t *pos) | 973 | static void *seq_start(struct seq_file *s, loff_t *pos) |
937 | __acquires(rcu_bh) | 974 | __acquires(rcu_bh) |
938 | { | 975 | { |
939 | rcu_read_lock_bh(); | 976 | rcu_read_lock_bh(); |
940 | return get_idx(seq->private, *pos); | 977 | return get_idx(seq_file_net(s), s->private, *pos); |
941 | } | 978 | } |
942 | 979 | ||
943 | static void *seq_next(struct seq_file *s, void *v, loff_t *pos) | 980 | static void *seq_next(struct seq_file *s, void *v, loff_t *pos) |
944 | { | 981 | { |
945 | (*pos)++; | 982 | (*pos)++; |
946 | return get_next(s->private, v); | 983 | return get_next(seq_file_net(s), s->private, v); |
947 | } | 984 | } |
948 | 985 | ||
949 | static void seq_stop(struct seq_file *s, void *v) | 986 | static void seq_stop(struct seq_file *s, void *v) |
@@ -972,8 +1009,8 @@ static const struct seq_operations nful_seq_ops = { | |||
972 | 1009 | ||
973 | static int nful_open(struct inode *inode, struct file *file) | 1010 | static int nful_open(struct inode *inode, struct file *file) |
974 | { | 1011 | { |
975 | return seq_open_private(file, &nful_seq_ops, | 1012 | return seq_open_net(inode, file, &nful_seq_ops, |
976 | sizeof(struct iter_state)); | 1013 | sizeof(struct iter_state)); |
977 | } | 1014 | } |
978 | 1015 | ||
979 | static const struct file_operations nful_file_ops = { | 1016 | static const struct file_operations nful_file_ops = { |
@@ -981,17 +1018,43 @@ static const struct file_operations nful_file_ops = { | |||
981 | .open = nful_open, | 1018 | .open = nful_open, |
982 | .read = seq_read, | 1019 | .read = seq_read, |
983 | .llseek = seq_lseek, | 1020 | .llseek = seq_lseek, |
984 | .release = seq_release_private, | 1021 | .release = seq_release_net, |
985 | }; | 1022 | }; |
986 | 1023 | ||
987 | #endif /* PROC_FS */ | 1024 | #endif /* PROC_FS */ |
988 | 1025 | ||
989 | static int __init nfnetlink_log_init(void) | 1026 | static int __net_init nfnl_log_net_init(struct net *net) |
990 | { | 1027 | { |
991 | int i, status = -ENOMEM; | 1028 | unsigned int i; |
1029 | struct nfnl_log_net *log = nfnl_log_pernet(net); | ||
992 | 1030 | ||
993 | for (i = 0; i < INSTANCE_BUCKETS; i++) | 1031 | for (i = 0; i < INSTANCE_BUCKETS; i++) |
994 | INIT_HLIST_HEAD(&instance_table[i]); | 1032 | INIT_HLIST_HEAD(&log->instance_table[i]); |
1033 | spin_lock_init(&log->instances_lock); | ||
1034 | |||
1035 | #ifdef CONFIG_PROC_FS | ||
1036 | if (!proc_create("nfnetlink_log", 0440, | ||
1037 | net->nf.proc_netfilter, &nful_file_ops)) | ||
1038 | return -ENOMEM; | ||
1039 | #endif | ||
1040 | return 0; | ||
1041 | } | ||
1042 | |||
1043 | static void __net_exit nfnl_log_net_exit(struct net *net) | ||
1044 | { | ||
1045 | remove_proc_entry("nfnetlink_log", net->nf.proc_netfilter); | ||
1046 | } | ||
1047 | |||
1048 | static struct pernet_operations nfnl_log_net_ops = { | ||
1049 | .init = nfnl_log_net_init, | ||
1050 | .exit = nfnl_log_net_exit, | ||
1051 | .id = &nfnl_log_net_id, | ||
1052 | .size = sizeof(struct nfnl_log_net), | ||
1053 | }; | ||
1054 | |||
1055 | static int __init nfnetlink_log_init(void) | ||
1056 | { | ||
1057 | int status = -ENOMEM; | ||
995 | 1058 | ||
996 | /* it's not really all that important to have a random value, so | 1059 | /* it's not really all that important to have a random value, so |
997 | * we can do this from the init function, even if there hasn't | 1060 | * we can do this from the init function, even if there hasn't |
@@ -1001,29 +1064,25 @@ static int __init nfnetlink_log_init(void) | |||
1001 | netlink_register_notifier(&nfulnl_rtnl_notifier); | 1064 | netlink_register_notifier(&nfulnl_rtnl_notifier); |
1002 | status = nfnetlink_subsys_register(&nfulnl_subsys); | 1065 | status = nfnetlink_subsys_register(&nfulnl_subsys); |
1003 | if (status < 0) { | 1066 | if (status < 0) { |
1004 | printk(KERN_ERR "log: failed to create netlink socket\n"); | 1067 | pr_err("log: failed to create netlink socket\n"); |
1005 | goto cleanup_netlink_notifier; | 1068 | goto cleanup_netlink_notifier; |
1006 | } | 1069 | } |
1007 | 1070 | ||
1008 | status = nf_log_register(NFPROTO_UNSPEC, &nfulnl_logger); | 1071 | status = nf_log_register(NFPROTO_UNSPEC, &nfulnl_logger); |
1009 | if (status < 0) { | 1072 | if (status < 0) { |
1010 | printk(KERN_ERR "log: failed to register logger\n"); | 1073 | pr_err("log: failed to register logger\n"); |
1011 | goto cleanup_subsys; | 1074 | goto cleanup_subsys; |
1012 | } | 1075 | } |
1013 | 1076 | ||
1014 | #ifdef CONFIG_PROC_FS | 1077 | status = register_pernet_subsys(&nfnl_log_net_ops); |
1015 | if (!proc_create("nfnetlink_log", 0440, | 1078 | if (status < 0) { |
1016 | proc_net_netfilter, &nful_file_ops)) { | 1079 | pr_err("log: failed to register pernet ops\n"); |
1017 | status = -ENOMEM; | ||
1018 | goto cleanup_logger; | 1080 | goto cleanup_logger; |
1019 | } | 1081 | } |
1020 | #endif | ||
1021 | return status; | 1082 | return status; |
1022 | 1083 | ||
1023 | #ifdef CONFIG_PROC_FS | ||
1024 | cleanup_logger: | 1084 | cleanup_logger: |
1025 | nf_log_unregister(&nfulnl_logger); | 1085 | nf_log_unregister(&nfulnl_logger); |
1026 | #endif | ||
1027 | cleanup_subsys: | 1086 | cleanup_subsys: |
1028 | nfnetlink_subsys_unregister(&nfulnl_subsys); | 1087 | nfnetlink_subsys_unregister(&nfulnl_subsys); |
1029 | cleanup_netlink_notifier: | 1088 | cleanup_netlink_notifier: |
@@ -1033,10 +1092,8 @@ cleanup_netlink_notifier: | |||
1033 | 1092 | ||
1034 | static void __exit nfnetlink_log_fini(void) | 1093 | static void __exit nfnetlink_log_fini(void) |
1035 | { | 1094 | { |
1095 | unregister_pernet_subsys(&nfnl_log_net_ops); | ||
1036 | nf_log_unregister(&nfulnl_logger); | 1096 | nf_log_unregister(&nfulnl_logger); |
1037 | #ifdef CONFIG_PROC_FS | ||
1038 | remove_proc_entry("nfnetlink_log", proc_net_netfilter); | ||
1039 | #endif | ||
1040 | nfnetlink_subsys_unregister(&nfulnl_subsys); | 1097 | nfnetlink_subsys_unregister(&nfulnl_subsys); |
1041 | netlink_unregister_notifier(&nfulnl_rtnl_notifier); | 1098 | netlink_unregister_notifier(&nfulnl_rtnl_notifier); |
1042 | } | 1099 | } |