Multicast routing stops functioning after 4G multicast packets recived.
Subsystems (3)
Hello,
Testing this patch as im typing this. will check status in about 12hours.
Unfortuantly, I dont have any receivers avaialble for requesting the multicast stream on the edge point anymore. So there is not TX traffic a.t.m..
I will have a better test-lab available next week. (hopefully).
Thanks again.
----- Original Message -----
From: Hannes Frederic Sowa
Sent: 01/07/14 09:20 PM
To: Bob Falken, Julian Anastasov, [email protected]
Subject: Re: Multicast routing stops functioning after 4G multicast packets recived.
Quoted 21 lines · Hannes Frederic Sowa
Quoted 12 lines · Hannes Frederic Sowa
Quoted 11 lines · Bob Falken
Hello,
I patched, kernel 3.2.53 yesterday,
8774002632packets, and ~9.1TB later, the multicast routing seems to function properly. :)Kudos for fixing this.
I will keep checking the next days.
As for IPv6 MR, my current setup i.e: the Multicast source, does not support IPv6, so cannot do a check for that natively.
Quoted 7 lines
Quoted 1 line
Unless I can translate IPv4 multicast into IPv6 multicast easily, using some iptable prerouting rules(?).
Thank you for testing!
I'll review the RCU regions again and will prepare the patches (before introduction of
ebc0ffae5dfb44("fib: RCU conversion offib_lookup()") and after.
Quoted 5 lines
It seems ip(6)mr_fib_lookup is not always called from rcu section (
ndo_start_xmit), so I had to restructure a bit. Could you retest this patch as preparation for a submission to stable? Thanks!RCU conversion can be done later then.
Broken patch, sorry. Please try this one:
net/ipv4/ipmr.c +18 -6
@@ -157,9 +157,12 @@ static struct mr_table *ipmr_get_table(struct net *net, u32 id)static int ipmr_fib_lookup (struct net *net,struct flowi4 *flp4,struct mr_table **mrt) { -struct ipmr_result res; -struct fib_lookup_arg arg = { .result = &res};int err; +struct ipmr_result res; +struct fib_lookup_arg arg = { + .result = &res, + .flags =FIB_LOOKUP_NOREF , + }; err =fib_rules_lookup (net->ipv4.mr_rules_ops,flowi4_to_flowi (flp4),0 , &arg);
@@ -448,16 +451,22 @@ failure:static netdev_tx_t reg_vif_xmit (struct sk_buff *skb,struct net_device *dev) { +int err; +struct ipmr_result res;struct net *net =dev_net (dev); -struct mr_table *mrt; + +struct fib_lookup_arg arg = { + .result = &res, + }; +struct flowi4 fl4 = { .flowi4_oif = dev->ifindex, .flowi4_iif = skb->skb_iif, .flowi4_mark = skb->mark, }; -int err; - err =ipmr_fib_lookup (net, &fl4, &mrt); + err =fib_rules_lookup (net->ipv4.mr_rules_ops, +flowi4_to_flowi (&fl4),0 , &arg);if (err <0 ) {kfree_skb (skb);return err;
@@ -466,9 +475,12 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)read_lock (&mrt_lock); dev->stats.tx_bytes += skb->len; dev->stats.tx_packets++; -ipmr_cache_report (mrt, skb, mrt->mroute_reg_vif_num,IGMPMSG_WHOLEPKT ); +ipmr_cache_report (res.mrt, skb, res.mrt->mroute_reg_vif_num, +IGMPMSG_WHOLEPKT );read_unlock (&mrt_lock);kfree_skb (skb); +if (arg.rule) +fib_rule_put (arg.rule);return NETDEV_TX_OK ; }
net/ipv6/ip6mr.c +16 -6
@@ -141,9 +141,12 @@ static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)static int ip6mr_fib_lookup (struct net *net,struct flowi6 *flp6,struct mr6_table **mrt) { -struct ip6mr_result res; -struct fib_lookup_arg arg = { .result = &res};int err; +struct ip6mr_result res; +struct fib_lookup_arg arg = { + .result = &res, + .flags =FIB_LOOKUP_NOREF , + }; err =fib_rules_lookup (net->ipv6.mr6_rules_ops,flowi6_to_flowi (flp6),0 , &arg);
@@ -693,16 +696,20 @@ static const struct inet6_protocol pim6_protocol = {static netdev_tx_t reg_vif_xmit (struct sk_buff *skb,struct net_device *dev) { +int err; +struct ip6mr_result res;struct net *net =dev_net (dev); -struct mr6_table *mrt;struct flowi6 fl6 = { .flowi6_oif = dev->ifindex, .flowi6_iif = skb->skb_iif, .flowi6_mark = skb->mark, }; -int err; +struct fib_lookup_arg arg = { + .result = &res, + }; - err =ip6mr_fib_lookup (net, &fl6, &mrt); + err =fib_rules_lookup (net->ipv6.mr6_rules_ops, +flowi6_to_flowi (&fl6),0 , &arg);if (err <0 ) {kfree_skb (skb);return err;
@@ -711,9 +718,12 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,read_lock (&mrt_lock); dev->stats.tx_bytes += skb->len; dev->stats.tx_packets++; -ip6mr_cache_report (mrt, skb, mrt->mroute_reg_vif_num,MRT6MSG_WHOLEPKT ); +ip6mr_cache_report (res.mrt, skb, res.mrt->mroute_reg_vif_num, +MRT6MSG_WHOLEPKT );read_unlock (&mrt_lock);kfree_skb (skb); +if (arg.rule) +fib_rule_put (arg.rule);return NETDEV_TX_OK ; }
Quoted 6 lines · Bob Falken
Hello,
Testing this patch as im typing this. will check status in about 12hours.
Unfortuantly, I dont have any receivers avaialble for requesting the multicast stream on the edge point anymore. So there is not TX traffic a.t.m..I will have a better test-lab available next week. (hopefully).
Ok, so I am proposing this patch. Only difference from the RFC is that I removed the superfluous arg.rule NULL-pointer checks (I hate if they are superfluous and they always seem to spread ;) ).
Maybe you could test this one instead and David could pick it up as soon as your results are in.
I'll also look for the stable kernels where FIB_LOOKUP_NOREF is not yet available.
Thank you,
Hannes
[PATCH net] net: avoid reference counter overflows on fib_rules in multicast forwarding
When introducing multiple table support for multicast forwarding in IPv4 and IPv6, necessary fib_rules_put reference count decrements were forgotten.
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.
So, use FIB_LOOKUP_NOREF if we are already in a RCU protected section and correctly deal with reference counter if not (called from ndo_start_xmit).
--- net/ipv4/ipmr.c | 23 +++++++++++++++++------ net/ipv6/ip6mr.c | 21 +++++++++++++++------ 2 files changed, 32 insertions(+), 12 deletions(-)
net/ipv4/ipmr.c +17 -6
@@ -157,9 +157,12 @@ static struct mr_table *ipmr_get_table(struct net *net, u32 id)static int ipmr_fib_lookup (struct net *net,struct flowi4 *flp4,struct mr_table **mrt) { -struct ipmr_result res; -struct fib_lookup_arg arg = { .result = &res, };int err; +struct ipmr_result res; +struct fib_lookup_arg arg = { + .result = &res, + .flags =FIB_LOOKUP_NOREF , + }; err =fib_rules_lookup (net->ipv4.mr_rules_ops,flowi4_to_flowi (flp4),0 , &arg);
@@ -448,16 +451,22 @@ failure:static netdev_tx_t reg_vif_xmit (struct sk_buff *skb,struct net_device *dev) { +int err; +struct ipmr_result res;struct net *net =dev_net (dev); -struct mr_table *mrt; + +struct fib_lookup_arg arg = { + .result = &res, + }; +struct flowi4 fl4 = { .flowi4_oif = dev->ifindex, .flowi4_iif = skb->skb_iif, .flowi4_mark = skb->mark, }; -int err; - err =ipmr_fib_lookup (net, &fl4, &mrt); + err =fib_rules_lookup (net->ipv4.mr_rules_ops, +flowi4_to_flowi (&fl4),0 , &arg);if (err <0 ) {kfree_skb (skb);return err;
@@ -466,9 +475,11 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)read_lock (&mrt_lock); dev->stats.tx_bytes += skb->len; dev->stats.tx_packets++; -ipmr_cache_report (mrt, skb, mrt->mroute_reg_vif_num,IGMPMSG_WHOLEPKT ); +ipmr_cache_report (res.mrt, skb, res.mrt->mroute_reg_vif_num, +IGMPMSG_WHOLEPKT );read_unlock (&mrt_lock);kfree_skb (skb); +fib_rule_put (arg.rule);return NETDEV_TX_OK ; }
net/ipv6/ip6mr.c +15 -6
@@ -141,9 +141,12 @@ static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)static int ip6mr_fib_lookup (struct net *net,struct flowi6 *flp6,struct mr6_table **mrt) { -struct ip6mr_result res; -struct fib_lookup_arg arg = { .result = &res, };int err; +struct ip6mr_result res; +struct fib_lookup_arg arg = { + .result = &res, + .flags =FIB_LOOKUP_NOREF , + }; err =fib_rules_lookup (net->ipv6.mr6_rules_ops,flowi6_to_flowi (flp6),0 , &arg);
@@ -693,16 +696,20 @@ static const struct inet6_protocol pim6_protocol = {static netdev_tx_t reg_vif_xmit (struct sk_buff *skb,struct net_device *dev) { +int err; +struct ip6mr_result res;struct net *net =dev_net (dev); -struct mr6_table *mrt;struct flowi6 fl6 = { .flowi6_oif = dev->ifindex, .flowi6_iif = skb->skb_iif, .flowi6_mark = skb->mark, }; -int err; +struct fib_lookup_arg arg = { + .result = &res, + }; - err =ip6mr_fib_lookup (net, &fl6, &mrt); + err =fib_rules_lookup (net->ipv6.mr6_rules_ops, +flowi6_to_flowi (&fl6),0 , &arg);if (err <0 ) {kfree_skb (skb);return err;
@@ -711,9 +718,11 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,read_lock (&mrt_lock); dev->stats.tx_bytes += skb->len; dev->stats.tx_packets++; -ip6mr_cache_report (mrt, skb, mrt->mroute_reg_vif_num,MRT6MSG_WHOLEPKT ); +ip6mr_cache_report (res.mrt, skb, res.mrt->mroute_reg_vif_num, +MRT6MSG_WHOLEPKT );read_unlock (&mrt_lock);kfree_skb (skb); +fib_rule_put (arg.rule);return NETDEV_TX_OK ; }
Signature · 1 line
1.8.4.2
Quoted 72 lines · Hannes Frederic Sowa
Ok, so I am proposing this patch. Only difference from the RFC is that I removed the superfluous arg.rule NULL-pointer checks (I hate if they are superfluous and they always seem to spread ;) ).
Maybe you could test this one instead and David could pick it up as soon as your results are in.
I'll also look for the stable kernels where
FIB_LOOKUP_NOREFis not yet available.Thank you,
Hannes
[PATCH net] net: avoid reference counter overflows on
fib_rulesin multicast forwardingWhen introducing multiple table support for multicast forwarding in IPv4 and IPv6, necessary
fib_rules_putreference count decrements were forgotten.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.
So, use
FIB_LOOKUP_NOREFif we are already in a RCU protected section and correctly deal with reference counter if not (called fromndo_start_xmit).Fixes f0ad0860d01e47 ("ipv4: ipmr: support multiple tables")Fixes d1db275dd3f6e4 ("ipv6: ip6mr: support multiple tables")Reported-by Bob Falken <[email protected]>Cc Patrick McHardy <[email protected]>Cc Thomas Graf <[email protected]>Cc Julian Anastasov <[email protected]>Cc Eric Dumazet <[email protected]>Signed-off-by Hannes Frederic Sowa <[email protected]>--- net/ipv4/ipmr.c | 23 +++++++++++++++++------ net/ipv6/ip6mr.c | 21 +++++++++++++++------ 2 files changed, 32 insertions(+), 12 deletions(-)net/ipv4/ipmr.c +12
-3@@ -157,9 +157,12 @@ static struct mr_table *ipmr_get_table(struct net *net, u32 id)static int ipmr_fib_lookup (struct net *net,struct flowi4 *flp4,struct mr_table **mrt) { -struct ipmr_result res; -struct fib_lookup_arg arg = { .result = &res, };int err; +struct ipmr_result res; +struct fib_lookup_arg arg = { + .result = &res, + .flags =FIB_LOOKUP_NOREF , + }; err =fib_rules_lookup (net->ipv4.mr_rules_ops,flowi4_to_flowi (flp4),0 , &arg);@@ -448,16 +451,22 @@ failure:static netdev_tx_t reg_vif_xmit (struct sk_buff *skb,struct net_device *dev) { +int err; +struct ipmr_result res;struct net *net =dev_net (dev); -struct mr_table *mrt; + +struct fib_lookup_arg arg = { + .result = &res, + }; +
net/ipv4/ipmr.c failure: · line 469
Quoted 10 lines
net/ipv4/ipmr.c +2
-2struct flowi4 fl4 = { .flowi4_oif = dev->ifindex, .flowi4_iif = skb->skb_iif, .flowi4_mark = skb->mark, }; -int err; - err =ipmr_fib_lookup (net, &fl4, &mrt); + err =fib_rules_lookup (net->ipv4.mr_rules_ops, +flowi4_to_flowi (&fl4),0 , &arg);
Its not clear to me why you expand ipmr_fib_lookup()
Is there something wrong with existing code ?
Its not mentioned in changelog
net/ipv4/ipmr.c static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) · line 482
Quoted 13 lines
net/ipv4/ipmr.c +3
-1if (err <0 ) {kfree_skb (skb);return err;@@ -466,9 +475,11 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)read_lock (&mrt_lock); dev->stats.tx_bytes += skb->len; dev->stats.tx_packets++; -ipmr_cache_report (mrt, skb, mrt->mroute_reg_vif_num,IGMPMSG_WHOLEPKT ); +ipmr_cache_report (res.mrt, skb, res.mrt->mroute_reg_vif_num, +IGMPMSG_WHOLEPKT );read_unlock (&mrt_lock);kfree_skb (skb); +fib_rule_put (arg.rule);
This is the one line that is really missing, patch could be smaller.
Quoted 33 lines
net/ipv4/ipmr.c +0
-0return NETDEV_TX_OK ; }net/ipv6/ip6mr.c +7
-3@@ -141,9 +141,12 @@ static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)static int ip6mr_fib_lookup (struct net *net,struct flowi6 *flp6,struct mr6_table **mrt) { -struct ip6mr_result res; -struct fib_lookup_arg arg = { .result = &res, };int err; +struct ip6mr_result res; +struct fib_lookup_arg arg = { + .result = &res, + .flags =FIB_LOOKUP_NOREF , + }; err =fib_rules_lookup (net->ipv6.mr6_rules_ops,flowi6_to_flowi (flp6),0 , &arg);@@ -693,16 +696,20 @@ static const struct inet6_protocol pim6_protocol = {static netdev_tx_t reg_vif_xmit (struct sk_buff *skb,struct net_device *dev) { +int err; +struct ip6mr_result res;struct net *net =dev_net (dev); -struct mr6_table *mrt;struct flowi6 fl6 = { .flowi6_oif = dev->ifindex, .flowi6_iif = skb->skb_iif,
net/ipv6/ip6mr.c static const struct inet6_protocol pim6_protocol = { · line 712
Quoted 10 lines
net/ipv6/ip6mr.c +5
-2.flowi6_mark = skb->mark, }; -int err; +struct fib_lookup_arg arg = { + .result = &res, + }; - err =ip6mr_fib_lookup (net, &fl6, &mrt); + err =fib_rules_lookup (net->ipv6.mr6_rules_ops, +flowi6_to_flowi (&fl6),0 , &arg);
same remark here.
Quoted 16 lines
net/ipv6/ip6mr.c +3
-1if (err <0 ) {kfree_skb (skb);return err;@@ -711,9 +718,11 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,read_lock (&mrt_lock); dev->stats.tx_bytes += skb->len; dev->stats.tx_packets++; -ip6mr_cache_report (mrt, skb, mrt->mroute_reg_vif_num,MRT6MSG_WHOLEPKT ); +ip6mr_cache_report (res.mrt, skb, res.mrt->mroute_reg_vif_num, +MRT6MSG_WHOLEPKT );read_unlock (&mrt_lock);kfree_skb (skb); +fib_rule_put (arg.rule);return NETDEV_TX_OK ; }
Quoted 3 lines · Eric Dumazet
Its not clear to me why you expand
ipmr_fib_lookup()Is there something wrong with existing code ?
There are three users of ipmr_fib_lookup, two of them are in rcu_read_lock section, one is not.
ipmr_fib_lookup does not pass down arg.rule reference, so I don't have a chance to call fib_rule_put(arg.rule) on it. Thus I left ipmr_fib_lookup, just adding FIB_LOOKUP_NOREF and expanding ipmr_fib_lookup into the other function so I still have access to arg.rule to decrement the reference counter.
Do you agree?
Quoted 8 lines · Hannes Frederic Sowa
Quoted 3 lines · Eric Dumazet
Its not clear to me why you expand
ipmr_fib_lookup()Is there something wrong with existing code ?
There are three users of
ipmr_fib_lookup, two of them are inrcu_read_locksection, one is not.
Quoted 7 lines
ipmr_fib_lookupdoes not pass down arg.rule reference, so I don't have a chance to callfib_rule_put(arg.rule)on it. Thus I leftipmr_fib_lookup, just addingFIB_LOOKUP_NOREFand expandingipmr_fib_lookupinto the other function so I still have access to arg.rule to decrement the reference counter.Do you agree?
Hmm, I see the problem now.
What about adding a parameter to ipmr_fib_lookup(), to keep its spirit ?
ipmr_fib_lookup(net, &fl4, &mrt);
->ipmr_fib_lookup(net, &fl4, &mrt, &rule);
Since ipmr_rt_fib_lookup() has the same rule leak, no ?
Its a bit late here, so maybe following is just stupid :
Cant we do the fib_rule_put() inside ipmr_fib_lookup() ?
Quoted 19 lines · Eric Dumazet
Quoted 8 lines · Hannes Frederic Sowa
Quoted 3 lines · Eric Dumazet
Its not clear to me why you expand
ipmr_fib_lookup()Is there something wrong with existing code ?
There are three users of
ipmr_fib_lookup, two of them are inrcu_read_locksection, one is not.Quoted 7 lines
ipmr_fib_lookupdoes not pass down arg.rule reference, so I don't have a chance to callfib_rule_put(arg.rule)on it. Thus I leftipmr_fib_lookup, just addingFIB_LOOKUP_NOREFand expandingipmr_fib_lookupinto the other function so I still have access to arg.rule to decrement the reference counter.Do you agree?
Hmm, I see the problem now.
Quoted 8 lines
What about adding a parameter to
ipmr_fib_lookup(), to keep its spirit ?
ipmr_fib_lookup(net, &fl4, &mrt);
->ipmr_fib_lookup(net, &fl4, &mrt, &rule);Since
ipmr_rt_fib_lookup()has the same rule leak, no ?
No, ipmr_rt_fib_lookup is fine. This function gets called only from rcu read locked section and we don't take table reference because of FIB_LOOKUP_NOREF, so we don't need to put reference counter on arg.table.
We could add the additional argument, just ignoring it in ipmr_rt_fib_lookup.
Quoted 3 lines
Its a bit late here, so maybe following is just stupid :
Cant we do thefib_rule_put()insideipmr_fib_lookup()?
We could add bool noref to ipmr_fib_lookup indicating we want to drop reference to rule just after lookup.
I'll check if freeing a rule has additional side-effects on dependencies in reg_vif_xmit. That would be a nice solution actually, thanks!
Quoted 27 lines · Hannes Frederic Sowa
Quoted 26 lines · Eric Dumazet
Quoted 8 lines · Hannes Frederic Sowa
Quoted 3 lines · Eric Dumazet
Its not clear to me why you expand
ipmr_fib_lookup()Is there something wrong with existing code ?
There are three users of
ipmr_fib_lookup, two of them are inrcu_read_locksection, one is not.Quoted 7 lines
ipmr_fib_lookupdoes not pass down arg.rule reference, so I don't have a chance to callfib_rule_put(arg.rule)on it. Thus I leftipmr_fib_lookup, just addingFIB_LOOKUP_NOREFand expandingipmr_fib_lookupinto the other function so I still have access to arg.rule to decrement the reference counter.Do you agree?
Hmm, I see the problem now.
What about adding a parameter to
ipmr_fib_lookup(), to keep its spirit ?
ipmr_fib_lookup(net, &fl4, &mrt);
->ipmr_fib_lookup(net, &fl4, &mrt, &rule);
Quoted 5 lines
Quoted 1 line
Since
ipmr_rt_fib_lookup()has the same rule leak, no ?No,
ipmr_rt_fib_lookupis fine. This function gets called only from rcu read locked section and we don't take table reference because ofFIB_LOOKUP_NOREF, so we don't need to put reference counter on arg.table.
arg.rule not table, actually.
Quoted 11 lines
We could add the additional argument, just ignoring it in
ipmr_rt_fib_lookup.Quoted 3 lines
Its a bit late here, so maybe following is just stupid :
Cant we do thefib_rule_put()insideipmr_fib_lookup()?We could add bool noref to
ipmr_fib_lookupindicating we want to drop reference to rule just after lookup.I'll check if freeing a rule has additional side-effects on dependencies in
reg_vif_xmit. That would be a nice solution actually, thanks!
Hmm, rule holds a reference to the net namespace in use. I don't know if we want to add this special case. I guess net-namespace reference cannot be removed while processing ndo_start_xmit callback but I don't like this special case somehow. But I guess it is possible.
Your opinion on that?
Thanks,
Hannes
Quoted 9 lines · Hannes Frederic Sowa
Quoted 8 lines
Quoted 2 lines
Its a bit late here, so maybe following is just stupid :
Cant we do thefib_rule_put()insideipmr_fib_lookup()?We could add bool noref to
ipmr_fib_lookupindicating we want to drop reference to rule just after lookup.I'll check if freeing a rule has additional side-effects on dependencies in
reg_vif_xmit. That would be a nice solution actually, thanks!
Quoted 6 lines
Hmm, rule holds a reference to the net namespace in use. I don't know if we want to add this special case. I guess net-namespace reference cannot be removed while processing
ndo_start_xmitcallback but I don't like this special case somehow. But I guess it is possible.Your opinion on that?
Hm, Eric. If we do that we can just specifiy FIB_LOOKUP_NOREF unconditionally. FIB_LOOKUP_NOREF has no other side effects on a ipmr lookup as taking the reference on the rule, which we would drop after that.
So we would actually be going back to the first patch in this thread. I guess it is just a matter of style?
Greetings,
Hannes
Quoted 7 lines · Hannes Frederic Sowa
Hm, Eric. If we do that we can just specifiy
FIB_LOOKUP_NOREFunconditionally.FIB_LOOKUP_NOREFhas no other side effects on a ipmr lookup as taking the reference on the rule, which we would drop after that.So we would actually be going back to the first patch in this thread. I guess it is just a matter of style?
Hi Hannes, please submit a formal patch, so that we can have a proper ground for discussion (I guess I'll only add my Acked-by)
Thanks !
PATCH 1/1 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.
---
Bob Falken already tested this patch, as it is similar to my first attempt but the additional and similar fix for ipv6.
We need an additional fix for kernels without FIB_LOOKUP_NOREF, but I'll move that to tomorrow, as it is already late here.
net/ipv4/ipmr.c | 7 +++++-- net/ipv6/ip6mr.c | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-)
net/ipv4/ipmr.c +5 -2
@@ -157,9 +157,12 @@ static struct mr_table *ipmr_get_table(struct net *net, u32 id)static int ipmr_fib_lookup (struct net *net,struct flowi4 *flp4,struct mr_table **mrt) { -struct ipmr_result res; -struct fib_lookup_arg arg = { .result = &res, };int err; +struct ipmr_result res; +struct fib_lookup_arg arg = { + .result = &res, + .flags =FIB_LOOKUP_NOREF , + }; err =fib_rules_lookup (net->ipv4.mr_rules_ops,flowi4_to_flowi (flp4),0 , &arg);
net/ipv6/ip6mr.c +5 -2
@@ -141,9 +141,12 @@ static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)static int ip6mr_fib_lookup (struct net *net,struct flowi6 *flp6,struct mr6_table **mrt) { -struct ip6mr_result res; -struct fib_lookup_arg arg = { .result = &res, };int err; +struct ip6mr_result res; +struct fib_lookup_arg arg = { + .result = &res, + .flags =FIB_LOOKUP_NOREF , + }; err =fib_rules_lookup (net->ipv6.mr6_rules_ops,flowi6_to_flowi (flp6),0 , &arg);
Signature · 1 line
1.8.4.2
Re: [PATCH net] net: avoid reference counter overflows on fib_rules in multicast forwarding
Quoted 8 lines · Hannes Frederic Sowa
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_NOREFflag tofib_rules_lookupcalls. 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.
We need to not forget this when/if we remove FIB_LOOKUP_NOREF flag, as all callers use it : We'll have to keep rcu_read_lock() in fib_rules_lookup()
Quoted 14 lines
Rules only hold references to the namespace, which are guaranteed to be available during the call of the non-rcu protected function
reg_vif_xmitbecause 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 <[email protected]>Cc Patrick McHardy <[email protected]>Cc Thomas Graf <[email protected]>Cc Julian Anastasov <[email protected]>Cc Eric Dumazet <[email protected]>Signed-off-by Hannes Frederic Sowa <[email protected]>
Quoted 6 lines
---
Bob Falken already tested this patch, as it is similar to my first attempt but the additional and similar fix for ipv6.We need an additional fix for kernels without
FIB_LOOKUP_NOREF, but I'll move that to tomorrow, as it is already late here.
Thanks !
Re: [PATCH net] net: avoid reference counter overflows on fib_rules in multicast forwarding
Quoted 5 lines · Eric Dumazet
Quoted 4 lines · Hannes Frederic Sowa
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.
Quoted 8 lines
Quoted 4 lines
This patch solves this by adding the
FIB_LOOKUP_NOREFflag tofib_rules_lookupcalls. 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.We need to not forget this when/if we remove
FIB_LOOKUP_NOREFflag, as all callers use it : We'll have to keeprcu_read_lock()infib_rules_lookup()
Yes. Also maybe there is a tiny race between ipmr_rules_exit and reg_vif_xmit. mrt table might get cleaned up while in reg_vif_xmit and initialisation code has an error and calls ipmr_rules_exit, because mr_tables are not reference counted and not managed by rcu (but reg_vif_xmit is also not rcuified). This could happen if an error happens while initialisation I don't think net namespace destruction is a problem here, as reg_vif_xmit still has a valid reference to the interface and thus the namespace.
Quoted 17 lines
Quoted 17 lines
Rules only hold references to the namespace, which are guaranteed to be available during the call of the non-rcu protected function
reg_vif_xmitbecause 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 <[email protected]>Cc Patrick McHardy <[email protected]>Cc Thomas Graf <[email protected]>Cc Julian Anastasov <[email protected]>Cc Eric Dumazet <[email protected]>Signed-off-by Hannes Frederic Sowa <[email protected]>---
Bob Falken already tested this patch, as it is similar to my first attempt but the additional and similar fix for ipv6.
Quoted 4 lines
Quoted 2 lines
We need an additional fix for kernels without
FIB_LOOKUP_NOREF, but I'll move that to tomorrow, as it is already late here.Acked-by Eric Dumazet <[email protected]>
Thanks for the review!
I don't think we need an additional patch for this for the longterm kernels 2.6.32 and 2.6.34, as rule support for ipmr and ip6mr only entered in 2.6.35. RCUification of fib_lookup happened in 2.6.37. So this patch should cover all current stable kernels.
Greetings,
Hannes
David Miller
maintainerRe: [PATCH net] net: avoid reference counter overflows on fib_rules in multicast forwarding
In reply to Hannes Frederic SowaFrom: Hannes Frederic Sowa <[email protected]>
Date: Mon, 13 Jan 2014 02:45:22 +0100
Quoted 14 lines
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_NOREFflag tofib_rules_lookupcalls. 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_xmitbecause of the interface reference which itself holds a reference to the net namespace.
Quoted 8 lines
Fixes f0ad0860d01e47 ("ipv4: ipmr: support multiple tables")Fixes d1db275dd3f6e4 ("ipv6: ip6mr: support multiple tables")Reported-by Bob Falken <[email protected]>Cc Patrick McHardy <[email protected]>Cc Thomas Graf <[email protected]>Cc Julian Anastasov <[email protected]>Cc Eric Dumazet <[email protected]>Signed-off-by Hannes Frederic Sowa <[email protected]>
Applied and queued up for -stable, th anks.