From: Tom Gundersen Date: Wed, 5 Mar 2014 07:13:30 +0000 (+0100) Subject: networkd: add dhcp server support X-Git-Tag: v215~443 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=dd43110f781a9245ec00531456fee68ed763a179;ds=sidebyside networkd: add dhcp server support When enabled in [Network] it will set up a dhcp server on the interface, listening on one of its statically configured IPv4 addresses and with a fixed size pool of leases determined from it. Example: [Match] Name=ve-arch-tree [Network] Address=192.168.12.5/24 DHCPServer=yes [Route] Gateway=192.168.12.5 Destination=192.168.12.0/24 In this case we will configure ve-arch-tree with the address 192.168.12.5 and hand out addresses in the range 192.168.12.6 - 192.168.12.38. In the future, we should (as suggested by Lennart) introduce a syntax to pick the server address automatically. --- diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 365342689..4b59af4ab 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -178,19 +178,6 @@ void link_drop(Link *link) { return; } -static int link_enter_configured(Link *link) { - assert(link); - assert(link->state == LINK_STATE_SETTING_ROUTES); - - log_info_link(link, "link configured"); - - link->state = LINK_STATE_CONFIGURED; - - link_save(link); - - return 0; -} - static void link_enter_unmanaged(Link *link) { assert(link); @@ -231,6 +218,16 @@ static int link_stop_clients(Link *link) { } } + if (link->network->dhcp_server) { + assert(link->dhcp_server); + + k = sd_dhcp_server_stop(link->dhcp_server); + if (k < 0) { + log_warning_link(link, "Could not stop DHCPv4 server: %s", strerror(-r)); + r = k; + } + } + return r; } @@ -249,6 +246,37 @@ static void link_enter_failed(Link *link) { link_save(link); } +static int link_enter_configured(Link *link) { + int r; + + assert(link); + assert(link->network); + assert(link->state == LINK_STATE_SETTING_ROUTES); + + + if (link->network->dhcp_server) { + log_debug_link(link, "offering DHCPv4 leases"); + + r = sd_dhcp_server_start(link->dhcp_server); + if (r < 0) { + log_warning_link(link, "could not start DHCPv4 server " + "instance: %s", strerror(-r)); + + link_enter_failed(link); + + return 0; + } + } + + log_info_link(link, "link configured"); + + link->state = LINK_STATE_CONFIGURED; + + link_save(link); + + return 0; +} + static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { Link *link = userdata; int r; @@ -1667,7 +1695,52 @@ static int link_configure(Link *link) { } } - if (link_has_carrier(link->flags, link->kernel_operstate)) { + if (link->network->dhcp_server) { + Address *address; + + r = sd_dhcp_server_new(&link->dhcp_server, link->ifindex); + if (r < 0) + return r; + + r = sd_dhcp_server_attach_event(link->dhcp_server, NULL, 0); + if (r < 0) + return r; + + LIST_FOREACH(addresses, address, + link->network->static_addresses) { + struct in_addr pool_start; + + if (address->family != AF_INET) + continue; + + /* currently this is picked essentially at random */ + r = sd_dhcp_server_set_address(link->dhcp_server, + &address->in_addr.in); + if (r < 0) + return r; + + /* offer 32 addresses starting from the address following the server address */ + pool_start.s_addr = htobe32(be32toh(address->in_addr.in.s_addr) + 1); + r = sd_dhcp_server_set_lease_pool(link->dhcp_server, + &pool_start, 32); + + break; + } + + /* TODO: + r = sd_dhcp_server_set_router(link->dhcp_server, + &main_address->in_addr.in); + if (r < 0) + return r; + + r = sd_dhcp_server_set_prefixlen(link->dhcp_server, + main_address->prefixlen); + if (r < 0) + return r; + */ + } + + if (link_has_carrier(link->flags, link->operstate)) { r = link_acquire_conf(link); if (r < 0) return r; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 5038cb545..7ef467eed 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -30,6 +30,7 @@ Network.Bond, config_parse_netdev, 0, Network.VLAN, config_parse_netdev, 0, offsetof(Network, vlans) Network.MACVLAN, config_parse_netdev, 0, offsetof(Network, macvlans) Network.DHCP, config_parse_bool, 0, offsetof(Network, dhcp) +Network.DHCPServer, config_parse_bool, 0, offsetof(Network, dhcp_server) Network.IPv4LL, config_parse_bool, 0, offsetof(Network, ipv4ll) Network.Address, config_parse_address, 0, 0 Network.Gateway, config_parse_gateway, 0, 0 diff --git a/src/network/networkd.h b/src/network/networkd.h index 6f77c7785..87eadd1c5 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -27,6 +27,7 @@ #include "sd-rtnl.h" #include "sd-bus.h" #include "sd-dhcp-client.h" +#include "sd-dhcp-server.h" #include "sd-ipv4ll.h" #include "udev.h" @@ -149,6 +150,8 @@ struct Network { bool dhcp_critical; bool ipv4ll; + bool dhcp_server; + LIST_HEAD(Address, static_addresses); LIST_HEAD(Route, static_routes); @@ -256,6 +259,8 @@ struct Link { char *lease_file; uint16_t original_mtu; sd_ipv4ll *ipv4ll; + + sd_dhcp_server *dhcp_server; }; struct Manager {