summaryrefslogtreecommitdiff
path: root/src/network/netdev
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/netdev')
-rw-r--r--src/network/netdev/bond.c141
-rw-r--r--src/network/netdev/bond.h28
-rw-r--r--src/network/netdev/bridge.c6
-rw-r--r--src/network/netdev/bridge.h1
-rw-r--r--src/network/netdev/dummy.h1
-rw-r--r--src/network/netdev/fou-tunnel.c129
-rw-r--r--src/network/netdev/fou-tunnel.h36
-rw-r--r--src/network/netdev/geneve.c12
-rw-r--r--src/network/netdev/geneve.h36
-rw-r--r--src/network/netdev/ipvlan.h7
-rw-r--r--src/network/netdev/macvlan.h3
-rw-r--r--src/network/netdev/netdev-gperf.gperf20
-rw-r--r--src/network/netdev/netdev.c156
-rw-r--r--src/network/netdev/netdev.h18
-rw-r--r--src/network/netdev/netdevsim.h1
-rw-r--r--src/network/netdev/tunnel.c193
-rw-r--r--src/network/netdev/tunnel.h55
-rw-r--r--src/network/netdev/tuntap.c20
-rw-r--r--src/network/netdev/tuntap.h1
-rw-r--r--src/network/netdev/vcan.c1
-rw-r--r--src/network/netdev/vcan.h1
-rw-r--r--src/network/netdev/veth.h1
-rw-r--r--src/network/netdev/vlan.h1
-rw-r--r--src/network/netdev/vrf.c5
-rw-r--r--src/network/netdev/vrf.h4
-rw-r--r--src/network/netdev/vxcan.c6
-rw-r--r--src/network/netdev/vxcan.h5
-rw-r--r--src/network/netdev/vxlan.c39
-rw-r--r--src/network/netdev/vxlan.h35
-rw-r--r--src/network/netdev/wireguard.c153
-rw-r--r--src/network/netdev/wireguard.h28
31 files changed, 805 insertions, 338 deletions
diff --git a/src/network/netdev/bond.c b/src/network/netdev/bond.c
index 5840a966ab..550a7f8914 100644
--- a/src/network/netdev/bond.c
+++ b/src/network/netdev/bond.c
@@ -7,6 +7,7 @@
#include "alloc-util.h"
#include "conf-parser.h"
+#include "ether-addr-util.h"
#include "extract-word.h"
#include "missing.h"
#include "netdev/bond.h"
@@ -284,10 +285,34 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlin
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_MIN_LINKS attribute: %m");
}
+ if (b->ad_actor_sys_prio != 0) {
+ r = sd_netlink_message_append_u16(m, IFLA_BOND_AD_ACTOR_SYS_PRIO, b->ad_actor_sys_prio);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_ACTOR_SYS_PRIO attribute: %m");
+ }
+
+ if (b->ad_user_port_key != 0) {
+ r = sd_netlink_message_append_u16(m, IFLA_BOND_AD_USER_PORT_KEY, b->ad_user_port_key);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_USER_PORT_KEY attribute: %m");
+ }
+
+ if (b->ad_actor_system) {
+ r = sd_netlink_message_append_ether_addr(m, IFLA_BOND_AD_ACTOR_SYSTEM, b->ad_actor_system);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_ACTOR_SYSTEM attribute: %m");
+ }
+
r = sd_netlink_message_append_u8(m, IFLA_BOND_ALL_SLAVES_ACTIVE, b->all_slaves_active);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ALL_SLAVES_ACTIVE attribute: %m");
+ if (b->tlb_dynamic_lb >= 0) {
+ r = sd_netlink_message_append_u8(m, IFLA_BOND_TLB_DYNAMIC_LB, b->tlb_dynamic_lb);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_TLB_DYNAMIC_LB attribute: %m");
+ }
+
if (b->arp_interval > 0) {
if (b->n_arp_ip_targets > 0) {
@@ -357,10 +382,8 @@ int config_parse_arp_ip_target_address(const char *unit,
return 0;
}
- LIST_PREPEND(arp_ip_target, b->arp_ip_targets, buffer);
+ LIST_PREPEND(arp_ip_target, b->arp_ip_targets, TAKE_PTR(buffer));
b->n_arp_ip_targets++;
-
- buffer = NULL;
}
if (b->n_arp_ip_targets > NETDEV_BOND_ARP_TARGETS_MAX)
@@ -371,6 +394,115 @@ int config_parse_arp_ip_target_address(const char *unit,
return 0;
}
+int config_parse_ad_actor_sys_prio(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+ Bond *b = userdata;
+ uint16_t v;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = safe_atou16(rvalue, &v);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse actor system priority '%s', ignoring: %m", rvalue);
+ return 0;
+ }
+
+ if (v == 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse actor system priority '%s'. Range is [1,65535], ignoring.", rvalue);
+ return 0;
+ }
+
+ b->ad_actor_sys_prio = v;
+
+ return 0;
+}
+
+int config_parse_ad_user_port_key(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+ Bond *b = userdata;
+ uint16_t v;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = safe_atou16(rvalue, &v);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse user port key '%s', ignoring: %m", rvalue);
+ return 0;
+ }
+
+ if (v > 1023) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse user port key '%s'. Range is [0,1023], ignoring.", rvalue);
+ return 0;
+ }
+
+ b->ad_user_port_key = v;
+
+ return 0;
+}
+
+int config_parse_ad_actor_system(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+ Bond *b = userdata;
+ _cleanup_free_ struct ether_addr *n = NULL;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ n = new0(struct ether_addr, 1);
+ if (!n)
+ return log_oom();
+
+ r = ether_addr_from_string(rvalue, n);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Not a valid MAC address %s. Ignoring assignment: %m", rvalue);
+ return 0;
+ }
+
+ if (ether_addr_is_null(n) || (n->ether_addr_octet[0] & 0x01)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address %s, can not be null or multicast. Ignoring assignment.", rvalue);
+ return 0;
+ }
+
+ free_and_replace(b->ad_actor_system, n);
+
+ return 0;
+}
+
static void bond_done(NetDev *netdev) {
ArpIpTarget *t = NULL, *n = NULL;
Bond *b;
@@ -381,6 +513,8 @@ static void bond_done(NetDev *netdev) {
assert(b);
+ free(b->ad_actor_system);
+
LIST_FOREACH_SAFE(arp_ip_target, t, n, b->arp_ip_targets)
free(t);
@@ -406,6 +540,7 @@ static void bond_init(NetDev *netdev) {
b->primary_reselect = _NETDEV_BOND_PRIMARY_RESELECT_INVALID;
b->all_slaves_active = false;
+ b->tlb_dynamic_lb = -1;
b->resend_igmp = RESEND_IGMP_DEFAULT;
b->packets_per_slave = PACKETS_PER_SLAVE_DEFAULT;
diff --git a/src/network/netdev/bond.h b/src/network/netdev/bond.h
index fd68a18985..31b922b032 100644
--- a/src/network/netdev/bond.h
+++ b/src/network/netdev/bond.h
@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-
#include "in-addr-util.h"
#include "list.h"
@@ -100,6 +99,8 @@ typedef struct Bond {
BondArpAllTargets arp_all_targets;
BondPrimaryReselect primary_reselect;
+ int tlb_dynamic_lb;
+
bool all_slaves_active;
unsigned resend_igmp;
@@ -107,6 +108,10 @@ typedef struct Bond {
unsigned num_grat_arp;
unsigned min_links;
+ uint16_t ad_actor_sys_prio;
+ uint16_t ad_user_port_key;
+ struct ether_addr *ad_actor_system;
+
usec_t miimon;
usec_t updelay;
usec_t downdelay;
@@ -144,12 +149,15 @@ BondArpAllTargets bond_arp_all_targets_from_string(const char *d) _pure_;
const char *bond_primary_reselect_to_string(BondPrimaryReselect d) _const_;
BondPrimaryReselect bond_primary_reselect_from_string(const char *d) _pure_;
-int config_parse_bond_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_bond_xmit_hash_policy(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_bond_lacp_rate(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_bond_ad_select(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_bond_fail_over_mac(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_bond_arp_validate(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_bond_arp_all_targets(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_bond_primary_reselect(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_arp_ip_target_address(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+CONFIG_PARSER_PROTOTYPE(config_parse_bond_mode);
+CONFIG_PARSER_PROTOTYPE(config_parse_bond_xmit_hash_policy);
+CONFIG_PARSER_PROTOTYPE(config_parse_bond_lacp_rate);
+CONFIG_PARSER_PROTOTYPE(config_parse_bond_ad_select);
+CONFIG_PARSER_PROTOTYPE(config_parse_bond_fail_over_mac);
+CONFIG_PARSER_PROTOTYPE(config_parse_bond_arp_validate);
+CONFIG_PARSER_PROTOTYPE(config_parse_bond_arp_all_targets);
+CONFIG_PARSER_PROTOTYPE(config_parse_bond_primary_reselect);
+CONFIG_PARSER_PROTOTYPE(config_parse_arp_ip_target_address);
+CONFIG_PARSER_PROTOTYPE(config_parse_ad_actor_sys_prio);
+CONFIG_PARSER_PROTOTYPE(config_parse_ad_user_port_key);
+CONFIG_PARSER_PROTOTYPE(config_parse_ad_actor_system);
diff --git a/src/network/netdev/bridge.c b/src/network/netdev/bridge.c
index be5914a2fa..0c804adb2e 100644
--- a/src/network/netdev/bridge.c
+++ b/src/network/netdev/bridge.c
@@ -9,8 +9,7 @@
#include "vlan-util.h"
/* callback for brige netdev's parameter set */
-static int netdev_bridge_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
- _cleanup_(netdev_unrefp) NetDev *netdev = userdata;
+static int netdev_bridge_set_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev *netdev) {
int r;
assert(netdev);
@@ -129,7 +128,8 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
- r = sd_netlink_call_async(netdev->manager->rtnl, req, netdev_bridge_set_handler, netdev, 0, NULL);
+ r = netlink_call_async(netdev->manager->rtnl, NULL, req, netdev_bridge_set_handler,
+ netdev_destroy_callback, netdev);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
diff --git a/src/network/netdev/bridge.h b/src/network/netdev/bridge.h
index 4854e46953..3edc93a767 100644
--- a/src/network/netdev/bridge.h
+++ b/src/network/netdev/bridge.h
@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-
#include "netdev/netdev.h"
typedef struct Bridge {
diff --git a/src/network/netdev/dummy.h b/src/network/netdev/dummy.h
index f4679a640d..93e0651f7d 100644
--- a/src/network/netdev/dummy.h
+++ b/src/network/netdev/dummy.h
@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-
#include "netdev/netdev.h"
typedef struct Dummy {
diff --git a/src/network/netdev/fou-tunnel.c b/src/network/netdev/fou-tunnel.c
new file mode 100644
index 0000000000..65dad384e2
--- /dev/null
+++ b/src/network/netdev/fou-tunnel.c
@@ -0,0 +1,129 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <linux/ip.h>
+
+#include "conf-parser.h"
+#include "missing.h"
+#include "netdev/fou-tunnel.h"
+#include "networkd-link.h"
+#include "networkd-manager.h"
+#include "parse-util.h"
+#include "sd-netlink.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "util.h"
+
+static const char* const fou_encap_type_table[_NETDEV_FOO_OVER_UDP_ENCAP_MAX] = {
+ [NETDEV_FOO_OVER_UDP_ENCAP_DIRECT] = "FooOverUDP",
+ [NETDEV_FOO_OVER_UDP_ENCAP_GUE] = "GenericUDPEncapsulation",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(fou_encap_type, FooOverUDPEncapType);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_fou_encap_type, fou_encap_type, FooOverUDPEncapType,
+ "Failed to parse Encapsulation=");
+
+static int netdev_fill_fou_tunnel_message(NetDev *netdev, sd_netlink_message **ret) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ FouTunnel *t;
+ int r;
+
+ assert(netdev);
+
+ t = FOU(netdev);
+
+ assert(t);
+
+ r = sd_genl_message_new(netdev->manager->genl, SD_GENL_FOU, FOU_CMD_ADD, &m);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m");
+
+ r = sd_netlink_message_append_u16(m, FOU_ATTR_PORT, htobe16(t->port));
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append FOU_ATTR_PORT attribute: %m");
+
+ r = sd_netlink_message_append_u8(m, FOU_ATTR_TYPE, FOU_ENCAP_GUE);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append FOU_ATTR_TYPE attribute: %m");
+
+ r = sd_netlink_message_append_u8(m, FOU_ATTR_AF, AF_INET);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append FOU_ATTR_AF attribute: %m");
+
+ r = sd_netlink_message_append_u8(m, FOU_ATTR_IPPROTO, t->fou_protocol);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append FOU_ATTR_IPPROTO attribute: %m");
+
+ *ret = m;
+ m = NULL;
+
+ return 0;
+}
+
+static int netdev_fou_tunnel_create(NetDev *netdev) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ uint32_t serial;
+ FouTunnel *t;
+ int r;
+
+ assert(netdev);
+
+ t = FOU(netdev);
+
+ assert(t);
+
+ r = netdev_fill_fou_tunnel_message(netdev, &m);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_send(netdev->manager->genl, m, &serial);
+ if (r < 0 && r != -EADDRINUSE)
+ return log_netdev_error_errno(netdev, r, "Failed to add FooOverUDP tunnel: %m");
+
+ return 0;
+}
+
+static int netdev_fou_tunnel_verify(NetDev *netdev, const char *filename) {
+ FouTunnel *t;
+
+ assert(netdev);
+ assert(filename);
+
+ t = FOU(netdev);
+
+ assert(t);
+
+ if (t->fou_encap_type == NETDEV_FOO_OVER_UDP_ENCAP_DIRECT && t->fou_protocol <= 0) {
+ log_netdev_error(netdev, "FooOverUDP protocol not configured in %s. Rejecting configuration.", filename);
+ return -EINVAL;
+ }
+
+ if (t->fou_encap_type == NETDEV_FOO_OVER_UDP_ENCAP_GUE && t->fou_protocol > 0) {
+ log_netdev_error(netdev, "FooOverUDP GUE can't be set with protocol configured in %s. Rejecting configuration.", filename);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void fou_tunnel_init(NetDev *netdev) {
+ FouTunnel *t;
+
+ assert(netdev);
+
+ t = FOU(netdev);
+
+ assert(t);
+
+ t->fou_encap_type = NETDEV_FOO_OVER_UDP_ENCAP_DIRECT;
+}
+
+const NetDevVTable foutnl_vtable = {
+ .object_size = sizeof(FouTunnel),
+ .init = fou_tunnel_init,
+ .sections = "Match\0NetDev\0FooOverUDP\0",
+ .create = netdev_fou_tunnel_create,
+ .create_type = NETDEV_CREATE_INDEPENDENT,
+ .config_verify = netdev_fou_tunnel_verify,
+};
diff --git a/src/network/netdev/fou-tunnel.h b/src/network/netdev/fou-tunnel.h
new file mode 100644
index 0000000000..b8abed19bd
--- /dev/null
+++ b/src/network/netdev/fou-tunnel.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#if HAVE_LINUX_FOU_H
+#include <linux/fou.h>
+#endif
+
+#include "in-addr-util.h"
+#include "missing_fou.h"
+#include "netdev/netdev.h"
+
+typedef enum FooOverUDPEncapType {
+ NETDEV_FOO_OVER_UDP_ENCAP_UNSPEC = FOU_ENCAP_UNSPEC,
+ NETDEV_FOO_OVER_UDP_ENCAP_DIRECT = FOU_ENCAP_DIRECT,
+ NETDEV_FOO_OVER_UDP_ENCAP_GUE = FOU_ENCAP_GUE,
+ _NETDEV_FOO_OVER_UDP_ENCAP_MAX,
+ _NETDEV_FOO_OVER_UDP_ENCAP_INVALID = -1,
+} FooOverUDPEncapType;
+
+typedef struct FouTunnel {
+ NetDev meta;
+
+ uint8_t fou_protocol;
+
+ uint16_t port;
+
+ FooOverUDPEncapType fou_encap_type;
+} FouTunnel;
+
+DEFINE_NETDEV_CAST(FOU, FouTunnel);
+extern const NetDevVTable foutnl_vtable;
+
+const char *fou_encap_type_to_string(FooOverUDPEncapType d) _const_;
+FooOverUDPEncapType fou_encap_type_from_string(const char *d) _pure_;
+
+CONFIG_PARSER_PROTOTYPE(config_parse_fou_encap_type);
diff --git a/src/network/netdev/geneve.c b/src/network/netdev/geneve.c
index 18b6b359f3..089bbfea22 100644
--- a/src/network/netdev/geneve.c
+++ b/src/network/netdev/geneve.c
@@ -2,12 +2,14 @@
#include <net/if.h>
+#include "sd-netlink.h"
+
#include "alloc-util.h"
#include "conf-parser.h"
#include "extract-word.h"
#include "geneve.h"
+#include "netlink-util.h"
#include "parse-util.h"
-#include "sd-netlink.h"
#include "string-util.h"
#include "strv.h"
#include "missing.h"
@@ -17,10 +19,10 @@
#define DEFAULT_GENEVE_DESTINATION_PORT 6081
/* callback for geneve netdev's created without a backing Link */
-static int geneve_netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
- _cleanup_(netdev_unrefp) NetDev *netdev = userdata;
+static int geneve_netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev *netdev) {
int r;
+ assert(netdev);
assert(netdev->state != _NETDEV_STATE_INVALID);
r = sd_netlink_message_get_errno(m);
@@ -135,12 +137,12 @@ static int netdev_geneve_create(NetDev *netdev) {
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
- r = sd_netlink_call_async(netdev->manager->rtnl, m, geneve_netdev_create_handler, netdev, 0, NULL);
+ r = netlink_call_async(netdev->manager->rtnl, NULL, m, geneve_netdev_create_handler,
+ netdev_destroy_callback, netdev);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
netdev_ref(netdev);
-
netdev->state = NETDEV_STATE_CREATING;
log_netdev_debug(netdev, "Creating");
diff --git a/src/network/netdev/geneve.h b/src/network/netdev/geneve.h
index dab9a4a553..c201981e02 100644
--- a/src/network/netdev/geneve.h
+++ b/src/network/netdev/geneve.h
@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-
typedef struct Geneve Geneve;
#include "in-addr-util.h"
@@ -34,35 +33,6 @@ struct Geneve {
DEFINE_NETDEV_CAST(GENEVE, Geneve);
extern const NetDevVTable geneve_vtable;
-int config_parse_geneve_vni(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata);
-
-int config_parse_geneve_address(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata);
-
-int config_parse_geneve_flow_label(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata);
+CONFIG_PARSER_PROTOTYPE(config_parse_geneve_vni);
+CONFIG_PARSER_PROTOTYPE(config_parse_geneve_address);
+CONFIG_PARSER_PROTOTYPE(config_parse_geneve_flow_label);
diff --git a/src/network/netdev/ipvlan.h b/src/network/netdev/ipvlan.h
index 8b698ebd1a..fb426d37e5 100644
--- a/src/network/netdev/ipvlan.h
+++ b/src/network/netdev/ipvlan.h
@@ -1,10 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-
#include <linux/if_link.h>
-#include "missing.h"
+#include "missing_if_link.h"
#include "netdev/netdev.h"
typedef enum IPVlanMode {
@@ -39,5 +38,5 @@ IPVlanMode ipvlan_mode_from_string(const char *d) _pure_;
const char *ipvlan_flags_to_string(IPVlanFlags d) _const_;
IPVlanFlags ipvlan_flags_from_string(const char *d) _pure_;
-int config_parse_ipvlan_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_ipvlan_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+CONFIG_PARSER_PROTOTYPE(config_parse_ipvlan_mode);
+CONFIG_PARSER_PROTOTYPE(config_parse_ipvlan_flags);
diff --git a/src/network/netdev/macvlan.h b/src/network/netdev/macvlan.h
index dcc0a3fd35..b473f1e19f 100644
--- a/src/network/netdev/macvlan.h
+++ b/src/network/netdev/macvlan.h
@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-
typedef struct MacVlan MacVlan;
#include "netdev/netdev.h"
@@ -29,4 +28,4 @@ extern const NetDevVTable macvtap_vtable;
const char *macvlan_mode_to_string(MacVlanMode d) _const_;
MacVlanMode macvlan_mode_from_string(const char *d) _pure_;
-int config_parse_macvlan_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+CONFIG_PARSER_PROTOTYPE(config_parse_macvlan_mode);
diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf
index dfcac9adbf..f7ca98fa46 100644
--- a/src/network/netdev/netdev-gperf.gperf
+++ b/src/network/netdev/netdev-gperf.gperf
@@ -19,6 +19,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
#include "netdev/netdev.h"
#include "netdev/vxcan.h"
#include "netdev/wireguard.h"
+#include "netdev/fou-tunnel.h"
#include "vlan-util.h"
%}
struct ConfigPerfItem;
@@ -65,6 +66,17 @@ Tunnel.CopyDSCP, config_parse_bool, 0,
Tunnel.EncapsulationLimit, config_parse_encap_limit, 0, offsetof(Tunnel, encap_limit)
Tunnel.Independent, config_parse_bool, 0, offsetof(Tunnel, independent)
Tunnel.AllowLocalRemote, config_parse_tristate, 0, offsetof(Tunnel, allow_localremote)
+Tunnel.FooOverUDP, config_parse_bool, 0, offsetof(Tunnel, fou_tunnel)
+Tunnel.FOUDestinationPort, config_parse_ip_port, 0, offsetof(Tunnel, fou_destination_port)
+Tunnel.FOUSourcePort, config_parse_ip_port, 0, offsetof(Tunnel, encap_src_port)
+Tunnel.Encapsulation, config_parse_fou_encap_type, 0, offsetof(Tunnel, fou_encap_type)
+Tunnel.IPv6RapidDeploymentPrefix, config_parse_6rd_prefix, 0, 0
+Tunnel.ERSPANIndex, config_parse_uint32, 0, offsetof(Tunnel, erspan_index)
+Tunnel.SerializeTunneledPackets, config_parse_tristate, 0, offsetof(Tunnel, erspan_sequence)
+Tunnel.ISATAP, config_parse_tristate, 0, offsetof(Tunnel, isatap)
+FooOverUDP.Protocol, config_parse_uint8, 0, offsetof(FouTunnel, fou_protocol)
+FooOverUDP.Encapsulation, config_parse_fou_encap_type, 0, offsetof(FouTunnel, fou_encap_type)
+FooOverUDP.Port, config_parse_ip_port, 0, offsetof(FouTunnel, port)
Peer.Name, config_parse_ifname, 0, offsetof(Veth, ifname_peer)
Peer.MACAddress, config_parse_hwaddr, 0, offsetof(Veth, mac_peer)
VXCAN.Peer, config_parse_ifname, 0, offsetof(VxCan, ifname_peer)
@@ -100,7 +112,9 @@ GENEVE.TOS, config_parse_uint8, 0,
GENEVE.TTL, config_parse_uint8, 0, offsetof(Geneve, ttl)
GENEVE.UDPChecksum, config_parse_bool, 0, offsetof(Geneve, udpcsum)
GENEVE.UDP6ZeroCheckSumRx, config_parse_bool, 0, offsetof(Geneve, udp6zerocsumrx)
+GENEVE.UDP6ZeroChecksumRx, config_parse_bool, 0, offsetof(Geneve, udp6zerocsumrx)
GENEVE.UDP6ZeroCheckSumTx, config_parse_bool, 0, offsetof(Geneve, udp6zerocsumtx)
+GENEVE.UDP6ZeroChecksumTx, config_parse_bool, 0, offsetof(Geneve, udp6zerocsumtx)
GENEVE.DestinationPort, config_parse_ip_port, 0, offsetof(Geneve, dest_port)
GENEVE.FlowLabel, config_parse_geneve_flow_label, 0, 0
Tun.OneQueue, config_parse_bool, 0, offsetof(TunTap, one_queue)
@@ -126,13 +140,17 @@ Bond.PrimaryReselectPolicy, config_parse_bond_primary_reselect, 0,
Bond.ResendIGMP, config_parse_unsigned, 0, offsetof(Bond, resend_igmp)
Bond.PacketsPerSlave, config_parse_unsigned, 0, offsetof(Bond, packets_per_slave)
Bond.GratuitousARP, config_parse_unsigned, 0, offsetof(Bond, num_grat_arp)
-Bond.AllSlavesActive, config_parse_unsigned, 0, offsetof(Bond, all_slaves_active)
+Bond.AllSlavesActive, config_parse_bool, 0, offsetof(Bond, all_slaves_active)
+Bond.DynamicTransmitLoadBalancing, config_parse_tristate, 0, offsetof(Bond, tlb_dynamic_lb)
Bond.MinLinks, config_parse_unsigned, 0, offsetof(Bond, min_links)
Bond.MIIMonitorSec, config_parse_sec, 0, offsetof(Bond, miimon)
Bond.UpDelaySec, config_parse_sec, 0, offsetof(Bond, updelay)
Bond.DownDelaySec, config_parse_sec, 0, offsetof(Bond, downdelay)
Bond.ARPIntervalSec, config_parse_sec, 0, offsetof(Bond, arp_interval)
Bond.LearnPacketIntervalSec, config_parse_sec, 0, offsetof(Bond, lp_interval)
+Bond.AdActorSystemPriority, config_parse_ad_actor_sys_prio, 0, offsetof(Bond, ad_actor_sys_prio)
+Bond.AdUserPortKey, config_parse_ad_user_port_key, 0, offsetof(Bond, ad_user_port_key)
+Bond.AdActorSystem, config_parse_ad_actor_system, 0, offsetof(Bond, ad_actor_system)
Bridge.HelloTimeSec, config_parse_sec, 0, offsetof(Bridge, hello_time)
Bridge.MaxAgeSec, config_parse_sec, 0, offsetof(Bridge, max_age)
Bridge.AgeingTimeSec, config_parse_sec, 0, offsetof(Bridge, ageing_time)
diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c
index 82ce88402f..f0e9d00246 100644
--- a/src/network/netdev/netdev.c
+++ b/src/network/netdev/netdev.c
@@ -16,6 +16,7 @@
#include "stat-util.h"
#include "string-table.h"
#include "string-util.h"
+#include "strv.h"
#include "netdev/bridge.h"
#include "netdev/bond.h"
@@ -33,6 +34,7 @@
#include "netdev/vxcan.h"
#include "netdev/wireguard.h"
#include "netdev/netdevsim.h"
+#include "netdev/fou-tunnel.h"
const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
[NETDEV_KIND_BRIDGE] = &bridge_vtable,
@@ -61,6 +63,8 @@ const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
[NETDEV_KIND_VXCAN] = &vxcan_vtable,
[NETDEV_KIND_WIREGUARD] = &wireguard_vtable,
[NETDEV_KIND_NETDEVSIM] = &netdevsim_vtable,
+ [NETDEV_KIND_FOU] = &foutnl_vtable,
+ [NETDEV_KIND_ERSPAN] = &erspan_vtable,
};
static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
@@ -90,45 +94,74 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
[NETDEV_KIND_VXCAN] = "vxcan",
[NETDEV_KIND_WIREGUARD] = "wireguard",
[NETDEV_KIND_NETDEVSIM] = "netdevsim",
+ [NETDEV_KIND_FOU] = "fou",
+ [NETDEV_KIND_ERSPAN] = "erspan",
};
DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
-DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
-static void netdev_cancel_callbacks(NetDev *netdev) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
- netdev_join_callback *callback;
+int config_parse_netdev_kind(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ NetDevKind k, *kind = data;
+
+ assert(rvalue);
+ assert(data);
+
+ k = netdev_kind_from_string(rvalue);
+ if (k < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse netdev kind, ignoring assignment: %s", rvalue);
+ return 0;
+ }
- if (!netdev || !netdev->manager)
- return;
+ if (*kind != _NETDEV_KIND_INVALID && *kind != k) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "Specified netdev kind is different from the previous value '%s', ignoring assignment: %s",
+ netdev_kind_to_string(*kind), rvalue);
+ return 0;
+ }
- rtnl_message_new_synthetic_error(netdev->manager->rtnl, -ENODEV, 0, &m);
+ *kind = k;
- while ((callback = netdev->callbacks)) {
- if (m) {
- assert(callback->link);
- assert(callback->callback);
- assert(netdev->manager);
- assert(netdev->manager->rtnl);
+ return 0;
+}
- callback->callback(netdev->manager->rtnl, m, callback->link);
- }
+static void netdev_callbacks_clear(NetDev *netdev) {
+ netdev_join_callback *callback;
+ if (!netdev)
+ return;
+
+ while ((callback = netdev->callbacks)) {
LIST_REMOVE(callbacks, netdev->callbacks, callback);
link_unref(callback->link);
free(callback);
}
}
-static void netdev_free(NetDev *netdev) {
- if (!netdev)
- return;
-
- netdev_cancel_callbacks(netdev);
-
+static void netdev_detach_from_manager(NetDev *netdev) {
if (netdev->ifname && netdev->manager)
hashmap_remove(netdev->manager->netdevs, netdev->ifname);
+ netdev->manager = NULL;
+}
+
+static NetDev *netdev_free(NetDev *netdev) {
+ assert(netdev);
+
+ netdev_callbacks_clear(netdev);
+
+ netdev_detach_from_manager(netdev);
+
free(netdev->filename);
free(netdev->description);
@@ -153,22 +186,10 @@ static void netdev_free(NetDev *netdev) {
NETDEV_VTABLE(netdev)->done)
NETDEV_VTABLE(netdev)->done(netdev);
- free(netdev);
+ return mfree(netdev);
}
-NetDev *netdev_unref(NetDev *netdev) {
- if (netdev && (-- netdev->n_ref <= 0))
- netdev_free(netdev);
-
- return NULL;
-}
-
-NetDev *netdev_ref(NetDev *netdev) {
- if (netdev)
- assert_se(++ netdev->n_ref >= 2);
-
- return netdev;
-}
+DEFINE_TRIVIAL_REF_UNREF_FUNC(NetDev, netdev, netdev_free);
void netdev_drop(NetDev *netdev) {
if (!netdev || netdev->state == NETDEV_STATE_LINGER)
@@ -178,7 +199,9 @@ void netdev_drop(NetDev *netdev) {
log_netdev_debug(netdev, "netdev removed");
- netdev_cancel_callbacks(netdev);
+ netdev_callbacks_clear(netdev);
+
+ netdev_detach_from_manager(netdev);
netdev_unref(netdev);
@@ -206,12 +229,12 @@ int netdev_get(Manager *manager, const char *name, NetDev **ret) {
static int netdev_enter_failed(NetDev *netdev) {
netdev->state = NETDEV_STATE_FAILED;
- netdev_cancel_callbacks(netdev);
+ netdev_callbacks_clear(netdev);
return 0;
}
-static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_netlink_message_handler_t callback) {
+static int netdev_enslave_ready(NetDev *netdev, Link* link, link_netlink_message_handler_t callback) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
@@ -238,7 +261,8 @@ static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_netlink_message_h
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_MASTER attribute: %m");
- r = sd_netlink_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
+ r = netlink_call_async(netdev->manager->rtnl, NULL, req, callback,
+ link_netlink_destroy_callback, link);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
@@ -282,10 +306,10 @@ static int netdev_enter_ready(NetDev *netdev) {
}
/* callback for netdev's created without a backing Link */
-static int netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
- _cleanup_(netdev_unrefp) NetDev *netdev = userdata;
+static int netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev *netdev) {
int r;
+ assert(netdev);
assert(netdev->state != _NETDEV_STATE_INVALID);
r = sd_netlink_message_get_errno(m);
@@ -303,7 +327,7 @@ static int netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, void *
return 1;
}
-int netdev_enslave(NetDev *netdev, Link *link, sd_netlink_message_handler_t callback) {
+static int netdev_enslave(NetDev *netdev, Link *link, link_netlink_message_handler_t callback) {
int r;
assert(netdev);
@@ -325,13 +349,14 @@ int netdev_enslave(NetDev *netdev, Link *link, sd_netlink_message_handler_t call
/* the netdev is not yet read, save this request for when it is */
netdev_join_callback *cb;
- cb = new0(netdev_join_callback, 1);
+ cb = new(netdev_join_callback, 1);
if (!cb)
return log_oom();
- cb->callback = callback;
- cb->link = link;
- link_ref(link);
+ *cb = (netdev_join_callback) {
+ .callback = callback,
+ .link = link_ref(link),
+ };
LIST_PREPEND(callbacks, netdev->callbacks, cb);
@@ -478,8 +503,7 @@ int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
return 0;
}
-static int netdev_create(NetDev *netdev, Link *link,
- sd_netlink_message_handler_t callback) {
+static int netdev_create(NetDev *netdev, Link *link, link_netlink_message_handler_t callback) {
int r;
assert(netdev);
@@ -546,13 +570,15 @@ static int netdev_create(NetDev *netdev, Link *link,
return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
if (link) {
- r = sd_netlink_call_async(netdev->manager->rtnl, m, callback, link, 0, NULL);
+ r = netlink_call_async(netdev->manager->rtnl, NULL, m, callback,
+ link_netlink_destroy_callback, link);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
link_ref(link);
} else {
- r = sd_netlink_call_async(netdev->manager->rtnl, m, netdev_create_handler, netdev, 0, NULL);
+ r = netlink_call_async(netdev->manager->rtnl, NULL, m, netdev_create_handler,
+ netdev_destroy_callback, netdev);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
@@ -568,7 +594,7 @@ static int netdev_create(NetDev *netdev, Link *link,
}
/* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
-int netdev_join(NetDev *netdev, Link *link, sd_netlink_message_handler_t callback) {
+int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t callback) {
int r;
assert(netdev);
@@ -596,7 +622,7 @@ int netdev_join(NetDev *netdev, Link *link, sd_netlink_message_handler_t callbac
return 0;
}
-static int netdev_load_one(Manager *manager, const char *filename) {
+int netdev_load_one(Manager *manager, const char *filename) {
_cleanup_(netdev_unrefp) NetDev *netdev_raw = NULL, *netdev = NULL;
_cleanup_fclose_ FILE *file = NULL;
const char *dropin_dirname;
@@ -619,13 +645,15 @@ static int netdev_load_one(Manager *manager, const char *filename) {
return 0;
}
- netdev_raw = new0(NetDev, 1);
+ netdev_raw = new(NetDev, 1);
if (!netdev_raw)
return log_oom();
- netdev_raw->n_ref = 1;
- netdev_raw->kind = _NETDEV_KIND_INVALID;
- netdev_raw->state = _NETDEV_STATE_INVALID; /* an invalid state means done() of the implementation won't be called on destruction */
+ *netdev_raw = (NetDev) {
+ .n_ref = 1,
+ .kind = _NETDEV_KIND_INVALID,
+ .state = _NETDEV_STATE_INVALID, /* an invalid state means done() of the implementation won't be called on destruction */
+ };
dropin_dirname = strjoina(basename(filename), ".d");
r = config_parse_many(filename, network_dirs, dropin_dirname,
@@ -669,10 +697,10 @@ static int netdev_load_one(Manager *manager, const char *filename) {
if (NETDEV_VTABLE(netdev)->init)
NETDEV_VTABLE(netdev)->init(netdev);
- r = config_parse(NULL, filename, file,
- NETDEV_VTABLE(netdev)->sections,
- config_item_perf_lookup, network_netdev_gperf_lookup,
- CONFIG_PARSE_WARN, netdev);
+ r = config_parse_many(filename, network_dirs, dropin_dirname,
+ NETDEV_VTABLE(netdev)->sections,
+ config_item_perf_lookup, network_netdev_gperf_lookup,
+ CONFIG_PARSE_WARN, netdev);
if (r < 0)
return r;
@@ -693,6 +721,10 @@ static int netdev_load_one(Manager *manager, const char *filename) {
return log_error_errno(r, "Failed to generate predictable MAC address for %s: %m", netdev->ifname);
}
+ r = hashmap_ensure_allocated(&netdev->manager->netdevs, &string_hash_ops);
+ if (r < 0)
+ return r;
+
r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
if (r < 0)
return r;
@@ -758,14 +790,12 @@ static int netdev_load_one(Manager *manager, const char *filename) {
int netdev_load(Manager *manager) {
_cleanup_strv_free_ char **files = NULL;
- NetDev *netdev;
char **f;
int r;
assert(manager);
- while ((netdev = hashmap_first(manager->netdevs)))
- netdev_unref(netdev);
+ hashmap_clear_with_destructor(manager->netdevs, netdev_unref);
r = conf_files_list_strv(&files, ".netdev", NULL, 0, network_dirs);
if (r < 0)
diff --git a/src/network/netdev/netdev.h b/src/network/netdev/netdev.h
index 8df26c0ac3..bfe1094181 100644
--- a/src/network/netdev/netdev.h
+++ b/src/network/netdev/netdev.h
@@ -1,17 +1,17 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-
#include "sd-netlink.h"
+#include "conf-parser.h"
#include "list.h"
+#include "../networkd-link.h"
#include "time-util.h"
typedef struct netdev_join_callback netdev_join_callback;
-typedef struct Link Link;
struct netdev_join_callback {
- sd_netlink_message_handler_t callback;
+ link_netlink_message_handler_t callback;
Link *link;
LIST_FIELDS(netdev_join_callback, callbacks);
@@ -44,6 +44,8 @@ typedef enum NetDevKind {
NETDEV_KIND_VXCAN,
NETDEV_KIND_WIREGUARD,
NETDEV_KIND_NETDEVSIM,
+ NETDEV_KIND_FOU,
+ NETDEV_KIND_ERSPAN,
_NETDEV_KIND_MAX,
_NETDEV_KIND_INVALID = -1
} NetDevKind;
@@ -72,7 +74,7 @@ typedef struct Condition Condition;
typedef struct NetDev {
Manager *manager;
- int n_ref;
+ unsigned n_ref;
char *filename;
@@ -146,23 +148,23 @@ extern const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX];
#define NETDEV(n) (&(n)->meta)
int netdev_load(Manager *manager);
+int netdev_load_one(Manager *manager, const char *filename);
void netdev_drop(NetDev *netdev);
NetDev *netdev_unref(NetDev *netdev);
NetDev *netdev_ref(NetDev *netdev);
-
+DEFINE_TRIVIAL_DESTRUCTOR(netdev_destroy_callback, NetDev, netdev_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(NetDev*, netdev_unref);
int netdev_get(Manager *manager, const char *name, NetDev **ret);
int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *newlink);
-int netdev_enslave(NetDev *netdev, Link *link, sd_netlink_message_handler_t callback);
int netdev_get_mac(const char *ifname, struct ether_addr **ret);
-int netdev_join(NetDev *netdev, Link *link, sd_netlink_message_handler_t cb);
+int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t cb);
const char *netdev_kind_to_string(NetDevKind d) _const_;
NetDevKind netdev_kind_from_string(const char *d) _pure_;
-int config_parse_netdev_kind(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+CONFIG_PARSER_PROTOTYPE(config_parse_netdev_kind);
/* gperf */
const struct ConfigPerfItem* network_netdev_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
diff --git a/src/network/netdev/netdevsim.h b/src/network/netdev/netdevsim.h
index 7287360f15..d3ed0c0d4f 100644
--- a/src/network/netdev/netdevsim.h
+++ b/src/network/netdev/netdevsim.h
@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-
typedef struct NetDevSim NetDevSim;
#include "netdev/netdev.h"
diff --git a/src/network/netdev/tunnel.c b/src/network/netdev/tunnel.c
index c15ca74717..684edddb5f 100644
--- a/src/network/netdev/tunnel.c
+++ b/src/network/netdev/tunnel.c
@@ -6,6 +6,10 @@
#include <linux/if_tunnel.h>
#include <linux/ip6_tunnel.h>
+#if HAVE_LINUX_FOU_H
+#include <linux/fou.h>
+#endif
+
#include "sd-netlink.h"
#include "conf-parser.h"
@@ -61,6 +65,21 @@ static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_netlin
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
+ if (t->fou_tunnel) {
+
+ r = sd_netlink_message_append_u16(m, IFLA_IPTUN_ENCAP_TYPE, t->fou_encap_type);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_TYPE attribute: %m");
+
+ r = sd_netlink_message_append_u16(m, IFLA_IPTUN_ENCAP_SPORT, htobe16(t->encap_src_port));
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_SPORT attribute: %m");
+
+ r = sd_netlink_message_append_u16(m, IFLA_IPTUN_ENCAP_DPORT, htobe16(t->fou_destination_port));
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_DPORT attribute: %m");
+ }
+
return r;
}
@@ -95,6 +114,29 @@ static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
+ if (t->sixrd_prefixlen > 0) {
+ r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_6RD_PREFIX, &t->sixrd_prefix);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_6RD_PREFIX attribute: %m");
+
+ /* u16 is deliberate here, even though we're passing a netmask that can never be >128. The kernel is
+ * expecting to receive the prefixlen as a u16.
+ */
+ r = sd_netlink_message_append_u16(m, IFLA_IPTUN_6RD_PREFIXLEN, t->sixrd_prefixlen);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_6RD_PREFIXLEN attribute: %m");
+ }
+
+ if (t->isatap >= 0) {
+ uint16_t flags = 0;
+
+ SET_FLAG(flags, SIT_ISATAP, t->isatap);
+
+ r = sd_netlink_message_append_u16(m, IFLA_IPTUN_FLAGS, flags);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLAGS attribute: %m");
+ }
+
return r;
}
@@ -142,6 +184,77 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink
return r;
}
+static int netdev_erspan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
+ uint32_t ikey = 0;
+ uint32_t okey = 0;
+ uint16_t iflags = 0;
+ uint16_t oflags = 0;
+ Tunnel *t;
+ int r;
+
+ assert(netdev);
+
+ t = ERSPAN(netdev);
+
+ assert(t);
+ assert(IN_SET(t->family, AF_INET, AF_UNSPEC));
+ assert(m);
+
+ r = sd_netlink_message_append_u32(m, IFLA_GRE_ERSPAN_INDEX, t->erspan_index);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_ERSPAN_INDEX attribute: %m");
+
+ if (t->key != 0) {
+ ikey = okey = htobe32(t->key);
+ iflags |= GRE_KEY;
+ oflags |= GRE_KEY;
+ }
+
+ if (t->ikey != 0) {
+ ikey = htobe32(t->ikey);
+ iflags |= GRE_KEY;
+ }
+
+ if (t->okey != 0) {
+ okey = htobe32(t->okey);
+ oflags |= GRE_KEY;
+ }
+
+ if (t->erspan_sequence > 0) {
+ iflags |= GRE_SEQ;
+ oflags |= GRE_SEQ;
+ } else if (t->erspan_sequence == 0) {
+ iflags &= ~GRE_SEQ;
+ oflags &= ~GRE_SEQ;
+ }
+
+ r = sd_netlink_message_append_u32(m, IFLA_GRE_IKEY, ikey);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_IKEY attribute: %m");
+
+ r = sd_netlink_message_append_u32(m, IFLA_GRE_OKEY, okey);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_OKEY attribute: %m");
+
+ r = sd_netlink_message_append_u16(m, IFLA_GRE_IFLAGS, iflags);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_IFLAGS attribute: %m");
+
+ r = sd_netlink_message_append_u16(m, IFLA_GRE_OFLAGS, oflags);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_OFLAGS, attribute: %m");
+
+ r = sd_netlink_message_append_in_addr(m, IFLA_GRE_LOCAL, &t->local.in);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
+
+ r = sd_netlink_message_append_in_addr(m, IFLA_GRE_REMOTE, &t->remote.in);
+ if (r < 0)
+ log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_REMOTE attribute: %m");
+
+ return r;
+}
+
static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
Tunnel *t;
int r;
@@ -384,6 +497,9 @@ static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
case NETDEV_KIND_IP6TNL:
t = IP6TNL(netdev);
break;
+ case NETDEV_KIND_ERSPAN:
+ t = ERSPAN(netdev);
+ break;
default:
assert_not_reached("Invalid tunnel kind");
}
@@ -396,17 +512,17 @@ static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
return -EINVAL;
}
- if (IN_SET(netdev->kind, NETDEV_KIND_VTI, NETDEV_KIND_IPIP, NETDEV_KIND_GRE, NETDEV_KIND_GRETAP) &&
+ if (IN_SET(netdev->kind, NETDEV_KIND_VTI, NETDEV_KIND_IPIP, NETDEV_KIND_SIT, NETDEV_KIND_GRE, NETDEV_KIND_GRETAP, NETDEV_KIND_ERSPAN) &&
(t->family != AF_INET || in_addr_is_null(t->family, &t->local))) {
log_netdev_error(netdev,
- "vti/ipip/gre/gretap tunnel without a local IPv4 address configured in %s. Ignoring", filename);
+ "vti/ipip/sit/gre/gretap/erspan tunnel without a local IPv4 address configured in %s. Ignoring", filename);
return -EINVAL;
}
- if (IN_SET(netdev->kind, NETDEV_KIND_VTI6, NETDEV_KIND_IP6TNL, NETDEV_KIND_IP6GRE) &&
+ if (IN_SET(netdev->kind, NETDEV_KIND_VTI6, NETDEV_KIND_IP6TNL, NETDEV_KIND_IP6GRE, NETDEV_KIND_IP6GRETAP) &&
(t->family != AF_INET6 || in_addr_is_null(t->family, &t->local))) {
log_netdev_error(netdev,
- "vti6/ip6tnl/ip6gre tunnel without a local IPv6 address configured in %s. Ignoring", filename);
+ "vti6/ip6tnl/ip6gre/ip6gretap tunnel without a local IPv6 address configured in %s. Ignoring", filename);
return -EINVAL;
}
@@ -417,6 +533,16 @@ static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
return -EINVAL;
}
+ if (t->fou_tunnel && t->fou_destination_port <= 0) {
+ log_netdev_error(netdev, "FooOverUDP missing port configured in %s. Ignoring", filename);
+ return -EINVAL;
+ }
+
+ if (netdev->kind == NETDEV_KIND_ERSPAN && (t->erspan_index >= (1 << 20) || t->erspan_index == 0)) {
+ log_netdev_error(netdev, "Invalid erspan index %d. Ignoring", t->erspan_index);
+ return -EINVAL;
+ }
+
return 0;
}
@@ -593,6 +719,42 @@ int config_parse_encap_limit(const char* unit,
return 0;
}
+int config_parse_6rd_prefix(const char* unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+ Tunnel *t = userdata;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ union in_addr_union p;
+ uint8_t l;
+ int r;
+
+ r = in_addr_prefix_from_string(rvalue, AF_INET6, &p, &l);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse 6rd prefix \"%s\", ignoring: %m", rvalue);
+ return 0;
+ }
+ if (l == 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "6rd prefix length of \"%s\" must be greater than zero, ignoring", rvalue);
+ return 0;
+ }
+
+ t->sixrd_prefix = p.in6;
+ t->sixrd_prefixlen = l;
+
+ return 0;
+}
+
static void ipip_init(NetDev *n) {
Tunnel *t = IPIP(n);
@@ -600,6 +762,7 @@ static void ipip_init(NetDev *n) {
assert(t);
t->pmtudisc = true;
+ t->fou_encap_type = FOU_ENCAP_DIRECT;
}
static void sit_init(NetDev *n) {
@@ -609,6 +772,7 @@ static void sit_init(NetDev *n) {
assert(t);
t->pmtudisc = true;
+ t->isatap = -1;
}
static void vti_init(NetDev *n) {
@@ -656,6 +820,18 @@ static void ip6gre_init(NetDev *n) {
t->ttl = DEFAULT_TNL_HOP_LIMIT;
}
+static void erspan_init(NetDev *n) {
+ Tunnel *t;
+
+ assert(n);
+
+ t = ERSPAN(n);
+
+ assert(t);
+
+ t->erspan_sequence = -1;
+}
+
static void ip6tnl_init(NetDev *n) {
Tunnel *t = IP6TNL(n);
@@ -749,3 +925,12 @@ const NetDevVTable ip6tnl_vtable = {
.create_type = NETDEV_CREATE_STACKED,
.config_verify = netdev_tunnel_verify,
};
+
+const NetDevVTable erspan_vtable = {
+ .object_size = sizeof(Tunnel),
+ .init = erspan_init,
+ .sections = "Match\0NetDev\0Tunnel\0",
+ .fill_message_create = netdev_erspan_fill_message_create,
+ .create_type = NETDEV_CREATE_INDEPENDENT,
+ .config_verify = netdev_tunnel_verify,
+};
diff --git a/src/network/netdev/tunnel.h b/src/network/netdev/tunnel.h
index b54b58ddee..8f511dd1f6 100644
--- a/src/network/netdev/tunnel.h
+++ b/src/network/netdev/tunnel.h
@@ -1,10 +1,11 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-
#include "in-addr-util.h"
+#include "conf-parser.h"
#include "netdev/netdev.h"
+#include "netdev/fou-tunnel.h"
typedef enum Ip6TnlMode {
NETDEV_IP6_TNL_MODE_IP6IP6,
@@ -28,6 +29,8 @@ typedef struct Tunnel {
int family;
int ipv6_flowlabel;
int allow_localremote;
+ int erspan_sequence;
+ int isatap;
unsigned ttl;
unsigned tos;
@@ -36,15 +39,24 @@ typedef struct Tunnel {
uint32_t key;
uint32_t ikey;
uint32_t okey;
+ uint32_t erspan_index;
union in_addr_union local;
union in_addr_union remote;
Ip6TnlMode ip6tnl_mode;
+ FooOverUDPEncapType fou_encap_type;
bool pmtudisc;
bool copy_dscp;
bool independent;
+ bool fou_tunnel;
+
+ uint16_t encap_src_port;
+ uint16_t fou_destination_port;
+
+ struct in6_addr sixrd_prefix;
+ uint8_t sixrd_prefixlen;
} Tunnel;
DEFINE_NETDEV_CAST(IPIP, Tunnel);
@@ -56,6 +68,7 @@ DEFINE_NETDEV_CAST(SIT, Tunnel);
DEFINE_NETDEV_CAST(VTI, Tunnel);
DEFINE_NETDEV_CAST(VTI6, Tunnel);
DEFINE_NETDEV_CAST(IP6TNL, Tunnel);
+DEFINE_NETDEV_CAST(ERSPAN, Tunnel);
extern const NetDevVTable ipip_vtable;
extern const NetDevVTable sit_vtable;
extern const NetDevVTable vti_vtable;
@@ -65,40 +78,14 @@ extern const NetDevVTable gretap_vtable;
extern const NetDevVTable ip6gre_vtable;
extern const NetDevVTable ip6gretap_vtable;
extern const NetDevVTable ip6tnl_vtable;
+extern const NetDevVTable erspan_vtable;
const char *ip6tnl_mode_to_string(Ip6TnlMode d) _const_;
Ip6TnlMode ip6tnl_mode_from_string(const char *d) _pure_;
-int config_parse_ip6tnl_mode(const char *unit, const char *filename,
- unsigned line, const char *section,
- unsigned section_line, const char *lvalue,
- int ltype, const char *rvalue, void *data,
- void *userdata);
-
-int config_parse_tunnel_address(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata);
-
-int config_parse_ipv6_flowlabel(const char *unit, const char *filename,
- unsigned line, const char *section,
- unsigned section_line, const char *lvalue,
- int ltype, const char *rvalue, void *data,
- void *userdata);
-
-int config_parse_encap_limit(const char *unit, const char *filename,
- unsigned line, const char *section,
- unsigned section_line, const char *lvalue,
- int ltype, const char *rvalue, void *data,
- void *userdata);
-int config_parse_tunnel_key(const char *unit, const char *filename,
- unsigned line, const char *section,
- unsigned section_line, const char *lvalue,
- int ltype, const char *rvalue, void *data,
- void *userdata);
+CONFIG_PARSER_PROTOTYPE(config_parse_ip6tnl_mode);
+CONFIG_PARSER_PROTOTYPE(config_parse_tunnel_address);
+CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_flowlabel);
+CONFIG_PARSER_PROTOTYPE(config_parse_encap_limit);
+CONFIG_PARSER_PROTOTYPE(config_parse_tunnel_key);
+CONFIG_PARSER_PROTOTYPE(config_parse_6rd_prefix);
diff --git a/src/network/netdev/tuntap.c b/src/network/netdev/tuntap.c
index 21fb7ab067..951138d257 100644
--- a/src/network/netdev/tuntap.c
+++ b/src/network/netdev/tuntap.c
@@ -60,12 +60,11 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
assert(netdev);
assert(ifr);
- fd = open(TUN_DEV, O_RDWR);
+ fd = open(TUN_DEV, O_RDWR|O_CLOEXEC);
if (fd < 0)
return log_netdev_error_errno(netdev, -errno, "Failed to open tun dev: %m");
- r = ioctl(fd, TUNSETIFF, ifr);
- if (r < 0)
+ if (ioctl(fd, TUNSETIFF, ifr) < 0)
return log_netdev_error_errno(netdev, -errno, "TUNSETIFF failed on tun dev: %m");
if (netdev->kind == NETDEV_KIND_TAP)
@@ -76,34 +75,29 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
assert(t);
if (t->user_name) {
-
user = t->user_name;
- r = get_user_creds(&user, &uid, NULL, NULL, NULL);
+ r = get_user_creds(&user, &uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Cannot resolve user name %s: %m", t->user_name);
- r = ioctl(fd, TUNSETOWNER, uid);
- if (r < 0)
+ if (ioctl(fd, TUNSETOWNER, uid) < 0)
return log_netdev_error_errno(netdev, -errno, "TUNSETOWNER failed on tun dev: %m");
}
if (t->group_name) {
-
group = t->group_name;
- r = get_group_creds(&group, &gid);
+ r = get_group_creds(&group, &gid, USER_CREDS_ALLOW_MISSING);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Cannot resolve group name %s: %m", t->group_name);
- r = ioctl(fd, TUNSETGROUP, gid);
- if (r < 0)
+ if (ioctl(fd, TUNSETGROUP, gid) < 0)
return log_netdev_error_errno(netdev, -errno, "TUNSETGROUP failed on tun dev: %m");
}
- r = ioctl(fd, TUNSETPERSIST, 1);
- if (r < 0)
+ if (ioctl(fd, TUNSETPERSIST, 1) < 0)
return log_netdev_error_errno(netdev, -errno, "TUNSETPERSIST failed on tun dev: %m");
return 0;
diff --git a/src/network/netdev/tuntap.h b/src/network/netdev/tuntap.h
index 6e8c66a000..9d9f9922b5 100644
--- a/src/network/netdev/tuntap.h
+++ b/src/network/netdev/tuntap.h
@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-
typedef struct TunTap TunTap;
#include "netdev/netdev.h"
diff --git a/src/network/netdev/vcan.c b/src/network/netdev/vcan.c
index f06ad0fb42..574d1cad31 100644
--- a/src/network/netdev/vcan.c
+++ b/src/network/netdev/vcan.c
@@ -4,5 +4,6 @@
const NetDevVTable vcan_vtable = {
.object_size = sizeof(VCan),
+ .sections = "Match\0NetDev\0",
.create_type = NETDEV_CREATE_INDEPENDENT,
};
diff --git a/src/network/netdev/vcan.h b/src/network/netdev/vcan.h
index d2540645c8..6f62686d08 100644
--- a/src/network/netdev/vcan.h
+++ b/src/network/netdev/vcan.h
@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-
typedef struct VCan VCan;
#include <linux/can/netlink.h>
diff --git a/src/network/netdev/veth.h b/src/network/netdev/veth.h
index 29cddab573..0bb9947bbd 100644
--- a/src/network/netdev/veth.h
+++ b/src/network/netdev/veth.h
@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-
typedef struct Veth Veth;
#include "netdev/netdev.h"
diff --git a/src/network/netdev/vlan.h b/src/network/netdev/vlan.h
index f3629f903b..b815e03dc5 100644
--- a/src/network/netdev/vlan.h
+++ b/src/network/netdev/vlan.h
@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-
typedef struct VLan VLan;
#include "netdev/netdev.h"
diff --git a/src/network/netdev/vrf.c b/src/network/netdev/vrf.c
index f341061344..5efab537cc 100644
--- a/src/network/netdev/vrf.c
+++ b/src/network/netdev/vrf.c
@@ -1,7 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- Copyright © 2016 Andreas Rammhold <andreas@rammhold.de>
-***/
#include <net/if.h>
@@ -30,7 +27,7 @@ static int netdev_vrf_fill_message_create(NetDev *netdev, Link *link, sd_netlink
const NetDevVTable vrf_vtable = {
.object_size = sizeof(Vrf),
- .sections = "NetDev\0VRF\0",
+ .sections = "Match\0NetDev\0VRF\0",
.fill_message_create = netdev_vrf_fill_message_create,
.create_type = NETDEV_CREATE_MASTER,
};
diff --git a/src/network/netdev/vrf.h b/src/network/netdev/vrf.h
index d1ac6f6976..05b3937856 100644
--- a/src/network/netdev/vrf.h
+++ b/src/network/netdev/vrf.h
@@ -1,10 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- Copyright © 2016 Andreas Rammhold <andreas@rammhold.de>
-***/
-
typedef struct Vrf Vrf;
#include "netdev/netdev.h"
diff --git a/src/network/netdev/vxcan.c b/src/network/netdev/vxcan.c
index f8139b52c3..e8ea70a1ed 100644
--- a/src/network/netdev/vxcan.c
+++ b/src/network/netdev/vxcan.c
@@ -1,7 +1,11 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-#include "netdev/vxcan.h"
+#if HAVE_LINUX_CAN_VXCAN_H
+#include <linux/can/vxcan.h>
+#endif
+
#include "missing.h"
+#include "netdev/vxcan.h"
static int netdev_vxcan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
VxCan *v;
diff --git a/src/network/netdev/vxcan.h b/src/network/netdev/vxcan.h
index 84a39ee3cb..b5de19740f 100644
--- a/src/network/netdev/vxcan.h
+++ b/src/network/netdev/vxcan.h
@@ -1,13 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-
typedef struct VxCan VxCan;
-#if HAVE_VXCAN_INFO_PEER
-#include <linux/can/vxcan.h>
-#endif
-
#include "netdev/netdev.h"
struct VxCan {
diff --git a/src/network/netdev/vxlan.c b/src/network/netdev/vxlan.c
index e23dd13648..4cb2eca3d2 100644
--- a/src/network/netdev/vxlan.c
+++ b/src/network/netdev/vxlan.c
@@ -42,7 +42,6 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_GROUP attribute: %m");
-
}
if (!in_addr_is_null(v->local_family, &v->local)) {
@@ -54,20 +53,19 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LOCAL attribute: %m");
-
}
r = sd_netlink_message_append_u32(m, IFLA_VXLAN_LINK, link->ifindex);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LINK attribute: %m");
- if (v->ttl) {
+ if (v->ttl != 0) {
r = sd_netlink_message_append_u8(m, IFLA_VXLAN_TTL, v->ttl);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_TTL attribute: %m");
}
- if (v->tos) {
+ if (v->tos != 0) {
r = sd_netlink_message_append_u8(m, IFLA_VXLAN_TOS, v->tos);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_TOS attribute: %m");
@@ -93,13 +91,13 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_L3MISS attribute: %m");
- if (v->fdb_ageing) {
+ if (v->fdb_ageing != 0) {
r = sd_netlink_message_append_u32(m, IFLA_VXLAN_AGEING, v->fdb_ageing / USEC_PER_SEC);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_AGEING attribute: %m");
}
- if (v->max_fdb) {
+ if (v->max_fdb != 0) {
r = sd_netlink_message_append_u32(m, IFLA_VXLAN_LIMIT, v->max_fdb);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LIMIT attribute: %m");
@@ -129,7 +127,7 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_PORT attribute: %m");
- if (v->port_range.low || v->port_range.high) {
+ if (v->port_range.low != 0 || v->port_range.high != 0) {
struct ifla_vxlan_port_range port_range;
port_range.low = htobe16(v->port_range.low);
@@ -214,9 +212,8 @@ int config_parse_port_range(const char *unit,
const char *rvalue,
void *data,
void *userdata) {
- _cleanup_free_ char *word = NULL;
VxLan *v = userdata;
- unsigned low, high;
+ uint16_t low, high;
int r;
assert(filename);
@@ -224,30 +221,10 @@ int config_parse_port_range(const char *unit,
assert(rvalue);
assert(data);
- r = extract_first_word(&rvalue, &word, NULL, 0);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract VXLAN port range, ignoring: %s", rvalue);
- return 0;
- }
-
- if (r == 0)
- return 0;
-
- r = parse_range(word, &low, &high);
+ r = parse_ip_port_range(rvalue, &low, &high);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse VXLAN port range '%s'", word);
- return 0;
- }
-
- if (low <= 0 || low > 65535 || high <= 0 || high > 65535) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to parse VXLAN port range '%s'. Port should be greater than 0 and less than 65535.", word);
- return 0;
- }
-
- if (high < low) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to parse VXLAN port range '%s'. Port range %u .. %u not valid", word, low, high);
+ "Failed to parse VXLAN port range '%s'. Port should be greater than 0 and less than 65535.", rvalue);
return 0;
}
diff --git a/src/network/netdev/vxlan.h b/src/network/netdev/vxlan.h
index e5eb20f187..3b273e97bd 100644
--- a/src/network/netdev/vxlan.h
+++ b/src/network/netdev/vxlan.h
@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-
typedef struct VxLan VxLan;
#include "in-addr-util.h"
@@ -48,34 +47,6 @@ struct VxLan {
DEFINE_NETDEV_CAST(VXLAN, VxLan);
extern const NetDevVTable vxlan_vtable;
-int config_parse_vxlan_address(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata);
-int config_parse_port_range(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata);
-
-int config_parse_flow_label(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata);
+CONFIG_PARSER_PROTOTYPE(config_parse_vxlan_address);
+CONFIG_PARSER_PROTOTYPE(config_parse_port_range);
+CONFIG_PARSER_PROTOTYPE(config_parse_flow_label);
diff --git a/src/network/netdev/wireguard.c b/src/network/netdev/wireguard.c
index fb91997f7a..167cf65046 100644
--- a/src/network/netdev/wireguard.c
+++ b/src/network/netdev/wireguard.c
@@ -1,22 +1,24 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
/***
- Copyright © 2016-2017 Jörg Thalheim <joerg@thalheim.io>
Copyright © 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
***/
#include <sys/ioctl.h>
#include <net/if.h>
+#include "sd-resolve.h"
+
#include "alloc-util.h"
-#include "parse-util.h"
#include "fd-util.h"
-#include "strv.h"
#include "hexdecoct.h"
-#include "string-util.h"
-#include "wireguard.h"
#include "networkd-link.h"
-#include "networkd-util.h"
#include "networkd-manager.h"
+#include "networkd-util.h"
+#include "parse-util.h"
+#include "resolve-private.h"
+#include "string-util.h"
+#include "strv.h"
+#include "wireguard.h"
#include "wireguard-netlink.h"
static void resolve_endpoints(NetDev *netdev);
@@ -29,10 +31,13 @@ static WireguardPeer *wireguard_peer_new(Wireguard *w, unsigned section) {
if (w->last_peer_section == section && w->peers)
return w->peers;
- peer = new0(WireguardPeer, 1);
+ peer = new(WireguardPeer, 1);
if (!peer)
return NULL;
- peer->flags = WGPEER_F_REPLACE_ALLOWEDIPS;
+
+ *peer = (WireguardPeer) {
+ .flags = WGPEER_F_REPLACE_ALLOWEDIPS,
+ };
LIST_PREPEND(peers, w->peers, peer);
w->last_peer_section = section;
@@ -42,7 +47,7 @@ static WireguardPeer *wireguard_peer_new(Wireguard *w, unsigned section) {
static int set_wireguard_interface(NetDev *netdev) {
int r;
- unsigned int i, j;
+ unsigned i, j;
WireguardPeer *peer, *peer_start;
WireguardIPmask *mask, *mask_start = NULL;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
@@ -108,7 +113,7 @@ static int set_wireguard_interface(NetDev *netdev) {
if (r < 0)
break;
- r = sd_netlink_message_append_u32(message, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, peer->persistent_keepalive_interval);
+ r = sd_netlink_message_append_u16(message, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, peer->persistent_keepalive_interval);
if (r < 0)
break;
@@ -196,12 +201,19 @@ static int set_wireguard_interface(NetDev *netdev) {
static WireguardEndpoint* wireguard_endpoint_free(WireguardEndpoint *e) {
if (!e)
return NULL;
- netdev_unref(e->netdev);
e->host = mfree(e->host);
e->port = mfree(e->port);
return mfree(e);
}
+static void wireguard_endpoint_destroy_callback(WireguardEndpoint *e) {
+ assert(e);
+ assert(e->netdev);
+
+ netdev_unref(e->netdev);
+ wireguard_endpoint_free(e);
+}
+
DEFINE_TRIVIAL_CLEANUP_FUNC(WireguardEndpoint*, wireguard_endpoint_free);
static int on_resolve_retry(sd_event_source *s, usec_t usec, void *userdata) {
@@ -212,8 +224,11 @@ static int on_resolve_retry(sd_event_source *s, usec_t usec, void *userdata) {
w = WIREGUARD(netdev);
assert(w);
- w->resolve_retry_event_source = sd_event_source_unref(w->resolve_retry_event_source);
+ if (!netdev->manager)
+ /* The netdev is detached. */
+ return 0;
+ assert(!w->unresolved_endpoints);
w->unresolved_endpoints = TAKE_PTR(w->failed_endpoints);
resolve_endpoints(netdev);
@@ -232,28 +247,30 @@ static int exponential_backoff_milliseconds(unsigned n_retries) {
static int wireguard_resolve_handler(sd_resolve_query *q,
int ret,
const struct addrinfo *ai,
- void *userdata) {
+ WireguardEndpoint *e) {
+ _cleanup_(netdev_unrefp) NetDev *netdev_will_unrefed = NULL;
NetDev *netdev;
Wireguard *w;
- _cleanup_(wireguard_endpoint_freep) WireguardEndpoint *e;
int r;
- assert(userdata);
- e = userdata;
- netdev = e->netdev;
+ assert(e);
+ assert(e->netdev);
- assert(netdev);
+ netdev = e->netdev;
w = WIREGUARD(netdev);
assert(w);
- w->resolve_query = sd_resolve_query_unref(w->resolve_query);
+ if (!netdev->manager)
+ /* The netdev is detached. */
+ return 0;
if (ret != 0) {
log_netdev_error(netdev, "Failed to resolve host '%s:%s': %s", e->host, e->port, gai_strerror(ret));
LIST_PREPEND(endpoints, w->failed_endpoints, e);
- e = NULL;
+ (void) sd_resolve_query_set_destroy_callback(q, NULL); /* Avoid freeing endpoint by destroy callback. */
+ netdev_will_unrefed = netdev; /* But netdev needs to be unrefed. */
} else if ((ai->ai_family == AF_INET && ai->ai_addrlen == sizeof(struct sockaddr_in)) ||
- (ai->ai_family == AF_INET6 && ai->ai_addrlen == sizeof(struct sockaddr_in6)))
+ (ai->ai_family == AF_INET6 && ai->ai_addrlen == sizeof(struct sockaddr_in6)))
memcpy(&e->peer->endpoint, ai->ai_addr, ai->ai_addrlen);
else
log_netdev_error(netdev, "Neither IPv4 nor IPv6 address found for peer endpoint: %s:%s", e->host, e->port);
@@ -265,51 +282,69 @@ static int wireguard_resolve_handler(sd_resolve_query *q,
set_wireguard_interface(netdev);
if (w->failed_endpoints) {
+ _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
+
w->n_retries++;
r = sd_event_add_time(netdev->manager->event,
- &w->resolve_retry_event_source,
+ &s,
CLOCK_MONOTONIC,
now(CLOCK_MONOTONIC) + exponential_backoff_milliseconds(w->n_retries),
0,
on_resolve_retry,
netdev);
- if (r < 0)
+ if (r < 0) {
log_netdev_warning_errno(netdev, r, "Could not arm resolve retry handler: %m");
+ return 0;
+ }
+
+ r = sd_event_source_set_destroy_callback(s, (sd_event_destroy_t) netdev_destroy_callback);
+ if (r < 0) {
+ log_netdev_warning_errno(netdev, r, "Failed to set destroy callback to event source: %m");
+ return 0;
+ }
+
+ (void) sd_event_source_set_floating(s, true);
+ netdev_ref(netdev);
}
return 0;
}
static void resolve_endpoints(NetDev *netdev) {
- int r = 0;
- Wireguard *w;
- WireguardEndpoint *endpoint;
static const struct addrinfo hints = {
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_DGRAM,
.ai_protocol = IPPROTO_UDP
};
+ WireguardEndpoint *endpoint;
+ Wireguard *w;
+ int r = 0;
assert(netdev);
w = WIREGUARD(netdev);
assert(w);
LIST_FOREACH(endpoints, endpoint, w->unresolved_endpoints) {
- r = sd_resolve_getaddrinfo(netdev->manager->resolve,
- &w->resolve_query,
- endpoint->host,
- endpoint->port,
- &hints,
- wireguard_resolve_handler,
- endpoint);
+ r = resolve_getaddrinfo(netdev->manager->resolve,
+ NULL,
+ endpoint->host,
+ endpoint->port,
+ &hints,
+ wireguard_resolve_handler,
+ wireguard_endpoint_destroy_callback,
+ endpoint);
if (r == -ENOBUFS)
break;
+ if (r < 0) {
+ log_netdev_error_errno(netdev, r, "Failed to create resolver: %m");
+ continue;
+ }
- LIST_REMOVE(endpoints, w->unresolved_endpoints, endpoint);
+ /* Avoid freeing netdev. It will be unrefed by the destroy callback. */
+ netdev_ref(netdev);
- if (r < 0)
- log_netdev_error_errno(netdev, r, "Failed create resolver: %m");
+ LIST_REMOVE(endpoints, w->unresolved_endpoints, endpoint);
}
}
@@ -532,12 +567,15 @@ int config_parse_wireguard_allowed_ips(const char *unit,
return 0;
}
- ipmask = new0(WireguardIPmask, 1);
+ ipmask = new(WireguardIPmask, 1);
if (!ipmask)
return log_oom();
- ipmask->family = family;
- ipmask->ip.in6 = addr.in6;
- ipmask->cidr = prefixlen;
+
+ *ipmask = (WireguardIPmask) {
+ .family = family,
+ .ip.in6 = addr.in6,
+ .cidr = prefixlen,
+ };
LIST_PREPEND(ipmasks, peer->ipmasks, ipmask);
}
@@ -573,10 +611,6 @@ int config_parse_wireguard_endpoint(const char *unit,
if (!peer)
return log_oom();
- endpoint = new0(WireguardEndpoint, 1);
- if (!endpoint)
- return log_oom();
-
if (rvalue[0] == '[') {
begin = &rvalue[1];
end = strchr(rvalue, ']');
@@ -610,12 +644,17 @@ int config_parse_wireguard_endpoint(const char *unit,
if (!port)
return log_oom();
- endpoint->peer = TAKE_PTR(peer);
- endpoint->host = TAKE_PTR(host);
- endpoint->port = TAKE_PTR(port);
- endpoint->netdev = netdev_ref(data);
- LIST_PREPEND(endpoints, w->unresolved_endpoints, endpoint);
- endpoint = NULL;
+ endpoint = new(WireguardEndpoint, 1);
+ if (!endpoint)
+ return log_oom();
+
+ *endpoint = (WireguardEndpoint) {
+ .peer = TAKE_PTR(peer),
+ .host = TAKE_PTR(host),
+ .port = TAKE_PTR(port),
+ .netdev = data,
+ };
+ LIST_PREPEND(endpoints, w->unresolved_endpoints, TAKE_PTR(endpoint));
return 0;
}
@@ -674,11 +713,11 @@ static void wireguard_done(NetDev *netdev) {
Wireguard *w;
WireguardPeer *peer;
WireguardIPmask *mask;
+ WireguardEndpoint *e;
assert(netdev);
w = WIREGUARD(netdev);
- assert(!w->unresolved_endpoints);
- w->resolve_retry_event_source = sd_event_source_unref(w->resolve_retry_event_source);
+ assert(w);
while ((peer = w->peers)) {
LIST_REMOVE(peers, w->peers, peer);
@@ -688,6 +727,16 @@ static void wireguard_done(NetDev *netdev) {
}
free(peer);
}
+
+ while ((e = w->unresolved_endpoints)) {
+ LIST_REMOVE(endpoints, w->unresolved_endpoints, e);
+ wireguard_endpoint_free(e);
+ }
+
+ while ((e = w->failed_endpoints)) {
+ LIST_REMOVE(endpoints, w->failed_endpoints, e);
+ wireguard_endpoint_free(e);
+ }
}
const NetDevVTable wireguard_vtable = {
diff --git a/src/network/netdev/wireguard.h b/src/network/netdev/wireguard.h
index 6fdbf09a7e..143e93cdc5 100644
--- a/src/network/netdev/wireguard.h
+++ b/src/network/netdev/wireguard.h
@@ -1,16 +1,11 @@
#pragma once
-/***
- Copyright © 2016 Jörg Thalheim <joerg@thalheim.io>
-***/
-
typedef struct Wireguard Wireguard;
+#include "in-addr-util.h"
#include "netdev.h"
-#include "sd-resolve.h"
-#include "wireguard-netlink.h"
#include "socket-util.h"
-#include "in-addr-util.h"
+#include "wireguard-netlink.h"
#ifndef IFNAMSIZ
#define IFNAMSIZ 16
@@ -51,33 +46,28 @@ struct Wireguard {
NetDev meta;
unsigned last_peer_section;
- char interface[IFNAMSIZ];
uint32_t flags;
- uint8_t public_key[WG_KEY_LEN];
uint8_t private_key[WG_KEY_LEN];
uint32_t fwmark;
uint16_t port;
LIST_HEAD(WireguardPeer, peers);
- size_t allocation_size;
- sd_event_source *resolve_retry_event_source;
LIST_HEAD(WireguardEndpoint, unresolved_endpoints);
LIST_HEAD(WireguardEndpoint, failed_endpoints);
unsigned n_retries;
- sd_resolve_query *resolve_query;
};
DEFINE_NETDEV_CAST(WIREGUARD, Wireguard);
extern const NetDevVTable wireguard_vtable;
-int config_parse_wireguard_allowed_ips(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_wireguard_endpoint(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_wireguard_listen_port(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_allowed_ips);
+CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_endpoint);
+CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_listen_port);
-int config_parse_wireguard_public_key(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_wireguard_private_key(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_wireguard_preshared_key(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_wireguard_keepalive(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_public_key);
+CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_private_key);
+CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_preshared_key);
+CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_keepalive);