#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"
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"))
+ if (STRPTR_IN_SET(link->kind, "vrf", "wireguard", "ipip", "gre", "ip6gre", "ip6tnl", "sit", "vti", "vti6", "can", "vcan", "vxcan", "nlmon"))
return false;
- if (link->network->bond)
+ /* 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;
- return link->network->link_local & ADDRESS_FAMILY_IPV4;
-}
-
-bool link_ipv4ll_fallback_enabled(Link *link) {
- assert(link);
-
- if (link->flags & IFF_LOOPBACK)
- return false;
-
- if (!link->network)
- 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);
}
/* 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) {
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);
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;
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;
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);
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 &&
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.
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;
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;
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;