FAILED: patch "[PATCH] net: mpls: Fix notifications when deleting a device" failed to apply to 4.9-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 4.9-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 7d4741eacdefa5f0475431645b56baf00784df1f Mon Sep 17 00:00:00 2001
From: Benjamin Poirier <[email protected]>
Date: Mon, 29 Nov 2021 15:15:05 +0900
Subject: [PATCH] net: mpls: Fix notifications when deleting a device
There are various problems related to netlink notifications for mpls route changes in response to interfaces being deleted:
* delete interface of only nexthop
DELROUTE notification is missing RTA_OIF attribute
* delete interface of non-last nexthop
NEWROUTE notification is missing entirely
* delete interface of last nexthop
DELROUTE notification is missing nexthop
All of these problems stem from the fact that existing routes are modified in-place before sending a notification. Restructure mpls_ifdown() to avoid changing the route in the DELROUTE cases and to create a copy in the NEWROUTE case.
net/mpls/af_mpls.c +52 -16
@@ -1491,22 +1491,52 @@ static void mpls_dev_destroy_rcu(struct rcu_head *head)kfree (mdev); } -static void mpls_ifdown (struct net_device *dev,int event) +static int mpls_ifdown (struct net_device *dev,int event) {struct mpls_route __rcu **platform_label;struct net *net =dev_net (dev); -u8 alive, deleted;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]); +bool nh_del = false; +u8 alive =0 ;if (!rt)continue ; - alive =0 ; - deleted =0 ; +if (event ==NETDEV_UNREGISTER ) { +u8 deleted =0 ; + +for_nexthops (rt) { +struct net_device *nh_dev = +rtnl_dereference (nh->nh_dev); + +if (!nh_dev || nh_dev == dev) + deleted++; +if (nh_dev == dev) + nh_del = true; + }endfor_nexthops (rt); + +/* if there are no more nexthops, delete the route */ +if (deleted == rt->rt_nhn) { +mpls_route_update (net, index,NULL ,NULL ); +continue ; + } + +if (nh_del) { +size_t size =sizeof (*rt) + rt->rt_nhn * + rt->rt_nh_size; +struct mpls_route *orig = rt; + + rt =kmalloc (size,GFP_KERNEL ); +if (!rt) +return -ENOMEM ; +memcpy (rt, orig, size); + } + } +change_nexthops (rt) {unsigned int nh_flags = nh->nh_flags;
@@ -1530,16 +1560,15 @@ static void mpls_ifdown(struct net_device *dev, int event) next:if (!(nh_flags & (RTNH_F_DEAD |RTNH_F_LINKDOWN ))) alive++; -if (!rtnl_dereference (nh->nh_dev)) - deleted++; }endfor_nexthops (rt);WRITE_ONCE (rt->rt_nhn_alive, alive); -/* if there are no more nexthops, delete the route */ -if (event ==NETDEV_UNREGISTER && deleted == rt->rt_nhn) -mpls_route_update (net, index,NULL ,NULL ); +if (nh_del) +mpls_route_update (net, index, rt,NULL ); } + +return 0 ; }static void mpls_ifup (struct net_device *dev,unsigned int flags)
@@ -1597,8 +1626,12 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,return NOTIFY_OK ;switch (event) { +int err; +case NETDEV_DOWN : -mpls_ifdown (dev, event); + err =mpls_ifdown (dev, event); +if (err) +return notifier_from_errno (err);break ;case NETDEV_UP : flags =dev_get_flags (dev);
@@ -1609,13 +1642,18 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,break ;case NETDEV_CHANGE : flags =dev_get_flags (dev); -if (flags & (IFF_RUNNING |IFF_LOWER_UP )) +if (flags & (IFF_RUNNING |IFF_LOWER_UP )) {mpls_ifup (dev,RTNH_F_DEAD |RTNH_F_LINKDOWN ); -else -mpls_ifdown (dev, event); + }else { + err =mpls_ifdown (dev, event); +if (err) +return notifier_from_errno (err); + }break ;case NETDEV_UNREGISTER : -mpls_ifdown (dev, event); + err =mpls_ifdown (dev, event); +if (err) +return notifier_from_errno (err); mdev =mpls_dev_get (dev);if (mdev) {mpls_dev_sysctl_unregister (dev, mdev);
@@ -1626,8 +1664,6 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,case NETDEV_CHANGENAME : mdev =mpls_dev_get (dev);if (mdev) { -int err; -mpls_dev_sysctl_unregister (dev, mdev); err =mpls_dev_sysctl_register (dev, mdev);if (err)