Mercurial > hg > dhcpcd
changeset 4522:e2582c7c7e1d draft
route: Use order from message / config
We can't just make the order up as that is prone to error.
So apply ordering as from the source.
| author | Roy Marples <roy@marples.name> |
|---|---|
| date | Fri, 07 Jun 2019 16:37:00 +0100 |
| parents | 9a0884e8ab97 |
| children | 605fe3b1f9ae |
| files | src/dhcp.c src/dhcpcd.h src/if-options.c src/ipv4.c src/ipv4.h src/ipv4ll.c src/ipv6.c src/route.c src/route.h |
| diffstat | 9 files changed, 125 insertions(+), 110 deletions(-) [+] |
line wrap: on
line diff
--- a/src/dhcp.c Sun May 05 19:04:02 2019 +0100 +++ b/src/dhcp.c Fri Jun 07 16:37:00 2019 +0100 @@ -468,9 +468,7 @@ sa_in_init(&rt->rt_dest, &dest); sa_in_init(&rt->rt_netmask, &netmask); sa_in_init(&rt->rt_gateway, &gateway); - if (rb_tree_insert_node(routes, rt) != rt) - rt_free(rt); - else + if (rt_proto_add(routes, rt)) n++; } return n;
--- a/src/dhcpcd.h Sun May 05 19:04:02 2019 +0100 +++ b/src/dhcpcd.h Fri Jun 07 16:37:00 2019 +0100 @@ -140,6 +140,7 @@ #ifdef RT_FREE_ROUTE_TABLE rb_tree_t froutes; /* free routes for re-use */ #endif + size_t rt_order; /* route order storage */ int pf_inet_fd; void *priv;
--- a/src/if-options.c Sun May 05 19:04:02 2019 +0100 +++ b/src/if-options.c Fri Jun 07 16:37:00 2019 +0100 @@ -1129,9 +1129,7 @@ sa_in_init(&rt->rt_dest, &addr); sa_in_init(&rt->rt_netmask, &addr2); sa_in_init(&rt->rt_gateway, &addr3); - if (rb_tree_insert_node(&ifo->routes, rt) != rt) - rt_free(rt); - else + if (rt_proto_add_ctx(&ifo->routes, rt, ctx)) add_environ(&ifo->config, arg, 0); } else if (strncmp(arg, "routers=", strlen("routers=")) == 0) { if (parse_addr(&addr, NULL, p) == -1) @@ -1142,9 +1140,7 @@ sa_in_init(&rt->rt_dest, &addr2); sa_in_init(&rt->rt_netmask, &addr2); sa_in_init(&rt->rt_gateway, &addr); - if (rb_tree_insert_node(&ifo->routes, rt) != rt) - rt_free(rt); - else + if (rt_proto_add_ctx(&ifo->routes, rt, ctx)) add_environ(&ifo->config, arg, 0); } else if (strncmp(arg, "interface_mtu=", strlen("interface_mtu=")) == 0 || @@ -2282,7 +2278,7 @@ ifo->script = UNCONST(default_script); ifo->metric = -1; ifo->auth.options |= DHCPCD_AUTH_REQUIRE; - rb_tree_init(&ifo->routes, &rt_compare_list_ops); + rb_tree_init(&ifo->routes, &rt_compare_proto_ops); #ifdef AUTH TAILQ_INIT(&ifo->auth.tokens); #endif @@ -2340,6 +2336,9 @@ buf = NULL; buflen = 0; + /* Reset route order */ + ctx->rt_order = 0; + /* Parse our embedded options file */ if (ifname == NULL && !(ctx->options & DHCPCD_PRINT_PIDFILE)) { /* Space for initial estimates */
--- a/src/ipv4.c Sun May 05 19:04:02 2019 +0100 +++ b/src/ipv4.c Fri Jun 07 16:37:00 2019 +0100 @@ -247,7 +247,7 @@ } static int -inet_dhcproutes(rb_tree_t *routes, struct interface *ifp) +inet_dhcproutes(rb_tree_t *routes, struct interface *ifp, bool *have_default) { const struct dhcp_state *state; rb_tree_t nroutes; @@ -263,7 +263,7 @@ /* An address does have to exist. */ assert(state->addr); - rb_tree_init(&nroutes, &rt_compare_list_ops); + rb_tree_init(&nroutes, &rt_compare_proto_ops); /* First, add a subnet route. */ if (!(ifp->flags & IFF_POINTOPOINT) && @@ -283,8 +283,7 @@ //in.s_addr = INADDR_ANY; //sa_in_init(&rt->rt_gateway, &in); rt->rt_gateway.sa_family = AF_UNSPEC; - if (rb_tree_insert_node(&nroutes, rt) != rt) - rt_free(rt); + rt_proto_add(&nroutes, rt); } /* If any set routes, grab them, otherwise DHCP routes. */ @@ -297,15 +296,14 @@ memcpy(rt, r, sizeof(*rt)); rt_setif(rt, ifp); rt->rt_dflags = RTDF_STATIC; - if (rb_tree_insert_node(&nroutes, rt) != rt) - rt_free(rt); + rt_proto_add(&nroutes, rt); } } else { if (dhcp_get_routes(&nroutes, ifp) == -1) return -1; } - /* If configured, Install a gateway to the desintion + /* If configured, install a gateway to the desintion * for P2P interfaces. */ if (ifp->flags & IFF_POINTOPOINT && has_option_mask(ifp->options->dstmask, DHO_ROUTER)) @@ -317,8 +315,7 @@ sa_in_init(&rt->rt_netmask, &in); sa_in_init(&rt->rt_gateway, &state->addr->brd); sa_in_init(&rt->rt_ifa, &state->addr->addr); - if (rb_tree_insert_node(&nroutes, rt) != rt) - rt_free(rt); + rt_proto_add(&nroutes, rt); } /* Copy our address as the source address and set mtu */ @@ -330,10 +327,13 @@ if (!(rt->rt_dflags & RTDF_STATIC)) rt->rt_dflags |= RTDF_DHCP; sa_in_init(&rt->rt_ifa, &state->addr->addr); - if (rb_tree_insert_node(routes, rt) != rt) + if (rb_tree_insert_node(routes, rt) != rt) { rt_free(rt); - else - n++; + continue; + } + if (rt_is_default(rt)) + *have_default = true; + n++; } return n; @@ -425,25 +425,23 @@ sa_in_init(&rth->rt_gateway, &in); rth->rt_mtu = dhcp_get_mtu(ifp); sa_in_init(&rth->rt_ifa, &state->addr->addr); - if (rb_tree_insert_node(routes, rth) != rth) - rt_free(rth); + rt_proto_add(routes, rt); } return 0; } bool -inet_getroutes(struct dhcpcd_ctx *ctx, rb_tree_t *routes, rb_tree_t *kroutes) +inet_getroutes(struct dhcpcd_ctx *ctx, rb_tree_t *routes) { struct interface *ifp; #ifdef IPV4LL - struct rt def; - bool have_default; + bool have_default = false; #endif TAILQ_FOREACH(ifp, ctx->ifaces, next) { if (!ifp->active) continue; - if (inet_dhcproutes(routes, ifp) == -1) + if (inet_dhcproutes(routes, ifp, &have_default) == -1) return false; #ifdef IPV4LL if (ipv4ll_subnetroute(routes, ifp) == -1) @@ -455,22 +453,14 @@ #ifdef IPV4LL /* If there is no default route, see if we can use an IPv4LL one. */ - memset(&def, 0, sizeof(def)); - def.rt_dest.sa_family = AF_INET; - def.rt_netmask.sa_family = AF_INET; - have_default = (rb_tree_find_node(routes, &def) != NULL); - if (!have_default) - have_default = (rb_tree_find_node(kroutes, &def) != NULL); + if (have_default) + return true; - if (!have_default) { - TAILQ_FOREACH(ifp, ctx->ifaces, next) { - if (ifp->active && - ipv4ll_defaultroute(routes, ifp) == 1) - break; - } + TAILQ_FOREACH(ifp, ctx->ifaces, next) { + if (ifp->active && + ipv4ll_defaultroute(routes, ifp) == 1) + break; } -#else - UNUSED(kroutes); #endif return true;
--- a/src/ipv4.h Sun May 05 19:04:02 2019 +0100 +++ b/src/ipv4.h Fri Jun 07 16:37:00 2019 +0100 @@ -118,7 +118,7 @@ uint32_t ipv4_getnetmask(uint32_t); int ipv4_hasaddr(const struct interface *); -bool inet_getroutes(struct dhcpcd_ctx *, rb_tree_t *, rb_tree_t *); +bool inet_getroutes(struct dhcpcd_ctx *, rb_tree_t *); #define STATE_ADDED 0x01 #define STATE_FAKE 0x02
--- a/src/ipv4ll.c Sun May 05 19:04:02 2019 +0100 +++ b/src/ipv4ll.c Fri Jun 07 16:37:00 2019 +0100 @@ -110,11 +110,7 @@ in.s_addr = INADDR_ANY; sa_in_init(&rt->rt_gateway, &in); sa_in_init(&rt->rt_ifa, &state->addr->addr); - if (rb_tree_insert_node(routes, rt) != rt) { - rt_free(rt); - return 0; - } - return 1; + return rt_proto_add(routes, rt) ? 1 : 0; } int @@ -137,11 +133,7 @@ sa_in_init(&rt->rt_netmask, &in); sa_in_init(&rt->rt_gateway, &in); sa_in_init(&rt->rt_ifa, &state->addr->addr); - if (rb_tree_insert_node(routes, rt) != rt) { - rt_free(rt); - return 0; - } - return 1; + return rt_proto_add(routes, rt) ? 1 : 0; } ssize_t
--- a/src/ipv6.c Sun May 05 19:04:02 2019 +0100 +++ b/src/ipv6.c Fri Jun 07 16:37:00 2019 +0100 @@ -2226,8 +2226,8 @@ (IPV6_AF_ADDED | IPV6_AF_STATIC)) { rt = inet6_makeprefix(ifp, NULL, ia); - if (rt && rb_tree_insert_node(routes, rt) != rt) - rt_free(rt); + if (rt) + rt_proto_add(routes, rt); } } } @@ -2251,17 +2251,14 @@ rt = inet6_makeprefix(rap->iface, rap, addr); if (rt) { rt->rt_dflags |= RTDF_RA; - if (rb_tree_insert_node(routes, rt) != rt) - rt_free(rt); + rt_proto_add(routes, rt); } } if (rap->lifetime) { rt = inet6_makerouter(rap); if (rt) { rt->rt_dflags |= RTDF_RA; - if (rb_tree_insert_node(routes, rt) != rt) - rt_free(rt); - else if (have_default) + if (rt_proto_add(routes, rt) && have_default) *have_default = true; } } @@ -2287,8 +2284,7 @@ if (rt == NULL) continue; rt->rt_dflags |= RTDF_DHCP; - if (rb_tree_insert_node(routes, rt) != rt) - rt_free(rt); + rt_proto_add(routes, rt); } } } @@ -2313,7 +2309,7 @@ #ifdef DHCP6 /* We have no way of knowing if prefixes added by DHCP are reachable * or not, so we have to assume they are. - * Add bound before delegated so we can prefer interfaces better */ + * Add bound before delegated so we can prefer interfaces better. */ if (inet6_dhcproutes(routes, ctx, DH6S_BOUND) == -1) return false; if (inet6_dhcproutes(routes, ctx, DH6S_DELEGATED) == -1)
--- a/src/route.c Sun May 05 19:04:02 2019 +0100 +++ b/src/route.c Fri Jun 07 16:37:00 2019 +0100 @@ -94,6 +94,17 @@ memset(dstp, 0, (size_t)(addre - dstp)); } +int +rt_cmp_dest(const struct rt *rt1, const struct rt *rt2) +{ + union sa_ss ma1 = { .sa.sa_family = AF_UNSPEC }; + union sa_ss ma2 = { .sa.sa_family = AF_UNSPEC }; + + rt_maskedaddr(&ma1.sa, &rt1->rt_dest, &rt1->rt_netmask); + rt_maskedaddr(&ma2.sa, &rt2->rt_dest, &rt2->rt_netmask); + return sa_cmp(&ma1.sa, &ma2.sa); +} + /* * On some systems, host routes have no need for a netmask. * However DHCP specifies host routes using an all-ones netmask. @@ -109,67 +120,63 @@ return sa_cmp(&rt1->rt_netmask, &rt2->rt_netmask); } -static bool rt_compare_os; +static int +rt_compare_os(__unused void *context, const void *node1, const void *node2) +{ + const struct rt *rt1 = node1, *rt2 = node2; + int c; + + /* Sort by masked destination. */ + c = rt_cmp_dest(rt1, rt2); + if (c != 0) + return c; + +#ifdef HAVE_ROUTE_METRIC + c = (int)(rt1->rt_ifp->metric - rt2->rt_ifp->metric); +#endif + return c; +} static int -rt_compare(void *context, const void *node1, const void *node2) +rt_compare_proto(__unused void *context, const void *node1, const void *node2) { const struct rt *rt1 = node1, *rt2 = node2; - bool rt1u, rt2u; - union sa_ss ma1 = { .sa.sa_family = AF_UNSPEC }; - union sa_ss ma2 = { .sa.sa_family = AF_UNSPEC }; int c; struct interface *ifp1, *ifp2; - /* Default routes come last. */ - rt1u = !(rt1->rt_flags & RTF_HOST) && - sa_is_unspecified(&rt1->rt_dest) && - sa_is_unspecified(&rt1->rt_netmask); - rt2u = !(rt2->rt_flags & RTF_HOST) && - sa_is_unspecified(&rt2->rt_dest) && - sa_is_unspecified(&rt2->rt_netmask); - if (rt1u != rt2u) - return rt1u ? 1 : -1; - - /* Sort by masked destination. */ - rt_maskedaddr(&ma1.sa, &rt1->rt_dest, &rt1->rt_netmask); - rt_maskedaddr(&ma2.sa, &rt2->rt_dest, &rt2->rt_netmask); - c = sa_cmp(&ma1.sa, &ma2.sa); - if (c != 0) - return c; - -#ifndef HAVE_ROUTE_METRIC - if (context == &rt_compare_os) - return 0; -#else - UNUSED(context); -#endif - - /* All other checks are by interface. */ - if (rt1->rt_ifp == NULL || rt2->rt_ifp == NULL) - return 0; + assert(rt1->rt_ifp != NULL); + assert(rt2->rt_ifp != NULL); ifp1 = rt1->rt_ifp; ifp2 = rt2->rt_ifp; - /* Prefer interfaces with a carrier */ + /* Prefer interfaces with a carrier. */ c = ifp1->carrier - ifp2->carrier; if (c != 0) return -c; - /* Lower metric interfaces come first */ - return (int)(ifp1->metric - ifp2->metric); + /* Lower metric interfaces come first. */ + c = (int)(ifp1->metric - ifp2->metric); + if (c != 0) + return c; + + /* Finally the order in which the route was given to us. */ + if (rt1->rt_order > rt2->rt_order) + return 1; + if (rt1->rt_order < rt2->rt_order) + return -1; + return 0; } static const rb_tree_ops_t rt_compare_os_ops = { - .rbto_compare_nodes = rt_compare, - .rbto_compare_key = rt_compare, + .rbto_compare_nodes = rt_compare_os, + .rbto_compare_key = rt_compare_os, .rbto_node_offset = offsetof(struct rt, rt_tree), - .rbto_context = &rt_compare_os + .rbto_context = NULL }; -const rb_tree_ops_t rt_compare_list_ops = { - .rbto_compare_nodes = rt_compare, - .rbto_compare_key = rt_compare, +const rb_tree_ops_t rt_compare_proto_ops = { + .rbto_compare_nodes = rt_compare_proto, + .rbto_compare_key = rt_compare_proto, .rbto_node_offset = offsetof(struct rt, rt_tree), .rbto_context = NULL }; @@ -200,6 +207,14 @@ #endif } +bool +rt_is_default(const struct rt *rt) +{ + + return sa_is_unspecified(&rt->rt_dest) && + sa_is_unspecified(&rt->rt_netmask); +} + static void rt_desc(const char *cmd, const struct rt *rt) { @@ -224,9 +239,7 @@ else loginfox("%s: %s host route to %s via %s", ifname, cmd, dest, gateway); - } else if (sa_is_unspecified(&rt->rt_dest) && - sa_is_unspecified(&rt->rt_netmask)) - { + } else if (rt_is_default(rt)) { if (gateway_unspec) loginfox("%s: %s default route", ifname, cmd); @@ -351,6 +364,26 @@ return rt; } +struct rt * +rt_proto_add_ctx(rb_tree_t *tree, struct rt *rt, struct dhcpcd_ctx *ctx) +{ + + rt->rt_order = ctx->rt_order++; + if (rb_tree_insert_node(tree, rt) == rt) + return rt; + + rt_free(rt); + return NULL; +} + +struct rt * +rt_proto_add(rb_tree_t *tree, struct rt *rt) +{ + + assert (rt->rt_ifp != NULL); + return rt_proto_add_ctx(tree, rt, rt->rt_ifp->ctx); +} + void rt_free(struct rt *rt) { @@ -629,15 +662,16 @@ struct rt *rt, *rtn; unsigned long long o; - rb_tree_init(&routes, &rt_compare_list_ops); + 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_initrt(ctx, &kroutes, af); + ctx->rt_order = 0; switch (af) { #ifdef INET case AF_INET: - if (!inet_getroutes(ctx, &routes, &kroutes)) + if (!inet_getroutes(ctx, &routes)) goto getfail; break; #endif
--- a/src/route.h Sun May 05 19:04:02 2019 +0100 +++ b/src/route.h Fri Jun 07 16:37:00 2019 +0100 @@ -91,21 +91,26 @@ #define RTDF_RA 0x08 /* Router Advertisement */ #define RTDF_DHCP 0x10 /* DHCP route */ #define RTDF_STATIC 0x20 /* Configured in dhcpcd */ + size_t rt_order; rb_node_t rt_tree; }; -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_dispose(struct dhcpcd_ctx *); void rt_free(struct rt *); void rt_freeif(struct interface *); +bool rt_is_default(const struct rt *); void rt_headclear0(struct dhcpcd_ctx *, rb_tree_t *, int); void rt_headclear(rb_tree_t *, int); void rt_headfreeif(rb_tree_t *); struct rt * rt_new0(struct dhcpcd_ctx *); void rt_setif(struct rt *, struct interface *); 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_build(struct dhcpcd_ctx *, int);
