diff options
-rw-r--r-- | include/linux/ipv6.h | 1 | ||||
-rw-r--r-- | include/linux/mroute6.h | 15 | ||||
-rw-r--r-- | include/linux/rtnetlink.h | 3 | ||||
-rw-r--r-- | include/net/netns/ipv6.h | 5 | ||||
-rw-r--r-- | net/ipv6/Kconfig | 14 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 2 | ||||
-rw-r--r-- | net/ipv6/ip6mr.c | 428 |
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 |
232 | extern struct sock *mroute6_socket(struct net *net); | 233 | extern struct sock *mroute6_socket(struct net *net, struct sk_buff *skb); |
233 | extern int ip6mr_sk_done(struct sock *sk); | 234 | extern int ip6mr_sk_done(struct sock *sk); |
234 | #else | 235 | #else |
235 | static inline struct sock *mroute6_socket(struct net *net) { return NULL; } | 236 | static inline struct sock *mroute6_socket(struct net *net, struct sk_buff *skb) |
236 | static inline int ip6mr_sk_done(struct sock *sk) { return 0; } | 237 | { |
238 | return NULL; | ||
239 | } | ||
240 | static 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 | ||
232 | config 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 | |||
232 | config IPV6_PIMSM_V2 | 246 | config 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 | ||
54 | struct mr6_table { | 55 | struct 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 | ||
75 | struct ip6mr_rule { | ||
76 | struct fib_rule common; | ||
77 | }; | ||
78 | |||
79 | struct 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 | ||
95 | static struct kmem_cache *mrt_cachep __read_mostly; | 106 | static struct kmem_cache *mrt_cachep __read_mostly; |
96 | 107 | ||
108 | static struct mr6_table *ip6mr_new_table(struct net *net, u32 id); | ||
109 | static void ip6mr_free_table(struct mr6_table *mrt); | ||
110 | |||
97 | static int ip6_mr_forward(struct net *net, struct mr6_table *mrt, | 111 | static 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); |
99 | static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt, | 113 | static 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, | |||
101 | static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, | 115 | static 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); |
103 | static void mroute_clean_tables(struct mr6_table *mrt); | 117 | static void mroute_clean_tables(struct mr6_table *mrt); |
118 | static 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 | |||
124 | static 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 | |||
135 | static 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 | |||
149 | static 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 | |||
174 | static int ip6mr_rule_match(struct fib_rule *rule, struct flowi *flp, int flags) | ||
175 | { | ||
176 | return 1; | ||
177 | } | ||
178 | |||
179 | static const struct nla_policy ip6mr_rule_policy[FRA_MAX + 1] = { | ||
180 | FRA_GENERIC_POLICY, | ||
181 | }; | ||
182 | |||
183 | static 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 | |||
189 | static int ip6mr_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, | ||
190 | struct nlattr **tb) | ||
191 | { | ||
192 | return 1; | ||
193 | } | ||
194 | |||
195 | static 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 | |||
204 | static 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 | |||
219 | static 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 | |||
244 | err2: | ||
245 | kfree(mrt); | ||
246 | err1: | ||
247 | fib_rules_unregister(ops); | ||
248 | return err; | ||
249 | } | ||
250 | |||
251 | static 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 | |||
263 | static struct mr6_table *ip6mr_get_table(struct net *net, u32 id) | ||
264 | { | ||
265 | return net->ipv6.mrt6; | ||
266 | } | ||
267 | |||
268 | static 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 | |||
275 | static 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 | |||
281 | static void __net_exit ip6mr_rules_exit(struct net *net) | ||
282 | { | ||
283 | ip6mr_free_table(net->ipv6.mrt6); | ||
284 | } | ||
285 | #endif | ||
286 | |||
287 | static 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 | |||
320 | static 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 | ||
108 | struct ipmr_mfc_iter { | 329 | struct 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 { | |||
115 | static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net, | 337 | static 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 | ||
145 | struct ipmr_vif_iter { | 367 | struct 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, | |||
165 | static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos) | 388 | static 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 | ||
199 | static int ip6mr_vif_seq_show(struct seq_file *seq, void *v) | 430 | static 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 | ||
242 | static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos) | 473 | static 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) | |||
293 | static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v) | 531 | static 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) | |||
305 | static int ipmr_mfc_seq_show(struct seq_file *seq, void *v) | 542 | static 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 | ||
466 | static struct net_device *ip6mr_reg_vif(struct net *net) | 720 | static 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 | ||
1024 | static int __net_init ip6mr_net_init(struct net *net) | 1286 | static 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 |
1062 | proc_cache_fail: | 1305 | proc_cache_fail: |
1063 | proc_net_remove(net, "ip6_mr_vif"); | 1306 | proc_net_remove(net, "ip6_mr_vif"); |
1064 | proc_vif_fail: | 1307 | proc_vif_fail: |
1065 | kfree(mrt); | 1308 | ip6mr_rules_exit(net); |
1066 | #endif | 1309 | #endif |
1067 | fail: | 1310 | fail: |
1068 | return err; | 1311 | return err; |
@@ -1070,15 +1313,11 @@ fail: | |||
1070 | 1313 | ||
1071 | static void __net_exit ip6mr_net_exit(struct net *net) | 1314 | static 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 | ||
1084 | static struct pernet_operations ip6mr_net_ops = { | 1323 | static struct pernet_operations ip6mr_net_ops = { |
@@ -1279,28 +1518,39 @@ static int ip6mr_sk_init(struct mr6_table *mrt, struct sock *sk) | |||
1279 | 1518 | ||
1280 | int ip6mr_sk_done(struct sock *sk) | 1519 | int 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 | ||
1301 | struct sock *mroute6_socket(struct net *net) | 1543 | struct 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 | ||