Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 1 Apr 2013 13:58:39 -0700
From:      Doug Ambrisko <ambrisko@ambrisko.com>
To:        Richard Tector <richard@tector.org.uk>
Cc:        freebsd-net@freebsd.org
Subject:   Re: Route next-hop interface behaviour
Message-ID:  <20130401205839.GA24595@ambrisko.com>
In-Reply-To: <51588F43.7060609@tector.org.uk>
References:  <51588F43.7060609@tector.org.uk>

next in thread | previous in thread | raw e-mail | index | archive | help

--3uo+9/B/ebqu+fSQ
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Sun, Mar 31, 2013 at 08:32:19PM +0100, Richard Tector wrote:
| Hi,
| 
| I'm not sure if it is expected behaviour but when configuring a static 
| route (default or otherwise) the outbound interface recorded in the 
| table does not update when the system's IP changes interface, even when 
| removing and re-adding it.
| 
| Fairly simple topology, system running 9.1-STABLE (30th March) with just 
| one of four 'em' interfaces in use - em0 with 10.0.2.199. Default route 
| to 10.0.2.1.
| 
| Whilst troubleshooting some odd TCP behaviour I thought I'd try a 
| different interface and so downed the active interface and brought up 
| one on a PCI card, and swapped the cable over:
| 
| # ifconfig em0 down
| # ifconfig em2 inet 10.0.2.199/24
| # ifconfig em2 up
| 
| #####
| If I then ping an external host it shows as the destination network 
| being inaccessible:
| 
| root@daffy:~ # ping 212.23.6.76
| PING 212.23.6.76 (212.23.6.76): 56 data bytes
| ping: sendto: Network is down
| 
| 
| #####
| Can contact the next hop just fine:
| 
| root@daffy:~ # ping 10.0.2.1
| PING 10.0.2.1 (10.0.2.1): 56 data bytes
| 64 bytes from 10.0.2.1: icmp_seq=0 ttl=64 time=0.211 ms
| 
| 
| #####
| Routing table shows that the default route is still bound to em0 even 
| though the next hop is on em2:
| 
| root@daffy:~ # netstat -rfinet -n
| Routing tables
| 
| Internet:
| Destination        Gateway            Flags    Refs      Use  Netif Expire
| default            10.0.2.1           UGS         0     3141    em0
|                                                                 ^^^
| 10.0.2.0/24        link#4             U           1      255    em2
| 10.0.2.199         link#1             UHS         1        0    lo0
| 127.0.0.1          link#9             UH          0        0    lo0
| 
| 
| #####
| Removing the default route and re-adding also leaves it on the old 
| interface:
| 
| root@daffy:~ # route delete default
| delete net default
| root@daffy:~ # route add default 10.0.2.1
| add net default: gateway 10.0.2.1
| root@daffy:~ # netstat -rfinet -n
| Routing tables
| 
| Internet:
| Destination        Gateway            Flags    Refs      Use  Netif Expire
| default            10.0.2.1           UGS         0        0    em0
| 10.0.2.0/24        link#4             U           0      688    em2
| 10.0.2.199         link#1             UHS         1        0    lo0
| 127.0.0.1          link#9             UH          0        0    lo0
| 
| I can understand the initial problem, but surely when I re-add the route 
| it should do a lookup against the table for the next hop, ie. 
| 10.0.2.0/24, and use the associated Netif?
| 
| What's interesting is that if I remove the IP configuration from em0 it 
| removes the default route above (even though the interface is downed). 
| Re-adding the route works.

You can try this patch:

Index: net/if.c
===================================================================
--- net/if.c	(revision 248707)
+++ net/if.c	(working copy)
@@ -1532,6 +1532,8 @@
 
 	IFNET_RLOCK_NOSLEEP();
 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+		if ((ifp->if_flags & IFF_UP) == 0)
+			continue;
 		IF_ADDR_RLOCK(ifp);
 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
 			if (ifa->ifa_addr->sa_family != addr->sa_family)
@@ -1620,6 +1622,8 @@
 
 	IFNET_RLOCK_NOSLEEP();
 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+		if ((ifp->if_flags & IFF_UP) == 0)
+			continue;
 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
 			continue;
 		IF_ADDR_RLOCK(ifp);
@@ -1672,6 +1676,8 @@
 	 */
 	IFNET_RLOCK_NOSLEEP();
 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+		if ((ifp->if_flags & IFF_UP) == 0)
+			continue;
 		IF_ADDR_RLOCK(ifp);
 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
 			char *cp, *cp2, *cp3;
Index: net/if_ethersubr.c
===================================================================
--- net/if_ethersubr.c	(revision 248707)
+++ net/if_ethersubr.c	(working copy)
@@ -812,6 +871,11 @@
 #if defined(NETATALK)
 	struct llc *l;
 #endif
+	/* Discard packet if interface is not up */
+	if ((ifp->if_flags & IFF_UP) == 0) {
+		m_freem(m);
+		return;
+	}
 
 	KASSERT(ifp != NULL, ("%s: NULL interface pointer", __func__));
 

The issue is that the routing doesn't look to see if the NIC is
up or not.  It just looks at the IP address.  So it tries to send
it out the first matching NIC that could be down.

Doug A.

--3uo+9/B/ebqu+fSQ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="up.patch"

Index: net/if.c
===================================================================
--- net/if.c	(revision 248707)
+++ net/if.c	(working copy)
@@ -1532,6 +1532,8 @@
 
 	IFNET_RLOCK_NOSLEEP();
 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+		if ((ifp->if_flags & IFF_UP) == 0)
+			continue;
 		IF_ADDR_RLOCK(ifp);
 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
 			if (ifa->ifa_addr->sa_family != addr->sa_family)
@@ -1620,6 +1622,8 @@
 
 	IFNET_RLOCK_NOSLEEP();
 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+		if ((ifp->if_flags & IFF_UP) == 0)
+			continue;
 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
 			continue;
 		IF_ADDR_RLOCK(ifp);
@@ -1672,6 +1676,8 @@
 	 */
 	IFNET_RLOCK_NOSLEEP();
 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+		if ((ifp->if_flags & IFF_UP) == 0)
+			continue;
 		IF_ADDR_RLOCK(ifp);
 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
 			char *cp, *cp2, *cp3;
Index: net/if_ethersubr.c
===================================================================
--- net/if_ethersubr.c	(revision 248707)
+++ net/if_ethersubr.c	(working copy)
@@ -812,6 +871,11 @@
 #if defined(NETATALK)
 	struct llc *l;
 #endif
+	/* Discard packet if interface is not up */
+	if ((ifp->if_flags & IFF_UP) == 0) {
+		m_freem(m);
+		return;
+	}
 
 	KASSERT(ifp != NULL, ("%s: NULL interface pointer", __func__));
 

--3uo+9/B/ebqu+fSQ--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20130401205839.GA24595>