#include <netinet/in.h>
#include <linux/if.h>
+#include <linux/if_arp.h>
#include "missing_network.h"
#include "networkd-link.h"
#include "string-table.h"
#include "sysctl-util.h"
-static int link_update_ipv6_sysctl(Link *link) {
+static bool link_is_configured_for_family(Link *link, int family) {
assert(link);
+ if (!link->network)
+ return false;
+
if (link->flags & IFF_LOOPBACK)
+ return false;
+
+ if (family == AF_INET6 && !socket_ipv6_is_supported())
+ return false;
+
+ return true;
+}
+
+static int link_update_ipv6_sysctl(Link *link) {
+ assert(link);
+
+ if (!link_is_configured_for_family(link, AF_INET6))
return 0;
if (!link_ipv6_enabled(link))
static int link_set_proxy_arp(Link *link) {
assert(link);
- if (link->flags & IFF_LOOPBACK)
- return 0;
-
- if (!link->network)
+ if (!link_is_configured_for_family(link, AF_INET))
return 0;
if (link->network->proxy_arp < 0)
assert(link);
assert(IN_SET(family, AF_INET, AF_INET6));
- if (family == AF_INET6 && !socket_ipv6_is_supported())
- return false;
-
- if (link->flags & IFF_LOOPBACK)
- return false;
-
- if (!link->network)
+ if (!link_is_configured_for_family(link, family))
return false;
return link->network->ip_forward & (family == AF_INET ? ADDRESS_FAMILY_IPV4 : ADDRESS_FAMILY_IPV6);
static int link_set_ipv4_rp_filter(Link *link) {
assert(link);
- if (link->flags & IFF_LOOPBACK)
- return 0;
-
- if (!link->network)
+ if (!link_is_configured_for_family(link, AF_INET))
return 0;
if (link->network->ipv4_rp_filter < 0)
assert(link);
assert(link->manager);
- if (!socket_ipv6_is_supported())
- return 0;
-
- if (link->flags & IFF_LOOPBACK)
- return 0;
-
- if (!link->network)
+ if (!link_is_configured_for_family(link, AF_INET6))
return 0;
val = link->network->ipv6_privacy_extensions;
static int link_set_ipv6_accept_ra(Link *link) {
assert(link);
- /* Make this a NOP if IPv6 is not available */
- if (!socket_ipv6_is_supported())
- return 0;
-
- if (link->flags & IFF_LOOPBACK)
- return 0;
-
- if (!link->network)
+ if (!link_is_configured_for_family(link, AF_INET6))
return 0;
return sysctl_write_ip_property(AF_INET6, link->ifname, "accept_ra", "0");
static int link_set_ipv6_dad_transmits(Link *link) {
assert(link);
- /* Make this a NOP if IPv6 is not available */
- if (!socket_ipv6_is_supported())
- return 0;
-
- if (link->flags & IFF_LOOPBACK)
- return 0;
-
- if (!link->network)
+ if (!link_is_configured_for_family(link, AF_INET6))
return 0;
if (link->network->ipv6_dad_transmits < 0)
static int link_set_ipv6_hop_limit(Link *link) {
assert(link);
- /* Make this a NOP if IPv6 is not available */
- if (!socket_ipv6_is_supported())
- return 0;
-
- if (link->flags & IFF_LOOPBACK)
- return 0;
-
- if (!link->network)
+ if (!link_is_configured_for_family(link, AF_INET6))
return 0;
if (link->network->ipv6_hop_limit <= 0)
assert(link);
- if (!socket_ipv6_is_supported())
- return 0;
-
- if (link->flags & IFF_LOOPBACK)
- return 0;
-
- if (!link->network)
+ if (!link_is_configured_for_family(link, AF_INET6))
return 0;
if (link->network->ipv6_proxy_ndp >= 0)
assert(link);
- /* Make this a NOP if IPv6 is not available */
- if (!socket_ipv6_is_supported())
- return 0;
-
- if (link->flags & IFF_LOOPBACK)
- return 0;
-
- if (!link->network)
+ if (!link_is_configured_for_family(link, AF_INET6))
return 0;
if (link->network->ipv6_mtu == 0)
static int link_set_ipv4_accept_local(Link *link) {
assert(link);
- if (link->flags & IFF_LOOPBACK)
+ if (!link_is_configured_for_family(link, AF_INET))
return 0;
if (link->network->ipv4_accept_local < 0)
static int link_set_ipv4_route_localnet(Link *link) {
assert(link);
- if (link->flags & IFF_LOOPBACK)
+ if (!link_is_configured_for_family(link, AF_INET))
return 0;
if (link->network->ipv4_route_localnet < 0)
return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "route_localnet", link->network->ipv4_route_localnet > 0);
}
+static int link_set_ipv4_promote_secondaries(Link *link) {
+ assert(link);
+
+ if (!link_is_configured_for_family(link, AF_INET))
+ return 0;
+
+ /* If promote_secondaries is not set, DHCP will work only as long as the IP address does not
+ * changes between leases. The kernel will remove all secondary IP addresses of an interface
+ * otherwise. The way systemd-networkd works is that the new IP of a lease is added as a
+ * secondary IP and when the primary one expires it relies on the kernel to promote the
+ * secondary IP. See also https://github.com/systemd/systemd/issues/7163 */
+ return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "promote_secondaries", true);
+}
+
int link_set_sysctl(Link *link) {
int r;
if (r < 0)
log_link_warning_errno(link, r, "Cannot set IPv4 reverse path filtering for interface, ignoring: %m");
- /* If promote_secondaries is not set, DHCP will work only as long as the IP address does not
- * changes between leases. The kernel will remove all secondary IP addresses of an interface
- * otherwise. The way systemd-networkd works is that the new IP of a lease is added as a
- * secondary IP and when the primary one expires it relies on the kernel to promote the
- * secondary IP. See also https://github.com/systemd/systemd/issues/7163 */
- r = sysctl_write_ip_property_boolean(AF_INET, link->ifname, "promote_secondaries", true);
+ r = link_set_ipv4_promote_secondaries(link);
if (r < 0)
log_link_warning_errno(link, r, "Cannot enable promote_secondaries for interface, ignoring: %m");