From: Roy Marples Date: Tue, 1 Apr 2025 12:32:32 +0000 (+0100) Subject: kroutes initial X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0ef4f47512eaadad2c8e9cd8eecb90b0f785fbc4;p=thirdparty%2Fdhcpcd.git kroutes initial --- diff --git a/src/dhcpcd.c b/src/dhcpcd.c index 7cea7bd5..0fc3b25a 100644 --- a/src/dhcpcd.c +++ b/src/dhcpcd.c @@ -2587,6 +2587,7 @@ start_manager: } } + rt_discover(&ctx); TAILQ_FOREACH(ifp, ctx.ifaces, next) { if (ifp->active) dhcpcd_initstate1(ifp, argc, argv, 0); diff --git a/src/dhcpcd.h b/src/dhcpcd.h index 2c5df6d1..d8ef5d99 100644 --- a/src/dhcpcd.h +++ b/src/dhcpcd.h @@ -142,6 +142,7 @@ struct dhcpcd_ctx { size_t ctl_extra; rb_tree_t routes; /* our routes */ + rb_tree_t kroutes; /* kernel routes */ #ifdef RT_FREE_ROUTE_TABLE rb_tree_t froutes; /* free routes for re-use */ #endif diff --git a/src/if-bsd.c b/src/if-bsd.c index bb9c223a..c0471197 100644 --- a/src/if-bsd.c +++ b/src/if-bsd.c @@ -866,24 +866,45 @@ if_realroute(const struct rt_msghdr *rtm) return true; } -static int -if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, const struct rt_msghdr *rtm) +static struct rt * +if_rtmtort(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm) { const struct sockaddr *rti_info[RTAX_MAX]; + struct interface *ifp; + struct rt *rt; if (!(rtm->rtm_addrs & RTA_DST)) { errno = EINVAL; - return -1; + return NULL; } if (rtm->rtm_type != RTM_MISS && !(rtm->rtm_addrs & RTA_GATEWAY)) { errno = EINVAL; - return -1; + return NULL; } if (get_addrs(rtm->rtm_addrs, (const char *)rtm + sizeof(*rtm), rtm->rtm_msglen - sizeof(*rtm), rti_info) == -1) - return -1; - memset(rt, 0, sizeof(*rt)); + return NULL; + + if (rtm->rtm_index) + ifp = if_findindex(ctx->ifaces, rtm->rtm_index); + else if (rtm->rtm_addrs & RTA_IFP) + ifp = if_findsa(ctx, rti_info[RTAX_IFP]); + else if (rtm->rtm_addrs & RTA_GATEWAY) + ifp = if_findsa(ctx, rti_info[RTAX_GATEWAY]); + else + ifp = if_findsa(ctx, rti_info[RTAX_DST]); + + if (ifp == NULL && rtm->rtm_type == RTM_MISS) + ifp = if_find(ctx->ifaces, "lo0"); + + if (ifp == NULL) { + errno = ESRCH; + return NULL; + } + + rt = rt_new0(ctx); + rt->rt_ifp = ifp; rt->rt_flags = (unsigned int)rtm->rtm_flags; if_copysa(&rt->rt_dest, rti_info[RTAX_DST]); @@ -924,23 +945,7 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, const struct rt_msghdr *rtm) rt->rt_mtu = (unsigned int)rtm->rtm_rmx.rmx_mtu; - if (rtm->rtm_index) - rt->rt_ifp = if_findindex(ctx->ifaces, rtm->rtm_index); - else if (rtm->rtm_addrs & RTA_IFP) - rt->rt_ifp = if_findsa(ctx, rti_info[RTAX_IFP]); - else if (rtm->rtm_addrs & RTA_GATEWAY) - rt->rt_ifp = if_findsa(ctx, rti_info[RTAX_GATEWAY]); - else - rt->rt_ifp = if_findsa(ctx, rti_info[RTAX_DST]); - - if (rt->rt_ifp == NULL && rtm->rtm_type == RTM_MISS) - rt->rt_ifp = if_find(ctx->ifaces, "lo0"); - - if (rt->rt_ifp == NULL) { - errno = ESRCH; - return -1; - } - return 0; + return rt; } static int @@ -960,13 +965,13 @@ if_sysctl(struct dhcpcd_ctx *ctx, } int -if_initrt(struct dhcpcd_ctx *ctx, rb_tree_t *kroutes, int af) +if_initrt(struct dhcpcd_ctx *ctx, int af) { struct rt_msghdr *rtm; int mib[6] = { CTL_NET, PF_ROUTE, 0, af, NET_RT_DUMP, 0 }; size_t bufl; char *buf = NULL, *p, *end; - struct rt rt, *rtn; + struct rt *rt; again: if (if_sysctl(ctx, mib, __arraycount(mib), NULL, &bufl, NULL, 0) == -1) @@ -994,15 +999,10 @@ again: } if (!if_realroute(rtm)) continue; - if (if_copyrt(ctx, &rt, rtm) != 0) + if ((rt = if_rtmtort(ctx, rtm)) == NULL) continue; - if ((rtn = rt_new(rt.rt_ifp)) == NULL) { - logerr(__func__); - break; - } - memcpy(rtn, &rt, sizeof(*rtn)); - if (rb_tree_insert_node(kroutes, rtn) != rtn) - rt_free(rtn); + if (rb_tree_insert_node(&ctx->kroutes, rt) != rt) + rt_free(rt); } free(buf); return p == end ? 0 : -1; @@ -1282,7 +1282,7 @@ if_ifinfo(struct dhcpcd_ctx *ctx, const struct if_msghdr *ifm) static int if_rtm(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm) { - struct rt rt; + struct rt *rt; if (rtm->rtm_msglen < sizeof(*rtm)) { errno = EINVAL; @@ -1301,7 +1301,7 @@ if_rtm(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm) } #endif - if (if_copyrt(ctx, &rt, rtm) == -1) + if ((rt = if_rtmtort(ctx, rtm)) == NULL) return errno == ENOTSUP ? 0 : -1; #ifdef INET6 @@ -1311,21 +1311,21 @@ if_rtm(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm) * existance with a hardware address. * Ensure we don't call this for a newly incomplete state. */ - if (rt.rt_dest.sa_family == AF_INET6 && - (rt.rt_flags & RTF_HOST || rtm->rtm_type == RTM_MISS) && - !(rtm->rtm_type == RTM_ADD && !(rt.rt_dflags & RTDF_GATELINK))) + if (rt->rt_dest.sa_family == AF_INET6 && + (rt->rt_flags & RTF_HOST || rtm->rtm_type == RTM_MISS) && + !(rtm->rtm_type == RTM_ADD && !(rt->rt_dflags & RTDF_GATELINK))) { bool reachable; reachable = (rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) && - rt.rt_dflags & RTDF_GATELINK; - ipv6nd_neighbour(ctx, &rt.rt_ss_dest.sin6.sin6_addr, reachable); + rt->rt_dflags & RTDF_GATELINK; + ipv6nd_neighbour(ctx, &rt->rt_ss_dest.sin6.sin6_addr, reachable); } #endif if (rtm->rtm_type != RTM_MISS && if_realroute(rtm)) - rt_recvrt(rtm->rtm_type, &rt, rtm->rtm_pid); + rt_recvrt(rtm->rtm_type, rt, rtm->rtm_pid); return 0; } diff --git a/src/if.h b/src/if.h index 8d1aeccf..80c47e97 100644 --- a/src/if.h +++ b/src/if.h @@ -249,7 +249,7 @@ int xsocket(int, int, int); int xsocketpair(int, int, int, int[2]); int if_route(unsigned char, const struct rt *rt); -int if_initrt(struct dhcpcd_ctx *, rb_tree_t *, int); +int if_initrt(struct dhcpcd_ctx *, int); int if_missfilter(struct interface *, struct sockaddr *); int if_missfilter_apply(struct dhcpcd_ctx *); diff --git a/src/route.c b/src/route.c index 0037dda4..2b1e038c 100644 --- a/src/route.c +++ b/src/route.c @@ -237,11 +237,21 @@ static const rb_tree_ops_t rt_compare_free_ops = { }; #endif +void +rt_discover(struct dhcpcd_ctx *ctx) +{ + + rt_headclear(&ctx->kroutes, AF_UNSPEC); + if (if_initrt(ctx, AF_UNSPEC) != 0) + logerr("%s: if_initrt", __func__); +} + void rt_init(struct dhcpcd_ctx *ctx) { rb_tree_init(&ctx->routes, &rt_compare_os_ops); + rb_tree_init(&ctx->kroutes, &rt_compare_os_ops); #ifdef RT_FREE_ROUTE_TABLE rb_tree_init(&ctx->froutes, &rt_compare_free_ops); #endif @@ -347,6 +357,7 @@ rt_dispose(struct dhcpcd_ctx *ctx) assert(ctx != NULL); rt_headfree(&ctx->routes); + rt_headfree(&ctx->kroutes); #ifdef RT_FREE_ROUTE_TABLE rt_headfree(&ctx->froutes); #ifdef RT_FREE_ROUTE_TABLE_STATS @@ -372,11 +383,10 @@ rt_new0(struct dhcpcd_ctx *ctx) #endif } else #endif - if ((rt = malloc(sizeof(*rt))) == NULL) { + if (rt == NULL && (rt = malloc(sizeof(*rt))) == NULL) logerr(__func__); - return NULL; - } - memset(rt, 0, sizeof(*rt)); + else + memset(rt, 0, sizeof(*rt)); return rt; } @@ -472,10 +482,11 @@ rt_freeif(struct interface *ifp) /* If something other than dhcpcd removes a route, * we need to remove it from our internal table. */ void -rt_recvrt(int cmd, const struct rt *rt, pid_t pid) +rt_recvrt(int cmd, struct rt *rt, pid_t pid) { struct dhcpcd_ctx *ctx; struct rt *f; + bool freert = false; assert(rt != NULL); assert(rt->rt_ifp != NULL); @@ -484,6 +495,25 @@ rt_recvrt(int cmd, const struct rt *rt, pid_t pid) ctx = rt->rt_ifp->ctx; switch(cmd) { + case RTM_ADD: /* FALLTHROUGH */ + case RTM_CHANGE: /* FALLTHROUGH */ + case RTM_DELETE: + /* For any of these actions, we delete any matching + * kernel route we have. */ + f = rb_tree_find_node(&ctx->kroutes, rt); + if (f != NULL) { + rb_tree_remove_node(&ctx->kroutes, f); + rt_free(f); + } + break; + } + + switch(cmd) { + case RTM_ADD: /* FALLTHROUGH */ + case RTM_CHANGE: + if (rb_tree_insert_node(&ctx->kroutes, rt) != rt) /* safety */ + freert = true; + break; case RTM_DELETE: f = rb_tree_find_node(&ctx->routes, rt); if (f != NULL) { @@ -501,6 +531,9 @@ rt_recvrt(int cmd, const struct rt *rt, pid_t pid) if (rt->rt_dest.sa_family == AF_INET) ipv4ll_recvrt(cmd, rt); #endif + + if (freert) + rt_free(rt); } /* Compare miscellaneous route details */ @@ -553,12 +586,12 @@ rt_cmp_lifetime(struct rt *nrt, struct rt *ort) #endif static bool -rt_add(rb_tree_t *kroutes, struct rt *nrt, struct rt *ort) +rt_add(struct rt *nrt, struct rt *ort) { struct dhcpcd_ctx *ctx; struct rt *krt; int loglevel = LOG_INFO; - bool change, result; + bool change; assert(nrt != NULL); ctx = nrt->rt_ifp->ctx; @@ -578,7 +611,7 @@ rt_add(rb_tree_t *kroutes, struct rt *nrt, struct rt *ort) sa_is_unspecified(&nrt->rt_netmask)) return false; - krt = rb_tree_find_node(kroutes, nrt); + krt = rb_tree_find_node(&ctx->kroutes, nrt); if (krt != NULL && krt->rt_ifp == nrt->rt_ifp && /* Only test flags dhcpcd controls */ @@ -616,10 +649,8 @@ rt_add(rb_tree_t *kroutes, struct rt *nrt, struct rt *ort) #endif if (change) { - if (if_route(RTM_CHANGE, nrt) != -1) { - result = true; - goto out; - } + if (if_route(RTM_CHANGE, nrt) != -1) + return true; if (errno != ESRCH) logerr("if_route (CHG)"); } @@ -631,9 +662,12 @@ rt_add(rb_tree_t *kroutes, struct rt *nrt, struct rt *ort) if (krt != NULL) { if (if_route(RTM_DELETE, krt) == -1 && errno != ESRCH) logerr("if_route (DEL)"); + else { + rb_tree_remove_node(&ctx->kroutes, krt); + rt_free(krt); + } } - result = true; - goto out; + return true; } /* If the kernel claims the route exists we need to rip out the @@ -650,6 +684,10 @@ rt_add(rb_tree_t *kroutes, struct rt *nrt, struct rt *ort) if (krt != NULL) { if (if_route(RTM_DELETE, krt) == -1 && errno != ESRCH) logerr("if_route (DEL)"); + else { + rb_tree_remove_node(&ctx->kroutes, krt); + rt_free(krt); + } } #ifdef ROUTE_PER_GATEWAY /* The OS allows many routes to the same dest with different gateways. @@ -665,22 +703,14 @@ rt_add(rb_tree_t *kroutes, struct rt *nrt, struct rt *ort) /* Shouldn't need to check for EEXIST, but some kernels don't * dump the subnet route just after we added the address. */ - if (if_route(RTM_ADD, nrt) != -1 || errno == EEXIST) { - result = true; - goto out; - } + if (if_route(RTM_ADD, nrt) != -1 || errno == EEXIST) + return true; #ifdef HAVE_ROUTE_METRIC logerr: #endif logerr("if_route (ADD)"); - -out: - if (krt != NULL) { - rb_tree_remove_node(kroutes, krt); - rt_free(krt); - } - return result; + return false; } static bool @@ -709,7 +739,7 @@ rt_cmp(const struct rt *r1, const struct rt *r2) } static bool -rt_doroute(rb_tree_t *kroutes, struct rt *rt) +rt_doroute(struct rt *rt) { struct dhcpcd_ctx *ctx; struct rt *or; @@ -729,20 +759,20 @@ rt_doroute(rb_tree_t *kroutes, struct rt *rt) #endif rt_cmp_mtu(rt, or) != 0) { - if (!rt_add(kroutes, rt, or)) + if (!rt_add(rt, or)) return false; } rb_tree_remove_node(&ctx->routes, or); rt_free(or); } else { if (rt->rt_dflags & RTDF_FAKE) { - or = rb_tree_find_node(kroutes, rt); + or = rb_tree_find_node(&ctx->kroutes, rt); if (or == NULL) return false; if (rt_cmp(rt, or) == 0) return false; } else { - if (!rt_add(kroutes, rt, NULL)) + if (!rt_add(rt, NULL)) return false; } } @@ -753,15 +783,12 @@ rt_doroute(rb_tree_t *kroutes, struct rt *rt) void rt_build(struct dhcpcd_ctx *ctx, int af) { - rb_tree_t routes, added, kroutes; + rb_tree_t routes, added; struct rt *rt, *rtn; unsigned long long o; rb_tree_init(&routes, &rt_compare_proto_ops); rb_tree_init(&added, &rt_compare_os_ops); - rb_tree_init(&kroutes, &rt_compare_os_ops); - if (if_initrt(ctx, &kroutes, af) != 0) - logerr("%s: if_initrt", __func__); ctx->rt_order = 0; ctx->options |= DHCPCD_RTBUILD; @@ -798,7 +825,7 @@ rt_build(struct dhcpcd_ctx *ctx, int af) /* Is this route already in our table? */ if (rb_tree_find_node(&added, rt) != NULL) continue; - if (rt_doroute(&kroutes, rt)) { + if (rt_doroute(rt)) { rb_tree_remove_node(&routes, rt); if (rb_tree_insert_node(&added, rt) != rt) { errno = EEXIST; @@ -845,5 +872,4 @@ rt_build(struct dhcpcd_ctx *ctx, int af) getfail: rt_headclear(&routes, AF_UNSPEC); - rt_headclear(&kroutes, AF_UNSPEC); } diff --git a/src/route.h b/src/route.h index eea7e559..20b64326 100644 --- a/src/route.h +++ b/src/route.h @@ -134,6 +134,7 @@ extern const rb_tree_ops_t rt_compare_list_ops; extern const rb_tree_ops_t rt_compare_proto_ops; void rt_init(struct dhcpcd_ctx *); +void rt_discover(struct dhcpcd_ctx *); void rt_dispose(struct dhcpcd_ctx *); void rt_free(struct rt *); void rt_freeif(struct interface *); @@ -147,7 +148,7 @@ struct rt * rt_new(struct interface *); struct rt * rt_proto_add_ctx(rb_tree_t *, struct rt *, struct dhcpcd_ctx *); struct rt * rt_proto_add(rb_tree_t *, struct rt *); int rt_cmp_dest(const struct rt *, const struct rt *); -void rt_recvrt(int, const struct rt *, pid_t); +void rt_recvrt(int, struct rt *, pid_t); void rt_build(struct dhcpcd_ctx *, int); #endif