2 This file is part of systemd.
4 Copyright (C) 2014 Axis Communications AB. All rights reserved.
5 Copyright (C) 2015 Tom Gundersen
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <arpa/inet.h>
27 #include "sd-ipv4acd.h"
29 #include "alloc-util.h"
31 #include "ether-addr-util.h"
33 #include "in-addr-util.h"
35 #include "random-util.h"
36 #include "siphash24.h"
37 #include "string-util.h"
40 /* Constants from the RFC */
41 #define PROBE_WAIT_USEC (1U * USEC_PER_SEC)
43 #define PROBE_MIN_USEC (1U * USEC_PER_SEC)
44 #define PROBE_MAX_USEC (2U * USEC_PER_SEC)
45 #define ANNOUNCE_WAIT_USEC (2U * USEC_PER_SEC)
46 #define ANNOUNCE_NUM 2U
47 #define ANNOUNCE_INTERVAL_USEC (2U * USEC_PER_SEC)
48 #define MAX_CONFLICTS 10U
49 #define RATE_LIMIT_INTERVAL_USEC (60U * USEC_PER_SEC)
50 #define DEFEND_INTERVAL_USEC (10U * USEC_PER_SEC)
52 typedef enum IPv4ACDState
{
54 IPV4ACD_STATE_STARTED
,
55 IPV4ACD_STATE_WAITING_PROBE
,
56 IPV4ACD_STATE_PROBING
,
57 IPV4ACD_STATE_WAITING_ANNOUNCE
,
58 IPV4ACD_STATE_ANNOUNCING
,
59 IPV4ACD_STATE_RUNNING
,
61 _IPV4ACD_STATE_INVALID
= -1
74 sd_event_source
*receive_message_event_source
;
75 sd_event_source
*timer_event_source
;
81 struct ether_addr mac_addr
;
85 sd_ipv4acd_callback_t callback
;
89 #define log_ipv4acd_errno(acd, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "IPV4ACD: " fmt, ##__VA_ARGS__)
90 #define log_ipv4acd(acd, fmt, ...) log_ipv4acd_errno(acd, 0, fmt, ##__VA_ARGS__)
92 static void ipv4acd_set_state(sd_ipv4acd
*acd
, IPv4ACDState st
, bool reset_counter
) {
94 assert(st
< _IPV4ACD_STATE_MAX
);
96 if (st
== acd
->state
&& !reset_counter
)
100 acd
->n_iteration
= 0;
104 static void ipv4acd_reset(sd_ipv4acd
*acd
) {
107 acd
->timer_event_source
= sd_event_source_unref(acd
->timer_event_source
);
108 acd
->receive_message_event_source
= sd_event_source_unref(acd
->receive_message_event_source
);
110 acd
->fd
= safe_close(acd
->fd
);
112 ipv4acd_set_state(acd
, IPV4ACD_STATE_INIT
, true);
115 sd_ipv4acd
*sd_ipv4acd_ref(sd_ipv4acd
*acd
) {
119 assert_se(acd
->n_ref
>= 1);
125 sd_ipv4acd
*sd_ipv4acd_unref(sd_ipv4acd
*acd
) {
129 assert_se(acd
->n_ref
>= 1);
136 sd_ipv4acd_detach_event(acd
);
143 int sd_ipv4acd_new(sd_ipv4acd
**ret
) {
144 _cleanup_(sd_ipv4acd_unrefp
) sd_ipv4acd
*acd
= NULL
;
146 assert_return(ret
, -EINVAL
);
148 acd
= new0(sd_ipv4acd
, 1);
153 acd
->state
= IPV4ACD_STATE_INIT
;
163 static void ipv4acd_client_notify(sd_ipv4acd
*acd
, int event
) {
169 acd
->callback(acd
, event
, acd
->userdata
);
172 int sd_ipv4acd_stop(sd_ipv4acd
*acd
) {
173 assert_return(acd
, -EINVAL
);
177 log_ipv4acd(acd
, "STOPPED");
179 ipv4acd_client_notify(acd
, SD_IPV4ACD_EVENT_STOP
);
184 static int ipv4acd_on_timeout(sd_event_source
*s
, uint64_t usec
, void *userdata
);
186 static int ipv4acd_set_next_wakeup(sd_ipv4acd
*acd
, usec_t usec
, usec_t random_usec
) {
187 _cleanup_(sd_event_source_unrefp
) sd_event_source
*timer
= NULL
;
188 usec_t next_timeout
, time_now
;
196 next_timeout
+= (usec_t
) random_u64() % random_usec
;
198 assert_se(sd_event_now(acd
->event
, clock_boottime_or_monotonic(), &time_now
) >= 0);
200 r
= sd_event_add_time(acd
->event
, &timer
, clock_boottime_or_monotonic(), time_now
+ next_timeout
, 0, ipv4acd_on_timeout
, acd
);
204 r
= sd_event_source_set_priority(timer
, acd
->event_priority
);
208 (void) sd_event_source_set_description(timer
, "ipv4acd-timer");
210 sd_event_source_unref(acd
->timer_event_source
);
211 acd
->timer_event_source
= timer
;
217 static bool ipv4acd_arp_conflict(sd_ipv4acd
*acd
, struct ether_arp
*arp
) {
222 if (memcmp(arp
->arp_spa
, &acd
->address
, sizeof(acd
->address
)) == 0)
225 /* the TPA matched instead of the SPA, this is not a conflict */
229 static int ipv4acd_on_timeout(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
230 sd_ipv4acd
*acd
= userdata
;
235 switch (acd
->state
) {
237 case IPV4ACD_STATE_STARTED
:
238 ipv4acd_set_state(acd
, IPV4ACD_STATE_WAITING_PROBE
, true);
240 if (acd
->n_conflict
>= MAX_CONFLICTS
) {
241 char ts
[FORMAT_TIMESPAN_MAX
];
242 log_ipv4acd(acd
, "Max conflicts reached, delaying by %s", format_timespan(ts
, sizeof(ts
), RATE_LIMIT_INTERVAL_USEC
, 0));
244 r
= ipv4acd_set_next_wakeup(acd
, RATE_LIMIT_INTERVAL_USEC
, PROBE_WAIT_USEC
);
250 r
= ipv4acd_set_next_wakeup(acd
, 0, PROBE_WAIT_USEC
);
257 case IPV4ACD_STATE_WAITING_PROBE
:
258 case IPV4ACD_STATE_PROBING
:
260 r
= arp_send_probe(acd
->fd
, acd
->ifindex
, acd
->address
, &acd
->mac_addr
);
262 log_ipv4acd_errno(acd
, r
, "Failed to send ARP probe: %m");
265 _cleanup_free_
char *address
= NULL
;
266 union in_addr_union addr
= { .in
.s_addr
= acd
->address
};
268 (void) in_addr_to_string(AF_INET
, &addr
, &address
);
269 log_ipv4acd(acd
, "Probing %s", strna(address
));
272 if (acd
->n_iteration
< PROBE_NUM
- 2) {
273 ipv4acd_set_state(acd
, IPV4ACD_STATE_PROBING
, false);
275 r
= ipv4acd_set_next_wakeup(acd
, PROBE_MIN_USEC
, (PROBE_MAX_USEC
-PROBE_MIN_USEC
));
279 ipv4acd_set_state(acd
, IPV4ACD_STATE_WAITING_ANNOUNCE
, true);
281 r
= ipv4acd_set_next_wakeup(acd
, ANNOUNCE_WAIT_USEC
, 0);
288 case IPV4ACD_STATE_ANNOUNCING
:
289 if (acd
->n_iteration
>= ANNOUNCE_NUM
- 1) {
290 ipv4acd_set_state(acd
, IPV4ACD_STATE_RUNNING
, false);
296 case IPV4ACD_STATE_WAITING_ANNOUNCE
:
297 /* Send announcement packet */
298 r
= arp_send_announcement(acd
->fd
, acd
->ifindex
, acd
->address
, &acd
->mac_addr
);
300 log_ipv4acd_errno(acd
, r
, "Failed to send ARP announcement: %m");
303 log_ipv4acd(acd
, "ANNOUNCE");
305 ipv4acd_set_state(acd
, IPV4ACD_STATE_ANNOUNCING
, false);
307 r
= ipv4acd_set_next_wakeup(acd
, ANNOUNCE_INTERVAL_USEC
, 0);
311 if (acd
->n_iteration
== 0) {
313 ipv4acd_client_notify(acd
, SD_IPV4ACD_EVENT_BIND
);
319 assert_not_reached("Invalid state.");
325 sd_ipv4acd_stop(acd
);
329 static void ipv4acd_on_conflict(sd_ipv4acd
*acd
) {
330 _cleanup_free_
char *address
= NULL
;
331 union in_addr_union addr
= { .in
.s_addr
= acd
->address
};
337 (void) in_addr_to_string(AF_INET
, &addr
, &address
);
338 log_ipv4acd(acd
, "Conflict on %s (%u)", strna(address
), acd
->n_conflict
);
341 ipv4acd_client_notify(acd
, SD_IPV4ACD_EVENT_CONFLICT
);
344 static int ipv4acd_on_packet(
350 sd_ipv4acd
*acd
= userdata
;
351 struct ether_arp packet
;
359 n
= recv(fd
, &packet
, sizeof(struct ether_arp
), 0);
361 if (errno
== EAGAIN
|| errno
== EINTR
)
364 log_ipv4acd_errno(acd
, errno
, "Failed to read ARP packet: %m");
367 if ((size_t) n
!= sizeof(struct ether_arp
)) {
368 log_ipv4acd(acd
, "Ignoring too short ARP packet.");
372 switch (acd
->state
) {
374 case IPV4ACD_STATE_ANNOUNCING
:
375 case IPV4ACD_STATE_RUNNING
:
377 if (ipv4acd_arp_conflict(acd
, &packet
)) {
380 assert_se(sd_event_now(acd
->event
, clock_boottime_or_monotonic(), &ts
) >= 0);
383 if (ts
> acd
->defend_window
) {
384 acd
->defend_window
= ts
+ DEFEND_INTERVAL_USEC
;
385 r
= arp_send_announcement(acd
->fd
, acd
->ifindex
, acd
->address
, &acd
->mac_addr
);
387 log_ipv4acd_errno(acd
, r
, "Failed to send ARP announcement: %m");
390 log_ipv4acd(acd
, "DEFEND");
393 ipv4acd_on_conflict(acd
);
397 case IPV4ACD_STATE_WAITING_PROBE
:
398 case IPV4ACD_STATE_PROBING
:
399 case IPV4ACD_STATE_WAITING_ANNOUNCE
:
400 /* BPF ensures this packet indicates a conflict */
401 ipv4acd_on_conflict(acd
);
405 assert_not_reached("Invalid state.");
411 sd_ipv4acd_stop(acd
);
415 int sd_ipv4acd_set_ifindex(sd_ipv4acd
*acd
, int ifindex
) {
416 assert_return(acd
, -EINVAL
);
417 assert_return(ifindex
> 0, -EINVAL
);
418 assert_return(acd
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
420 acd
->ifindex
= ifindex
;
425 int sd_ipv4acd_set_mac(sd_ipv4acd
*acd
, const struct ether_addr
*addr
) {
426 assert_return(acd
, -EINVAL
);
427 assert_return(addr
, -EINVAL
);
428 assert_return(acd
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
430 acd
->mac_addr
= *addr
;
435 int sd_ipv4acd_detach_event(sd_ipv4acd
*acd
) {
436 assert_return(acd
, -EINVAL
);
438 acd
->event
= sd_event_unref(acd
->event
);
443 int sd_ipv4acd_attach_event(sd_ipv4acd
*acd
, sd_event
*event
, int64_t priority
) {
446 assert_return(acd
, -EINVAL
);
447 assert_return(!acd
->event
, -EBUSY
);
450 acd
->event
= sd_event_ref(event
);
452 r
= sd_event_default(&acd
->event
);
457 acd
->event_priority
= priority
;
462 int sd_ipv4acd_set_callback(sd_ipv4acd
*acd
, sd_ipv4acd_callback_t cb
, void *userdata
) {
463 assert_return(acd
, -EINVAL
);
466 acd
->userdata
= userdata
;
471 int sd_ipv4acd_set_address(sd_ipv4acd
*acd
, const struct in_addr
*address
) {
472 assert_return(acd
, -EINVAL
);
473 assert_return(address
, -EINVAL
);
474 assert_return(acd
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
476 acd
->address
= address
->s_addr
;
481 int sd_ipv4acd_is_running(sd_ipv4acd
*acd
) {
482 assert_return(acd
, false);
484 return acd
->state
!= IPV4ACD_STATE_INIT
;
487 int sd_ipv4acd_start(sd_ipv4acd
*acd
) {
490 assert_return(acd
, -EINVAL
);
491 assert_return(acd
->event
, -EINVAL
);
492 assert_return(acd
->ifindex
> 0, -EINVAL
);
493 assert_return(acd
->address
!= 0, -EINVAL
);
494 assert_return(!ether_addr_is_null(&acd
->mac_addr
), -EINVAL
);
495 assert_return(acd
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
497 r
= arp_network_bind_raw_socket(acd
->ifindex
, acd
->address
, &acd
->mac_addr
);
503 acd
->defend_window
= 0;
506 r
= sd_event_add_io(acd
->event
, &acd
->receive_message_event_source
, acd
->fd
, EPOLLIN
, ipv4acd_on_packet
, acd
);
510 r
= sd_event_source_set_priority(acd
->receive_message_event_source
, acd
->event_priority
);
514 (void) sd_event_source_set_description(acd
->receive_message_event_source
, "ipv4acd-receive-message");
516 r
= ipv4acd_set_next_wakeup(acd
, 0, 0);
520 ipv4acd_set_state(acd
, IPV4ACD_STATE_STARTED
, true);