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