diff options
| author | Patrick McHardy <kaber@trash.net> | 2010-04-13 01:03:19 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2010-04-13 17:49:32 -0400 |
| commit | e258beb22f4d3ea3dc88586ffc9c990d0eb03380 (patch) | |
| tree | 7bd4dc984757894cbfb355189e9172a4a566596c | |
| parent | f74e49b5613206fb18468bdc9509a1db746aa01b (diff) | |
ipv4: ipmr: move unres_queue and timer to per-namespace data
The unres_queue is currently shared between all namespaces. Following patches
will additionally allow to create multiple multicast routing tables in each
namespace. Having a single shared queue for all these users seems to excessive,
move the queue and the cleanup timer to the per-namespace data to unshare it.
As a side-effect, this fixes a bug in the seq file iteration functions: the
first entry returned is always from the current namespace, entries returned
after that may belong to any namespace.
Signed-off-by: Patrick McHardy <kaber@trash.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 | 70 |
2 files changed, 31 insertions, 41 deletions
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index 2764994c9136..b15e518f952a 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h | |||
| @@ -60,6 +60,8 @@ struct netns_ipv4 { | |||
| 60 | 60 | ||
| 61 | #ifdef CONFIG_IP_MROUTE | 61 | #ifdef CONFIG_IP_MROUTE |
| 62 | struct sock *mroute_sk; | 62 | struct sock *mroute_sk; |
| 63 | struct timer_list ipmr_expire_timer; | ||
| 64 | struct mfc_cache *mfc_unres_queue; | ||
| 63 | struct mfc_cache **mfc_cache_array; | 65 | struct mfc_cache **mfc_cache_array; |
| 64 | struct vif_device *vif_table; | 66 | struct vif_device *vif_table; |
| 65 | int maxvif; | 67 | int maxvif; |
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 9d4f6d1340a4..d6aa65e2b08f 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c | |||
| @@ -80,8 +80,6 @@ static DEFINE_RWLOCK(mrt_lock); | |||
| 80 | 80 | ||
| 81 | #define VIF_EXISTS(_net, _idx) ((_net)->ipv4.vif_table[_idx].dev != NULL) | 81 | #define VIF_EXISTS(_net, _idx) ((_net)->ipv4.vif_table[_idx].dev != NULL) |
| 82 | 82 | ||
| 83 | static struct mfc_cache *mfc_unres_queue; /* Queue of unresolved entries */ | ||
| 84 | |||
| 85 | /* Special spinlock for queue of unresolved entries */ | 83 | /* Special spinlock for queue of unresolved entries */ |
| 86 | static DEFINE_SPINLOCK(mfc_unres_lock); | 84 | static DEFINE_SPINLOCK(mfc_unres_lock); |
| 87 | 85 | ||
| @@ -100,8 +98,6 @@ static int ipmr_cache_report(struct net *net, | |||
| 100 | struct sk_buff *pkt, vifi_t vifi, int assert); | 98 | struct sk_buff *pkt, vifi_t vifi, int assert); |
| 101 | static int ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm); | 99 | static int ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm); |
| 102 | 100 | ||
| 103 | static struct timer_list ipmr_expire_timer; | ||
| 104 | |||
| 105 | /* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */ | 101 | /* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */ |
| 106 | 102 | ||
| 107 | static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v) | 103 | static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v) |
| @@ -364,25 +360,26 @@ static void ipmr_destroy_unres(struct mfc_cache *c) | |||
| 364 | } | 360 | } |
| 365 | 361 | ||
| 366 | 362 | ||
| 367 | /* Single timer process for all the unresolved queue. */ | 363 | /* Timer process for the unresolved queue. */ |
| 368 | 364 | ||
| 369 | static void ipmr_expire_process(unsigned long dummy) | 365 | static void ipmr_expire_process(unsigned long arg) |
| 370 | { | 366 | { |
| 367 | struct net *net = (struct net *)arg; | ||
| 371 | unsigned long now; | 368 | unsigned long now; |
| 372 | unsigned long expires; | 369 | unsigned long expires; |
| 373 | struct mfc_cache *c, **cp; | 370 | struct mfc_cache *c, **cp; |
| 374 | 371 | ||
| 375 | if (!spin_trylock(&mfc_unres_lock)) { | 372 | if (!spin_trylock(&mfc_unres_lock)) { |
| 376 | mod_timer(&ipmr_expire_timer, jiffies+HZ/10); | 373 | mod_timer(&net->ipv4.ipmr_expire_timer, jiffies+HZ/10); |
| 377 | return; | 374 | return; |
| 378 | } | 375 | } |
| 379 | 376 | ||
| 380 | if (mfc_unres_queue == NULL) | 377 | if (net->ipv4.mfc_unres_queue == NULL) |
| 381 | goto out; | 378 | goto out; |
| 382 | 379 | ||
| 383 | now = jiffies; | 380 | now = jiffies; |
| 384 | expires = 10*HZ; | 381 | expires = 10*HZ; |
| 385 | cp = &mfc_unres_queue; | 382 | cp = &net->ipv4.mfc_unres_queue; |
| 386 | 383 | ||
| 387 | while ((c=*cp) != NULL) { | 384 | while ((c=*cp) != NULL) { |
| 388 | if (time_after(c->mfc_un.unres.expires, now)) { | 385 | if (time_after(c->mfc_un.unres.expires, now)) { |
| @@ -398,8 +395,8 @@ static void ipmr_expire_process(unsigned long dummy) | |||
| 398 | ipmr_destroy_unres(c); | 395 | ipmr_destroy_unres(c); |
| 399 | } | 396 | } |
| 400 | 397 | ||
| 401 | if (mfc_unres_queue != NULL) | 398 | if (net->ipv4.mfc_unres_queue != NULL) |
| 402 | mod_timer(&ipmr_expire_timer, jiffies + expires); | 399 | mod_timer(&net->ipv4.ipmr_expire_timer, jiffies + expires); |
| 403 | 400 | ||
| 404 | out: | 401 | out: |
| 405 | spin_unlock(&mfc_unres_lock); | 402 | spin_unlock(&mfc_unres_lock); |
| @@ -708,9 +705,8 @@ ipmr_cache_unresolved(struct net *net, vifi_t vifi, struct sk_buff *skb) | |||
| 708 | const struct iphdr *iph = ip_hdr(skb); | 705 | const struct iphdr *iph = ip_hdr(skb); |
| 709 | 706 | ||
| 710 | spin_lock_bh(&mfc_unres_lock); | 707 | spin_lock_bh(&mfc_unres_lock); |
| 711 | for (c=mfc_unres_queue; c; c=c->next) { | 708 | for (c=net->ipv4.mfc_unres_queue; c; c=c->next) { |
| 712 | if (net_eq(mfc_net(c), net) && | 709 | if (c->mfc_mcastgrp == iph->daddr && |
| 713 | c->mfc_mcastgrp == iph->daddr && | ||
| 714 | c->mfc_origin == iph->saddr) | 710 | c->mfc_origin == iph->saddr) |
| 715 | break; | 711 | break; |
| 716 | } | 712 | } |
| @@ -751,10 +747,10 @@ ipmr_cache_unresolved(struct net *net, vifi_t vifi, struct sk_buff *skb) | |||
| 751 | } | 747 | } |
| 752 | 748 | ||
| 753 | atomic_inc(&net->ipv4.cache_resolve_queue_len); | 749 | atomic_inc(&net->ipv4.cache_resolve_queue_len); |
| 754 | c->next = mfc_unres_queue; | 750 | c->next = net->ipv4.mfc_unres_queue; |
| 755 | mfc_unres_queue = c; | 751 | net->ipv4.mfc_unres_queue = c; |
| 756 | 752 | ||
| 757 | mod_timer(&ipmr_expire_timer, c->mfc_un.unres.expires); | 753 | mod_timer(&net->ipv4.ipmr_expire_timer, c->mfc_un.unres.expires); |
| 758 | } | 754 | } |
| 759 | 755 | ||
| 760 | /* | 756 | /* |
| @@ -849,18 +845,17 @@ static int ipmr_mfc_add(struct net *net, struct mfcctl *mfc, int mrtsock) | |||
| 849 | * need to send on the frames and tidy up. | 845 | * need to send on the frames and tidy up. |
| 850 | */ | 846 | */ |
| 851 | spin_lock_bh(&mfc_unres_lock); | 847 | spin_lock_bh(&mfc_unres_lock); |
| 852 | for (cp = &mfc_unres_queue; (uc=*cp) != NULL; | 848 | for (cp = &net->ipv4.mfc_unres_queue; (uc=*cp) != NULL; |
| 853 | cp = &uc->next) { | 849 | cp = &uc->next) { |
| 854 | if (net_eq(mfc_net(uc), net) && | 850 | if (uc->mfc_origin == c->mfc_origin && |
| 855 | uc->mfc_origin == c->mfc_origin && | ||
| 856 | uc->mfc_mcastgrp == c->mfc_mcastgrp) { | 851 | uc->mfc_mcastgrp == c->mfc_mcastgrp) { |
| 857 | *cp = uc->next; | 852 | *cp = uc->next; |
| 858 | atomic_dec(&net->ipv4.cache_resolve_queue_len); | 853 | atomic_dec(&net->ipv4.cache_resolve_queue_len); |
| 859 | break; | 854 | break; |
| 860 | } | 855 | } |
| 861 | } | 856 | } |
| 862 | if (mfc_unres_queue == NULL) | 857 | if (net->ipv4.mfc_unres_queue == NULL) |
| 863 | del_timer(&ipmr_expire_timer); | 858 | del_timer(&net->ipv4.ipmr_expire_timer); |
| 864 | spin_unlock_bh(&mfc_unres_lock); | 859 | spin_unlock_bh(&mfc_unres_lock); |
| 865 | 860 | ||
| 866 | if (uc) { | 861 | if (uc) { |
| @@ -912,14 +907,9 @@ static void mroute_clean_tables(struct net *net) | |||
| 912 | struct mfc_cache *c, **cp; | 907 | struct mfc_cache *c, **cp; |
| 913 | 908 | ||
| 914 | spin_lock_bh(&mfc_unres_lock); | 909 | spin_lock_bh(&mfc_unres_lock); |
| 915 | cp = &mfc_unres_queue; | 910 | cp = &net->ipv4.mfc_unres_queue; |
| 916 | while ((c = *cp) != NULL) { | 911 | while ((c = *cp) != NULL) { |
| 917 | if (!net_eq(mfc_net(c), net)) { | ||
| 918 | cp = &c->next; | ||
| 919 | continue; | ||
| 920 | } | ||
| 921 | *cp = c->next; | 912 | *cp = c->next; |
| 922 | |||
| 923 | ipmr_destroy_unres(c); | 913 | ipmr_destroy_unres(c); |
| 924 | } | 914 | } |
| 925 | spin_unlock_bh(&mfc_unres_lock); | 915 | spin_unlock_bh(&mfc_unres_lock); |
| @@ -1819,11 +1809,10 @@ static struct mfc_cache *ipmr_mfc_seq_idx(struct net *net, | |||
| 1819 | return mfc; | 1809 | return mfc; |
| 1820 | read_unlock(&mrt_lock); | 1810 | read_unlock(&mrt_lock); |
| 1821 | 1811 | ||
| 1822 | it->cache = &mfc_unres_queue; | 1812 | it->cache = &net->ipv4.mfc_unres_queue; |
| 1823 | spin_lock_bh(&mfc_unres_lock); | 1813 | spin_lock_bh(&mfc_unres_lock); |
| 1824 | for (mfc = mfc_unres_queue; mfc; mfc = mfc->next) | 1814 | for (mfc = net->ipv4.mfc_unres_queue; mfc; mfc = mfc->next) |
| 1825 | if (net_eq(mfc_net(mfc), net) && | 1815 | if (pos-- == 0) |
| 1826 | pos-- == 0) | ||
| 1827 | return mfc; | 1816 | return mfc; |
| 1828 | spin_unlock_bh(&mfc_unres_lock); | 1817 | spin_unlock_bh(&mfc_unres_lock); |
| 1829 | 1818 | ||
| @@ -1857,7 +1846,7 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
| 1857 | if (mfc->next) | 1846 | if (mfc->next) |
| 1858 | return mfc->next; | 1847 | return mfc->next; |
| 1859 | 1848 | ||
| 1860 | if (it->cache == &mfc_unres_queue) | 1849 | if (it->cache == &net->ipv4.mfc_unres_queue) |
| 1861 | goto end_of_list; | 1850 | goto end_of_list; |
| 1862 | 1851 | ||
| 1863 | BUG_ON(it->cache != net->ipv4.mfc_cache_array); | 1852 | BUG_ON(it->cache != net->ipv4.mfc_cache_array); |
| @@ -1870,13 +1859,11 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
| 1870 | 1859 | ||
