#include "virt.h"
#include "bus-util.h"
#include "network-internal.h"
+#include "conf-parser.h"
#include "network-util.h"
#include "dhcp-lease-internal.h"
if (!link->network)
return 0;
- if (link->network->dhcp) {
+ if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) {
assert(link->dhcp_client);
k = sd_dhcp_client_stop(link->dhcp_client);
}
}
- if (link->network->dhcp6) {
+ if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) {
assert(link->icmp6_router_discovery);
if (link->dhcp6_client) {
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: could not get routes: %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;
r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
if (r < 0 && r != -ENOENT) {
- log_warning_link(link, "DHCP error: %s", strerror(-r));
+ log_warning_link(link, "DHCP error: could not get gateway: %s",
+ strerror(-r));
return r;
}
link_ref(link);
link->route_messages ++;
}
+
+ if (link->network->dhcp_routes)
+ link_set_dhcp_routes(link);
}
if (link->route_messages == 0) {
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);
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;
r = sd_dhcp_lease_get_router(lease, &gateway);
if (r < 0 && r != -ENOENT) {
- log_warning_link(link, "DHCP error: %s", strerror(-r));
+ log_warning_link(link, "DHCP error: could not get gateway: %s",
+ strerror(-r));
return r;
}
break;
default:
if (event < 0)
- log_warning_link(link, "DHCP error: %s", strerror(-event));
+ log_warning_link(link, "DHCP error: client failed: %s", strerror(-event));
else
log_warning_link(link, "DHCP unknown event: %d", event);
break;
}
}
- if (link->network->dhcp) {
+ if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V4)) {
assert(link->dhcp_client);
log_debug_link(link, "acquiring DHCPv4 lease");
}
}
- if (link->network->dhcp6) {
+ if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) {
assert(link->icmp6_router_discovery);
log_debug_link(link, "discovering IPv6 routers");
}
}
- if (!link->network->dhcp && !link->network->ipv4ll)
- return link_enter_set_addresses(link);
-
- return 0;
+ return link_enter_set_addresses(link);
}
static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
return r;
}
- if (link->network->dhcp) {
+ if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V4)) {
r = sd_dhcp_client_new(&link->dhcp_client);
if (r < 0)
return r;
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) {
return r;
}
- if (link->network->dhcp6) {
+ if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) {
r = sd_icmp6_nd_new(&link->icmp6_router_discovery);
if (r < 0)
return r;
};
DEFINE_STRING_TABLE_LOOKUP(link_operstate, LinkOperationalState);
+
+static const char* const dhcp_support_table[_DHCP_SUPPORT_MAX] = {
+ [DHCP_SUPPORT_NONE] = "none",
+ [DHCP_SUPPORT_BOTH] = "both",
+ [DHCP_SUPPORT_V4] = "v4",
+ [DHCP_SUPPORT_V6] = "v6",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(dhcp_support, DHCPSupport);
+
+int config_parse_dhcp(
+ const char* unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ DHCPSupport *dhcp = data;
+ int k;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ /* Our enum shall be a superset of booleans, hence first try
+ * to parse as boolean, and then as enum */
+
+ k = parse_boolean(rvalue);
+ if (k > 0)
+ *dhcp = DHCP_SUPPORT_BOTH;
+ else if (k == 0)
+ *dhcp = DHCP_SUPPORT_NONE;
+ else {
+ DHCPSupport s;
+
+ s = dhcp_support_from_string(rvalue);
+ if (s < 0){
+ log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse DHCP option, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ *dhcp = s;
+ }
+
+ return 0;
+}