From: Robert Shearman <rshearma@brocade.com>
To: Roopa Prabhu <roopa@cumulusnetworks.com>, <ebiederm@xmission.com>
Cc: <davem@davemloft.net>, <netdev@vger.kernel.org>
Subject: Re: [PATCH net-next v6] mpls: support for dead routes
Date: Mon, 30 Nov 2015 23:02:27 +0000 [thread overview]
Message-ID: <565CD583.8050507@brocade.com> (raw)
In-Reply-To: <1448768313-34809-1-git-send-email-roopa@cumulusnetworks.com>
On 29/11/15 03:38, Roopa Prabhu wrote:
> From: Roopa Prabhu <roopa@cumulusnetworks.com>
> }
> }
>
> - nh_index = hash % rt->rt_nhn;
> + return hash;
> +}
> +
> +static struct mpls_nh *mpls_select_multipath(struct mpls_route *rt,
> + struct sk_buff *skb, bool bos)
> +{
> + u32 hash = 0;
> + int nh_index = 0;
> + int n = 0;
> +
> + /* No need to look further into packet if there's only
> + * one path
> + */
> + if (rt->rt_nhn == 1)
> + goto out;
> +
> + if (rt->rt_nhn_alive <= 0)
> + return NULL;
> +
> + hash = mpls_multipath_hash(rt, skb, bos);
> + nh_index = hash % rt->rt_nhn_alive;
There's a possibility that the compiler could generate multiple reads to
rt_nhn_alive and thus see partial updates. If this happens, then we
could end up accessing a nexthop pointer that is actually beyond the end
of the nexthop array.
I don't think any form of memory barrier is necessary so I would
therefore suggest fixing this by changing the line above to:
nh_index = hash % ACCESS_ONCE(rt->rt_nhn_alive);
If we assume that it's OK to drop packets for a short time around the
change, then the rt->rt_nhn_alive <= 0 check above is fine as is.
Similarly if we assume that it's OK for packets to go via nexthops they
wouldn't normally do transiently then the rt->rt_nhn_alive == rt->rt_nhn
check below is also fine as is.
However, it might look confusing to a casual observer, so perhaps we
should consider stashing the alive nexthop count in a variable, still
getting it using the ACCESS_ONCE macro?
> + if (rt->rt_nhn_alive == rt->rt_nhn)
> + goto out;
> + for_nexthops(rt) {
> + if (nh->nh_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN))
> + continue;
> + if (n == nh_index)
> + return nh;
> + n++;
> + } endfor_nexthops(rt);
> +
> out:
> return &rt->rt_nh[nh_index];
> }
...
> return ERR_PTR(err);
> }
>
> -static void mpls_ifdown(struct net_device *dev)
> +static void mpls_ifdown(struct net_device *dev, int event)
> {
> struct mpls_route __rcu **platform_label;
> struct net *net = dev_net(dev);
> - struct mpls_dev *mdev;
> unsigned index;
>
> platform_label = rtnl_dereference(net->mpls.platform_label);
> for (index = 0; index < net->mpls.platform_labels; index++) {
> struct mpls_route *rt = rtnl_dereference(platform_label[index]);
> +
> if (!rt)
> continue;
> - for_nexthops(rt) {
> +
> + change_nexthops(rt) {
> if (rtnl_dereference(nh->nh_dev) != dev)
> continue;
> - nh->nh_dev = NULL;
> + switch (event) {
> + case NETDEV_DOWN:
> + case NETDEV_UNREGISTER:
> + nh->nh_flags |= RTNH_F_DEAD;
> + /* fall through */
> + case NETDEV_CHANGE:
> + nh->nh_flags |= RTNH_F_LINKDOWN;
> + rt->rt_nhn_alive--;
For the similar reasons as above, to prevent mpls_select_multipath
seeing partial updates I think this should be:
ACCESS_ONCE(rt->rt_nhn_alive) = rt->rt_nhn_alive - 1;
Again, I don't think any memory barrier is required here, but I could be
mistaken.
No special treatment of nh->nh_flags is required if we assume that it's
OK transiently for packets to be dropped or go via a different nexthop
than in steady state.
> + break;
> + }
> + if (event == NETDEV_UNREGISTER)
> + RCU_INIT_POINTER(nh->nh_dev, NULL);
> } endfor_nexthops(rt);
> }
>
> - mdev = mpls_dev_get(dev);
> - if (!mdev)
> - return;
>
> - mpls_dev_sysctl_unregister(mdev);
> + return;
> +}
> +
> +static void mpls_ifup(struct net_device *dev, unsigned int nh_flags)
> +{
> + struct mpls_route __rcu **platform_label;
> + struct net *net = dev_net(dev);
> + unsigned index;
> + int alive;
> +
> + platform_label = rtnl_dereference(net->mpls.platform_label);
> + for (index = 0; index < net->mpls.platform_labels; index++) {
> + struct mpls_route *rt = rtnl_dereference(platform_label[index]);
> +
> + if (!rt)
> + continue;
> +
> + alive = 0;
> + change_nexthops(rt) {
> + struct net_device *nh_dev =
> + rtnl_dereference(nh->nh_dev);
> +
> + if (!(nh->nh_flags & nh_flags)) {
> + alive++;
> + continue;
> + }
> + if (nh_dev != dev)
> + continue;
> + alive++;
> + nh->nh_flags &= ~nh_flags;
> + } endfor_nexthops(rt);
>
> - RCU_INIT_POINTER(dev->mpls_ptr, NULL);
> + rt->rt_nhn_alive = alive;
For the similar reasons as above, to prevent mpls_select_multipath
seeing partial updates I think this should be:
ACCESS_ONCE(rt->rt_nhn_alive) = alive;
Again, I don't think any memory barrier is required here, but I could be
mistaken.
> + }
>
> - kfree_rcu(mdev, rcu);
> + return;
> }
>
> static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
next prev parent reply other threads:[~2015-11-30 23:02 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-11-29 3:38 [PATCH net-next v6] mpls: support for dead routes Roopa Prabhu
2015-11-30 23:02 ` Robert Shearman [this message]
2015-12-01 20:43 ` David Miller
2015-12-02 4:39 ` roopa
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=565CD583.8050507@brocade.com \
--to=rshearma@brocade.com \
--cc=davem@davemloft.net \
--cc=ebiederm@xmission.com \
--cc=netdev@vger.kernel.org \
--cc=roopa@cumulusnetworks.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).