Hi,

Routing daemons like ospfd use two interfaces to obtain route information from
the kernel:
- sysctl
- route messages

Route information from sysctl contain correct route priorities, route messages
not. This can lead to incorrect routes inside the daemons. If daemons see routes
with different priorities, they assume to see different routes.
My attached patch adds route priorities to route messages to offer a consistent
view to kernel routes with both interfaces.

Here an example of a problem, caused by this bug:

/etc/hostname.em3:
rtlabel EXPORT_DIRECT
inet 192.168.58.57 255.255.255.0 192.168.58.255
inet alias 1.0.0.1 255.255.255.0 192.168.58.255

/etc/ospfd.conf:
area 10.188.0.0 {
            interface em3:192.168.58.57 {
                        }
}
redistribute rtlabel EXPORT_DIRECT

If the interface address 1.0.0.1 is set before starting the ospfd, we have ha
route with a priority of 4:
$ ospfctl show fib | grep 1.0.0
*C        4 1.0.0.0/24           link#4

Now we delete the route with ifconfig and take a look to the generated route
message:
$ ifconfig em3 inet delete 1.0.0.1

RTM_DELETE: Delete Route: len 224, priority 0, table 0, ifidx 4, pid: 0, seq 0,
errno 0
flags:<DONE,CLONING>
use:        0   mtu:        0    expire:        0 
locks:  inits: 
sockaddrs: <DST,GATEWAY,NETMASK,IFP,IFA,LABEL>
 1.0.0.0 1.0.0.1 255.255.255.0 08:00:27:fd:b8:81 1.0.0.1 EXPORT_DIRECT

Because the priority 0 of the deleted cloning route doesn't match to the
priority of the fib route, ospfd is still seeing/announcing the network:

$ ospfctl show fib | grep 1.0.0
*C        4 1.0.0.0/24           link#4

Please take a look to my patch.

Thanks and Regards

Florian

Index: net/route.c
===================================================================
RCS file: /openbsd//src/sys/net/route.c,v
retrieving revision 1.296
diff -u -p -r1.296 route.c
--- net/route.c 7 Mar 2016 18:44:00 -0000       1.296
+++ net/route.c 24 Mar 2016 08:36:17 -0000
@@ -248,8 +248,8 @@ rt_match(struct sockaddr *dst, uint32_t 
                        error = rtrequest(RTM_RESOLVE, &info, RTP_DEFAULT,
                            &rt, tableid);
                        if (error) {
-                               rt_missmsg(RTM_MISS, &info, 0, 0, error,
-                                   tableid);
+                               rt_missmsg(RTM_MISS, &info, 0, RTP_NONE, 0,
+                                   error, tableid);
                        } else {
                                /* Inform listeners of the new route */
                                rt_sendmsg(rt, RTM_ADD, tableid);
@@ -488,7 +488,8 @@ rt_sendmsg(struct rtentry *rt, int cmd, 
                info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
        }
 
-       rt_missmsg(cmd, &info, rt->rt_flags, rt->rt_ifidx, 0, rtableid);
+       rt_missmsg(cmd, &info, rt->rt_flags, rt->rt_priority, rt->rt_ifidx, 0,
+           rtableid);
        if_put(ifp);
 }
 
@@ -522,6 +523,7 @@ rtredirect(struct sockaddr *dst, struct 
        struct ifaddr           *ifa;
        unsigned int             ifidx = 0;
        int                      flags = RTF_GATEWAY|RTF_HOST;
+       uint8_t                  prio = RTP_NONE;
 
        splsoftassert(IPL_SOFTNET);
 
@@ -578,8 +580,10 @@ create:
                        rt = NULL;
                        error = rtrequest(RTM_ADD, &info, RTP_DEFAULT, &rt,
                            rdomain);
-                       if (error == 0)
+                       if (error == 0) {
                                flags = rt->rt_flags;
+                               prio = rt->rt_priority;
+                       }
                        stat = &rtstat.rts_dynamic;
                } else {
                        /*
@@ -588,6 +592,7 @@ create:
                         */
                        rt->rt_flags |= RTF_MODIFIED;
                        flags |= RTF_MODIFIED;
+                       prio = rt->rt_priority;
                        stat = &rtstat.rts_newgateway;
                        rt_setgate(rt, gateway);
                }
@@ -609,7 +614,7 @@ out:
        info.rti_info[RTAX_DST] = dst;
        info.rti_info[RTAX_GATEWAY] = gateway;
        info.rti_info[RTAX_AUTHOR] = src;
-       rt_missmsg(RTM_REDIRECT, &info, flags, ifidx, error, rdomain);
+       rt_missmsg(RTM_REDIRECT, &info, flags, prio, ifidx, error, rdomain);
 }
 
 /*
@@ -638,7 +643,8 @@ rtdeletemsg(struct rtentry *rt, struct i
        info.rti_flags = rt->rt_flags;
        ifidx = rt->rt_ifidx;
        error = rtrequest_delete(&info, rt->rt_priority, ifp, &rt, tableid);
-       rt_missmsg(RTM_DELETE, &info, info.rti_flags, ifidx, error, tableid);
+       rt_missmsg(RTM_DELETE, &info, info.rti_flags, rt->rt_priority, ifidx,
+           error, tableid);
        if (error == 0)
                rtfree(rt);
        return (error);
Index: net/route.h
===================================================================
RCS file: /openbsd//src/sys/net/route.h,v
retrieving revision 1.132
diff -u -p -r1.132 route.h
--- net/route.h 24 Feb 2016 22:41:53 -0000      1.132
+++ net/route.h 24 Mar 2016 08:36:17 -0000
@@ -360,7 +360,7 @@ void         rt_maskedcopy(struct sockaddr *,
 struct sockaddr *rt_plen2mask(struct rtentry *, struct sockaddr_in6 *);
 void    rt_sendmsg(struct rtentry *, int, u_int);
 void    rt_sendaddrmsg(struct rtentry *, int);
-void    rt_missmsg(int, struct rt_addrinfo *, int, u_int, int, u_int);
+void    rt_missmsg(int, struct rt_addrinfo *, int, u_char, u_int, int, u_int);
 int     rt_setgate(struct rtentry *, struct sockaddr *);
 int     rt_checkgate(struct ifnet *, struct rtentry *, struct sockaddr *,
            unsigned int, struct rtentry **);
Index: net/rtsock.c
===================================================================
RCS file: /openbsd//src/sys/net/rtsock.c,v
retrieving revision 1.186
diff -u -p -r1.186 rtsock.c
--- net/rtsock.c        12 Jan 2016 09:27:46 -0000      1.186
+++ net/rtsock.c        24 Mar 2016 08:36:17 -0000
@@ -1063,8 +1063,8 @@ again:
  * destination.
  */
 void
-rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, u_int ifidx,
-    int error, u_int tableid)
+rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, uint8_t prio,
+    u_int ifidx, int error, u_int tableid)
 {
        struct rt_msghdr        *rtm;
        struct mbuf             *m;
@@ -1077,6 +1077,7 @@ rt_missmsg(int type, struct rt_addrinfo 
                return;
        rtm = mtod(m, struct rt_msghdr *);
        rtm->rtm_flags = RTF_DONE | flags;
+       rtm->rtm_priority = prio;
        rtm->rtm_errno = error;
        rtm->rtm_tableid = tableid;
        rtm->rtm_addrs = rtinfo->rti_addrs;
Index: netinet/in_pcb.c
===================================================================
RCS file: /openbsd//src/sys/netinet/in_pcb.c,v
retrieving revision 1.197
diff -u -p -r1.197 in_pcb.c
--- netinet/in_pcb.c    23 Mar 2016 15:50:36 -0000      1.197
+++ netinet/in_pcb.c    24 Mar 2016 08:36:17 -0000
@@ -692,8 +692,8 @@ in_losing(struct inpcb *inp)
                info.rti_info[RTAX_DST] = &inp->inp_route.ro_dst;
                info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
                info.rti_info[RTAX_NETMASK] = rt_plen2mask(rt, &sa_mask);
-               rt_missmsg(RTM_LOSING, &info, rt->rt_flags, rt->rt_ifidx, 0,
-                   inp->inp_rtableid);
+               rt_missmsg(RTM_LOSING, &info, rt->rt_flags, rt->rt_priority,
+                   rt->rt_ifidx, 0, inp->inp_rtableid);
                if (rt->rt_flags & RTF_DYNAMIC)
                        (void)rtrequest(RTM_DELETE, &info, rt->rt_priority,
                            NULL, inp->inp_rtableid);

Reply via email to