From: Roy Marples Date: Tue, 5 Mar 2019 00:28:36 +0000 (+0000) Subject: route: Remove kroutes and make froutes optional X-Git-Tag: v8.0.0~69 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0f3fef65c52ebe102f242ef6b79f45aef46d52d5;p=thirdparty%2Fdhcpcd.git route: Remove kroutes and make froutes optional This is an attempt to reduce the memory dhcpcd uses. By removing kroutes and froutes from global context. kroutes are generated at the start of rt_build and freed at the end. --- diff --git a/src/dhcp.c b/src/dhcp.c index 73ca69f8..b85bce94 100644 --- a/src/dhcp.c +++ b/src/dhcp.c @@ -3648,15 +3648,9 @@ dhcp_init(struct interface *ifp) const struct if_options *ifo; uint8_t len; char buf[(sizeof(ifo->clientid) - 1) * 3]; - int r; - r = dhcp_initstate(ifp); - if (r == -1) + if (dhcp_initstate(ifp) == -1) return -1; - else if (r == 1) { - /* Now is a good time to find IPv4 routes */ - if_initrt(ifp->ctx, AF_INET); - } state = D_STATE(ifp); state->state = DHS_INIT; diff --git a/src/dhcp6.c b/src/dhcp6.c index da5242fd..390615ae 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -2830,7 +2830,6 @@ dhcp6_delegate_prefix(struct interface *ifp) } /* Now all addresses have been added, rebuild the routing table. */ - if_initrt(ifp->ctx, AF_INET6); rt_build(ifp->ctx, AF_INET6); } @@ -2895,7 +2894,6 @@ dhcp6_find_delegates(struct interface *ifp) state = D6_STATE(ifp); state->state = DH6S_DELEGATED; ipv6_addaddrs(&state->addrs); - if_initrt(ifp->ctx, AF_INET6); rt_build(ifp->ctx, AF_INET6); dhcp6_script_try_run(ifp, 1); } @@ -3133,7 +3131,6 @@ dhcp6_bind(struct interface *ifp, const char *op, const char *sfrom) else lognewinfo("%s: expire in %"PRIu32" seconds", ifp->name, state->expire); - if_initrt(ifp->ctx, AF_INET6); rt_build(ifp->ctx, AF_INET6); if (!timed_out) dhcp6_writelease(ifp); diff --git a/src/dhcpcd.h b/src/dhcpcd.h index a09f40fb..df229fd3 100644 --- a/src/dhcpcd.h +++ b/src/dhcpcd.h @@ -138,8 +138,9 @@ struct dhcpcd_ctx { struct if_head *ifaces; rb_tree_t routes; /* our routes */ - rb_tree_t kroutes; /* all kernel routes */ +#ifdef RT_FREE_ROUTE_TABLE rb_tree_t froutes; /* free routes for re-use */ +#endif int pf_inet_fd; void *priv; diff --git a/src/if-bsd.c b/src/if-bsd.c index 8d281b42..20981411 100644 --- a/src/if-bsd.c +++ b/src/if-bsd.c @@ -657,15 +657,13 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, const struct rt_msghdr *rtm) } int -if_initrt(struct dhcpcd_ctx *ctx, int af) +if_initrt(struct dhcpcd_ctx *ctx, rb_tree_t *kroutes, int af) { struct rt_msghdr *rtm; int mib[6]; size_t needed; char *buf, *p, *end; - struct rt rt; - - rt_headclear(&ctx->kroutes, af); + struct rt rt, *rtn; mib[0] = CTL_NET; mib[1] = PF_ROUTE; @@ -688,10 +686,15 @@ if_initrt(struct dhcpcd_ctx *ctx, int af) end = buf + needed; for (p = buf; p < end; p += rtm->rtm_msglen) { rtm = (void *)p; - if (if_copyrt(ctx, &rt, rtm) == 0) { - rt.rt_dflags |= RTDF_INIT; - rt_recvrt(RTM_ADD, &rt); + if (if_copyrt(ctx, &rt, rtm) != 0) + 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); } free(buf); return 0; diff --git a/src/if-linux.c b/src/if-linux.c index 1e55d672..13f58c9b 100644 --- a/src/if-linux.c +++ b/src/if-linux.c @@ -351,8 +351,8 @@ if_closesockets_os(struct dhcpcd_ctx *ctx) static int get_netlink(struct dhcpcd_ctx *ctx, struct iovec *iov, - struct interface *ifp, int fd, int flags, - int (*callback)(struct dhcpcd_ctx *, struct interface *, struct nlmsghdr *)) + void *arg, int fd, int flags, + int (*callback)(struct dhcpcd_ctx *, void *, struct nlmsghdr *)) { struct sockaddr_nl nladdr = { .nl_pid = 0 }; struct msghdr msg = { @@ -406,7 +406,7 @@ recv_again: again = 0; break; } - if (callback && (r = callback(ctx, ifp, nlm)) != 0) + if (callback && (r = callback(ctx, arg, nlm)) != 0) break; } @@ -822,9 +822,9 @@ if_handlelink(struct dhcpcd_ctx *ctx) } static int -send_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp, +send_netlink(struct dhcpcd_ctx *ctx, void *arg, int protocol, struct nlmsghdr *hdr, - int (*callback)(struct dhcpcd_ctx *, struct interface *, struct nlmsghdr *)) + int (*callback)(struct dhcpcd_ctx *, void *, struct nlmsghdr *)) { int s, r; struct sockaddr_nl snl = { .nl_family = AF_NETLINK }; @@ -854,7 +854,7 @@ send_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp, .iov_len = sizeof(buf), }; - r = get_netlink(ctx, &riov, ifp, s, 0, callback); + r = get_netlink(ctx, &riov, arg, s, 0, callback); } else r = -1; if (protocol != NETLINK_ROUTE) @@ -1031,7 +1031,7 @@ genl_parse(struct nlmsghdr *nlm, struct nlattr *tb[], int maxtype) } static int -_gnl_getfamily(__unused struct dhcpcd_ctx *ctx, __unused struct interface *ifp, +_gnl_getfamily(__unused struct dhcpcd_ctx *ctx, __unused void *arg, struct nlmsghdr *nlm) { struct nlattr *tb[CTRL_ATTR_FAMILY_ID + 1]; @@ -1066,9 +1066,10 @@ gnl_getfamily(struct dhcpcd_ctx *ctx, const char *name) } static int -_if_getssid_nl80211(__unused struct dhcpcd_ctx *ctx, struct interface *ifp, +_if_getssid_nl80211(__unused struct dhcpcd_ctx *ctx, void *arg, struct nlmsghdr *nlm) { + struct interface *ifp = arg; struct nlattr *tb[NL80211_ATTR_BSS + 1]; struct nlattr *bss[NL80211_BSS_STATUS + 1]; uint32_t status; @@ -1284,20 +1285,26 @@ if_route(unsigned char cmd, const struct rt *rt) } static int -_if_initrt(struct dhcpcd_ctx *ctx, __unused struct interface *ifp, +_if_initrt(struct dhcpcd_ctx *ctx, void *arg, struct nlmsghdr *nlm) { - struct rt rt; + struct rt rt, *rtn; + rb_tree_t *kroutes = arg; - if (if_copyrt(ctx, &rt, nlm) == 0) { - rt.rt_dflags |= RTDF_INIT; - rt_recvrt(RTM_ADD, &rt); + if (if_copyrt(ctx, &rt, nlm) != 0) + return 0; + if ((rtn = rt_new(rt.rt_ifp)) == NULL) { + logerr(__func__); + return 0; } + memcpy(rtn, &rt, sizeof(*rtn)); + if (rb_tree_insert_node(kroutes, rtn) != rtn) + rt_free(rtn); return 0; } int -if_initrt(struct dhcpcd_ctx *ctx, int af) +if_initrt(struct dhcpcd_ctx *ctx, rb_tree_t *kroutes, int af) { struct nlmr nlm = { .hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)), @@ -1308,7 +1315,7 @@ if_initrt(struct dhcpcd_ctx *ctx, int af) }; rt_headclear(&ctx->kroutes, af); - return send_netlink(ctx, NULL, NETLINK_ROUTE, &nlm.hdr, &_if_initrt); + return send_netlink(ctx, kroutes, NETLINK_ROUTE, &nlm.hdr, &_if_initrt); } diff --git a/src/if.h b/src/if.h index 1aac439b..0abde5b3 100644 --- a/src/if.h +++ b/src/if.h @@ -178,7 +178,7 @@ int if_handlelink(struct dhcpcd_ctx *); #endif int if_route(unsigned char, const struct rt *rt); -int if_initrt(struct dhcpcd_ctx *, int); +int if_initrt(struct dhcpcd_ctx *, rb_tree_t *, int); #ifdef INET int if_address(unsigned char, const struct ipv4_addr *); diff --git a/src/ipv4.c b/src/ipv4.c index cdccf6ce..e5ede166 100644 --- a/src/ipv4.c +++ b/src/ipv4.c @@ -767,10 +767,6 @@ ipv4_applyaddr(void *arg) state->addr = ia; state->added = STATE_ADDED; - /* Find any freshly added routes, such as the subnet route. - * We do this because we cannot rely on recieving the kernel - * notification right now via our link socket. */ - if_initrt(ifp->ctx, AF_INET); rt_build(ifp->ctx, AF_INET); #ifdef ARP diff --git a/src/ipv4ll.c b/src/ipv4ll.c index 5ae3d485..e4662ca7 100644 --- a/src/ipv4ll.c +++ b/src/ipv4ll.c @@ -218,7 +218,6 @@ test: return; } timespecclear(&state->defend); - if_initrt(ifp->ctx, AF_INET); rt_build(ifp->ctx, AF_INET); arp_announce(astate); script_runreason(ifp, "IPV4LL"); @@ -526,10 +525,6 @@ ipv4ll_recvrt(__unused int cmd, const struct rt *rt) struct dhcpcd_ctx *ctx; struct interface *ifp; - /* Ignore route init. */ - if (rt->rt_dflags & RTDF_INIT) - return 0; - /* Only interested in default route changes. */ if (sa_is_unspecified(&rt->rt_dest)) return 0; @@ -538,7 +533,6 @@ ipv4ll_recvrt(__unused int cmd, const struct rt *rt) ctx = rt->rt_ifp->ctx; TAILQ_FOREACH(ifp, ctx->ifaces, next) { if (IPV4LL_STATE_RUNNING(ifp)) { - if_initrt(ctx, AF_INET); rt_build(ctx, AF_INET); break; } diff --git a/src/ipv6.c b/src/ipv6.c index ee626330..34c302fe 100644 --- a/src/ipv6.c +++ b/src/ipv6.c @@ -1604,7 +1604,6 @@ ipv6_startstatic(struct interface *ifp) ia->prefix_pltime = ND6_INFINITE_LIFETIME; ia->dadcallback = ipv6_staticdadcallback; ipv6_addaddr(ia, NULL); - if_initrt(ifp->ctx, AF_INET6); rt_build(ifp->ctx, AF_INET6); if (run_script) script_runreason(ifp, "STATIC6"); @@ -1646,8 +1645,6 @@ ipv6_start(struct interface *ifp) ipv6_regentempifid(ifp); } - /* Load existing routes */ - if_initrt(ifp->ctx, AF_INET6); return 0; } @@ -1671,10 +1668,8 @@ ipv6_freedrop(struct interface *ifp, int drop) ipv6_freedrop_addrs(&state->addrs, drop ? 2 : 0, NULL); if (drop) { - if (ifp->ctx->ra_routers != NULL) { - if_initrt(ifp->ctx, AF_INET6); + if (ifp->ctx->ra_routers != NULL) rt_build(ifp->ctx, AF_INET6); - } } else { /* Because we need to cache the addresses we don't control, * we only free the state on when NOT dropping addresses. */ diff --git a/src/ipv6nd.c b/src/ipv6nd.c index e148f862..51e69f8a 100644 --- a/src/ipv6nd.c +++ b/src/ipv6nd.c @@ -1213,11 +1213,6 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, ipv6_addtempaddrs(ifp, &rap->acquired); #endif - /* Find any freshly added routes, such as the subnet route. - * We do this because we cannot rely on recieving the kernel - * notification right now via our link socket. */ - if_initrt(ifp->ctx, AF_INET6); - rt_build(ifp->ctx, AF_INET6); if (ipv6nd_scriptrun(rap)) return; diff --git a/src/route.c b/src/route.c index d7cfe7ba..4d924f4b 100644 --- a/src/route.c +++ b/src/route.c @@ -131,6 +131,7 @@ const rb_tree_ops_t rt_compare_list_ops = { .rbto_context = NULL }; +#ifdef RT_FREE_ROUTE_TABLE static int rt_compare_free(__unused void *context, const void *node1, const void *node2) { @@ -144,14 +145,16 @@ static const rb_tree_ops_t rt_compare_free_ops = { .rbto_node_offset = offsetof(struct rt, rt_tree), .rbto_context = NULL }; +#endif 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 } static void @@ -207,7 +210,9 @@ rt_headclear0(struct dhcpcd_ctx *ctx, rb_tree_t *rts, int af) if (rts == NULL) return; assert(ctx != NULL); +#ifdef RT_FREE_ROUTE_TABLE assert(&ctx->froutes != rts); +#endif RB_TREE_FOREACH_SAFE(rt, rts, rtn) { if (af != AF_UNSPEC && @@ -246,8 +251,9 @@ 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); +#endif } struct rt * @@ -256,9 +262,12 @@ rt_new0(struct dhcpcd_ctx *ctx) struct rt *rt; assert(ctx != NULL); +#ifdef RT_FREE_ROUTE_TABLE if ((rt = RB_TREE_MIN(&ctx->froutes)) != NULL) rb_tree_remove_node(&ctx->froutes, rt); - else if ((rt = malloc(sizeof(*rt))) == NULL) { + else +#endif + if ((rt = malloc(sizeof(*rt))) == NULL) { logerr(__func__); return NULL; } @@ -293,6 +302,7 @@ rt_new(struct interface *ifp) void rt_free(struct rt *rt) { +#ifdef RT_FREE_ROUTE_TABLE struct dhcpcd_ctx *ctx; assert(rt != NULL); @@ -301,6 +311,9 @@ rt_free(struct rt *rt) ctx = rt->rt_ifp->ctx; rb_tree_insert_node(&ctx->froutes, rt); +#else + free(rt); +#endif } void @@ -318,27 +331,6 @@ rt_freeif(struct interface *ifp) rt_free(rt); } } - RB_TREE_FOREACH_SAFE(rt, &ctx->kroutes, rtn) { - if (rt->rt_ifp == ifp) { - rb_tree_remove_node(&ctx->kroutes, rt); - rt_free(rt); - } - } -} - -static void -rt_kfree(struct rt *rt) -{ - struct dhcpcd_ctx *ctx; - struct rt *f; - - assert(rt != NULL); - ctx = rt->rt_ifp->ctx; - f = rb_tree_find_node(&ctx->kroutes, rt); - if (f == NULL) - return; - rb_tree_remove_node(&ctx->kroutes, f); - rt_free(f); } /* If something other than dhcpcd removes a route, @@ -357,11 +349,6 @@ rt_recvrt(int cmd, const struct rt *rt) switch(cmd) { case RTM_DELETE: - f = rb_tree_find_node(&ctx->kroutes, rt); - if (f != NULL) { - rb_tree_remove_node(&ctx->kroutes, f); - rt_free(f); - } f = rb_tree_find_node(&ctx->routes, rt); if (f != NULL) { rb_tree_remove_node(&ctx->routes, f); @@ -369,13 +356,6 @@ rt_recvrt(int cmd, const struct rt *rt) rt_free(f); } break; - case RTM_ADD: - if ((f = rt_new(rt->rt_ifp)) == NULL) - break; - memcpy(f, rt, sizeof(*f)); - if (rb_tree_insert_node(&ctx->kroutes, f) != f) - rt_free(f); - break; } #if defined(IPV4LL) && defined(HAVE_ROUTE_METRIC) @@ -385,7 +365,7 @@ rt_recvrt(int cmd, const struct rt *rt) } static bool -rt_add(struct rt *nrt, struct rt *ort) +rt_add(rb_tree_t *kroutes, struct rt *nrt, struct rt *ort) { struct dhcpcd_ctx *ctx; bool change; @@ -412,7 +392,7 @@ rt_add(struct rt *nrt, struct rt *ort) change = false; if (ort == NULL) { - ort = rb_tree_find_node(&ctx->kroutes, nrt); + ort = rb_tree_find_node(kroutes, nrt); if (ort != NULL && ((ort->rt_flags & RTF_REJECT && nrt->rt_flags & RTF_REJECT) || @@ -483,8 +463,6 @@ rt_add(struct rt *nrt, struct rt *ort) if (ort != NULL) { if (if_route(RTM_DELETE, ort) == -1 && errno != ESRCH) logerr("if_route (DEL)"); - else - rt_kfree(ort); } #ifdef ROUTE_PER_GATEWAY /* The OS allows many routes to the same dest with different gateways. @@ -497,8 +475,11 @@ rt_add(struct rt *nrt, struct rt *ort) } } #endif - if (if_route(RTM_ADD, nrt) != -1) + if (if_route(RTM_ADD, nrt) != -1) { + if (ort != NULL) + memcpy(ort, nrt, sizeof(*ort)); return true; + } #ifdef HAVE_ROUTE_METRIC logerr: #endif @@ -515,10 +496,6 @@ rt_delete(struct rt *rt) retval = if_route(RTM_DELETE, rt) == -1 ? false : true; if (!retval && errno != ENOENT && errno != ESRCH) logerr(__func__); - /* Remove the route from our kernel table so we can add a - * IPv4LL default route if possible. */ - else - rt_kfree(rt); return retval; } @@ -534,7 +511,7 @@ rt_cmp(const struct rt *r1, const struct rt *r2) } static bool -rt_doroute(struct rt *rt) +rt_doroute(rb_tree_t *kroutes, struct rt *rt) { struct dhcpcd_ctx *ctx; struct rt *or; @@ -551,20 +528,20 @@ rt_doroute(struct rt *rt) sa_cmp(&or->rt_ifa, &rt->rt_ifa) != 0) || or->rt_mtu != rt->rt_mtu) { - if (!rt_add(rt, or)) + if (!rt_add(kroutes, 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(&ctx->kroutes, rt); + or = rb_tree_find_node(kroutes, rt); if (or == NULL) return false; if (!rt_cmp(rt, or)) return false; } else { - if (!rt_add(rt, NULL)) + if (!rt_add(kroutes, rt, NULL)) return false; } } @@ -575,10 +552,11 @@ rt_doroute(struct rt *rt) void rt_build(struct dhcpcd_ctx *ctx, int af) { - rb_tree_t routes, added; + rb_tree_t kroutes, routes, added; struct rt *rt, *rtn; unsigned long long o; + rb_tree_init(&kroutes, &rt_compare_os_ops); rb_tree_init(&routes, &rt_compare_list_ops); rb_tree_init(&added, &rt_compare_os_ops); @@ -597,6 +575,8 @@ rt_build(struct dhcpcd_ctx *ctx, int af) #endif } + if_initrt(ctx, &kroutes, af); + RB_TREE_FOREACH_SAFE(rt, &routes, rtn) { if (rt->rt_dest.sa_family != af && rt->rt_gateway.sa_family != af) @@ -604,7 +584,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(rt)) { + if (rt_doroute(&kroutes, rt)) { rb_tree_remove_node(&routes, rt); if (rb_tree_insert_node(&added, rt) != rt) { errno = EEXIST; @@ -642,6 +622,8 @@ 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 19b0d4c9..1786c506 100644 --- a/src/route.h +++ b/src/route.h @@ -75,7 +75,6 @@ struct rt { unsigned int rt_metric; #endif unsigned int rt_dflags; -#define RTDF_INIT 0x01 /* Generated by if_initrt() */ #define RTDF_IFA_ROUTE 0x02 /* Address generated route */ #define RTDF_FAKE 0x04 /* Maybe us on lease reboot */ #define RTDF_RA 0x08 /* Router Advertisement */