1
0
mirror of https://github.com/systemd/systemd synced 2026-04-22 23:15:20 +02:00

Compare commits

..

No commits in common. "ba119ffcf98d28d1a205c2c985f6d41b8ccce402" and "04386f56b56968e7451811fcf387abc8146083e4" have entirely different histories.

16 changed files with 130 additions and 407 deletions

View File

@ -881,15 +881,12 @@
<varlistentry> <varlistentry>
<term><varname>Local=</varname></term> <term><varname>Local=</varname></term>
<listitem> <listitem>
<para>Specifies the IP address of a local interface. Takes an IP address, or the special <para>Specifies the IP address of the local interface. Takes an IP address, or the special values
values <literal>auto</literal>, <literal>static</literal>, or <literal>dynamic</literal>. <literal>auto</literal>, <literal>static</literal>, or <literal>dynamic</literal>. When an address
Optionally a name of a local interface can be specified after <literal>@</literal>, e.g. is set, then the local interface must have the address. If <literal>auto</literal>, then one of the
<literal>192.168.0.1@eth0</literal> or <literal>auto@eth0</literal>. When an address is addresses on the local interface is used. Similarly, if <literal>static</literal> or
specified, then a local or specified interface must have the address, and the remote address <literal>dynamic</literal> is set, then one of the static or dynamic addresses on the local
must be accessible through the local address. If <literal>auto</literal>, then one of the interface is used. Defaults to <literal>auto</literal>.</para>
addresses on a local or specified interface which is accessible to the remote address will be
used. Similarly, if <literal>static</literal> or <literal>dynamic</literal> is set, then one
of the static or dynamic addresses will be used. Defaults to <literal>auto</literal>.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>

View File

@ -869,6 +869,7 @@ Table=1234</programlisting></para>
<term><varname>IPoIB=</varname></term> <term><varname>IPoIB=</varname></term>
<term><varname>IPVLAN=</varname></term> <term><varname>IPVLAN=</varname></term>
<term><varname>IPVTAP=</varname></term> <term><varname>IPVTAP=</varname></term>
<term><varname>L2TP=</varname></term>
<term><varname>MACsec=</varname></term> <term><varname>MACsec=</varname></term>
<term><varname>MACVLAN=</varname></term> <term><varname>MACVLAN=</varname></term>
<term><varname>MACVTAP=</varname></term> <term><varname>MACVTAP=</varname></term>
@ -877,7 +878,7 @@ Table=1234</programlisting></para>
<term><varname>VXLAN=</varname></term> <term><varname>VXLAN=</varname></term>
<term><varname>Xfrm=</varname></term> <term><varname>Xfrm=</varname></term>
<listitem> <listitem>
<para>The name of an IPoIB, IPVLAN, IPVTAP, MACsec, MACVLAN, MACVTAP, tunnel, VLAN, <para>The name of an IPoIB, IPVLAN, IPVTAP, L2TP, MACsec, MACVLAN, MACVTAP, tunnel, VLAN,
VXLAN, or Xfrm to be created on the link. See VXLAN, or Xfrm to be created on the link. See
<citerefentry><refentrytitle>systemd.netdev</refentrytitle><manvolnum>5</manvolnum></citerefentry>. <citerefentry><refentrytitle>systemd.netdev</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
This option may be specified more than once.</para> This option may be specified more than once.</para>

View File

@ -10,7 +10,6 @@
#include "netlink-util.h" #include "netlink-util.h"
#include "networkd-address.h" #include "networkd-address.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-route-util.h"
#include "parse-util.h" #include "parse-util.h"
#include "socket-util.h" #include "socket-util.h"
#include "string-table.h" #include "string-table.h"
@ -246,114 +245,44 @@ static int netdev_l2tp_create_message_session(NetDev *netdev, L2tpSession *sessi
return 0; return 0;
} }
static int link_get_l2tp_local_address(Link *link, L2tpTunnel *t, union in_addr_union *ret) { static int l2tp_acquire_local_address_one(L2tpTunnel *t, Address *a, union in_addr_union *ret) {
Address *a; if (a->family != t->family)
return -EINVAL;
assert(link); if (in_addr_is_set(a->family, &a->in_addr_peer))
assert(t); return -EINVAL;
SET_FOREACH(a, link->addresses) { if (t->local_address_type == NETDEV_L2TP_LOCAL_ADDRESS_STATIC &&
if (!address_is_ready(a)) !FLAGS_SET(a->flags, IFA_F_PERMANENT))
continue; return -EINVAL;
if (a->family != t->family) if (t->local_address_type == NETDEV_L2TP_LOCAL_ADDRESS_DYNAMIC &&
continue; FLAGS_SET(a->flags, IFA_F_PERMANENT))
return -EINVAL;
if (in_addr_is_set(a->family, &a->in_addr_peer)) *ret = a->in_addr;
continue; return 0;
if (t->local_address_type == NETDEV_L2TP_LOCAL_ADDRESS_STATIC &&
!FLAGS_SET(a->flags, IFA_F_PERMANENT))
continue;
if (t->local_address_type == NETDEV_L2TP_LOCAL_ADDRESS_DYNAMIC &&
FLAGS_SET(a->flags, IFA_F_PERMANENT))
continue;
if (ret)
*ret = a->in_addr;
}
return -ENOENT;
} }
static int l2tp_get_local_address(NetDev *netdev, union in_addr_union *ret) { static int l2tp_acquire_local_address(L2tpTunnel *t, Link *link, union in_addr_union *ret) {
Link *link = NULL;
L2tpTunnel *t;
Address *a; Address *a;
int r;
assert(netdev); assert(t);
assert(netdev->manager); assert(link);
assert_se(t = L2TP(netdev)); assert(ret);
assert(IN_SET(t->family, AF_INET, AF_INET6));
if (t->local_ifname) {
r = link_get_by_name(netdev->manager, t->local_ifname, &link);
if (r < 0)
return r;
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
return -EBUSY;
}
if (netdev->manager->manage_foreign_routes) {
/* First, check if the remote address is accessible. */
if (link)
r = link_address_is_reachable(link, t->family, &t->remote, &t->local, &a);
else
r = manager_address_is_reachable(netdev->manager, t->family, &t->remote, &t->local, &a);
if (r < 0)
return r;
}
if (in_addr_is_set(t->family, &t->local)) { if (in_addr_is_set(t->family, &t->local)) {
/* local address is explicitly specified. */ /* local address is explicitly specified. */
*ret = t->local;
if (!a) {
if (link)
r = link_get_address(link, t->family, &t->local, 0, &a);
else
r = manager_get_address(netdev->manager, t->family, &t->local, 0, &a);
if (r < 0)
return r;
if (!address_is_ready(a))
return -EBUSY;
}
if (ret)
*ret = a->in_addr;
return 0; return 0;
} }
if (a) { SET_FOREACH(a, link->addresses)
if (t->local_address_type == NETDEV_L2TP_LOCAL_ADDRESS_STATIC && if (l2tp_acquire_local_address_one(t, a, ret) >= 0)
!FLAGS_SET(a->flags, IFA_F_PERMANENT)) return 1;
return -EINVAL;
if (t->local_address_type == NETDEV_L2TP_LOCAL_ADDRESS_DYNAMIC && return -ENODATA;
FLAGS_SET(a->flags, IFA_F_PERMANENT))
return -EINVAL;
if (ret)
*ret = a->in_addr;
return 0;
}
if (link)
return link_get_l2tp_local_address(link, t, ret);
HASHMAP_FOREACH(link, netdev->manager->links_by_index) {
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
continue;
if (link_get_l2tp_local_address(link, t, ret) >= 0)
return 0;
}
return -ENOENT;
} }
static void l2tp_session_destroy_callback(L2tpSession *session) { static void l2tp_session_destroy_callback(L2tpSession *session) {
@ -432,7 +361,7 @@ static int l2tp_create_tunnel_handler(sd_netlink *rtnl, sd_netlink_message *m, N
return 1; return 1;
} }
static int l2tp_create_tunnel(NetDev *netdev) { static int l2tp_create_tunnel(NetDev *netdev, Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
union in_addr_union local_address; union in_addr_union local_address;
L2tpTunnel *t; L2tpTunnel *t;
@ -441,11 +370,11 @@ static int l2tp_create_tunnel(NetDev *netdev) {
assert(netdev); assert(netdev);
assert_se(t = L2TP(netdev)); assert_se(t = L2TP(netdev));
r = l2tp_get_local_address(netdev, &local_address); r = l2tp_acquire_local_address(t, link, &local_address);
if (r < 0) if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not find local address."); return log_netdev_error_errno(netdev, r, "Could not find local address.");
if (t->local_address_type >= 0 && DEBUG_LOGGING) { if (r > 0 && DEBUG_LOGGING) {
_cleanup_free_ char *str = NULL; _cleanup_free_ char *str = NULL;
(void) in_addr_to_string(t->family, &local_address, &str); (void) in_addr_to_string(t->family, &local_address, &str);
@ -466,11 +395,7 @@ static int l2tp_create_tunnel(NetDev *netdev) {
return 0; return 0;
} }
static int netdev_l2tp_is_ready_to_create(NetDev *netdev, Link *link) { int config_parse_l2tp_tunnel_address(
return l2tp_get_local_address(netdev, NULL) >= 0;
}
int config_parse_l2tp_tunnel_local_address(
const char *unit, const char *unit,
const char *filename, const char *filename,
unsigned line, unsigned line,
@ -482,115 +407,42 @@ int config_parse_l2tp_tunnel_local_address(
void *data, void *data,
void *userdata) { void *userdata) {
_cleanup_free_ char *addr_or_type = NULL, *ifname = NULL;
L2tpLocalAddressType type;
L2tpTunnel *t = userdata; L2tpTunnel *t = userdata;
const char *p = rvalue; union in_addr_union *addr = data;
int r; int r;
assert(filename); assert(filename);
assert(lvalue); assert(lvalue);
assert(rvalue); assert(rvalue);
assert(t); assert(data);
if (isempty(rvalue)) { if (streq(lvalue, "Local")) {
t->local_ifname = mfree(t->local_ifname); L2tpLocalAddressType addr_type;
t->local_address_type = NETDEV_L2TP_LOCAL_ADDRESS_AUTO;
t->local = IN_ADDR_NULL;
if (!in_addr_is_set(t->family, &t->remote)) if (isempty(rvalue))
/* If Remote= is not specified yet, then also clear family. */ addr_type = NETDEV_L2TP_LOCAL_ADDRESS_AUTO;
t->family = AF_UNSPEC; else
addr_type = l2tp_local_address_type_from_string(rvalue);
return 0; if (addr_type >= 0) {
} if (!in_addr_is_set(t->family, &t->remote))
/* If Remote= is not specified yet, then also clear family. */
t->family = AF_UNSPEC;
r = extract_first_word(&p, &addr_or_type, "@", 0); t->local = IN_ADDR_NULL;
if (r < 0) t->local_address_type = addr_type;
return log_oom();
if (r == 0) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid L2TP Tunnel address specified in %s=, ignoring assignment: %s", lvalue, rvalue);
return 0;
}
if (!isempty(p)) {
if (!ifname_valid_full(p, IFNAME_VALID_ALTERNATIVE)) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid interface name specified in %s=, ignoring assignment: %s", lvalue, rvalue);
return 0; return 0;
} }
ifname = strdup(p);
if (!ifname)
return log_oom();
}
type = l2tp_local_address_type_from_string(rvalue);
if (type >= 0) {
free_and_replace(t->local_ifname, ifname);
t->local_address_type = type;
t->local = IN_ADDR_NULL;
if (!in_addr_is_set(t->family, &t->remote))
/* If Remote= is not specified yet, then also clear family. */
t->family = AF_UNSPEC;
return 0;
} }
if (t->family == AF_UNSPEC) if (t->family == AF_UNSPEC)
r = in_addr_from_string_auto(rvalue, &t->family, &t->local); r = in_addr_from_string_auto(rvalue, &t->family, addr);
else else
r = in_addr_from_string(t->family, rvalue, &t->local); r = in_addr_from_string(t->family, rvalue, addr);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, log_syntax(unit, LOG_WARNING, filename, line, r,
"Invalid L2TP Tunnel address specified in %s=, ignoring assignment: %s", lvalue, rvalue); "Invalid L2TP Tunnel address specified in %s='%s', ignoring assignment: %m", lvalue, rvalue);
return 0;
}
free_and_replace(t->local_ifname, ifname);
t->local_address_type = _NETDEV_L2TP_LOCAL_ADDRESS_INVALID;
return 0;
}
int config_parse_l2tp_tunnel_remote_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) {
L2tpTunnel *t = userdata;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(t);
if (isempty(rvalue)) {
t->remote = IN_ADDR_NULL;
if (!in_addr_is_set(t->family, &t->local))
/* If Local= is not specified yet, then also clear family. */
t->family = AF_UNSPEC;
return 0;
}
if (t->family == AF_UNSPEC)
r = in_addr_from_string_auto(rvalue, &t->family, &t->remote);
else
r = in_addr_from_string(t->family, rvalue, &t->remote);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Invalid L2TP Tunnel address specified in %s=, ignoring assignment: %s", lvalue, rvalue);
return 0; return 0;
} }
@ -847,16 +699,14 @@ static void l2tp_tunnel_done(NetDev *netdev) {
assert(t); assert(t);
ordered_hashmap_free_with_destructor(t->sessions_by_section, l2tp_session_free); ordered_hashmap_free_with_destructor(t->sessions_by_section, l2tp_session_free);
free(t->local_ifname);
} }
const NetDevVTable l2tptnl_vtable = { const NetDevVTable l2tptnl_vtable = {
.object_size = sizeof(L2tpTunnel), .object_size = sizeof(L2tpTunnel),
.init = l2tp_tunnel_init, .init = l2tp_tunnel_init,
.sections = NETDEV_COMMON_SECTIONS "L2TP\0L2TPSession\0", .sections = NETDEV_COMMON_SECTIONS "L2TP\0L2TPSession\0",
.create = l2tp_create_tunnel, .create_after_configured = l2tp_create_tunnel,
.done = l2tp_tunnel_done, .done = l2tp_tunnel_done,
.create_type = NETDEV_CREATE_INDEPENDENT, .create_type = NETDEV_CREATE_AFTER_CONFIGURED,
.is_ready_to_create = netdev_l2tp_is_ready_to_create,
.config_verify = netdev_l2tp_tunnel_verify, .config_verify = netdev_l2tp_tunnel_verify,
}; };

View File

@ -58,7 +58,6 @@ struct L2tpTunnel {
bool udp6_csum_rx; bool udp6_csum_rx;
bool udp6_csum_tx; bool udp6_csum_tx;
char *local_ifname;
L2tpLocalAddressType local_address_type; L2tpLocalAddressType local_address_type;
union in_addr_union local; union in_addr_union local;
union in_addr_union remote; union in_addr_union remote;
@ -71,8 +70,7 @@ struct L2tpTunnel {
DEFINE_NETDEV_CAST(L2TP, L2tpTunnel); DEFINE_NETDEV_CAST(L2TP, L2tpTunnel);
extern const NetDevVTable l2tptnl_vtable; extern const NetDevVTable l2tptnl_vtable;
CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_tunnel_local_address); CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_tunnel_address);
CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_tunnel_remote_address);
CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_tunnel_id); CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_tunnel_id);
CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_encap_type); CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_encap_type);
CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_session_l2spec); CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_session_l2spec);

View File

@ -103,8 +103,8 @@ L2TP.TunnelId, config_parse_l2tp_tunnel_id,
L2TP.PeerTunnelId, config_parse_l2tp_tunnel_id, 0, offsetof(L2tpTunnel, peer_tunnel_id) L2TP.PeerTunnelId, config_parse_l2tp_tunnel_id, 0, offsetof(L2tpTunnel, peer_tunnel_id)
L2TP.UDPSourcePort, config_parse_ip_port, 0, offsetof(L2tpTunnel, l2tp_udp_sport) L2TP.UDPSourcePort, config_parse_ip_port, 0, offsetof(L2tpTunnel, l2tp_udp_sport)
L2TP.UDPDestinationPort, config_parse_ip_port, 0, offsetof(L2tpTunnel, l2tp_udp_dport) L2TP.UDPDestinationPort, config_parse_ip_port, 0, offsetof(L2tpTunnel, l2tp_udp_dport)
L2TP.Local, config_parse_l2tp_tunnel_local_address, 0, 0 L2TP.Local, config_parse_l2tp_tunnel_address, 0, offsetof(L2tpTunnel, local)
L2TP.Remote, config_parse_l2tp_tunnel_remote_address, 0, 0 L2TP.Remote, config_parse_l2tp_tunnel_address, 0, offsetof(L2tpTunnel, remote)
L2TP.EncapsulationType, config_parse_l2tp_encap_type, 0, offsetof(L2tpTunnel, l2tp_encap_type) L2TP.EncapsulationType, config_parse_l2tp_encap_type, 0, offsetof(L2tpTunnel, l2tp_encap_type)
L2TP.UDPCheckSum, config_parse_bool, 0, offsetof(L2tpTunnel, udp_csum) L2TP.UDPCheckSum, config_parse_bool, 0, offsetof(L2tpTunnel, udp_csum)
L2TP.UDP6CheckSumRx, config_parse_bool, 0, offsetof(L2tpTunnel, udp6_csum_rx) L2TP.UDP6CheckSumRx, config_parse_bool, 0, offsetof(L2tpTunnel, udp6_csum_rx)

View File

@ -144,7 +144,7 @@ bool netdev_is_managed(NetDev *netdev) {
static bool netdev_is_stacked_and_independent(NetDev *netdev) { static bool netdev_is_stacked_and_independent(NetDev *netdev) {
assert(netdev); assert(netdev);
if (netdev_get_create_type(netdev) != NETDEV_CREATE_STACKED) if (!IN_SET(netdev_get_create_type(netdev), NETDEV_CREATE_STACKED, NETDEV_CREATE_AFTER_CONFIGURED))
return false; return false;
switch (netdev->kind) { switch (netdev->kind) {
@ -180,7 +180,7 @@ static bool netdev_is_stacked_and_independent(NetDev *netdev) {
static bool netdev_is_stacked(NetDev *netdev) { static bool netdev_is_stacked(NetDev *netdev) {
assert(netdev); assert(netdev);
if (netdev_get_create_type(netdev) != NETDEV_CREATE_STACKED) if (!IN_SET(netdev_get_create_type(netdev), NETDEV_CREATE_STACKED, NETDEV_CREATE_AFTER_CONFIGURED))
return false; return false;
if (netdev_is_stacked_and_independent(netdev)) if (netdev_is_stacked_and_independent(netdev))
@ -617,6 +617,10 @@ static int netdev_is_ready_to_create(NetDev *netdev, Link *link) {
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
return false; return false;
if (netdev_get_create_type(netdev) == NETDEV_CREATE_AFTER_CONFIGURED &&
link->state != LINK_STATE_CONFIGURED)
return false;
if (link->set_link_messages > 0) if (link->set_link_messages > 0)
return false; return false;
@ -648,21 +652,28 @@ int request_process_stacked_netdev(Request *req) {
if (r <= 0) if (r <= 0)
return r; return r;
r = stacked_netdev_create(netdev, link, req->netlink_handler); switch (netdev_get_create_type(netdev)) {
case NETDEV_CREATE_STACKED:
r = stacked_netdev_create(netdev, link, req->netlink_handler);
break;
case NETDEV_CREATE_AFTER_CONFIGURED:
assert(NETDEV_VTABLE(netdev)->create_after_configured);
r = NETDEV_VTABLE(netdev)->create_after_configured(netdev, link);
break;
default:
assert_not_reached();
}
if (r < 0) if (r < 0)
return log_netdev_warning_errno(netdev, r, "Failed to create netdev: %m"); return log_netdev_warning_errno(netdev, r, "Failed to create netdev: %m");
return 1; return 1;
} }
static int link_create_stacked_netdev_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { static int link_create_stacked_netdev_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r; int r;
assert(m); assert(m);
assert(link); assert(link);
assert(link->create_stacked_netdev_messages > 0);
link->create_stacked_netdev_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 0; return 0;
@ -674,6 +685,18 @@ static int link_create_stacked_netdev_handler(sd_netlink *rtnl, sd_netlink_messa
return 0; return 0;
} }
return 1;
}
static int link_create_stacked_netdev_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
assert(link);
assert(link->create_stacked_netdev_messages > 0);
link->create_stacked_netdev_messages--;
if (link_create_stacked_netdev_handler_internal(rtnl, m, link) <= 0)
return 0;
if (link->create_stacked_netdev_messages == 0) { if (link->create_stacked_netdev_messages == 0) {
link->stacked_netdevs_created = true; link->stacked_netdevs_created = true;
log_link_debug(link, "Stacked netdevs created."); log_link_debug(link, "Stacked netdevs created.");
@ -683,6 +706,10 @@ static int link_create_stacked_netdev_handler(sd_netlink *rtnl, sd_netlink_messa
return 0; return 0;
} }
static int link_create_stacked_netdev_after_configured_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return 0;
}
int link_request_stacked_netdev(Link *link, NetDev *netdev) { int link_request_stacked_netdev(Link *link, NetDev *netdev) {
int r; int r;
@ -695,11 +722,15 @@ int link_request_stacked_netdev(Link *link, NetDev *netdev) {
if (!IN_SET(netdev->state, NETDEV_STATE_LOADING, NETDEV_STATE_FAILED) || netdev->ifindex > 0) if (!IN_SET(netdev->state, NETDEV_STATE_LOADING, NETDEV_STATE_FAILED) || netdev->ifindex > 0)
return 0; /* Already created. */ return 0; /* Already created. */
link->stacked_netdevs_created = false; if (netdev_get_create_type(netdev) == NETDEV_CREATE_STACKED) {
r = link_queue_request(link, REQUEST_TYPE_NETDEV_STACKED, netdev_ref(netdev), true, link->stacked_netdevs_created = false;
&link->create_stacked_netdev_messages, r = link_queue_request(link, REQUEST_TYPE_NETDEV_STACKED, netdev_ref(netdev), true,
link_create_stacked_netdev_handler, &link->create_stacked_netdev_messages,
NULL); link_create_stacked_netdev_handler,
NULL);
} else
r = link_queue_request(link, REQUEST_TYPE_NETDEV_STACKED, netdev_ref(netdev), true,
NULL, link_create_stacked_netdev_after_configured_handler, NULL);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to request stacked netdev '%s': %m", return log_link_error_errno(link, r, "Failed to request stacked netdev '%s': %m",
netdev->ifname); netdev->ifname);

View File

@ -103,6 +103,7 @@ typedef enum NetDevState {
typedef enum NetDevCreateType { typedef enum NetDevCreateType {
NETDEV_CREATE_INDEPENDENT, NETDEV_CREATE_INDEPENDENT,
NETDEV_CREATE_STACKED, NETDEV_CREATE_STACKED,
NETDEV_CREATE_AFTER_CONFIGURED,
_NETDEV_CREATE_MAX, _NETDEV_CREATE_MAX,
_NETDEV_CREATE_INVALID = -EINVAL, _NETDEV_CREATE_INVALID = -EINVAL,
} NetDevCreateType; } NetDevCreateType;
@ -159,6 +160,9 @@ typedef struct NetDevVTable {
/* create netdev, if not done via rtnl */ /* create netdev, if not done via rtnl */
int (*create)(NetDev *netdev); int (*create)(NetDev *netdev);
/* create netdev after link is fully configured */
int (*create_after_configured)(NetDev *netdev, Link *link);
/* perform additional configuration after netdev has been createad */ /* perform additional configuration after netdev has been createad */
int (*post_create)(NetDev *netdev, Link *link); int (*post_create)(NetDev *netdev, Link *link);

View File

@ -602,35 +602,19 @@ int link_get_address(Link *link, int family, const union in_addr_union *address,
return -ENOENT; return -ENOENT;
} }
int manager_get_address(Manager *manager, int family, const union in_addr_union *address, unsigned char prefixlen, Address **ret) { int manager_has_address(Manager *manager, int family, const union in_addr_union *address, bool check_ready) {
Address *a;
Link *link; Link *link;
assert(manager); assert(manager);
assert(IN_SET(family, AF_INET, AF_INET6)); assert(IN_SET(family, AF_INET, AF_INET6));
assert(address); assert(address);
HASHMAP_FOREACH(link, manager->links_by_index) { HASHMAP_FOREACH(link, manager->links_by_index)
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) if (link_get_address(link, family, address, 0, &a) >= 0)
continue; return check_ready ? address_is_ready(a) : address_exists(a);
if (link_get_address(link, family, address, prefixlen, ret) >= 0) return false;
return 0;
}
return -ENOENT;
}
bool manager_has_address(Manager *manager, int family, const union in_addr_union *address, bool check_ready) {
Address *a;
assert(manager);
assert(IN_SET(family, AF_INET, AF_INET6));
assert(address);
if (manager_get_address(manager, family, address, 0, &a) < 0)
return false;
return check_ready ? address_is_ready(a) : address_exists(a);
} }
const char* format_lifetime(char *buf, size_t l, usec_t lifetime_usec) { const char* format_lifetime(char *buf, size_t l, usec_t lifetime_usec) {

View File

@ -88,8 +88,7 @@ static inline int link_get_ipv4_address(Link *link, const struct in_addr *addres
assert(address); assert(address);
return link_get_address(link, AF_INET, &(union in_addr_union) { .in = *address }, prefixlen, ret); return link_get_address(link, AF_INET, &(union in_addr_union) { .in = *address }, prefixlen, ret);
} }
int manager_get_address(Manager *manager, int family, const union in_addr_union *address, unsigned char prefixlen, Address **ret); int manager_has_address(Manager *manager, int family, const union in_addr_union *address, bool check_ready);
bool manager_has_address(Manager *manager, int family, const union in_addr_union *address, bool check_ready);
void address_cancel_request(Address *address); void address_cancel_request(Address *address);
int link_request_address( int link_request_address(

View File

@ -93,7 +93,7 @@ Network.VRF, config_parse_ifname,
Network.IPoIB, config_parse_stacked_netdev, NETDEV_KIND_IPOIB, offsetof(Network, stacked_netdev_names) Network.IPoIB, config_parse_stacked_netdev, NETDEV_KIND_IPOIB, offsetof(Network, stacked_netdev_names)
Network.IPVLAN, config_parse_stacked_netdev, NETDEV_KIND_IPVLAN, offsetof(Network, stacked_netdev_names) Network.IPVLAN, config_parse_stacked_netdev, NETDEV_KIND_IPVLAN, offsetof(Network, stacked_netdev_names)
Network.IPVTAP, config_parse_stacked_netdev, NETDEV_KIND_IPVTAP, offsetof(Network, stacked_netdev_names) Network.IPVTAP, config_parse_stacked_netdev, NETDEV_KIND_IPVTAP, offsetof(Network, stacked_netdev_names)
Network.L2TP, config_parse_warn_compat, DISABLED_LEGACY, 0 Network.L2TP, config_parse_stacked_netdev, NETDEV_KIND_L2TP, offsetof(Network, stacked_netdev_names)
Network.MACsec, config_parse_stacked_netdev, NETDEV_KIND_MACSEC, offsetof(Network, stacked_netdev_names) Network.MACsec, config_parse_stacked_netdev, NETDEV_KIND_MACSEC, offsetof(Network, stacked_netdev_names)
Network.MACVLAN, config_parse_stacked_netdev, NETDEV_KIND_MACVLAN, offsetof(Network, stacked_netdev_names) Network.MACVLAN, config_parse_stacked_netdev, NETDEV_KIND_MACVLAN, offsetof(Network, stacked_netdev_names)
Network.MACVTAP, config_parse_stacked_netdev, NETDEV_KIND_MACVTAP, offsetof(Network, stacked_netdev_names) Network.MACVTAP, config_parse_stacked_netdev, NETDEV_KIND_MACVTAP, offsetof(Network, stacked_netdev_names)

View File

@ -871,6 +871,7 @@ int config_parse_stacked_netdev(
NETDEV_KIND_IPOIB, NETDEV_KIND_IPOIB,
NETDEV_KIND_IPVLAN, NETDEV_KIND_IPVLAN,
NETDEV_KIND_IPVTAP, NETDEV_KIND_IPVTAP,
NETDEV_KIND_L2TP,
NETDEV_KIND_MACSEC, NETDEV_KIND_MACSEC,
NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVLAN,
NETDEV_KIND_MACVTAP, NETDEV_KIND_MACVTAP,

View File

@ -102,21 +102,14 @@ int manager_find_uplink(Manager *m, int family, Link *exclude, Link **ret) {
return 0; return 0;
} }
bool gateway_is_ready(Link *link, bool onlink, int family, const union in_addr_union *gw) { static bool link_address_is_reachable(Link *link, int family, const union in_addr_union *address) {
Route *route; Route *route;
Address *a; Address *a;
assert(link); assert(link);
assert(link->manager); assert(link->manager);
assert(IN_SET(family, AF_INET, AF_INET6));
if (onlink) assert(address);
return true;
if (!gw || !in_addr_is_set(family, gw))
return true;
if (family == AF_INET6 && in6_addr_is_link_local(&gw->in6))
return true;
SET_FOREACH(route, link->routes) { SET_FOREACH(route, link->routes) {
if (!route_exists(route)) if (!route_exists(route))
@ -125,7 +118,7 @@ bool gateway_is_ready(Link *link, bool onlink, int family, const union in_addr_u
continue; continue;
if (!in_addr_is_set(route->family, &route->dst) && route->dst_prefixlen == 0) if (!in_addr_is_set(route->family, &route->dst) && route->dst_prefixlen == 0)
continue; continue;
if (in_addr_prefix_covers(family, &route->dst, route->dst_prefixlen, gw) > 0) if (in_addr_prefix_covers(family, &route->dst, route->dst_prefixlen, address) > 0)
return true; return true;
} }
@ -143,148 +136,27 @@ bool gateway_is_ready(Link *link, bool onlink, int family, const union in_addr_u
continue; continue;
if (in_addr_is_set(a->family, &a->in_addr_peer)) if (in_addr_is_set(a->family, &a->in_addr_peer))
continue; continue;
if (in_addr_prefix_covers(family, &a->in_addr, a->prefixlen, gw) > 0) if (in_addr_prefix_covers(family, &a->in_addr, a->prefixlen, address) > 0)
return true; return true;
} }
return false; return false;
} }
static int link_address_is_reachable_internal( bool gateway_is_ready(Link *link, bool onlink, int family, const union in_addr_union *gw) {
Link *link,
int family,
const union in_addr_union *address,
const union in_addr_union *prefsrc, /* optional */
Route **ret) {
Route *route, *found = NULL;
assert(link); assert(link);
assert(IN_SET(family, AF_INET, AF_INET6)); assert(gw);
assert(address);
SET_FOREACH(route, link->routes) { if (onlink)
if (!route_exists(route)) return true;
continue;
if (route->type != RTN_UNICAST) if (!in_addr_is_set(family, gw))
continue; return true;
if (route->family != family) if (family == AF_INET6 && in6_addr_is_link_local(&gw->in6))
continue; return true;
if (in_addr_prefix_covers(family, &route->dst, route->dst_prefixlen, address) <= 0) return link_address_is_reachable(link, family, gw);
continue;
if (prefsrc &&
in_addr_is_set(family, prefsrc) &&
in_addr_is_set(family, &route->prefsrc) &&
!in_addr_equal(family, prefsrc, &route->prefsrc))
continue;
if (found && found->priority <= route->priority)
continue;
found = route;
}
if (!found)
return -ENOENT;
if (ret)
*ret = found;
return 0;
}
int link_address_is_reachable(
Link *link,
int family,
const union in_addr_union *address,
const union in_addr_union *prefsrc, /* optional */
Address **ret) {
Route *route;
Address *a;
int r;
assert(link);
assert(IN_SET(family, AF_INET, AF_INET6));
assert(address);
/* This checks if the address is reachable, and optionally return the Address object of the
* preferred source to access the address. */
r = link_address_is_reachable_internal(link, family, address, prefsrc, &route);
if (r < 0)
return r;
if (!in_addr_is_set(route->family, &route->prefsrc)) {
if (ret)
*ret = NULL;
return 0;
}
r = link_get_address(link, route->family, &route->prefsrc, 0, &a);
if (r < 0)
return r;
if (!address_is_ready(a))
return -EBUSY;
if (ret)
*ret = a;
return 0;
}
int manager_address_is_reachable(
Manager *manager,
int family,
const union in_addr_union *address,
const union in_addr_union *prefsrc, /* optional */
Address **ret) {
Route *route, *found = NULL;
Address *a;
Link *link;
int r;
assert(manager);
HASHMAP_FOREACH(link, manager->links_by_index) {
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
continue;
if (link_address_is_reachable_internal(link, family, address, prefsrc, &route) < 0)
continue;
if (found && found->priority <= route->priority)
continue;
found = route;
}
if (!found)
return -ENOENT;
if (!in_addr_is_set(found->family, &found->prefsrc)) {
if (ret)
*ret = NULL;
return 0;
}
r = link_get_address(found->link, found->family, &found->prefsrc, 0, &a);
if (r < 0)
return r;
if (!address_is_ready(a))
return -EBUSY;
if (ret)
*ret = a;
return 0;
} }
static const char * const route_type_table[__RTN_MAX] = { static const char * const route_type_table[__RTN_MAX] = {

View File

@ -8,7 +8,6 @@
typedef struct Link Link; typedef struct Link Link;
typedef struct Manager Manager; typedef struct Manager Manager;
typedef struct Address Address;
unsigned routes_max(void); unsigned routes_max(void);
@ -16,20 +15,6 @@ int manager_find_uplink(Manager *m, int family, Link *exclude, Link **ret);
bool gateway_is_ready(Link *link, bool onlink, int family, const union in_addr_union *gw); bool gateway_is_ready(Link *link, bool onlink, int family, const union in_addr_union *gw);
int link_address_is_reachable(
Link *link,
int family,
const union in_addr_union *address,
const union in_addr_union *prefsrc, /* optional */
Address **ret);
int manager_address_is_reachable(
Manager *manager,
int family,
const union in_addr_union *address,
const union in_addr_union *prefsrc, /* optional */
Address **ret);
int route_type_from_string(const char *s) _pure_; int route_type_from_string(const char *s) _pure_;
const char *route_type_to_string(int t) _const_; const char *route_type_to_string(int t) _const_;

View File

@ -5,3 +5,4 @@ Name=test1
[Network] [Network]
Address=192.168.30.100/24 Address=192.168.30.100/24
IPv6AcceptRA=false IPv6AcceptRA=false
L2TP=l2tp99

View File

@ -6,7 +6,7 @@ Name=l2tp99
[L2TP] [L2TP]
TunnelId=10 TunnelId=10
PeerTunnelId=12 PeerTunnelId=12
Local=static@test1 Local=static
Remote=192.168.30.101 Remote=192.168.30.101
EncapsulationType=ip EncapsulationType=ip

View File

@ -8,7 +8,7 @@ TunnelId=10
PeerTunnelId=11 PeerTunnelId=11
UDPSourcePort=3000 UDPSourcePort=3000
UDPDestinationPort=4000 UDPDestinationPort=4000
Local=static@test1 Local=static
Remote=192.168.30.101 Remote=192.168.30.101
EncapsulationType=udp EncapsulationType=udp
UDPCheckSum=true UDPCheckSum=true