From 1985c54ff35278aee81e019b8badabdc6993af89 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 7 Jan 2020 14:43:09 +0900 Subject: [PATCH] network: static routes via DHCP gateway This makes Gateway= also take "DHCP". If "DHCP" is set, then the gateway address provided by DHCP or IPv6 RA is used. Closes #8213. --- man/systemd.network.xml | 4 +++- src/network/networkd-dhcp4.c | 31 +++++++++++++++++++++++++++++++ src/network/networkd-link.c | 2 ++ src/network/networkd-ndisc.c | 20 ++++++++++++++++++++ src/network/networkd-route.c | 15 ++++++++++++--- src/network/networkd-route.h | 1 + 6 files changed, 69 insertions(+), 4 deletions(-) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 4cd2520173..4299583fe7 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -1216,7 +1216,9 @@ Gateway= - As in the [Network] section. + Takes the gateway address or special value dhcp. If + dhcp, then the gateway address provided by DHCP (or in the IPv6 case, + provided by IPv6 RA) is used. diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 66d83e76bf..70377ad6bb 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -377,6 +377,23 @@ static int link_set_dhcp_routes(Link *link) { return log_link_error_errno(link, r, "Could not set router: %m"); } + Route *rt; + LIST_FOREACH(routes, rt, link->network->static_routes) { + if (!rt->gateway_from_dhcp) + continue; + + if (rt->family != AF_INET) + continue; + + rt->gw.in = router[0]; + + r = route_configure(rt, link, dhcp4_route_handler); + if (r < 0) + return log_link_error_errno(link, r, "Could not set gateway: %m"); + if (r > 0) + link->dhcp4_messages++; + } + return link_set_dns_routes(link, &address); } @@ -480,6 +497,20 @@ static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, const struct in_ if (remove_all || !set_contains(link->dhcp_routes, route)) (void) route_remove(route, link, NULL); + Route *rt; + LIST_FOREACH(routes, rt, link->network->static_routes) { + if (!rt->gateway_from_dhcp) + continue; + + if (rt->family != AF_INET) + continue; + + if (!remove_all && in4_addr_equal(router, &rt->gw.in)) + continue; + + (void) route_remove(rt, link, NULL); + } + return 0; } diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 23d0ee675b..f2027057c4 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1039,6 +1039,8 @@ int link_request_set_routes(Link *link) { /* First add the routes that enable us to talk to gateways, then add in the others that need a gateway. */ for (phase = 0; phase < _PHASE_MAX; phase++) LIST_FOREACH(routes, rt, link->network->static_routes) { + if (rt->gateway_from_dhcp) + continue; if ((in_addr_is_null(rt->family, &rt->gw) && ordered_set_isempty(rt->multipath_routes)) != (phase == PHASE_NON_GATEWAY)) continue; diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index d1db9e4931..fb3d6f2a84 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -169,6 +169,26 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) { if (r > 0) link->ndisc_messages++; + Route *route_gw; + LIST_FOREACH(routes, route_gw, link->network->static_routes) { + if (!route_gw->gateway_from_dhcp) + continue; + + if (route_gw->family != AF_INET6) + continue; + + route_gw->gw = gateway; + + r = route_configure(route_gw, link, ndisc_netlink_route_message_handler); + if (r < 0) { + log_link_error_errno(link, r, "Could not set gateway: %m"); + link_enter_failed(link); + return r; + } + if (r > 0) + link->ndisc_messages++; + } + return 0; } diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index ecc8d219b7..4e90fdef18 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -998,10 +998,19 @@ int config_parse_gateway( /* we are not in an Route section, so treat * this as the special '0' section */ r = route_new_static(network, NULL, 0, &n); - } else + if (r < 0) + return r; + } else { r = route_new_static(network, filename, section_line, &n); - if (r < 0) - return r; + if (r < 0) + return r; + + if (streq(rvalue, "dhcp")) { + n->gateway_from_dhcp = true; + TAKE_PTR(n); + return 0; + } + } if (n->family == AF_UNSPEC) r = in_addr_from_string_auto(rvalue, &n->family, &n->gw); diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index 91bba368ee..067c65f2f7 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -48,6 +48,7 @@ struct Route { unsigned char pref; unsigned flags; int gateway_onlink; + bool gateway_from_dhcp; union in_addr_union gw; union in_addr_union dst;