summaryrefslogtreecommitdiff
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/networkctl.c22
-rw-r--r--src/network/networkd-address.c17
-rw-r--r--src/network/networkd-address.h1
-rw-r--r--src/network/networkd-dhcp4.c4
-rw-r--r--src/network/networkd-dhcp6.c96
-rw-r--r--src/network/networkd-fdb.c2
-rw-r--r--src/network/networkd-ipv4ll.c8
-rw-r--r--src/network/networkd-link-bus.c5
-rw-r--r--src/network/networkd-link.c301
-rw-r--r--src/network/networkd-link.h13
-rw-r--r--src/network/networkd-manager.c19
-rw-r--r--src/network/networkd-ndisc.c191
-rw-r--r--src/network/networkd-netdev-bond.c21
-rw-r--r--src/network/networkd-netdev-bridge.c2
-rw-r--r--src/network/networkd-netdev-tuntap.c2
-rw-r--r--src/network/networkd-netdev-veth.c1
-rw-r--r--src/network/networkd-netdev-vxlan.c5
-rw-r--r--src/network/networkd-netdev.c6
-rw-r--r--src/network/networkd-route.c8
-rw-r--r--src/network/networkd-route.h2
-rw-r--r--src/network/networkd-util.c10
-rw-r--r--src/network/test-network-tables.c9
-rw-r--r--src/network/test-network.c4
23 files changed, 517 insertions, 232 deletions
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
index ba7e3ba74a..6fcb3050c7 100644
--- a/src/network/networkctl.c
+++ b/src/network/networkctl.c
@@ -36,7 +36,6 @@
#include "lldp.h"
#include "local-addresses.h"
#include "locale-util.h"
-#include "locale-util.h"
#include "netlink-util.h"
#include "pager.h"
#include "parse-util.h"
@@ -910,12 +909,10 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) {
_cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
_cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
_cleanup_free_ LinkInfo *links = NULL;
- const char *state, *word;
-
double ttl = -1;
uint32_t capability;
int i, r, c, j;
- size_t ll;
+ const char *p;
char **s;
pager_open_if_enabled();
@@ -956,14 +953,19 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) {
return -ENOMEM;
STRV_FOREACH(s, l) {
- FOREACH_WORD_QUOTED(word, ll, *s, state) {
- _cleanup_free_ char *t = NULL, *a = NULL, *b = NULL;
- t = strndup(word, ll);
- if (!t)
- return -ENOMEM;
+ p = *s;
+ for (;;) {
+ _cleanup_free_ char *a = NULL, *b = NULL, *word = NULL;
+
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse LLDP syntax \"%s\": %m", *s);
+
+ if (r == 0)
+ break;
- r = split_pair(t, "=", &a, &b);
+ r = split_pair(word, "=", &a, &b);
if (r < 0)
continue;
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index 8b6acf2e1d..c0562e5788 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -248,6 +248,8 @@ static int address_add_internal(Link *link, Set **addresses,
address->family = family;
address->in_addr = *in_addr;
address->prefixlen = prefixlen;
+ /* Consider address tentative until we get the real flags from the kernel */
+ address->flags = IFA_F_TENTATIVE;
r = set_ensure_allocated(addresses, &address_hash_ops);
if (r < 0)
@@ -327,13 +329,13 @@ static int address_release(Address *address) {
int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo) {
bool ready;
+ int r;
assert(address);
assert(cinfo);
ready = address_is_ready(address);
- address->added = true;
address->flags = flags;
address->scope = scope;
address->cinfo = *cinfo;
@@ -341,8 +343,17 @@ int address_update(Address *address, unsigned char flags, unsigned char scope, s
if (address->link) {
link_update_operstate(address->link);
- if (!ready && address_is_ready(address))
+ if (!ready && address_is_ready(address)) {
link_check_ready(address->link);
+
+ if (address->family == AF_INET6 &&
+ in_addr_is_link_local(AF_INET6, &address->in_addr) &&
+ !address->link->ipv6ll_address) {
+ r = link_ipv6ll_gained(address->link);
+ if (r < 0)
+ return r;
+ }
+ }
}
return 0;
@@ -769,5 +780,5 @@ int config_parse_label(const char *unit,
bool address_is_ready(const Address *a) {
assert(a);
- return a->added && !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED));
+ return !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED));
}
diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h
index 0b1f3b688b..4049a23bdc 100644
--- a/src/network/networkd-address.h
+++ b/src/network/networkd-address.h
@@ -52,7 +52,6 @@ struct Address {
union in_addr_union in_addr;
union in_addr_union in_addr_peer;
- bool added:1;
bool ip_masquerade_done:1;
LIST_FIELDS(Address, addresses);
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index b58fc5808c..b9c60a3c77 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -34,7 +34,7 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
int r;
assert(link);
- assert(link->dhcp4_messages);
+ assert(link->dhcp4_messages > 0);
link->dhcp4_messages --;
@@ -44,7 +44,7 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
link_enter_failed(link);
}
- if (!link->dhcp4_messages) {
+ if (link->dhcp4_messages == 0) {
link->dhcp4_configured = true;
link_check_ready(link);
}
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index c3332bb1ac..f83ff54369 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -131,7 +131,8 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
case SD_DHCP6_CLIENT_EVENT_STOP:
case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE:
case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX:
- log_link_warning(link, "DHCPv6 lease lost");
+ if (sd_dhcp6_client_get_lease(client, NULL) >= 0)
+ log_link_warning(link, "DHCPv6 lease lost");
link->dhcp6_configured = false;
break;
@@ -165,83 +166,82 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
link_check_ready(link);
}
-int dhcp6_configure(Link *link, bool inf_req) {
- int r, information_request;
+int dhcp6_request_address(Link *link) {
+ int r, inf_req;
+ bool running;
- assert_return(link, -EINVAL);
+ assert(link);
+ assert(link->dhcp6_client);
- link->dhcp6_configured = false;
+ r = sd_dhcp6_client_get_information_request(link->dhcp6_client, &inf_req);
+ if (r < 0)
+ return r;
- if (link->dhcp6_client) {
- r = sd_dhcp6_client_get_information_request(link->dhcp6_client, &information_request);
- if (r < 0) {
- log_link_warning_errno(link, r, "Could not get DHCPv6 Information request setting: %m");
- goto error;
- }
+ if (!inf_req)
+ return 0;
- if (information_request && !inf_req) {
- r = sd_dhcp6_client_stop(link->dhcp6_client);
- if (r < 0) {
- log_link_warning_errno(link, r, "Could not stop DHCPv6 while setting Managed mode: %m");
- goto error;
- }
+ r = sd_dhcp6_client_is_running(link->dhcp6_client);
+ if (r < 0)
+ return r;
+ else
+ running = !!r;
- r = sd_dhcp6_client_set_information_request(link->dhcp6_client, false);
- if (r < 0) {
- log_link_warning_errno(link, r, "Could not unset DHCPv6 Information request: %m");
- goto error;
- }
+ if (running) {
+ r = sd_dhcp6_client_stop(link->dhcp6_client);
+ if (r < 0)
+ return r;
+ }
- }
+ r = sd_dhcp6_client_set_information_request(link->dhcp6_client, false);
+ if (r < 0)
+ return r;
+ if (running) {
r = sd_dhcp6_client_start(link->dhcp6_client);
- if (r < 0 && r != -EALREADY) {
- log_link_warning_errno(link, r, "Could not restart DHCPv6: %m");
- goto error;
- }
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
- if (r == -EALREADY)
- link->dhcp6_configured = true;
+int dhcp6_configure(Link *link) {
+ sd_dhcp6_client *client = NULL;
+ int r;
+
+ assert(link);
+ r = sd_dhcp6_client_new(&client);
+ if (r < 0)
return r;
- }
- r = sd_dhcp6_client_new(&link->dhcp6_client);
+ r = sd_dhcp6_client_attach_event(client, NULL, 0);
if (r < 0)
goto error;
- r = sd_dhcp6_client_attach_event(link->dhcp6_client, NULL, 0);
+ r = sd_dhcp6_client_set_information_request(client, true);
if (r < 0)
goto error;
- r = sd_dhcp6_client_set_mac(link->dhcp6_client,
+ r = sd_dhcp6_client_set_mac(client,
(const uint8_t *) &link->mac,
sizeof (link->mac), ARPHRD_ETHER);
if (r < 0)
goto error;
- r = sd_dhcp6_client_set_index(link->dhcp6_client, link->ifindex);
+ r = sd_dhcp6_client_set_index(client, link->ifindex);
if (r < 0)
goto error;
- r = sd_dhcp6_client_set_callback(link->dhcp6_client, dhcp6_handler,
- link);
+ r = sd_dhcp6_client_set_callback(client, dhcp6_handler, link);
if (r < 0)
goto error;
- if (inf_req) {
- r = sd_dhcp6_client_set_information_request(link->dhcp6_client, true);
- if (r < 0)
- goto error;
- }
-
- r = sd_dhcp6_client_start(link->dhcp6_client);
- if (r < 0)
- goto error;
+ link->dhcp6_client = client;
- return r;
+ return 0;
- error:
- link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
+error:
+ sd_dhcp6_client_unref(client);
return r;
}
diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c
index c9222b8cb8..6e5480ee22 100644
--- a/src/network/networkd-fdb.c
+++ b/src/network/networkd-fdb.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <net/if.h>
#include <net/ethernet.h>
+#include <net/if.h>
#include "alloc-util.h"
#include "conf-parser.h"
diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c
index ed0d861e7a..f4aac4bb93 100644
--- a/src/network/networkd-ipv4ll.c
+++ b/src/network/networkd-ipv4ll.c
@@ -22,8 +22,8 @@
#include <netinet/ether.h>
#include <linux/if.h>
-#include "networkd-link.h"
#include "network-internal.h"
+#include "networkd-link.h"
static int ipv4ll_address_lost(Link *link) {
_cleanup_address_free_ Address *address = NULL;
@@ -201,7 +201,7 @@ static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){
}
int ipv4ll_configure(Link *link) {
- uint8_t seed[8];
+ uint64_t seed;
int r;
assert(link);
@@ -215,11 +215,11 @@ int ipv4ll_configure(Link *link) {
}
if (link->udev_device) {
- r = net_get_unique_predictable_data(link->udev_device, seed);
+ r = net_get_unique_predictable_data(link->udev_device, &seed);
if (r >= 0) {
assert_cc(sizeof(unsigned) <= 8);
- r = sd_ipv4ll_set_address_seed(link->ipv4ll, *(unsigned *)seed);
+ r = sd_ipv4ll_set_address_seed(link->ipv4ll, (unsigned)seed);
if (r < 0)
return r;
}
diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c
index 11b35d6cf8..d09a3c2d07 100644
--- a/src/network/networkd-link-bus.c
+++ b/src/network/networkd-link-bus.c
@@ -19,13 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "bus-util.h"
-#include "strv.h"
-
#include "alloc-util.h"
+#include "bus-util.h"
#include "networkd-link.h"
#include "networkd.h"
#include "parse-util.h"
+#include "strv.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_operational_state, link_operstate, LinkOperationalState);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_administrative_state, link_state, LinkState);
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 13d2fc6d0d..a415035887 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -111,20 +111,56 @@ static bool link_ipv4_forward_enabled(Link *link) {
if (!link->network)
return false;
+ if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID)
+ return false;
+
return link->network->ip_forward & ADDRESS_FAMILY_IPV4;
}
static bool link_ipv6_forward_enabled(Link *link) {
+
+ if (!socket_ipv6_is_supported())
+ return false;
+
if (link->flags & IFF_LOOPBACK)
return false;
if (!link->network)
return false;
+ if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID)
+ return false;
+
return link->network->ip_forward & ADDRESS_FAMILY_IPV6;
}
+bool link_ipv6_accept_ra_enabled(Link *link) {
+ if (link->flags & IFF_LOOPBACK)
+ return false;
+
+ if (!link->network)
+ return false;
+
+ /* If unset use system default (enabled if local forwarding is disabled.
+ * disabled if local forwarding is enabled).
+ * If set, ignore or enforce RA independent of local forwarding state.
+ */
+ if (link->network->ipv6_accept_ra < 0)
+ /* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */
+ return !link_ipv6_forward_enabled(link);
+ else if (link->network->ipv6_accept_ra > 0)
+ /* accept RA even if ip_forward is enabled */
+ return true;
+ else
+ /* ignore RA */
+ return false;
+}
+
static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) {
+
+ if (!socket_ipv6_is_supported())
+ return _IPV6_PRIVACY_EXTENSIONS_INVALID;
+
if (link->flags & IFF_LOOPBACK)
return _IPV6_PRIVACY_EXTENSIONS_INVALID;
@@ -470,9 +506,6 @@ static int link_stop_clients(Link *link) {
assert(link->manager);
assert(link->manager->event);
- if (!link->network)
- return 0;
-
if (link->dhcp_client) {
k = sd_dhcp_client_stop(link->dhcp_client);
if (k < 0)
@@ -485,13 +518,13 @@ static int link_stop_clients(Link *link) {
r = log_link_warning_errno(link, r, "Could not stop IPv4 link-local: %m");
}
- if(link->ndisc_router_discovery) {
- if (link->dhcp6_client) {
- k = sd_dhcp6_client_stop(link->dhcp6_client);
- if (k < 0)
- r = log_link_warning_errno(link, r, "Could not stop DHCPv6 client: %m");
- }
+ if (link->dhcp6_client) {
+ k = sd_dhcp6_client_stop(link->dhcp6_client);
+ if (k < 0)
+ r = log_link_warning_errno(link, r, "Could not stop DHCPv6 client: %m");
+ }
+ if (link->ndisc_router_discovery) {
k = sd_ndisc_stop(link->ndisc_router_discovery);
if (k < 0)
r = log_link_warning_errno(link, r, "Could not stop IPv6 Router Discovery: %m");
@@ -581,6 +614,10 @@ void link_check_ready(Link *link) {
!link->ipv4ll_route)
return;
+ if (link_ipv6ll_enabled(link))
+ if (!link->ipv6ll_address)
+ return;
+
if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) &&
!link->dhcp4_configured) ||
(link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) &&
@@ -589,6 +626,9 @@ void link_check_ready(Link *link) {
!link->dhcp4_configured && !link->dhcp6_configured))
return;
+ if (link_ipv6_accept_ra_enabled(link) && !link->ndisc_configured)
+ return;
+
SET_FOREACH(a, link->addresses, i)
if (!address_is_ready(a))
return;
@@ -1213,6 +1253,34 @@ static void lldp_handler(sd_lldp *lldp, int event, void *userdata) {
}
}
+static int link_acquire_ipv6_conf(Link *link) {
+ int r;
+
+ assert(link);
+
+ if (link_dhcp6_enabled(link)) {
+ assert(link->dhcp6_client);
+
+ log_link_debug(link, "Acquiring DHCPv6 lease");
+
+ r = sd_dhcp6_client_start(link->dhcp6_client);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease: %m");
+ }
+
+ if (link_ipv6_accept_ra_enabled(link)) {
+ assert(link->ndisc_router_discovery);
+
+ log_link_debug(link, "Discovering IPv6 routers");
+
+ r = sd_ndisc_router_discovery_start(link->ndisc_router_discovery);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not start IPv6 Router Discovery: %m");
+ }
+
+ return 0;
+}
+
static int link_acquire_conf(Link *link) {
int r;
@@ -1241,16 +1309,6 @@ static int link_acquire_conf(Link *link) {
return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m");
}
- if (link_dhcp6_enabled(link)) {
- assert(link->ndisc_router_discovery);
-
- log_link_debug(link, "Discovering IPv6 routers");
-
- r = sd_ndisc_router_discovery_start(link->ndisc_router_discovery);
- if (r < 0)
- return log_link_warning_errno(link, r, "Could not start IPv6 Router Discovery: %m");
- }
-
if (link_lldp_enabled(link)) {
assert(link->lldp);
@@ -1800,55 +1858,43 @@ static int link_enter_join_netdev(Link *link) {
}
static int link_set_ipv4_forward(Link *link) {
- const char *p = NULL, *v;
int r;
- if (link->flags & IFF_LOOPBACK)
- return 0;
-
- if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID)
+ if (!link_ipv4_forward_enabled(link))
return 0;
- p = strjoina("/proc/sys/net/ipv4/conf/", link->ifname, "/forwarding");
- v = one_zero(link_ipv4_forward_enabled(link));
-
- r = write_string_file(p, v, 0);
- if (r < 0) {
- /* If the right value is set anyway, don't complain */
- if (verify_one_line_file(p, v) > 0)
- return 0;
+ /* We propagate the forwarding flag from one interface to the
+ * global setting one way. This means: as long as at least one
+ * interface was configured at any time that had IP forwarding
+ * enabled the setting will stay on for good. We do this
+ * primarily to keep IPv4 and IPv6 packet forwarding behaviour
+ * somewhat in sync (see below). */
- log_link_warning_errno(link, r, "Cannot configure IPv4 forwarding for interface %s: %m", link->ifname);
- }
+ r = write_string_file("/proc/sys/net/ipv4/ip_forward", "1", WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Cannot turn on IPv4 packet forwarding, ignoring: %m");
return 0;
}
static int link_set_ipv6_forward(Link *link) {
- const char *p = NULL, *v = NULL;
int r;
- /* Make this a NOP if IPv6 is not available */
- if (!socket_ipv6_is_supported())
+ if (!link_ipv6_forward_enabled(link))
return 0;
- if (link->flags & IFF_LOOPBACK)
- return 0;
-
- if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID)
- return 0;
-
- p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/forwarding");
- v = one_zero(link_ipv6_forward_enabled(link));
-
- r = write_string_file(p, v, 0);
- if (r < 0) {
- /* If the right value is set anyway, don't complain */
- if (verify_one_line_file(p, v) > 0)
- return 0;
+ /* On Linux, the IPv6 stack does not not know a per-interface
+ * packet forwarding setting: either packet forwarding is on
+ * for all, or off for all. We hence don't bother with a
+ * per-interface setting, but simply propagate the interface
+ * flag, if it is set, to the global flag, one-way. Note that
+ * while IPv4 would allow a per-interface flag, we expose the
+ * same behaviour there and also propagate the setting from
+ * one to all, to keep things simple (see above). */
- log_link_warning_errno(link, r, "Cannot configure IPv6 forwarding for interface: %m");
- }
+ r = write_string_file("/proc/sys/net/ipv6/conf/all/forwarding", "1", WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Cannot configure IPv6 packet forwarding, ignoring: %m");
return 0;
}
@@ -1859,31 +1905,22 @@ static int link_set_ipv6_privacy_extensions(Link *link) {
const char *p = NULL;
int r;
- /* Make this a NOP if IPv6 is not available */
- if (!socket_ipv6_is_supported())
- return 0;
-
s = link_ipv6_privacy_extensions(link);
- if (s == _IPV6_PRIVACY_EXTENSIONS_INVALID)
+ if (s < 0)
return 0;
p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/use_tempaddr");
- xsprintf(buf, "%u", link->network->ipv6_privacy_extensions);
-
- r = write_string_file(p, buf, 0);
- if (r < 0) {
- /* If the right value is set anyway, don't complain */
- if (verify_one_line_file(p, buf) > 0)
- return 0;
+ xsprintf(buf, "%u", (unsigned) link->network->ipv6_privacy_extensions);
+ r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+ if (r < 0)
log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extension for interface: %m");
- }
return 0;
}
static int link_set_ipv6_accept_ra(Link *link) {
- const char *p = NULL, *v = NULL;
+ const char *p = NULL;
int r;
/* Make this a NOP if IPv6 is not available */
@@ -1893,36 +1930,21 @@ static int link_set_ipv6_accept_ra(Link *link) {
if (link->flags & IFF_LOOPBACK)
return 0;
- /* If unset use system default (enabled if local forwarding is disabled.
- * disabled if local forwarding is enabled).
- * If set, ignore or enforce RA independent of local forwarding state.
- */
- if (link->network->ipv6_accept_ra < 0)
- /* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */
- v = "1";
- else if (link->network->ipv6_accept_ra > 0)
- /* "2" means accept RA even if ip_forward is enabled */
- v = "2";
- else
- /* "0" means ignore RA */
- v = "0";
+ if (!link->network)
+ return 0;
p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/accept_ra");
- r = write_string_file(p, v, 0);
- if (r < 0) {
- /* If the right value is set anyway, don't complain */
- if (verify_one_line_file(p, v) > 0)
- return 0;
-
- log_link_warning_errno(link, r, "Cannot configure IPv6 accept_ra for interface: %m");
- }
+ /* We handle router advertisments ourselves, tell the kernel to GTFO */
+ r = write_string_file(p, "0", WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Cannot disable kernel IPv6 accept_ra for interface: %m");
return 0;
}
static int link_set_ipv6_dad_transmits(Link *link) {
- char buf[DECIMAL_STR_MAX(unsigned) + 1];
+ char buf[DECIMAL_STR_MAX(int) + 1];
const char *p = NULL;
int r;
@@ -1933,27 +1955,24 @@ static int link_set_ipv6_dad_transmits(Link *link) {
if (link->flags & IFF_LOOPBACK)
return 0;
+ if (!link->network)
+ return 0;
+
if (link->network->ipv6_dad_transmits < 0)
return 0;
p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/dad_transmits");
+ xsprintf(buf, "%i", link->network->ipv6_dad_transmits);
- xsprintf(buf, "%u", link->network->ipv6_dad_transmits);
-
- r = write_string_file(p, buf, 0);
- if (r < 0) {
- /* If the right value is set anyway, don't complain */
- if (verify_one_line_file(p, buf) > 0)
- return 0;
-
+ r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+ if (r < 0)
log_link_warning_errno(link, r, "Cannot set IPv6 dad transmits for interface: %m");
- }
return 0;
}
static int link_set_ipv6_hop_limit(Link *link) {
- char buf[DECIMAL_STR_MAX(unsigned) + 1];
+ char buf[DECIMAL_STR_MAX(int) + 1];
const char *p = NULL;
int r;
@@ -1964,20 +1983,46 @@ static int link_set_ipv6_hop_limit(Link *link) {
if (link->flags & IFF_LOOPBACK)
return 0;
+ if (!link->network)
+ return 0;
+
if (link->network->ipv6_hop_limit < 0)
return 0;
p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/hop_limit");
+ xsprintf(buf, "%i", link->network->ipv6_hop_limit);
- xsprintf(buf, "%u", link->network->ipv6_hop_limit);
+ r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Cannot set IPv6 hop limit for interface: %m");
- r = write_string_file(p, buf, 0);
- if (r < 0) {
- /* If the right value is set anyway, don't complain */
- if (verify_one_line_file(p, buf) > 0)
- return 0;
+ return 0;
+}
- log_link_warning_errno(link, r, "Cannot set IPv6 hop limit for interface: %m");
+static int link_drop_foreign_config(Link *link) {
+ Address *address;
+ Route *route;
+ Iterator i;
+ int r;
+
+ SET_FOREACH(address, link->addresses_foreign, i) {
+ /* we consider IPv6LL addresses to be managed by the kernel */
+ if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1)
+ continue;
+
+ r = address_remove(address, link, link_address_remove_handler);
+ if (r < 0)
+ return r;
+ }
+
+ SET_FOREACH(route, link->routes_foreign, i) {
+ /* do not touch routes managed by the kernel */
+ if (route->protocol == RTPROT_KERNEL)
+ continue;
+
+ r = route_remove(route, link, link_address_remove_handler);
+ if (r < 0)
+ return r;
}
return 0;
@@ -1990,6 +2035,10 @@ static int link_configure(Link *link) {
assert(link->network);
assert(link->state == LINK_STATE_PENDING);
+ r = link_drop_foreign_config(link);
+ if (r < 0)
+ return r;
+
r = link_set_bridge_fdb(link);
if (r < 0)
return r;
@@ -2041,6 +2090,12 @@ static int link_configure(Link *link) {
}
if (link_dhcp6_enabled(link)) {
+ r = dhcp6_configure(link);
+ if (r < 0)
+ return r;
+ }
+
+ if (link_ipv6_accept_ra_enabled(link)) {
r = ndisc_configure(link);
if (r < 0)
return r;
@@ -2065,6 +2120,12 @@ static int link_configure(Link *link) {
r = link_acquire_conf(link);
if (r < 0)
return r;
+
+ if (link->ipv6ll_address) {
+ r = link_acquire_ipv6_conf(link);
+ if (r < 0)
+ return r;
+ }
}
return link_enter_join_netdev(link);
@@ -2411,12 +2472,33 @@ failed:
return r;
}
+int link_ipv6ll_gained(Link *link) {
+ int r;
+
+ assert(link);
+
+ log_link_info(link, "Gained IPv6LL");
+
+ link->ipv6ll_address = true;
+ link_check_ready(link);
+
+ if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_PENDING, LINK_STATE_UNMANAGED, LINK_STATE_FAILED)) {
+ r = link_acquire_ipv6_conf(link);
+ if (r < 0) {
+ link_enter_failed(link);
+ return r;
+ }
+ }
+
+ return 0;
+}
+
static int link_carrier_gained(Link *link) {
int r;
assert(link);
- if (link->network) {
+ if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_PENDING, LINK_STATE_UNMANAGED, LINK_STATE_FAILED)) {
r = link_acquire_conf(link);
if (r < 0) {
link_enter_failed(link);
@@ -2639,9 +2721,8 @@ int link_save(Link *link) {
sd_dhcp6_lease *dhcp6_lease = NULL;
if (link->dhcp6_client) {
- r = sd_dhcp6_client_get_lease(link->dhcp6_client,
- &dhcp6_lease);
- if (r < 0)
+ r = sd_dhcp6_client_get_lease(link->dhcp6_client, &dhcp6_lease);
+ if (r < 0 && r != -ENOMSG)
log_link_debug(link, "No DHCPv6 lease");
}
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index a22041870e..b564bcbca0 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -95,10 +95,13 @@ struct Link {
unsigned dhcp4_messages;
bool dhcp4_configured;
bool dhcp6_configured;
+ unsigned ndisc_messages;
+ bool ndisc_configured;
sd_ipv4ll *ipv4ll;
- bool ipv4ll_address;
- bool ipv4ll_route;
+ bool ipv4ll_address:1;
+ bool ipv4ll_route:1;
+ bool ipv6ll_address:1;
bool static_configured;
@@ -141,13 +144,16 @@ int link_save(Link *link);
int link_carrier_reset(Link *link);
bool link_has_carrier(Link *link);
+int link_ipv6ll_gained(Link *link);
+
int link_set_mtu(Link *link, uint32_t mtu);
int link_set_hostname(Link *link, const char *hostname);
int link_set_timezone(Link *link, const char *timezone);
int ipv4ll_configure(Link *link);
int dhcp4_configure(Link *link);
-int dhcp6_configure(Link *link, bool information_request);
+int dhcp6_configure(Link *link);
+int dhcp6_request_address(Link *link);
int ndisc_configure(Link *link);
bool link_lldp_enabled(Link *link);
@@ -156,6 +162,7 @@ bool link_ipv6ll_enabled(Link *link);
bool link_dhcp4_server_enabled(Link *link);
bool link_dhcp4_enabled(Link *link);
bool link_dhcp6_enabled(Link *link);
+bool link_ipv6_accept_ra_enabled(Link *link);
const char* link_state_to_string(LinkState s) _const_;
LinkState link_state_from_string(const char *s) _pure_;
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index a5701001c1..42f58fed19 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -577,9 +577,7 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &cinfo);
if (r >= 0) {
- if (cinfo.ifa_valid == CACHE_INFO_INFINITY_LIFE_TIME)
- valid_str = "ever";
- else
+ if (cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME)
valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
cinfo.ifa_valid * USEC_PER_SEC,
USEC_PER_SEC);
@@ -590,7 +588,8 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
switch (type) {
case RTM_NEWADDR:
if (address)
- log_link_debug(link, "Updating address: %s/%u (valid for %s)", buf, prefixlen, valid_str);
+ log_link_debug(link, "Updating address: %s/%u (valid %s%s)", buf, prefixlen,
+ valid_str ? "for " : "forever", valid_str ?: "");
else {
/* An address appeared that we did not request */
r = address_add_foreign(link, family, &in_addr, prefixlen, &address);
@@ -598,7 +597,8 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
log_link_warning_errno(link, r, "Failed to add address %s/%u: %m", buf, prefixlen);
return 0;
} else
- log_link_debug(link, "Adding address: %s/%u (valid for %s)", buf, prefixlen, valid_str);
+ log_link_debug(link, "Adding address: %s/%u (valid %s%s)", buf, prefixlen,
+ valid_str ? "for " : "forever", valid_str ?: "");
}
address_update(address, flags, scope, &cinfo);
@@ -608,10 +608,12 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
case RTM_DELADDR:
if (address) {
- log_link_debug(link, "Removing address: %s/%u (valid for %s)", buf, prefixlen, valid_str);
+ log_link_debug(link, "Removing address: %s/%u (valid %s%s)", buf, prefixlen,
+ valid_str ? "for " : "forever", valid_str ?: "");
address_drop(address);
} else
- log_link_warning(link, "Removing non-existent address: %s/%u (valid for %s)", buf, prefixlen, valid_str);
+ log_link_warning(link, "Removing non-existent address: %s/%u (valid %s%s)", buf, prefixlen,
+ valid_str ? "for " : "forever", valid_str ?: "");
break;
default:
@@ -1091,7 +1093,8 @@ static bool manager_check_idle(void *userdata) {
link_ipv4ll_enabled(link) ||
link_dhcp4_server_enabled(link) ||
link_dhcp4_enabled(link) ||
- link_dhcp6_enabled(link))
+ link_dhcp6_enabled(link) ||
+ link_ipv6_accept_ra_enabled(link))
return false;
}
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c
index 33e692f97f..126f9c0fe9 100644
--- a/src/network/networkd-ndisc.c
+++ b/src/network/networkd-ndisc.c
@@ -20,14 +20,132 @@
***/
#include <netinet/ether.h>
+#include <netinet/icmp6.h>
#include <linux/if.h>
#include "sd-ndisc.h"
#include "networkd-link.h"
-static void ndisc_router_handler(sd_ndisc *nd, int event, void *userdata) {
+static int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+ _cleanup_link_unref_ Link *link = userdata;
+ int r;
+
+ assert(link);
+ assert(link->ndisc_messages > 0);
+
+ link->ndisc_messages --;
+
+ r = sd_netlink_message_get_errno(m);
+ if (r < 0 && r != -EEXIST) {
+ log_link_error_errno(link, r, "Could not set NDisc route or address: %m");
+ link_enter_failed(link);
+ }
+
+ if (link->ndisc_messages == 0) {
+ link->ndisc_configured = true;
+ link_check_ready(link);
+ }
+
+ return 1;
+}
+
+static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen,
+ unsigned lifetime_preferred, unsigned lifetime_valid, void *userdata) {
+ _cleanup_address_free_ Address *address = NULL;
Link *link = userdata;
+ usec_t time_now;
+ int r;
+
+ assert(nd);
+ assert(link);
+ assert(link->network);
+
+ if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return;
+
+ r = address_new(&address);
+ if (r < 0) {
+ log_link_error_errno(link, r, "Could not allocate address: %m");
+ return;
+ }
+
+ assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0);
+
+ address->family = AF_INET6;
+ address->in_addr.in6 = *prefix;
+ if (in_addr_is_null(AF_INET6, (const union in_addr_union *) &link->network->ipv6_token) == 0)
+ memcpy(&address->in_addr.in6 + 8, &link->network->ipv6_token + 8, 8);
+ else {
+ /* see RFC4291 section 2.5.1 */
+ address->in_addr.in6.__in6_u.__u6_addr8[8] = link->mac.ether_addr_octet[0];
+ address->in_addr.in6.__in6_u.__u6_addr8[8] ^= 1 << 1;
+ address->in_addr.in6.__in6_u.__u6_addr8[9] = link->mac.ether_addr_octet[1];
+ address->in_addr.in6.__in6_u.__u6_addr8[10] = link->mac.ether_addr_octet[2];
+ address->in_addr.in6.__in6_u.__u6_addr8[11] = 0xff;
+ address->in_addr.in6.__in6_u.__u6_addr8[12] = 0xfe;
+ address->in_addr.in6.__in6_u.__u6_addr8[13] = link->mac.ether_addr_octet[3];
+ address->in_addr.in6.__in6_u.__u6_addr8[14] = link->mac.ether_addr_octet[4];
+ address->in_addr.in6.__in6_u.__u6_addr8[15] = link->mac.ether_addr_octet[5];
+ }
+ address->prefixlen = prefixlen;
+ address->flags = IFA_F_NOPREFIXROUTE;
+ address->cinfo.ifa_prefered = lifetime_preferred;
+ address->cinfo.ifa_valid = lifetime_valid;
+
+ r = address_configure(address, link, ndisc_netlink_handler, true);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Could not set SLAAC address: %m");
+ link_enter_failed(link);
+ return;
+ }
+
+ link->ndisc_messages ++;
+}
+
+static void ndisc_prefix_onlink_handler(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, unsigned lifetime, void *userdata) {
+ _cleanup_route_free_ Route *route = NULL;
+ Link *link = userdata;
+ usec_t time_now;
+ int r;
+
+ assert(nd);
+ assert(link);
+
+ if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return;
+
+ r = route_new(&route);
+ if (r < 0) {
+ log_link_error_errno(link, r, "Could not allocate route: %m");
+ return;
+ }
+
+ assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0);
+
+ route->family = AF_INET6;
+ route->table = RT_TABLE_MAIN;
+ route->protocol = RTPROT_RA;
+ route->flags = RTM_F_PREFIX;
+ route->dst.in6 = *prefix;
+ route->dst_prefixlen = prefixlen;
+ route->lifetime = time_now + lifetime * USEC_PER_SEC;
+
+ r = route_configure(route, link, ndisc_netlink_handler);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Could not set prefix route: %m");
+ link_enter_failed(link);
+ return;
+ }
+
+ link->ndisc_messages ++;
+}
+
+static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata) {
+ _cleanup_route_free_ Route *route = NULL;
+ Link *link = userdata;
+ usec_t time_now;
+ int r;
assert(link);
assert(link->network);
@@ -36,27 +154,64 @@ static void ndisc_router_handler(sd_ndisc *nd, int event, void *userdata) {
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return;
- switch(event) {
- case SD_NDISC_EVENT_ROUTER_ADVERTISMENT_NONE:
+ if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) {
+ if (flags & ND_RA_FLAG_MANAGED)
+ dhcp6_request_address(link);
+
+ r = sd_dhcp6_client_start(link->dhcp6_client);
+ if (r < 0 && r != -EALREADY)
+ log_link_warning_errno(link, r, "Starting DHCPv6 client on NDisc request failed: %m");
+ }
+
+ if (!gateway)
return;
- case SD_NDISC_EVENT_ROUTER_ADVERTISMENT_OTHER:
- dhcp6_configure(link, true);
+ r = route_new(&route);
+ if (r < 0) {
+ log_link_error_errno(link, r, "Could not allocate route: %m");
+ return;
+ }
- break;
- case SD_NDISC_EVENT_ROUTER_ADVERTISMENT_TIMEOUT:
- case SD_NDISC_EVENT_ROUTER_ADVERTISMENT_MANAGED:
- dhcp6_configure(link, false);
+ assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0);
- break;
+ route->family = AF_INET6;
+ route->table = RT_TABLE_MAIN;
+ route->protocol = RTPROT_RA;
+ route->pref = pref;
+ route->gw.in6 = *gateway;
+ route->lifetime = time_now + lifetime * USEC_PER_SEC;
- default:
- if (event < 0)
- log_link_warning_errno(link, event, "IPv6 Neighbor Discover error: %m");
- else
- log_link_warning(link, "IPv6 Neighbor Discovery unknown event: %d", event);
+ r = route_configure(route, link, ndisc_netlink_handler);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Could not set default route: %m");
+ link_enter_failed(link);
+ return;
+ }
+
+ link->ndisc_messages ++;
+}
+
+static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) {
+ Link *link = userdata;
+ int r;
+ assert(link);
+
+ if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return;
+
+ switch (event) {
+ case SD_NDISC_EVENT_TIMEOUT:
+ dhcp6_request_address(link);
+
+ r = sd_dhcp6_client_start(link->dhcp6_client);
+ if (r < 0 && r != -EALREADY)
+ log_link_warning_errno(link, r, "Starting DHCPv6 client after NDisc timeout failed: %m");
break;
+ case SD_NDISC_EVENT_STOP:
+ break;
+ default:
+ log_link_warning(link, "IPv6 Neighbor Discovery unknown event: %d", event);
}
}
@@ -82,7 +237,11 @@ int ndisc_configure(Link *link) {
return r;
r = sd_ndisc_set_callback(link->ndisc_router_discovery,
- ndisc_router_handler, link);
+ ndisc_router_handler,
+ ndisc_prefix_onlink_handler,
+ ndisc_prefix_autonomous_handler,
+ ndisc_handler,
+ link);
return r;
}
diff --git a/src/network/networkd-netdev-bond.c b/src/network/networkd-netdev-bond.c
index 70105b8aa0..50b9021d09 100644
--- a/src/network/networkd-netdev-bond.c
+++ b/src/network/networkd-netdev-bond.c
@@ -29,8 +29,8 @@
#include "conf-parser.h"
#include "missing.h"
#include "networkd-netdev-bond.h"
-#include "string-util.h"
#include "string-table.h"
+#include "string-util.h"
/*
* Number of seconds between instances where the bonding
@@ -340,8 +340,6 @@ int config_parse_arp_ip_target_address(const char *unit,
void *data,
void *userdata) {
Bond *b = userdata;
- const char *word, *state;
- size_t l;
int r;
assert(filename);
@@ -349,14 +347,19 @@ int config_parse_arp_ip_target_address(const char *unit,
assert(rvalue);
assert(data);
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
+ for (;;) {
_cleanup_free_ ArpIpTarget *buffer = NULL;
_cleanup_free_ char *n = NULL;
int f;
- n = strndup(word, l);
- if (!n)
- return -ENOMEM;
+ r = extract_first_word(&rvalue, &n, NULL, 0);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Bond ARP ip target address, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ if (r == 0)
+ break;
buffer = new0(ArpIpTarget, 1);
if (!buffer)
@@ -380,7 +383,9 @@ int config_parse_arp_ip_target_address(const char *unit,
}
if (b->n_arp_ip_targets > NETDEV_BOND_ARP_TARGETS_MAX)
- log_syntax(unit, LOG_WARNING, filename, line, 0, "More than the maximum number of kernel-supported ARP ip targets specified: %d > %d", b->n_arp_ip_targets, NETDEV_BOND_ARP_TARGETS_MAX);
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "More than the maximum number of kernel-supported ARP ip targets specified: %d > %d",
+ b->n_arp_ip_targets, NETDEV_BOND_ARP_TARGETS_MAX);
return 0;
}
diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c
index 57c58d83b4..a991bdb5fb 100644
--- a/src/network/networkd-netdev-bridge.c
+++ b/src/network/networkd-netdev-bridge.c
@@ -22,9 +22,9 @@
#include <net/if.h>
-#include "networkd-netdev-bridge.h"
#include "missing.h"
#include "netlink-util.h"
+#include "networkd-netdev-bridge.h"
/* callback for brige netdev's parameter set */
static int netdev_bridge_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c
index 851e83537e..3d504a8564 100644
--- a/src/network/networkd-netdev-tuntap.c
+++ b/src/network/networkd-netdev-tuntap.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/ioctl.h>
#include <net/if.h>
+#include <sys/ioctl.h>
#include <linux/if_tun.h>
#include "alloc-util.h"
diff --git a/src/network/networkd-netdev-veth.c b/src/network/networkd-netdev-veth.c
index bee1a16726..773a1ee6d1 100644
--- a/src/network/networkd-netdev-veth.c
+++ b/src/network/networkd-netdev-veth.c
@@ -23,6 +23,7 @@
#include <linux/veth.h>
#include "sd-netlink.h"
+
#include "networkd-netdev-veth.h"
static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
diff --git a/src/network/networkd-netdev-vxlan.c b/src/network/networkd-netdev-vxlan.c
index 755ad2f934..7932b93335 100644
--- a/src/network/networkd-netdev-vxlan.c
+++ b/src/network/networkd-netdev-vxlan.c
@@ -22,10 +22,11 @@
#include <net/if.h>
#include "sd-netlink.h"
-#include "networkd-netdev-vxlan.h"
-#include "networkd-link.h"
+
#include "conf-parser.h"
#include "missing.h"
+#include "networkd-link.h"
+#include "networkd-netdev-vxlan.h"
static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
VxLan *v;
diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index dd0b400c6a..a86a6383da 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -411,7 +411,7 @@ int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *message) {
int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
_cleanup_free_ struct ether_addr *mac = NULL;
- uint8_t result[8];
+ uint64_t result;
size_t l, sz;
uint8_t *v;
int r;
@@ -438,10 +438,10 @@ int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
/* Let's hash the host machine ID plus the container name. We
* use a fixed, but originally randomly created hash key here. */
- siphash24(result, v, sz, HASH_KEY.bytes);
+ result = siphash24(v, sz, HASH_KEY.bytes);
assert_cc(ETH_ALEN <= sizeof(result));
- memcpy(mac->ether_addr_octet, result, ETH_ALEN);
+ memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
/* see eth_random_addr in the kernel */
mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index f4bbd06af1..ed06c21160 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -494,10 +494,18 @@ int route_configure(Route *route, Link *link,
if (r < 0)
return log_error_errno(r, "Could not set scope: %m");
+ r = sd_rtnl_message_route_set_flags(req, route->flags);
+ if (r < 0)
+ return log_error_errno(r, "Colud not set flags: %m");
+
r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
if (r < 0)
return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
+ r = sd_netlink_message_append_u8(req, RTA_PREF, route->pref);
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTA_PREF attribute: %m");
+
r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
if (r < 0)
return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h
index d0a51838ed..b276756674 100644
--- a/src/network/networkd-route.h
+++ b/src/network/networkd-route.h
@@ -40,6 +40,8 @@ struct Route {
unsigned char tos;
uint32_t priority; /* note that ip(8) calls this 'metric' */
unsigned char table;
+ unsigned char pref;
+ unsigned flags;
union in_addr_union gw;
union in_addr_union dst;
diff --git a/src/network/networkd-util.c b/src/network/networkd-util.c
index df091393f6..2545621a93 100644
--- a/src/network/networkd-util.c
+++ b/src/network/networkd-util.c
@@ -79,10 +79,18 @@ int config_parse_address_family_boolean_with_kernel(
assert(rvalue);
assert(data);
+ /* This function is mostly obsolete now. It simply redirects
+ * "kernel" to "no". In older networkd versions we used to
+ * distuingish IPForward=off from IPForward=kernel, where the
+ * former would explicitly turn off forwarding while the
+ * latter would simply not touch the setting. But that logic
+ * is gone, hence silently accept the old setting, but turn it
+ * to "no". */
+
s = address_family_boolean_from_string(rvalue);
if (s < 0) {
if (streq(rvalue, "kernel"))
- s = _ADDRESS_FAMILY_BOOLEAN_INVALID;
+ s = ADDRESS_FAMILY_NO;
else {
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPForward= option, ignoring: %s", rvalue);
return 0;
diff --git a/src/network/test-network-tables.c b/src/network/test-network-tables.c
index 438214015d..ecbbe6c3c9 100644
--- a/src/network/test-network-tables.c
+++ b/src/network/test-network-tables.c
@@ -1,11 +1,10 @@
-#include "networkd.h"
-#include "networkd-netdev-bond.h"
-#include "networkd-netdev-macvlan.h"
#include "dhcp6-internal.h"
#include "dhcp6-protocol.h"
-#include "netlink-internal.h"
#include "ethtool-util.h"
-
+#include "netlink-internal.h"
+#include "networkd-netdev-bond.h"
+#include "networkd-netdev-macvlan.h"
+#include "networkd.h"
#include "test-tables.h"
int main(int argc, char **argv) {
diff --git a/src/network/test-network.c b/src/network/test-network.c
index dbed3795e3..a1a77b6867 100644
--- a/src/network/test-network.c
+++ b/src/network/test-network.c
@@ -20,9 +20,9 @@
***/
#include "alloc-util.h"
-#include "networkd.h"
-#include "network-internal.h"
#include "dhcp-lease-internal.h"
+#include "network-internal.h"
+#include "networkd.h"
static void test_deserialize_in_addr(void) {
_cleanup_free_ struct in_addr *addresses = NULL;