2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2019-05-09 02:33:45 +02:00
|
|
|
#include <netinet/in.h>
|
2013-10-17 03:18:36 +02:00
|
|
|
#include <linux/if.h>
|
2019-07-24 11:22:43 +02:00
|
|
|
#include <linux/if_arp.h>
|
2020-06-21 13:17:34 +02:00
|
|
|
#include <linux/if_link.h>
|
2014-07-01 20:58:49 +02:00
|
|
|
#include <unistd.h>
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2019-10-30 09:02:15 +01:00
|
|
|
#include "bond.h"
|
|
|
|
#include "bridge.h"
|
2014-01-13 23:48:28 +01:00
|
|
|
#include "bus-util.h"
|
2018-07-02 20:19:15 +02:00
|
|
|
#include "dhcp-identifier.h"
|
2015-08-26 20:48:21 +02:00
|
|
|
#include "dhcp-lease-internal.h"
|
2018-11-30 22:08:41 +01:00
|
|
|
#include "env-file.h"
|
2019-01-07 12:16:19 +01:00
|
|
|
#include "ethtool-util.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "fd-util.h"
|
2015-09-23 01:53:29 +02:00
|
|
|
#include "fileio.h"
|
2019-10-30 09:02:15 +01:00
|
|
|
#include "ipvlan.h"
|
2018-12-06 07:20:07 +01:00
|
|
|
#include "missing_network.h"
|
2015-09-23 01:53:29 +02:00
|
|
|
#include "netlink-util.h"
|
2014-03-21 21:38:14 +01:00
|
|
|
#include "network-internal.h"
|
2019-05-09 08:39:19 +02:00
|
|
|
#include "networkd-can.h"
|
2019-06-29 21:33:34 +02:00
|
|
|
#include "networkd-dhcp-server.h"
|
2019-06-29 20:57:47 +02:00
|
|
|
#include "networkd-dhcp4.h"
|
|
|
|
#include "networkd-dhcp6.h"
|
|
|
|
#include "networkd-ipv4ll.h"
|
2017-02-11 00:47:55 +01:00
|
|
|
#include "networkd-ipv6-proxy-ndp.h"
|
2019-05-26 22:35:02 +02:00
|
|
|
#include "networkd-link-bus.h"
|
|
|
|
#include "networkd-link.h"
|
2016-02-21 14:14:08 +01:00
|
|
|
#include "networkd-lldp-tx.h"
|
2016-11-13 04:59:06 +01:00
|
|
|
#include "networkd-manager.h"
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
#include "networkd-ndisc.h"
|
2018-11-29 04:00:58 +01:00
|
|
|
#include "networkd-neighbor.h"
|
2020-06-21 13:17:34 +02:00
|
|
|
#include "networkd-sriov.h"
|
2017-05-12 15:48:33 +02:00
|
|
|
#include "networkd-radv.h"
|
2017-09-14 21:51:39 +02:00
|
|
|
#include "networkd-routing-policy-rule.h"
|
2019-07-24 07:46:55 +02:00
|
|
|
#include "networkd-wifi.h"
|
2015-09-23 01:53:29 +02:00
|
|
|
#include "set.h"
|
|
|
|
#include "socket-util.h"
|
2019-12-04 11:12:36 +01:00
|
|
|
#include "stat-util.h"
|
2015-10-27 01:26:31 +01:00
|
|
|
#include "stdio-util.h"
|
2015-10-26 22:31:05 +01:00
|
|
|
#include "string-table.h"
|
2018-08-22 07:30:49 +02:00
|
|
|
#include "strv.h"
|
2019-02-18 06:30:32 +01:00
|
|
|
#include "sysctl-util.h"
|
2020-02-10 12:53:00 +01:00
|
|
|
#include "tc.h"
|
2018-11-30 21:05:27 +01:00
|
|
|
#include "tmpfile-util.h"
|
2019-03-04 04:19:05 +01:00
|
|
|
#include "udev-util.h"
|
2015-09-23 01:53:29 +02:00
|
|
|
#include "util.h"
|
2019-10-30 09:02:15 +01:00
|
|
|
#include "vrf.h"
|
2015-08-27 13:59:06 +02:00
|
|
|
|
2019-02-12 04:49:45 +01:00
|
|
|
uint32_t link_get_vrf_table(Link *link) {
|
|
|
|
return link->network->vrf ? VRF(link->network->vrf)->table : RT_TABLE_MAIN;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t link_get_dhcp_route_table(Link *link) {
|
|
|
|
/* When the interface is part of an VRF use the VRFs routing table, unless
|
|
|
|
* another table is explicitly specified. */
|
|
|
|
if (link->network->dhcp_route_table_set)
|
|
|
|
return link->network->dhcp_route_table;
|
|
|
|
return link_get_vrf_table(link);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t link_get_ipv6_accept_ra_route_table(Link *link) {
|
|
|
|
if (link->network->ipv6_accept_ra_route_table_set)
|
|
|
|
return link->network->ipv6_accept_ra_route_table;
|
|
|
|
return link_get_vrf_table(link);
|
|
|
|
}
|
|
|
|
|
2018-08-06 10:28:27 +02:00
|
|
|
DUID* link_get_duid(Link *link) {
|
|
|
|
if (link->network->duid.type != _DUID_TYPE_INVALID)
|
|
|
|
return &link->network->duid;
|
|
|
|
else
|
|
|
|
return &link->manager->duid;
|
|
|
|
}
|
|
|
|
|
2016-02-20 23:27:57 +01:00
|
|
|
static bool link_dhcp6_enabled(Link *link) {
|
|
|
|
assert(link);
|
|
|
|
|
2016-04-20 15:32:24 +02:00
|
|
|
if (!socket_ipv6_is_supported())
|
|
|
|
return false;
|
|
|
|
|
2014-09-04 20:54:08 +02:00
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
2019-02-09 14:40:05 +01:00
|
|
|
if (link->network->bond)
|
|
|
|
return false;
|
|
|
|
|
2019-07-25 03:11:45 +02:00
|
|
|
if (link->iftype == ARPHRD_CAN)
|
2019-05-20 08:59:44 +02:00
|
|
|
return false;
|
|
|
|
|
2015-06-09 01:05:34 +02:00
|
|
|
return link->network->dhcp & ADDRESS_FAMILY_IPV6;
|
2014-09-04 20:54:08 +02:00
|
|
|
}
|
|
|
|
|
2016-02-20 23:27:57 +01:00
|
|
|
static bool link_dhcp4_enabled(Link *link) {
|
|
|
|
assert(link);
|
|
|
|
|
2014-09-04 20:54:08 +02:00
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
2019-02-09 14:40:05 +01:00
|
|
|
if (link->network->bond)
|
|
|
|
return false;
|
|
|
|
|
2019-07-25 03:11:45 +02:00
|
|
|
if (link->iftype == ARPHRD_CAN)
|
2019-05-20 08:59:44 +02:00
|
|
|
return false;
|
|
|
|
|
2015-06-09 01:05:34 +02:00
|
|
|
return link->network->dhcp & ADDRESS_FAMILY_IPV4;
|
2014-09-04 20:54:08 +02:00
|
|
|
}
|
|
|
|
|
2016-02-20 23:27:57 +01:00
|
|
|
static bool link_dhcp4_server_enabled(Link *link) {
|
|
|
|
assert(link);
|
|
|
|
|
2014-09-04 20:54:08 +02:00
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
2019-02-09 14:40:05 +01:00
|
|
|
if (link->network->bond)
|
|
|
|
return false;
|
|
|
|
|
2019-07-25 03:11:45 +02:00
|
|
|
if (link->iftype == ARPHRD_CAN)
|
2019-05-20 08:59:44 +02:00
|
|
|
return false;
|
|
|
|
|
2014-09-04 20:54:08 +02:00
|
|
|
return link->network->dhcp_server;
|
|
|
|
}
|
|
|
|
|
2019-08-03 22:09:08 +02:00
|
|
|
bool link_ipv4ll_enabled(Link *link, AddressFamily mask) {
|
2016-02-20 23:27:57 +01:00
|
|
|
assert(link);
|
2019-05-22 07:49:46 +02:00
|
|
|
assert((mask & ~(ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) == 0);
|
2016-02-20 23:27:57 +01:00
|
|
|
|
2014-09-04 20:54:08 +02:00
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
2019-07-25 03:11:45 +02:00
|
|
|
if (link->iftype == ARPHRD_CAN)
|
2019-07-24 11:23:45 +02:00
|
|
|
return false;
|
|
|
|
|
2019-07-08 17:09:46 +02:00
|
|
|
if (STRPTR_IN_SET(link->kind,
|
|
|
|
"vrf", "wireguard", "ipip", "gre", "ip6gre","ip6tnl", "sit", "vti",
|
2020-09-17 08:18:18 +02:00
|
|
|
"vti6", "nlmon", "xfrm", "bareudp"))
|
2018-01-26 15:34:09 +01:00
|
|
|
return false;
|
|
|
|
|
2019-05-20 06:15:02 +02:00
|
|
|
/* L3 or L3S mode do not support ARP. */
|
|
|
|
if (IN_SET(link_get_ipvlan_mode(link), NETDEV_IPVLAN_MODE_L3, NETDEV_IPVLAN_MODE_L3S))
|
|
|
|
return false;
|
|
|
|
|
2019-02-09 14:40:05 +01:00
|
|
|
if (link->network->bond)
|
|
|
|
return false;
|
|
|
|
|
2019-05-22 07:49:46 +02:00
|
|
|
return link->network->link_local & mask;
|
2019-05-01 08:43:23 +02:00
|
|
|
}
|
|
|
|
|
2016-02-20 23:27:57 +01:00
|
|
|
static bool link_ipv6ll_enabled(Link *link) {
|
|
|
|
assert(link);
|
|
|
|
|
2016-04-20 15:32:24 +02:00
|
|
|
if (!socket_ipv6_is_supported())
|
|
|
|
return false;
|
|
|
|
|
2015-02-08 22:27:15 +01:00
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
2019-07-25 03:11:45 +02:00
|
|
|
if (link->iftype == ARPHRD_CAN)
|
2019-07-24 11:23:45 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (STRPTR_IN_SET(link->kind, "vrf", "wireguard", "ipip", "gre", "sit", "vti", "nlmon"))
|
2018-01-26 15:34:09 +01:00
|
|
|
return false;
|
|
|
|
|
2019-02-09 14:40:05 +01:00
|
|
|
if (link->network->bond)
|
|
|
|
return false;
|
|
|
|
|
2015-06-09 01:05:34 +02:00
|
|
|
return link->network->link_local & ADDRESS_FAMILY_IPV6;
|
2014-09-04 20:54:08 +02:00
|
|
|
}
|
|
|
|
|
2016-04-21 02:34:13 +02:00
|
|
|
static bool link_ipv6_enabled(Link *link) {
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (!socket_ipv6_is_supported())
|
|
|
|
return false;
|
|
|
|
|
2019-02-20 02:07:20 +01:00
|
|
|
if (link->network->bond)
|
2016-05-28 07:35:01 +02:00
|
|
|
return false;
|
|
|
|
|
2019-07-25 03:11:45 +02:00
|
|
|
if (link->iftype == ARPHRD_CAN)
|
2019-05-20 08:59:44 +02:00
|
|
|
return false;
|
|
|
|
|
2016-05-25 14:40:48 +02:00
|
|
|
/* DHCPv6 client will not be started if no IPv6 link-local address is configured. */
|
2019-08-27 16:15:24 +02:00
|
|
|
if (link_ipv6ll_enabled(link))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (network_has_static_ipv6_configurations(link->network))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
2016-04-21 02:34:13 +02:00
|
|
|
}
|
|
|
|
|
2017-05-12 15:48:33 +02:00
|
|
|
static bool link_radv_enabled(Link *link) {
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (!link_ipv6ll_enabled(link))
|
|
|
|
return false;
|
|
|
|
|
2018-01-15 15:47:55 +01:00
|
|
|
return link->network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE;
|
2017-05-12 15:48:33 +02:00
|
|
|
}
|
|
|
|
|
2015-01-13 20:07:13 +01:00
|
|
|
static bool link_ipv4_forward_enabled(Link *link) {
|
2016-02-20 23:27:57 +01:00
|
|
|
assert(link);
|
|
|
|
|
2015-01-13 13:47:08 +01:00
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
2019-08-03 22:09:08 +02:00
|
|
|
if (link->network->ip_forward == _ADDRESS_FAMILY_INVALID)
|
2015-11-13 12:49:15 +01:00
|
|
|
return false;
|
|
|
|
|
2015-06-09 01:05:34 +02:00
|
|
|
return link->network->ip_forward & ADDRESS_FAMILY_IPV4;
|
2015-01-13 20:07:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool link_ipv6_forward_enabled(Link *link) {
|
2016-02-20 23:27:57 +01:00
|
|
|
assert(link);
|
2015-11-13 12:49:15 +01:00
|
|
|
|
|
|
|
if (!socket_ipv6_is_supported())
|
|
|
|
return false;
|
|
|
|
|
2015-01-13 20:07:13 +01:00
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
2019-08-03 22:09:08 +02:00
|
|
|
if (link->network->ip_forward == _ADDRESS_FAMILY_INVALID)
|
2015-11-13 12:49:15 +01:00
|
|
|
return false;
|
|
|
|
|
2015-06-09 01:05:34 +02:00
|
|
|
return link->network->ip_forward & ADDRESS_FAMILY_IPV6;
|
2015-01-13 13:47:08 +01:00
|
|
|
}
|
|
|
|
|
2016-04-14 11:56:57 +02:00
|
|
|
static bool link_proxy_arp_enabled(Link *link) {
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (link->network->proxy_arp < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-02-20 23:27:57 +01:00
|
|
|
static bool link_ipv6_accept_ra_enabled(Link *link) {
|
|
|
|
assert(link);
|
|
|
|
|
2016-04-20 15:32:24 +02:00
|
|
|
if (!socket_ipv6_is_supported())
|
|
|
|
return false;
|
|
|
|
|
networkd: IPv6 router discovery - follow IPv6AcceptRouterAdvertisemnt=
The previous behavior:
When DHCPv6 was enabled, router discover was performed first, and then DHCPv6 was
enabled only if the relevant flags were passed in the Router Advertisement message.
Moreover, router discovery was performed even if AcceptRouterAdvertisements=false,
moreover, even if router advertisements were accepted (by the kernel) the flags
indicating that DHCPv6 should be performed were ignored.
New behavior:
If RouterAdvertisements are accepted, and either no routers are found, or an
advertisement is received indicating DHCPv6 should be performed, the DHCPv6
client is started. Moreover, the DHCP option now truly enables the DHCPv6
client regardless of router discovery (though it will probably not be
very useful to get a lease withotu any routes, this seems the more consistent
approach).
The recommended default setting should be to set DHCP=ipv4 and to leave
IPv6AcceptRouterAdvertisements unset.
2015-10-18 18:25:58 +02:00
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
2017-10-18 11:12:59 +02:00
|
|
|
if (!link_ipv6ll_enabled(link))
|
|
|
|
return false;
|
|
|
|
|
networkd: IPv6 router discovery - follow IPv6AcceptRouterAdvertisemnt=
The previous behavior:
When DHCPv6 was enabled, router discover was performed first, and then DHCPv6 was
enabled only if the relevant flags were passed in the Router Advertisement message.
Moreover, router discovery was performed even if AcceptRouterAdvertisements=false,
moreover, even if router advertisements were accepted (by the kernel) the flags
indicating that DHCPv6 should be performed were ignored.
New behavior:
If RouterAdvertisements are accepted, and either no routers are found, or an
advertisement is received indicating DHCPv6 should be performed, the DHCPv6
client is started. Moreover, the DHCP option now truly enables the DHCPv6
client regardless of router discovery (though it will probably not be
very useful to get a lease withotu any routes, this seems the more consistent
approach).
The recommended default setting should be to set DHCP=ipv4 and to leave
IPv6AcceptRouterAdvertisements unset.
2015-10-18 18:25:58 +02:00
|
|
|
/* If unset use system default (enabled if local forwarding is disabled.
|
|
|
|
* disabled if local forwarding is enabled).
|
|
|
|
* If set, ignore or enforce RA independent of local forwarding state.
|
|
|
|
*/
|
|
|
|
if (link->network->ipv6_accept_ra < 0)
|
|
|
|
/* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */
|
|
|
|
return !link_ipv6_forward_enabled(link);
|
|
|
|
else if (link->network->ipv6_accept_ra > 0)
|
|
|
|
/* accept RA even if ip_forward is enabled */
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
/* ignore RA */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-07-06 20:29:33 +02:00
|
|
|
static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) {
|
2016-04-20 15:32:24 +02:00
|
|
|
assert(link);
|
2015-11-13 12:32:38 +01:00
|
|
|
|
|
|
|
if (!socket_ipv6_is_supported())
|
|
|
|
return _IPV6_PRIVACY_EXTENSIONS_INVALID;
|
|
|
|
|
2015-07-05 07:54:31 +02:00
|
|
|
if (link->flags & IFF_LOOPBACK)
|
2015-07-06 20:29:33 +02:00
|
|
|
return _IPV6_PRIVACY_EXTENSIONS_INVALID;
|
2015-07-05 07:54:31 +02:00
|
|
|
|
|
|
|
if (!link->network)
|
2015-07-06 20:29:33 +02:00
|
|
|
return _IPV6_PRIVACY_EXTENSIONS_INVALID;
|
2015-07-05 07:54:31 +02:00
|
|
|
|
|
|
|
return link->network->ipv6_privacy_extensions;
|
|
|
|
}
|
|
|
|
|
2019-08-22 13:26:54 +02:00
|
|
|
static int link_update_ipv6_sysctl(Link *link) {
|
2019-08-19 12:00:35 +02:00
|
|
|
bool enabled;
|
2016-04-21 02:34:13 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return 0;
|
|
|
|
|
2019-08-19 12:00:35 +02:00
|
|
|
enabled = link_ipv6_enabled(link);
|
|
|
|
if (enabled) {
|
|
|
|
r = sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "disable_ipv6", false);
|
|
|
|
if (r < 0)
|
2019-08-22 13:26:54 +02:00
|
|
|
return log_link_warning_errno(link, r, "Cannot enable IPv6: %m");
|
|
|
|
|
|
|
|
log_link_info(link, "IPv6 successfully enabled");
|
2019-08-19 12:00:35 +02:00
|
|
|
}
|
2016-04-21 02:34:13 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-02-15 04:35:30 +01:00
|
|
|
static bool link_is_enslaved(Link *link) {
|
|
|
|
if (link->flags & IFF_SLAVE)
|
|
|
|
/* Even if the link is not managed by networkd, honor IFF_SLAVE flag. */
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
2019-05-22 03:46:11 +02:00
|
|
|
if (link->master_ifindex > 0 && link->network->bridge)
|
2019-02-15 04:35:30 +01:00
|
|
|
return true;
|
|
|
|
|
2019-05-22 03:46:11 +02:00
|
|
|
/* TODO: add conditions for other netdevs. */
|
|
|
|
|
2019-02-15 04:35:30 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-02-20 02:31:15 +01:00
|
|
|
static void link_update_master_operstate(Link *link, NetDev *netdev) {
|
|
|
|
Link *master;
|
|
|
|
|
|
|
|
if (!netdev)
|
|
|
|
return;
|
|
|
|
|
2020-06-25 06:41:47 +02:00
|
|
|
if (netdev->ifindex <= 0)
|
|
|
|
return;
|
|
|
|
|
2019-02-20 02:31:15 +01:00
|
|
|
if (link_get(link->manager, netdev->ifindex, &master) < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
link_update_operstate(master, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void link_update_operstate(Link *link, bool also_update_master) {
|
2015-09-30 18:17:43 +02:00
|
|
|
LinkOperationalState operstate;
|
2019-06-16 01:58:39 +02:00
|
|
|
LinkCarrierState carrier_state;
|
|
|
|
LinkAddressState address_state;
|
2019-06-16 02:03:25 +02:00
|
|
|
_cleanup_strv_free_ char **p = NULL;
|
2019-06-16 01:58:39 +02:00
|
|
|
uint8_t scope = RT_SCOPE_NOWHERE;
|
2019-06-16 02:03:25 +02:00
|
|
|
bool changed = false;
|
2019-06-16 01:58:39 +02:00
|
|
|
Address *address;
|
2019-02-15 04:29:59 +01:00
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (link->kernel_operstate == IF_OPER_DORMANT)
|
2019-06-16 01:58:39 +02:00
|
|
|
carrier_state = LINK_CARRIER_STATE_DORMANT;
|
2015-09-30 18:17:43 +02:00
|
|
|
else if (link_has_carrier(link)) {
|
2019-06-16 01:58:39 +02:00
|
|
|
if (link_is_enslaved(link))
|
|
|
|
carrier_state = LINK_CARRIER_STATE_ENSLAVED;
|
2015-09-30 18:17:43 +02:00
|
|
|
else
|
2019-06-16 01:58:39 +02:00
|
|
|
carrier_state = LINK_CARRIER_STATE_CARRIER;
|
2015-09-30 18:17:43 +02:00
|
|
|
} else if (link->flags & IFF_UP)
|
2019-06-16 01:58:39 +02:00
|
|
|
carrier_state = LINK_CARRIER_STATE_NO_CARRIER;
|
2015-09-30 18:17:43 +02:00
|
|
|
else
|
2019-06-16 01:58:39 +02:00
|
|
|
carrier_state = LINK_CARRIER_STATE_OFF;
|
2015-09-30 18:17:43 +02:00
|
|
|
|
2019-06-16 01:58:39 +02:00
|
|
|
if (carrier_state >= LINK_CARRIER_STATE_CARRIER) {
|
2019-02-12 22:32:48 +01:00
|
|
|
Link *slave;
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(slave, link->slaves) {
|
2019-02-12 22:32:48 +01:00
|
|
|
link_update_operstate(slave, false);
|
2015-09-30 18:17:43 +02:00
|
|
|
|
2019-06-16 01:58:39 +02:00
|
|
|
if (slave->carrier_state < LINK_CARRIER_STATE_CARRIER)
|
|
|
|
carrier_state = LINK_CARRIER_STATE_DEGRADED_CARRIER;
|
2015-09-30 18:17:43 +02:00
|
|
|
}
|
2019-02-12 22:32:48 +01:00
|
|
|
}
|
2015-09-30 18:17:43 +02:00
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(address, link->addresses) {
|
2019-06-16 01:58:39 +02:00
|
|
|
if (!address_is_ready(address))
|
|
|
|
continue;
|
2015-09-30 18:17:43 +02:00
|
|
|
|
2019-06-16 01:58:39 +02:00
|
|
|
if (address->scope < scope)
|
|
|
|
scope = address->scope;
|
|
|
|
}
|
2015-09-30 18:17:43 +02:00
|
|
|
|
2019-06-16 01:58:39 +02:00
|
|
|
/* for operstate we also take foreign addresses into account */
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(address, link->addresses_foreign) {
|
2019-06-16 01:58:39 +02:00
|
|
|
if (!address_is_ready(address))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (address->scope < scope)
|
|
|
|
scope = address->scope;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (scope < RT_SCOPE_SITE)
|
|
|
|
/* universally accessible addresses found */
|
|
|
|
address_state = LINK_ADDRESS_STATE_ROUTABLE;
|
|
|
|
else if (scope < RT_SCOPE_HOST)
|
|
|
|
/* only link or site local addresses found */
|
|
|
|
address_state = LINK_ADDRESS_STATE_DEGRADED;
|
2015-09-30 18:17:43 +02:00
|
|
|
else
|
2019-06-16 01:58:39 +02:00
|
|
|
/* no useful addresses found */
|
|
|
|
address_state = LINK_ADDRESS_STATE_OFF;
|
|
|
|
|
|
|
|
/* Mapping of address and carrier state vs operational state
|
|
|
|
* carrier state
|
|
|
|
* | off | no-carrier | dormant | degraded-carrier | carrier | enslaved
|
|
|
|
* ------------------------------------------------------------------------------
|
|
|
|
* off | off | no-carrier | dormant | degraded-carrier | carrier | enslaved
|
|
|
|
* address_state degraded | off | no-carrier | dormant | degraded-carrier | degraded | enslaved
|
|
|
|
* routable | off | no-carrier | dormant | degraded-carrier | routable | routable
|
|
|
|
*/
|
2015-09-30 18:17:43 +02:00
|
|
|
|
2019-06-16 01:58:39 +02:00
|
|
|
if (carrier_state < LINK_CARRIER_STATE_CARRIER || address_state == LINK_ADDRESS_STATE_OFF)
|
|
|
|
operstate = (LinkOperationalState) carrier_state;
|
|
|
|
else if (address_state == LINK_ADDRESS_STATE_ROUTABLE)
|
|
|
|
operstate = LINK_OPERSTATE_ROUTABLE;
|
|
|
|
else if (carrier_state == LINK_CARRIER_STATE_CARRIER)
|
|
|
|
operstate = LINK_OPERSTATE_DEGRADED;
|
|
|
|
else
|
2019-02-15 04:29:59 +01:00
|
|
|
operstate = LINK_OPERSTATE_ENSLAVED;
|
|
|
|
|
2019-06-16 02:03:25 +02:00
|
|
|
if (link->carrier_state != carrier_state) {
|
|
|
|
link->carrier_state = carrier_state;
|
|
|
|
changed = true;
|
|
|
|
if (strv_extend(&p, "CarrierState") < 0)
|
|
|
|
log_oom();
|
|
|
|
}
|
2019-02-12 22:32:48 +01:00
|
|
|
|
2019-06-16 02:03:25 +02:00
|
|
|
if (link->address_state != address_state) {
|
|
|
|
link->address_state = address_state;
|
|
|
|
changed = true;
|
|
|
|
if (strv_extend(&p, "AddressState") < 0)
|
|
|
|
log_oom();
|
2019-02-12 22:32:48 +01:00
|
|
|
}
|
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
if (link->operstate != operstate) {
|
|
|
|
link->operstate = operstate;
|
2019-06-16 02:03:25 +02:00
|
|
|
changed = true;
|
|
|
|
if (strv_extend(&p, "OperationalState") < 0)
|
|
|
|
log_oom();
|
2015-09-30 18:17:43 +02:00
|
|
|
}
|
2019-02-12 22:32:48 +01:00
|
|
|
|
2019-06-16 02:03:25 +02:00
|
|
|
if (p)
|
|
|
|
link_send_changed_strv(link, p);
|
|
|
|
if (changed)
|
|
|
|
link_dirty(link);
|
|
|
|
|
2019-02-20 02:31:15 +01:00
|
|
|
if (also_update_master && link->network) {
|
|
|
|
link_update_master_operstate(link, link->network->bond);
|
|
|
|
link_update_master_operstate(link, link->network->bridge);
|
2019-02-12 22:32:48 +01:00
|
|
|
}
|
2015-09-30 18:17:43 +02:00
|
|
|
}
|
|
|
|
|
2014-09-04 14:10:43 +02:00
|
|
|
#define FLAG_STRING(string, flag, old, new) \
|
|
|
|
(((old ^ new) & flag) \
|
|
|
|
? ((old & flag) ? (" -" string) : (" +" string)) \
|
|
|
|
: "")
|
|
|
|
|
2019-05-22 03:46:11 +02:00
|
|
|
static int link_update_flags(Link *link, sd_netlink_message *m, bool force_update_operstate) {
|
2014-09-04 14:10:43 +02:00
|
|
|
unsigned flags, unknown_flags_added, unknown_flags_removed, unknown_flags;
|
|
|
|
uint8_t operstate;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
r = sd_rtnl_message_link_get_flags(m, &flags);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not get link flags: %m");
|
2014-09-04 14:10:43 +02:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_u8(m, IFLA_OPERSTATE, &operstate);
|
2014-09-04 14:10:43 +02:00
|
|
|
if (r < 0)
|
|
|
|
/* if we got a message without operstate, take it to mean
|
|
|
|
the state was unchanged */
|
|
|
|
operstate = link->kernel_operstate;
|
|
|
|
|
2019-05-22 03:46:11 +02:00
|
|
|
if (!force_update_operstate && (link->flags == flags) && (link->kernel_operstate == operstate))
|
2014-09-04 14:10:43 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (link->flags != flags) {
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Flags change:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
2014-09-04 14:10:43 +02:00
|
|
|
FLAG_STRING("LOOPBACK", IFF_LOOPBACK, link->flags, flags),
|
|
|
|
FLAG_STRING("MASTER", IFF_MASTER, link->flags, flags),
|
|
|
|
FLAG_STRING("SLAVE", IFF_SLAVE, link->flags, flags),
|
|
|
|
FLAG_STRING("UP", IFF_UP, link->flags, flags),
|
|
|
|
FLAG_STRING("DORMANT", IFF_DORMANT, link->flags, flags),
|
|
|
|
FLAG_STRING("LOWER_UP", IFF_LOWER_UP, link->flags, flags),
|
|
|
|
FLAG_STRING("RUNNING", IFF_RUNNING, link->flags, flags),
|
|
|
|
FLAG_STRING("MULTICAST", IFF_MULTICAST, link->flags, flags),
|
|
|
|
FLAG_STRING("BROADCAST", IFF_BROADCAST, link->flags, flags),
|
|
|
|
FLAG_STRING("POINTOPOINT", IFF_POINTOPOINT, link->flags, flags),
|
|
|
|
FLAG_STRING("PROMISC", IFF_PROMISC, link->flags, flags),
|
|
|
|
FLAG_STRING("ALLMULTI", IFF_ALLMULTI, link->flags, flags),
|
|
|
|
FLAG_STRING("PORTSEL", IFF_PORTSEL, link->flags, flags),
|
|
|
|
FLAG_STRING("AUTOMEDIA", IFF_AUTOMEDIA, link->flags, flags),
|
|
|
|
FLAG_STRING("DYNAMIC", IFF_DYNAMIC, link->flags, flags),
|
|
|
|
FLAG_STRING("NOARP", IFF_NOARP, link->flags, flags),
|
|
|
|
FLAG_STRING("NOTRAILERS", IFF_NOTRAILERS, link->flags, flags),
|
|
|
|
FLAG_STRING("DEBUG", IFF_DEBUG, link->flags, flags),
|
|
|
|
FLAG_STRING("ECHO", IFF_ECHO, link->flags, flags));
|
|
|
|
|
|
|
|
unknown_flags = ~(IFF_LOOPBACK | IFF_MASTER | IFF_SLAVE | IFF_UP |
|
|
|
|
IFF_DORMANT | IFF_LOWER_UP | IFF_RUNNING |
|
|
|
|
IFF_MULTICAST | IFF_BROADCAST | IFF_POINTOPOINT |
|
|
|
|
IFF_PROMISC | IFF_ALLMULTI | IFF_PORTSEL |
|
|
|
|
IFF_AUTOMEDIA | IFF_DYNAMIC | IFF_NOARP |
|
|
|
|
IFF_NOTRAILERS | IFF_DEBUG | IFF_ECHO);
|
|
|
|
unknown_flags_added = ((link->flags ^ flags) & flags & unknown_flags);
|
|
|
|
unknown_flags_removed = ((link->flags ^ flags) & link->flags & unknown_flags);
|
|
|
|
|
|
|
|
/* link flags are currently at most 18 bits, let's align to
|
|
|
|
* printing 20 */
|
|
|
|
if (unknown_flags_added)
|
2014-11-27 20:20:23 +01:00
|
|
|
log_link_debug(link,
|
2015-04-21 17:40:18 +02:00
|
|
|
"Unknown link flags gained: %#.5x (ignoring)",
|
2014-09-04 14:10:43 +02:00
|
|
|
unknown_flags_added);
|
|
|
|
|
|
|
|
if (unknown_flags_removed)
|
2014-11-27 20:20:23 +01:00
|
|
|
log_link_debug(link,
|
2015-04-21 17:40:18 +02:00
|
|
|
"Unknown link flags lost: %#.5x (ignoring)",
|
2014-09-04 14:10:43 +02:00
|
|
|
unknown_flags_removed);
|
|
|
|
}
|
|
|
|
|
|
|
|
link->flags = flags;
|
|
|
|
link->kernel_operstate = operstate;
|
|
|
|
|
2019-02-12 22:32:48 +01:00
|
|
|
link_update_operstate(link, true);
|
2014-09-04 14:10:43 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
|
tree-wide: drop redundant _cleanup_ macros (#8810)
This drops a good number of type-specific _cleanup_ macros, and patches
all users to just use the generic ones.
In most recent code we abstained from defining type-specific macros, and
this basically removes all those added already, with the exception of
the really low-level ones.
Having explicit macros for this is not too useful, as the expression
without the extra macro is generally just 2ch wider. We should generally
emphesize generic code, unless there are really good reasons for
specific code, hence let's follow this in this case too.
Note that _cleanup_free_ and similar really low-level, libc'ish, Linux
API'ish macros continue to be defined, only the really high-level OO
ones are dropped. From now on this should really be the rule: for really
low-level stuff, such as memory allocation, fd handling and so one, go
ahead and define explicit per-type macros, but for high-level, specific
program code, just use the generic _cleanup_() macro directly, in order
to keep things simple and as readable as possible for the uninitiated.
Note that before this patch some of the APIs (notable libudev ones) were
already used with the high-level macros at some places and with the
generic _cleanup_ macro at others. With this patch we hence unify on the
latter.
2018-04-25 12:31:45 +02:00
|
|
|
_cleanup_(link_unrefp) Link *link = NULL;
|
2016-06-09 13:44:31 +02:00
|
|
|
const char *ifname, *kind = NULL;
|
2016-02-18 22:49:02 +01:00
|
|
|
unsigned short iftype;
|
2019-12-15 14:46:19 +01:00
|
|
|
int r, ifindex;
|
|
|
|
uint16_t type;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2014-02-22 20:19:49 +01:00
|
|
|
assert(manager);
|
2014-04-15 14:21:44 +02:00
|
|
|
assert(message);
|
2013-10-17 03:18:36 +02:00
|
|
|
assert(ret);
|
|
|
|
|
2016-06-09 13:44:31 +02:00
|
|
|
/* check for link kind */
|
|
|
|
r = sd_netlink_message_enter_container(message, IFLA_LINKINFO);
|
|
|
|
if (r == 0) {
|
2018-07-03 07:36:15 +02:00
|
|
|
(void) sd_netlink_message_read_string(message, IFLA_INFO_KIND, &kind);
|
2016-06-09 13:44:31 +02:00
|
|
|
r = sd_netlink_message_exit_container(message);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_type(message, &type);
|
2014-04-15 14:21:44 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
else if (type != RTM_NEWLINK)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
else if (ifindex <= 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2016-02-18 22:49:02 +01:00
|
|
|
r = sd_rtnl_message_link_get_type(message, &iftype);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_string(message, IFLA_IFNAME, &ifname);
|
2014-04-15 14:21:44 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-11-12 06:55:52 +01:00
|
|
|
link = new(Link, 1);
|
2013-10-17 03:18:36 +02:00
|
|
|
if (!link)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2018-11-12 06:55:52 +01:00
|
|
|
*link = (Link) {
|
|
|
|
.n_ref = 1,
|
|
|
|
.manager = manager,
|
|
|
|
.state = LINK_STATE_PENDING,
|
|
|
|
.ifindex = ifindex,
|
|
|
|
.iftype = iftype,
|
2019-05-27 01:52:27 +02:00
|
|
|
|
|
|
|
.n_dns = (unsigned) -1,
|
|
|
|
.dns_default_route = -1,
|
|
|
|
.llmnr = _RESOLVE_SUPPORT_INVALID,
|
|
|
|
.mdns = _RESOLVE_SUPPORT_INVALID,
|
|
|
|
.dnssec_mode = _DNSSEC_MODE_INVALID,
|
|
|
|
.dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
|
2018-11-12 06:55:52 +01:00
|
|
|
};
|
|
|
|
|
2014-04-15 14:21:44 +02:00
|
|
|
link->ifname = strdup(ifname);
|
|
|
|
if (!link->ifname)
|
|
|
|
return -ENOMEM;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2016-06-09 13:44:31 +02:00
|
|
|
if (kind) {
|
|
|
|
link->kind = strdup(kind);
|
|
|
|
if (!link->kind)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2018-10-19 13:12:35 +02:00
|
|
|
r = sd_netlink_message_read_u32(message, IFLA_MASTER, (uint32_t *)&link->master_ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
log_link_debug_errno(link, r, "New device has no master, continuing without");
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac);
|
2014-06-04 21:29:08 +02:00
|
|
|
if (r < 0)
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
log_link_debug_errno(link, r, "MAC address not found for new device, continuing without");
|
2014-06-04 21:29:08 +02:00
|
|
|
|
2020-06-03 09:19:29 +02:00
|
|
|
r = ethtool_get_permanent_macaddr(&manager->ethtool_fd, link->ifname, &link->permanent_mac);
|
2019-01-07 12:16:19 +01:00
|
|
|
if (r < 0)
|
|
|
|
log_link_debug_errno(link, r, "Permanent MAC address not found for new device, continuing without: %m");
|
|
|
|
|
2020-06-03 09:19:29 +02:00
|
|
|
r = ethtool_get_driver(&manager->ethtool_fd, link->ifname, &link->driver);
|
|
|
|
if (r < 0)
|
|
|
|
log_link_debug_errno(link, r, "Failed to get driver, continuing without: %m");
|
|
|
|
|
2019-12-15 14:46:19 +01:00
|
|
|
r = sd_netlink_message_read_strv(message, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &link->alternative_names);
|
|
|
|
if (r < 0 && r != -ENODATA)
|
|
|
|
return r;
|
|
|
|
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
if (asprintf(&link->state_file, "/run/systemd/netif/links/%d", link->ifindex) < 0)
|
2014-03-14 14:05:56 +01:00
|
|
|
return -ENOMEM;
|
2014-02-27 01:24:05 +01:00
|
|
|
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
if (asprintf(&link->lease_file, "/run/systemd/netif/leases/%d", link->ifindex) < 0)
|
2014-05-08 18:53:32 +02:00
|
|
|
return -ENOMEM;
|
|
|
|
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
if (asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d", link->ifindex) < 0)
|
2014-12-11 05:29:55 +01:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2014-08-13 01:00:18 +02:00
|
|
|
r = hashmap_ensure_allocated(&manager->links, NULL);
|
2014-07-28 11:39:37 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = hashmap_put(manager->links, INT_TO_PTR(link->ifindex), link);
|
2013-10-17 03:18:36 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-05-22 03:46:11 +02:00
|
|
|
r = link_update_flags(link, message, false);
|
2014-09-04 14:10:43 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*ret = TAKE_PTR(link);
|
2013-10-17 03:18:36 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-05-27 01:52:27 +02:00
|
|
|
void link_ntp_settings_clear(Link *link) {
|
|
|
|
link->ntp = strv_free(link->ntp);
|
|
|
|
}
|
|
|
|
|
|
|
|
void link_dns_settings_clear(Link *link) {
|
2020-07-03 09:48:29 +02:00
|
|
|
if (link->n_dns != (unsigned) -1)
|
|
|
|
for (unsigned i = 0; i < link->n_dns; i++)
|
|
|
|
in_addr_full_free(link->dns[i]);
|
2019-05-27 01:52:27 +02:00
|
|
|
link->dns = mfree(link->dns);
|
|
|
|
link->n_dns = (unsigned) -1;
|
|
|
|
|
|
|
|
link->search_domains = ordered_set_free_free(link->search_domains);
|
|
|
|
link->route_domains = ordered_set_free_free(link->route_domains);
|
|
|
|
|
|
|
|
link->dns_default_route = -1;
|
|
|
|
link->llmnr = _RESOLVE_SUPPORT_INVALID;
|
|
|
|
link->mdns = _RESOLVE_SUPPORT_INVALID;
|
|
|
|
link->dnssec_mode = _DNSSEC_MODE_INVALID;
|
|
|
|
link->dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID;
|
|
|
|
|
|
|
|
link->dnssec_negative_trust_anchors = set_free_free(link->dnssec_negative_trust_anchors);
|
|
|
|
}
|
|
|
|
|
2019-06-21 05:06:56 +02:00
|
|
|
static void link_free_engines(Link *link) {
|
|
|
|
if (!link)
|
|
|
|
return;
|
|
|
|
|
|
|
|
link->dhcp_server = sd_dhcp_server_unref(link->dhcp_server);
|
|
|
|
link->dhcp_client = sd_dhcp_client_unref(link->dhcp_client);
|
|
|
|
link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
|
|
|
|
|
|
|
|
link->lldp = sd_lldp_unref(link->lldp);
|
|
|
|
|
|
|
|
ndisc_flush(link);
|
|
|
|
|
|
|
|
link->ipv4ll = sd_ipv4ll_unref(link->ipv4ll);
|
|
|
|
link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
|
2020-07-22 20:13:42 +02:00
|
|
|
link->dhcp6_lease = sd_dhcp6_lease_unref(link->dhcp6_lease);
|
2019-06-21 05:06:56 +02:00
|
|
|
link->ndisc = sd_ndisc_unref(link->ndisc);
|
|
|
|
link->radv = sd_radv_unref(link->radv);
|
|
|
|
}
|
|
|
|
|
2018-08-27 07:01:46 +02:00
|
|
|
static Link *link_free(Link *link) {
|
2014-05-16 00:28:22 +02:00
|
|
|
Address *address;
|
|
|
|
|
2018-08-27 07:01:46 +02:00
|
|
|
assert(link);
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2019-05-27 01:52:27 +02:00
|
|
|
link_ntp_settings_clear(link);
|
|
|
|
link_dns_settings_clear(link);
|
|
|
|
|
2020-07-22 01:22:55 +02:00
|
|
|
link->routes = set_free(link->routes);
|
|
|
|
link->routes_foreign = set_free(link->routes_foreign);
|
2020-07-21 16:06:51 +02:00
|
|
|
link->dhcp_routes = set_free(link->dhcp_routes);
|
|
|
|
link->dhcp_routes_old = set_free(link->dhcp_routes_old);
|
2020-07-22 20:13:42 +02:00
|
|
|
link->dhcp6_routes = set_free(link->dhcp6_routes);
|
|
|
|
link->dhcp6_routes_old = set_free(link->dhcp6_routes_old);
|
|
|
|
link->dhcp6_pd_routes = set_free(link->dhcp6_pd_routes);
|
|
|
|
link->dhcp6_pd_routes_old = set_free(link->dhcp6_pd_routes_old);
|
2020-07-22 04:55:07 +02:00
|
|
|
link->ndisc_routes = set_free(link->ndisc_routes);
|
2015-09-30 14:01:44 +02:00
|
|
|
|
2020-07-22 01:22:55 +02:00
|
|
|
link->nexthops = set_free(link->nexthops);
|
|
|
|
link->nexthops_foreign = set_free(link->nexthops_foreign);
|
2019-10-04 21:40:51 +02:00
|
|
|
|
2020-07-22 01:22:55 +02:00
|
|
|
link->neighbors = set_free(link->neighbors);
|
|
|
|
link->neighbors_foreign = set_free(link->neighbors_foreign);
|
2019-04-19 09:53:34 +02:00
|
|
|
|
2020-07-22 01:22:55 +02:00
|
|
|
link->addresses = set_free(link->addresses);
|
|
|
|
link->addresses_foreign = set_free(link->addresses_foreign);
|
2020-07-23 17:52:32 +02:00
|
|
|
link->static_addresses = set_free(link->static_addresses);
|
2020-07-22 20:13:42 +02:00
|
|
|
link->dhcp6_addresses = set_free(link->dhcp6_addresses);
|
|
|
|
link->dhcp6_addresses_old = set_free(link->dhcp6_addresses_old);
|
|
|
|
link->dhcp6_pd_addresses = set_free(link->dhcp6_pd_addresses);
|
|
|
|
link->dhcp6_pd_addresses_old = set_free(link->dhcp6_pd_addresses_old);
|
2020-07-22 04:55:07 +02:00
|
|
|
link->ndisc_addresses = set_free(link->ndisc_addresses);
|
2015-09-30 14:01:44 +02:00
|
|
|
|
2014-06-18 18:22:14 +02:00
|
|
|
while ((address = link->pool_addresses)) {
|
|
|
|
LIST_REMOVE(addresses, link->pool_addresses, address);
|
|
|
|
address_free(address);
|
|
|
|
}
|
|
|
|
|
2016-05-06 21:27:36 +02:00
|
|
|
link_lldp_emit_stop(link);
|
2019-06-21 05:06:56 +02:00
|
|
|
link_free_engines(link);
|
2014-05-08 18:53:32 +02:00
|
|
|
free(link->lease_file);
|
2014-12-11 05:29:55 +01:00
|
|
|
free(link->lldp_file);
|
|
|
|
|
2013-11-24 23:36:58 +01:00
|
|
|
free(link->ifname);
|
2019-12-15 14:46:19 +01:00
|
|
|
strv_free(link->alternative_names);
|
2016-06-12 19:59:21 +02:00
|
|
|
free(link->kind);
|
2019-07-24 07:46:55 +02:00
|
|
|
free(link->ssid);
|
2020-06-03 09:19:29 +02:00
|
|
|
free(link->driver);
|
2016-06-09 13:44:31 +02:00
|
|
|
|
2018-07-03 07:36:15 +02:00
|
|
|
(void) unlink(link->state_file);
|
2014-02-27 01:24:05 +01:00
|
|
|
free(link->state_file);
|
2013-11-24 23:36:58 +01:00
|
|
|
|
2018-08-22 07:30:49 +02:00
|
|
|
sd_device_unref(link->sd_device);
|
2014-03-21 19:23:35 +01:00
|
|
|
|
2015-02-17 13:06:57 +01:00
|
|
|
hashmap_free(link->bound_to_links);
|
|
|
|
hashmap_free(link->bound_by_links);
|
|
|
|
|
2019-04-15 09:38:45 +02:00
|
|
|
set_free_with_destructor(link->slaves, link_unref);
|
2019-02-20 03:32:29 +01:00
|
|
|
|
2019-05-04 08:05:11 +02:00
|
|
|
network_unref(link->network);
|
|
|
|
|
2018-08-27 07:01:46 +02:00
|
|
|
return mfree(link);
|
2014-05-08 18:54:26 +02:00
|
|
|
}
|
|
|
|
|
2018-08-27 07:01:46 +02:00
|
|
|
DEFINE_TRIVIAL_REF_UNREF_FUNC(Link, link, link_free);
|
2014-05-08 18:54:26 +02:00
|
|
|
|
2014-02-18 21:42:05 +01:00
|
|
|
int link_get(Manager *m, int ifindex, Link **ret) {
|
|
|
|
Link *link;
|
|
|
|
|
|
|
|
assert(m);
|
2020-06-25 06:17:37 +02:00
|
|
|
assert(ifindex > 0);
|
2014-02-18 21:42:05 +01:00
|
|
|
assert(ret);
|
|
|
|
|
2014-07-28 11:39:37 +02:00
|
|
|
link = hashmap_get(m->links, INT_TO_PTR(ifindex));
|
2014-02-18 21:42:05 +01:00
|
|
|
if (!link)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
*ret = link;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-05-20 08:59:44 +02:00
|
|
|
void link_set_state(Link *link, LinkState state) {
|
2015-02-04 11:44:37 +01:00
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (link->state == state)
|
|
|
|
return;
|
|
|
|
|
2019-04-15 13:56:01 +02:00
|
|
|
log_link_debug(link, "State changed: %s -> %s",
|
|
|
|
link_state_to_string(link->state),
|
|
|
|
link_state_to_string(state));
|
|
|
|
|
2015-02-04 11:44:37 +01:00
|
|
|
link->state = state;
|
|
|
|
|
|
|
|
link_send_changed(link, "AdministrativeState", NULL);
|
|
|
|
}
|
|
|
|
|
2014-04-20 19:49:00 +02:00
|
|
|
static void link_enter_unmanaged(Link *link) {
|
|
|
|
assert(link);
|
|
|
|
|
2015-02-04 11:44:37 +01:00
|
|
|
link_set_state(link, LINK_STATE_UNMANAGED);
|
2014-04-20 19:49:00 +02:00
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(link);
|
2014-04-20 19:49:00 +02:00
|
|
|
}
|
|
|
|
|
2019-06-03 19:05:26 +02:00
|
|
|
int link_stop_clients(Link *link, bool may_keep_dhcp) {
|
2014-04-22 19:25:31 +02:00
|
|
|
int r = 0, k;
|
2019-11-21 16:54:52 +01:00
|
|
|
Address *ad;
|
2014-04-22 19:25:31 +02:00
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
|
|
|
assert(link->manager->event);
|
|
|
|
|
2019-10-01 17:12:31 +02:00
|
|
|
bool keep_dhcp = may_keep_dhcp &&
|
|
|
|
link->network &&
|
|
|
|
(link->manager->restarting ||
|
|
|
|
FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP_ON_STOP));
|
|
|
|
|
|
|
|
if (link->dhcp_client && !keep_dhcp) {
|
2014-04-22 19:25:31 +02:00
|
|
|
k = sd_dhcp_client_stop(link->dhcp_client);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (k < 0)
|
2016-02-18 22:49:48 +01:00
|
|
|
r = log_link_warning_errno(link, k, "Could not stop DHCPv4 client: %m");
|
2014-04-22 19:25:31 +02:00
|
|
|
}
|
|
|
|
|
2014-07-25 01:13:47 +02:00
|
|
|
if (link->ipv4ll) {
|
2014-04-22 19:25:31 +02:00
|
|
|
k = sd_ipv4ll_stop(link->ipv4ll);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (k < 0)
|
2016-02-18 22:49:48 +01:00
|
|
|
r = log_link_warning_errno(link, k, "Could not stop IPv4 link-local: %m");
|
2014-03-05 08:13:30 +01:00
|
|
|
}
|
|
|
|
|
2019-11-21 16:54:52 +01:00
|
|
|
if (link->network)
|
|
|
|
LIST_FOREACH(addresses, ad, link->network->static_addresses)
|
|
|
|
if (ad->acd && sd_ipv4acd_is_running(ad->acd) == 0) {
|
|
|
|
k = sd_ipv4acd_stop(ad->acd);
|
|
|
|
if (k < 0)
|
|
|
|
r = log_link_warning_errno(link, k, "Could not stop IPv4 ACD client: %m");
|
|
|
|
}
|
|
|
|
|
networkd: IPv6 router discovery - follow IPv6AcceptRouterAdvertisemnt=
The previous behavior:
When DHCPv6 was enabled, router discover was performed first, and then DHCPv6 was
enabled only if the relevant flags were passed in the Router Advertisement message.
Moreover, router discovery was performed even if AcceptRouterAdvertisements=false,
moreover, even if router advertisements were accepted (by the kernel) the flags
indicating that DHCPv6 should be performed were ignored.
New behavior:
If RouterAdvertisements are accepted, and either no routers are found, or an
advertisement is received indicating DHCPv6 should be performed, the DHCPv6
client is started. Moreover, the DHCP option now truly enables the DHCPv6
client regardless of router discovery (though it will probably not be
very useful to get a lease withotu any routes, this seems the more consistent
approach).
The recommended default setting should be to set DHCP=ipv4 and to leave
IPv6AcceptRouterAdvertisements unset.
2015-10-18 18:25:58 +02:00
|
|
|
if (link->dhcp6_client) {
|
|
|
|
k = sd_dhcp6_client_stop(link->dhcp6_client);
|
|
|
|
if (k < 0)
|
2016-02-18 22:49:48 +01:00
|
|
|
r = log_link_warning_errno(link, k, "Could not stop DHCPv6 client: %m");
|
networkd: IPv6 router discovery - follow IPv6AcceptRouterAdvertisemnt=
The previous behavior:
When DHCPv6 was enabled, router discover was performed first, and then DHCPv6 was
enabled only if the relevant flags were passed in the Router Advertisement message.
Moreover, router discovery was performed even if AcceptRouterAdvertisements=false,
moreover, even if router advertisements were accepted (by the kernel) the flags
indicating that DHCPv6 should be performed were ignored.
New behavior:
If RouterAdvertisements are accepted, and either no routers are found, or an
advertisement is received indicating DHCPv6 should be performed, the DHCPv6
client is started. Moreover, the DHCP option now truly enables the DHCPv6
client regardless of router discovery (though it will probably not be
very useful to get a lease withotu any routes, this seems the more consistent
approach).
The recommended default setting should be to set DHCP=ipv4 and to leave
IPv6AcceptRouterAdvertisements unset.
2015-10-18 18:25:58 +02:00
|
|
|
}
|
2014-06-19 14:40:01 +02:00
|
|
|
|
2020-07-22 20:13:42 +02:00
|
|
|
if (link_dhcp6_pd_is_enabled(link)) {
|
|
|
|
k = dhcp6_pd_remove(link);
|
|
|
|
if (k < 0)
|
|
|
|
r = log_link_warning_errno(link, k, "Could not remove DHCPv6 PD addresses and routes: %m");
|
|
|
|
}
|
|
|
|
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
if (link->ndisc) {
|
|
|
|
k = sd_ndisc_stop(link->ndisc);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (k < 0)
|
2016-02-18 22:49:48 +01:00
|
|
|
r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m");
|
2014-06-19 14:40:01 +02:00
|
|
|
}
|
|
|
|
|
2017-05-12 15:48:33 +02:00
|
|
|
if (link->radv) {
|
2020-07-07 04:06:08 +02:00
|
|
|
k = sd_radv_stop(link->radv);
|
2017-05-12 15:48:33 +02:00
|
|
|
if (k < 0)
|
|
|
|
r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Advertisement: %m");
|
|
|
|
}
|
|
|
|
|
2016-05-06 21:27:36 +02:00
|
|
|
link_lldp_emit_stop(link);
|
2014-04-22 19:25:31 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-08-06 15:54:03 +02:00
|
|
|
void link_enter_failed(Link *link) {
|
2013-12-14 19:09:04 +01:00
|
|
|
assert(link);
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2014-05-08 20:50:05 +02:00
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
2014-04-22 19:26:04 +02:00
|
|
|
return;
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_warning(link, "Failed");
|
2014-01-02 15:30:46 +01:00
|
|
|
|
2015-02-04 11:44:37 +01:00
|
|
|
link_set_state(link, LINK_STATE_FAILED);
|
2014-02-27 01:24:05 +01:00
|
|
|
|
2019-06-03 19:05:26 +02:00
|
|
|
link_stop_clients(link, false);
|
2014-04-22 19:25:31 +02:00
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(link);
|
2013-11-14 16:22:51 +01:00
|
|
|
}
|
|
|
|
|
2019-03-11 08:11:47 +01:00
|
|
|
static int link_join_netdevs_after_configured(Link *link) {
|
|
|
|
NetDev *netdev;
|
|
|
|
int r;
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH(netdev, link->network->stacked_netdevs) {
|
2019-03-11 08:11:47 +01:00
|
|
|
if (netdev->ifindex > 0)
|
|
|
|
/* Assume already enslaved. */
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (netdev_get_create_type(netdev) != NETDEV_CREATE_AFTER_CONFIGURED)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
log_struct(LOG_DEBUG,
|
|
|
|
LOG_LINK_INTERFACE(link),
|
|
|
|
LOG_NETDEV_INTERFACE(netdev),
|
|
|
|
LOG_LINK_MESSAGE(link, "Enslaving by '%s'", netdev->ifname));
|
|
|
|
|
|
|
|
r = netdev_join(netdev, link, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return log_struct_errno(LOG_WARNING, r,
|
|
|
|
LOG_LINK_INTERFACE(link),
|
|
|
|
LOG_NETDEV_INTERFACE(netdev),
|
|
|
|
LOG_LINK_MESSAGE(link, "Could not join netdev '%s': %m", netdev->ifname));
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-12-05 15:31:48 +01:00
|
|
|
static void link_enter_configured(Link *link) {
|
2014-03-05 08:13:30 +01:00
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
2016-12-05 15:31:48 +01:00
|
|
|
|
2018-12-01 00:36:33 +01:00
|
|
|
if (link->state != LINK_STATE_CONFIGURING)
|
2016-12-05 15:31:48 +01:00
|
|
|
return;
|
2014-03-05 08:13:30 +01:00
|
|
|
|
2015-02-04 11:44:37 +01:00
|
|
|
link_set_state(link, LINK_STATE_CONFIGURED);
|
2014-03-05 08:13:30 +01:00
|
|
|
|
2019-03-11 08:11:47 +01:00
|
|
|
(void) link_join_netdevs_after_configured(link);
|
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(link);
|
2014-03-05 08:13:30 +01:00
|
|
|
}
|
|
|
|
|
2018-12-30 14:10:32 +01:00
|
|
|
static int link_request_set_routing_policy_rule(Link *link) {
|
2017-11-20 17:50:48 +01:00
|
|
|
RoutingPolicyRule *rule, *rrule = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
|
|
|
|
2018-12-30 14:08:10 +01:00
|
|
|
link->routing_policy_rules_configured = false;
|
|
|
|
|
2017-11-20 17:50:48 +01:00
|
|
|
LIST_FOREACH(rules, rule, link->network->rules) {
|
2019-06-19 06:04:24 +02:00
|
|
|
r = routing_policy_rule_get(link->manager, rule, &rrule);
|
2019-06-18 06:09:06 +02:00
|
|
|
if (r >= 0) {
|
|
|
|
if (r == 0)
|
|
|
|
(void) routing_policy_rule_make_local(link->manager, rrule);
|
2017-11-20 17:50:48 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-06-04 07:40:21 +02:00
|
|
|
r = routing_policy_rule_configure(rule, link, NULL);
|
2019-07-14 17:35:49 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not set routing policy rules: %m");
|
2019-06-11 16:29:57 +02:00
|
|
|
if (r > 0)
|
|
|
|
link->routing_policy_rule_messages++;
|
2017-11-20 17:50:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
routing_policy_rule_purge(link->manager, link);
|
2020-07-14 05:48:02 +02:00
|
|
|
if (link->routing_policy_rule_messages == 0)
|
2017-12-12 16:25:36 +01:00
|
|
|
link->routing_policy_rules_configured = true;
|
2020-07-14 05:48:02 +02:00
|
|
|
else {
|
2017-12-12 16:25:36 +01:00
|
|
|
log_link_debug(link, "Setting routing policy rules");
|
2019-07-13 17:02:44 +02:00
|
|
|
link_set_state(link, LINK_STATE_CONFIGURING);
|
|
|
|
}
|
2017-11-20 17:50:48 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-10-04 21:40:51 +02:00
|
|
|
static int nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->nexthop_messages > 0);
|
|
|
|
assert(IN_SET(link->state, LINK_STATE_CONFIGURING,
|
|
|
|
LINK_STATE_FAILED, LINK_STATE_LINGER));
|
|
|
|
|
|
|
|
link->nexthop_messages--;
|
|
|
|
|
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_errno(m);
|
|
|
|
if (r < 0 && r != -EEXIST) {
|
2019-11-30 07:54:07 +01:00
|
|
|
log_link_message_warning_errno(link, m, r, "Could not set nexthop");
|
2019-10-04 21:40:51 +02:00
|
|
|
link_enter_failed(link);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (link->nexthop_messages == 0) {
|
|
|
|
log_link_debug(link, "Nexthop set");
|
|
|
|
link->static_nexthops_configured = true;
|
|
|
|
link_check_ready(link);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-07-10 17:36:38 +02:00
|
|
|
static int link_request_set_nexthop(Link *link) {
|
2019-10-04 21:40:51 +02:00
|
|
|
NextHop *nh;
|
|
|
|
int r;
|
|
|
|
|
2020-07-12 20:12:11 +02:00
|
|
|
link->static_nexthops_configured = false;
|
|
|
|
|
2019-10-04 21:40:51 +02:00
|
|
|
LIST_FOREACH(nexthops, nh, link->network->static_nexthops) {
|
|
|
|
r = nexthop_configure(nh, link, nexthop_handler);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not set nexthop: %m");
|
|
|
|
if (r > 0)
|
|
|
|
link->nexthop_messages++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (link->nexthop_messages == 0) {
|
|
|
|
link->static_nexthops_configured = true;
|
|
|
|
link_check_ready(link);
|
|
|
|
} else {
|
|
|
|
log_link_debug(link, "Setting nexthop");
|
|
|
|
link_set_state(link, LINK_STATE_CONFIGURING);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-11-28 21:06:52 +01:00
|
|
|
static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
2013-11-14 16:22:51 +01:00
|
|
|
int r;
|
|
|
|
|
2018-10-06 06:55:19 +02:00
|
|
|
assert(link);
|
2017-12-12 16:25:36 +01:00
|
|
|
assert(link->route_messages > 0);
|
2018-12-01 00:36:33 +01:00
|
|
|
assert(IN_SET(link->state, LINK_STATE_CONFIGURING,
|
|
|
|
LINK_STATE_FAILED, LINK_STATE_LINGER));
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2017-12-12 16:25:36 +01:00
|
|
|
link->route_messages--;
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2014-08-06 15:54:25 +02:00
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
2013-11-14 16:22:51 +01:00
|
|
|
return 1;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_errno(m);
|
2019-07-14 17:35:49 +02:00
|
|
|
if (r < 0 && r != -EEXIST) {
|
2019-11-30 07:54:07 +01:00
|
|
|
log_link_message_warning_errno(link, m, r, "Could not set route");
|
2019-07-14 17:35:49 +02:00
|
|
|
link_enter_failed(link);
|
|
|
|
return 1;
|
|
|
|
}
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2017-12-12 16:25:36 +01:00
|
|
|
if (link->route_messages == 0) {
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Routes set");
|
2017-12-12 16:25:36 +01:00
|
|
|
link->static_routes_configured = true;
|
2020-07-12 20:12:11 +02:00
|
|
|
link_request_set_nexthop(link);
|
2013-12-03 18:48:20 +01:00
|
|
|
}
|
2013-11-14 16:22:51 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-04-29 07:02:34 +02:00
|
|
|
int link_request_set_routes(Link *link) {
|
2018-11-28 21:25:47 +01:00
|
|
|
enum {
|
|
|
|
PHASE_NON_GATEWAY, /* First phase: Routes without a gateway */
|
|
|
|
PHASE_GATEWAY, /* Second phase: Routes with a gateway */
|
|
|
|
_PHASE_MAX
|
|
|
|
} phase;
|
2014-02-04 23:13:52 +01:00
|
|
|
Route *rt;
|
2013-11-14 16:22:51 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
2018-12-01 00:36:33 +01:00
|
|
|
assert(link->state != _LINK_STATE_INVALID);
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2018-12-30 14:08:10 +01:00
|
|
|
link->static_routes_configured = false;
|
2018-01-09 09:13:06 +01:00
|
|
|
|
2020-07-23 17:52:32 +02:00
|
|
|
if (!link->addresses_ready)
|
|
|
|
return 0;
|
|
|
|
|
2019-07-16 06:02:38 +02:00
|
|
|
if (!link_has_carrier(link) && !link->network->configure_without_carrier)
|
|
|
|
/* During configuring addresses, the link lost its carrier. As networkd is dropping
|
|
|
|
* the addresses now, let's not configure the routes either. */
|
|
|
|
return 0;
|
|
|
|
|
2018-12-30 14:10:32 +01:00
|
|
|
r = link_request_set_routing_policy_rule(link);
|
2018-12-30 14:07:23 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2018-11-28 21:25:47 +01:00
|
|
|
/* First add the routes that enable us to talk to gateways, then add in the others that need a gateway. */
|
|
|
|
for (phase = 0; phase < _PHASE_MAX; phase++)
|
|
|
|
LIST_FOREACH(routes, rt, link->network->static_routes) {
|
2020-01-07 06:43:09 +01:00
|
|
|
if (rt->gateway_from_dhcp)
|
|
|
|
continue;
|
2018-11-26 18:13:17 +01:00
|
|
|
|
2019-11-28 16:36:02 +01:00
|
|
|
if ((in_addr_is_null(rt->family, &rt->gw) && ordered_set_isempty(rt->multipath_routes)) != (phase == PHASE_NON_GATEWAY))
|
2018-11-28 21:25:47 +01:00
|
|
|
continue;
|
2014-02-04 23:13:52 +01:00
|
|
|
|
2020-07-22 02:41:30 +02:00
|
|
|
r = route_configure(rt, link, route_handler, NULL);
|
2019-07-14 17:35:49 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not set routes: %m");
|
2019-06-11 16:26:11 +02:00
|
|
|
if (r > 0)
|
|
|
|
link->route_messages++;
|
2018-11-26 18:13:17 +01:00
|
|
|
}
|
2014-01-01 15:16:34 +01:00
|
|
|
|
2017-12-12 16:25:36 +01:00
|
|
|
if (link->route_messages == 0) {
|
|
|
|
link->static_routes_configured = true;
|
2020-07-12 20:12:11 +02:00
|
|
|
link_request_set_nexthop(link);
|
2019-07-13 17:02:44 +02:00
|
|
|
} else {
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Setting routes");
|
2019-07-13 17:02:44 +02:00
|
|
|
link_set_state(link, LINK_STATE_CONFIGURING);
|
|
|
|
}
|
2013-11-14 16:22:51 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-12-05 10:39:41 +01:00
|
|
|
void link_check_ready(Link *link) {
|
|
|
|
Address *a;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
2020-07-21 23:07:42 +02:00
|
|
|
if (link->state == LINK_STATE_CONFIGURED)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (link->state != LINK_STATE_CONFIGURING) {
|
|
|
|
log_link_debug(link, "%s(): link is in %s state.", __func__, link_state_to_string(link->state));
|
2018-12-05 10:39:41 +01:00
|
|
|
return;
|
2020-07-12 01:23:19 +02:00
|
|
|
}
|
2018-12-05 10:39:41 +01:00
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return;
|
|
|
|
|
2020-07-12 01:23:19 +02:00
|
|
|
if (!link->addresses_configured) {
|
|
|
|
log_link_debug(link, "%s(): static addresses are not configured.", __func__);
|
2018-12-05 10:39:41 +01:00
|
|
|
return;
|
2020-07-12 01:23:19 +02:00
|
|
|
}
|
2018-12-05 10:39:41 +01:00
|
|
|
|
2020-07-12 01:23:19 +02:00
|
|
|
if (!link->neighbors_configured) {
|
|
|
|
log_link_debug(link, "%s(): static neighbors are not configured.", __func__);
|
2018-12-05 10:39:41 +01:00
|
|
|
return;
|
2020-07-12 01:23:19 +02:00
|
|
|
}
|
2018-12-05 10:39:41 +01:00
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(a, link->addresses)
|
2020-07-12 01:23:19 +02:00
|
|
|
if (!address_is_ready(a)) {
|
|
|
|
_cleanup_free_ char *str = NULL;
|
|
|
|
|
|
|
|
(void) in_addr_to_string(a->family, &a->in_addr, &str);
|
|
|
|
log_link_debug(link, "%s(): an address %s/%d is not ready.", __func__, strnull(str), a->prefixlen);
|
2018-12-05 11:49:35 +01:00
|
|
|
return;
|
2020-07-12 01:23:19 +02:00
|
|
|
}
|
2018-12-05 11:49:35 +01:00
|
|
|
|
2020-07-12 01:23:19 +02:00
|
|
|
if (!link->static_routes_configured) {
|
|
|
|
log_link_debug(link, "%s(): static routes are not configured.", __func__);
|
2018-12-05 10:39:41 +01:00
|
|
|
return;
|
2020-07-12 01:23:19 +02:00
|
|
|
}
|
2018-12-05 10:39:41 +01:00
|
|
|
|
2020-07-12 01:23:19 +02:00
|
|
|
if (!link->static_nexthops_configured) {
|
|
|
|
log_link_debug(link, "%s(): static nexthops are not configured.", __func__);
|
2019-10-04 21:40:51 +02:00
|
|
|
return;
|
2020-07-12 01:23:19 +02:00
|
|
|
}
|
2019-10-04 21:40:51 +02:00
|
|
|
|
2020-07-12 01:23:19 +02:00
|
|
|
if (!link->routing_policy_rules_configured) {
|
|
|
|
log_link_debug(link, "%s(): static routing policy rules are not configured.", __func__);
|
2018-12-05 10:39:41 +01:00
|
|
|
return;
|
2020-07-12 01:23:19 +02:00
|
|
|
}
|
2018-12-05 10:39:41 +01:00
|
|
|
|
2020-07-12 01:23:19 +02:00
|
|
|
if (!link->tc_configured) {
|
|
|
|
log_link_debug(link, "%s(): traffic controls are not configured.", __func__);
|
2019-10-29 16:19:34 +01:00
|
|
|
return;
|
2020-07-12 01:23:19 +02:00
|
|
|
}
|
2019-10-29 16:19:34 +01:00
|
|
|
|
2020-07-12 01:23:19 +02:00
|
|
|
if (!link->sr_iov_configured) {
|
|
|
|
log_link_debug(link, "%s(): SR-IOV is not configured.", __func__);
|
2020-06-21 13:17:34 +02:00
|
|
|
return;
|
2020-07-12 01:23:19 +02:00
|
|
|
}
|
2020-06-21 13:17:34 +02:00
|
|
|
|
2020-09-15 09:20:36 +02:00
|
|
|
if (!link->bridge_mdb_configured) {
|
|
|
|
log_link_debug(link, "%s(): Bridge MDB is not configured.", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-13 22:16:11 +02:00
|
|
|
if (link_has_carrier(link) || !link->network->configure_without_carrier) {
|
2020-08-14 10:45:44 +02:00
|
|
|
bool has_ndisc_address = false;
|
|
|
|
NDiscAddress *n;
|
2018-12-05 10:39:41 +01:00
|
|
|
|
2020-07-22 18:21:40 +02:00
|
|
|
if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4) && !link->ipv4ll_address_configured) {
|
2020-07-12 01:23:19 +02:00
|
|
|
log_link_debug(link, "%s(): IPv4LL is not configured.", __func__);
|
2019-06-13 22:16:11 +02:00
|
|
|
return;
|
2020-07-12 01:23:19 +02:00
|
|
|
}
|
2018-12-05 10:39:41 +01:00
|
|
|
|
2019-06-13 22:16:11 +02:00
|
|
|
if (link_ipv6ll_enabled(link) &&
|
2020-07-12 01:23:19 +02:00
|
|
|
in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address)) {
|
|
|
|
log_link_debug(link, "%s(): IPv6LL is not configured.", __func__);
|
2019-06-13 22:16:11 +02:00
|
|
|
return;
|
2020-07-12 01:23:19 +02:00
|
|
|
}
|
2018-12-05 10:39:41 +01:00
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(n, link->ndisc_addresses)
|
2020-08-14 10:45:44 +02:00
|
|
|
if (!n->marked) {
|
|
|
|
has_ndisc_address = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-07-23 14:18:24 +02:00
|
|
|
if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link)) &&
|
2020-08-14 10:45:44 +02:00
|
|
|
!link->dhcp_address && set_isempty(link->dhcp6_addresses) && !has_ndisc_address &&
|
2020-07-23 14:18:24 +02:00
|
|
|
!(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address_configured)) {
|
|
|
|
log_link_debug(link, "%s(): DHCP4 or DHCP6 is enabled but no dynamic address is assigned yet.", __func__);
|
2020-07-12 07:57:45 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-22 20:13:42 +02:00
|
|
|
if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_dhcp6_pd_is_enabled(link) || link_ipv6_accept_ra_enabled(link)) {
|
2020-07-12 01:23:19 +02:00
|
|
|
if (!link->dhcp4_configured &&
|
|
|
|
!(link->dhcp6_address_configured && link->dhcp6_route_configured) &&
|
|
|
|
!(link->dhcp6_pd_address_configured && link->dhcp6_pd_route_configured) &&
|
2020-07-12 06:55:44 +02:00
|
|
|
!(link->ndisc_addresses_configured && link->ndisc_routes_configured) &&
|
2020-07-22 18:21:40 +02:00
|
|
|
!(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address_configured)) {
|
2020-07-12 01:23:19 +02:00
|
|
|
/* When DHCP or RA is enabled, at least one protocol must provide an address, or
|
|
|
|
* an IPv4ll fallback address must be configured. */
|
|
|
|
log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-12 06:55:44 +02:00
|
|
|
log_link_debug(link, "%s(): dhcp4:%s dhcp6_addresses:%s dhcp_routes:%s dhcp_pd_addresses:%s dhcp_pd_routes:%s ndisc_addresses:%s ndisc_routes:%s",
|
2020-07-12 01:23:19 +02:00
|
|
|
__func__,
|
|
|
|
yes_no(link->dhcp4_configured),
|
|
|
|
yes_no(link->dhcp6_address_configured),
|
|
|
|
yes_no(link->dhcp6_route_configured),
|
|
|
|
yes_no(link->dhcp6_pd_address_configured),
|
|
|
|
yes_no(link->dhcp6_pd_route_configured),
|
2020-07-12 06:55:44 +02:00
|
|
|
yes_no(link->ndisc_addresses_configured),
|
|
|
|
yes_no(link->ndisc_routes_configured));
|
2020-07-12 01:23:19 +02:00
|
|
|
}
|
2019-06-13 22:16:11 +02:00
|
|
|
}
|
2018-12-05 10:39:41 +01:00
|
|
|
|
2020-07-21 23:07:42 +02:00
|
|
|
link_enter_configured(link);
|
2018-12-05 10:39:41 +01:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-29 04:00:58 +01:00
|
|
|
static int link_request_set_neighbors(Link *link) {
|
|
|
|
Neighbor *neighbor;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
|
|
|
assert(link->state != _LINK_STATE_INVALID);
|
|
|
|
|
2018-12-30 14:08:10 +01:00
|
|
|
link->neighbors_configured = false;
|
2018-11-29 04:00:58 +01:00
|
|
|
|
|
|
|
LIST_FOREACH(neighbors, neighbor, link->network->neighbors) {
|
|
|
|
r = neighbor_configure(neighbor, link, NULL);
|
2019-07-14 17:35:49 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not set neighbor: %m");
|
2018-11-29 04:00:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (link->neighbor_messages == 0) {
|
|
|
|
link->neighbors_configured = true;
|
|
|
|
link_check_ready(link);
|
2019-07-13 17:02:44 +02:00
|
|
|
} else {
|
2018-11-29 04:00:58 +01:00
|
|
|
log_link_debug(link, "Setting neighbors");
|
2019-07-13 17:02:44 +02:00
|
|
|
link_set_state(link, LINK_STATE_CONFIGURING);
|
|
|
|
}
|
2018-11-29 04:00:58 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-07-23 17:52:32 +02:00
|
|
|
static int link_set_bridge_fdb(Link *link) {
|
|
|
|
FdbEntry *fdb_entry;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
LIST_FOREACH(static_fdb_entries, fdb_entry, link->network->static_fdb_entries) {
|
|
|
|
r = fdb_entry_configure(link, fdb_entry);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Failed to add MAC entry to static MAC table: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int static_address_ready_callback(Address *address) {
|
|
|
|
Address *a;
|
|
|
|
Link *link;
|
|
|
|
|
|
|
|
assert(address);
|
|
|
|
assert(address->link);
|
|
|
|
|
|
|
|
link = address->link;
|
|
|
|
|
|
|
|
if (!link->addresses_configured)
|
|
|
|
return 0;
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(a, link->static_addresses)
|
2020-07-23 17:52:32 +02:00
|
|
|
if (!address_is_ready(a)) {
|
|
|
|
_cleanup_free_ char *str = NULL;
|
|
|
|
|
|
|
|
(void) in_addr_to_string(a->family, &a->in_addr, &str);
|
|
|
|
log_link_debug(link, "an address %s/%u is not ready", strnull(str), a->prefixlen);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This should not be called again */
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(a, link->static_addresses)
|
2020-07-23 17:52:32 +02:00
|
|
|
a->callback = NULL;
|
|
|
|
|
|
|
|
link->addresses_ready = true;
|
|
|
|
|
|
|
|
return link_request_set_routes(link);
|
|
|
|
}
|
|
|
|
|
2020-07-07 01:39:14 +02:00
|
|
|
static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
2013-11-14 16:22:51 +01:00
|
|
|
int r;
|
|
|
|
|
2014-07-03 22:47:51 +02:00
|
|
|
assert(rtnl);
|
2014-01-01 15:16:34 +01:00
|
|
|
assert(m);
|
|
|
|
assert(link);
|
|
|
|
assert(link->ifname);
|
2017-12-12 16:25:36 +01:00
|
|
|
assert(link->address_messages > 0);
|
2018-12-01 00:36:33 +01:00
|
|
|
assert(IN_SET(link->state, LINK_STATE_CONFIGURING,
|
2014-05-08 20:50:05 +02:00
|
|
|
LINK_STATE_FAILED, LINK_STATE_LINGER));
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2017-12-12 16:25:36 +01:00
|
|
|
link->address_messages--;
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2014-07-01 10:09:52 +02:00
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
2013-11-14 16:22:51 +01:00
|
|
|
return 1;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_errno(m);
|
2019-07-14 17:35:49 +02:00
|
|
|
if (r < 0 && r != -EEXIST) {
|
2019-11-30 07:54:07 +01:00
|
|
|
log_link_message_warning_errno(link, m, r, "Could not set address");
|
2019-07-14 17:35:49 +02:00
|
|
|
link_enter_failed(link);
|
|
|
|
return 1;
|
|
|
|
} else if (r >= 0)
|
|
|
|
(void) manager_rtnl_process_address(rtnl, m, link->manager);
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2017-12-12 16:25:36 +01:00
|
|
|
if (link->address_messages == 0) {
|
2020-07-23 17:52:32 +02:00
|
|
|
Address *a;
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Addresses set");
|
2018-12-01 00:54:45 +01:00
|
|
|
link->addresses_configured = true;
|
2020-07-23 17:52:32 +02:00
|
|
|
|
|
|
|
/* When all static addresses are already ready, then static_address_ready_callback()
|
|
|
|
* will not be called automatically. So, call it here. */
|
|
|
|
a = set_first(link->static_addresses);
|
|
|
|
if (!a) {
|
|
|
|
log_link_warning(link, "No static address is stored.");
|
|
|
|
link_enter_failed(link);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (!a->callback) {
|
|
|
|
log_link_warning(link, "Address ready callback is not set.");
|
|
|
|
link_enter_failed(link);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
r = a->callback(a);
|
|
|
|
if (r < 0)
|
|
|
|
link_enter_failed(link);
|
2013-12-03 18:48:20 +01:00
|
|
|
}
|
2013-11-14 16:22:51 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-07-23 17:52:32 +02:00
|
|
|
static int static_address_configure(Address *address, Link *link, bool update) {
|
|
|
|
Address *ret;
|
2016-10-06 11:45:07 +02:00
|
|
|
int r;
|
2016-10-05 17:06:40 +02:00
|
|
|
|
2020-07-23 17:52:32 +02:00
|
|
|
assert(address);
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
r = address_configure(address, link, address_handler, update, &ret);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not configure static address: %m");
|
|
|
|
|
|
|
|
link->address_messages++;
|
|
|
|
|
|
|
|
r = set_ensure_put(&link->static_addresses, &address_hash_ops, ret);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Failed to store static address: %m");
|
|
|
|
|
|
|
|
ret->callback = static_address_ready_callback;
|
2016-10-05 17:06:40 +02:00
|
|
|
|
2016-10-06 11:45:07 +02:00
|
|
|
return 0;
|
2016-10-05 17:06:40 +02:00
|
|
|
}
|
|
|
|
|
2018-12-01 00:36:33 +01:00
|
|
|
static int link_request_set_addresses(Link *link) {
|
2017-04-25 12:36:50 +02:00
|
|
|
AddressLabel *label;
|
2014-02-04 23:13:52 +01:00
|
|
|
Address *ad;
|
2020-02-27 13:32:43 +01:00
|
|
|
Prefix *p;
|
2013-11-14 16:22:51 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
2014-01-01 15:16:34 +01:00
|
|
|
assert(link->state != _LINK_STATE_INVALID);
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2020-08-08 05:36:18 +02:00
|
|
|
if (link->address_remove_messages != 0) {
|
|
|
|
log_link_debug(link, "Removing old addresses, new addresses will be configured later.");
|
|
|
|
link->request_static_addresses = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-12-30 14:08:10 +01:00
|
|
|
/* Reset all *_configured flags we are configuring. */
|
2020-08-08 05:36:18 +02:00
|
|
|
link->request_static_addresses = false;
|
2018-12-30 14:08:10 +01:00
|
|
|
link->addresses_configured = false;
|
2018-12-05 11:49:35 +01:00
|
|
|
link->addresses_ready = false;
|
2018-12-30 14:08:10 +01:00
|
|
|
link->neighbors_configured = false;
|
|
|
|
link->static_routes_configured = false;
|
2019-10-04 21:40:51 +02:00
|
|
|
link->static_nexthops_configured = false;
|
2018-12-30 14:08:10 +01:00
|
|
|
link->routing_policy_rules_configured = false;
|
|
|
|
|
2016-10-05 17:06:40 +02:00
|
|
|
r = link_set_bridge_fdb(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-09-15 09:20:36 +02:00
|
|
|
r = link_set_bridge_mdb(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-12-30 14:07:23 +01:00
|
|
|
r = link_request_set_neighbors(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2018-11-29 04:00:58 +01:00
|
|
|
|
2014-05-15 20:10:33 +02:00
|
|
|
LIST_FOREACH(addresses, ad, link->network->static_addresses) {
|
2019-01-17 06:15:46 +01:00
|
|
|
bool update;
|
|
|
|
|
2020-07-21 18:03:16 +02:00
|
|
|
if (ad->family == AF_INET6 && !in_addr_is_null(ad->family, &ad->in_addr_peer))
|
|
|
|
update = address_get(link, ad->family, &ad->in_addr_peer, ad->prefixlen, NULL) > 0;
|
|
|
|
else
|
|
|
|
update = address_get(link, ad->family, &ad->in_addr, ad->prefixlen, NULL) > 0;
|
2019-01-17 06:15:46 +01:00
|
|
|
|
2020-07-23 17:52:32 +02:00
|
|
|
r = static_address_configure(ad, link, update);
|
2019-07-14 17:35:49 +02:00
|
|
|
if (r < 0)
|
2020-07-23 17:52:32 +02:00
|
|
|
return r;
|
2017-04-25 12:36:50 +02:00
|
|
|
}
|
|
|
|
|
2020-07-28 22:09:38 +02:00
|
|
|
if (link->network->router_prefix_delegation & RADV_PREFIX_DELEGATION_STATIC)
|
2020-02-27 13:32:43 +01:00
|
|
|
LIST_FOREACH(prefixes, p, link->network->static_prefixes) {
|
|
|
|
_cleanup_(address_freep) Address *address = NULL;
|
|
|
|
|
|
|
|
if (!p->assign)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = address_new(&address);
|
|
|
|
if (r < 0)
|
2020-07-23 17:52:32 +02:00
|
|
|
return log_oom();
|
2020-02-27 13:32:43 +01:00
|
|
|
|
|
|
|
r = sd_radv_prefix_get_prefix(p->radv_prefix, &address->in_addr.in6, &address->prefixlen);
|
|
|
|
if (r < 0)
|
2020-07-23 17:52:32 +02:00
|
|
|
return log_link_warning_errno(link, r, "Could not get RA prefix: %m");
|
2020-02-27 13:32:43 +01:00
|
|
|
|
|
|
|
r = generate_ipv6_eui_64_address(link, &address->in_addr.in6);
|
|
|
|
if (r < 0)
|
2020-07-23 17:52:32 +02:00
|
|
|
return log_link_warning_errno(link, r, "Could not generate EUI64 address: %m");
|
2020-02-27 13:32:43 +01:00
|
|
|
|
|
|
|
address->family = AF_INET6;
|
2020-07-23 17:52:32 +02:00
|
|
|
r = static_address_configure(address, link, true);
|
2020-02-27 13:32:43 +01:00
|
|
|
if (r < 0)
|
2020-07-23 17:52:32 +02:00
|
|
|
return r;
|
2020-02-27 13:32:43 +01:00
|
|
|
}
|
|
|
|
|
2017-04-25 12:36:50 +02:00
|
|
|
LIST_FOREACH(labels, label, link->network->address_labels) {
|
2018-11-28 21:14:53 +01:00
|
|
|
r = address_label_configure(label, link, NULL, false);
|
2019-07-14 17:35:49 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not set address label: %m");
|
2014-01-01 15:16:34 +01:00
|
|
|
|
2017-12-12 16:25:36 +01:00
|
|
|
link->address_label_messages++;
|
2013-11-14 16:22:51 +01:00
|
|
|
}
|
|
|
|
|
2020-07-23 17:52:32 +02:00
|
|
|
/* now that we can figure out a default address for the dhcp server, start it */
|
2018-07-09 07:40:54 +02:00
|
|
|
if (link_dhcp4_server_enabled(link) && (link->flags & IFF_UP)) {
|
2019-06-29 21:33:34 +02:00
|
|
|
r = dhcp4_server_configure(link);
|
2019-07-14 17:35:49 +02:00
|
|
|
if (r < 0)
|
2015-01-30 19:54:01 +01:00
|
|
|
return r;
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Offering DHCPv4 leases");
|
2015-01-30 19:54:01 +01:00
|
|
|
}
|
|
|
|
|
2018-12-01 00:54:45 +01:00
|
|
|
if (link->address_messages == 0) {
|
|
|
|
link->addresses_configured = true;
|
2020-07-23 17:52:32 +02:00
|
|
|
link->addresses_ready = true;
|
|
|
|
r = link_request_set_routes(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2019-07-13 17:02:44 +02:00
|
|
|
} else {
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Setting addresses");
|
2019-07-13 17:02:44 +02:00
|
|
|
link_set_state(link, LINK_STATE_CONFIGURING);
|
|
|
|
}
|
2014-08-06 13:48:11 +02:00
|
|
|
|
2013-11-14 16:22:51 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-06-01 15:18:21 +02:00
|
|
|
static int link_set_bridge_vlan(Link *link) {
|
2019-05-10 16:31:20 +02:00
|
|
|
int r;
|
2016-06-01 15:18:21 +02:00
|
|
|
|
|
|
|
r = br_vlan_configure(link, link->network->pvid, link->network->br_vid_bitmap, link->network->br_untagged_bitmap);
|
|
|
|
if (r < 0)
|
|
|
|
log_link_error_errno(link, r, "Failed to assign VLANs to bridge port: %m");
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2016-06-03 19:20:46 +02:00
|
|
|
static int link_set_proxy_arp(Link *link) {
|
2016-04-14 11:56:57 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
if (!link_proxy_arp_enabled(link))
|
|
|
|
return 0;
|
|
|
|
|
2019-02-18 06:30:32 +01:00
|
|
|
r = sysctl_write_ip_property_boolean(AF_INET, link->ifname, "proxy_arp", link->network->proxy_arp > 0);
|
2016-04-14 11:56:57 +02:00
|
|
|
if (r < 0)
|
|
|
|
log_link_warning_errno(link, r, "Cannot configure proxy ARP for interface: %m");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-12-19 19:14:42 +01:00
|
|
|
static int link_configure_continue(Link *link);
|
2018-08-13 09:12:08 +02:00
|
|
|
|
2018-11-28 21:06:52 +01:00
|
|
|
static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
2014-01-13 23:07:59 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(link);
|
|
|
|
assert(link->ifname);
|
|
|
|
|
2018-08-13 09:12:08 +02:00
|
|
|
link->setting_mtu = false;
|
|
|
|
|
2014-07-01 10:09:52 +02:00
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
2014-01-13 23:07:59 +01:00
|
|
|
return 1;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_errno(m);
|
2019-07-14 17:35:49 +02:00
|
|
|
if (r < 0)
|
2019-11-30 07:54:07 +01:00
|
|
|
log_link_message_warning_errno(link, m, r, "Could not set MTU, ignoring");
|
2019-07-14 17:35:49 +02:00
|
|
|
else
|
|
|
|
log_link_debug(link, "Setting MTU done.");
|
2018-08-13 09:12:08 +02:00
|
|
|
|
2019-07-14 17:35:49 +02:00
|
|
|
if (link->state == LINK_STATE_INITIALIZED) {
|
2019-12-19 19:14:42 +01:00
|
|
|
r = link_configure_continue(link);
|
2019-07-14 17:35:49 +02:00
|
|
|
if (r < 0)
|
|
|
|
link_enter_failed(link);
|
|
|
|
}
|
2014-01-13 23:07:59 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-05-15 09:02:06 +02:00
|
|
|
int link_set_mtu(Link *link, uint32_t mtu) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
2014-01-13 23:07:59 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
|
|
|
assert(link->manager->rtnl);
|
|
|
|
|
2019-02-27 01:57:16 +01:00
|
|
|
if (mtu == 0 || link->setting_mtu)
|
|
|
|
return 0;
|
|
|
|
|
2019-05-15 09:02:06 +02:00
|
|
|
if (link->mtu == mtu)
|
2018-08-08 14:14:20 +02:00
|
|
|
return 0;
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Setting MTU: %" PRIu32, mtu);
|
2014-01-13 23:07:59 +01:00
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
|
2014-01-13 23:07:59 +01:00
|
|
|
|
2018-06-14 19:19:25 +02:00
|
|
|
/* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes
|
2018-08-08 13:21:07 +02:00
|
|
|
* on the interface. Bump up MTU bytes to IPV6_MTU_MIN. */
|
|
|
|
if (link_ipv6_enabled(link) && mtu < IPV6_MIN_MTU) {
|
2018-06-14 19:19:25 +02:00
|
|
|
|
|
|
|
log_link_warning(link, "Bumping MTU to " STRINGIFY(IPV6_MIN_MTU) ", as "
|
2019-10-29 15:31:58 +01:00
|
|
|
"IPv6 is requested and requires a minimum MTU of " STRINGIFY(IPV6_MIN_MTU) " bytes");
|
2018-06-14 19:19:25 +02:00
|
|
|
|
2018-08-08 13:21:07 +02:00
|
|
|
mtu = IPV6_MIN_MTU;
|
2018-06-14 19:19:25 +02:00
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_append_u32(req, IFLA_MTU, mtu);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append MTU: %m");
|
2014-01-13 23:07:59 +01:00
|
|
|
|
2018-11-28 21:06:52 +01:00
|
|
|
r = netlink_call_async(link->manager->rtnl, NULL, req, set_mtu_handler,
|
|
|
|
link_netlink_destroy_callback, link);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
2014-01-13 23:07:59 +01:00
|
|
|
|
2014-06-19 19:41:57 +02:00
|
|
|
link_ref(link);
|
2018-10-06 06:55:19 +02:00
|
|
|
link->setting_mtu = true;
|
2014-05-08 19:46:06 +02:00
|
|
|
|
2014-01-13 23:07:59 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-05-16 04:42:46 +02:00
|
|
|
static bool link_reduces_vlan_mtu(Link *link) {
|
|
|
|
/* See netif_reduces_vlan_mtu() in kernel. */
|
|
|
|
return streq_ptr(link->kind, "macsec");
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t link_get_requested_mtu_by_stacked_netdevs(Link *link) {
|
|
|
|
uint32_t mtu = 0;
|
|
|
|
NetDev *dev;
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH(dev, link->network->stacked_netdevs)
|
2019-05-16 04:42:46 +02:00
|
|
|
if (dev->kind == NETDEV_KIND_VLAN && dev->mtu > 0)
|
|
|
|
/* See vlan_dev_change_mtu() in kernel. */
|
|
|
|
mtu = MAX(mtu, link_reduces_vlan_mtu(link) ? dev->mtu + 4 : dev->mtu);
|
|
|
|
|
|
|
|
else if (dev->kind == NETDEV_KIND_MACVLAN && dev->mtu > mtu)
|
|
|
|
/* See macvlan_change_mtu() in kernel. */
|
|
|
|
mtu = dev->mtu;
|
|
|
|
|
|
|
|
return mtu;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_configure_mtu(Link *link) {
|
|
|
|
uint32_t mtu;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
|
|
|
|
|
|
|
if (link->network->mtu > 0)
|
|
|
|
return link_set_mtu(link, link->network->mtu);
|
|
|
|
|
|
|
|
mtu = link_get_requested_mtu_by_stacked_netdevs(link);
|
|
|
|
if (link->mtu >= mtu)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
log_link_notice(link, "Bumping MTU bytes from %"PRIu32" to %"PRIu32" because of stacked device. "
|
|
|
|
"If it is not desired, then please explicitly specify MTUBytes= setting.",
|
|
|
|
link->mtu, mtu);
|
|
|
|
|
|
|
|
return link_set_mtu(link, mtu);
|
|
|
|
}
|
|
|
|
|
2018-11-28 21:06:52 +01:00
|
|
|
static int set_flags_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
2016-08-04 16:00:58 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(link);
|
|
|
|
assert(link->ifname);
|
|
|
|
|
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_errno(m);
|
|
|
|
if (r < 0)
|
2019-11-30 07:54:07 +01:00
|
|
|
log_link_message_warning_errno(link, m, r, "Could not set link flags, ignoring");
|
2016-08-04 16:00:58 +02:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_set_flags(Link *link) {
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
|
|
|
unsigned ifi_change = 0;
|
|
|
|
unsigned ifi_flags = 0;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
|
|
|
assert(link->manager->rtnl);
|
|
|
|
|
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return 0;
|
|
|
|
|
2018-06-01 16:22:12 +02:00
|
|
|
if (link->network->arp < 0 && link->network->multicast < 0 && link->network->allmulticast < 0)
|
2016-08-04 16:00:58 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
|
|
|
|
|
|
|
|
if (link->network->arp >= 0) {
|
|
|
|
ifi_change |= IFF_NOARP;
|
2018-05-29 16:58:11 +02:00
|
|
|
SET_FLAG(ifi_flags, IFF_NOARP, link->network->arp == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (link->network->multicast >= 0) {
|
|
|
|
ifi_change |= IFF_MULTICAST;
|
|
|
|
SET_FLAG(ifi_flags, IFF_MULTICAST, link->network->multicast);
|
2016-08-04 16:00:58 +02:00
|
|
|
}
|
|
|
|
|
2018-06-01 16:22:12 +02:00
|
|
|
if (link->network->allmulticast >= 0) {
|
|
|
|
ifi_change |= IFF_ALLMULTI;
|
|
|
|
SET_FLAG(ifi_flags, IFF_ALLMULTI, link->network->allmulticast);
|
|
|
|
}
|
|
|
|
|
2016-08-04 16:00:58 +02:00
|
|
|
r = sd_rtnl_message_link_set_flags(req, ifi_flags, ifi_change);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not set link flags: %m");
|
|
|
|
|
2018-11-28 21:06:52 +01:00
|
|
|
r = netlink_call_async(link->manager->rtnl, NULL, req, set_flags_handler,
|
|
|
|
link_netlink_destroy_callback, link);
|
2016-08-04 16:00:58 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
|
|
|
|
|
|
|
link_ref(link);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-11-10 21:30:59 +01:00
|
|
|
static int link_acquire_ipv6_conf(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (link_ipv6_accept_ra_enabled(link)) {
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
assert(link->ndisc);
|
2015-11-10 21:30:59 +01:00
|
|
|
|
|
|
|
log_link_debug(link, "Discovering IPv6 routers");
|
|
|
|
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
r = sd_ndisc_start(link->ndisc);
|
2015-11-16 16:46:14 +01:00
|
|
|
if (r < 0 && r != -EBUSY)
|
2015-11-10 21:30:59 +01:00
|
|
|
return log_link_warning_errno(link, r, "Could not start IPv6 Router Discovery: %m");
|
|
|
|
}
|
|
|
|
|
2017-05-12 15:48:33 +02:00
|
|
|
if (link_radv_enabled(link)) {
|
|
|
|
assert(link->radv);
|
|
|
|
assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0);
|
|
|
|
|
|
|
|
log_link_debug(link, "Starting IPv6 Router Advertisements");
|
|
|
|
|
2020-01-31 07:52:56 +01:00
|
|
|
r = radv_emit_dns(link);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Failed to configure DNS or Domains in IPv6 Router Advertisement: %m");
|
|
|
|
|
2017-05-12 15:48:33 +02:00
|
|
|
r = sd_radv_start(link->radv);
|
|
|
|
if (r < 0 && r != -EBUSY)
|
|
|
|
return log_link_warning_errno(link, r, "Could not start IPv6 Router Advertisement: %m");
|
|
|
|
}
|
|
|
|
|
2020-07-02 01:03:17 +02:00
|
|
|
if (link_dhcp6_enabled(link) && IN_SET(link->network->dhcp6_without_ra,
|
|
|
|
DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST,
|
|
|
|
DHCP6_CLIENT_START_MODE_SOLICIT)) {
|
2020-02-15 13:51:34 +01:00
|
|
|
assert(link->dhcp6_client);
|
|
|
|
assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0);
|
|
|
|
|
2020-07-02 01:03:17 +02:00
|
|
|
r = dhcp6_request_address(link, link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST);
|
2020-02-15 13:51:34 +01:00
|
|
|
if (r < 0 && r != -EBUSY)
|
2020-07-22 20:13:42 +02:00
|
|
|
return log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease: %m");
|
2020-02-15 13:51:34 +01:00
|
|
|
else
|
|
|
|
log_link_debug(link, "Acquiring DHCPv6 lease");
|
|
|
|
}
|
|
|
|
|
2020-07-22 20:13:42 +02:00
|
|
|
r = dhcp6_request_prefix_delegation(link);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Failed to request DHCPv6 prefix delegation: %m");
|
2018-10-02 20:29:09 +02:00
|
|
|
|
2015-11-10 21:30:59 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-29 01:03:29 +02:00
|
|
|
static int link_acquire_ipv4_conf(Link *link) {
|
2014-01-03 02:07:56 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
|
|
|
assert(link->manager->event);
|
|
|
|
|
2019-05-22 07:49:46 +02:00
|
|
|
if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4)) {
|
2014-03-20 19:57:19 +01:00
|
|
|
assert(link->ipv4ll);
|
2014-01-03 02:07:56 +01:00
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Acquiring IPv4 link-local address");
|
2014-02-28 16:10:20 +01:00
|
|
|
|
|
|
|
r = sd_ipv4ll_start(link->ipv4ll);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
|
2014-02-28 16:10:20 +01:00
|
|
|
}
|
|
|
|
|
2014-09-04 20:54:08 +02:00
|
|
|
if (link_dhcp4_enabled(link)) {
|
2014-03-20 19:57:19 +01:00
|
|
|
assert(link->dhcp_client);
|
2014-01-03 02:07:56 +01:00
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Acquiring DHCPv4 lease");
|
2014-01-12 15:24:11 +01:00
|
|
|
|
2014-02-28 16:10:20 +01:00
|
|
|
r = sd_dhcp_client_start(link->dhcp_client);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m");
|
2014-02-28 16:10:20 +01:00
|
|
|
}
|
2014-01-03 02:07:56 +01:00
|
|
|
|
2016-04-29 01:03:29 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_acquire_conf(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
r = link_acquire_ipv4_conf(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-02-03 00:24:17 +01:00
|
|
|
if (!in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address)) {
|
2016-04-29 01:03:29 +02:00
|
|
|
r = link_acquire_ipv6_conf(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2016-05-06 21:27:36 +02:00
|
|
|
if (link_lldp_emit_enabled(link)) {
|
|
|
|
r = link_lldp_emit_start(link);
|
2016-02-21 14:14:08 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Failed to start LLDP transmission: %m");
|
|
|
|
}
|
|
|
|
|
2014-01-03 02:07:56 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-09-04 14:05:54 +02:00
|
|
|
bool link_has_carrier(Link *link) {
|
2014-05-07 16:35:05 +02:00
|
|
|
/* see Documentation/networking/operstates.txt in the kernel sources */
|
|
|
|
|
2014-09-04 14:05:54 +02:00
|
|
|
if (link->kernel_operstate == IF_OPER_UP)
|
2014-05-07 16:35:05 +02:00
|
|
|
return true;
|
|
|
|
|
2014-09-04 14:05:54 +02:00
|
|
|
if (link->kernel_operstate == IF_OPER_UNKNOWN)
|
2014-05-07 16:35:05 +02:00
|
|
|
/* operstate may not be implemented, so fall back to flags */
|
2019-05-17 02:14:59 +02:00
|
|
|
if (FLAGS_SET(link->flags, IFF_LOWER_UP | IFF_RUNNING) &&
|
|
|
|
!FLAGS_SET(link->flags, IFF_DORMANT))
|
2014-05-07 16:35:05 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-02-11 13:28:23 +01:00
|
|
|
static int link_address_genmode_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
2019-12-19 19:17:45 +01:00
|
|
|
link->setting_genmode = false;
|
|
|
|
|
2019-02-11 13:28:23 +01:00
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_errno(m);
|
|
|
|
if (r < 0)
|
2019-11-30 07:54:07 +01:00
|
|
|
log_link_message_warning_errno(link, m, r, "Could not set address genmode for interface, ignoring");
|
2019-12-19 19:17:45 +01:00
|
|
|
else
|
|
|
|
log_link_debug(link, "Setting address genmode done.");
|
|
|
|
|
|
|
|
if (link->state == LINK_STATE_INITIALIZED) {
|
|
|
|
r = link_configure_continue(link);
|
|
|
|
if (r < 0)
|
|
|
|
link_enter_failed(link);
|
|
|
|
}
|
2019-02-11 13:28:23 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_configure_addrgen_mode(Link *link) {
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
|
|
|
uint8_t ipv6ll_mode;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
|
|
|
assert(link->manager);
|
|
|
|
assert(link->manager->rtnl);
|
|
|
|
|
2019-12-19 19:17:45 +01:00
|
|
|
if (!socket_ipv6_is_supported() || link->setting_genmode)
|
2019-05-09 07:39:46 +02:00
|
|
|
return 0;
|
|
|
|
|
2019-02-11 13:28:23 +01:00
|
|
|
log_link_debug(link, "Setting address genmode for link");
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_open_container(req, AF_INET6);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not open AF_INET6 container: %m");
|
|
|
|
|
|
|
|
if (!link_ipv6ll_enabled(link))
|
|
|
|
ipv6ll_mode = IN6_ADDR_GEN_MODE_NONE;
|
2020-06-30 10:01:30 +02:00
|
|
|
else if (link->network->ipv6ll_address_gen_mode < 0) {
|
2020-04-18 17:59:29 +02:00
|
|
|
r = sysctl_read_ip_property(AF_INET6, link->ifname, "stable_secret", NULL);
|
|
|
|
if (r < 0) {
|
|
|
|
/* The file may not exist. And even if it exists, when stable_secret is unset,
|
|
|
|
* reading the file fails with EIO. */
|
|
|
|
log_link_debug_errno(link, r, "Failed to read sysctl property stable_secret: %m");
|
|
|
|
|
|
|
|
ipv6ll_mode = IN6_ADDR_GEN_MODE_EUI64;
|
|
|
|
} else
|
|
|
|
ipv6ll_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
|
|
|
|
} else
|
2020-06-30 10:01:30 +02:00
|
|
|
ipv6ll_mode = link->network->ipv6ll_address_gen_mode;
|
2019-02-11 13:28:23 +01:00
|
|
|
|
|
|
|
r = sd_netlink_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, ipv6ll_mode);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append IFLA_INET6_ADDR_GEN_MODE: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_close_container(req);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not close AF_INET6 container: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_close_container(req);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
|
|
|
|
|
|
|
|
r = netlink_call_async(link->manager->rtnl, NULL, req, link_address_genmode_handler,
|
|
|
|
link_netlink_destroy_callback, link);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
|
|
|
|
|
|
|
link_ref(link);
|
2019-12-19 19:17:45 +01:00
|
|
|
link->setting_genmode = true;
|
2019-02-11 13:28:23 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-28 21:06:52 +01:00
|
|
|
static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
2013-12-03 18:48:20 +01:00
|
|
|
int r;
|
|
|
|
|
2014-01-03 00:55:09 +01:00
|
|
|
assert(link);
|
|
|
|
|
2014-07-01 10:09:52 +02:00
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
2014-01-03 00:55:09 +01:00
|
|
|
return 1;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_errno(m);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
2018-10-10 07:36:32 +02:00
|
|
|
/* we warn but don't fail the link, as it may be brought up later */
|
2019-11-30 07:54:07 +01:00
|
|
|
log_link_message_warning_errno(link, m, r, "Could not bring up interface");
|
2014-04-22 19:36:40 +02:00
|
|
|
|
2013-11-14 16:22:51 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-01-24 04:07:41 +01:00
|
|
|
static int link_up(Link *link) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
2013-10-17 03:18:36 +02:00
|
|
|
int r;
|
|
|
|
|
2013-11-14 16:22:51 +01:00
|
|
|
assert(link);
|
2014-12-04 21:57:13 +01:00
|
|
|
assert(link->network);
|
2013-11-14 16:22:51 +01:00
|
|
|
assert(link->manager);
|
|
|
|
assert(link->manager->rtnl);
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Bringing link up");
|
2014-01-02 15:30:46 +01:00
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2016-05-28 07:31:41 +02:00
|
|
|
/* set it free if not enslaved with networkd */
|
2016-06-13 01:05:49 +02:00
|
|
|
if (!link->network->bridge && !link->network->bond && !link->network->vrf) {
|
2016-05-28 07:31:41 +02:00
|
|
|
r = sd_netlink_message_append_u32(req, IFLA_MASTER, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append IFLA_MASTER attribute: %m");
|
|
|
|
}
|
|
|
|
|
2014-01-21 15:20:42 +01:00
|
|
|
r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not set link flags: %m");
|
2013-12-06 18:16:16 +01:00
|
|
|
|
2014-12-04 21:57:13 +01:00
|
|
|
if (link->network->mac) {
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_append_ether_addr(req, IFLA_ADDRESS, link->network->mac);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not set MAC address: %m");
|
2014-12-04 21:57:13 +01:00
|
|
|
}
|
|
|
|
|
2018-11-28 21:06:52 +01:00
|
|
|
r = netlink_call_async(link->manager->rtnl, NULL, req, link_up_handler,
|
|
|
|
link_netlink_destroy_callback, link);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2014-05-08 19:46:06 +02:00
|
|
|
link_ref(link);
|
|
|
|
|
2013-11-14 16:22:51 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-28 21:06:52 +01:00
|
|
|
static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
2015-02-17 13:06:57 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
|
|
|
return 1;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_errno(m);
|
2015-02-17 13:06:57 +01:00
|
|
|
if (r < 0)
|
2019-11-30 07:54:07 +01:00
|
|
|
log_link_message_warning_errno(link, m, r, "Could not bring down interface");
|
2015-02-17 13:06:57 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-05-09 08:53:01 +02:00
|
|
|
int link_down(Link *link, link_netlink_message_handler_t callback) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
2015-02-17 13:06:57 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
|
|
|
assert(link->manager->rtnl);
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Bringing link down");
|
2015-02-17 13:06:57 +01:00
|
|
|
|
|
|
|
r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
|
|
|
|
RTM_SETLINK, link->ifindex);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
|
2015-02-17 13:06:57 +01:00
|
|
|
|
|
|
|
r = sd_rtnl_message_link_set_flags(req, 0, IFF_UP);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not set link flags: %m");
|
2015-02-17 13:06:57 +01:00
|
|
|
|
2019-05-09 08:53:01 +02:00
|
|
|
r = netlink_call_async(link->manager->rtnl, NULL, req,
|
|
|
|
callback ?: link_down_handler,
|
2018-11-28 21:06:52 +01:00
|
|
|
link_netlink_destroy_callback, link);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
2015-02-17 13:06:57 +01:00
|
|
|
|
|
|
|
link_ref(link);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-07 14:36:55 +02:00
|
|
|
static int link_group_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_errno(m);
|
|
|
|
if (r < 0)
|
|
|
|
log_link_message_warning_errno(link, m, r, "Could not set group for the interface");
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_set_group(Link *link) {
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
|
|
|
assert(link->manager);
|
|
|
|
assert(link->manager->rtnl);
|
|
|
|
|
|
|
|
if (link->network->group <= 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
log_link_debug(link, "Setting group");
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_append_u32(req, IFLA_GROUP, link->network->group);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not set link group: %m");
|
|
|
|
|
|
|
|
r = netlink_call_async(link->manager->rtnl, NULL, req, link_group_handler,
|
|
|
|
link_netlink_destroy_callback, link);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
|
|
|
|
|
|
|
link_ref(link);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-17 13:06:57 +01:00
|
|
|
static int link_handle_bound_to_list(Link *link) {
|
|
|
|
Link *l;
|
|
|
|
int r;
|
|
|
|
bool required_up = false;
|
|
|
|
bool link_is_up = false;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (hashmap_isempty(link->bound_to_links))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (link->flags & IFF_UP)
|
|
|
|
link_is_up = true;
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH (l, link->bound_to_links)
|
2015-02-17 13:06:57 +01:00
|
|
|
if (link_has_carrier(l)) {
|
|
|
|
required_up = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!required_up && link_is_up) {
|
2019-05-09 08:53:01 +02:00
|
|
|
r = link_down(link, NULL);
|
2015-02-17 13:06:57 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
} else if (required_up && !link_is_up) {
|
|
|
|
r = link_up(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_handle_bound_by_list(Link *link) {
|
|
|
|
Link *l;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (hashmap_isempty(link->bound_by_links))
|
|
|
|
return 0;
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH (l, link->bound_by_links) {
|
2015-02-17 13:06:57 +01:00
|
|
|
r = link_handle_bound_to_list(l);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_put_carrier(Link *link, Link *carrier, Hashmap **h) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(carrier);
|
|
|
|
|
|
|
|
if (link == carrier)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (hashmap_get(*h, INT_TO_PTR(carrier->ifindex)))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
r = hashmap_ensure_allocated(h, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = hashmap_put(*h, INT_TO_PTR(carrier->ifindex), carrier);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_new_bound_by_list(Link *link) {
|
|
|
|
Manager *m;
|
|
|
|
Link *carrier;
|
|
|
|
int r;
|
|
|
|
bool list_updated = false;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
|
|
|
|
|
|
|
m = link->manager;
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH(carrier, m->links) {
|
2015-02-17 13:06:57 +01:00
|
|
|
if (!carrier->network)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (strv_isempty(carrier->network->bind_carrier))
|
|
|
|
continue;
|
|
|
|
|
2020-01-12 12:26:26 +01:00
|
|
|
if (strv_fnmatch(carrier->network->bind_carrier, link->ifname)) {
|
2015-02-17 13:06:57 +01:00
|
|
|
r = link_put_carrier(link, carrier, &link->bound_by_links);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
list_updated = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (list_updated)
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(link);
|
2015-02-17 13:06:57 +01:00
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH(carrier, link->bound_by_links) {
|
2015-02-17 13:06:57 +01:00
|
|
|
r = link_put_carrier(carrier, link, &carrier->bound_to_links);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(carrier);
|
2015-02-17 13:06:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_new_bound_to_list(Link *link) {
|
|
|
|
Manager *m;
|
|
|
|
Link *carrier;
|
|
|
|
int r;
|
|
|
|
bool list_updated = false;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (strv_isempty(link->network->bind_carrier))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
m = link->manager;
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH (carrier, m->links) {
|
2020-01-12 12:26:26 +01:00
|
|
|
if (strv_fnmatch(link->network->bind_carrier, carrier->ifname)) {
|
2015-02-17 13:06:57 +01:00
|
|
|
r = link_put_carrier(link, carrier, &link->bound_to_links);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
list_updated = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (list_updated)
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(link);
|
2015-02-17 13:06:57 +01:00
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH (carrier, link->bound_to_links) {
|
2015-02-17 13:06:57 +01:00
|
|
|
r = link_put_carrier(carrier, link, &carrier->bound_by_links);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(carrier);
|
2015-02-17 13:06:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_new_carrier_maps(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = link_new_bound_by_list(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = link_handle_bound_by_list(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = link_new_bound_to_list(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = link_handle_bound_to_list(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void link_free_bound_to_list(Link *link) {
|
|
|
|
Link *bound_to;
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH (bound_to, link->bound_to_links) {
|
2015-02-17 13:06:57 +01:00
|
|
|
hashmap_remove(link->bound_to_links, INT_TO_PTR(bound_to->ifindex));
|
|
|
|
|
|
|
|
if (hashmap_remove(bound_to->bound_by_links, INT_TO_PTR(link->ifindex)))
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(bound_to);
|
2015-02-17 13:06:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void link_free_bound_by_list(Link *link) {
|
|
|
|
Link *bound_by;
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH (bound_by, link->bound_by_links) {
|
2015-02-17 13:06:57 +01:00
|
|
|
hashmap_remove(link->bound_by_links, INT_TO_PTR(bound_by->ifindex));
|
|
|
|
|
|
|
|
if (hashmap_remove(bound_by->bound_to_links, INT_TO_PTR(link->ifindex))) {
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(bound_by);
|
2015-02-17 13:06:57 +01:00
|
|
|
link_handle_bound_to_list(bound_by);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void link_free_carrier_maps(Link *link) {
|
|
|
|
bool list_updated = false;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (!hashmap_isempty(link->bound_to_links)) {
|
|
|
|
link_free_bound_to_list(link);
|
|
|
|
list_updated = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hashmap_isempty(link->bound_by_links)) {
|
|
|
|
link_free_bound_by_list(link);
|
|
|
|
list_updated = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (list_updated)
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(link);
|
2015-02-17 13:06:57 +01:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-04-15 09:38:45 +02:00
|
|
|
static int link_append_to_master(Link *link, NetDev *netdev) {
|
|
|
|
Link *master;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(netdev);
|
|
|
|
|
|
|
|
r = link_get(link->manager, netdev->ifindex, &master);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-06-05 15:12:29 +02:00
|
|
|
r = set_ensure_put(&master->slaves, NULL, link);
|
2019-09-21 16:01:14 +02:00
|
|
|
if (r <= 0)
|
2019-04-15 09:38:45 +02:00
|
|
|
return r;
|
|
|
|
|
|
|
|
link_ref(link);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void link_drop_from_master(Link *link, NetDev *netdev) {
|
|
|
|
Link *master;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (!link->manager || !netdev)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (link_get(link->manager, netdev->ifindex, &master) < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
link_unref(set_remove(master->slaves, link));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void link_detach_from_manager(Link *link) {
|
|
|
|
if (!link || !link->manager)
|
|
|
|
return;
|
|
|
|
|
|
|
|
link_unref(set_remove(link->manager->links_requesting_uuid, link));
|
|
|
|
link_clean(link);
|
|
|
|
|
|
|
|
/* The following must be called at last. */
|
|
|
|
assert_se(hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex)) == link);
|
|
|
|
link_unref(link);
|
|
|
|
}
|
|
|
|
|
2015-02-17 13:06:57 +01:00
|
|
|
void link_drop(Link *link) {
|
|
|
|
if (!link || link->state == LINK_STATE_LINGER)
|
|
|
|
return;
|
|
|
|
|
|
|
|
link_set_state(link, LINK_STATE_LINGER);
|
|
|
|
|
|
|
|
link_free_carrier_maps(link);
|
|
|
|
|
2019-04-15 09:38:45 +02:00
|
|
|
if (link->network) {
|
|
|
|
link_drop_from_master(link, link->network->bridge);
|
|
|
|
link_drop_from_master(link, link->network->bond);
|
|
|
|
}
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Link removed");
|
2015-02-17 13:06:57 +01:00
|
|
|
|
2018-07-03 07:36:15 +02:00
|
|
|
(void) unlink(link->state_file);
|
2018-11-04 12:36:13 +01:00
|
|
|
link_detach_from_manager(link);
|
2015-02-17 13:06:57 +01:00
|
|
|
}
|
|
|
|
|
2014-07-05 14:53:54 +02:00
|
|
|
static int link_joined(Link *link) {
|
2013-11-14 16:22:51 +01:00
|
|
|
int r;
|
|
|
|
|
2013-12-14 19:09:04 +01:00
|
|
|
assert(link);
|
2014-01-01 15:16:34 +01:00
|
|
|
assert(link->network);
|
2013-12-03 18:48:20 +01:00
|
|
|
|
2015-02-17 13:06:57 +01:00
|
|
|
if (!hashmap_isempty(link->bound_to_links)) {
|
|
|
|
r = link_handle_bound_to_list(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
} else if (!(link->flags & IFF_UP)) {
|
2014-04-15 14:21:44 +02:00
|
|
|
r = link_up(link);
|
|
|
|
if (r < 0) {
|
|
|
|
link_enter_failed(link);
|
|
|
|
return r;
|
|
|
|
}
|
2013-12-14 19:09:04 +01:00
|
|
|
}
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2016-02-23 18:52:52 +01:00
|
|
|
if (link->network->bridge) {
|
2014-11-15 04:17:16 +01:00
|
|
|
r = link_set_bridge(link);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
log_link_error_errno(link, r, "Could not set bridge message: %m");
|
2019-02-20 02:31:15 +01:00
|
|
|
|
|
|
|
r = link_append_to_master(link, link->network->bridge);
|
|
|
|
if (r < 0)
|
|
|
|
log_link_error_errno(link, r, "Failed to add to bridge master's slave list: %m");
|
2014-11-15 04:17:16 +01:00
|
|
|
}
|
|
|
|
|
2016-12-21 19:10:36 +01:00
|
|
|
if (link->network->bond) {
|
2019-02-09 14:41:13 +01:00
|
|
|
r = link_set_bond(link);
|
2016-12-21 19:10:36 +01:00
|
|
|
if (r < 0)
|
|
|
|
log_link_error_errno(link, r, "Could not set bond message: %m");
|
2019-02-12 22:32:48 +01:00
|
|
|
|
2019-02-20 02:31:15 +01:00
|
|
|
r = link_append_to_master(link, link->network->bond);
|
2019-02-12 22:32:48 +01:00
|
|
|
if (r < 0)
|
|
|
|
log_link_error_errno(link, r, "Failed to add to bond master's slave list: %m");
|
2016-12-21 19:10:36 +01:00
|
|
|
}
|
|
|
|
|
2016-08-04 17:11:13 +02:00
|
|
|
if (link->network->use_br_vlan &&
|
|
|
|
(link->network->bridge || streq_ptr("bridge", link->kind))) {
|
2016-06-01 15:18:21 +02:00
|
|
|
r = link_set_bridge_vlan(link);
|
|
|
|
if (r < 0)
|
|
|
|
log_link_error_errno(link, r, "Could not set bridge vlan: %m");
|
|
|
|
}
|
|
|
|
|
2017-06-07 17:30:46 +02:00
|
|
|
/* Skip setting up addresses until it gets carrier,
|
|
|
|
or it would try to set addresses twice,
|
|
|
|
which is bad for non-idempotent steps. */
|
2017-09-06 16:57:04 +02:00
|
|
|
if (!link_has_carrier(link) && !link->network->configure_without_carrier)
|
2017-06-07 17:30:46 +02:00
|
|
|
return 0;
|
|
|
|
|
2019-07-13 17:02:44 +02:00
|
|
|
link_set_state(link, LINK_STATE_CONFIGURING);
|
2018-12-01 00:36:33 +01:00
|
|
|
return link_request_set_addresses(link);
|
2013-11-24 23:37:56 +01:00
|
|
|
}
|
|
|
|
|
2018-11-28 21:06:52 +01:00
|
|
|
static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
2013-11-24 23:37:56 +01:00
|
|
|
int r;
|
|
|
|
|
2014-01-03 00:55:09 +01:00
|
|
|
assert(link);
|
2013-12-14 19:09:04 +01:00
|
|
|
assert(link->network);
|
2019-02-15 04:35:30 +01:00
|
|
|
assert(link->enslaving > 0);
|
2013-11-24 23:37:56 +01:00
|
|
|
|
2016-02-23 05:32:04 +01:00
|
|
|
link->enslaving--;
|
2014-01-21 21:58:08 +01:00
|
|
|
|
2014-07-01 10:09:52 +02:00
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
2013-11-24 23:37:56 +01:00
|
|
|
return 1;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_errno(m);
|
2014-07-01 13:30:23 +02:00
|
|
|
if (r < 0 && r != -EEXIST) {
|
2019-11-30 07:54:07 +01:00
|
|
|
log_link_message_warning_errno(link, m, r, "Could not join netdev");
|
2013-12-14 19:09:04 +01:00
|
|
|
link_enter_failed(link);
|
|
|
|
return 1;
|
2019-07-14 17:35:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
log_link_debug(link, "Joined netdev");
|
2013-11-24 23:37:56 +01:00
|
|
|
|
2019-02-15 04:35:30 +01:00
|
|
|
if (link->enslaving == 0) {
|
2019-07-14 17:35:49 +02:00
|
|
|
r = link_joined(link);
|
|
|
|
if (r < 0)
|
|
|
|
link_enter_failed(link);
|
2019-02-15 04:35:30 +01:00
|
|
|
}
|
2013-11-24 23:37:56 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-07-05 14:53:54 +02:00
|
|
|
static int link_enter_join_netdev(Link *link) {
|
2014-07-28 12:10:37 +02:00
|
|
|
NetDev *netdev;
|
2013-11-24 23:37:56 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
2019-04-15 10:34:00 +02:00
|
|
|
assert(link->state == LINK_STATE_INITIALIZED);
|
2013-11-24 23:37:56 +01:00
|
|
|
|
2018-12-01 00:36:33 +01:00
|
|
|
link_set_state(link, LINK_STATE_CONFIGURING);
|
2013-11-24 23:37:56 +01:00
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
link_dirty(link);
|
2019-02-15 04:35:30 +01:00
|
|
|
link->enslaving = 0;
|
2013-11-24 23:37:56 +01:00
|
|
|
|
2014-05-09 12:20:21 +02:00
|
|
|
if (link->network->bond) {
|
2018-10-19 13:12:35 +02:00
|
|
|
if (link->network->bond->state == NETDEV_STATE_READY &&
|
|
|
|
link->network->bond->ifindex == link->master_ifindex)
|
|
|
|
return link_joined(link);
|
|
|
|
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_struct(LOG_DEBUG,
|
|
|
|
LOG_LINK_INTERFACE(link),
|
|
|
|
LOG_NETDEV_INTERFACE(link->network->bond),
|
2018-06-04 12:59:22 +02:00
|
|
|
LOG_LINK_MESSAGE(link, "Enslaving by '%s'", link->network->bond->ifname));
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
|
2019-02-15 04:35:30 +01:00
|
|
|
link->enslaving++;
|
|
|
|
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
r = netdev_join(link->network->bond, link, netdev_join_handler);
|
2014-01-21 21:58:08 +01:00
|
|
|
if (r < 0) {
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_struct_errno(LOG_WARNING, r,
|
|
|
|
LOG_LINK_INTERFACE(link),
|
|
|
|
LOG_NETDEV_INTERFACE(link->network->bond),
|
2018-06-04 12:59:22 +02:00
|
|
|
LOG_LINK_MESSAGE(link, "Could not join netdev '%s': %m", link->network->bond->ifname));
|
2014-01-21 21:58:08 +01:00
|
|
|
link_enter_failed(link);
|
|
|
|
return r;
|
|
|
|
}
|
2014-03-05 10:41:13 +01:00
|
|
|
}
|
|
|
|
|
2014-05-09 12:20:21 +02:00
|
|
|
if (link->network->bridge) {
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_struct(LOG_DEBUG,
|
|
|
|
LOG_LINK_INTERFACE(link),
|
|
|
|
LOG_NETDEV_INTERFACE(link->network->bridge),
|
2018-06-04 12:59:22 +02:00
|
|
|
LOG_LINK_MESSAGE(link, "Enslaving by '%s'", link->network->bridge->ifname));
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
|
2019-02-15 04:35:30 +01:00
|
|
|
link->enslaving++;
|
|
|
|
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
r = netdev_join(link->network->bridge, link, netdev_join_handler);
|
2014-03-05 10:41:13 +01:00
|
|
|
if (r < 0) {
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_struct_errno(LOG_WARNING, r,
|
|
|
|
LOG_LINK_INTERFACE(link),
|
|
|
|
LOG_NETDEV_INTERFACE(link->network->bridge),
|
2018-06-04 12:59:22 +02:00
|
|
|
LOG_LINK_MESSAGE(link, "Could not join netdev '%s': %m", link->network->bridge->ifname));
|
2014-03-05 10:41:13 +01:00
|
|
|
link_enter_failed(link);
|
|
|
|
return r;
|
|
|
|
}
|
2014-01-21 21:58:08 +01:00
|
|
|
}
|
|
|
|
|
2016-06-13 01:05:49 +02:00
|
|
|
if (link->network->vrf) {
|
|
|
|
log_struct(LOG_DEBUG,
|
|
|
|
LOG_LINK_INTERFACE(link),
|
|
|
|
LOG_NETDEV_INTERFACE(link->network->vrf),
|
2018-06-04 12:59:22 +02:00
|
|
|
LOG_LINK_MESSAGE(link, "Enslaving by '%s'", link->network->vrf->ifname));
|
|
|
|
|
2019-02-15 04:35:30 +01:00
|
|
|
link->enslaving++;
|
|
|
|
|
2016-06-13 01:05:49 +02:00
|
|
|
r = netdev_join(link->network->vrf, link, netdev_join_handler);
|
|
|
|
if (r < 0) {
|
|
|
|
log_struct_errno(LOG_WARNING, r,
|
|
|
|
LOG_LINK_INTERFACE(link),
|
|
|
|
LOG_NETDEV_INTERFACE(link->network->vrf),
|
2018-06-04 12:59:22 +02:00
|
|
|
LOG_LINK_MESSAGE(link, "Could not join netdev '%s': %m", link->network->vrf->ifname));
|
2016-06-13 01:05:49 +02:00
|
|
|
link_enter_failed(link);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH(netdev, link->network->stacked_netdevs) {
|
2014-05-12 07:18:24 +02:00
|
|
|
|
2019-03-11 07:35:35 +01:00
|
|
|
if (netdev->ifindex > 0)
|
|
|
|
/* Assume already enslaved. */
|
2017-11-20 18:58:06 +01:00
|
|
|
continue;
|
|
|
|
|
2019-03-11 08:11:47 +01:00
|
|
|
if (netdev_get_create_type(netdev) != NETDEV_CREATE_STACKED)
|
|
|
|
continue;
|
|
|
|
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_struct(LOG_DEBUG,
|
|
|
|
LOG_LINK_INTERFACE(link),
|
|
|
|
LOG_NETDEV_INTERFACE(netdev),
|
2018-06-04 12:59:22 +02:00
|
|
|
LOG_LINK_MESSAGE(link, "Enslaving by '%s'", netdev->ifname));
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
|
2019-02-15 04:35:30 +01:00
|
|
|
link->enslaving++;
|
|
|
|
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
r = netdev_join(netdev, link, netdev_join_handler);
|
2014-05-12 07:18:24 +02:00
|
|
|
if (r < 0) {
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_struct_errno(LOG_WARNING, r,
|
|
|
|
LOG_LINK_INTERFACE(link),
|
|
|
|
LOG_NETDEV_INTERFACE(netdev),
|
2018-06-04 12:59:22 +02:00
|
|
|
LOG_LINK_MESSAGE(link, "Could not join netdev '%s': %m", netdev->ifname));
|
2014-06-16 08:24:33 +02:00
|
|
|
link_enter_failed(link);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-15 04:35:30 +01:00
|
|
|
if (link->enslaving == 0)
|
|
|
|
return link_joined(link);
|
|
|
|
|
2013-12-14 19:09:04 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-01-13 20:07:13 +01:00
|
|
|
static int link_set_ipv4_forward(Link *link) {
|
2015-01-13 13:47:08 +01:00
|
|
|
int r;
|
|
|
|
|
2015-11-13 12:49:15 +01:00
|
|
|
if (!link_ipv4_forward_enabled(link))
|
2015-07-06 13:38:47 +02:00
|
|
|
return 0;
|
|
|
|
|
2015-11-13 12:49:15 +01:00
|
|
|
/* We propagate the forwarding flag from one interface to the
|
|
|
|
* global setting one way. This means: as long as at least one
|
|
|
|
* interface was configured at any time that had IP forwarding
|
|
|
|
* enabled the setting will stay on for good. We do this
|
|
|
|
* primarily to keep IPv4 and IPv6 packet forwarding behaviour
|
|
|
|
* somewhat in sync (see below). */
|
2015-07-06 13:38:47 +02:00
|
|
|
|
2019-02-18 06:30:32 +01:00
|
|
|
r = sysctl_write_ip_property(AF_INET, NULL, "ip_forward", "1");
|
2015-11-13 00:54:56 +01:00
|
|
|
if (r < 0)
|
2015-11-13 12:49:15 +01:00
|
|
|
log_link_warning_errno(link, r, "Cannot turn on IPv4 packet forwarding, ignoring: %m");
|
2015-01-13 20:50:46 +01:00
|
|
|
|
2015-01-13 20:07:13 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_set_ipv6_forward(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
2015-11-13 12:49:15 +01:00
|
|
|
if (!link_ipv6_forward_enabled(link))
|
2015-05-01 20:48:08 +02:00
|
|
|
return 0;
|
|
|
|
|
2016-07-10 14:48:23 +02:00
|
|
|
/* On Linux, the IPv6 stack does not know a per-interface
|
2015-11-13 12:49:15 +01:00
|
|
|
* packet forwarding setting: either packet forwarding is on
|
|
|
|
* for all, or off for all. We hence don't bother with a
|
|
|
|
* per-interface setting, but simply propagate the interface
|
|
|
|
* flag, if it is set, to the global flag, one-way. Note that
|
|
|
|
* while IPv4 would allow a per-interface flag, we expose the
|
|
|
|
* same behaviour there and also propagate the setting from
|
|
|
|
* one to all, to keep things simple (see above). */
|
2015-07-06 13:38:47 +02:00
|
|
|
|
2019-02-18 06:30:32 +01:00
|
|
|
r = sysctl_write_ip_property(AF_INET6, "all", "forwarding", "1");
|
2015-11-13 00:54:56 +01:00
|
|
|
if (r < 0)
|
2015-11-13 12:49:15 +01:00
|
|
|
log_link_warning_errno(link, r, "Cannot configure IPv6 packet forwarding, ignoring: %m");
|
2015-01-13 13:47:08 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-05 07:54:31 +02:00
|
|
|
static int link_set_ipv6_privacy_extensions(Link *link) {
|
2015-07-06 20:29:33 +02:00
|
|
|
IPv6PrivacyExtensions s;
|
2015-07-05 07:54:31 +02:00
|
|
|
int r;
|
|
|
|
|
2015-07-06 20:29:33 +02:00
|
|
|
s = link_ipv6_privacy_extensions(link);
|
2015-11-13 12:30:57 +01:00
|
|
|
if (s < 0)
|
2015-07-05 07:54:31 +02:00
|
|
|
return 0;
|
|
|
|
|
2019-02-18 06:30:32 +01:00
|
|
|
r = sysctl_write_ip_property_int(AF_INET6, link->ifname, "use_tempaddr", (int) link->network->ipv6_privacy_extensions);
|
2015-11-13 00:54:56 +01:00
|
|
|
if (r < 0)
|
2015-07-05 07:54:31 +02:00
|
|
|
log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extension for interface: %m");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-12 04:48:06 +02:00
|
|
|
static int link_set_ipv6_accept_ra(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* Make this a NOP if IPv6 is not available */
|
|
|
|
if (!socket_ipv6_is_supported())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return 0;
|
|
|
|
|
2015-11-13 12:32:38 +01:00
|
|
|
if (!link->network)
|
|
|
|
return 0;
|
|
|
|
|
2019-02-18 06:30:32 +01:00
|
|
|
r = sysctl_write_ip_property(AF_INET6, link->ifname, "accept_ra", "0");
|
2015-11-13 00:54:56 +01:00
|
|
|
if (r < 0)
|
2015-11-18 21:32:43 +01:00
|
|
|
log_link_warning_errno(link, r, "Cannot disable kernel IPv6 accept_ra for interface: %m");
|
2015-09-12 04:48:06 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-12 11:01:10 +02:00
|
|
|
static int link_set_ipv6_dad_transmits(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* Make this a NOP if IPv6 is not available */
|
|
|
|
if (!socket_ipv6_is_supported())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return 0;
|
|
|
|
|
2015-11-13 12:32:38 +01:00
|
|
|
if (!link->network)
|
|
|
|
return 0;
|
|
|
|
|
2015-10-12 11:01:10 +02:00
|
|
|
if (link->network->ipv6_dad_transmits < 0)
|
|
|
|
return 0;
|
|
|
|
|
2019-02-18 06:30:32 +01:00
|
|
|
r = sysctl_write_ip_property_int(AF_INET6, link->ifname, "dad_transmits", link->network->ipv6_dad_transmits);
|
2015-11-13 00:54:56 +01:00
|
|
|
if (r < 0)
|
2015-10-12 11:01:10 +02:00
|
|
|
log_link_warning_errno(link, r, "Cannot set IPv6 dad transmits for interface: %m");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-11-10 04:56:38 +01:00
|
|
|
static int link_set_ipv6_hop_limit(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* Make this a NOP if IPv6 is not available */
|
|
|
|
if (!socket_ipv6_is_supported())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return 0;
|
|
|
|
|
2015-11-13 12:32:38 +01:00
|
|
|
if (!link->network)
|
|
|
|
return 0;
|
|
|
|
|
2015-11-10 04:56:38 +01:00
|
|
|
if (link->network->ipv6_hop_limit < 0)
|
|
|
|
return 0;
|
|
|
|
|
2019-02-18 06:30:32 +01:00
|
|
|
r = sysctl_write_ip_property_int(AF_INET6, link->ifname, "hop_limit", link->network->ipv6_hop_limit);
|
2015-11-13 00:54:56 +01:00
|
|
|
if (r < 0)
|
2015-11-10 04:56:38 +01:00
|
|
|
log_link_warning_errno(link, r, "Cannot set IPv6 hop limit for interface: %m");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-04-20 11:38:39 +02:00
|
|
|
static int link_set_ipv6_mtu(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* Make this a NOP if IPv6 is not available */
|
|
|
|
if (!socket_ipv6_is_supported())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (link->network->ipv6_mtu == 0)
|
|
|
|
return 0;
|
|
|
|
|
2019-10-29 15:31:58 +01:00
|
|
|
/* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes
|
|
|
|
* on the interface. Bump up IPv6 MTU bytes to IPV6_MTU_MIN. */
|
|
|
|
if (link->network->ipv6_mtu < IPV6_MIN_MTU) {
|
|
|
|
log_link_notice(link, "Bumping IPv6 MTU to "STRINGIFY(IPV6_MIN_MTU)" byte minimum required");
|
|
|
|
link->network->ipv6_mtu = IPV6_MIN_MTU;
|
|
|
|
}
|
|
|
|
|
2019-02-18 06:30:32 +01:00
|
|
|
r = sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", link->network->ipv6_mtu);
|
2019-10-29 15:31:58 +01:00
|
|
|
if (r < 0) {
|
|
|
|
if (link->mtu < link->network->ipv6_mtu)
|
|
|
|
log_link_warning(link, "Cannot set IPv6 MTU %"PRIu32" higher than device MTU %"PRIu32,
|
|
|
|
link->network->ipv6_mtu, link->mtu);
|
|
|
|
else
|
|
|
|
log_link_warning_errno(link, r, "Cannot set IPv6 MTU for interface: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
link->ipv6_mtu_set = true;
|
2018-04-20 11:38:39 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-06-08 06:48:14 +02:00
|
|
|
static int link_set_ipv4_accept_local(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (link->network->ipv4_accept_local < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
r = sysctl_write_ip_property_boolean(AF_INET, link->ifname, "accept_local", link->network->ipv4_accept_local);
|
|
|
|
if (r < 0)
|
|
|
|
log_link_warning_errno(link, r, "Cannot set IPv4 accept_local flag for interface: %m");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-31 13:33:54 +01:00
|
|
|
static bool link_is_static_address_configured(Link *link, Address *address) {
|
|
|
|
Address *net_address;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(address);
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
LIST_FOREACH(addresses, net_address, link->network->static_addresses)
|
|
|
|
if (address_equal(net_address, address))
|
|
|
|
return true;
|
2020-07-21 18:03:16 +02:00
|
|
|
else if (address->family == AF_INET6 && net_address->family == AF_INET6 &&
|
|
|
|
in_addr_equal(AF_INET6, &address->in_addr, &net_address->in_addr_peer) > 0)
|
|
|
|
return true;
|
2018-10-31 13:33:54 +01:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-04-19 09:53:34 +02:00
|
|
|
static bool link_is_neighbor_configured(Link *link, Neighbor *neighbor) {
|
|
|
|
Neighbor *net_neighbor;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(neighbor);
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
LIST_FOREACH(neighbors, net_neighbor, link->network->neighbors)
|
|
|
|
if (neighbor_equal(net_neighbor, neighbor))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-11-06 13:28:12 +01:00
|
|
|
static bool link_is_static_route_configured(Link *link, Route *route) {
|
|
|
|
Route *net_route;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(route);
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
LIST_FOREACH(routes, net_route, link->network->static_routes)
|
|
|
|
if (route_equal(net_route, route))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-06-03 05:33:13 +02:00
|
|
|
static bool link_address_is_dynamic(Link *link, Address *address) {
|
|
|
|
Route *route;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(address);
|
|
|
|
|
|
|
|
if (address->cinfo.ifa_prefered != CACHE_INFO_INFINITY_LIFE_TIME)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
/* Even when the address is leased from a DHCP server, networkd assign the address
|
|
|
|
* without lifetime when KeepConfiguration=dhcp. So, let's check that we have
|
|
|
|
* corresponding routes with RTPROT_DHCP. */
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(route, link->routes_foreign) {
|
2019-06-03 05:33:13 +02:00
|
|
|
if (route->protocol != RTPROT_DHCP)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (address->family != route->family)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (in_addr_equal(address->family, &address->in_addr, &route->prefsrc))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-01-05 00:41:18 +01:00
|
|
|
static int link_enumerate_ipv6_tentative_addresses(Link *link) {
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
|
|
|
sd_netlink_message *addr;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
|
|
|
assert(link->manager->rtnl);
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_GETADDR, 0, AF_INET6);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_call(link->manager->rtnl, req, 0, &reply);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
for (addr = reply; addr; addr = sd_netlink_message_next(addr)) {
|
|
|
|
unsigned char flags;
|
|
|
|
int ifindex;
|
|
|
|
|
|
|
|
r = sd_rtnl_message_addr_get_ifindex(addr, &ifindex);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: invalid ifindex, ignoring: %m");
|
|
|
|
continue;
|
|
|
|
} else if (link->ifindex != ifindex)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = sd_rtnl_message_addr_get_flags(addr, &flags);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received address message with invalid flags, ignoring: %m");
|
|
|
|
continue;
|
|
|
|
} else if (!(flags & IFA_F_TENTATIVE))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
log_link_debug(link, "Found tentative ipv6 link-local address");
|
|
|
|
(void) manager_rtnl_process_address(link->manager->rtnl, addr, link->manager);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-02 16:52:49 +02:00
|
|
|
static int link_drop_foreign_config(Link *link) {
|
|
|
|
Address *address;
|
2019-04-19 09:53:34 +02:00
|
|
|
Neighbor *neighbor;
|
2015-10-02 16:52:49 +02:00
|
|
|
Route *route;
|
|
|
|
int r;
|
|
|
|
|
2020-01-05 00:41:18 +01:00
|
|
|
/* The kernel doesn't notify us about tentative addresses;
|
|
|
|
* so if ipv6ll is disabled, we need to enumerate them now so we can drop them below */
|
|
|
|
if (!link_ipv6ll_enabled(link)) {
|
|
|
|
r = link_enumerate_ipv6_tentative_addresses(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(address, link->addresses_foreign) {
|
2015-11-18 21:32:43 +01:00
|
|
|
/* we consider IPv6LL addresses to be managed by the kernel */
|
2019-09-15 23:07:38 +02:00
|
|
|
if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1 && link_ipv6ll_enabled(link))
|
2015-10-02 16:52:49 +02:00
|
|
|
continue;
|
|
|
|
|
2019-06-03 05:33:13 +02:00
|
|
|
if (link_address_is_dynamic(link, address)) {
|
2019-09-17 14:29:23 +02:00
|
|
|
if (link->network && FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
|
2019-06-03 05:33:13 +02:00
|
|
|
continue;
|
2019-09-17 14:29:23 +02:00
|
|
|
} else if (link->network && FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
|
2019-06-03 05:33:13 +02:00
|
|
|
continue;
|
|
|
|
|
2018-10-31 13:33:54 +01:00
|
|
|
if (link_is_static_address_configured(link, address)) {
|
|
|
|
r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Failed to add address: %m");
|
|
|
|
} else {
|
2018-11-28 21:22:08 +01:00
|
|
|
r = address_remove(address, link, NULL);
|
2018-10-31 13:33:54 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
2015-10-02 16:52:49 +02:00
|
|
|
}
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(neighbor, link->neighbors_foreign) {
|
2019-04-19 09:53:34 +02:00
|
|
|
if (link_is_neighbor_configured(link, neighbor)) {
|
|
|
|
r = neighbor_add(link, neighbor->family, &neighbor->in_addr, &neighbor->lladdr, neighbor->lladdr_size, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
} else {
|
|
|
|
r = neighbor_remove(neighbor, link, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(route, link->routes_foreign) {
|
2015-11-18 21:32:43 +01:00
|
|
|
/* do not touch routes managed by the kernel */
|
2015-10-02 16:52:49 +02:00
|
|
|
if (route->protocol == RTPROT_KERNEL)
|
|
|
|
continue;
|
|
|
|
|
2019-07-09 17:30:27 +02:00
|
|
|
/* do not touch multicast route added by kernel */
|
|
|
|
/* FIXME: Why the kernel adds this route with protocol RTPROT_BOOT??? We need to investigate that.
|
|
|
|
* https://tools.ietf.org/html/rfc4862#section-5.4 may explain why. */
|
|
|
|
if (route->protocol == RTPROT_BOOT &&
|
|
|
|
route->family == AF_INET6 &&
|
|
|
|
route->dst_prefixlen == 8 &&
|
|
|
|
in_addr_equal(AF_INET6, &route->dst, &(union in_addr_union) { .in6 = {{{ 0xff,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }}} }))
|
|
|
|
continue;
|
|
|
|
|
2019-09-17 14:29:23 +02:00
|
|
|
if (route->protocol == RTPROT_STATIC && link->network &&
|
2019-06-03 05:33:13 +02:00
|
|
|
FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
|
|
|
|
continue;
|
|
|
|
|
2019-09-17 14:29:23 +02:00
|
|
|
if (route->protocol == RTPROT_DHCP && link->network &&
|
2019-06-03 05:33:13 +02:00
|
|
|
FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
|
|
|
|
continue;
|
|
|
|
|
2018-11-06 13:28:12 +01:00
|
|
|
if (link_is_static_route_configured(link, route)) {
|
2019-09-09 17:16:41 +02:00
|
|
|
r = route_add(link, route, NULL);
|
2018-11-06 13:28:12 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
} else {
|
2018-11-28 21:22:42 +01:00
|
|
|
r = route_remove(route, link, NULL);
|
2018-11-06 13:28:12 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
2015-10-02 16:52:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-08 05:36:18 +02:00
|
|
|
static int remove_static_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(link);
|
|
|
|
assert(link->ifname);
|
|
|
|
assert(link->address_remove_messages > 0);
|
|
|
|
|
|
|
|
link->address_remove_messages--;
|
|
|
|
|
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_errno(m);
|
|
|
|
if (r < 0 && r != -EADDRNOTAVAIL)
|
|
|
|
log_link_message_warning_errno(link, m, r, "Could not drop address");
|
|
|
|
else if (r >= 0)
|
|
|
|
(void) manager_rtnl_process_address(rtnl, m, link->manager);
|
|
|
|
|
|
|
|
if (link->address_remove_messages == 0 && link->request_static_addresses) {
|
|
|
|
link_set_state(link, LINK_STATE_CONFIGURING);
|
|
|
|
r = link_request_set_addresses(link);
|
|
|
|
if (r < 0)
|
|
|
|
link_enter_failed(link);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-08-04 15:56:39 +02:00
|
|
|
static int link_drop_config(Link *link) {
|
2017-06-06 16:43:24 +02:00
|
|
|
Address *address, *pool_address;
|
2019-04-19 09:53:34 +02:00
|
|
|
Neighbor *neighbor;
|
2016-08-04 15:56:39 +02:00
|
|
|
Route *route;
|
|
|
|
int r;
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(address, link->addresses) {
|
2016-08-04 15:56:39 +02:00
|
|
|
/* we consider IPv6LL addresses to be managed by the kernel */
|
2019-09-15 23:07:38 +02:00
|
|
|
if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1 && link_ipv6ll_enabled(link))
|
2016-08-04 15:56:39 +02:00
|
|
|
continue;
|
|
|
|
|
2020-08-08 05:36:18 +02:00
|
|
|
r = address_remove(address, link, remove_static_address_handler);
|
2016-08-04 15:56:39 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2017-06-06 16:43:24 +02:00
|
|
|
|
2020-08-08 05:36:18 +02:00
|
|
|
link->address_remove_messages++;
|
|
|
|
|
2017-06-06 16:43:24 +02:00
|
|
|
/* If this address came from an address pool, clean up the pool */
|
2020-08-08 05:31:59 +02:00
|
|
|
LIST_FOREACH(addresses, pool_address, link->pool_addresses)
|
2017-06-06 16:43:24 +02:00
|
|
|
if (address_equal(address, pool_address)) {
|
|
|
|
LIST_REMOVE(addresses, link->pool_addresses, pool_address);
|
|
|
|
address_free(pool_address);
|
|
|
|
break;
|
|
|
|
}
|
2016-08-04 15:56:39 +02:00
|
|
|
}
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(neighbor, link->neighbors) {
|
2019-04-19 09:53:34 +02:00
|
|
|
r = neighbor_remove(neighbor, link, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(route, link->routes) {
|
2016-08-04 15:56:39 +02:00
|
|
|
/* do not touch routes managed by the kernel */
|
|
|
|
if (route->protocol == RTPROT_KERNEL)
|
|
|
|
continue;
|
|
|
|
|
2018-11-28 21:22:42 +01:00
|
|
|
r = route_remove(route, link, NULL);
|
2016-08-04 15:56:39 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2016-10-25 12:08:43 +02:00
|
|
|
ndisc_flush(link);
|
|
|
|
|
2016-08-04 15:56:39 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-21 16:54:52 +01:00
|
|
|
static int link_configure_ipv4_dad(Link *link) {
|
|
|
|
Address *address;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
|
|
|
|
|
|
|
LIST_FOREACH(addresses, address, link->network->static_addresses)
|
|
|
|
if (address->family == AF_INET &&
|
|
|
|
FLAGS_SET(address->duplicate_address_detection, ADDRESS_FAMILY_IPV4)) {
|
|
|
|
r = configure_ipv4_duplicate_address_detection(link, address);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Failed to configure IPv4ACD: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-02-10 12:53:00 +01:00
|
|
|
static int link_configure_traffic_control(Link *link) {
|
|
|
|
TrafficControl *tc;
|
2013-11-24 23:37:56 +01:00
|
|
|
int r;
|
|
|
|
|
2020-02-10 12:53:00 +01:00
|
|
|
link->tc_configured = false;
|
|
|
|
link->tc_messages = 0;
|
2019-10-29 16:19:34 +01:00
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
ORDERED_HASHMAP_FOREACH(tc, link->network->tc_by_section) {
|
2020-02-10 12:53:00 +01:00
|
|
|
r = traffic_control_configure(link, tc);
|
2019-10-29 16:19:34 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2020-02-10 12:53:00 +01:00
|
|
|
if (link->tc_messages == 0)
|
|
|
|
link->tc_configured = true;
|
2019-10-29 16:19:34 +01:00
|
|
|
else
|
2020-02-10 12:53:00 +01:00
|
|
|
log_link_debug(link, "Configuring traffic control");
|
2019-10-29 16:19:34 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-06-21 13:17:34 +02:00
|
|
|
static int link_configure_sr_iov(Link *link) {
|
|
|
|
SRIOV *sr_iov;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
link->sr_iov_configured = false;
|
|
|
|
link->sr_iov_messages = 0;
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
ORDERED_HASHMAP_FOREACH(sr_iov, link->network->sr_iov_by_section) {
|
2020-06-21 13:17:34 +02:00
|
|
|
r = sr_iov_configure(link, sr_iov);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (link->sr_iov_messages == 0)
|
|
|
|
link->sr_iov_configured = true;
|
|
|
|
else
|
|
|
|
log_link_debug(link, "Configuring SR-IOV");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-10-29 16:19:34 +01:00
|
|
|
static int link_configure(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
2013-12-14 19:09:04 +01:00
|
|
|
assert(link);
|
2014-08-06 15:54:03 +02:00
|
|
|
assert(link->network);
|
2019-04-15 10:34:00 +02:00
|
|
|
assert(link->state == LINK_STATE_INITIALIZED);
|
2014-03-09 14:43:37 +01:00
|
|
|
|
2020-02-10 12:53:00 +01:00
|
|
|
r = link_configure_traffic_control(link);
|
2019-10-29 16:19:34 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-06-21 13:17:34 +02:00
|
|
|
r = link_configure_sr_iov(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-07-25 03:11:45 +02:00
|
|
|
if (link->iftype == ARPHRD_CAN)
|
2018-05-30 11:47:23 +02:00
|
|
|
return link_configure_can(link);
|
2016-09-14 18:15:16 +02:00
|
|
|
|
2019-08-19 12:00:35 +02:00
|
|
|
/* If IPv6 configured that is static IPv6 address and IPv6LL autoconfiguration is enabled
|
|
|
|
* for this interface, then enable IPv6 */
|
2019-08-22 13:26:54 +02:00
|
|
|
(void) link_update_ipv6_sysctl(link);
|
2019-08-19 12:00:35 +02:00
|
|
|
|
2016-04-14 11:56:57 +02:00
|
|
|
r = link_set_proxy_arp(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2017-02-11 00:47:55 +01:00
|
|
|
r = ipv6_proxy_ndp_addresses_configure(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-01-13 20:07:13 +01:00
|
|
|
r = link_set_ipv4_forward(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = link_set_ipv6_forward(link);
|
2015-01-13 13:47:08 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-07-05 07:54:31 +02:00
|
|
|
r = link_set_ipv6_privacy_extensions(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-09-12 04:48:06 +02:00
|
|
|
r = link_set_ipv6_accept_ra(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-10-12 11:01:10 +02:00
|
|
|
r = link_set_ipv6_dad_transmits(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2015-11-10 04:56:38 +01:00
|
|
|
|
|
|
|
r = link_set_ipv6_hop_limit(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2015-10-12 11:01:10 +02:00
|
|
|
|
2020-06-08 06:48:14 +02:00
|
|
|
r = link_set_ipv4_accept_local(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-08-04 16:00:58 +02:00
|
|
|
r = link_set_flags(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-04-07 14:36:55 +02:00
|
|
|
r = link_set_group(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-05-22 07:49:46 +02:00
|
|
|
if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) {
|
2014-08-06 15:54:03 +02:00
|
|
|
r = ipv4ll_configure(link);
|
2014-03-20 19:57:19 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-09-04 20:54:08 +02:00
|
|
|
if (link_dhcp4_enabled(link)) {
|
2017-11-24 21:03:05 +01:00
|
|
|
r = dhcp4_set_promote_secondaries(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2014-08-08 12:12:17 +02:00
|
|
|
r = dhcp4_configure(link);
|
2014-03-20 19:57:19 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-09-04 20:54:08 +02:00
|
|
|
if (link_dhcp4_server_enabled(link)) {
|
2014-03-05 08:13:30 +01:00
|
|
|
r = sd_dhcp_server_new(&link->dhcp_server, link->ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_dhcp_server_attach_event(link->dhcp_server, NULL, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2015-11-16 16:47:18 +01:00
|
|
|
if (link_dhcp6_enabled(link) ||
|
|
|
|
link_ipv6_accept_ra_enabled(link)) {
|
networkd: IPv6 router discovery - follow IPv6AcceptRouterAdvertisemnt=
The previous behavior:
When DHCPv6 was enabled, router discover was performed first, and then DHCPv6 was
enabled only if the relevant flags were passed in the Router Advertisement message.
Moreover, router discovery was performed even if AcceptRouterAdvertisements=false,
moreover, even if router advertisements were accepted (by the kernel) the flags
indicating that DHCPv6 should be performed were ignored.
New behavior:
If RouterAdvertisements are accepted, and either no routers are found, or an
advertisement is received indicating DHCPv6 should be performed, the DHCPv6
client is started. Moreover, the DHCP option now truly enables the DHCPv6
client regardless of router discovery (though it will probably not be
very useful to get a lease withotu any routes, this seems the more consistent
approach).
The recommended default setting should be to set DHCP=ipv4 and to leave
IPv6AcceptRouterAdvertisements unset.
2015-10-18 18:25:58 +02:00
|
|
|
r = dhcp6_configure(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (link_ipv6_accept_ra_enabled(link)) {
|
2015-10-16 17:34:58 +02:00
|
|
|
r = ndisc_configure(link);
|
2014-06-19 14:40:01 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2017-05-12 15:48:33 +02:00
|
|
|
if (link_radv_enabled(link)) {
|
|
|
|
r = radv_configure(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2016-02-21 14:14:08 +01:00
|
|
|
if (link_lldp_rx_enabled(link)) {
|
2019-05-09 07:21:55 +02:00
|
|
|
r = link_lldp_rx_configure(link);
|
2016-02-20 22:35:02 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-11-23 05:26:14 +01:00
|
|
|
}
|
|
|
|
|
2019-05-16 04:42:46 +02:00
|
|
|
r = link_configure_mtu(link);
|
2019-02-27 01:57:16 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2018-06-14 19:19:25 +02:00
|
|
|
|
2019-05-09 07:39:46 +02:00
|
|
|
r = link_configure_addrgen_mode(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2019-02-11 13:28:23 +01:00
|
|
|
|
2019-11-21 16:54:52 +01:00
|
|
|
r = link_configure_ipv4_dad(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-12-19 19:14:42 +01:00
|
|
|
return link_configure_continue(link);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The configuration continues in this separate function, instead of
|
|
|
|
* including this in the above link_configure() function, for two
|
|
|
|
* reasons:
|
|
|
|
* 1) some devices reset the link when the mtu is set, which caused
|
|
|
|
* an infinite loop here in networkd; see:
|
|
|
|
* https://github.com/systemd/systemd/issues/6593
|
|
|
|
* https://github.com/systemd/systemd/issues/9831
|
|
|
|
* 2) if ipv6ll is disabled, then bringing the interface up must be
|
|
|
|
* delayed until after we get confirmation from the kernel that
|
|
|
|
* the addr_gen_mode parameter has been set (via netlink), see:
|
|
|
|
* https://github.com/systemd/systemd/issues/13882
|
|
|
|
*/
|
|
|
|
static int link_configure_continue(Link *link) {
|
2018-08-13 09:12:08 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
2019-04-15 10:34:00 +02:00
|
|
|
assert(link->state == LINK_STATE_INITIALIZED);
|
2018-08-13 09:12:08 +02:00
|
|
|
|
2019-12-19 19:17:45 +01:00
|
|
|
if (link->setting_mtu || link->setting_genmode)
|
2018-08-13 09:12:08 +02:00
|
|
|
return 0;
|
|
|
|
|
network: drop foreign config after addr_gen_mode has been set
Interfaces may come up at any time, even during our initialization of
them, for various reasons; e.g. the kernel will raise VLAN when its
parent is raised; or we will raise an interface if configured with
BindCarrier and its associated interfaces come up.
When LinkLocalAddressing has been disabled for ipv6, we disable
addr_gen_mode in the kernel, so it will not automatically create a
ipv6ll address when the interface is raised. However, we currently
drop all foreign addresses before disabling addr_gen_mode.
If the link has been up for a long time, then its kernel-created ipv6ll
address will be correctly dropped. If the link is down, and stays
down until we raise it after finishing configuration, the addr_gen_mode
setting will be disabled when the interface is raised and the kernel
will not create any ipv6ll address.
However, if the interface is raised after dropping foreign config,
but before we have disabled addr_gen_mode, the kernel will create a
ipv6ll tentative address that will eventually finish DAD and become a
working ipv6ll address, even though we have been configured to disable
ipv6ll.
Moving our call to drop foreign addresses to after we have successfully
set addr_gen_mode closes this window; after we disable addr_gen_mode,
we can safely remove foreign ipv6ll addresses (including tentative ones)
and be sure that the kernel will not create any more.
Fixes: #13882.
2020-01-06 22:35:28 +01:00
|
|
|
/* Drop foreign config, but ignore loopback or critical devices.
|
|
|
|
* We do not want to remove loopback address or addresses used for root NFS. */
|
|
|
|
if (!(link->flags & IFF_LOOPBACK) &&
|
|
|
|
link->network->keep_configuration != KEEP_CONFIGURATION_YES) {
|
|
|
|
r = link_drop_foreign_config(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2019-10-29 15:31:58 +01:00
|
|
|
/* The kernel resets ipv6 mtu after changing device mtu;
|
|
|
|
* we must set this here, after we've set device mtu */
|
|
|
|
r = link_set_ipv6_mtu(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2017-09-06 16:57:04 +02:00
|
|
|
if (link_has_carrier(link) || link->network->configure_without_carrier) {
|
2014-04-22 19:40:05 +02:00
|
|
|
r = link_acquire_conf(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-04-22 21:45:17 +02:00
|
|
|
}
|
2014-04-22 19:40:05 +02:00
|
|
|
|
2014-07-05 14:53:54 +02:00
|
|
|
return link_enter_join_netdev(link);
|
2014-04-15 14:21:44 +02:00
|
|
|
}
|
|
|
|
|
2018-07-02 20:19:15 +02:00
|
|
|
static int duid_set_uuid(DUID *duid, sd_id128_t uuid) {
|
|
|
|
assert(duid);
|
|
|
|
|
|
|
|
if (duid->raw_data_len > 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (duid->type != DUID_TYPE_UUID)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
memcpy(&duid->raw_data, &uuid, sizeof(sd_id128_t));
|
|
|
|
duid->raw_data_len = sizeof(sd_id128_t);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
|
|
|
|
Manager *manager = userdata;
|
|
|
|
const sd_bus_error *e;
|
|
|
|
const void *a;
|
|
|
|
size_t sz;
|
|
|
|
DUID *duid;
|
|
|
|
Link *link;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(manager);
|
|
|
|
|
|
|
|
e = sd_bus_message_get_error(m);
|
|
|
|
if (e) {
|
|
|
|
log_error_errno(sd_bus_error_get_errno(e),
|
2018-08-23 11:32:55 +02:00
|
|
|
"Could not get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %s",
|
2018-07-02 20:19:15 +02:00
|
|
|
e->message);
|
|
|
|
goto configure;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_bus_message_read_array(m, 'y', &a, &sz);
|
|
|
|
if (r < 0)
|
|
|
|
goto configure;
|
|
|
|
|
|
|
|
if (sz != sizeof(sd_id128_t)) {
|
2018-08-23 11:32:55 +02:00
|
|
|
log_error("Invalid product UUID. Falling back to use machine-app-specific ID as DUID-UUID.");
|
2018-07-02 20:19:15 +02:00
|
|
|
goto configure;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(&manager->product_uuid, a, sz);
|
|
|
|
while ((duid = set_steal_first(manager->duids_requesting_uuid)))
|
|
|
|
(void) duid_set_uuid(duid, manager->product_uuid);
|
|
|
|
|
|
|
|
manager->duids_requesting_uuid = set_free(manager->duids_requesting_uuid);
|
|
|
|
|
|
|
|
configure:
|
|
|
|
while ((link = set_steal_first(manager->links_requesting_uuid))) {
|
2019-08-11 02:11:20 +02:00
|
|
|
link_unref(link);
|
|
|
|
|
2018-07-02 20:19:15 +02:00
|
|
|
r = link_configure(link);
|
|
|
|
if (r < 0)
|
2019-07-14 17:35:49 +02:00
|
|
|
link_enter_failed(link);
|
2018-07-02 20:19:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
manager->links_requesting_uuid = set_free(manager->links_requesting_uuid);
|
|
|
|
|
|
|
|
/* To avoid calling GetProductUUID() bus method so frequently, set the flag below
|
|
|
|
* even if the method fails. */
|
|
|
|
manager->has_product_uuid = true;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool link_requires_uuid(Link *link) {
|
|
|
|
const DUID *duid;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
|
|
|
assert(link->network);
|
|
|
|
|
|
|
|
duid = link_get_duid(link);
|
|
|
|
if (duid->type != DUID_TYPE_UUID || duid->raw_data_len != 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (link_dhcp4_enabled(link) && IN_SET(link->network->dhcp_client_identifier, DHCP_CLIENT_ID_DUID, DHCP_CLIENT_ID_DUID_ONLY))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (link_dhcp6_enabled(link) || link_ipv6_accept_ra_enabled(link))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_configure_duid(Link *link) {
|
|
|
|
Manager *m;
|
|
|
|
DUID *duid;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
|
|
|
assert(link->network);
|
|
|
|
|
|
|
|
m = link->manager;
|
|
|
|
duid = link_get_duid(link);
|
|
|
|
|
|
|
|
if (!link_requires_uuid(link))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (m->has_product_uuid) {
|
|
|
|
(void) duid_set_uuid(duid, m->product_uuid);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m->links_requesting_uuid) {
|
|
|
|
r = manager_request_product_uuid(m, link);
|
|
|
|
if (r < 0) {
|
|
|
|
if (r == -ENOMEM)
|
|
|
|
return r;
|
|
|
|
|
2018-08-23 11:32:55 +02:00
|
|
|
log_link_warning_errno(link, r,
|
|
|
|
"Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m");
|
2018-07-02 20:19:15 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
r = set_put(m->links_requesting_uuid, link);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
2020-06-05 14:24:57 +02:00
|
|
|
if (r > 0)
|
|
|
|
link_ref(link);
|
2018-07-02 20:19:15 +02:00
|
|
|
|
|
|
|
r = set_put(m->duids_requesting_uuid, duid);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-12-15 14:46:19 +01:00
|
|
|
static int link_reconfigure_internal(Link *link, sd_netlink_message *m, bool force) {
|
2019-07-04 06:52:03 +02:00
|
|
|
Network *network;
|
|
|
|
int r;
|
|
|
|
|
2019-12-15 14:46:19 +01:00
|
|
|
if (m) {
|
|
|
|
_cleanup_strv_free_ char **s = NULL;
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_errno(m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_strv(m, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &s);
|
|
|
|
if (r < 0 && r != -ENODATA)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
strv_free_and_replace(link->alternative_names, s);
|
|
|
|
}
|
|
|
|
|
2020-06-03 09:19:29 +02:00
|
|
|
r = network_get(link->manager, link->iftype, link->sd_device,
|
|
|
|
link->ifname, link->alternative_names, link->driver,
|
|
|
|
&link->mac, &link->permanent_mac,
|
|
|
|
link->wlan_iftype, link->ssid, &link->bssid, &network);
|
2019-07-04 06:52:03 +02:00
|
|
|
if (r == -ENOENT) {
|
|
|
|
link_enter_unmanaged(link);
|
|
|
|
return 0;
|
|
|
|
} else if (r == 0 && network->unmanaged) {
|
|
|
|
link_enter_unmanaged(link);
|
|
|
|
return 0;
|
|
|
|
} else if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-10-23 15:32:27 +02:00
|
|
|
if (link->network == network && !force)
|
2019-07-04 06:52:03 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
log_link_info(link, "Re-configuring with %s", network->filename);
|
|
|
|
|
|
|
|
/* Dropping old .network file */
|
|
|
|
r = link_stop_clients(link, false);
|
2019-12-15 14:46:19 +01:00
|
|
|
if (r < 0)
|
2019-07-04 06:52:03 +02:00
|
|
|
return r;
|
|
|
|
|
|
|
|
if (link_dhcp4_server_enabled(link))
|
|
|
|
(void) sd_dhcp_server_stop(link->dhcp_server);
|
|
|
|
|
|
|
|
r = link_drop_config(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-12-05 11:54:29 +01:00
|
|
|
if (!IN_SET(link->state, LINK_STATE_UNMANAGED, LINK_STATE_PENDING, LINK_STATE_INITIALIZED)) {
|
2019-07-04 06:52:03 +02:00
|
|
|
log_link_debug(link, "State is %s, dropping config", link_state_to_string(link->state));
|
|
|
|
r = link_drop_foreign_config(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
link_free_carrier_maps(link);
|
|
|
|
link_free_engines(link);
|
|
|
|
link->network = network_unref(link->network);
|
|
|
|
|
|
|
|
/* Then, apply new .network file */
|
|
|
|
r = network_apply(network, link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = link_new_carrier_maps(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
link_set_state(link, LINK_STATE_INITIALIZED);
|
2020-01-20 12:38:21 +01:00
|
|
|
link_dirty(link);
|
2019-07-04 06:52:03 +02:00
|
|
|
|
|
|
|
/* link_configure_duid() returns 0 if it requests product UUID. In that case,
|
|
|
|
* link_configure() is called later asynchronously. */
|
|
|
|
r = link_configure_duid(link);
|
|
|
|
if (r <= 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = link_configure(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-12-15 14:46:19 +01:00
|
|
|
static int link_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = link_reconfigure_internal(link, m, false);
|
|
|
|
if (r < 0)
|
|
|
|
link_enter_failed(link);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_force_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = link_reconfigure_internal(link, m, true);
|
|
|
|
if (r < 0)
|
|
|
|
link_enter_failed(link);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int link_reconfigure(Link *link, bool force) {
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
|
|
|
int r;
|
|
|
|
|
2020-01-22 08:06:50 +01:00
|
|
|
if (IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_LINGER))
|
|
|
|
return 0;
|
|
|
|
|
2019-12-15 14:46:19 +01:00
|
|
|
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_GETLINK,
|
|
|
|
link->ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = netlink_call_async(link->manager->rtnl, NULL, req,
|
|
|
|
force ? link_force_reconfigure_handler : link_reconfigure_handler,
|
|
|
|
link_netlink_destroy_callback, link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
link_ref(link);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-10 07:34:00 +02:00
|
|
|
static int link_initialized_and_synced(Link *link) {
|
2014-04-15 14:21:44 +02:00
|
|
|
Network *network;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->ifname);
|
|
|
|
assert(link->manager);
|
|
|
|
|
2019-04-15 10:34:00 +02:00
|
|
|
/* We may get called either from the asynchronous netlink callback,
|
|
|
|
* or directly for link_add() if running in a container. See link_add(). */
|
|
|
|
if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED))
|
2019-04-25 10:41:59 +02:00
|
|
|
return 0;
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Link state is up-to-date");
|
2019-04-15 10:34:00 +02:00
|
|
|
link_set_state(link, LINK_STATE_INITIALIZED);
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2015-02-17 13:06:57 +01:00
|
|
|
r = link_new_bound_by_list(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = link_handle_bound_by_list(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-10-01 21:14:06 +02:00
|
|
|
if (!link->network) {
|
2019-07-24 08:16:26 +02:00
|
|
|
r = wifi_get_info(link);
|
2019-07-24 07:46:55 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-06-03 09:19:29 +02:00
|
|
|
r = network_get(link->manager, link->iftype, link->sd_device,
|
|
|
|
link->ifname, link->alternative_names, link->driver,
|
|
|
|
&link->mac, &link->permanent_mac,
|
|
|
|
link->wlan_iftype, link->ssid, &link->bssid, &network);
|
2015-10-01 21:14:06 +02:00
|
|
|
if (r == -ENOENT) {
|
|
|
|
link_enter_unmanaged(link);
|
2019-04-25 10:41:59 +02:00
|
|
|
return 0;
|
2016-09-28 00:18:14 +02:00
|
|
|
} else if (r == 0 && network->unmanaged) {
|
|
|
|
link_enter_unmanaged(link);
|
|
|
|
return 0;
|
2015-10-01 21:14:06 +02:00
|
|
|
} else if (r < 0)
|
|
|
|
return r;
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2015-10-01 21:14:06 +02:00
|
|
|
if (link->flags & IFF_LOOPBACK) {
|
|
|
|
if (network->link_local != ADDRESS_FAMILY_NO)
|
|
|
|
log_link_debug(link, "Ignoring link-local autoconfiguration for loopback link");
|
2014-09-04 20:54:08 +02:00
|
|
|
|
2015-10-01 21:14:06 +02:00
|
|
|
if (network->dhcp != ADDRESS_FAMILY_NO)
|
|
|
|
log_link_debug(link, "Ignoring DHCP clients for loopback link");
|
2014-09-04 20:54:08 +02:00
|
|
|
|
2015-10-01 21:14:06 +02:00
|
|
|
if (network->dhcp_server)
|
|
|
|
log_link_debug(link, "Ignoring DHCP server for loopback link");
|
|
|
|
}
|
2014-09-04 13:40:24 +02:00
|
|
|
|
2016-09-28 12:32:31 +02:00
|
|
|
r = network_apply(network, link);
|
2015-10-01 21:14:06 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2015-02-17 13:06:57 +01:00
|
|
|
r = link_new_bound_to_list(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-07-02 20:19:15 +02:00
|
|
|
/* link_configure_duid() returns 0 if it requests product UUID. In that case,
|
|
|
|
* link_configure() is called later asynchronously. */
|
|
|
|
r = link_configure_duid(link);
|
|
|
|
if (r <= 0)
|
|
|
|
return r;
|
|
|
|
|
2014-03-09 14:43:37 +01:00
|
|
|
r = link_configure(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-04-25 10:41:59 +02:00
|
|
|
return 0;
|
2014-04-15 14:21:44 +02:00
|
|
|
}
|
|
|
|
|
2018-11-28 21:06:52 +01:00
|
|
|
static int link_initialized_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
2019-12-15 14:46:19 +01:00
|
|
|
_cleanup_strv_free_ char **s = NULL;
|
2019-07-14 17:35:49 +02:00
|
|
|
int r;
|
|
|
|
|
2019-12-15 14:46:19 +01:00
|
|
|
r = sd_netlink_message_get_errno(m);
|
|
|
|
if (r < 0) {
|
2019-12-23 15:41:09 +01:00
|
|
|
log_link_warning_errno(link, r, "Failed to wait for the interface to be initialized: %m");
|
2019-12-15 14:46:19 +01:00
|
|
|
link_enter_failed(link);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_strv(m, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &s);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
link_enter_failed(link);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
strv_free_and_replace(link->alternative_names, s);
|
|
|
|
|
2019-07-14 17:35:49 +02:00
|
|
|
r = link_initialized_and_synced(link);
|
|
|
|
if (r < 0)
|
|
|
|
link_enter_failed(link);
|
2018-10-10 07:34:00 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-08-22 07:30:49 +02:00
|
|
|
int link_initialized(Link *link, sd_device *device) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
2014-06-14 18:52:46 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
|
|
|
assert(link->manager->rtnl);
|
|
|
|
assert(device);
|
|
|
|
|
2014-08-13 15:34:27 +02:00
|
|
|
if (link->state != LINK_STATE_PENDING)
|
2014-06-14 18:52:46 +02:00
|
|
|
return 0;
|
|
|
|
|
2018-08-22 07:30:49 +02:00
|
|
|
if (link->sd_device)
|
2014-07-13 01:11:52 +02:00
|
|
|
return 0;
|
|
|
|
|
2014-11-27 20:20:23 +01:00
|
|
|
log_link_debug(link, "udev initialized link");
|
2019-04-15 10:34:00 +02:00
|
|
|
link_set_state(link, LINK_STATE_INITIALIZED);
|
2014-06-14 18:52:46 +02:00
|
|
|
|
2018-08-22 07:30:49 +02:00
|
|
|
link->sd_device = sd_device_ref(device);
|
2014-06-14 18:52:46 +02:00
|
|
|
|
2014-08-08 12:12:17 +02:00
|
|
|
/* udev has initialized the link, but we don't know if we have yet
|
|
|
|
* processed the NEWLINK messages with the latest state. Do a GETLINK,
|
|
|
|
* when it returns we know that the pending NEWLINKs have already been
|
|
|
|
* processed and that we are up-to-date */
|
2014-06-14 18:52:46 +02:00
|
|
|
|
2014-08-08 12:12:17 +02:00
|
|
|
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_GETLINK,
|
|
|
|
link->ifindex);
|
2014-06-14 18:52:46 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-11-28 21:06:52 +01:00
|
|
|
r = netlink_call_async(link->manager->rtnl, NULL, req, link_initialized_handler,
|
|
|
|
link_netlink_destroy_callback, link);
|
2014-06-14 18:52:46 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2014-07-01 10:09:52 +02:00
|
|
|
link_ref(link);
|
|
|
|
|
2014-06-14 18:52:46 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-01 21:14:06 +02:00
|
|
|
static int link_load(Link *link) {
|
2015-10-01 22:29:50 +02:00
|
|
|
_cleanup_free_ char *network_file = NULL,
|
|
|
|
*addresses = NULL,
|
2015-10-25 14:45:53 +01:00
|
|
|
*routes = NULL,
|
2015-10-01 22:29:50 +02:00
|
|
|
*dhcp4_address = NULL,
|
|
|
|
*ipv4ll_address = NULL;
|
|
|
|
union in_addr_union address;
|
2015-10-01 21:14:06 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
2018-11-12 14:04:47 +01:00
|
|
|
r = parse_env_file(NULL, link->state_file,
|
2015-10-01 21:14:06 +02:00
|
|
|
"NETWORK_FILE", &network_file,
|
|
|
|
"ADDRESSES", &addresses,
|
2015-10-25 14:45:53 +01:00
|
|
|
"ROUTES", &routes,
|
2015-10-01 22:29:50 +02:00
|
|
|
"DHCP4_ADDRESS", &dhcp4_address,
|
2018-11-12 14:18:03 +01:00
|
|
|
"IPV4LL_ADDRESS", &ipv4ll_address);
|
2015-10-01 21:14:06 +02:00
|
|
|
if (r < 0 && r != -ENOENT)
|
|
|
|
return log_link_error_errno(link, r, "Failed to read %s: %m", link->state_file);
|
|
|
|
|
|
|
|
if (network_file) {
|
|
|
|
Network *network;
|
|
|
|
char *suffix;
|
|
|
|
|
|
|
|
/* drop suffix */
|
|
|
|
suffix = strrchr(network_file, '.');
|
|
|
|
if (!suffix) {
|
|
|
|
log_link_debug(link, "Failed to get network name from %s", network_file);
|
|
|
|
goto network_file_fail;
|
|
|
|
}
|
|
|
|
*suffix = '\0';
|
|
|
|
|
|
|
|
r = network_get_by_name(link->manager, basename(network_file), &network);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_debug_errno(link, r, "Failed to get network %s: %m", basename(network_file));
|
|
|
|
goto network_file_fail;
|
|
|
|
}
|
|
|
|
|
2016-09-28 12:32:31 +02:00
|
|
|
r = network_apply(network, link);
|
2015-10-01 21:14:06 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Failed to apply network %s: %m", basename(network_file));
|
|
|
|
}
|
|
|
|
|
|
|
|
network_file_fail:
|
|
|
|
|
2020-07-06 16:21:34 +02:00
|
|
|
for (const char *p = addresses; p; ) {
|
|
|
|
_cleanup_free_ char *address_str = NULL;
|
|
|
|
char *prefixlen_str;
|
|
|
|
int family;
|
|
|
|
unsigned char prefixlen;
|
2015-10-01 21:14:06 +02:00
|
|
|
|
2020-07-06 16:21:34 +02:00
|
|
|
r = extract_first_word(&p, &address_str, NULL, 0);
|
|
|
|
if (r < 0)
|
|
|
|
log_link_warning_errno(link, r, "failed to parse ADDRESSES: %m");
|
|
|
|
if (r <= 0)
|
|
|
|
break;
|
2015-10-01 21:14:06 +02:00
|
|
|
|
2020-07-06 16:21:34 +02:00
|
|
|
prefixlen_str = strchr(address_str, '/');
|
|
|
|
if (!prefixlen_str) {
|
|
|
|
log_link_debug(link, "Failed to parse address and prefix length %s", address_str);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
*prefixlen_str++ = '\0';
|
2015-10-01 21:14:06 +02:00
|
|
|
|
2020-07-06 16:21:34 +02:00
|
|
|
r = sscanf(prefixlen_str, "%hhu", &prefixlen);
|
|
|
|
if (r != 1) {
|
|
|
|
log_link_error(link, "Failed to parse prefixlen %s", prefixlen_str);
|
|
|
|
continue;
|
|
|
|
}
|
2015-10-01 21:14:06 +02:00
|
|
|
|
2020-07-06 16:21:34 +02:00
|
|
|
r = in_addr_from_string_auto(address_str, &family, &address);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_debug_errno(link, r, "Failed to parse address %s: %m", address_str);
|
|
|
|
continue;
|
2015-10-01 21:14:06 +02:00
|
|
|
}
|
|
|
|
|
2020-07-06 16:21:34 +02:00
|
|
|
r = address_add(link, family, &address, prefixlen, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Failed to add address: %m");
|
|
|
|
}
|
2015-11-22 18:37:58 +01:00
|
|
|
|
2020-07-06 16:21:34 +02:00
|
|
|
for (const char *p = routes; p; ) {
|
|
|
|
_cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
|
|
|
|
_cleanup_(route_freep) Route *tmp = NULL;
|
|
|
|
_cleanup_free_ char *route_str = NULL;
|
|
|
|
char *prefixlen_str;
|
|
|
|
Route *route;
|
2015-10-25 14:45:53 +01:00
|
|
|
|
2020-07-06 16:21:34 +02:00
|
|
|
r = extract_first_word(&p, &route_str, NULL, 0);
|
|
|
|
if (r < 0)
|
|
|
|
log_link_debug_errno(link, r, "failed to parse ROUTES: %m");
|
|
|
|
if (r <= 0)
|
|
|
|
break;
|
2015-10-27 17:37:42 +01:00
|
|
|
|
2020-07-06 16:21:34 +02:00
|
|
|
prefixlen_str = strchr(route_str, '/');
|
|
|
|
if (!prefixlen_str) {
|
|
|
|
log_link_debug(link, "Failed to parse route %s", route_str);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
*prefixlen_str++ = '\0';
|
2015-10-25 14:45:53 +01:00
|
|
|
|
2020-07-06 16:21:34 +02:00
|
|
|
r = route_new(&tmp);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
2015-10-25 14:45:53 +01:00
|
|
|
|
2020-07-06 16:21:34 +02:00
|
|
|
r = sscanf(prefixlen_str,
|
|
|
|
"%hhu/%hhu/%"SCNu32"/%"PRIu32"/"USEC_FMT,
|
|
|
|
&tmp->dst_prefixlen,
|
|
|
|
&tmp->tos,
|
|
|
|
&tmp->priority,
|
|
|
|
&tmp->table,
|
|
|
|
&tmp->lifetime);
|
|
|
|
if (r != 5) {
|
|
|
|
log_link_debug(link,
|
|
|
|
"Failed to parse destination prefix length, tos, priority, table or expiration %s",
|
|
|
|
prefixlen_str);
|
|
|
|
continue;
|
|
|
|
}
|
2019-09-09 17:16:41 +02:00
|
|
|
|
2020-07-06 16:21:34 +02:00
|
|
|
r = in_addr_from_string_auto(route_str, &tmp->family, &tmp->dst);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_debug_errno(link, r, "Failed to parse route destination %s: %m", route_str);
|
|
|
|
continue;
|
|
|
|
}
|
2015-10-25 14:45:53 +01:00
|
|
|
|
2020-07-06 16:21:34 +02:00
|
|
|
r = route_add(link, tmp, &route);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Failed to add route: %m");
|
2015-10-25 14:45:53 +01:00
|
|
|
|
2020-07-06 16:21:34 +02:00
|
|
|
if (route->lifetime != USEC_INFINITY && !kernel_route_expiration_supported()) {
|
|
|
|
r = sd_event_add_time(link->manager->event, &expire,
|
|
|
|
clock_boottime_or_monotonic(),
|
|
|
|
route->lifetime, 0, route_expire_handler, route);
|
2015-10-25 14:45:53 +01:00
|
|
|
if (r < 0)
|
2020-07-06 16:21:34 +02:00
|
|
|
log_link_warning_errno(link, r, "Could not arm route expiration handler: %m");
|
2015-10-25 14:45:53 +01:00
|
|
|
}
|
2020-07-06 16:21:34 +02:00
|
|
|
|
|
|
|
sd_event_source_unref(route->expire);
|
|
|
|
route->expire = TAKE_PTR(expire);
|
2015-10-25 14:45:53 +01:00
|
|
|
}
|
|
|
|
|
2015-10-01 22:29:50 +02:00
|
|
|
if (dhcp4_address) {
|
|
|
|
r = in_addr_from_string(AF_INET, dhcp4_address, &address);
|
|
|
|
if (r < 0) {
|
2016-08-21 19:15:26 +02:00
|
|
|
log_link_debug_errno(link, r, "Failed to parse DHCPv4 address %s: %m", dhcp4_address);
|
2015-10-01 22:29:50 +02:00
|
|
|
goto dhcp4_address_fail;
|
|
|
|
}
|
|
|
|
|
2018-04-17 16:55:04 +02:00
|
|
|
r = sd_dhcp_client_new(&link->dhcp_client, link->network ? link->network->dhcp_anonymize : 0);
|
2015-10-01 22:29:50 +02:00
|
|
|
if (r < 0)
|
2016-08-21 19:15:26 +02:00
|
|
|
return log_link_error_errno(link, r, "Failed to create DHCPv4 client: %m");
|
2015-10-01 22:29:50 +02:00
|
|
|
|
2020-03-23 22:34:17 +01:00
|
|
|
r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Failed to attach DHCPv4 event: %m");
|
|
|
|
|
2015-10-01 22:29:50 +02:00
|
|
|
r = sd_dhcp_client_set_request_address(link->dhcp_client, &address.in);
|
|
|
|
if (r < 0)
|
2016-08-21 19:15:26 +02:00
|
|
|
return log_link_error_errno(link, r, "Failed to set initial DHCPv4 address %s: %m", dhcp4_address);
|
2015-10-01 22:29:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
dhcp4_address_fail:
|
|
|
|
|
|
|
|
if (ipv4ll_address) {
|
|
|
|
r = in_addr_from_string(AF_INET, ipv4ll_address, &address);
|
|
|
|
if (r < 0) {
|
2016-08-21 19:15:26 +02:00
|
|
|
log_link_debug_errno(link, r, "Failed to parse IPv4LL address %s: %m", ipv4ll_address);
|
2015-10-01 22:29:50 +02:00
|
|
|
goto ipv4ll_address_fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_ipv4ll_new(&link->ipv4ll);
|
|
|
|
if (r < 0)
|
2016-08-21 19:15:26 +02:00
|
|
|
return log_link_error_errno(link, r, "Failed to create IPv4LL client: %m");
|
2015-10-01 22:29:50 +02:00
|
|
|
|
2020-03-23 22:34:17 +01:00
|
|
|
r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Failed to attach IPv4LL event: %m");
|
|
|
|
|
2015-10-01 22:29:50 +02:00
|
|
|
r = sd_ipv4ll_set_address(link->ipv4ll, &address.in);
|
|
|
|
if (r < 0)
|
2016-08-21 19:15:26 +02:00
|
|
|
return log_link_error_errno(link, r, "Failed to set initial IPv4LL address %s: %m", ipv4ll_address);
|
2015-10-01 22:29:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ipv4ll_address_fail:
|
|
|
|
|
2015-10-01 21:14:06 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
|
2018-08-22 07:30:49 +02:00
|
|
|
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
|
2014-04-15 14:21:44 +02:00
|
|
|
char ifindex_str[2 + DECIMAL_STR_MAX(int)];
|
2018-08-22 07:30:49 +02:00
|
|
|
Link *link;
|
2018-10-29 09:32:21 +01:00
|
|
|
int r;
|
2014-04-15 14:21:44 +02:00
|
|
|
|
|
|
|
assert(m);
|
2014-05-11 13:58:18 +02:00
|
|
|
assert(m->rtnl);
|
2014-04-15 14:21:44 +02:00
|
|
|
assert(message);
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
r = link_new(m, message, ret);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
link = *ret;
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Link %d added", link->ifindex);
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2015-10-01 21:14:06 +02:00
|
|
|
r = link_load(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-12-04 11:12:36 +01:00
|
|
|
if (path_is_read_only_fs("/sys") <= 0) {
|
|
|
|
/* udev should be around */
|
2014-07-28 11:39:37 +02:00
|
|
|
sprintf(ifindex_str, "n%d", link->ifindex);
|
2018-08-22 07:30:49 +02:00
|
|
|
r = sd_device_new_from_device_id(&device, ifindex_str);
|
|
|
|
if (r < 0) {
|
2019-09-17 14:34:06 +02:00
|
|
|
log_link_warning_errno(link, r, "Could not find device, waiting for device initialization: %m");
|
|
|
|
return 0;
|
2015-10-09 17:21:15 +02:00
|
|
|
}
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2018-10-29 09:32:21 +01:00
|
|
|
r = sd_device_get_is_initialized(device);
|
2018-08-22 07:30:49 +02:00
|
|
|
if (r < 0) {
|
2019-12-04 11:12:36 +01:00
|
|
|
log_link_warning_errno(link, r, "Could not determine whether the device is initialized: %m");
|
2018-08-22 07:30:49 +02:00
|
|
|
goto failed;
|
|
|
|
}
|
2018-10-29 09:32:21 +01:00
|
|
|
if (r == 0) {
|
2014-04-15 14:21:44 +02:00
|
|
|
/* not yet ready */
|
2014-11-27 20:20:23 +01:00
|
|
|
log_link_debug(link, "link pending udev initialization...");
|
2014-04-15 14:21:44 +02:00
|
|
|
return 0;
|
2014-05-16 14:47:43 +02:00
|
|
|
}
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2019-03-04 04:19:05 +01:00
|
|
|
r = device_is_renaming(device);
|
|
|
|
if (r < 0) {
|
2019-12-04 11:12:36 +01:00
|
|
|
log_link_warning_errno(link, r, "Failed to determine the device is being renamed: %m");
|
2019-03-04 04:19:05 +01:00
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
if (r > 0) {
|
2019-12-04 11:12:36 +01:00
|
|
|
log_link_debug(link, "Interface is being renamed, pending initialization.");
|
2019-03-04 04:19:05 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-06-14 18:52:46 +02:00
|
|
|
r = link_initialized(link, device);
|
|
|
|
if (r < 0)
|
2015-10-09 17:21:15 +02:00
|
|
|
goto failed;
|
2014-06-14 18:52:46 +02:00
|
|
|
} else {
|
2018-10-10 07:34:00 +02:00
|
|
|
r = link_initialized_and_synced(link);
|
2014-06-14 18:52:46 +02:00
|
|
|
if (r < 0)
|
2015-10-09 17:21:15 +02:00
|
|
|
goto failed;
|
2014-06-14 18:52:46 +02:00
|
|
|
}
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2014-03-09 14:43:37 +01:00
|
|
|
return 0;
|
2015-10-09 17:21:15 +02:00
|
|
|
failed:
|
|
|
|
link_enter_failed(link);
|
|
|
|
return r;
|
2014-03-09 14:43:37 +01:00
|
|
|
}
|
|
|
|
|
2015-11-16 17:43:08 +01:00
|
|
|
int link_ipv6ll_gained(Link *link, const struct in6_addr *address) {
|
2015-11-10 21:30:59 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
log_link_info(link, "Gained IPv6LL");
|
|
|
|
|
2015-11-16 17:43:08 +01:00
|
|
|
link->ipv6ll_address = *address;
|
2015-11-10 21:30:59 +01:00
|
|
|
link_check_ready(link);
|
|
|
|
|
2019-05-03 01:13:10 +02:00
|
|
|
if (IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) {
|
2015-11-10 21:30:59 +01:00
|
|
|
r = link_acquire_ipv6_conf(link);
|
|
|
|
if (r < 0) {
|
|
|
|
link_enter_failed(link);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-03 15:44:12 +01:00
|
|
|
static int link_carrier_gained(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
2019-07-24 08:16:26 +02:00
|
|
|
r = wifi_get_info(link);
|
2019-07-24 07:46:55 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r > 0) {
|
2019-12-15 14:46:19 +01:00
|
|
|
r = link_reconfigure_internal(link, NULL, false);
|
|
|
|
if (r < 0) {
|
|
|
|
link_enter_failed(link);
|
2019-07-24 07:46:55 +02:00
|
|
|
return r;
|
2019-12-15 14:46:19 +01:00
|
|
|
}
|
2019-07-24 07:46:55 +02:00
|
|
|
}
|
|
|
|
|
2019-05-03 01:13:10 +02:00
|
|
|
if (IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) {
|
2015-02-03 15:44:12 +01:00
|
|
|
r = link_acquire_conf(link);
|
|
|
|
if (r < 0) {
|
|
|
|
link_enter_failed(link);
|
|
|
|
return r;
|
|
|
|
}
|
2016-04-29 01:03:29 +02:00
|
|
|
|
2019-07-13 17:02:44 +02:00
|
|
|
link_set_state(link, LINK_STATE_CONFIGURING);
|
2018-12-01 00:36:33 +01:00
|
|
|
r = link_request_set_addresses(link);
|
2016-04-29 01:03:29 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2015-02-03 15:44:12 +01:00
|
|
|
}
|
|
|
|
|
2015-02-17 13:06:57 +01:00
|
|
|
r = link_handle_bound_by_list(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-09-15 09:20:36 +02:00
|
|
|
if (!link->bridge_mdb_configured) {
|
|
|
|
r = link_set_bridge_mdb(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (streq_ptr(link->kind, "bridge")) {
|
|
|
|
Link *slave;
|
|
|
|
|
|
|
|
SET_FOREACH(slave, link->slaves) {
|
|
|
|
if (slave->bridge_mdb_configured)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = link_set_bridge_mdb(slave);
|
|
|
|
if (r < 0)
|
|
|
|
link_enter_failed(slave);
|
|
|
|
}
|
|
|
|
}
|
2020-09-09 14:09:29 +02:00
|
|
|
|
2015-02-03 15:44:12 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_carrier_lost(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
2019-02-16 19:57:13 +01:00
|
|
|
if (link->network && link->network->ignore_carrier_loss)
|
2018-06-01 11:34:49 +02:00
|
|
|
return 0;
|
|
|
|
|
2017-11-28 17:24:52 +01:00
|
|
|
/* Some devices reset itself while setting the MTU. This causes the DHCP client fall into a loop.
|
2018-08-13 09:12:08 +02:00
|
|
|
* setting_mtu keep track whether the device got reset because of setting MTU and does not drop the
|
|
|
|
* configuration and stop the clients as well. */
|
2017-11-26 15:21:45 +01:00
|
|
|
if (link->setting_mtu)
|
|
|
|
return 0;
|
|
|
|
|
2019-06-03 19:05:26 +02:00
|
|
|
r = link_stop_clients(link, false);
|
2015-02-03 15:44:12 +01:00
|
|
|
if (r < 0) {
|
|
|
|
link_enter_failed(link);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2017-10-18 12:38:56 +02:00
|
|
|
if (link_dhcp4_server_enabled(link))
|
|
|
|
(void) sd_dhcp_server_stop(link->dhcp_server);
|
2017-06-09 17:18:25 +02:00
|
|
|
|
2016-08-04 15:56:39 +02:00
|
|
|
r = link_drop_config(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-12-05 11:54:29 +01:00
|
|
|
if (!IN_SET(link->state, LINK_STATE_UNMANAGED, LINK_STATE_PENDING, LINK_STATE_INITIALIZED)) {
|
2016-09-24 16:07:45 +02:00
|
|
|
log_link_debug(link, "State is %s, dropping config", link_state_to_string(link->state));
|
2016-08-24 17:26:48 +02:00
|
|
|
r = link_drop_foreign_config(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
2016-08-04 15:56:39 +02:00
|
|
|
|
2015-02-17 13:06:57 +01:00
|
|
|
r = link_handle_bound_by_list(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-02-03 15:44:12 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int link_carrier_reset(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (link_has_carrier(link)) {
|
|
|
|
r = link_carrier_lost(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = link_carrier_gained(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_info(link, "Reset carrier");
|
2015-02-03 15:44:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-10-29 15:31:58 +01:00
|
|
|
/* This is called every time an interface admin state changes to up;
|
|
|
|
* specifically, when IFF_UP flag changes from unset to set */
|
|
|
|
static int link_admin_state_up(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* We set the ipv6 mtu after the device mtu, but the kernel resets
|
|
|
|
* ipv6 mtu on NETDEV_UP, so we need to reset it. The check for
|
|
|
|
* ipv6_mtu_set prevents this from trying to set it too early before
|
|
|
|
* the link->network has been setup; we only need to reset it
|
|
|
|
* here if we've already set it during normal initialization. */
|
|
|
|
if (link->ipv6_mtu_set) {
|
|
|
|
r = link_set_ipv6_mtu(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
int link_update(Link *link, sd_netlink_message *m) {
|
2019-12-15 14:46:19 +01:00
|
|
|
_cleanup_strv_free_ char **s = NULL;
|
2014-03-20 19:20:55 +01:00
|
|
|
struct ether_addr mac;
|
2014-07-18 02:35:16 +02:00
|
|
|
const char *ifname;
|
2014-08-01 15:42:08 +02:00
|
|
|
uint32_t mtu;
|
2019-10-29 15:31:58 +01:00
|
|
|
bool had_carrier, carrier_gained, carrier_lost, link_was_admin_up;
|
2019-05-22 03:46:11 +02:00
|
|
|
int old_master, r;
|
2013-12-17 18:36:09 +01:00
|
|
|
|
2013-12-03 18:48:20 +01:00
|
|
|
assert(link);
|
2014-04-19 20:39:17 +02:00
|
|
|
assert(link->ifname);
|
2013-12-17 18:36:09 +01:00
|
|
|
assert(m);
|
|
|
|
|
2014-05-09 12:11:15 +02:00
|
|
|
if (link->state == LINK_STATE_LINGER) {
|
2019-04-27 02:22:40 +02:00
|
|
|
log_link_info(link, "Link re-added");
|
2018-12-01 00:36:33 +01:00
|
|
|
link_set_state(link, LINK_STATE_CONFIGURING);
|
2015-02-17 13:06:57 +01:00
|
|
|
|
|
|
|
r = link_new_carrier_maps(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-05-09 12:11:15 +02:00
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_string(m, IFLA_IFNAME, &ifname);
|
2014-04-19 20:39:17 +02:00
|
|
|
if (r >= 0 && !streq(ifname, link->ifname)) {
|
2019-03-04 04:01:26 +01:00
|
|
|
Manager *manager = link->manager;
|
2014-04-19 20:39:17 +02:00
|
|
|
|
2019-03-04 04:01:26 +01:00
|
|
|
log_link_info(link, "Interface name change detected, %s has been renamed to %s.", link->ifname, ifname);
|
2015-02-17 13:06:57 +01:00
|
|
|
|
2019-03-04 04:01:26 +01:00
|
|
|
link_drop(link);
|
|
|
|
r = link_add(manager, m, &link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-04-19 20:39:17 +02:00
|
|
|
}
|
|
|
|
|
2019-12-15 14:46:19 +01:00
|
|
|
r = sd_netlink_message_read_strv(m, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &s);
|
|
|
|
if (r >= 0)
|
|
|
|
strv_free_and_replace(link->alternative_names, s);
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_u32(m, IFLA_MTU, &mtu);
|
2014-08-01 15:42:08 +02:00
|
|
|
if (r >= 0 && mtu > 0) {
|
|
|
|
link->mtu = mtu;
|
2018-04-20 16:33:00 +02:00
|
|
|
if (link->original_mtu == 0) {
|
2014-08-01 15:42:08 +02:00
|
|
|
link->original_mtu = mtu;
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_debug(link, "Saved original MTU: %" PRIu32, link->original_mtu);
|
2014-08-01 15:42:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (link->dhcp_client) {
|
2014-08-08 12:12:17 +02:00
|
|
|
r = sd_dhcp_client_set_mtu(link->dhcp_client,
|
|
|
|
link->mtu);
|
2018-08-07 08:48:37 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not update MTU in DHCP client: %m");
|
2014-08-01 15:42:08 +02:00
|
|
|
}
|
2017-05-12 15:48:33 +02:00
|
|
|
|
|
|
|
if (link->radv) {
|
|
|
|
r = sd_radv_set_mtu(link->radv, link->mtu);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not set MTU for Router Advertisement: %m");
|
|
|
|
}
|
2014-03-07 17:34:38 +01:00
|
|
|
}
|
2014-03-05 11:53:26 +01:00
|
|
|
|
2014-04-13 22:10:34 +02:00
|
|
|
/* The kernel may broadcast NEWLINK messages without the MAC address
|
|
|
|
set, simply ignore them. */
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &mac);
|
2020-07-19 18:40:21 +02:00
|
|
|
if (r >= 0 && memcmp(link->mac.ether_addr_octet, mac.ether_addr_octet, ETH_ALEN) != 0) {
|
|
|
|
|
|
|
|
memcpy(link->mac.ether_addr_octet, mac.ether_addr_octet, ETH_ALEN);
|
|
|
|
|
|
|
|
log_link_debug(link, "Gained new MAC address: "
|
|
|
|
"%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
|
|
|
|
mac.ether_addr_octet[0],
|
|
|
|
mac.ether_addr_octet[1],
|
|
|
|
mac.ether_addr_octet[2],
|
|
|
|
mac.ether_addr_octet[3],
|
|
|
|
mac.ether_addr_octet[4],
|
|
|
|
mac.ether_addr_octet[5]);
|
|
|
|
|
|
|
|
if (link->ipv4ll) {
|
|
|
|
bool restart = sd_ipv4ll_is_running(link->ipv4ll) > 0;
|
|
|
|
|
|
|
|
if (restart) {
|
|
|
|
r = sd_ipv4ll_stop(link->ipv4ll);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
2020-07-19 18:40:21 +02:00
|
|
|
return log_link_warning_errno(link, r, "Could not stop IPv4LL client: %m");
|
2014-03-20 19:20:55 +01:00
|
|
|
}
|
|
|
|
|
2020-07-19 18:40:21 +02:00
|
|
|
r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not update MAC address in IPv4LL client: %m");
|
|
|
|
|
|
|
|
if (restart) {
|
|
|
|
r = sd_ipv4ll_start(link->ipv4ll);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
2020-07-19 18:40:21 +02:00
|
|
|
return log_link_warning_errno(link, r, "Could not restart IPv4LL client: %m");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (link->dhcp_client) {
|
|
|
|
r = sd_dhcp_client_set_mac(link->dhcp_client,
|
|
|
|
(const uint8_t *) &link->mac,
|
|
|
|
sizeof (link->mac),
|
|
|
|
ARPHRD_ETHER);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m");
|
|
|
|
|
|
|
|
r = dhcp4_set_client_identifier(link);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not set DHCP client identifier: %m");
|
|
|
|
}
|
2016-03-31 01:33:55 +02:00
|
|
|
|
2020-07-19 18:40:21 +02:00
|
|
|
if (link->dhcp6_client) {
|
|
|
|
const DUID* duid = link_get_duid(link);
|
|
|
|
bool restart = sd_dhcp6_client_is_running(link->dhcp6_client) > 0;
|
|
|
|
|
|
|
|
if (restart) {
|
|
|
|
r = sd_dhcp6_client_stop(link->dhcp6_client);
|
2018-08-06 10:33:12 +02:00
|
|
|
if (r < 0)
|
2020-07-19 18:40:21 +02:00
|
|
|
return log_link_warning_errno(link, r, "Could not stop DHCPv6 client: %m");
|
2014-03-20 19:20:55 +01:00
|
|
|
}
|
2014-06-19 14:40:01 +02:00
|
|
|
|
2020-07-19 18:40:21 +02:00
|
|
|
r = sd_dhcp6_client_set_mac(link->dhcp6_client,
|
|
|
|
(const uint8_t *) &link->mac,
|
|
|
|
sizeof (link->mac),
|
|
|
|
ARPHRD_ETHER);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not update MAC address in DHCPv6 client: %m");
|
networkd: rework duid_{type,duid_type,duid,duid_len} setting
Separate fields are replaced with a struct.
Second second duid type field is removed. The first field was used to carry
the result of DUIDType= configuration, and the second was either a copy of
this, or contained the type extracted from DuidRawData. The semantics are changed
so that the type specified in DUIDType is always used. DUIDRawData= no longer
overrides the type setting.
The networkd code is now more constrained than the sd-dhcp code:
DUIDRawData cannot have 0 length, length 0 is treated the same as unsetting.
Likewise, it is not possible to set a DUIDType=0. If it ever becomes necessary
to set type=0 or a zero-length duid, the code can be changed to support that.
Nevertheless, I think that's unlikely.
This addresses #3127 § 1 and 3.
v2:
- rename DUID.duid, DUID.duid_len to DUID.raw_data, DUID.raw_data_len
2016-04-29 05:23:45 +02:00
|
|
|
|
2020-07-19 18:40:21 +02:00
|
|
|
if (link->network->iaid_set) {
|
|
|
|
r = sd_dhcp6_client_set_iaid(link->dhcp6_client, link->network->iaid);
|
2015-04-21 17:40:18 +02:00
|
|
|
if (r < 0)
|
2020-07-19 18:40:21 +02:00
|
|
|
return log_link_warning_errno(link, r, "Could not update DHCPv6 IAID: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_dhcp6_client_set_duid(link->dhcp6_client,
|
|
|
|
duid->type,
|
|
|
|
duid->raw_data_len > 0 ? duid->raw_data : NULL,
|
|
|
|
duid->raw_data_len);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not update DHCPv6 DUID: %m");
|
|
|
|
|
|
|
|
if (restart) {
|
|
|
|
r = sd_dhcp6_client_start(link->dhcp6_client);
|
2016-03-31 01:33:55 +02:00
|
|
|
if (r < 0)
|
2020-07-19 18:40:21 +02:00
|
|
|
return log_link_warning_errno(link, r, "Could not restart DHCPv6 client: %m");
|
2014-06-19 14:40:01 +02:00
|
|
|
}
|
2020-07-19 18:40:21 +02:00
|
|
|
}
|
2017-05-12 15:48:33 +02:00
|
|
|
|
2020-07-19 18:40:21 +02:00
|
|
|
if (link->radv) {
|
|
|
|
bool restart = sd_radv_is_running(link->radv);
|
|
|
|
|
|
|
|
if (restart) {
|
|
|
|
r = sd_radv_stop(link->radv);
|
2017-05-12 15:48:33 +02:00
|
|
|
if (r < 0)
|
2020-07-19 18:40:21 +02:00
|
|
|
return log_link_warning_errno(link, r, "Could not stop Router Advertisement: %m");
|
2017-05-12 15:48:33 +02:00
|
|
|
}
|
2018-01-24 10:17:07 +01:00
|
|
|
|
2020-07-19 18:40:21 +02:00
|
|
|
r = sd_radv_set_mac(link->radv, &link->mac);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not update MAC for Router Advertisement: %m");
|
|
|
|
|
|
|
|
if (restart) {
|
|
|
|
r = sd_radv_start(link->radv);
|
2018-01-24 10:17:07 +01:00
|
|
|
if (r < 0)
|
2020-07-19 18:40:21 +02:00
|
|
|
return log_link_warning_errno(link, r, "Could not restart Router Advertisement: %m");
|
2018-01-24 10:17:07 +01:00
|
|
|
}
|
2014-03-20 19:20:55 +01:00
|
|
|
}
|
2020-07-19 18:40:21 +02:00
|
|
|
|
|
|
|
if (link->ndisc) {
|
|
|
|
r = sd_ndisc_set_mac(link->ndisc, &link->mac);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not update MAC for NDisc: %m");
|
|
|
|
}
|
2014-01-13 23:07:59 +01:00
|
|
|
}
|
|
|
|
|
2019-05-22 03:46:11 +02:00
|
|
|
old_master = link->master_ifindex;
|
|
|
|
(void) sd_netlink_message_read_u32(m, IFLA_MASTER, (uint32_t *) &link->master_ifindex);
|
|
|
|
|
2019-10-29 15:31:58 +01:00
|
|
|
link_was_admin_up = link->flags & IFF_UP;
|
2014-09-04 14:05:54 +02:00
|
|
|
had_carrier = link_has_carrier(link);
|
|
|
|
|
2019-05-22 03:46:11 +02:00
|
|
|
r = link_update_flags(link, m, old_master != link->master_ifindex);
|
2014-09-04 14:05:54 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-10-29 15:31:58 +01:00
|
|
|
if (!link_was_admin_up && (link->flags & IFF_UP)) {
|
|
|
|
log_link_info(link, "Link UP");
|
|
|
|
|
|
|
|
r = link_admin_state_up(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
} else if (link_was_admin_up && !(link->flags & IFF_UP))
|
|
|
|
log_link_info(link, "Link DOWN");
|
|
|
|
|
2016-02-20 22:35:02 +01:00
|
|
|
r = link_update_lldp(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2014-09-04 14:05:54 +02:00
|
|
|
carrier_gained = !had_carrier && link_has_carrier(link);
|
|
|
|
carrier_lost = had_carrier && !link_has_carrier(link);
|
|
|
|
|
|
|
|
if (carrier_gained) {
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_info(link, "Gained carrier");
|
2014-09-04 14:05:54 +02:00
|
|
|
|
2015-02-03 15:44:12 +01:00
|
|
|
r = link_carrier_gained(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-09-04 14:05:54 +02:00
|
|
|
} else if (carrier_lost) {
|
2015-04-21 17:40:18 +02:00
|
|
|
log_link_info(link, "Lost carrier");
|
2014-09-04 14:05:54 +02:00
|
|
|
|
2015-02-03 15:44:12 +01:00
|
|
|
r = link_carrier_lost(link);
|
|
|
|
if (r < 0)
|
2014-09-04 14:05:54 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2013-12-03 18:48:20 +01:00
|
|
|
}
|
2014-02-27 01:24:05 +01:00
|
|
|
|
2016-02-19 20:43:03 +01:00
|
|
|
static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) {
|
|
|
|
bool space = false;
|
|
|
|
Link *link;
|
|
|
|
|
|
|
|
assert(f);
|
|
|
|
assert(prefix);
|
|
|
|
|
|
|
|
if (hashmap_isempty(h))
|
|
|
|
return;
|
|
|
|
|
2017-12-11 19:50:30 +01:00
|
|
|
fputs(prefix, f);
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH(link, h) {
|
2016-02-19 20:43:03 +01:00
|
|
|
if (space)
|
2017-12-11 19:50:30 +01:00
|
|
|
fputc(' ', f);
|
2016-02-19 20:43:03 +01:00
|
|
|
|
|
|
|
fprintf(f, "%i", link->ifindex);
|
|
|
|
space = true;
|
|
|
|
}
|
|
|
|
|
2017-12-11 19:50:30 +01:00
|
|
|
fputc('\n', f);
|
2016-02-19 20:43:03 +01:00
|
|
|
}
|
|
|
|
|
2020-07-03 11:29:13 +02:00
|
|
|
static void link_save_dns(Link *link, FILE *f, struct in_addr_full **dns, unsigned n_dns, bool *space) {
|
2020-05-24 19:18:39 +02:00
|
|
|
for (unsigned j = 0; j < n_dns; j++) {
|
2020-07-03 09:48:29 +02:00
|
|
|
const char *str;
|
2019-05-27 01:52:27 +02:00
|
|
|
|
2020-07-03 11:29:13 +02:00
|
|
|
if (dns[j]->ifindex != 0 && dns[j]->ifindex != link->ifindex)
|
|
|
|
continue;
|
|
|
|
|
2020-07-03 09:48:29 +02:00
|
|
|
str = in_addr_full_to_string(dns[j]);
|
|
|
|
if (!str)
|
2019-05-27 01:52:27 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (*space)
|
|
|
|
fputc(' ', f);
|
2020-07-03 09:48:29 +02:00
|
|
|
fputs(str, f);
|
2019-05-27 01:52:27 +02:00
|
|
|
*space = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
networkd: unfoobar serialization of links
We'd start writing an entry line, then another one, then another one,
and then output the rest of the first one, and then some other random
stuff, and the rest of some other lines... Results were ...eh... random.
Let's define a helper to avoid some of the copy&paste madness, and separate
blocks that output a single line with /**********************************/.
This rework doesn't change what data is written, it only tries to fix the
format of the output. The fact that some entries only write data from
link->network, and some from either link->network or link, some stuff only
for dhpc4 leases while some for both dhpc4 and dhcp6, etc, looks rather
suspicious too, but I didn't touch this.
2020-05-24 22:02:47 +02:00
|
|
|
static void serialize_addresses(
|
|
|
|
FILE *f,
|
|
|
|
const char *lvalue,
|
|
|
|
bool *space,
|
|
|
|
char **addresses,
|
|
|
|
sd_dhcp_lease *lease,
|
|
|
|
bool conditional,
|
2020-05-29 11:26:24 +02:00
|
|
|
sd_dhcp_lease_server_type what,
|
networkd: unfoobar serialization of links
We'd start writing an entry line, then another one, then another one,
and then output the rest of the first one, and then some other random
stuff, and the rest of some other lines... Results were ...eh... random.
Let's define a helper to avoid some of the copy&paste madness, and separate
blocks that output a single line with /**********************************/.
This rework doesn't change what data is written, it only tries to fix the
format of the output. The fact that some entries only write data from
link->network, and some from either link->network or link, some stuff only
for dhpc4 leases while some for both dhpc4 and dhcp6, etc, looks rather
suspicious too, but I didn't touch this.
2020-05-24 22:02:47 +02:00
|
|
|
sd_dhcp6_lease *lease6,
|
|
|
|
bool conditional6,
|
|
|
|
int (*lease6_get_addr)(sd_dhcp6_lease*, const struct in6_addr**),
|
|
|
|
int (*lease6_get_fqdn)(sd_dhcp6_lease*, char ***)) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
bool _space = false;
|
|
|
|
if (!space)
|
|
|
|
space = &_space;
|
|
|
|
|
|
|
|
if (lvalue)
|
|
|
|
fprintf(f, "%s=", lvalue);
|
|
|
|
fputstrv(f, addresses, NULL, space);
|
|
|
|
|
|
|
|
if (lease && conditional) {
|
|
|
|
const struct in_addr *lease_addresses;
|
|
|
|
|
|
|
|
r = sd_dhcp_lease_get_servers(lease, what, &lease_addresses);
|
|
|
|
if (r > 0)
|
2020-05-26 10:19:31 +02:00
|
|
|
serialize_in_addrs(f, lease_addresses, r, space, in4_addr_is_non_local);
|
networkd: unfoobar serialization of links
We'd start writing an entry line, then another one, then another one,
and then output the rest of the first one, and then some other random
stuff, and the rest of some other lines... Results were ...eh... random.
Let's define a helper to avoid some of the copy&paste madness, and separate
blocks that output a single line with /**********************************/.
This rework doesn't change what data is written, it only tries to fix the
format of the output. The fact that some entries only write data from
link->network, and some from either link->network or link, some stuff only
for dhpc4 leases while some for both dhpc4 and dhcp6, etc, looks rather
suspicious too, but I didn't touch this.
2020-05-24 22:02:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (lease6 && conditional6 && lease6_get_addr) {
|
|
|
|
const struct in6_addr *in6_addrs;
|
|
|
|
|
|
|
|
r = lease6_get_addr(lease6, &in6_addrs);
|
2020-05-26 10:19:31 +02:00
|
|
|
if (r > 0)
|
|
|
|
serialize_in6_addrs(f, in6_addrs, r, space);
|
networkd: unfoobar serialization of links
We'd start writing an entry line, then another one, then another one,
and then output the rest of the first one, and then some other random
stuff, and the rest of some other lines... Results were ...eh... random.
Let's define a helper to avoid some of the copy&paste madness, and separate
blocks that output a single line with /**********************************/.
This rework doesn't change what data is written, it only tries to fix the
format of the output. The fact that some entries only write data from
link->network, and some from either link->network or link, some stuff only
for dhpc4 leases while some for both dhpc4 and dhcp6, etc, looks rather
suspicious too, but I didn't touch this.
2020-05-24 22:02:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (lease6 && conditional6 && lease6_get_fqdn) {
|
|
|
|
char **in6_hosts;
|
|
|
|
|
|
|
|
r = lease6_get_fqdn(lease6, &in6_hosts);
|
|
|
|
if (r > 0)
|
|
|
|
fputstrv(f, in6_hosts, NULL, space);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lvalue)
|
|
|
|
fputc('\n', f);
|
|
|
|
}
|
|
|
|
|
2014-02-27 01:24:05 +01:00
|
|
|
int link_save(Link *link) {
|
2020-04-22 14:49:27 +02:00
|
|
|
const char *admin_state, *oper_state, *carrier_state, *address_state;
|
2014-05-08 18:53:32 +02:00
|
|
|
_cleanup_free_ char *temp_path = NULL;
|
2014-02-27 01:24:05 +01:00
|
|
|
_cleanup_fclose_ FILE *f = NULL;
|
2015-10-12 17:54:41 +02:00
|
|
|
Route *route;
|
2020-06-09 10:49:08 +02:00
|
|
|
Address *a;
|
2014-02-27 01:24:05 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->state_file);
|
2014-05-08 18:53:32 +02:00
|
|
|
assert(link->lease_file);
|
2014-05-08 17:21:37 +02:00
|
|
|
assert(link->manager);
|
|
|
|
|
2014-05-08 20:50:05 +02:00
|
|
|
if (link->state == LINK_STATE_LINGER) {
|
2019-03-27 14:36:36 +01:00
|
|
|
(void) unlink(link->state_file);
|
2014-05-08 20:50:05 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
link_lldp_save(link);
|
|
|
|
|
2014-05-07 16:35:05 +02:00
|
|
|
admin_state = link_state_to_string(link->state);
|
|
|
|
assert(admin_state);
|
|
|
|
|
2014-05-19 20:44:21 +02:00
|
|
|
oper_state = link_operstate_to_string(link->operstate);
|
|
|
|
assert(oper_state);
|
2014-05-07 16:35:05 +02:00
|
|
|
|
2019-06-09 21:56:03 +02:00
|
|
|
carrier_state = link_carrier_state_to_string(link->carrier_state);
|
|
|
|
assert(carrier_state);
|
|
|
|
|
|
|
|
address_state = link_address_state_to_string(link->address_state);
|
|
|
|
assert(address_state);
|
|
|
|
|
2014-02-27 01:24:05 +01:00
|
|
|
r = fopen_temporary(link->state_file, &f, &temp_path);
|
|
|
|
if (r < 0)
|
2015-04-21 17:40:18 +02:00
|
|
|
goto fail;
|
2014-02-27 01:24:05 +01:00
|
|
|
|
2016-11-18 17:04:26 +01:00
|
|
|
(void) fchmod(fileno(f), 0644);
|
2014-02-27 01:24:05 +01:00
|
|
|
|
|
|
|
fprintf(f,
|
|
|
|
"# This is private data. Do not parse.\n"
|
2014-05-07 16:35:05 +02:00
|
|
|
"ADMIN_STATE=%s\n"
|
2019-06-09 21:56:03 +02:00
|
|
|
"OPER_STATE=%s\n"
|
|
|
|
"CARRIER_STATE=%s\n"
|
|
|
|
"ADDRESS_STATE=%s\n",
|
|
|
|
admin_state, oper_state, carrier_state, address_state);
|
2014-02-27 01:24:05 +01:00
|
|
|
|
2014-05-19 18:42:14 +02:00
|
|
|
if (link->network) {
|
2019-05-12 22:40:31 +02:00
|
|
|
char **dhcp6_domains = NULL, **dhcp_domains = NULL;
|
|
|
|
const char *dhcp_domainname = NULL, *p;
|
|
|
|
bool space;
|
2015-07-06 14:00:12 +02:00
|
|
|
|
2017-11-30 18:03:50 +01:00
|
|
|
fprintf(f, "REQUIRED_FOR_ONLINE=%s\n",
|
|
|
|
yes_no(link->network->required_for_online));
|
|
|
|
|
networkd: unfoobar serialization of links
We'd start writing an entry line, then another one, then another one,
and then output the rest of the first one, and then some other random
stuff, and the rest of some other lines... Results were ...eh... random.
Let's define a helper to avoid some of the copy&paste madness, and separate
blocks that output a single line with /**********************************/.
This rework doesn't change what data is written, it only tries to fix the
format of the output. The fact that some entries only write data from
link->network, and some from either link->network or link, some stuff only
for dhpc4 leases while some for both dhpc4 and dhcp6, etc, looks rather
suspicious too, but I didn't touch this.
2020-05-24 22:02:47 +02:00
|
|
|
LinkOperationalStateRange st = link->network->required_operstate_for_online;
|
|
|
|
fprintf(f, "REQUIRED_OPER_STATE_FOR_ONLINE=%s%s%s\n",
|
|
|
|
strempty(link_operstate_to_string(st.min)),
|
|
|
|
st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? ":" : "",
|
|
|
|
st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? strempty(link_operstate_to_string(st.max)) : "");
|
2019-03-06 06:29:49 +01:00
|
|
|
|
2014-09-08 13:50:52 +02:00
|
|
|
fprintf(f, "NETWORK_FILE=%s\n", link->network->filename);
|
|
|
|
|
networkd: unfoobar serialization of links
We'd start writing an entry line, then another one, then another one,
and then output the rest of the first one, and then some other random
stuff, and the rest of some other lines... Results were ...eh... random.
Let's define a helper to avoid some of the copy&paste madness, and separate
blocks that output a single line with /**********************************/.
This rework doesn't change what data is written, it only tries to fix the
format of the output. The fact that some entries only write data from
link->network, and some from either link->network or link, some stuff only
for dhpc4 leases while some for both dhpc4 and dhcp6, etc, looks rather
suspicious too, but I didn't touch this.
2020-05-24 22:02:47 +02:00
|
|
|
/************************************************************/
|
|
|
|
|
2017-12-11 19:50:30 +01:00
|
|
|
fputs("DNS=", f);
|
2014-08-18 18:59:48 +02:00
|
|
|
space = false;
|
2019-05-27 01:52:27 +02:00
|
|
|
if (link->n_dns != (unsigned) -1)
|
2020-07-03 11:29:13 +02:00
|
|
|
link_save_dns(link, f, link->dns, link->n_dns, &space);
|
2019-05-27 01:52:27 +02:00
|
|
|
else
|
2020-07-03 11:29:13 +02:00
|
|
|
link_save_dns(link, f, link->network->dns, link->network->n_dns, &space);
|
2014-08-15 15:42:56 +02:00
|
|
|
|
networkd: unfoobar serialization of links
We'd start writing an entry line, then another one, then another one,
and then output the rest of the first one, and then some other random
stuff, and the rest of some other lines... Results were ...eh... random.
Let's define a helper to avoid some of the copy&paste madness, and separate
blocks that output a single line with /**********************************/.
This rework doesn't change what data is written, it only tries to fix the
format of the output. The fact that some entries only write data from
link->network, and some from either link->network or link, some stuff only
for dhpc4 leases while some for both dhpc4 and dhcp6, etc, looks rather
suspicious too, but I didn't touch this.
2020-05-24 22:02:47 +02:00
|
|
|
serialize_addresses(f, NULL, &space,
|
|
|
|
NULL,
|
|
|
|
link->dhcp_lease,
|
|
|
|
link->network->dhcp_use_dns,
|
2020-05-29 11:26:24 +02:00
|
|
|
SD_DHCP_LEASE_DNS,
|
2020-07-22 20:13:42 +02:00
|
|
|
link->dhcp6_lease,
|
networkd: unfoobar serialization of links
We'd start writing an entry line, then another one, then another one,
and then output the rest of the first one, and then some other random
stuff, and the rest of some other lines... Results were ...eh... random.
Let's define a helper to avoid some of the copy&paste madness, and separate
blocks that output a single line with /**********************************/.
This rework doesn't change what data is written, it only tries to fix the
format of the output. The fact that some entries only write data from
link->network, and some from either link->network or link, some stuff only
for dhpc4 leases while some for both dhpc4 and dhcp6, etc, looks rather
suspicious too, but I didn't touch this.
2020-05-24 22:02:47 +02:00
|
|
|
link->network->dhcp6_use_dns,
|
|
|
|
sd_dhcp6_lease_get_dns,
|
|
|
|
NULL);
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
|
2020-07-17 22:46:53 +02:00
|
|
|
/* Make sure to flush out old entries before we use the NDisc data */
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
ndisc_vacuum(link);
|
|
|
|
|
2018-05-02 20:16:10 +02:00
|
|
|
if (link->network->ipv6_accept_ra_use_dns && link->ndisc_rdnss) {
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
NDiscRDNSS *dd;
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(dd, link->ndisc_rdnss)
|
2020-05-26 10:19:31 +02:00
|
|
|
serialize_in6_addrs(f, &dd->address, 1, &space);
|
2019-09-18 15:22:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fputc('\n', f);
|
|
|
|
|
networkd: unfoobar serialization of links
We'd start writing an entry line, then another one, then another one,
and then output the rest of the first one, and then some other random
stuff, and the rest of some other lines... Results were ...eh... random.
Let's define a helper to avoid some of the copy&paste madness, and separate
blocks that output a single line with /**********************************/.
This rework doesn't change what data is written, it only tries to fix the
format of the output. The fact that some entries only write data from
link->network, and some from either link->network or link, some stuff only
for dhpc4 leases while some for both dhpc4 and dhcp6, etc, looks rather
suspicious too, but I didn't touch this.
2020-05-24 22:02:47 +02:00
|
|
|
/************************************************************/
|
|
|
|
|
|
|
|
serialize_addresses(f, "NTP", NULL,
|
|
|
|
link->ntp ?: link->network->ntp,
|
|
|
|
link->dhcp_lease,
|
|
|
|
link->network->dhcp_use_ntp,
|
2020-05-29 11:26:24 +02:00
|
|
|
SD_DHCP_LEASE_NTP,
|
2020-07-22 20:13:42 +02:00
|
|
|
link->dhcp6_lease,
|
networkd: unfoobar serialization of links
We'd start writing an entry line, then another one, then another one,
and then output the rest of the first one, and then some other random
stuff, and the rest of some other lines... Results were ...eh... random.
Let's define a helper to avoid some of the copy&paste madness, and separate
blocks that output a single line with /**********************************/.
This rework doesn't change what data is written, it only tries to fix the
format of the output. The fact that some entries only write data from
link->network, and some from either link->network or link, some stuff only
for dhpc4 leases while some for both dhpc4 and dhcp6, etc, looks rather
suspicious too, but I didn't touch this.
2020-05-24 22:02:47 +02:00
|
|
|
link->network->dhcp6_use_ntp,
|
|
|
|
sd_dhcp6_lease_get_ntp_addrs,
|
|
|
|
sd_dhcp6_lease_get_ntp_fqdn);
|
|
|
|
|
|
|
|
serialize_addresses(f, "SIP", NULL,
|
2020-06-16 20:35:18 +02:00
|
|
|
NULL,
|
networkd: unfoobar serialization of links
We'd start writing an entry line, then another one, then another one,
and then output the rest of the first one, and then some other random
stuff, and the rest of some other lines... Results were ...eh... random.
Let's define a helper to avoid some of the copy&paste madness, and separate
blocks that output a single line with /**********************************/.
This rework doesn't change what data is written, it only tries to fix the
format of the output. The fact that some entries only write data from
link->network, and some from either link->network or link, some stuff only
for dhpc4 leases while some for both dhpc4 and dhcp6, etc, looks rather
suspicious too, but I didn't touch this.
2020-05-24 22:02:47 +02:00
|
|
|
link->dhcp_lease,
|
|
|
|
link->network->dhcp_use_sip,
|
2020-05-29 11:26:24 +02:00
|
|
|
SD_DHCP_LEASE_SIP,
|
2020-06-16 20:35:18 +02:00
|
|
|
NULL, false, NULL, NULL);
|
networkd: unfoobar serialization of links
We'd start writing an entry line, then another one, then another one,
and then output the rest of the first one, and then some other random
stuff, and the rest of some other lines... Results were ...eh... random.
Let's define a helper to avoid some of the copy&paste madness, and separate
blocks that output a single line with /**********************************/.
This rework doesn't change what data is written, it only tries to fix the
format of the output. The fact that some entries only write data from
link->network, and some from either link->network or link, some stuff only
for dhpc4 leases while some for both dhpc4 and dhcp6, etc, looks rather
suspicious too, but I didn't touch this.
2020-05-24 22:02:47 +02:00
|
|
|
|
|
|
|
/************************************************************/
|
2014-08-03 18:45:07 +02:00
|
|
|
|
2016-01-25 22:27:01 +01:00
|
|
|
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
|
2017-05-13 16:19:32 +02:00
|
|
|
if (link->dhcp_lease) {
|
2016-01-25 22:27:01 +01:00
|
|
|
(void) sd_dhcp_lease_get_domainname(link->dhcp_lease, &dhcp_domainname);
|
2017-05-13 16:19:32 +02:00
|
|
|
(void) sd_dhcp_lease_get_search_domains(link->dhcp_lease, &dhcp_domains);
|
|
|
|
}
|
2020-07-22 20:13:42 +02:00
|
|
|
if (link->dhcp6_lease)
|
|
|
|
(void) sd_dhcp6_lease_get_domains(link->dhcp6_lease, &dhcp6_domains);
|
2015-07-06 14:00:12 +02:00
|
|
|
}
|
|
|
|
|
2019-05-12 22:40:31 +02:00
|
|
|
fputs("DOMAINS=", f);
|
|
|
|
space = false;
|
2020-09-08 11:58:29 +02:00
|
|
|
ORDERED_SET_FOREACH(p, link->search_domains ?: link->network->search_domains)
|
2019-05-12 22:40:31 +02:00
|
|
|
fputs_with_space(f, p, NULL, &space);
|
2015-07-06 14:00:12 +02:00
|
|
|
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) {
|
|
|
|
if (dhcp_domainname)
|
|
|
|
fputs_with_space(f, dhcp_domainname, NULL, &space);
|
2017-05-13 16:19:32 +02:00
|
|
|
if (dhcp_domains)
|
|
|
|
fputstrv(f, dhcp_domains, NULL, &space);
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
if (dhcp6_domains)
|
|
|
|
fputstrv(f, dhcp6_domains, NULL, &space);
|
2019-07-14 03:30:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_YES) {
|
|
|
|
NDiscDNSSL *dd;
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(dd, link->ndisc_dnssl)
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
|
|
|
|
}
|
2016-01-25 22:27:01 +01:00
|
|
|
|
2017-12-11 19:50:30 +01:00
|
|
|
fputc('\n', f);
|
2014-08-15 14:21:08 +02:00
|
|
|
|
networkd: unfoobar serialization of links
We'd start writing an entry line, then another one, then another one,
and then output the rest of the first one, and then some other random
stuff, and the rest of some other lines... Results were ...eh... random.
Let's define a helper to avoid some of the copy&paste madness, and separate
blocks that output a single line with /**********************************/.
This rework doesn't change what data is written, it only tries to fix the
format of the output. The fact that some entries only write data from
link->network, and some from either link->network or link, some stuff only
for dhpc4 leases while some for both dhpc4 and dhcp6, etc, looks rather
suspicious too, but I didn't touch this.
2020-05-24 22:02:47 +02:00
|
|
|
/************************************************************/
|
|
|
|
|
2019-05-12 22:40:31 +02:00
|
|
|
fputs("ROUTE_DOMAINS=", f);
|
|
|
|
space = false;
|
2020-09-08 11:58:29 +02:00
|
|
|
ORDERED_SET_FOREACH(p, link->route_domains ?: link->network->route_domains)
|
2019-05-12 22:40:31 +02:00
|
|
|
fputs_with_space(f, p, NULL, &space);
|
2016-01-25 22:27:01 +01:00
|
|
|
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE) {
|
|
|
|
if (dhcp_domainname)
|
|
|
|
fputs_with_space(f, dhcp_domainname, NULL, &space);
|
2017-05-13 16:19:32 +02:00
|
|
|
if (dhcp_domains)
|
|
|
|
fputstrv(f, dhcp_domains, NULL, &space);
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
if (dhcp6_domains)
|
|
|
|
fputstrv(f, dhcp6_domains, NULL, &space);
|
2019-07-14 03:30:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_ROUTE) {
|
|
|
|
NDiscDNSSL *dd;
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(dd, link->ndisc_dnssl)
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
|
|
|
|
}
|
2016-01-25 22:27:01 +01:00
|
|
|
|
2017-12-11 19:50:30 +01:00
|
|
|
fputc('\n', f);
|
2014-08-15 14:49:31 +02:00
|
|
|
|
networkd: unfoobar serialization of links
We'd start writing an entry line, then another one, then another one,
and then output the rest of the first one, and then some other random
stuff, and the rest of some other lines... Results were ...eh... random.
Let's define a helper to avoid some of the copy&paste madness, and separate
blocks that output a single line with /**********************************/.
This rework doesn't change what data is written, it only tries to fix the
format of the output. The fact that some entries only write data from
link->network, and some from either link->network or link, some stuff only
for dhpc4 leases while some for both dhpc4 and dhcp6, etc, looks rather
suspicious too, but I didn't touch this.
2020-05-24 22:02:47 +02:00
|
|
|
/************************************************************/
|
|
|
|
|
2014-08-08 12:12:17 +02:00
|
|
|
fprintf(f, "LLMNR=%s\n",
|
2019-05-27 01:52:27 +02:00
|
|
|
resolve_support_to_string(link->llmnr >= 0 ? link->llmnr : link->network->llmnr));
|
networkd: unfoobar serialization of links
We'd start writing an entry line, then another one, then another one,
and then output the rest of the first one, and then some other random
stuff, and the rest of some other lines... Results were ...eh... random.
Let's define a helper to avoid some of the copy&paste madness, and separate
blocks that output a single line with /**********************************/.
This rework doesn't change what data is written, it only tries to fix the
format of the output. The fact that some entries only write data from
link->network, and some from either link->network or link, some stuff only
for dhpc4 leases while some for both dhpc4 and dhcp6, etc, looks rather
suspicious too, but I didn't touch this.
2020-05-24 22:02:47 +02:00
|
|
|
|
|
|
|
/************************************************************/
|
|
|
|
|
2016-01-05 17:32:25 +01:00
|
|
|
fprintf(f, "MDNS=%s\n",
|
2019-05-27 01:52:27 +02:00
|
|
|
resolve_support_to_string(link->mdns >= 0 ? link->mdns : link->network->mdns));
|
|
|
|
|
networkd: unfoobar serialization of links
We'd start writing an entry line, then another one, then another one,
and then output the rest of the first one, and then some other random
stuff, and the rest of some other lines... Results were ...eh... random.
Let's define a helper to avoid some of the copy&paste madness, and separate
blocks that output a single line with /**********************************/.
This rework doesn't change what data is written, it only tries to fix the
format of the output. The fact that some entries only write data from
link->network, and some from either link->network or link, some stuff only
for dhpc4 leases while some for both dhpc4 and dhcp6, etc, looks rather
suspicious too, but I didn't touch this.
2020-05-24 22:02:47 +02:00
|
|
|
/************************************************************/
|
|
|
|
|
|
|
|
int dns_default_route =
|
|
|
|
link->dns_default_route >= 0 ? link->dns_default_route :
|
|
|
|
link->network->dns_default_route;
|
|
|
|
if (dns_default_route >= 0)
|
|
|
|
fprintf(f, "DNS_DEFAULT_ROUTE=%s\n", yes_no(dns_default_route));
|
|
|
|
|
|
|
|
/************************************************************/
|
|
|
|
|
|
|
|
DnsOverTlsMode dns_over_tls_mode =
|
|
|
|
link->dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID ? link->dns_over_tls_mode :
|
|
|
|
link->network->dns_over_tls_mode;
|
|
|
|
if (dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID)
|
|
|
|
fprintf(f, "DNS_OVER_TLS=%s\n", dns_over_tls_mode_to_string(dns_over_tls_mode));
|
|
|
|
|
|
|
|
/************************************************************/
|
|
|
|
|
|
|
|
DnssecMode dnssec_mode =
|
|
|
|
link->dnssec_mode != _DNSSEC_MODE_INVALID ? link->dnssec_mode :
|
|
|
|
link->network->dnssec_mode;
|
|
|
|
if (dnssec_mode != _DNSSEC_MODE_INVALID)
|
|
|
|
fprintf(f, "DNSSEC=%s\n", dnssec_mode_to_string(dnssec_mode));
|
|
|
|
|
|
|
|
/************************************************************/
|
|
|
|
|
|
|
|
Set *nta_anchors = link->dnssec_negative_trust_anchors;
|
|
|
|
if (set_isempty(nta_anchors))
|
|
|
|
nta_anchors = link->network->dnssec_negative_trust_anchors;
|
|
|
|
|
|
|
|
if (!set_isempty(nta_anchors)) {
|
2016-01-06 18:36:32 +01:00
|
|
|
const char *n;
|
|
|
|
|
2017-12-11 19:50:30 +01:00
|
|
|
fputs("DNSSEC_NTA=", f);
|
2016-01-06 18:36:32 +01:00
|
|
|
space = false;
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(n, nta_anchors)
|
2016-01-25 22:42:36 +01:00
|
|
|
fputs_with_space(f, n, NULL, &space);
|
2017-12-11 19:50:30 +01:00
|
|
|
fputc('\n', f);
|
2016-01-06 18:36:32 +01:00
|
|
|
}
|
|
|
|
|
networkd: unfoobar serialization of links
We'd start writing an entry line, then another one, then another one,
and then output the rest of the first one, and then some other random
stuff, and the rest of some other lines... Results were ...eh... random.
Let's define a helper to avoid some of the copy&paste madness, and separate
blocks that output a single line with /**********************************/.
This rework doesn't change what data is written, it only tries to fix the
format of the output. The fact that some entries only write data from
link->network, and some from either link->network or link, some stuff only
for dhpc4 leases while some for both dhpc4 and dhcp6, etc, looks rather
suspicious too, but I didn't touch this.
2020-05-24 22:02:47 +02:00
|
|
|
/************************************************************/
|
|
|
|
|
2017-12-11 19:50:30 +01:00
|
|
|
fputs("ADDRESSES=", f);
|
2015-09-30 15:32:16 +02:00
|
|
|
space = false;
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(a, link->addresses) {
|
2015-09-30 15:32:16 +02:00
|
|
|
_cleanup_free_ char *address_str = NULL;
|
|
|
|
|
|
|
|
r = in_addr_to_string(a->family, &a->in_addr, &address_str);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
fprintf(f, "%s%s/%u", space ? " " : "", address_str, a->prefixlen);
|
|
|
|
space = true;
|
|
|
|
}
|
2017-12-11 19:50:30 +01:00
|
|
|
fputc('\n', f);
|
2015-10-12 17:54:41 +02:00
|
|
|
|
networkd: unfoobar serialization of links
We'd start writing an entry line, then another one, then another one,
and then output the rest of the first one, and then some other random
stuff, and the rest of some other lines... Results were ...eh... random.
Let's define a helper to avoid some of the copy&paste madness, and separate
blocks that output a single line with /**********************************/.
This rework doesn't change what data is written, it only tries to fix the
format of the output. The fact that some entries only write data from
link->network, and some from either link->network or link, some stuff only
for dhpc4 leases while some for both dhpc4 and dhcp6, etc, looks rather
suspicious too, but I didn't touch this.
2020-05-24 22:02:47 +02:00
|
|
|
/************************************************************/
|
|
|
|
|
2017-12-11 19:50:30 +01:00
|
|
|
fputs("ROUTES=", f);
|
2015-10-12 17:54:41 +02:00
|
|
|
space = false;
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(route, link->routes) {
|
2015-10-12 17:54:41 +02:00
|
|
|
_cleanup_free_ char *route_str = NULL;
|
|
|
|
|
|
|
|
r = in_addr_to_string(route->family, &route->dst, &route_str);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
|
|
|
|
networkd: fix two format string mismatches
../src/network/networkd-link.c:3577:84: warning: format specifies type 'unsigned char' but the argument has type 'uint32_t' (aka 'unsigned int') [-Wformat]
route->dst_prefixlen, route->tos, route->priority, route->table, route->lifetime);
^~~~~~~~~~~~
../src/network/networkd-manager.c:1146:132: warning: format specifies type 'unsigned char' but the argument has type 'uint32_t' (aka 'unsigned int') [-Wformat]
rule->from_prefixlen, space ? " " : "", to_str, rule->to_prefixlen, rule->tos, rule->fwmark, rule->fwmask, rule->table);
^~~~~~~~~~~
Also add some line breaks to make it easier to see which argument is for which
part of the format string.
2017-11-01 22:43:32 +01:00
|
|
|
fprintf(f, "%s%s/%hhu/%hhu/%"PRIu32"/%"PRIu32"/"USEC_FMT,
|
|
|
|
space ? " " : "", route_str,
|
2015-10-26 12:29:37 +01:00
|
|
|
route->dst_prefixlen, route->tos, route->priority, route->table, route->lifetime);
|
2015-10-12 17:54:41 +02:00
|
|
|
space = true;
|
|
|
|
}
|
|
|
|
|
2017-12-11 19:50:30 +01:00
|
|
|
fputc('\n', f);
|
2014-05-19 18:42:14 +02:00
|
|
|
}
|
2014-05-18 22:04:14 +02:00
|
|
|
|
2016-02-19 20:43:03 +01:00
|
|
|
print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links);
|
|
|
|
print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links);
|
2015-02-17 13:06:57 +01:00
|
|
|
|
2015-08-26 19:19:32 +02:00
|
|
|
if (link->dhcp_lease) {
|
2015-08-26 20:48:21 +02:00
|
|
|
r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
|
2014-02-27 01:24:05 +01:00
|
|
|
if (r < 0)
|
2014-08-12 11:55:06 +02:00
|
|
|
goto fail;
|
2014-02-27 01:24:05 +01:00
|
|
|
|
2014-05-18 22:04:14 +02:00
|
|
|
fprintf(f,
|
2014-07-23 13:48:18 +02:00
|
|
|
"DHCP_LEASE=%s\n",
|
|
|
|
link->lease_file);
|
2014-05-07 16:35:05 +02:00
|
|
|
} else
|
2019-03-27 14:36:36 +01:00
|
|
|
(void) unlink(link->lease_file);
|
2014-02-27 01:24:05 +01:00
|
|
|
|
2015-10-01 22:29:50 +02:00
|
|
|
if (link->ipv4ll) {
|
|
|
|
struct in_addr address;
|
|
|
|
|
|
|
|
r = sd_ipv4ll_get_address(link->ipv4ll, &address);
|
|
|
|
if (r >= 0) {
|
2017-12-11 19:50:30 +01:00
|
|
|
fputs("IPV4LL_ADDRESS=", f);
|
2018-12-14 16:25:01 +01:00
|
|
|
serialize_in_addrs(f, &address, 1, false, NULL);
|
2017-12-11 19:50:30 +01:00
|
|
|
fputc('\n', f);
|
2015-10-01 22:29:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-09 16:48:42 +02:00
|
|
|
if (link->dhcp6_client) {
|
|
|
|
_cleanup_free_ char *duid = NULL;
|
|
|
|
uint32_t iaid;
|
|
|
|
|
|
|
|
r = sd_dhcp6_client_get_iaid(link->dhcp6_client, &iaid);
|
|
|
|
if (r >= 0)
|
|
|
|
fprintf(f, "DHCP6_CLIENT_IAID=0x%x\n", iaid);
|
|
|
|
|
|
|
|
r = sd_dhcp6_client_duid_as_string(link->dhcp6_client, &duid);
|
|
|
|
if (r >= 0)
|
|
|
|
fprintf(f, "DHCP6_CLIENT_DUID=%s\n", duid);
|
|
|
|
}
|
2020-06-09 10:49:08 +02:00
|
|
|
|
2014-08-12 11:55:06 +02:00
|
|
|
r = fflush_and_check(f);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
2014-02-27 01:24:05 +01:00
|
|
|
|
2014-08-12 11:55:06 +02:00
|
|
|
if (rename(temp_path, link->state_file) < 0) {
|
2014-02-27 01:24:05 +01:00
|
|
|
r = -errno;
|
2014-08-12 11:55:06 +02:00
|
|
|
goto fail;
|
2014-02-27 01:24:05 +01:00
|
|
|
}
|
|
|
|
|
2014-08-12 11:55:06 +02:00
|
|
|
return 0;
|
2015-07-29 20:31:07 +02:00
|
|
|
|
2014-08-12 11:55:06 +02:00
|
|
|
fail:
|
2015-04-21 17:40:18 +02:00
|
|
|
(void) unlink(link->state_file);
|
|
|
|
if (temp_path)
|
|
|
|
(void) unlink(temp_path);
|
|
|
|
|
2015-07-29 20:31:07 +02:00
|
|
|
return log_link_error_errno(link, r, "Failed to save link data to %s: %m", link->state_file);
|
2014-02-27 01:24:05 +01:00
|
|
|
}
|
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
/* The serialized state in /run is no longer up-to-date. */
|
|
|
|
void link_dirty(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
2016-04-21 16:08:07 +02:00
|
|
|
/* mark manager dirty as link is dirty */
|
|
|
|
manager_dirty(link->manager);
|
|
|
|
|
2020-06-05 15:12:29 +02:00
|
|
|
r = set_ensure_put(&link->manager->dirty_links, NULL, link);
|
2016-04-21 16:08:07 +02:00
|
|
|
if (r <= 0)
|
2020-06-05 15:12:29 +02:00
|
|
|
/* Ignore allocation errors and don't take another ref if the link was already dirty */
|
2015-09-30 18:17:43 +02:00
|
|
|
return;
|
|
|
|
link_ref(link);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The serialized state in /run is up-to-date */
|
|
|
|
void link_clean(Link *link) {
|
|
|
|
assert(link);
|
|
|
|
assert(link->manager);
|
|
|
|
|
2018-10-06 06:55:19 +02:00
|
|
|
link_unref(set_remove(link->manager->dirty_links, link));
|
2015-09-30 18:17:43 +02:00
|
|
|
}
|
|
|
|
|
2020-07-20 22:21:28 +02:00
|
|
|
int link_save_and_clean(Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = link_save(link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
link_clean(link);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-02-27 01:24:05 +01:00
|
|
|
static const char* const link_state_table[_LINK_STATE_MAX] = {
|
2014-08-13 15:34:27 +02:00
|
|
|
[LINK_STATE_PENDING] = "pending",
|
2019-04-15 10:34:00 +02:00
|
|
|
[LINK_STATE_INITIALIZED] = "initialized",
|
2018-12-01 00:36:33 +01:00
|
|
|
[LINK_STATE_CONFIGURING] = "configuring",
|
2014-02-27 01:24:05 +01:00
|
|
|
[LINK_STATE_CONFIGURED] = "configured",
|
2014-04-20 19:49:00 +02:00
|
|
|
[LINK_STATE_UNMANAGED] = "unmanaged",
|
2014-02-27 01:24:05 +01:00
|
|
|
[LINK_STATE_FAILED] = "failed",
|
2014-05-08 20:50:05 +02:00
|
|
|
[LINK_STATE_LINGER] = "linger",
|
2014-02-27 01:24:05 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
DEFINE_STRING_TABLE_LOOKUP(link_state, LinkState);
|
2019-11-30 07:54:07 +01:00
|
|
|
|
|
|
|
int log_link_message_full_errno(Link *link, sd_netlink_message *m, int level, int err, const char *msg) {
|
|
|
|
const char *err_msg = NULL;
|
|
|
|
|
|
|
|
(void) sd_netlink_message_read_string(m, NLMSGERR_ATTR_MSG, &err_msg);
|
2020-09-08 19:33:03 +02:00
|
|
|
return log_link_full_errno(link, level, err,
|
|
|
|
"%s: %s%s%s%m",
|
|
|
|
msg,
|
|
|
|
strempty(err_msg),
|
|
|
|
err_msg && !endswith(err_msg, ".") ? "." : "",
|
|
|
|
err_msg ? " " : "");
|
2019-11-30 07:54:07 +01:00
|
|
|
}
|