6f9c14e
From fbd40ea0180a2d328c5adc61414dc8bab9335ce2 Mon Sep 17 00:00:00 2001
6f9c14e
From: "David S. Miller" <davem@davemloft.net>
6f9c14e
Date: Sun, 13 Mar 2016 23:28:00 -0400
6f9c14e
Subject: ipv4: Don't do expensive useless work during inetdev destroy.
6f9c14e
6f9c14e
When an inetdev is destroyed, every address assigned to the interface
6f9c14e
is removed.  And in this scenerio we do two pointless things which can
6f9c14e
be very expensive if the number of assigned interfaces is large:
6f9c14e
6f9c14e
1) Address promotion.  We are deleting all addresses, so there is no
6f9c14e
   point in doing this.
6f9c14e
6f9c14e
2) A full nf conntrack table purge for every address.  We only need to
6f9c14e
   do this once, as is already caught by the existing
6f9c14e
   masq_dev_notifier so masq_inet_event() can skip this.
6f9c14e
6f9c14e
Reported-by: Solar Designer <solar@openwall.com>
6f9c14e
Signed-off-by: David S. Miller <davem@davemloft.net>
6f9c14e
Tested-by: Cyrill Gorcunov <gorcunov@openvz.org>
6f9c14e
---
6f9c14e
 net/ipv4/devinet.c                          |  4 ++++
6f9c14e
 net/ipv4/fib_frontend.c                     |  4 ++++
6f9c14e
 net/ipv4/netfilter/nf_nat_masquerade_ipv4.c | 12 ++++++++++--
6f9c14e
 3 files changed, 18 insertions(+), 2 deletions(-)
6f9c14e
6f9c14e
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
6f9c14e
index 65e76a4..e333bc8 100644
6f9c14e
--- a/net/ipv4/devinet.c
6f9c14e
+++ b/net/ipv4/devinet.c
6f9c14e
@@ -334,6 +334,9 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
6f9c14e
 
6f9c14e
 	ASSERT_RTNL();
6f9c14e
 
6f9c14e
+	if (in_dev->dead)
6f9c14e
+		goto no_promotions;
6f9c14e
+
6f9c14e
 	/* 1. Deleting primary ifaddr forces deletion all secondaries
6f9c14e
 	 * unless alias promotion is set
6f9c14e
 	 **/
6f9c14e
@@ -380,6 +383,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
6f9c14e
 			fib_del_ifaddr(ifa, ifa1);
6f9c14e
 	}
6f9c14e
 
6f9c14e
+no_promotions:
6f9c14e
 	/* 2. Unlink it */
6f9c14e
 
6f9c14e
 	*ifap = ifa1->ifa_next;
6f9c14e
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
6f9c14e
index 4734475..21add55 100644
6f9c14e
--- a/net/ipv4/fib_frontend.c
6f9c14e
+++ b/net/ipv4/fib_frontend.c
6f9c14e
@@ -922,6 +922,9 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
6f9c14e
 		subnet = 1;
6f9c14e
 	}
6f9c14e
 
6f9c14e
+	if (in_dev->dead)
6f9c14e
+		goto no_promotions;
6f9c14e
+
6f9c14e
 	/* Deletion is more complicated than add.
6f9c14e
 	 * We should take care of not to delete too much :-)
6f9c14e
 	 *
6f9c14e
@@ -997,6 +1000,7 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
6f9c14e
 		}
6f9c14e
 	}
6f9c14e
 
6f9c14e
+no_promotions:
6f9c14e
 	if (!(ok & BRD_OK))
6f9c14e
 		fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
6f9c14e
 	if (subnet && ifa->ifa_prefixlen < 31) {
6f9c14e
diff --git a/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c b/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c
6f9c14e
index c6eb421..ea91058 100644
6f9c14e
--- a/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c
6f9c14e
+++ b/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c
6f9c14e
@@ -108,10 +108,18 @@ static int masq_inet_event(struct notifier_block *this,
6f9c14e
 			   unsigned long event,
6f9c14e
 			   void *ptr)
6f9c14e
 {
6f9c14e
-	struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
6f9c14e
+	struct in_device *idev = ((struct in_ifaddr *)ptr)->ifa_dev;
6f9c14e
 	struct netdev_notifier_info info;
6f9c14e
 
6f9c14e
-	netdev_notifier_info_init(&info, dev);
6f9c14e
+	/* The masq_dev_notifier will catch the case of the device going
6f9c14e
+	 * down.  So if the inetdev is dead and being destroyed we have
6f9c14e
+	 * no work to do.  Otherwise this is an individual address removal
6f9c14e
+	 * and we have to perform the flush.
6f9c14e
+	 */
6f9c14e
+	if (idev->dead)
6f9c14e
+		return NOTIFY_DONE;
6f9c14e
+
6f9c14e
+	netdev_notifier_info_init(&info, idev->dev);
6f9c14e
 	return masq_device_event(this, event, &info;;
6f9c14e
 }
6f9c14e
 
6f9c14e
-- 
6f9c14e
cgit v0.12
6f9c14e