summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Gundersen <teg@jklm.no>2016-03-10 14:38:42 +0100
committerTom Gundersen <teg@jklm.no>2016-03-10 14:38:42 +0100
commitead02a14ede96738250c3aac83adf9ecc1b7e2f1 (patch)
tree2c5a91b5102fe014299ef15f86f30ee3569fe260
parent79c96fd20457f208c752506030295b4cf64a2994 (diff)
parentc83321e6d40b294e73e2881e4a98172c4244323b (diff)
Merge pull request #2818 from vinaykul/master
DHCP DUID and IAID configurability
-rw-r--r--Makefile-man.am7
-rw-r--r--Makefile.am4
-rw-r--r--man/networkd.conf.xml112
-rw-r--r--man/systemd.network.xml6
-rw-r--r--src/libsystemd-network/dhcp-identifier.c2
-rw-r--r--src/libsystemd-network/dhcp-identifier.h41
-rw-r--r--src/libsystemd-network/dhcp6-protocol.h7
-rw-r--r--src/libsystemd-network/network-internal.c28
-rw-r--r--src/libsystemd-network/network-internal.h4
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c48
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c49
-rw-r--r--src/network/networkd-conf.c133
-rw-r--r--src/network/networkd-conf.h32
-rw-r--r--src/network/networkd-dhcp4.c8
-rw-r--r--src/network/networkd-dhcp6.c10
-rw-r--r--src/network/networkd-gperf.gperf18
-rw-r--r--src/network/networkd-link.c18
-rw-r--r--src/network/networkd-manager.c2
-rw-r--r--src/network/networkd-network-gperf.gperf1
-rw-r--r--src/network/networkd-network.h2
-rw-r--r--src/network/networkd.c5
-rw-r--r--src/network/networkd.h5
-rw-r--r--src/systemd/sd-dhcp-client.h4
-rw-r--r--src/systemd/sd-dhcp6-client.h7
24 files changed, 509 insertions, 44 deletions
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 25ba63e075..9cee98ec5a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5390,6 +5390,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 \
@@ -5438,6 +5440,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
@@ -5534,6 +5537,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 @@
+<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<!--
+ 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 <http://www.gnu.org/licenses/>.
+-->
+
+<refentry id="networkd.conf" conditional='ENABLE_NETWORKD'
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <refentryinfo>
+ <title>networkd.conf</title>
+ <productname>systemd</productname>
+
+ <authorgroup>
+ <author>
+ <contrib>Developer</contrib>
+ <firstname>Vinay</firstname>
+ <surname>Kulkarni</surname>
+ <email>kulkarniv@vmware.com</email>
+ </author>
+ </authorgroup>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>networkd.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>networkd.conf</refname>
+ <refname>networkd.conf.d</refname>
+ <refpurpose>Global Network configuration files</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <para><filename>/etc/systemd/networkd.conf</filename></para>
+ <para><filename>/etc/systemd/networkd.conf.d/*.conf</filename></para>
+ <para><filename>/usr/lib/systemd/networkd.conf.d/*.conf</filename></para>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>These configuration files control global network parameters.
+ For e.g. DHCP Unique Identifier (DUID).</para>
+
+ </refsect1>
+
+ <xi:include href="standard-conf.xml" xpointer="main-conf" />
+
+ <refsect1>
+ <title>[DUID] Section Options</title>
+
+ <para>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 <filename>/etc/machine-id</filename> file.</para>
+
+ <para>The configured DHCP DUID should conform to the specification in
+ <ulink url="http://tools.ietf.org/html/rfc3315#section-9">RFC 3315</ulink>,
+ <ulink url="http://tools.ietf.org/html/rfc6355">RFC 6355</ulink>. To configure IAID, see
+ <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum>
+ </citerefentry>.</para>
+
+ <para>The following options are available in <literal>[DUID]</literal> section:</para>
+
+ <variablelist class='network-directives'>
+
+ <varlistentry>
+ <term><varname>Type=</varname></term>
+ <listitem><para>The type of DUID specified in this section. The following values are
+ supported:</para>
+ <para>raw : If <literal>Type=raw</literal>, then <literal>RawData=</literal> specifies
+ the entire DUID. For e.g: <literal>RawData=00:02:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00</literal>
+ 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".</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>RawData=</varname></term>
+ <listitem><para>Specifies the DUID bytes as a single newline-terminated, hexadecimal
+ string, with each byte separated by a ':'.</para></listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ </para>
+ </refsect1>
+
+</refentry>
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.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>IAIDValue=</varname></term>
+ <listitem>
+ <para>Identity Association Identifier for the interface. This is a 32-bit value specified in host byte order.</para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
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 <teg@jklm.no>
+
+ 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 <http://www.gnu.org/licenses/>.
+ ***/
+
+#include <ctype.h>
+
+#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 <teg@jklm.no>
+
+ 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 <http://www.gnu.org/licenses/>.
+***/
+
+#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 <stddef.h>
+#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,