/* SPDX-License-Identifier: LGPL-2.1+ */
-#include <netinet/ether.h>
+#include <netinet/in.h>
#include <linux/if.h>
-#include <linux/can/netlink.h>
#include <unistd.h>
#include "alloc-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "missing_network.h"
+#include "netdev/bond.h"
+#include "netdev/bridge.h"
+#include "netdev/ipvlan.h"
#include "netdev/vrf.h"
#include "netlink-util.h"
#include "network-internal.h"
+#include "networkd-can.h"
#include "networkd-ipv6-proxy-ndp.h"
#include "networkd-lldp-tx.h"
#include "networkd-manager.h"
if (link->network->bond)
return false;
+ if (STRPTR_IN_SET(link->kind, "can", "vcan", "vxcan"))
+ return false;
+
if (manager_sysctl_ipv6_enabled(link->manager) == 0)
return false;
if (link->network->bond)
return false;
+ if (STRPTR_IN_SET(link->kind, "can", "vcan", "vxcan"))
+ return false;
+
return link->network->dhcp & ADDRESS_FAMILY_IPV4;
}
if (link->network->bond)
return false;
+ if (STRPTR_IN_SET(link->kind, "can", "vcan", "vxcan"))
+ return false;
+
return link->network->dhcp_server;
}
-bool link_ipv4ll_enabled(Link *link) {
+bool link_ipv4ll_enabled(Link *link, AddressFamilyBoolean mask) {
assert(link);
+ assert((mask & ~(ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) == 0);
if (link->flags & IFF_LOOPBACK)
return false;
if (!link->network)
return false;
- if (STRPTR_IN_SET(link->kind, "vrf", "wireguard"))
- return false;
-
- if (link->network->bond)
- return false;
-
- return link->network->link_local & ADDRESS_FAMILY_IPV4;
-}
-
-bool link_ipv4ll_fallback_enabled(Link *link) {
- assert(link);
-
- if (link->flags & IFF_LOOPBACK)
+ if (STRPTR_IN_SET(link->kind, "vrf", "wireguard", "ipip", "gre", "ip6gre", "ip6tnl", "sit", "vti", "vti6", "can", "vcan", "vxcan", "nlmon"))
return false;
- if (!link->network)
+ /* L3 or L3S mode do not support ARP. */
+ if (IN_SET(link_get_ipvlan_mode(link), NETDEV_IPVLAN_MODE_L3, NETDEV_IPVLAN_MODE_L3S))
return false;
- if (STRPTR_IN_SET(link->kind, "vrf", "wireguard"))
+ if (link->network->bond)
return false;
if (link->network->bond)
return false;
- return link->network->link_local & ADDRESS_FAMILY_FALLBACK_IPV4;
+ return link->network->link_local & mask;
}
static bool link_ipv6ll_enabled(Link *link) {
if (!link->network)
return false;
- if (STRPTR_IN_SET(link->kind, "vrf", "wireguard"))
+ if (STRPTR_IN_SET(link->kind, "vrf", "wireguard", "ipip", "gre", "sit", "vti", "can", "vcan", "vxcan", "nlmon"))
return false;
if (link->network->bond)
if (manager_sysctl_ipv6_enabled(link->manager) == 0)
return false;
+ if (STRPTR_IN_SET(link->kind, "can", "vcan", "vxcan"))
+ return false;
+
/* DHCPv6 client will not be started if no IPv6 link-local address is configured. */
return link_ipv6ll_enabled(link) || network_has_static_ipv6_addresses(link->network);
}
return link->network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE;
}
-static bool link_lldp_rx_enabled(Link *link) {
- assert(link);
-
- if (link->flags & IFF_LOOPBACK)
- return false;
-
- if (link->iftype != ARPHRD_ETHER)
- return false;
-
- if (!link->network)
- return false;
-
- /* LLDP should be handled on bridge slaves as those have a direct
- * connection to their peers not on the bridge master. Linux doesn't
- * even (by default) forward lldp packets to the bridge master.*/
- if (streq_ptr("bridge", link->kind))
- return false;
-
- return link->network->lldp_mode != LLDP_MODE_NO;
-}
-
-static bool link_lldp_emit_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 != LLDP_EMIT_NO;
-}
-
static bool link_ipv4_forward_enabled(Link *link) {
assert(link);
r = sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "disable_ipv6", disabled);
if (r < 0)
- log_link_warning_errno(link, r, "Cannot %s IPv6 for interface %s: %m",
- enable_disable(!disabled), link->ifname);
+ log_link_warning_errno(link, r, "Cannot %s IPv6: %m", enable_disable(!disabled));
else
log_link_info(link, "IPv6 successfully %sd", enable_disable(!disabled));
/* Even if the link is not managed by networkd, honor IFF_SLAVE flag. */
return true;
- if (!link->enslaved_raw)
- return false;
-
if (!link->network)
return false;
- if (link->network->bridge)
- /* TODO: support the case when link is not managed by networkd. */
+ if (link->master_ifindex > 0 && link->network->bridge)
return true;
+ /* TODO: add conditions for other netdevs. */
+
return false;
}
? ((old & flag) ? (" -" string) : (" +" string)) \
: "")
-static int link_update_flags(Link *link, sd_netlink_message *m) {
+static int link_update_flags(Link *link, sd_netlink_message *m, bool force_update_operstate) {
unsigned flags, unknown_flags_added, unknown_flags_removed, unknown_flags;
uint8_t operstate;
int r;
the state was unchanged */
operstate = link->kernel_operstate;
- if ((link->flags == flags) && (link->kernel_operstate == operstate))
+ if (!force_update_operstate && (link->flags == flags) && (link->kernel_operstate == operstate))
return 0;
if (link->flags != flags) {
return 0;
}
-DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_unref);
-
static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
_cleanup_(link_unrefp) Link *link = NULL;
uint16_t type;
if (r < 0)
return r;
- r = link_update_flags(link, message);
+ r = link_update_flags(link, message, false);
if (r < 0)
return r;
return 0;
}
-static void link_set_state(Link *link, LinkState state) {
+void link_set_state(Link *link, LinkState state) {
assert(link);
if (link->state == state)
static void link_enter_unmanaged(Link *link) {
assert(link);
- log_link_debug(link, "Unmanaged");
-
link_set_state(link, LINK_STATE_UNMANAGED);
link_dirty(link);
}
-int link_stop_clients(Link *link) {
+int link_stop_clients(Link *link, bool may_keep_dhcp) {
int r = 0, k;
assert(link);
assert(link->manager);
assert(link->manager->event);
- if (link->dhcp_client) {
+ dhcp4_release_old_lease(link);
+
+ if (link->dhcp_client && (!may_keep_dhcp || !link->network ||
+ !FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP_ON_STOP))) {
k = sd_dhcp_client_stop(link->dhcp_client);
if (k < 0)
r = log_link_warning_errno(link, k, "Could not stop DHCPv4 client: %m");
link_set_state(link, LINK_STATE_FAILED);
- link_stop_clients(link);
+ link_stop_clients(link, false);
link_dirty(link);
}
continue;
}
- r = routing_policy_rule_configure(rule, link, NULL, false);
+ r = routing_policy_rule_configure(rule, link, NULL);
if (r < 0) {
log_link_warning_errno(link, r, "Could not set routing policy rules: %m");
link_enter_failed(link);
return r;
}
-
- link->routing_policy_rule_messages++;
+ if (r > 0)
+ link->routing_policy_rule_messages++;
}
routing_policy_rule_purge(link->manager, link);
link_enter_failed(link);
return r;
}
-
- link->route_messages++;
+ if (r > 0)
+ link->route_messages++;
}
if (link->route_messages == 0) {
if (!link->addresses_ready) {
link->addresses_ready = true;
link_request_set_routes(link);
+ return;
}
if (!link->static_routes_configured)
if (!link->routing_policy_rules_configured)
return;
- if (link_ipv4ll_enabled(link) && !(link->ipv4ll_address && link->ipv4ll_route))
+ if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4) && !(link->ipv4ll_address && link->ipv4ll_route))
return;
if (link_ipv6ll_enabled(link) &&
return;
if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link)) &&
- !(link->dhcp4_configured || link->dhcp6_configured) &&
- !(link_ipv4ll_fallback_enabled(link) && link->ipv4ll_address && link->ipv4ll_route))
+ !link->dhcp4_configured &&
+ !link->dhcp6_configured &&
+ !(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address && link->ipv4ll_route))
/* When DHCP is enabled, at least one protocol must provide an address, or
* an IPv4ll fallback address must be configured. */
return;
log_debug("Copying NTP server information from %s", link->ifname);
STRV_FOREACH(a, link->network->ntp) {
- struct in_addr ia;
+ union in_addr_union ia;
/* Only look for IPv4 addresses */
- if (inet_pton(AF_INET, *a, &ia) <= 0)
+ if (in_addr_from_string(AF_INET, *a, &ia) <= 0)
continue;
/* Never propagate obviously borked data */
- if (in4_addr_is_null(&ia) || in4_addr_is_localhost(&ia))
+ if (in4_addr_is_null(&ia.in) || in4_addr_is_localhost(&ia.in))
continue;
if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1))
return log_oom();
- addresses[n_addresses++] = ia;
+ addresses[n_addresses++] = ia.in;
}
if (link->network->dhcp_use_ntp && link->dhcp_lease) {
link_enter_failed(link);
return r;
}
-
- link->address_messages++;
+ if (r > 0)
+ link->address_messages++;
}
LIST_FOREACH(labels, label, link->network->address_labels) {
}
static int link_set_bridge_vlan(Link *link) {
- int r = 0;
+ int r;
r = br_vlan_configure(link, link->network->pvid, link->network->br_vid_bitmap, link->network->br_untagged_bitmap);
if (r < 0)
return 0;
}
-static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- int r;
-
- assert(link);
-
- log_link_debug(link, "Set link");
-
- r = sd_netlink_message_get_errno(m);
- if (r < 0 && r != -EEXIST) {
- log_link_error_errno(link, r, "Could not join netdev: %m");
- link_enter_failed(link);
- }
-
- return 1;
-}
-
static int link_configure_after_setting_mtu(Link *link);
static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return 1;
}
-int link_set_mtu(Link *link, uint32_t mtu, bool force) {
+int link_set_mtu(Link *link, uint32_t mtu) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
if (mtu == 0 || link->setting_mtu)
return 0;
- if (force ? link->mtu == mtu : link->mtu >= mtu)
+ if (link->mtu == mtu)
return 0;
log_link_debug(link, "Setting MTU: %" PRIu32, mtu);
return 0;
}
+static bool link_reduces_vlan_mtu(Link *link) {
+ /* See netif_reduces_vlan_mtu() in kernel. */
+ return streq_ptr(link->kind, "macsec");
+}
+
+static uint32_t link_get_requested_mtu_by_stacked_netdevs(Link *link) {
+ uint32_t mtu = 0;
+ NetDev *dev;
+ Iterator i;
+
+ HASHMAP_FOREACH(dev, link->network->stacked_netdevs, i)
+ if (dev->kind == NETDEV_KIND_VLAN && dev->mtu > 0)
+ /* See vlan_dev_change_mtu() in kernel. */
+ mtu = MAX(mtu, link_reduces_vlan_mtu(link) ? dev->mtu + 4 : dev->mtu);
+
+ else if (dev->kind == NETDEV_KIND_MACVLAN && dev->mtu > mtu)
+ /* See macvlan_change_mtu() in kernel. */
+ mtu = dev->mtu;
+
+ return mtu;
+}
+
+static int link_configure_mtu(Link *link) {
+ uint32_t mtu;
+
+ assert(link);
+ assert(link->network);
+
+ if (link->network->mtu > 0)
+ return link_set_mtu(link, link->network->mtu);
+
+ mtu = link_get_requested_mtu_by_stacked_netdevs(link);
+ if (link->mtu >= mtu)
+ return 0;
+
+ log_link_notice(link, "Bumping MTU bytes from %"PRIu32" to %"PRIu32" because of stacked device. "
+ "If it is not desired, then please explicitly specify MTUBytes= setting.",
+ link->mtu, mtu);
+
+ return link_set_mtu(link, mtu);
+}
+
static int set_flags_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
return 0;
}
-static int link_set_bridge(Link *link) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
- int r;
-
- assert(link);
- assert(link->network);
-
- r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
-
- r = sd_rtnl_message_link_set_family(req, PF_BRIDGE);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not set message family: %m");
-
- r = sd_netlink_message_open_container(req, IFLA_PROTINFO);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_PROTINFO attribute: %m");
-
- if (link->network->use_bpdu >= 0) {
- r = sd_netlink_message_append_u8(req, IFLA_BRPORT_GUARD, link->network->use_bpdu);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_GUARD attribute: %m");
- }
-
- if (link->network->hairpin >= 0) {
- r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MODE, link->network->hairpin);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MODE attribute: %m");
- }
-
- if (link->network->fast_leave >= 0) {
- r = sd_netlink_message_append_u8(req, IFLA_BRPORT_FAST_LEAVE, link->network->fast_leave);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_FAST_LEAVE attribute: %m");
- }
-
- if (link->network->allow_port_to_be_root >= 0) {
- r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROTECT, link->network->allow_port_to_be_root);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_PROTECT attribute: %m");
-
- }
-
- if (link->network->unicast_flood >= 0) {
- r = sd_netlink_message_append_u8(req, IFLA_BRPORT_UNICAST_FLOOD, link->network->unicast_flood);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_UNICAST_FLOOD attribute: %m");
- }
-
- if (link->network->multicast_flood >= 0) {
- r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MCAST_FLOOD, link->network->multicast_flood);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MCAST_FLOOD attribute: %m");
- }
-
- if (link->network->multicast_to_unicast >= 0) {
- r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MCAST_TO_UCAST, link->network->multicast_to_unicast);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MCAST_TO_UCAST attribute: %m");
- }
-
- if (link->network->neighbor_suppression >= 0) {
- r = sd_netlink_message_append_u8(req, IFLA_BRPORT_NEIGH_SUPPRESS, link->network->neighbor_suppression);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_NEIGH_SUPPRESS attribute: %m");
- }
-
- if (link->network->learning >= 0) {
- r = sd_netlink_message_append_u8(req, IFLA_BRPORT_LEARNING, link->network->learning);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_LEARNING attribute: %m");
- }
-
- if (link->network->cost != 0) {
- r = sd_netlink_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_COST attribute: %m");
- }
-
- if (link->network->priority != LINK_BRIDGE_PORT_PRIORITY_INVALID) {
- r = sd_netlink_message_append_u16(req, IFLA_BRPORT_PRIORITY, link->network->priority);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_PRIORITY attribute: %m");
- }
-
- r = sd_netlink_message_close_container(req);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_LINKINFO attribute: %m");
-
- r = netlink_call_async(link->manager->rtnl, NULL, req, link_set_handler,
- link_netlink_destroy_callback, link);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
-
- link_ref(link);
-
- return r;
-}
-
-static int link_set_bond_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- int r;
-
- assert(m);
- assert(link);
- assert(link->ifname);
-
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 1;
-
- r = sd_netlink_message_get_errno(m);
- if (r < 0) {
- log_link_warning_errno(link, r, "Could not set bonding interface: %m");
- return 1;
- }
-
- return 1;
-}
-
-static int link_set_bond(Link *link) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
- int r;
-
- assert(link);
- assert(link->network);
-
- r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_NEWLINK, link->network->bond->ifindex);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
-
- r = sd_netlink_message_set_flags(req, NLM_F_REQUEST | NLM_F_ACK);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not set netlink flags: %m");
-
- r = sd_netlink_message_open_container(req, IFLA_LINKINFO);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_PROTINFO attribute: %m");
-
- r = sd_netlink_message_open_container_union(req, IFLA_INFO_DATA, "bond");
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_INFO_DATA attribute: %m");
-
- if (link->network->active_slave) {
- r = sd_netlink_message_append_u32(req, IFLA_BOND_ACTIVE_SLAVE, link->ifindex);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_BOND_ACTIVE_SLAVE attribute: %m");
- }
-
- if (link->network->primary_slave) {
- r = sd_netlink_message_append_u32(req, IFLA_BOND_PRIMARY, link->ifindex);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_BOND_PRIMARY attribute: %m");
- }
-
- r = sd_netlink_message_close_container(req);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_LINKINFO attribute: %m");
-
- r = sd_netlink_message_close_container(req);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_INFO_DATA attribute: %m");
-
- r = netlink_call_async(link->manager->rtnl, NULL, req, link_set_bond_handler,
- link_netlink_destroy_callback, link);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
-
- link_ref(link);
-
- return r;
-}
-
-static int link_lldp_save(Link *link) {
- _cleanup_free_ char *temp_path = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- sd_lldp_neighbor **l = NULL;
- int n = 0, r, i;
-
- assert(link);
- assert(link->lldp_file);
-
- if (!link->lldp) {
- (void) unlink(link->lldp_file);
- return 0;
- }
-
- r = sd_lldp_get_neighbors(link->lldp, &l);
- if (r < 0)
- goto finish;
- if (r == 0) {
- (void) unlink(link->lldp_file);
- goto finish;
- }
-
- n = r;
-
- r = fopen_temporary(link->lldp_file, &f, &temp_path);
- if (r < 0)
- goto finish;
-
- fchmod(fileno(f), 0644);
-
- for (i = 0; i < n; i++) {
- const void *p;
- le64_t u;
- size_t sz;
-
- r = sd_lldp_neighbor_get_raw(l[i], &p, &sz);
- if (r < 0)
- goto finish;
-
- u = htole64(sz);
- (void) fwrite(&u, 1, sizeof(u), f);
- (void) fwrite(p, 1, sz, f);
- }
-
- r = fflush_and_check(f);
- if (r < 0)
- goto finish;
-
- if (rename(temp_path, link->lldp_file) < 0) {
- r = -errno;
- goto finish;
- }
-
-finish:
- if (r < 0) {
- (void) unlink(link->lldp_file);
- if (temp_path)
- (void) unlink(temp_path);
-
- log_link_error_errno(link, r, "Failed to save LLDP data to %s: %m", link->lldp_file);
- }
-
- if (l) {
- for (i = 0; i < n; i++)
- sd_lldp_neighbor_unref(l[i]);
- free(l);
- }
-
- return r;
-}
-
-static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) {
- Link *link = userdata;
- int r;
-
- assert(link);
-
- (void) link_lldp_save(link);
-
- 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_emit_start(link);
- if (r < 0)
- log_link_warning_errno(link, r, "Failed to restart LLDP transmission: %m");
- }
-}
-
static int link_acquire_ipv6_conf(Link *link) {
int r;
assert(link->manager);
assert(link->manager->event);
- if (link_ipv4ll_enabled(link)) {
+ if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4)) {
assert(link->ipv4ll);
log_link_debug(link, "Acquiring IPv4 link-local address");
if (link->kernel_operstate == IF_OPER_UNKNOWN)
/* operstate may not be implemented, so fall back to flags */
- if ((link->flags & IFF_LOWER_UP) && !(link->flags & IFF_DORMANT))
+ if (FLAGS_SET(link->flags, IFF_LOWER_UP | IFF_RUNNING) &&
+ !FLAGS_SET(link->flags, IFF_DORMANT))
return true;
return false;
assert(link->manager);
assert(link->manager->rtnl);
+ if (!socket_ipv6_is_supported())
+ return 0;
+
log_link_debug(link, "Setting address genmode for link");
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
return log_link_error_errno(link, r, "Could not set MAC address: %m");
}
- if (link_ipv6_enabled(link)) {
- r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
-
- /* if the kernel lacks ipv6 support setting IFF_UP fails if any ipv6 options are passed */
- r = sd_netlink_message_open_container(req, AF_INET6);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not open AF_INET6 container: %m");
-
- if (!in_addr_is_null(AF_INET6, &link->network->ipv6_token)) {
- r = sd_netlink_message_append_in6_addr(req, IFLA_INET6_TOKEN, &link->network->ipv6_token.in6);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_INET6_TOKEN: %m");
- }
-
- r = sd_netlink_message_close_container(req);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not close AF_INET6 container: %m");
-
- r = sd_netlink_message_close_container(req);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
- }
-
r = netlink_call_async(link->manager->rtnl, NULL, req, link_up_handler,
link_netlink_destroy_callback, link);
if (r < 0)
return 0;
}
-static int link_up_can(Link *link) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
- int r;
-
- assert(link);
-
- log_link_debug(link, "Bringing CAN link up");
-
- r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
-
- r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not set link flags: %m");
-
- r = netlink_call_async(link->manager->rtnl, NULL, req, link_up_handler,
- link_netlink_destroy_callback, link);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
-
- link_ref(link);
-
- return 0;
-}
-
-static int link_set_can(Link *link) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
- int r;
-
- assert(link);
- assert(link->network);
- assert(link->manager);
- assert(link->manager->rtnl);
-
- log_link_debug(link, "link_set_can");
-
- r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_NEWLINK, link->ifindex);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to allocate netlink message: %m");
-
- r = sd_netlink_message_set_flags(m, NLM_F_REQUEST | NLM_F_ACK);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not set netlink flags: %m");
-
- r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to open netlink container: %m");
-
- r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, link->kind);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_INFO_DATA attribute: %m");
-
- if (link->network->can_bitrate > 0 || link->network->can_sample_point > 0) {
- struct can_bittiming bt = {
- .bitrate = link->network->can_bitrate,
- .sample_point = link->network->can_sample_point,
- };
-
- if (link->network->can_bitrate > UINT32_MAX) {
- log_link_error(link, "bitrate (%zu) too big.", link->network->can_bitrate);
- return -ERANGE;
- }
-
- log_link_debug(link, "Setting bitrate = %d bit/s", bt.bitrate);
- if (link->network->can_sample_point > 0)
- log_link_debug(link, "Setting sample point = %d.%d%%", bt.sample_point / 10, bt.sample_point % 10);
- else
- log_link_debug(link, "Using default sample point");
-
- r = sd_netlink_message_append_data(m, IFLA_CAN_BITTIMING, &bt, sizeof(bt));
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_CAN_BITTIMING attribute: %m");
- }
-
- if (link->network->can_restart_us > 0) {
- char time_string[FORMAT_TIMESPAN_MAX];
- uint64_t restart_ms;
-
- if (link->network->can_restart_us == USEC_INFINITY)
- restart_ms = 0;
- else
- restart_ms = DIV_ROUND_UP(link->network->can_restart_us, USEC_PER_MSEC);
-
- format_timespan(time_string, FORMAT_TIMESPAN_MAX, restart_ms * 1000, MSEC_PER_SEC);
-
- if (restart_ms > UINT32_MAX) {
- log_link_error(link, "restart timeout (%s) too big.", time_string);
- return -ERANGE;
- }
-
- log_link_debug(link, "Setting restart = %s", time_string);
-
- r = sd_netlink_message_append_u32(m, IFLA_CAN_RESTART_MS, restart_ms);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_CAN_RESTART_MS attribute: %m");
- }
-
- if (link->network->can_triple_sampling >= 0) {
- struct can_ctrlmode cm = {
- .mask = CAN_CTRLMODE_3_SAMPLES,
- .flags = link->network->can_triple_sampling ? CAN_CTRLMODE_3_SAMPLES : 0,
- };
-
- log_link_debug(link, "%sabling triple-sampling", link->network->can_triple_sampling ? "En" : "Dis");
-
- r = sd_netlink_message_append_data(m, IFLA_CAN_CTRLMODE, &cm, sizeof(cm));
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append IFLA_CAN_CTRLMODE attribute: %m");
- }
-
- r = sd_netlink_message_close_container(m);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to close netlink container: %m");
-
- r = sd_netlink_message_close_container(m);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to close netlink container: %m");
-
- r = netlink_call_async(link->manager->rtnl, NULL, m, link_set_handler,
- link_netlink_destroy_callback, link);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
-
- link_ref(link);
-
- if (!(link->flags & IFF_UP)) {
- r = link_up_can(link);
- if (r < 0) {
- link_enter_failed(link);
- return r;
- }
- }
-
- log_link_debug(link, "link_set_can done");
-
- return r;
-}
-
static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
if (r < 0)
log_link_warning_errno(link, r, "Could not bring down interface: %m");
- if (streq_ptr(link->kind, "can"))
- link_set_can(link);
-
return 1;
}
-int link_down(Link *link) {
+int link_down(Link *link, link_netlink_message_handler_t callback) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
if (r < 0)
return log_link_error_errno(link, r, "Could not set link flags: %m");
- r = netlink_call_async(link->manager->rtnl, NULL, req, link_down_handler,
+ r = netlink_call_async(link->manager->rtnl, NULL, req,
+ callback ?: link_down_handler,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
}
if (!required_up && link_is_up) {
- r = link_down(link);
+ r = link_down(link, NULL);
if (r < 0)
return r;
} else if (required_up && !link_is_up) {
assert(link);
assert(link->network);
assert(link->enslaving > 0);
- assert(!link->enslaved_raw);
link->enslaving--;
log_link_debug(link, "Joined netdev");
if (link->enslaving == 0) {
- link->enslaved_raw = true;
link_joined(link);
}
link_dirty(link);
link->enslaving = 0;
- link->enslaved_raw = false;
if (link->network->bond) {
if (link->network->bond->state == NETDEV_STATE_READY &&
return false;
}
+static bool link_address_is_dynamic(Link *link, Address *address) {
+ Route *route;
+ Iterator i;
+
+ assert(link);
+ assert(address);
+
+ if (address->cinfo.ifa_prefered != CACHE_INFO_INFINITY_LIFE_TIME)
+ return true;
+
+ /* Even when the address is leased from a DHCP server, networkd assign the address
+ * without lifetime when KeepConfiguration=dhcp. So, let's check that we have
+ * corresponding routes with RTPROT_DHCP. */
+ SET_FOREACH(route, link->routes_foreign, i) {
+ if (route->protocol != RTPROT_DHCP)
+ continue;
+
+ if (address->family != route->family)
+ continue;
+
+ if (in_addr_equal(address->family, &address->in_addr, &route->prefsrc))
+ return true;
+ }
+
+ return false;
+}
+
static int link_drop_foreign_config(Link *link) {
Address *address;
Route *route;
if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1)
continue;
+ if (link_address_is_dynamic(link, address)) {
+ if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
+ continue;
+ } else if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
+ continue;
+
if (link_is_static_address_configured(link, address)) {
r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
if (r < 0)
if (route->protocol == RTPROT_KERNEL)
continue;
+ if (route->protocol == RTPROT_STATIC &&
+ FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
+ continue;
+
+ if (route->protocol == RTPROT_DHCP &&
+ FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
+ continue;
+
if (link_is_static_route_configured(link, route)) {
r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL);
if (r < 0)
return 0;
}
-static int link_update_lldp(Link *link) {
- int r;
-
- assert(link);
-
- if (!link->lldp)
- return 0;
-
- if (link->flags & IFF_UP) {
- r = sd_lldp_start(link->lldp);
- if (r > 0)
- log_link_debug(link, "Started LLDP.");
- } else {
- r = sd_lldp_stop(link->lldp);
- if (r > 0)
- log_link_debug(link, "Stopped LLDP.");
- }
-
- return r;
-}
-
-static int link_configure_can(Link *link) {
- int r;
-
- if (streq_ptr(link->kind, "can")) {
- /* The CAN interface must be down to configure bitrate, etc... */
- if ((link->flags & IFF_UP)) {
- r = link_down(link);
- if (r < 0) {
- link_enter_failed(link);
- return r;
- }
-
- return 0;
- }
-
- return link_set_can(link);
- }
-
- if (!(link->flags & IFF_UP)) {
- r = link_up_can(link);
- if (r < 0) {
- link_enter_failed(link);
- return r;
- }
- }
-
- return 0;
-}
-
static int link_configure(Link *link) {
int r;
assert(link->network);
assert(link->state == LINK_STATE_INITIALIZED);
- if (STRPTR_IN_SET(link->kind, "can", "vcan"))
+ if (STRPTR_IN_SET(link->kind, "can", "vcan", "vxcan"))
return link_configure_can(link);
/* Drop foreign config, but ignore loopback or critical devices.
* We do not want to remove loopback address or addresses used for root NFS. */
- if (!(link->flags & IFF_LOOPBACK) && !(link->network->dhcp_critical)) {
+ if (!(link->flags & IFF_LOOPBACK) &&
+ link->network->keep_configuration != KEEP_CONFIGURATION_YES) {
r = link_drop_foreign_config(link);
if (r < 0)
return r;
if (r < 0)
return r;
- if (link_ipv4ll_enabled(link) || link_ipv4ll_fallback_enabled(link)) {
+ if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) {
r = ipv4ll_configure(link);
if (r < 0)
return r;
}
if (link_lldp_rx_enabled(link)) {
- r = sd_lldp_new(&link->lldp);
- if (r < 0)
- return r;
-
- r = sd_lldp_set_ifindex(link->lldp, link->ifindex);
- if (r < 0)
- return r;
-
- r = sd_lldp_match_capabilities(link->lldp,
- link->network->lldp_mode == LLDP_MODE_ROUTERS_ONLY ?
- SD_LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS :
- SD_LLDP_SYSTEM_CAPABILITIES_ALL);
- if (r < 0)
- return r;
-
- r = sd_lldp_set_filter_address(link->lldp, &link->mac);
- if (r < 0)
- return r;
-
- r = sd_lldp_attach_event(link->lldp, NULL, 0);
- if (r < 0)
- return r;
-
- r = sd_lldp_set_callback(link->lldp, lldp_handler, link);
- if (r < 0)
- return r;
-
- r = link_update_lldp(link);
+ r = link_lldp_rx_configure(link);
if (r < 0)
return r;
}
- r = link_set_mtu(link, link->network->mtu, link->network->mtu_is_set);
+ r = link_configure_mtu(link);
if (r < 0)
return r;
- if (socket_ipv6_is_supported()) {
- r = link_configure_addrgen_mode(link);
- if (r < 0)
- return r;
- }
+ r = link_configure_addrgen_mode(link);
+ if (r < 0)
+ return r;
return link_configure_after_setting_mtu(link);
}
if (link->setting_mtu)
return 0;
- r = link_stop_clients(link);
+ r = link_stop_clients(link, false);
if (r < 0) {
link_enter_failed(link);
return r;
const char *ifname;
uint32_t mtu;
bool had_carrier, carrier_gained, carrier_lost;
- int r;
+ int old_master, r;
assert(link);
assert(link->ifname);
}
}
+ old_master = link->master_ifindex;
+ (void) sd_netlink_message_read_u32(m, IFLA_MASTER, (uint32_t *) &link->master_ifindex);
+
had_carrier = link_has_carrier(link);
- r = link_update_flags(link, m);
+ r = link_update_flags(link, m, old_master != link->master_ifindex);
if (r < 0)
return r;
admin_state, oper_state);
if (link->network) {
- bool space;
+ char **dhcp6_domains = NULL, **dhcp_domains = NULL;
+ const char *dhcp_domainname = NULL, *p;
sd_dhcp6_lease *dhcp6_lease = NULL;
- const char *dhcp_domainname = NULL;
- char **dhcp6_domains = NULL;
- char **dhcp_domains = NULL;
unsigned j;
+ bool space;
fprintf(f, "REQUIRED_FOR_ONLINE=%s\n",
yes_no(link->network->required_for_online));
(void) sd_dhcp6_lease_get_domains(dhcp6_lease, &dhcp6_domains);
}
- ordered_set_print(f, "DOMAINS=", link->network->search_domains);
+ fputs("DOMAINS=", f);
+ space = false;
+ ORDERED_SET_FOREACH(p, link->network->search_domains, i)
+ fputs_with_space(f, p, NULL, &space);
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) {
NDiscDNSSL *dd;
fputc('\n', f);
- ordered_set_print(f, "ROUTE_DOMAINS=", link->network->route_domains);
+ fputs("ROUTE_DOMAINS=", f);
+ space = false;
+ ORDERED_SET_FOREACH(p, link->network->route_domains, i)
+ fputs_with_space(f, p, NULL, &space);
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE) {
NDiscDNSSL *dd;