diff options
author | Alexey Dobriyan <adobriyan@gmail.com> | 2008-10-08 05:35:10 -0400 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2008-10-08 05:35:10 -0400 |
commit | 3bb0d1c00f86b13bb184193a8f0189ddd6f0459f (patch) | |
tree | 8568fd96a42abf8d64eb83c8afcb1adcdc4bd394 /net | |
parent | 84541cc13a3bb31a58c096dde3517461e3ad91c2 (diff) |
netfilter: netns nf_conntrack: GRE conntracking in netns
* make keymap list per-netns
* per-netns keymal lock (not strictly necessary)
* flush keymap at netns stop and module unload.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/nf_conntrack_pptp.c | 2 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto_gre.c | 97 |
2 files changed, 75 insertions, 24 deletions
diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c index 5db7df5d19b7..e47d5de41cc2 100644 --- a/net/netfilter/nf_conntrack_pptp.c +++ b/net/netfilter/nf_conntrack_pptp.c | |||
@@ -602,7 +602,7 @@ static int __init nf_conntrack_pptp_init(void) | |||
602 | static void __exit nf_conntrack_pptp_fini(void) | 602 | static void __exit nf_conntrack_pptp_fini(void) |
603 | { | 603 | { |
604 | nf_conntrack_helper_unregister(&pptp); | 604 | nf_conntrack_helper_unregister(&pptp); |
605 | nf_ct_gre_keymap_flush(); | 605 | nf_ct_gre_keymap_flush(&init_net); |
606 | } | 606 | } |
607 | 607 | ||
608 | module_init(nf_conntrack_pptp_init); | 608 | module_init(nf_conntrack_pptp_init); |
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index 5b1273a01fe3..a2cdbcbf64c4 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c | |||
@@ -29,8 +29,11 @@ | |||
29 | #include <linux/list.h> | 29 | #include <linux/list.h> |
30 | #include <linux/seq_file.h> | 30 | #include <linux/seq_file.h> |
31 | #include <linux/in.h> | 31 | #include <linux/in.h> |
32 | #include <linux/netdevice.h> | ||
32 | #include <linux/skbuff.h> | 33 | #include <linux/skbuff.h> |
33 | 34 | #include <net/dst.h> | |
35 | #include <net/net_namespace.h> | ||
36 | #include <net/netns/generic.h> | ||
34 | #include <net/netfilter/nf_conntrack_l4proto.h> | 37 | #include <net/netfilter/nf_conntrack_l4proto.h> |
35 | #include <net/netfilter/nf_conntrack_helper.h> | 38 | #include <net/netfilter/nf_conntrack_helper.h> |
36 | #include <net/netfilter/nf_conntrack_core.h> | 39 | #include <net/netfilter/nf_conntrack_core.h> |
@@ -40,19 +43,23 @@ | |||
40 | #define GRE_TIMEOUT (30 * HZ) | 43 | #define GRE_TIMEOUT (30 * HZ) |
41 | #define GRE_STREAM_TIMEOUT (180 * HZ) | 44 | #define GRE_STREAM_TIMEOUT (180 * HZ) |
42 | 45 | ||
43 | static DEFINE_RWLOCK(nf_ct_gre_lock); | 46 | static int proto_gre_net_id; |
44 | static LIST_HEAD(gre_keymap_list); | 47 | struct netns_proto_gre { |
48 | rwlock_t keymap_lock; | ||
49 | struct list_head keymap_list; | ||
50 | }; | ||
45 | 51 | ||
46 | void nf_ct_gre_keymap_flush(void) | 52 | void nf_ct_gre_keymap_flush(struct net *net) |
47 | { | 53 | { |
54 | struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id); | ||
48 | struct nf_ct_gre_keymap *km, *tmp; | 55 | struct nf_ct_gre_keymap *km, *tmp; |
49 | 56 | ||
50 | write_lock_bh(&nf_ct_gre_lock); | 57 | write_lock_bh(&net_gre->keymap_lock); |
51 | list_for_each_entry_safe(km, tmp, &gre_keymap_list, list) { | 58 | list_for_each_entry_safe(km, tmp, &net_gre->keymap_list, list) { |
52 | list_del(&km->list); | 59 | list_del(&km->list); |
53 | kfree(km); | 60 | kfree(km); |
54 | } | 61 | } |
55 | write_unlock_bh(&nf_ct_gre_lock); | 62 | write_unlock_bh(&net_gre->keymap_lock); |
56 | } | 63 | } |
57 | EXPORT_SYMBOL(nf_ct_gre_keymap_flush); | 64 | EXPORT_SYMBOL(nf_ct_gre_keymap_flush); |
58 | 65 | ||
@@ -67,19 +74,20 @@ static inline int gre_key_cmpfn(const struct nf_ct_gre_keymap *km, | |||
67 | } | 74 | } |
68 | 75 | ||
69 | /* look up the source key for a given tuple */ | 76 | /* look up the source key for a given tuple */ |
70 | static __be16 gre_keymap_lookup(struct nf_conntrack_tuple *t) | 77 | static __be16 gre_keymap_lookup(struct net *net, struct nf_conntrack_tuple *t) |
71 | { | 78 | { |
79 | struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id); | ||
72 | struct nf_ct_gre_keymap *km; | 80 | struct nf_ct_gre_keymap *km; |
73 | __be16 key = 0; | 81 | __be16 key = 0; |
74 | 82 | ||
75 | read_lock_bh(&nf_ct_gre_lock); | 83 | read_lock_bh(&net_gre->keymap_lock); |
76 | list_for_each_entry(km, &gre_keymap_list, list) { | 84 | list_for_each_entry(km, &net_gre->keymap_list, list) { |
77 | if (gre_key_cmpfn(km, t)) { | 85 | if (gre_key_cmpfn(km, t)) { |
78 | key = km->tuple.src.u.gre.key; | 86 | key = km->tuple.src.u.gre.key; |
79 | break; | 87 | break; |
80 | } | 88 | } |
81 | } | 89 | } |
82 | read_unlock_bh(&nf_ct_gre_lock); | 90 | read_unlock_bh(&net_gre->keymap_lock); |
83 | 91 | ||
84 | pr_debug("lookup src key 0x%x for ", key); | 92 | pr_debug("lookup src key 0x%x for ", key); |
85 | nf_ct_dump_tuple(t); | 93 | nf_ct_dump_tuple(t); |
@@ -91,20 +99,22 @@ static __be16 gre_keymap_lookup(struct nf_conntrack_tuple *t) | |||
91 | int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir, | 99 | int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir, |
92 | struct nf_conntrack_tuple *t) | 100 | struct nf_conntrack_tuple *t) |
93 | { | 101 | { |
102 | struct net *net = nf_ct_net(ct); | ||
103 | struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id); | ||
94 | struct nf_conn_help *help = nfct_help(ct); | 104 | struct nf_conn_help *help = nfct_help(ct); |
95 | struct nf_ct_gre_keymap **kmp, *km; | 105 | struct nf_ct_gre_keymap **kmp, *km; |
96 | 106 | ||
97 | kmp = &help->help.ct_pptp_info.keymap[dir]; | 107 | kmp = &help->help.ct_pptp_info.keymap[dir]; |
98 | if (*kmp) { | 108 | if (*kmp) { |
99 | /* check whether it's a retransmission */ | 109 | /* check whether it's a retransmission */ |
100 | read_lock_bh(&nf_ct_gre_lock); | 110 | read_lock_bh(&net_gre->keymap_lock); |
101 | list_for_each_entry(km, &gre_keymap_list, list) { | 111 | list_for_each_entry(km, &net_gre->keymap_list, list) { |
102 | if (gre_key_cmpfn(km, t) && km == *kmp) { | 112 | if (gre_key_cmpfn(km, t) && km == *kmp) { |
103 | read_unlock_bh(&nf_ct_gre_lock); | 113 | read_unlock_bh(&net_gre->keymap_lock); |
104 | return 0; | 114 | return 0; |
105 | } | 115 | } |
106 | } | 116 | } |
107 | read_unlock_bh(&nf_ct_gre_lock); | 117 | read_unlock_bh(&net_gre->keymap_lock); |
108 | pr_debug("trying to override keymap_%s for ct %p\n", | 118 | pr_debug("trying to override keymap_%s for ct %p\n", |
109 | dir == IP_CT_DIR_REPLY ? "reply" : "orig", ct); | 119 | dir == IP_CT_DIR_REPLY ? "reply" : "orig", ct); |
110 | return -EEXIST; | 120 | return -EEXIST; |
@@ -119,9 +129,9 @@ int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir, | |||
119 | pr_debug("adding new entry %p: ", km); | 129 | pr_debug("adding new entry %p: ", km); |
120 | nf_ct_dump_tuple(&km->tuple); | 130 | nf_ct_dump_tuple(&km->tuple); |
121 | 131 | ||
122 | write_lock_bh(&nf_ct_gre_lock); | 132 | write_lock_bh(&net_gre->keymap_lock); |
123 | list_add_tail(&km->list, &gre_keymap_list); | 133 | list_add_tail(&km->list, &net_gre->keymap_list); |
124 | write_unlock_bh(&nf_ct_gre_lock); | 134 | write_unlock_bh(&net_gre->keymap_lock); |
125 | 135 | ||
126 | return 0; | 136 | return 0; |
127 | } | 137 | } |
@@ -130,12 +140,14 @@ EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_add); | |||
130 | /* destroy the keymap entries associated with specified master ct */ | 140 | /* destroy the keymap entries associated with specified master ct */ |
131 | void nf_ct_gre_keymap_destroy(struct nf_conn *ct) | 141 | void nf_ct_gre_keymap_destroy(struct nf_conn *ct) |
132 | { | 142 | { |
143 | struct net *net = nf_ct_net(ct); | ||
144 | struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id); | ||
133 | struct nf_conn_help *help = nfct_help(ct); | 145 | struct nf_conn_help *help = nfct_help(ct); |
134 | enum ip_conntrack_dir dir; | 146 | enum ip_conntrack_dir dir; |
135 | 147 | ||
136 | pr_debug("entering for ct %p\n", ct); | 148 | pr_debug("entering for ct %p\n", ct); |
137 | 149 | ||
138 | write_lock_bh(&nf_ct_gre_lock); | 150 | write_lock_bh(&net_gre->keymap_lock); |
139 | for (dir = IP_CT_DIR_ORIGINAL; dir < IP_CT_DIR_MAX; dir++) { | 151 | for (dir = IP_CT_DIR_ORIGINAL; dir < IP_CT_DIR_MAX; dir++) { |
140 | if (help->help.ct_pptp_info.keymap[dir]) { | 152 | if (help->help.ct_pptp_info.keymap[dir]) { |
141 | pr_debug("removing %p from list\n", | 153 | pr_debug("removing %p from list\n", |
@@ -145,7 +157,7 @@ void nf_ct_gre_keymap_destroy(struct nf_conn *ct) | |||
145 | help->help.ct_pptp_info.keymap[dir] = NULL; | 157 | help->help.ct_pptp_info.keymap[dir] = NULL; |
146 | } | 158 | } |
147 | } | 159 | } |
148 | write_unlock_bh(&nf_ct_gre_lock); | 160 | write_unlock_bh(&net_gre->keymap_lock); |
149 | } | 161 | } |
150 | EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_destroy); | 162 | EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_destroy); |
151 | 163 | ||
@@ -164,6 +176,7 @@ static bool gre_invert_tuple(struct nf_conntrack_tuple *tuple, | |||
164 | static bool gre_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, | 176 | static bool gre_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, |
165 | struct nf_conntrack_tuple *tuple) | 177 | struct nf_conntrack_tuple *tuple) |
166 | { | 178 | { |
179 | struct net *net = dev_net(skb->dev ? skb->dev : skb->dst->dev); | ||
167 | const struct gre_hdr_pptp *pgrehdr; | 180 | const struct gre_hdr_pptp *pgrehdr; |
168 | struct gre_hdr_pptp _pgrehdr; | 181 | struct gre_hdr_pptp _pgrehdr; |
169 | __be16 srckey; | 182 | __be16 srckey; |
@@ -190,7 +203,7 @@ static bool gre_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, | |||
190 | } | 203 | } |
191 | 204 | ||
192 | tuple->dst.u.gre.key = pgrehdr->call_id; | 205 | tuple->dst.u.gre.key = pgrehdr->call_id; |
193 | srckey = gre_keymap_lookup(tuple); | 206 | srckey = gre_keymap_lookup(net, tuple); |
194 | tuple->src.u.gre.key = srckey; | 207 | tuple->src.u.gre.key = srckey; |
195 | 208 | ||
196 | return true; | 209 | return true; |
@@ -285,15 +298,53 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { | |||
285 | #endif | 298 | #endif |
286 | }; | 299 | }; |
287 | 300 | ||
301 | static int proto_gre_net_init(struct net *net) | ||
302 | { | ||
303 | struct netns_proto_gre *net_gre; | ||
304 | int rv; | ||
305 | |||
306 | net_gre = kmalloc(sizeof(struct netns_proto_gre), GFP_KERNEL); | ||
307 | if (!net_gre) | ||
308 | return -ENOMEM; | ||
309 | rwlock_init(&net_gre->keymap_lock); | ||
310 | INIT_LIST_HEAD(&net_gre->keymap_list); | ||
311 | |||
312 | rv = net_assign_generic(net, proto_gre_net_id, net_gre); | ||
313 | if (rv < 0) | ||
314 | kfree(net_gre); | ||
315 | return rv; | ||
316 | } | ||
317 | |||
318 | static void proto_gre_net_exit(struct net *net) | ||
319 | { | ||
320 | struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id); | ||
321 | |||
322 | nf_ct_gre_keymap_flush(net); | ||
323 | kfree(net_gre); | ||
324 | } | ||
325 | |||
326 | static struct pernet_operations proto_gre_net_ops = { | ||
327 | .init = proto_gre_net_init, | ||
328 | .exit = proto_gre_net_exit, | ||
329 | }; | ||
330 | |||
288 | static int __init nf_ct_proto_gre_init(void) | 331 | static int __init nf_ct_proto_gre_init(void) |
289 | { | 332 | { |
290 | return nf_conntrack_l4proto_register(&nf_conntrack_l4proto_gre4); | 333 | int rv; |
334 | |||
335 | rv = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_gre4); | ||
336 | if (rv < 0) | ||
337 | return rv; | ||
338 | rv = register_pernet_gen_device(&proto_gre_net_id, &proto_gre_net_ops); | ||
339 | if (rv < 0) | ||
340 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4); | ||
341 | return rv; | ||
291 | } | 342 | } |
292 | 343 | ||
293 | static void nf_ct_proto_gre_fini(void) | 344 | static void nf_ct_proto_gre_fini(void) |
294 | { | 345 | { |
295 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4); | 346 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4); |
296 | nf_ct_gre_keymap_flush(); | 347 | unregister_pernet_gen_device(proto_gre_net_id, &proto_gre_net_ops); |
297 | } | 348 | } |
298 | 349 | ||
299 | module_init(nf_ct_proto_gre_init); | 350 | module_init(nf_ct_proto_gre_init); |