Skip to contentSkip to conversation

new "fromarp" route flag

PATCH New Michael Schroeder 1 participant 1 message Mar 22, 2004

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 new "fromarp" route flag

The following patch implements a new route flag, "fromarp".

Problem description:
--------------------

Zeroconf hardware automatically assigns an ip address from the link local range (169.254.1.0 - 169.254.254.255). This ip addresses don't get routed and are local to the interfaces. To address such a component, one can add a link local route:

    ip route add 169.254.0.0/16 dev eth0

Things get ugly if a host is multihomed and zeroconf hardware is conected to more than one interface. It is not possible to add a route in that case.

Solution:
---------

My patch adds a new route flag, "fromarp", to the kernel. Example:

ip route add 169.254.0.0/16 fromarp nexthop dev eth0 nexthop dev eth1

If a packet is to be send with such a route, the kernel checks the arp cache of the interfaces specified in the route. If a match is found, the packet is send to the matching interface. Otherwise an arp request is sent from all of the interfaces.

Comments anyone?

include/linux/in_route.h renamed from include/linux/in_route.h.orig +1 -0
@@ -18,6 +18,7 @@
 #define RTCF_MASQ	0x00400000
 #define RTCF_SNAT	0x00800000
 #define RTCF_DOREDIRECT 0x01000000
+#define RTCF_FROMARP    0x02000000
 #define RTCF_DIRECTSRC	0x04000000
 #define RTCF_DNAT	0x08000000
 #define RTCF_BROADCAST	0x10000000
include/linux/rtnetlink.h renamed from include/linux/rtnetlink.h.orig +1 -0
@@ -170,6 +170,7 @@
 #define RTM_F_CLONED		0x200	/* This route is cloned		*/
 #define RTM_F_EQUALIZE		0x400	/* Multipath equalizer: NI	*/
 #define RTM_F_PREFIX		0x800	/* Prefix addresses		*/
+#define RTM_F_FROMARP		0x1000	/* Select if from arpcache      */
 
 /* Reserved table identifiers */
 
net/ipv4/arp.c renamed from net/ipv4/arp.c.orig +6 -0
@@ -952,6 +952,12 @@
 	return 0;
 }
 
+struct neighbour *arp_lookup(u32 ip, struct net_device *dev, int creat)
+{
+        return __neigh_lookup(&arp_tbl, &ip, dev, creat);
+}
+
+
 /*
  *	User level interface (ioctl)
  */
net/ipv4/fib_semantics.c renamed from net/ipv4/fib_semantics.c.orig +48 -0

52 lines not on this page · raw message

net/ipv4/route.c renamed from net/ipv4/route.c.orig +22 -6
@@ -1332,7 +1332,9 @@
 {
 	struct rtable *rt;
 
-	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
+	rt = (struct rtable *) skb->dst;
+	if (!rt || !(rt->rt_flags & RTCF_FROMARP))
+		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
 
 	rt = (struct rtable *) skb->dst;
 	if (rt)
@@ -2077,9 +2079,13 @@
 	}
 
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
-	if (res.fi->fib_nhs > 1 && fl.oif == 0)
-		fib_select_multipath(&fl, &res);
-	else
+	if (res.fi->fib_nhs > 1 && fl.oif == 0) {
+		if (res.fi->fib_flags & RTM_F_FROMARP) {
+			if (!fib_select_fromarp(&fl, &res))
+				flags |= RTCF_FROMARP;
+		} else
+			fib_select_multipath(&fl, &res);
+	}
 #endif
 	if (!res.prefixlen && res.type == RTN_UNICAST && !fl.oif)
 		fib_select_default(&fl, &res);
@@ -2190,8 +2196,18 @@
 
 	rth->rt_flags = flags;
 
-	hash = rt_hash_code(oldflp->fl4_dst, oldflp->fl4_src ^ (oldflp->oif << 5), tos);
-	err = rt_intern_hash(hash, rth, rp);
+	if (flags & RTCF_FROMARP) {
+		err = 0;
+		if (rth->rt_type == RTN_UNICAST || rth->fl.iif == 0) {
+			if ((err = arp_bind_neighbour(&rth->u.dst)) != 0)
+				rt_drop(rth);
+		}
+		if (!err)
+			*rp = rth;
+	} else {
+		hash = rt_hash_code(oldflp->fl4_dst, oldflp->fl4_src ^ (oldflp->oif << 5), tos);
+		err = rt_intern_hash(hash, rth, rp);
+	}
 done:
 	if (free_res)
 		fib_res_put(&res);

Cheers,
Michael.

Signature · 2 lines
Michael Schroeder                                   [email protected]
main(_){while(_=~getchar())putchar(~_-1/(~(_|32)/13*2-11)*13);}