Route next-hop interface behaviour

Doug Ambrisko ambrisko at ambrisko.com
Mon Apr 1 20:58:47 UTC 2013


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 at 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 at 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 at 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 at daffy:~ # route delete default
| delete net default
| root at daffy:~ # route add default 10.0.2.1
| add net default: gateway 10.0.2.1
| root at 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.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: up.patch
Type: text/x-diff
Size: 1318 bytes
Desc: not available
URL: <http://lists.freebsd.org/pipermail/freebsd-net/attachments/20130401/22156a69/attachment.patch>


More information about the freebsd-net mailing list