diff -ur v2.4.26/linux/Documentation/filesystems/proc.txt linux/Documentation/filesystems/proc.txt --- v2.4.26/linux/Documentation/filesystems/proc.txt 2003-06-14 08:41:59.000000000 +0300 +++ linux/Documentation/filesystems/proc.txt 2004-03-28 19:13:07.139797168 +0300 @@ -1527,6 +1527,15 @@ Log packets with source addresses with no known route to kernel log. +loop +---- + +By default (loop=0) the traffic between local IP addresses +is routed via interface "lo". Setting this flag for two +interfaces allows traffic between their IP addresses to +be looped externally. This is useful for setups where the +interfaces are attached to same broadcast medium. + mc_forwarding ------------- diff -ur v2.4.26/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt --- v2.4.26/linux/Documentation/networking/ip-sysctl.txt 2004-03-28 16:23:57.000000000 +0300 +++ linux/Documentation/networking/ip-sysctl.txt 2004-03-28 19:13:07.139797168 +0300 @@ -391,6 +391,13 @@ conf/all/mc_forwarding must also be set to TRUE to enable multicast routing for the interface +loop - BOOLEAN + By default (loop=0) the traffic between local IP addresses + is routed via interface "lo". Setting this flag for two + interfaces allows traffic between their IP addresses to + be looped externally. This is useful for setups where the + interfaces are attached to same broadcast medium. + medium_id - INTEGER Integer value used to differentiate the devices by the medium they are attached to. Two devices can have different id values when diff -ur v2.4.26/linux/include/linux/inetdevice.h linux/include/linux/inetdevice.h --- v2.4.26/linux/include/linux/inetdevice.h 2004-03-28 16:23:57.000000000 +0300 +++ linux/include/linux/inetdevice.h 2004-03-28 19:13:37.075246288 +0300 @@ -22,6 +22,7 @@ int arp_ignore; int medium_id; int force_igmp_version; + int loop; void *sysctl; }; @@ -73,6 +74,7 @@ (ipv4_devconf.accept_redirects || (in_dev)->cnf.accept_redirects))) #define IN_DEV_ARPFILTER(in_dev) (ipv4_devconf.arp_filter || (in_dev)->cnf.arp_filter) +#define IN_DEV_LOOP(in_dev) ((in_dev)->cnf.loop) #define IN_DEV_ARP_ANNOUNCE(in_dev) (max(ipv4_devconf.arp_announce, (in_dev)->cnf.arp_announce)) #define IN_DEV_ARP_IGNORE(in_dev) (max(ipv4_devconf.arp_ignore, (in_dev)->cnf.arp_ignore)) diff -ur v2.4.26/linux/include/linux/sysctl.h linux/include/linux/sysctl.h --- v2.4.26/linux/include/linux/sysctl.h 2004-03-28 16:23:57.000000000 +0300 +++ linux/include/linux/sysctl.h 2004-03-28 19:14:37.726025968 +0300 @@ -364,6 +364,7 @@ NET_IPV4_CONF_FORCE_IGMP_VERSION=17, NET_IPV4_CONF_ARP_ANNOUNCE=18, NET_IPV4_CONF_ARP_IGNORE=19, + NET_IPV4_CONF_LOOP=20, }; /* /proc/sys/net/ipv4/netfilter */ diff -ur v2.4.26/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c --- v2.4.26/linux/net/ipv4/devinet.c 2004-03-28 16:23:57.000000000 +0300 +++ linux/net/ipv4/devinet.c 2004-03-28 19:15:00.831513400 +0300 @@ -1134,7 +1134,7 @@ static struct devinet_sysctl_table { struct ctl_table_header *sysctl_header; - ctl_table devinet_vars[20]; + ctl_table devinet_vars[21]; ctl_table devinet_dev[2]; ctl_table devinet_conf_dir[2]; ctl_table devinet_proto_dir[2]; @@ -1189,6 +1189,9 @@ {NET_IPV4_CONF_ARP_IGNORE, "arp_ignore", &ipv4_devconf.arp_ignore, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_IPV4_CONF_LOOP, "loop", + &ipv4_devconf.loop, sizeof(int), 0644, NULL, + &proc_dointvec}, {NET_IPV4_CONF_FORCE_IGMP_VERSION, "force_igmp_version", &ipv4_devconf.force_igmp_version, sizeof(int), 0644, NULL, &proc_dointvec}, diff -ur v2.4.26/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c --- v2.4.26/linux/net/ipv4/fib_frontend.c 2003-08-25 22:06:13.000000000 +0300 +++ linux/net/ipv4/fib_frontend.c 2004-03-28 19:13:07.144796408 +0300 @@ -209,7 +209,7 @@ struct in_device *in_dev; struct rt_key key; struct fib_result res; - int no_addr, rpf; + int no_addr, rpf, loop; int ret; key.dst = src; @@ -219,12 +219,13 @@ key.iif = oif; key.scope = RT_SCOPE_UNIVERSE; - no_addr = rpf = 0; + no_addr = rpf = loop = 0; read_lock(&inetdev_lock); in_dev = __in_dev_get(dev); if (in_dev) { no_addr = in_dev->ifa_list == NULL; rpf = IN_DEV_RPFILTER(in_dev); + loop = IN_DEV_LOOP(in_dev); } read_unlock(&inetdev_lock); @@ -233,6 +234,11 @@ if (fib_lookup(&key, &res)) goto last_resort; + if (loop && res.type == RTN_LOCAL) { + *spec_dst = FIB_RES_PREFSRC(res); + fib_res_put(&res); + return 0; + } if (res.type != RTN_UNICAST) goto e_inval_res; *spec_dst = FIB_RES_PREFSRC(res); diff -ur v2.4.26/linux/net/ipv4/route.c linux/net/ipv4/route.c --- v2.4.26/linux/net/ipv4/route.c 2003-11-28 22:04:14.000000000 +0200 +++ linux/net/ipv4/route.c 2004-03-28 19:13:07.146796104 +0300 @@ -1853,6 +1853,11 @@ dev_put(dev_out); goto out; /* Wrong error code */ } + err = -ENETDOWN; + if (!(dev_out->flags&IFF_UP)) { + dev_put(dev_out); + goto out; + } if (LOCAL_MCAST(oldkey->dst) || oldkey->dst == 0xFFFFFFFF) { if (!key.src) @@ -1922,10 +1927,41 @@ goto e_inval; if (res.type == RTN_LOCAL) { - if (!key.src) - key.src = key.dst; + struct in_device *in_dev; + u32 src; + if (dev_out) dev_put(dev_out); + dev_out = FIB_RES_DEV(res); + in_dev = in_dev_get(dev_out); + src = key.src? : FIB_RES_PREFSRC(res); + if (in_dev && IN_DEV_LOOP(in_dev) && src) { + struct net_device *dev_src; + + in_dev_put(in_dev); + in_dev = NULL; + dev_src = ip_dev_find(src); + if (dev_src && dev_src != dev_out && + (in_dev = in_dev_get(dev_src)) && + IN_DEV_LOOP(in_dev)) { + in_dev_put(in_dev); + dev_out = dev_src; + key.src = src; + key.oif = dev_out->ifindex; + res.type = RTN_UNICAST; + if (res.fi) { + fib_info_put(res.fi); + res.fi = NULL; + } + goto make_route; + } + if (dev_src) + dev_put(dev_src); + } + if (in_dev) + in_dev_put(in_dev); + if (!key.src) + key.src = key.dst; dev_out = &loopback_dev; dev_hold(dev_out); key.oif = dev_out->ifindex;