On 29/11/15 03:38, Roopa Prabhu wrote:
From: Roopa Prabhu <[email protected]>
}
}
- 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,
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html