2020-11-09 05:23:58 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
2014-08-06 15:54:03 +02:00
|
|
|
|
2019-05-09 02:33:45 +02:00
|
|
|
#include <netinet/in.h>
|
2014-08-06 15:54:03 +02:00
|
|
|
#include <linux/if.h>
|
|
|
|
|
|
|
|
#include "network-internal.h"
|
2016-11-13 04:59:06 +01:00
|
|
|
#include "networkd-address.h"
|
2019-06-29 20:57:47 +02:00
|
|
|
#include "networkd-ipv4ll.h"
|
2016-11-13 04:59:06 +01:00
|
|
|
#include "networkd-link.h"
|
2019-06-29 20:57:47 +02:00
|
|
|
#include "networkd-manager.h"
|
|
|
|
#include "parse-util.h"
|
2014-08-06 15:54:03 +02:00
|
|
|
|
|
|
|
static int ipv4ll_address_lost(Link *link) {
|
tree-wide: drop redundant _cleanup_ macros (#8810)
This drops a good number of type-specific _cleanup_ macros, and patches
all users to just use the generic ones.
In most recent code we abstained from defining type-specific macros, and
this basically removes all those added already, with the exception of
the really low-level ones.
Having explicit macros for this is not too useful, as the expression
without the extra macro is generally just 2ch wider. We should generally
emphesize generic code, unless there are really good reasons for
specific code, hence let's follow this in this case too.
Note that _cleanup_free_ and similar really low-level, libc'ish, Linux
API'ish macros continue to be defined, only the really high-level OO
ones are dropped. From now on this should really be the rule: for really
low-level stuff, such as memory allocation, fd handling and so one, go
ahead and define explicit per-type macros, but for high-level, specific
program code, just use the generic _cleanup_() macro directly, in order
to keep things simple and as readable as possible for the uninitiated.
Note that before this patch some of the APIs (notable libudev ones) were
already used with the high-level macros at some places and with the
generic _cleanup_ macro at others. With this patch we hence unify on the
latter.
2018-04-25 12:31:45 +02:00
|
|
|
_cleanup_(address_freep) Address *address = NULL;
|
2014-08-06 15:54:03 +02:00
|
|
|
struct in_addr addr;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
2020-07-22 18:21:40 +02:00
|
|
|
link->ipv4ll_address_configured = false;
|
2014-08-06 15:54:03 +02:00
|
|
|
|
|
|
|
r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
|
|
|
|
if (r < 0)
|
|
|
|
return 0;
|
|
|
|
|
2020-10-07 13:42:54 +02:00
|
|
|
log_link_debug(link, "IPv4 link-local release "IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(addr));
|
2014-08-06 15:54:03 +02:00
|
|
|
|
2015-09-21 15:53:40 +02:00
|
|
|
r = address_new(&address);
|
2018-08-07 08:48:37 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not allocate address: %m");
|
2014-08-06 15:54:03 +02:00
|
|
|
|
|
|
|
address->family = AF_INET;
|
|
|
|
address->in_addr.in = addr;
|
|
|
|
address->prefixlen = 16;
|
|
|
|
address->scope = RT_SCOPE_LINK;
|
|
|
|
|
2019-05-14 10:58:20 +02:00
|
|
|
r = address_remove(address, link, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-08-06 15:54:03 +02:00
|
|
|
|
2015-09-28 13:38:43 +02:00
|
|
|
link_check_ready(link);
|
2014-08-06 15:54:03 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-28 21:06:52 +01:00
|
|
|
static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
2014-08-06 15:54:03 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
2020-07-22 18:21:40 +02:00
|
|
|
assert(!link->ipv4ll_address_configured);
|
2014-08-06 15:54:03 +02:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_errno(m);
|
2014-08-06 15:54:03 +02:00
|
|
|
if (r < 0 && r != -EEXIST) {
|
2019-11-30 07:54:07 +01:00
|
|
|
log_link_message_warning_errno(link, m, r, "could not set ipv4ll address");
|
2014-08-06 15:54:03 +02:00
|
|
|
link_enter_failed(link);
|
2019-07-14 17:35:49 +02:00
|
|
|
return 1;
|
2014-12-08 19:54:06 +01:00
|
|
|
} else if (r >= 0)
|
2019-07-14 17:35:49 +02:00
|
|
|
(void) manager_rtnl_process_address(rtnl, m, link->manager);
|
2014-08-06 15:54:03 +02:00
|
|
|
|
2020-07-22 18:21:40 +02:00
|
|
|
link->ipv4ll_address_configured = true;
|
2019-08-28 15:42:33 +02:00
|
|
|
link_check_ready(link);
|
2014-08-06 15:54:03 +02:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
|
tree-wide: drop redundant _cleanup_ macros (#8810)
This drops a good number of type-specific _cleanup_ macros, and patches
all users to just use the generic ones.
In most recent code we abstained from defining type-specific macros, and
this basically removes all those added already, with the exception of
the really low-level ones.
Having explicit macros for this is not too useful, as the expression
without the extra macro is generally just 2ch wider. We should generally
emphesize generic code, unless there are really good reasons for
specific code, hence let's follow this in this case too.
Note that _cleanup_free_ and similar really low-level, libc'ish, Linux
API'ish macros continue to be defined, only the really high-level OO
ones are dropped. From now on this should really be the rule: for really
low-level stuff, such as memory allocation, fd handling and so one, go
ahead and define explicit per-type macros, but for high-level, specific
program code, just use the generic _cleanup_() macro directly, in order
to keep things simple and as readable as possible for the uninitiated.
Note that before this patch some of the APIs (notable libudev ones) were
already used with the high-level macros at some places and with the
generic _cleanup_ macro at others. With this patch we hence unify on the
latter.
2018-04-25 12:31:45 +02:00
|
|
|
_cleanup_(address_freep) Address *ll_addr = NULL;
|
2014-08-06 15:54:03 +02:00
|
|
|
struct in_addr address;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(ll);
|
|
|
|
assert(link);
|
|
|
|
|
2020-07-22 18:21:40 +02:00
|
|
|
link->ipv4ll_address_configured = false;
|
2019-02-12 05:00:25 +01:00
|
|
|
|
2014-08-06 15:54:03 +02:00
|
|
|
r = sd_ipv4ll_get_address(ll, &address);
|
|
|
|
if (r == -ENOENT)
|
|
|
|
return 0;
|
|
|
|
else if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-10-07 13:42:54 +02:00
|
|
|
log_link_debug(link, "IPv4 link-local claim "IPV4_ADDRESS_FMT_STR,
|
|
|
|
IPV4_ADDRESS_FMT_VAL(address));
|
2014-08-06 15:54:03 +02:00
|
|
|
|
2015-09-21 15:53:40 +02:00
|
|
|
r = address_new(&ll_addr);
|
2014-08-06 15:54:03 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
ll_addr->family = AF_INET;
|
|
|
|
ll_addr->in_addr.in = address;
|
|
|
|
ll_addr->prefixlen = 16;
|
2016-06-15 01:26:01 +02:00
|
|
|
ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htobe32(0xfffffffflu >> ll_addr->prefixlen);
|
2014-08-06 15:54:03 +02:00
|
|
|
ll_addr->scope = RT_SCOPE_LINK;
|
|
|
|
|
2020-07-22 02:41:30 +02:00
|
|
|
r = address_configure(ll_addr, link, ipv4ll_address_handler, false, NULL);
|
2014-08-06 15:54:03 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-02-23 18:52:52 +01:00
|
|
|
static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
|
2014-08-06 15:54:03 +02:00
|
|
|
Link *link = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
|
|
|
|
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch(event) {
|
2015-09-22 15:08:28 +02:00
|
|
|
case SD_IPV4LL_EVENT_STOP:
|
2017-03-31 22:40:18 +02:00
|
|
|
r = ipv4ll_address_lost(link);
|
|
|
|
if (r < 0) {
|
|
|
|
link_enter_failed(link);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
2015-09-22 15:08:28 +02:00
|
|
|
case SD_IPV4LL_EVENT_CONFLICT:
|
2014-08-06 15:54:03 +02:00
|
|
|
r = ipv4ll_address_lost(link);
|
|
|
|
if (r < 0) {
|
|
|
|
link_enter_failed(link);
|
|
|
|
return;
|
|
|
|
}
|
2017-03-31 22:40:18 +02:00
|
|
|
|
|
|
|
r = sd_ipv4ll_restart(ll);
|
|
|
|
if (r < 0)
|
2019-05-07 15:54:15 +02:00
|
|
|
log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
|
2014-08-06 15:54:03 +02:00
|
|
|
break;
|
2015-09-22 15:08:28 +02:00
|
|
|
case SD_IPV4LL_EVENT_BIND:
|
2014-08-06 15:54:03 +02:00
|
|
|
r = ipv4ll_address_claimed(ll, link);
|
|
|
|
if (r < 0) {
|
2019-02-12 05:00:25 +01:00
|
|
|
log_link_error(link, "Failed to configure ipv4ll address: %m");
|
2014-08-06 15:54:03 +02:00
|
|
|
link_enter_failed(link);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2015-08-20 11:40:10 +02:00
|
|
|
log_link_warning(link, "IPv4 link-local unknown event: %d", event);
|
2014-08-06 15:54:03 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int ipv4ll_configure(Link *link) {
|
2015-11-16 09:21:20 +01:00
|
|
|
uint64_t seed;
|
2014-08-06 15:54:03 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
2020-10-04 00:37:22 +02:00
|
|
|
|
networkd: merge ll addressing fallback modes into normal "boolean" values
They are not really boolean, because we have both ipv4 and ipv6, but
for each protocol we have either unset, no, and yes.
From https://github.com/systemd/systemd/issues/13316#issuecomment-582906817:
LinkLocalAddressing must be a boolean option, at least for ipv4:
- LinkLocalAddressing=no => no LL at all.
- LinkLocalAddressing=yes + Static Address => invalid configuration, warn and
interpret as LinkLocalAddressing=no, no LL at all.
(we check that during parsing and reject)
- LinkLocalAddressing=yes + DHCP => LL process should be subordinated to the
DHCP one, an LL address must be acquired at start or after a short N
unsuccessful DHCP attemps, and must not stop DHCP to keeping trying. When a
DHCP address is acquired, drop the LL address. If the DHCP address is lost,
re-adquire a new LL address.
(next patch will move in this direction)
- LinkLocalAddressing=fallback has no reason to exist, because LL address must
always be allocated as a fallback option when using DHCP. Having both DHCP
and LL address at the same time is an RFC violation, so
LinkLocalAdressing=yes correctly implemented is already the "fallback"
behavior. The fallback option must be deprecated and if present in older
configs must be interpreted as LinkLocalAddressing=yes.
(removed)
- And for IPv6, the LinkLocalAddress option has any sense at all? IPv6-LL
address aren't required to be always set for every IPv6 enabled interface (in
this case, coexisting with static or dynamic address if any)? Shouldn't be
always =yes?
(good question)
This effectively reverts 29e81083bd2fcb2dbf83f67ef358c7d25adf7e9d. There is no
special "fallback" mode now, so the check doesn't make sense anymore.
2020-10-08 16:59:26 +02:00
|
|
|
if (!link_ipv4ll_enabled(link))
|
2020-10-04 00:37:22 +02:00
|
|
|
return 0;
|
2014-08-06 15:54:03 +02:00
|
|
|
|
2020-10-28 07:30:25 +01:00
|
|
|
if (!link->ipv4ll) {
|
|
|
|
r = sd_ipv4ll_new(&link->ipv4ll);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_ipv4ll_attach_event(link->ipv4ll, link->manager->event, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
2014-08-06 15:54:03 +02:00
|
|
|
|
2018-08-22 07:30:49 +02:00
|
|
|
if (link->sd_device &&
|
2019-06-17 09:42:46 +02:00
|
|
|
net_get_unique_predictable_data(link->sd_device, true, &seed) >= 0) {
|
2018-08-22 07:30:49 +02:00
|
|
|
r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-08-06 15:54:03 +02:00
|
|
|
}
|
|
|
|
|
2020-10-26 18:07:49 +01:00
|
|
|
r = sd_ipv4ll_set_mac(link->ipv4ll, &link->hw_addr.addr.ether);
|
2014-08-06 15:54:03 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-05-23 16:13:18 +02:00
|
|
|
r = sd_ipv4ll_set_ifindex(link->ipv4ll, link->ifindex);
|
2014-08-06 15:54:03 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2019-06-29 20:57:47 +02:00
|
|
|
|
2020-10-02 13:25:11 +02:00
|
|
|
int ipv4ll_update_mac(Link *link) {
|
|
|
|
bool restart;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (!link->ipv4ll)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
restart = sd_ipv4ll_is_running(link->ipv4ll) > 0;
|
|
|
|
|
2020-10-15 00:39:55 +02:00
|
|
|
r = sd_ipv4ll_stop(link->ipv4ll);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2020-10-02 13:25:11 +02:00
|
|
|
|
2020-10-26 18:07:49 +01:00
|
|
|
r = sd_ipv4ll_set_mac(link->ipv4ll, &link->hw_addr.addr.ether);
|
2020-10-02 13:25:11 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (restart) {
|
|
|
|
r = sd_ipv4ll_start(link->ipv4ll);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-29 20:57:47 +02:00
|
|
|
int config_parse_ipv4ll(
|
|
|
|
const char* unit,
|
|
|
|
const char *filename,
|
|
|
|
unsigned line,
|
|
|
|
const char *section,
|
|
|
|
unsigned section_line,
|
|
|
|
const char *lvalue,
|
|
|
|
int ltype,
|
|
|
|
const char *rvalue,
|
|
|
|
void *data,
|
|
|
|
void *userdata) {
|
|
|
|
|
2019-08-03 22:09:08 +02:00
|
|
|
AddressFamily *link_local = data;
|
2019-06-29 20:57:47 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
/* Note that this is mostly like
|
2019-08-03 22:09:08 +02:00
|
|
|
* config_parse_address_family(), except that it
|
2019-06-29 20:57:47 +02:00
|
|
|
* applies only to IPv4 */
|
|
|
|
|
|
|
|
r = parse_boolean(rvalue);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
2019-06-29 20:57:47 +02:00
|
|
|
"Failed to parse %s=%s, ignoring assignment. "
|
|
|
|
"Note that the setting %s= is deprecated, please use LinkLocalAddressing= instead.",
|
|
|
|
lvalue, rvalue, lvalue);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, r);
|
|
|
|
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
|
|
|
"%s=%s is deprecated, please use LinkLocalAddressing=%s instead.",
|
2019-08-03 22:09:08 +02:00
|
|
|
lvalue, rvalue, address_family_to_string(*link_local));
|
2019-06-29 20:57:47 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|