From 34437b4f9c9c51b0a6f93788bdb9a105b8e46b66 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 19 Feb 2016 17:58:52 +0100 Subject: sd-lldp: rework sd-lldp API This reworks the sd-lldp substantially, simplifying things on one hand, and extending the logic a bit on the other. Specifically: - Besides the sd_lldp object only one other object is maintained now, sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for maintainging info about peers in the database. Separation between packet, TLV and chassis data is not maintained anymore. This should be a major simplification. - The sd-lldp API has been extended so that a couple of per-neighbor fields may be queried directly, without iterating through the object. Other fields that may appear multiple times, OTOH have to be iterated through. - The maximum number of entries in the neighbor database is now configurable during runtime. - The generation of callbacks from sd_lldp objects is more restricted: callbacks are only invoked when actual data changed. - The TTL information is now hooked with a timer event, so that removals from the neighbor database due to TTLs now result in a callback event. - Querying LLDP neighbor database will now return a strictly ordered array, to guarantee stability. - A "capabilities" mask may now be configured, that selects what type of LLDP neighbor data is collected. This may be used to restrict collection of LLDP info about routers instead of all neighbors. This is now exposed via networkd's LLDP= setting. - sd-lldp's API to serialize the collected data to text files has been removed. Instead, there's now an API to extract the raw binary data from LLDP neighbor objects, as well as one to convert this raw binary data back to an LLDP neighbor object. networkd will save this raw binary data to /run now, and the client side can simply parse the information. - support for parsing the more exotic TLVs has been removed, since we are not using that. Instead there are now APIs to extract the raw data from TLVs. Given how easy it is to parse the TLVs clients should do so now directly instead of relying on our APIs for that. - A lot of the APIs that parse out LLDP strings have been simplified so that they actually return strings, instead of char arrays with a length. To deal with possibly dangerous characters the strings are escaped if needed. - APIs to extract and format the chassis and port IDs as strings has been added. - lldp.h has been simplified a lot. The enums are anonymous now, since they were never used as enums, but simply as constants. Most definitions we don't actually use ourselves have eben removed. --- src/network/networkd-network-gperf.gperf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/network/networkd-network-gperf.gperf') diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 409df1709f..d67da5d7b6 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -40,7 +40,7 @@ Network.DHCPServer, config_parse_bool, Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local) Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route) Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token) -Network.LLDP, config_parse_bool, 0, offsetof(Network, lldp) +Network.LLDP, config_parse_lldp_mode, 0, offsetof(Network, lldp_mode) Network.Address, config_parse_address, 0, 0 Network.Gateway, config_parse_gateway, 0, 0 Network.Domains, config_parse_domains, 0, 0 -- cgit v1.2.3-54-g00ecf From 8e1ad1eaf74cd8eadf6a9b14e5d6edb24ab2da91 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Feb 2016 14:14:08 +0100 Subject: networkd: add basic LLDP transmission support Let's add some minimalistic LLDP sender support. The idea is that this is either on or off, and all fields determined automatically rather than configured explicitly. --- Makefile.am | 4 +- src/basic/hostname-util.c | 28 +++ src/basic/hostname-util.h | 1 + src/network/networkd-link.c | 29 ++- src/network/networkd-link.h | 5 + src/network/networkd-lldp-tx.c | 347 +++++++++++++++++++++++++++++++ src/network/networkd-lldp-tx.h | 25 +++ src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-network.h | 3 +- 9 files changed, 439 insertions(+), 4 deletions(-) create mode 100644 src/network/networkd-lldp-tx.c create mode 100644 src/network/networkd-lldp-tx.h (limited to 'src/network/networkd-network-gperf.gperf') diff --git a/Makefile.am b/Makefile.am index 70fcedf0da..627a076cd9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5341,7 +5341,9 @@ libnetworkd_core_la_SOURCES = \ src/network/networkd-address-pool.h \ src/network/networkd-address-pool.c \ src/network/networkd-util.h \ - src/network/networkd-util.c + src/network/networkd-util.c \ + src/network/networkd-lldp-tx.h \ + src/network/networkd-lldp-tx.c nodist_libnetworkd_core_la_SOURCES = \ src/network/networkd-network-gperf.c \ diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index 57031b645c..f900c509a3 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -48,6 +48,9 @@ bool hostname_is_set(void) { char* gethostname_malloc(void) { struct utsname u; + /* This call tries to return something useful, either the actual hostname or it makes something up. The only + * reason it might mail is OOM. It might even return "localhost" if that's set. */ + assert_se(uname(&u) >= 0); if (isempty(u.nodename) || streq(u.nodename, "(none)")) @@ -56,6 +59,31 @@ char* gethostname_malloc(void) { return strdup(u.nodename); } +int gethostname_strict(char **ret) { + struct utsname u; + char *k; + + /* This call will rather fail than make up a name. It will not return "localhost" either. */ + + assert_se(uname(&u) >= 0); + + if (isempty(u.nodename)) + return -ENXIO; + + if (streq(u.nodename, "(none)")) + return -ENXIO; + + if (is_localhost(u.nodename)) + return -ENXIO; + + k = strdup(u.nodename); + if (!k) + return -ENOMEM; + + *ret = k; + return 0; +} + static bool hostname_valid_char(char c) { return (c >= 'a' && c <= 'z') || diff --git a/src/basic/hostname-util.h b/src/basic/hostname-util.h index d062eddea1..7af4e6c7ec 100644 --- a/src/basic/hostname-util.h +++ b/src/basic/hostname-util.h @@ -26,6 +26,7 @@ bool hostname_is_set(void); char* gethostname_malloc(void); +int gethostname_strict(char **ret); bool hostname_is_valid(const char *s, bool allow_trailing_dot) _pure_; char* hostname_cleanup(char *s); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 2bc6e3c842..86fa4f07f2 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -30,6 +30,7 @@ #include "netlink-util.h" #include "network-internal.h" #include "networkd-link.h" +#include "networkd-lldp-tx.h" #include "networkd-netdev.h" #include "set.h" #include "socket-util.h" @@ -99,7 +100,7 @@ static bool link_ipv6ll_enabled(Link *link) { return link->network->link_local & ADDRESS_FAMILY_IPV6; } -static bool link_lldp_enabled(Link *link) { +static bool link_lldp_rx_enabled(Link *link) { assert(link); if (link->flags & IFF_LOOPBACK) @@ -117,6 +118,21 @@ static bool link_lldp_enabled(Link *link) { return link->network->lldp_mode != LLDP_MODE_NO; } +static bool link_lldp_tx_enabled(Link *link) { + assert(link); + + if (link->flags & IFF_LOOPBACK) + return false; + + if (link->iftype != ARPHRD_ETHER) + return false; + + if (!link->network) + return false; + + return link->network->lldp_emit; +} + static bool link_ipv4_forward_enabled(Link *link) { assert(link); @@ -419,6 +435,8 @@ static void link_free(Link *link) { sd_dhcp_client_unref(link->dhcp_client); sd_dhcp_lease_unref(link->dhcp_lease); + link_lldp_tx_stop(link); + free(link->lease_file); sd_lldp_unref(link->lldp); @@ -546,6 +564,7 @@ static int link_stop_clients(Link *link) { r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m"); } + link_lldp_tx_stop(link); return r; } @@ -1383,6 +1402,12 @@ static int link_acquire_conf(Link *link) { return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m"); } + if (link_lldp_tx_enabled(link)) { + r = link_lldp_tx_start(link); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to start LLDP transmission: %m"); + } + return 0; } @@ -2191,7 +2216,7 @@ static int link_configure(Link *link) { return r; } - if (link_lldp_enabled(link)) { + if (link_lldp_rx_enabled(link)) { r = sd_lldp_new(&link->lldp, link->ifindex); if (r < 0) return r; diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index d9f637cb6e..f2a64ca9b5 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -112,9 +112,14 @@ struct Link { sd_dhcp6_client *dhcp6_client; bool rtnl_extended_attrs; + /* This is about LLDP reception */ sd_lldp *lldp; char *lldp_file; + /* This is about LLDP transmission */ + unsigned lldp_tx_fast; /* The LLDP txFast counter (See 802.1ab-2009, section 9.2.5.18) */ + sd_event_source *lldp_tx_event_source; + Hashmap *bound_by_links; Hashmap *bound_to_links; }; diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c new file mode 100644 index 0000000000..ae8367a60e --- /dev/null +++ b/src/network/networkd-lldp-tx.c @@ -0,0 +1,347 @@ +/*** + This file is part of systemd. + + Copyright 2016 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "fd-util.h" +#include "fileio.h" +#include "hostname-util.h" +#include "lldp.h" +#include "networkd-lldp-tx.h" +#include "random-util.h" +#include "socket-util.h" +#include "string-util.h" +#include "unaligned.h" + +/* The LLDP spec calls this "txFastInit", see 9.2.5.19 */ +#define LLDP_TX_FAST_INIT 4U + +/* The LLDP spec calls this "msgTxHold", see 9.2.5.6 */ +#define LLDP_TX_HOLD 4U + +/* The jitter range to add, see 9.2.2. */ +#define LLDP_JITTER_USEC (400U * USEC_PER_MSEC) + +/* The LLDP spec calls this msgTxInterval, but we subtract half the jitter off it. */ +#define LLDP_TX_INTERVAL_USEC (30U * USEC_PER_SEC - LLDP_JITTER_USEC / 2) + +/* The LLDP spec calls this msgFastTx, but we subtract half the jitter off it. */ +#define LLDP_FAST_TX_USEC (1U * USEC_PER_SEC - LLDP_JITTER_USEC / 2) + +static int lldp_write_tlv_header(uint8_t **p, uint8_t id, size_t sz) { + assert(p); + + if (id > 127) + return -EBADMSG; + if (sz > 511) + return -ENOBUFS; + + (*p)[0] = (id << 1) | !!(sz & 256); + (*p)[1] = sz & 255; + + *p = *p + 2; + return 0; +} + +static int lldp_make_packet( + const struct ether_addr *hwaddr, + const char *machine_id, + const char *ifname, + uint16_t ttl, + const char *port_description, + const char *hostname, + const char *pretty_hostname, + uint16_t system_capabilities, + uint16_t enabled_capabilities, + void **ret, size_t *sz) { + + size_t machine_id_length, ifname_length, port_description_length = 0, hostname_length = 0, pretty_hostname_length = 0; + _cleanup_free_ void *packet = NULL; + struct ether_header *h; + uint8_t *p; + size_t l; + int r; + + assert(hwaddr); + assert(machine_id); + assert(ifname); + assert(ret); + assert(sz); + + machine_id_length = strlen(machine_id); + ifname_length = strlen(ifname); + + if (port_description) + port_description_length = strlen(port_description); + + if (hostname) + hostname_length = strlen(hostname); + + if (pretty_hostname) + pretty_hostname_length = strlen(pretty_hostname); + + l = sizeof(struct ether_header) + + /* Chassis ID */ + 2 + 1 + machine_id_length + + /* Port ID */ + 2 + 1 + ifname_length + + /* TTL */ + 2 + 2 + + /* System Capabilities */ + 2 + 4 + + /* End */ + 2; + + /* Port Description */ + if (port_description) + l += 2 + port_description_length; + + /* System Name */ + if (hostname) + l += 2 + hostname_length; + + /* System Description */ + if (pretty_hostname) + l += 2 + pretty_hostname_length; + + packet = malloc(l); + if (!packet) + return -ENOMEM; + + h = (struct ether_header*) packet; + h->ether_type = htobe16(ETHERTYPE_LLDP); + memcpy(h->ether_dhost, &(struct ether_addr) { LLDP_MULTICAST_ADDR }, ETH_ALEN); + memcpy(h->ether_shost, hwaddr, ETH_ALEN); + + p = (uint8_t*) packet + sizeof(struct ether_header); + + r = lldp_write_tlv_header(&p, LLDP_TYPE_CHASSIS_ID, 1 + machine_id_length); + if (r < 0) + return r; + *(p++) = LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED; + p = mempcpy(p, machine_id, machine_id_length); + + r = lldp_write_tlv_header(&p, LLDP_TYPE_PORT_ID, 1 + ifname_length); + if (r < 0) + return r; + *(p++) = LLDP_PORT_SUBTYPE_INTERFACE_NAME; + p = mempcpy(p, ifname, ifname_length); + + r = lldp_write_tlv_header(&p, LLDP_TYPE_TTL, 2); + if (r < 0) + return r; + unaligned_write_be16(p, ttl); + p += 2; + + if (port_description) { + r = lldp_write_tlv_header(&p, LLDP_TYPE_PORT_DESCRIPTION, port_description_length); + if (r < 0) + return r; + p = mempcpy(p, port_description, port_description_length); + } + + if (hostname) { + r = lldp_write_tlv_header(&p, LLDP_TYPE_SYSTEM_NAME, hostname_length); + if (r < 0) + return r; + p = mempcpy(p, hostname, hostname_length); + } + + if (pretty_hostname) { + r = lldp_write_tlv_header(&p, LLDP_TYPE_SYSTEM_DESCRIPTION, pretty_hostname_length); + if (r < 0) + return r; + p = mempcpy(p, pretty_hostname, pretty_hostname_length); + } + + r = lldp_write_tlv_header(&p, LLDP_TYPE_SYSTEM_CAPABILITIES, 4); + if (r < 0) + return r; + unaligned_write_be16(p, system_capabilities); + p += 2; + unaligned_write_be16(p, enabled_capabilities); + p += 2; + + r = lldp_write_tlv_header(&p, LLDP_TYPE_END, 0); + if (r < 0) + return r; + + assert(p == (uint8_t*) packet + l); + + *ret = packet; + *sz = l; + + packet = NULL; + return 0; +} + +static int lldp_send_packet(int ifindex, const void *packet, size_t packet_size) { + + union sockaddr_union sa = { + .ll.sll_family = AF_PACKET, + .ll.sll_protocol = htobe16(ETHERTYPE_LLDP), + .ll.sll_ifindex = ifindex, + .ll.sll_halen = ETH_ALEN, + .ll.sll_addr = LLDP_MULTICAST_ADDR, + }; + + _cleanup_close_ int fd = -1; + ssize_t l; + + assert(ifindex > 0); + assert(packet || packet_size <= 0); + + fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC, IPPROTO_RAW); + if (fd < 0) + return -errno; + + l = sendto(fd, packet, packet_size, MSG_NOSIGNAL, &sa.sa, sizeof(sa.ll)); + if (l < 0) + return -errno; + + if ((size_t) l != packet_size) + return -EIO; + + return 0; +} + +static int link_send_lldp(Link *link) { + char machine_id_string[SD_ID128_STRING_MAX]; + _cleanup_free_ char *hostname = NULL, *pretty_hostname = NULL; + _cleanup_free_ void *packet = NULL; + size_t packet_size = 0; + sd_id128_t machine_id; + uint16_t caps; + usec_t ttl; + int r; + + r = sd_id128_get_machine(&machine_id); + if (r < 0) + return r; + + (void) gethostname_strict(&hostname); + (void) parse_env_file("/etc/machine-info", NEWLINE, "PRETTY_HOSTNAME", &pretty_hostname, NULL); + + ttl = DIV_ROUND_UP(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1, USEC_PER_SEC); + if (ttl > (usec_t) UINT16_MAX) + ttl = (usec_t) UINT16_MAX; + + caps = (link->network && link->network->ip_forward != ADDRESS_FAMILY_NO) ? + LLDP_SYSTEM_CAPABILITIES_ROUTER : + LLDP_SYSTEM_CAPABILITIES_STATION; + + r = lldp_make_packet(&link->mac, + sd_id128_to_string(machine_id, machine_id_string), + link->ifname, + (uint16_t) ttl, + link->network ? link->network->description : NULL, + hostname, + pretty_hostname, + LLDP_SYSTEM_CAPABILITIES_STATION|LLDP_SYSTEM_CAPABILITIES_BRIDGE|LLDP_SYSTEM_CAPABILITIES_ROUTER, + caps, + &packet, &packet_size); + if (r < 0) + return r; + + return lldp_send_packet(link->ifindex, packet, packet_size); +} + +static int on_lldp_timer(sd_event_source *s, usec_t t, void *userdata) { + Link *link = userdata; + usec_t current, delay, next; + int r; + + assert(s); + assert(userdata); + + log_link_debug(link, "Sending LLDP packet..."); + + r = link_send_lldp(link); + if (r < 0) + log_link_debug_errno(link, r, "Failed to send LLDP packet, ignoring: %m"); + + if (link->lldp_tx_fast > 0) + link->lldp_tx_fast--; + + assert_se(sd_event_now(sd_event_source_get_event(s), clock_boottime_or_monotonic(), ¤t) >= 0); + + delay = link->lldp_tx_fast > 0 ? LLDP_FAST_TX_USEC : LLDP_TX_INTERVAL_USEC; + next = usec_add(usec_add(current, delay), (usec_t) random_u64() % LLDP_JITTER_USEC); + + r = sd_event_source_set_time(s, next); + if (r < 0) + return log_link_error_errno(link, r, "Failed to restart LLDP timer: %m"); + + r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT); + if (r < 0) + return log_link_error_errno(link, r, "Failed to enable LLDP timer: %m"); + + return 0; +} + +int link_lldp_tx_start(Link *link) { + usec_t next; + int r; + + assert(link); + + /* Starts the LLDP transmission in "fast" mode. If it is already started, turns "fast" mode back on again. */ + + link->lldp_tx_fast = LLDP_TX_FAST_INIT; + + next = usec_add(usec_add(now(clock_boottime_or_monotonic()), LLDP_FAST_TX_USEC), + (usec_t) random_u64() % LLDP_JITTER_USEC); + + if (link->lldp_tx_event_source) { + usec_t old; + + /* Lower the timeout, maybe */ + r = sd_event_source_get_time(link->lldp_tx_event_source, &old); + if (r < 0) + return r; + + if (old <= next) + return 0; + + return sd_event_source_set_time(link->lldp_tx_event_source, next); + } else { + r = sd_event_add_time( + link->manager->event, + &link->lldp_tx_event_source, + clock_boottime_or_monotonic(), + next, + 0, + on_lldp_timer, + link); + if (r < 0) + return r; + + (void) sd_event_source_set_description(link->lldp_tx_event_source, "lldp-tx"); + } + + return 0; +} + +void link_lldp_tx_stop(Link *link) { + assert(link); + + link->lldp_tx_event_source = sd_event_source_unref(link->lldp_tx_event_source); +} diff --git a/src/network/networkd-lldp-tx.h b/src/network/networkd-lldp-tx.h new file mode 100644 index 0000000000..8c7f403005 --- /dev/null +++ b/src/network/networkd-lldp-tx.h @@ -0,0 +1,25 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "networkd-link.h" + +int link_lldp_tx_start(Link *link); +void link_lldp_tx_stop(Link *link); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index d67da5d7b6..a5d1714293 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -41,6 +41,7 @@ Network.LinkLocalAddressing, config_parse_address_family_boolean, Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route) Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token) Network.LLDP, config_parse_lldp_mode, 0, offsetof(Network, lldp_mode) +Network.EmitLLDP, config_parse_bool, 0, offsetof(Network, lldp_emit) Network.Address, config_parse_address, 0, 0 Network.Gateway, config_parse_gateway, 0, 0 Network.Domains, config_parse_domains, 0, 0 diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 9dcebfbf7b..4a13e2b574 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -145,7 +145,8 @@ struct Network { struct ether_addr *mac; unsigned mtu; - LLDPMode lldp_mode; + LLDPMode lldp_mode; /* LLDP reception */ + bool lldp_emit; /* LLDP transmission */ LIST_HEAD(Address, static_addresses); LIST_HEAD(Route, static_routes); -- cgit v1.2.3-54-g00ecf From c83321e6d40b294e73e2881e4a98172c4244323b Mon Sep 17 00:00:00 2001 From: Vinay Kulkarni Date: Wed, 9 Mar 2016 21:58:44 -0800 Subject: DHCP DUID and IAID configurability --- Makefile-man.am | 7 ++ Makefile.am | 4 + man/networkd.conf.xml | 112 +++++++++++++++++++++++++ man/systemd.network.xml | 6 ++ src/libsystemd-network/dhcp-identifier.c | 2 +- src/libsystemd-network/dhcp-identifier.h | 41 ++++++++- src/libsystemd-network/dhcp6-protocol.h | 7 -- src/libsystemd-network/network-internal.c | 28 +++++++ src/libsystemd-network/network-internal.h | 4 + src/libsystemd-network/sd-dhcp-client.c | 48 ++++++++++- src/libsystemd-network/sd-dhcp6-client.c | 49 +++++------ src/network/networkd-conf.c | 133 ++++++++++++++++++++++++++++++ src/network/networkd-conf.h | 32 +++++++ src/network/networkd-dhcp4.c | 8 +- src/network/networkd-dhcp6.c | 10 +++ src/network/networkd-gperf.gperf | 18 ++++ src/network/networkd-link.c | 18 ++++ src/network/networkd-manager.c | 2 + src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-network.h | 2 + src/network/networkd.c | 5 ++ src/network/networkd.h | 5 ++ src/systemd/sd-dhcp-client.h | 4 + src/systemd/sd-dhcp6-client.h | 7 +- 24 files changed, 509 insertions(+), 44 deletions(-) create mode 100644 man/networkd.conf.xml create mode 100644 src/network/networkd-conf.c create mode 100644 src/network/networkd-conf.h create mode 100644 src/network/networkd-gperf.gperf (limited to 'src/network/networkd-network-gperf.gperf') diff --git a/Makefile-man.am b/Makefile-man.am index 3f03afc2ef..a7e348b1f1 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -1960,15 +1960,21 @@ endif if ENABLE_NETWORKD MANPAGES += \ man/networkctl.1 \ + man/networkd.conf.5 \ man/systemd-networkd-wait-online.service.8 \ man/systemd-networkd.service.8 \ man/systemd.netdev.5 \ man/systemd.network.5 MANPAGES_ALIAS += \ + man/networkd.conf.d.5 \ man/systemd-networkd-wait-online.8 \ man/systemd-networkd.8 +man/networkd.conf.d.5: man/networkd.conf.5 man/systemd-networkd-wait-online.8: man/systemd-networkd-wait-online.service.8 man/systemd-networkd.8: man/systemd-networkd.service.8 +man/networkd.conf.d.html: man/networkd.conf.html + $(html-alias) + man/systemd-networkd-wait-online.html: man/systemd-networkd-wait-online.service.html $(html-alias) @@ -2479,6 +2485,7 @@ EXTRA_DIST += \ man/machinectl.xml \ man/modules-load.d.xml \ man/networkctl.xml \ + man/networkd.conf.xml \ man/nss-myhostname.xml \ man/nss-mymachines.xml \ man/nss-resolve.xml \ diff --git a/Makefile.am b/Makefile.am index 04553d81b2..5f47a81762 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5306,6 +5306,8 @@ libnetworkd_core_la_CFLAGS = \ libnetworkd_core_la_SOURCES = \ src/libsystemd-network/network-internal.h \ src/network/networkd.h \ + src/network/networkd-conf.h \ + src/network/networkd-conf.c \ src/network/networkd-link.h \ src/network/networkd-link.c \ src/network/networkd-netdev.h \ @@ -5354,6 +5356,7 @@ libnetworkd_core_la_SOURCES = \ src/network/networkd-lldp-tx.c nodist_libnetworkd_core_la_SOURCES = \ + src/network/networkd-gperf.c \ src/network/networkd-network-gperf.c \ src/network/networkd-netdev-gperf.c @@ -5450,6 +5453,7 @@ BUSNAMES_TARGET_WANTS += \ endif gperf_gperf_sources += \ + src/network/networkd-gperf.gperf \ src/network/networkd-network-gperf.gperf \ src/network/networkd-netdev-gperf.gperf diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml new file mode 100644 index 0000000000..5e2927ba54 --- /dev/null +++ b/man/networkd.conf.xml @@ -0,0 +1,112 @@ + + + + + + + + networkd.conf + systemd + + + + Developer + Vinay + Kulkarni + kulkarniv@vmware.com + + + + + + networkd.conf + 5 + + + + networkd.conf + networkd.conf.d + Global Network configuration files + + + + /etc/systemd/networkd.conf + /etc/systemd/networkd.conf.d/*.conf + /usr/lib/systemd/networkd.conf.d/*.conf + + + + Description + + These configuration files control global network parameters. + For e.g. DHCP Unique Identifier (DUID). + + + + + + + [DUID] Section Options + + This section configures the DUID value used by the DHCP protocol. The DUID value + specified here overrides the DUID that systemd-networkd generates using the machine-id + from the /etc/machine-id file. + + The configured DHCP DUID should conform to the specification in + RFC 3315, + RFC 6355. To configure IAID, see + systemd.network5 + . + + The following options are available in [DUID] section: + + + + + Type= + The type of DUID specified in this section. The following values are + supported: + raw : If Type=raw, then RawData= specifies + the entire DUID. For e.g: RawData=00:02:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00 + specifies a 14 byte long DUID-EN ("00:02"), with enterprise number 43793 ("00:00:ab:11"), + and identifier value "f9:2a:c2:77:29:f9:5c:00". + + + + RawData= + Specifies the DUID bytes as a single newline-terminated, hexadecimal + string, with each byte separated by a ':'. + + + + + + + See Also + + systemd1, + systemd.network5, + machine-id1 + + + + diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 752a15a4e0..c6bbb95833 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -204,6 +204,12 @@ understood to the base of 1024. + + IAIDValue= + + Identity Association Identifier for the interface. This is a 32-bit value specified in host byte order. + + diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index 1d9ec7be82..1bef368852 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -43,7 +43,7 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { if (r < 0) return r; - unaligned_write_be16(&duid->type, DHCP6_DUID_EN); + unaligned_write_be16(&duid->type, DHCP_DUID_TYPE_EN); unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN); *len = sizeof(duid->type) + sizeof(duid->en); diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index 93f06f5938..cb953cb416 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -25,13 +25,23 @@ #include "sparse-endian.h" #include "unaligned.h" +typedef enum DHCPDUIDType { + DHCP_DUID_TYPE_RAW = 0, + DHCP_DUID_TYPE_LLT = 1, + DHCP_DUID_TYPE_EN = 2, + DHCP_DUID_TYPE_LL = 3, + DHCP_DUID_TYPE_UUID = 4, + _DHCP_DUID_TYPE_MAX, + _DHCP_DUID_TYPE_INVALID = -1, +} DHCPDUIDType; + /* RFC 3315 section 9.1: * A DUID can be no more than 128 octets long (not including the type code). */ #define MAX_DUID_LEN 128 struct duid { - uint16_t type; + be16_t type; union { struct { /* DHCP6_DUID_LLT */ @@ -61,3 +71,32 @@ struct duid { int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len); int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id); + +static inline int dhcp_validate_duid_len(be16_t duid_type, size_t duid_len) { + struct duid d; + + assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); + + switch (be16toh(duid_type)) { + case DHCP_DUID_TYPE_LLT: + if (duid_len <= sizeof(d.llt)) + return -EINVAL; + break; + case DHCP_DUID_TYPE_EN: + if (duid_len != sizeof(d.en)) + return -EINVAL; + break; + case DHCP_DUID_TYPE_LL: + if (duid_len <= sizeof(d.ll)) + return -EINVAL; + break; + case DHCP_DUID_TYPE_UUID: + if (duid_len != sizeof(d.uuid)) + return -EINVAL; + break; + default: + /* accept unknown type in order to be forward compatible */ + break; + } + return 0; +} diff --git a/src/libsystemd-network/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h index ee4bdfb07f..2487c470ab 100644 --- a/src/libsystemd-network/dhcp6-protocol.h +++ b/src/libsystemd-network/dhcp6-protocol.h @@ -62,13 +62,6 @@ enum { #define DHCP6_REB_TIMEOUT 10 * USEC_PER_SEC #define DHCP6_REB_MAX_RT 600 * USEC_PER_SEC -enum { - DHCP6_DUID_LLT = 1, - DHCP6_DUID_EN = 2, - DHCP6_DUID_LL = 3, - DHCP6_DUID_UUID = 4, -}; - enum DHCP6State { DHCP6_STATE_STOPPED = 0, DHCP6_STATE_INFORMATION_REQUEST = 1, diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index cb7252bbeb..7c21f42591 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -335,6 +335,34 @@ int config_parse_hwaddr(const char *unit, return 0; } +int config_parse_iaid_value(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) { + uint32_t iaid_value; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if ((r = safe_atou32(rvalue, &iaid_value)) < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to read IAID: %s", rvalue); + return r; + } + + *((be32_t *)data) = htobe32(iaid_value); + + return 0; +} + void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) { unsigned i; diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index c8a531ab0f..d8b551e8ce 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -62,6 +62,10 @@ int config_parse_ifalias(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); +int config_parse_iaid_value(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); + int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result); const char *net_get_name(struct udev_device *device); diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 1188b31500..b108e35386 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -82,7 +82,7 @@ struct sd_dhcp_client { } _packed_ ll; struct { /* 255: Node-specific (RFC 4361) */ - uint32_t iaid; + be32_t iaid; struct duid duid; } _packed_ ns; struct { @@ -298,6 +298,51 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, return 0; } +int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, be32_t iaid, + size_t duid_len, struct duid *duid) { + DHCP_CLIENT_DONT_DESTROY(client); + int r; + assert_return(client, -EINVAL); + zero(client->client_id); + + client->client_id.type = 255; + + /* If IAID is not configured, generate it. */ + if (iaid == 0) { + r = dhcp_identifier_set_iaid(client->index, client->mac_addr, + client->mac_addr_len, + &client->client_id.ns.iaid); + if (r < 0) + return r; + } else + client->client_id.ns.iaid = iaid; + + /* If DUID is not configured, generate DUID-EN. */ + if (duid_len == 0) { + r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, + &duid_len); + if (r < 0) + return r; + } else { + r = dhcp_validate_duid_len(client->client_id.type, + duid_len - sizeof(client->client_id.type)); + if (r < 0) + return r; + memcpy(&client->client_id.ns.duid, duid, duid_len); + } + + client->client_id_len = sizeof(client->client_id.type) + duid_len + + sizeof(client->client_id.ns.iaid); + + if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { + log_dhcp_client(client, "Configured IAID+DUID, restarting."); + client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); + sd_dhcp_client_start(client); + } + + return 0; +} + int sd_dhcp_client_set_hostname(sd_dhcp_client *client, const char *hostname) { char *new_hostname = NULL; @@ -469,7 +514,6 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, if (client->arp_type == ARPHRD_ETHER) memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN); - /* If no client identifier exists, construct an RFC 4361-compliant one */ if (client->client_id_len == 0) { size_t duid_len; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index af4709d788..7cecba120c 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -180,41 +180,30 @@ static int client_ensure_duid(sd_dhcp6_client *client) { return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); } -int sd_dhcp6_client_set_duid( - sd_dhcp6_client *client, - uint16_t type, - uint8_t *duid, size_t duid_len) { +int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, size_t duid_len, + struct duid *duid) { + int r; assert_return(client, -EINVAL); - assert_return(duid, -EINVAL); - assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); - assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); - switch (type) { - case DHCP6_DUID_LLT: - if (duid_len <= sizeof(client->duid.llt)) - return -EINVAL; - break; - case DHCP6_DUID_EN: - if (duid_len != sizeof(client->duid.en)) - return -EINVAL; - break; - case DHCP6_DUID_LL: - if (duid_len <= sizeof(client->duid.ll)) - return -EINVAL; - break; - case DHCP6_DUID_UUID: - if (duid_len != sizeof(client->duid.uuid)) - return -EINVAL; - break; - default: - /* accept unknown type in order to be forward compatible */ - break; + if (duid_len > 0) { + r = dhcp_validate_duid_len(duid->type, + duid_len - sizeof(duid->type)); + if (r < 0) + return r; + + memcpy(&client->duid, duid, duid_len); + client->duid_len = duid_len; } - client->duid.type = htobe16(type); - memcpy(&client->duid.raw.data, duid, duid_len); - client->duid_len = duid_len + sizeof(client->duid.type); + return 0; +} + +int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, be32_t iaid) { + assert_return(client, -EINVAL); + assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); + + client->ia_na.id = iaid; return 0; } diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c new file mode 100644 index 0000000000..4bc92b8171 --- /dev/null +++ b/src/network/networkd-conf.c @@ -0,0 +1,133 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . + ***/ + +#include + +#include "conf-parser.h" +#include "def.h" +#include "dhcp-identifier.h" +#include "networkd-conf.h" +#include "string-table.h" + +int manager_parse_config_file(Manager *m) { + assert(m); + + return config_parse_many(PKGSYSCONFDIR "/networkd.conf", + CONF_PATHS_NULSTR("systemd/networkd.conf.d"), + "DUID\0", + config_item_perf_lookup, networkd_gperf_lookup, + false, m); +} + +static const char* const dhcp_duid_type_table[_DHCP_DUID_TYPE_MAX] = { + [DHCP_DUID_TYPE_RAW] = "raw", + [DHCP_DUID_TYPE_LLT] = "link-layer-time", + [DHCP_DUID_TYPE_EN] = "vendor", + [DHCP_DUID_TYPE_LL] = "link-layer", + [DHCP_DUID_TYPE_UUID] = "uuid" +}; +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_duid_type, DHCPDUIDType); +DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_duid_type, dhcp_duid_type, DHCPDUIDType, "Failed to parse DHCP DUID type"); + +int config_parse_dhcp_duid_raw( + 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) { + int r; + long byte; + char *cbyte, *pnext; + const char *pduid = (const char *)rvalue; + size_t count = 0, duid_len = 0; + Manager *m = userdata; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(m); + assert(m->dhcp_duid_type != _DHCP_DUID_TYPE_INVALID); + + switch (m->dhcp_duid_type) { + case DHCP_DUID_TYPE_LLT: + /* RawData contains DUID-LLT link-layer address (offset 6) */ + duid_len = 6; + break; + case DHCP_DUID_TYPE_EN: + /* RawData contains DUID-EN identifier (offset 4) */ + duid_len = 4; + break; + case DHCP_DUID_TYPE_LL: + /* RawData contains DUID-LL link-layer address (offset 2) */ + duid_len = 2; + break; + case DHCP_DUID_TYPE_UUID: + /* RawData specifies UUID (offset 0) - fall thru */ + case DHCP_DUID_TYPE_RAW: + /* First two bytes of RawData is DUID Type - fall thru */ + default: + break; + } + + if (m->dhcp_duid_type != DHCP_DUID_TYPE_RAW) + m->dhcp_duid.type = htobe16(m->dhcp_duid_type); + + /* RawData contains DUID in format " NN:NN:NN... " */ + while (true) { + r = extract_first_word(&pduid, &cbyte, ":", 0); + if (r < 0) { + log_error("Failed to read DUID."); + return -EINVAL; + } + if (r == 0) + break; + if (duid_len >= MAX_DUID_LEN) { + log_error("DUID length exceeds maximum length."); + return -EINVAL; + } + + errno = 0; + byte = strtol(cbyte, &pnext, 16); + if ((errno == ERANGE && (byte == LONG_MAX || byte == LONG_MIN)) + || (errno != 0 && byte == 0) || (cbyte == pnext)) { + log_error("Invalid DUID byte: %s.", cbyte); + return -EINVAL; + } + + /* If DHCP_DUID_TYPE_RAW, first two bytes holds DUID Type */ + if ((m->dhcp_duid_type == DHCP_DUID_TYPE_RAW) && (count < 2)) { + m->dhcp_duid.type |= (byte << (8 * count)); + count++; + continue; + } + + m->dhcp_duid.raw.data[duid_len++] = byte; + } + + m->dhcp_duid_len = sizeof(m->dhcp_duid.type) + duid_len; + + return 0; +} diff --git a/src/network/networkd-conf.h b/src/network/networkd-conf.h new file mode 100644 index 0000000000..6d9ce010e3 --- /dev/null +++ b/src/network/networkd-conf.h @@ -0,0 +1,32 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2014 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "networkd.h" + + +int manager_parse_config_file(Manager *m); + +const struct ConfigPerfItem* networkd_gperf_lookup(const char *key, unsigned length); + +int config_parse_dhcp_duid_type(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); +int config_parse_dhcp_duid_raw(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); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 68998eabf2..3bbb21295c 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -625,7 +625,13 @@ int dhcp4_configure(Link *link) { switch (link->network->dhcp_client_identifier) { case DHCP_CLIENT_ID_DUID: - /* Library defaults to this. */ + /* If configured, apply user specified DUID and/or IAID */ + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid_value, + link->manager->dhcp_duid_len, + &link->manager->dhcp_duid); + if (r < 0) + return r; break; case DHCP_CLIENT_ID_MAC: r = sd_dhcp_client_set_client_id(link->dhcp_client, diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 5f7a005c36..9f59cb3f8a 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -230,6 +230,16 @@ int dhcp6_configure(Link *link) { if (r < 0) goto error; + r = sd_dhcp6_client_set_iaid(client, link->network->iaid_value); + if (r < 0) + goto error; + + r = sd_dhcp6_client_set_duid(client, + link->manager->dhcp_duid_len, + &link->manager->dhcp_duid); + if (r < 0) + goto error; + r = sd_dhcp6_client_set_index(client, link->ifindex); if (r < 0) goto error; diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf new file mode 100644 index 0000000000..3ef4155476 --- /dev/null +++ b/src/network/networkd-gperf.gperf @@ -0,0 +1,18 @@ +%{ +#include +#include "conf-parser.h" +#include "networkd-conf.h" +%} +struct ConfigPerfItem; +%null_strings +%language=ANSI-C +%define slot-name section_and_lvalue +%define hash-function-name networkd_gperf_hash +%define lookup-function-name networkd_gperf_lookup +%readonly-tables +%omit-struct-type +%struct-type +%includes +%% +DUID.Type, config_parse_dhcp_duid_type, 0, offsetof(Manager, dhcp_duid_type) +DUID.RawData, config_parse_dhcp_duid_raw, 0, offsetof(Manager, dhcp_duid) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index ff4bd76554..67b04560cd 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2781,6 +2781,13 @@ int link_update(Link *link, sd_netlink_message *m) { ARPHRD_ETHER); if (r < 0) return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m"); + + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid_value, + link->manager->dhcp_duid_len, + &link->manager->dhcp_duid); + if (r < 0) + return log_link_warning_errno(link, r, "Could not update DUID/IAID in DHCP client: %m"); } if (link->dhcp6_client) { @@ -2790,6 +2797,17 @@ int link_update(Link *link, sd_netlink_message *m) { ARPHRD_ETHER); if (r < 0) return log_link_warning_errno(link, r, "Could not update MAC address in DHCPv6 client: %m"); + + r = sd_dhcp6_client_set_iaid(link->dhcp6_client, + link->network->iaid_value); + if (r < 0) + return log_link_warning_errno(link, r, "Could not update DHCPv6 IAID: %m"); + + r = sd_dhcp6_client_set_duid(link->dhcp6_client, + link->manager->dhcp_duid_len, + &link->manager->dhcp_duid); + if (r < 0) + return log_link_warning_errno(link, r, "Could not update DHCPv6 DUID: %m"); } } } diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index b8cb7f875d..8d443f7b0f 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1037,6 +1037,8 @@ int manager_new(Manager **ret) { if (r < 0) return r; + m->dhcp_duid_type = _DHCP_DUID_TYPE_INVALID; + *ret = m; m = NULL; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index a5d1714293..7a9a136d5b 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -26,6 +26,7 @@ Match.KernelCommandLine, config_parse_net_condition, Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch) Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac) Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu) +Link.IAIDValue, config_parse_iaid_value, 0, offsetof(Network, iaid_value) Network.Description, config_parse_string, 0, offsetof(Network, description) Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge) Network.Bond, config_parse_netdev, 0, offsetof(Network, bond) diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 4a13e2b574..c5530cdfba 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -30,6 +30,7 @@ typedef struct Network Network; #include "networkd-route.h" #include "networkd-util.h" #include "networkd.h" +#include "sparse-endian.h" #define DHCP_ROUTE_METRIC 1024 #define IPV4LL_ROUTE_METRIC 2048 @@ -144,6 +145,7 @@ struct Network { struct ether_addr *mac; unsigned mtu; + be32_t iaid_value; LLDPMode lldp_mode; /* LLDP reception */ bool lldp_emit; /* LLDP transmission */ diff --git a/src/network/networkd.c b/src/network/networkd.c index 3a2615e6fd..c8f81a2ca6 100644 --- a/src/network/networkd.c +++ b/src/network/networkd.c @@ -21,6 +21,7 @@ #include "capability-util.h" #include "networkd.h" +#include "networkd-conf.h" #include "signal-util.h" #include "user-util.h" @@ -89,6 +90,10 @@ int main(int argc, char *argv[]) { goto out; } + r = manager_parse_config_file(m); + if (r < 0) + log_warning_errno(r, "Failed to parse configuration file: %m"); + r = manager_load_config(m); if (r < 0) { log_error_errno(r, "Could not load configuration files: %m"); diff --git a/src/network/networkd.h b/src/network/networkd.h index 6bdd8302a0..d815f30610 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -35,6 +35,7 @@ typedef struct Manager Manager; #include "networkd-link.h" #include "networkd-network.h" #include "networkd-util.h" +#include "dhcp-identifier.h" struct Manager { sd_netlink *rtnl; @@ -61,6 +62,10 @@ struct Manager { LIST_HEAD(AddressPool, address_pools); usec_t network_dirs_ts_usec; + + DHCPDUIDType dhcp_duid_type; + size_t dhcp_duid_len; + struct duid dhcp_duid; }; extern const char* const network_dirs[]; diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index ef45370505..7873cb1e04 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -27,6 +27,7 @@ #include "sd-dhcp-lease.h" #include "sd-event.h" +#include "sparse-endian.h" #include "_sd-common.h" @@ -82,6 +83,7 @@ enum { SD_DHCP_OPTION_END = 255, }; +struct duid; typedef struct sd_dhcp_client sd_dhcp_client; typedef void (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, @@ -98,6 +100,8 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr, size_t addr_len, uint16_t arp_type); int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, const uint8_t *data, size_t data_len); +int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, be32_t iaid, + size_t duid_len, struct duid *duid); int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type, const uint8_t **data, size_t *data_len); int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu); diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 1bedc941aa..ebdd017628 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -26,6 +26,7 @@ #include "sd-dhcp6-lease.h" #include "sd-event.h" +#include "sparse-endian.h" #include "_sd-common.h" @@ -74,6 +75,7 @@ enum { /* option codes 144-65535 are unassigned */ }; +struct duid; typedef struct sd_dhcp6_client sd_dhcp6_client; typedef void (*sd_dhcp6_client_callback_t)(sd_dhcp6_client *client, int event, @@ -85,8 +87,9 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index); int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address); int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, size_t addr_len, uint16_t arp_type); -int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid, - size_t duid_len); +int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, size_t duid_len, + struct duid *duid); +int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, be32_t iaid); int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled); int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled); int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, -- cgit v1.2.3-54-g00ecf From afec45395fb019f19ac1e157fce9128b0137b25e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 21 Mar 2016 18:24:24 -0400 Subject: Revert "DHCP DUID and IAID configurability" --- Makefile-man.am | 7 -- Makefile.am | 4 - man/networkd.conf.xml | 112 ------------------------- man/systemd.network.xml | 6 -- src/libsystemd-network/dhcp-identifier.c | 2 +- src/libsystemd-network/dhcp-identifier.h | 41 +-------- src/libsystemd-network/dhcp6-protocol.h | 7 ++ src/libsystemd-network/network-internal.c | 28 ------- src/libsystemd-network/network-internal.h | 4 - src/libsystemd-network/sd-dhcp-client.c | 48 +---------- src/libsystemd-network/sd-dhcp6-client.c | 49 ++++++----- src/network/networkd-conf.c | 133 ------------------------------ src/network/networkd-conf.h | 32 ------- src/network/networkd-dhcp4.c | 8 +- src/network/networkd-dhcp6.c | 10 --- src/network/networkd-gperf.gperf | 18 ---- src/network/networkd-link.c | 18 ---- src/network/networkd-manager.c | 2 - src/network/networkd-network-gperf.gperf | 1 - src/network/networkd-network.h | 2 - src/network/networkd.c | 5 -- src/network/networkd.h | 5 -- src/systemd/sd-dhcp-client.h | 4 - src/systemd/sd-dhcp6-client.h | 7 +- 24 files changed, 44 insertions(+), 509 deletions(-) delete mode 100644 man/networkd.conf.xml delete mode 100644 src/network/networkd-conf.c delete mode 100644 src/network/networkd-conf.h delete mode 100644 src/network/networkd-gperf.gperf (limited to 'src/network/networkd-network-gperf.gperf') diff --git a/Makefile-man.am b/Makefile-man.am index a7e348b1f1..3f03afc2ef 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -1960,21 +1960,15 @@ endif if ENABLE_NETWORKD MANPAGES += \ man/networkctl.1 \ - man/networkd.conf.5 \ man/systemd-networkd-wait-online.service.8 \ man/systemd-networkd.service.8 \ man/systemd.netdev.5 \ man/systemd.network.5 MANPAGES_ALIAS += \ - man/networkd.conf.d.5 \ man/systemd-networkd-wait-online.8 \ man/systemd-networkd.8 -man/networkd.conf.d.5: man/networkd.conf.5 man/systemd-networkd-wait-online.8: man/systemd-networkd-wait-online.service.8 man/systemd-networkd.8: man/systemd-networkd.service.8 -man/networkd.conf.d.html: man/networkd.conf.html - $(html-alias) - man/systemd-networkd-wait-online.html: man/systemd-networkd-wait-online.service.html $(html-alias) @@ -2485,7 +2479,6 @@ EXTRA_DIST += \ man/machinectl.xml \ man/modules-load.d.xml \ man/networkctl.xml \ - man/networkd.conf.xml \ man/nss-myhostname.xml \ man/nss-mymachines.xml \ man/nss-resolve.xml \ diff --git a/Makefile.am b/Makefile.am index c2a82a5a35..9a7ae2c286 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5398,8 +5398,6 @@ libnetworkd_core_la_CFLAGS = \ libnetworkd_core_la_SOURCES = \ src/libsystemd-network/network-internal.h \ src/network/networkd.h \ - src/network/networkd-conf.h \ - src/network/networkd-conf.c \ src/network/networkd-link.h \ src/network/networkd-link.c \ src/network/networkd-netdev.h \ @@ -5448,7 +5446,6 @@ libnetworkd_core_la_SOURCES = \ src/network/networkd-lldp-tx.c nodist_libnetworkd_core_la_SOURCES = \ - src/network/networkd-gperf.c \ src/network/networkd-network-gperf.c \ src/network/networkd-netdev-gperf.c @@ -5545,7 +5542,6 @@ BUSNAMES_TARGET_WANTS += \ endif gperf_gperf_sources += \ - src/network/networkd-gperf.gperf \ src/network/networkd-network-gperf.gperf \ src/network/networkd-netdev-gperf.gperf diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml deleted file mode 100644 index 5e2927ba54..0000000000 --- a/man/networkd.conf.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - networkd.conf - systemd - - - - Developer - Vinay - Kulkarni - kulkarniv@vmware.com - - - - - - networkd.conf - 5 - - - - networkd.conf - networkd.conf.d - Global Network configuration files - - - - /etc/systemd/networkd.conf - /etc/systemd/networkd.conf.d/*.conf - /usr/lib/systemd/networkd.conf.d/*.conf - - - - Description - - These configuration files control global network parameters. - For e.g. DHCP Unique Identifier (DUID). - - - - - - - [DUID] Section Options - - This section configures the DUID value used by the DHCP protocol. The DUID value - specified here overrides the DUID that systemd-networkd generates using the machine-id - from the /etc/machine-id file. - - The configured DHCP DUID should conform to the specification in - RFC 3315, - RFC 6355. To configure IAID, see - systemd.network5 - . - - The following options are available in [DUID] section: - - - - - Type= - The type of DUID specified in this section. The following values are - supported: - raw : If Type=raw, then RawData= specifies - the entire DUID. For e.g: RawData=00:02:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00 - specifies a 14 byte long DUID-EN ("00:02"), with enterprise number 43793 ("00:00:ab:11"), - and identifier value "f9:2a:c2:77:29:f9:5c:00". - - - - RawData= - Specifies the DUID bytes as a single newline-terminated, hexadecimal - string, with each byte separated by a ':'. - - - - - - - See Also - - systemd1, - systemd.network5, - machine-id1 - - - - diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 73b9c00543..f2e715cf6f 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -204,12 +204,6 @@ understood to the base of 1024. - - IAIDValue= - - Identity Association Identifier for the interface. This is a 32-bit value specified in host byte order. - - diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index 1bef368852..1d9ec7be82 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -43,7 +43,7 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { if (r < 0) return r; - unaligned_write_be16(&duid->type, DHCP_DUID_TYPE_EN); + unaligned_write_be16(&duid->type, DHCP6_DUID_EN); unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN); *len = sizeof(duid->type) + sizeof(duid->en); diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index cb953cb416..93f06f5938 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -25,23 +25,13 @@ #include "sparse-endian.h" #include "unaligned.h" -typedef enum DHCPDUIDType { - DHCP_DUID_TYPE_RAW = 0, - DHCP_DUID_TYPE_LLT = 1, - DHCP_DUID_TYPE_EN = 2, - DHCP_DUID_TYPE_LL = 3, - DHCP_DUID_TYPE_UUID = 4, - _DHCP_DUID_TYPE_MAX, - _DHCP_DUID_TYPE_INVALID = -1, -} DHCPDUIDType; - /* RFC 3315 section 9.1: * A DUID can be no more than 128 octets long (not including the type code). */ #define MAX_DUID_LEN 128 struct duid { - be16_t type; + uint16_t type; union { struct { /* DHCP6_DUID_LLT */ @@ -71,32 +61,3 @@ struct duid { int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len); int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id); - -static inline int dhcp_validate_duid_len(be16_t duid_type, size_t duid_len) { - struct duid d; - - assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); - - switch (be16toh(duid_type)) { - case DHCP_DUID_TYPE_LLT: - if (duid_len <= sizeof(d.llt)) - return -EINVAL; - break; - case DHCP_DUID_TYPE_EN: - if (duid_len != sizeof(d.en)) - return -EINVAL; - break; - case DHCP_DUID_TYPE_LL: - if (duid_len <= sizeof(d.ll)) - return -EINVAL; - break; - case DHCP_DUID_TYPE_UUID: - if (duid_len != sizeof(d.uuid)) - return -EINVAL; - break; - default: - /* accept unknown type in order to be forward compatible */ - break; - } - return 0; -} diff --git a/src/libsystemd-network/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h index 2487c470ab..ee4bdfb07f 100644 --- a/src/libsystemd-network/dhcp6-protocol.h +++ b/src/libsystemd-network/dhcp6-protocol.h @@ -62,6 +62,13 @@ enum { #define DHCP6_REB_TIMEOUT 10 * USEC_PER_SEC #define DHCP6_REB_MAX_RT 600 * USEC_PER_SEC +enum { + DHCP6_DUID_LLT = 1, + DHCP6_DUID_EN = 2, + DHCP6_DUID_LL = 3, + DHCP6_DUID_UUID = 4, +}; + enum DHCP6State { DHCP6_STATE_STOPPED = 0, DHCP6_STATE_INFORMATION_REQUEST = 1, diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index 7c21f42591..cb7252bbeb 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -335,34 +335,6 @@ int config_parse_hwaddr(const char *unit, return 0; } -int config_parse_iaid_value(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) { - uint32_t iaid_value; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((r = safe_atou32(rvalue, &iaid_value)) < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to read IAID: %s", rvalue); - return r; - } - - *((be32_t *)data) = htobe32(iaid_value); - - return 0; -} - void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) { unsigned i; diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index d8b551e8ce..c8a531ab0f 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -62,10 +62,6 @@ int config_parse_ifalias(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); -int config_parse_iaid_value(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); - int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result); const char *net_get_name(struct udev_device *device); diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index b108e35386..1188b31500 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -82,7 +82,7 @@ struct sd_dhcp_client { } _packed_ ll; struct { /* 255: Node-specific (RFC 4361) */ - be32_t iaid; + uint32_t iaid; struct duid duid; } _packed_ ns; struct { @@ -298,51 +298,6 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, return 0; } -int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, be32_t iaid, - size_t duid_len, struct duid *duid) { - DHCP_CLIENT_DONT_DESTROY(client); - int r; - assert_return(client, -EINVAL); - zero(client->client_id); - - client->client_id.type = 255; - - /* If IAID is not configured, generate it. */ - if (iaid == 0) { - r = dhcp_identifier_set_iaid(client->index, client->mac_addr, - client->mac_addr_len, - &client->client_id.ns.iaid); - if (r < 0) - return r; - } else - client->client_id.ns.iaid = iaid; - - /* If DUID is not configured, generate DUID-EN. */ - if (duid_len == 0) { - r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, - &duid_len); - if (r < 0) - return r; - } else { - r = dhcp_validate_duid_len(client->client_id.type, - duid_len - sizeof(client->client_id.type)); - if (r < 0) - return r; - memcpy(&client->client_id.ns.duid, duid, duid_len); - } - - client->client_id_len = sizeof(client->client_id.type) + duid_len + - sizeof(client->client_id.ns.iaid); - - if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { - log_dhcp_client(client, "Configured IAID+DUID, restarting."); - client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); - sd_dhcp_client_start(client); - } - - return 0; -} - int sd_dhcp_client_set_hostname(sd_dhcp_client *client, const char *hostname) { char *new_hostname = NULL; @@ -514,6 +469,7 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, if (client->arp_type == ARPHRD_ETHER) memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN); + /* If no client identifier exists, construct an RFC 4361-compliant one */ if (client->client_id_len == 0) { size_t duid_len; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 7cecba120c..af4709d788 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -180,30 +180,41 @@ static int client_ensure_duid(sd_dhcp6_client *client) { return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); } -int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, size_t duid_len, - struct duid *duid) { - int r; +int sd_dhcp6_client_set_duid( + sd_dhcp6_client *client, + uint16_t type, + uint8_t *duid, size_t duid_len) { assert_return(client, -EINVAL); - assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); + assert_return(duid, -EINVAL); + assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); - if (duid_len > 0) { - r = dhcp_validate_duid_len(duid->type, - duid_len - sizeof(duid->type)); - if (r < 0) - return r; + assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); - memcpy(&client->duid, duid, duid_len); - client->duid_len = duid_len; + switch (type) { + case DHCP6_DUID_LLT: + if (duid_len <= sizeof(client->duid.llt)) + return -EINVAL; + break; + case DHCP6_DUID_EN: + if (duid_len != sizeof(client->duid.en)) + return -EINVAL; + break; + case DHCP6_DUID_LL: + if (duid_len <= sizeof(client->duid.ll)) + return -EINVAL; + break; + case DHCP6_DUID_UUID: + if (duid_len != sizeof(client->duid.uuid)) + return -EINVAL; + break; + default: + /* accept unknown type in order to be forward compatible */ + break; } - return 0; -} - -int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, be32_t iaid) { - assert_return(client, -EINVAL); - assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); - - client->ia_na.id = iaid; + client->duid.type = htobe16(type); + memcpy(&client->duid.raw.data, duid, duid_len); + client->duid_len = duid_len + sizeof(client->duid.type); return 0; } diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c deleted file mode 100644 index 4bc92b8171..0000000000 --- a/src/network/networkd-conf.c +++ /dev/null @@ -1,133 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2014 Tom Gundersen - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . - ***/ - -#include - -#include "conf-parser.h" -#include "def.h" -#include "dhcp-identifier.h" -#include "networkd-conf.h" -#include "string-table.h" - -int manager_parse_config_file(Manager *m) { - assert(m); - - return config_parse_many(PKGSYSCONFDIR "/networkd.conf", - CONF_PATHS_NULSTR("systemd/networkd.conf.d"), - "DUID\0", - config_item_perf_lookup, networkd_gperf_lookup, - false, m); -} - -static const char* const dhcp_duid_type_table[_DHCP_DUID_TYPE_MAX] = { - [DHCP_DUID_TYPE_RAW] = "raw", - [DHCP_DUID_TYPE_LLT] = "link-layer-time", - [DHCP_DUID_TYPE_EN] = "vendor", - [DHCP_DUID_TYPE_LL] = "link-layer", - [DHCP_DUID_TYPE_UUID] = "uuid" -}; -DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_duid_type, DHCPDUIDType); -DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_duid_type, dhcp_duid_type, DHCPDUIDType, "Failed to parse DHCP DUID type"); - -int config_parse_dhcp_duid_raw( - 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) { - int r; - long byte; - char *cbyte, *pnext; - const char *pduid = (const char *)rvalue; - size_t count = 0, duid_len = 0; - Manager *m = userdata; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(m); - assert(m->dhcp_duid_type != _DHCP_DUID_TYPE_INVALID); - - switch (m->dhcp_duid_type) { - case DHCP_DUID_TYPE_LLT: - /* RawData contains DUID-LLT link-layer address (offset 6) */ - duid_len = 6; - break; - case DHCP_DUID_TYPE_EN: - /* RawData contains DUID-EN identifier (offset 4) */ - duid_len = 4; - break; - case DHCP_DUID_TYPE_LL: - /* RawData contains DUID-LL link-layer address (offset 2) */ - duid_len = 2; - break; - case DHCP_DUID_TYPE_UUID: - /* RawData specifies UUID (offset 0) - fall thru */ - case DHCP_DUID_TYPE_RAW: - /* First two bytes of RawData is DUID Type - fall thru */ - default: - break; - } - - if (m->dhcp_duid_type != DHCP_DUID_TYPE_RAW) - m->dhcp_duid.type = htobe16(m->dhcp_duid_type); - - /* RawData contains DUID in format " NN:NN:NN... " */ - while (true) { - r = extract_first_word(&pduid, &cbyte, ":", 0); - if (r < 0) { - log_error("Failed to read DUID."); - return -EINVAL; - } - if (r == 0) - break; - if (duid_len >= MAX_DUID_LEN) { - log_error("DUID length exceeds maximum length."); - return -EINVAL; - } - - errno = 0; - byte = strtol(cbyte, &pnext, 16); - if ((errno == ERANGE && (byte == LONG_MAX || byte == LONG_MIN)) - || (errno != 0 && byte == 0) || (cbyte == pnext)) { - log_error("Invalid DUID byte: %s.", cbyte); - return -EINVAL; - } - - /* If DHCP_DUID_TYPE_RAW, first two bytes holds DUID Type */ - if ((m->dhcp_duid_type == DHCP_DUID_TYPE_RAW) && (count < 2)) { - m->dhcp_duid.type |= (byte << (8 * count)); - count++; - continue; - } - - m->dhcp_duid.raw.data[duid_len++] = byte; - } - - m->dhcp_duid_len = sizeof(m->dhcp_duid.type) + duid_len; - - return 0; -} diff --git a/src/network/networkd-conf.h b/src/network/networkd-conf.h deleted file mode 100644 index 6d9ce010e3..0000000000 --- a/src/network/networkd-conf.h +++ /dev/null @@ -1,32 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2014 Tom Gundersen - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "networkd.h" - - -int manager_parse_config_file(Manager *m); - -const struct ConfigPerfItem* networkd_gperf_lookup(const char *key, unsigned length); - -int config_parse_dhcp_duid_type(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); -int config_parse_dhcp_duid_raw(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); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 3bbb21295c..68998eabf2 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -625,13 +625,7 @@ int dhcp4_configure(Link *link) { switch (link->network->dhcp_client_identifier) { case DHCP_CLIENT_ID_DUID: - /* If configured, apply user specified DUID and/or IAID */ - r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, - link->network->iaid_value, - link->manager->dhcp_duid_len, - &link->manager->dhcp_duid); - if (r < 0) - return r; + /* Library defaults to this. */ break; case DHCP_CLIENT_ID_MAC: r = sd_dhcp_client_set_client_id(link->dhcp_client, diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 9f59cb3f8a..5f7a005c36 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -230,16 +230,6 @@ int dhcp6_configure(Link *link) { if (r < 0) goto error; - r = sd_dhcp6_client_set_iaid(client, link->network->iaid_value); - if (r < 0) - goto error; - - r = sd_dhcp6_client_set_duid(client, - link->manager->dhcp_duid_len, - &link->manager->dhcp_duid); - if (r < 0) - goto error; - r = sd_dhcp6_client_set_index(client, link->ifindex); if (r < 0) goto error; diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf deleted file mode 100644 index 3ef4155476..0000000000 --- a/src/network/networkd-gperf.gperf +++ /dev/null @@ -1,18 +0,0 @@ -%{ -#include -#include "conf-parser.h" -#include "networkd-conf.h" -%} -struct ConfigPerfItem; -%null_strings -%language=ANSI-C -%define slot-name section_and_lvalue -%define hash-function-name networkd_gperf_hash -%define lookup-function-name networkd_gperf_lookup -%readonly-tables -%omit-struct-type -%struct-type -%includes -%% -DUID.Type, config_parse_dhcp_duid_type, 0, offsetof(Manager, dhcp_duid_type) -DUID.RawData, config_parse_dhcp_duid_raw, 0, offsetof(Manager, dhcp_duid) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 67b04560cd..ff4bd76554 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2781,13 +2781,6 @@ int link_update(Link *link, sd_netlink_message *m) { ARPHRD_ETHER); if (r < 0) return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m"); - - r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, - link->network->iaid_value, - link->manager->dhcp_duid_len, - &link->manager->dhcp_duid); - if (r < 0) - return log_link_warning_errno(link, r, "Could not update DUID/IAID in DHCP client: %m"); } if (link->dhcp6_client) { @@ -2797,17 +2790,6 @@ int link_update(Link *link, sd_netlink_message *m) { ARPHRD_ETHER); if (r < 0) return log_link_warning_errno(link, r, "Could not update MAC address in DHCPv6 client: %m"); - - r = sd_dhcp6_client_set_iaid(link->dhcp6_client, - link->network->iaid_value); - if (r < 0) - return log_link_warning_errno(link, r, "Could not update DHCPv6 IAID: %m"); - - r = sd_dhcp6_client_set_duid(link->dhcp6_client, - link->manager->dhcp_duid_len, - &link->manager->dhcp_duid); - if (r < 0) - return log_link_warning_errno(link, r, "Could not update DHCPv6 DUID: %m"); } } } diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 8d443f7b0f..b8cb7f875d 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1037,8 +1037,6 @@ int manager_new(Manager **ret) { if (r < 0) return r; - m->dhcp_duid_type = _DHCP_DUID_TYPE_INVALID; - *ret = m; m = NULL; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 7a9a136d5b..a5d1714293 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -26,7 +26,6 @@ Match.KernelCommandLine, config_parse_net_condition, Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch) Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac) Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu) -Link.IAIDValue, config_parse_iaid_value, 0, offsetof(Network, iaid_value) Network.Description, config_parse_string, 0, offsetof(Network, description) Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge) Network.Bond, config_parse_netdev, 0, offsetof(Network, bond) diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index c5530cdfba..4a13e2b574 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -30,7 +30,6 @@ typedef struct Network Network; #include "networkd-route.h" #include "networkd-util.h" #include "networkd.h" -#include "sparse-endian.h" #define DHCP_ROUTE_METRIC 1024 #define IPV4LL_ROUTE_METRIC 2048 @@ -145,7 +144,6 @@ struct Network { struct ether_addr *mac; unsigned mtu; - be32_t iaid_value; LLDPMode lldp_mode; /* LLDP reception */ bool lldp_emit; /* LLDP transmission */ diff --git a/src/network/networkd.c b/src/network/networkd.c index c8f81a2ca6..3a2615e6fd 100644 --- a/src/network/networkd.c +++ b/src/network/networkd.c @@ -21,7 +21,6 @@ #include "capability-util.h" #include "networkd.h" -#include "networkd-conf.h" #include "signal-util.h" #include "user-util.h" @@ -90,10 +89,6 @@ int main(int argc, char *argv[]) { goto out; } - r = manager_parse_config_file(m); - if (r < 0) - log_warning_errno(r, "Failed to parse configuration file: %m"); - r = manager_load_config(m); if (r < 0) { log_error_errno(r, "Could not load configuration files: %m"); diff --git a/src/network/networkd.h b/src/network/networkd.h index d815f30610..6bdd8302a0 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -35,7 +35,6 @@ typedef struct Manager Manager; #include "networkd-link.h" #include "networkd-network.h" #include "networkd-util.h" -#include "dhcp-identifier.h" struct Manager { sd_netlink *rtnl; @@ -62,10 +61,6 @@ struct Manager { LIST_HEAD(AddressPool, address_pools); usec_t network_dirs_ts_usec; - - DHCPDUIDType dhcp_duid_type; - size_t dhcp_duid_len; - struct duid dhcp_duid; }; extern const char* const network_dirs[]; diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index 7873cb1e04..ef45370505 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -27,7 +27,6 @@ #include "sd-dhcp-lease.h" #include "sd-event.h" -#include "sparse-endian.h" #include "_sd-common.h" @@ -83,7 +82,6 @@ enum { SD_DHCP_OPTION_END = 255, }; -struct duid; typedef struct sd_dhcp_client sd_dhcp_client; typedef void (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, @@ -100,8 +98,6 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr, size_t addr_len, uint16_t arp_type); int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, const uint8_t *data, size_t data_len); -int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, be32_t iaid, - size_t duid_len, struct duid *duid); int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type, const uint8_t **data, size_t *data_len); int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu); diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index ebdd017628..1bedc941aa 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -26,7 +26,6 @@ #include "sd-dhcp6-lease.h" #include "sd-event.h" -#include "sparse-endian.h" #include "_sd-common.h" @@ -75,7 +74,6 @@ enum { /* option codes 144-65535 are unassigned */ }; -struct duid; typedef struct sd_dhcp6_client sd_dhcp6_client; typedef void (*sd_dhcp6_client_callback_t)(sd_dhcp6_client *client, int event, @@ -87,9 +85,8 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index); int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address); int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, size_t addr_len, uint16_t arp_type); -int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, size_t duid_len, - struct duid *duid); -int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, be32_t iaid); +int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid, + size_t duid_len); int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled); int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled); int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, -- cgit v1.2.3-54-g00ecf From 413708d106afb5ec36464c3fad56f081373320e0 Mon Sep 17 00:00:00 2001 From: Vinay Kulkarni Date: Wed, 30 Mar 2016 16:33:55 -0700 Subject: DHCP DUID, IAID configuration options --- Makefile-man.am | 7 ++ Makefile.am | 4 + man/networkd.conf.xml | 159 ++++++++++++++++++++++++++++++ man/systemd.network.xml | 86 ++++++++++++++++ src/libsystemd-network/dhcp-identifier.c | 2 +- src/libsystemd-network/dhcp-identifier.h | 41 +++++++- src/libsystemd-network/dhcp6-protocol.h | 7 -- src/libsystemd-network/network-internal.c | 29 ++++++ src/libsystemd-network/network-internal.h | 4 + src/libsystemd-network/sd-dhcp-client.c | 48 ++++++++- src/libsystemd-network/sd-dhcp6-client.c | 48 ++++----- src/network/networkd-conf.c | 155 +++++++++++++++++++++++++++++ src/network/networkd-conf.h | 36 +++++++ src/network/networkd-dhcp4.c | 16 ++- src/network/networkd-dhcp6.c | 17 ++++ src/network/networkd-gperf.gperf | 18 ++++ src/network/networkd-link.c | 33 +++++++ src/network/networkd-manager.c | 2 + src/network/networkd-network-gperf.gperf | 4 + src/network/networkd-network.c | 2 + src/network/networkd-network.h | 8 ++ src/network/networkd.c | 5 + src/network/networkd.h | 8 ++ src/systemd/sd-dhcp-client.h | 2 + src/systemd/sd-dhcp6-client.h | 5 +- 25 files changed, 703 insertions(+), 43 deletions(-) create mode 100644 man/networkd.conf.xml create mode 100644 src/network/networkd-conf.c create mode 100644 src/network/networkd-conf.h create mode 100644 src/network/networkd-gperf.gperf (limited to 'src/network/networkd-network-gperf.gperf') diff --git a/Makefile-man.am b/Makefile-man.am index 3f03afc2ef..a7e348b1f1 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -1960,15 +1960,21 @@ endif if ENABLE_NETWORKD MANPAGES += \ man/networkctl.1 \ + man/networkd.conf.5 \ man/systemd-networkd-wait-online.service.8 \ man/systemd-networkd.service.8 \ man/systemd.netdev.5 \ man/systemd.network.5 MANPAGES_ALIAS += \ + man/networkd.conf.d.5 \ man/systemd-networkd-wait-online.8 \ man/systemd-networkd.8 +man/networkd.conf.d.5: man/networkd.conf.5 man/systemd-networkd-wait-online.8: man/systemd-networkd-wait-online.service.8 man/systemd-networkd.8: man/systemd-networkd.service.8 +man/networkd.conf.d.html: man/networkd.conf.html + $(html-alias) + man/systemd-networkd-wait-online.html: man/systemd-networkd-wait-online.service.html $(html-alias) @@ -2479,6 +2485,7 @@ EXTRA_DIST += \ man/machinectl.xml \ man/modules-load.d.xml \ man/networkctl.xml \ + man/networkd.conf.xml \ man/nss-myhostname.xml \ man/nss-mymachines.xml \ man/nss-resolve.xml \ diff --git a/Makefile.am b/Makefile.am index 2b72a53ecd..350416af30 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5398,6 +5398,8 @@ libnetworkd_core_la_CFLAGS = \ libnetworkd_core_la_SOURCES = \ src/libsystemd-network/network-internal.h \ src/network/networkd.h \ + src/network/networkd-conf.h \ + src/network/networkd-conf.c \ src/network/networkd-link.h \ src/network/networkd-link.c \ src/network/networkd-netdev.h \ @@ -5446,6 +5448,7 @@ libnetworkd_core_la_SOURCES = \ src/network/networkd-lldp-tx.c nodist_libnetworkd_core_la_SOURCES = \ + src/network/networkd-gperf.c \ src/network/networkd-network-gperf.c \ src/network/networkd-netdev-gperf.c @@ -5542,6 +5545,7 @@ BUSNAMES_TARGET_WANTS += \ endif gperf_gperf_sources += \ + src/network/networkd-gperf.gperf \ src/network/networkd-network-gperf.gperf \ src/network/networkd-netdev-gperf.gperf diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml new file mode 100644 index 0000000000..30674e12bc --- /dev/null +++ b/man/networkd.conf.xml @@ -0,0 +1,159 @@ + + + + + + + + networkd.conf + systemd + + + + Developer + Vinay + Kulkarni + kulkarniv@vmware.com + + + + + + networkd.conf + 5 + + + + networkd.conf + networkd.conf.d + Global Network configuration files + + + + /etc/systemd/networkd.conf + /etc/systemd/networkd.conf.d/*.conf + /usr/lib/systemd/networkd.conf.d/*.conf + + + + Description + + These configuration files control global network parameters. + For e.g. DHCP Unique Identifier (DUID). + + + + + + + [DUID] Section Options + + This section configures the DHCP Unique Idendifier (DUID) value used by DHCP + protocol. DHCPv6 client protocol sends the DHCP Unique Identifier and the interface + Identity Association Identifier (IAID) to a DHCP server when acquiring a dynamic IPv6 + address. DHCPv4 client protocol sends IAID and DUID to the DHCP server when acquiring + a dynamic IPv4 address if . IAID and DUID allows + a DHCP server to uniquely identify the machine and the interface requesting a DHCP IP. + To configure IAID and ClientIdentifier, see systemd.network + 5. + + The DUID value specified here overrides the DUID that systemd-networkd + generates using the machine-id from the /etc/machine-id file. + To configure DUID per-network, see systemd.network + 5. + + The configured DHCP DUID should conform to the specification in + RFC 3315, + RFC 6355. To configure IAID, see + systemd.network5 + . + + The following options are available in [DUID] section: + + + + + Type= + The type of DUID specified in this section. The following values are + supported: + raw : If Type=raw, then RawData= specifies + the entire DUID. For e.g: RawData=00:02:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00 + specifies a 14 byte long DUID-EN ("00:02"), with enterprise number 43793 ("00:00:ab:11"), + and identifier value "f9:2a:c2:77:29:f9:5c:00".If Type is not specified and + RawData is specified, Type defaults to 'raw'. + Type will support the following values in the future: + link-layer-and-time : If Type=link-layer-and-time, then + MACAddress= and TimeStamp= specify the hardware + address and time-stamp for DUID-LLT. + vendor : If Type=vendor, then EnterpriseNumber= + and RawData= specify the enterprise number and identifier for DUID-EN. + link-layer : If Type=link-layer, then MACAddress= + specifies the hardware address for DUID-LL. + uuid : If Type=uuid, then UUID= specifies DUID-UUID. + + + + + RawData= + Specifies the DUID bytes as a single newline-terminated, hexadecimal + string, with each byte separated by a ':'. + + + + + + The following options will be supported in the future: + + + + MACAddress= + Specifies the link-layer address for DUID Type or . + + + TimeStamp= + Specifies the DUID generation time for DUID Type . + + + EnterpriseNumber= + Specifies the enterprise number for DUID Type + . + + + UUID= + Specifies the UUID for DUID Type . + + + + + + + See Also + + systemd1, + systemd.network5, + machine-id1 + + + + diff --git a/man/systemd.network.xml b/man/systemd.network.xml index f2e715cf6f..8611c0032d 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -204,6 +204,12 @@ understood to the base of 1024. + + IAIDValue= + + Identity Association Identifier for the interface, a 32-bit unsigned integer. + + @@ -823,6 +829,86 @@ + + [DUID] Section Options + + This section configures the DHCP Unique Idendifier (DUID) value used by DHCP + protocol. DHCPv6 client protocol sends the DHCP Unique Identifier and the interface + Identity Association Identifier (IAID) to a DHCP server when acquiring a dynamic IPv6 + address. DHCPv4 client protocol sends IAID and DUID to the DHCP server when acquiring + a dynamic IPv4 address if . IAID and DUID allows a + DHCP server to uniquely identify the machine and the interface requesting a DHCP IP. + + The DUID value specified here overrides the DUID that systemd-networkd generates + using the machine-id from the /etc/machine-id file, as well as the + global DUID that may be specified in networkd.conf + 5. + + The configured DHCP DUID should conform to the specification in + RFC 3315, + RFC 6355. + + The following options are available in [DUID] section: + + + + + Type= + The type of DUID specified in this section. The following values are + supported: + raw : If Type=raw, then RawData= specifies + the entire DUID. For e.g: RawData=00:02:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00 + specifies a 14 byte long DUID-EN ("00:02"), with enterprise number 43793 ("00:00:ab:11"), + and identifier value "f9:2a:c2:77:29:f9:5c:00".If Type is not specified and + RawData is specified, Type defaults to 'raw'. + Type will support the following values in the future: + link-layer-and-time : If Type=link-layer-and-time, then + MACAddress= and TimeStamp= specify the hardware + address and time-stamp for DUID-LLT. + vendor : If Type=vendor, then EnterpriseNumber= + and RawData= specify the enterprise number and identifier for DUID-EN. + link-layer : If Type=link-layer, then MACAddress= + specifies the hardware address for DUID-LL. + uuid : If Type=uuid, then UUID= specifies DUID-UUID. + + + + + RawData= + Specifies the DUID bytes as a single newline-terminated, hexadecimal + string, with each byte separated by a ':'. + + + + + + + The following options will be supported in the future: + + + + MACAddress= + Specifies the link-layer address for DUID Type or . + + + TimeStamp= + Specifies the DUID generation time for DUID Type . + + + EnterpriseNumber= + Specifies the enterprise number for DUID Type . + + + UUID= + Specifies the UUID for DUID Type . + + + + + [DHCPServer] Section Options The [DHCPServer] section contains diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index 1d9ec7be82..4f7d4d8bf2 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -43,7 +43,7 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { if (r < 0) return r; - unaligned_write_be16(&duid->type, DHCP6_DUID_EN); + unaligned_write_be16(&duid->type, DUID_TYPE_EN); unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN); *len = sizeof(duid->type) + sizeof(duid->en); diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index 93f06f5938..babae15c5b 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -25,13 +25,23 @@ #include "sparse-endian.h" #include "unaligned.h" +typedef enum DUIDType { + DUID_TYPE_RAW = 0, + DUID_TYPE_LLT = 1, + DUID_TYPE_EN = 2, + DUID_TYPE_LL = 3, + DUID_TYPE_UUID = 4, + _DUID_TYPE_MAX, + _DUID_TYPE_INVALID = -1, +} DUIDType; + /* RFC 3315 section 9.1: * A DUID can be no more than 128 octets long (not including the type code). */ #define MAX_DUID_LEN 128 struct duid { - uint16_t type; + be16_t type; union { struct { /* DHCP6_DUID_LLT */ @@ -61,3 +71,32 @@ struct duid { int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len); int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id); + +static inline int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) { + struct duid d; + + assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); + + switch (duid_type) { + case DUID_TYPE_LLT: + if (duid_len <= sizeof(d.llt)) + return -EINVAL; + break; + case DUID_TYPE_EN: + if (duid_len != sizeof(d.en)) + return -EINVAL; + break; + case DUID_TYPE_LL: + if (duid_len <= sizeof(d.ll)) + return -EINVAL; + break; + case DUID_TYPE_UUID: + if (duid_len != sizeof(d.uuid)) + return -EINVAL; + break; + default: + /* accept unknown type in order to be forward compatible */ + break; + } + return 0; +} diff --git a/src/libsystemd-network/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h index ee4bdfb07f..2487c470ab 100644 --- a/src/libsystemd-network/dhcp6-protocol.h +++ b/src/libsystemd-network/dhcp6-protocol.h @@ -62,13 +62,6 @@ enum { #define DHCP6_REB_TIMEOUT 10 * USEC_PER_SEC #define DHCP6_REB_MAX_RT 600 * USEC_PER_SEC -enum { - DHCP6_DUID_LLT = 1, - DHCP6_DUID_EN = 2, - DHCP6_DUID_LL = 3, - DHCP6_DUID_UUID = 4, -}; - enum DHCP6State { DHCP6_STATE_STOPPED = 0, DHCP6_STATE_INFORMATION_REQUEST = 1, diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index cb7252bbeb..0e2d757b2b 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -335,6 +335,35 @@ int config_parse_hwaddr(const char *unit, return 0; } +int config_parse_iaid(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) { + uint32_t iaid; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = safe_atou32(rvalue, &iaid); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to read IAID: %s", rvalue); + return r; + } + + *((uint32_t *)data) = iaid; + + return 0; +} + void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) { unsigned i; diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index c8a531ab0f..72432774d7 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -62,6 +62,10 @@ int config_parse_ifalias(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); +int config_parse_iaid(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); + int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result); const char *net_get_name(struct udev_device *device); diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 1188b31500..287b6e26fa 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -82,7 +82,7 @@ struct sd_dhcp_client { } _packed_ ll; struct { /* 255: Node-specific (RFC 4361) */ - uint32_t iaid; + be32_t iaid; struct duid duid; } _packed_ ns; struct { @@ -298,6 +298,52 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, return 0; } +int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, uint32_t iaid, + uint16_t duid_type, uint8_t *duid, size_t duid_len) { + DHCP_CLIENT_DONT_DESTROY(client); + int r; + assert_return(client, -EINVAL); + zero(client->client_id); + + client->client_id.type = 255; + + /* If IAID is not configured, generate it. */ + if (iaid == 0) { + r = dhcp_identifier_set_iaid(client->index, client->mac_addr, + client->mac_addr_len, + &client->client_id.ns.iaid); + if (r < 0) + return r; + } else + client->client_id.ns.iaid = htobe32(iaid); + + /* If DUID is not configured, generate DUID-EN. */ + if (duid_len == 0) { + r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, + &duid_len); + if (r < 0) + return r; + } else { + r = dhcp_validate_duid_len(client->client_id.type, duid_len); + if (r < 0) + return r; + client->client_id.ns.duid.type = htobe16(duid_type); + memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len); + duid_len += sizeof(client->client_id.ns.duid.type); + } + + client->client_id_len = sizeof(client->client_id.type) + duid_len + + sizeof(client->client_id.ns.iaid); + + if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { + log_dhcp_client(client, "Configured IAID+DUID, restarting."); + client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); + sd_dhcp_client_start(client); + } + + return 0; +} + int sd_dhcp_client_set_hostname(sd_dhcp_client *client, const char *hostname) { char *new_hostname = NULL; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index af4709d788..ee4fb4fc1e 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -180,41 +180,29 @@ static int client_ensure_duid(sd_dhcp6_client *client) { return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); } -int sd_dhcp6_client_set_duid( - sd_dhcp6_client *client, - uint16_t type, - uint8_t *duid, size_t duid_len) { +int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t duid_type, + uint8_t *duid, size_t duid_len) { + int r; assert_return(client, -EINVAL); - assert_return(duid, -EINVAL); - assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); - assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); - switch (type) { - case DHCP6_DUID_LLT: - if (duid_len <= sizeof(client->duid.llt)) - return -EINVAL; - break; - case DHCP6_DUID_EN: - if (duid_len != sizeof(client->duid.en)) - return -EINVAL; - break; - case DHCP6_DUID_LL: - if (duid_len <= sizeof(client->duid.ll)) - return -EINVAL; - break; - case DHCP6_DUID_UUID: - if (duid_len != sizeof(client->duid.uuid)) - return -EINVAL; - break; - default: - /* accept unknown type in order to be forward compatible */ - break; + if (duid_len > 0) { + r = dhcp_validate_duid_len(duid_type, duid_len); + if (r < 0) + return r; + client->duid.type = htobe16(duid_type); + memcpy(&client->duid.raw.data, duid, duid_len); + client->duid_len = duid_len + sizeof(client->duid.type); } - client->duid.type = htobe16(type); - memcpy(&client->duid.raw.data, duid, duid_len); - client->duid_len = duid_len + sizeof(client->duid.type); + return 0; +} + +int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid) { + assert_return(client, -EINVAL); + assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); + + client->ia_na.id = htobe32(iaid); return 0; } diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c new file mode 100644 index 0000000000..8b149124b3 --- /dev/null +++ b/src/network/networkd-conf.c @@ -0,0 +1,155 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Vinay Kulkarni + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . + ***/ + +#include + +#include "conf-parser.h" +#include "def.h" +#include "dhcp-identifier.h" +#include "networkd-conf.h" +#include "string-table.h" + +int manager_parse_config_file(Manager *m) { + assert(m); + + return config_parse_many(PKGSYSCONFDIR "/networkd.conf", + CONF_PATHS_NULSTR("systemd/networkd.conf.d"), + "DUID\0", + config_item_perf_lookup, networkd_gperf_lookup, + false, m); +} + +static const char* const duid_type_table[_DUID_TYPE_MAX] = { + [DUID_TYPE_RAW] = "raw", + [DUID_TYPE_LLT] = "link-layer-time", + [DUID_TYPE_EN] = "vendor", + [DUID_TYPE_LL] = "link-layer", + [DUID_TYPE_UUID] = "uuid" +}; +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(duid_type, DUIDType); +DEFINE_CONFIG_PARSE_ENUM(config_parse_duid_type, duid_type, DUIDType, "Failed to parse DUID type"); + +int config_parse_duid_rawdata( + 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) { + int r; + long byte; + char *cbyte, *pnext; + const char *pduid = rvalue; + size_t count = 0, duid_index = 0; + Manager *m; + Network *n; + DUIDType *duid_type; + uint16_t *dhcp_duid_type; + size_t *dhcp_duid_len; + uint8_t *dhcp_duid; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(userdata); + + if (ltype == DUID_CONFIG_SOURCE_GLOBAL) { + m = userdata; + duid_type = &m->duid_type; + dhcp_duid_type = &m->dhcp_duid_type; + dhcp_duid_len = &m->dhcp_duid_len; + dhcp_duid = m->dhcp_duid; + } else { + /* DUID_CONFIG_SOURCE_NETWORK */ + n = userdata; + duid_type = &n->duid_type; + dhcp_duid_type = &n->dhcp_duid_type; + dhcp_duid_len = &n->dhcp_duid_len; + dhcp_duid = n->dhcp_duid; + } + + if (*duid_type == _DUID_TYPE_INVALID) + *duid_type = DUID_TYPE_RAW; + + switch (*duid_type) { + case DUID_TYPE_LLT: + /* RawData contains DUID-LLT link-layer address (offset 6) */ + duid_index = 6; + break; + case DUID_TYPE_EN: + /* RawData contains DUID-EN identifier (offset 4) */ + duid_index = 4; + break; + case DUID_TYPE_LL: + /* RawData contains DUID-LL link-layer address (offset 2) */ + duid_index = 2; + break; + case DUID_TYPE_UUID: + /* RawData specifies UUID (offset 0) - fall thru */ + case DUID_TYPE_RAW: + /* First two bytes of RawData is DUID Type - fall thru */ + default: + break; + } + + if (*duid_type != DUID_TYPE_RAW) + *dhcp_duid_type = (uint16_t)(*duid_type); + + /* RawData contains DUID in format " NN:NN:NN... " */ + while (true) { + r = extract_first_word(&pduid, &cbyte, ":", 0); + if (r < 0) { + log_error("Failed to read DUID."); + return -EINVAL; + } + if (r == 0) + break; + if (duid_index >= MAX_DUID_LEN) { + log_error("DUID length exceeds maximum length."); + return -EINVAL; + } + + errno = 0; + byte = strtol(cbyte, &pnext, 16); + if ((errno == ERANGE && (byte == LONG_MAX || byte == LONG_MIN)) + || (errno != 0 && byte == 0) || (cbyte == pnext)) { + log_error("Invalid DUID byte: %s.", cbyte); + return -EINVAL; + } + + /* If DUID_TYPE_RAW, first two bytes hold DHCP DUID type code */ + if ((*duid_type == DUID_TYPE_RAW) && (count < 2)) { + *dhcp_duid_type |= (byte << (8 * (1 - count))); + count++; + continue; + } + + dhcp_duid[duid_index++] = byte; + } + + *dhcp_duid_len = duid_index; + + return 0; +} diff --git a/src/network/networkd-conf.h b/src/network/networkd-conf.h new file mode 100644 index 0000000000..efc370f839 --- /dev/null +++ b/src/network/networkd-conf.h @@ -0,0 +1,36 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2014 Vinay Kulkarni + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "networkd.h" + +typedef enum DuidConfigSource { + DUID_CONFIG_SOURCE_GLOBAL = 0, + DUID_CONFIG_SOURCE_NETWORK, +} DuidConfigSource; + +int manager_parse_config_file(Manager *m); + +const struct ConfigPerfItem* networkd_gperf_lookup(const char *key, unsigned length); + +int config_parse_duid_type(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); +int config_parse_duid_rawdata(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); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 68998eabf2..0589ebf227 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -625,7 +625,21 @@ int dhcp4_configure(Link *link) { switch (link->network->dhcp_client_identifier) { case DHCP_CLIENT_ID_DUID: - /* Library defaults to this. */ + /* If configured, apply user specified DUID and/or IAID */ + if (link->network->duid_type != _DUID_TYPE_INVALID) + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid, + link->network->dhcp_duid_type, + link->network->dhcp_duid, + link->network->dhcp_duid_len); + else + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid, + link->manager->dhcp_duid_type, + link->manager->dhcp_duid, + link->manager->dhcp_duid_len); + if (r < 0) + return r; break; case DHCP_CLIENT_ID_MAC: r = sd_dhcp_client_set_client_id(link->dhcp_client, diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 5f7a005c36..d4b2fbfc57 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -230,6 +230,23 @@ int dhcp6_configure(Link *link) { if (r < 0) goto error; + r = sd_dhcp6_client_set_iaid(client, link->network->iaid); + if (r < 0) + goto error; + + if (link->network->duid_type != _DUID_TYPE_INVALID) + r = sd_dhcp6_client_set_duid(client, + link->network->dhcp_duid_type, + link->network->dhcp_duid, + link->network->dhcp_duid_len); + else + r = sd_dhcp6_client_set_duid(client, + link->manager->dhcp_duid_type, + link->manager->dhcp_duid, + link->manager->dhcp_duid_len); + if (r < 0) + goto error; + r = sd_dhcp6_client_set_index(client, link->ifindex); if (r < 0) goto error; diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf new file mode 100644 index 0000000000..0625fb335b --- /dev/null +++ b/src/network/networkd-gperf.gperf @@ -0,0 +1,18 @@ +%{ +#include +#include "conf-parser.h" +#include "networkd-conf.h" +%} +struct ConfigPerfItem; +%null_strings +%language=ANSI-C +%define slot-name section_and_lvalue +%define hash-function-name networkd_gperf_hash +%define lookup-function-name networkd_gperf_lookup +%readonly-tables +%omit-struct-type +%struct-type +%includes +%% +DUID.Type, config_parse_duid_type, 0, offsetof(Manager, duid_type) +DUID.RawData, config_parse_duid_rawdata, DUID_CONFIG_SOURCE_GLOBAL, offsetof(Manager, dhcp_duid) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index ff4bd76554..eac8123311 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2781,6 +2781,21 @@ int link_update(Link *link, sd_netlink_message *m) { ARPHRD_ETHER); if (r < 0) return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m"); + + if (link->network->duid_type != _DUID_TYPE_INVALID) + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid, + link->network->dhcp_duid_type, + link->network->dhcp_duid, + link->network->dhcp_duid_len); + else + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid, + link->manager->dhcp_duid_type, + link->manager->dhcp_duid, + link->manager->dhcp_duid_len); + if (r < 0) + return log_link_warning_errno(link, r, "Could not update DUID/IAID in DHCP client: %m"); } if (link->dhcp6_client) { @@ -2790,6 +2805,24 @@ int link_update(Link *link, sd_netlink_message *m) { ARPHRD_ETHER); if (r < 0) return log_link_warning_errno(link, r, "Could not update MAC address in DHCPv6 client: %m"); + + r = sd_dhcp6_client_set_iaid(link->dhcp6_client, + link->network->iaid); + if (r < 0) + return log_link_warning_errno(link, r, "Could not update DHCPv6 IAID: %m"); + + if (link->network->duid_type != _DUID_TYPE_INVALID) + r = sd_dhcp6_client_set_duid(link->dhcp6_client, + link->network->dhcp_duid_type, + link->network->dhcp_duid, + link->network->dhcp_duid_len); + else + r = sd_dhcp6_client_set_duid(link->dhcp6_client, + link->manager->dhcp_duid_type, + link->manager->dhcp_duid, + link->manager->dhcp_duid_len); + if (r < 0) + return log_link_warning_errno(link, r, "Could not update DHCPv6 DUID: %m"); } } } diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index b8cb7f875d..d355aaa19c 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1037,6 +1037,8 @@ int manager_new(Manager **ret) { if (r < 0) return r; + m->duid_type = _DUID_TYPE_INVALID; + *ret = m; m = NULL; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index a5d1714293..9793938080 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -2,6 +2,7 @@ #include #include "conf-parser.h" #include "networkd.h" +#include "networkd-conf.h" #include "network-internal.h" %} struct ConfigPerfItem; @@ -26,6 +27,9 @@ Match.KernelCommandLine, config_parse_net_condition, Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch) Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac) Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu) +Link.IAID, config_parse_iaid, 0, offsetof(Network, iaid) +DUID.Type, config_parse_duid_type, 0, offsetof(Network, duid_type) +DUID.RawData, config_parse_duid_rawdata, DUID_CONFIG_SOURCE_NETWORK, offsetof(Network, dhcp_duid) Network.Description, config_parse_string, 0, offsetof(Network, description) Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge) Network.Bond, config_parse_netdev, 0, offsetof(Network, bond) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 491b9a3efa..5946ba18dc 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -131,10 +131,12 @@ static int network_load_one(Manager *manager, const char *filename) { network->ipv6_accept_ra = -1; network->ipv6_dad_transmits = -1; network->ipv6_hop_limit = -1; + network->duid_type = _DUID_TYPE_INVALID; r = config_parse(NULL, filename, file, "Match\0" "Link\0" + "DUID\0" "Network\0" "Address\0" "Route\0" diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 4a13e2b574..5400a8bc9d 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -24,6 +24,7 @@ typedef struct Network Network; +#include "dhcp-identifier.h" #include "networkd-address.h" #include "networkd-fdb.h" #include "networkd-netdev.h" @@ -144,6 +145,13 @@ struct Network { struct ether_addr *mac; unsigned mtu; + uint32_t iaid; + /* Value of Type in [DUID] section */ + DUIDType duid_type; + /* DUID type code - RFC 3315 */ + uint16_t dhcp_duid_type; + size_t dhcp_duid_len; + uint8_t dhcp_duid[MAX_DUID_LEN]; LLDPMode lldp_mode; /* LLDP reception */ bool lldp_emit; /* LLDP transmission */ diff --git a/src/network/networkd.c b/src/network/networkd.c index 3a2615e6fd..c8f81a2ca6 100644 --- a/src/network/networkd.c +++ b/src/network/networkd.c @@ -21,6 +21,7 @@ #include "capability-util.h" #include "networkd.h" +#include "networkd-conf.h" #include "signal-util.h" #include "user-util.h" @@ -89,6 +90,10 @@ int main(int argc, char *argv[]) { goto out; } + r = manager_parse_config_file(m); + if (r < 0) + log_warning_errno(r, "Failed to parse configuration file: %m"); + r = manager_load_config(m); if (r < 0) { log_error_errno(r, "Could not load configuration files: %m"); diff --git a/src/network/networkd.h b/src/network/networkd.h index 6bdd8302a0..72a2438ac8 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -31,6 +31,7 @@ typedef struct Manager Manager; +#include "dhcp-identifier.h" #include "networkd-address-pool.h" #include "networkd-link.h" #include "networkd-network.h" @@ -61,6 +62,13 @@ struct Manager { LIST_HEAD(AddressPool, address_pools); usec_t network_dirs_ts_usec; + + /* Value of Type in [DUID] section */ + DUIDType duid_type; + /* DUID type code - RFC 3315 */ + uint16_t dhcp_duid_type; + size_t dhcp_duid_len; + uint8_t dhcp_duid[MAX_DUID_LEN]; }; extern const char* const network_dirs[]; diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index ef45370505..374ff8774e 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -98,6 +98,8 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr, size_t addr_len, uint16_t arp_type); int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, const uint8_t *data, size_t data_len); +int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, uint32_t iaid, + uint16_t duid_type, uint8_t *duid, size_t duid_len); int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type, const uint8_t **data, size_t *data_len); int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu); diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 1bedc941aa..4604cb6382 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -85,8 +85,9 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index); int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address); int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, size_t addr_len, uint16_t arp_type); -int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid, - size_t duid_len); +int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t duid_type, + uint8_t *duid, size_t duid_len); +int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid); int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled); int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled); int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, -- cgit v1.2.3-54-g00ecf From 23d8b221c0490b1b00044072b329d3ab76d561e3 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Thu, 14 Apr 2016 15:26:57 +0530 Subject: networkd: Add support to configure proxy arp support to interfaces (#3020) Fixes: #2889 --- man/systemd.network.xml | 11 +++++++++- src/network/networkd-link.c | 35 ++++++++++++++++++++++++++++++++ src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-network.c | 1 + src/network/networkd-network.h | 1 + 5 files changed, 48 insertions(+), 1 deletion(-) (limited to 'src/network/networkd-network-gperf.gperf') diff --git a/man/systemd.network.xml b/man/systemd.network.xml index c9ef041004..d7947836e9 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -548,6 +548,15 @@ Defaults to unset. + + ProxyARP= + A boolean. Configures proxy ARP. Proxy ARP is the technique in which one host, + usually a router, answers ARP requests intended for another machine. By "faking" its identity, + the router accepts responsibility for routing packets to the "real" destination. (see RFC 1027. + Defaults to unset. + + Bridge= @@ -844,7 +853,7 @@ global DUID that may be specified in networkd.conf 5. - The configured DHCP DUID should conform to the specification in + The configured DHCP DUID should conform to the specification in RFC 3315, RFC 6355. diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 88b3cbe90a..9059a68fe3 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -165,6 +165,21 @@ static bool link_ipv6_forward_enabled(Link *link) { return link->network->ip_forward & ADDRESS_FAMILY_IPV6; } +static bool link_proxy_arp_enabled(Link *link) { + assert(link); + + if (link->flags & IFF_LOOPBACK) + return false; + + if (!link->network) + return false; + + if (link->network->proxy_arp < 0) + return false; + + return true; +} + static bool link_ipv6_accept_ra_enabled(Link *link) { assert(link); @@ -1039,6 +1054,22 @@ static int link_set_bridge_fdb(Link *const link) { return r; } +static int link_set_proxy_arp(Link *const link) { + const char *p = NULL; + int r; + + if (!link_proxy_arp_enabled(link)) + return 0; + + p = strjoina("/proc/sys/net/ipv4/conf/", link->ifname, "/proxy_arp"); + + r = write_string_file(p, one_zero(link->network->proxy_arp), WRITE_STRING_FILE_VERIFY_ON_FAILURE); + if (r < 0) + log_link_warning_errno(link, r, "Cannot configure proxy ARP for interface: %m"); + + return 0; +} + static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { _cleanup_link_unref_ Link *link = userdata; int r; @@ -2167,6 +2198,10 @@ static int link_configure(Link *link) { if (r < 0) return r; + r = link_set_proxy_arp(link); + if (r < 0) + return r; + r = link_set_ipv4_forward(link); if (r < 0) return r; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 9793938080..1da99cd5bc 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -61,6 +61,7 @@ Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, Network.IPv6AcceptRouterAdvertisements, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra) Network.IPv6DuplicateAddressDetection, config_parse_int, 0, offsetof(Network, ipv6_dad_transmits) Network.IPv6HopLimit, config_parse_int, 0, offsetof(Network, ipv6_hop_limit) +Network.ProxyARP, config_parse_tristate, 0, offsetof(Network, proxy_arp) Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier) Address.Address, config_parse_address, 0, 0 Address.Peer, config_parse_address, 0, 0 diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 5946ba18dc..1c7adf5180 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -132,6 +132,7 @@ static int network_load_one(Manager *manager, const char *filename) { network->ipv6_dad_transmits = -1; network->ipv6_hop_limit = -1; network->duid_type = _DUID_TYPE_INVALID; + network->proxy_arp = -1; r = config_parse(NULL, filename, file, "Match\0" diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 5400a8bc9d..3d44113b05 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -139,6 +139,7 @@ struct Network { int ipv6_accept_ra; int ipv6_dad_transmits; int ipv6_hop_limit; + int proxy_arp; union in_addr_union ipv6_token; IPv6PrivacyExtensions ipv6_privacy_extensions; -- cgit v1.2.3-54-g00ecf From 076ea6f6d2d9d119cd467e7776e020d5766e2577 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 26 Apr 2016 16:19:28 +0200 Subject: networkd: clean up DUID code a bit Let's move DUID configuration into the [DHCP] section, since it only makes sense in a DHCP context, and should be close to the configuration of ClientIdentifier= and suchlike. This really shouldn't be a section of its own, we don't have any for any of our other per-protocol specific identifiers... Follow-up for #2890 #2943 --- man/systemd.network.xml | 59 ++++++++++++-------------------- src/network/networkd-conf.c | 55 ++++++++++++++++------------- src/network/networkd-gperf.gperf | 4 +-- src/network/networkd-network-gperf.gperf | 4 +-- src/network/networkd-network.c | 1 - 5 files changed, 57 insertions(+), 66 deletions(-) (limited to 'src/network/networkd-network-gperf.gperf') diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 9bf1b198ad..2a20748376 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -815,9 +815,8 @@ ClientIdentifier= - DHCP client identifier to use. Either mac - to use the MAC address of the link or duid - (the default) to use a RFC4361-compliant Client ID. + The DHCPv4 client identifier to use. Either mac to use the MAC address of the link + or duid (the default, see below) to use a RFC4361-compliant Client ID. @@ -827,6 +826,25 @@ type and configuration. + + DUIDRawData= + Specifies the DHCP DUID bytes as a single newline-terminated, hexadecimal string, with each + byte separated by a ':'. A DHCPv6 client sends the DHCP Unique Identifier (DUID) and the interface Identity + Association Identifier (IAID) to a DHCP server when acquiring a dynamic IPv6 address. Similar, DHCPv4 clients + send the IAID and DUID to the DHCP server when acquiring a dynamic IPv4 address if + . IAID and DUID allows a DHCP server to uniquely identify the machine + and the interface requesting a DHCP IP address. + + The DUID value specified here takes precedence over the DUID that systemd-networkd generates + using the machine-id from the /etc/machine-id file, as well as the + global DUID that may be specified in networkd.conf + 5. + + The configured DHCP DUID should conform to the specification in + RFC 3315, + RFC 6355. + + RequestBroadcast= @@ -846,40 +864,7 @@ - - - - - [DUID] Section Options - - This section configures the DHCP Unique Identifier (DUID) value used by DHCP - protocol. DHCPv6 client protocol sends the DHCP Unique Identifier and the interface - Identity Association Identifier (IAID) to a DHCP server when acquiring a dynamic IPv6 - address. DHCPv4 client protocol sends IAID and DUID to the DHCP server when acquiring - a dynamic IPv4 address if . IAID and DUID allows a - DHCP server to uniquely identify the machine and the interface requesting a DHCP IP. - - The DUID value specified here overrides the DUID that systemd-networkd generates - using the machine-id from the /etc/machine-id file, as well as the - global DUID that may be specified in networkd.conf - 5. - - The configured DHCP DUID should conform to the specification in - RFC 3315, - RFC 6355. - - The following options are available in [DUID] section: - - - - - RawData= - Specifies the DUID bytes as a single newline-terminated, hexadecimal - string, with each byte separated by a ':'. - - - - + [DHCPServer] Section Options diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c index 73a8d16b58..70f0121d6d 100644 --- a/src/network/networkd-conf.c +++ b/src/network/networkd-conf.c @@ -31,7 +31,7 @@ int manager_parse_config_file(Manager *m) { return config_parse_many(PKGSYSCONFDIR "/networkd.conf", CONF_PATHS_NULSTR("systemd/networkd.conf.d"), - "DUID\0", + "DHCP\0", config_item_perf_lookup, networkd_gperf_lookup, false, m); } @@ -57,7 +57,8 @@ int config_parse_duid_rawdata( const char *rvalue, void *data, void *userdata) { - int r, n1, n2, byte; + + int r; char *cbyte; const char *pduid = rvalue; Manager *m = userdata; @@ -72,71 +73,78 @@ int config_parse_duid_rawdata( assert(rvalue); assert(userdata); - duidtype = (ltype == DUID_CONFIG_SOURCE_GLOBAL) ? m->duid_type - : n->duid_type; + duidtype = (ltype == DUID_CONFIG_SOURCE_GLOBAL) ? m->duid_type : n->duid_type; if (duidtype == _DUID_TYPE_INVALID) duidtype = DUID_TYPE_RAW; switch (duidtype) { + case DUID_TYPE_LLT: /* RawData contains DUID-LLT link-layer address (offset 6) */ duid_start_offset = 6; break; + case DUID_TYPE_EN: /* RawData contains DUID-EN identifier (offset 4) */ duid_start_offset = 4; break; + case DUID_TYPE_LL: /* RawData contains DUID-LL link-layer address (offset 2) */ duid_start_offset = 2; break; + case DUID_TYPE_UUID: /* RawData specifies UUID (offset 0) - fall thru */ + case DUID_TYPE_RAW: /* First two bytes of RawData is DUID Type - fall thru */ + default: break; } if (duidtype != DUID_TYPE_RAW) - dhcp_duid_type = (uint16_t)duidtype; + dhcp_duid_type = (uint16_t) duidtype; /* RawData contains DUID in format " NN:NN:NN... " */ for (;;) { + int n1, n2; + uint32_t byte; + r = extract_first_word(&pduid, &cbyte, ":", 0); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, - "Failed to read DUID, ignoring assignment: %s.", rvalue); - goto exit; + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to read DUID, ignoring assignment: %s.", rvalue); + return 0; } if (r == 0) break; - if ((duid_start_offset + dhcp_duid_len) >= MAX_DUID_LEN) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "Max DUID length exceeded, ignoring assignment: %s.", rvalue); - goto exit; + if (duid_start_offset + dhcp_duid_len >= MAX_DUID_LEN) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Max DUID length exceeded, ignoring assignment: %s.", rvalue); + return 0; } len = strlen(cbyte); - if ((len == 0) || (len > 2)) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "Invalid length - DUID byte: %s, ignoring assignment: %s.", cbyte, rvalue); - goto exit; + if (len != 1 && len != 2) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid length - DUID byte: %s, ignoring assignment: %s.", cbyte, rvalue); + return 0; } - n2 = 0; n1 = unhexchar(cbyte[0]); if (len == 2) n2 = unhexchar(cbyte[1]); - if ((n1 < 0) || (n2 < 0)) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "Invalid DUID byte: %s. Ignoring assignment: %s.", cbyte, rvalue); - goto exit; + else + n2 = 0; + + if (n1 < 0 || n2 < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid DUID byte: %s. Ignoring assignment: %s.", cbyte, rvalue); + return 0; } - byte = (n1 << (4 * (len-1))) | n2; + + byte = ((uint8_t) n1 << (4 * (len-1))) | (uint8_t) n2; /* If DUID_TYPE_RAW, first two bytes hold DHCP DUID type code */ - if ((duidtype == DUID_TYPE_RAW) && (count < 2)) { + if (duidtype == DUID_TYPE_RAW && count < 2) { dhcp_duid_type |= (byte << (8 * (1 - count))); count++; continue; @@ -159,6 +167,5 @@ int config_parse_duid_rawdata( memcpy(&n->dhcp_duid[duid_start_offset], dhcp_duid, dhcp_duid_len); } -exit: return 0; } diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf index 0625fb335b..afc71b4cb8 100644 --- a/src/network/networkd-gperf.gperf +++ b/src/network/networkd-gperf.gperf @@ -14,5 +14,5 @@ struct ConfigPerfItem; %struct-type %includes %% -DUID.Type, config_parse_duid_type, 0, offsetof(Manager, duid_type) -DUID.RawData, config_parse_duid_rawdata, DUID_CONFIG_SOURCE_GLOBAL, offsetof(Manager, dhcp_duid) +DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Manager, duid_type) +DHCP.DUIDRawData, config_parse_duid_rawdata, DUID_CONFIG_SOURCE_GLOBAL, offsetof(Manager, dhcp_duid) diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 1da99cd5bc..654d6a0316 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -28,8 +28,6 @@ Match.Architecture, config_parse_net_condition, Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac) Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu) Link.IAID, config_parse_iaid, 0, offsetof(Network, iaid) -DUID.Type, config_parse_duid_type, 0, offsetof(Network, duid_type) -DUID.RawData, config_parse_duid_rawdata, DUID_CONFIG_SOURCE_NETWORK, offsetof(Network, dhcp_duid) Network.Description, config_parse_string, 0, offsetof(Network, description) Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge) Network.Bond, config_parse_netdev, 0, offsetof(Network, bond) @@ -85,6 +83,8 @@ DHCP.Hostname, config_parse_hostname, DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast) DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) +DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid_type) +DHCP.DUIDRawData, config_parse_duid_rawdata, DUID_CONFIG_SOURCE_NETWORK, offsetof(Network, dhcp_duid) DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone) DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 07f8fb028f..2ebcdfa744 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -137,7 +137,6 @@ static int network_load_one(Manager *manager, const char *filename) { r = config_parse(NULL, filename, file, "Match\0" "Link\0" - "DUID\0" "Network\0" "Address\0" "Route\0" -- cgit v1.2.3-54-g00ecf From 8341a5c381a72d504768fe296f8e30a324eeff77 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 28 Apr 2016 23:23:45 -0400 Subject: networkd: rework duid_{type,duid_type,duid,duid_len} setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Separate fields are replaced with a struct. Second second duid type field is removed. The first field was used to carry the result of DUIDType= configuration, and the second was either a copy of this, or contained the type extracted from DuidRawData. The semantics are changed so that the type specified in DUIDType is always used. DUIDRawData= no longer overrides the type setting. The networkd code is now more constrained than the sd-dhcp code: DUIDRawData cannot have 0 length, length 0 is treated the same as unsetting. Likewise, it is not possible to set a DUIDType=0. If it ever becomes necessary to set type=0 or a zero-length duid, the code can be changed to support that. Nevertheless, I think that's unlikely. This addresses #3127 § 1 and 3. v2: - rename DUID.duid, DUID.duid_len to DUID.raw_data, DUID.raw_data_len --- src/network/networkd-conf.c | 87 +++++--------------------------- src/network/networkd-conf.h | 29 ++++++++--- src/network/networkd-dhcp4.c | 24 ++++----- src/network/networkd-dhcp6.c | 16 +++--- src/network/networkd-gperf.gperf | 4 +- src/network/networkd-link.c | 35 +++++-------- src/network/networkd-manager.c | 2 +- src/network/networkd-network-gperf.gperf | 4 +- src/network/networkd-network.c | 2 +- src/network/networkd-network.h | 15 +++--- src/network/networkd.h | 14 ++--- 11 files changed, 88 insertions(+), 144 deletions(-) (limited to 'src/network/networkd-network-gperf.gperf') diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c index 70f0121d6d..1b2047f8f4 100644 --- a/src/network/networkd-conf.c +++ b/src/network/networkd-conf.c @@ -41,7 +41,7 @@ static const char* const duid_type_table[_DUID_TYPE_MAX] = { [DUID_TYPE_LLT] = "link-layer-time", [DUID_TYPE_EN] = "vendor", [DUID_TYPE_LL] = "link-layer", - [DUID_TYPE_UUID] = "uuid" + [DUID_TYPE_UUID] = "uuid", }; DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(duid_type, DUIDType); DEFINE_CONFIG_PARSE_ENUM(config_parse_duid_type, duid_type, DUIDType, "Failed to parse DUID type"); @@ -58,69 +58,29 @@ int config_parse_duid_rawdata( void *data, void *userdata) { - int r; - char *cbyte; - const char *pduid = rvalue; - Manager *m = userdata; - Network *n = userdata; - DUIDType duidtype; - uint16_t dhcp_duid_type = 0; - uint8_t dhcp_duid[MAX_DUID_LEN]; - size_t len, count = 0, duid_start_offset = 0, dhcp_duid_len = 0; + DUID *ret = data; + uint8_t raw_data[MAX_DUID_LEN]; + unsigned count = 0; assert(filename); assert(lvalue); assert(rvalue); - assert(userdata); + assert(ret); - duidtype = (ltype == DUID_CONFIG_SOURCE_GLOBAL) ? m->duid_type : n->duid_type; - - if (duidtype == _DUID_TYPE_INVALID) - duidtype = DUID_TYPE_RAW; - - switch (duidtype) { - - case DUID_TYPE_LLT: - /* RawData contains DUID-LLT link-layer address (offset 6) */ - duid_start_offset = 6; - break; - - case DUID_TYPE_EN: - /* RawData contains DUID-EN identifier (offset 4) */ - duid_start_offset = 4; - break; - - case DUID_TYPE_LL: - /* RawData contains DUID-LL link-layer address (offset 2) */ - duid_start_offset = 2; - break; - - case DUID_TYPE_UUID: - /* RawData specifies UUID (offset 0) - fall thru */ - - case DUID_TYPE_RAW: - /* First two bytes of RawData is DUID Type - fall thru */ - - default: - break; - } - - if (duidtype != DUID_TYPE_RAW) - dhcp_duid_type = (uint16_t) duidtype; - - /* RawData contains DUID in format " NN:NN:NN... " */ + /* RawData contains DUID in format "NN:NN:NN..." */ for (;;) { - int n1, n2; + int n1, n2, len, r; uint32_t byte; + char *cbyte; - r = extract_first_word(&pduid, &cbyte, ":", 0); + r = extract_first_word(&rvalue, &cbyte, ":", 0); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, "Failed to read DUID, ignoring assignment: %s.", rvalue); return 0; } if (r == 0) break; - if (duid_start_offset + dhcp_duid_len >= MAX_DUID_LEN) { + if (count >= MAX_DUID_LEN) { log_syntax(unit, LOG_ERR, filename, line, 0, "Max DUID length exceeded, ignoring assignment: %s.", rvalue); return 0; } @@ -142,30 +102,11 @@ int config_parse_duid_rawdata( } byte = ((uint8_t) n1 << (4 * (len-1))) | (uint8_t) n2; - - /* If DUID_TYPE_RAW, first two bytes hold DHCP DUID type code */ - if (duidtype == DUID_TYPE_RAW && count < 2) { - dhcp_duid_type |= (byte << (8 * (1 - count))); - count++; - continue; - } - - dhcp_duid[duid_start_offset + dhcp_duid_len] = byte; - dhcp_duid_len++; - } - - if (ltype == DUID_CONFIG_SOURCE_GLOBAL) { - m->duid_type = duidtype; - m->dhcp_duid_type = dhcp_duid_type; - m->dhcp_duid_len = dhcp_duid_len; - memcpy(&m->dhcp_duid[duid_start_offset], dhcp_duid, dhcp_duid_len); - } else { - /* DUID_CONFIG_SOURCE_NETWORK */ - n->duid_type = duidtype; - n->dhcp_duid_type = dhcp_duid_type; - n->dhcp_duid_len = dhcp_duid_len; - memcpy(&n->dhcp_duid[duid_start_offset], dhcp_duid, dhcp_duid_len); + raw_data[count++] = byte; } + assert_cc(sizeof(raw_data) == sizeof(ret->raw_data)); + memcpy(ret->raw_data, raw_data, count); + ret->raw_data_len = count; return 0; } diff --git a/src/network/networkd-conf.h b/src/network/networkd-conf.h index 671e656d7b..c7bfb42a72 100644 --- a/src/network/networkd-conf.h +++ b/src/network/networkd-conf.h @@ -21,14 +21,29 @@ #include "networkd.h" -typedef enum DuidConfigSource { - DUID_CONFIG_SOURCE_GLOBAL = 0, - DUID_CONFIG_SOURCE_NETWORK, -} DuidConfigSource; - int manager_parse_config_file(Manager *m); const struct ConfigPerfItem* networkd_gperf_lookup(const char *key, unsigned length); -int config_parse_duid_type(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); -int config_parse_duid_rawdata(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); +int config_parse_duid_type( + 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); +int config_parse_duid_rawdata( + 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); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index d31ea4d066..89926e8a7e 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -628,28 +628,24 @@ int dhcp4_configure(Link *link) { } switch (link->network->dhcp_client_identifier) { - case DHCP_CLIENT_ID_DUID: + case DHCP_CLIENT_ID_DUID: { /* If configured, apply user specified DUID and/or IAID */ - if (link->network->duid_type != _DUID_TYPE_INVALID) - r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, - link->network->iaid, - link->network->dhcp_duid_type, - link->network->dhcp_duid, - link->network->dhcp_duid_len); - else - r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, - link->network->iaid, - link->manager->dhcp_duid_type, - link->manager->dhcp_duid, - link->manager->dhcp_duid_len); + const DUID *duid = link_duid(link); + + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid, + duid->type, + duid->raw_data_len > 0 ? duid->raw_data : NULL, + duid->raw_data_len); if (r < 0) return r; break; + } case DHCP_CLIENT_ID_MAC: r = sd_dhcp_client_set_client_id(link->dhcp_client, ARPHRD_ETHER, (const uint8_t *) &link->mac, - sizeof (link->mac)); + sizeof(link->mac)); if (r < 0) return r; break; diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index b9c4b8962c..ccca4e9522 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -206,6 +206,7 @@ int dhcp6_request_address(Link *link) { int dhcp6_configure(Link *link) { sd_dhcp6_client *client = NULL; int r; + const DUID *duid; assert(link); @@ -234,16 +235,11 @@ int dhcp6_configure(Link *link) { if (r < 0) goto error; - if (link->network->duid_type != _DUID_TYPE_INVALID) - r = sd_dhcp6_client_set_duid(client, - link->network->dhcp_duid_type, - link->network->dhcp_duid, - link->network->dhcp_duid_len); - else - r = sd_dhcp6_client_set_duid(client, - link->manager->dhcp_duid_type, - link->manager->dhcp_duid, - link->manager->dhcp_duid_len); + duid = link_duid(link); + r = sd_dhcp6_client_set_duid(client, + duid->type, + duid->raw_data_len > 0 ? duid->raw_data : NULL, + duid->raw_data_len); if (r < 0) goto error; diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf index afc71b4cb8..3fdfe74955 100644 --- a/src/network/networkd-gperf.gperf +++ b/src/network/networkd-gperf.gperf @@ -14,5 +14,5 @@ struct ConfigPerfItem; %struct-type %includes %% -DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Manager, duid_type) -DHCP.DUIDRawData, config_parse_duid_rawdata, DUID_CONFIG_SOURCE_GLOBAL, offsetof(Manager, dhcp_duid) +DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Manager, duid.type) +DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, duid) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index a88e4c34ed..c646af1f1a 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2879,6 +2879,8 @@ int link_update(Link *link, sd_netlink_message *m) { } if (link->dhcp_client) { + const DUID *duid = link_duid(link); + r = sd_dhcp_client_set_mac(link->dhcp_client, (const uint8_t *) &link->mac, sizeof (link->mac), @@ -2886,23 +2888,18 @@ int link_update(Link *link, sd_netlink_message *m) { if (r < 0) return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m"); - if (link->network->duid_type != _DUID_TYPE_INVALID) - r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, - link->network->iaid, - link->network->dhcp_duid_type, - link->network->dhcp_duid, - link->network->dhcp_duid_len); - else - r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, - link->network->iaid, - link->manager->dhcp_duid_type, - link->manager->dhcp_duid, - link->manager->dhcp_duid_len); + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid, + duid->type, + duid->raw_data_len > 0 ? duid->raw_data : NULL, + duid->raw_data_len); if (r < 0) return log_link_warning_errno(link, r, "Could not update DUID/IAID in DHCP client: %m"); } if (link->dhcp6_client) { + const DUID* duid = link_duid(link); + r = sd_dhcp6_client_set_mac(link->dhcp6_client, (const uint8_t *) &link->mac, sizeof (link->mac), @@ -2915,16 +2912,10 @@ int link_update(Link *link, sd_netlink_message *m) { if (r < 0) return log_link_warning_errno(link, r, "Could not update DHCPv6 IAID: %m"); - if (link->network->duid_type != _DUID_TYPE_INVALID) - r = sd_dhcp6_client_set_duid(link->dhcp6_client, - link->network->dhcp_duid_type, - link->network->dhcp_duid, - link->network->dhcp_duid_len); - else - r = sd_dhcp6_client_set_duid(link->dhcp6_client, - link->manager->dhcp_duid_type, - link->manager->dhcp_duid, - link->manager->dhcp_duid_len); + r = sd_dhcp6_client_set_duid(link->dhcp6_client, + duid->type, + duid->raw_data_len > 0 ? duid->raw_data : NULL, + duid->raw_data_len); if (r < 0) return log_link_warning_errno(link, r, "Could not update DHCPv6 DUID: %m"); } diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 0cb5781c71..5dcd4df536 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1037,7 +1037,7 @@ int manager_new(Manager **ret) { if (r < 0) return r; - m->duid_type = DUID_TYPE_EN; + m->duid.type = DUID_TYPE_EN; *ret = m; m = NULL; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 654d6a0316..6bf57cdf99 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -83,8 +83,8 @@ DHCP.Hostname, config_parse_hostname, DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast) DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) -DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid_type) -DHCP.DUIDRawData, config_parse_duid_rawdata, DUID_CONFIG_SOURCE_NETWORK, offsetof(Network, dhcp_duid) +DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid.type) +DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid) DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone) DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 2ebcdfa744..206c270e50 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -131,7 +131,7 @@ static int network_load_one(Manager *manager, const char *filename) { network->ipv6_accept_ra = -1; network->ipv6_dad_transmits = -1; network->ipv6_hop_limit = -1; - network->duid_type = _DUID_TYPE_INVALID; + network->duid.type = _DUID_TYPE_INVALID; network->proxy_arp = -1; r = config_parse(NULL, filename, file, diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 9b8096f9ae..ff2414efdd 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -68,6 +68,14 @@ typedef enum LLDPMode { _LLDP_MODE_INVALID = -1, } LLDPMode; +typedef struct DUID { + /* Value of Type in [DHCP] section */ + DUIDType type; + + uint8_t raw_data_len; + uint8_t raw_data[MAX_DUID_LEN]; +} DUID; + typedef struct Manager Manager; struct Network { @@ -150,12 +158,7 @@ struct Network { struct ether_addr *mac; unsigned mtu; uint32_t iaid; - /* Value of Type in [DUID] section */ - DUIDType duid_type; - /* DUID type code - RFC 3315 */ - uint16_t dhcp_duid_type; - size_t dhcp_duid_len; - uint8_t dhcp_duid[MAX_DUID_LEN]; + DUID duid; LLDPMode lldp_mode; /* LLDP reception */ bool lldp_emit; /* LLDP transmission */ diff --git a/src/network/networkd.h b/src/network/networkd.h index 39826a440d..26d9e7d6e0 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -74,14 +74,16 @@ struct Manager { usec_t network_dirs_ts_usec; - /* Value of Type in [DUID] section */ - DUIDType duid_type; - /* DUID type code - RFC 3315 */ - uint16_t dhcp_duid_type; - size_t dhcp_duid_len; - uint8_t dhcp_duid[MAX_DUID_LEN]; + DUID duid; }; +static inline const DUID* link_duid(const Link *link) { + if (link->network->duid.type != _DUID_TYPE_INVALID) + return &link->network->duid; + else + return &link->manager->duid; +} + extern const sd_bus_vtable manager_vtable[]; int manager_new(Manager **ret); -- cgit v1.2.3-54-g00ecf From c953b24c651afc47abed8ea63381501aa82eb2e8 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Tue, 3 May 2016 23:18:21 +0530 Subject: networkd: add support to set route table networkd: add support to set route table 1. add support to configure the table id. if id is less than 256 we can fit this in the header of route as netlink property is a char. But in kernel this proepty is a unsigned 32. Hence if greater that 256 add this as RTA_TABLE attribute. 2. we are not setting the address family now. Now set this property. --- man/systemd.network.xml | 8 ++++ src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-route.c | 64 +++++++++++++++++++++++++++++++- src/network/networkd-route.h | 3 +- 4 files changed, 74 insertions(+), 2 deletions(-) (limited to 'src/network/networkd-network-gperf.gperf') diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 2a20748376..1ed7b67086 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -706,6 +706,14 @@ inet_pton3. + + Table=num + + The table identifier for the route (a number between 1 and 4294967295, or 0 to unset). + The table can be retrieved using ip route show table num. + + + diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 654d6a0316..471e300fde 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -71,6 +71,7 @@ Route.Source, config_parse_destination, Route.Metric, config_parse_route_priority, 0, 0 Route.Scope, config_parse_route_scope, 0, 0 Route.PreferredSource, config_parse_preferred_src, 0, 0 +Route.Table, config_parse_route_table, 0, 0 DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier) DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_use_dns) DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_use_ntp) diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index bda2707e6d..01094b20bd 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -451,6 +451,10 @@ int route_configure(Route *route, Link *link, r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m"); + + r = sd_rtnl_message_route_set_family(req, route->family); + if (r < 0) + return log_error_errno(r, "Could not set route family: %m"); } if (route->dst_prefixlen) { @@ -494,7 +498,26 @@ int route_configure(Route *route, Link *link, r = sd_rtnl_message_route_set_flags(req, route->flags); if (r < 0) - return log_error_errno(r, "Colud not set flags: %m"); + return log_error_errno(r, "Could not set flags: %m"); + + if (route->table != RT_TABLE_DEFAULT) { + + if (route->table < 256) { + r = sd_rtnl_message_route_set_table(req, route->table); + if (r < 0) + return log_error_errno(r, "Could not set route table: %m"); + } else { + + r = sd_rtnl_message_route_set_table(req, RT_TABLE_UNSPEC); + if (r < 0) + return log_error_errno(r, "Could not set route table: %m"); + + /* Table attribute to allow allow more than 256. */ + r = sd_netlink_message_append_data(req, RTA_TABLE, &route->table, sizeof(route->table)); + if (r < 0) + return log_error_errno(r, "Could not append RTA_TABLE attribute: %m"); + } + } r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority); if (r < 0) @@ -777,3 +800,42 @@ int config_parse_route_scope(const char *unit, return 0; } + +int config_parse_route_table(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) { + _cleanup_route_free_ Route *n = NULL; + Network *network = userdata; + uint32_t k; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = route_new_static(network, section_line, &n); + if (r < 0) + return r; + + r = safe_atou32(rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue); + return 0; + } + + n->table = k; + + n = NULL; + + return 0; +} diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index a4a4bf2653..3ddeea96b7 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -37,7 +37,7 @@ struct Route { unsigned char protocol; /* RTPROT_* */ unsigned char tos; uint32_t priority; /* note that ip(8) calls this 'metric' */ - unsigned char table; + uint32_t table; unsigned char pref; unsigned flags; @@ -74,3 +74,4 @@ int config_parse_preferred_src(const char *unit, const char *filename, unsigned int config_parse_destination(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); int config_parse_route_priority(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); int config_parse_route_scope(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); +int config_parse_route_table(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); -- cgit v1.2.3-54-g00ecf From b5834a0b38c1aa7d6975d76971cd75c07455d129 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Wed, 4 May 2016 01:24:26 +0530 Subject: networkd: Add support to configure IPv6 preferred lifetime (#3102) Closes #2166. We only allow 0, infinity and forever. infinity and forever is same. --- man/systemd.network.xml | 12 ++++++++ src/network/networkd-address.c | 48 ++++++++++++++++++++++++++++++++ src/network/networkd-address.h | 1 + src/network/networkd-network-gperf.gperf | 1 + 4 files changed, 62 insertions(+) (limited to 'src/network/networkd-network-gperf.gperf') diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 1ed7b67086..5e287faa6e 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -652,6 +652,18 @@ An address label. + + PreferredLifetime= + + Allows the default "preferred lifetime" of the address to be overridden. + Only three settings are accepted: forever or infinity + which is the default and means that the address never expires, and 0 which means + that the address is considered immediately "expired" and will not be used, + unless explicitly requested. A setting of PreferredLifetime=0 is useful for + addresses which are added to be used only by a specific application, + which is then configured to use them explicitly. + + diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 429319da6b..8b52a1f742 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -774,6 +774,54 @@ int config_parse_label(const char *unit, return 0; } +int config_parse_lifetime(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) { + Network *network = userdata; + _cleanup_address_free_ Address *n = NULL; + unsigned k; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = address_new_static(network, section_line, &n); + if (r < 0) + return r; + + if (STR_IN_SET(rvalue, "forever", "infinity")) { + n->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME; + n = NULL; + + return 0; + } + + r = safe_atou(rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse PreferredLifetime, ignoring: %s", rvalue); + return 0; + } + + if (k != 0) + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid PreferredLifetime value, ignoring: %d", k); + else { + n->cinfo.ifa_prefered = k; + n = NULL; + } + + return 0; +} + bool address_is_ready(const Address *a) { assert(a); diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h index 338f6eb9a2..3c81978fb1 100644 --- a/src/network/networkd-address.h +++ b/src/network/networkd-address.h @@ -74,3 +74,4 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free); int config_parse_address(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); int config_parse_broadcast(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); int config_parse_label(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); +int config_parse_lifetime(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); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 471e300fde..550b5e5240 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -65,6 +65,7 @@ Address.Address, config_parse_address, Address.Peer, config_parse_address, 0, 0 Address.Broadcast, config_parse_broadcast, 0, 0 Address.Label, config_parse_label, 0, 0 +Address.PreferredLifetime, config_parse_lifetime, 0, 0 Route.Gateway, config_parse_gateway, 0, 0 Route.Destination, config_parse_destination, 0, 0 Route.Source, config_parse_destination, 0, 0 -- cgit v1.2.3-54-g00ecf From d05def163ea09bc2e617703546e5f9db95e27e5b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 6 May 2016 17:04:05 +0200 Subject: networkd: move the IAID configuration option into the [DHCP] section It's only relevant to DHCP, and it should be where the DUID is configured too. --- man/systemd.network.xml | 13 +++++++------ src/network/networkd-network-gperf.gperf | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src/network/networkd-network-gperf.gperf') diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 3ee80a64a0..40e40b8308 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -206,12 +206,6 @@ below 1280 (the minimum MTU for IPv6) it will automatically be increased to this value. - - IAID= - - Identity Association Identifier for the interface, a 32-bit unsigned integer. - - Note that an interface without any static IPv6 addresses configured, and neither @@ -867,6 +861,13 @@ + + IAID= + + The DHCP Identity Association Identifier (IAID) for the interface, a 32-bit unsigned integer. + + + RequestBroadcast= diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 51e750b299..a9a541559e 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -27,7 +27,6 @@ Match.KernelCommandLine, config_parse_net_condition, Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch) Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac) Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu) -Link.IAID, config_parse_iaid, 0, offsetof(Network, iaid) Network.Description, config_parse_string, 0, offsetof(Network, description) Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge) Network.Bond, config_parse_netdev, 0, offsetof(Network, bond) @@ -89,6 +88,7 @@ DHCP.DUIDType, config_parse_duid_type, DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid) DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone) +DHCP.IAID, config_parse_iaid, 0, offsetof(Network, iaid) DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec) DHCPServer.DefaultLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec) DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_dns) -- cgit v1.2.3-54-g00ecf From 7272b25e163d1c7395ff0da1397511c7946c0873 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 6 May 2016 21:27:36 +0200 Subject: networkd: reworkd LLDP emission to allow control of propagation level This allows selecting the propagation level of emitted LLDP packets (specifically: the destination MAC address of the packets). This is useful because it allows generating LLDP packets that optionally cross certain types of bridges. See 802.11ab-2009, Table 7-1 for details. --- man/systemd.network.xml | 28 ++++++--- src/network/networkd-link.c | 16 ++--- src/network/networkd-link.h | 2 +- src/network/networkd-lldp-tx.c | 102 +++++++++++++++++++++++++------ src/network/networkd-lldp-tx.h | 14 ++++- src/network/networkd-network-gperf.gperf | 2 +- src/network/networkd-network.h | 3 +- 7 files changed, 126 insertions(+), 41 deletions(-) (limited to 'src/network/networkd-network-gperf.gperf') diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 6d45d6c807..70e3804746 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -363,18 +363,26 @@ EmitLLDP= - Controls support for Ethernet LLDP packet emission. Accepts a boolean parameter and defaults to - false. If enabled a short LLDP packet with information about the local system is sent out in regular - intervals on the link. The LLDP packet will contain information about the local host name, the local - machine ID (as stored in - machine-id5) and the + Controls support for Ethernet LLDP packet emission. Accepts a boolean parameter or the special values + nearest-bridge, non-tpmr-bridge and + customer-bridge. Defaults to false, which turns off LLDP packet emission. If not false, + a short LLDP packet with information about the local system is sent out in regular intervals on the + link. The LLDP packet will contain information about the local host name, the local machine ID (as stored + in machine-id5) and the local interface name, as well as the pretty hostname of the system (as set in machine-info5). LLDP - emission is only available on Ethernet links. Note that this setting passed data suitable for - identification of host to the network and should thus not be used on untrusted networks, where such - identification data should not be made available. Use this option to enable other systems to identify on - which interface they are connected to this system. See LLDP= above for an option to - enable LLDP reception. + emission is only available on Ethernet links. Note that this setting passes data suitable for + identification of host to the network and should thus not be enabled on untrusted networks, where such + identification data should not be made available. Use this option to permit other systems to identify on + which interfaces they are connected to this system. The three special values control propagation of the + LLDP packets. The nearest-bridge setting permits propagation only to the nearest + connected bridge, non-tpmr-bridge permits propagation across Two-Port MAC Relays, but + not any other bridges, and customer-bridge permits propagation until a customer bridge + is reached. For details about these concepts, see IEEE 802.1AB-2009. Note that + configuring this setting to true is equivalent to nearest-bridge, the recommended and + most restricted level of propagation. See LLDP= above for an option to enable LLDP + reception. diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index c646af1f1a..4e3f62cf51 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -131,7 +131,7 @@ static bool link_lldp_rx_enabled(Link *link) { return link->network->lldp_mode != LLDP_MODE_NO; } -static bool link_lldp_tx_enabled(Link *link) { +static bool link_lldp_emit_enabled(Link *link) { assert(link); if (link->flags & IFF_LOOPBACK) @@ -143,7 +143,7 @@ static bool link_lldp_tx_enabled(Link *link) { if (!link->network) return false; - return link->network->lldp_emit; + return link->network->lldp_emit != LLDP_EMIT_NO; } static bool link_ipv4_forward_enabled(Link *link) { @@ -491,7 +491,7 @@ static void link_free(Link *link) { sd_dhcp_client_unref(link->dhcp_client); sd_dhcp_lease_unref(link->dhcp_lease); - link_lldp_tx_stop(link); + link_lldp_emit_stop(link); free(link->lease_file); @@ -618,7 +618,7 @@ static int link_stop_clients(Link *link) { r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m"); } - link_lldp_tx_stop(link); + link_lldp_emit_stop(link); return r; } @@ -1411,12 +1411,12 @@ static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n (void) link_lldp_save(link); - if (link_lldp_tx_enabled(link) && event == SD_LLDP_EVENT_ADDED) { + if (link_lldp_emit_enabled(link) && event == SD_LLDP_EVENT_ADDED) { /* If we received information about a new neighbor, restart the LLDP "fast" logic */ log_link_debug(link, "Received LLDP datagram from previously unknown neighbor, restarting 'fast' LLDP transmission."); - r = link_lldp_tx_start(link); + r = link_lldp_emit_start(link); if (r < 0) log_link_warning_errno(link, r, "Failed to restart LLDP transmission: %m"); } @@ -1501,8 +1501,8 @@ static int link_acquire_conf(Link *link) { return r; } - if (link_lldp_tx_enabled(link)) { - r = link_lldp_tx_start(link); + if (link_lldp_emit_enabled(link)) { + r = link_lldp_emit_start(link); if (r < 0) return log_link_warning_errno(link, r, "Failed to start LLDP transmission: %m"); } diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 86139be557..14c4a02c7e 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -121,7 +121,7 @@ typedef struct Link { /* This is about LLDP transmission */ unsigned lldp_tx_fast; /* The LLDP txFast counter (See 802.1ab-2009, section 9.2.5.18) */ - sd_event_source *lldp_tx_event_source; + sd_event_source *lldp_emit_event_source; Hashmap *bound_by_links; Hashmap *bound_to_links; diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c index 03b694c3f1..3aa768388b 100644 --- a/src/network/networkd-lldp-tx.c +++ b/src/network/networkd-lldp-tx.c @@ -25,16 +25,14 @@ #include "fd-util.h" #include "fileio.h" #include "hostname-util.h" +#include "networkd-lldp-tx.h" +#include "networkd.h" +#include "parse-util.h" #include "random-util.h" #include "socket-util.h" #include "string-util.h" #include "unaligned.h" -#include "networkd.h" -#include "networkd-lldp-tx.h" - -#define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } - /* The LLDP spec calls this "txFastInit", see 9.2.5.19 */ #define LLDP_TX_FAST_INIT 4U @@ -50,6 +48,12 @@ /* The LLDP spec calls this msgFastTx, but we subtract half the jitter off it. */ #define LLDP_FAST_TX_USEC (1U * USEC_PER_SEC - LLDP_JITTER_USEC / 2) +static const struct ether_addr lldp_multicast_addr[_LLDP_EMIT_MAX] = { + [LLDP_EMIT_NEAREST_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }}, + [LLDP_EMIT_NON_TPMR_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }}, + [LLDP_EMIT_CUSTOMER_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }}, +}; + static int lldp_write_tlv_header(uint8_t **p, uint8_t id, size_t sz) { assert(p); @@ -66,6 +70,7 @@ static int lldp_write_tlv_header(uint8_t **p, uint8_t id, size_t sz) { } static int lldp_make_packet( + LLDPEmit mode, const struct ether_addr *hwaddr, const char *machine_id, const char *ifname, @@ -84,6 +89,8 @@ static int lldp_make_packet( size_t l; int r; + assert(mode > LLDP_EMIT_NO); + assert(mode < _LLDP_EMIT_MAX); assert(hwaddr); assert(machine_id); assert(ifname); @@ -132,7 +139,7 @@ static int lldp_make_packet( h = (struct ether_header*) packet; h->ether_type = htobe16(ETHERTYPE_LLDP); - memcpy(h->ether_dhost, &(struct ether_addr) { LLDP_MULTICAST_ADDR }, ETH_ALEN); + memcpy(h->ether_dhost, lldp_multicast_addr + mode, ETH_ALEN); memcpy(h->ether_shost, hwaddr, ETH_ALEN); p = (uint8_t*) packet + sizeof(struct ether_header); @@ -197,22 +204,28 @@ static int lldp_make_packet( return 0; } -static int lldp_send_packet(int ifindex, const void *packet, size_t packet_size) { +static int lldp_send_packet( + int ifindex, + const struct ether_addr *address, + const void *packet, + size_t packet_size) { union sockaddr_union sa = { .ll.sll_family = AF_PACKET, .ll.sll_protocol = htobe16(ETHERTYPE_LLDP), .ll.sll_ifindex = ifindex, .ll.sll_halen = ETH_ALEN, - .ll.sll_addr = LLDP_MULTICAST_ADDR, }; _cleanup_close_ int fd = -1; ssize_t l; assert(ifindex > 0); + assert(address); assert(packet || packet_size <= 0); + memcpy(sa.ll.sll_addr, address, ETH_ALEN); + fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC, IPPROTO_RAW); if (fd < 0) return -errno; @@ -237,6 +250,13 @@ static int link_send_lldp(Link *link) { usec_t ttl; int r; + assert(link); + + if (!link->network || link->network->lldp_emit == LLDP_EMIT_NO) + return 0; + + assert(link->network->lldp_emit < _LLDP_EMIT_MAX); + r = sd_id128_get_machine(&machine_id); if (r < 0) return r; @@ -251,7 +271,8 @@ static int link_send_lldp(Link *link) { SD_LLDP_SYSTEM_CAPABILITIES_ROUTER : SD_LLDP_SYSTEM_CAPABILITIES_STATION; - r = lldp_make_packet(&link->mac, + r = lldp_make_packet(link->network->lldp_emit, + &link->mac, sd_id128_to_string(machine_id, machine_id_string), link->ifname, (uint16_t) ttl, @@ -264,7 +285,7 @@ static int link_send_lldp(Link *link) { if (r < 0) return r; - return lldp_send_packet(link->ifindex, packet, packet_size); + return lldp_send_packet(link->ifindex, lldp_multicast_addr + link->network->lldp_emit, packet, packet_size); } static int on_lldp_timer(sd_event_source *s, usec_t t, void *userdata) { @@ -300,12 +321,17 @@ static int on_lldp_timer(sd_event_source *s, usec_t t, void *userdata) { return 0; } -int link_lldp_tx_start(Link *link) { +int link_lldp_emit_start(Link *link) { usec_t next; int r; assert(link); + if (!link->network || link->network->lldp_emit == LLDP_EMIT_NO) { + link_lldp_emit_stop(link); + return 0; + } + /* Starts the LLDP transmission in "fast" mode. If it is already started, turns "fast" mode back on again. */ link->lldp_tx_fast = LLDP_TX_FAST_INIT; @@ -313,22 +339,22 @@ int link_lldp_tx_start(Link *link) { next = usec_add(usec_add(now(clock_boottime_or_monotonic()), LLDP_FAST_TX_USEC), (usec_t) random_u64() % LLDP_JITTER_USEC); - if (link->lldp_tx_event_source) { + if (link->lldp_emit_event_source) { usec_t old; /* Lower the timeout, maybe */ - r = sd_event_source_get_time(link->lldp_tx_event_source, &old); + r = sd_event_source_get_time(link->lldp_emit_event_source, &old); if (r < 0) return r; if (old <= next) return 0; - return sd_event_source_set_time(link->lldp_tx_event_source, next); + return sd_event_source_set_time(link->lldp_emit_event_source, next); } else { r = sd_event_add_time( link->manager->event, - &link->lldp_tx_event_source, + &link->lldp_emit_event_source, clock_boottime_or_monotonic(), next, 0, @@ -337,14 +363,54 @@ int link_lldp_tx_start(Link *link) { if (r < 0) return r; - (void) sd_event_source_set_description(link->lldp_tx_event_source, "lldp-tx"); + (void) sd_event_source_set_description(link->lldp_emit_event_source, "lldp-tx"); } return 0; } -void link_lldp_tx_stop(Link *link) { +void link_lldp_emit_stop(Link *link) { assert(link); - link->lldp_tx_event_source = sd_event_source_unref(link->lldp_tx_event_source); + link->lldp_emit_event_source = sd_event_source_unref(link->lldp_emit_event_source); +} + +int config_parse_lldp_emit( + 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) { + + LLDPEmit *emit = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) + *emit = LLDP_EMIT_NO; + else if (streq(rvalue, "nearest-bridge")) + *emit = LLDP_EMIT_NEAREST_BRIDGE; + else if (streq(rvalue, "non-tpmr-bridge")) + *emit = LLDP_EMIT_NON_TPMR_BRIDGE; + else if (streq(rvalue, "customer-bridge")) + *emit = LLDP_EMIT_CUSTOMER_BRIDGE; + else { + r = parse_boolean(rvalue); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse LLDP emission setting, ignoring: %s", rvalue); + return 0; + } + + *emit = r ? LLDP_EMIT_NEAREST_BRIDGE : LLDP_EMIT_NO; + } + + return 0; } diff --git a/src/network/networkd-lldp-tx.h b/src/network/networkd-lldp-tx.h index 8c7f403005..4680c9d950 100644 --- a/src/network/networkd-lldp-tx.h +++ b/src/network/networkd-lldp-tx.h @@ -21,5 +21,15 @@ #include "networkd-link.h" -int link_lldp_tx_start(Link *link); -void link_lldp_tx_stop(Link *link); +typedef enum LLDPEmit { + LLDP_EMIT_NO, + LLDP_EMIT_NEAREST_BRIDGE, + LLDP_EMIT_NON_TPMR_BRIDGE, + LLDP_EMIT_CUSTOMER_BRIDGE, + _LLDP_EMIT_MAX, +} LLDPEmit; + +int link_lldp_emit_start(Link *link); +void link_lldp_emit_stop(Link *link); + +int config_parse_lldp_emit(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); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index a9a541559e..4425ee4e2f 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -42,7 +42,7 @@ Network.LinkLocalAddressing, config_parse_address_family_boolean, Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route) Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token) Network.LLDP, config_parse_lldp_mode, 0, offsetof(Network, lldp_mode) -Network.EmitLLDP, config_parse_bool, 0, offsetof(Network, lldp_emit) +Network.EmitLLDP, config_parse_lldp_emit, 0, offsetof(Network, lldp_emit) Network.Address, config_parse_address, 0, 0 Network.Gateway, config_parse_gateway, 0, 0 Network.Domains, config_parse_domains, 0, 0 diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index ff2414efdd..4cd0fa4ab8 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -29,6 +29,7 @@ #include "networkd-address.h" #include "networkd-fdb.h" +#include "networkd-lldp-tx.h" #include "networkd-netdev.h" #include "networkd-route.h" #include "networkd-util.h" @@ -161,7 +162,7 @@ struct Network { DUID duid; LLDPMode lldp_mode; /* LLDP reception */ - bool lldp_emit; /* LLDP transmission */ + LLDPEmit lldp_emit; /* LLDP transmission */ LIST_HEAD(Address, static_addresses); LIST_HEAD(Route, static_routes); -- cgit v1.2.3-54-g00ecf From 77ff6022fa30005f8e965c42064e0274d329b6c0 Mon Sep 17 00:00:00 2001 From: Clemens Gruber Date: Wed, 18 May 2016 01:34:25 +0200 Subject: networkd: Add EmitRouter= option for DHCP Server (#3251) Add an option to disable appending DHCP option 3 (Router) to the DHCP OFFER and ACK packets. This commit adds the boolean option EmitRouter= for the [DHCPServer] section in .network files. Rationale: On embedded devices, it is very useful to have a DHCP server running on an USB OTG ethernet gadget interface to avoid manual setup on the client PCs, but it should only serve IP addresses, no route(r)s. Otherwise, Windows clients experience network connectivity issues, due to them using the address set in DHCP option 3 as default gateway. Signed-off-by: Clemens Gruber --- NEWS | 32 +++++++++++++++------------ man/systemd.network.xml | 10 +++++++++ src/libsystemd-network/dhcp-server-internal.h | 2 ++ src/libsystemd-network/sd-dhcp-server.c | 31 +++++++++++++++++++------- src/network/networkd-link.c | 6 +++++ src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-network.c | 1 + src/network/networkd-network.h | 1 + src/systemd/sd-dhcp-server.h | 1 + 9 files changed, 63 insertions(+), 22 deletions(-) (limited to 'src/network/networkd-network-gperf.gperf') diff --git a/NEWS b/NEWS index ff2dd9abbf..a6e0581879 100644 --- a/NEWS +++ b/NEWS @@ -180,22 +180,26 @@ CHANGES WITH 230 in spe: service. Please leave PrivateDevices= off if you run into problems with this. + * The systemd-networkd DHCP server gained the option EmitRouter=, which + defaults to yes, to configure if the DHCP Option 3 (Router) should be + emitted. + Contributions from: Alban Crequy, Alexander Kuleshov, Alex Crawford, Andrew Eikum, Beniamino Galvani, Benjamin Robin, Benjamin ROBIN, Biao - Lu, Bjørnar Ness, Calvin Owens, Christian Hesse, Colin Guthrie, Daniel - J Walsh, Daniel Mack, Dan Nicholson, daurnimator, David Herrmann, David - R. Hedges, Elias Probst, Emmanuel Gil Peyrot, EMOziko, Evgeny - Vereshchagin, Federico, Felipe Sateler, Filipe Brandenburger, Franck - Bui, frankheckenbach, Georgia Brikis, Harald Hoyer, Hendrik Brueckner, - Hristo Venev, Iago López Galeiras, Ian Kelling, Ismo Puustinen, Jakub - Wilk, Jaroslav Škarvada, Jeff Huang, Joel Holdsworth, kayrus, Klearchos - Chaloulos, Lennart Poettering, Lubomir Rintel, Lukas Nykryn, Lukáš - Nykrýn, Mantas Mikulėnas, Marcel Holtmann, Martin Pitt, Michael Biebl, - michaelolbrich, Michał Bartoszkiewicz, Michal Koutný, Michal Sekletar, - Mike Frysinger, Mike Gilbert, Mingcong Bai, Ming Lin, mulkieran, - muzena, Nalin Dahyabhai, Naohiro Aota, Nathan McSween, Nicolas - Braud-Santoni, Patrik Flykt, Peter Hutterer, Petr Lautrbach, Petros - Angelatos, Piotr Drąg, Rabin Vincent, Robert Węcławski, Ronny + Lu, Bjørnar Ness, Calvin Owens, Christian Hesse, Clemens Gruber, Colin + Guthrie, Daniel J Walsh, Daniel Mack, Dan Nicholson, daurnimator, David + Herrmann, David R. Hedges, Elias Probst, Emmanuel Gil Peyrot, EMOziko, + Evgeny Vereshchagin, Federico, Felipe Sateler, Filipe Brandenburger, + Franck Bui, frankheckenbach, Georgia Brikis, Harald Hoyer, Hendrik + Brueckner, Hristo Venev, Iago López Galeiras, Ian Kelling, Ismo + Puustinen, Jakub Wilk, Jaroslav Škarvada, Jeff Huang, Joel Holdsworth, + kayrus, Klearchos Chaloulos, Lennart Poettering, Lubomir Rintel, Lukas + Nykryn, Lukáš Nykrýn, Mantas Mikulėnas, Marcel Holtmann, Martin Pitt, + Michael Biebl, michaelolbrich, Michał Bartoszkiewicz, Michal Koutný, + Michal Sekletar, Mike Frysinger, Mike Gilbert, Mingcong Bai, Ming Lin, + mulkieran, muzena, Nalin Dahyabhai, Naohiro Aota, Nathan McSween, + Nicolas Braud-Santoni, Patrik Flykt, Peter Hutterer, Petr Lautrbach, + Petros Angelatos, Piotr Drąg, Rabin Vincent, Robert Węcławski, Ronny Chevalier, Samuel Tardieu, Stefan Schallenberg, Steven Siloti, Susant Sahani, Sylvain Plantefève, Taylor Smock, tblume, Tejun Heo, Thomas Blume, Thomas Haller, Thomas Hindoe Paaboel Andersen, Thomas diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 70e3804746..d917fe2c12 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -981,6 +981,16 @@ DNS=. + + EmitRouter= + + Similar to the EmitDNS= + setting described above, this setting configures whether the + DHCP lease should contain the router option. The same syntax, + propagation semantics and defaults apply as for + EmitDNS=. + + EmitTimezone= Timezone= diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h index adb557167a..0c76956fad 100644 --- a/src/libsystemd-network/dhcp-server-internal.h +++ b/src/libsystemd-network/dhcp-server-internal.h @@ -63,6 +63,8 @@ struct sd_dhcp_server { struct in_addr *ntp, *dns; unsigned n_ntp, n_dns; + bool emit_router; + Hashmap *leases_by_client_id; DHCPLease **bound_leases; DHCPLease invalid_lease; diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 9adf8ec19d..fb335337c4 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -468,10 +468,12 @@ static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req, if (r < 0) return r; - r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0, - SD_DHCP_OPTION_ROUTER, 4, &server->address); - if (r < 0) - return r; + if (server->emit_router) { + r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0, + SD_DHCP_OPTION_ROUTER, 4, &server->address); + if (r < 0) + return r; + } r = dhcp_server_send_packet(server, req, packet, DHCP_OFFER, offset); if (r < 0) @@ -505,10 +507,12 @@ static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req, if (r < 0) return r; - r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0, - SD_DHCP_OPTION_ROUTER, 4, &server->address); - if (r < 0) - return r; + if (server->emit_router) { + r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0, + SD_DHCP_OPTION_ROUTER, 4, &server->address); + if (r < 0) + return r; + } if (server->n_dns > 0) { r = dhcp_option_append( @@ -1158,3 +1162,14 @@ int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], u return 1; } + +int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled) { + assert_return(server, -EINVAL); + + if (enabled == server->emit_router) + return 0; + + server->emit_router = enabled; + + return 1; +} diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index f3a79b0ec8..16a3609a0b 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1020,6 +1020,12 @@ static int link_enter_set_addresses(Link *link) { log_link_warning_errno(link, r, "Failed to set NTP server for DHCP server, ignoring: %m"); } + r = sd_dhcp_server_set_emit_router(link->dhcp_server, link->network->dhcp_server_emit_router); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to set router emission for DHCP server: %m"); + return r; + } + if (link->network->dhcp_server_emit_timezone) { _cleanup_free_ char *buffer = NULL; const char *tz = NULL; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 4425ee4e2f..03e4e3b39f 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -95,6 +95,7 @@ DHCPServer.EmitDNS, config_parse_bool, DHCPServer.DNS, config_parse_dhcp_server_dns, 0, 0 DHCPServer.EmitNTP, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_ntp) DHCPServer.NTP, config_parse_dhcp_server_ntp, 0, 0 +DHCPServer.EmitRouter, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_router) DHCPServer.EmitTimezone, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_timezone) DHCPServer.Timezone, config_parse_timezone, 0, offsetof(Network, dhcp_server_timezone) DHCPServer.PoolOffset, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_offset) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 206c270e50..dd89b3770c 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -113,6 +113,7 @@ static int network_load_one(Manager *manager, const char *filename) { network->dhcp_server_emit_dns = true; network->dhcp_server_emit_ntp = true; + network->dhcp_server_emit_router = true; network->dhcp_server_emit_timezone = true; network->use_bpdu = true; diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 4cd0fa4ab8..91099161ce 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -127,6 +127,7 @@ struct Network { bool dhcp_server_emit_ntp; struct in_addr *dhcp_server_ntp; unsigned n_dhcp_server_ntp; + bool dhcp_server_emit_router; bool dhcp_server_emit_timezone; char *dhcp_server_timezone; usec_t dhcp_server_default_lease_time_usec, dhcp_server_max_lease_time_usec; diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h index fcef083ce6..d4517a26d6 100644 --- a/src/systemd/sd-dhcp-server.h +++ b/src/systemd/sd-dhcp-server.h @@ -51,6 +51,7 @@ int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *addres int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *timezone); int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr ntp[], unsigned n); int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr dns[], unsigned n); +int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled); int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint32_t t); int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t); -- cgit v1.2.3-54-g00ecf