Merge pull request #19980 from yuwata/sd-ipv4acd-filter-all-hwaddr

network: IPv4LL and ACD fixes
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2021-06-30 22:22:47 +02:00
committed by GitHub
41 changed files with 881 additions and 684 deletions

View File

@@ -37,6 +37,16 @@ int hw_addr_compare(const struct hw_addr_data *a, const struct hw_addr_data *b)
return memcmp(a->bytes, b->bytes, a->length);
}
static void hw_addr_hash_func(const struct hw_addr_data *p, struct siphash *state) {
assert(p);
assert(state);
siphash24_compress(&p->length, sizeof(p->length), state);
siphash24_compress(p->bytes, p->length, state);
}
DEFINE_HASH_OPS(hw_addr_hash_ops, struct hw_addr_data, hw_addr_hash_func, hw_addr_compare);
char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
assert(addr);
assert(buffer);

View File

@@ -36,6 +36,8 @@ static inline bool hw_addr_is_null(const struct hw_addr_data *addr) {
return hw_addr_equal(addr, &HW_ADDR_NULL);
}
extern const struct hash_ops hw_addr_hash_ops;
#define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X"
#define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5]

View File

@@ -8,11 +8,13 @@
#include <netinet/if_ether.h>
#include "arp-util.h"
#include "ether-addr-util.h"
#include "fd-util.h"
#include "in-addr-util.h"
#include "unaligned.h"
#include "util.h"
int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_addr *eth_mac) {
int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *eth_mac) {
struct sock_filter filter[] = {
BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */
BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct ether_arp), 1, 0), /* packet >= arp packet ? */
@@ -46,13 +48,13 @@ int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
/* Sender Protocol Address or Target Protocol Address must be equal to the one we care about */
BPF_STMT(BPF_LD + BPF_IMM, htobe32(address)), /* A <- clients IP */
BPF_STMT(BPF_LD + BPF_IMM, htobe32(a->s_addr)), /* A <- clients IP */
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_spa)), /* A <- SPA */
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* X xor A */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */
BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
BPF_STMT(BPF_LD + BPF_IMM, htobe32(address)), /* A <- clients IP */
BPF_STMT(BPF_LD + BPF_IMM, htobe32(a->s_addr)), /* A <- clients IP */
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_tpa)), /* A <- TPA */
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* X xor A */
@@ -61,15 +63,25 @@ int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
};
struct sock_fprog fprog = {
.len = ELEMENTSOF(filter),
.filter = (struct sock_filter*) filter
.len = ELEMENTSOF(filter),
.filter = (struct sock_filter*) filter,
};
assert(fd >= 0);
if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) < 0)
return -errno;
return 0;
}
int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *eth_mac) {
union sockaddr_union link = {
.ll.sll_family = AF_PACKET,
.ll.sll_family = AF_PACKET,
.ll.sll_protocol = htobe16(ETH_P_ARP),
.ll.sll_ifindex = ifindex,
.ll.sll_halen = ETH_ALEN,
.ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
.ll.sll_ifindex = ifindex,
.ll.sll_halen = ETH_ALEN,
.ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
};
_cleanup_close_ int s = -1;
int r;
@@ -80,59 +92,57 @@ int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_
if (s < 0)
return -errno;
r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
r = arp_update_filter(s, a, eth_mac);
if (r < 0)
return -errno;
return r;
r = bind(s, &link.sa, sizeof(link.ll));
if (r < 0)
if (bind(s, &link.sa, sizeof(link.ll)) < 0)
return -errno;
return TAKE_FD(s);
}
static int arp_send_packet(int fd, int ifindex,
be32_t pa, const struct ether_addr *ha,
bool announce) {
int arp_send_packet(
int fd,
int ifindex,
const struct in_addr *pa,
const struct ether_addr *ha,
bool announce) {
union sockaddr_union link = {
.ll.sll_family = AF_PACKET,
.ll.sll_family = AF_PACKET,
.ll.sll_protocol = htobe16(ETH_P_ARP),
.ll.sll_ifindex = ifindex,
.ll.sll_halen = ETH_ALEN,
.ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
.ll.sll_ifindex = ifindex,
.ll.sll_halen = ETH_ALEN,
.ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
};
struct ether_arp arp = {
.ea_hdr.ar_hrd = htobe16(ARPHRD_ETHER), /* HTYPE */
.ea_hdr.ar_pro = htobe16(ETHERTYPE_IP), /* PTYPE */
.ea_hdr.ar_hln = ETH_ALEN, /* HLEN */
.ea_hdr.ar_pln = sizeof(be32_t), /* PLEN */
.ea_hdr.ar_op = htobe16(ARPOP_REQUEST), /* REQUEST */
.ea_hdr.ar_hrd = htobe16(ARPHRD_ETHER), /* HTYPE */
.ea_hdr.ar_pro = htobe16(ETHERTYPE_IP), /* PTYPE */
.ea_hdr.ar_hln = ETH_ALEN, /* HLEN */
.ea_hdr.ar_pln = sizeof(struct in_addr), /* PLEN */
.ea_hdr.ar_op = htobe16(ARPOP_REQUEST), /* REQUEST */
};
int r;
ssize_t n;
assert(fd >= 0);
assert(pa != 0);
assert(ifindex > 0);
assert(pa);
assert(in4_addr_is_set(pa));
assert(ha);
assert(!ether_addr_is_null(ha));
memcpy(&arp.arp_sha, ha, ETH_ALEN);
memcpy(&arp.arp_tpa, &pa, sizeof(pa));
memcpy(&arp.arp_tpa, pa, sizeof(struct in_addr));
if (announce)
memcpy(&arp.arp_spa, &pa, sizeof(pa));
memcpy(&arp.arp_spa, pa, sizeof(struct in_addr));
r = sendto(fd, &arp, sizeof(struct ether_arp), 0, &link.sa, sizeof(link.ll));
if (r < 0)
n = sendto(fd, &arp, sizeof(struct ether_arp), 0, &link.sa, sizeof(link.ll));
if (n < 0)
return -errno;
if (n != sizeof(struct ether_arp))
return -EIO;
return 0;
}
int arp_send_probe(int fd, int ifindex,
be32_t pa, const struct ether_addr *ha) {
return arp_send_packet(fd, ifindex, pa, ha, false);
}
int arp_send_announcement(int fd, int ifindex,
be32_t pa, const struct ether_addr *ha) {
return arp_send_packet(fd, ifindex, pa, ha, true);
}

View File

@@ -6,13 +6,31 @@
***/
#include <net/ethernet.h>
#include <netinet/in.h>
#include "socket-util.h"
#include "sparse-endian.h"
int arp_network_bind_raw_socket(int index, be32_t address, const struct ether_addr *eth_mac);
int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *eth_mac);
int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *eth_mac);
int arp_send_probe(int fd, int ifindex,
be32_t pa, const struct ether_addr *ha);
int arp_send_announcement(int fd, int ifindex,
be32_t pa, const struct ether_addr *ha);
int arp_send_packet(
int fd,
int ifindex,
const struct in_addr *pa,
const struct ether_addr *ha,
bool announce);
static inline int arp_send_probe(
int fd,
int ifindex,
const struct in_addr *pa,
const struct ether_addr *ha) {
return arp_send_packet(fd, ifindex, pa, ha, false);
}
static inline int arp_send_announcement(
int fd,
int ifindex,
const struct in_addr *pa,
const struct ether_addr *ha) {
return arp_send_packet(fd, ifindex, pa, ha, true);
}

View File

@@ -18,6 +18,7 @@
#include "fd-util.h"
#include "in-addr-util.h"
#include "log-link.h"
#include "memory-util.h"
#include "network-common.h"
#include "random-util.h"
#include "siphash24.h"
@@ -64,7 +65,7 @@ struct sd_ipv4acd {
sd_event_source *timer_event_source;
usec_t defend_window;
be32_t address;
struct in_addr address;
/* External */
struct ether_addr mac_addr;
@@ -72,7 +73,9 @@ struct sd_ipv4acd {
sd_event *event;
int event_priority;
sd_ipv4acd_callback_t callback;
void* userdata;
void *userdata;
sd_ipv4acd_check_mac_callback_t check_mac_callback;
void *check_mac_userdata;
};
#define log_ipv4acd_errno(acd, error, fmt, ...) \
@@ -208,18 +211,6 @@ static int ipv4acd_set_next_wakeup(sd_ipv4acd *acd, usec_t usec, usec_t random_u
acd->event_priority, "ipv4acd-timer", true);
}
static bool ipv4acd_arp_conflict(sd_ipv4acd *acd, struct ether_arp *arp) {
assert(acd);
assert(arp);
/* see the BPF */
if (memcmp(arp->arp_spa, &acd->address, sizeof(acd->address)) == 0)
return true;
/* the TPA matched instead of the SPA, this is not a conflict */
return false;
}
static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
sd_ipv4acd *acd = userdata;
int r = 0;
@@ -229,38 +220,34 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata)
switch (acd->state) {
case IPV4ACD_STATE_STARTED:
acd->defend_window = 0;
ipv4acd_set_state(acd, IPV4ACD_STATE_WAITING_PROBE, true);
if (acd->n_conflict >= MAX_CONFLICTS) {
char ts[FORMAT_TIMESPAN_MAX];
log_ipv4acd(acd, "Max conflicts reached, delaying by %s", format_timespan(ts, sizeof(ts), RATE_LIMIT_INTERVAL_USEC, 0));
log_ipv4acd(acd, "Max conflicts reached, delaying by %s",
format_timespan(ts, sizeof(ts), RATE_LIMIT_INTERVAL_USEC, 0));
r = ipv4acd_set_next_wakeup(acd, RATE_LIMIT_INTERVAL_USEC, PROBE_WAIT_USEC);
if (r < 0)
goto fail;
} else {
} else
r = ipv4acd_set_next_wakeup(acd, 0, PROBE_WAIT_USEC);
if (r < 0)
goto fail;
}
if (r < 0)
goto fail;
break;
case IPV4ACD_STATE_WAITING_PROBE:
case IPV4ACD_STATE_PROBING:
/* Send a probe */
r = arp_send_probe(acd->fd, acd->ifindex, acd->address, &acd->mac_addr);
r = arp_send_probe(acd->fd, acd->ifindex, &acd->address, &acd->mac_addr);
if (r < 0) {
log_ipv4acd_errno(acd, r, "Failed to send ARP probe: %m");
goto fail;
} else {
_cleanup_free_ char *address = NULL;
union in_addr_union addr = { .in.s_addr = acd->address };
(void) in_addr_to_string(AF_INET, &addr, &address);
log_ipv4acd(acd, "Probing %s", strna(address));
}
log_ipv4acd(acd, "Probing "IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(acd->address));
if (acd->n_iteration < PROBE_NUM - 2) {
ipv4acd_set_state(acd, IPV4ACD_STATE_PROBING, false);
@@ -286,12 +273,13 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata)
_fallthrough_;
case IPV4ACD_STATE_WAITING_ANNOUNCE:
/* Send announcement packet */
r = arp_send_announcement(acd->fd, acd->ifindex, acd->address, &acd->mac_addr);
r = arp_send_announcement(acd->fd, acd->ifindex, &acd->address, &acd->mac_addr);
if (r < 0) {
log_ipv4acd_errno(acd, r, "Failed to send ARP announcement: %m");
goto fail;
} else
log_ipv4acd(acd, "ANNOUNCE");
}
log_ipv4acd(acd, "Announcing "IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(acd->address));
ipv4acd_set_state(acd, IPV4ACD_STATE_ANNOUNCING, false);
@@ -317,16 +305,45 @@ fail:
return 0;
}
static void ipv4acd_on_conflict(sd_ipv4acd *acd) {
_cleanup_free_ char *address = NULL;
union in_addr_union addr = { .in.s_addr = acd->address };
static bool ipv4acd_arp_conflict(sd_ipv4acd *acd, const struct ether_arp *arp, bool announced) {
assert(acd);
assert(arp);
/* RFC 5227 section 2.1.1.
* "the host receives any ARP packet (Request *or* Reply) on the interface where the probe is
* being performed, where the packet's 'sender IP address' is the address being probed for,
* then the host MUST treat this address as being in use by some other host" */
if (memcmp(arp->arp_spa, &acd->address, sizeof(struct in_addr)) == 0)
return true;
if (announced)
/* the TPA matched instead of SPA, this is not a conflict */
return false;
/* "any ARP Probe where the packet's 'target IP address' is the address being probed for, and
* the packet's 'sender hardware address' is not the hardware address of any of the host's
* interfaces, then the host SHOULD similarly treat this as an address conflict" */
if (arp->ea_hdr.ar_op != htobe16(ARPOP_REQUEST))
return false; /* not ARP Request, ignoring. */
if (memeqzero(arp->arp_spa, sizeof(struct in_addr)) == 0)
return false; /* not ARP Probe, ignoring. */
if (memcmp(arp->arp_tpa, &acd->address, sizeof(struct in_addr)) != 0)
return false; /* target IP address does not match, BPF code is broken? */
if (acd->check_mac_callback &&
acd->check_mac_callback(acd, (const struct ether_addr*) arp->arp_sha, acd->check_mac_userdata) > 0)
/* sender hardware is one of the host's interfaces, ignoring. */
return true;
return true; /* conflict! */
}
static void ipv4acd_on_conflict(sd_ipv4acd *acd) {
assert(acd);
acd->n_conflict++;
(void) in_addr_to_string(AF_INET, &addr, &address);
log_ipv4acd(acd, "Conflict on %s (%u)", strna(address), acd->n_conflict);
log_ipv4acd(acd, "Conflict on "IPV4_ADDRESS_FMT_STR" (%u)", IPV4_ADDRESS_FMT_VAL(acd->address), acd->n_conflict);
ipv4acd_reset(acd);
ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_CONFLICT);
@@ -365,7 +382,7 @@ static int ipv4acd_on_packet(
case IPV4ACD_STATE_ANNOUNCING:
case IPV4ACD_STATE_RUNNING:
if (ipv4acd_arp_conflict(acd, &packet)) {
if (ipv4acd_arp_conflict(acd, &packet, true)) {
usec_t ts;
assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &ts) >= 0);
@@ -373,12 +390,13 @@ static int ipv4acd_on_packet(
/* Defend address */
if (ts > acd->defend_window) {
acd->defend_window = ts + DEFEND_INTERVAL_USEC;
r = arp_send_announcement(acd->fd, acd->ifindex, acd->address, &acd->mac_addr);
r = arp_send_announcement(acd->fd, acd->ifindex, &acd->address, &acd->mac_addr);
if (r < 0) {
log_ipv4acd_errno(acd, r, "Failed to send ARP announcement: %m");
goto fail;
} else
log_ipv4acd(acd, "DEFEND");
}
log_ipv4acd(acd, "Defending "IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(acd->address));
} else
ipv4acd_on_conflict(acd);
@@ -388,8 +406,8 @@ static int ipv4acd_on_packet(
case IPV4ACD_STATE_WAITING_PROBE:
case IPV4ACD_STATE_PROBING:
case IPV4ACD_STATE_WAITING_ANNOUNCE:
/* BPF ensures this packet indicates a conflict */
ipv4acd_on_conflict(acd);
if (ipv4acd_arp_conflict(acd, &packet, false))
ipv4acd_on_conflict(acd);
break;
default:
@@ -438,12 +456,24 @@ const char *sd_ipv4acd_get_ifname(sd_ipv4acd *acd) {
}
int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr) {
int r;
assert_return(acd, -EINVAL);
assert_return(addr, -EINVAL);
assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
assert_return(!ether_addr_is_null(addr), -EINVAL);
acd->mac_addr = *addr;
if (!sd_ipv4acd_is_running(acd))
return 0;
assert(acd->fd >= 0);
r = arp_update_filter(acd->fd, &acd->address, &acd->mac_addr);
if (r < 0) {
ipv4acd_reset(acd);
return r;
}
return 0;
}
@@ -483,21 +513,51 @@ int sd_ipv4acd_set_callback(sd_ipv4acd *acd, sd_ipv4acd_callback_t cb, void *use
return 0;
}
int sd_ipv4acd_set_check_mac_callback(sd_ipv4acd *acd, sd_ipv4acd_check_mac_callback_t cb, void *userdata) {
assert_return(acd, -EINVAL);
acd->check_mac_callback = cb;
acd->check_mac_userdata = userdata;
return 0;
}
int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address) {
int r;
assert_return(acd, -EINVAL);
assert_return(address, -EINVAL);
assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
assert_return(in4_addr_is_set(address), -EINVAL);
acd->address = address->s_addr;
if (in4_addr_equal(&acd->address, address))
return 0;
acd->address = *address;
if (!sd_ipv4acd_is_running(acd))
return 0;
assert(acd->fd >= 0);
r = arp_update_filter(acd->fd, &acd->address, &acd->mac_addr);
if (r < 0)
goto fail;
r = ipv4acd_set_next_wakeup(acd, 0, 0);
if (r < 0)
goto fail;
ipv4acd_set_state(acd, IPV4ACD_STATE_STARTED, true);
return 0;
fail:
ipv4acd_reset(acd);
return r;
}
int sd_ipv4acd_get_address(sd_ipv4acd *acd, struct in_addr *address) {
assert_return(acd, -EINVAL);
assert_return(address, -EINVAL);
address->s_addr = acd->address;
*address = acd->address;
return 0;
}
@@ -514,16 +574,15 @@ int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts) {
assert_return(acd, -EINVAL);
assert_return(acd->event, -EINVAL);
assert_return(acd->ifindex > 0, -EINVAL);
assert_return(acd->address != 0, -EINVAL);
assert_return(in4_addr_is_set(&acd->address), -EINVAL);
assert_return(!ether_addr_is_null(&acd->mac_addr), -EINVAL);
assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
r = arp_network_bind_raw_socket(acd->ifindex, acd->address, &acd->mac_addr);
r = arp_network_bind_raw_socket(acd->ifindex, &acd->address, &acd->mac_addr);
if (r < 0)
return r;
CLOSE_AND_REPLACE(acd->fd, r);
acd->defend_window = 0;
if (reset_conflicts)
acd->n_conflict = 0;

View File

@@ -46,7 +46,10 @@ struct sd_ipv4ll {
be32_t claimed_address;
sd_ipv4ll_callback_t callback;
void* userdata;
void *userdata;
sd_ipv4ll_check_mac_callback_t check_mac_callback;
void *check_mac_userdata;
};
#define log_ipv4ll_errno(ll, error, fmt, ...) \
@@ -60,7 +63,8 @@ struct sd_ipv4ll {
sd_ipv4ll_get_ifname(ll), \
0, fmt, ##__VA_ARGS__)
static void ipv4ll_on_acd(sd_ipv4acd *ll, int event, void *userdata);
static void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata);
static int ipv4ll_check_mac(sd_ipv4acd *acd, const struct ether_addr *mac, void *userdata);
static sd_ipv4ll *ipv4ll_free(sd_ipv4ll *ll) {
assert(ll);
@@ -91,6 +95,10 @@ int sd_ipv4ll_new(sd_ipv4ll **ret) {
if (r < 0)
return r;
r = sd_ipv4acd_set_check_mac_callback(ll->acd, ipv4ll_check_mac, ll);
if (r < 0)
return r;
*ret = TAKE_PTR(ll);
return 0;
@@ -137,7 +145,7 @@ int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) {
assert_return(ll, -EINVAL);
assert_return(addr, -EINVAL);
assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY);
assert_return(!ether_addr_is_null(addr), -EINVAL);
r = sd_ipv4acd_set_mac(ll->acd, addr);
if (r < 0)
@@ -168,6 +176,15 @@ int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdat
return 0;
}
int sd_ipv4ll_set_check_mac_callback(sd_ipv4ll *ll, sd_ipv4ll_check_mac_callback_t cb, void *userdata) {
assert_return(ll, -EINVAL);
ll->check_mac_callback = cb;
ll->check_mac_userdata = userdata;
return 0;
}
int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address) {
assert_return(ll, -EINVAL);
assert_return(address, -EINVAL);
@@ -351,3 +368,14 @@ void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
error:
ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_STOP);
}
static int ipv4ll_check_mac(sd_ipv4acd *acd, const struct ether_addr *mac, void *userdata) {
sd_ipv4ll *ll = userdata;
assert(ll);
if (ll->check_mac_callback)
return ll->check_mac_callback(ll, mac, ll->check_mac_userdata);
return 0;
}

View File

@@ -42,43 +42,31 @@ static void basic_request_handler(sd_ipv4ll *ll, int event, void *userdata) {
}
}
static int arp_network_send_raw_socket(int fd, int ifindex,
const struct ether_arp *arp) {
assert_se(arp);
assert_se(ifindex > 0);
assert_se(fd >= 0);
int arp_send_packet(
int fd,
int ifindex,
const struct in_addr *pa,
const struct ether_addr *ha,
bool announce) {
if (send(fd, arp, sizeof(struct ether_arp), 0) < 0)
struct ether_arp ea = {};
assert_se(fd >= 0);
assert_se(ifindex > 0);
assert_se(pa);
assert_se(ha);
if (send(fd, &ea, sizeof(struct ether_arp), 0) < 0)
return -errno;
return 0;
}
int arp_send_probe(int fd, int ifindex,
be32_t pa, const struct ether_addr *ha) {
struct ether_arp ea = {};
assert_se(fd >= 0);
assert_se(ifindex > 0);
assert_se(pa != 0);
assert_se(ha);
return arp_network_send_raw_socket(fd, ifindex, &ea);
int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *eth_mac) {
return 0;
}
int arp_send_announcement(int fd, int ifindex,
be32_t pa, const struct ether_addr *ha) {
struct ether_arp ea = {};
assert_se(fd >= 0);
assert_se(ifindex > 0);
assert_se(pa != 0);
assert_se(ha);
return arp_network_send_raw_socket(fd, ifindex, &ea);
}
int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_addr *eth_mac) {
int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *eth_mac) {
if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
return -errno;

View File

@@ -79,6 +79,8 @@ sources = files('''
networkd-dhcp4.h
networkd-dhcp6.c
networkd-dhcp6.h
networkd-ipv4acd.c
networkd-ipv4acd.h
networkd-ipv4ll.c
networkd-ipv4ll.h
networkd-ipv6-proxy-ndp.c

View File

@@ -95,7 +95,7 @@ static bool address_pool_prefix_is_taken(
assert(p);
assert(u);
HASHMAP_FOREACH(l, p->manager->links) {
HASHMAP_FOREACH(l, p->manager->links_by_index) {
Address *a;
/* Don't clash with assigned addresses */

File diff suppressed because it is too large Load Diff

View File

@@ -41,12 +41,13 @@ typedef struct Address {
bool scope_set:1;
bool ip_masquerade_done:1;
bool is_static:1; /* currently only used by IPv4ACD */
bool acd_announced:1;
AddressFamily duplicate_address_detection;
sd_ipv4acd *acd;
/* Called when address become ready */
address_ready_callback_t callback;
sd_ipv4acd *acd;
} Address;
int address_new(Address **ret);
@@ -55,6 +56,7 @@ int address_get(Link *link, const Address *in, Address **ret);
int address_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg);
int address_remove(const Address *address, Link *link);
bool address_equal(const Address *a1, const Address *a2);
int address_dup(const Address *src, Address **ret);
bool address_is_ready(const Address *a);
void address_set_broadcast(Address *a);
@@ -70,10 +72,6 @@ int link_get_ipv6_address(Link *link, const struct in6_addr *address, Address **
int link_get_ipv4_address(Link *link, const struct in_addr *address, unsigned char prefixlen, Address **ret);
int manager_has_address(Manager *manager, int family, const union in_addr_union *address, bool check_ready);
void ipv4_dad_unref(Link *link);
int ipv4_dad_stop(Link *link);
int ipv4_dad_update_mac(Link *link);
int link_request_address(
Link *link,
Address *address,
@@ -81,6 +79,7 @@ int link_request_address(
unsigned *message_counter,
link_netlink_message_handler_t netlink_handler,
Request **ret);
int link_request_static_address(Link *link, Address *address, bool consume);
int link_request_static_addresses(Link *link);
int request_process_address(Request *req);

View File

@@ -228,7 +228,7 @@ static bool bridge_fdb_is_ready_to_configure(BridgeFDB *fdb, Link *link) {
fdb->outgoing_ifindex = out->ifindex;
} else if (fdb->outgoing_ifindex > 0) {
if (link_get(link->manager, fdb->outgoing_ifindex, &out) < 0)
if (link_get_by_index(link->manager, fdb->outgoing_ifindex, &out) < 0)
return false;
}
if (out && !link_is_ready_to_configure(out, false))

View File

@@ -249,7 +249,7 @@ static bool bridge_mdb_is_ready_to_configure(Link *link) {
if (link->master_ifindex != link->network->bridge->ifindex)
return false;
if (link_get(link->manager, link->master_ifindex, &master) < 0)
if (link_get_by_index(link->manager, link->master_ifindex, &master) < 0)
return false;
if (!streq_ptr(master->kind, "bridge"))

View File

@@ -104,7 +104,7 @@ static int dhcp_server_find_uplink(Link *link, Link **ret) {
return link_get_by_name(link->manager, link->network->dhcp_server_uplink_name, ret);
if (link->network->dhcp_server_uplink_index > 0)
return link_get(link->manager, link->network->dhcp_server_uplink_index, ret);
return link_get_by_index(link->manager, link->network->dhcp_server_uplink_index, ret);
if (link->network->dhcp_server_uplink_index == 0) {
/* It is not necessary to propagate error in automatic selection. */

View File

@@ -14,6 +14,7 @@
#include "network-internal.h"
#include "networkd-address.h"
#include "networkd-dhcp4.h"
#include "networkd-ipv4acd.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-network.h"
@@ -84,9 +85,6 @@ static int dhcp4_release_old_lease(Link *link) {
static void dhcp4_check_ready(Link *link) {
int r;
if (link->network->dhcp_send_decline && !link->dhcp4_address_bind)
return;
if (link->dhcp4_messages > 0) {
log_link_debug(link, "%s(): DHCPv4 address and routes are not set.", __func__);
return;
@@ -738,7 +736,7 @@ static int dhcp4_remove_all(Link *link) {
return r;
}
static int dhcp_lease_lost(Link *link) {
int dhcp4_lease_lost(Link *link) {
int k, r = 0;
assert(link);
@@ -748,7 +746,7 @@ static int dhcp_lease_lost(Link *link) {
link->dhcp4_configured = false;
/* dhcp_lease_lost() may be called during renewing IP address. */
/* dhcp4_lease_lost() may be called during renewing IP address. */
k = dhcp4_release_old_lease(link);
if (k < 0)
r = k;
@@ -768,7 +766,23 @@ static int dhcp_lease_lost(Link *link) {
link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
link_dirty(link);
(void) sd_ipv4acd_stop(link->dhcp_acd);
if (link->network->dhcp_send_decline) {
Address *a;
/* The acquired address may be still ARP probing and not configured. */
SET_FOREACH(a, link->addresses_ipv4acd)
if (!a->is_static && address_get(link, a, NULL) < 0) {
Request req = {
.link = link,
.address = a,
};
log_link_debug(link, "Canceling the request to configure DHCPv4 address "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(a->in_addr.in));
request_drop(ordered_set_get(link->manager->request_queue, &req));
}
}
if (r < 0)
return r;
@@ -780,149 +794,6 @@ static int dhcp_lease_lost(Link *link) {
return link_request_static_routes(link, true);
}
static void dhcp_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
struct in_addr address;
Link *link;
int r;
assert(acd);
assert(userdata);
link = userdata;
switch (event) {
case SD_IPV4ACD_EVENT_STOP:
log_link_debug(link, "Stopping ACD client for DHCPv4 address.");
return;
case SD_IPV4ACD_EVENT_BIND:
if (DEBUG_LOGGING) {
(void) sd_dhcp_lease_get_address(link->dhcp_lease, &address);
log_link_debug(link, "Successfully claimed DHCPv4 address "IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(address));
}
link->dhcp4_address_bind = true;
dhcp4_check_ready(link);
break;
case SD_IPV4ACD_EVENT_CONFLICT:
(void) sd_dhcp_lease_get_address(link->dhcp_lease, &address);
log_link_warning(link, "DAD conflict. Dropping DHCPv4 address "IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(address));
r = sd_dhcp_client_send_decline(link->dhcp_client);
if (r < 0)
log_link_warning_errno(link, r, "Failed to send DHCP DECLINE, ignoring: %m");
if (link->dhcp_lease) {
r = dhcp_lease_lost(link);
if (r < 0)
link_enter_failed(link);
}
break;
default:
assert_not_reached("Invalid IPv4ACD event.");
}
(void) sd_ipv4acd_stop(acd);
return;
}
static int dhcp4_configure_dad(Link *link) {
int r;
assert(link);
assert(link->manager);
assert(link->network);
if (!link->network->dhcp_send_decline)
return 0;
if (!link->dhcp_acd) {
r = sd_ipv4acd_new(&link->dhcp_acd);
if (r < 0)
return r;
r = sd_ipv4acd_attach_event(link->dhcp_acd, link->manager->event, 0);
if (r < 0)
return r;
}
r = sd_ipv4acd_set_ifindex(link->dhcp_acd, link->ifindex);
if (r < 0)
return r;
r = sd_ipv4acd_set_mac(link->dhcp_acd, &link->hw_addr.ether);
if (r < 0)
return r;
return 0;
}
static int dhcp4_dad_update_mac(Link *link) {
bool running;
int r;
assert(link);
if (!link->dhcp_acd)
return 0;
running = sd_ipv4acd_is_running(link->dhcp_acd);
r = sd_ipv4acd_stop(link->dhcp_acd);
if (r < 0)
return r;
r = sd_ipv4acd_set_mac(link->dhcp_acd, &link->hw_addr.ether);
if (r < 0)
return r;
if (running) {
r = sd_ipv4acd_start(link->dhcp_acd, true);
if (r < 0)
return r;
}
return 0;
}
static int dhcp4_start_acd(Link *link) {
struct in_addr addr, old;
int r;
if (!link->network->dhcp_send_decline)
return 0;
if (!link->dhcp_lease)
return 0;
(void) sd_ipv4acd_stop(link->dhcp_acd);
link->dhcp4_address_bind = false;
r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
if (r < 0)
return r;
r = sd_ipv4acd_get_address(link->dhcp_acd, &old);
if (r < 0)
return r;
r = sd_ipv4acd_set_address(link->dhcp_acd, &addr);
if (r < 0)
return r;
r = sd_ipv4acd_set_callback(link->dhcp_acd, dhcp_address_on_acd, link);
if (r < 0)
return r;
log_link_debug(link, "Starting IPv4ACD client. Probing DHCPv4 address "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(addr));
return sd_ipv4acd_start(link->dhcp_acd, !in4_addr_equal(&addr, &old));
}
static int dhcp4_address_ready_callback(Address *address) {
assert(address);
@@ -957,11 +828,6 @@ static int dhcp4_after_address_configure(Request *req, void *object) {
}
link->dhcp_address = address;
r = dhcp4_start_acd(link);
if (r < 0)
return log_link_error_errno(link, r, "Failed to start IPv4ACD for DHCPv4 address: %m");
return 0;
}
@@ -1057,6 +923,7 @@ static int dhcp4_request_address(Link *link, bool announce) {
addr->broadcast.s_addr = address.s_addr | ~netmask.s_addr;
SET_FLAG(addr->flags, IFA_F_NOPREFIXROUTE, !link_prefixroute(link));
addr->route_metric = link->network->dhcp_route_metric;
addr->duplicate_address_detection = link->network->dhcp_send_decline ? ADDRESS_FAMILY_IPV4 : ADDRESS_FAMILY_NO;
if (address_get(link, addr, NULL) < 0)
link->dhcp4_configured = false;
@@ -1180,7 +1047,7 @@ static int dhcp_lease_ip_change(sd_dhcp_client *client, Link *link) {
r = dhcp_lease_acquired(client, link);
if (r < 0)
(void) dhcp_lease_lost(link);
(void) dhcp4_lease_lost(link);
return r;
}
@@ -1276,7 +1143,7 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
r, "Failed to send DHCP RELEASE, ignoring: %m");
}
r = dhcp_lease_lost(link);
r = dhcp4_lease_lost(link);
if (r < 0) {
link_enter_failed(link);
return r;
@@ -1291,7 +1158,7 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
}
if (link->dhcp_lease) {
r = dhcp_lease_lost(link);
r = dhcp4_lease_lost(link);
if (r < 0) {
link_enter_failed(link);
return r;
@@ -1687,10 +1554,6 @@ int dhcp4_configure(Link *link) {
if (r < 0)
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set initial DHCPv4 address: %m");
r = dhcp4_configure_dad(link);
if (r < 0)
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to configure service type: %m");
return dhcp4_set_client_identifier(link);
}
@@ -1708,15 +1571,7 @@ int dhcp4_update_mac(Link *link) {
if (r < 0)
return r;
r = dhcp4_set_client_identifier(link);
if (r < 0)
return r;
r = dhcp4_dad_update_mac(link);
if (r < 0)
return r;
return 0;
return dhcp4_set_client_identifier(link);
}
int dhcp4_start(Link *link) {

View File

@@ -21,6 +21,7 @@ void network_adjust_dhcp4(Network *network);
int dhcp4_configure(Link *link);
int dhcp4_update_mac(Link *link);
int dhcp4_start(Link *link);
int dhcp4_lease_lost(Link *link);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_client_identifier);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_acl_ip_address);

View File

@@ -602,7 +602,7 @@ static void dhcp6_pd_prefix_distribute(Link *dhcp6_link,
assert(masked_pd_prefix);
assert(pd_prefix_len <= 64);
HASHMAP_FOREACH(link, dhcp6_link->manager->links) {
HASHMAP_FOREACH(link, dhcp6_link->manager->links_by_index) {
_cleanup_free_ char *assigned_buf = NULL;
struct in6_addr assigned_prefix;
@@ -706,7 +706,7 @@ static void dhcp6_pd_prefix_lost(Link *dhcp6_link) {
assert(dhcp6_link);
assert(dhcp6_link->manager);
HASHMAP_FOREACH(link, dhcp6_link->manager->links) {
HASHMAP_FOREACH(link, dhcp6_link->manager->links_by_index) {
if (link == dhcp6_link)
continue;
@@ -954,7 +954,7 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) {
assert(dhcp6_link);
assert(dhcp6_link->dhcp6_lease);
HASHMAP_FOREACH(link, dhcp6_link->manager->links) {
HASHMAP_FOREACH(link, dhcp6_link->manager->links_by_index) {
if (link == dhcp6_link)
continue;
@@ -1024,7 +1024,7 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) {
false);
}
HASHMAP_FOREACH(link, dhcp6_link->manager->links) {
HASHMAP_FOREACH(link, dhcp6_link->manager->links_by_index) {
if (link == dhcp6_link)
continue;
@@ -1450,7 +1450,7 @@ int dhcp6_request_prefix_delegation(Link *link) {
log_link_debug(link, "Requesting DHCPv6 prefixes to be delegated for new link");
HASHMAP_FOREACH(l, link->manager->links) {
HASHMAP_FOREACH(l, link->manager->links_by_index) {
int r, enabled;
if (l == link)
@@ -1548,7 +1548,7 @@ static bool dhcp6_enable_prefix_delegation(Link *dhcp6_link) {
assert(dhcp6_link);
assert(dhcp6_link->manager);
HASHMAP_FOREACH(link, dhcp6_link->manager->links) {
HASHMAP_FOREACH(link, dhcp6_link->manager->links_by_index) {
if (link == dhcp6_link)
continue;

View File

@@ -0,0 +1,290 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-dhcp-client.h"
#include "sd-ipv4acd.h"
#include "networkd-address.h"
#include "networkd-dhcp4.h"
#include "networkd-ipv4acd.h"
#include "networkd-link.h"
#include "networkd-manager.h"
static int static_address_on_stop(Link *link, Address *address) {
int r;
assert(link);
assert(address);
if (address_get(link, address, NULL) < 0)
return 0;
log_link_debug(link, "Removing address "IPV4_ADDRESS_FMT_STR", as the ACD client is stopped.",
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
r = address_remove(address, link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to remove address "IPV4_ADDRESS_FMT_STR": %m",
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
return 0;
}
static int static_address_on_conflict(Link *link, Address *address) {
int r;
assert(link);
assert(address);
if (address_get(link, address, NULL) < 0) {
log_link_warning(link, "Cannot configure requested address "IPV4_ADDRESS_FMT_STR", as an address conflict is detected.",
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
return 0;
}
log_link_warning(link, "Dropping address "IPV4_ADDRESS_FMT_STR", as an address conflict is detected.",
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
r = address_remove(address, link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to remove address "IPV4_ADDRESS_FMT_STR": %m",
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
return 0;
}
static int dhcp4_address_on_conflict(Link *link) {
int r;
assert(link);
assert(link->dhcp_client);
r = sd_dhcp_client_send_decline(link->dhcp_client);
if (r < 0)
log_link_warning_errno(link, r, "Failed to send DHCP DECLINE, ignoring: %m");
if (!link->dhcp_lease)
/* Unlikely, but during probing the address, the lease may be lost. */
return 0;
log_link_warning(link, "Dropping DHCPv4 lease, as an address conflict is detected.");
r = dhcp4_lease_lost(link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to drop DHCPv4 lease: %m");
/* It is not necessary to call address_remove() here, as dhcp4_lease_lost() removes it. */
return 0;
}
static void on_acd(sd_ipv4acd *acd, int event, void *userdata, bool is_static) {
Address *address = userdata;
Link *link;
int r;
assert(acd);
assert(address);
assert(address->acd == acd);
assert(address->link);
assert(address->family == AF_INET);
link = address->link;
switch (event) {
case SD_IPV4ACD_EVENT_STOP:
if (is_static) {
r = static_address_on_stop(link, address);
if (r < 0)
link_enter_failed(link);
}
/* We have nothing to do for DHCPv4 lease here, as the dhcp client is already stopped
* when stopping the ipv4acd client. See link_stop_engines(). */
break;
case SD_IPV4ACD_EVENT_BIND:
log_link_debug(link, "Successfully claimed address "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
address->acd_announced = true;
break;
case SD_IPV4ACD_EVENT_CONFLICT:
if (is_static)
r = static_address_on_conflict(link, address);
else
r = dhcp4_address_on_conflict(link);
if (r < 0)
link_enter_failed(link);
break;
default:
assert_not_reached("Invalid IPv4ACD event.");
}
}
static void static_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
on_acd(acd, event, userdata, true);
}
static void dhcp4_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
on_acd(acd, event, userdata, false);
}
static int ipv4acd_check_mac(sd_ipv4acd *acd, const struct ether_addr *mac, void *userdata) {
Manager *m = userdata;
struct hw_addr_data hw_addr;
assert(m);
assert(mac);
hw_addr = (struct hw_addr_data) {
.length = ETH_ALEN,
.ether = *mac,
};
return link_get_by_hw_addr(m, &hw_addr, NULL) >= 0;
}
static int ipv4acd_configure(Link *link, const Address *a) {
_cleanup_(address_freep) Address *address = NULL;
int r;
assert(link);
assert(a);
assert(a->family == AF_INET);
log_link_debug(link, "Configuring IPv4ACD for address "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(a->in_addr.in));
r = address_dup(a, &address);
if (r < 0)
return r;
r = set_ensure_put(&link->addresses_ipv4acd, &address_hash_ops, address);
if (r < 0)
return r;
if (r == 0)
return -EEXIST;
address->link = link;
r = sd_ipv4acd_new(&address->acd);
if (r < 0)
return r;
r = sd_ipv4acd_attach_event(address->acd, link->manager->event, 0);
if (r < 0)
return r;
r = sd_ipv4acd_set_ifindex(address->acd, link->ifindex);
if (r < 0)
return r;
r = sd_ipv4acd_set_mac(address->acd, &link->hw_addr.ether);
if (r < 0)
return r;
r = sd_ipv4acd_set_address(address->acd, &address->in_addr.in);
if (r < 0)
return r;
r = sd_ipv4acd_set_callback(address->acd,
address->is_static ? static_address_on_acd : dhcp4_address_on_acd,
address);
if (r < 0)
return r;
r = sd_ipv4acd_set_check_mac_callback(address->acd, ipv4acd_check_mac, link->manager);
if (r < 0)
return r;
if (link_has_carrier(link)) {
r = sd_ipv4acd_start(address->acd, true);
if (r < 0)
return r;
}
TAKE_PTR(address);
return 0;
}
int ipv4acd_address_is_ready_to_configure(Link *link, const Address *address) {
Address *acd_address;
int r;
acd_address = set_get(link->addresses_ipv4acd, address);
if (!acd_address) {
r = ipv4acd_configure(link, address);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to configure IPv4ACD client: %m");
return false;
}
if (!acd_address->acd_announced)
return false;
r = set_ensure_put(&link->addresses, &address_hash_ops, acd_address);
if (r < 0)
return log_oom();
if (r == 0)
return log_link_warning_errno(link, SYNTHETIC_ERRNO(EEXIST), "Address already exists.");
acd_address->flags |= IFA_F_TENTATIVE;
return true;
}
int ipv4acd_update_mac(Link *link) {
Address *address;
int k, r = 0;
assert(link);
if (link->hw_addr.length != ETH_ALEN)
return 0;
if (ether_addr_is_null(&link->hw_addr.ether))
return 0;
SET_FOREACH(address, link->addresses_ipv4acd) {
assert(address->acd);
k = sd_ipv4acd_set_mac(address->acd, &link->hw_addr.ether);
if (k < 0)
r = k;
}
if (r < 0)
link_enter_failed(link);
return r;
}
int ipv4acd_start(Link *link) {
Address *address;
int r;
assert(link);
SET_FOREACH(address, link->addresses_ipv4acd) {
if (sd_ipv4acd_is_running(address->acd))
continue;
r = sd_ipv4acd_start(address->acd, true);
if (r < 0)
return r;
}
return 0;
}
int ipv4acd_stop(Link *link) {
Address *address;
int k, r = 0;
assert(link);
SET_FOREACH(address, link->addresses_ipv4acd) {
k = sd_ipv4acd_stop(address->acd);
if (k < 0)
r = k;
}
return r;
}

View File

@@ -0,0 +1,10 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
typedef struct Address Address;
typedef struct Link Link;
int ipv4acd_address_is_ready_to_configure(Link *link, const Address *address);
int ipv4acd_update_mac(Link *link);
int ipv4acd_start(Link *link);
int ipv4acd_stop(Link *link);

View File

@@ -122,8 +122,10 @@ static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
}
r = sd_ipv4ll_restart(ll);
if (r < 0)
if (r < 0) {
log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
link_enter_failed(link);
}
break;
case SD_IPV4LL_EVENT_BIND:
r = ipv4ll_address_claimed(ll, link);
@@ -139,6 +141,21 @@ static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
}
}
static int ipv4ll_check_mac(sd_ipv4ll *ll, const struct ether_addr *mac, void *userdata) {
Manager *m = userdata;
struct hw_addr_data hw_addr;
assert(m);
assert(mac);
hw_addr = (struct hw_addr_data) {
.length = ETH_ALEN,
.ether = *mac,
};
return link_get_by_hw_addr(m, &hw_addr, NULL) >= 0;
}
int ipv4ll_configure(Link *link) {
uint64_t seed;
int r;
@@ -178,35 +195,20 @@ int ipv4ll_configure(Link *link) {
if (r < 0)
return r;
return 0;
return sd_ipv4ll_set_check_mac_callback(link->ipv4ll, ipv4ll_check_mac, link->manager);
}
int ipv4ll_update_mac(Link *link) {
bool restart;
int r;
assert(link);
if (link->hw_addr.length != ETH_ALEN)
return 0;
if (ether_addr_is_null(&link->hw_addr.ether))
return 0;
if (!link->ipv4ll)
return 0;
restart = sd_ipv4ll_is_running(link->ipv4ll) > 0;
r = sd_ipv4ll_stop(link->ipv4ll);
if (r < 0)
return r;
r = sd_ipv4ll_set_mac(link->ipv4ll, &link->hw_addr.ether);
if (r < 0)
return r;
if (restart) {
r = sd_ipv4ll_start(link->ipv4ll);
if (r < 0)
return r;
}
return 0;
return sd_ipv4ll_set_mac(link->ipv4ll, &link->hw_addr.ether);
}
int config_parse_ipv4ll(

Some files were not shown because too many files have changed in this diff Show More