aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHannes Frederic Sowa <hannes@stressinduktion.org>2014-01-12 20:45:22 -0500
committerDavid S. Miller <davem@davemloft.net>2014-01-14 20:37:25 -0500
commit95f4a45de1a0f172b35451fc52283290adb21f6e (patch)
tree04574bc5a4f4b60133b3dbc72c5174a9f847b3b4
parent7c4b5175f65f31e0cd9867a6ddc3171007dfc110 (diff)
net: avoid reference counter overflows on fib_rules in multicast forwarding
Bob Falken reported that after 4G packets, multicast forwarding stopped working. This was because of a rule reference counter overflow which freed the rule as soon as the overflow happend. This patch solves this by adding the FIB_LOOKUP_NOREF flag to fib_rules_lookup calls. This is safe even from non-rcu locked sections as in this case the flag only implies not taking a reference to the rule, which we don't need at all. Rules only hold references to the namespace, which are guaranteed to be available during the call of the non-rcu protected function reg_vif_xmit because of the interface reference which itself holds a reference to the net namespace. Fixes: f0ad0860d01e47 ("ipv4: ipmr: support multiple tables") Fixes: d1db275dd3f6e4 ("ipv6: ip6mr: support multiple tables") Reported-by: Bob Falken <NetFestivalHaveFun@gmx.com> Cc: Patrick McHardy <kaber@trash.net> Cc: Thomas Graf <tgraf@suug.ch> Cc: Julian Anastasov <ja@ssi.bg> Cc: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Acked-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/ipmr.c7
-rw-r--r--net/ipv6/ip6mr.c7
2 files changed, 10 insertions, 4 deletions
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 62212c772a4b..1672409f5ba5 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -157,9 +157,12 @@ static struct mr_table *ipmr_get_table(struct net *net, u32 id)
157static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4, 157static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4,
158 struct mr_table **mrt) 158 struct mr_table **mrt)
159{ 159{
160 struct ipmr_result res;
161 struct fib_lookup_arg arg = { .result = &res, };
162 int err; 160 int err;
161 struct ipmr_result res;
162 struct fib_lookup_arg arg = {
163 .result = &res,
164 .flags = FIB_LOOKUP_NOREF,
165 };
163 166
164 err = fib_rules_lookup(net->ipv4.mr_rules_ops, 167 err = fib_rules_lookup(net->ipv4.mr_rules_ops,
165 flowi4_to_flowi(flp4), 0, &arg); 168 flowi4_to_flowi(flp4), 0, &arg);
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index f365310bfcca..0eb4038a4d63 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -141,9 +141,12 @@ static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)
141static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6, 141static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
142 struct mr6_table **mrt) 142 struct mr6_table **mrt)
143{ 143{
144 struct ip6mr_result res;
145 struct fib_lookup_arg arg = { .result = &res, };
146 int err; 144 int err;
145 struct ip6mr_result res;
146 struct fib_lookup_arg arg = {
147 .result = &res,
148 .flags = FIB_LOOKUP_NOREF,
149 };
147 150
148 err = fib_rules_lookup(net->ipv6.mr6_rules_ops, 151 err = fib_rules_lookup(net->ipv6.mr6_rules_ops,
149 flowi6_to_flowi(flp6), 0, &arg); 152 flowi6_to_flowi(flp6), 0, &arg);