The kernel code in src/sys/net/route.c depends on the interfaces to know where addresses go. This can cause dubious error reporting and inappropriate routing if the routing table contains information that the interfaces themselves don't know about. The following patch corrects ifa_ifwithroute() so in certain circumstances it will query the routing table in an appropriate fashion in case the desired gateway is on a interface that doesn't know it. This also helps resolve problems of multiple interfaces on the same network or on subnetworks of one another. In these cases the kernel routing table will trump all information from the interfaces as to where things should be headed for new entries, unless the user specifically states otherwise. This has been tested with no ill effects on a variety of 3.4-release and stable machines. It looks like the patch could also be relevant to -current OpenBSD and NetBSD. - William Carrel How-To-Repeat: ifconfig xx0 10.0.0.1 netmask 255.255.255.0 route add 10.0.1.1/32 -interface xx0 -cloning route add default 10.0.1.1 This will throw a "No route to host" error without the patch, with the patch the kernel routing table will be checked and it will properly set the default gateway to 10.0.1.1 on xx0.
Responsible Changed From-To: gnats-admin->freebsd-bugs Misfiled PR.
This patch is applicable for both FreeBSD-stable AND FreeBSD-current, as well as OpenBSD and NetBSD. It has no noticeable ill-effects on the machines of nearly a dozen FreeBSD users that have been testing the patch for me. Nor does it have ill effects on the OpenBSD and NetBSD machines I have access to. It fixes some brain-dead behavior of the kernel routing table on all these operating systems. It causes the routing table to check itself for the ifa to assign to new routes before asking the interfaces. There are occasions (such as Ethernet point to point links) where the interfaces' idea of where a packet should go could disagree with the routing tables user made static entries. This leads to some very bizarre behavior for things like the default gateway if they get their packets routed to the wrong interface. The patch is available here: http://www.FreeBSD.org/cgi/query-pr.cgi?pr=16318 I just thought I'd post this around again to draw attention to my open PR with code included, and mention that I've had successful testing reports on -current. -- William Carrel
This fixed a big problem for me. I had been wondering why it wasn't possible to have the default gateway in a different (but connected) network. This should be in the released kernel!
This problem still affects the FreeBSD kernel in 4.0 and 5.0. A patch file for 4.0-STABLE follows, I've tested this on 4.0-RELEASE and 4.0-STABLE (incl. SMP for what it's worth). There is no difference between route.c at HEAD(5.0-current) and RELENG_4(4.0-stable) so this patch should work effectively in both of the aforementioned. And it does still fix my routing troubles. (and this time I sent the PR followup to a qualified name.) --- route.c.orig Sat May 27 14:48:42 2000 +++ route.c Sat May 27 15:01:43 2000 @@ -400,6 +400,9 @@ struct sockaddr *dst, *gateway; { register struct ifaddr *ifa; + struct rtentry *rt; + + ifa = 0; if ((flags & RTF_GATEWAY) == 0) { /* * If we are adding a route to an interface, @@ -408,7 +411,6 @@ * as our clue to the interface. Otherwise * we can use the local address. */ - ifa = 0; if (flags & RTF_HOST) { ifa = ifa_ifwithdstaddr(dst); } @@ -425,18 +427,33 @@ if (ifa == 0) ifa = ifa_ifwithnet(gateway); if (ifa == 0) { - struct rtentry *rt = rtalloc1(dst, 0, 0UL); - if (rt == 0) - return (0); - rt->rt_refcnt--; - if ((ifa = rt->rt_ifa) == 0) - return (0); + rt = rtalloc1(dst, 0, 0UL); + if (rt) { + rt->rt_refcnt--; + if (rt->rt_ifa) + ifa = rt->rt_ifa; + } } - if (ifa->ifa_addr->sa_family != dst->sa_family) { + if ((ifa) && (ifa->ifa_addr->sa_family != dst->sa_family)) { struct ifaddr *oifa = ifa; ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); if (ifa == 0) ifa = oifa; + } + /* + * If we are adding a gateway, it is quite + * possible that the routing table has a static + * entry in place for the gateway, that may + * not agree with the info from the interfaces. + * The routing table should carry more precedence + * than the interfaces in this matter. + * Must be careful not to stomp on new entries from + * rtinit, hence (ifa->ifa_addr !=gateway). + */ + if ((ifa == 0 || ifa->ifa_addr != gateway) && + (rt = rtalloc1(gateway,0,0UL))) { + rt->rt_refcnt--; + ifa = rt->rt_ifa; } return (ifa); } ----- End forwarded message -----
State Changed From-To: open->feedback Does this problem still occur in newer versions of FreeBSD, such as 4.3-RELEASE?
State Changed From-To: feedback->closed Automatic feedback timeout. If additional feedback that warrants the re-opening of this PR is available but not included in the audit trail, please include the feedback in a reply to this message (preserving the Subject line) and ask that the PR be re-opened.
I can confirm that this problem still occurs in RELENG_4. I'm not sure if the patch I provided is still valid. To reproduce on a system with two interfaces... ifconfig if0 10.0.1.0 -netmask 255.255.255.0 ifconfig if1 10.0.2.0 -netmask 255.255.255.0 route add 10.0.2.1 -interface if0 route add default 10.0.2.1 netstat -rnfinet will show that the default route points toward if1 even though a static route for 10.0.2.1 shows it should be going to if0. Since the route add default won't take an -interface argument it gets a little difficult to handle. The patch provided against the ancient version fixed it there. I'm not sure how much that code has changed in the past year or two. p.s. apologies for the late reply