]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-neighbor.c
network: make Reload bus method synchronous
[thirdparty/systemd.git] / src / network / networkd-neighbor.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
e4a71bf3 2
e4a71bf3 3#include "alloc-util.h"
e4a71bf3 4#include "hashmap.h"
e4a71bf3
WKI
5#include "netlink-util.h"
6#include "networkd-link.h"
7#include "networkd-manager.h"
8#include "networkd-neighbor.h"
1939ebeb 9#include "networkd-network.h"
40ca350e 10#include "networkd-queue.h"
d1bdafd2 11#include "set.h"
e4a71bf3 12
2a75f23b
YW
13static Neighbor* neighbor_detach_impl(Neighbor *neighbor) {
14 assert(neighbor);
15 assert(!neighbor->link || !neighbor->network);
e4a71bf3
WKI
16
17 if (neighbor->network) {
b0ba6938 18 assert(neighbor->section);
aa9626ee 19 ordered_hashmap_remove(neighbor->network->neighbors_by_section, neighbor->section);
2a75f23b
YW
20 neighbor->network = NULL;
21 return neighbor;
d1bdafd2
WKI
22 }
23
2a75f23b 24 if (neighbor->link) {
d1bdafd2 25 set_remove(neighbor->link->neighbors, neighbor);
2a75f23b
YW
26 neighbor->link = NULL;
27 return neighbor;
28 }
29
30 return NULL;
31}
e4a71bf3 32
2a75f23b
YW
33static void neighbor_detach(Neighbor *neighbor) {
34 neighbor_unref(neighbor_detach_impl(neighbor));
35}
36
37static Neighbor* neighbor_free(Neighbor *neighbor) {
38 if (!neighbor)
39 return NULL;
40
41 neighbor_detach_impl(neighbor);
42
43 config_section_free(neighbor->section);
64753f35 44 return mfree(neighbor);
e4a71bf3
WKI
45}
46
2a75f23b
YW
47DEFINE_TRIVIAL_REF_UNREF_FUNC(Neighbor, neighbor, neighbor_free);
48DEFINE_SECTION_CLEANUP_FUNCTIONS(Neighbor, neighbor_unref);
49
50static void neighbor_hash_func(const Neighbor *neighbor, struct siphash *state);
51static int neighbor_compare_func(const Neighbor *a, const Neighbor *b);
52
53DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
54 neighbor_hash_ops_detach,
55 Neighbor,
56 neighbor_hash_func,
57 neighbor_compare_func,
58 neighbor_detach);
59
60DEFINE_PRIVATE_HASH_OPS(
61 neighbor_hash_ops,
62 Neighbor,
63 neighbor_hash_func,
64 neighbor_compare_func);
65
66DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
67 neighbor_section_hash_ops,
68 ConfigSection,
69 config_section_hash_func,
70 config_section_compare_func,
71 Neighbor,
72 neighbor_detach);
73
74static int neighbor_new(Neighbor **ret) {
75 Neighbor *neighbor;
76
77 assert(ret);
78
79 neighbor = new(Neighbor, 1);
80 if (!neighbor)
81 return -ENOMEM;
82
83 *neighbor = (Neighbor) {
84 .n_ref = 1,
85 };
86
87 *ret = TAKE_PTR(neighbor);
88 return 0;
89}
0d6e933e 90
e4a71bf3 91static int neighbor_new_static(Network *network, const char *filename, unsigned section_line, Neighbor **ret) {
307fe3cd 92 _cleanup_(config_section_freep) ConfigSection *n = NULL;
2a75f23b 93 _cleanup_(neighbor_unrefp) Neighbor *neighbor = NULL;
e4a71bf3
WKI
94 int r;
95
96 assert(network);
97 assert(ret);
b0ba6938
YW
98 assert(filename);
99 assert(section_line > 0);
e4a71bf3 100
307fe3cd 101 r = config_section_new(filename, section_line, &n);
b0ba6938
YW
102 if (r < 0)
103 return r;
e4a71bf3 104
aa9626ee 105 neighbor = ordered_hashmap_get(network->neighbors_by_section, n);
b0ba6938
YW
106 if (neighbor) {
107 *ret = TAKE_PTR(neighbor);
108 return 0;
e4a71bf3
WKI
109 }
110
2a75f23b
YW
111 r = neighbor_new(&neighbor);
112 if (r < 0)
113 return r;
e4a71bf3 114
2a75f23b
YW
115 neighbor->network = network;
116 neighbor->section = TAKE_PTR(n);
117 neighbor->source = NETWORK_CONFIG_SOURCE_STATIC;
e4a71bf3 118
2a75f23b 119 r = ordered_hashmap_ensure_put(&network->neighbors_by_section, &neighbor_section_hash_ops, neighbor->section, neighbor);
b0ba6938
YW
120 if (r < 0)
121 return r;
e4a71bf3
WKI
122
123 *ret = TAKE_PTR(neighbor);
e4a71bf3
WKI
124 return 0;
125}
126
193c4af9 127static int neighbor_dup(const Neighbor *neighbor, Neighbor **ret) {
2a75f23b 128 _cleanup_(neighbor_unrefp) Neighbor *dest = NULL;
193c4af9
YW
129
130 assert(neighbor);
131 assert(ret);
132
133 dest = newdup(Neighbor, neighbor, 1);
134 if (!dest)
135 return -ENOMEM;
136
2a75f23b
YW
137 /* Clear the reference counter and all pointers */
138 dest->n_ref = 1;
193c4af9
YW
139 dest->link = NULL;
140 dest->network = NULL;
141 dest->section = NULL;
142
143 *ret = TAKE_PTR(dest);
144 return 0;
145}
146
09d09207 147static void neighbor_hash_func(const Neighbor *neighbor, struct siphash *state) {
d1bdafd2
WKI
148 assert(neighbor);
149
c01a5c05 150 siphash24_compress_typesafe(neighbor->family, state);
d1bdafd2 151
aa9626ee 152 if (!IN_SET(neighbor->family, AF_INET, AF_INET6))
d1bdafd2 153 /* treat any other address family as AF_UNSPEC */
aa9626ee 154 return;
a811fb8b 155
aa9626ee
YW
156 /* Equality of neighbors are given by the destination address.
157 * See neigh_lookup() in the kernel. */
c01a5c05 158 in_addr_hash_func(&neighbor->in_addr, neighbor->family, state);
d1bdafd2
WKI
159}
160
09d09207 161static int neighbor_compare_func(const Neighbor *a, const Neighbor *b) {
d1bdafd2
WKI
162 int r;
163
164 r = CMP(a->family, b->family);
165 if (r != 0)
166 return r;
167
aa9626ee
YW
168 if (!IN_SET(a->family, AF_INET, AF_INET6))
169 /* treat any other address family as AF_UNSPEC */
170 return 0;
d1bdafd2 171
aa9626ee 172 return memcmp(&a->in_addr, &b->in_addr, FAMILY_ADDRESS_SIZE(a->family));
d1bdafd2
WKI
173}
174
5d098f5d
YW
175static int neighbor_get_request(Link *link, const Neighbor *neighbor, Request **ret) {
176 Request *req;
177
178 assert(link);
179 assert(link->manager);
180 assert(neighbor);
181
182 req = ordered_set_get(
183 link->manager->request_queue,
184 &(Request) {
185 .link = link,
186 .type = REQUEST_TYPE_NEIGHBOR,
187 .userdata = (void*) neighbor,
188 .hash_func = (hash_func_t) neighbor_hash_func,
189 .compare_func = (compare_func_t) neighbor_compare_func,
190 });
191 if (!req)
192 return -ENOENT;
193
194 if (ret)
195 *ret = req;
196 return 0;
197}
198
c902fa08 199int neighbor_get(Link *link, const Neighbor *in, Neighbor **ret) {
19f8cffc 200 Neighbor *existing;
d1bdafd2
WKI
201
202 assert(link);
19f8cffc 203 assert(in);
d1bdafd2 204
19f8cffc 205 existing = set_get(link->neighbors, in);
193c4af9
YW
206 if (!existing)
207 return -ENOENT;
d1bdafd2 208
193c4af9
YW
209 if (ret)
210 *ret = existing;
211 return 0;
d1bdafd2
WKI
212}
213
2a75f23b 214static int neighbor_attach(Link *link, Neighbor *neighbor) {
d1bdafd2
WKI
215 int r;
216
217 assert(link);
193c4af9 218 assert(neighbor);
2a75f23b 219 assert(!neighbor->link);
d1bdafd2 220
2a75f23b 221 r = set_ensure_put(&link->neighbors, &neighbor_hash_ops_detach, neighbor);
d1bdafd2
WKI
222 if (r < 0)
223 return r;
224 if (r == 0)
225 return -EEXIST;
226
227 neighbor->link = link;
2a75f23b 228 neighbor_ref(neighbor);
d1bdafd2
WKI
229 return 0;
230}
231
2775e1c5 232static void log_neighbor_debug(const Neighbor *neighbor, const char *str, const Link *link) {
84dbb3fd 233 _cleanup_free_ char *state = NULL;
2775e1c5
YW
234
235 assert(neighbor);
236 assert(str);
237
238 if (!DEBUG_LOGGING)
239 return;
240
193c4af9 241 (void) network_config_state_to_string_alloc(neighbor->state, &state);
2775e1c5
YW
242
243 log_link_debug(link,
193c4af9
YW
244 "%s %s neighbor (%s): lladdr: %s, dst: %s",
245 str, strna(network_config_source_to_string(neighbor->source)), strna(state),
84dbb3fd
ZJS
246 HW_ADDR_TO_STR(&neighbor->ll_addr),
247 IN_ADDR_TO_STRING(neighbor->family, &neighbor->in_addr));
2775e1c5 248}
193c4af9 249
54ff39f7 250static int neighbor_configure(Neighbor *neighbor, Link *link, Request *req) {
a79a8d16 251 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
fceee7cc
YW
252 int r;
253
254 assert(neighbor);
255 assert(link);
256 assert(link->ifindex > 0);
257 assert(link->manager);
258 assert(link->manager->rtnl);
54ff39f7 259 assert(req);
fceee7cc 260
2775e1c5
YW
261 log_neighbor_debug(neighbor, "Configuring", link);
262
a79a8d16 263 r = sd_rtnl_message_new_neigh(link->manager->rtnl, &m, RTM_NEWNEIGH,
9be0b3ab 264 link->ifindex, neighbor->family);
fceee7cc 265 if (r < 0)
a79a8d16 266 return r;
fceee7cc 267
754252f9
YW
268 r = sd_rtnl_message_neigh_set_state(m, NUD_PERMANENT);
269 if (r < 0)
270 return r;
271
272 r = netlink_message_append_hw_addr(m, NDA_LLADDR, &neighbor->ll_addr);
273 if (r < 0)
274 return r;
275
276 r = netlink_message_append_in_addr_union(m, NDA_DST, neighbor->family, &neighbor->in_addr);
fceee7cc 277 if (r < 0)
a79a8d16 278 return r;
fceee7cc 279
80d62d4f 280 return request_call_netlink_async(link->manager->rtnl, m, req);
fceee7cc
YW
281}
282
09d09207 283static int neighbor_process_request(Request *req, Link *link, Neighbor *neighbor) {
5d098f5d 284 Neighbor *existing;
8bed7c55
YW
285 int r;
286
287 assert(req);
ff51134c
YW
288 assert(link);
289 assert(neighbor);
8bed7c55
YW
290
291 if (!link_is_ready_to_configure(link, false))
292 return 0;
293
54ff39f7 294 r = neighbor_configure(neighbor, link, req);
8bed7c55
YW
295 if (r < 0)
296 return log_link_warning_errno(link, r, "Failed to configure neighbor: %m");
297
298 neighbor_enter_configuring(neighbor);
5d098f5d
YW
299 if (neighbor_get(link, neighbor, &existing) >= 0)
300 neighbor_enter_configuring(existing);
301
8bed7c55
YW
302 return 1;
303}
304
80d62d4f 305static int static_neighbor_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Neighbor *neighbor) {
7575e1f4
YW
306 int r;
307
308 assert(m);
309 assert(link);
7575e1f4
YW
310
311 r = sd_netlink_message_get_errno(m);
40ca350e
YW
312 if (r < 0 && r != -EEXIST) {
313 log_link_message_warning_errno(link, m, r, "Could not set neighbor");
314 link_enter_failed(link);
315 return 1;
316 }
7575e1f4 317
40ca350e 318 if (link->static_neighbor_messages == 0) {
7575e1f4 319 log_link_debug(link, "Neighbors set");
40ca350e 320 link->static_neighbors_configured = true;
7575e1f4
YW
321 link_check_ready(link);
322 }
323
324 return 1;
325}
326
80d62d4f 327static int link_request_neighbor(Link *link, const Neighbor *neighbor) {
2a75f23b 328 _cleanup_(neighbor_unrefp) Neighbor *tmp = NULL;
5d098f5d 329 Neighbor *existing = NULL;
193c4af9
YW
330 int r;
331
40ca350e
YW
332 assert(link);
333 assert(neighbor);
193c4af9
YW
334 assert(neighbor->source != NETWORK_CONFIG_SOURCE_FOREIGN);
335
bbeceaf2
YW
336 if (neighbor->ll_addr.length != link->hw_addr.length) {
337 log_link_debug(link,
da59599d 338 "The link layer address length (%zu) for neighbor %s does not match with "
bbeceaf2
YW
339 "the hardware address length (%zu), ignoring the setting.",
340 neighbor->ll_addr.length,
341 IN_ADDR_TO_STRING(neighbor->family, &neighbor->in_addr),
342 link->hw_addr.length);
343 return 0;
344 }
345
5d098f5d
YW
346 r = neighbor_dup(neighbor, &tmp);
347 if (r < 0)
348 return r;
193c4af9 349
5d098f5d
YW
350 if (neighbor_get(link, neighbor, &existing) >= 0)
351 /* Copy state for logging below. */
352 tmp->state = existing->state;
193c4af9 353
5d098f5d 354 log_neighbor_debug(tmp, "Requesting", link);
09d09207 355 r = link_queue_request_safe(link, REQUEST_TYPE_NEIGHBOR,
5d098f5d 356 tmp,
2a75f23b 357 neighbor_unref,
09d09207
YW
358 neighbor_hash_func,
359 neighbor_compare_func,
360 neighbor_process_request,
361 &link->static_neighbor_messages,
362 static_neighbor_configure_handler,
363 NULL);
193c4af9
YW
364 if (r <= 0)
365 return r;
366
5d098f5d
YW
367 neighbor_enter_requesting(tmp);
368 if (existing)
369 neighbor_enter_requesting(existing);
370
371 TAKE_PTR(tmp);
193c4af9 372 return 1;
40ca350e
YW
373}
374
375int link_request_static_neighbors(Link *link) {
58f1fe9a
YW
376 Neighbor *neighbor;
377 int r;
378
379 assert(link);
380 assert(link->network);
381 assert(link->state != _LINK_STATE_INVALID);
382
40ca350e 383 link->static_neighbors_configured = false;
58f1fe9a 384
aa9626ee 385 ORDERED_HASHMAP_FOREACH(neighbor, link->network->neighbors_by_section) {
80d62d4f 386 r = link_request_neighbor(link, neighbor);
58f1fe9a 387 if (r < 0)
40ca350e 388 return log_link_warning_errno(link, r, "Could not request neighbor: %m");
58f1fe9a
YW
389 }
390
40ca350e
YW
391 if (link->static_neighbor_messages == 0) {
392 link->static_neighbors_configured = true;
58f1fe9a
YW
393 link_check_ready(link);
394 } else {
40ca350e 395 log_link_debug(link, "Requesting neighbors");
58f1fe9a
YW
396 link_set_state(link, LINK_STATE_CONFIGURING);
397 }
398
399 return 0;
400}
401
84c86ae1 402static int neighbor_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, RemoveRequest *rreq) {
fceee7cc
YW
403 int r;
404
405 assert(m);
84c86ae1 406 assert(rreq);
fceee7cc 407
84c86ae1
YW
408 Link *link = ASSERT_PTR(rreq->link);
409 Neighbor *neighbor = ASSERT_PTR(rreq->userdata);
410
411 if (link->state == LINK_STATE_LINGER)
412 return 0;
fceee7cc
YW
413
414 r = sd_netlink_message_get_errno(m);
84c86ae1 415 if (r < 0) {
fceee7cc 416 /* Neighbor may not exist because it already got deleted, ignore that. */
84c86ae1
YW
417 log_link_message_full_errno(link, m,
418 (r == -ESRCH || !neighbor->link) ? LOG_DEBUG : LOG_WARNING,
419 r, "Could not remove neighbor");
420
421 if (neighbor->link) {
422 /* If the neighbor cannot be removed, then assume the neighbor is already removed. */
423 log_neighbor_debug(neighbor, "Forgetting", link);
424
425 Request *req;
426 if (neighbor_get_request(link, neighbor, &req) >= 0)
427 neighbor_enter_removed(req->userdata);
428
429 neighbor_detach(neighbor);
430 }
431 }
fceee7cc
YW
432
433 return 1;
434}
435
c902fa08 436int neighbor_remove(Neighbor *neighbor, Link *link) {
754252f9 437 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
fceee7cc
YW
438 int r;
439
440 assert(neighbor);
c902fa08
YW
441 assert(link);
442 assert(link->manager);
443 assert(link->manager->rtnl);
fceee7cc 444
fe0acbf7
YW
445 /* If the neighbor is remembered, then use the remembered object. */
446 (void) neighbor_get(link, neighbor, &neighbor);
447
2775e1c5
YW
448 log_neighbor_debug(neighbor, "Removing", link);
449
754252f9 450 r = sd_rtnl_message_new_neigh(link->manager->rtnl, &m, RTM_DELNEIGH,
9be0b3ab 451 link->ifindex, neighbor->family);
fceee7cc
YW
452 if (r < 0)
453 return log_link_error_errno(link, r, "Could not allocate RTM_DELNEIGH message: %m");
454
754252f9 455 r = netlink_message_append_in_addr_union(m, NDA_DST, neighbor->family, &neighbor->in_addr);
fceee7cc
YW
456 if (r < 0)
457 return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m");
458
84c86ae1 459 r = link_remove_request_add(link, neighbor, neighbor, link->manager->rtnl, m, neighbor_remove_handler);
fceee7cc 460 if (r < 0)
84c86ae1 461 return log_link_error_errno(link, r, "Could not queue rtnetlink message: %m");
fceee7cc 462
193c4af9 463 neighbor_enter_removing(neighbor);
fceee7cc
YW
464 return 0;
465}
466
193c4af9
YW
467int link_drop_foreign_neighbors(Link *link) {
468 Neighbor *neighbor;
1339b950 469 int r = 0;
59048336
YW
470
471 assert(link);
193c4af9 472 assert(link->network);
59048336 473
193c4af9
YW
474 /* First, mark all neighbors. */
475 SET_FOREACH(neighbor, link->neighbors) {
476 /* Do not remove neighbors we configured. */
477 if (neighbor->source != NETWORK_CONFIG_SOURCE_FOREIGN)
478 continue;
59048336 479
193c4af9
YW
480 /* Ignore neighbors not assigned yet or already removing. */
481 if (!neighbor_exists(neighbor))
482 continue;
59048336 483
193c4af9
YW
484 neighbor_mark(neighbor);
485 }
59048336 486
193c4af9 487 /* Next, unmark requested neighbors. They will be configured later. */
aa9626ee 488 ORDERED_HASHMAP_FOREACH(neighbor, link->network->neighbors_by_section) {
193c4af9 489 Neighbor *existing;
59048336 490
193c4af9
YW
491 if (neighbor_get(link, neighbor, &existing) >= 0)
492 neighbor_unmark(existing);
493 }
59048336 494
193c4af9
YW
495 SET_FOREACH(neighbor, link->neighbors) {
496 if (!neighbor_is_marked(neighbor))
497 continue;
59048336 498
c902fa08 499 RET_GATHER(r, neighbor_remove(neighbor, link));
193c4af9
YW
500 }
501
502 return r;
59048336
YW
503}
504
a0e99a37 505int link_drop_managed_neighbors(Link *link) {
59048336 506 Neighbor *neighbor;
1339b950 507 int r = 0;
59048336
YW
508
509 assert(link);
510
511 SET_FOREACH(neighbor, link->neighbors) {
a0e99a37
YW
512 /* Do not touch nexthops managed by kernel or other tools. */
513 if (neighbor->source == NETWORK_CONFIG_SOURCE_FOREIGN)
514 continue;
515
193c4af9
YW
516 /* Ignore neighbors not assigned yet or already removing. */
517 if (!neighbor_exists(neighbor))
518 continue;
519
c902fa08 520 RET_GATHER(r, neighbor_remove(neighbor, link));
59048336
YW
521 }
522
523 return r;
524}
525
b4564f4e
YW
526void link_foreignize_neighbors(Link *link) {
527 Neighbor *neighbor;
528
529 assert(link);
530
531 SET_FOREACH(neighbor, link->neighbors)
532 neighbor->source = NETWORK_CONFIG_SOURCE_FOREIGN;
533}
534
eab052d2 535int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
2a75f23b 536 _cleanup_(neighbor_unrefp) Neighbor *tmp = NULL;
eab052d2 537 Neighbor *neighbor = NULL;
5d098f5d 538 Request *req = NULL;
eab052d2 539 uint16_t type, state;
5d098f5d 540 bool is_new = false;
19f8cffc
YW
541 int ifindex, r;
542 Link *link;
eab052d2
YW
543
544 assert(rtnl);
545 assert(message);
546 assert(m);
547
548 if (sd_netlink_message_is_error(message)) {
549 r = sd_netlink_message_get_errno(message);
550 if (r < 0)
551 log_message_warning_errno(message, r, "rtnl: failed to receive neighbor message, ignoring");
552
553 return 0;
554 }
555
556 r = sd_netlink_message_get_type(message, &type);
557 if (r < 0) {
558 log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
559 return 0;
560 } else if (!IN_SET(type, RTM_NEWNEIGH, RTM_DELNEIGH)) {
561 log_warning("rtnl: received unexpected message type %u when processing neighbor, ignoring.", type);
562 return 0;
563 }
564
565 r = sd_rtnl_message_neigh_get_state(message, &state);
566 if (r < 0) {
19f8cffc 567 log_warning_errno(r, "rtnl: received neighbor message with invalid state, ignoring: %m");
eab052d2 568 return 0;
18e530b0
YW
569 } else if (!FLAGS_SET(state, NUD_PERMANENT))
570 /* Currently, we are interested in only static neighbors. */
eab052d2 571 return 0;
eab052d2
YW
572
573 r = sd_rtnl_message_neigh_get_ifindex(message, &ifindex);
574 if (r < 0) {
575 log_warning_errno(r, "rtnl: could not get ifindex from message, ignoring: %m");
576 return 0;
577 } else if (ifindex <= 0) {
578 log_warning("rtnl: received neighbor message with invalid ifindex %d, ignoring.", ifindex);
579 return 0;
580 }
581
6eab614d 582 r = link_get_by_index(m, ifindex, &link);
18e530b0 583 if (r < 0)
27a21339
YW
584 /* when enumerating we might be out of sync, but we will get the neighbor again. Also,
585 * kernel sends messages about neighbors after a link is removed. So, just ignore it. */
eab052d2 586 return 0;
eab052d2 587
2a75f23b
YW
588 r = neighbor_new(&tmp);
589 if (r < 0)
be26893c 590 return log_oom();
19f8cffc 591
5d098f5d 592 /* First, retrieve the fundamental information about the neighbor. */
19f8cffc 593 r = sd_rtnl_message_neigh_get_family(message, &tmp->family);
eab052d2
YW
594 if (r < 0) {
595 log_link_warning(link, "rtnl: received neighbor message without family, ignoring.");
596 return 0;
18e530b0
YW
597 }
598 if (tmp->family == AF_BRIDGE) /* Currently, we do not support it. */
599 return 0;
600 if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
19f8cffc 601 log_link_debug(link, "rtnl: received neighbor message with invalid family '%i', ignoring.", tmp->family);
eab052d2
YW
602 return 0;
603 }
604
19f8cffc
YW
605 r = netlink_message_read_in_addr_union(message, NDA_DST, tmp->family, &tmp->in_addr);
606 if (r < 0) {
607 log_link_warning_errno(link, r, "rtnl: received neighbor message without valid address, ignoring: %m");
608 return 0;
eab052d2
YW
609 }
610
5d098f5d 611 /* Then, find the managed Neighbor and Request objects corresponding to the netlink notification. */
19f8cffc 612 (void) neighbor_get(link, tmp, &neighbor);
5d098f5d 613 (void) neighbor_get_request(link, tmp, &req);
eab052d2 614
5d098f5d 615 if (type == RTM_DELNEIGH) {
193c4af9
YW
616 if (neighbor) {
617 neighbor_enter_removed(neighbor);
5d098f5d 618 log_neighbor_debug(neighbor, "Forgetting removed", link);
2a75f23b 619 neighbor_detach(neighbor);
193c4af9
YW
620 } else
621 log_neighbor_debug(tmp, "Kernel removed unknown", link);
eab052d2 622
5d098f5d
YW
623 if (req)
624 neighbor_enter_removed(req->userdata);
eab052d2 625
5d098f5d
YW
626 return 0;
627 }
628
629 /* If we did not know the neighbor, then save it. */
630 if (!neighbor) {
2a75f23b 631 r = neighbor_attach(link, tmp);
5d098f5d 632 if (r < 0) {
e924dc59 633 log_link_warning_errno(link, r, "Failed to save received neighbor, ignoring: %m");
5d098f5d
YW
634 return 0;
635 }
2a75f23b 636 neighbor = tmp;
5d098f5d 637 is_new = true;
eab052d2
YW
638 }
639
5d098f5d
YW
640 /* Also update information that cannot be obtained through netlink notification. */
641 if (req && req->waiting_reply) {
642 Neighbor *n = ASSERT_PTR(req->userdata);
643
644 neighbor->source = n->source;
645 }
646
647 /* Then, update miscellaneous info. */
648 r = netlink_message_read_hw_addr(message, NDA_LLADDR, &neighbor->ll_addr);
649 if (r < 0 && r != -ENODATA)
650 log_link_debug_errno(link, r, "rtnl: received neighbor message without valid link layer address, ignoring: %m");
651
652 neighbor_enter_configured(neighbor);
653 if (req)
654 neighbor_enter_configured(req->userdata);
655
656 log_neighbor_debug(neighbor, is_new ? "Remembering" : "Received remembered", link);
eab052d2
YW
657 return 1;
658}
659
78ada14f 660static int neighbor_section_verify(Neighbor *neighbor) {
044d4b40
YW
661 if (section_is_invalid(neighbor->section))
662 return -EINVAL;
663
664 if (neighbor->family == AF_UNSPEC)
665 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
666 "%s: Neighbor section without Address= configured. "
667 "Ignoring [Neighbor] section from line %u.",
668 neighbor->section->filename, neighbor->section->line);
669
4d4d7910
YW
670 if (neighbor->family == AF_INET6 && !socket_ipv6_is_supported())
671 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
672 "%s: Neighbor section with an IPv6 destination address configured, "
673 "but the kernel does not support IPv6. "
674 "Ignoring [Neighbor] section from line %u.",
675 neighbor->section->filename, neighbor->section->line);
676
17193d76 677 if (neighbor->ll_addr.length == 0)
044d4b40
YW
678 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
679 "%s: Neighbor section without LinkLayerAddress= configured. "
680 "Ignoring [Neighbor] section from line %u.",
681 neighbor->section->filename, neighbor->section->line);
682
683 return 0;
684}
685
aa9626ee
YW
686int network_drop_invalid_neighbors(Network *network) {
687 _cleanup_set_free_ Set *neighbors = NULL;
78ada14f 688 Neighbor *neighbor;
aa9626ee 689 int r;
78ada14f
YW
690
691 assert(network);
692
aa9626ee
YW
693 ORDERED_HASHMAP_FOREACH(neighbor, network->neighbors_by_section) {
694 Neighbor *dup;
695
696 if (neighbor_section_verify(neighbor) < 0) {
2a75f23b 697 /* Drop invalid [Neighbor] sections. Note that neighbor_detach() will drop the
aa9626ee 698 * neighbor from neighbors_by_section. */
2a75f23b 699 neighbor_detach(neighbor);
aa9626ee
YW
700 continue;
701 }
702
703 /* Always use the setting specified later. So, remove the previously assigned setting. */
704 dup = set_remove(neighbors, neighbor);
705 if (dup) {
706 log_warning("%s: Duplicated neighbor settings for %s is specified at line %u and %u, "
47ac844e 707 "dropping the neighbor setting specified at line %u.",
aa9626ee
YW
708 dup->section->filename,
709 IN_ADDR_TO_STRING(neighbor->family, &neighbor->in_addr),
710 neighbor->section->line,
711 dup->section->line, dup->section->line);
2a75f23b
YW
712 /* neighbor_detach() will drop the neighbor from neighbors_by_section. */
713 neighbor_detach(dup);
aa9626ee
YW
714 }
715
2a75f23b
YW
716 /* Use neighbor_hash_ops, instead of neighbor_hash_ops_detach. Otherwise, the Neighbor objects
717 * will be detached. */
aa9626ee
YW
718 r = set_ensure_put(&neighbors, &neighbor_hash_ops, neighbor);
719 if (r < 0)
720 return log_oom();
721 assert(r > 0);
722 }
723
724 return 0;
78ada14f
YW
725}
726
727
b956364d
YW
728int config_parse_neighbor_address(
729 const char *unit,
730 const char *filename,
731 unsigned line,
732 const char *section,
733 unsigned section_line,
734 const char *lvalue,
735 int ltype,
736 const char *rvalue,
737 void *data,
738 void *userdata) {
e4a71bf3 739
2a75f23b 740 _cleanup_(neighbor_unref_or_set_invalidp) Neighbor *n = NULL;
99534007 741 Network *network = ASSERT_PTR(userdata);
e4a71bf3
WKI
742 int r;
743
744 assert(filename);
745 assert(section);
746 assert(lvalue);
747 assert(rvalue);
e4a71bf3
WKI
748
749 r = neighbor_new_static(network, filename, section_line, &n);
750 if (r < 0)
d96edb2c 751 return log_oom();
e4a71bf3 752
13b7b8bd
YW
753 if (isempty(rvalue)) {
754 n->family = AF_UNSPEC;
755 n->in_addr = IN_ADDR_NULL;
756 TAKE_PTR(n);
757 return 0;
758 }
759
e4a71bf3
WKI
760 r = in_addr_from_string_auto(rvalue, &n->family, &n->in_addr);
761 if (r < 0) {
d96edb2c
YW
762 log_syntax(unit, LOG_WARNING, filename, line, r,
763 "Neighbor Address is invalid, ignoring assignment: %s", rvalue);
e4a71bf3
WKI
764 return 0;
765 }
766
767 TAKE_PTR(n);
e4a71bf3
WKI
768 return 0;
769}
770
b956364d
YW
771int config_parse_neighbor_lladdr(
772 const char *unit,
773 const char *filename,
774 unsigned line,
775 const char *section,
776 unsigned section_line,
777 const char *lvalue,
778 int ltype,
779 const char *rvalue,
780 void *data,
781 void *userdata) {
e4a71bf3 782
2a75f23b 783 _cleanup_(neighbor_unref_or_set_invalidp) Neighbor *n = NULL;
99534007 784 Network *network = ASSERT_PTR(userdata);
b956364d
YW
785 int r;
786
787 assert(filename);
788 assert(section);
789 assert(lvalue);
790 assert(rvalue);
b956364d
YW
791
792 r = neighbor_new_static(network, filename, section_line, &n);
793 if (r < 0)
d96edb2c 794 return log_oom();
b956364d 795
13b7b8bd
YW
796 if (isempty(rvalue)) {
797 n->ll_addr = HW_ADDR_NULL;
798 TAKE_PTR(n);
799 return 0;
800 }
801
17193d76 802 r = parse_hw_addr(rvalue, &n->ll_addr);
e4a71bf3 803 if (r < 0) {
d96edb2c 804 log_syntax(unit, LOG_WARNING, filename, line, r,
17193d76
YW
805 "Neighbor %s= is invalid, ignoring assignment: %s",
806 lvalue, rvalue);
e4a71bf3
WKI
807 return 0;
808 }
809
e4a71bf3 810 TAKE_PTR(n);
e4a71bf3
WKI
811 return 0;
812}