Hi,
I ran into a problem where when using /31 netmasks on point to point
links, I am unable to add a larger summary route that happens to have
the same network address as the /31 link route the box has. It's a
bit hard to explain so hopefully the art below helps.
bsd1 rtr2
+---------------------+ +---------------------+
| vio0 172.19.6.33/31|<----------->|172.19.6.32/31 if1 |
+---------------------+ +---------------------+
172.19.6.32/27 -> 172.19.6.32
$route show
...
172.17.6.32/31 172.17.6.33 UCn 1 0 - 4 vio0
172.17.6.32 50:40:61:d6:05:e3 UHLch 79 5959 - 3 vio0
172.17.6.33 52:54:00:e7:0c:c5 UHLl 0 70 - 1 vio0
When I try to add the /27 route, it comes back with invalid argument
$ doas route add 172.17.6.32/27 172.17.6.32
add net 172.17.6.32/27: gateway 172.17.6.32: Invalid argument
I managed to track this down to a check in rtsock.c where it thinks that
the route I am adding is a modification of the existing L2 route for
172.19.7.32. The Invalid Argument is because later on in the RTM_CHANGE
code it wants a AF of the new nexthop to be the same as the route it
thinks its changing. When using /30 routes this would never happen as
you wouldn't get a host on the network address I guess.
Diff below fixed the problem by also checking the prefix length matches
before assuming the route isn't a new route and jumping into RTM_CHANGE
code.
The code in change: also checks the AF are the same, before it will
do a modification so I'm not sure if this should also check that before
assuming the route isn't actually a new one?
As far as I could tell reading the other code, it seemed like the only
way to get RTF_CACHED flag was to be a L2 nexthop, so I don't think that
there would be a case where the prefix length of the new and old entries
don't match but the intent was to go through the change path.
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index a717d112e..9dbc8ca90 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -937,7 +937,10 @@ rtm_output(struct rt_msghdr *rtm, struct rtentry **prt,
* cached route because this can lead to races in the
* receive path. Instead we update the L2 cache.
*/
- if ((rt != NULL) && ISSET(rt->rt_flags, RTF_CACHED)) {
+ plen = rtable_satoplen(info->rti_info[RTAX_DST]->sa_family,
+ info->rti_info[RTAX_NETMASK]);
+ if ((rt != NULL) && (plen == rt->rt_plen) &&
+ ISSET(rt->rt_flags, RTF_CACHED)) {
ifp = if_get(rt->rt_ifidx);
if (ifp == NULL) {
rtfree(rt);