if (link->network->bond)
return false;
- if (STRPTR_IN_SET(link->kind, "can", "vcan"))
+ if (STRPTR_IN_SET(link->kind, "can", "vcan", "vxcan"))
return false;
if (manager_sysctl_ipv6_enabled(link->manager) == 0)
if (link->network->bond)
return false;
- if (STRPTR_IN_SET(link->kind, "can", "vcan"))
+ 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"))
+ 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", "ipip", "gre", "ip6gre", "ip6tnl", "sit", "vti", "vti6", "can", "vcan"))
+ if (STRPTR_IN_SET(link->kind, "vrf", "wireguard", "ipip", "gre", "ip6gre", "ip6tnl", "sit", "vti", "vti6", "can", "vcan", "vxcan", "nlmon"))
return false;
/* L3 or L3S mode do not support ARP. */
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)
- return false;
-
- if (!link->network)
- return false;
-
- if (STRPTR_IN_SET(link->kind, "vrf", "wireguard", "ipip", "gre", "ip6gre", "ip6tnl", "sit", "vti", "vti6", "can", "vcan"))
- return false;
-
- /* 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 (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", "ipip", "gre", "sit", "vti", "can", "vcan"))
+ 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"))
+ 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. */
if (link->master_ifindex > 0 && link->network->bridge)
return true;
- if (!link->enslaved_raw)
- return false;
-
/* TODO: add conditions for other netdevs. */
return false;
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->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;
link_enter_failed(link);
return r;
}
-
- link->address_messages++;
+ if (r > 0)
+ link->address_messages++;
}
LIST_FOREACH(labels, label, link->network->address_labels) {
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");
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)
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->setting_mtu)
return 0;
- r = link_stop_clients(link);
+ r = link_stop_clients(link, false);
if (r < 0) {
link_enter_failed(link);
return r;