]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-ipv4acd.c
ipv4acd: rename "ll" parameter to "acd" everywhere
[thirdparty/systemd.git] / src / libsystemd-network / sd-ipv4acd.c
1 /***
2 This file is part of systemd.
3
4 Copyright (C) 2014 Axis Communications AB. All rights reserved.
5 Copyright (C) 2015 Tom Gundersen
6
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.
11
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.
16
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/>.
19 ***/
20
21 #include <arpa/inet.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "sd-ipv4acd.h"
28
29 #include "alloc-util.h"
30 #include "arp-util.h"
31 #include "ether-addr-util.h"
32 #include "fd-util.h"
33 #include "in-addr-util.h"
34 #include "list.h"
35 #include "random-util.h"
36 #include "siphash24.h"
37 #include "string-util.h"
38 #include "util.h"
39
40 /* Constants from the RFC */
41 #define PROBE_WAIT_USEC (1U * USEC_PER_SEC)
42 #define PROBE_NUM 3U
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)
51
52 typedef enum IPv4ACDState {
53 IPV4ACD_STATE_INIT,
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,
60 _IPV4ACD_STATE_MAX,
61 _IPV4ACD_STATE_INVALID = -1
62 } IPv4ACDState;
63
64 struct sd_ipv4acd {
65 unsigned n_ref;
66
67 IPv4ACDState state;
68 int ifindex;
69 int fd;
70
71 unsigned n_iteration;
72 unsigned n_conflict;
73
74 sd_event_source *receive_message_event_source;
75 sd_event_source *timer_event_source;
76
77 usec_t defend_window;
78 be32_t address;
79
80 /* External */
81 struct ether_addr mac_addr;
82
83 sd_event *event;
84 int event_priority;
85 sd_ipv4acd_callback_t callback;
86 void* userdata;
87 };
88
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__)
91
92 static void ipv4acd_set_state(sd_ipv4acd *acd, IPv4ACDState st, bool reset_counter) {
93 assert(acd);
94 assert(st < _IPV4ACD_STATE_MAX);
95
96 if (st == acd->state && !reset_counter)
97 acd->n_iteration++;
98 else {
99 acd->state = st;
100 acd->n_iteration = 0;
101 }
102 }
103
104 static void ipv4acd_reset(sd_ipv4acd *acd) {
105 assert(acd);
106
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);
109
110 acd->fd = safe_close(acd->fd);
111
112 ipv4acd_set_state(acd, IPV4ACD_STATE_INIT, true);
113 }
114
115 sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *acd) {
116 if (!acd)
117 return NULL;
118
119 assert_se(acd->n_ref >= 1);
120 acd->n_ref++;
121
122 return acd;
123 }
124
125 sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *acd) {
126 if (!acd)
127 return NULL;
128
129 assert_se(acd->n_ref >= 1);
130 acd->n_ref--;
131
132 if (acd->n_ref > 0)
133 return NULL;
134
135 ipv4acd_reset(acd);
136 sd_ipv4acd_detach_event(acd);
137
138 free(acd);
139
140 return NULL;
141 }
142
143 int sd_ipv4acd_new(sd_ipv4acd **ret) {
144 _cleanup_(sd_ipv4acd_unrefp) sd_ipv4acd *acd = NULL;
145
146 assert_return(ret, -EINVAL);
147
148 acd = new0(sd_ipv4acd, 1);
149 if (!acd)
150 return -ENOMEM;
151
152 acd->n_ref = 1;
153 acd->state = IPV4ACD_STATE_INIT;
154 acd->ifindex = -1;
155 acd->fd = -1;
156
157 *ret = acd;
158 acd = NULL;
159
160 return 0;
161 }
162
163 static void ipv4acd_client_notify(sd_ipv4acd *acd, int event) {
164 assert(acd);
165
166 if (!acd->callback)
167 return;
168
169 acd->callback(acd, event, acd->userdata);
170 }
171
172 int sd_ipv4acd_stop(sd_ipv4acd *acd) {
173 assert_return(acd, -EINVAL);
174
175 ipv4acd_reset(acd);
176
177 log_ipv4acd(acd, "STOPPED");
178
179 ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_STOP);
180
181 return 0;
182 }
183
184 static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata);
185
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;
189 int r;
190
191 assert(acd);
192
193 next_timeout = usec;
194
195 if (random_usec > 0)
196 next_timeout += (usec_t) random_u64() % random_usec;
197
198 assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &time_now) >= 0);
199
200 r = sd_event_add_time(acd->event, &timer, clock_boottime_or_monotonic(), time_now + next_timeout, 0, ipv4acd_on_timeout, acd);
201 if (r < 0)
202 return r;
203
204 r = sd_event_source_set_priority(timer, acd->event_priority);
205 if (r < 0)
206 return r;
207
208 (void) sd_event_source_set_description(timer, "ipv4acd-timer");
209
210 sd_event_source_unref(acd->timer_event_source);
211 acd->timer_event_source = timer;
212 timer = NULL;
213
214 return 0;
215 }
216
217 static bool ipv4acd_arp_conflict(sd_ipv4acd *acd, struct ether_arp *arp) {
218 assert(acd);
219 assert(arp);
220
221 /* see the BPF */
222 if (memcmp(arp->arp_spa, &acd->address, sizeof(acd->address)) == 0)
223 return true;
224
225 /* the TPA matched instead of the SPA, this is not a conflict */
226 return false;
227 }
228
229 static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
230 sd_ipv4acd *acd = userdata;
231 int r = 0;
232
233 assert(acd);
234
235 switch (acd->state) {
236
237 case IPV4ACD_STATE_STARTED:
238 ipv4acd_set_state(acd, IPV4ACD_STATE_WAITING_PROBE, true);
239
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));
243
244 r = ipv4acd_set_next_wakeup(acd, RATE_LIMIT_INTERVAL_USEC, PROBE_WAIT_USEC);
245 if (r < 0)
246 goto fail;
247
248 acd->n_conflict = 0;
249 } else {
250 r = ipv4acd_set_next_wakeup(acd, 0, PROBE_WAIT_USEC);
251 if (r < 0)
252 goto fail;
253 }
254
255 break;
256
257 case IPV4ACD_STATE_WAITING_PROBE:
258 case IPV4ACD_STATE_PROBING:
259 /* Send a probe */
260 r = arp_send_probe(acd->fd, acd->ifindex, acd->address, &acd->mac_addr);
261 if (r < 0) {
262 log_ipv4acd_errno(acd, r, "Failed to send ARP probe: %m");
263 goto fail;
264 } else {
265 _cleanup_free_ char *address = NULL;
266 union in_addr_union addr = { .in.s_addr = acd->address };
267
268 (void) in_addr_to_string(AF_INET, &addr, &address);
269 log_ipv4acd(acd, "Probing %s", strna(address));
270 }
271
272 if (acd->n_iteration < PROBE_NUM - 2) {
273 ipv4acd_set_state(acd, IPV4ACD_STATE_PROBING, false);
274
275 r = ipv4acd_set_next_wakeup(acd, PROBE_MIN_USEC, (PROBE_MAX_USEC-PROBE_MIN_USEC));
276 if (r < 0)
277 goto fail;
278 } else {
279 ipv4acd_set_state(acd, IPV4ACD_STATE_WAITING_ANNOUNCE, true);
280
281 r = ipv4acd_set_next_wakeup(acd, ANNOUNCE_WAIT_USEC, 0);
282 if (r < 0)
283 goto fail;
284 }
285
286 break;
287
288 case IPV4ACD_STATE_ANNOUNCING:
289 if (acd->n_iteration >= ANNOUNCE_NUM - 1) {
290 ipv4acd_set_state(acd, IPV4ACD_STATE_RUNNING, false);
291 break;
292 }
293
294 /* fall through */
295
296 case IPV4ACD_STATE_WAITING_ANNOUNCE:
297 /* Send announcement packet */
298 r = arp_send_announcement(acd->fd, acd->ifindex, acd->address, &acd->mac_addr);
299 if (r < 0) {
300 log_ipv4acd_errno(acd, r, "Failed to send ARP announcement: %m");
301 goto fail;
302 } else
303 log_ipv4acd(acd, "ANNOUNCE");
304
305 ipv4acd_set_state(acd, IPV4ACD_STATE_ANNOUNCING, false);
306
307 r = ipv4acd_set_next_wakeup(acd, ANNOUNCE_INTERVAL_USEC, 0);
308 if (r < 0)
309 goto fail;
310
311 if (acd->n_iteration == 0) {
312 acd->n_conflict = 0;
313 ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_BIND);
314 }
315
316 break;
317
318 default:
319 assert_not_reached("Invalid state.");
320 }
321
322 return 0;
323
324 fail:
325 sd_ipv4acd_stop(acd);
326 return 0;
327 }
328
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 };
332
333 assert(acd);
334
335 acd->n_conflict++;
336
337 (void) in_addr_to_string(AF_INET, &addr, &address);
338 log_ipv4acd(acd, "Conflict on %s (%u)", strna(address), acd->n_conflict);
339
340 ipv4acd_reset(acd);
341 ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_CONFLICT);
342 }
343
344 static int ipv4acd_on_packet(
345 sd_event_source *s,
346 int fd,
347 uint32_t revents,
348 void *userdata) {
349
350 sd_ipv4acd *acd = userdata;
351 struct ether_arp packet;
352 ssize_t n;
353 int r;
354
355 assert(s);
356 assert(acd);
357 assert(fd >= 0);
358
359 n = recv(fd, &packet, sizeof(struct ether_arp), 0);
360 if (n < 0) {
361 if (errno == EAGAIN || errno == EINTR)
362 return 0;
363
364 log_ipv4acd_errno(acd, errno, "Failed to read ARP packet: %m");
365 goto fail;
366 }
367 if ((size_t) n != sizeof(struct ether_arp)) {
368 log_ipv4acd(acd, "Ignoring too short ARP packet.");
369 return 0;
370 }
371
372 switch (acd->state) {
373
374 case IPV4ACD_STATE_ANNOUNCING:
375 case IPV4ACD_STATE_RUNNING:
376
377 if (ipv4acd_arp_conflict(acd, &packet)) {
378 usec_t ts;
379
380 assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &ts) >= 0);
381
382 /* Defend address */
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);
386 if (r < 0) {
387 log_ipv4acd_errno(acd, r, "Failed to send ARP announcement: %m");
388 goto fail;
389 } else
390 log_ipv4acd(acd, "DEFEND");
391
392 } else
393 ipv4acd_on_conflict(acd);
394 }
395 break;
396
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);
402 break;
403
404 default:
405 assert_not_reached("Invalid state.");
406 }
407
408 return 0;
409
410 fail:
411 sd_ipv4acd_stop(acd);
412 return 0;
413 }
414
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);
419
420 acd->ifindex = ifindex;
421
422 return 0;
423 }
424
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);
429
430 acd->mac_addr = *addr;
431
432 return 0;
433 }
434
435 int sd_ipv4acd_detach_event(sd_ipv4acd *acd) {
436 assert_return(acd, -EINVAL);
437
438 acd->event = sd_event_unref(acd->event);
439
440 return 0;
441 }
442
443 int sd_ipv4acd_attach_event(sd_ipv4acd *acd, sd_event *event, int64_t priority) {
444 int r;
445
446 assert_return(acd, -EINVAL);
447 assert_return(!acd->event, -EBUSY);
448
449 if (event)
450 acd->event = sd_event_ref(event);
451 else {
452 r = sd_event_default(&acd->event);
453 if (r < 0)
454 return r;
455 }
456
457 acd->event_priority = priority;
458
459 return 0;
460 }
461
462 int sd_ipv4acd_set_callback(sd_ipv4acd *acd, sd_ipv4acd_callback_t cb, void *userdata) {
463 assert_return(acd, -EINVAL);
464
465 acd->callback = cb;
466 acd->userdata = userdata;
467
468 return 0;
469 }
470
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);
475
476 acd->address = address->s_addr;
477
478 return 0;
479 }
480
481 int sd_ipv4acd_is_running(sd_ipv4acd *acd) {
482 assert_return(acd, false);
483
484 return acd->state != IPV4ACD_STATE_INIT;
485 }
486
487 int sd_ipv4acd_start(sd_ipv4acd *acd) {
488 int r;
489
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);
496
497 r = arp_network_bind_raw_socket(acd->ifindex, acd->address, &acd->mac_addr);
498 if (r < 0)
499 return r;
500
501 safe_close(acd->fd);
502 acd->fd = r;
503 acd->defend_window = 0;
504 acd->n_conflict = 0;
505
506 r = sd_event_add_io(acd->event, &acd->receive_message_event_source, acd->fd, EPOLLIN, ipv4acd_on_packet, acd);
507 if (r < 0)
508 goto fail;
509
510 r = sd_event_source_set_priority(acd->receive_message_event_source, acd->event_priority);
511 if (r < 0)
512 goto fail;
513
514 (void) sd_event_source_set_description(acd->receive_message_event_source, "ipv4acd-receive-message");
515
516 r = ipv4acd_set_next_wakeup(acd, 0, 0);
517 if (r < 0)
518 goto fail;
519
520 ipv4acd_set_state(acd, IPV4ACD_STATE_STARTED, true);
521 return 0;
522
523 fail:
524 ipv4acd_reset(acd);
525 return r;
526 }