mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
Merge pull request #22627 from yuwata/network-l2tp-cleanups
network: cleanups for L2TP tunnel
This commit is contained in:
commit
ba119ffcf9
@ -881,12 +881,15 @@
|
||||
<varlistentry>
|
||||
<term><varname>Local=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the IP address of the local interface. Takes an IP address, or the special values
|
||||
<literal>auto</literal>, <literal>static</literal>, or <literal>dynamic</literal>. When an address
|
||||
is set, then the local interface must have the address. If <literal>auto</literal>, then one of the
|
||||
addresses on the local interface is used. Similarly, if <literal>static</literal> or
|
||||
<literal>dynamic</literal> is set, then one of the static or dynamic addresses on the local
|
||||
interface is used. Defaults to <literal>auto</literal>.</para>
|
||||
<para>Specifies the IP address of a local interface. Takes an IP address, or the special
|
||||
values <literal>auto</literal>, <literal>static</literal>, or <literal>dynamic</literal>.
|
||||
Optionally a name of a local interface can be specified after <literal>@</literal>, e.g.
|
||||
<literal>192.168.0.1@eth0</literal> or <literal>auto@eth0</literal>. When an address is
|
||||
specified, then a local or specified interface must have the address, and the remote address
|
||||
must be accessible through the local address. If <literal>auto</literal>, then one of the
|
||||
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>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
|
@ -869,7 +869,6 @@ Table=1234</programlisting></para>
|
||||
<term><varname>IPoIB=</varname></term>
|
||||
<term><varname>IPVLAN=</varname></term>
|
||||
<term><varname>IPVTAP=</varname></term>
|
||||
<term><varname>L2TP=</varname></term>
|
||||
<term><varname>MACsec=</varname></term>
|
||||
<term><varname>MACVLAN=</varname></term>
|
||||
<term><varname>MACVTAP=</varname></term>
|
||||
@ -878,7 +877,7 @@ Table=1234</programlisting></para>
|
||||
<term><varname>VXLAN=</varname></term>
|
||||
<term><varname>Xfrm=</varname></term>
|
||||
<listitem>
|
||||
<para>The name of an IPoIB, IPVLAN, IPVTAP, L2TP, MACsec, MACVLAN, MACVTAP, tunnel, VLAN,
|
||||
<para>The name of an IPoIB, IPVLAN, IPVTAP, MACsec, MACVLAN, MACVTAP, tunnel, VLAN,
|
||||
VXLAN, or Xfrm to be created on the link. See
|
||||
<citerefentry><refentrytitle>systemd.netdev</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
|
||||
This option may be specified more than once.</para>
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "netlink-util.h"
|
||||
#include "networkd-address.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "networkd-route-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "string-table.h"
|
||||
@ -245,44 +246,114 @@ static int netdev_l2tp_create_message_session(NetDev *netdev, L2tpSession *sessi
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l2tp_acquire_local_address_one(L2tpTunnel *t, Address *a, union in_addr_union *ret) {
|
||||
if (a->family != t->family)
|
||||
return -EINVAL;
|
||||
|
||||
if (in_addr_is_set(a->family, &a->in_addr_peer))
|
||||
return -EINVAL;
|
||||
|
||||
if (t->local_address_type == NETDEV_L2TP_LOCAL_ADDRESS_STATIC &&
|
||||
!FLAGS_SET(a->flags, IFA_F_PERMANENT))
|
||||
return -EINVAL;
|
||||
|
||||
if (t->local_address_type == NETDEV_L2TP_LOCAL_ADDRESS_DYNAMIC &&
|
||||
FLAGS_SET(a->flags, IFA_F_PERMANENT))
|
||||
return -EINVAL;
|
||||
|
||||
*ret = a->in_addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l2tp_acquire_local_address(L2tpTunnel *t, Link *link, union in_addr_union *ret) {
|
||||
static int link_get_l2tp_local_address(Link *link, L2tpTunnel *t, union in_addr_union *ret) {
|
||||
Address *a;
|
||||
|
||||
assert(t);
|
||||
assert(link);
|
||||
assert(ret);
|
||||
assert(IN_SET(t->family, AF_INET, AF_INET6));
|
||||
assert(t);
|
||||
|
||||
SET_FOREACH(a, link->addresses) {
|
||||
if (!address_is_ready(a))
|
||||
continue;
|
||||
|
||||
if (a->family != t->family)
|
||||
continue;
|
||||
|
||||
if (in_addr_is_set(a->family, &a->in_addr_peer))
|
||||
continue;
|
||||
|
||||
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) {
|
||||
Link *link = NULL;
|
||||
L2tpTunnel *t;
|
||||
Address *a;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(netdev->manager);
|
||||
assert_se(t = L2TP(netdev));
|
||||
|
||||
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)) {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
SET_FOREACH(a, link->addresses)
|
||||
if (l2tp_acquire_local_address_one(t, a, ret) >= 0)
|
||||
return 1;
|
||||
if (a) {
|
||||
if (t->local_address_type == NETDEV_L2TP_LOCAL_ADDRESS_STATIC &&
|
||||
!FLAGS_SET(a->flags, IFA_F_PERMANENT))
|
||||
return -EINVAL;
|
||||
|
||||
return -ENODATA;
|
||||
if (t->local_address_type == NETDEV_L2TP_LOCAL_ADDRESS_DYNAMIC &&
|
||||
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) {
|
||||
@ -361,7 +432,7 @@ static int l2tp_create_tunnel_handler(sd_netlink *rtnl, sd_netlink_message *m, N
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l2tp_create_tunnel(NetDev *netdev, Link *link) {
|
||||
static int l2tp_create_tunnel(NetDev *netdev) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
union in_addr_union local_address;
|
||||
L2tpTunnel *t;
|
||||
@ -370,11 +441,11 @@ static int l2tp_create_tunnel(NetDev *netdev, Link *link) {
|
||||
assert(netdev);
|
||||
assert_se(t = L2TP(netdev));
|
||||
|
||||
r = l2tp_acquire_local_address(t, link, &local_address);
|
||||
r = l2tp_get_local_address(netdev, &local_address);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not find local address.");
|
||||
|
||||
if (r > 0 && DEBUG_LOGGING) {
|
||||
if (t->local_address_type >= 0 && DEBUG_LOGGING) {
|
||||
_cleanup_free_ char *str = NULL;
|
||||
|
||||
(void) in_addr_to_string(t->family, &local_address, &str);
|
||||
@ -395,7 +466,95 @@ static int l2tp_create_tunnel(NetDev *netdev, Link *link) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_l2tp_tunnel_address(
|
||||
static int netdev_l2tp_is_ready_to_create(NetDev *netdev, Link *link) {
|
||||
return l2tp_get_local_address(netdev, NULL) >= 0;
|
||||
}
|
||||
|
||||
int config_parse_l2tp_tunnel_local_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) {
|
||||
|
||||
_cleanup_free_ char *addr_or_type = NULL, *ifname = NULL;
|
||||
L2tpLocalAddressType type;
|
||||
L2tpTunnel *t = userdata;
|
||||
const char *p = rvalue;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(t);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
t->local_ifname = mfree(t->local_ifname);
|
||||
t->local_address_type = NETDEV_L2TP_LOCAL_ADDRESS_AUTO;
|
||||
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;
|
||||
}
|
||||
|
||||
r = extract_first_word(&p, &addr_or_type, "@", 0);
|
||||
if (r < 0)
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
r = in_addr_from_string_auto(rvalue, &t->family, &t->local);
|
||||
else
|
||||
r = in_addr_from_string(t->family, rvalue, &t->local);
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
@ -408,41 +567,30 @@ int config_parse_l2tp_tunnel_address(
|
||||
void *userdata) {
|
||||
|
||||
L2tpTunnel *t = userdata;
|
||||
union in_addr_union *addr = data;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
assert(t);
|
||||
|
||||
if (streq(lvalue, "Local")) {
|
||||
L2tpLocalAddressType addr_type;
|
||||
if (isempty(rvalue)) {
|
||||
t->remote = IN_ADDR_NULL;
|
||||
|
||||
if (isempty(rvalue))
|
||||
addr_type = NETDEV_L2TP_LOCAL_ADDRESS_AUTO;
|
||||
else
|
||||
addr_type = l2tp_local_address_type_from_string(rvalue);
|
||||
if (!in_addr_is_set(t->family, &t->local))
|
||||
/* If Local= is not specified yet, then also clear family. */
|
||||
t->family = AF_UNSPEC;
|
||||
|
||||
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;
|
||||
|
||||
t->local = IN_ADDR_NULL;
|
||||
t->local_address_type = addr_type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (t->family == AF_UNSPEC)
|
||||
r = in_addr_from_string_auto(rvalue, &t->family, addr);
|
||||
r = in_addr_from_string_auto(rvalue, &t->family, &t->remote);
|
||||
else
|
||||
r = in_addr_from_string(t->family, rvalue, addr);
|
||||
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='%s', ignoring assignment: %m", lvalue, rvalue);
|
||||
"Invalid L2TP Tunnel address specified in %s=, ignoring assignment: %s", lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -699,14 +847,16 @@ static void l2tp_tunnel_done(NetDev *netdev) {
|
||||
assert(t);
|
||||
|
||||
ordered_hashmap_free_with_destructor(t->sessions_by_section, l2tp_session_free);
|
||||
free(t->local_ifname);
|
||||
}
|
||||
|
||||
const NetDevVTable l2tptnl_vtable = {
|
||||
.object_size = sizeof(L2tpTunnel),
|
||||
.init = l2tp_tunnel_init,
|
||||
.sections = NETDEV_COMMON_SECTIONS "L2TP\0L2TPSession\0",
|
||||
.create_after_configured = l2tp_create_tunnel,
|
||||
.create = l2tp_create_tunnel,
|
||||
.done = l2tp_tunnel_done,
|
||||
.create_type = NETDEV_CREATE_AFTER_CONFIGURED,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
.is_ready_to_create = netdev_l2tp_is_ready_to_create,
|
||||
.config_verify = netdev_l2tp_tunnel_verify,
|
||||
};
|
||||
|
@ -58,6 +58,7 @@ struct L2tpTunnel {
|
||||
bool udp6_csum_rx;
|
||||
bool udp6_csum_tx;
|
||||
|
||||
char *local_ifname;
|
||||
L2tpLocalAddressType local_address_type;
|
||||
union in_addr_union local;
|
||||
union in_addr_union remote;
|
||||
@ -70,7 +71,8 @@ struct L2tpTunnel {
|
||||
DEFINE_NETDEV_CAST(L2TP, L2tpTunnel);
|
||||
extern const NetDevVTable l2tptnl_vtable;
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_tunnel_address);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_tunnel_local_address);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_tunnel_remote_address);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_tunnel_id);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_encap_type);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_session_l2spec);
|
||||
|
@ -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.UDPSourcePort, config_parse_ip_port, 0, offsetof(L2tpTunnel, l2tp_udp_sport)
|
||||
L2TP.UDPDestinationPort, config_parse_ip_port, 0, offsetof(L2tpTunnel, l2tp_udp_dport)
|
||||
L2TP.Local, config_parse_l2tp_tunnel_address, 0, offsetof(L2tpTunnel, local)
|
||||
L2TP.Remote, config_parse_l2tp_tunnel_address, 0, offsetof(L2tpTunnel, remote)
|
||||
L2TP.Local, config_parse_l2tp_tunnel_local_address, 0, 0
|
||||
L2TP.Remote, config_parse_l2tp_tunnel_remote_address, 0, 0
|
||||
L2TP.EncapsulationType, config_parse_l2tp_encap_type, 0, offsetof(L2tpTunnel, l2tp_encap_type)
|
||||
L2TP.UDPCheckSum, config_parse_bool, 0, offsetof(L2tpTunnel, udp_csum)
|
||||
L2TP.UDP6CheckSumRx, config_parse_bool, 0, offsetof(L2tpTunnel, udp6_csum_rx)
|
||||
|
@ -144,7 +144,7 @@ bool netdev_is_managed(NetDev *netdev) {
|
||||
static bool netdev_is_stacked_and_independent(NetDev *netdev) {
|
||||
assert(netdev);
|
||||
|
||||
if (!IN_SET(netdev_get_create_type(netdev), NETDEV_CREATE_STACKED, NETDEV_CREATE_AFTER_CONFIGURED))
|
||||
if (netdev_get_create_type(netdev) != NETDEV_CREATE_STACKED)
|
||||
return false;
|
||||
|
||||
switch (netdev->kind) {
|
||||
@ -180,7 +180,7 @@ static bool netdev_is_stacked_and_independent(NetDev *netdev) {
|
||||
static bool netdev_is_stacked(NetDev *netdev) {
|
||||
assert(netdev);
|
||||
|
||||
if (!IN_SET(netdev_get_create_type(netdev), NETDEV_CREATE_STACKED, NETDEV_CREATE_AFTER_CONFIGURED))
|
||||
if (netdev_get_create_type(netdev) != NETDEV_CREATE_STACKED)
|
||||
return false;
|
||||
|
||||
if (netdev_is_stacked_and_independent(netdev))
|
||||
@ -617,10 +617,6 @@ static int netdev_is_ready_to_create(NetDev *netdev, Link *link) {
|
||||
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
|
||||
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)
|
||||
return false;
|
||||
|
||||
@ -652,28 +648,21 @@ int request_process_stacked_netdev(Request *req) {
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
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();
|
||||
}
|
||||
r = stacked_netdev_create(netdev, link, req->netlink_handler);
|
||||
if (r < 0)
|
||||
return log_netdev_warning_errno(netdev, r, "Failed to create netdev: %m");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int link_create_stacked_netdev_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
static int link_create_stacked_netdev_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
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))
|
||||
return 0;
|
||||
@ -685,18 +674,6 @@ static int link_create_stacked_netdev_handler_internal(sd_netlink *rtnl, sd_netl
|
||||
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) {
|
||||
link->stacked_netdevs_created = true;
|
||||
log_link_debug(link, "Stacked netdevs created.");
|
||||
@ -706,10 +683,6 @@ static int link_create_stacked_netdev_handler(sd_netlink *rtnl, sd_netlink_messa
|
||||
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 r;
|
||||
|
||||
@ -722,15 +695,11 @@ int link_request_stacked_netdev(Link *link, NetDev *netdev) {
|
||||
if (!IN_SET(netdev->state, NETDEV_STATE_LOADING, NETDEV_STATE_FAILED) || netdev->ifindex > 0)
|
||||
return 0; /* Already created. */
|
||||
|
||||
if (netdev_get_create_type(netdev) == NETDEV_CREATE_STACKED) {
|
||||
link->stacked_netdevs_created = false;
|
||||
r = link_queue_request(link, REQUEST_TYPE_NETDEV_STACKED, netdev_ref(netdev), true,
|
||||
&link->create_stacked_netdev_messages,
|
||||
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);
|
||||
link->stacked_netdevs_created = false;
|
||||
r = link_queue_request(link, REQUEST_TYPE_NETDEV_STACKED, netdev_ref(netdev), true,
|
||||
&link->create_stacked_netdev_messages,
|
||||
link_create_stacked_netdev_handler,
|
||||
NULL);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to request stacked netdev '%s': %m",
|
||||
netdev->ifname);
|
||||
|
@ -103,7 +103,6 @@ typedef enum NetDevState {
|
||||
typedef enum NetDevCreateType {
|
||||
NETDEV_CREATE_INDEPENDENT,
|
||||
NETDEV_CREATE_STACKED,
|
||||
NETDEV_CREATE_AFTER_CONFIGURED,
|
||||
_NETDEV_CREATE_MAX,
|
||||
_NETDEV_CREATE_INVALID = -EINVAL,
|
||||
} NetDevCreateType;
|
||||
@ -160,9 +159,6 @@ typedef struct NetDevVTable {
|
||||
/* create netdev, if not done via rtnl */
|
||||
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 */
|
||||
int (*post_create)(NetDev *netdev, Link *link);
|
||||
|
||||
|
@ -602,19 +602,35 @@ int link_get_address(Link *link, int family, const union in_addr_union *address,
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int manager_has_address(Manager *manager, int family, const union in_addr_union *address, bool check_ready) {
|
||||
Address *a;
|
||||
int manager_get_address(Manager *manager, int family, const union in_addr_union *address, unsigned char prefixlen, Address **ret) {
|
||||
Link *link;
|
||||
|
||||
assert(manager);
|
||||
assert(IN_SET(family, AF_INET, AF_INET6));
|
||||
assert(address);
|
||||
|
||||
HASHMAP_FOREACH(link, manager->links_by_index)
|
||||
if (link_get_address(link, family, address, 0, &a) >= 0)
|
||||
return check_ready ? address_is_ready(a) : address_exists(a);
|
||||
HASHMAP_FOREACH(link, manager->links_by_index) {
|
||||
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
|
||||
continue;
|
||||
|
||||
return false;
|
||||
if (link_get_address(link, family, address, prefixlen, ret) >= 0)
|
||||
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) {
|
||||
|
@ -88,7 +88,8 @@ static inline int link_get_ipv4_address(Link *link, const struct in_addr *addres
|
||||
assert(address);
|
||||
return link_get_address(link, AF_INET, &(union in_addr_union) { .in = *address }, prefixlen, ret);
|
||||
}
|
||||
int manager_has_address(Manager *manager, int family, const union in_addr_union *address, bool check_ready);
|
||||
int manager_get_address(Manager *manager, int family, const union in_addr_union *address, unsigned char prefixlen, Address **ret);
|
||||
bool manager_has_address(Manager *manager, int family, const union in_addr_union *address, bool check_ready);
|
||||
|
||||
void address_cancel_request(Address *address);
|
||||
int link_request_address(
|
||||
|
@ -93,7 +93,7 @@ Network.VRF, config_parse_ifname,
|
||||
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.IPVTAP, config_parse_stacked_netdev, NETDEV_KIND_IPVTAP, offsetof(Network, stacked_netdev_names)
|
||||
Network.L2TP, config_parse_stacked_netdev, NETDEV_KIND_L2TP, offsetof(Network, stacked_netdev_names)
|
||||
Network.L2TP, config_parse_warn_compat, DISABLED_LEGACY, 0
|
||||
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.MACVTAP, config_parse_stacked_netdev, NETDEV_KIND_MACVTAP, offsetof(Network, stacked_netdev_names)
|
||||
|
@ -871,7 +871,6 @@ int config_parse_stacked_netdev(
|
||||
NETDEV_KIND_IPOIB,
|
||||
NETDEV_KIND_IPVLAN,
|
||||
NETDEV_KIND_IPVTAP,
|
||||
NETDEV_KIND_L2TP,
|
||||
NETDEV_KIND_MACSEC,
|
||||
NETDEV_KIND_MACVLAN,
|
||||
NETDEV_KIND_MACVTAP,
|
||||
|
@ -102,14 +102,21 @@ int manager_find_uplink(Manager *m, int family, Link *exclude, Link **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool link_address_is_reachable(Link *link, int family, const union in_addr_union *address) {
|
||||
bool gateway_is_ready(Link *link, bool onlink, int family, const union in_addr_union *gw) {
|
||||
Route *route;
|
||||
Address *a;
|
||||
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
assert(IN_SET(family, AF_INET, AF_INET6));
|
||||
assert(address);
|
||||
|
||||
if (onlink)
|
||||
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) {
|
||||
if (!route_exists(route))
|
||||
@ -118,7 +125,7 @@ static bool link_address_is_reachable(Link *link, int family, const union in_add
|
||||
continue;
|
||||
if (!in_addr_is_set(route->family, &route->dst) && route->dst_prefixlen == 0)
|
||||
continue;
|
||||
if (in_addr_prefix_covers(family, &route->dst, route->dst_prefixlen, address) > 0)
|
||||
if (in_addr_prefix_covers(family, &route->dst, route->dst_prefixlen, gw) > 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -136,27 +143,148 @@ static bool link_address_is_reachable(Link *link, int family, const union in_add
|
||||
continue;
|
||||
if (in_addr_is_set(a->family, &a->in_addr_peer))
|
||||
continue;
|
||||
if (in_addr_prefix_covers(family, &a->in_addr, a->prefixlen, address) > 0)
|
||||
if (in_addr_prefix_covers(family, &a->in_addr, a->prefixlen, gw) > 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool gateway_is_ready(Link *link, bool onlink, int family, const union in_addr_union *gw) {
|
||||
static int link_address_is_reachable_internal(
|
||||
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(gw);
|
||||
assert(IN_SET(family, AF_INET, AF_INET6));
|
||||
assert(address);
|
||||
|
||||
if (onlink)
|
||||
return true;
|
||||
SET_FOREACH(route, link->routes) {
|
||||
if (!route_exists(route))
|
||||
continue;
|
||||
|
||||
if (!in_addr_is_set(family, gw))
|
||||
return true;
|
||||
if (route->type != RTN_UNICAST)
|
||||
continue;
|
||||
|
||||
if (family == AF_INET6 && in6_addr_is_link_local(&gw->in6))
|
||||
return true;
|
||||
if (route->family != family)
|
||||
continue;
|
||||
|
||||
return link_address_is_reachable(link, family, gw);
|
||||
if (in_addr_prefix_covers(family, &route->dst, route->dst_prefixlen, address) <= 0)
|
||||
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] = {
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
typedef struct Link Link;
|
||||
typedef struct Manager Manager;
|
||||
typedef struct Address Address;
|
||||
|
||||
unsigned routes_max(void);
|
||||
|
||||
@ -15,6 +16,20 @@ 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);
|
||||
|
||||
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_;
|
||||
const char *route_type_to_string(int t) _const_;
|
||||
|
||||
|
@ -5,4 +5,3 @@ Name=test1
|
||||
[Network]
|
||||
Address=192.168.30.100/24
|
||||
IPv6AcceptRA=false
|
||||
L2TP=l2tp99
|
||||
|
@ -6,7 +6,7 @@ Name=l2tp99
|
||||
[L2TP]
|
||||
TunnelId=10
|
||||
PeerTunnelId=12
|
||||
Local=static
|
||||
Local=static@test1
|
||||
Remote=192.168.30.101
|
||||
EncapsulationType=ip
|
||||
|
||||
|
@ -8,7 +8,7 @@ TunnelId=10
|
||||
PeerTunnelId=11
|
||||
UDPSourcePort=3000
|
||||
UDPDestinationPort=4000
|
||||
Local=static
|
||||
Local=static@test1
|
||||
Remote=192.168.30.101
|
||||
EncapsulationType=udp
|
||||
UDPCheckSum=true
|
||||
|
Loading…
Reference in New Issue
Block a user