2020-11-09 13:23:58 +09:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2021-07-12 21:23:41 +09:00
|
|
|
#include <net/if.h>
|
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 18:22:43 +09:00
|
|
|
#include <linux/if_arp.h>
|
2020-06-21 11:17:34 +00:00
|
|
|
#include <linux/if_link.h>
|
2021-07-26 10:58:46 -07:00
|
|
|
#include <linux/netdevice.h>
|
2021-04-11 23:29:11 +03:00
|
|
|
#include <sys/socket.h>
|
2014-07-01 11:58:49 -07:00
|
|
|
#include <unistd.h>
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2021-11-07 12:18:08 +09:00
|
|
|
#include "arphrd-util.h"
|
2020-10-02 21:43:05 +02:00
|
|
|
#include "batadv.h"
|
2019-10-30 17:02:15 +09:00
|
|
|
#include "bond.h"
|
|
|
|
|
#include "bridge.h"
|
2015-09-23 01:53:29 +02:00
|
|
|
#include "bus-util.h"
|
2021-02-21 15:51:51 +09:00
|
|
|
#include "device-private.h"
|
|
|
|
|
#include "device-util.h"
|
2018-07-03 03:19:15 +09:00
|
|
|
#include "dhcp-identifier.h"
|
2015-09-23 01:53:29 +02:00
|
|
|
#include "dhcp-lease-internal.h"
|
2018-11-30 22:08:41 +01:00
|
|
|
#include "env-file.h"
|
2019-01-07 20:16:19 +09:00
|
|
|
#include "ethtool-util.h"
|
2021-11-13 10:50:03 +09:00
|
|
|
#include "event-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"
|
2021-07-12 21:23:41 +09:00
|
|
|
#include "format-util.h"
|
2021-01-20 17:18:10 +09:00
|
|
|
#include "fs-util.h"
|
2022-06-24 09:13:42 +02:00
|
|
|
#include "glyph-util.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"
|
|
|
|
|
#include "network-internal.h"
|
2020-09-30 01:40:03 +09:00
|
|
|
#include "networkd-address-label.h"
|
2020-10-02 14:01:59 +09:00
|
|
|
#include "networkd-address.h"
|
2021-05-14 13:24:48 +09:00
|
|
|
#include "networkd-bridge-fdb.h"
|
2021-05-18 05:09:59 +09:00
|
|
|
#include "networkd-bridge-mdb.h"
|
2019-05-09 15:39:19 +09:00
|
|
|
#include "networkd-can.h"
|
2021-12-05 03:12:46 +09:00
|
|
|
#include "networkd-dhcp-prefix-delegation.h"
|
2019-06-30 04:33:34 +09:00
|
|
|
#include "networkd-dhcp-server.h"
|
2019-06-30 03:57:47 +09:00
|
|
|
#include "networkd-dhcp4.h"
|
|
|
|
|
#include "networkd-dhcp6.h"
|
2021-06-22 04:08:19 +09:00
|
|
|
#include "networkd-ipv4acd.h"
|
2019-06-30 03:57:47 +09:00
|
|
|
#include "networkd-ipv4ll.h"
|
network: use request queue to configure addresses, routes, and nexthops
Why is this necessary? Several examples below.
- When a route sets prefsrc, then the address must be already assigned
(see issue #19285), and also it must be ready if IPv6.
- When a route or nexthop sets gateway, then the address must be reachable.
- When a route sets nexthop ID, then the corresponding nexthop must be
assigned.
- When a route sets multipath routes on another interface, then the
interface must exist and be ready to configure.
- When configuring address, the same address must not be under removing
(see issue #18108).
Etc,. etc,...
So, this makes all requests about addresses, routes, and nethops are once
stored in the queue, and will be processed when they are ready to configure.
Fixes #18108 and #19285.
2021-05-05 22:46:44 +09:00
|
|
|
#include "networkd-ipv6-proxy-ndp.h"
|
2019-05-27 05:35:02 +09: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-28 19:00:58 -08:00
|
|
|
#include "networkd-neighbor.h"
|
2020-09-29 17:47:28 +09:00
|
|
|
#include "networkd-nexthop.h"
|
2021-05-07 15:39:16 +09:00
|
|
|
#include "networkd-queue.h"
|
2017-05-12 16:48:33 +03:00
|
|
|
#include "networkd-radv.h"
|
2021-09-06 16:09:38 +09:00
|
|
|
#include "networkd-route.h"
|
2017-09-14 19:51:39 +00:00
|
|
|
#include "networkd-routing-policy-rule.h"
|
2021-05-21 04:51:07 +09:00
|
|
|
#include "networkd-setlink.h"
|
2021-05-07 15:39:16 +09:00
|
|
|
#include "networkd-sriov.h"
|
2021-02-21 14:23:04 +09:00
|
|
|
#include "networkd-state-file.h"
|
2021-05-07 15:39:16 +09:00
|
|
|
#include "networkd-sysctl.h"
|
2015-09-23 01:53:29 +02:00
|
|
|
#include "set.h"
|
|
|
|
|
#include "socket-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 14:30:49 +09:00
|
|
|
#include "strv.h"
|
2020-02-10 20:53:00 +09:00
|
|
|
#include "tc.h"
|
2018-11-30 21:05:27 +01:00
|
|
|
#include "tmpfile-util.h"
|
2019-03-04 12:19:05 +09:00
|
|
|
#include "udev-util.h"
|
2013-10-17 03:18:36 +02:00
|
|
|
#include "util.h"
|
2019-10-30 17:02:15 +09:00
|
|
|
#include "vrf.h"
|
2015-08-27 13:59:06 +02:00
|
|
|
|
2020-10-04 06:25:44 +09:00
|
|
|
bool link_ipv6_enabled(Link *link) {
|
2016-04-21 06:04:13 +05:30
|
|
|
assert(link);
|
|
|
|
|
|
|
|
|
|
if (!socket_ipv6_is_supported())
|
|
|
|
|
return false;
|
|
|
|
|
|
2019-02-20 10:07:20 +09:00
|
|
|
if (link->network->bond)
|
2016-05-28 13:35:01 +08:00
|
|
|
return false;
|
|
|
|
|
|
2019-07-25 10:11:45 +09:00
|
|
|
if (link->iftype == ARPHRD_CAN)
|
2019-05-20 15:59:44 +09:00
|
|
|
return false;
|
|
|
|
|
|
2016-05-25 20:40:48 +08:00
|
|
|
/* DHCPv6 client will not be started if no IPv6 link-local address is configured. */
|
2019-08-27 23:15:24 +09:00
|
|
|
if (link_ipv6ll_enabled(link))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if (network_has_static_ipv6_configurations(link->network))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
2016-04-21 06:04:13 +05:30
|
|
|
}
|
|
|
|
|
|
2021-05-07 15:45:28 +09:00
|
|
|
bool link_is_ready_to_configure(Link *link, bool allow_unmanaged) {
|
|
|
|
|
assert(link);
|
|
|
|
|
|
2021-05-18 04:52:53 +09:00
|
|
|
if (!link->network) {
|
2021-05-07 15:45:28 +09:00
|
|
|
if (!allow_unmanaged)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return link_has_carrier(link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
|
|
|
|
|
return false;
|
|
|
|
|
|
2021-06-07 16:26:10 +09:00
|
|
|
if (!link->network->configure_without_carrier) {
|
|
|
|
|
if (link->set_flags_messages > 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (!link_has_carrier(link))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2021-05-07 15:45:28 +09:00
|
|
|
|
2021-05-21 04:51:07 +09:00
|
|
|
if (link->set_link_messages > 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
2021-05-29 00:31:37 +09:00
|
|
|
if (!link->activated)
|
|
|
|
|
return false;
|
|
|
|
|
|
2021-05-07 15:45:28 +09:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-27 08:52:27 +09:00
|
|
|
void link_ntp_settings_clear(Link *link) {
|
|
|
|
|
link->ntp = strv_free(link->ntp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void link_dns_settings_clear(Link *link) {
|
2021-03-03 13:07:10 +09:00
|
|
|
if (link->n_dns != UINT_MAX)
|
2020-07-03 16:48:29 +09:00
|
|
|
for (unsigned i = 0; i < link->n_dns; i++)
|
|
|
|
|
in_addr_full_free(link->dns[i]);
|
2019-05-27 08:52:27 +09:00
|
|
|
link->dns = mfree(link->dns);
|
2021-03-03 13:07:10 +09:00
|
|
|
link->n_dns = UINT_MAX;
|
2019-05-27 08:52:27 +09:00
|
|
|
|
2021-03-13 16:12:55 +09:00
|
|
|
link->search_domains = ordered_set_free(link->search_domains);
|
|
|
|
|
link->route_domains = ordered_set_free(link->route_domains);
|
2019-05-27 08:52:27 +09:00
|
|
|
|
|
|
|
|
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 12:06:56 +09: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);
|
2021-12-06 01:35:55 +09:00
|
|
|
link->dhcp4_6rd_tunnel_name = mfree(link->dhcp4_6rd_tunnel_name);
|
2019-06-21 12:06:56 +09:00
|
|
|
|
2021-09-26 12:39:36 +09:00
|
|
|
link->lldp_rx = sd_lldp_rx_unref(link->lldp_rx);
|
2021-09-26 19:13:20 +09:00
|
|
|
link->lldp_tx = sd_lldp_tx_unref(link->lldp_tx);
|
2019-06-21 12:06:56 +09:00
|
|
|
|
|
|
|
|
ndisc_flush(link);
|
|
|
|
|
|
|
|
|
|
link->ipv4ll = sd_ipv4ll_unref(link->ipv4ll);
|
|
|
|
|
link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
|
2020-07-23 03:13:42 +09:00
|
|
|
link->dhcp6_lease = sd_dhcp6_lease_unref(link->dhcp6_lease);
|
2019-06-21 12:06:56 +09:00
|
|
|
link->ndisc = sd_ndisc_unref(link->ndisc);
|
|
|
|
|
link->radv = sd_radv_unref(link->radv);
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-27 14:01:46 +09:00
|
|
|
static Link *link_free(Link *link) {
|
|
|
|
|
assert(link);
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2019-05-27 08:52:27 +09:00
|
|
|
link_ntp_settings_clear(link);
|
|
|
|
|
link_dns_settings_clear(link);
|
|
|
|
|
|
2020-07-22 08:22:55 +09:00
|
|
|
link->routes = set_free(link->routes);
|
|
|
|
|
link->nexthops = set_free(link->nexthops);
|
|
|
|
|
link->neighbors = set_free(link->neighbors);
|
|
|
|
|
link->addresses = set_free(link->addresses);
|
2022-02-24 16:08:50 +09:00
|
|
|
link->qdiscs = set_free(link->qdiscs);
|
|
|
|
|
link->tclasses = set_free(link->tclasses);
|
2015-09-30 14:01:44 +02:00
|
|
|
|
2021-12-05 07:29:05 +09:00
|
|
|
link->dhcp_pd_prefixes = set_free(link->dhcp_pd_prefixes);
|
2021-04-20 10:50:36 +09:00
|
|
|
|
2019-06-21 12:06:56 +09:00
|
|
|
link_free_engines(link);
|
2014-12-11 09:59:55 +05:30
|
|
|
|
2013-11-24 23:36:58 +01:00
|
|
|
free(link->ifname);
|
2019-12-15 22:46:19 +09:00
|
|
|
strv_free(link->alternative_names);
|
2016-06-12 19:59:21 +02:00
|
|
|
free(link->kind);
|
2019-07-24 14:46:55 +09:00
|
|
|
free(link->ssid);
|
2021-11-13 10:50:03 +09:00
|
|
|
free(link->previous_ssid);
|
2020-06-03 16:19:29 +09:00
|
|
|
free(link->driver);
|
2016-06-09 13:44:31 +02:00
|
|
|
|
2021-03-03 16:31:28 +09:00
|
|
|
unlink_and_free(link->lease_file);
|
|
|
|
|
unlink_and_free(link->lldp_file);
|
|
|
|
|
unlink_and_free(link->state_file);
|
2013-11-24 23:36:58 +01:00
|
|
|
|
2022-07-23 20:00:44 +09:00
|
|
|
sd_device_unref(link->dev);
|
2022-02-18 00:01:28 +09:00
|
|
|
netdev_unref(link->netdev);
|
2014-03-21 19:23:35 +01:00
|
|
|
|
2015-02-17 04:06:57 -08:00
|
|
|
hashmap_free(link->bound_to_links);
|
|
|
|
|
hashmap_free(link->bound_by_links);
|
|
|
|
|
|
2019-04-15 16:38:45 +09:00
|
|
|
set_free_with_destructor(link->slaves, link_unref);
|
2019-02-20 11:32:29 +09:00
|
|
|
|
2019-05-04 08:05:11 +02:00
|
|
|
network_unref(link->network);
|
|
|
|
|
|
2021-11-13 10:50:03 +09:00
|
|
|
sd_event_source_disable_unref(link->carrier_lost_timer);
|
|
|
|
|
|
2018-08-27 14:01:46 +09:00
|
|
|
return mfree(link);
|
2013-10-17 03:18:36 +02:00
|
|
|
}
|
|
|
|
|
|
2018-08-27 14:01:46 +09:00
|
|
|
DEFINE_TRIVIAL_REF_UNREF_FUNC(Link, link, link_free);
|
2014-05-08 18:54:26 +02:00
|
|
|
|
2021-06-25 15:58:30 +09:00
|
|
|
int link_get_by_index(Manager *m, int ifindex, Link **ret) {
|
2014-02-18 21:42:05 +01:00
|
|
|
Link *link;
|
|
|
|
|
|
|
|
|
|
assert(m);
|
2020-06-25 13:17:37 +09:00
|
|
|
assert(ifindex > 0);
|
2014-02-18 21:42:05 +01:00
|
|
|
|
2021-06-25 15:58:30 +09:00
|
|
|
link = hashmap_get(m->links_by_index, INT_TO_PTR(ifindex));
|
2014-02-18 21:42:05 +01:00
|
|
|
if (!link)
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
2021-05-14 16:00:52 +09:00
|
|
|
if (ret)
|
|
|
|
|
*ret = link;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2014-02-18 21:42:05 +01:00
|
|
|
|
2021-05-14 16:00:52 +09:00
|
|
|
int link_get_by_name(Manager *m, const char *ifname, Link **ret) {
|
|
|
|
|
Link *link;
|
|
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
assert(ifname);
|
|
|
|
|
|
|
|
|
|
link = hashmap_get(m->links_by_name, ifname);
|
|
|
|
|
if (!link)
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
|
*ret = link;
|
2014-02-18 21:42:05 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-25 16:25:48 +09:00
|
|
|
int link_get_by_hw_addr(Manager *m, const struct hw_addr_data *hw_addr, Link **ret) {
|
|
|
|
|
Link *link;
|
|
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
assert(hw_addr);
|
|
|
|
|
|
|
|
|
|
link = hashmap_get(m->links_by_hw_addr, hw_addr);
|
|
|
|
|
if (!link)
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
|
*ret = link;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 12:33:28 +09:00
|
|
|
int link_get_master(Link *link, Link **ret) {
|
|
|
|
|
assert(link);
|
|
|
|
|
assert(link->manager);
|
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
|
|
if (link->master_ifindex <= 0 || link->master_ifindex == link->ifindex)
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
2021-06-25 15:58:30 +09:00
|
|
|
return link_get_by_index(link->manager, link->master_ifindex, ret);
|
2021-05-26 12:33:28 +09:00
|
|
|
}
|
|
|
|
|
|
2019-05-20 15:59:44 +09: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 20:56:01 +09: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);
|
2021-01-20 16:56:21 +09:00
|
|
|
link_dirty(link);
|
2015-02-04 11:44:37 +01:00
|
|
|
}
|
|
|
|
|
|
2020-10-15 07:56:27 +09:00
|
|
|
int link_stop_engines(Link *link, bool may_keep_dhcp) {
|
2014-04-22 19:25:31 +02:00
|
|
|
int r = 0, k;
|
|
|
|
|
|
|
|
|
|
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 &&
|
2021-06-22 04:08:19 +09:00
|
|
|
!link->network->dhcp_send_decline && /* IPv4 ACD for the DHCPv4 address is running. */
|
2019-10-01 17:12:31 +02:00
|
|
|
(link->manager->restarting ||
|
|
|
|
|
FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP_ON_STOP));
|
|
|
|
|
|
2020-10-15 07:38:45 +09:00
|
|
|
if (!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
|
|
|
}
|
|
|
|
|
|
2020-10-15 07:56:27 +09:00
|
|
|
k = sd_dhcp_server_stop(link->dhcp_server);
|
|
|
|
|
if (k < 0)
|
|
|
|
|
r = log_link_warning_errno(link, k, "Could not stop DHCPv4 server: %m");
|
|
|
|
|
|
2021-09-26 12:39:36 +09:00
|
|
|
k = sd_lldp_rx_stop(link->lldp_rx);
|
2020-10-15 07:57:33 +09:00
|
|
|
if (k < 0)
|
2021-09-26 19:13:20 +09:00
|
|
|
r = log_link_warning_errno(link, k, "Could not stop LLDP Rx: %m");
|
|
|
|
|
|
|
|
|
|
k = sd_lldp_tx_stop(link->lldp_tx);
|
|
|
|
|
if (k < 0)
|
|
|
|
|
r = log_link_warning_errno(link, k, "Could not stop LLDP Tx: %m");
|
2020-10-15 07:57:33 +09:00
|
|
|
|
2020-10-15 07:38:45 +09:00
|
|
|
k = sd_ipv4ll_stop(link->ipv4ll);
|
|
|
|
|
if (k < 0)
|
|
|
|
|
r = log_link_warning_errno(link, k, "Could not stop IPv4 link-local: %m");
|
2014-03-05 08:13:30 +01:00
|
|
|
|
2021-06-22 04:08:19 +09:00
|
|
|
k = ipv4acd_stop(link);
|
2020-10-02 12:12:25 +09:00
|
|
|
if (k < 0)
|
|
|
|
|
r = log_link_warning_errno(link, k, "Could not stop IPv4 ACD client: %m");
|
2019-11-21 16:54:52 +01:00
|
|
|
|
2020-10-15 07:38:45 +09:00
|
|
|
k = sd_dhcp6_client_stop(link->dhcp6_client);
|
|
|
|
|
if (k < 0)
|
|
|
|
|
r = log_link_warning_errno(link, k, "Could not stop DHCPv6 client: %m");
|
2014-06-25 12:36:55 +03:00
|
|
|
|
2021-12-05 07:29:05 +09:00
|
|
|
k = dhcp_pd_remove(link, /* only_marked = */ false);
|
2020-10-04 07:37:22 +09:00
|
|
|
if (k < 0)
|
|
|
|
|
r = log_link_warning_errno(link, k, "Could not remove DHCPv6 PD addresses and routes: %m");
|
2020-07-23 03:13:42 +09:00
|
|
|
|
2020-10-15 07:38:45 +09:00
|
|
|
k = sd_ndisc_stop(link->ndisc);
|
|
|
|
|
if (k < 0)
|
|
|
|
|
r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m");
|
2014-06-19 15:40:01 +03:00
|
|
|
|
2022-01-31 19:09:30 +09:00
|
|
|
ndisc_flush(link);
|
|
|
|
|
|
2020-10-15 07:38:45 +09:00
|
|
|
k = sd_radv_stop(link->radv);
|
|
|
|
|
if (k < 0)
|
|
|
|
|
r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Advertisement: %m");
|
2017-05-12 16:48:33 +03:00
|
|
|
|
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 23:39:04 +05:30
|
|
|
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
|
|
|
|
2020-10-15 07:56:27 +09:00
|
|
|
(void) link_stop_engines(link, false);
|
2013-11-14 16:22:51 +01:00
|
|
|
}
|
|
|
|
|
|
2018-12-05 20:39:41 +11:00
|
|
|
void link_check_ready(Link *link) {
|
|
|
|
|
Address *a;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
2020-07-22 06:07:42 +09:00
|
|
|
if (link->state == LINK_STATE_CONFIGURED)
|
|
|
|
|
return;
|
|
|
|
|
|
2020-11-23 13:55:26 +09:00
|
|
|
if (link->state != LINK_STATE_CONFIGURING)
|
|
|
|
|
return (void) log_link_debug(link, "%s(): link is in %s state.", __func__, link_state_to_string(link->state));
|
2018-12-05 20:39:41 +11:00
|
|
|
|
|
|
|
|
if (!link->network)
|
2021-05-29 01:24:44 +09:00
|
|
|
return (void) log_link_debug(link, "%s(): link is unmanaged.", __func__);
|
2018-12-05 20:39:41 +11:00
|
|
|
|
2021-06-06 14:14:44 +09:00
|
|
|
if (!link->tc_configured)
|
|
|
|
|
return (void) log_link_debug(link, "%s(): traffic controls are not configured.", __func__);
|
2021-04-30 07:10:34 +09:00
|
|
|
|
2021-05-29 01:24:44 +09:00
|
|
|
if (link->set_link_messages > 0)
|
|
|
|
|
return (void) log_link_debug(link, "%s(): link layer is configuring.", __func__);
|
|
|
|
|
|
|
|
|
|
if (!link->activated)
|
|
|
|
|
return (void) log_link_debug(link, "%s(): link is not activated.", __func__);
|
|
|
|
|
|
2021-06-06 14:14:44 +09:00
|
|
|
if (link->iftype == ARPHRD_CAN) {
|
|
|
|
|
/* let's shortcut things for CAN which doesn't need most of checks below. */
|
|
|
|
|
link_set_state(link, LINK_STATE_CONFIGURED);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-07 05:34:08 +09:00
|
|
|
if (!link->stacked_netdevs_created)
|
|
|
|
|
return (void) log_link_debug(link, "%s(): stacked netdevs are not created.", __func__);
|
|
|
|
|
|
network: use request queue to configure addresses, routes, and nexthops
Why is this necessary? Several examples below.
- When a route sets prefsrc, then the address must be already assigned
(see issue #19285), and also it must be ready if IPv6.
- When a route or nexthop sets gateway, then the address must be reachable.
- When a route sets nexthop ID, then the corresponding nexthop must be
assigned.
- When a route sets multipath routes on another interface, then the
interface must exist and be ready to configure.
- When configuring address, the same address must not be under removing
(see issue #18108).
Etc,. etc,...
So, this makes all requests about addresses, routes, and nethops are once
stored in the queue, and will be processed when they are ready to configure.
Fixes #18108 and #19285.
2021-05-05 22:46:44 +09:00
|
|
|
if (!link->static_addresses_configured)
|
2020-11-23 13:55:26 +09:00
|
|
|
return (void) log_link_debug(link, "%s(): static addresses are not configured.", __func__);
|
2018-12-05 20:39:41 +11:00
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(a, link->addresses)
|
2022-06-03 16:37:38 +02:00
|
|
|
if (!address_is_ready(a))
|
|
|
|
|
return (void) log_link_debug(link, "%s(): address %s is not ready.", __func__,
|
|
|
|
|
IN_ADDR_PREFIX_TO_STRING(a->family, &a->in_addr, a->prefixlen));
|
2018-12-05 21:49:35 +11:00
|
|
|
|
2021-05-18 13:24:32 +09:00
|
|
|
if (!link->static_address_labels_configured)
|
|
|
|
|
return (void) log_link_debug(link, "%s(): static address labels are not configured.", __func__);
|
|
|
|
|
|
2021-05-14 14:05:00 +09:00
|
|
|
if (!link->static_bridge_fdb_configured)
|
|
|
|
|
return (void) log_link_debug(link, "%s(): static bridge MDB entries are not configured.", __func__);
|
|
|
|
|
|
2021-05-18 05:09:59 +09:00
|
|
|
if (!link->static_bridge_mdb_configured)
|
|
|
|
|
return (void) log_link_debug(link, "%s(): static bridge MDB entries are not configured.", __func__);
|
|
|
|
|
|
2021-05-18 14:21:42 +09:00
|
|
|
if (!link->static_ipv6_proxy_ndp_configured)
|
|
|
|
|
return (void) log_link_debug(link, "%s(): static IPv6 proxy NDP addresses are not configured.", __func__);
|
|
|
|
|
|
2021-05-07 16:05:31 +09:00
|
|
|
if (!link->static_neighbors_configured)
|
|
|
|
|
return (void) log_link_debug(link, "%s(): static neighbors are not configured.", __func__);
|
|
|
|
|
|
2020-11-23 13:55:26 +09:00
|
|
|
if (!link->static_nexthops_configured)
|
|
|
|
|
return (void) log_link_debug(link, "%s(): static nexthops are not configured.", __func__);
|
2019-10-04 21:40:51 +02:00
|
|
|
|
network: use request queue to configure addresses, routes, and nexthops
Why is this necessary? Several examples below.
- When a route sets prefsrc, then the address must be already assigned
(see issue #19285), and also it must be ready if IPv6.
- When a route or nexthop sets gateway, then the address must be reachable.
- When a route sets nexthop ID, then the corresponding nexthop must be
assigned.
- When a route sets multipath routes on another interface, then the
interface must exist and be ready to configure.
- When configuring address, the same address must not be under removing
(see issue #18108).
Etc,. etc,...
So, this makes all requests about addresses, routes, and nethops are once
stored in the queue, and will be processed when they are ready to configure.
Fixes #18108 and #19285.
2021-05-05 22:46:44 +09:00
|
|
|
if (!link->static_routes_configured)
|
|
|
|
|
return (void) log_link_debug(link, "%s(): static routes are not configured.", __func__);
|
|
|
|
|
|
2021-05-07 15:57:13 +09:00
|
|
|
if (!link->static_routing_policy_rules_configured)
|
2020-11-23 13:55:26 +09:00
|
|
|
return (void) log_link_debug(link, "%s(): static routing policy rules are not configured.", __func__);
|
2018-12-05 20:39:41 +11:00
|
|
|
|
2020-11-23 13:55:26 +09:00
|
|
|
if (!link->sr_iov_configured)
|
|
|
|
|
return (void) log_link_debug(link, "%s(): SR-IOV is not configured.", __func__);
|
2020-06-21 11:17:34 +00:00
|
|
|
|
network: always check dynamic address assignments before entering configured state
Previously (v248 or earlier), even if no static address is configured,
the link did not enter configured state, as e.g. Link::static_addresses_configured
is false until the link gained its carrier.
But, after the commit 1187fc337577cecd685d331eeab656be186ba3b2, the
situation was changed. Static addresses, routes, and etc are requested even
if the link does not have its carrier, and thus the link enters configured
state when no static address and etc are specified.
This makes the link does not enter configured state before it gains its
carrier when at least one of dynamic address assignment protocols (e.g.
DHCP) except for NDISC is enabled.
Note that, unfortunately, netplan always enables ConfigureWithoutCarrier=
for all virtual devices, e.g. bridge. See,
https://github.com/canonical/netplan/commit/978e20f902f6b92a46dc6e0050e2172e834e4617
So, we need to support e.g. the following strange config:
```
[Netowkr]
ConfigureWithoutCarrier=yes
DHCP=yes
```
Fixes #19855.
2021-06-11 20:34:17 +09:00
|
|
|
/* IPv6LL is assigned after the link gains its carrier. */
|
|
|
|
|
if (!link->network->configure_without_carrier &&
|
|
|
|
|
link_ipv6ll_enabled(link) &&
|
|
|
|
|
!in6_addr_is_set(&link->ipv6ll_address))
|
|
|
|
|
return (void) log_link_debug(link, "%s(): IPv6LL is not configured yet.", __func__);
|
2018-12-05 20:39:41 +11:00
|
|
|
|
2021-09-06 16:09:38 +09:00
|
|
|
bool has_dynamic_address = false;
|
|
|
|
|
SET_FOREACH(a, link->addresses) {
|
|
|
|
|
if (address_is_marked(a))
|
|
|
|
|
continue;
|
|
|
|
|
if (!address_exists(a))
|
|
|
|
|
continue;
|
|
|
|
|
if (IN_SET(a->source,
|
2021-10-15 02:53:52 +09:00
|
|
|
NETWORK_CONFIG_SOURCE_IPV4LL,
|
|
|
|
|
NETWORK_CONFIG_SOURCE_DHCP4,
|
|
|
|
|
NETWORK_CONFIG_SOURCE_DHCP6,
|
2021-12-05 07:29:05 +09:00
|
|
|
NETWORK_CONFIG_SOURCE_DHCP_PD,
|
2021-10-15 02:53:52 +09:00
|
|
|
NETWORK_CONFIG_SOURCE_NDISC)) {
|
2021-09-06 16:09:38 +09:00
|
|
|
has_dynamic_address = true;
|
network: always check dynamic address assignments before entering configured state
Previously (v248 or earlier), even if no static address is configured,
the link did not enter configured state, as e.g. Link::static_addresses_configured
is false until the link gained its carrier.
But, after the commit 1187fc337577cecd685d331eeab656be186ba3b2, the
situation was changed. Static addresses, routes, and etc are requested even
if the link does not have its carrier, and thus the link enters configured
state when no static address and etc are specified.
This makes the link does not enter configured state before it gains its
carrier when at least one of dynamic address assignment protocols (e.g.
DHCP) except for NDISC is enabled.
Note that, unfortunately, netplan always enables ConfigureWithoutCarrier=
for all virtual devices, e.g. bridge. See,
https://github.com/canonical/netplan/commit/978e20f902f6b92a46dc6e0050e2172e834e4617
So, we need to support e.g. the following strange config:
```
[Netowkr]
ConfigureWithoutCarrier=yes
DHCP=yes
```
Fixes #19855.
2021-06-11 20:34:17 +09:00
|
|
|
break;
|
2020-07-12 08:23:19 +09:00
|
|
|
}
|
2021-09-06 16:09:38 +09:00
|
|
|
}
|
network: always check dynamic address assignments before entering configured state
Previously (v248 or earlier), even if no static address is configured,
the link did not enter configured state, as e.g. Link::static_addresses_configured
is false until the link gained its carrier.
But, after the commit 1187fc337577cecd685d331eeab656be186ba3b2, the
situation was changed. Static addresses, routes, and etc are requested even
if the link does not have its carrier, and thus the link enters configured
state when no static address and etc are specified.
This makes the link does not enter configured state before it gains its
carrier when at least one of dynamic address assignment protocols (e.g.
DHCP) except for NDISC is enabled.
Note that, unfortunately, netplan always enables ConfigureWithoutCarrier=
for all virtual devices, e.g. bridge. See,
https://github.com/canonical/netplan/commit/978e20f902f6b92a46dc6e0050e2172e834e4617
So, we need to support e.g. the following strange config:
```
[Netowkr]
ConfigureWithoutCarrier=yes
DHCP=yes
```
Fixes #19855.
2021-06-11 20:34:17 +09:00
|
|
|
|
2021-09-06 16:09:38 +09:00
|
|
|
if ((link_ipv4ll_enabled(link) || link_dhcp4_enabled(link) || link_dhcp6_with_address_enabled(link) ||
|
2021-12-05 07:29:05 +09:00
|
|
|
(link_dhcp_pd_is_enabled(link) && link->network->dhcp_pd_assign)) && !has_dynamic_address)
|
network: always check dynamic address assignments before entering configured state
Previously (v248 or earlier), even if no static address is configured,
the link did not enter configured state, as e.g. Link::static_addresses_configured
is false until the link gained its carrier.
But, after the commit 1187fc337577cecd685d331eeab656be186ba3b2, the
situation was changed. Static addresses, routes, and etc are requested even
if the link does not have its carrier, and thus the link enters configured
state when no static address and etc are specified.
This makes the link does not enter configured state before it gains its
carrier when at least one of dynamic address assignment protocols (e.g.
DHCP) except for NDISC is enabled.
Note that, unfortunately, netplan always enables ConfigureWithoutCarrier=
for all virtual devices, e.g. bridge. See,
https://github.com/canonical/netplan/commit/978e20f902f6b92a46dc6e0050e2172e834e4617
So, we need to support e.g. the following strange config:
```
[Netowkr]
ConfigureWithoutCarrier=yes
DHCP=yes
```
Fixes #19855.
2021-06-11 20:34:17 +09:00
|
|
|
/* When DHCP[46] or IPv4LL is enabled, at least one address is acquired by them. */
|
2021-12-05 07:29:05 +09:00
|
|
|
return (void) log_link_debug(link, "%s(): DHCPv4, DHCPv6, DHCP-PD or IPv4LL is enabled but no dynamic address is assigned yet.", __func__);
|
network: always check dynamic address assignments before entering configured state
Previously (v248 or earlier), even if no static address is configured,
the link did not enter configured state, as e.g. Link::static_addresses_configured
is false until the link gained its carrier.
But, after the commit 1187fc337577cecd685d331eeab656be186ba3b2, the
situation was changed. Static addresses, routes, and etc are requested even
if the link does not have its carrier, and thus the link enters configured
state when no static address and etc are specified.
This makes the link does not enter configured state before it gains its
carrier when at least one of dynamic address assignment protocols (e.g.
DHCP) except for NDISC is enabled.
Note that, unfortunately, netplan always enables ConfigureWithoutCarrier=
for all virtual devices, e.g. bridge. See,
https://github.com/canonical/netplan/commit/978e20f902f6b92a46dc6e0050e2172e834e4617
So, we need to support e.g. the following strange config:
```
[Netowkr]
ConfigureWithoutCarrier=yes
DHCP=yes
```
Fixes #19855.
2021-06-11 20:34:17 +09:00
|
|
|
|
|
|
|
|
/* Ignore NDisc when ConfigureWithoutCarrier= is enabled, as IPv6AcceptRA= is enabled by default. */
|
2021-09-06 16:09:38 +09:00
|
|
|
if (link_ipv4ll_enabled(link) || link_dhcp4_enabled(link) ||
|
2021-12-05 07:29:05 +09:00
|
|
|
link_dhcp6_enabled(link) || link_dhcp_pd_is_enabled(link) ||
|
2021-09-06 16:09:38 +09:00
|
|
|
(!link->network->configure_without_carrier && link_ipv6_accept_ra_enabled(link))) {
|
network: always check dynamic address assignments before entering configured state
Previously (v248 or earlier), even if no static address is configured,
the link did not enter configured state, as e.g. Link::static_addresses_configured
is false until the link gained its carrier.
But, after the commit 1187fc337577cecd685d331eeab656be186ba3b2, the
situation was changed. Static addresses, routes, and etc are requested even
if the link does not have its carrier, and thus the link enters configured
state when no static address and etc are specified.
This makes the link does not enter configured state before it gains its
carrier when at least one of dynamic address assignment protocols (e.g.
DHCP) except for NDISC is enabled.
Note that, unfortunately, netplan always enables ConfigureWithoutCarrier=
for all virtual devices, e.g. bridge. See,
https://github.com/canonical/netplan/commit/978e20f902f6b92a46dc6e0050e2172e834e4617
So, we need to support e.g. the following strange config:
```
[Netowkr]
ConfigureWithoutCarrier=yes
DHCP=yes
```
Fixes #19855.
2021-06-11 20:34:17 +09:00
|
|
|
|
2021-09-06 16:09:38 +09:00
|
|
|
if (!link->ipv4ll_address_configured && !link->dhcp4_configured &&
|
2021-12-05 07:29:05 +09:00
|
|
|
!link->dhcp6_configured && !link->dhcp_pd_configured && !link->ndisc_configured)
|
network: always check dynamic address assignments before entering configured state
Previously (v248 or earlier), even if no static address is configured,
the link did not enter configured state, as e.g. Link::static_addresses_configured
is false until the link gained its carrier.
But, after the commit 1187fc337577cecd685d331eeab656be186ba3b2, the
situation was changed. Static addresses, routes, and etc are requested even
if the link does not have its carrier, and thus the link enters configured
state when no static address and etc are specified.
This makes the link does not enter configured state before it gains its
carrier when at least one of dynamic address assignment protocols (e.g.
DHCP) except for NDISC is enabled.
Note that, unfortunately, netplan always enables ConfigureWithoutCarrier=
for all virtual devices, e.g. bridge. See,
https://github.com/canonical/netplan/commit/978e20f902f6b92a46dc6e0050e2172e834e4617
So, we need to support e.g. the following strange config:
```
[Netowkr]
ConfigureWithoutCarrier=yes
DHCP=yes
```
Fixes #19855.
2021-06-11 20:34:17 +09:00
|
|
|
/* When DHCP[46], NDisc, or IPv4LL is enabled, at least one protocol must be finished. */
|
|
|
|
|
return (void) log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__);
|
|
|
|
|
|
2021-12-05 07:29:05 +09:00
|
|
|
log_link_debug(link, "%s(): IPv4LL:%s DHCPv4:%s DHCPv6:%s DHCP-PD:%s NDisc:%s",
|
network: always check dynamic address assignments before entering configured state
Previously (v248 or earlier), even if no static address is configured,
the link did not enter configured state, as e.g. Link::static_addresses_configured
is false until the link gained its carrier.
But, after the commit 1187fc337577cecd685d331eeab656be186ba3b2, the
situation was changed. Static addresses, routes, and etc are requested even
if the link does not have its carrier, and thus the link enters configured
state when no static address and etc are specified.
This makes the link does not enter configured state before it gains its
carrier when at least one of dynamic address assignment protocols (e.g.
DHCP) except for NDISC is enabled.
Note that, unfortunately, netplan always enables ConfigureWithoutCarrier=
for all virtual devices, e.g. bridge. See,
https://github.com/canonical/netplan/commit/978e20f902f6b92a46dc6e0050e2172e834e4617
So, we need to support e.g. the following strange config:
```
[Netowkr]
ConfigureWithoutCarrier=yes
DHCP=yes
```
Fixes #19855.
2021-06-11 20:34:17 +09:00
|
|
|
__func__,
|
|
|
|
|
yes_no(link->ipv4ll_address_configured),
|
2021-09-06 16:09:38 +09:00
|
|
|
yes_no(link->dhcp4_configured),
|
|
|
|
|
yes_no(link->dhcp6_configured),
|
2021-12-05 07:29:05 +09:00
|
|
|
yes_no(link->dhcp_pd_configured),
|
2021-09-06 16:09:38 +09:00
|
|
|
yes_no(link->ndisc_configured));
|
2019-06-14 05:16:11 +09:00
|
|
|
}
|
2018-12-05 20:39:41 +11:00
|
|
|
|
2021-05-27 01:20:29 +09:00
|
|
|
link_set_state(link, LINK_STATE_CONFIGURED);
|
2018-12-05 20:39:41 +11:00
|
|
|
}
|
|
|
|
|
|
2021-05-18 14:42:47 +09:00
|
|
|
static int link_request_static_configs(Link *link) {
|
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
|
|
|
|
2021-05-18 13:24:32 +09:00
|
|
|
r = link_request_static_addresses(link);
|
2021-05-07 15:57:13 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2021-05-18 13:24:32 +09:00
|
|
|
r = link_request_static_address_labels(link);
|
2018-12-30 22:07:23 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2018-11-28 19:00:58 -08:00
|
|
|
|
2021-05-14 14:05:00 +09:00
|
|
|
r = link_request_static_bridge_fdb(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2021-05-18 05:45:28 +09:00
|
|
|
r = link_request_static_bridge_mdb(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2021-05-18 14:21:42 +09:00
|
|
|
r = link_request_static_ipv6_proxy_ndp_addresses(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2021-05-07 16:05:31 +09:00
|
|
|
r = link_request_static_neighbors(link);
|
2020-10-02 11:17:49 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2020-02-27 13:32:43 +01:00
|
|
|
|
network: use request queue to configure addresses, routes, and nexthops
Why is this necessary? Several examples below.
- When a route sets prefsrc, then the address must be already assigned
(see issue #19285), and also it must be ready if IPv6.
- When a route or nexthop sets gateway, then the address must be reachable.
- When a route sets nexthop ID, then the corresponding nexthop must be
assigned.
- When a route sets multipath routes on another interface, then the
interface must exist and be ready to configure.
- When configuring address, the same address must not be under removing
(see issue #18108).
Etc,. etc,...
So, this makes all requests about addresses, routes, and nethops are once
stored in the queue, and will be processed when they are ready to configure.
Fixes #18108 and #19285.
2021-05-05 22:46:44 +09:00
|
|
|
r = link_request_static_nexthops(link, false);
|
2020-09-30 01:33:25 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2014-01-01 15:16:34 +01:00
|
|
|
|
network: use request queue to configure addresses, routes, and nexthops
Why is this necessary? Several examples below.
- When a route sets prefsrc, then the address must be already assigned
(see issue #19285), and also it must be ready if IPv6.
- When a route or nexthop sets gateway, then the address must be reachable.
- When a route sets nexthop ID, then the corresponding nexthop must be
assigned.
- When a route sets multipath routes on another interface, then the
interface must exist and be ready to configure.
- When configuring address, the same address must not be under removing
(see issue #18108).
Etc,. etc,...
So, this makes all requests about addresses, routes, and nethops are once
stored in the queue, and will be processed when they are ready to configure.
Fixes #18108 and #19285.
2021-05-05 22:46:44 +09:00
|
|
|
r = link_request_static_routes(link, false);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = link_request_static_routing_policy_rules(link);
|
2020-10-02 16:35:54 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2015-01-30 19:54:01 +01:00
|
|
|
|
2013-11-14 16:22:51 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 14:52:45 +09:00
|
|
|
static int link_request_stacked_netdevs(Link *link) {
|
|
|
|
|
NetDev *netdev;
|
2020-06-17 16:28:39 -04:00
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
2021-05-26 14:52:45 +09:00
|
|
|
link->stacked_netdevs_created = false;
|
2020-06-17 16:28:39 -04:00
|
|
|
|
2021-05-26 14:52:45 +09:00
|
|
|
HASHMAP_FOREACH(netdev, link->network->stacked_netdevs) {
|
2021-08-12 14:38:34 +09:00
|
|
|
r = link_request_stacked_netdev(link, netdev);
|
2021-05-26 14:52:45 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
}
|
2020-06-17 16:28:39 -04:00
|
|
|
|
2021-12-08 01:36:07 +09:00
|
|
|
if (link->create_stacked_netdev_messages == 0) {
|
2021-05-26 14:52:45 +09:00
|
|
|
link->stacked_netdevs_created = true;
|
2021-12-08 01:36:07 +09:00
|
|
|
link_check_ready(link);
|
|
|
|
|
}
|
2020-06-17 16:28:39 -04:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-18 14:46:22 +09:00
|
|
|
static int link_acquire_dynamic_ipv6_conf(Link *link) {
|
2015-11-10 21:30:59 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
2021-10-21 23:36:04 +09:00
|
|
|
r = radv_start(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_warning_errno(link, r, "Failed to start IPv6 Router Advertisement engine: %m");
|
2017-05-12 16:48:33 +03:00
|
|
|
|
2021-04-10 11:47:50 +09:00
|
|
|
r = ndisc_start(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_warning_errno(link, r, "Failed to start IPv6 Router Discovery: %m");
|
2020-02-15 13:51:34 +01:00
|
|
|
|
2021-04-10 11:47:50 +09:00
|
|
|
r = dhcp6_start(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_warning_errno(link, r, "Failed to start DHCPv6 client: %m");
|
2020-02-15 13:51:34 +01:00
|
|
|
|
2015-11-10 21:30:59 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-18 14:46:22 +09:00
|
|
|
static int link_acquire_dynamic_ipv4_conf(Link *link) {
|
2014-01-03 02:07:56 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
assert(link->manager);
|
|
|
|
|
assert(link->manager->event);
|
|
|
|
|
|
2020-10-08 20:14:51 +02:00
|
|
|
if (link->dhcp_client) {
|
2021-04-10 11:47:50 +09:00
|
|
|
r = dhcp4_start(link);
|
2020-10-08 20:14:51 +02:00
|
|
|
if (r < 0)
|
2021-04-10 11:47:50 +09:00
|
|
|
return log_link_warning_errno(link, r, "Failed to start DHCPv4 client: %m");
|
2020-10-08 20:14:51 +02:00
|
|
|
|
2021-06-15 23:24:46 +09:00
|
|
|
log_link_debug(link, "Acquiring DHCPv4 lease.");
|
2014-02-28 16:10:20 +01:00
|
|
|
|
2021-06-15 23:24:46 +09:00
|
|
|
} else if (link->ipv4ll) {
|
2022-06-30 10:27:27 +02:00
|
|
|
if (in4_addr_is_set(&link->network->ipv4ll_start_address)) {
|
|
|
|
|
r = sd_ipv4ll_set_address(link->ipv4ll, &link->network->ipv4ll_start_address);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_warning_errno(link, r, "Could not set IPv4 link-local start address: %m");
|
|
|
|
|
}
|
|
|
|
|
|
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");
|
2021-06-15 23:24:46 +09:00
|
|
|
|
|
|
|
|
log_link_debug(link, "Acquiring IPv4 link-local address.");
|
2014-01-03 02:07:56 +01:00
|
|
|
}
|
|
|
|
|
|
2021-05-18 16:12:40 +09:00
|
|
|
if (link->dhcp_server) {
|
|
|
|
|
r = sd_dhcp_server_start(link->dhcp_server);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_warning_errno(link, r, "Could not start DHCP server: %m");
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-22 04:08:19 +09:00
|
|
|
r = ipv4acd_start(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_warning_errno(link, r, "Could not start IPv4 ACD client: %m");
|
|
|
|
|
|
2016-04-29 04:33:29 +05:30
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-18 14:46:22 +09:00
|
|
|
static int link_acquire_dynamic_conf(Link *link) {
|
2016-04-29 04:33:29 +05:30
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
2021-10-21 23:36:04 +09:00
|
|
|
assert(link->network);
|
2016-04-29 04:33:29 +05:30
|
|
|
|
2021-05-18 14:46:22 +09:00
|
|
|
r = link_acquire_dynamic_ipv4_conf(link);
|
2016-04-29 04:33:29 +05:30
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2021-02-18 01:29:43 +09:00
|
|
|
if (in6_addr_is_set(&link->ipv6ll_address)) {
|
2021-05-18 14:46:22 +09:00
|
|
|
r = link_acquire_dynamic_ipv6_conf(link);
|
2016-04-29 04:33:29 +05:30
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-05 07:29:05 +09:00
|
|
|
if (!link_radv_enabled(link) || !link->network->dhcp_pd_announce) {
|
2021-10-21 23:36:04 +09:00
|
|
|
/* DHCPv6PD downstream does not require IPv6LL address. But may require RADV to be
|
|
|
|
|
* configured, and RADV may not be configured yet here. Only acquire subnet prefix when
|
|
|
|
|
* RADV is disabled, or the announcement of the prefix is disabled. Otherwise, the
|
|
|
|
|
* below will be called in radv_start(). */
|
2021-12-05 07:29:05 +09:00
|
|
|
r = dhcp_request_prefix_delegation(link);
|
2021-10-21 23:36:04 +09:00
|
|
|
if (r < 0)
|
2021-12-05 07:29:05 +09:00
|
|
|
return log_link_warning_errno(link, r, "Failed to request DHCP delegated subnet prefix: %m");
|
2021-10-21 23:36:04 +09:00
|
|
|
}
|
|
|
|
|
|
2021-09-26 19:13:20 +09:00
|
|
|
if (link->lldp_tx) {
|
|
|
|
|
r = sd_lldp_tx_start(link->lldp_tx);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_warning_errno(link, r, "Failed to start LLDP transmission: %m");
|
|
|
|
|
}
|
2016-02-21 14:14:08 +01:00
|
|
|
|
2021-09-26 12:39:36 +09:00
|
|
|
if (link->lldp_rx) {
|
|
|
|
|
r = sd_lldp_rx_start(link->lldp_rx);
|
2021-06-12 12:26:37 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_warning_errno(link, r, "Failed to start LLDP client: %m");
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-03 02:07:56 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-08 15:52:53 +09:00
|
|
|
int link_ipv6ll_gained(Link *link) {
|
2021-05-26 12:47:28 +09:00
|
|
|
int r;
|
2014-05-07 16:35:05 +02:00
|
|
|
|
2021-05-26 12:47:28 +09:00
|
|
|
assert(link);
|
2014-05-07 16:35:05 +02:00
|
|
|
|
2021-05-26 12:47:28 +09:00
|
|
|
log_link_info(link, "Gained IPv6LL");
|
2014-05-07 16:35:05 +02:00
|
|
|
|
2021-09-08 15:52:53 +09:00
|
|
|
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
r = link_acquire_dynamic_ipv6_conf(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2021-05-26 12:47:28 +09:00
|
|
|
link_check_ready(link);
|
|
|
|
|
return 0;
|
2014-05-07 16:35:05 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-29 00:31:37 +09:00
|
|
|
int link_handle_bound_to_list(Link *link) {
|
2015-02-17 04:06:57 -08:00
|
|
|
bool required_up = false;
|
|
|
|
|
bool link_is_up = false;
|
2021-05-26 13:04:26 +09:00
|
|
|
Link *l;
|
2015-02-17 04:06:57 -08:00
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
2021-06-06 15:32:24 +09:00
|
|
|
/* If at least one interface in bound_to_links has carrier, then make this interface up.
|
|
|
|
|
* If all interfaces in bound_to_links do not, then make this interface down. */
|
|
|
|
|
|
2015-02-17 04:06:57 -08:00
|
|
|
if (hashmap_isempty(link->bound_to_links))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (link->flags & IFF_UP)
|
|
|
|
|
link_is_up = true;
|
|
|
|
|
|
2021-05-26 13:04:26 +09:00
|
|
|
HASHMAP_FOREACH(l, link->bound_to_links)
|
2015-02-17 04:06:57 -08:00
|
|
|
if (link_has_carrier(l)) {
|
|
|
|
|
required_up = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 13:04:26 +09:00
|
|
|
if (!required_up && link_is_up)
|
2021-06-06 16:59:41 +09:00
|
|
|
return link_request_to_bring_up_or_down(link, /* up = */ false);
|
2021-05-26 13:04:26 +09:00
|
|
|
if (required_up && !link_is_up)
|
2021-06-06 16:59:41 +09:00
|
|
|
return link_request_to_bring_up_or_down(link, /* up = */ true);
|
2015-02-17 04:06:57 -08:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int link_handle_bound_by_list(Link *link) {
|
|
|
|
|
Link *l;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
2021-06-06 15:32:24 +09:00
|
|
|
/* Update up or down state of interfaces which depend on this interface's carrier state. */
|
|
|
|
|
|
2015-02-17 04:06:57 -08:00
|
|
|
if (hashmap_isempty(link->bound_by_links))
|
|
|
|
|
return 0;
|
|
|
|
|
|
2021-05-26 13:04:26 +09:00
|
|
|
HASHMAP_FOREACH(l, link->bound_by_links) {
|
2015-02-17 04:06:57 -08: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;
|
|
|
|
|
|
2021-01-14 06:42:50 +01:00
|
|
|
r = hashmap_ensure_put(h, NULL, INT_TO_PTR(carrier->ifindex), carrier);
|
2015-02-17 04:06:57 -08:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2021-01-20 16:56:21 +09:00
|
|
|
link_dirty(link);
|
|
|
|
|
|
2015-02-17 04:06:57 -08:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int link_new_bound_by_list(Link *link) {
|
|
|
|
|
Manager *m;
|
|
|
|
|
Link *carrier;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
assert(link->manager);
|
|
|
|
|
|
|
|
|
|
m = link->manager;
|
|
|
|
|
|
2021-06-25 15:58:30 +09:00
|
|
|
HASHMAP_FOREACH(carrier, m->links_by_index) {
|
2015-02-17 04:06:57 -08: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 04:06:57 -08:00
|
|
|
r = link_put_carrier(link, carrier, &link->bound_by_links);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH(carrier, link->bound_by_links) {
|
2015-02-17 04:06:57 -08:00
|
|
|
r = link_put_carrier(carrier, link, &carrier->bound_to_links);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int link_new_bound_to_list(Link *link) {
|
|
|
|
|
Manager *m;
|
|
|
|
|
Link *carrier;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
assert(link->manager);
|
|
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (strv_isempty(link->network->bind_carrier))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
m = link->manager;
|
|
|
|
|
|
2021-06-25 15:58:30 +09:00
|
|
|
HASHMAP_FOREACH(carrier, m->links_by_index) {
|
2020-01-12 12:26:26 +01:00
|
|
|
if (strv_fnmatch(link->network->bind_carrier, carrier->ifname)) {
|
2015-02-17 04:06:57 -08:00
|
|
|
r = link_put_carrier(link, carrier, &link->bound_to_links);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 13:04:26 +09:00
|
|
|
HASHMAP_FOREACH(carrier, link->bound_to_links) {
|
2015-02-17 04:06:57 -08:00
|
|
|
r = link_put_carrier(carrier, link, &carrier->bound_by_links);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void link_free_bound_to_list(Link *link) {
|
2021-01-20 16:56:21 +09:00
|
|
|
bool updated = false;
|
2015-02-17 04:06:57 -08:00
|
|
|
Link *bound_to;
|
|
|
|
|
|
2021-01-20 16:56:21 +09:00
|
|
|
assert(link);
|
|
|
|
|
|
|
|
|
|
while ((bound_to = hashmap_steal_first(link->bound_to_links))) {
|
|
|
|
|
updated = true;
|
2015-02-17 04:06:57 -08:00
|
|
|
|
|
|
|
|
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 04:06:57 -08:00
|
|
|
}
|
|
|
|
|
|
2021-01-20 16:56:21 +09:00
|
|
|
if (updated)
|
|
|
|
|
link_dirty(link);
|
2015-02-17 04:06:57 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void link_free_bound_by_list(Link *link) {
|
2021-01-20 16:56:21 +09:00
|
|
|
bool updated = false;
|
2015-02-17 04:06:57 -08:00
|
|
|
Link *bound_by;
|
|
|
|
|
|
2021-01-20 16:56:21 +09:00
|
|
|
assert(link);
|
|
|
|
|
|
|
|
|
|
while ((bound_by = hashmap_steal_first(link->bound_by_links))) {
|
|
|
|
|
updated = true;
|
2015-02-17 04:06:57 -08:00
|
|
|
|
|
|
|
|
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 04:06:57 -08:00
|
|
|
link_handle_bound_to_list(bound_by);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-20 16:56:21 +09:00
|
|
|
if (updated)
|
|
|
|
|
link_dirty(link);
|
2015-02-17 04:06:57 -08:00
|
|
|
}
|
|
|
|
|
|
2021-05-26 12:33:28 +09:00
|
|
|
static int link_append_to_master(Link *link) {
|
2019-04-15 16:38:45 +09:00
|
|
|
Link *master;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
2021-05-26 12:33:28 +09:00
|
|
|
/* - The link may have no master.
|
|
|
|
|
* - RTM_NEWLINK message about master interface may not be received yet. */
|
|
|
|
|
if (link_get_master(link, &master) < 0)
|
|
|
|
|
return 0;
|
2019-04-15 16:38:45 +09:00
|
|
|
|
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 16:38:45 +09:00
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
link_ref(link);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 12:33:28 +09:00
|
|
|
static void link_drop_from_master(Link *link) {
|
2019-04-15 16:38:45 +09:00
|
|
|
Link *master;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
2021-05-26 12:33:28 +09:00
|
|
|
if (!link->manager)
|
2019-04-15 16:38:45 +09:00
|
|
|
return;
|
|
|
|
|
|
2021-05-26 12:33:28 +09:00
|
|
|
if (link_get_master(link, &master) < 0)
|
2019-04-15 16:38:45 +09:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
link_unref(set_remove(master->slaves, link));
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-17 15:32:57 +09:00
|
|
|
static void link_drop_requests(Link *link) {
|
|
|
|
|
Request *req;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
assert(link->manager);
|
|
|
|
|
|
|
|
|
|
ORDERED_SET_FOREACH(req, link->manager->request_queue)
|
|
|
|
|
if (req->link == link)
|
network: make Request object take Manager*
Previously, even though all Request object are owned by Manager, they
do not have direct reference to Manager, but through Link or NetDev
object. But, as Link or NetDev can be NULL, we need to conditionalize
how to access Manager from Request with the type of the request.
This makes the way simpler, as now Request object has direct reference
to Manager.
This also rename request_drop() -> request_detach(), as in the previous
commit, the reference counter is introduced, so even if a reference of
a Request object from Manager is dropped, the object may still alive.
The naming `request_drop()` sounds the object will freed by the
function. But it may not. And `request_detach()` suggests the object
will not be managed by Manager any more, and I think it is more
appropreate.
This is just a cleanup, and should not change any behavior.
2022-02-27 15:39:16 +09:00
|
|
|
request_detach(link->manager, req);
|
2021-05-17 15:32:57 +09:00
|
|
|
}
|
|
|
|
|
|
2021-05-14 15:58:15 +09:00
|
|
|
static Link *link_drop(Link *link) {
|
2021-05-17 15:40:15 +09:00
|
|
|
if (!link)
|
2021-05-14 15:58:15 +09:00
|
|
|
return NULL;
|
2015-02-17 04:06:57 -08:00
|
|
|
|
2021-05-17 15:40:15 +09:00
|
|
|
assert(link->manager);
|
|
|
|
|
|
2015-02-17 04:06:57 -08:00
|
|
|
link_set_state(link, LINK_STATE_LINGER);
|
|
|
|
|
|
2021-05-17 15:40:15 +09:00
|
|
|
/* Drop all references from other links and manager. Note that async netlink calls may have
|
|
|
|
|
* references to the link, and they will be dropped when we receive replies. */
|
|
|
|
|
|
2021-05-17 15:32:57 +09:00
|
|
|
link_drop_requests(link);
|
|
|
|
|
|
2022-02-01 11:37:45 +09:00
|
|
|
link_free_bound_to_list(link);
|
|
|
|
|
link_free_bound_by_list(link);
|
2015-02-17 04:06:57 -08:00
|
|
|
|
2021-05-26 12:33:28 +09:00
|
|
|
link_drop_from_master(link);
|
2019-04-15 16:38:45 +09:00
|
|
|
|
2021-09-29 17:32:55 +09:00
|
|
|
if (link->state_file)
|
|
|
|
|
(void) unlink(link->state_file);
|
|
|
|
|
|
2021-05-17 15:40:15 +09:00
|
|
|
link_clean(link);
|
|
|
|
|
|
2021-05-14 16:00:52 +09:00
|
|
|
STRV_FOREACH(n, link->alternative_names)
|
|
|
|
|
hashmap_remove(link->manager->links_by_name, *n);
|
|
|
|
|
hashmap_remove(link->manager->links_by_name, link->ifname);
|
|
|
|
|
|
2021-06-25 16:25:48 +09:00
|
|
|
/* bonding master and its slaves have the same hardware address. */
|
2022-01-29 00:30:22 +09:00
|
|
|
hashmap_remove_value(link->manager->links_by_hw_addr, &link->hw_addr, link);
|
2021-06-25 16:25:48 +09:00
|
|
|
|
2021-05-17 15:40:15 +09:00
|
|
|
/* The following must be called at last. */
|
2021-06-25 15:58:30 +09:00
|
|
|
assert_se(hashmap_remove(link->manager->links_by_index, INT_TO_PTR(link->ifindex)) == link);
|
2021-05-14 15:58:15 +09:00
|
|
|
return link_unref(link);
|
2015-02-17 04:06:57 -08:00
|
|
|
}
|
|
|
|
|
|
2015-10-02 16:52:49 +02:00
|
|
|
static int link_drop_foreign_config(Link *link) {
|
2020-10-28 20:27:23 +09:00
|
|
|
int k, r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
assert(link->manager);
|
2015-10-02 16:52:49 +02:00
|
|
|
|
2021-06-14 07:13:58 +09:00
|
|
|
/* Drop foreign config, but ignore unmanaged, loopback, or critical interfaces. We do not want
|
|
|
|
|
* to remove loopback address or addresses used for root NFS. */
|
|
|
|
|
|
|
|
|
|
if (IN_SET(link->state, LINK_STATE_UNMANAGED, LINK_STATE_PENDING, LINK_STATE_INITIALIZED))
|
|
|
|
|
return 0;
|
|
|
|
|
if (FLAGS_SET(link->flags, IFF_LOOPBACK))
|
|
|
|
|
return 0;
|
|
|
|
|
if (link->network->keep_configuration == KEEP_CONFIGURATION_YES)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2021-05-07 16:35:42 +09:00
|
|
|
r = link_drop_foreign_routes(link);
|
2020-10-28 20:27:23 +09:00
|
|
|
|
2021-02-15 10:00:14 +09:00
|
|
|
k = link_drop_foreign_nexthops(link);
|
|
|
|
|
if (k < 0 && r >= 0)
|
|
|
|
|
r = k;
|
|
|
|
|
|
2021-05-07 16:35:42 +09:00
|
|
|
k = link_drop_foreign_addresses(link);
|
|
|
|
|
if (k < 0 && r >= 0)
|
|
|
|
|
r = k;
|
|
|
|
|
|
|
|
|
|
k = link_drop_foreign_neighbors(link);
|
|
|
|
|
if (k < 0 && r >= 0)
|
|
|
|
|
r = k;
|
|
|
|
|
|
2020-10-28 20:27:23 +09:00
|
|
|
k = manager_drop_foreign_routing_policy_rules(link->manager);
|
|
|
|
|
if (k < 0 && r >= 0)
|
|
|
|
|
r = k;
|
|
|
|
|
|
|
|
|
|
return r;
|
2015-10-02 16:52:49 +02:00
|
|
|
}
|
|
|
|
|
|
2022-01-31 19:08:27 +09:00
|
|
|
static int link_drop_managed_config(Link *link) {
|
2020-10-28 20:27:23 +09:00
|
|
|
int k, r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
assert(link->manager);
|
2016-08-04 19:26:39 +05:30
|
|
|
|
2022-01-31 19:08:27 +09:00
|
|
|
r = link_drop_managed_routes(link);
|
2020-10-28 20:27:23 +09:00
|
|
|
|
2022-01-31 19:08:27 +09:00
|
|
|
k = link_drop_managed_nexthops(link);
|
2021-02-15 10:00:14 +09:00
|
|
|
if (k < 0 && r >= 0)
|
|
|
|
|
r = k;
|
|
|
|
|
|
2022-01-31 19:08:27 +09:00
|
|
|
k = link_drop_managed_addresses(link);
|
2021-05-07 16:35:42 +09:00
|
|
|
if (k < 0 && r >= 0)
|
|
|
|
|
r = k;
|
|
|
|
|
|
2022-01-31 19:08:27 +09:00
|
|
|
k = link_drop_managed_neighbors(link);
|
2021-05-07 16:35:42 +09:00
|
|
|
if (k < 0 && r >= 0)
|
|
|
|
|
r = k;
|
|
|
|
|
|
2022-01-31 19:08:27 +09:00
|
|
|
k = link_drop_managed_routing_policy_rules(link);
|
2020-10-28 20:27:23 +09:00
|
|
|
if (k < 0 && r >= 0)
|
|
|
|
|
r = k;
|
2016-08-04 19:26:39 +05:30
|
|
|
|
2020-10-28 20:27:23 +09:00
|
|
|
return r;
|
2016-08-04 19:26:39 +05:30
|
|
|
}
|
|
|
|
|
|
2021-10-26 02:29:09 +09:00
|
|
|
static void link_foreignize_config(Link *link) {
|
|
|
|
|
assert(link);
|
|
|
|
|
assert(link->manager);
|
|
|
|
|
|
|
|
|
|
link_foreignize_routes(link);
|
|
|
|
|
link_foreignize_nexthops(link);
|
|
|
|
|
link_foreignize_addresses(link);
|
|
|
|
|
link_foreignize_neighbors(link);
|
|
|
|
|
link_foreignize_routing_policy_rules(link);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-21 04:02:01 +09:00
|
|
|
static int link_configure(Link *link) {
|
2019-10-30 00:19:34 +09:00
|
|
|
int r;
|
|
|
|
|
|
2013-12-14 23:39:04 +05:30
|
|
|
assert(link);
|
2014-08-06 15:54:03 +02:00
|
|
|
assert(link->network);
|
2019-04-15 17:34:00 +09:00
|
|
|
assert(link->state == LINK_STATE_INITIALIZED);
|
2014-03-09 14:43:37 +01:00
|
|
|
|
2021-05-26 14:52:45 +09:00
|
|
|
link_set_state(link, LINK_STATE_CONFIGURING);
|
|
|
|
|
|
2022-01-31 22:30:39 +09:00
|
|
|
r = link_new_bound_to_list(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2022-01-26 03:49:27 +09:00
|
|
|
r = link_request_traffic_control(link);
|
2019-10-30 00:19:34 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2021-06-06 14:14:44 +09:00
|
|
|
if (link->iftype == ARPHRD_CAN) {
|
|
|
|
|
/* let's shortcut things for CAN which doesn't need most of what's done below. */
|
|
|
|
|
r = link_request_to_set_can(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
return link_request_to_activate(link);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-23 16:48:36 +09:00
|
|
|
r = link_request_sr_iov_vfs(link);
|
2020-06-21 11:17:34 +00:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2020-10-04 06:25:44 +09:00
|
|
|
r = link_set_sysctl(link);
|
2016-04-14 15:26:57 +05:30
|
|
|
if (r < 0)
|
2020-10-04 06:25:44 +09:00
|
|
|
return r;
|
2016-04-14 15:26:57 +05:30
|
|
|
|
2021-06-13 05:12:03 +09:00
|
|
|
r = link_request_to_set_mac(link, /* allow_retry = */ true);
|
2020-06-17 16:28:39 -04:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2021-11-08 09:41:51 +09:00
|
|
|
r = link_request_to_set_ipoib(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2021-05-21 13:50:39 +09:00
|
|
|
r = link_request_to_set_flags(link);
|
2016-08-04 19:30:58 +05:30
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2021-05-21 14:21:09 +09:00
|
|
|
r = link_request_to_set_group(link);
|
2020-04-07 14:36:55 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2021-05-26 14:52:45 +09:00
|
|
|
r = link_configure_mtu(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = link_request_to_set_addrgen_mode(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = link_request_to_set_master(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = link_request_stacked_netdevs(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = link_request_to_set_bond(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = link_request_to_set_bridge(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = link_request_to_set_bridge_vlan(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = link_request_to_activate(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2020-10-04 07:37:22 +09:00
|
|
|
r = ipv4ll_configure(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2014-03-20 19:57:19 +01:00
|
|
|
|
2021-06-15 23:24:46 +09:00
|
|
|
r = link_request_dhcp4_client(link);
|
2020-10-04 07:37:22 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2017-11-24 21:03:05 +01:00
|
|
|
|
2021-06-15 23:24:46 +09:00
|
|
|
r = link_request_dhcp6_client(link);
|
2020-10-04 07:37:22 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2014-03-20 19:57:19 +01:00
|
|
|
|
2022-01-31 12:35:44 +09:00
|
|
|
r = link_request_ndisc(link);
|
2020-10-04 07:37:22 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2014-06-19 15:40:01 +03:00
|
|
|
|
2021-05-18 01:55:42 +09:00
|
|
|
r = link_request_dhcp_server(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2021-06-16 03:37:57 +09:00
|
|
|
r = link_request_radv(link);
|
2020-10-02 16:39:45 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2017-05-12 16:48:33 +03:00
|
|
|
|
2020-10-04 07:37:22 +09:00
|
|
|
r = link_lldp_rx_configure(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2014-11-23 09:56:14 +05:30
|
|
|
|
2021-09-26 19:13:20 +09:00
|
|
|
r = link_lldp_tx_configure(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2021-06-14 07:13:58 +09:00
|
|
|
r = link_drop_foreign_config(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
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 16:35:28 -05:00
|
|
|
|
2021-05-26 14:52:45 +09:00
|
|
|
r = link_request_static_configs(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
if (!link_has_carrier(link))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return link_acquire_dynamic_conf(link);
|
2014-04-15 14:21:44 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-12 20:58:06 +09:00
|
|
|
static int link_get_network(Link *link, Network **ret) {
|
|
|
|
|
Network *network;
|
2021-05-12 21:07:14 +09:00
|
|
|
int r;
|
2021-05-12 20:58:06 +09:00
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
assert(link->manager);
|
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
|
|
ORDERED_HASHMAP_FOREACH(network, link->manager->networks) {
|
|
|
|
|
bool warn = false;
|
|
|
|
|
|
2021-05-12 21:07:14 +09:00
|
|
|
r = net_match_config(
|
2021-05-12 20:58:06 +09:00
|
|
|
&network->match,
|
2022-07-23 20:00:44 +09:00
|
|
|
link->dev,
|
2021-11-05 02:59:11 +09:00
|
|
|
&link->hw_addr,
|
|
|
|
|
&link->permanent_hw_addr,
|
2021-05-12 20:58:06 +09:00
|
|
|
link->driver,
|
|
|
|
|
link->iftype,
|
2022-02-17 21:06:12 +09:00
|
|
|
link->kind,
|
2021-05-12 20:58:06 +09:00
|
|
|
link->ifname,
|
|
|
|
|
link->alternative_names,
|
|
|
|
|
link->wlan_iftype,
|
|
|
|
|
link->ssid,
|
2021-05-12 21:07:14 +09:00
|
|
|
&link->bssid);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
if (r == 0)
|
2021-05-12 20:58:06 +09:00
|
|
|
continue;
|
|
|
|
|
|
2022-07-23 20:00:44 +09:00
|
|
|
if (network->match.ifname && link->dev) {
|
2021-05-12 20:58:06 +09:00
|
|
|
uint8_t name_assign_type = NET_NAME_UNKNOWN;
|
|
|
|
|
const char *attr;
|
|
|
|
|
|
2022-07-23 20:00:44 +09:00
|
|
|
if (sd_device_get_sysattr_value(link->dev, "name_assign_type", &attr) >= 0)
|
2021-05-12 20:58:06 +09:00
|
|
|
(void) safe_atou8(attr, &name_assign_type);
|
|
|
|
|
|
|
|
|
|
warn = name_assign_type == NET_NAME_ENUM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log_link_full(link, warn ? LOG_WARNING : LOG_DEBUG,
|
|
|
|
|
"found matching network '%s'%s.",
|
|
|
|
|
network->filename,
|
|
|
|
|
warn ? ", based on potentially unpredictable interface name" : "");
|
|
|
|
|
|
|
|
|
|
if (network->unmanaged)
|
|
|
|
|
return -ENOENT;
|
|
|
|
|
|
|
|
|
|
*ret = network;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -ENOENT;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-12 11:46:01 +09:00
|
|
|
static int link_reconfigure_impl(Link *link, bool force) {
|
2021-06-14 06:58:06 +09:00
|
|
|
Network *network = NULL;
|
2022-02-18 00:01:28 +09:00
|
|
|
NetDev *netdev = NULL;
|
2019-07-04 13:52:03 +09:00
|
|
|
int r;
|
|
|
|
|
|
2021-05-26 13:45:14 +09:00
|
|
|
assert(link);
|
2019-12-15 22:46:19 +09:00
|
|
|
|
2022-01-31 16:32:05 +09:00
|
|
|
if (!IN_SET(link->state, LINK_STATE_INITIALIZED, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED, LINK_STATE_UNMANAGED))
|
|
|
|
|
return 0;
|
|
|
|
|
|
2022-02-18 00:01:28 +09:00
|
|
|
r = netdev_get(link->manager, link->ifname, &netdev);
|
|
|
|
|
if (r < 0 && r != -ENOENT)
|
|
|
|
|
return r;
|
|
|
|
|
|
2021-05-12 20:58:06 +09:00
|
|
|
r = link_get_network(link, &network);
|
2021-06-14 06:58:06 +09:00
|
|
|
if (r < 0 && r != -ENOENT)
|
2019-07-04 13:52:03 +09:00
|
|
|
return r;
|
|
|
|
|
|
2022-01-31 16:32:05 +09:00
|
|
|
if (link->state != LINK_STATE_UNMANAGED && !network)
|
|
|
|
|
/* If link is in initialized state, then link->network is also NULL. */
|
|
|
|
|
force = true;
|
|
|
|
|
|
2019-10-23 22:32:27 +09:00
|
|
|
if (link->network == network && !force)
|
2019-07-04 13:52:03 +09:00
|
|
|
return 0;
|
|
|
|
|
|
2022-01-31 16:32:05 +09:00
|
|
|
if (network) {
|
|
|
|
|
if (link->state == LINK_STATE_INITIALIZED)
|
|
|
|
|
log_link_info(link, "Configuring with %s.", network->filename);
|
|
|
|
|
else
|
|
|
|
|
log_link_info(link, "Reconfiguring with %s.", network->filename);
|
|
|
|
|
} else
|
|
|
|
|
log_link_full(link, link->state == LINK_STATE_INITIALIZED ? LOG_DEBUG : LOG_INFO,
|
|
|
|
|
"Unmanaging interface.");
|
2019-07-04 13:52:03 +09:00
|
|
|
|
|
|
|
|
/* Dropping old .network file */
|
2020-10-15 07:56:27 +09:00
|
|
|
r = link_stop_engines(link, false);
|
2019-12-15 22:46:19 +09:00
|
|
|
if (r < 0)
|
2019-07-04 13:52:03 +09:00
|
|
|
return r;
|
|
|
|
|
|
2021-05-07 15:39:16 +09:00
|
|
|
link_drop_requests(link);
|
|
|
|
|
|
2022-02-13 19:57:09 +09:00
|
|
|
if (network && !force && network->keep_configuration != KEEP_CONFIGURATION_YES)
|
2021-10-26 02:29:09 +09:00
|
|
|
/* When a new/updated .network file is assigned, first make all configs (addresses,
|
|
|
|
|
* routes, and so on) foreign, and then drop unnecessary configs later by
|
2022-02-13 19:57:09 +09:00
|
|
|
* link_drop_foreign_config() in link_configure().
|
|
|
|
|
* Note, when KeepConfiguration=yes, link_drop_foreign_config() does nothing. Hence,
|
|
|
|
|
* here we need to drop the configs such as addresses, routes, and so on configured by
|
|
|
|
|
* the previously assigned .network file. */
|
2021-10-26 02:29:09 +09:00
|
|
|
link_foreignize_config(link);
|
|
|
|
|
else {
|
2022-01-31 19:08:27 +09:00
|
|
|
/* Remove all managed configs. Note, foreign configs are removed in later by
|
|
|
|
|
* link_configure() -> link_drop_foreign_config() if the link is managed by us. */
|
|
|
|
|
r = link_drop_managed_config(link);
|
2021-10-26 02:29:09 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
}
|
2019-07-04 13:52:03 +09:00
|
|
|
|
2022-01-31 22:30:39 +09:00
|
|
|
/* The bound_to map depends on .network file, hence it needs to be freed. But, do not free the
|
|
|
|
|
* bound_by map. Otherwise, if a link enters unmanaged state below, then its carrier state will
|
|
|
|
|
* not propagated to other interfaces anymore. Moreover, it is not necessary to recreate the
|
|
|
|
|
* map here, as it depends on .network files assigned to other links. */
|
|
|
|
|
link_free_bound_to_list(link);
|
|
|
|
|
|
2019-07-04 13:52:03 +09:00
|
|
|
link_free_engines(link);
|
|
|
|
|
link->network = network_unref(link->network);
|
|
|
|
|
|
2022-02-18 00:01:28 +09:00
|
|
|
netdev_unref(link->netdev);
|
|
|
|
|
link->netdev = netdev_ref(netdev);
|
|
|
|
|
|
2021-06-14 06:58:06 +09:00
|
|
|
if (!network) {
|
|
|
|
|
link_set_state(link, LINK_STATE_UNMANAGED);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-04 13:52:03 +09:00
|
|
|
/* Then, apply new .network file */
|
2021-01-20 16:56:21 +09:00
|
|
|
link->network = network_ref(network);
|
2021-05-26 13:01:59 +09:00
|
|
|
link_update_operstate(link, true);
|
2021-01-20 16:56:21 +09:00
|
|
|
link_dirty(link);
|
2019-07-04 13:52:03 +09:00
|
|
|
|
|
|
|
|
link_set_state(link, LINK_STATE_INITIALIZED);
|
network: add ActivationPolicy= configuration parameter
This parameter allows configuring the activation policy for an interface,
meaning how it manages the interface's administrative state (IFF_UP flag).
The policy can be configured to bring the interface either up or down when
the interface is (re)configured, to always force the interface either up or
down, or to never change the interface administrative state.
If the interface is bound with BindCarrier=, its administrative state is
controlled by the interface(s) it's bound to, and this parameter is forced
to 'bound'.
This changes the default behavior of how systemd-networkd sets the IFF_UP
flag; previously, it was set up (if not already up) every time the
link_joined() function was called. Now, with the default ActivationPolicy=
setting of 'up', it will only set the IFF_UP flag once, the first time
link_joined() is called, during an interface's configuration; and on
the first link_joined() call each time the interface is reconfigured.
Fixes: #3031
Fixes: #17437
2020-06-18 16:09:40 -04:00
|
|
|
link->activated = false;
|
2019-07-04 13:52:03 +09:00
|
|
|
|
|
|
|
|
r = link_configure(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2021-05-26 13:43:05 +09:00
|
|
|
return 1;
|
2019-07-04 13:52:03 +09:00
|
|
|
}
|
|
|
|
|
|
2021-09-21 04:57:43 +09:00
|
|
|
static int link_reconfigure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool force) {
|
2019-12-15 22:46:19 +09:00
|
|
|
int r;
|
|
|
|
|
|
2021-06-12 12:01:42 +09:00
|
|
|
assert(link);
|
|
|
|
|
|
2021-05-26 13:45:14 +09:00
|
|
|
r = link_getlink_handler_internal(rtnl, m, link, "Failed to update link state");
|
|
|
|
|
if (r <= 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2021-06-12 11:46:01 +09:00
|
|
|
r = link_reconfigure_impl(link, force);
|
2021-06-12 12:01:42 +09:00
|
|
|
if (r < 0) {
|
2019-12-15 22:46:19 +09:00
|
|
|
link_enter_failed(link);
|
2021-06-12 12:01:42 +09:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int link_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
2021-09-21 04:57:43 +09:00
|
|
|
return link_reconfigure_handler_internal(rtnl, m, link, /* force = */ false);
|
2021-06-12 12:01:42 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int link_force_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
2021-09-21 04:57:43 +09:00
|
|
|
return link_reconfigure_handler_internal(rtnl, m, link, /* force = */ true);
|
2021-06-12 12:01:42 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int link_reconfigure_after_sleep_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
2021-09-21 04:57:43 +09:00
|
|
|
r = link_reconfigure_handler_internal(rtnl, m, link, /* force = */ false);
|
2021-06-12 12:01:42 +09:00
|
|
|
if (r != 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
/* r == 0 means an error occurs, the link is unmanaged, or the matching network file is unchanged. */
|
|
|
|
|
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* re-request static configs, and restart engines. */
|
|
|
|
|
r = link_stop_engines(link, false);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
link_enter_failed(link);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = link_acquire_dynamic_conf(link);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
link_enter_failed(link);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = link_request_static_configs(link);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
link_enter_failed(link);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2019-12-15 22:46:19 +09:00
|
|
|
|
2021-05-26 13:45:14 +09:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-12 12:01:42 +09:00
|
|
|
static int link_reconfigure_internal(Link *link, link_netlink_message_handler_t callback) {
|
2019-12-15 22:46:19 +09:00
|
|
|
int r;
|
|
|
|
|
|
2021-06-12 12:01:42 +09:00
|
|
|
assert(link);
|
|
|
|
|
assert(callback);
|
|
|
|
|
|
2020-12-11 12:15:45 +09:00
|
|
|
/* When link in pending or initialized state, then link_configure() will be called. To prevent
|
2020-12-11 11:39:16 +01:00
|
|
|
* the function from being called multiple times simultaneously, refuse to reconfigure the
|
|
|
|
|
* interface in these cases. */
|
2020-12-11 12:15:45 +09:00
|
|
|
if (IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED, LINK_STATE_LINGER))
|
2020-12-11 11:39:16 +01:00
|
|
|
return 0; /* 0 means no-op. */
|
2020-01-22 16:06:50 +09:00
|
|
|
|
2021-06-12 12:01:42 +09:00
|
|
|
r = link_call_getlink(link, callback);
|
2019-12-15 22:46:19 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2020-12-11 12:15:45 +09:00
|
|
|
return 1; /* 1 means the interface will be reconfigured. */
|
2019-12-15 22:46:19 +09:00
|
|
|
}
|
|
|
|
|
|
2021-06-12 12:01:42 +09:00
|
|
|
int link_reconfigure(Link *link, bool force) {
|
|
|
|
|
return link_reconfigure_internal(link, force ? link_force_reconfigure_handler : link_reconfigure_handler);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int link_reconfigure_after_sleep(Link *link) {
|
|
|
|
|
return link_reconfigure_internal(link, link_reconfigure_after_sleep_handler);
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-10 14:34:00 +09:00
|
|
|
static int link_initialized_and_synced(Link *link) {
|
2014-04-15 14:21:44 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
assert(link->manager);
|
|
|
|
|
|
2021-09-29 18:19:38 +09:00
|
|
|
if (link->manager->test_mode) {
|
|
|
|
|
log_link_debug(link, "Running in test mode, refusing to enter initialized state.");
|
|
|
|
|
link_set_state(link, LINK_STATE_UNMANAGED);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-31 16:32:05 +09:00
|
|
|
/* This may get called either from the asynchronous netlink callback,
|
2021-05-26 13:13:13 +09:00
|
|
|
* or directly from link_check_initialized() if running in a container. */
|
2019-04-15 17:34:00 +09:00
|
|
|
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 17:34:00 +09:00
|
|
|
link_set_state(link, LINK_STATE_INITIALIZED);
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2015-02-17 04:06:57 -08: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;
|
|
|
|
|
|
2022-01-31 16:32:05 +09:00
|
|
|
return link_reconfigure_impl(link, /* force = */ false);
|
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-07-15 00:35:49 +09:00
|
|
|
int r;
|
|
|
|
|
|
2021-05-26 13:45:14 +09:00
|
|
|
r = link_getlink_handler_internal(rtnl, m, link, "Failed to wait for the interface to be initialized");
|
|
|
|
|
if (r <= 0)
|
2021-05-14 16:00:52 +09:00
|
|
|
return r;
|
2019-12-15 22:46:19 +09:00
|
|
|
|
2019-07-15 00:35:49 +09:00
|
|
|
r = link_initialized_and_synced(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
link_enter_failed(link);
|
2021-05-26 13:45:14 +09:00
|
|
|
|
|
|
|
|
return 0;
|
2018-10-10 14:34:00 +09:00
|
|
|
}
|
|
|
|
|
|
2021-02-21 15:51:51 +09:00
|
|
|
static int link_initialized(Link *link, sd_device *device) {
|
2014-06-14 18:52:46 +02:00
|
|
|
assert(link);
|
|
|
|
|
assert(device);
|
|
|
|
|
|
2021-09-10 08:09:56 +09:00
|
|
|
/* Always replace with the new sd_device object. As the sysname (and possibly other properties
|
|
|
|
|
* or sysattrs) may be outdated. */
|
2022-07-23 20:00:44 +09:00
|
|
|
device_unref_and_replace(link->dev, device);
|
2014-06-14 18:52:46 +02:00
|
|
|
|
2021-09-10 08:09:56 +09:00
|
|
|
/* Do not ignore unamanaged state case here. If an interface is renamed after being once
|
|
|
|
|
* configured, and the corresponding .network file has Name= in [Match] section, then the
|
|
|
|
|
* interface may be already in unmanaged state. See #20657. */
|
|
|
|
|
if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_UNMANAGED))
|
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 17:34:00 +09:00
|
|
|
link_set_state(link, LINK_STATE_INITIALIZED);
|
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
|
|
|
|
2021-05-26 13:45:14 +09:00
|
|
|
return link_call_getlink(link, link_initialized_handler);
|
2014-06-14 18:52:46 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
static int link_check_initialized(Link *link) {
|
2018-08-22 14:30:49 +09:00
|
|
|
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
|
2018-10-29 17:32:21 +09:00
|
|
|
int r;
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
assert(link);
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2022-02-17 18:55:24 +09:00
|
|
|
if (!udev_available())
|
2021-05-26 13:13:13 +09:00
|
|
|
return link_initialized_and_synced(link);
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2021-05-26 13:04:26 +09:00
|
|
|
/* udev should be around */
|
2021-06-09 23:33:50 +09:00
|
|
|
r = sd_device_new_from_ifindex(&device, link->ifindex);
|
2021-05-26 13:04:26 +09:00
|
|
|
if (r < 0) {
|
|
|
|
|
log_link_debug_errno(link, r, "Could not find device, waiting for device initialization: %m");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = sd_device_get_is_initialized(device);
|
2021-05-26 13:13:13 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_warning_errno(link, r, "Could not determine whether the device is initialized: %m");
|
2021-05-26 13:04:26 +09:00
|
|
|
if (r == 0) {
|
|
|
|
|
/* not yet ready */
|
|
|
|
|
log_link_debug(link, "link pending udev initialization...");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = device_is_renaming(device);
|
2021-05-26 13:13:13 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_warning_errno(link, r, "Failed to determine the device is being renamed: %m");
|
2021-05-26 13:04:26 +09:00
|
|
|
if (r > 0) {
|
|
|
|
|
log_link_debug(link, "Interface is being renamed, pending initialization.");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
return link_initialized(link, device);
|
2014-03-09 14:43:37 +01:00
|
|
|
}
|
|
|
|
|
|
2022-07-22 08:32:39 +09:00
|
|
|
int manager_udev_process_link(Manager *m, sd_device *device, sd_device_action_t action) {
|
2021-02-21 15:51:51 +09:00
|
|
|
int r, ifindex;
|
2022-07-22 08:32:39 +09:00
|
|
|
Link *link;
|
2021-02-21 15:51:51 +09:00
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
assert(device);
|
|
|
|
|
|
|
|
|
|
r = sd_device_get_ifindex(device, &ifindex);
|
2022-07-22 08:32:39 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return log_device_debug_errno(device, r, "Failed to get ifindex: %m");
|
2021-02-21 15:51:51 +09:00
|
|
|
|
2022-07-23 09:00:32 +09:00
|
|
|
r = link_get_by_index(m, ifindex, &link);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
/* This error is not critical, as the corresponding rtnl message may be received later. */
|
|
|
|
|
log_device_debug_errno(device, r, "Failed to get link from ifindex %i, ignoring: %m", ifindex);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Let's unref the sd-device object assigned to the corresponding Link object, but keep the Link
|
|
|
|
|
* object here. It will be removed only when rtnetlink says so. */
|
|
|
|
|
if (action == SD_DEVICE_REMOVE) {
|
|
|
|
|
link->dev = sd_device_unref(link->dev);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-21 15:51:51 +09:00
|
|
|
r = device_is_renaming(device);
|
2022-07-22 08:32:39 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return log_device_debug_errno(device, r, "Failed to determine if the device is renaming or not: %m");
|
2021-02-21 15:51:51 +09:00
|
|
|
if (r > 0) {
|
2022-07-22 08:32:39 +09:00
|
|
|
log_device_debug(device, "Device is renaming, waiting for the interface to be renamed.");
|
2022-07-23 09:11:54 +09:00
|
|
|
/* TODO:
|
|
|
|
|
* What happens when a device is initialized, then soon renamed after that? When we detect
|
|
|
|
|
* such, maybe we should cancel or postpone all queued requests for the interface. */
|
2021-02-21 15:51:51 +09:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 13:00:08 +09:00
|
|
|
r = link_initialized(link, device);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
link_enter_failed(link);
|
2021-02-21 15:51:51 +09:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-03 15:44:12 +01:00
|
|
|
static int link_carrier_gained(Link *link) {
|
2021-11-13 10:50:03 +09:00
|
|
|
bool force_reconfigure;
|
2015-02-03 15:44:12 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
2021-11-13 10:50:03 +09:00
|
|
|
r = event_source_disable(link->carrier_lost_timer);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
log_link_warning_errno(link, r, "Failed to disable carrier lost timer, ignoring: %m");
|
|
|
|
|
|
2021-12-09 03:04:21 +09:00
|
|
|
/* If a wireless interface was connected to an access point, and the SSID is changed (that is,
|
|
|
|
|
* both previous_ssid and ssid are non-NULL), then the connected wireless network could be
|
|
|
|
|
* changed. So, always reconfigure the link. Which means e.g. the DHCP client will be
|
|
|
|
|
* restarted, and the correct network information will be gained.
|
|
|
|
|
*
|
|
|
|
|
* However, do not reconfigure the wireless interface forcibly if it was not connected to any
|
|
|
|
|
* access points previously (previous_ssid is NULL in this case). As, a .network file may be
|
|
|
|
|
* already assigned to the interface (in that case, the .network file does not have the SSID=
|
|
|
|
|
* setting in the [Match] section), and the interface is already being configured. Of course,
|
|
|
|
|
* there may exist another .network file with higher priority and a matching SSID= setting. But
|
|
|
|
|
* in that case, link_reconfigure_impl() can handle that without the force_reconfigure flag.
|
|
|
|
|
*
|
2021-11-13 10:50:03 +09:00
|
|
|
* For non-wireless interfaces, we have no way to detect the connected network change. So,
|
2021-12-09 03:04:21 +09:00
|
|
|
* setting force_reconfigure = false. Note, both ssid and previous_ssid are NULL in that case. */
|
|
|
|
|
force_reconfigure = link->previous_ssid && !streq_ptr(link->previous_ssid, link->ssid);
|
2021-11-13 10:50:03 +09:00
|
|
|
link->previous_ssid = mfree(link->previous_ssid);
|
|
|
|
|
|
2021-11-19 05:12:35 +09:00
|
|
|
if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_FAILED, LINK_STATE_LINGER)) {
|
2021-11-14 11:51:58 +09:00
|
|
|
/* At this stage, both wlan and link information should be up-to-date. Hence,
|
|
|
|
|
* it is not necessary to call RTM_GETLINK, NL80211_CMD_GET_INTERFACE, or
|
|
|
|
|
* NL80211_CMD_GET_STATION commands, and simply call link_reconfigure_impl().
|
|
|
|
|
* Note, link_reconfigure_impl() returns 1 when the link is reconfigured. */
|
2021-11-13 10:50:03 +09:00
|
|
|
r = link_reconfigure_impl(link, force_reconfigure);
|
2021-11-14 11:51:58 +09:00
|
|
|
if (r != 0)
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 16:36:54 +09:00
|
|
|
r = link_handle_bound_by_list(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2021-04-30 07:10:34 +09:00
|
|
|
if (link->iftype == ARPHRD_CAN)
|
|
|
|
|
/* let's shortcut things for CAN which doesn't need most of what's done below. */
|
2021-06-06 16:36:54 +09:00
|
|
|
return 0;
|
2021-04-30 07:10:34 +09:00
|
|
|
|
2019-05-03 01:13:10 +02:00
|
|
|
if (IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) {
|
2021-05-18 14:46:22 +09:00
|
|
|
r = link_acquire_dynamic_conf(link);
|
2021-05-18 14:59:10 +09:00
|
|
|
if (r < 0)
|
2015-02-03 15:44:12 +01:00
|
|
|
return r;
|
2016-04-29 04:33:29 +05:30
|
|
|
|
2021-05-18 14:42:47 +09:00
|
|
|
r = link_request_static_configs(link);
|
2016-04-29 04:33:29 +05:30
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2015-02-03 15:44:12 +01:00
|
|
|
}
|
|
|
|
|
|
2021-06-06 16:36:54 +09:00
|
|
|
return 0;
|
2015-02-03 15:44:12 +01:00
|
|
|
}
|
|
|
|
|
|
2021-11-13 10:50:03 +09:00
|
|
|
static int link_carrier_lost_impl(Link *link) {
|
|
|
|
|
int r, ret = 0;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
|
|
link->previous_ssid = mfree(link->previous_ssid);
|
|
|
|
|
|
|
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
r = link_stop_engines(link, false);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
ret = r;
|
|
|
|
|
|
2022-01-31 19:08:27 +09:00
|
|
|
r = link_drop_managed_config(link);
|
2021-11-13 10:50:03 +09:00
|
|
|
if (r < 0 && ret >= 0)
|
|
|
|
|
ret = r;
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int link_carrier_lost_handler(sd_event_source *s, uint64_t usec, void *userdata) {
|
|
|
|
|
Link *link = userdata;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
|
|
r = link_carrier_lost_impl(link);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
log_link_warning_errno(link, r, "Failed to process carrier lost event: %m");
|
|
|
|
|
link_enter_failed(link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-03 15:44:12 +01:00
|
|
|
static int link_carrier_lost(Link *link) {
|
2022-03-30 00:52:09 +09:00
|
|
|
uint16_t dhcp_mtu;
|
|
|
|
|
usec_t usec;
|
2015-02-03 15:44:12 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
2021-06-06 16:36:54 +09:00
|
|
|
r = link_handle_bound_by_list(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2018-06-01 15:04:49 +05:30
|
|
|
|
2021-04-30 07:10:34 +09:00
|
|
|
if (link->iftype == ARPHRD_CAN)
|
|
|
|
|
/* let's shortcut things for CAN which doesn't need most of what's done below. */
|
2021-06-06 16:36:54 +09:00
|
|
|
return 0;
|
|
|
|
|
|
2021-09-05 17:14:36 +09:00
|
|
|
if (!link->network)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2022-03-30 00:52:09 +09:00
|
|
|
if (link->network->ignore_carrier_loss_set)
|
|
|
|
|
/* If IgnoreCarrierLoss= is explicitly specified, then use the specified value. */
|
|
|
|
|
usec = link->network->ignore_carrier_loss_usec;
|
|
|
|
|
|
|
|
|
|
else if (link->network->bond && link->wlan_iftype > 0)
|
|
|
|
|
/* Enslaving wlan interface to a bond disconnects from the connected AP, and causes its
|
|
|
|
|
* carrier to be lost. See #19832. */
|
|
|
|
|
usec = 3 * USEC_PER_SEC;
|
|
|
|
|
|
|
|
|
|
else if (link->network->dhcp_use_mtu &&
|
|
|
|
|
link->dhcp_lease &&
|
|
|
|
|
sd_dhcp_lease_get_mtu(link->dhcp_lease, &dhcp_mtu) >= 0 &&
|
|
|
|
|
dhcp_mtu != link->original_mtu)
|
|
|
|
|
/* Some drivers reset interfaces when changing MTU. Resetting interfaces by the static
|
|
|
|
|
* MTU should not cause any issues, as MTU is changed only once. However, setting MTU
|
|
|
|
|
* through DHCP lease causes an infinite loop of resetting the interface. See #18738. */
|
|
|
|
|
usec = 5 * USEC_PER_SEC;
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
/* Otherwise, use the currently set value. */
|
|
|
|
|
usec = link->network->ignore_carrier_loss_usec;
|
|
|
|
|
|
|
|
|
|
if (usec == USEC_INFINITY)
|
2021-06-06 16:36:54 +09:00
|
|
|
return 0;
|
2021-04-30 07:10:34 +09:00
|
|
|
|
2022-03-30 00:52:09 +09:00
|
|
|
if (usec == 0)
|
2021-11-13 10:50:03 +09:00
|
|
|
return link_carrier_lost_impl(link);
|
2015-02-03 15:44:12 +01:00
|
|
|
|
2021-11-13 10:50:03 +09:00
|
|
|
return event_reset_time_relative(link->manager->event,
|
|
|
|
|
&link->carrier_lost_timer,
|
2022-03-28 16:41:10 +02:00
|
|
|
CLOCK_BOOTTIME,
|
2022-03-30 00:52:09 +09:00
|
|
|
usec,
|
2021-11-13 10:50:03 +09:00
|
|
|
0,
|
|
|
|
|
link_carrier_lost_handler,
|
|
|
|
|
link,
|
|
|
|
|
0,
|
|
|
|
|
"link-carrier-loss",
|
|
|
|
|
true);
|
2015-02-03 15:44:12 +01:00
|
|
|
}
|
|
|
|
|
|
2019-10-29 10:31:58 -04:00
|
|
|
static int link_admin_state_up(Link *link) {
|
|
|
|
|
int r;
|
|
|
|
|
|
network: add ActivationPolicy= configuration parameter
This parameter allows configuring the activation policy for an interface,
meaning how it manages the interface's administrative state (IFF_UP flag).
The policy can be configured to bring the interface either up or down when
the interface is (re)configured, to always force the interface either up or
down, or to never change the interface administrative state.
If the interface is bound with BindCarrier=, its administrative state is
controlled by the interface(s) it's bound to, and this parameter is forced
to 'bound'.
This changes the default behavior of how systemd-networkd sets the IFF_UP
flag; previously, it was set up (if not already up) every time the
link_joined() function was called. Now, with the default ActivationPolicy=
setting of 'up', it will only set the IFF_UP flag once, the first time
link_joined() is called, during an interface's configuration; and on
the first link_joined() call each time the interface is reconfigured.
Fixes: #3031
Fixes: #17437
2020-06-18 16:09:40 -04:00
|
|
|
assert(link);
|
|
|
|
|
|
2021-02-21 15:51:51 +09:00
|
|
|
/* This is called every time an interface admin state changes to up;
|
|
|
|
|
* specifically, when IFF_UP flag changes from unset to set. */
|
|
|
|
|
|
network: add ActivationPolicy= configuration parameter
This parameter allows configuring the activation policy for an interface,
meaning how it manages the interface's administrative state (IFF_UP flag).
The policy can be configured to bring the interface either up or down when
the interface is (re)configured, to always force the interface either up or
down, or to never change the interface administrative state.
If the interface is bound with BindCarrier=, its administrative state is
controlled by the interface(s) it's bound to, and this parameter is forced
to 'bound'.
This changes the default behavior of how systemd-networkd sets the IFF_UP
flag; previously, it was set up (if not already up) every time the
link_joined() function was called. Now, with the default ActivationPolicy=
setting of 'up', it will only set the IFF_UP flag once, the first time
link_joined() is called, during an interface's configuration; and on
the first link_joined() call each time the interface is reconfigured.
Fixes: #3031
Fixes: #17437
2020-06-18 16:09:40 -04:00
|
|
|
if (!link->network)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2021-06-06 15:24:43 +09:00
|
|
|
if (link->activated && link->network->activation_policy == ACTIVATION_POLICY_ALWAYS_DOWN) {
|
2022-01-28 10:40:30 +09:00
|
|
|
log_link_info(link, "Activation policy is \"always-down\", forcing link down.");
|
2021-06-06 17:02:00 +09:00
|
|
|
return link_request_to_bring_up_or_down(link, /* up = */ false);
|
network: add ActivationPolicy= configuration parameter
This parameter allows configuring the activation policy for an interface,
meaning how it manages the interface's administrative state (IFF_UP flag).
The policy can be configured to bring the interface either up or down when
the interface is (re)configured, to always force the interface either up or
down, or to never change the interface administrative state.
If the interface is bound with BindCarrier=, its administrative state is
controlled by the interface(s) it's bound to, and this parameter is forced
to 'bound'.
This changes the default behavior of how systemd-networkd sets the IFF_UP
flag; previously, it was set up (if not already up) every time the
link_joined() function was called. Now, with the default ActivationPolicy=
setting of 'up', it will only set the IFF_UP flag once, the first time
link_joined() is called, during an interface's configuration; and on
the first link_joined() call each time the interface is reconfigured.
Fixes: #3031
Fixes: #17437
2020-06-18 16:09:40 -04:00
|
|
|
}
|
|
|
|
|
|
2019-10-29 10:31:58 -04:00
|
|
|
/* We set the ipv6 mtu after the device mtu, but the kernel resets
|
2021-05-24 14:59:09 +09:00
|
|
|
* ipv6 mtu on NETDEV_UP, so we need to reset it. */
|
|
|
|
|
r = link_set_ipv6_mtu(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
log_link_warning_errno(link, r, "Cannot set IPv6 MTU, ignoring: %m");
|
2019-10-29 10:31:58 -04:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
network: add ActivationPolicy= configuration parameter
This parameter allows configuring the activation policy for an interface,
meaning how it manages the interface's administrative state (IFF_UP flag).
The policy can be configured to bring the interface either up or down when
the interface is (re)configured, to always force the interface either up or
down, or to never change the interface administrative state.
If the interface is bound with BindCarrier=, its administrative state is
controlled by the interface(s) it's bound to, and this parameter is forced
to 'bound'.
This changes the default behavior of how systemd-networkd sets the IFF_UP
flag; previously, it was set up (if not already up) every time the
link_joined() function was called. Now, with the default ActivationPolicy=
setting of 'up', it will only set the IFF_UP flag once, the first time
link_joined() is called, during an interface's configuration; and on
the first link_joined() call each time the interface is reconfigured.
Fixes: #3031
Fixes: #17437
2020-06-18 16:09:40 -04:00
|
|
|
static int link_admin_state_down(Link *link) {
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2021-06-06 15:24:43 +09:00
|
|
|
if (link->activated && link->network->activation_policy == ACTIVATION_POLICY_ALWAYS_UP) {
|
2022-01-28 10:40:30 +09:00
|
|
|
log_link_info(link, "Activation policy is \"always-up\", forcing link up.");
|
2021-06-06 17:02:00 +09:00
|
|
|
return link_request_to_bring_up_or_down(link, /* up = */ true);
|
network: add ActivationPolicy= configuration parameter
This parameter allows configuring the activation policy for an interface,
meaning how it manages the interface's administrative state (IFF_UP flag).
The policy can be configured to bring the interface either up or down when
the interface is (re)configured, to always force the interface either up or
down, or to never change the interface administrative state.
If the interface is bound with BindCarrier=, its administrative state is
controlled by the interface(s) it's bound to, and this parameter is forced
to 'bound'.
This changes the default behavior of how systemd-networkd sets the IFF_UP
flag; previously, it was set up (if not already up) every time the
link_joined() function was called. Now, with the default ActivationPolicy=
setting of 'up', it will only set the IFF_UP flag once, the first time
link_joined() is called, during an interface's configuration; and on
the first link_joined() call each time the interface is reconfigured.
Fixes: #3031
Fixes: #17437
2020-06-18 16:09:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 12:47:28 +09:00
|
|
|
static bool link_is_enslaved(Link *link) {
|
|
|
|
|
if (link->flags & IFF_SLAVE)
|
|
|
|
|
return true;
|
|
|
|
|
|
2021-09-03 08:04:29 +09:00
|
|
|
if (link->master_ifindex > 0)
|
2021-05-26 12:47:28 +09:00
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static LinkAddressState address_state_from_scope(uint8_t scope) {
|
|
|
|
|
if (scope < RT_SCOPE_SITE)
|
|
|
|
|
/* universally accessible addresses found */
|
|
|
|
|
return LINK_ADDRESS_STATE_ROUTABLE;
|
|
|
|
|
|
|
|
|
|
if (scope < RT_SCOPE_HOST)
|
|
|
|
|
/* only link or site local addresses found */
|
|
|
|
|
return LINK_ADDRESS_STATE_DEGRADED;
|
|
|
|
|
|
|
|
|
|
/* no useful addresses found */
|
|
|
|
|
return LINK_ADDRESS_STATE_OFF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void link_update_operstate(Link *link, bool also_update_master) {
|
|
|
|
|
LinkOperationalState operstate;
|
|
|
|
|
LinkCarrierState carrier_state;
|
|
|
|
|
LinkAddressState ipv4_address_state, ipv6_address_state, address_state;
|
|
|
|
|
LinkOnlineState online_state;
|
|
|
|
|
_cleanup_strv_free_ char **p = NULL;
|
|
|
|
|
uint8_t ipv4_scope = RT_SCOPE_NOWHERE, ipv6_scope = RT_SCOPE_NOWHERE;
|
|
|
|
|
bool changed = false;
|
|
|
|
|
Address *address;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
|
|
if (link->kernel_operstate == IF_OPER_DORMANT)
|
|
|
|
|
carrier_state = LINK_CARRIER_STATE_DORMANT;
|
|
|
|
|
else if (link_has_carrier(link)) {
|
|
|
|
|
if (link_is_enslaved(link))
|
|
|
|
|
carrier_state = LINK_CARRIER_STATE_ENSLAVED;
|
|
|
|
|
else
|
|
|
|
|
carrier_state = LINK_CARRIER_STATE_CARRIER;
|
|
|
|
|
} else if (link->flags & IFF_UP)
|
|
|
|
|
carrier_state = LINK_CARRIER_STATE_NO_CARRIER;
|
|
|
|
|
else
|
|
|
|
|
carrier_state = LINK_CARRIER_STATE_OFF;
|
|
|
|
|
|
|
|
|
|
if (carrier_state >= LINK_CARRIER_STATE_CARRIER) {
|
|
|
|
|
Link *slave;
|
|
|
|
|
|
|
|
|
|
SET_FOREACH(slave, link->slaves) {
|
|
|
|
|
link_update_operstate(slave, false);
|
|
|
|
|
|
|
|
|
|
if (slave->carrier_state < LINK_CARRIER_STATE_CARRIER)
|
|
|
|
|
carrier_state = LINK_CARRIER_STATE_DEGRADED_CARRIER;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SET_FOREACH(address, link->addresses) {
|
|
|
|
|
if (!address_is_ready(address))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (address->family == AF_INET)
|
|
|
|
|
ipv4_scope = MIN(ipv4_scope, address->scope);
|
|
|
|
|
|
|
|
|
|
if (address->family == AF_INET6)
|
|
|
|
|
ipv6_scope = MIN(ipv6_scope, address->scope);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ipv4_address_state = address_state_from_scope(ipv4_scope);
|
|
|
|
|
ipv6_address_state = address_state_from_scope(ipv6_scope);
|
|
|
|
|
address_state = address_state_from_scope(MIN(ipv4_scope, ipv6_scope));
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
operstate = LINK_OPERSTATE_ENSLAVED;
|
|
|
|
|
|
|
|
|
|
/* Only determine online state for managed links with RequiredForOnline=yes */
|
|
|
|
|
if (!link->network || !link->network->required_for_online)
|
|
|
|
|
online_state = _LINK_ONLINE_STATE_INVALID;
|
|
|
|
|
else if (operstate < link->network->required_operstate_for_online.min ||
|
|
|
|
|
operstate > link->network->required_operstate_for_online.max)
|
|
|
|
|
online_state = LINK_ONLINE_STATE_OFFLINE;
|
|
|
|
|
else {
|
|
|
|
|
AddressFamily required_family = link->network->required_family_for_online;
|
|
|
|
|
bool needs_ipv4 = required_family & ADDRESS_FAMILY_IPV4;
|
|
|
|
|
bool needs_ipv6 = required_family & ADDRESS_FAMILY_IPV6;
|
|
|
|
|
|
|
|
|
|
/* The operational state is within the range required for online.
|
|
|
|
|
* If a particular address family is also required, we might revert
|
|
|
|
|
* to offline in the blocks below. */
|
|
|
|
|
online_state = LINK_ONLINE_STATE_ONLINE;
|
|
|
|
|
|
|
|
|
|
if (link->network->required_operstate_for_online.min >= LINK_OPERSTATE_DEGRADED) {
|
|
|
|
|
if (needs_ipv4 && ipv4_address_state < LINK_ADDRESS_STATE_DEGRADED)
|
|
|
|
|
online_state = LINK_ONLINE_STATE_OFFLINE;
|
|
|
|
|
if (needs_ipv6 && ipv6_address_state < LINK_ADDRESS_STATE_DEGRADED)
|
|
|
|
|
online_state = LINK_ONLINE_STATE_OFFLINE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (link->network->required_operstate_for_online.min >= LINK_OPERSTATE_ROUTABLE) {
|
|
|
|
|
if (needs_ipv4 && ipv4_address_state < LINK_ADDRESS_STATE_ROUTABLE)
|
|
|
|
|
online_state = LINK_ONLINE_STATE_OFFLINE;
|
|
|
|
|
if (needs_ipv6 && ipv6_address_state < LINK_ADDRESS_STATE_ROUTABLE)
|
|
|
|
|
online_state = LINK_ONLINE_STATE_OFFLINE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (link->carrier_state != carrier_state) {
|
|
|
|
|
link->carrier_state = carrier_state;
|
|
|
|
|
changed = true;
|
|
|
|
|
if (strv_extend(&p, "CarrierState") < 0)
|
|
|
|
|
log_oom();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (link->address_state != address_state) {
|
|
|
|
|
link->address_state = address_state;
|
|
|
|
|
changed = true;
|
|
|
|
|
if (strv_extend(&p, "AddressState") < 0)
|
|
|
|
|
log_oom();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (link->ipv4_address_state != ipv4_address_state) {
|
|
|
|
|
link->ipv4_address_state = ipv4_address_state;
|
|
|
|
|
changed = true;
|
|
|
|
|
if (strv_extend(&p, "IPv4AddressState") < 0)
|
|
|
|
|
log_oom();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (link->ipv6_address_state != ipv6_address_state) {
|
|
|
|
|
link->ipv6_address_state = ipv6_address_state;
|
|
|
|
|
changed = true;
|
|
|
|
|
if (strv_extend(&p, "IPv6AddressState") < 0)
|
|
|
|
|
log_oom();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (link->operstate != operstate) {
|
|
|
|
|
link->operstate = operstate;
|
|
|
|
|
changed = true;
|
|
|
|
|
if (strv_extend(&p, "OperationalState") < 0)
|
|
|
|
|
log_oom();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (link->online_state != online_state) {
|
|
|
|
|
link->online_state = online_state;
|
|
|
|
|
changed = true;
|
|
|
|
|
if (strv_extend(&p, "OnlineState") < 0)
|
|
|
|
|
log_oom();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (p)
|
|
|
|
|
link_send_changed_strv(link, p);
|
|
|
|
|
if (changed)
|
|
|
|
|
link_dirty(link);
|
|
|
|
|
|
|
|
|
|
if (also_update_master) {
|
|
|
|
|
Link *master;
|
|
|
|
|
|
|
|
|
|
if (link_get_master(link, &master) >= 0)
|
|
|
|
|
link_update_operstate(master, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define FLAG_STRING(string, flag, old, new) \
|
|
|
|
|
(((old ^ new) & flag) \
|
|
|
|
|
? ((old & flag) ? (" -" string) : (" +" string)) \
|
|
|
|
|
: "")
|
|
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
static int link_update_flags(Link *link, sd_netlink_message *message) {
|
2021-09-21 04:57:43 +09:00
|
|
|
bool link_was_admin_up, had_carrier;
|
2021-05-26 12:47:28 +09:00
|
|
|
uint8_t operstate;
|
|
|
|
|
unsigned flags;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
2021-05-26 13:13:13 +09:00
|
|
|
assert(message);
|
2021-05-26 12:47:28 +09:00
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
r = sd_rtnl_message_link_get_flags(message, &flags);
|
2021-05-26 12:47:28 +09:00
|
|
|
if (r < 0)
|
2021-05-26 13:13:13 +09:00
|
|
|
return log_link_debug_errno(link, r, "rtnl: failed to read link flags: %m");
|
2021-05-26 12:47:28 +09:00
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
r = sd_netlink_message_read_u8(message, IFLA_OPERSTATE, &operstate);
|
|
|
|
|
if (r == -ENODATA)
|
|
|
|
|
/* If we got a message without operstate, assume the state was unchanged. */
|
2021-05-26 12:47:28 +09:00
|
|
|
operstate = link->kernel_operstate;
|
2021-05-26 13:13:13 +09:00
|
|
|
else if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "rtnl: failed to read operational state: %m");
|
2021-05-26 12:47:28 +09:00
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
if (link->flags == flags && link->kernel_operstate == operstate)
|
2021-05-26 12:47:28 +09:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (link->flags != flags) {
|
|
|
|
|
unsigned unknown_flags, unknown_flags_added, unknown_flags_removed;
|
|
|
|
|
|
|
|
|
|
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",
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
if (unknown_flags_added)
|
|
|
|
|
log_link_debug(link, "Unknown link flags gained, ignoring: %#.5x", unknown_flags_added);
|
|
|
|
|
|
|
|
|
|
if (unknown_flags_removed)
|
|
|
|
|
log_link_debug(link, "Unknown link flags lost, ignoring: %#.5x", unknown_flags_removed);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
link_was_admin_up = link->flags & IFF_UP;
|
|
|
|
|
had_carrier = link_has_carrier(link);
|
|
|
|
|
|
2021-05-26 12:47:28 +09:00
|
|
|
link->flags = flags;
|
|
|
|
|
link->kernel_operstate = operstate;
|
|
|
|
|
|
|
|
|
|
link_update_operstate(link, true);
|
|
|
|
|
|
2019-10-29 10:31:58 -04: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;
|
network: add ActivationPolicy= configuration parameter
This parameter allows configuring the activation policy for an interface,
meaning how it manages the interface's administrative state (IFF_UP flag).
The policy can be configured to bring the interface either up or down when
the interface is (re)configured, to always force the interface either up or
down, or to never change the interface administrative state.
If the interface is bound with BindCarrier=, its administrative state is
controlled by the interface(s) it's bound to, and this parameter is forced
to 'bound'.
This changes the default behavior of how systemd-networkd sets the IFF_UP
flag; previously, it was set up (if not already up) every time the
link_joined() function was called. Now, with the default ActivationPolicy=
setting of 'up', it will only set the IFF_UP flag once, the first time
link_joined() is called, during an interface's configuration; and on
the first link_joined() call each time the interface is reconfigured.
Fixes: #3031
Fixes: #17437
2020-06-18 16:09:40 -04:00
|
|
|
} else if (link_was_admin_up && !(link->flags & IFF_UP)) {
|
2019-10-29 10:31:58 -04:00
|
|
|
log_link_info(link, "Link DOWN");
|
|
|
|
|
|
network: add ActivationPolicy= configuration parameter
This parameter allows configuring the activation policy for an interface,
meaning how it manages the interface's administrative state (IFF_UP flag).
The policy can be configured to bring the interface either up or down when
the interface is (re)configured, to always force the interface either up or
down, or to never change the interface administrative state.
If the interface is bound with BindCarrier=, its administrative state is
controlled by the interface(s) it's bound to, and this parameter is forced
to 'bound'.
This changes the default behavior of how systemd-networkd sets the IFF_UP
flag; previously, it was set up (if not already up) every time the
link_joined() function was called. Now, with the default ActivationPolicy=
setting of 'up', it will only set the IFF_UP flag once, the first time
link_joined() is called, during an interface's configuration; and on
the first link_joined() call each time the interface is reconfigured.
Fixes: #3031
Fixes: #17437
2020-06-18 16:09:40 -04:00
|
|
|
r = link_admin_state_down(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
if (!had_carrier && link_has_carrier(link)) {
|
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;
|
2021-05-26 13:13:13 +09:00
|
|
|
} else if (had_carrier && !link_has_carrier(link)) {
|
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
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
static int link_update_master(Link *link, sd_netlink_message *message) {
|
|
|
|
|
int master_ifindex, r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
assert(message);
|
|
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, IFLA_MASTER, (uint32_t*) &master_ifindex);
|
|
|
|
|
if (r == -ENODATA)
|
|
|
|
|
return 0;
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "rtnl: failed to read master ifindex: %m");
|
|
|
|
|
|
2021-09-03 07:24:15 +09:00
|
|
|
if (master_ifindex == link->ifindex)
|
|
|
|
|
master_ifindex = 0;
|
|
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
if (master_ifindex == link->master_ifindex)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (link->master_ifindex == 0)
|
2022-05-16 13:14:37 +02:00
|
|
|
log_link_debug(link, "Attached to master interface: %i", master_ifindex);
|
2021-05-26 13:13:13 +09:00
|
|
|
else if (master_ifindex == 0)
|
2022-05-16 13:14:37 +02:00
|
|
|
log_link_debug(link, "Detached from master interface: %i", link->master_ifindex);
|
2021-05-26 13:13:13 +09:00
|
|
|
else
|
2022-06-24 09:13:42 +02:00
|
|
|
log_link_debug(link, "Master interface changed: %i %s %i", link->master_ifindex,
|
|
|
|
|
special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), master_ifindex);
|
2021-05-26 13:13:13 +09:00
|
|
|
|
|
|
|
|
link_drop_from_master(link);
|
|
|
|
|
|
|
|
|
|
link->master_ifindex = master_ifindex;
|
|
|
|
|
|
|
|
|
|
r = link_append_to_master(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Failed to append link to master: %m");
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-17 05:24:26 +09:00
|
|
|
static int link_update_driver(Link *link, sd_netlink_message *message) {
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
assert(link->manager);
|
|
|
|
|
assert(message);
|
|
|
|
|
|
|
|
|
|
/* Driver is already read. Assuming the driver is never changed. */
|
|
|
|
|
if (link->driver)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* When udevd is running, read the driver after the interface is initialized by udevd.
|
|
|
|
|
* Otherwise, ethtool may not work correctly. See issue #22538.
|
|
|
|
|
* When udevd is not running, read the value when the interface is detected. */
|
|
|
|
|
if (link->state != (udev_available() ? LINK_STATE_INITIALIZED : LINK_STATE_PENDING))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
r = ethtool_get_driver(&link->manager->ethtool_fd, link->ifname, &link->driver);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
log_link_debug_errno(link, r, "Failed to get driver, continuing without: %m");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log_link_debug(link, "Found driver: %s", strna(link->driver));
|
|
|
|
|
|
|
|
|
|
if (streq_ptr(link->driver, "dsa")) {
|
|
|
|
|
uint32_t dsa_master_ifindex = 0;
|
|
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, IFLA_LINK, &dsa_master_ifindex);
|
|
|
|
|
if (r < 0 && r != -ENODATA)
|
|
|
|
|
return log_link_debug_errno(link, r, "rtnl: failed to read ifindex of the DSA master interface: %m");
|
|
|
|
|
|
|
|
|
|
if (dsa_master_ifindex > INT_MAX) {
|
|
|
|
|
log_link_debug(link, "rtnl: received too large DSA master ifindex (%"PRIu32" > INT_MAX), ignoring.",
|
|
|
|
|
dsa_master_ifindex);
|
|
|
|
|
dsa_master_ifindex = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
link->dsa_master_ifindex = (int) dsa_master_ifindex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int link_update_permanent_hardware_address(Link *link, sd_netlink_message *message) {
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
assert(link->manager);
|
|
|
|
|
assert(message);
|
|
|
|
|
|
|
|
|
|
if (link->permanent_hw_addr.length > 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* When udevd is running, read the permanent hardware address after the interface is
|
|
|
|
|
* initialized by udevd. Otherwise, ethtool may not work correctly. See issue #22538.
|
|
|
|
|
* When udevd is not running, read the value when the interface is detected. */
|
|
|
|
|
if (link->state != (udev_available() ? LINK_STATE_INITIALIZED : LINK_STATE_PENDING))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
r = netlink_message_read_hw_addr(message, IFLA_PERM_ADDRESS, &link->permanent_hw_addr);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
if (r != -ENODATA)
|
|
|
|
|
return log_link_debug_errno(link, r, "Failed to read IFLA_PERM_ADDRESS attribute: %m");
|
|
|
|
|
|
|
|
|
|
if (netlink_message_read_hw_addr(message, IFLA_ADDRESS, NULL) >= 0) {
|
|
|
|
|
/* Fallback to ethtool, if the link has a hardware address. */
|
|
|
|
|
r = ethtool_get_permanent_hw_addr(&link->manager->ethtool_fd, link->ifname, &link->permanent_hw_addr);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
log_link_debug_errno(link, r, "Permanent hardware address not found, continuing without: %m");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (link->permanent_hw_addr.length > 0)
|
|
|
|
|
log_link_debug(link, "Saved permanent hardware address: %s", HW_ADDR_TO_STR(&link->permanent_hw_addr));
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
static int link_update_hardware_address(Link *link, sd_netlink_message *message) {
|
2021-07-01 14:52:05 +09:00
|
|
|
struct hw_addr_data addr;
|
2021-05-26 13:13:13 +09:00
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
assert(message);
|
|
|
|
|
|
|
|
|
|
r = netlink_message_read_hw_addr(message, IFLA_BROADCAST, &link->bcast_addr);
|
|
|
|
|
if (r < 0 && r != -ENODATA)
|
|
|
|
|
return log_link_debug_errno(link, r, "rtnl: failed to read broadcast address: %m");
|
|
|
|
|
|
2021-07-01 14:52:05 +09:00
|
|
|
r = netlink_message_read_hw_addr(message, IFLA_ADDRESS, &addr);
|
2021-05-26 13:13:13 +09:00
|
|
|
if (r == -ENODATA)
|
|
|
|
|
return 0;
|
|
|
|
|
if (r < 0)
|
2021-06-25 16:25:48 +09:00
|
|
|
return log_link_debug_errno(link, r, "rtnl: failed to read hardware address: %m");
|
2021-05-26 13:13:13 +09:00
|
|
|
|
2021-07-01 14:52:05 +09:00
|
|
|
if (hw_addr_equal(&link->hw_addr, &addr))
|
2021-05-26 13:13:13 +09:00
|
|
|
return 0;
|
|
|
|
|
|
2021-11-06 14:12:30 +09:00
|
|
|
if (link->hw_addr.length == 0)
|
2021-07-01 14:52:05 +09:00
|
|
|
log_link_debug(link, "Saved hardware address: %s", HW_ADDR_TO_STR(&addr));
|
2021-06-25 16:25:48 +09:00
|
|
|
else {
|
2022-06-24 09:13:42 +02:00
|
|
|
log_link_debug(link, "Hardware address is changed: %s %s %s",
|
|
|
|
|
HW_ADDR_TO_STR(&link->hw_addr),
|
|
|
|
|
special_glyph(SPECIAL_GLYPH_ARROW_RIGHT),
|
|
|
|
|
HW_ADDR_TO_STR(&addr));
|
2021-05-26 13:13:13 +09:00
|
|
|
|
2022-01-29 00:30:22 +09:00
|
|
|
hashmap_remove_value(link->manager->links_by_hw_addr, &link->hw_addr, link);
|
2021-06-25 16:25:48 +09:00
|
|
|
}
|
|
|
|
|
|
2021-07-01 14:52:05 +09:00
|
|
|
link->hw_addr = addr;
|
|
|
|
|
|
2021-06-25 16:25:48 +09:00
|
|
|
if (!hw_addr_is_null(&link->hw_addr)) {
|
|
|
|
|
r = hashmap_ensure_put(&link->manager->links_by_hw_addr, &hw_addr_hash_ops, &link->hw_addr, link);
|
|
|
|
|
if (r == -EEXIST && streq_ptr(link->kind, "bond"))
|
|
|
|
|
/* bonding master and its slaves have the same hardware address. */
|
|
|
|
|
r = hashmap_replace(link->manager->links_by_hw_addr, &link->hw_addr, link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
log_link_debug_errno(link, r, "Failed to manage link by its new hardware address, ignoring: %m");
|
|
|
|
|
}
|
2021-05-26 13:13:13 +09:00
|
|
|
|
2021-06-22 04:08:19 +09:00
|
|
|
r = ipv4ll_update_mac(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Could not update MAC address in IPv4 ACD client: %m");
|
|
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
r = ipv4ll_update_mac(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Could not update MAC address in IPv4LL client: %m");
|
|
|
|
|
|
|
|
|
|
r = dhcp4_update_mac(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Could not update MAC address in DHCP client: %m");
|
|
|
|
|
|
|
|
|
|
r = dhcp6_update_mac(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Could not update MAC address in DHCPv6 client: %m");
|
|
|
|
|
|
|
|
|
|
r = radv_update_mac(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Could not update MAC address for Router Advertisement: %m");
|
|
|
|
|
|
2022-07-14 05:23:01 +09:00
|
|
|
if (link->ndisc && link->hw_addr.length == ETH_ALEN) {
|
2021-06-10 00:19:47 +09:00
|
|
|
r = sd_ndisc_set_mac(link->ndisc, &link->hw_addr.ether);
|
2021-05-26 13:13:13 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Could not update MAC for NDisc: %m");
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-26 12:39:36 +09:00
|
|
|
if (link->lldp_rx) {
|
|
|
|
|
r = sd_lldp_rx_set_filter_address(link->lldp_rx, &link->hw_addr.ether);
|
2021-05-26 13:13:13 +09:00
|
|
|
if (r < 0)
|
2021-09-26 19:13:20 +09:00
|
|
|
return log_link_debug_errno(link, r, "Could not update MAC address for LLDP Rx: %m");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (link->lldp_tx) {
|
|
|
|
|
r = sd_lldp_tx_set_hwaddr(link->lldp_tx, &link->hw_addr.ether);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Could not update MAC address for LLDP Tx: %m");
|
2021-05-26 13:13:13 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int link_update_mtu(Link *link, sd_netlink_message *message) {
|
2021-06-06 14:46:58 +09:00
|
|
|
uint32_t mtu, min_mtu = 0, max_mtu = UINT32_MAX;
|
2021-05-26 13:13:13 +09:00
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
assert(message);
|
|
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, IFLA_MTU, &mtu);
|
|
|
|
|
if (r == -ENODATA)
|
|
|
|
|
return 0;
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "rtnl: failed to read MTU in RTM_NEWLINK message: %m");
|
2021-06-14 15:43:43 +09:00
|
|
|
if (mtu == 0)
|
|
|
|
|
return 0;
|
2021-05-26 13:13:13 +09:00
|
|
|
|
2021-06-06 14:46:58 +09:00
|
|
|
r = sd_netlink_message_read_u32(message, IFLA_MIN_MTU, &min_mtu);
|
|
|
|
|
if (r < 0 && r != -ENODATA)
|
|
|
|
|
return log_link_debug_errno(link, r, "rtnl: failed to read minimum MTU in RTM_NEWLINK message: %m");
|
|
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, IFLA_MAX_MTU, &max_mtu);
|
|
|
|
|
if (r < 0 && r != -ENODATA)
|
|
|
|
|
return log_link_debug_errno(link, r, "rtnl: failed to read maximum MTU in RTM_NEWLINK message: %m");
|
|
|
|
|
|
|
|
|
|
if (max_mtu == 0)
|
|
|
|
|
max_mtu = UINT32_MAX;
|
|
|
|
|
|
|
|
|
|
link->min_mtu = min_mtu;
|
|
|
|
|
link->max_mtu = max_mtu;
|
|
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
if (link->original_mtu == 0) {
|
|
|
|
|
link->original_mtu = mtu;
|
2021-06-06 14:46:58 +09:00
|
|
|
log_link_debug(link, "Saved original MTU %" PRIu32" (min: %"PRIu32", max: %"PRIu32")",
|
|
|
|
|
link->original_mtu, link->min_mtu, link->max_mtu);
|
2021-05-26 13:13:13 +09:00
|
|
|
}
|
|
|
|
|
|
2021-06-06 14:46:58 +09:00
|
|
|
if (link->mtu == mtu)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2021-06-14 15:43:43 +09:00
|
|
|
if (link->mtu != 0)
|
2022-06-24 09:13:42 +02:00
|
|
|
log_link_debug(link, "MTU is changed: %"PRIu32" %s %"PRIu32" (min: %"PRIu32", max: %"PRIu32")",
|
|
|
|
|
link->mtu, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), mtu,
|
|
|
|
|
link->min_mtu, link->max_mtu);
|
2021-05-26 13:13:13 +09:00
|
|
|
|
|
|
|
|
link->mtu = mtu;
|
|
|
|
|
|
|
|
|
|
if (link->dhcp_client) {
|
|
|
|
|
r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Could not update MTU in DHCP client: %m");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (link->radv) {
|
|
|
|
|
r = sd_radv_set_mtu(link->radv, link->mtu);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Could not set MTU for Router Advertisement: %m");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int link_update_alternative_names(Link *link, sd_netlink_message *message) {
|
|
|
|
|
_cleanup_strv_free_ char **altnames = NULL;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
assert(message);
|
|
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_strv(message, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &altnames);
|
2021-11-19 05:36:44 +09:00
|
|
|
if (r == -ENODATA)
|
|
|
|
|
/* The message does not have IFLA_PROP_LIST container attribute. It does not means the
|
|
|
|
|
* interface has no alternative name. */
|
|
|
|
|
return 0;
|
|
|
|
|
if (r < 0)
|
2021-05-26 13:13:13 +09:00
|
|
|
return log_link_debug_errno(link, r, "rtnl: failed to read alternative names: %m");
|
|
|
|
|
|
2021-11-19 06:01:45 +09:00
|
|
|
if (strv_equal(altnames, link->alternative_names))
|
|
|
|
|
return 0;
|
|
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
STRV_FOREACH(n, link->alternative_names)
|
|
|
|
|
hashmap_remove(link->manager->links_by_name, *n);
|
|
|
|
|
|
|
|
|
|
strv_free_and_replace(link->alternative_names, altnames);
|
|
|
|
|
|
|
|
|
|
STRV_FOREACH(n, link->alternative_names) {
|
|
|
|
|
r = hashmap_ensure_put(&link->manager->links_by_name, &string_hash_ops, *n, link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Failed to manage link by its new alternative names: %m");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int link_update_name(Link *link, sd_netlink_message *message) {
|
2021-09-28 21:19:07 +09:00
|
|
|
char ifname_from_index[IF_NAMESIZE];
|
2021-05-26 13:13:13 +09:00
|
|
|
const char *ifname;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
assert(message);
|
|
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_string(message, IFLA_IFNAME, &ifname);
|
|
|
|
|
if (r == -ENODATA)
|
2021-06-15 14:09:29 +09:00
|
|
|
/* Hmm?? But ok. */
|
2021-05-26 13:13:13 +09:00
|
|
|
return 0;
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Failed to read interface name in RTM_NEWLINK message: %m");
|
|
|
|
|
|
|
|
|
|
if (streq(ifname, link->ifname))
|
|
|
|
|
return 0;
|
|
|
|
|
|
2021-09-28 21:19:07 +09:00
|
|
|
r = format_ifname(link->ifindex, ifname_from_index);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Could not get interface name for index %i.", link->ifindex);
|
2021-07-12 21:23:41 +09:00
|
|
|
|
|
|
|
|
if (!streq(ifname, ifname_from_index)) {
|
|
|
|
|
log_link_debug(link, "New interface name '%s' received from the kernel does not correspond "
|
|
|
|
|
"with the name currently configured on the actual interface '%s'. Ignoring.",
|
|
|
|
|
ifname, ifname_from_index);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
log_link_info(link, "Interface name change detected, renamed to %s.", ifname);
|
|
|
|
|
|
|
|
|
|
hashmap_remove(link->manager->links_by_name, link->ifname);
|
|
|
|
|
|
|
|
|
|
r = free_and_strdup(&link->ifname, ifname);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_oom_debug();
|
|
|
|
|
|
|
|
|
|
r = hashmap_ensure_put(&link->manager->links_by_name, &string_hash_ops, link->ifname, link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Failed to manage link by its new name: %m");
|
|
|
|
|
|
2021-07-13 20:02:44 +09:00
|
|
|
if (link->dhcp_client) {
|
|
|
|
|
r = sd_dhcp_client_set_ifname(link->dhcp_client, link->ifname);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Failed to update interface name in DHCP client: %m");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (link->dhcp6_client) {
|
|
|
|
|
r = sd_dhcp6_client_set_ifname(link->dhcp6_client, link->ifname);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Failed to update interface name in DHCP6 client: %m");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (link->ndisc) {
|
|
|
|
|
r = sd_ndisc_set_ifname(link->ndisc, link->ifname);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Failed to update interface name in NDisc: %m");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (link->dhcp_server) {
|
|
|
|
|
r = sd_dhcp_server_set_ifname(link->dhcp_server, link->ifname);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Failed to update interface name in DHCP server: %m");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (link->radv) {
|
|
|
|
|
r = sd_radv_set_ifname(link->radv, link->ifname);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Failed to update interface name in Router Advertisement: %m");
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-26 12:39:36 +09:00
|
|
|
if (link->lldp_rx) {
|
|
|
|
|
r = sd_lldp_rx_set_ifname(link->lldp_rx, link->ifname);
|
2021-07-13 20:02:44 +09:00
|
|
|
if (r < 0)
|
2021-09-26 19:13:20 +09:00
|
|
|
return log_link_debug_errno(link, r, "Failed to update interface name in LLDP Rx: %m");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (link->lldp_tx) {
|
|
|
|
|
r = sd_lldp_tx_set_ifname(link->lldp_tx, link->ifname);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Failed to update interface name in LLDP Tx: %m");
|
2021-07-13 20:02:44 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (link->ipv4ll) {
|
|
|
|
|
r = sd_ipv4ll_set_ifname(link->ipv4ll, link->ifname);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Failed to update interface name in IPv4LL client: %m");
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-08 14:08:13 +09:00
|
|
|
r = ipv4acd_set_ifname(link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_link_debug_errno(link, r, "Failed to update interface name in IPv4ACD client: %m");
|
2021-07-13 20:02:44 +09:00
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int link_update(Link *link, sd_netlink_message *message) {
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
assert(message);
|
|
|
|
|
|
|
|
|
|
r = link_update_name(link, message);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = link_update_alternative_names(link, message);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = link_update_mtu(link, message);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2022-02-17 05:24:26 +09:00
|
|
|
r = link_update_driver(link, message);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = link_update_permanent_hardware_address(link, message);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
r = link_update_hardware_address(link, message);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = link_update_master(link, message);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2022-02-08 22:26:23 +09:00
|
|
|
r = link_update_ipv6ll_addrgen_mode(link, message);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
return link_update_flags(link, message);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 12:47:28 +09:00
|
|
|
static Link *link_drop_or_unref(Link *link) {
|
|
|
|
|
if (!link)
|
|
|
|
|
return NULL;
|
|
|
|
|
if (!link->manager)
|
|
|
|
|
return link_unref(link);
|
|
|
|
|
return link_drop(link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_drop_or_unref);
|
|
|
|
|
|
|
|
|
|
static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
|
2021-05-26 13:13:13 +09:00
|
|
|
_cleanup_free_ char *ifname = NULL, *kind = NULL, *state_file = NULL, *lease_file = NULL, *lldp_file = NULL;
|
2021-05-26 12:47:28 +09:00
|
|
|
_cleanup_(link_drop_or_unrefp) Link *link = NULL;
|
|
|
|
|
unsigned short iftype;
|
|
|
|
|
int r, ifindex;
|
|
|
|
|
|
|
|
|
|
assert(manager);
|
|
|
|
|
assert(message);
|
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
|
|
r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
|
|
|
|
|
if (r < 0)
|
2021-05-26 13:13:13 +09:00
|
|
|
return log_debug_errno(r, "rtnl: failed to read ifindex from link message: %m");
|
2021-05-26 12:47:28 +09:00
|
|
|
else if (ifindex <= 0)
|
2021-05-26 13:13:13 +09:00
|
|
|
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "rtnl: received link message without valid ifindex.");
|
2021-05-26 12:47:28 +09:00
|
|
|
|
|
|
|
|
r = sd_rtnl_message_link_get_type(message, &iftype);
|
|
|
|
|
if (r < 0)
|
2021-05-26 13:13:13 +09:00
|
|
|
return log_debug_errno(r, "rtnl: failed to read interface type from link message: %m");
|
2021-05-26 12:47:28 +09:00
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_string_strdup(message, IFLA_IFNAME, &ifname);
|
|
|
|
|
if (r < 0)
|
2021-05-26 13:13:13 +09:00
|
|
|
return log_debug_errno(r, "rtnl: failed to read interface name from link message: %m");
|
2021-05-26 12:47:28 +09:00
|
|
|
|
|
|
|
|
/* check for link kind */
|
|
|
|
|
r = sd_netlink_message_enter_container(message, IFLA_LINKINFO);
|
|
|
|
|
if (r >= 0) {
|
2021-05-26 13:13:13 +09:00
|
|
|
r = sd_netlink_message_read_string_strdup(message, IFLA_INFO_KIND, &kind);
|
|
|
|
|
if (r < 0 && r != -ENODATA)
|
|
|
|
|
return log_debug_errno(r, "rtnl: failed to read interface kind from link message: %m");
|
2021-05-26 12:47:28 +09:00
|
|
|
r = sd_netlink_message_exit_container(message);
|
|
|
|
|
if (r < 0)
|
2021-05-26 13:13:13 +09:00
|
|
|
return log_debug_errno(r, "rtnl: failed to exit IFLA_LINKINFO container: %m");
|
2021-05-26 12:47:28 +09:00
|
|
|
}
|
|
|
|
|
|
2021-09-29 17:32:55 +09:00
|
|
|
if (!manager->test_mode) {
|
|
|
|
|
/* Do not update state files when running in test mode. */
|
|
|
|
|
if (asprintf(&state_file, "/run/systemd/netif/links/%d", ifindex) < 0)
|
|
|
|
|
return log_oom_debug();
|
2021-05-26 13:13:13 +09:00
|
|
|
|
2021-09-29 17:32:55 +09:00
|
|
|
if (asprintf(&lease_file, "/run/systemd/netif/leases/%d", ifindex) < 0)
|
|
|
|
|
return log_oom_debug();
|
2021-05-26 13:13:13 +09:00
|
|
|
|
2021-09-29 17:32:55 +09:00
|
|
|
if (asprintf(&lldp_file, "/run/systemd/netif/lldp/%d", ifindex) < 0)
|
|
|
|
|
return log_oom_debug();
|
|
|
|
|
}
|
2021-05-26 13:13:13 +09:00
|
|
|
|
2021-05-26 12:47:28 +09:00
|
|
|
link = new(Link, 1);
|
|
|
|
|
if (!link)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
*link = (Link) {
|
|
|
|
|
.n_ref = 1,
|
|
|
|
|
.state = LINK_STATE_PENDING,
|
|
|
|
|
.online_state = _LINK_ONLINE_STATE_INVALID,
|
|
|
|
|
.ifindex = ifindex,
|
|
|
|
|
.iftype = iftype,
|
|
|
|
|
.ifname = TAKE_PTR(ifname),
|
|
|
|
|
.kind = TAKE_PTR(kind),
|
|
|
|
|
|
2022-02-08 22:26:23 +09:00
|
|
|
.ipv6ll_address_gen_mode = _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_INVALID,
|
|
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
.state_file = TAKE_PTR(state_file),
|
|
|
|
|
.lease_file = TAKE_PTR(lease_file),
|
|
|
|
|
.lldp_file = TAKE_PTR(lldp_file),
|
|
|
|
|
|
2021-05-26 12:47:28 +09:00
|
|
|
.n_dns = UINT_MAX,
|
|
|
|
|
.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,
|
|
|
|
|
};
|
|
|
|
|
|
2021-06-25 15:58:30 +09:00
|
|
|
r = hashmap_ensure_put(&manager->links_by_index, NULL, INT_TO_PTR(link->ifindex), link);
|
2021-05-26 12:47:28 +09:00
|
|
|
if (r < 0)
|
2021-05-26 13:13:13 +09:00
|
|
|
return log_link_debug_errno(link, r, "Failed to store link into manager: %m");
|
2021-05-26 12:47:28 +09:00
|
|
|
|
|
|
|
|
link->manager = manager;
|
|
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
r = hashmap_ensure_put(&manager->links_by_name, &string_hash_ops, link->ifname, link);
|
2021-05-26 12:47:28 +09:00
|
|
|
if (r < 0)
|
2021-05-26 13:13:13 +09:00
|
|
|
return log_link_debug_errno(link, r, "Failed to manage link by its interface name: %m");
|
2021-05-26 12:47:28 +09:00
|
|
|
|
2021-11-07 12:18:08 +09:00
|
|
|
log_link_debug(link, "Saved new link: ifindex=%i, iftype=%s(%u), kind=%s",
|
|
|
|
|
link->ifindex, strna(arphrd_to_name(link->iftype)), link->iftype, strna(link->kind));
|
|
|
|
|
|
2021-05-26 12:47:28 +09:00
|
|
|
*ret = TAKE_PTR(link);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *manager) {
|
2021-02-21 15:51:51 +09:00
|
|
|
Link *link = NULL;
|
|
|
|
|
NetDev *netdev = NULL;
|
|
|
|
|
uint16_t type;
|
|
|
|
|
const char *name;
|
|
|
|
|
int r, ifindex;
|
|
|
|
|
|
|
|
|
|
assert(rtnl);
|
|
|
|
|
assert(message);
|
2021-05-26 13:13:13 +09:00
|
|
|
assert(manager);
|
2021-02-21 15:51:51 +09:00
|
|
|
|
|
|
|
|
if (sd_netlink_message_is_error(message)) {
|
|
|
|
|
r = sd_netlink_message_get_errno(message);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
log_message_warning_errno(message, r, "rtnl: Could not receive link message, ignoring");
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_type(message, &type);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
log_warning_errno(r, "rtnl: Could not get message type, ignoring: %m");
|
|
|
|
|
return 0;
|
|
|
|
|
} else if (!IN_SET(type, RTM_NEWLINK, RTM_DELLINK)) {
|
|
|
|
|
log_warning("rtnl: Received unexpected message type %u when processing link, ignoring.", type);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
log_warning_errno(r, "rtnl: Could not get ifindex from link message, ignoring: %m");
|
|
|
|
|
return 0;
|
|
|
|
|
} else if (ifindex <= 0) {
|
|
|
|
|
log_warning("rtnl: received link message with invalid ifindex %d, ignoring.", ifindex);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
log_warning_errno(r, "rtnl: Received link message without ifname, ignoring: %m");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-25 15:58:30 +09:00
|
|
|
(void) link_get_by_index(manager, ifindex, &link);
|
2021-05-26 13:13:13 +09:00
|
|
|
(void) netdev_get(manager, name, &netdev);
|
2021-02-21 15:51:51 +09:00
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
|
case RTM_NEWLINK:
|
|
|
|
|
if (netdev) {
|
|
|
|
|
/* netdev exists, so make sure the ifindex matches */
|
|
|
|
|
r = netdev_set_ifindex(netdev, message);
|
|
|
|
|
if (r < 0) {
|
2022-02-09 02:14:12 +09:00
|
|
|
log_netdev_warning_errno(netdev, r, "Could not process new link message for netdev, ignoring: %m");
|
2021-02-21 15:51:51 +09:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 13:13:13 +09:00
|
|
|
if (!link) {
|
|
|
|
|
/* link is new, so add it */
|
|
|
|
|
r = link_new(manager, message, &link);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
log_warning_errno(r, "Could not process new link message: %m");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = link_update(link, message);
|
|
|
|
|
if (r < 0) {
|
2022-02-09 02:14:12 +09:00
|
|
|
log_link_warning_errno(link, r, "Could not process link message: %m");
|
2021-05-26 13:13:13 +09:00
|
|
|
link_enter_failed(link);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = link_check_initialized(link);
|
|
|
|
|
if (r < 0) {
|
2022-02-09 02:14:12 +09:00
|
|
|
log_link_warning_errno(link, r, "Failed to check link is initialized: %m");
|
2021-05-26 13:13:13 +09:00
|
|
|
link_enter_failed(link);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
r = link_update(link, message);
|
|
|
|
|
if (r < 0) {
|
2022-02-09 02:14:12 +09:00
|
|
|
log_link_warning_errno(link, r, "Could not process link message: %m");
|
2021-05-26 13:13:13 +09:00
|
|
|
link_enter_failed(link);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2021-02-21 15:51:51 +09:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RTM_DELLINK:
|
|
|
|
|
link_drop(link);
|
|
|
|
|
netdev_drop(netdev);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
Drop the text argument from assert_not_reached()
In general we almost never hit those asserts in production code, so users see
them very rarely, if ever. But either way, we just need something that users
can pass to the developers.
We have quite a few of those asserts, and some have fairly nice messages, but
many are like "WTF?" or "???" or "unexpected something". The error that is
printed includes the file location, and function name. In almost all functions
there's at most one assert, so the function name alone is enough to identify
the failure for a developer. So we don't get much extra from the message, and
we might just as well drop them.
Dropping them makes our code a tiny bit smaller, and most importantly, improves
development experience by making it easy to insert such an assert in the code
without thinking how to phrase the argument.
2021-07-27 12:27:28 +02:00
|
|
|
assert_not_reached();
|
2021-02-21 15:51:51 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 13:44:02 +09:00
|
|
|
int link_getlink_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg) {
|
|
|
|
|
uint16_t message_type;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
assert(link);
|
|
|
|
|
assert(error_msg);
|
|
|
|
|
|
|
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_errno(m);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
log_link_message_warning_errno(link, m, r, error_msg);
|
|
|
|
|
link_enter_failed(link);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_type(m, &message_type);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
log_link_debug_errno(link, r, "rtnl: failed to read link message type, ignoring: %m");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (message_type != RTM_NEWLINK) {
|
|
|
|
|
log_link_debug(link, "rtnl: received invalid link message type, ignoring.");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = link_update(link, m);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
link_enter_failed(link);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int link_call_getlink(Link *link, link_netlink_message_handler_t callback) {
|
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
assert(link->manager);
|
|
|
|
|
assert(link->manager->rtnl);
|
|
|
|
|
assert(callback);
|
|
|
|
|
|
|
|
|
|
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, callback,
|
|
|
|
|
link_netlink_destroy_callback, link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
link_ref(link);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-27 01:24:05 +01:00
|
|
|
static const char* const link_state_table[_LINK_STATE_MAX] = {
|
2021-11-26 12:03:44 +01:00
|
|
|
[LINK_STATE_PENDING] = "pending",
|
2019-04-15 17:34:00 +09:00
|
|
|
[LINK_STATE_INITIALIZED] = "initialized",
|
2018-11-30 15:36:33 -08:00
|
|
|
[LINK_STATE_CONFIGURING] = "configuring",
|
2021-11-26 12:03:44 +01:00
|
|
|
[LINK_STATE_CONFIGURED] = "configured",
|
|
|
|
|
[LINK_STATE_UNMANAGED] = "unmanaged",
|
|
|
|
|
[LINK_STATE_FAILED] = "failed",
|
|
|
|
|
[LINK_STATE_LINGER] = "linger",
|
2014-02-27 01:24:05 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
DEFINE_STRING_TABLE_LOOKUP(link_state, LinkState);
|
2021-11-14 18:36:42 +09:00
|
|
|
|
|
|
|
|
int link_flags_to_string_alloc(uint32_t flags, char **ret) {
|
|
|
|
|
_cleanup_free_ char *str = NULL;
|
2021-11-26 12:03:12 +01:00
|
|
|
static const char* map[] = {
|
|
|
|
|
[LOG2U(IFF_UP)] = "up", /* interface is up. */
|
|
|
|
|
[LOG2U(IFF_BROADCAST)] = "broadcast", /* broadcast address valid.*/
|
|
|
|
|
[LOG2U(IFF_DEBUG)] = "debug", /* turn on debugging. */
|
|
|
|
|
[LOG2U(IFF_LOOPBACK)] = "loopback", /* interface is a loopback net. */
|
|
|
|
|
[LOG2U(IFF_POINTOPOINT)] = "point-to-point", /* interface has p-p link. */
|
|
|
|
|
[LOG2U(IFF_NOTRAILERS)] = "no-trailers", /* avoid use of trailers. */
|
|
|
|
|
[LOG2U(IFF_RUNNING)] = "running", /* interface RFC2863 OPER_UP. */
|
|
|
|
|
[LOG2U(IFF_NOARP)] = "no-arp", /* no ARP protocol. */
|
|
|
|
|
[LOG2U(IFF_PROMISC)] = "promiscuous", /* receive all packets. */
|
|
|
|
|
[LOG2U(IFF_ALLMULTI)] = "all-multicast", /* receive all multicast packets. */
|
|
|
|
|
[LOG2U(IFF_MASTER)] = "master", /* master of a load balancer. */
|
|
|
|
|
[LOG2U(IFF_SLAVE)] = "slave", /* slave of a load balancer. */
|
|
|
|
|
[LOG2U(IFF_MULTICAST)] = "multicast", /* supports multicast.*/
|
|
|
|
|
[LOG2U(IFF_PORTSEL)] = "portsel", /* can set media type. */
|
|
|
|
|
[LOG2U(IFF_AUTOMEDIA)] = "auto-media", /* auto media select active. */
|
|
|
|
|
[LOG2U(IFF_DYNAMIC)] = "dynamic", /* dialup device with changing addresses. */
|
|
|
|
|
[LOG2U(IFF_LOWER_UP)] = "lower-up", /* driver signals L1 up. */
|
|
|
|
|
[LOG2U(IFF_DORMANT)] = "dormant", /* driver signals dormant. */
|
|
|
|
|
[LOG2U(IFF_ECHO)] = "echo", /* echo sent packets. */
|
2021-11-14 18:36:42 +09:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < ELEMENTSOF(map); i++)
|
2021-11-26 12:03:12 +01:00
|
|
|
if (FLAGS_SET(flags, 1 << i) && map[i])
|
|
|
|
|
if (!strextend_with_separator(&str, ",", map[i]))
|
|
|
|
|
return -ENOMEM;
|
2021-11-14 18:36:42 +09:00
|
|
|
|
|
|
|
|
*ret = TAKE_PTR(str);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char * const kernel_operstate_table[] = {
|
|
|
|
|
[IF_OPER_UNKNOWN] = "unknown",
|
|
|
|
|
[IF_OPER_NOTPRESENT] = "not-present",
|
|
|
|
|
[IF_OPER_DOWN] = "down",
|
|
|
|
|
[IF_OPER_LOWERLAYERDOWN] = "lower-layer-down",
|
|
|
|
|
[IF_OPER_TESTING] = "testing",
|
|
|
|
|
[IF_OPER_DORMANT] = "dormant",
|
|
|
|
|
[IF_OPER_UP] = "up",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(kernel_operstate, int);
|