aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2010-05-11 08:40:55 -0400
committerPatrick McHardy <kaber@trash.net>2010-05-11 08:40:55 -0400
commitd1db275dd3f6e4182c4c4b4a1ac6287925d60569 (patch)
treeb8edf6661661ff84785495e2e053ce908417a9ff
parent6bd521433942d85e80f7a731a88cc91a327f38e0 (diff)
ipv6: ip6mr: support multiple tables
This patch adds support for multiple independant multicast routing instances, named "tables". Userspace multicast routing daemons can bind to a specific table instance by issuing a setsockopt call using a new option MRT6_TABLE. The table number is stored in the raw socket data and affects all following ip6mr setsockopt(), getsockopt() and ioctl() calls. By default, a single table (RT6_TABLE_DFLT) is created with a default routing rule pointing to it. Newly created pim6reg devices have the table number appended ("pim6regX"), with the exception of devices created in the default table, which are named just "pim6reg" for compatibility reasons. Packets are directed to a specific table instance using routing rules, similar to how regular routing rules work. Currently iif, oif and mark are supported as keys, source and destination addresses could be supported additionally. Example usage: - bind pimd/xorp/... to a specific table: uint32_t table = 123; setsockopt(fd, SOL_IPV6, MRT6_TABLE, &table, sizeof(table)); - create routing rules directing packets to the new table: # ip -6 mrule add iif eth0 lookup 123 # ip -6 mrule add oif eth0 lookup 123 Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r--include/linux/ipv6.h1
-rw-r--r--include/linux/mroute6.h15
-rw-r--r--include/linux/rtnetlink.h3
-rw-r--r--include/net/netns/ipv6.h5
-rw-r--r--net/ipv6/Kconfig14
-rw-r--r--net/ipv6/ip6_output.c2
-rw-r--r--net/ipv6/ip6mr.c428
7 files changed, 396 insertions, 72 deletions
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 0e269038bb38..99e1ab7e3eec 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -383,6 +383,7 @@ struct raw6_sock {
383 __u32 checksum; /* perform checksum */ 383 __u32 checksum; /* perform checksum */
384 __u32 offset; /* checksum offset */ 384 __u32 offset; /* checksum offset */
385 struct icmp6_filter filter; 385 struct icmp6_filter filter;
386 __u32 ip6mr_table;
386 /* ipv6_pinfo has to be the last member of raw6_sock, see inet6_sk_generic */ 387 /* ipv6_pinfo has to be the last member of raw6_sock, see inet6_sk_generic */
387 struct ipv6_pinfo inet6; 388 struct ipv6_pinfo inet6;
388}; 389};
diff --git a/include/linux/mroute6.h b/include/linux/mroute6.h
index 0370dd4f2389..6091ab77f388 100644
--- a/include/linux/mroute6.h
+++ b/include/linux/mroute6.h
@@ -24,7 +24,8 @@
24#define MRT6_DEL_MFC (MRT6_BASE+5) /* Delete a multicast forwarding entry */ 24#define MRT6_DEL_MFC (MRT6_BASE+5) /* Delete a multicast forwarding entry */
25#define MRT6_VERSION (MRT6_BASE+6) /* Get the kernel multicast version */ 25#define MRT6_VERSION (MRT6_BASE+6) /* Get the kernel multicast version */
26#define MRT6_ASSERT (MRT6_BASE+7) /* Activate PIM assert mode */ 26#define MRT6_ASSERT (MRT6_BASE+7) /* Activate PIM assert mode */
27#define MRT6_PIM (MRT6_BASE+8) /* enable PIM code */ 27#define MRT6_PIM (MRT6_BASE+8) /* enable PIM code */
28#define MRT6_TABLE (MRT6_BASE+9) /* Specify mroute table ID */
28 29
29#define SIOCGETMIFCNT_IN6 SIOCPROTOPRIVATE /* IP protocol privates */ 30#define SIOCGETMIFCNT_IN6 SIOCPROTOPRIVATE /* IP protocol privates */
30#define SIOCGETSGCNT_IN6 (SIOCPROTOPRIVATE+1) 31#define SIOCGETSGCNT_IN6 (SIOCPROTOPRIVATE+1)
@@ -229,11 +230,17 @@ extern int ip6mr_get_route(struct net *net, struct sk_buff *skb,
229 struct rtmsg *rtm, int nowait); 230 struct rtmsg *rtm, int nowait);
230 231
231#ifdef CONFIG_IPV6_MROUTE 232#ifdef CONFIG_IPV6_MROUTE
232extern struct sock *mroute6_socket(struct net *net); 233extern struct sock *mroute6_socket(struct net *net, struct sk_buff *skb);
233extern int ip6mr_sk_done(struct sock *sk); 234extern int ip6mr_sk_done(struct sock *sk);
234#else 235#else
235static inline struct sock *mroute6_socket(struct net *net) { return NULL; } 236static inline struct sock *mroute6_socket(struct net *net, struct sk_buff *skb)
236static inline int ip6mr_sk_done(struct sock *sk) { return 0; } 237{
238 return NULL;
239}
240static inline int ip6mr_sk_done(struct sock *sk)
241{
242 return 0;
243}
237#endif 244#endif
238#endif 245#endif
239 246
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 5a42c36cb6aa..fbc8cb0d48c3 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -11,7 +11,8 @@
11 * families, values above 128 may be used arbitrarily. 11 * families, values above 128 may be used arbitrarily.
12 */ 12 */
13#define RTNL_FAMILY_IPMR 128 13#define RTNL_FAMILY_IPMR 128
14#define RTNL_FAMILY_MAX 128 14#define RTNL_FAMILY_IP6MR 129
15#define RTNL_FAMILY_MAX 129
15 16
16/**** 17/****
17 * Routing/neighbour discovery messages. 18 * Routing/neighbour discovery messages.
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index 4e2780e6d8bc..81abfcb2eb4e 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -59,7 +59,12 @@ struct netns_ipv6 {
59 struct sock *tcp_sk; 59 struct sock *tcp_sk;
60 struct sock *igmp_sk; 60 struct sock *igmp_sk;
61#ifdef CONFIG_IPV6_MROUTE 61#ifdef CONFIG_IPV6_MROUTE
62#ifndef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
62 struct mr6_table *mrt6; 63 struct mr6_table *mrt6;
64#else
65 struct list_head mr6_tables;
66 struct fib_rules_ops *mr6_rules_ops;
67#endif
63#endif 68#endif
64}; 69};
65#endif 70#endif
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index a578096152ab..36d7437ac054 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -229,6 +229,20 @@ config IPV6_MROUTE
229 Experimental support for IPv6 multicast forwarding. 229 Experimental support for IPv6 multicast forwarding.
230 If unsure, say N. 230 If unsure, say N.
231 231
232config IPV6_MROUTE_MULTIPLE_TABLES
233 bool "IPv6: multicast policy routing"
234 depends on IPV6_MROUTE
235 select FIB_RULES
236 help
237 Normally, a multicast router runs a userspace daemon and decides
238 what to do with a multicast packet based on the source and
239 destination addresses. If you say Y here, the multicast router
240 will also be able to take interfaces and packet marks into
241 account and run multiple instances of userspace daemons
242 simultaneously, each one handling a single table.
243
244 If unsure, say N.
245
232config IPV6_PIMSM_V2 246config IPV6_PIMSM_V2
233 bool "IPv6: PIM-SM version 2 support (EXPERIMENTAL)" 247 bool "IPv6: PIM-SM version 2 support (EXPERIMENTAL)"
234 depends on IPV6_MROUTE 248 depends on IPV6_MROUTE
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 5173acaeb501..cd963f64e27c 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -108,7 +108,7 @@ static int ip6_finish_output2(struct sk_buff *skb)
108 struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); 108 struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
109 109
110 if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(skb->sk) && 110 if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(skb->sk) &&
111 ((mroute6_socket(dev_net(dev)) && 111 ((mroute6_socket(dev_net(dev), skb) &&
112 !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) || 112 !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) ||
113 ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr, 113 ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr,
114 &ipv6_hdr(skb)->saddr))) { 114 &ipv6_hdr(skb)->saddr))) {
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 9419fceeed41..c2920a1a6db3 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -42,6 +42,7 @@
42#include <linux/if_arp.h> 42#include <linux/if_arp.h>
43#include <net/checksum.h> 43#include <net/checksum.h>
44#include <net/netlink.h> 44#include <net/netlink.h>
45#include <net/fib_rules.h>
45 46
46#include <net/ipv6.h> 47#include <net/ipv6.h>
47#include <net/ip6_route.h> 48#include <net/ip6_route.h>
@@ -52,9 +53,11 @@
52#include <net/ip6_checksum.h> 53#include <net/ip6_checksum.h>
53 54
54struct mr6_table { 55struct mr6_table {
56 struct list_head list;
55#ifdef CONFIG_NET_NS 57#ifdef CONFIG_NET_NS
56 struct net *net; 58 struct net *net;
57#endif 59#endif
60 u32 id;
58 struct sock *mroute6_sk; 61 struct sock *mroute6_sk;
59 struct timer_list ipmr_expire_timer; 62 struct timer_list ipmr_expire_timer;
60 struct list_head mfc6_unres_queue; 63 struct list_head mfc6_unres_queue;
@@ -69,6 +72,14 @@ struct mr6_table {
69#endif 72#endif
70}; 73};
71 74
75struct ip6mr_rule {
76 struct fib_rule common;
77};
78
79struct ip6mr_result {
80 struct mr6_table *mrt;
81};
82
72/* Big lock, protecting vif table, mrt cache and mroute socket state. 83/* Big lock, protecting vif table, mrt cache and mroute socket state.
73 Note that the changes are semaphored via rtnl_lock. 84 Note that the changes are semaphored via rtnl_lock.
74 */ 85 */
@@ -94,6 +105,9 @@ static DEFINE_SPINLOCK(mfc_unres_lock);
94 105
95static struct kmem_cache *mrt_cachep __read_mostly; 106static struct kmem_cache *mrt_cachep __read_mostly;
96 107
108static struct mr6_table *ip6mr_new_table(struct net *net, u32 id);
109static void ip6mr_free_table(struct mr6_table *mrt);
110
97static int ip6_mr_forward(struct net *net, struct mr6_table *mrt, 111static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
98 struct sk_buff *skb, struct mfc6_cache *cache); 112 struct sk_buff *skb, struct mfc6_cache *cache);
99static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt, 113static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
@@ -101,12 +115,220 @@ static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
101static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, 115static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
102 struct mfc6_cache *c, struct rtmsg *rtm); 116 struct mfc6_cache *c, struct rtmsg *rtm);
103static void mroute_clean_tables(struct mr6_table *mrt); 117static void mroute_clean_tables(struct mr6_table *mrt);
118static void ipmr_expire_process(unsigned long arg);
119
120#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
121#define ip6mr_for_each_table(mrt, met) \
122 list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list)
123
124static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)
125{
126 struct mr6_table *mrt;
104 127
128 ip6mr_for_each_table(mrt, net) {
129 if (mrt->id == id)
130 return mrt;
131 }
132 return NULL;
133}
134
135static int ip6mr_fib_lookup(struct net *net, struct flowi *flp,
136 struct mr6_table **mrt)
137{
138 struct ip6mr_result res;
139 struct fib_lookup_arg arg = { .result = &res, };
140 int err;
141
142 err = fib_rules_lookup(net->ipv6.mr6_rules_ops, flp, 0, &arg);
143 if (err < 0)
144 return err;
145 *mrt = res.mrt;
146 return 0;
147}
148
149static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp,
150 int flags, struct fib_lookup_arg *arg)
151{
152 struct ip6mr_result *res = arg->result;
153 struct mr6_table *mrt;
154
155 switch (rule->action) {
156 case FR_ACT_TO_TBL:
157 break;
158 case FR_ACT_UNREACHABLE:
159 return -ENETUNREACH;
160 case FR_ACT_PROHIBIT:
161 return -EACCES;
162 case FR_ACT_BLACKHOLE:
163 default:
164 return -EINVAL;
165 }
166
167 mrt = ip6mr_get_table(rule->fr_net, rule->table);
168 if (mrt == NULL)
169 return -EAGAIN;
170 res->mrt = mrt;
171 return 0;
172}
173
174static int ip6mr_rule_match(struct fib_rule *rule, struct flowi *flp, int flags)
175{
176 return 1;
177}
178
179static const struct nla_policy ip6mr_rule_policy[FRA_MAX + 1] = {
180 FRA_GENERIC_POLICY,
181};
182
183static int ip6mr_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
184 struct fib_rule_hdr *frh, struct nlattr **tb)
185{
186 return 0;
187}
188
189static int ip6mr_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
190 struct nlattr **tb)
191{
192 return 1;
193}
194
195static int ip6mr_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
196 struct fib_rule_hdr *frh)
197{
198 frh->dst_len = 0;
199 frh->src_len = 0;
200 frh->tos = 0;
201 return 0;
202}
203
204static const struct fib_rules_ops __net_initdata ip6mr_rules_ops_template = {
205 .family = RTNL_FAMILY_IP6MR,
206 .rule_size = sizeof(struct ip6mr_rule),
207 .addr_size = sizeof(struct in6_addr),
208 .action = ip6mr_rule_action,
209 .match = ip6mr_rule_match,
210 .configure = ip6mr_rule_configure,
211 .compare = ip6mr_rule_compare,
212 .default_pref = fib_default_rule_pref,
213 .fill = ip6mr_rule_fill,
214 .nlgroup = RTNLGRP_IPV6_RULE,
215 .policy = ip6mr_rule_policy,
216 .owner = THIS_MODULE,
217};
218
219static int __net_init ip6mr_rules_init(struct net *net)
220{
221 struct fib_rules_ops *ops;
222 struct mr6_table *mrt;
223 int err;
224
225 ops = fib_rules_register(&ip6mr_rules_ops_template, net);
226 if (IS_ERR(ops))
227 return PTR_ERR(ops);
228
229 INIT_LIST_HEAD(&net->ipv6.mr6_tables);
230
231 mrt = ip6mr_new_table(net, RT6_TABLE_DFLT);
232 if (mrt == NULL) {
233 err = -ENOMEM;
234 goto err1;
235 }
236
237 err = fib_default_rule_add(ops, 0x7fff, RT6_TABLE_DFLT, 0);
238 if (err < 0)
239 goto err2;
240
241 net->ipv6.mr6_rules_ops = ops;
242 return 0;
243
244err2:
245 kfree(mrt);
246err1:
247 fib_rules_unregister(ops);
248 return err;
249}
250
251static void __net_exit ip6mr_rules_exit(struct net *net)
252{
253 struct mr6_table *mrt, *next;
254
255 list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list)
256 ip6mr_free_table(mrt);
257 fib_rules_unregister(net->ipv6.mr6_rules_ops);
258}
259#else
260#define ip6mr_for_each_table(mrt, net) \
261 for (mrt = net->ipv6.mrt6; mrt; mrt = NULL)
262
263static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)
264{
265 return net->ipv6.mrt6;
266}
267
268static int ip6mr_fib_lookup(struct net *net, struct flowi *flp,
269 struct mr6_table **mrt)
270{
271 *mrt = net->ipv6.mrt6;
272 return 0;
273}
274
275static int __net_init ip6mr_rules_init(struct net *net)
276{
277 net->ipv6.mrt6 = ip6mr_new_table(net, RT6_TABLE_DFLT);
278 return net->ipv6.mrt6 ? 0 : -ENOMEM;
279}
280
281static void __net_exit ip6mr_rules_exit(struct net *net)
282{
283 ip6mr_free_table(net->ipv6.mrt6);
284}
285#endif
286
287static struct mr6_table *ip6mr_new_table(struct net *net, u32 id)
288{
289 struct mr6_table *mrt;
290 unsigned int i;
291
292 mrt = ip6mr_get_table(net, id);
293 if (mrt != NULL)
294 return mrt;
295
296 mrt = kzalloc(sizeof(*mrt), GFP_KERNEL);
297 if (mrt == NULL)
298 return NULL;
299 mrt->id = id;
300 write_pnet(&mrt->net, net);
301
302 /* Forwarding cache */
303 for (i = 0; i < MFC6_LINES; i++)
304 INIT_LIST_HEAD(&mrt->mfc6_cache_array[i]);
305
306 INIT_LIST_HEAD(&mrt->mfc6_unres_queue);
307
308 setup_timer(&mrt->ipmr_expire_timer, ipmr_expire_process,
309 (unsigned long)mrt);
310
311#ifdef CONFIG_IPV6_PIMSM_V2
312 mrt->mroute_reg_vif_num = -1;
313#endif
314#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
315 list_add_tail_rcu(&mrt->list, &net->ipv6.mr6_tables);
316#endif
317 return mrt;
318}
319
320static void ip6mr_free_table(struct mr6_table *mrt)
321{
322 del_timer(&mrt->ipmr_expire_timer);
323 mroute_clean_tables(mrt);
324 kfree(mrt);
325}
105 326
106#ifdef CONFIG_PROC_FS 327#ifdef CONFIG_PROC_FS
107 328
108struct ipmr_mfc_iter { 329struct ipmr_mfc_iter {
109 struct seq_net_private p; 330 struct seq_net_private p;
331 struct mr6_table *mrt;
110 struct list_head *cache; 332 struct list_head *cache;
111 int ct; 333 int ct;
112}; 334};
@@ -115,7 +337,7 @@ struct ipmr_mfc_iter {
115static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net, 337static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net,
116 struct ipmr_mfc_iter *it, loff_t pos) 338 struct ipmr_mfc_iter *it, loff_t pos)
117{ 339{
118 struct mr6_table *mrt = net->ipv6.mrt6; 340 struct mr6_table *mrt = it->mrt;
119 struct mfc6_cache *mfc; 341 struct mfc6_cache *mfc;
120 342
121 read_lock(&mrt_lock); 343 read_lock(&mrt_lock);
@@ -144,6 +366,7 @@ static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net,
144 366
145struct ipmr_vif_iter { 367struct ipmr_vif_iter {
146 struct seq_net_private p; 368 struct seq_net_private p;
369 struct mr6_table *mrt;
147 int ct; 370 int ct;
148}; 371};
149 372
@@ -151,7 +374,7 @@ static struct mif_device *ip6mr_vif_seq_idx(struct net *net,
151 struct ipmr_vif_iter *iter, 374 struct ipmr_vif_iter *iter,
152 loff_t pos) 375 loff_t pos)
153{ 376{
154 struct mr6_table *mrt = net->ipv6.mrt6; 377 struct mr6_table *mrt = iter->mrt;
155 378
156 for (iter->ct = 0; iter->ct < mrt->maxvif; ++iter->ct) { 379 for (iter->ct = 0; iter->ct < mrt->maxvif; ++iter->ct) {
157 if (!MIF_EXISTS(mrt, iter->ct)) 380 if (!MIF_EXISTS(mrt, iter->ct))
@@ -165,7 +388,15 @@ static struct mif_device *ip6mr_vif_seq_idx(struct net *net,
165static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos) 388static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos)
166 __acquires(mrt_lock) 389 __acquires(mrt_lock)
167{ 390{
391 struct ipmr_vif_iter *iter = seq->private;
168 struct net *net = seq_file_net(seq); 392 struct net *net = seq_file_net(seq);
393 struct mr6_table *mrt;
394
395 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
396 if (mrt == NULL)
397 return ERR_PTR(-ENOENT);
398
399 iter->mrt = mrt;
169 400
170 read_lock(&mrt_lock); 401 read_lock(&mrt_lock);
171 return *pos ? ip6mr_vif_seq_idx(net, seq->private, *pos - 1) 402 return *pos ? ip6mr_vif_seq_idx(net, seq->private, *pos - 1)
@@ -176,7 +407,7 @@ static void *ip6mr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
176{ 407{
177 struct ipmr_vif_iter *iter = seq->private; 408 struct ipmr_vif_iter *iter = seq->private;
178 struct net *net = seq_file_net(seq); 409 struct net *net = seq_file_net(seq);
179 struct mr6_table *mrt = net->ipv6.mrt6; 410 struct mr6_table *mrt = iter->mrt;
180 411
181 ++*pos; 412 ++*pos;
182 if (v == SEQ_START_TOKEN) 413 if (v == SEQ_START_TOKEN)
@@ -198,8 +429,8 @@ static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v)
198 429
199static int ip6mr_vif_seq_show(struct seq_file *seq, void *v) 430static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
200{ 431{
201 struct net *net = seq_file_net(seq); 432 struct ipmr_vif_iter *iter = seq->private;
202 struct mr6_table *mrt = net->ipv6.mrt6; 433 struct mr6_table *mrt = iter->mrt;
203 434
204 if (v == SEQ_START_TOKEN) { 435 if (v == SEQ_START_TOKEN) {
205 seq_puts(seq, 436 seq_puts(seq,
@@ -241,8 +472,15 @@ static const struct file_operations ip6mr_vif_fops = {
241 472
242static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos) 473static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
243{ 474{
475 struct ipmr_mfc_iter *it = seq->private;
244 struct net *net = seq_file_net(seq); 476 struct net *net = seq_file_net(seq);
477 struct mr6_table *mrt;
478
479 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
480 if (mrt == NULL)
481 return ERR_PTR(-ENOENT);
245 482
483 it->mrt = mrt;
246 return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1) 484 return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
247 : SEQ_START_TOKEN; 485 : SEQ_START_TOKEN;
248} 486}
@@ -252,7 +490,7 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
252 struct mfc6_cache *mfc = v; 490 struct mfc6_cache *mfc = v;
253 struct ipmr_mfc_iter *it = seq->private; 491 struct ipmr_mfc_iter *it = seq->private;
254 struct net *net = seq_file_net(seq); 492 struct net *net = seq_file_net(seq);
255 struct mr6_table *mrt = net->ipv6.mrt6; 493 struct mr6_table *mrt = it->mrt;
256 494
257 ++*pos; 495 ++*pos;
258 496
@@ -293,8 +531,7 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
293static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v) 531static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
294{ 532{
295 struct ipmr_mfc_iter *it = seq->private; 533 struct ipmr_mfc_iter *it = seq->private;
296 struct net *net = seq_file_net(seq); 534 struct mr6_table *mrt = it->mrt;
297 struct mr6_table *mrt = net->ipv6.mrt6;
298 535
299 if (it->cache == &mrt->mfc6_unres_queue) 536 if (it->cache == &mrt->mfc6_unres_queue)
300 spin_unlock_bh(&mfc_unres_lock); 537 spin_unlock_bh(&mfc_unres_lock);
@@ -305,8 +542,6 @@ static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
305static int ipmr_mfc_seq_show(struct seq_file *seq, void *v) 542static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
306{ 543{
307 int n; 544 int n;
308 struct net *net = seq_file_net(seq);
309 struct mr6_table *mrt = net->ipv6.mrt6;
310 545
311 if (v == SEQ_START_TOKEN) { 546 if (v == SEQ_START_TOKEN) {
312 seq_puts(seq, 547 seq_puts(seq,
@@ -316,6 +551,7 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
316 } else { 551 } else {
317 const struct mfc6_cache *mfc = v; 552 const struct mfc6_cache *mfc = v;
318 const struct ipmr_mfc_iter *it = seq->private; 553 const struct ipmr_mfc_iter *it = seq->private;
554 struct mr6_table *mrt = it->mrt;
319 555
320 seq_printf(seq, "%pI6 %pI6 %-3hd", 556 seq_printf(seq, "%pI6 %pI6 %-3hd",
321 &mfc->mf6c_mcastgrp, &mfc->mf6c_origin, 557 &mfc->mf6c_mcastgrp, &mfc->mf6c_origin,
@@ -375,8 +611,12 @@ static int pim6_rcv(struct sk_buff *skb)
375 struct ipv6hdr *encap; 611 struct ipv6hdr *encap;
376 struct net_device *reg_dev = NULL; 612 struct net_device *reg_dev = NULL;
377 struct net *net = dev_net(skb->dev); 613 struct net *net = dev_net(skb->dev);
378 struct mr6_table *mrt = net->ipv6.mrt6; 614 struct mr6_table *mrt;
379 int reg_vif_num = mrt->mroute_reg_vif_num; 615 struct flowi fl = {
616 .iif = skb->dev->ifindex,
617 .mark = skb->mark,
618 };
619 int reg_vif_num;
380 620
381 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap))) 621 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
382 goto drop; 622 goto drop;
@@ -399,6 +639,10 @@ static int pim6_rcv(struct sk_buff *skb)
399 ntohs(encap->payload_len) + sizeof(*pim) > skb->len) 639 ntohs(encap->payload_len) + sizeof(*pim) > skb->len)
400 goto drop; 640 goto drop;
401 641
642 if (ip6mr_fib_lookup(net, &fl, &mrt) < 0)
643 goto drop;
644 reg_vif_num = mrt->mroute_reg_vif_num;
645
402 read_lock(&mrt_lock); 646 read_lock(&mrt_lock);
403 if (reg_vif_num >= 0) 647 if (reg_vif_num >= 0)
404 reg_dev = mrt->vif6_table[reg_vif_num].dev; 648 reg_dev = mrt->vif6_table[reg_vif_num].dev;
@@ -438,7 +682,17 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
438 struct net_device *dev) 682 struct net_device *dev)
439{ 683{
440 struct net *net = dev_net(dev); 684 struct net *net = dev_net(dev);
441 struct mr6_table *mrt = net->ipv6.mrt6; 685 struct mr6_table *mrt;
686 struct flowi fl = {
687 .oif = dev->ifindex,
688 .iif = skb->skb_iif,
689 .mark = skb->mark,
690 };
691 int err;
692
693 err = ip6mr_fib_lookup(net, &fl, &mrt);
694 if (err < 0)
695 return err;
442 696
443 read_lock(&mrt_lock); 697 read_lock(&mrt_lock);
444 dev->stats.tx_bytes += skb->len; 698 dev->stats.tx_bytes += skb->len;
@@ -463,11 +717,17 @@ static void reg_vif_setup(struct net_device *dev)
463 dev->features |= NETIF_F_NETNS_LOCAL; 717 dev->features |= NETIF_F_NETNS_LOCAL;
464} 718}
465 719
466static struct net_device *ip6mr_reg_vif(struct net *net) 720static struct net_device *ip6mr_reg_vif(struct net *net, struct mr6_table *mrt)
467{ 721{
468 struct net_device *dev; 722 struct net_device *dev;
723 char name[IFNAMSIZ];
724
725 if (mrt->id == RT6_TABLE_DFLT)
726 sprintf(name, "pim6reg");
727 else
728 sprintf(name, "pim6reg%u", mrt->id);
469 729
470 dev = alloc_netdev(0, "pim6reg", reg_vif_setup); 730 dev = alloc_netdev(0, name, reg_vif_setup);
471 if (dev == NULL) 731 if (dev == NULL)
472 return NULL; 732 return NULL;
473 733
@@ -665,7 +925,7 @@ static int mif6_add(struct net *net, struct mr6_table *mrt,
665 */ 925 */
666 if (mrt->mroute_reg_vif_num >= 0) 926 if (mrt->mroute_reg_vif_num >= 0)
667 return -EADDRINUSE; 927 return -EADDRINUSE;
668 dev = ip6mr_reg_vif(net); 928 dev = ip6mr_reg_vif(net, mrt);
669 if (!dev) 929 if (!dev)
670 return -ENOBUFS; 930 return -ENOBUFS;
671 err = dev_set_allmulti(dev, 1); 931 err = dev_set_allmulti(dev, 1);
@@ -995,7 +1255,7 @@ static int ip6mr_device_event(struct notifier_block *this,
995{ 1255{
996 struct net_device *dev = ptr; 1256 struct net_device *dev = ptr;
997 struct net *net = dev_net(dev); 1257 struct net *net = dev_net(dev);
998 struct mr6_table *mrt = net->ipv6.mrt6; 1258 struct mr6_table *mrt;
999 struct mif_device *v; 1259 struct mif_device *v;
1000 int ct; 1260 int ct;
1001 LIST_HEAD(list); 1261 LIST_HEAD(list);
@@ -1003,10 +1263,12 @@ static int ip6mr_device_event(struct notifier_block *this,
1003 if (event != NETDEV_UNREGISTER) 1263 if (event != NETDEV_UNREGISTER)
1004 return NOTIFY_DONE; 1264 return NOTIFY_DONE;
1005 1265
1006 v = &mrt->vif6_table[0]; 1266 ip6mr_for_each_table(mrt, net) {
1007 for (ct = 0; ct < mrt->maxvif; ct++, v++) { 1267 v = &mrt->vif6_table[0];
1008 if (v->dev == dev) 1268 for (ct = 0; ct < mrt->maxvif; ct++, v++) {
1009 mif6_delete(mrt, ct, &list); 1269 if (v->dev == dev)
1270 mif6_delete(mrt, ct, &list);
1271 }
1010 } 1272 }
1011 unregister_netdevice_many(&list); 1273 unregister_netdevice_many(&list);
1012 1274
@@ -1023,29 +1285,11 @@ static struct notifier_block ip6_mr_notifier = {
1023 1285
1024static int __net_init ip6mr_net_init(struct net *net) 1286static int __net_init ip6mr_net_init(struct net *net)
1025{ 1287{
1026 struct mr6_table *mrt; 1288 int err;
1027 unsigned int i;
1028 int err = 0;
1029 1289
1030 mrt = kzalloc(sizeof(*mrt), GFP_KERNEL); 1290 err = ip6mr_rules_init(net);
1031 if (mrt == NULL) { 1291 if (err < 0)
1032 err = -ENOMEM;
1033 goto fail; 1292 goto fail;
1034 }
1035
1036 write_pnet(&mrt->net, net);
1037
1038 for (i = 0; i < MFC6_LINES; i++)
1039 INIT_LIST_HEAD(&mrt->mfc6_cache_array[i]);
1040
1041 INIT_LIST_HEAD(&mrt->mfc6_unres_queue);
1042
1043 setup_timer(&mrt->ipmr_expire_timer, ipmr_expire_process,
1044 (unsigned long)mrt);
1045
1046#ifdef CONFIG_IPV6_PIMSM_V2
1047 mrt->mroute_reg_vif_num = -1;
1048#endif
1049 1293
1050#ifdef CONFIG_PROC_FS 1294#ifdef CONFIG_PROC_FS
1051 err = -ENOMEM; 1295 err = -ENOMEM;
@@ -1055,14 +1299,13 @@ static int __net_init ip6mr_net_init(struct net *net)
1055 goto proc_cache_fail; 1299 goto proc_cache_fail;
1056#endif 1300#endif
1057 1301
1058 net->ipv6.mrt6 = mrt;
1059 return 0; 1302 return 0;
1060 1303
1061#ifdef CONFIG_PROC_FS 1304#ifdef CONFIG_PROC_FS
1062proc_cache_fail: 1305proc_cache_fail:
1063 proc_net_remove(net, "ip6_mr_vif"); 1306 proc_net_remove(net, "ip6_mr_vif");
1064proc_vif_fail: 1307proc_vif_fail:
1065 kfree(mrt); 1308 ip6mr_rules_exit(net);
1066#endif 1309#endif
1067fail: 1310fail:
1068 return err; 1311 return err;
@@ -1070,15 +1313,11 @@ fail:
1070 1313
1071static void __net_exit ip6mr_net_exit(struct net *net) 1314static void __net_exit ip6mr_net_exit(struct net *net)
1072{ 1315{
1073 struct mr6_table *mrt = net->ipv6.mrt6;
1074
1075#ifdef CONFIG_PROC_FS 1316#ifdef CONFIG_PROC_FS
1076 proc_net_remove(net, "ip6_mr_cache"); 1317 proc_net_remove(net, "ip6_mr_cache");
1077 proc_net_remove(net, "ip6_mr_vif"); 1318 proc_net_remove(net, "ip6_mr_vif");
1078#endif 1319#endif
1079 del_timer(&mrt->ipmr_expire_timer); 1320 ip6mr_rules_exit(net);
1080 mroute_clean_tables(mrt);
1081 kfree(mrt);
1082} 1321}
1083 1322
1084static struct pernet_operations ip6mr_net_ops = { 1323static struct pernet_operations ip6mr_net_ops = {
@@ -1279,28 +1518,39 @@ static int ip6mr_sk_init(struct mr6_table *mrt, struct sock *sk)
1279 1518
1280int ip6mr_sk_done(struct sock *sk) 1519int ip6mr_sk_done(struct sock *sk)
1281{ 1520{
1282 int err = 0; 1521 int err = -EACCES;
1283 struct net *net = sock_net(sk); 1522 struct net *net = sock_net(sk);
1284 struct mr6_table *mrt = net->ipv6.mrt6; 1523 struct mr6_table *mrt;
1285 1524
1286 rtnl_lock(); 1525 rtnl_lock();
1287 if (sk == mrt->mroute6_sk) { 1526 ip6mr_for_each_table(mrt, net) {
1288 write_lock_bh(&mrt_lock); 1527 if (sk == mrt->mroute6_sk) {
1289 mrt->mroute6_sk = NULL; 1528 write_lock_bh(&mrt_lock);
1290 net->ipv6.devconf_all->mc_forwarding--; 1529 mrt->mroute6_sk = NULL;
1291 write_unlock_bh(&mrt_lock); 1530 net->ipv6.devconf_all->mc_forwarding--;
1531 write_unlock_bh(&mrt_lock);
1292 1532
1293 mroute_clean_tables(mrt); 1533 mroute_clean_tables(mrt);
1294 } else 1534 err = 0;
1295 err = -EACCES; 1535 break;
1536 }
1537 }
1296 rtnl_unlock(); 1538 rtnl_unlock();
1297 1539
1298 return err; 1540 return err;
1299} 1541}
1300 1542
1301struct sock *mroute6_socket(struct net *net) 1543struct sock *mroute6_socket(struct net *net, struct sk_buff *skb)
1302{ 1544{
1303 struct mr6_table *mrt = net->ipv6.mrt6; 1545 struct mr6_table *mrt;
1546 struct flowi fl = {
1547 .iif = skb->skb_iif,
1548 .oif = skb->dev->ifindex,
1549 .mark = skb->mark,
1550 };
1551
1552 if (ip6mr_fib_lookup(net, &fl, &mrt) < 0)
1553 return NULL;
1304 1554
1305 return mrt->mroute6_sk; 1555 return mrt->mroute6_sk;
1306} 1556}
@@ -1319,7 +1569,11 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
1319 struct mf6cctl mfc; 1569 struct mf6cctl mfc;
1320 mifi_t mifi; 1570 mifi_t mifi;
1321 struct net *net = sock_net(sk); 1571 struct net *net = sock_net(sk);
1322 struct mr6_table *mrt = net->ipv6.mrt6; 1572 struct mr6_table *mrt;
1573
1574 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1575 if (mrt == NULL)
1576 return -ENOENT;
1323 1577
1324 if (optname != MRT6_INIT) { 1578 if (optname != MRT6_INIT) {
1325 if (sk != mrt->mroute6_sk && !capable(CAP_NET_ADMIN)) 1579 if (sk != mrt->mroute6_sk && !capable(CAP_NET_ADMIN))
@@ -1409,6 +1663,27 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
1409 } 1663 }
1410 1664
1411#endif 1665#endif
1666#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
1667 case MRT6_TABLE:
1668 {
1669 u32 v;
1670
1671 if (optlen != sizeof(u32))
1672 return -EINVAL;
1673 if (get_user(v, (u32 __user *)optval))
1674 return -EFAULT;
1675 if (sk == mrt->mroute6_sk)
1676 return -EBUSY;
1677
1678 rtnl_lock();
1679 ret = 0;
1680 if (!ip6mr_new_table(net, v))
1681 ret = -ENOMEM;
1682 raw6_sk(sk)->ip6mr_table = v;
1683 rtnl_unlock();
1684 return ret;
1685 }
1686#endif
1412 /* 1687 /*
1413 * Spurious command, or MRT6_VERSION which you cannot 1688 * Spurious command, or MRT6_VERSION which you cannot
1414 * set. 1689 * set.
@@ -1428,7 +1703,11 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval,
1428 int olr; 1703 int olr;
1429 int val; 1704 int val;
1430 struct net *net = sock_net(sk); 1705 struct net *net = sock_net(sk);
1431 struct mr6_table *mrt = net->ipv6.mrt6; 1706 struct mr6_table *mrt;
1707
1708 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1709 if (mrt == NULL)
1710 return -ENOENT;
1432 1711
1433 switch (optname) { 1712 switch (optname) {
1434 case MRT6_VERSION: 1713 case MRT6_VERSION:
@@ -1471,7 +1750,11 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
1471 struct mif_device *vif; 1750 struct mif_device *vif;
1472 struct mfc6_cache *c; 1751 struct mfc6_cache *c;
1473 struct net *net = sock_net(sk); 1752 struct net *net = sock_net(sk);
1474 struct mr6_table *mrt = net->ipv6.mrt6; 1753 struct mr6_table *mrt;
1754
1755 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1756 if (mrt == NULL)
1757 return -ENOENT;
1475 1758
1476 switch (cmd) { 1759 switch (cmd) {
1477 case SIOCGETMIFCNT_IN6: 1760 case SIOCGETMIFCNT_IN6:
@@ -1683,7 +1966,16 @@ int ip6_mr_input(struct sk_buff *skb)
1683{ 1966{
1684 struct mfc6_cache *cache; 1967 struct mfc6_cache *cache;
1685 struct net *net = dev_net(skb->dev); 1968 struct net *net = dev_net(skb->dev);
1686 struct mr6_table *mrt = net->ipv6.mrt6; 1969 struct mr6_table *mrt;
1970 struct flowi fl = {
1971 .iif = skb->dev->ifindex,
1972 .mark = skb->mark,
1973 };
1974 int err;
1975
1976 err = ip6mr_fib_lookup(net, &fl, &mrt);
1977 if (err < 0)
1978 return err;
1687 1979
1688 read_lock(&mrt_lock); 1980 read_lock(&mrt_lock);
1689 cache = ip6mr_cache_find(mrt, 1981 cache = ip6mr_cache_find(mrt,
@@ -1758,10 +2050,14 @@ int ip6mr_get_route(struct net *net,
1758 struct sk_buff *skb, struct rtmsg *rtm, int nowait) 2050 struct sk_buff *skb, struct rtmsg *rtm, int nowait)
1759{ 2051{
1760 int err; 2052 int err;
1761 struct mr6_table *mrt = net->ipv6.mrt6; 2053 struct mr6_table *mrt;
1762 struct mfc6_cache *cache; 2054 struct mfc6_cache *cache;
1763 struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); 2055 struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
1764 2056
2057 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
2058 if (mrt == NULL)
2059 return -ENOENT;
2060
1765 read_lock(&mrt_lock); 2061 read_lock(&mrt_lock);
1766 cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr); 2062 cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
1767 2063