diff options
author | Eugene Yakubovich <eyakubovich@gmail.com> | 2014-06-27 15:00:06 -0700 |
---|---|---|
committer | Tom Gundersen <teg@jklm.no> | 2014-06-29 15:18:21 +0200 |
commit | e1ea665edac17d75fce01b72dadfa3211b60df2c (patch) | |
tree | 9f1d4c8ae93862cf5ebae973cd48d053ef34c0dd /src/network/networkd-link.c | |
parent | ed942a9eb22d50f667909ad6184b45015d28d054 (diff) |
Add support for DHCP static route options
This adds support for DHCP options 33 and 121: Static Route and
Classless Static Route. To enable this feature, set UseRoutes=true
in .network file. Returned routes are added to the routing table.
Diffstat (limited to 'src/network/networkd-link.c')
-rw-r--r-- | src/network/networkd-link.c | 85 |
1 files changed, 83 insertions, 2 deletions
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 5d280b5b82..82e517e78c 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -402,6 +402,51 @@ static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { return 1; } +static int link_set_dhcp_routes(Link *link) { + struct sd_dhcp_route *static_routes; + size_t static_routes_size; + int r; + unsigned i; + + assert(link); + + r = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes, &static_routes_size); + if (r < 0) { + if (r != -ENOENT) + log_warning_link(link, "DHCP error: %s", strerror(-r)); + return r; + } + + for (i = 0; i < static_routes_size; i++) { + _cleanup_route_free_ Route *route = NULL; + + r = route_new_dynamic(&route); + if (r < 0) { + log_error_link(link, "Could not allocate route: %s", + strerror(-r)); + return r; + } + + route->family = AF_INET; + route->in_addr.in = static_routes[i].gw_addr; + route->dst_addr.in = static_routes[i].dst_addr; + route->dst_prefixlen = static_routes[i].dst_prefixlen; + route->metrics = DHCP_STATIC_ROUTE_METRIC; + + r = route_configure(route, link, &route_handler); + if (r < 0) { + log_warning_link(link, + "could not set host route: %s", strerror(-r)); + return r; + } + + link_ref(link); + link->route_messages ++; + } + + return 0; +} + static int link_enter_set_routes(Link *link) { Route *rt; int r; @@ -525,6 +570,9 @@ static int link_enter_set_routes(Link *link) { link_ref(link); link->route_messages ++; } + + if (link->network->dhcp_routes) + link_set_dhcp_routes(link); } if (link->route_messages == 0) { @@ -901,12 +949,11 @@ static int link_set_mtu(Link *link, uint32_t mtu) { static int dhcp_lease_lost(Link *link) { _cleanup_address_free_ Address *address = NULL; - _cleanup_route_free_ Route *route_gw = NULL; - _cleanup_route_free_ Route *route = NULL; struct in_addr addr; struct in_addr netmask; struct in_addr gateway; unsigned prefixlen; + unsigned i; int r; assert(link); @@ -914,10 +961,36 @@ static int dhcp_lease_lost(Link *link) { log_warning_link(link, "DHCP lease lost"); + if (link->network->dhcp_routes) { + struct sd_dhcp_route *routes; + size_t routes_size; + + r = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes, &routes_size); + if (r >= 0) { + for (i = 0; i < routes_size; i++) { + _cleanup_route_free_ Route *route = NULL; + + r = route_new_dynamic(&route); + if (r >= 0) { + route->family = AF_INET; + route->in_addr.in = routes[i].gw_addr; + route->dst_addr.in = routes[i].dst_addr; + route->dst_prefixlen = routes[i].dst_prefixlen; + + route_drop(route, link, &route_drop_handler); + link_ref(link); + } + } + } + } + r = address_new_dynamic(&address); if (r >= 0) { r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway); if (r >= 0) { + _cleanup_route_free_ Route *route_gw = NULL; + _cleanup_route_free_ Route *route = NULL; + r = route_new_dynamic(&route_gw); if (r >= 0) { route_gw->family = AF_INET; @@ -1952,6 +2025,14 @@ static int link_configure(Link *link) { if (r < 0) return r; } + if (link->network->dhcp_routes) { + r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_STATIC_ROUTE); + if (r < 0) + return r; + r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_CLASSLESS_STATIC_ROUTE); + if (r < 0) + return r; + } } if (link->network->dhcp_server) { |