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 #define IPV4ACD_NETWORK 0xA9FE0000UL
53 #define IPV4ACD_NETMASK 0xFFFF0000UL
55 #define log_ipv4acd_errno(ll, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "ACD: " fmt, ##__VA_ARGS__)
56 #define log_ipv4acd(ll, fmt, ...) log_ipv4acd_errno(ll, 0, fmt, ##__VA_ARGS__)
58 typedef enum IPv4ACDState
{
60 IPV4ACD_STATE_STARTED
,
61 IPV4ACD_STATE_WAITING_PROBE
,
62 IPV4ACD_STATE_PROBING
,
63 IPV4ACD_STATE_WAITING_ANNOUNCE
,
64 IPV4ACD_STATE_ANNOUNCING
,
65 IPV4ACD_STATE_RUNNING
,
67 _IPV4ACD_STATE_INVALID
= -1
80 sd_event_source
*receive_message_event_source
;
81 sd_event_source
*timer_event_source
;
87 struct ether_addr mac_addr
;
91 sd_ipv4acd_callback_t callback
;
95 static void ipv4acd_set_state(sd_ipv4acd
*ll
, IPv4ACDState st
, bool reset_counter
) {
97 assert(st
< _IPV4ACD_STATE_MAX
);
99 if (st
== ll
->state
&& !reset_counter
)
107 static void ipv4acd_reset(sd_ipv4acd
*ll
) {
110 ll
->timer_event_source
= sd_event_source_unref(ll
->timer_event_source
);
111 ll
->receive_message_event_source
= sd_event_source_unref(ll
->receive_message_event_source
);
113 ll
->fd
= safe_close(ll
->fd
);
115 ipv4acd_set_state(ll
, IPV4ACD_STATE_INIT
, true);
118 sd_ipv4acd
*sd_ipv4acd_ref(sd_ipv4acd
*ll
) {
122 assert_se(ll
->n_ref
>= 1);
128 sd_ipv4acd
*sd_ipv4acd_unref(sd_ipv4acd
*ll
) {
132 assert_se(ll
->n_ref
>= 1);
139 sd_ipv4acd_detach_event(ll
);
146 int sd_ipv4acd_new(sd_ipv4acd
**ret
) {
147 _cleanup_(sd_ipv4acd_unrefp
) sd_ipv4acd
*ll
= NULL
;
149 assert_return(ret
, -EINVAL
);
151 ll
= new0(sd_ipv4acd
, 1);
156 ll
->state
= IPV4ACD_STATE_INIT
;
166 static void ipv4acd_client_notify(sd_ipv4acd
*ll
, int event
) {
172 ll
->callback(ll
, event
, ll
->userdata
);
175 int sd_ipv4acd_stop(sd_ipv4acd
*ll
) {
176 assert_return(ll
, -EINVAL
);
180 log_ipv4acd(ll
, "STOPPED");
182 ipv4acd_client_notify(ll
, SD_IPV4ACD_EVENT_STOP
);
187 static int ipv4acd_on_timeout(sd_event_source
*s
, uint64_t usec
, void *userdata
);
189 static int ipv4acd_set_next_wakeup(sd_ipv4acd
*ll
, usec_t usec
, usec_t random_usec
) {
190 _cleanup_(sd_event_source_unrefp
) sd_event_source
*timer
= NULL
;
191 usec_t next_timeout
, time_now
;
199 next_timeout
+= (usec_t
) random_u64() % random_usec
;
201 assert_se(sd_event_now(ll
->event
, clock_boottime_or_monotonic(), &time_now
) >= 0);
203 r
= sd_event_add_time(ll
->event
, &timer
, clock_boottime_or_monotonic(), time_now
+ next_timeout
, 0, ipv4acd_on_timeout
, ll
);
207 r
= sd_event_source_set_priority(timer
, ll
->event_priority
);
211 (void) sd_event_source_set_description(timer
, "ipv4acd-timer");
213 sd_event_source_unref(ll
->timer_event_source
);
214 ll
->timer_event_source
= timer
;
220 static bool ipv4acd_arp_conflict(sd_ipv4acd
*ll
, struct ether_arp
*arp
) {
225 if (memcmp(arp
->arp_spa
, &ll
->address
, sizeof(ll
->address
)) == 0)
228 /* the TPA matched instead of the SPA, this is not a conflict */
232 static int ipv4acd_on_timeout(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
233 sd_ipv4acd
*ll
= userdata
;
240 case IPV4ACD_STATE_STARTED
:
241 ipv4acd_set_state(ll
, IPV4ACD_STATE_WAITING_PROBE
, true);
243 if (ll
->n_conflict
>= MAX_CONFLICTS
) {
244 char ts
[FORMAT_TIMESPAN_MAX
];
245 log_ipv4acd(ll
, "Max conflicts reached, delaying by %s", format_timespan(ts
, sizeof(ts
), RATE_LIMIT_INTERVAL_USEC
, 0));
247 r
= ipv4acd_set_next_wakeup(ll
, RATE_LIMIT_INTERVAL_USEC
, PROBE_WAIT_USEC
);
253 r
= ipv4acd_set_next_wakeup(ll
, 0, PROBE_WAIT_USEC
);
260 case IPV4ACD_STATE_WAITING_PROBE
:
261 case IPV4ACD_STATE_PROBING
:
263 r
= arp_send_probe(ll
->fd
, ll
->ifindex
, ll
->address
, &ll
->mac_addr
);
265 log_ipv4acd_errno(ll
, r
, "Failed to send ARP probe: %m");
268 _cleanup_free_
char *address
= NULL
;
269 union in_addr_union addr
= { .in
.s_addr
= ll
->address
};
271 (void) in_addr_to_string(AF_INET
, &addr
, &address
);
272 log_ipv4acd(ll
, "Probing %s", strna(address
));
275 if (ll
->n_iteration
< PROBE_NUM
- 2) {
276 ipv4acd_set_state(ll
, IPV4ACD_STATE_PROBING
, false);
278 r
= ipv4acd_set_next_wakeup(ll
, PROBE_MIN_USEC
, (PROBE_MAX_USEC
-PROBE_MIN_USEC
));
282 ipv4acd_set_state(ll
, IPV4ACD_STATE_WAITING_ANNOUNCE
, true);
284 r
= ipv4acd_set_next_wakeup(ll
, ANNOUNCE_WAIT_USEC
, 0);
291 case IPV4ACD_STATE_ANNOUNCING
:
292 if (ll
->n_iteration
>= ANNOUNCE_NUM
- 1) {
293 ipv4acd_set_state(ll
, IPV4ACD_STATE_RUNNING
, false);
299 case IPV4ACD_STATE_WAITING_ANNOUNCE
:
300 /* Send announcement packet */
301 r
= arp_send_announcement(ll
->fd
, ll
->ifindex
, ll
->address
, &ll
->mac_addr
);
303 log_ipv4acd_errno(ll
, r
, "Failed to send ARP announcement: %m");
306 log_ipv4acd(ll
, "ANNOUNCE");
308 ipv4acd_set_state(ll
, IPV4ACD_STATE_ANNOUNCING
, false);
310 r
= ipv4acd_set_next_wakeup(ll
, ANNOUNCE_INTERVAL_USEC
, 0);
314 if (ll
->n_iteration
== 0) {
316 ipv4acd_client_notify(ll
, SD_IPV4ACD_EVENT_BIND
);
322 assert_not_reached("Invalid state.");
332 static void ipv4acd_on_conflict(sd_ipv4acd
*ll
) {
333 _cleanup_free_
char *address
= NULL
;
334 union in_addr_union addr
= { .in
.s_addr
= ll
->address
};
340 (void) in_addr_to_string(AF_INET
, &addr
, &address
);
341 log_ipv4acd(ll
, "Conflict on %s (%u)", strna(address
), ll
->n_conflict
);
344 ipv4acd_client_notify(ll
, SD_IPV4ACD_EVENT_CONFLICT
);
347 static int ipv4acd_on_packet(
353 sd_ipv4acd
*ll
= userdata
;
354 struct ether_arp packet
;
362 n
= recv(fd
, &packet
, sizeof(struct ether_arp
), 0);
364 if (errno
== EAGAIN
|| errno
== EINTR
)
367 log_ipv4acd_errno(ll
, errno
, "Failed to read ARP packet: %m");
370 if ((size_t) n
!= sizeof(struct ether_arp
)) {
371 log_ipv4acd(ll
, "Ignoring too short ARP packet.");
377 case IPV4ACD_STATE_ANNOUNCING
:
378 case IPV4ACD_STATE_RUNNING
:
380 if (ipv4acd_arp_conflict(ll
, &packet
)) {
383 assert_se(sd_event_now(ll
->event
, clock_boottime_or_monotonic(), &ts
) >= 0);
386 if (ts
> ll
->defend_window
) {
387 ll
->defend_window
= ts
+ DEFEND_INTERVAL_USEC
;
388 r
= arp_send_announcement(ll
->fd
, ll
->ifindex
, ll
->address
, &ll
->mac_addr
);
390 log_ipv4acd_errno(ll
, r
, "Failed to send ARP announcement: %m");
393 log_ipv4acd(ll
, "DEFEND");
396 ipv4acd_on_conflict(ll
);
400 case IPV4ACD_STATE_WAITING_PROBE
:
401 case IPV4ACD_STATE_PROBING
:
402 case IPV4ACD_STATE_WAITING_ANNOUNCE
:
403 /* BPF ensures this packet indicates a conflict */
404 ipv4acd_on_conflict(ll
);
408 assert_not_reached("Invalid state.");
418 int sd_ipv4acd_set_ifindex(sd_ipv4acd
*ll
, int ifindex
) {
419 assert_return(ll
, -EINVAL
);
420 assert_return(ifindex
> 0, -EINVAL
);
421 assert_return(ll
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
423 ll
->ifindex
= ifindex
;
428 int sd_ipv4acd_set_mac(sd_ipv4acd
*ll
, const struct ether_addr
*addr
) {
429 assert_return(ll
, -EINVAL
);
430 assert_return(addr
, -EINVAL
);
431 assert_return(ll
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
433 ll
->mac_addr
= *addr
;
438 int sd_ipv4acd_detach_event(sd_ipv4acd
*ll
) {
439 assert_return(ll
, -EINVAL
);
441 ll
->event
= sd_event_unref(ll
->event
);
446 int sd_ipv4acd_attach_event(sd_ipv4acd
*ll
, sd_event
*event
, int64_t priority
) {
449 assert_return(ll
, -EINVAL
);
450 assert_return(!ll
->event
, -EBUSY
);
453 ll
->event
= sd_event_ref(event
);
455 r
= sd_event_default(&ll
->event
);
460 ll
->event_priority
= priority
;
465 int sd_ipv4acd_set_callback(sd_ipv4acd
*ll
, sd_ipv4acd_callback_t cb
, void *userdata
) {
466 assert_return(ll
, -EINVAL
);
469 ll
->userdata
= userdata
;
474 int sd_ipv4acd_set_address(sd_ipv4acd
*ll
, const struct in_addr
*address
) {
475 assert_return(ll
, -EINVAL
);
476 assert_return(address
, -EINVAL
);
477 assert_return(ll
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
479 ll
->address
= address
->s_addr
;
484 int sd_ipv4acd_is_running(sd_ipv4acd
*ll
) {
485 assert_return(ll
, false);
487 return ll
->state
!= IPV4ACD_STATE_INIT
;
490 int sd_ipv4acd_start(sd_ipv4acd
*ll
) {
493 assert_return(ll
, -EINVAL
);
494 assert_return(ll
->event
, -EINVAL
);
495 assert_return(ll
->ifindex
> 0, -EINVAL
);
496 assert_return(ll
->address
!= 0, -EINVAL
);
497 assert_return(!ether_addr_is_null(&ll
->mac_addr
), -EINVAL
);
498 assert_return(ll
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
500 r
= arp_network_bind_raw_socket(ll
->ifindex
, ll
->address
, &ll
->mac_addr
);
506 ll
->defend_window
= 0;
509 r
= sd_event_add_io(ll
->event
, &ll
->receive_message_event_source
, ll
->fd
, EPOLLIN
, ipv4acd_on_packet
, ll
);
513 r
= sd_event_source_set_priority(ll
->receive_message_event_source
, ll
->event_priority
);
517 (void) sd_event_source_set_description(ll
->receive_message_event_source
, "ipv4acd-receive-message");
519 r
= ipv4acd_set_next_wakeup(ll
, 0, 0);
523 ipv4acd_set_state(ll
, IPV4ACD_STATE_STARTED
, true);