[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: nslu2: two devices: one by default



On Sat, Oct 31, 2009 at 03:19:22PM +0100, Xan wrote:
> En/na Lennart Sorensen ha escrit:
>> On Fri, Oct 30, 2009 at 05:32:09PM +0100, Xan wrote:
>>   
>>> Hi,
>>>
>>> Perhaps it's a too much simple question, but I don't know what 
>>> achieve  that: In nslu2 I have two network devices: eth0 and wlan0 
>>> (wifi). I just  want that:
>>>
>>> - nslu2 tries if eth0 is plugged. If it's, then all network 
>>> connection  were established via eth0
>>> - if eth0 is unplugged, then all network connection were established 
>>> via  wlan0.
>>>
>>> Now the first is done, but when I unplugged the eth0 I can't reach 
>>> the  system (all packets loose)
>>>
>>> Anyone could help me? I suspect that I have to touch the route table. 
>>> Is  it true?
>>> My route table is:
>>>
>>> # route
>>> Kernel IP routing table
>>> Destination     Gateway         Genmask         Flags Metric Ref    
>>> Use  Iface
>>> localnet        *               255.255.0.0     U     0      0        0 eth0
>>> localnet        *               255.255.0.0     U     0      0        
>>> 0  wlan0
>>> default         172.26.0.1      0.0.0.0         UG    0      0        
>>> 0  wlan0
>>> default         172.26.0.1      0.0.0.0         UG    0      0        0 eth0
>>>
>>> wlan0 has static ip 172.26.0.3 and eth0 has static ip 172.26.0.2
>>>
>>> 172.26.0.1 is the router (what has internet connectivity). I just 
>>> want  to have local network connections between all other devices and 
>>> my nslu2.
>>>     
>>
>> Linux in general does not deal with ignoring routes just because an
>> interface is down.  Unix like systems never do.  Routers do.
>>   
> But I can reach other boxes with the same network and different ip?
> What's the easiest solution to achieve that when I unplug eth0 I can  
> reach nslu2 via wlan0?

Well in your case it appears that right now eth0 is the first choice for
reaching the local network, and wlan0 is the first choice for default
route, although since the default route uses a gateway on your local
network, it may still use eth0 for that.  If eth0 goes down, you won't
be able to reach the local network, since the route in use goes to eth0
and it is down.

I use a small kernel patch that makes the kernel delete local network
routes whenever a link is down, and readd it when the link comes back.
That solves the problem.  I manage any additional static routes
(including default route) through zebra (quagga route deamon) with link
detect enabled.

The patch I use is:

diff -ruN build_i386_none_gx1.ori/Documentation/networking/ip-sysctl.txt build_i386_none_gx1/Documentation/networking/ip-sysctl.txt
--- build_i386_none_gx1.ori/Documentation/networking/ip-sysctl.txt	2009-03-30 14:34:14.000000000 -0400
+++ build_i386_none_gx1/Documentation/networking/ip-sysctl.txt	2009-03-30 14:30:35.000000000 -0400
@@ -791,7 +791,10 @@
 disable_xfrm - BOOLEAN
 	Disable IPSEC encryption on this interface, whatever the policy
 
-
+link_detect - BOOLEAN
+	Causes loss of carrier remove interface addresses the same as
+	setting device down. When carrier is restored, the addresses
+	are restored.
 
 tag - INTEGER
 	Allows you to write a number, which can be used as required.
diff -ruN build_i386_none_gx1.ori/include/linux/inetdevice.h build_i386_none_gx1/include/linux/inetdevice.h
--- build_i386_none_gx1.ori/include/linux/inetdevice.h	2009-03-30 14:34:14.000000000 -0400
+++ build_i386_none_gx1/include/linux/inetdevice.h	2009-03-30 14:30:35.000000000 -0400
@@ -97,6 +97,7 @@
 #define IN_DEV_PROMOTE_SECONDARIES(in_dev) \
 					IN_DEV_ORCONF((in_dev), \
 						      PROMOTE_SECONDARIES)
+#define IN_DEV_LINK_DETECT(in_dev)	IN_DEV_ORCONF((in_dev), LINK_DETECT)
 
 #define IN_DEV_RX_REDIRECTS(in_dev) \
 	((IN_DEV_FORWARD(in_dev) && \
diff -ruN build_i386_none_gx1.ori/include/linux/notifier.h build_i386_none_gx1/include/linux/notifier.h
--- build_i386_none_gx1.ori/include/linux/notifier.h	2009-03-30 14:34:14.000000000 -0400
+++ build_i386_none_gx1/include/linux/notifier.h	2009-03-30 14:30:35.000000000 -0400
@@ -197,6 +197,7 @@
 #define NETDEV_GOING_DOWN	0x0009
 #define NETDEV_CHANGENAME	0x000A
 #define NETDEV_FEAT_CHANGE	0x000B
+#define NETDEV_LINK_DOWN	0x00FF /* Used for link detect handling */
 
 #define SYS_DOWN	0x0001	/* Notify of system down */
 #define SYS_RESTART	SYS_DOWN
diff -ruN build_i386_none_gx1.ori/include/linux/sysctl.h build_i386_none_gx1/include/linux/sysctl.h
--- build_i386_none_gx1.ori/include/linux/sysctl.h	2009-03-30 14:34:14.000000000 -0400
+++ build_i386_none_gx1/include/linux/sysctl.h	2009-03-30 14:30:35.000000000 -0400
@@ -490,6 +490,7 @@
 	NET_IPV4_CONF_ARP_IGNORE=19,
 	NET_IPV4_CONF_PROMOTE_SECONDARIES=20,
 	NET_IPV4_CONF_ARP_ACCEPT=21,
+	NET_IPV4_CONF_LINK_DETECT=22,
 	__NET_IPV4_CONF_MAX
 };
 
diff -ruN build_i386_none_gx1.ori/kernel/sysctl_check.c build_i386_none_gx1/kernel/sysctl_check.c
--- build_i386_none_gx1.ori/kernel/sysctl_check.c	2009-03-30 14:34:14.000000000 -0400
+++ build_i386_none_gx1/kernel/sysctl_check.c	2009-03-30 14:30:35.000000000 -0400
@@ -219,6 +219,7 @@
 	{ NET_IPV4_CONF_ARP_IGNORE,		"arp_ignore" },
 	{ NET_IPV4_CONF_PROMOTE_SECONDARIES,	"promote_secondaries" },
 	{ NET_IPV4_CONF_ARP_ACCEPT,		"arp_accept" },
+	{ NET_IPV4_CONF_LINK_DETECT,		"link_detect" },
 	{}
 };
 
diff -ruN build_i386_none_gx1.ori/net/ipv4/devinet.c build_i386_none_gx1/net/ipv4/devinet.c
--- build_i386_none_gx1.ori/net/ipv4/devinet.c	2009-03-30 14:34:14.000000000 -0400
+++ build_i386_none_gx1/net/ipv4/devinet.c	2009-03-30 14:30:35.000000000 -0400
@@ -1434,6 +1434,7 @@
 					      "force_igmp_version"),
 		DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
 					      "promote_secondaries"),
+		DEVINET_SYSCTL_RW_ENTRY(LINK_DETECT, "link_detect"),
 	},
 };
 
diff -ruN build_i386_none_gx1.ori/net/ipv4/fib_frontend.c build_i386_none_gx1/net/ipv4/fib_frontend.c
--- build_i386_none_gx1.ori/net/ipv4/fib_frontend.c	2009-03-30 14:34:14.000000000 -0400
+++ build_i386_none_gx1/net/ipv4/fib_frontend.c	2009-03-30 14:33:29.000000000 -0400
@@ -906,9 +906,12 @@
 static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
 	struct in_ifaddr *ifa = (struct in_ifaddr*)ptr;
+	struct net_device *dev = ifa->ifa_dev->dev;
+	struct in_device *in_dev = __in_dev_get_rtnl(dev);
 
 	switch (event) {
 	case NETDEV_UP:
 		fib_add_ifaddr(ifa);
+		if (IN_DEV_LINK_DETECT(in_dev) && !netif_carrier_ok(dev)) fib_del_ifaddr(ifa);
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
 		fib_sync_up(ifa->ifa_dev->dev);
@@ -943,8 +946,14 @@
 	if (!in_dev)
 		return NOTIFY_DONE;
 
+	/* Link detect causes changes in carrier to add/remove addresses from FIB */
+	if (event == NETDEV_CHANGE && netif_running(dev)
+	    && IN_DEV_LINK_DETECT(in_dev))
+		event = netif_carrier_ok(dev) ? NETDEV_UP : NETDEV_LINK_DOWN;
+
 	switch (event) {
 	case NETDEV_UP:
+		if (IN_DEV_LINK_DETECT(in_dev) && !netif_carrier_ok(dev)) break;
 		for_ifa(in_dev) {
 			fib_add_ifaddr(ifa);
 		} endfor_ifa(in_dev);
@@ -956,6 +965,12 @@
 	case NETDEV_DOWN:
 		fib_disable_ip(dev, 0);
 		break;
+	case NETDEV_LINK_DOWN:
+		for_ifa(in_dev) {
+			fib_del_ifaddr(ifa);
+		} endfor_ifa(in_dev);
+		rt_cache_flush(-1);
+		break;
 	case NETDEV_CHANGEMTU:
 	case NETDEV_CHANGE:
 		rt_cache_flush(0);

Other than patching the kernel to change the behaviour to be more router
like though, about the best you can do is have a cron job or daemon
check the link state, and delete the route if the link goes down, and
add it back when the link returns.  I consider that ugly and fragile
though.

-- 
Len Sorensen


Reply to: