[systemd-devel] [PATCH 17/17] networkd: add dhcp server support

Tom Gundersen teg at jklm.no
Mon May 26 12:39:46 PDT 2014


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.
---
 src/network/networkd-link.c              | 101 ++++++++++++++++++++++++++-----
 src/network/networkd-network-gperf.gperf |   1 +
 src/network/networkd.h                   |   5 ++
 3 files changed, 93 insertions(+), 14 deletions(-)

diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 6677b94..b80a002 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -174,19 +174,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);
 
@@ -227,6 +214,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;
 }
 
@@ -245,6 +242,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;
@@ -1663,7 +1691,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 5038cb5..7ef467e 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 cfe24f5..994c052 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"
 
@@ -145,6 +146,8 @@ struct Network {
         bool dhcp_critical;
         bool ipv4ll;
 
+        bool dhcp_server;
+
         LIST_HEAD(Address, static_addresses);
         LIST_HEAD(Route, static_routes);
 
@@ -252,6 +255,8 @@ struct Link {
         char *lease_file;
         uint16_t original_mtu;
         sd_ipv4ll *ipv4ll;
+
+        sd_dhcp_server *dhcp_server;
 };
 
 struct Manager {
-- 
1.9.0



More information about the systemd-devel mailing list