mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-10 01:17:44 +03:00
Merge pull request #19980 from yuwata/sd-ipv4acd-filter-all-hwaddr
network: IPv4LL and ACD fixes
This commit is contained in:
commit
807aa0b64b
@ -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);
|
||||
|
@ -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]
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "netlink-util.h"
|
||||
#include "networkd-address-pool.h"
|
||||
#include "networkd-address.h"
|
||||
#include "networkd-ipv4acd.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "networkd-network.h"
|
||||
#include "networkd-queue.h"
|
||||
@ -129,6 +130,7 @@ static int address_new_static(Network *network, const char *filename, unsigned s
|
||||
|
||||
address->network = network;
|
||||
address->section = TAKE_PTR(n);
|
||||
address->is_static = true;
|
||||
|
||||
r = ordered_hashmap_ensure_put(&network->addresses_by_section, &network_config_hash_ops, address->section, address);
|
||||
if (r < 0)
|
||||
@ -152,6 +154,7 @@ Address *address_free(Address *address) {
|
||||
|
||||
set_remove(address->link->addresses, address);
|
||||
set_remove(address->link->addresses_foreign, address);
|
||||
set_remove(address->link->addresses_ipv4acd, address);
|
||||
set_remove(address->link->static_addresses, address);
|
||||
if (address->link->dhcp_address == address)
|
||||
address->link->dhcp_address = NULL;
|
||||
@ -301,11 +304,23 @@ bool address_equal(const Address *a1, const Address *a2) {
|
||||
return address_compare_func(a1, a2) == 0;
|
||||
}
|
||||
|
||||
static int address_copy(Address *dest, const Address *src) {
|
||||
int address_dup(const Address *src, Address **ret) {
|
||||
_cleanup_(address_freep) Address *dest = NULL;
|
||||
int r;
|
||||
|
||||
assert(dest);
|
||||
assert(src);
|
||||
assert(ret);
|
||||
|
||||
dest = newdup(Address, src, 1);
|
||||
if (!dest)
|
||||
return -ENOMEM;
|
||||
|
||||
/* clear all pointers */
|
||||
dest->network = NULL;
|
||||
dest->section = NULL;
|
||||
dest->link = NULL;
|
||||
dest->label = NULL;
|
||||
dest->acd = NULL;
|
||||
|
||||
if (src->family == AF_INET) {
|
||||
r = free_and_strdup(&dest->label, src->label);
|
||||
@ -313,17 +328,7 @@ static int address_copy(Address *dest, const Address *src) {
|
||||
return r;
|
||||
}
|
||||
|
||||
dest->family = src->family;
|
||||
dest->prefixlen = src->prefixlen;
|
||||
dest->scope = src->scope;
|
||||
dest->flags = src->flags;
|
||||
dest->cinfo = src->cinfo;
|
||||
dest->in_addr = src->in_addr;
|
||||
dest->in_addr_peer = src->in_addr_peer;
|
||||
if (address_may_have_broadcast(src))
|
||||
dest->broadcast = src->broadcast;
|
||||
dest->duplicate_address_detection = src->duplicate_address_detection;
|
||||
|
||||
*ret = TAKE_PTR(dest);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -373,11 +378,7 @@ static int address_add_internal(Link *link, Set **addresses, const Address *in,
|
||||
assert(addresses);
|
||||
assert(in);
|
||||
|
||||
r = address_new(&address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = address_copy(address, in);
|
||||
r = address_dup(in, &address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -598,7 +599,7 @@ int manager_has_address(Manager *manager, int family, const union in_addr_union
|
||||
assert(address);
|
||||
|
||||
if (family == AF_INET) {
|
||||
HASHMAP_FOREACH(link, manager->links)
|
||||
HASHMAP_FOREACH(link, manager->links_by_index)
|
||||
if (link_get_ipv4_address(link, &address->in, 0, &a) >= 0)
|
||||
return !check_ready || address_is_ready(a);
|
||||
} else {
|
||||
@ -611,7 +612,7 @@ int manager_has_address(Manager *manager, int family, const union in_addr_union
|
||||
tmp->family = family;
|
||||
tmp->in_addr = *address;
|
||||
|
||||
HASHMAP_FOREACH(link, manager->links)
|
||||
HASHMAP_FOREACH(link, manager->links_by_index)
|
||||
if (address_get(link, tmp, &a) >= 0)
|
||||
return !check_ready || address_is_ready(a);
|
||||
}
|
||||
@ -658,6 +659,7 @@ static void log_address_debug(const Address *address, const char *str, const Lin
|
||||
}
|
||||
|
||||
static int address_set_netlink_message(const Address *address, sd_netlink_message *req, Link *link) {
|
||||
uint32_t flags;
|
||||
int r;
|
||||
|
||||
assert(address);
|
||||
@ -669,14 +671,16 @@ static int address_set_netlink_message(const Address *address, sd_netlink_messag
|
||||
return log_link_error_errno(link, r, "Could not set prefixlen: %m");
|
||||
|
||||
/* On remove, only IFA_F_MANAGETEMPADDR flag for IPv6 addresses are used. But anyway, set all
|
||||
* flags here unconditionally. Without setting the flag, the template addresses generated by
|
||||
* kernel will not be removed automatically when the main address is removed. */
|
||||
r = sd_rtnl_message_addr_set_flags(req, address->flags & 0xff);
|
||||
* flags except tentative flag here unconditionally. Without setting the flag, the template
|
||||
* addresses generated by kernel will not be removed automatically when the main address is
|
||||
* removed. */
|
||||
flags = address->flags & ~IFA_F_TENTATIVE;
|
||||
r = sd_rtnl_message_addr_set_flags(req, flags & 0xff);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not set flags: %m");
|
||||
|
||||
if ((address->flags & ~0xff) != 0) {
|
||||
r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags);
|
||||
if ((flags & ~0xff) != 0) {
|
||||
r = sd_netlink_message_append_u32(req, IFA_FLAGS, flags);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not set extended flags: %m");
|
||||
}
|
||||
@ -955,11 +959,7 @@ static int address_acquire(Link *link, const Address *original, Address **ret) {
|
||||
else if (original->family == AF_INET6)
|
||||
in_addr.in6.s6_addr[15] |= 1;
|
||||
|
||||
r = address_new(&na);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = address_copy(na, original);
|
||||
r = address_dup(original, &na);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -997,17 +997,12 @@ int address_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ipv4_dad_configure(Address *address);
|
||||
|
||||
static int address_configure(
|
||||
const Address *address,
|
||||
Link *link,
|
||||
link_netlink_message_handler_t callback,
|
||||
Address **ret) {
|
||||
link_netlink_message_handler_t callback) {
|
||||
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||
Address *acquired_address, *a;
|
||||
bool update;
|
||||
int r;
|
||||
|
||||
assert(address);
|
||||
@ -1018,28 +1013,10 @@ static int address_configure(
|
||||
assert(link->manager->rtnl);
|
||||
assert(callback);
|
||||
|
||||
/* If this is a new address, then refuse adding more than the limit */
|
||||
if (address_get(link, address, NULL) <= 0 &&
|
||||
set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX)
|
||||
return log_link_error_errno(link, SYNTHETIC_ERRNO(E2BIG),
|
||||
"Too many addresses are configured, refusing: %m");
|
||||
log_address_debug(address, "Configuring", link);
|
||||
|
||||
r = address_acquire(link, address, &acquired_address);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to acquire an address from pool: %m");
|
||||
if (acquired_address)
|
||||
address = acquired_address;
|
||||
|
||||
update = address_get(link, address, NULL) >= 0;
|
||||
|
||||
log_address_debug(address, update ? "Updating" : "Configuring", link);
|
||||
|
||||
if (update)
|
||||
r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
|
||||
link->ifindex, address->family);
|
||||
else
|
||||
r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
|
||||
link->ifindex, address->family);
|
||||
r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
|
||||
link->ifindex, address->family);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not allocate RTM_NEWADDR message: %m");
|
||||
|
||||
@ -1075,31 +1052,11 @@ static int address_configure(
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append IFA_RT_PRIORITY attribute: %m");
|
||||
|
||||
r = address_add(link, address, &a);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not add address: %m");
|
||||
|
||||
r = address_set_masquerade(a, true);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Could not enable IP masquerading, ignoring: %m");
|
||||
|
||||
r = netlink_call_async(link->manager->rtnl, NULL, req, callback, link_netlink_destroy_callback, link);
|
||||
if (r < 0) {
|
||||
(void) address_set_masquerade(a, false);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
||||
}
|
||||
|
||||
link_ref(link);
|
||||
|
||||
if (FLAGS_SET(address->duplicate_address_detection, ADDRESS_FAMILY_IPV4)) {
|
||||
r = ipv4_dad_configure(a);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Failed to start IPv4ACD client, ignoring: %m");
|
||||
}
|
||||
|
||||
if (ret)
|
||||
*ret = a;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1151,12 +1108,45 @@ int link_request_address(
|
||||
link_netlink_message_handler_t netlink_handler,
|
||||
Request **ret) {
|
||||
|
||||
Address *acquired;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(address);
|
||||
|
||||
r = address_acquire(link, address, &acquired);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to acquire an address from pool: %m");
|
||||
if (r > 0) {
|
||||
if (consume_object) {
|
||||
address_free(address);
|
||||
consume_object = false; /* address from pool is already managed by Link. */
|
||||
}
|
||||
address = acquired;
|
||||
}
|
||||
|
||||
log_address_debug(address, "Requesting", link);
|
||||
return link_queue_request(link, REQUEST_TYPE_ADDRESS, address, consume_object,
|
||||
message_counter, netlink_handler, ret);
|
||||
r = link_queue_request(link, REQUEST_TYPE_ADDRESS, address, consume_object,
|
||||
message_counter, netlink_handler, ret);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to request address: %m");
|
||||
return r;
|
||||
}
|
||||
|
||||
int link_request_static_address(Link *link, Address *address, bool consume) {
|
||||
Request *req;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(address);
|
||||
|
||||
r = link_request_address(link, address, consume, &link->static_address_messages,
|
||||
static_address_handler, &req);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
req->after_configure = static_address_after_configure;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int link_request_static_addresses(Link *link) {
|
||||
@ -1170,21 +1160,13 @@ int link_request_static_addresses(Link *link) {
|
||||
link->static_addresses_configured = false;
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(a, link->network->addresses_by_section) {
|
||||
Request *req;
|
||||
|
||||
r = link_request_address(link, a, false, &link->static_address_messages,
|
||||
static_address_handler, &req);
|
||||
r = link_request_static_address(link, a, false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
continue;
|
||||
|
||||
req->after_configure = static_address_after_configure;
|
||||
}
|
||||
|
||||
HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
|
||||
_cleanup_(address_freep) Address *address = NULL;
|
||||
Request *req;
|
||||
|
||||
if (!p->assign)
|
||||
continue;
|
||||
@ -1204,14 +1186,9 @@ int link_request_static_addresses(Link *link) {
|
||||
address->family = AF_INET6;
|
||||
address->route_metric = p->route_metric;
|
||||
|
||||
r = link_request_address(link, TAKE_PTR(address), true, &link->static_address_messages,
|
||||
static_address_handler, &req);
|
||||
r = link_request_static_address(link, TAKE_PTR(address), true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
continue;
|
||||
|
||||
req->after_configure = static_address_after_configure;
|
||||
}
|
||||
|
||||
if (in4_addr_is_set(&link->network->dhcp_server_address)) {
|
||||
@ -1229,14 +1206,9 @@ int link_request_static_addresses(Link *link) {
|
||||
/* The same address may be explicitly configured in [Address] or [Network] section.
|
||||
* Configure the DHCP server address only when it is not. */
|
||||
if (!link_is_static_address_configured(link, address)) {
|
||||
Request *req;
|
||||
|
||||
r = link_request_address(link, TAKE_PTR(address), true, &link->static_address_messages,
|
||||
static_address_handler, &req);
|
||||
r = link_request_static_address(link, TAKE_PTR(address), true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
req->after_configure = static_address_after_configure;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1251,8 +1223,42 @@ int link_request_static_addresses(Link *link) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int address_is_ready_to_configure(Link *link, const Address *address) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(address);
|
||||
|
||||
if (!link_is_ready_to_configure(link, false))
|
||||
return false;
|
||||
|
||||
if (link->address_remove_messages > 0)
|
||||
return false;
|
||||
|
||||
if (address_get(link, address, NULL) >= 0)
|
||||
return true;
|
||||
|
||||
/* If this is a new address, then refuse adding more than the limit */
|
||||
if (set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX)
|
||||
return log_link_warning_errno(link, SYNTHETIC_ERRNO(E2BIG),
|
||||
"Too many addresses are configured, refusing: %m");
|
||||
|
||||
if (address->family == AF_INET &&
|
||||
address->duplicate_address_detection & ADDRESS_FAMILY_IPV4 &&
|
||||
link->hw_addr.length == ETH_ALEN &&
|
||||
!ether_addr_is_null(&link->hw_addr.ether))
|
||||
return ipv4acd_address_is_ready_to_configure(link, address);
|
||||
|
||||
r = address_add(link, address, NULL);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Could not add address: %m");;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int request_process_address(Request *req) {
|
||||
Address *ret = NULL; /* avoid false maybe-uninitialized warning */
|
||||
Address *a;
|
||||
Link *link;
|
||||
int r;
|
||||
|
||||
assert(req);
|
||||
@ -1260,13 +1266,17 @@ int request_process_address(Request *req) {
|
||||
assert(req->address);
|
||||
assert(req->type == REQUEST_TYPE_ADDRESS);
|
||||
|
||||
if (!link_is_ready_to_configure(req->link, false))
|
||||
return 0;
|
||||
link = req->link;
|
||||
|
||||
if (req->link->address_remove_messages > 0)
|
||||
return 0;
|
||||
r = address_is_ready_to_configure(link, req->address);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
r = address_configure(req->address, req->link, req->netlink_handler, &ret);
|
||||
r = address_get(link, req->address, &a);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = address_configure(a, link, req->netlink_handler);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1274,11 +1284,15 @@ int request_process_address(Request *req) {
|
||||
req->message_counter = NULL;
|
||||
|
||||
if (req->after_configure) {
|
||||
r = req->after_configure(req, ret);
|
||||
r = req->after_configure(req, a);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = address_set_masquerade(a, true);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Could not enable IP masquerading, ignoring: %m");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1319,7 +1333,7 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = link_get(m, ifindex, &link);
|
||||
r = link_get_by_index(m, ifindex, &link);
|
||||
if (r < 0 || !link) {
|
||||
/* when enumerating we might be out of sync, but we will get the address again, so just
|
||||
* ignore it */
|
||||
@ -1462,157 +1476,6 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void static_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
|
||||
Address *address;
|
||||
Link *link;
|
||||
int r;
|
||||
|
||||
assert(acd);
|
||||
assert(userdata);
|
||||
|
||||
address = (Address *) userdata;
|
||||
link = address->link;
|
||||
|
||||
assert(address->family == AF_INET);
|
||||
|
||||
switch (event) {
|
||||
case SD_IPV4ACD_EVENT_STOP:
|
||||
log_link_debug(link, "Stopping ACD client...");
|
||||
return;
|
||||
|
||||
case SD_IPV4ACD_EVENT_BIND:
|
||||
log_link_debug(link, "Successfully claimed address "IPV4_ADDRESS_FMT_STR,
|
||||
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
|
||||
link_check_ready(link);
|
||||
break;
|
||||
|
||||
case SD_IPV4ACD_EVENT_CONFLICT:
|
||||
log_link_warning(link, "DAD conflict. Dropping address "IPV4_ADDRESS_FMT_STR,
|
||||
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
|
||||
r = address_remove(address, link);
|
||||
if (r < 0)
|
||||
log_link_error_errno(link, r, "Failed to drop DAD conflicted address "IPV4_ADDRESS_FMT_STR,
|
||||
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
|
||||
|
||||
link_check_ready(link);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached("Invalid IPv4ACD event.");
|
||||
}
|
||||
|
||||
(void) sd_ipv4acd_stop(acd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int ipv4_dad_configure(Address *address) {
|
||||
int r;
|
||||
|
||||
assert(address);
|
||||
assert(address->link);
|
||||
|
||||
if (address->family != AF_INET)
|
||||
return 0;
|
||||
|
||||
log_address_debug(address, "Starting IPv4ACD client. Probing", address->link);
|
||||
|
||||
if (!address->acd) {
|
||||
r = sd_ipv4acd_new(&address->acd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ipv4acd_attach_event(address->acd, address->link->manager->event, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_ipv4acd_set_ifindex(address->acd, address->link->ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ipv4acd_set_mac(address->acd, &address->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, static_address_on_acd, address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_ipv4acd_start(address->acd, true);
|
||||
}
|
||||
|
||||
static int ipv4_dad_update_mac_one(Address *address) {
|
||||
bool running;
|
||||
int r;
|
||||
|
||||
assert(address);
|
||||
|
||||
if (!address->acd)
|
||||
return 0;
|
||||
|
||||
running = sd_ipv4acd_is_running(address->acd);
|
||||
|
||||
r = sd_ipv4acd_stop(address->acd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ipv4acd_set_mac(address->acd, &address->link->hw_addr.ether);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (running) {
|
||||
r = sd_ipv4acd_start(address->acd, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipv4_dad_update_mac(Link *link) {
|
||||
Address *address;
|
||||
int k, r = 0;
|
||||
|
||||
assert(link);
|
||||
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
k = ipv4_dad_update_mac_one(address);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int ipv4_dad_stop(Link *link) {
|
||||
Address *address;
|
||||
int k, r = 0;
|
||||
|
||||
assert(link);
|
||||
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
k = sd_ipv4acd_stop(address->acd);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void ipv4_dad_unref(Link *link) {
|
||||
Address *address;
|
||||
|
||||
assert(link);
|
||||
|
||||
SET_FOREACH(address, link->addresses)
|
||||
address->acd = sd_ipv4acd_unref(address->acd);
|
||||
}
|
||||
|
||||
int config_parse_broadcast(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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"))
|
||||
|
@ -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. */
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
290
src/network/networkd-ipv4acd.c
Normal file
290
src/network/networkd-ipv4acd.c
Normal 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;
|
||||
}
|
10
src/network/networkd-ipv4acd.h
Normal file
10
src/network/networkd-ipv4acd.h
Normal 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);
|
@ -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(
|
||||
|
@ -114,11 +114,11 @@ int manager_build_json(Manager *manager, JsonVariant **ret) {
|
||||
assert(manager);
|
||||
assert(ret);
|
||||
|
||||
elements = new(JsonVariant*, hashmap_size(manager->links));
|
||||
elements = new(JsonVariant*, hashmap_size(manager->links_by_index));
|
||||
if (!elements)
|
||||
return -ENOMEM;
|
||||
|
||||
HASHMAP_FOREACH(link, manager->links) {
|
||||
HASHMAP_FOREACH(link, manager->links_by_index) {
|
||||
r = link_build_json(link, elements + n);
|
||||
if (r < 0)
|
||||
goto finalize;
|
||||
|
@ -834,11 +834,11 @@ int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***
|
||||
assert(m);
|
||||
assert(nodes);
|
||||
|
||||
l = new0(char*, hashmap_size(m->links) + 1);
|
||||
l = new0(char*, hashmap_size(m->links_by_index) + 1);
|
||||
if (!l)
|
||||
return -ENOMEM;
|
||||
|
||||
HASHMAP_FOREACH(link, m->links) {
|
||||
HASHMAP_FOREACH(link, m->links_by_index) {
|
||||
char *p;
|
||||
|
||||
p = link_bus_path(link);
|
||||
@ -874,7 +874,7 @@ int link_object_find(sd_bus *bus, const char *path, const char *interface, void
|
||||
if (ifindex < 0)
|
||||
return 0;
|
||||
|
||||
r = link_get(m, ifindex, &link);
|
||||
r = link_get_by_index(m, ifindex, &link);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "networkd-dhcp-server.h"
|
||||
#include "networkd-dhcp4.h"
|
||||
#include "networkd-dhcp6.h"
|
||||
#include "networkd-ipv4acd.h"
|
||||
#include "networkd-ipv4ll.h"
|
||||
#include "networkd-ipv6-proxy-ndp.h"
|
||||
#include "networkd-link-bus.h"
|
||||
@ -74,6 +75,12 @@ bool link_ipv4ll_enabled(Link *link) {
|
||||
if (link->iftype == ARPHRD_CAN)
|
||||
return false;
|
||||
|
||||
if (link->hw_addr.length != ETH_ALEN)
|
||||
return false;
|
||||
|
||||
if (ether_addr_is_null(&link->hw_addr.ether))
|
||||
return false;
|
||||
|
||||
if (STRPTR_IN_SET(link->kind,
|
||||
"vrf", "wireguard", "ipip", "gre", "ip6gre","ip6tnl", "sit", "vti",
|
||||
"vti6", "nlmon", "xfrm", "bareudp"))
|
||||
@ -198,7 +205,6 @@ static void link_free_engines(Link *link) {
|
||||
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);
|
||||
link->dhcp_acd = sd_ipv4acd_unref(link->dhcp_acd);
|
||||
|
||||
link->lldp = sd_lldp_unref(link->lldp);
|
||||
link_lldp_emit_stop(link);
|
||||
@ -210,8 +216,6 @@ static void link_free_engines(Link *link) {
|
||||
link->dhcp6_lease = sd_dhcp6_lease_unref(link->dhcp6_lease);
|
||||
link->ndisc = sd_ndisc_unref(link->ndisc);
|
||||
link->radv = sd_radv_unref(link->radv);
|
||||
|
||||
ipv4_dad_unref(link);
|
||||
}
|
||||
|
||||
static Link *link_free(Link *link) {
|
||||
@ -238,6 +242,7 @@ static Link *link_free(Link *link) {
|
||||
|
||||
link->addresses = set_free(link->addresses);
|
||||
link->addresses_foreign = set_free(link->addresses_foreign);
|
||||
link->addresses_ipv4acd = set_free(link->addresses_ipv4acd);
|
||||
link->pool_addresses = set_free(link->pool_addresses);
|
||||
link->static_addresses = set_free(link->static_addresses);
|
||||
link->dhcp6_addresses = set_free(link->dhcp6_addresses);
|
||||
@ -274,13 +279,13 @@ static Link *link_free(Link *link) {
|
||||
|
||||
DEFINE_TRIVIAL_REF_UNREF_FUNC(Link, link, link_free);
|
||||
|
||||
int link_get(Manager *m, int ifindex, Link **ret) {
|
||||
int link_get_by_index(Manager *m, int ifindex, Link **ret) {
|
||||
Link *link;
|
||||
|
||||
assert(m);
|
||||
assert(ifindex > 0);
|
||||
|
||||
link = hashmap_get(m->links, INT_TO_PTR(ifindex));
|
||||
link = hashmap_get(m->links_by_index, INT_TO_PTR(ifindex));
|
||||
if (!link)
|
||||
return -ENODEV;
|
||||
|
||||
@ -304,6 +309,21 @@ int link_get_by_name(Manager *m, const char *ifname, Link **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int link_get_master(Link *link, Link **ret) {
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
@ -312,7 +332,7 @@ int link_get_master(Link *link, Link **ret) {
|
||||
if (link->master_ifindex <= 0 || link->master_ifindex == link->ifindex)
|
||||
return -ENODEV;
|
||||
|
||||
return link_get(link->manager, link->master_ifindex, ret);
|
||||
return link_get_by_index(link->manager, link->master_ifindex, ret);
|
||||
}
|
||||
|
||||
void link_set_state(Link *link, LinkState state) {
|
||||
@ -340,6 +360,7 @@ int link_stop_engines(Link *link, bool may_keep_dhcp) {
|
||||
|
||||
bool keep_dhcp = may_keep_dhcp &&
|
||||
link->network &&
|
||||
!link->network->dhcp_send_decline && /* IPv4 ACD for the DHCPv4 address is running. */
|
||||
(link->manager->restarting ||
|
||||
FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP_ON_STOP));
|
||||
|
||||
@ -349,10 +370,6 @@ int link_stop_engines(Link *link, bool may_keep_dhcp) {
|
||||
r = log_link_warning_errno(link, k, "Could not stop DHCPv4 client: %m");
|
||||
}
|
||||
|
||||
k = sd_ipv4acd_stop(link->dhcp_acd);
|
||||
if (k < 0)
|
||||
r = log_link_warning_errno(link, k, "Could not stop IPv4 ACD client for DHCPv4: %m");
|
||||
|
||||
k = sd_dhcp_server_stop(link->dhcp_server);
|
||||
if (k < 0)
|
||||
r = log_link_warning_errno(link, k, "Could not stop DHCPv4 server: %m");
|
||||
@ -365,7 +382,7 @@ int link_stop_engines(Link *link, bool may_keep_dhcp) {
|
||||
if (k < 0)
|
||||
r = log_link_warning_errno(link, k, "Could not stop IPv4 link-local: %m");
|
||||
|
||||
k = ipv4_dad_stop(link);
|
||||
k = ipv4acd_stop(link);
|
||||
if (k < 0)
|
||||
r = log_link_warning_errno(link, k, "Could not stop IPv4 ACD client: %m");
|
||||
|
||||
@ -647,6 +664,10 @@ static int link_acquire_dynamic_ipv4_conf(Link *link) {
|
||||
return log_link_warning_errno(link, r, "Could not start DHCP server: %m");
|
||||
}
|
||||
|
||||
r = ipv4acd_start(link);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Could not start IPv4 ACD client: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -774,7 +795,7 @@ static int link_new_bound_by_list(Link *link) {
|
||||
|
||||
m = link->manager;
|
||||
|
||||
HASHMAP_FOREACH(carrier, m->links) {
|
||||
HASHMAP_FOREACH(carrier, m->links_by_index) {
|
||||
if (!carrier->network)
|
||||
continue;
|
||||
|
||||
@ -813,7 +834,7 @@ static int link_new_bound_to_list(Link *link) {
|
||||
|
||||
m = link->manager;
|
||||
|
||||
HASHMAP_FOREACH(carrier, m->links) {
|
||||
HASHMAP_FOREACH(carrier, m->links_by_index) {
|
||||
if (strv_fnmatch(link->network->bind_carrier, carrier->ifname)) {
|
||||
r = link_put_carrier(link, carrier, &link->bound_to_links);
|
||||
if (r < 0)
|
||||
@ -961,11 +982,14 @@ static Link *link_drop(Link *link) {
|
||||
|
||||
STRV_FOREACH(n, link->alternative_names)
|
||||
hashmap_remove(link->manager->links_by_name, *n);
|
||||
|
||||
hashmap_remove(link->manager->links_by_name, link->ifname);
|
||||
|
||||
/* bonding master and its slaves have the same hardware address. */
|
||||
if (hashmap_get(link->manager->links_by_hw_addr, &link->hw_addr) == link)
|
||||
hashmap_remove(link->manager->links_by_hw_addr, &link->hw_addr);
|
||||
|
||||
/* The following must be called at last. */
|
||||
assert_se(hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex)) == link);
|
||||
assert_se(hashmap_remove(link->manager->links_by_index, INT_TO_PTR(link->ifindex)) == link);
|
||||
return link_unref(link);
|
||||
}
|
||||
|
||||
@ -1471,7 +1495,7 @@ int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, voi
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = link_get(m, ifindex, &link);
|
||||
r = link_get_by_index(m, ifindex, &link);
|
||||
if (r < 0) {
|
||||
log_device_debug_errno(device, r, "Failed to get link from ifindex %i, ignoring: %m", ifindex);
|
||||
return 0;
|
||||
@ -1974,7 +1998,7 @@ static int link_update_master(Link *link, sd_netlink_message *message) {
|
||||
}
|
||||
|
||||
static int link_update_hardware_address(Link *link, sd_netlink_message *message) {
|
||||
struct hw_addr_data hw_addr;
|
||||
struct hw_addr_data old;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
@ -1984,18 +2008,38 @@ static int link_update_hardware_address(Link *link, sd_netlink_message *message)
|
||||
if (r < 0 && r != -ENODATA)
|
||||
return log_link_debug_errno(link, r, "rtnl: failed to read broadcast address: %m");
|
||||
|
||||
r = netlink_message_read_hw_addr(message, IFLA_ADDRESS, &hw_addr);
|
||||
old = link->hw_addr;
|
||||
r = netlink_message_read_hw_addr(message, IFLA_ADDRESS, &link->hw_addr);
|
||||
if (r == -ENODATA)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "rtnl: failed to read hardware address: %m");
|
||||
return log_link_debug_errno(link, r, "rtnl: failed to read hardware address: %m");
|
||||
|
||||
if (hw_addr_equal(&link->hw_addr, &hw_addr))
|
||||
if (hw_addr_equal(&link->hw_addr, &old))
|
||||
return 0;
|
||||
|
||||
link->hw_addr = hw_addr;
|
||||
if (hw_addr_is_null(&old))
|
||||
log_link_debug(link, "Saved hardware address: %s", HW_ADDR_TO_STR(&link->hw_addr));
|
||||
else {
|
||||
log_link_debug(link, "Hardware address is changed: %s → %s",
|
||||
HW_ADDR_TO_STR(&old), HW_ADDR_TO_STR(&link->hw_addr));
|
||||
|
||||
log_link_debug(link, "Gained new hardware address: %s", HW_ADDR_TO_STR(&hw_addr));
|
||||
if (hashmap_get(link->manager->links_by_hw_addr, &old) == link)
|
||||
hashmap_remove(link->manager->links_by_hw_addr, &old);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
r = ipv4ll_update_mac(link);
|
||||
if (r < 0)
|
||||
@ -2025,10 +2069,6 @@ static int link_update_hardware_address(Link *link, sd_netlink_message *message)
|
||||
return log_link_debug_errno(link, r, "Could not update MAC address for LLDP: %m");
|
||||
}
|
||||
|
||||
r = ipv4_dad_update_mac(link);
|
||||
if (r < 0)
|
||||
return log_link_debug_errno(link, r, "Could not update MAC address in IPv4 ACD client: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2257,7 +2297,7 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
|
||||
.dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
|
||||
};
|
||||
|
||||
r = hashmap_ensure_put(&manager->links, NULL, INT_TO_PTR(link->ifindex), link);
|
||||
r = hashmap_ensure_put(&manager->links_by_index, NULL, INT_TO_PTR(link->ifindex), link);
|
||||
if (r < 0)
|
||||
return log_link_debug_errno(link, r, "Failed to store link into manager: %m");
|
||||
|
||||
@ -2323,7 +2363,7 @@ int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Man
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void) link_get(manager, ifindex, &link);
|
||||
(void) link_get_by_index(manager, ifindex, &link);
|
||||
(void) netdev_get(manager, name, &netdev);
|
||||
|
||||
switch (type) {
|
||||
|
@ -104,6 +104,7 @@ typedef struct Link {
|
||||
|
||||
Set *addresses;
|
||||
Set *addresses_foreign;
|
||||
Set *addresses_ipv4acd;
|
||||
Set *pool_addresses;
|
||||
Set *static_addresses;
|
||||
Set *neighbors;
|
||||
@ -119,11 +120,9 @@ typedef struct Link {
|
||||
Set *dhcp_routes, *dhcp_routes_old;
|
||||
char *lease_file;
|
||||
unsigned dhcp4_messages;
|
||||
sd_ipv4acd *dhcp_acd;
|
||||
bool dhcp4_route_failed:1;
|
||||
bool dhcp4_route_retrying:1;
|
||||
bool dhcp4_configured:1;
|
||||
bool dhcp4_address_bind:1;
|
||||
|
||||
sd_ipv4ll *ipv4ll;
|
||||
bool ipv4ll_address_configured:1;
|
||||
@ -218,8 +217,9 @@ Link *link_ref(Link *link);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_unref);
|
||||
DEFINE_TRIVIAL_DESTRUCTOR(link_netlink_destroy_callback, Link, link_unref);
|
||||
|
||||
int link_get(Manager *m, int ifindex, Link **ret);
|
||||
int link_get_by_index(Manager *m, int ifindex, Link **ret);
|
||||
int link_get_by_name(Manager *m, const char *ifname, Link **ret);
|
||||
int link_get_by_hw_addr(Manager *m, const struct hw_addr_data *hw_addr, Link **ret);
|
||||
int link_get_master(Link *link, Link **ret);
|
||||
|
||||
int link_getlink_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg);
|
||||
|
@ -31,7 +31,7 @@ static int method_list_links(sd_bus_message *message, void *userdata, sd_bus_err
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
HASHMAP_FOREACH(link, manager->links) {
|
||||
HASHMAP_FOREACH(link, manager->links_by_index) {
|
||||
_cleanup_free_ char *path = NULL;
|
||||
|
||||
path = link_bus_path(link);
|
||||
@ -95,8 +95,8 @@ static int method_get_link_by_index(sd_bus_message *message, void *userdata, sd_
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
link = hashmap_get(manager->links, INT_TO_PTR(ifindex));
|
||||
if (!link)
|
||||
r = link_get_by_index(manager, ifindex, &link);
|
||||
if (r < 0)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %i not known", ifindex);
|
||||
|
||||
r = sd_bus_message_new_method_return(message, &reply);
|
||||
@ -126,8 +126,8 @@ static int call_link_method(Manager *m, sd_bus_message *message, sd_bus_message_
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
l = hashmap_get(m->links, INT_TO_PTR(ifindex));
|
||||
if (!l)
|
||||
r = link_get_by_index(m, ifindex, &l);
|
||||
if (r < 0)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %i not known", ifindex);
|
||||
|
||||
return handler(message, l, error);
|
||||
@ -215,7 +215,7 @@ static int bus_method_reload(sd_bus_message *message, void *userdata, sd_bus_err
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
HASHMAP_FOREACH(link, manager->links) {
|
||||
HASHMAP_FOREACH(link, manager->links_by_index) {
|
||||
r = link_reconfigure(link, /* force = */ false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -58,7 +58,7 @@ static int manager_reset_all(Manager *m) {
|
||||
|
||||
assert(m);
|
||||
|
||||
HASHMAP_FOREACH(link, m->links) {
|
||||
HASHMAP_FOREACH(link, m->links_by_index) {
|
||||
r = link_carrier_reset(link);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "Could not reset carrier: %m");
|
||||
@ -451,7 +451,7 @@ Manager* manager_free(Manager *m) {
|
||||
|
||||
free(m->state_file);
|
||||
|
||||
HASHMAP_FOREACH(link, m->links)
|
||||
HASHMAP_FOREACH(link, m->links_by_index)
|
||||
(void) link_stop_engines(link, true);
|
||||
|
||||
m->request_queue = ordered_set_free(m->request_queue);
|
||||
@ -462,7 +462,8 @@ Manager* manager_free(Manager *m) {
|
||||
m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref);
|
||||
m->links_requesting_uuid = set_free_with_destructor(m->links_requesting_uuid, link_unref);
|
||||
m->links_by_name = hashmap_free(m->links_by_name);
|
||||
m->links = hashmap_free_with_destructor(m->links, link_unref);
|
||||
m->links_by_hw_addr = hashmap_free(m->links_by_hw_addr);
|
||||
m->links_by_index = hashmap_free_with_destructor(m->links_by_index, link_unref);
|
||||
|
||||
m->networks = ordered_hashmap_free_with_destructor(m->networks, network_unref);
|
||||
|
||||
@ -528,7 +529,7 @@ int manager_start(Manager *m) {
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to update state file %s, ignoring: %m", m->state_file);
|
||||
|
||||
HASHMAP_FOREACH(link, m->links) {
|
||||
HASHMAP_FOREACH(link, m->links_by_index) {
|
||||
r = link_save(link);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Failed to update link state file %s, ignoring: %m", link->state_file);
|
||||
|
@ -44,8 +44,9 @@ struct Manager {
|
||||
LinkAddressState ipv6_address_state;
|
||||
LinkOnlineState online_state;
|
||||
|
||||
Hashmap *links;
|
||||
Hashmap *links_by_index;
|
||||
Hashmap *links_by_name;
|
||||
Hashmap *links_by_hw_addr;
|
||||
Hashmap *netdevs;
|
||||
OrderedHashmap *networks;
|
||||
Hashmap *dhcp6_prefixes;
|
||||
|
@ -536,7 +536,7 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = link_get(m, ifindex, &link);
|
||||
r = link_get_by_index(m, ifindex, &link);
|
||||
if (r < 0 || !link) {
|
||||
/* when enumerating we might be out of sync, but we will get the neighbor again. Also,
|
||||
* kernel sends messages about neighbors after a link is removed. So, just ignore it. */
|
||||
|
@ -645,7 +645,7 @@ static bool links_have_nexthop(const Manager *manager, const NextHop *nexthop, c
|
||||
|
||||
assert(manager);
|
||||
|
||||
HASHMAP_FOREACH(link, manager->links) {
|
||||
HASHMAP_FOREACH(link, manager->links_by_index) {
|
||||
if (link == except)
|
||||
continue;
|
||||
|
||||
@ -765,7 +765,7 @@ static bool nexthop_is_ready_to_configure(Link *link, const NextHop *nexthop) {
|
||||
if (!FLAGS_SET(link->flags, IFF_UP))
|
||||
return false;
|
||||
|
||||
HASHMAP_FOREACH(l, link->manager->links) {
|
||||
HASHMAP_FOREACH(l, link->manager->links_by_index) {
|
||||
if (l->address_remove_messages > 0)
|
||||
return false;
|
||||
if (l->nexthop_remove_messages > 0)
|
||||
@ -868,7 +868,7 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message,
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = link_get(m, ifindex, &link);
|
||||
r = link_get_by_index(m, ifindex, &link);
|
||||
if (r < 0 || !link) {
|
||||
if (!m->enumerating)
|
||||
log_warning("rtnl: received nexthop message for link (%"PRIu32") we do not know about, ignoring", ifindex);
|
||||
|
@ -78,6 +78,9 @@ static Request *request_free(Request *req) {
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Request*, request_free);
|
||||
|
||||
void request_drop(Request *req) {
|
||||
if (!req)
|
||||
return;
|
||||
|
||||
if (req->message_counter)
|
||||
(*req->message_counter)--;
|
||||
|
||||
|
@ -753,7 +753,7 @@ bool manager_address_is_reachable(Manager *manager, int family, const union in_a
|
||||
assert(IN_SET(family, AF_INET, AF_INET6));
|
||||
assert(address);
|
||||
|
||||
HASHMAP_FOREACH(link, manager->links) {
|
||||
HASHMAP_FOREACH(link, manager->links_by_index) {
|
||||
Route *route;
|
||||
|
||||
SET_FOREACH(route, link->routes)
|
||||
@ -807,7 +807,7 @@ int manager_find_uplink(Manager *m, int family, Link *exclude, Link **ret) {
|
||||
/* Looks for a suitable "uplink", via black magic: an interface that is up and where the
|
||||
* default route with the highest priority points to. */
|
||||
|
||||
HASHMAP_FOREACH(link, m->links) {
|
||||
HASHMAP_FOREACH(link, m->links_by_index) {
|
||||
if (link == exclude)
|
||||
continue;
|
||||
|
||||
@ -1106,7 +1106,7 @@ static bool links_have_static_route(const Manager *manager, const Route *route,
|
||||
|
||||
assert(manager);
|
||||
|
||||
HASHMAP_FOREACH(link, manager->links) {
|
||||
HASHMAP_FOREACH(link, manager->links_by_index) {
|
||||
if (link == except)
|
||||
continue;
|
||||
|
||||
@ -1260,7 +1260,7 @@ static int route_add_and_setup_timer_one(Link *link, const Route *route, const M
|
||||
} else if (m && m->ifindex != 0 && m->ifindex != link->ifindex) {
|
||||
Link *link_gw;
|
||||
|
||||
r = link_get(link->manager, m->ifindex, &link_gw);
|
||||
r = link_get_by_index(link->manager, m->ifindex, &link_gw);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get link with ifindex %d: %m", m->ifindex);
|
||||
|
||||
@ -1685,7 +1685,7 @@ static int route_is_ready_to_configure(const Route *route, Link *link) {
|
||||
} else {
|
||||
Link *l;
|
||||
|
||||
HASHMAP_FOREACH(l, link->manager->links) {
|
||||
HASHMAP_FOREACH(l, link->manager->links_by_index) {
|
||||
if (l->address_remove_messages > 0)
|
||||
return false;
|
||||
if (l->nexthop_remove_messages > 0)
|
||||
@ -1720,7 +1720,7 @@ static int route_is_ready_to_configure(const Route *route, Link *link) {
|
||||
|
||||
m->ifindex = l->ifindex;
|
||||
} else if (m->ifindex > 0) {
|
||||
if (link_get(link->manager, m->ifindex, &l) < 0)
|
||||
if (link_get_by_index(link->manager, m->ifindex, &l) < 0)
|
||||
return false;
|
||||
}
|
||||
if (l && !link_is_ready_to_configure(l, true))
|
||||
@ -1805,7 +1805,7 @@ static int process_route_one(Manager *manager, Link *link, uint16_t type, const
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"rtnl: received multipath route with invalid ifindex, ignoring.");
|
||||
|
||||
r = link_get(manager, m->ifindex, &link);
|
||||
r = link_get_by_index(manager, m->ifindex, &link);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "rtnl: received multipath route for link (%d) we do not know, ignoring: %m", m->ifindex);
|
||||
return 0;
|
||||
@ -1898,7 +1898,7 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = link_get(m, ifindex, &link);
|
||||
r = link_get_by_index(m, ifindex, &link);
|
||||
if (r < 0 || !link) {
|
||||
/* when enumerating we might be out of sync, but we will
|
||||
* get the route again, so just ignore it */
|
||||
|
@ -607,7 +607,7 @@ static int links_have_routing_policy_rule(const Manager *m, const RoutingPolicyR
|
||||
assert(m);
|
||||
assert(rule);
|
||||
|
||||
HASHMAP_FOREACH(link, m->links) {
|
||||
HASHMAP_FOREACH(link, m->links_by_index) {
|
||||
RoutingPolicyRule *link_rule;
|
||||
|
||||
if (link == except)
|
||||
|
@ -26,9 +26,9 @@ static int process_message(Manager *manager, sd_netlink_message *message) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
link = hashmap_get(manager->links, INT_TO_PTR(ifindex));
|
||||
if (!link)
|
||||
return -ENODEV;
|
||||
r = link_get_by_index(manager, ifindex, &link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
link->stats_old = link->stats_new;
|
||||
|
||||
@ -62,7 +62,7 @@ static int speed_meter_handler(sd_event_source *s, uint64_t usec, void *userdata
|
||||
manager->speed_meter_usec_old = manager->speed_meter_usec_new;
|
||||
manager->speed_meter_usec_new = usec_now;
|
||||
|
||||
HASHMAP_FOREACH(link, manager->links)
|
||||
HASHMAP_FOREACH(link, manager->links_by_index)
|
||||
link->stats_updated = false;
|
||||
|
||||
r = sd_rtnl_message_new_link(manager->rtnl, &req, RTM_GETLINK, 0);
|
||||
|
@ -121,7 +121,7 @@ int manager_save(Manager *m) {
|
||||
assert(m);
|
||||
assert(m->state_file);
|
||||
|
||||
HASHMAP_FOREACH(link, m->links) {
|
||||
HASHMAP_FOREACH(link, m->links_by_index) {
|
||||
const struct in_addr *addresses;
|
||||
|
||||
if (link->flags & IFF_LOOPBACK)
|
||||
|
@ -36,11 +36,13 @@ enum {
|
||||
|
||||
typedef struct sd_ipv4acd sd_ipv4acd;
|
||||
typedef void (*sd_ipv4acd_callback_t)(sd_ipv4acd *acd, int event, void *userdata);
|
||||
typedef int (*sd_ipv4acd_check_mac_callback_t)(sd_ipv4acd *acd, const struct ether_addr *mac, void *userdata);
|
||||
|
||||
int sd_ipv4acd_detach_event(sd_ipv4acd *acd);
|
||||
int sd_ipv4acd_attach_event(sd_ipv4acd *acd, sd_event *event, int64_t priority);
|
||||
int sd_ipv4acd_get_address(sd_ipv4acd *acd, struct in_addr *address);
|
||||
int sd_ipv4acd_set_callback(sd_ipv4acd *acd, sd_ipv4acd_callback_t cb, void *userdata);
|
||||
int sd_ipv4acd_set_check_mac_callback(sd_ipv4acd *acd, sd_ipv4acd_check_mac_callback_t cb, void *userdata);
|
||||
int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr);
|
||||
int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int interface_index);
|
||||
int sd_ipv4acd_get_ifindex(sd_ipv4acd *acd);
|
||||
|
@ -36,11 +36,13 @@ enum {
|
||||
|
||||
typedef struct sd_ipv4ll sd_ipv4ll;
|
||||
typedef void (*sd_ipv4ll_callback_t)(sd_ipv4ll *ll, int event, void *userdata);
|
||||
typedef int (*sd_ipv4ll_check_mac_callback_t)(sd_ipv4ll *ll, const struct ether_addr *mac, void *userdata);
|
||||
|
||||
int sd_ipv4ll_detach_event(sd_ipv4ll *ll);
|
||||
int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority);
|
||||
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_ifindex(sd_ipv4ll *ll, int interface_index);
|
||||
int sd_ipv4ll_get_ifindex(sd_ipv4ll *ll);
|
||||
|
@ -1,8 +0,0 @@
|
||||
[Match]
|
||||
Name=veth99
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
|
||||
[Address]
|
||||
Address=192.168.100.10/24
|
@ -1,9 +1,9 @@
|
||||
[Match]
|
||||
Name=veth-peer
|
||||
Name=veth99
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
|
||||
[Address]
|
||||
Address=192.168.100.10/24
|
||||
Address=192.168.100.11/24
|
||||
DuplicateAddressDetection=ipv4
|
@ -0,0 +1,3 @@
|
||||
[Address]
|
||||
Address=192.168.100.10/24
|
||||
DuplicateAddressDetection=ipv4
|
@ -3,12 +3,11 @@ Name=veth-peer
|
||||
|
||||
[Network]
|
||||
Address=192.168.5.1/24
|
||||
Address=192.168.5.10/24
|
||||
IPv6AcceptRA=false
|
||||
DHCPServer=yes
|
||||
|
||||
[DHCPServer]
|
||||
PoolOffset=10
|
||||
PoolSize=1
|
||||
PoolSize=100
|
||||
DNS=192.168.5.1
|
||||
NTP=192.168.5.1
|
||||
|
@ -1797,8 +1797,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
|
||||
'23-active-slave.network',
|
||||
'24-keep-configuration-static.network',
|
||||
'24-search-domain.network',
|
||||
'25-address-dad-veth-peer.network',
|
||||
'25-address-dad-veth99.network',
|
||||
'25-address-ipv4acd-veth99.network',
|
||||
'25-address-link-section.network',
|
||||
'25-address-peer-ipv4.network',
|
||||
'25-address-static.network',
|
||||
@ -1868,6 +1867,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
|
||||
remove_routes(self.routes)
|
||||
remove_links(self.links)
|
||||
stop_networkd(show_logs=False)
|
||||
call('ip netns del ns99', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
|
||||
def tearDown(self):
|
||||
remove_blackhole_nexthops()
|
||||
@ -1876,6 +1876,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
|
||||
remove_links(self.links)
|
||||
remove_unit_from_networkd_path(self.units)
|
||||
stop_networkd(show_logs=True)
|
||||
call('ip netns del ns99', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
|
||||
def test_address_static(self):
|
||||
copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
|
||||
@ -1929,19 +1930,33 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
|
||||
for i in range(1,254):
|
||||
self.assertIn(f'inet 10.3.3.{i}/16 brd 10.3.255.255', output)
|
||||
|
||||
def test_address_dad(self):
|
||||
copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network',
|
||||
'25-veth.netdev')
|
||||
def test_address_ipv4acd(self):
|
||||
check_output('ip netns add ns99')
|
||||
check_output('ip link add veth99 type veth peer veth-peer')
|
||||
check_output('ip link set veth-peer netns ns99')
|
||||
check_output('ip link set veth99 up')
|
||||
check_output('ip netns exec ns99 ip link set veth-peer up')
|
||||
check_output('ip netns exec ns99 ip address add 192.168.100.10/24 dev veth-peer')
|
||||
|
||||
copy_unit_to_networkd_unit_path('25-address-ipv4acd-veth99.network', dropins=False)
|
||||
start_networkd()
|
||||
self.wait_online(['veth99:routable', 'veth-peer:degraded'])
|
||||
self.wait_online(['veth99:routable'])
|
||||
|
||||
output = check_output('ip -4 address show dev veth99')
|
||||
print(output)
|
||||
self.assertRegex(output, '192.168.100.10/24')
|
||||
self.assertNotIn('192.168.100.10/24', output)
|
||||
self.assertIn('192.168.100.11/24', output)
|
||||
|
||||
output = check_output('ip -4 address show dev veth-peer')
|
||||
copy_unit_to_networkd_unit_path('25-address-ipv4acd-veth99.network.d/conflict-address.conf')
|
||||
run(*networkctl_cmd, 'reload', env=env)
|
||||
time.sleep(1)
|
||||
rc = call(*wait_online_cmd, '--timeout=10s', '--interface=veth99:routable', env=env)
|
||||
self.assertTrue(rc == 1)
|
||||
|
||||
output = check_output('ip -4 address show dev veth99')
|
||||
print(output)
|
||||
self.assertNotRegex(output, '192.168.100.10/24')
|
||||
self.assertNotIn('192.168.100.10/24', output)
|
||||
self.assertIn('192.168.100.11/24', output)
|
||||
|
||||
def test_address_peer_ipv4(self):
|
||||
# test for issue #17304
|
||||
@ -4619,9 +4634,11 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
|
||||
copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
|
||||
|
||||
start_networkd()
|
||||
self.wait_online(['veth-peer:carrier'])
|
||||
rc = call(*wait_online_cmd, '--timeout=10s', '--interface=veth99:routable', env=env)
|
||||
self.assertTrue(rc == 1)
|
||||
self.wait_online(['veth99:routable', 'veth-peer:routable'])
|
||||
|
||||
output = check_output('ip -4 address show dev veth99 scope global dynamic')
|
||||
print(output)
|
||||
self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
|
||||
|
||||
class NetworkdIPv6PrefixTests(unittest.TestCase, Utilities):
|
||||
links = ['veth99']
|
||||
|
Loading…
Reference in New Issue
Block a user