On Thu, Jul 28, 2022 at 12:48:05PM +0200, Claudio Jeker wrote: > Next step on the epic saga of cleaning up kroute.c > > Refactor kroute_remove() so that a struct kroute_full can be passed to the > function. It updates the struct kroute_full with the route that got removed. > > I split the code into kroute[46]_remove() to make kroute_remove() less > cluttered. The return value of those two functions is a bit overloaded but > I hope to make this better further down the road.
That's fine for now. An obvious suggestion would be to use an out parameter for multipath. Let kroute[46]_remove() return -1, 0 (where -1 and 0 have the same meaning as -2 and -1 in your diff), otherwise return 1. Then you can do: case AID_INET: ret = kroute4_remove(kt, kf, any, &multipath); if (ret <= 0) return ret; break; Diff looks good, some comments inline. ok tb > > -- > :wq Claudio > > Index: kroute.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/kroute.c,v > retrieving revision 1.283 > diff -u -p -r1.283 kroute.c > --- kroute.c 27 Jul 2022 17:23:17 -0000 1.283 > +++ kroute.c 28 Jul 2022 09:20:50 -0000 > @@ -123,10 +123,6 @@ int kr4_change(struct ktable *, struct k > int kr6_change(struct ktable *, struct kroute_full *); > int krVPN4_change(struct ktable *, struct kroute_full *); > int krVPN6_change(struct ktable *, struct kroute_full *); > -int kr4_delete(struct ktable *, struct kroute_full *); > -int kr6_delete(struct ktable *, struct kroute_full *); > -int krVPN4_delete(struct ktable *, struct kroute_full *); > -int krVPN6_delete(struct ktable *, struct kroute_full *); > int kr_net_match(struct ktable *, struct network_config *, uint16_t, int); > struct network *kr_net_find(struct ktable *, struct network *); > void kr_net_clear(struct ktable *); > @@ -144,18 +140,17 @@ struct kroute *kroute_find(struct ktable > uint8_t, uint8_t); > struct kroute *kroute_matchgw(struct kroute *, struct bgpd_addr *); > int kroute_insert(struct ktable *, struct kroute_full *); > -int kroute_remove(struct ktable *, struct kroute *); > +int kroute_remove(struct ktable *, struct kroute_full *, int); > void kroute_clear(struct ktable *); > > struct kroute6 *kroute6_find(struct ktable *, const struct bgpd_addr *, > uint8_t, uint8_t); > struct kroute6 *kroute6_matchgw(struct kroute6 *, struct bgpd_addr *); > -int kroute6_remove(struct ktable *, struct kroute6 *); > void kroute6_clear(struct ktable *); > > struct knexthop *knexthop_find(struct ktable *, struct bgpd_addr *); > int knexthop_insert(struct ktable *, struct knexthop *); > -int knexthop_remove(struct ktable *, struct knexthop *); > +void knexthop_remove(struct ktable *, struct knexthop *); > void knexthop_clear(struct ktable *); > > struct kif_node *kif_find(int); > @@ -662,18 +657,7 @@ kr_delete(u_int rtableid, struct kroute_ > return (0); > kf->flags |= F_BGPD; > kf->priority = RTP_MINE; > - switch (kf->prefix.aid) { > - case AID_INET: > - return (kr4_delete(kt, kf)); > - case AID_INET6: > - return (kr6_delete(kt, kf)); > - case AID_VPN_IPv4: > - return (krVPN4_delete(kt, kf)); > - case AID_VPN_IPv6: > - return (krVPN6_delete(kt, kf)); > - } > - log_warnx("%s: not handled AID", __func__); > - return (-1); > + return kroute_remove(kt, kf, 1); > } > > int > @@ -689,18 +673,12 @@ kr_flush(u_int rtableid) > > RB_FOREACH_SAFE(kr, kroute_tree, &kt->krt, next) > if ((kr->flags & F_BGPD_INSERTED)) { > - if (kt->fib_sync) /* coupled */ > - send_rtmsg(kr_state.fd, RTM_DELETE, kt, > - kr_tofull(kr)); > - if (kroute_remove(kt, kr) == -1) > + if (kroute_remove(kt, kr_tofull(kr), 1) == -1) > return (-1); > } > RB_FOREACH_SAFE(kr6, kroute6_tree, &kt->krt6, next6) > if ((kr6->flags & F_BGPD_INSERTED)) { > - if (kt->fib_sync) /* coupled */ > - send_rtmsg(kr_state.fd, RTM_DELETE, kt, > - kr6_tofull(kr6)); > - if (kroute6_remove(kt, kr6) == -1) > + if (kroute_remove(kt, kr6_tofull(kr6), 1) == -1) > return (-1); > } > > @@ -708,86 +686,6 @@ kr_flush(u_int rtableid) > return (0); > } > > -int > -kr4_delete(struct ktable *kt, struct kroute_full *kf) > -{ > - struct kroute *kr; > - > - if ((kr = kroute_find(kt, &kf->prefix, kf->prefixlen, > - kf->priority)) == NULL) > - return (0); > - > - if (!(kr->flags & F_BGPD_INSERTED)) > - return (0); > - > - send_rtmsg(kr_state.fd, RTM_DELETE, kt, kr_tofull(kr)); > - > - if (kroute_remove(kt, kr) == -1) > - return (-1); > - > - return (0); > -} > - > -int > -kr6_delete(struct ktable *kt, struct kroute_full *kf) > -{ > - struct kroute6 *kr6; > - > - if ((kr6 = kroute6_find(kt, &kf->prefix, kf->prefixlen, > - kf->priority)) == NULL) > - return (0); > - > - if (!(kr6->flags & F_BGPD_INSERTED)) > - return (0); > - > - send_rtmsg(kr_state.fd, RTM_DELETE, kt, kr6_tofull(kr6)); > - > - if (kroute6_remove(kt, kr6) == -1) > - return (-1); > - > - return (0); > -} > - > -int > -krVPN4_delete(struct ktable *kt, struct kroute_full *kf) > -{ > - struct kroute *kr; > - > - if ((kr = kroute_find(kt, &kf->prefix, kf->prefixlen, > - kf->priority)) == NULL) > - return (0); > - > - if (!(kr->flags & F_BGPD_INSERTED)) > - return (0); > - > - send_rtmsg(kr_state.fd, RTM_DELETE, kt, kr_tofull(kr)); > - > - if (kroute_remove(kt, kr) == -1) > - return (-1); > - > - return (0); > -} > - > -int > -krVPN6_delete(struct ktable *kt, struct kroute_full *kf) > -{ > - struct kroute6 *kr6; > - > - if ((kr6 = kroute6_find(kt, &kf->prefix, kf->prefixlen, > - kf->priority)) == NULL) > - return (0); > - > - if (!(kr6->flags & F_BGPD_INSERTED)) > - return (0); > - > - send_rtmsg(kr_state.fd, RTM_DELETE, kt, kr6_tofull(kr6)); > - > - if (kroute6_remove(kt, kr6) == -1) > - return (-1); > - > - return (0); > -} > - > void > kr_shutdown(void) > { > @@ -1711,7 +1609,7 @@ kroute_insert(struct ktable *kt, struct > { > struct kroute *kr, *krm; > struct kroute6 *kr6, *kr6m; > - struct knexthop *h; > + struct knexthop *n; > uint32_t mplslabel = 0; > > if (kf->prefix.aid == AID_VPN_IPv4 || > @@ -1800,10 +1698,10 @@ kroute_insert(struct ktable *kt, struct > > /* XXX this is wrong for nexthop validated via BGP */ > if (!(kf->flags & F_BGPD)) { > - RB_FOREACH(h, knexthop_tree, KT2KNT(kt)) > - if (prefix_compare(&kf->prefix, &h->nexthop, > + RB_FOREACH(n, knexthop_tree, KT2KNT(kt)) > + if (prefix_compare(&kf->prefix, &n->nexthop, > kf->prefixlen) == 0) > - knexthop_validate(kt, h); > + knexthop_validate(kt, n); > > if (krm == NULL) > /* redistribute multipath routes only once */ > @@ -1814,57 +1712,163 @@ kroute_insert(struct ktable *kt, struct > } > > > -int > -kroute_remove(struct ktable *kt, struct kroute *kr) > +static int > +kroute4_remove(struct ktable *kt, struct kroute_full *kf, int any) > { > - struct kroute *krm; > - struct knexthop *s; > + struct kroute *kr, *krm; > + int multipath = 0; > > - if ((krm = RB_FIND(kroute_tree, &kt->krt, kr)) == NULL) { > - log_warnx("%s: failed to find %s/%u", __func__, > - inet_ntoa(kr->prefix), kr->prefixlen); > + if ((kr = kroute_find(kt, &kf->prefix, kf->prefixlen, > + kf->priority)) == NULL) > + return (-1); > + > + if ((kr->flags & F_BGPD) != (kf->flags & F_BGPD)) { > + log_warnx("%s: wrong type for %s/%u", __func__, > + log_addr(&kf->prefix), kf->prefixlen); > + if (!(kf->flags & F_BGPD)) > + kr->flags &= ~F_BGPD_INSERTED; > return (-1); > } > > + /* get the correct route to remove */ > + if (any) { > + krm = kr; > + } else { I'd probably have done: krm = kr if (!any) { > + if ((krm = kroute_matchgw(kr, &kf->nexthop)) == NULL) { > + log_warnx("delete %s/%u: route not found", > + log_addr(&kf->prefix), kf->prefixlen); > + return (-2); > + } > + } > + > if (krm == kr) { > /* head element */ > - if (RB_REMOVE(kroute_tree, &kt->krt, kr) == NULL) { > - log_warnx("%s: failed for %s/%u", __func__, > - inet_ntoa(kr->prefix), kr->prefixlen); > - return (-1); Would it not be easier to initialize multipath to 1 and set it to 0 here if kr->next == NULL? > + RB_REMOVE(kroute_tree, &kt->krt, kr); > + if (kr->next != NULL) { > + kr = kr->next; > + if (RB_INSERT(kroute_tree, &kt->krt, kr) != NULL) { > + log_warnx("%s: failed to add %s/%u", > + __func__, inet_ntoa(kr->prefix), > + kr->prefixlen); > + return (-2); > + } > + multipath = 1; > } > + } else { > + /* somewhere in the list */ > + while (kr->next != krm && kr->next != NULL) > + kr = kr->next; > + if (kr->next == NULL) { > + log_warnx("%s: multipath list corrupted for %s/%u", > + __func__, inet_ntoa(kr->prefix), kr->prefixlen); > + return (-2); > + } > + kr->next = krm->next; > + multipath = 1; > + } > + *kf = *kr_tofull(krm); > + > + rtlabel_unref(krm->labelid); > + free(krm); > + return (multipath); > +} > + > +static int > +kroute6_remove(struct ktable *kt, struct kroute_full *kf, int any) > +{ > + struct kroute6 *kr, *krm; > + int multipath = 0; > + > + if ((kr = kroute6_find(kt, &kf->prefix, kf->prefixlen, > + kf->priority)) == NULL) > + return (-1); > + > + if ((kr->flags & F_BGPD) != (kf->flags & F_BGPD)) { > + log_warnx("%s: wrong type for %s/%u", __func__, > + log_addr(&kf->prefix), kf->prefixlen); > + if (!(kf->flags & F_BGPD)) > + kr->flags &= ~F_BGPD_INSERTED; > + return (-1); > + } > + > + /* get the correct route to remove */ > + if (any) { > + krm = kr; same re krm = kr; if (!any) { > + } else { > + if ((krm = kroute6_matchgw(kr, &kf->nexthop)) == NULL) { > + log_warnx("delete %s/%u: route not found", > + log_addr(&kf->prefix), kf->prefixlen); > + return (-2); > + } > + } > + > + if (krm == kr) { > + /* head element */ > + RB_REMOVE(kroute6_tree, &kt->krt6, kr); ditto re multipath = 1 by default. > if (kr->next != NULL) { > - if (RB_INSERT(kroute_tree, &kt->krt, kr->next) != > - NULL) { > + kr = kr->next; > + if (RB_INSERT(kroute6_tree, &kt->krt6, kr) != NULL) { > log_warnx("%s: failed to add %s/%u", __func__, > - inet_ntoa(kr->prefix), kr->prefixlen); > - return (-1); > + log_in6addr(&kr->prefix), kr->prefixlen); > + return (-2); > } > + multipath = 1; > } > } else { > /* somewhere in the list */ > - while (krm->next != kr && krm->next != NULL) > - krm = krm->next; > - if (krm->next == NULL) { > + while (kr->next != krm && kr->next != NULL) > + kr = kr->next; > + if (kr->next == NULL) { > log_warnx("%s: multipath list corrupted for %s/%u", > - __func__, inet_ntoa(kr->prefix), kr->prefixlen); > - return (-1); > + __func__, log_in6addr(&kr->prefix), kr->prefixlen); > + return (-2); > } > - krm->next = kr->next; > + kr->next = krm->next; > + multipath = 1; > + } > + *kf = *kr6_tofull(krm); > + > + rtlabel_unref(krm->labelid); > + free(krm); > + return (multipath); > +} > + > + > +int > +kroute_remove(struct ktable *kt, struct kroute_full *kf, int any) > +{ > + struct knexthop *n; > + int multipath; > + > + switch (kf->prefix.aid) { > + case AID_INET: > + multipath = kroute4_remove(kt, kf, any); > + break; > + case AID_INET6: > + multipath = kroute6_remove(kt, kf, any); > + break; > + default: > + log_warnx("%s: not handled AID", __func__); > + return (-1); > } > > + if (multipath < 0) > + return (multipath + 1); > + > /* check whether a nexthop depends on this kroute */ > - if (kr->flags & F_NEXTHOP) > - RB_FOREACH(s, knexthop_tree, KT2KNT(kt)) > - if (s->kroute == kr) > - knexthop_validate(kt, s); > + if (kf->flags & F_NEXTHOP) > + RB_FOREACH(n, knexthop_tree, KT2KNT(kt)) One or two pairs of braces would help > + if (prefix_compare(&kf->prefix, &n->nexthop, > + kf->prefixlen) == 0) > + knexthop_validate(kt, n); > > - if (!(kr->flags & F_BGPD) && kr == krm && kr->next == NULL) > + if (!((kf->flags & F_BGPD) || multipath)) maybe use De Morgan: if (!(kf->flags & F_BGPD) && !multipath) > /* again remove only once */ > - kr_redistribute(IMSG_NETWORK_REMOVE, kt, kr_tofull(kr)); > + kr_redistribute(IMSG_NETWORK_REMOVE, kt, kf); > + > + if (kf->flags & F_BGPD_INSERTED) > + send_rtmsg(kr_state.fd, RTM_DELETE, kt, kf); send_rtmsg() is now called later than before. I suspect that's fine, but I'm not 100% sure. > > - rtlabel_unref(kr->labelid); > - free(kr); > return (0); > } > > @@ -1874,7 +1878,7 @@ kroute_clear(struct ktable *kt) > struct kroute *kr; > > while ((kr = RB_MIN(kroute_tree, &kt->krt)) != NULL) > - kroute_remove(kt, kr); > + kroute_remove(kt, kr_tofull(kr), 1); > } > > struct kroute6 * > @@ -1924,67 +1928,13 @@ kroute6_matchgw(struct kroute6 *kr, stru > return (NULL); > } > > -int > -kroute6_remove(struct ktable *kt, struct kroute6 *kr) > -{ > - struct kroute6 *krm; > - struct knexthop *s; > - > - if ((krm = RB_FIND(kroute6_tree, &kt->krt6, kr)) == NULL) { > - log_warnx("%s: failed for %s/%u", __func__, > - log_in6addr(&kr->prefix), kr->prefixlen); > - return (-1); > - } > - > - if (krm == kr) { > - /* head element */ > - if (RB_REMOVE(kroute6_tree, &kt->krt6, kr) == NULL) { > - log_warnx("%s: failed for %s/%u", __func__, > - log_in6addr(&kr->prefix), kr->prefixlen); > - return (-1); > - } > - if (kr->next != NULL) { > - if (RB_INSERT(kroute6_tree, &kt->krt6, kr->next) != > - NULL) { > - log_warnx("%s: failed to add %s/%u", __func__, > - log_in6addr(&kr->prefix), kr->prefixlen); > - return (-1); > - } > - } > - } else { > - /* somewhere in the list */ > - while (krm->next != kr && krm->next != NULL) > - krm = krm->next; > - if (krm->next == NULL) { > - log_warnx("%s: multipath list corrupted for %s/%u", > - __func__, log_in6addr(&kr->prefix), kr->prefixlen); > - return (-1); > - } > - krm->next = kr->next; > - } > - > - /* check whether a nexthop depends on this kroute */ > - if (kr->flags & F_NEXTHOP) > - RB_FOREACH(s, knexthop_tree, KT2KNT(kt)) > - if (s->kroute == kr) > - knexthop_validate(kt, s); > - > - if (!(kr->flags & F_BGPD) && kr == krm && kr->next == NULL) > - /* again remove only once */ > - kr_redistribute(IMSG_NETWORK_REMOVE, kt, kr6_tofull(kr)); > - > - rtlabel_unref(kr->labelid); > - free(kr); > - return (0); > -} > - > void > kroute6_clear(struct ktable *kt) > { > struct kroute6 *kr; > > while ((kr = RB_MIN(kroute6_tree, &kt->krt6)) != NULL) > - kroute6_remove(kt, kr); > + kroute_remove(kt, kr6_tofull(kr), 1); > } > > struct knexthop * > @@ -2013,19 +1963,12 @@ knexthop_insert(struct ktable *kt, struc > return (0); > } > > -int > +void > knexthop_remove(struct ktable *kt, struct knexthop *kn) > { > kroute_detach_nexthop(kt, kn); > - > - if (RB_REMOVE(knexthop_tree, KT2KNT(kt), kn) == NULL) { > - log_warnx("%s: failed for %s", __func__, > - log_addr(&kn->nexthop)); > - return (-1); > - } > - > + RB_REMOVE(knexthop_tree, KT2KNT(kt), kn); > free(kn); > - return (0); > } > > void > @@ -3082,51 +3025,7 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt > int > kr_fib_delete(struct ktable *kt, struct kroute_full *kf, int mpath) > { > - struct kroute *kr; > - struct kroute6 *kr6; > - > - switch (kf->prefix.aid) { > - case AID_INET: > - if ((kr = kroute_find(kt, &kf->prefix, kf->prefixlen, > - kf->priority)) == NULL) > - return (0); > - if (mpath) { > - /* get the correct route */ > - if ((kr = kroute_matchgw(kr, &kf->nexthop)) == NULL) { > - log_warnx("delete %s/%u: route not found", > - log_addr(&kf->prefix), kf->prefixlen); > - return (0); > - } > - } > - if (kf->flags & F_BGPD) { > - kr->flags &= ~F_BGPD_INSERTED; > - return (0); > - } > - if (kroute_remove(kt, kr) == -1) > - return (-1); > - break; > - case AID_INET6: > - if ((kr6 = kroute6_find(kt, &kf->prefix, kf->prefixlen, > - kf->priority)) == NULL) > - return (0); > - if (mpath) { > - /* get the correct route */ > - if ((kr6 = kroute6_matchgw(kr6, &kf->nexthop)) == > - NULL) { > - log_warnx("delete %s/%u: route not found", > - log_addr(&kf->prefix), kf->prefixlen); > - return (0); > - } > - } > - if (kf->flags & F_BGPD) { > - kr6->flags &= ~F_BGPD_INSERTED; > - return (0); > - } > - if (kroute6_remove(kt, kr6) == -1) > - return (-1); > - break; > - } > - return (0); > + return kroute_remove(kt, kf, !mpath); > } > > int >