diff options
-rw-r--r-- | include/linux/fib_rules.h | 1 | ||||
-rw-r--r-- | include/linux/mroute.h | 3 | ||||
-rw-r--r-- | include/net/netns/ipv4.h | 5 | ||||
-rw-r--r-- | include/net/raw.h | 1 | ||||
-rw-r--r-- | net/ipv4/Kconfig | 14 | ||||
-rw-r--r-- | net/ipv4/ipmr.c | 399 |
6 files changed, 361 insertions, 62 deletions
diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h index 405e41139a4d..04a397619ebe 100644 --- a/include/linux/fib_rules.h +++ b/include/linux/fib_rules.h | |||
@@ -21,6 +21,7 @@ | |||
21 | #define FIB_RULES_IPV4 AF_INET | 21 | #define FIB_RULES_IPV4 AF_INET |
22 | #define FIB_RULES_IPV6 AF_INET6 | 22 | #define FIB_RULES_IPV6 AF_INET6 |
23 | #define FIB_RULES_DECNET AF_DECnet | 23 | #define FIB_RULES_DECNET AF_DECnet |
24 | #define FIB_RULES_IPMR 128 | ||
24 | 25 | ||
25 | struct fib_rule_hdr { | 26 | struct fib_rule_hdr { |
26 | __u8 family; | 27 | __u8 family; |
diff --git a/include/linux/mroute.h b/include/linux/mroute.h index 7ff6c77d6008..fa04b246c9ae 100644 --- a/include/linux/mroute.h +++ b/include/linux/mroute.h | |||
@@ -27,7 +27,8 @@ | |||
27 | #define MRT_DEL_MFC (MRT_BASE+5) /* Delete a multicast forwarding entry */ | 27 | #define MRT_DEL_MFC (MRT_BASE+5) /* Delete a multicast forwarding entry */ |
28 | #define MRT_VERSION (MRT_BASE+6) /* Get the kernel multicast version */ | 28 | #define MRT_VERSION (MRT_BASE+6) /* Get the kernel multicast version */ |
29 | #define MRT_ASSERT (MRT_BASE+7) /* Activate PIM assert mode */ | 29 | #define MRT_ASSERT (MRT_BASE+7) /* Activate PIM assert mode */ |
30 | #define MRT_PIM (MRT_BASE+8) /* enable PIM code */ | 30 | #define MRT_PIM (MRT_BASE+8) /* enable PIM code */ |
31 | #define MRT_TABLE (MRT_BASE+9) /* Specify mroute table ID */ | ||
31 | 32 | ||
32 | #define SIOCGETVIFCNT SIOCPROTOPRIVATE /* IP protocol privates */ | 33 | #define SIOCGETVIFCNT SIOCPROTOPRIVATE /* IP protocol privates */ |
33 | #define SIOCGETSGCNT (SIOCPROTOPRIVATE+1) | 34 | #define SIOCGETSGCNT (SIOCPROTOPRIVATE+1) |
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index 72e762ab3e5d..ae07feec6446 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h | |||
@@ -59,7 +59,12 @@ struct netns_ipv4 { | |||
59 | atomic_t rt_genid; | 59 | atomic_t rt_genid; |
60 | 60 | ||
61 | #ifdef CONFIG_IP_MROUTE | 61 | #ifdef CONFIG_IP_MROUTE |
62 | #ifndef CONFIG_IP_MROUTE_MULTIPLE_TABLES | ||
62 | struct mr_table *mrt; | 63 | struct mr_table *mrt; |
64 | #else | ||
65 | struct list_head mr_tables; | ||
66 | struct fib_rules_ops *mr_rules_ops; | ||
67 | #endif | ||
63 | #endif | 68 | #endif |
64 | }; | 69 | }; |
65 | #endif | 70 | #endif |
diff --git a/include/net/raw.h b/include/net/raw.h index 67cc64369432..43c57502659b 100644 --- a/include/net/raw.h +++ b/include/net/raw.h | |||
@@ -61,6 +61,7 @@ struct raw_sock { | |||
61 | /* inet_sock has to be the first member */ | 61 | /* inet_sock has to be the first member */ |
62 | struct inet_sock inet; | 62 | struct inet_sock inet; |
63 | struct icmp_filter filter; | 63 | struct icmp_filter filter; |
64 | u32 ipmr_table; | ||
64 | }; | 65 | }; |
65 | 66 | ||
66 | static inline struct raw_sock *raw_sk(const struct sock *sk) | 67 | static inline struct raw_sock *raw_sk(const struct sock *sk) |
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index c9a1c68767ff..be597749c385 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig | |||
@@ -250,6 +250,20 @@ config IP_MROUTE | |||
250 | <file:Documentation/networking/multicast.txt>. If you haven't heard | 250 | <file:Documentation/networking/multicast.txt>. If you haven't heard |
251 | about it, you don't need it. | 251 | about it, you don't need it. |
252 | 252 | ||
253 | config IP_MROUTE_MULTIPLE_TABLES | ||
254 | bool "IP: multicast policy routing" | ||
255 | depends on IP_ADVANCED_ROUTER | ||
256 | select FIB_RULES | ||
257 | help | ||
258 | Normally, a multicast router runs a userspace daemon and decides | ||
259 | what to do with a multicast packet based on the source and | ||
260 | destination addresses. If you say Y here, the multicast router | ||
261 | will also be able to take interfaces and packet marks into | ||
262 | account and run multiple instances of userspace daemons | ||
263 | simultaneously, each one handling a single table. | ||
264 | |||
265 | If unsure, say N. | ||
266 | |||
253 | config IP_PIMSM_V1 | 267 | config IP_PIMSM_V1 |
254 | bool "IP: PIM-SM version 1 support" | 268 | bool "IP: PIM-SM version 1 support" |
255 | depends on IP_MROUTE | 269 | depends on IP_MROUTE |
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 498f4e907d52..5df5fd74c6d1 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c | |||
@@ -63,12 +63,15 @@ | |||
63 | #include <net/ipip.h> | 63 | #include <net/ipip.h> |
64 | #include <net/checksum.h> | 64 | #include <net/checksum.h> |
65 | #include <net/netlink.h> | 65 | #include <net/netlink.h> |
66 | #include <net/fib_rules.h> | ||
66 | 67 | ||
67 | #if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2) | 68 | #if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2) |
68 | #define CONFIG_IP_PIMSM 1 | 69 | #define CONFIG_IP_PIMSM 1 |
69 | #endif | 70 | #endif |
70 | 71 | ||
71 | struct mr_table { | 72 | struct mr_table { |
73 | struct list_head list; | ||
74 | u32 id; | ||
72 | struct sock *mroute_sk; | 75 | struct sock *mroute_sk; |
73 | struct timer_list ipmr_expire_timer; | 76 | struct timer_list ipmr_expire_timer; |
74 | struct list_head mfc_unres_queue; | 77 | struct list_head mfc_unres_queue; |
@@ -83,6 +86,14 @@ struct mr_table { | |||
83 | #endif | 86 | #endif |
84 | }; | 87 | }; |
85 | 88 | ||
89 | struct ipmr_rule { | ||
90 | struct fib_rule common; | ||
91 | }; | ||
92 | |||
93 | struct ipmr_result { | ||
94 | struct mr_table *mrt; | ||
95 | }; | ||
96 | |||
86 | /* Big lock, protecting vif table, mrt cache and mroute socket state. | 97 | /* Big lock, protecting vif table, mrt cache and mroute socket state. |
87 | Note that the changes are semaphored via rtnl_lock. | 98 | Note that the changes are semaphored via rtnl_lock. |
88 | */ | 99 | */ |
@@ -108,6 +119,7 @@ static DEFINE_SPINLOCK(mfc_unres_lock); | |||
108 | 119 | ||
109 | static struct kmem_cache *mrt_cachep __read_mostly; | 120 | static struct kmem_cache *mrt_cachep __read_mostly; |
110 | 121 | ||
122 | static struct mr_table *ipmr_new_table(struct net *net, u32 id); | ||
111 | static int ip_mr_forward(struct net *net, struct mr_table *mrt, | 123 | static int ip_mr_forward(struct net *net, struct mr_table *mrt, |
112 | struct sk_buff *skb, struct mfc_cache *cache, | 124 | struct sk_buff *skb, struct mfc_cache *cache, |
113 | int local); | 125 | int local); |
@@ -115,6 +127,206 @@ static int ipmr_cache_report(struct mr_table *mrt, | |||
115 | struct sk_buff *pkt, vifi_t vifi, int assert); | 127 | struct sk_buff *pkt, vifi_t vifi, int assert); |
116 | static int ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb, | 128 | static int ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb, |
117 | struct mfc_cache *c, struct rtmsg *rtm); | 129 | struct mfc_cache *c, struct rtmsg *rtm); |
130 | static void ipmr_expire_process(unsigned long arg); | ||
131 | |||
132 | #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES | ||
133 | #define ipmr_for_each_table(mrt, net) \ | ||
134 | list_for_each_entry_rcu(mrt, &net->ipv4.mr_tables, list) | ||
135 | |||
136 | static struct mr_table *ipmr_get_table(struct net *net, u32 id) | ||
137 | { | ||
138 | struct mr_table *mrt; | ||
139 | |||
140 | ipmr_for_each_table(mrt, net) { | ||
141 | if (mrt->id == id) | ||
142 | return mrt; | ||
143 | } | ||
144 | return NULL; | ||
145 | } | ||
146 | |||
147 | static int ipmr_fib_lookup(struct net *net, struct flowi *flp, | ||
148 | struct mr_table **mrt) | ||
149 | { | ||
150 | struct ipmr_result res; | ||
151 | struct fib_lookup_arg arg = { .result = &res, }; | ||
152 | int err; | ||
153 | |||
154 | err = fib_rules_lookup(net->ipv4.mr_rules_ops, flp, 0, &arg); | ||
155 | if (err < 0) | ||
156 | return err; | ||
157 | *mrt = res.mrt; | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static int ipmr_rule_action(struct fib_rule *rule, struct flowi *flp, | ||
162 | int flags, struct fib_lookup_arg *arg) | ||
163 | { | ||
164 | struct ipmr_result *res = arg->result; | ||
165 | struct mr_table *mrt; | ||
166 | |||
167 | switch (rule->action) { | ||
168 | case FR_ACT_TO_TBL: | ||
169 | break; | ||
170 | case FR_ACT_UNREACHABLE: | ||
171 | return -ENETUNREACH; | ||
172 | case FR_ACT_PROHIBIT: | ||
173 | return -EACCES; | ||
174 | case FR_ACT_BLACKHOLE: | ||
175 | default: | ||
176 | return -EINVAL; | ||
177 | } | ||
178 | |||
179 | mrt = ipmr_get_table(rule->fr_net, rule->table); | ||
180 | if (mrt == NULL) | ||
181 | return -EAGAIN; | ||
182 | res->mrt = mrt; | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static int ipmr_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) | ||
187 | { | ||
188 | return 1; | ||
189 | } | ||
190 | |||
191 | static const struct nla_policy ipmr_rule_policy[FRA_MAX + 1] = { | ||
192 | FRA_GENERIC_POLICY, | ||
193 | }; | ||
194 | |||
195 | static int ipmr_rule_configure(struct fib_rule *rule, struct sk_buff *skb, | ||
196 | struct fib_rule_hdr *frh, struct nlattr **tb) | ||
197 | { | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static int ipmr_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, | ||
202 | struct nlattr **tb) | ||
203 | { | ||
204 | return 1; | ||
205 | } | ||
206 | |||
207 | static int ipmr_rule_fill(struct fib_rule *rule, struct sk_buff *skb, | ||
208 | struct fib_rule_hdr *frh) | ||
209 | { | ||
210 | frh->dst_len = 0; | ||
211 | frh->src_len = 0; | ||
212 | frh->tos = 0; | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static struct fib_rules_ops ipmr_rules_ops_template = { | ||
217 | .family = FIB_RULES_IPMR, | ||
218 | .rule_size = sizeof(struct ipmr_rule), | ||
219 | .addr_size = sizeof(u32), | ||
220 | .action = ipmr_rule_action, | ||
221 | .match = ipmr_rule_match, | ||
222 | .configure = ipmr_rule_configure, | ||
223 | .compare = ipmr_rule_compare, | ||
224 | .default_pref = fib_default_rule_pref, | ||
225 | .fill = ipmr_rule_fill, | ||
226 | .nlgroup = RTNLGRP_IPV4_RULE, | ||
227 | .policy = ipmr_rule_policy, | ||
228 | .owner = THIS_MODULE, | ||
229 | }; | ||
230 | |||
231 | static int __net_init ipmr_rules_init(struct net *net) | ||
232 | { | ||
233 | struct fib_rules_ops *ops; | ||
234 | struct mr_table *mrt; | ||
235 | int err; | ||
236 | |||
237 | ops = fib_rules_register(&ipmr_rules_ops_template, net); | ||
238 | if (IS_ERR(ops)) | ||
239 | return PTR_ERR(ops); | ||
240 | |||
241 | INIT_LIST_HEAD(&net->ipv4.mr_tables); | ||
242 | |||
243 | mrt = ipmr_new_table(net, RT_TABLE_DEFAULT); | ||
244 | if (mrt == NULL) { | ||
245 | err = -ENOMEM; | ||
246 | goto err1; | ||
247 | } | ||
248 | |||
249 | err = fib_default_rule_add(ops, 0x7fff, RT_TABLE_DEFAULT, 0); | ||
250 | if (err < 0) | ||
251 | goto err2; | ||
252 | |||
253 | net->ipv4.mr_rules_ops = ops; | ||
254 | return 0; | ||
255 | |||
256 | err2: | ||
257 | kfree(mrt); | ||
258 | err1: | ||
259 | fib_rules_unregister(ops); | ||
260 | return err; | ||
261 | } | ||
262 | |||
263 | static void __net_exit ipmr_rules_exit(struct net *net) | ||
264 | { | ||
265 | struct mr_table *mrt, *next; | ||
266 | |||
267 | list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) | ||
268 | kfree(mrt); | ||
269 | fib_rules_unregister(net->ipv4.mr_rules_ops); | ||
270 | } | ||
271 | #else | ||
272 | #define ipmr_for_each_table(mrt, net) \ | ||
273 | for (mrt = net->ipv4.mrt; mrt; mrt = NULL) | ||
274 | |||
275 | static struct mr_table *ipmr_get_table(struct net *net, u32 id) | ||
276 | { | ||
277 | return net->ipv4.mrt; | ||
278 | } | ||
279 | |||
280 | static int ipmr_fib_lookup(struct net *net, struct flowi *flp, | ||
281 | struct mr_table **mrt) | ||
282 | { | ||
283 | *mrt = net->ipv4.mrt; | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static int __net_init ipmr_rules_init(struct net *net) | ||
288 | { | ||
289 | net->ipv4.mrt = ipmr_new_table(net, RT_TABLE_DEFAULT); | ||
290 | return net->ipv4.mrt ? 0 : -ENOMEM; | ||
291 | } | ||
292 | |||
293 | static void __net_exit ipmr_rules_exit(struct net *net) | ||
294 | { | ||
295 | kfree(net->ipv4.mrt); | ||
296 | } | ||
297 | #endif | ||
298 | |||
299 | static struct mr_table *ipmr_new_table(struct net *net, u32 id) | ||
300 | { | ||
301 | struct mr_table *mrt; | ||
302 | unsigned int i; | ||
303 | |||
304 | mrt = ipmr_get_table(net, id); | ||
305 | if (mrt != NULL) | ||
306 | return mrt; | ||
307 | |||
308 | mrt = kzalloc(sizeof(*mrt), GFP_KERNEL); | ||
309 | if (mrt == NULL) | ||
310 | return NULL; | ||
311 | mrt->id = id; | ||
312 | |||
313 | /* Forwarding cache */ | ||
314 | for (i = 0; i < MFC_LINES; i++) | ||
315 | INIT_LIST_HEAD(&mrt->mfc_cache_array[i]); | ||
316 | |||
317 | INIT_LIST_HEAD(&mrt->mfc_unres_queue); | ||
318 | |||
319 | setup_timer(&mrt->ipmr_expire_timer, ipmr_expire_process, | ||
320 | (unsigned long)mrt); | ||
321 | |||
322 | #ifdef CONFIG_IP_PIMSM | ||
323 | mrt->mroute_reg_vif_num = -1; | ||
324 | #endif | ||
325 | #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES | ||
326 | list_add_tail_rcu(&mrt->list, &net->ipv4.mr_tables); | ||
327 | #endif | ||
328 | return mrt; | ||
329 | } | ||
118 | 330 | ||
119 | /* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */ | 331 | /* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */ |
120 | 332 | ||
@@ -215,7 +427,17 @@ failure: | |||
215 | static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) | 427 | static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) |
216 | { | 428 | { |
217 | struct net *net = dev_net(dev); | 429 | struct net *net = dev_net(dev); |
218 | struct mr_table *mrt = net->ipv4.mrt; | 430 | struct mr_table *mrt; |
431 | struct flowi fl = { | ||
432 | .oif = dev->ifindex, | ||
433 | .iif = skb->skb_iif, | ||
434 | .mark = skb->mark, | ||
435 | }; | ||
436 | int err; | ||
437 | |||
438 | err = ipmr_fib_lookup(net, &fl, &mrt); | ||
439 | if (err < 0) | ||
440 | return err; | ||
219 | 441 | ||
220 | read_lock(&mrt_lock); | 442 | read_lock(&mrt_lock); |
221 | dev->stats.tx_bytes += skb->len; | 443 | dev->stats.tx_bytes += skb->len; |
@@ -240,12 +462,18 @@ static void reg_vif_setup(struct net_device *dev) | |||
240 | dev->features |= NETIF_F_NETNS_LOCAL; | 462 | dev->features |= NETIF_F_NETNS_LOCAL; |
241 | } | 463 | } |
242 | 464 | ||
243 | static struct net_device *ipmr_reg_vif(struct net *net) | 465 | static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt) |
244 | { | 466 | { |
245 | struct net_device *dev; | 467 | struct net_device *dev; |
246 | struct in_device *in_dev; | 468 | struct in_device *in_dev; |
469 | char name[IFNAMSIZ]; | ||
470 | |||
471 | if (mrt->id == RT_TABLE_DEFAULT) | ||
472 | sprintf(name, "pimreg"); | ||
473 | else | ||
474 | sprintf(name, "pimreg%u", mrt->id); | ||
247 | 475 | ||
248 | dev = alloc_netdev(0, "pimreg", reg_vif_setup); | 476 | dev = alloc_netdev(0, name, reg_vif_setup); |
249 | 477 | ||
250 | if (dev == NULL) | 478 | if (dev == NULL) |
251 | return NULL; | 479 | return NULL; |
@@ -461,7 +689,7 @@ static int vif_add(struct net *net, struct mr_table *mrt, | |||
461 | */ | 689 | */ |
462 | if (mrt->mroute_reg_vif_num >= 0) | 690 | if (mrt->mroute_reg_vif_num >= 0) |
463 | return -EADDRINUSE; | 691 | return -EADDRINUSE; |
464 | dev = ipmr_reg_vif(net); | 692 | dev = ipmr_reg_vif(net, mrt); |
465 | if (!dev) | 693 | if (!dev) |
466 | return -ENOBUFS; | 694 | return -ENOBUFS; |
467 | err = dev_set_allmulti(dev, 1); | 695 | err = dev_set_allmulti(dev, 1); |
@@ -928,17 +1156,19 @@ static void mroute_clean_tables(struct mr_table *mrt) | |||
928 | static void mrtsock_destruct(struct sock *sk) | 1156 | static void mrtsock_destruct(struct sock *sk) |
929 | { | 1157 | { |
930 | struct net *net = sock_net(sk); | 1158 | struct net *net = sock_net(sk); |
931 | struct mr_table *mrt = net->ipv4.mrt; | 1159 | struct mr_table *mrt; |
932 | 1160 | ||
933 | rtnl_lock(); | 1161 | rtnl_lock(); |
934 | if (sk == mrt->mroute_sk) { | 1162 | ipmr_for_each_table(mrt, net) { |
935 | IPV4_DEVCONF_ALL(net, MC_FORWARDING)--; | 1163 | if (sk == mrt->mroute_sk) { |
1164 | IPV4_DEVCONF_ALL(net, MC_FORWARDING)--; | ||
936 | 1165 | ||
937 | write_lock_bh(&mrt_lock); | 1166 | write_lock_bh(&mrt_lock); |
938 | mrt->mroute_sk = NULL; | 1167 | mrt->mroute_sk = NULL; |
939 | write_unlock_bh(&mrt_lock); | 1168 | write_unlock_bh(&mrt_lock); |
940 | 1169 | ||
941 | mroute_clean_tables(mrt); | 1170 | mroute_clean_tables(mrt); |
1171 | } | ||
942 | } | 1172 | } |
943 | rtnl_unlock(); | 1173 | rtnl_unlock(); |
944 | } | 1174 | } |
@@ -956,7 +1186,11 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi | |||
956 | struct vifctl vif; | 1186 | struct vifctl vif; |
957 | struct mfcctl mfc; | 1187 | struct mfcctl mfc; |
958 | struct net *net = sock_net(sk); | 1188 | struct net *net = sock_net(sk); |
959 | struct mr_table *mrt = net->ipv4.mrt; | 1189 | struct mr_table *mrt; |
1190 | |||
1191 | mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT); | ||
1192 | if (mrt == NULL) | ||
1193 | return -ENOENT; | ||
960 | 1194 | ||
961 | if (optname != MRT_INIT) { | 1195 | if (optname != MRT_INIT) { |
962 | if (sk != mrt->mroute_sk && !capable(CAP_NET_ADMIN)) | 1196 | if (sk != mrt->mroute_sk && !capable(CAP_NET_ADMIN)) |
@@ -1055,6 +1289,27 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi | |||
1055 | return ret; | 1289 | return ret; |
1056 | } | 1290 | } |
1057 | #endif | 1291 | #endif |
1292 | #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES | ||
1293 | case MRT_TABLE: | ||
1294 | { | ||
1295 | u32 v; | ||
1296 | |||
1297 | if (optlen != sizeof(u32)) | ||
1298 | return -EINVAL; | ||
1299 | if (get_user(v, (u32 __user *)optval)) | ||
1300 | return -EFAULT; | ||
1301 | if (sk == mrt->mroute_sk) | ||
1302 | return -EBUSY; | ||
1303 | |||
1304 | rtnl_lock(); | ||
1305 | ret = 0; | ||
1306 | if (!ipmr_new_table(net, v)) | ||
1307 | ret = -ENOMEM; | ||
1308 | raw_sk(sk)->ipmr_table = v; | ||
1309 | rtnl_unlock(); | ||
1310 | return ret; | ||
1311 | } | ||
1312 | #endif | ||
1058 | /* | 1313 | /* |
1059 | * Spurious command, or MRT_VERSION which you cannot | 1314 | * Spurious command, or MRT_VERSION which you cannot |
1060 | * set. | 1315 | * set. |
@@ -1073,7 +1328,11 @@ int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int | |||
1073 | int olr; | 1328 | int olr; |
1074 | int val; | 1329 | int val; |
1075 | struct net *net = sock_net(sk); | 1330 | struct net *net = sock_net(sk); |
1076 | struct mr_table *mrt = net->ipv4.mrt; | 1331 | struct mr_table *mrt; |
1332 | |||
1333 | mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT); | ||
1334 | if (mrt == NULL) | ||
1335 | return -ENOENT; | ||
1077 | 1336 | ||
1078 | if (optname != MRT_VERSION && | 1337 | if (optname != MRT_VERSION && |
1079 | #ifdef CONFIG_IP_PIMSM | 1338 | #ifdef CONFIG_IP_PIMSM |
@@ -1115,7 +1374,11 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) | |||
1115 | struct vif_device *vif; | 1374 | struct vif_device *vif; |
1116 | struct mfc_cache *c; | 1375 | struct mfc_cache *c; |
1117 | struct net *net = sock_net(sk); | 1376 | struct net *net = sock_net(sk); |
1118 | struct mr_table *mrt = net->ipv4.mrt; | 1377 | struct mr_table *mrt; |
1378 | |||
1379 | mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT); | ||
1380 | if (mrt == NULL) | ||
1381 | return -ENOENT; | ||
1119 | 1382 | ||
1120 | switch (cmd) { | 1383 | switch (cmd) { |
1121 | case SIOCGETVIFCNT: | 1384 | case SIOCGETVIFCNT: |
@@ -1166,17 +1429,20 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v | |||
1166 | { | 1429 | { |
1167 | struct net_device *dev = ptr; | 1430 | struct net_device *dev = ptr; |
1168 | struct net *net = dev_net(dev); | 1431 | struct net *net = dev_net(dev); |
1169 | struct mr_table *mrt = net->ipv4.mrt; | 1432 | struct mr_table *mrt; |
1170 | struct vif_device *v; | 1433 | struct vif_device *v; |
1171 | int ct; | 1434 | int ct; |
1172 | LIST_HEAD(list); | 1435 | LIST_HEAD(list); |
1173 | 1436 | ||
1174 | if (event != NETDEV_UNREGISTER) | 1437 | if (event != NETDEV_UNREGISTER) |
1175 | return NOTIFY_DONE; | 1438 | return NOTIFY_DONE; |
1176 | v = &mrt->vif_table[0]; | 1439 | |
1177 | for (ct = 0; ct < mrt->maxvif; ct++, v++) { | 1440 | ipmr_for_each_table(mrt, net) { |
1178 | if (v->dev == dev) | 1441 | v = &mrt->vif_table[0]; |
1179 | vif_delete(mrt, ct, 1, &list); | 1442 | for (ct = 0; ct < mrt->maxvif; ct++, v++) { |
1443 | if (v->dev == dev) | ||
1444 | vif_delete(mrt, ct, 1, &list); | ||
1445 | } | ||
1180 | } | 1446 | } |
1181 | unregister_netdevice_many(&list); | 1447 | unregister_netdevice_many(&list); |
1182 | return NOTIFY_DONE; | 1448 | return NOTIFY_DONE; |
@@ -1443,8 +1709,9 @@ int ip_mr_input(struct sk_buff *skb) | |||
1443 | { | 1709 | { |
1444 | struct mfc_cache *cache; | 1710 | struct mfc_cache *cache; |
1445 | struct net *net = dev_net(skb->dev); | 1711 | struct net *net = dev_net(skb->dev); |
1446 | struct mr_table *mrt = net->ipv4.mrt; | ||
1447 | int local = skb_rtable(skb)->rt_flags & RTCF_LOCAL; | 1712 | int local = skb_rtable(skb)->rt_flags & RTCF_LOCAL; |
1713 | struct mr_table *mrt; | ||
1714 | int err; | ||
1448 | 1715 | ||
1449 | /* Packet is looped back after forward, it should not be | 1716 | /* Packet is looped back after forward, it should not be |
1450 | forwarded second time, but still can be delivered locally. | 1717 | forwarded second time, but still can be delivered locally. |
@@ -1452,6 +1719,10 @@ int ip_mr_input(struct sk_buff *skb) | |||
1452 | if (IPCB(skb)->flags&IPSKB_FORWARDED) | 1719 | if (IPCB(skb)->flags&IPSKB_FORWARDED) |
1453 | goto dont_forward; | 1720 | goto dont_forward; |
1454 | 1721 | ||
1722 | err = ipmr_fib_lookup(net, &skb_rtable(skb)->fl, &mrt); | ||
1723 | if (err < 0) | ||
1724 | return err; | ||
1725 | |||
1455 | if (!local) { | 1726 | if (!local) { |
1456 | if (IPCB(skb)->opt.router_alert) { | 1727 | if (IPCB(skb)->opt.router_alert) { |
1457 | if (ip_call_ra_chain(skb)) | 1728 | if (ip_call_ra_chain(skb)) |
@@ -1522,12 +1793,11 @@ dont_forward: | |||
1522 | } | 1793 | } |
1523 | 1794 | ||
1524 | #ifdef CONFIG_IP_PIMSM | 1795 | #ifdef CONFIG_IP_PIMSM |
1525 | static int __pim_rcv(struct sk_buff *skb, unsigned int pimlen) | 1796 | static int __pim_rcv(struct mr_table *mrt, struct sk_buff *skb, |
1797 | unsigned int pimlen) | ||
1526 | { | 1798 | { |
1527 | struct net_device *reg_dev = NULL; | 1799 | struct net_device *reg_dev = NULL; |
1528 | struct iphdr *encap; | 1800 | struct iphdr *encap; |
1529 | struct net *net = dev_net(skb->dev); | ||
1530 | struct mr_table *mrt = net->ipv4.mrt; | ||
1531 | 1801 | ||
1532 | encap = (struct iphdr *)(skb_transport_header(skb) + pimlen); | 1802 | encap = (struct iphdr *)(skb_transport_header(skb) + pimlen); |
1533 | /* | 1803 | /* |
@@ -1578,18 +1848,21 @@ int pim_rcv_v1(struct sk_buff * skb) | |||
1578 | { | 1848 | { |
1579 | struct igmphdr *pim; | 1849 | struct igmphdr *pim; |
1580 | struct net *net = dev_net(skb->dev); | 1850 | struct net *net = dev_net(skb->dev); |
1581 | struct mr_table *mrt = net->ipv4.mrt; | 1851 | struct mr_table *mrt; |
1582 | 1852 | ||
1583 | if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr))) | 1853 | if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr))) |
1584 | goto drop; | 1854 | goto drop; |
1585 | 1855 | ||
1586 | pim = igmp_hdr(skb); | 1856 | pim = igmp_hdr(skb); |
1587 | 1857 | ||
1858 | if (ipmr_fib_lookup(net, &skb_rtable(skb)->fl, &mrt) < 0) | ||
1859 | goto drop; | ||
1860 | |||
1588 | if (!mrt->mroute_do_pim || | 1861 | if (!mrt->mroute_do_pim || |
1589 | pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER) | 1862 | pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER) |
1590 | goto drop; | 1863 | goto drop; |
1591 | 1864 | ||
1592 | if (__pim_rcv(skb, sizeof(*pim))) { | 1865 | if (__pim_rcv(mrt, skb, sizeof(*pim))) { |
1593 | drop: | 1866 | drop: |
1594 | kfree_skb(skb); | 1867 | kfree_skb(skb); |
1595 | } | 1868 | } |
@@ -1601,6 +1874,8 @@ drop: | |||
1601 | static int pim_rcv(struct sk_buff * skb) | 1874 | static int pim_rcv(struct sk_buff * skb) |
1602 | { | 1875 | { |
1603 | struct pimreghdr *pim; | 1876 | struct pimreghdr *pim; |
1877 | struct net *net = dev_net(skb->dev); | ||
1878 | struct mr_table *mrt; | ||
1604 | 1879 | ||
1605 | if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr))) | 1880 | if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr))) |
1606 | goto drop; | 1881 | goto drop; |
@@ -1612,7 +1887,10 @@ static int pim_rcv(struct sk_buff * skb) | |||
1612 | csum_fold(skb_checksum(skb, 0, skb->len, 0)))) | 1887 | csum_fold(skb_checksum(skb, 0, skb->len, 0)))) |
1613 | goto drop; | 1888 | goto drop; |
1614 | 1889 | ||
1615 | if (__pim_rcv(skb, sizeof(*pim))) { | 1890 | if (ipmr_fib_lookup(net, &skb_rtable(skb)->fl, &mrt) < 0) |
1891 | goto drop; | ||
1892 | |||
1893 | if (__pim_rcv(mrt, skb, sizeof(*pim))) { | ||
1616 | drop: | 1894 | drop: |
1617 | kfree_skb(skb); | 1895 | kfree_skb(skb); |
1618 | } | 1896 | } |
@@ -1663,10 +1941,14 @@ int ipmr_get_route(struct net *net, | |||
1663 | struct sk_buff *skb, struct rtmsg *rtm, int nowait) | 1941 | struct sk_buff *skb, struct rtmsg *rtm, int nowait) |
1664 | { | 1942 | { |
1665 | int err; | 1943 | int err; |
1666 | struct mr_table *mrt = net->ipv4.mrt; | 1944 | struct mr_table *mrt; |
1667 | struct mfc_cache *cache; | 1945 | struct mfc_cache *cache; |
1668 | struct rtable *rt = skb_rtable(skb); | 1946 | struct rtable *rt = skb_rtable(skb); |
1669 | 1947 | ||
1948 | mrt = ipmr_get_table(net, RT_TABLE_DEFAULT); | ||
1949 | if (mrt == NULL) | ||
1950 | return -ENOENT; | ||
1951 | |||
1670 | read_lock(&mrt_lock); | 1952 | read_lock(&mrt_lock); |
1671 | cache = ipmr_cache_find(mrt, rt->rt_src, rt->rt_dst); | 1953 | cache = ipmr_cache_find(mrt, rt->rt_src, rt->rt_dst); |
1672 | 1954 | ||
@@ -1717,6 +1999,7 @@ int ipmr_get_route(struct net *net, | |||
1717 | */ | 1999 | */ |
1718 | struct ipmr_vif_iter { | 2000 | struct ipmr_vif_iter { |
1719 | struct seq_net_private p; | 2001 | struct seq_net_private p; |
2002 | struct mr_table *mrt; | ||
1720 | int ct; | 2003 | int ct; |
1721 | }; | 2004 | }; |
1722 | 2005 | ||
@@ -1724,7 +2007,7 @@ static struct vif_device *ipmr_vif_seq_idx(struct net *net, | |||
1724 | struct ipmr_vif_iter *iter, | 2007 | struct ipmr_vif_iter *iter, |
1725 | loff_t pos) | 2008 | loff_t pos) |
1726 | { | 2009 | { |
1727 | struct mr_table *mrt = net->ipv4.mrt; | 2010 | struct mr_table *mrt = iter->mrt; |
1728 | 2011 | ||
1729 | for (iter->ct = 0; iter->ct < mrt->maxvif; ++iter->ct) { | 2012 | for (iter->ct = 0; iter->ct < mrt->maxvif; ++iter->ct) { |
1730 | if (!VIF_EXISTS(mrt, iter->ct)) | 2013 | if (!VIF_EXISTS(mrt, iter->ct)) |
@@ -1738,7 +2021,15 @@ static struct vif_device *ipmr_vif_seq_idx(struct net *net, | |||
1738 | static void *ipmr_vif_seq_start(struct seq_file *seq, loff_t *pos) | 2021 | static void *ipmr_vif_seq_start(struct seq_file *seq, loff_t *pos) |
1739 | __acquires(mrt_lock) | 2022 | __acquires(mrt_lock) |
1740 | { | 2023 | { |
2024 | struct ipmr_vif_iter *iter = seq->private; | ||
1741 | struct net *net = seq_file_net(seq); | 2025 | struct net *net = seq_file_net(seq); |
2026 | struct mr_table *mrt; | ||
2027 | |||
2028 | mrt = ipmr_get_table(net, RT_TABLE_DEFAULT); | ||
2029 | if (mrt == NULL) | ||
2030 | return ERR_PTR(-ENOENT); | ||
2031 | |||
2032 | iter->mrt = mrt; | ||
1742 | 2033 | ||
1743 | read_lock(&mrt_lock); | 2034 | read_lock(&mrt_lock); |
1744 | return *pos ? ipmr_vif_seq_idx(net, seq->private, *pos - 1) | 2035 | return *pos ? ipmr_vif_seq_idx(net, seq->private, *pos - 1) |
@@ -1749,7 +2040,7 @@ static void *ipmr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
1749 | { | 2040 | { |
1750 | struct ipmr_vif_iter *iter = seq->private; | 2041 | struct ipmr_vif_iter *iter = seq->private; |
1751 | struct net *net = seq_file_net(seq); | 2042 | struct net *net = seq_file_net(seq); |
1752 | struct mr_table *mrt = net->ipv4.mrt; | 2043 | struct mr_table *mrt = iter->mrt; |
1753 | 2044 | ||
1754 | ++*pos; | 2045 | ++*pos; |
1755 | if (v == SEQ_START_TOKEN) | 2046 | if (v == SEQ_START_TOKEN) |
@@ -1771,8 +2062,8 @@ static void ipmr_vif_seq_stop(struct seq_file *seq, void *v) | |||
1771 | 2062 | ||
1772 | static int ipmr_vif_seq_show(struct seq_file *seq, void *v) | 2063 | static int ipmr_vif_seq_show(struct seq_file *seq, void *v) |
1773 | { | 2064 | { |
1774 | struct net *net = seq_file_net(seq); | 2065 | struct ipmr_vif_iter *iter = seq->private; |
1775 | struct mr_table *mrt = net->ipv4.mrt; | 2066 | struct mr_table *mrt = iter->mrt; |
1776 | 2067 | ||
1777 | if (v == SEQ_START_TOKEN) { | 2068 | if (v == SEQ_START_TOKEN) { |
1778 | seq_puts(seq, | 2069 | seq_puts(seq, |
@@ -1814,6 +2105,7 @@ static const struct file_operations ipmr_vif_fops = { | |||
1814 | 2105 | ||
1815 | struct ipmr_mfc_iter { | 2106 | struct ipmr_mfc_iter { |
1816 | struct seq_net_private p; | 2107 | struct seq_net_private p; |
2108 | struct mr_table *mrt; | ||
1817 | struct list_head *cache; | 2109 | struct list_head *cache; |
1818 | int ct; | 2110 | int ct; |
1819 | }; | 2111 | }; |
@@ -1822,7 +2114,7 @@ struct ipmr_mfc_iter { | |||
1822 | static struct mfc_cache *ipmr_mfc_seq_idx(struct net *net, | 2114 | static struct mfc_cache *ipmr_mfc_seq_idx(struct net *net, |
1823 | struct ipmr_mfc_iter *it, loff_t pos) | 2115 | struct ipmr_mfc_iter *it, loff_t pos) |
1824 | { | 2116 | { |
1825 | struct mr_table *mrt = net->ipv4.mrt; | 2117 | struct mr_table *mrt = it->mrt; |
1826 | struct mfc_cache *mfc; | 2118 | struct mfc_cache *mfc; |
1827 | 2119 | ||
1828 | read_lock(&mrt_lock); | 2120 | read_lock(&mrt_lock); |
@@ -1850,7 +2142,13 @@ static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos) | |||
1850 | { | 2142 | { |
1851 | struct ipmr_mfc_iter *it = seq->private; | 2143 | struct ipmr_mfc_iter *it = seq->private; |
1852 | struct net *net = seq_file_net(seq); | 2144 | struct net *net = seq_file_net(seq); |
2145 | struct mr_table *mrt; | ||
2146 | |||
2147 | mrt = ipmr_get_table(net, RT_TABLE_DEFAULT); | ||
2148 | if (mrt == NULL) | ||
2149 | return ERR_PTR(-ENOENT); | ||
1853 | 2150 | ||
2151 | it->mrt = mrt; | ||
1854 | it->cache = NULL; | 2152 | it->cache = NULL; |
1855 | it->ct = 0; | 2153 | it->ct = 0; |
1856 | return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1) | 2154 | return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1) |
@@ -1862,7 +2160,7 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
1862 | struct mfc_cache *mfc = v; | 2160 | struct mfc_cache *mfc = v; |
1863 | struct ipmr_mfc_iter *it = seq->private; | 2161 | struct ipmr_mfc_iter *it = seq->private; |
1864 | struct net *net = seq_file_net(seq); | 2162 | struct net *net = seq_file_net(seq); |
1865 | struct mr_table *mrt = net->ipv4.mrt; | 2163 | struct mr_table *mrt = it->mrt; |
1866 | 2164 | ||
1867 | ++*pos; | 2165 | ++*pos; |
1868 | 2166 | ||
@@ -1903,8 +2201,7 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
1903 | static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v) | 2201 | static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v) |
1904 | { | 2202 | { |
1905 | struct ipmr_mfc_iter *it = seq->private; | 2203 | struct ipmr_mfc_iter *it = seq->private; |
1906 | struct net *net = seq_file_net(seq); | 2204 | struct mr_table *mrt = it->mrt; |
1907 | struct mr_table *mrt = net->ipv4.mrt; | ||
1908 | 2205 | ||
1909 | if (it->cache == &mrt->mfc_unres_queue) | 2206 | if (it->cache == &mrt->mfc_unres_queue) |
1910 | spin_unlock_bh(&mfc_unres_lock); | 2207 | spin_unlock_bh(&mfc_unres_lock); |
@@ -1915,8 +2212,6 @@ static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v) | |||
1915 | static int ipmr_mfc_seq_show(struct seq_file *seq, void *v) | 2212 | static int ipmr_mfc_seq_show(struct seq_file *seq, void *v) |
1916 | { | 2213 | { |
1917 | int n; | 2214 | int n; |
1918 | struct net *net = seq_file_net(seq); | ||
1919 | struct mr_table *mrt = net->ipv4.mrt; | ||
1920 | 2215 | ||
1921 | if (v == SEQ_START_TOKEN) { | 2216 | if (v == SEQ_START_TOKEN) { |
1922 | seq_puts(seq, | 2217 | seq_puts(seq, |
@@ -1924,6 +2219,7 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v) | |||
1924 | } else { | 2219 | } else { |
1925 | const struct mfc_cache *mfc = v; | 2220 | const struct mfc_cache *mfc = v; |
1926 | const struct ipmr_mfc_iter *it = seq->private; | 2221 | const struct ipmr_mfc_iter *it = seq->private; |
2222 | const struct mr_table *mrt = it->mrt; | ||
1927 | 2223 | ||
1928 | seq_printf(seq, "%08lX %08lX %-3hd", | 2224 | seq_printf(seq, "%08lX %08lX %-3hd", |
1929 | (unsigned long) mfc->mfc_mcastgrp, | 2225 | (unsigned long) mfc->mfc_mcastgrp, |
@@ -1989,28 +2285,11 @@ static const struct net_protocol pim_protocol = { | |||
1989 | */ | 2285 | */ |
1990 | static int __net_init ipmr_net_init(struct net *net) | 2286 | static int __net_init ipmr_net_init(struct net *net) |
1991 | { | 2287 | { |
1992 | struct mr_table *mrt; | 2288 | int err; |
1993 | unsigned int i; | ||
1994 | int err = 0; | ||
1995 | 2289 | ||
1996 | mrt = kzalloc(sizeof(*mrt), GFP_KERNEL); | 2290 | err = ipmr_rules_init(net); |
1997 | if (mrt == NULL) { | 2291 | if (err < 0) |
1998 | err = -ENOMEM; | ||
1999 | goto fail; | 2292 | goto fail; |
2000 | } | ||
2001 | |||
2002 | /* Forwarding cache */ | ||
2003 | for (i = 0; i < MFC_LINES; i++) | ||
2004 | INIT_LIST_HEAD(&mrt->mfc_cache_array[i]); | ||
2005 | |||
2006 | INIT_LIST_HEAD(&mrt->mfc_unres_queue); | ||
2007 | |||
2008 | setup_timer(&mrt->ipmr_expire_timer, ipmr_expire_process, | ||
2009 | (unsigned long)net); | ||
2010 | |||
2011 | #ifdef CONFIG_IP_PIMSM | ||
2012 | mrt->mroute_reg_vif_num = -1; | ||
2013 | #endif | ||
2014 | 2293 | ||
2015 | #ifdef CONFIG_PROC_FS | 2294 | #ifdef CONFIG_PROC_FS |
2016 | err = -ENOMEM; | 2295 | err = -ENOMEM; |
@@ -2019,15 +2298,13 @@ static int __net_init ipmr_net_init(struct net *net) | |||
2019 | if (!proc_net_fops_create(net, "ip_mr_cache", 0, &ipmr_mfc_fops)) | 2298 | if (!proc_net_fops_create(net, "ip_mr_cache", 0, &ipmr_mfc_fops)) |
2020 | goto proc_cache_fail; | 2299 | goto proc_cache_fail; |
2021 | #endif | 2300 | #endif |
2022 | |||
2023 | net->ipv4.mrt = mrt; | ||
2024 | return 0; | 2301 | return 0; |
2025 | 2302 | ||
2026 | #ifdef CONFIG_PROC_FS | 2303 | #ifdef CONFIG_PROC_FS |
2027 | proc_cache_fail: | 2304 | proc_cache_fail: |
2028 | proc_net_remove(net, "ip_mr_vif"); | 2305 | proc_net_remove(net, "ip_mr_vif"); |
2029 | proc_vif_fail: | 2306 | proc_vif_fail: |
2030 | kfree(mrt); | 2307 | ipmr_rules_exit(net); |
2031 | #endif | 2308 | #endif |
2032 | fail: | 2309 | fail: |
2033 | return err; | 2310 | return err; |
@@ -2039,7 +2316,7 @@ static void __net_exit ipmr_net_exit(struct net *net) | |||
2039 | proc_net_remove(net, "ip_mr_cache"); | 2316 | proc_net_remove(net, "ip_mr_cache"); |
2040 | proc_net_remove(net, "ip_mr_vif"); | 2317 | proc_net_remove(net, "ip_mr_vif"); |
2041 | #endif | 2318 | #endif |
2042 | kfree(net->ipv4.mrt); | 2319 | ipmr_rules_exit(net); |
2043 | } | 2320 | } |
2044 | 2321 | ||
2045 | static struct pernet_operations ipmr_net_ops = { | 2322 | static struct pernet_operations ipmr_net_ops = { |