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

Lennart Poettering lennart at poettering.net
Tue May 27 04:50:20 PDT 2014


On Tue, 27.05.14 04:38, Zbigniew Jędrzejewski-Szmek (zbyszek at in.waw.pl) wrote:

> 
> On Mon, May 26, 2014 at 09:39:46PM +0200, Tom Gundersen wrote:
> > 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.
> Hi Tom,
> before looking at the code, a couple of general questions:
> - does the DHCP server have to be part of networkd? Isn't the job
>   of acquiring addresses and giving out addresses separate and
>   shouldn't
>   two different processes be responsible?

I am very sure this should be in networkd. It's a very minor step to not
only configure the local address and netmask, but also offer assigning
these addresses to others. It's really just the other half of dhcp. In
many ways the dhcp server is actually simpler than the client, since it
just reacts, never acts, and never needs to locally/actively apply
configuration. Moreover, the packet handling already kinda exists due to
the dhcp client we have.

I also really want the integration with the rest of networkd, in regard
of forwarding the various bits and pieces that we know of the network,
starting from the DNS configuration (so that we can just forward DNS
server info, instead of having to masquerade it), but also about NTP,
about timezones and whatnot. 

In today's network world dhcp is even used for the most basic of
links. whether you use it between a container and the host, between a VM
and its host, whether you turn your laptop into a hotspot for sharing
your network, whether you use bluetooth PAN stuff, or whether you use
miracast, ... A DHCP server really isn't and shouldn't be that
standalone thing you install, that like let's say apache, or mysql is a
major service you run. Instead it is just this tiny facet that some
links we set up need a bit more management than others from our side. It
is and should be a tiny detail of adressing, and whether you take the
role of requesting addresses via dhcp or of serving them is an
implementation detail in most ways, something that isn't relevant for much.q

The container usecase alone is already the reason why I am so very sure
I want this stuff, and that it needs to be in networkd, and just work. I
want this fully automatic, so that we can create a hundred of veth
tunnels, and trivially easy (simply by setting DHCPServer=yes for their
.network file) make them automatically configured, passing the relevant
configuration bits on.

Remember that the goal here is not to write another ldap enabled
monstrosity. This really should be just this tiny thing that can pass
the bits of configuration it received from the user or from other
interfaces on to a few other hosts, if that's desired. The focus is
clearly on being automatic, and needing very little configuration. In
the long run it should even be able to pick its own address range (which
is useful to scale nicely to 100 veth tunnels), and hence just b this
thing that works, that nicely scales, is as automatic as possible, and
not the thing that people ever want to configure in all details and bells
and whistles, because we already have enough dhcp server implementations
for those cases...

But anyway, I think it's easy to fall in the trap to assume that the
server might actually be more complex than the client. Or that a server
was an uncommon case. The dhcp server is in many ways simpler (doesn't
even need raw sockets, ...), and simply a commodity we need not only on
real networks all the time, but also on internal virtual links and links
to local periphery devices...

I hope that makes sense,

Lennart
> - why the fixed limit of 32 addresses? Shouldn't the default be to give
>   out all possible addresses except for the server one?
> 
> Zbyszek
> 
> > 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 {
> _______________________________________________
> systemd-devel mailing list
> systemd-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel


Lennart

-- 
Lennart Poettering, Red Hat


More information about the systemd-devel mailing list