Compare commits
3 Commits
8403c1a2a0
...
57c9133b99
Author | SHA1 | Date |
---|---|---|
![]() |
57c9133b99 | |
![]() |
6052d7584a | |
![]() |
5c14eef88c |
5
NEWS
5
NEWS
|
@ -489,6 +489,11 @@ CHANGES WITH 257:
|
|||
existing interfaces, and invoke 'networkctl reload' or restart
|
||||
systemd-networkd.
|
||||
|
||||
* The timeout for IPv4 Duplicate Address Detection can now be
|
||||
configured via a new IPv4DuplicateAddressDetectionTimeout=
|
||||
setting. The default timeout value has been changed from 7 seconds to
|
||||
200 milliseconds.
|
||||
|
||||
systemd-boot, systemd-stub, and related tools:
|
||||
|
||||
* The EFI stub now supports loading of .ucode sections with microcode
|
||||
|
|
|
@ -987,6 +987,17 @@ DuplicateAddressDetection=none</programlisting></para>
|
|||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>IPv4DuplicateAddressDetectionTimeout=</varname></term>
|
||||
<listitem>
|
||||
<para>Configures the maximum timeout for IPv4 Duplicate Address Detection (RFC 5227). Must be a
|
||||
value between 1 millisecond and 60 seconds. If set, Duplicate Address Detection takes a randomized
|
||||
time between 57% (4/7) and 100% of the given value. If unset, defaults to 200 milliseconds.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>IPv4ReversePathFilter=</varname></term>
|
||||
<listitem>
|
||||
|
|
|
@ -25,18 +25,26 @@
|
|||
#include "string-util.h"
|
||||
#include "time-util.h"
|
||||
|
||||
/* Constants from the RFC */
|
||||
#define PROBE_WAIT_USEC (1U * USEC_PER_SEC)
|
||||
#define PROBE_NUM 3U
|
||||
#define PROBE_MIN_USEC (1U * USEC_PER_SEC)
|
||||
#define PROBE_MAX_USEC (2U * USEC_PER_SEC)
|
||||
#define ANNOUNCE_WAIT_USEC (2U * USEC_PER_SEC)
|
||||
#define ANNOUNCE_NUM 2U
|
||||
/* Intervals from the RFC in seconds, need to be multiplied by the time unit */
|
||||
#define PROBE_WAIT 1U
|
||||
#define PROBE_MIN 1U
|
||||
#define PROBE_MAX 2U
|
||||
#define ANNOUNCE_WAIT 2U
|
||||
#define TOTAL_TIMEOUT 7U
|
||||
|
||||
/* Intervals from the RFC not adjusted to the time unit */
|
||||
#define ANNOUNCE_INTERVAL_USEC (2U * USEC_PER_SEC)
|
||||
#define MAX_CONFLICTS 10U
|
||||
#define RATE_LIMIT_INTERVAL_USEC (60U * USEC_PER_SEC)
|
||||
#define DEFEND_INTERVAL_USEC (10U * USEC_PER_SEC)
|
||||
|
||||
/* Other constants from the RFC */
|
||||
#define PROBE_NUM 3U
|
||||
#define ANNOUNCE_NUM 2U
|
||||
#define MAX_CONFLICTS 10U
|
||||
|
||||
/* Default timeout from the RFC */
|
||||
#define TIMEOUT_DEFAULT_USEC (200 * USEC_PER_MSEC)
|
||||
|
||||
typedef enum IPv4ACDState {
|
||||
IPV4ACD_STATE_INIT,
|
||||
IPV4ACD_STATE_STARTED,
|
||||
|
@ -60,6 +68,10 @@ struct sd_ipv4acd {
|
|||
unsigned n_iteration;
|
||||
unsigned n_conflict;
|
||||
|
||||
/* Indicates the duration of a "time unit", i.e. one second in the RFC but scaled to the
|
||||
* chosen total duration. Represents 1/7 of the total conflict detection timeout. */
|
||||
uint64_t time_unit;
|
||||
|
||||
sd_event_source *receive_message_event_source;
|
||||
sd_event_source *timer_event_source;
|
||||
|
||||
|
@ -150,6 +162,7 @@ int sd_ipv4acd_new(sd_ipv4acd **ret) {
|
|||
*acd = (sd_ipv4acd) {
|
||||
.n_ref = 1,
|
||||
.state = IPV4ACD_STATE_INIT,
|
||||
.time_unit = TIMEOUT_DEFAULT_USEC / TOTAL_TIMEOUT,
|
||||
.ifindex = -1,
|
||||
.fd = -EBADF,
|
||||
};
|
||||
|
@ -218,14 +231,20 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata)
|
|||
case IPV4ACD_STATE_STARTED:
|
||||
acd->defend_window = 0;
|
||||
|
||||
log_ipv4acd(acd,
|
||||
"Started on address " IPV4_ADDRESS_FMT_STR " with a max timeout of %" PRIu64 "msec",
|
||||
IPV4_ADDRESS_FMT_VAL(acd->address),
|
||||
(acd->time_unit * TOTAL_TIMEOUT + (USEC_PER_MSEC - 1)) / USEC_PER_MSEC);
|
||||
|
||||
ipv4acd_set_state(acd, IPV4ACD_STATE_WAITING_PROBE, true);
|
||||
|
||||
if (acd->n_conflict >= MAX_CONFLICTS) {
|
||||
log_ipv4acd(acd, "Max conflicts reached, delaying by %s",
|
||||
FORMAT_TIMESPAN(RATE_LIMIT_INTERVAL_USEC, 0));
|
||||
r = ipv4acd_set_next_wakeup(acd, RATE_LIMIT_INTERVAL_USEC, PROBE_WAIT_USEC);
|
||||
r = ipv4acd_set_next_wakeup(
|
||||
acd, RATE_LIMIT_INTERVAL_USEC, PROBE_WAIT * acd->time_unit);
|
||||
} else
|
||||
r = ipv4acd_set_next_wakeup(acd, 0, PROBE_WAIT_USEC);
|
||||
r = ipv4acd_set_next_wakeup(acd, 0, PROBE_WAIT * acd->time_unit);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
|
@ -245,13 +264,16 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata)
|
|||
if (acd->n_iteration < PROBE_NUM - 2) {
|
||||
ipv4acd_set_state(acd, IPV4ACD_STATE_PROBING, false);
|
||||
|
||||
r = ipv4acd_set_next_wakeup(acd, PROBE_MIN_USEC, (PROBE_MAX_USEC-PROBE_MIN_USEC));
|
||||
r = ipv4acd_set_next_wakeup(
|
||||
acd,
|
||||
PROBE_MIN * acd->time_unit,
|
||||
(PROBE_MAX - PROBE_MIN) * acd->time_unit);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
} else {
|
||||
ipv4acd_set_state(acd, IPV4ACD_STATE_WAITING_ANNOUNCE, true);
|
||||
|
||||
r = ipv4acd_set_next_wakeup(acd, ANNOUNCE_WAIT_USEC, 0);
|
||||
r = ipv4acd_set_next_wakeup(acd, ANNOUNCE_WAIT * acd->time_unit, 0);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
@ -442,6 +464,18 @@ int sd_ipv4acd_set_ifname(sd_ipv4acd *acd, const char *ifname) {
|
|||
return free_and_strdup(&acd->ifname, ifname);
|
||||
}
|
||||
|
||||
int sd_ipv4acd_set_timeout(sd_ipv4acd *acd, uint64_t timeout_usec) {
|
||||
assert_return(acd, -EINVAL);
|
||||
|
||||
if (timeout_usec == 0)
|
||||
timeout_usec = TIMEOUT_DEFAULT_USEC;
|
||||
|
||||
/* Clamp the total duration to a value between 1ms and 1 minute */
|
||||
acd->time_unit = CLAMP(timeout_usec, 1U * USEC_PER_MSEC, 60U * USEC_PER_SEC) / TOTAL_TIMEOUT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4acd_get_ifname(sd_ipv4acd *acd, const char **ret) {
|
||||
int r;
|
||||
|
||||
|
|
|
@ -153,6 +153,12 @@ int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4ll_set_timeout(sd_ipv4ll *ll, uint64_t timeout_usec) {
|
||||
assert_return(ll, -EINVAL);
|
||||
|
||||
return sd_ipv4acd_set_timeout(ll->acd, timeout_usec);
|
||||
}
|
||||
|
||||
int sd_ipv4ll_detach_event(sd_ipv4ll *ll) {
|
||||
assert_return(ll, -EINVAL);
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ DEFINE_PRIVATE_HASH_OPS_FULL(
|
|||
bool link_ipv4acd_supported(Link *link) {
|
||||
assert(link);
|
||||
|
||||
if (link->flags & IFF_LOOPBACK)
|
||||
if (link->flags & (IFF_LOOPBACK | IFF_NOARP))
|
||||
return false;
|
||||
|
||||
/* ARPHRD_INFINIBAND seems to potentially support IPv4ACD.
|
||||
|
@ -39,13 +39,6 @@ bool link_ipv4acd_supported(Link *link) {
|
|||
if (ether_addr_is_null(&link->hw_addr.ether))
|
||||
return false;
|
||||
|
||||
if (streq_ptr(link->kind, "vrf"))
|
||||
return false;
|
||||
|
||||
/* L3 or L3S mode do not support ARP. */
|
||||
if (IN_SET(link_get_ipvlan_mode(link), NETDEV_IPVLAN_MODE_L3, NETDEV_IPVLAN_MODE_L3S))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -212,6 +205,7 @@ int ipv4acd_configure(Link *link, const Address *address) {
|
|||
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
assert(link->network);
|
||||
assert(address);
|
||||
|
||||
if (address->family != AF_INET)
|
||||
|
@ -256,6 +250,10 @@ int ipv4acd_configure(Link *link, const Address *address) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ipv4acd_set_timeout(acd, link->network->ipv4_dad_timeout);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ipv4acd_set_callback(acd, on_acd, link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
|
@ -223,6 +223,7 @@ int ipv4ll_configure(Link *link) {
|
|||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->network);
|
||||
|
||||
if (!link_ipv4ll_enabled(link))
|
||||
return 0;
|
||||
|
@ -253,6 +254,10 @@ int ipv4ll_configure(Link *link) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ipv4ll_set_timeout(link->ipv4ll, link->network->ipv4_dad_timeout);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ipv4ll_set_ifindex(link->ipv4ll, link->ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
|
@ -139,6 +139,7 @@ Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extension
|
|||
Network.IPv6AcceptRA, config_parse_tristate, 0, offsetof(Network, ndisc)
|
||||
Network.IPv6AcceptRouterAdvertisements, config_parse_tristate, 0, offsetof(Network, ndisc)
|
||||
Network.IPv6DuplicateAddressDetection, config_parse_int, 0, offsetof(Network, ipv6_dad_transmits)
|
||||
Network.IPv4DuplicateAddressDetectionTimeout, config_parse_sec, 0, offsetof(Network, ipv4_dad_timeout)
|
||||
Network.IPv6HopLimit, config_parse_uint8, 0, offsetof(Network, ipv6_hop_limit)
|
||||
Network.IPv6RetransmissionTimeSec, config_parse_sec, 0, offsetof(Network, ipv6_retransmission_time)
|
||||
Network.IPv6ProxyNDP, config_parse_tristate, 0, offsetof(Network, ipv6_proxy_ndp)
|
||||
|
|
|
@ -112,6 +112,7 @@ struct Network {
|
|||
char **bind_carrier;
|
||||
bool default_route_on_device;
|
||||
AddressFamily ip_masquerade;
|
||||
usec_t ipv4_dad_timeout;
|
||||
|
||||
/* Protocol independent settings */
|
||||
UseDomains use_domains;
|
||||
|
|
|
@ -48,6 +48,7 @@ int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int interface_index);
|
|||
int sd_ipv4acd_get_ifindex(sd_ipv4acd *acd);
|
||||
int sd_ipv4acd_set_ifname(sd_ipv4acd *acd, const char *interface_name);
|
||||
int sd_ipv4acd_get_ifname(sd_ipv4acd *acd, const char **ret);
|
||||
int sd_ipv4acd_set_timeout(sd_ipv4acd *acd, uint64_t timeout_usec);
|
||||
int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address);
|
||||
int sd_ipv4acd_is_running(sd_ipv4acd *acd);
|
||||
int sd_ipv4acd_is_bound(sd_ipv4acd *acd);
|
||||
|
|
|
@ -44,6 +44,7 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address);
|
|||
int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata);
|
||||
int sd_ipv4ll_set_check_mac_callback(sd_ipv4ll *ll, sd_ipv4ll_check_mac_callback_t cb, void *userdata);
|
||||
int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr);
|
||||
int sd_ipv4ll_set_timeout(sd_ipv4ll *ll, uint64_t timeout_usec);
|
||||
int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int interface_index);
|
||||
int sd_ipv4ll_get_ifindex(sd_ipv4ll *ll);
|
||||
int sd_ipv4ll_set_ifname(sd_ipv4ll *ll, const char *interface_name);
|
||||
|
|
Loading…
Reference in New Issue