1
0
mirror of https://github.com/systemd/systemd.git synced 2025-02-04 21:47:31 +03:00

network: set broadcast address on request

Previously, the broadcast address was set to a Address object in
address_section_verify() (or address_acquire()). But, for wireguard
interfaces, we do not use the broadcast address. The .network file may
be assigned to multiple interfaces, hence, we cannot determine if we
should set the broadcast address in address_section_verify().

This makes the broadcast address set in link_request_address().
Then, we set the broadcast address only when we need it.
This commit is contained in:
Yu Watanabe 2022-02-24 07:07:02 +09:00
parent 5d0030310c
commit e680486d6f
4 changed files with 37 additions and 33 deletions

View File

@ -174,8 +174,9 @@ void link_mark_addresses(Link *link, NetworkConfigSource source, const struct in
}
}
static bool address_may_have_broadcast(const Address *a) {
static bool address_needs_to_set_broadcast(const Address *a, Link *link) {
assert(a);
assert(link);
if (a->family != AF_INET)
return false;
@ -188,38 +189,26 @@ static bool address_may_have_broadcast(const Address *a) {
if (a->prefixlen > 30)
return false;
/* If explicitly configured, do not update the address. */
if (in4_addr_is_set(&a->broadcast))
return false;
if (a->set_broadcast >= 0)
return a->set_broadcast;
return true; /* Defaults to true. */
/* Defaults to true, except for wireguard, as typical configuration for wireguard does not set
* broadcast. */
return !streq_ptr(link->kind, "wireguard");
}
void address_set_broadcast(Address *a) {
assert(a);
if (!address_may_have_broadcast(a))
return;
/* If explicitly configured, do not update the address. */
if (in4_addr_is_set(&a->broadcast))
return;
/* If Address= is 0.0.0.0, then the broadcast address will be set later in address_acquire(). */
if (in4_addr_is_null(&a->in_addr.in))
return;
a->broadcast.s_addr = a->in_addr.in.s_addr | htobe32(UINT32_C(0xffffffff) >> a->prefixlen);
}
static bool address_may_set_broadcast(const Address *a, const Link *link) {
void address_set_broadcast(Address *a, Link *link) {
assert(a);
assert(link);
if (!address_may_have_broadcast(a))
return false;
if (!address_needs_to_set_broadcast(a, link))
return;
/* Typical configuration for wireguard does not set broadcast. */
return !streq_ptr(link->kind, "wireguard");
a->broadcast.s_addr = a->in_addr.in.s_addr | htobe32(UINT32_C(0xffffffff) >> a->prefixlen);
}
static struct ifa_cacheinfo *address_set_cinfo(const Address *a, struct ifa_cacheinfo *cinfo) {
@ -975,7 +964,6 @@ static int address_acquire(Link *link, const Address *original, Address **ret) {
return r;
na->in_addr = in_addr;
address_set_broadcast(na);
*ret = TAKE_PTR(na);
return 1;
@ -1037,7 +1025,7 @@ static int address_configure(
r = netlink_message_append_in_addr_union(req, IFA_ADDRESS, address->family, &address->in_addr_peer);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFA_ADDRESS attribute: %m");
} else if (address_may_set_broadcast(address, link)) {
} else if (in4_addr_is_set(&address->broadcast)) {
r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFA_BROADCAST attribute: %m");
@ -1132,6 +1120,21 @@ int link_request_address(
consume_object = true;
}
if (address_needs_to_set_broadcast(address, link)) {
if (!consume_object) {
Address *a;
r = address_dup(address, &a);
if (r < 0)
return r;
address = a;
consume_object = true;
}
address_set_broadcast(address, link);
}
if (address_get(link, address, &existing) < 0) {
_cleanup_(address_freep) Address *tmp = NULL;
@ -1922,10 +1925,11 @@ static int address_section_verify(Address *address) {
address->section->filename, address->section->line);
}
if (address_may_have_broadcast(address))
address_set_broadcast(address);
else if (address->broadcast.s_addr != 0) {
log_warning("%s: broadcast address is set for IPv6 address or IPv4 address with prefixlength larger than 30. "
if (in4_addr_is_set(&address->broadcast) &&
(address->family == AF_INET6 || address->prefixlen > 30 ||
in_addr_is_set(address->family, &address->in_addr_peer))) {
log_warning("%s: broadcast address is set for an IPv6 address, "
"an IPv4 address with peer address, or with prefix length larger than 30. "
"Ignoring Broadcast= setting in the [Address] section from line %u.",
address->section->filename, address->section->line);

View File

@ -70,7 +70,7 @@ int address_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m,
int address_remove(Address *address);
int address_dup(const Address *src, Address **ret);
bool address_is_ready(const Address *a);
void address_set_broadcast(Address *a);
void address_set_broadcast(Address *a, Link *link);
DEFINE_SECTION_CLEANUP_FUNCTIONS(Address, address_free);

View File

@ -106,7 +106,7 @@ int link_request_dhcp_server_address(Link *link) {
address->family = AF_INET;
address->in_addr.in = link->network->dhcp_server_address;
address->prefixlen = link->network->dhcp_server_address_prefixlen;
address_set_broadcast(address);
address_set_broadcast(address, link);
if (address_get(link, address, &existing) >= 0 &&
address_exists(existing) &&

View File

@ -34,7 +34,7 @@ static int address_new_from_ipv4ll(Link *link, Address **ret) {
address->prefixlen = 16;
address->scope = RT_SCOPE_LINK;
address->route_metric = IPV4LL_ROUTE_METRIC;
address_set_broadcast(address);
address_set_broadcast(address, link);
*ret = TAKE_PTR(address);
return 0;