]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
route: Remove kroutes and make froutes optional
authorRoy Marples <roy@marples.name>
Tue, 5 Mar 2019 00:28:36 +0000 (00:28 +0000)
committerRoy Marples <roy@marples.name>
Tue, 5 Mar 2019 00:28:36 +0000 (00:28 +0000)
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.

12 files changed:
src/dhcp.c
src/dhcp6.c
src/dhcpcd.h
src/if-bsd.c
src/if-linux.c
src/if.h
src/ipv4.c
src/ipv4ll.c
src/ipv6.c
src/ipv6nd.c
src/route.c
src/route.h

index 73ca69f8ee8fd2bf6b38b2702ce370cfedfbf14f..b85bce94087d83af81162ef85ec2ebe26d54bc52 100644 (file)
@@ -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;
index da5242fd58e04183f0487edc60e077a5dac5314c..390615aeb45ec68d60c98ba4f7048939d5db4af9 100644 (file)
@@ -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);
index a09f40fba2877a02bbb4b0b257cc7b69b9ef6ce4..df229fd337cb0d59fc19b681baf4aa382556c9ae 100644 (file)
@@ -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;
index 8d281b4269048fe2eaa5559701e7acedffab3013..209814117384967f78fd519d537f047d569123c0 100644 (file)
@@ -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;
index 1e55d672da587eba1671135690ab28cae6848897..13f58c9b4c64bcfb30ed05e659822eb9cb619d08 100644 (file)
@@ -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);
 }
 
 
index 1aac439b81af584602f6a7e464fdbe0e5b37588e..0abde5b3711615e0c1541b27c8e87be989429e22 100644 (file)
--- 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 *);
index cdccf6ce1fddadcd91028ec3a5cefa223eb92410..e5ede16663e7955214b7784d52350f4e1b5d17a0 100644 (file)
@@ -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
index 5ae3d4859056a443bb8ad209426f43711d3771b5..e4662ca7f929ac58148202ccbeb47211527565b5 100644 (file)
@@ -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;
                }
index ee62633085b5d043979ed57433af21a4df6db2f8..34c302fe9a878a27f9ae73c89b3c51516cf7667d 100644 (file)
@@ -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. */
index e148f862c5248a24df90daa62a8814cd117473e3..51e69f8a8b4c06b92473a5392db96a4bf884b76c 100644 (file)
@@ -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;
index d7cfe7ba730fbb09cb88d22c83a86599c770c18a..4d924f4b2806ffbb7fc7d6e57ef65ebc71720dee 100644 (file)
@@ -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);
 }
index 19b0d4c9998a86353d941b0a263633c9f196b01a..1786c506ae59440caabb30769d2fc1aeeb255284 100644 (file)
@@ -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 */