diff options
author | Benjamin Thery <benjamin.thery@bull.net> | 2009-01-21 23:56:16 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-01-22 16:57:34 -0500 |
commit | cf958ae377ee2545ae70cf48d38e7eb4308c27ea (patch) | |
tree | f304ea66b789f4287968fcaa57831cd4fa8e2576 | |
parent | 70a269e6c9c9b38b1a37dce068c59e9a912f8578 (diff) |
netns: ipmr: dynamically allocate vif_table
Preliminary work to make IPv6 multicast routing netns-aware.
Dynamically allocate interface table vif_table and move it to
struct netns_ipv4, and update MIF_EXISTS() macro.
At the moment, vif_table is only referenced in init_net.
Signed-off-by: Benjamin Thery <benjamin.thery@bull.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/netns/ipv4.h | 2 | ||||
-rw-r--r-- | net/ipv4/ipmr.c | 109 |
2 files changed, 70 insertions, 41 deletions
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index 4f00722c7478..edbcccbbc318 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h | |||
@@ -57,6 +57,8 @@ struct netns_ipv4 { | |||
57 | 57 | ||
58 | #ifdef CONFIG_IP_MROUTE | 58 | #ifdef CONFIG_IP_MROUTE |
59 | struct sock *mroute_sk; | 59 | struct sock *mroute_sk; |
60 | struct vif_device *vif_table; | ||
61 | int maxvif; | ||
60 | #endif | 62 | #endif |
61 | }; | 63 | }; |
62 | #endif | 64 | #endif |
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index ac324b702e8b..75a5f79cc226 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c | |||
@@ -77,10 +77,7 @@ static DEFINE_RWLOCK(mrt_lock); | |||
77 | * Multicast router control variables | 77 | * Multicast router control variables |
78 | */ | 78 | */ |
79 | 79 | ||
80 | static struct vif_device vif_table[MAXVIFS]; /* Devices */ | 80 | #define VIF_EXISTS(_net, _idx) ((_net)->ipv4.vif_table[_idx].dev != NULL) |
81 | static int maxvif; | ||
82 | |||
83 | #define VIF_EXISTS(idx) (vif_table[idx].dev != NULL) | ||
84 | 81 | ||
85 | static int mroute_do_assert; /* Set in PIM assert */ | 82 | static int mroute_do_assert; /* Set in PIM assert */ |
86 | static int mroute_do_pim; | 83 | static int mroute_do_pim; |
@@ -286,10 +283,10 @@ static int vif_delete(int vifi, int notify) | |||
286 | struct net_device *dev; | 283 | struct net_device *dev; |
287 | struct in_device *in_dev; | 284 | struct in_device *in_dev; |
288 | 285 | ||
289 | if (vifi < 0 || vifi >= maxvif) | 286 | if (vifi < 0 || vifi >= init_net.ipv4.maxvif) |
290 | return -EADDRNOTAVAIL; | 287 | return -EADDRNOTAVAIL; |
291 | 288 | ||
292 | v = &vif_table[vifi]; | 289 | v = &init_net.ipv4.vif_table[vifi]; |
293 | 290 | ||
294 | write_lock_bh(&mrt_lock); | 291 | write_lock_bh(&mrt_lock); |
295 | dev = v->dev; | 292 | dev = v->dev; |
@@ -305,13 +302,13 @@ static int vif_delete(int vifi, int notify) | |||
305 | reg_vif_num = -1; | 302 | reg_vif_num = -1; |
306 | #endif | 303 | #endif |
307 | 304 | ||
308 | if (vifi+1 == maxvif) { | 305 | if (vifi+1 == init_net.ipv4.maxvif) { |
309 | int tmp; | 306 | int tmp; |
310 | for (tmp=vifi-1; tmp>=0; tmp--) { | 307 | for (tmp=vifi-1; tmp>=0; tmp--) { |
311 | if (VIF_EXISTS(tmp)) | 308 | if (VIF_EXISTS(&init_net, tmp)) |
312 | break; | 309 | break; |
313 | } | 310 | } |
314 | maxvif = tmp+1; | 311 | init_net.ipv4.maxvif = tmp+1; |
315 | } | 312 | } |
316 | 313 | ||
317 | write_unlock_bh(&mrt_lock); | 314 | write_unlock_bh(&mrt_lock); |
@@ -411,8 +408,9 @@ static void ipmr_update_thresholds(struct mfc_cache *cache, unsigned char *ttls) | |||
411 | cache->mfc_un.res.maxvif = 0; | 408 | cache->mfc_un.res.maxvif = 0; |
412 | memset(cache->mfc_un.res.ttls, 255, MAXVIFS); | 409 | memset(cache->mfc_un.res.ttls, 255, MAXVIFS); |
413 | 410 | ||
414 | for (vifi=0; vifi<maxvif; vifi++) { | 411 | for (vifi = 0; vifi < init_net.ipv4.maxvif; vifi++) { |
415 | if (VIF_EXISTS(vifi) && ttls[vifi] && ttls[vifi] < 255) { | 412 | if (VIF_EXISTS(&init_net, vifi) && |
413 | ttls[vifi] && ttls[vifi] < 255) { | ||
416 | cache->mfc_un.res.ttls[vifi] = ttls[vifi]; | 414 | cache->mfc_un.res.ttls[vifi] = ttls[vifi]; |
417 | if (cache->mfc_un.res.minvif > vifi) | 415 | if (cache->mfc_un.res.minvif > vifi) |
418 | cache->mfc_un.res.minvif = vifi; | 416 | cache->mfc_un.res.minvif = vifi; |
@@ -425,13 +423,13 @@ static void ipmr_update_thresholds(struct mfc_cache *cache, unsigned char *ttls) | |||
425 | static int vif_add(struct vifctl *vifc, int mrtsock) | 423 | static int vif_add(struct vifctl *vifc, int mrtsock) |
426 | { | 424 | { |
427 | int vifi = vifc->vifc_vifi; | 425 | int vifi = vifc->vifc_vifi; |
428 | struct vif_device *v = &vif_table[vifi]; | 426 | struct vif_device *v = &init_net.ipv4.vif_table[vifi]; |
429 | struct net_device *dev; | 427 | struct net_device *dev; |
430 | struct in_device *in_dev; | 428 | struct in_device *in_dev; |
431 | int err; | 429 | int err; |
432 | 430 | ||
433 | /* Is vif busy ? */ | 431 | /* Is vif busy ? */ |
434 | if (VIF_EXISTS(vifi)) | 432 | if (VIF_EXISTS(&init_net, vifi)) |
435 | return -EADDRINUSE; | 433 | return -EADDRINUSE; |
436 | 434 | ||
437 | switch (vifc->vifc_flags) { | 435 | switch (vifc->vifc_flags) { |
@@ -509,8 +507,8 @@ static int vif_add(struct vifctl *vifc, int mrtsock) | |||
509 | if (v->flags&VIFF_REGISTER) | 507 | if (v->flags&VIFF_REGISTER) |
510 | reg_vif_num = vifi; | 508 | reg_vif_num = vifi; |
511 | #endif | 509 | #endif |
512 | if (vifi+1 > maxvif) | 510 | if (vifi+1 > init_net.ipv4.maxvif) |
513 | maxvif = vifi+1; | 511 | init_net.ipv4.maxvif = vifi+1; |
514 | write_unlock_bh(&mrt_lock); | 512 | write_unlock_bh(&mrt_lock); |
515 | return 0; | 513 | return 0; |
516 | } | 514 | } |
@@ -849,8 +847,8 @@ static void mroute_clean_tables(struct sock *sk) | |||
849 | /* | 847 | /* |
850 | * Shut down all active vif entries | 848 | * Shut down all active vif entries |
851 | */ | 849 | */ |
852 | for (i=0; i<maxvif; i++) { | 850 | for (i = 0; i < init_net.ipv4.maxvif; i++) { |
853 | if (!(vif_table[i].flags&VIFF_STATIC)) | 851 | if (!(init_net.ipv4.vif_table[i].flags&VIFF_STATIC)) |
854 | vif_delete(i, 0); | 852 | vif_delete(i, 0); |
855 | } | 853 | } |
856 | 854 | ||
@@ -1088,11 +1086,11 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) | |||
1088 | case SIOCGETVIFCNT: | 1086 | case SIOCGETVIFCNT: |
1089 | if (copy_from_user(&vr, arg, sizeof(vr))) | 1087 | if (copy_from_user(&vr, arg, sizeof(vr))) |
1090 | return -EFAULT; | 1088 | return -EFAULT; |
1091 | if (vr.vifi >= maxvif) | 1089 | if (vr.vifi >= init_net.ipv4.maxvif) |
1092 | return -EINVAL; | 1090 | return -EINVAL; |
1093 | read_lock(&mrt_lock); | 1091 | read_lock(&mrt_lock); |
1094 | vif=&vif_table[vr.vifi]; | 1092 | vif = &init_net.ipv4.vif_table[vr.vifi]; |
1095 | if (VIF_EXISTS(vr.vifi)) { | 1093 | if (VIF_EXISTS(&init_net, vr.vifi)) { |
1096 | vr.icount = vif->pkt_in; | 1094 | vr.icount = vif->pkt_in; |
1097 | vr.ocount = vif->pkt_out; | 1095 | vr.ocount = vif->pkt_out; |
1098 | vr.ibytes = vif->bytes_in; | 1096 | vr.ibytes = vif->bytes_in; |
@@ -1140,8 +1138,8 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v | |||
1140 | 1138 | ||
1141 | if (event != NETDEV_UNREGISTER) | 1139 | if (event != NETDEV_UNREGISTER) |
1142 | return NOTIFY_DONE; | 1140 | return NOTIFY_DONE; |
1143 | v=&vif_table[0]; | 1141 | v = &init_net.ipv4.vif_table[0]; |
1144 | for (ct=0; ct<maxvif; ct++,v++) { | 1142 | for (ct = 0; ct < init_net.ipv4.maxvif; ct++, v++) { |
1145 | if (v->dev == dev) | 1143 | if (v->dev == dev) |
1146 | vif_delete(ct, 1); | 1144 | vif_delete(ct, 1); |
1147 | } | 1145 | } |
@@ -1204,7 +1202,7 @@ static inline int ipmr_forward_finish(struct sk_buff *skb) | |||
1204 | static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi) | 1202 | static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi) |
1205 | { | 1203 | { |
1206 | const struct iphdr *iph = ip_hdr(skb); | 1204 | const struct iphdr *iph = ip_hdr(skb); |
1207 | struct vif_device *vif = &vif_table[vifi]; | 1205 | struct vif_device *vif = &init_net.ipv4.vif_table[vifi]; |
1208 | struct net_device *dev; | 1206 | struct net_device *dev; |
1209 | struct rtable *rt; | 1207 | struct rtable *rt; |
1210 | int encap = 0; | 1208 | int encap = 0; |
@@ -1305,8 +1303,8 @@ out_free: | |||
1305 | static int ipmr_find_vif(struct net_device *dev) | 1303 | static int ipmr_find_vif(struct net_device *dev) |
1306 | { | 1304 | { |
1307 | int ct; | 1305 | int ct; |
1308 | for (ct=maxvif-1; ct>=0; ct--) { | 1306 | for (ct = init_net.ipv4.maxvif-1; ct >= 0; ct--) { |
1309 | if (vif_table[ct].dev == dev) | 1307 | if (init_net.ipv4.vif_table[ct].dev == dev) |
1310 | break; | 1308 | break; |
1311 | } | 1309 | } |
1312 | return ct; | 1310 | return ct; |
@@ -1326,7 +1324,7 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local | |||
1326 | /* | 1324 | /* |
1327 | * Wrong interface: drop packet and (maybe) send PIM assert. | 1325 | * Wrong interface: drop packet and (maybe) send PIM assert. |
1328 | */ | 1326 | */ |
1329 | if (vif_table[vif].dev != skb->dev) { | 1327 | if (init_net.ipv4.vif_table[vif].dev != skb->dev) { |
1330 | int true_vifi; | 1328 | int true_vifi; |
1331 | 1329 | ||
1332 | if (skb->rtable->fl.iif == 0) { | 1330 | if (skb->rtable->fl.iif == 0) { |
@@ -1362,8 +1360,8 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local | |||
1362 | goto dont_forward; | 1360 | goto dont_forward; |
1363 | } | 1361 | } |
1364 | 1362 | ||
1365 | vif_table[vif].pkt_in++; | 1363 | init_net.ipv4.vif_table[vif].pkt_in++; |
1366 | vif_table[vif].bytes_in += skb->len; | 1364 | init_net.ipv4.vif_table[vif].bytes_in += skb->len; |
1367 | 1365 | ||
1368 | /* | 1366 | /* |
1369 | * Forward the frame | 1367 | * Forward the frame |
@@ -1500,7 +1498,7 @@ static int __pim_rcv(struct sk_buff *skb, unsigned int pimlen) | |||
1500 | 1498 | ||
1501 | read_lock(&mrt_lock); | 1499 | read_lock(&mrt_lock); |
1502 | if (reg_vif_num >= 0) | 1500 | if (reg_vif_num >= 0) |
1503 | reg_dev = vif_table[reg_vif_num].dev; | 1501 | reg_dev = init_net.ipv4.vif_table[reg_vif_num].dev; |
1504 | if (reg_dev) | 1502 | if (reg_dev) |
1505 | dev_hold(reg_dev); | 1503 | dev_hold(reg_dev); |
1506 | read_unlock(&mrt_lock); | 1504 | read_unlock(&mrt_lock); |
@@ -1581,7 +1579,7 @@ ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm) | |||
1581 | { | 1579 | { |
1582 | int ct; | 1580 | int ct; |
1583 | struct rtnexthop *nhp; | 1581 | struct rtnexthop *nhp; |
1584 | struct net_device *dev = vif_table[c->mfc_parent].dev; | 1582 | struct net_device *dev = init_net.ipv4.vif_table[c->mfc_parent].dev; |
1585 | u8 *b = skb_tail_pointer(skb); | 1583 | u8 *b = skb_tail_pointer(skb); |
1586 | struct rtattr *mp_head; | 1584 | struct rtattr *mp_head; |
1587 | 1585 | ||
@@ -1597,7 +1595,7 @@ ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm) | |||
1597 | nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); | 1595 | nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); |
1598 | nhp->rtnh_flags = 0; | 1596 | nhp->rtnh_flags = 0; |
1599 | nhp->rtnh_hops = c->mfc_un.res.ttls[ct]; | 1597 | nhp->rtnh_hops = c->mfc_un.res.ttls[ct]; |
1600 | nhp->rtnh_ifindex = vif_table[ct].dev->ifindex; | 1598 | nhp->rtnh_ifindex = init_net.ipv4.vif_table[ct].dev->ifindex; |
1601 | nhp->rtnh_len = sizeof(*nhp); | 1599 | nhp->rtnh_len = sizeof(*nhp); |
1602 | } | 1600 | } |
1603 | } | 1601 | } |
@@ -1672,11 +1670,11 @@ struct ipmr_vif_iter { | |||
1672 | static struct vif_device *ipmr_vif_seq_idx(struct ipmr_vif_iter *iter, | 1670 | static struct vif_device *ipmr_vif_seq_idx(struct ipmr_vif_iter *iter, |
1673 | loff_t pos) | 1671 | loff_t pos) |
1674 | { | 1672 | { |
1675 | for (iter->ct = 0; iter->ct < maxvif; ++iter->ct) { | 1673 | for (iter->ct = 0; iter->ct < init_net.ipv4.maxvif; ++iter->ct) { |
1676 | if (!VIF_EXISTS(iter->ct)) | 1674 | if (!VIF_EXISTS(&init_net, iter->ct)) |
1677 | continue; | 1675 | continue; |
1678 | if (pos-- == 0) | 1676 | if (pos-- == 0) |
1679 | return &vif_table[iter->ct]; | 1677 | return &init_net.ipv4.vif_table[iter->ct]; |
1680 | } | 1678 | } |
1681 | return NULL; | 1679 | return NULL; |
1682 | } | 1680 | } |
@@ -1697,10 +1695,10 @@ static void *ipmr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
1697 | if (v == SEQ_START_TOKEN) | 1695 | if (v == SEQ_START_TOKEN) |
1698 | return ipmr_vif_seq_idx(iter, 0); | 1696 | return ipmr_vif_seq_idx(iter, 0); |
1699 | 1697 | ||
1700 | while (++iter->ct < maxvif) { | 1698 | while (++iter->ct < init_net.ipv4.maxvif) { |
1701 | if (!VIF_EXISTS(iter->ct)) | 1699 | if (!VIF_EXISTS(&init_net, iter->ct)) |
1702 | continue; | 1700 | continue; |
1703 | return &vif_table[iter->ct]; | 1701 | return &init_net.ipv4.vif_table[iter->ct]; |
1704 | } | 1702 | } |
1705 | return NULL; | 1703 | return NULL; |
1706 | } | 1704 | } |
@@ -1722,7 +1720,7 @@ static int ipmr_vif_seq_show(struct seq_file *seq, void *v) | |||
1722 | 1720 | ||
1723 | seq_printf(seq, | 1721 | seq_printf(seq, |
1724 | "%2Zd %-10s %8ld %7ld %8ld %7ld %05X %08X %08X\n", | 1722 | "%2Zd %-10s %8ld %7ld %8ld %7ld %05X %08X %08X\n", |
1725 | vif - vif_table, | 1723 | vif - init_net.ipv4.vif_table, |
1726 | name, vif->bytes_in, vif->pkt_in, | 1724 | name, vif->bytes_in, vif->pkt_in, |
1727 | vif->bytes_out, vif->pkt_out, | 1725 | vif->bytes_out, vif->pkt_out, |
1728 | vif->flags, vif->local, vif->remote); | 1726 | vif->flags, vif->local, vif->remote); |
@@ -1864,9 +1862,9 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v) | |||
1864 | mfc->mfc_un.res.wrong_if); | 1862 | mfc->mfc_un.res.wrong_if); |
1865 | for (n = mfc->mfc_un.res.minvif; | 1863 | for (n = mfc->mfc_un.res.minvif; |
1866 | n < mfc->mfc_un.res.maxvif; n++ ) { | 1864 | n < mfc->mfc_un.res.maxvif; n++ ) { |
1867 | if (VIF_EXISTS(n) | 1865 | if (VIF_EXISTS(&init_net, n) && |
1868 | && mfc->mfc_un.res.ttls[n] < 255) | 1866 | mfc->mfc_un.res.ttls[n] < 255) |
1869 | seq_printf(seq, | 1867 | seq_printf(seq, |
1870 | " %2d:%-3d", | 1868 | " %2d:%-3d", |
1871 | n, mfc->mfc_un.res.ttls[n]); | 1869 | n, mfc->mfc_un.res.ttls[n]); |
1872 | } | 1870 | } |
@@ -1913,6 +1911,29 @@ static struct net_protocol pim_protocol = { | |||
1913 | /* | 1911 | /* |
1914 | * Setup for IP multicast routing | 1912 | * Setup for IP multicast routing |
1915 | */ | 1913 | */ |
1914 | static int __net_init ipmr_net_init(struct net *net) | ||
1915 | { | ||
1916 | int err = 0; | ||
1917 | |||
1918 | net->ipv4.vif_table = kcalloc(MAXVIFS, sizeof(struct vif_device), | ||
1919 | GFP_KERNEL); | ||
1920 | if (!net->ipv4.vif_table) { | ||
1921 | err = -ENOMEM; | ||
1922 | goto fail; | ||
1923 | } | ||
1924 | fail: | ||
1925 | return err; | ||
1926 | } | ||
1927 | |||
1928 | static void __net_exit ipmr_net_exit(struct net *net) | ||
1929 | { | ||
1930 | kfree(net->ipv4.vif_table); | ||
1931 | } | ||
1932 | |||
1933 | static struct pernet_operations ipmr_net_ops = { | ||
1934 | .init = ipmr_net_init, | ||
1935 | .exit = ipmr_net_exit, | ||
1936 | }; | ||
1916 | 1937 | ||
1917 | int __init ip_mr_init(void) | 1938 | int __init ip_mr_init(void) |
1918 | { | 1939 | { |
@@ -1925,6 +1946,10 @@ int __init ip_mr_init(void) | |||
1925 | if (!mrt_cachep) | 1946 | if (!mrt_cachep) |
1926 | return -ENOMEM; | 1947 | return -ENOMEM; |
1927 | 1948 | ||
1949 | err = register_pernet_subsys(&ipmr_net_ops); | ||
1950 | if (err) | ||
1951 | goto reg_pernet_fail; | ||
1952 | |||
1928 | setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0); | 1953 | setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0); |
1929 | err = register_netdevice_notifier(&ip_mr_notifier); | 1954 | err = register_netdevice_notifier(&ip_mr_notifier); |
1930 | if (err) | 1955 | if (err) |
@@ -1945,6 +1970,8 @@ proc_vif_fail: | |||
1945 | #endif | 1970 | #endif |
1946 | reg_notif_fail: | 1971 | reg_notif_fail: |
1947 | del_timer(&ipmr_expire_timer); | 1972 | del_timer(&ipmr_expire_timer); |
1973 | unregister_pernet_subsys(&ipmr_net_ops); | ||
1974 | reg_pernet_fail: | ||
1948 | kmem_cache_destroy(mrt_cachep); | 1975 | kmem_cache_destroy(mrt_cachep); |
1949 | return err; | 1976 | return err; |
1950 | } | 1977 | } |