On Wed, Jun 08, 2022 at 06:27:36PM +0200, Claudio Jeker wrote:
> On Wed, Jun 08, 2022 at 06:10:21PM +0200, Theo Buehler wrote:
> > On Wed, Jun 08, 2022 at 01:28:14PM +0200, Claudio Jeker wrote:
> > > The idea behind this diff is to use struct kroute_full in more places.
> > > Mainly when parsing route messages. This allows to factor out the pure
> > > route message parsing into dispatch_rtmsg_addr() and use it in both the
> > > gerneral routing socket code but also in fetchtables(). Which removes some
> > > duplicated code.
> > > 
> > > As a second step then this kroute_full is applied to the kroute tree. Here
> > > I limited my changes to be minimal for now. A follow up will look more
> > > into kr_fib_change() and tries to streamline that code and the bits in
> > > fetchtable().
> > > 
> > > Also struct kroute_full could be used in more places with the goal to have
> > > less mostly similar function for IPv4, IPv6 and the L3VPNs. Again this is
> > > for later.
> > > 
> > > This should behave the same as before but dispatch_rtmsg_addr() decides
> > > now in a different way if a route is connected or not (using the
> > > RTF_GATEWAY flag for this). With this loopback routes show now up as
> > > connected. It should have no noticable impact on routing.
> > > 
> > > Please give this a good test.
> > 
> > I spent some time with this diff. This is outside my comfort zone.  I'll
> > need to read this once more with a fresh head.
> > 
> > I like the direction and less spaghetti is good.
> > 
> > Some small remarks and questions inline.
> 
> Thanks for looking into this. Not many people around that actually
> understand the route socket so I know this is way out of everyones comfort
> zone. The kroute code got hammered into shape and then copied around way
> to many times. A lot of the code is pure spahetti. I try to work with
> smaller diffs to make review somewhat possible.
>  
> > > Index: kroute.c
> > > ===================================================================
> > > RCS file: /cvs/src/usr.sbin/bgpd/kroute.c,v
> > > retrieving revision 1.251
> > > diff -u -p -r1.251 kroute.c
> > > --- kroute.c      7 Jun 2022 16:42:07 -0000       1.251
> > > +++ kroute.c      7 Jun 2022 17:05:37 -0000
> > > @@ -3482,23 +3385,34 @@ dispatch_rtmsg(u_int rdomain)
> > >           case RTM_ADD:
> > >           case RTM_CHANGE:
> > >           case RTM_DELETE:
> > > -                 sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
> > > -                 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
> > > -
> > >                   if (rtm->rtm_pid == kr_state.pid) /* cause by us */
> > >                           continue;
> > >  
> > > -                 if (rtm->rtm_errno)              /* failed attempts */
> > > -                         continue;
> > > +                 /* failed attempts */
> > > +                 if (rtm->rtm_errno || !(rtm->rtm_flags & RTF_DONE))
> > > +                         return (-1);
> > >  
> > > -                 if (rtm->rtm_flags & RTF_LLINFO) /* arp cache */
> > > +                 if ((kt = ktable_get(rtm->rtm_tableid)) == NULL)
> > >                           continue;
> > >  
> > > -                 if ((kt = ktable_get(rtm->rtm_tableid)) == NULL)
> > > +                 if (dispatch_rtmsg_addr(rtm, &kl) == -1)
> > >                           continue;
> > >  
> > > -                 if (dispatch_rtmsg_addr(rtm, rti_info, kt) == -1)
> > > -                         return (-1);
> > > +                 if (rtm->rtm_flags & RTF_MPATH)
> > > +                         mpath = 1;
> > 
> > I guess the #ifdef RTF_MPATH was dropped since kroute.c is no longer
> > built outside of OpenBSD with recent -portable changes?
> 
> Yes, also the time when OpenBSD had no RTF_MPATH has long passed. So
> I see no reason to clutter this code with #ifdefs.
> For portable I would love to split the code further up so that the kroute
> code is portable but the routing socket bits are per platform. Right now
> changes to kroute.c are a pain since I need to track also the protable
> files.
>  
> > > @@ -3517,191 +3431,190 @@ dispatch_rtmsg(u_int rdomain)
> > >  }
> > >  
> > >  int
> > > -dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr 
> > > *rti_info[RTAX_MAX],
> > > -    struct ktable *kt)
> > > +dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct kroute_full *kr)
> > 
> > This is the only kroute_full called kr in the entire file. I would
> > prefer calling it kl (or kf as in the older code you don't touch).
> 
> Naming is hard. I agree using kl may be better here. Will adjust the code.
>  
> > >   case AF_INET:
> > > -         prefix.aid = AID_INET;
> > > -         prefix.v4.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
> > >           sa_in = (struct sockaddr_in *)rti_info[RTAX_NETMASK];
> > >           if (sa_in != NULL) {
> > >                   if (sa_in->sin_len != 0)
> > > -                         prefixlen = mask2prefixlen(
> > > +                         kr->prefixlen = mask2prefixlen(
> > >                               sa_in->sin_addr.s_addr);
> > 
> > I would wrap this the same way as the assignment a few lines down:
> > 
> >                             kr->prefixlen =
> >                                 mask2prefixlen(sa_in->sin_addr.s_addr);
> 
> Yes, indeed.
>  
> > >   case AID_INET:
> > > -         sa_in = (struct sockaddr_in *)sa;
> > > -         if ((kr = kroute_find(kt, prefix.v4.s_addr, prefixlen,
> > > -             prio)) != NULL) {
> > > +         if ((kr = kroute_find(kt, kl->prefix.v4.s_addr, kl->prefixlen,
> > > +             kl->priority)) != NULL) {
> > >                   if (kr->r.flags & F_KERNEL) {
> > >                           /* get the correct route */
> > > -                         if (mpath && rtm->rtm_type == RTM_CHANGE &&
> > > -                             (kr = kroute_matchgw(kr, sa_in)) == NULL) {
> > > +                         if (mpath && type == RTM_CHANGE &&
> > > +                             (kr = kroute_matchgw(kr, &kl->nexthop)) ==
> > > +                             NULL) {
> > >                                   log_warnx("%s[change]: "
> > >                                       "mpath route not found", __func__);
> > >                                   goto add4;
> > > -                         } else if (mpath && rtm->rtm_type == RTM_ADD)
> > > +                         } else if (mpath && type == RTM_ADD)
> > >                                   goto add4;
> > >  
> > > -                         if (sa_in != NULL) {
> > > +                         if (kl->nexthop.aid == AID_INET) {
> > >                                   if (kr->r.nexthop.s_addr !=
> > > -                                     sa_in->sin_addr.s_addr)
> > > +                                     kl->nexthop.v4.s_addr)
> > >                                           changed = 1;
> > >                                   kr->r.nexthop.s_addr =
> > > -                                     sa_in->sin_addr.s_addr;
> > > +                                     kl->nexthop.v4.s_addr;
> > 
> > why is there no kr->r.ifindex assignment here?
> 
> I don't know. The old code was already like this. I remember that ifindex
> was unreliable in the old times but again that is like 5+ years ago.
> I did not want to introduce code changes which I'm sure wont cause
> trouble. I think this is something to tackle at a later stage.
>  
> -- 
> :wq Claudio

and here is the updated diff I forgot to include 

-- 
:wq Claudio

Index: kroute.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/kroute.c,v
retrieving revision 1.251
diff -u -p -r1.251 kroute.c
--- kroute.c    7 Jun 2022 16:42:07 -0000       1.251
+++ kroute.c    8 Jun 2022 16:23:51 -0000
@@ -125,12 +125,11 @@ int       kroute6_compare(struct kroute6_node 
 int    knexthop_compare(struct knexthop_node *, struct knexthop_node *);
 int    kredist_compare(struct kredist_node *, struct kredist_node *);
 int    kif_compare(struct kif_node *, struct kif_node *);
-void   kr_fib_update_prio(u_int, uint8_t);
 
 struct kroute_node     *kroute_find(struct ktable *, in_addr_t, uint8_t,
                            uint8_t);
 struct kroute_node     *kroute_matchgw(struct kroute_node *,
-                           struct sockaddr_in *);
+                           struct bgpd_addr *);
 int                     kroute_insert(struct ktable *, struct kroute_node *);
 int                     kroute_remove(struct ktable *, struct kroute_node *);
 void                    kroute_clear(struct ktable *);
@@ -138,7 +137,7 @@ void                         kroute_clear(struct ktable *);
 struct kroute6_node    *kroute6_find(struct ktable *, const struct in6_addr *,
                            uint8_t, uint8_t);
 struct kroute6_node    *kroute6_matchgw(struct kroute6_node *,
-                           struct sockaddr_in6 *);
+                           struct bgpd_addr *);
 int                     kroute6_insert(struct ktable *, struct kroute6_node *);
 int                     kroute6_remove(struct ktable *, struct kroute6_node *);
 void                    kroute6_clear(struct ktable *);
@@ -188,8 +187,9 @@ int         send_rt6msg(int, int, struct ktable
 int            dispatch_rtmsg(u_int);
 int            fetchtable(struct ktable *);
 int            fetchifs(int);
-int            dispatch_rtmsg_addr(struct rt_msghdr *,
-                   struct sockaddr *[RTAX_MAX], struct ktable *);
+int            dispatch_rtmsg_addr(struct rt_msghdr *, struct kroute_full *);
+int            kr_fib_delete(struct ktable *, struct kroute_full *, int);
+int            kr_fib_change(struct ktable *, struct kroute_full *, int, int);
 
 RB_PROTOTYPE(kroute_tree, kroute_node, entry, kroute_compare)
 RB_GENERATE(kroute_tree, kroute_node, entry, kroute_compare)
@@ -1780,21 +1780,21 @@ kroute_find(struct ktable *kt, in_addr_t
 }
 
 struct kroute_node *
-kroute_matchgw(struct kroute_node *kr, struct sockaddr_in *sa_in)
+kroute_matchgw(struct kroute_node *kr, struct bgpd_addr *gw)
 {
        in_addr_t       nexthop;
 
-       if (sa_in == NULL) {
+       if (gw->aid != AID_INET) {
                log_warnx("%s: no nexthop defined", __func__);
                return (NULL);
        }
-       nexthop = sa_in->sin_addr.s_addr;
+       nexthop = gw->v4.s_addr;
 
-       while (kr) {
+       do {
                if (kr->r.nexthop.s_addr == nexthop)
                        return (kr);
                kr = kr->next;
-       }
+       } while (kr);
 
        return (NULL);
 }
@@ -1933,21 +1933,21 @@ kroute6_find(struct ktable *kt, const st
 }
 
 struct kroute6_node *
-kroute6_matchgw(struct kroute6_node *kr, struct sockaddr_in6 *sa_in6)
+kroute6_matchgw(struct kroute6_node *kr, struct bgpd_addr *gw)
 {
        struct in6_addr nexthop;
 
-       if (sa_in6 == NULL) {
+       if (gw->aid != AID_INET6) {
                log_warnx("%s: no nexthop defined", __func__);
                return (NULL);
        }
-       memcpy(&nexthop, &sa_in6->sin6_addr, sizeof(nexthop));
+       nexthop = gw->v6;
 
-       while (kr) {
+       do {
                if (memcmp(&kr->r.nexthop, &nexthop, sizeof(nexthop)) == 0)
                        return (kr);
                kr = kr->next;
-       }
+       } while (kr);
 
        return (NULL);
 }
@@ -3180,12 +3180,9 @@ fetchtable(struct ktable *kt)
        int                      mib[7];
        char                    *buf = NULL, *next, *lim;
        struct rt_msghdr        *rtm;
-       struct sockaddr         *sa, *gw, *rti_info[RTAX_MAX];
-       struct sockaddr_in      *sa_in;
-       struct sockaddr_in6     *sa_in6;
-       struct sockaddr_rtlabel *label;
-       struct kroute_node      *kr = NULL;
-       struct kroute6_node     *kr6 = NULL;
+       struct kroute_full       kl;
+       struct kroute_node      *kr;
+       struct kroute6_node     *kr6;
 
        mib[0] = CTL_NET;
        mib[1] = PF_ROUTE;
@@ -3219,145 +3216,49 @@ fetchtable(struct ktable *kt)
                rtm = (struct rt_msghdr *)next;
                if (rtm->rtm_version != RTM_VERSION)
                        continue;
-               sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
-               get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
 
-               if ((sa = rti_info[RTAX_DST]) == NULL)
+               if (dispatch_rtmsg_addr(rtm, &kl) == -1)
                        continue;
 
-               /* Skip ARP/ND cache and broadcast routes. */
-               if (rtm->rtm_flags & (RTF_LLINFO|RTF_BROADCAST))
-                       continue;
-
-               switch (sa->sa_family) {
-               case AF_INET:
-                       if ((kr = calloc(1, sizeof(struct kroute_node))) ==
-                           NULL) {
-                               log_warn("%s", __func__);
-                               free(buf);
-                               return (-1);
-                       }
-
-                       kr->r.flags = F_KERNEL;
-                       kr->r.priority = rtm->rtm_priority;
-                       kr->r.ifindex = rtm->rtm_index;
-                       kr->r.prefix.s_addr =
-                           ((struct sockaddr_in *)sa)->sin_addr.s_addr;
-                       sa_in = (struct sockaddr_in *)rti_info[RTAX_NETMASK];
-                       if (rtm->rtm_flags & RTF_STATIC)
-                               kr->r.flags |= F_STATIC;
-                       if (rtm->rtm_flags & RTF_BLACKHOLE)
-                               kr->r.flags |= F_BLACKHOLE;
-                       if (rtm->rtm_flags & RTF_REJECT)
-                               kr->r.flags |= F_REJECT;
-                       if (rtm->rtm_flags & RTF_DYNAMIC)
-                               kr->r.flags |= F_DYNAMIC;
-                       if (sa_in != NULL) {
-                               if (sa_in->sin_len == 0)
-                                       break;
-                               kr->r.prefixlen =
-                                   mask2prefixlen(sa_in->sin_addr.s_addr);
-                       } else if (rtm->rtm_flags & RTF_HOST)
-                               kr->r.prefixlen = 32;
-                       else
-                               kr->r.prefixlen =
-                                   prefixlen_classful(kr->r.prefix.s_addr);
-                       if ((label = (struct sockaddr_rtlabel *)
-                           rti_info[RTAX_LABEL]) != NULL) {
-                               kr->r.labelid =
-                                   rtlabel_name2id(label->sr_label);
-                       }
-                       break;
-               case AF_INET6:
-                       if ((kr6 = calloc(1, sizeof(struct kroute6_node))) ==
-                           NULL) {
+               if (kl.prefix.aid == AID_INET) {
+                       if ((kr = calloc(1,
+                           sizeof(struct kroute_node))) == NULL) {
                                log_warn("%s", __func__);
-                               free(buf);
                                return (-1);
                        }
+                       kr->r.prefix.s_addr = kl.prefix.v4.s_addr;
+                       kr->r.prefixlen = kl.prefixlen;
+                       if (kl.nexthop.aid == AID_INET)
+                               kr->r.nexthop.s_addr = kl.nexthop.v4.s_addr;
+                       kr->r.flags = kl.flags;
+                       kr->r.ifindex = kl.ifindex;
+                       kr->r.priority = kl.priority;
+                       kr->r.labelid = rtlabel_name2id(kl.label);
 
-                       kr6->r.flags = F_KERNEL;
-                       kr6->r.priority = rtm->rtm_priority;
-                       kr6->r.ifindex = rtm->rtm_index;
-                       memcpy(&kr6->r.prefix,
-                           &((struct sockaddr_in6 *)sa)->sin6_addr,
-                           sizeof(kr6->r.prefix));
-
-                       sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK];
-                       if (rtm->rtm_flags & RTF_STATIC)
-                               kr6->r.flags |= F_STATIC;
-                       if (rtm->rtm_flags & RTF_BLACKHOLE)
-                               kr6->r.flags |= F_BLACKHOLE;
-                       if (rtm->rtm_flags & RTF_REJECT)
-                               kr6->r.flags |= F_REJECT;
-                       if (rtm->rtm_flags & RTF_DYNAMIC)
-                               kr6->r.flags |= F_DYNAMIC;
-                       if (sa_in6 != NULL) {
-                               if (sa_in6->sin6_len == 0)
-                                       break;
-                               kr6->r.prefixlen = mask2prefixlen6(sa_in6);
-                       } else if (rtm->rtm_flags & RTF_HOST)
-                               kr6->r.prefixlen = 128;
-                       else
-                               fatalx("INET6 route without netmask");
-                       if ((label = (struct sockaddr_rtlabel *)
-                           rti_info[RTAX_LABEL]) != NULL) {
-                               kr6->r.labelid =
-                                   rtlabel_name2id(label->sr_label);
-                       }
-                       break;
-               default:
-                       continue;
-               }
-
-               if ((gw = rti_info[RTAX_GATEWAY]) != NULL)
-                       switch (gw->sa_family) {
-                       case AF_INET:
-                               if (kr == NULL)
-                                       fatalx("v4 gateway for !v4 dst?!");
-
-                               if (rtm->rtm_flags & RTF_CONNECTED) {
-                                       kr->r.flags |= F_CONNECTED;
-                                       break;
-                               }
-
-                               kr->r.nexthop.s_addr =
-                                   ((struct sockaddr_in *)gw)->sin_addr.s_addr;
-                               break;
-                       case AF_INET6:
-                               if (kr6 == NULL)
-                                       fatalx("v6 gateway for !v6 dst?!");
-
-                               if (rtm->rtm_flags & RTF_CONNECTED) {
-                                       kr6->r.flags |= F_CONNECTED;
-                                       break;
-                               }
-
-                               memcpy(&kr6->r.nexthop,
-                                   &((struct sockaddr_in6 *)gw)->sin6_addr,
-                                   sizeof(kr6->r.nexthop));
-                               break;
-                       case AF_LINK:
-                               /*
-                                * Traditional BSD connected routes have
-                                * a gateway of type AF_LINK.
-                                */
-                               if (sa->sa_family == AF_INET)
-                                       kr->r.flags |= F_CONNECTED;
-                               else if (sa->sa_family == AF_INET6)
-                                       kr6->r.flags |= F_CONNECTED;
-                               break;
-                       }
-
-               if (sa->sa_family == AF_INET) {
-                       if (rtm->rtm_priority == kr_state.fib_prio) {
+                       if (kl.priority == kr_state.fib_prio) {
                                send_rtmsg(kr_state.fd, RTM_DELETE, kt, &kr->r);
                                rtlabel_unref(kr->r.labelid);
                                free(kr);
                        } else
                                kroute_insert(kt, kr);
-               } else if (sa->sa_family == AF_INET6) {
-                       if (rtm->rtm_priority == kr_state.fib_prio) {
+               } else if (kl.prefix.aid == AID_INET6) {
+                       if ((kr6 = calloc(1,
+                           sizeof(struct kroute6_node))) == NULL) {
+                               log_warn("%s", __func__);
+                               return (-1);
+                       }
+                       kr6->r.prefix = kl.prefix.v6;
+                       kr6->r.prefixlen = kl.prefixlen;
+                       if (kl.nexthop.aid == AID_INET6)
+                               kr6->r.nexthop = kl.nexthop.v6;
+                       else
+                               kr6->r.nexthop = in6addr_any;
+                       kr6->r.flags = kl.flags;
+                       kr6->r.ifindex = kl.ifindex;
+                       kr6->r.priority = kl.priority;
+                       kr6->r.labelid = rtlabel_name2id(kl.label);
+
+                       if (kl.priority == kr_state.fib_prio) {
                                send_rt6msg(kr_state.fd, RTM_DELETE, kt,
                                    &kr6->r);
                                rtlabel_unref(kr6->r.labelid);
@@ -3454,8 +3355,9 @@ dispatch_rtmsg(u_int rdomain)
        char                    *next, *lim;
        struct rt_msghdr        *rtm;
        struct if_msghdr         ifm;
-       struct sockaddr         *sa, *rti_info[RTAX_MAX];
+       struct kroute_full       kl;
        struct ktable           *kt;
+       int                      mpath = 0;
 
        if ((n = read(kr_state.fd, &buf, sizeof(buf))) == -1) {
                if (errno == EAGAIN || errno == EINTR)
@@ -3482,23 +3384,34 @@ dispatch_rtmsg(u_int rdomain)
                case RTM_ADD:
                case RTM_CHANGE:
                case RTM_DELETE:
-                       sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
-                       get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
-
                        if (rtm->rtm_pid == kr_state.pid) /* cause by us */
                                continue;
 
-                       if (rtm->rtm_errno)              /* failed attempts */
-                               continue;
+                       /* failed attempts */
+                       if (rtm->rtm_errno || !(rtm->rtm_flags & RTF_DONE))
+                               return (-1);
 
-                       if (rtm->rtm_flags & RTF_LLINFO) /* arp cache */
+                       if ((kt = ktable_get(rtm->rtm_tableid)) == NULL)
                                continue;
 
-                       if ((kt = ktable_get(rtm->rtm_tableid)) == NULL)
+                       if (dispatch_rtmsg_addr(rtm, &kl) == -1)
                                continue;
 
-                       if (dispatch_rtmsg_addr(rtm, rti_info, kt) == -1)
-                               return (-1);
+                       if (rtm->rtm_flags & RTF_MPATH)
+                               mpath = 1;
+
+                       switch (rtm->rtm_type) {
+                       case RTM_ADD:
+                       case RTM_CHANGE:
+                               if (kr_fib_change(kt, &kl, rtm->rtm_type,
+                                   mpath) == -1)
+                                       return -1;
+                               break;
+                       case RTM_DELETE:
+                               if (kr_fib_delete(kt, &kl, mpath) == -1)
+                                       return -1;
+                               break;
+                       }
                        break;
                case RTM_IFINFO:
                        memcpy(&ifm, next, sizeof(ifm));
@@ -3517,191 +3430,190 @@ dispatch_rtmsg(u_int rdomain)
 }
 
 int
-dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX],
-    struct ktable *kt)
+dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct kroute_full *kl)
 {
-       struct sockaddr         *sa;
+       struct sockaddr         *sa, *rti_info[RTAX_MAX];
        struct sockaddr_in      *sa_in;
        struct sockaddr_in6     *sa_in6;
        struct sockaddr_rtlabel *label;
-       struct kroute_node      *kr;
-       struct kroute6_node     *kr6;
-       struct bgpd_addr         prefix;
-       int                      flags, oflags, mpath = 0, changed = 0;
-       int                      rtlabel_changed = 0;
-       uint16_t                 ifindex, new_labelid;
-       uint8_t                  prefixlen;
-       uint8_t                  prio;
-
-       flags = F_KERNEL;
-       ifindex = 0;
-       prefixlen = 0;
-       bzero(&prefix, sizeof(prefix));
+
+       sa = (struct sockaddr *)((char *)rtm + rtm->rtm_hdrlen);
+       get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
+
+       /* Skip ARP/ND cache and broadcast routes. */
+       if (rtm->rtm_flags & (RTF_LLINFO|RTF_BROADCAST))
+               return (-1);
 
        if ((sa = rti_info[RTAX_DST]) == NULL) {
-               log_warnx("empty route message");
-               return (0);
+               log_warnx("route message without destination");
+               return (-1);
        }
 
+       memset(kl, 0, sizeof(*kl));
+       kl->flags = F_KERNEL;
+
        if (rtm->rtm_flags & RTF_STATIC)
-               flags |= F_STATIC;
+               kl->flags |= F_STATIC;
        if (rtm->rtm_flags & RTF_BLACKHOLE)
-               flags |= F_BLACKHOLE;
+               kl->flags |= F_BLACKHOLE;
        if (rtm->rtm_flags & RTF_REJECT)
-               flags |= F_REJECT;
+               kl->flags |= F_REJECT;
        if (rtm->rtm_flags & RTF_DYNAMIC)
-               flags |= F_DYNAMIC;
-#ifdef RTF_MPATH
-       if (rtm->rtm_flags & RTF_MPATH)
-               mpath = 1;
-#endif
+               kl->flags |= F_DYNAMIC;
 
-       prio = rtm->rtm_priority;
+       kl->priority = rtm->rtm_priority;
        label = (struct sockaddr_rtlabel *)rti_info[RTAX_LABEL];
+       if (label != NULL)
+               if (strlcpy(kl->label, label->sr_label, sizeof(kl->label)) >=
+                   sizeof(kl->label))
+                       fatalx("rtm label overflow");
 
+       sa2addr(sa, &kl->prefix, NULL);
        switch (sa->sa_family) {
        case AF_INET:
-               prefix.aid = AID_INET;
-               prefix.v4.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
                sa_in = (struct sockaddr_in *)rti_info[RTAX_NETMASK];
                if (sa_in != NULL) {
                        if (sa_in->sin_len != 0)
-                               prefixlen = mask2prefixlen(
-                                   sa_in->sin_addr.s_addr);
+                               kl->prefixlen =
+                                   mask2prefixlen(sa_in->sin_addr.s_addr);
                } else if (rtm->rtm_flags & RTF_HOST)
-                       prefixlen = 32;
+                       kl->prefixlen = 32;
                else
-                       prefixlen =
-                           prefixlen_classful(prefix.v4.s_addr);
+                       kl->prefixlen =
+                           prefixlen_classful(kl->prefix.v4.s_addr);
                break;
        case AF_INET6:
-               prefix.aid = AID_INET6;
-               memcpy(&prefix.v6, &((struct sockaddr_in6 *)sa)->sin6_addr,
-                   sizeof(struct in6_addr));
                sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK];
                if (sa_in6 != NULL) {
                        if (sa_in6->sin6_len != 0)
-                               prefixlen = mask2prefixlen6(sa_in6);
+                               kl->prefixlen = mask2prefixlen6(sa_in6);
                } else if (rtm->rtm_flags & RTF_HOST)
-                       prefixlen = 128;
+                       kl->prefixlen = 128;
                else
                        fatalx("in6 net addr without netmask");
                break;
        default:
-               return (0);
+               return (-1);
        }
 
-       if ((sa = rti_info[RTAX_GATEWAY]) != NULL)
+       if ((sa = rti_info[RTAX_GATEWAY]) == NULL) {
+               log_warnx("route %s/%u without gateway",
+                   log_addr(&kl->prefix), kl->prefixlen);
+               return (-1);
+       }
+
+       if (rtm->rtm_flags & RTF_GATEWAY) {
                switch (sa->sa_family) {
                case AF_LINK:
-                       flags |= F_CONNECTED;
-                       ifindex = rtm->rtm_index;
-                       sa = NULL;
-                       mpath = 0;      /* link local stuff can't be mpath */
+                       kl->flags |= F_CONNECTED;
+                       kl->ifindex = rtm->rtm_index;
                        break;
                case AF_INET:
                case AF_INET6:
-                       if (rtm->rtm_flags & RTF_CONNECTED) {
-                               flags |= F_CONNECTED;
-                               ifindex = rtm->rtm_index;
-                               sa = NULL;
-                               mpath = 0; /* link local stuff can't be mpath */
-                       }
+                       sa2addr(rti_info[RTAX_GATEWAY], &kl->nexthop, NULL);
                        break;
                }
+       } else {
+               kl->flags |= F_CONNECTED;
+               kl->ifindex = rtm->rtm_index;
+       }
 
-       if (rtm->rtm_type == RTM_DELETE) {
-               switch (prefix.aid) {
-               case AID_INET:
-                       sa_in = (struct sockaddr_in *)sa;
-                       if ((kr = kroute_find(kt, prefix.v4.s_addr,
-                           prefixlen, prio)) == NULL)
-                               return (0);
-                       if (!(kr->r.flags & F_KERNEL))
-                               return (0);
+       return (0);
+}
 
-                       if (mpath)
-                               /* get the correct route */
-                               if ((kr = kroute_matchgw(kr, sa_in)) == NULL) {
-                                       log_warnx("%s[delete]: "
-                                           "mpath route not found", __func__);
-                                       return (0);
-                               }
+int
+kr_fib_delete(struct ktable *kt, struct kroute_full *kl, int mpath)
+{
+       struct kroute_node      *kr;
+       struct kroute6_node     *kr6;
 
-                       if (kroute_remove(kt, kr) == -1)
-                               return (-1);
-                       break;
-               case AID_INET6:
-                       sa_in6 = (struct sockaddr_in6 *)sa;
-                       if ((kr6 = kroute6_find(kt, &prefix.v6, prefixlen,
-                           prio)) == NULL)
-                               return (0);
-                       if (!(kr6->r.flags & F_KERNEL))
-                               return (0);
+       switch (kl->prefix.aid) {
+       case AID_INET:
+               if ((kr = kroute_find(kt, kl->prefix.v4.s_addr,
+                   kl->prefixlen, kl->priority)) == NULL)
+                       return (0);
+               if (!(kr->r.flags & F_KERNEL))
+                       return (0);
 
-                       if (mpath)
-                               /* get the correct route */
-                               if ((kr6 = kroute6_matchgw(kr6, sa_in6)) ==
-                                   NULL) {
-                                       log_warnx("%s[delete]: IPv6 mpath "
-                                           "route not found", __func__);
-                                       return (0);
-                               }
+               if (mpath) {
+                       /* get the correct route */
+                       if ((kr = kroute_matchgw(kr, &kl->nexthop)) == NULL) {
+                               log_warnx("delete %s/%u: route not found",
+                                   log_addr(&kl->prefix), kl->prefixlen);
+                               return (0);
+                       }
+               }
+               if (kroute_remove(kt, kr) == -1)
+                       return (-1);
+               break;
+       case AID_INET6:
+               if ((kr6 = kroute6_find(kt, &kl->prefix.v6, kl->prefixlen,
+                   kl->priority)) == NULL)
+                       return (0);
+               if (!(kr6->r.flags & F_KERNEL))
+                       return (0);
 
-                       if (kroute6_remove(kt, kr6) == -1)
-                               return (-1);
-                       break;
+               if (mpath) {
+                       /* get the correct route */
+                       if ((kr6 = kroute6_matchgw(kr6, &kl->nexthop)) ==
+                           NULL) {
+                               log_warnx("delete %s/%u: route not found",
+                                   log_addr(&kl->prefix), kl->prefixlen);
+                               return (0);
+                       }
                }
-               return (0);
+               if (kroute6_remove(kt, kr6) == -1)
+                       return (-1);
+               break;
        }
+       return (0);
+}
 
-       if (sa == NULL && !(flags & F_CONNECTED)) {
-               log_warnx("%s: no nexthop for %s/%u",
-                   __func__, log_addr(&prefix), prefixlen);
-               return (0);
-       }
+int
+kr_fib_change(struct ktable *kt, struct kroute_full *kl, int type, int mpath)
+{
+       struct kroute_node      *kr;
+       struct kroute6_node     *kr6;
+       int                      flags, oflags;
+       int                      changed = 0, rtlabel_changed = 0;
+       uint16_t                 new_labelid;
 
-       switch (prefix.aid) {
+       flags = kl->flags;
+       switch (kl->prefix.aid) {
        case AID_INET:
-               sa_in = (struct sockaddr_in *)sa;
-               if ((kr = kroute_find(kt, prefix.v4.s_addr, prefixlen,
-                   prio)) != NULL) {
+               if ((kr = kroute_find(kt, kl->prefix.v4.s_addr, kl->prefixlen,
+                   kl->priority)) != NULL) {
                        if (kr->r.flags & F_KERNEL) {
                                /* get the correct route */
-                               if (mpath && rtm->rtm_type == RTM_CHANGE &&
-                                   (kr = kroute_matchgw(kr, sa_in)) == NULL) {
+                               if (mpath && type == RTM_CHANGE &&
+                                   (kr = kroute_matchgw(kr, &kl->nexthop)) ==
+                                   NULL) {
                                        log_warnx("%s[change]: "
                                            "mpath route not found", __func__);
                                        goto add4;
-                               } else if (mpath && rtm->rtm_type == RTM_ADD)
+                               } else if (mpath && type == RTM_ADD)
                                        goto add4;
 
-                               if (sa_in != NULL) {
+                               if (kl->nexthop.aid == AID_INET) {
                                        if (kr->r.nexthop.s_addr !=
-                                           sa_in->sin_addr.s_addr)
+                                           kl->nexthop.v4.s_addr)
                                                changed = 1;
                                        kr->r.nexthop.s_addr =
-                                           sa_in->sin_addr.s_addr;
+                                           kl->nexthop.v4.s_addr;
                                } else {
                                        if (kr->r.nexthop.s_addr != 0)
                                                changed = 1;
                                        kr->r.nexthop.s_addr = 0;
+                                       kr->r.ifindex = kl->ifindex;
                                }
 
                                if (kr->r.flags & F_NEXTHOP)
                                        flags |= F_NEXTHOP;
 
-                               if (label != NULL) {
-                                       new_labelid =
-                                           rtlabel_name2id(label->sr_label);
-                                       if (kr->r.labelid != new_labelid) {
-                                               rtlabel_unref(kr->r.labelid);
-                                               kr->r.labelid = new_labelid;
-                                               rtlabel_changed = 1;
-                                       }
-                               } else if (kr->r.labelid) {
+                               new_labelid = rtlabel_name2id(kl->label);
+                               if (kr->r.labelid != new_labelid) {
                                        rtlabel_unref(kr->r.labelid);
-                                       kr->r.labelid = 0;
+                                       kr->r.labelid = new_labelid;
                                        rtlabel_changed = 1;
                                }
 
@@ -3729,10 +3641,6 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt
                                if (kr->r.flags & F_NEXTHOP && changed)
                                        knexthop_track(kt, kr);
                        }
-               } else if (rtm->rtm_type == RTM_CHANGE) {
-                       log_warnx("%s: change req for %s/%u: not in table",
-                           __func__, log_addr(&prefix), prefixlen);
-                       return (0);
                } else {
 add4:
                        if ((kr = calloc(1,
@@ -3740,70 +3648,54 @@ add4:
                                log_warn("%s", __func__);
                                return (-1);
                        }
-                       kr->r.prefix.s_addr = prefix.v4.s_addr;
-                       kr->r.prefixlen = prefixlen;
-                       if (sa_in != NULL)
-                               kr->r.nexthop.s_addr = sa_in->sin_addr.s_addr;
-                       else
-                               kr->r.nexthop.s_addr = 0;
+                       kr->r.prefix.s_addr = kl->prefix.v4.s_addr;
+                       kr->r.prefixlen = kl->prefixlen;
+                       if (kl->nexthop.aid == AID_INET)
+                               kr->r.nexthop.s_addr = kl->nexthop.v4.s_addr;
                        kr->r.flags = flags;
-                       kr->r.ifindex = ifindex;
-                       kr->r.priority = prio;
+                       kr->r.ifindex = kl->ifindex;
+                       kr->r.priority = kl->priority;
+                       kr->r.labelid = rtlabel_name2id(kl->label);
 
-                       if (label) {
-                               kr->r.labelid =
-                                   rtlabel_name2id(label->sr_label);
-                       }
                        kroute_insert(kt, kr);
                }
                break;
        case AID_INET6:
-               sa_in6 = (struct sockaddr_in6 *)sa;
-               if ((kr6 = kroute6_find(kt, &prefix.v6, prefixlen, prio)) !=
-                   NULL) {
+               if ((kr6 = kroute6_find(kt, &kl->prefix.v6, kl->prefixlen,
+                   kl->priority)) != NULL) {
                        if (kr6->r.flags & F_KERNEL) {
                                /* get the correct route */
-                               if (mpath && rtm->rtm_type == RTM_CHANGE &&
-                                   (kr6 = kroute6_matchgw(kr6, sa_in6)) ==
-                                   NULL) {
+                               if (mpath && type == RTM_CHANGE &&
+                                   (kr6 = kroute6_matchgw(kr6, &kl->nexthop))
+                                   == NULL) {
                                        log_warnx("%s[change]: IPv6 mpath "
                                            "route not found", __func__);
                                        goto add6;
-                               } else if (mpath && rtm->rtm_type == RTM_ADD)
+                               } else if (mpath && type == RTM_ADD)
                                        goto add6;
 
-                               if (sa_in6 != NULL) {
+                               if (kl->nexthop.aid == AID_INET6) {
                                        if (memcmp(&kr6->r.nexthop,
-                                           &sa_in6->sin6_addr,
+                                           &kl->nexthop.v6,
                                            sizeof(struct in6_addr)))
                                                changed = 1;
-                                       memcpy(&kr6->r.nexthop,
-                                           &sa_in6->sin6_addr,
-                                           sizeof(struct in6_addr));
+                                       kr6->r.nexthop = kl->nexthop.v6;
                                } else {
                                        if (memcmp(&kr6->r.nexthop,
                                            &in6addr_any,
                                            sizeof(struct in6_addr)))
                                                changed = 1;
-                                       memcpy(&kr6->r.nexthop,
-                                           &in6addr_any,
-                                           sizeof(struct in6_addr));
+                                       kr6->r.nexthop = in6addr_any;
+                                       kr6->r.ifindex = kl->ifindex;
                                }
 
                                if (kr6->r.flags & F_NEXTHOP)
                                        flags |= F_NEXTHOP;
 
-                               if (label != NULL) {
-                                       new_labelid =
-                                           rtlabel_name2id(label->sr_label);
-                                       if (kr6->r.labelid != new_labelid) {
-                                               rtlabel_unref(kr6->r.labelid);
-                                               kr6->r.labelid = new_labelid;
-                                               rtlabel_changed = 1;
-                                       }
-                               } else if (kr6->r.labelid) {
+                               new_labelid = rtlabel_name2id(kl->label);
+                               if (kr6->r.labelid != new_labelid) {
                                        rtlabel_unref(kr6->r.labelid);
-                                       kr6->r.labelid = 0;
+                                       kr6->r.labelid = new_labelid;
                                        rtlabel_changed = 1;
                                }
 
@@ -3832,10 +3724,6 @@ add4:
                                if (kr6->r.flags & F_NEXTHOP && changed)
                                        knexthop_track(kt, kr6);
                        }
-               } else if (rtm->rtm_type == RTM_CHANGE) {
-                       log_warnx("%s: change req for %s/%u: not in table",
-                           __func__, log_addr(&prefix), prefixlen);
-                       return (0);
                } else {
 add6:
                        if ((kr6 = calloc(1,
@@ -3843,23 +3731,17 @@ add6:
                                log_warn("%s", __func__);
                                return (-1);
                        }
-                       memcpy(&kr6->r.prefix, &prefix.v6,
-                           sizeof(struct in6_addr));
-                       kr6->r.prefixlen = prefixlen;
-                       if (sa_in6 != NULL)
-                               memcpy(&kr6->r.nexthop, &sa_in6->sin6_addr,
-                                   sizeof(struct in6_addr));
+                       kr6->r.prefix = kl->prefix.v6;
+                       kr6->r.prefixlen = kl->prefixlen;
+                       if (kl->nexthop.aid == AID_INET6)
+                               kr6->r.nexthop = kl->nexthop.v6;
                        else
-                               memcpy(&kr6->r.nexthop, &in6addr_any,
-                                   sizeof(struct in6_addr));
+                               kr6->r.nexthop = in6addr_any;
                        kr6->r.flags = flags;
-                       kr6->r.ifindex = ifindex;
-                       kr6->r.priority = prio;
+                       kr6->r.ifindex = kl->ifindex;
+                       kr6->r.priority = kl->priority;
+                       kr6->r.labelid = rtlabel_name2id(kl->label);
 
-                       if (label) {
-                               kr6->r.labelid =
-                                   rtlabel_name2id(label->sr_label);
-                       }
                        kroute6_insert(kt, kr6);
                }
                break;

Reply via email to