]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-ipv4acd.c
ipv4acd: introduce new "started" state
[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 1
42 #define PROBE_NUM 3
43 #define PROBE_MIN 1
44 #define PROBE_MAX 2
45 #define ANNOUNCE_WAIT 2
46 #define ANNOUNCE_NUM 2
47 #define ANNOUNCE_INTERVAL 2
48 #define MAX_CONFLICTS 10
49 #define RATE_LIMIT_INTERVAL 60
50 #define DEFEND_INTERVAL 10
51
52 #define IPV4ACD_NETWORK 0xA9FE0000UL
53 #define IPV4ACD_NETMASK 0xFFFF0000UL
54
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__)
57
58 typedef enum IPv4ACDState {
59 IPV4ACD_STATE_INIT,
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,
66 _IPV4ACD_STATE_MAX,
67 _IPV4ACD_STATE_INVALID = -1
68 } IPv4ACDState;
69
70 struct sd_ipv4acd {
71 unsigned n_ref;
72
73 IPv4ACDState state;
74 int ifindex;
75 int fd;
76
77 unsigned n_iteration;
78 unsigned n_conflict;
79
80 sd_event_source *receive_message_event_source;
81 sd_event_source *timer_event_source;
82
83 usec_t defend_window;
84 be32_t address;
85
86 /* External */
87 struct ether_addr mac_addr;
88
89 sd_event *event;
90 int event_priority;
91 sd_ipv4acd_callback_t callback;
92 void* userdata;
93 };
94
95 static void ipv4acd_set_state(sd_ipv4acd *ll, IPv4ACDState st, bool reset_counter) {
96 assert(ll);
97 assert(st < _IPV4ACD_STATE_MAX);
98
99 if (st == ll->state && !reset_counter)
100 ll->n_iteration++;
101 else {
102 ll->state = st;
103 ll->n_iteration = 0;
104 }
105 }
106
107 static void ipv4acd_reset(sd_ipv4acd *ll) {
108 assert(ll);
109
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);
112
113 ll->fd = safe_close(ll->fd);
114
115 ipv4acd_set_state(ll, IPV4ACD_STATE_INIT, true);
116 }
117
118 sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll) {
119 if (!ll)
120 return NULL;
121
122 assert_se(ll->n_ref >= 1);
123 ll->n_ref++;
124
125 return ll;
126 }
127
128 sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll) {
129 if (!ll)
130 return NULL;
131
132 assert_se(ll->n_ref >= 1);
133 ll->n_ref--;
134
135 if (ll->n_ref > 0)
136 return NULL;
137
138 ipv4acd_reset(ll);
139 sd_ipv4acd_detach_event(ll);
140
141 free(ll);
142
143 return NULL;
144 }
145
146 int sd_ipv4acd_new(sd_ipv4acd **ret) {
147 _cleanup_(sd_ipv4acd_unrefp) sd_ipv4acd *ll = NULL;
148
149 assert_return(ret, -EINVAL);
150
151 ll = new0(sd_ipv4acd, 1);
152 if (!ll)
153 return -ENOMEM;
154
155 ll->n_ref = 1;
156 ll->state = IPV4ACD_STATE_INIT;
157 ll->ifindex = -1;
158 ll->fd = -1;
159
160 *ret = ll;
161 ll = NULL;
162
163 return 0;
164 }
165
166 static void ipv4acd_client_notify(sd_ipv4acd *ll, int event) {
167 assert(ll);
168
169 if (!ll->callback)
170 return;
171
172 ll->callback(ll, event, ll->userdata);
173 }
174
175 int sd_ipv4acd_stop(sd_ipv4acd *ll) {
176 assert_return(ll, -EINVAL);
177
178 ipv4acd_reset(ll);
179
180 log_ipv4acd(ll, "STOPPED");
181
182 ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_STOP);
183
184 return 0;
185 }
186
187 static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata);
188
189 static int ipv4acd_set_next_wakeup(sd_ipv4acd *ll, int sec, int random_sec) {
190 _cleanup_(sd_event_source_unrefp) sd_event_source *timer = NULL;
191 usec_t next_timeout;
192 usec_t time_now;
193 int r;
194
195 assert(sec >= 0);
196 assert(random_sec >= 0);
197 assert(ll);
198
199 next_timeout = sec * USEC_PER_SEC;
200
201 if (random_sec)
202 next_timeout += random_u32() % (random_sec * USEC_PER_SEC);
203
204 assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now) >= 0);
205
206 r = sd_event_add_time(ll->event, &timer, clock_boottime_or_monotonic(),
207 time_now + next_timeout, 0, ipv4acd_on_timeout, ll);
208 if (r < 0)
209 return r;
210
211 r = sd_event_source_set_priority(timer, ll->event_priority);
212 if (r < 0)
213 return r;
214
215 (void) sd_event_source_set_description(timer, "ipv4acd-timer");
216
217 sd_event_source_unref(ll->timer_event_source);
218 ll->timer_event_source = timer;
219 timer = NULL;
220
221 return 0;
222 }
223
224 static bool ipv4acd_arp_conflict(sd_ipv4acd *ll, struct ether_arp *arp) {
225 assert(ll);
226 assert(arp);
227
228 /* see the BPF */
229 if (memcmp(arp->arp_spa, &ll->address, sizeof(ll->address)) == 0)
230 return true;
231
232 /* the TPA matched instead of the SPA, this is not a conflict */
233 return false;
234 }
235
236 static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
237 sd_ipv4acd *ll = userdata;
238 int r = 0;
239
240 assert(ll);
241
242 switch (ll->state) {
243
244 case IPV4ACD_STATE_STARTED:
245 ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_PROBE, true);
246
247 if (ll->n_conflict >= MAX_CONFLICTS) {
248 log_ipv4acd(ll, "Max conflicts reached, delaying by %us", RATE_LIMIT_INTERVAL);
249
250 r = ipv4acd_set_next_wakeup(ll, RATE_LIMIT_INTERVAL, PROBE_WAIT);
251 if (r < 0)
252 goto out;
253
254 ll->n_conflict = 0;
255 } else {
256 r = ipv4acd_set_next_wakeup(ll, 0, PROBE_WAIT);
257 if (r < 0)
258 goto out;
259 }
260
261 break;
262
263 case IPV4ACD_STATE_WAITING_PROBE:
264 case IPV4ACD_STATE_PROBING:
265 /* Send a probe */
266 r = arp_send_probe(ll->fd, ll->ifindex, ll->address, &ll->mac_addr);
267 if (r < 0) {
268 log_ipv4acd_errno(ll, r, "Failed to send ARP probe: %m");
269 goto out;
270 } else {
271 _cleanup_free_ char *address = NULL;
272 union in_addr_union addr = { .in.s_addr = ll->address };
273
274 (void) in_addr_to_string(AF_INET, &addr, &address);
275 log_ipv4acd(ll, "Probing %s", strna(address));
276 }
277
278 if (ll->n_iteration < PROBE_NUM - 2) {
279 ipv4acd_set_state(ll, IPV4ACD_STATE_PROBING, false);
280
281 r = ipv4acd_set_next_wakeup(ll, PROBE_MIN, (PROBE_MAX-PROBE_MIN));
282 if (r < 0)
283 goto out;
284 } else {
285 ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_ANNOUNCE, true);
286
287 r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_WAIT, 0);
288 if (r < 0)
289 goto out;
290 }
291
292 break;
293
294 case IPV4ACD_STATE_ANNOUNCING:
295 if (ll->n_iteration >= ANNOUNCE_NUM - 1) {
296 ipv4acd_set_state(ll, IPV4ACD_STATE_RUNNING, false);
297 break;
298 }
299
300 /* fall through */
301
302 case IPV4ACD_STATE_WAITING_ANNOUNCE:
303 /* Send announcement packet */
304 r = arp_send_announcement(ll->fd, ll->ifindex, ll->address, &ll->mac_addr);
305 if (r < 0) {
306 log_ipv4acd_errno(ll, r, "Failed to send ARP announcement: %m");
307 goto out;
308 } else
309 log_ipv4acd(ll, "ANNOUNCE");
310
311 ipv4acd_set_state(ll, IPV4ACD_STATE_ANNOUNCING, false);
312
313 r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_INTERVAL, 0);
314 if (r < 0)
315 goto out;
316
317 if (ll->n_iteration == 0) {
318 ll->n_conflict = 0;
319 ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_BIND);
320 }
321
322 break;
323
324 default:
325 assert_not_reached("Invalid state.");
326 }
327
328 out:
329 if (r < 0)
330 sd_ipv4acd_stop(ll);
331
332 return 1;
333 }
334
335 static void ipv4acd_on_conflict(sd_ipv4acd *ll) {
336 _cleanup_free_ char *address = NULL;
337 union in_addr_union addr = { .in.s_addr = ll->address };
338
339 assert(ll);
340
341 ll->n_conflict++;
342
343 (void) in_addr_to_string(AF_INET, &addr, &address);
344 log_ipv4acd(ll, "Conflict on %s (%u)", strna(address), ll->n_conflict);
345
346 ipv4acd_reset(ll);
347 ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_CONFLICT);
348 }
349
350 static int ipv4acd_on_packet(
351 sd_event_source *s,
352 int fd,
353 uint32_t revents,
354 void *userdata) {
355
356 sd_ipv4acd *ll = userdata;
357 struct ether_arp packet;
358 ssize_t n;
359 int r;
360
361 assert(s);
362 assert(ll);
363 assert(fd >= 0);
364
365 n = recv(fd, &packet, sizeof(struct ether_arp), 0);
366 if (n < 0) {
367 if (errno == EAGAIN || errno == EINTR)
368 return 0;
369
370 r = log_ipv4acd_errno(ll, errno, "Failed to read ARP packet: %m");
371 goto out;
372 }
373 if ((size_t) n != sizeof(struct ether_arp)) {
374 log_ipv4acd(ll, "Ignoring too short ARP packet.");
375 return 0;
376 }
377
378 switch (ll->state) {
379
380 case IPV4ACD_STATE_ANNOUNCING:
381 case IPV4ACD_STATE_RUNNING:
382
383 if (ipv4acd_arp_conflict(ll, &packet)) {
384 usec_t ts;
385
386 assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &ts) >= 0);
387
388 /* Defend address */
389 if (ts > ll->defend_window) {
390 ll->defend_window = ts + DEFEND_INTERVAL * USEC_PER_SEC;
391 r = arp_send_announcement(ll->fd, ll->ifindex, ll->address, &ll->mac_addr);
392 if (r < 0) {
393 log_ipv4acd_errno(ll, r, "Failed to send ARP announcement: %m");
394 goto out;
395 } else
396 log_ipv4acd(ll, "DEFEND");
397
398 } else
399 ipv4acd_on_conflict(ll);
400 }
401 break;
402
403 case IPV4ACD_STATE_WAITING_PROBE:
404 case IPV4ACD_STATE_PROBING:
405 case IPV4ACD_STATE_WAITING_ANNOUNCE:
406 /* BPF ensures this packet indicates a conflict */
407 ipv4acd_on_conflict(ll);
408 break;
409
410 default:
411 assert_not_reached("Invalid state.");
412 }
413
414 out:
415 if (r < 0)
416 sd_ipv4acd_stop(ll);
417
418 return 1;
419 }
420
421 int sd_ipv4acd_set_ifindex(sd_ipv4acd *ll, int ifindex) {
422 assert_return(ll, -EINVAL);
423 assert_return(ifindex > 0, -EINVAL);
424 assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
425
426 ll->ifindex = ifindex;
427
428 return 0;
429 }
430
431 int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr) {
432 assert_return(ll, -EINVAL);
433 assert_return(addr, -EINVAL);
434 assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
435
436 memcpy(&ll->mac_addr, addr, ETH_ALEN);
437
438 return 0;
439 }
440
441 int sd_ipv4acd_detach_event(sd_ipv4acd *ll) {
442 assert_return(ll, -EINVAL);
443
444 ll->event = sd_event_unref(ll->event);
445
446 return 0;
447 }
448
449 int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int64_t priority) {
450 int r;
451
452 assert_return(ll, -EINVAL);
453 assert_return(!ll->event, -EBUSY);
454
455 if (event)
456 ll->event = sd_event_ref(event);
457 else {
458 r = sd_event_default(&ll->event);
459 if (r < 0)
460 return r;
461 }
462
463 ll->event_priority = priority;
464
465 return 0;
466 }
467
468 int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_callback_t cb, void *userdata) {
469 assert_return(ll, -EINVAL);
470
471 ll->callback = cb;
472 ll->userdata = userdata;
473
474 return 0;
475 }
476
477 int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address) {
478 assert_return(ll, -EINVAL);
479 assert_return(address, -EINVAL);
480 assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
481
482 ll->address = address->s_addr;
483
484 return 0;
485 }
486
487 int sd_ipv4acd_is_running(sd_ipv4acd *ll) {
488 assert_return(ll, false);
489
490 return ll->state != IPV4ACD_STATE_INIT;
491 }
492
493 int sd_ipv4acd_start(sd_ipv4acd *ll) {
494 int r;
495
496 assert_return(ll, -EINVAL);
497 assert_return(ll->event, -EINVAL);
498 assert_return(ll->ifindex > 0, -EINVAL);
499 assert_return(ll->address != 0, -EINVAL);
500 assert_return(!ether_addr_is_null(&ll->mac_addr), -EINVAL);
501 assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
502
503 r = arp_network_bind_raw_socket(ll->ifindex, ll->address, &ll->mac_addr);
504 if (r < 0)
505 return r;
506
507 safe_close(ll->fd);
508 ll->fd = r;
509 ll->defend_window = 0;
510
511 r = sd_event_add_io(ll->event, &ll->receive_message_event_source, ll->fd, EPOLLIN, ipv4acd_on_packet, ll);
512 if (r < 0)
513 goto fail;
514
515 r = sd_event_source_set_priority(ll->receive_message_event_source, ll->event_priority);
516 if (r < 0)
517 goto fail;
518
519 (void) sd_event_source_set_description(ll->receive_message_event_source, "ipv4acd-receive-message");
520
521 r = ipv4acd_set_next_wakeup(ll, 0, 0);
522 if (r < 0)
523 goto fail;
524
525 ipv4acd_set_state(ll, IPV4ACD_STATE_STARTED, true);
526 return 0;
527
528 fail:
529 ipv4acd_reset(ll);
530 return r;
531 }