]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-neighbor.c
mkosi: Update centos submodule to latest
[thirdparty/systemd.git] / src / network / networkd-neighbor.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "alloc-util.h"
4 #include "hashmap.h"
5 #include "netlink-util.h"
6 #include "networkd-link.h"
7 #include "networkd-manager.h"
8 #include "networkd-neighbor.h"
9 #include "networkd-network.h"
10 #include "networkd-queue.h"
11 #include "set.h"
12
13 static Neighbor* neighbor_detach_impl(Neighbor *neighbor) {
14 assert(neighbor);
15 assert(!neighbor->link || !neighbor->network);
16
17 if (neighbor->network) {
18 assert(neighbor->section);
19 ordered_hashmap_remove(neighbor->network->neighbors_by_section, neighbor->section);
20 neighbor->network = NULL;
21 return neighbor;
22 }
23
24 if (neighbor->link) {
25 set_remove(neighbor->link->neighbors, neighbor);
26 neighbor->link = NULL;
27 return neighbor;
28 }
29
30 return NULL;
31 }
32
33 static void neighbor_detach(Neighbor *neighbor) {
34 neighbor_unref(neighbor_detach_impl(neighbor));
35 }
36
37 static Neighbor* neighbor_free(Neighbor *neighbor) {
38 if (!neighbor)
39 return NULL;
40
41 neighbor_detach_impl(neighbor);
42
43 config_section_free(neighbor->section);
44 return mfree(neighbor);
45 }
46
47 DEFINE_TRIVIAL_REF_UNREF_FUNC(Neighbor, neighbor, neighbor_free);
48 DEFINE_SECTION_CLEANUP_FUNCTIONS(Neighbor, neighbor_unref);
49
50 static void neighbor_hash_func(const Neighbor *neighbor, struct siphash *state);
51 static int neighbor_compare_func(const Neighbor *a, const Neighbor *b);
52
53 DEFINE_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
60 DEFINE_PRIVATE_HASH_OPS(
61 neighbor_hash_ops,
62 Neighbor,
63 neighbor_hash_func,
64 neighbor_compare_func);
65
66 DEFINE_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
74 static 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 }
90
91 static int neighbor_new_static(Network *network, const char *filename, unsigned section_line, Neighbor **ret) {
92 _cleanup_(config_section_freep) ConfigSection *n = NULL;
93 _cleanup_(neighbor_unrefp) Neighbor *neighbor = NULL;
94 int r;
95
96 assert(network);
97 assert(ret);
98 assert(filename);
99 assert(section_line > 0);
100
101 r = config_section_new(filename, section_line, &n);
102 if (r < 0)
103 return r;
104
105 neighbor = ordered_hashmap_get(network->neighbors_by_section, n);
106 if (neighbor) {
107 *ret = TAKE_PTR(neighbor);
108 return 0;
109 }
110
111 r = neighbor_new(&neighbor);
112 if (r < 0)
113 return r;
114
115 neighbor->network = network;
116 neighbor->section = TAKE_PTR(n);
117 neighbor->source = NETWORK_CONFIG_SOURCE_STATIC;
118
119 r = ordered_hashmap_ensure_put(&network->neighbors_by_section, &neighbor_section_hash_ops, neighbor->section, neighbor);
120 if (r < 0)
121 return r;
122
123 *ret = TAKE_PTR(neighbor);
124 return 0;
125 }
126
127 static int neighbor_dup(const Neighbor *neighbor, Neighbor **ret) {
128 _cleanup_(neighbor_unrefp) Neighbor *dest = NULL;
129
130 assert(neighbor);
131 assert(ret);
132
133 dest = newdup(Neighbor, neighbor, 1);
134 if (!dest)
135 return -ENOMEM;
136
137 /* Clear the reference counter and all pointers */
138 dest->n_ref = 1;
139 dest->link = NULL;
140 dest->network = NULL;
141 dest->section = NULL;
142
143 *ret = TAKE_PTR(dest);
144 return 0;
145 }
146
147 static void neighbor_hash_func(const Neighbor *neighbor, struct siphash *state) {
148 assert(neighbor);
149
150 siphash24_compress_typesafe(neighbor->family, state);
151
152 if (!IN_SET(neighbor->family, AF_INET, AF_INET6))
153 /* treat any other address family as AF_UNSPEC */
154 return;
155
156 /* Equality of neighbors are given by the destination address.
157 * See neigh_lookup() in the kernel. */
158 in_addr_hash_func(&neighbor->in_addr, neighbor->family, state);
159 }
160
161 static int neighbor_compare_func(const Neighbor *a, const Neighbor *b) {
162 int r;
163
164 r = CMP(a->family, b->family);
165 if (r != 0)
166 return r;
167
168 if (!IN_SET(a->family, AF_INET, AF_INET6))
169 /* treat any other address family as AF_UNSPEC */
170 return 0;
171
172 return memcmp(&a->in_addr, &b->in_addr, FAMILY_ADDRESS_SIZE(a->family));
173 }
174
175 static 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
199 int neighbor_get(Link *link, const Neighbor *in, Neighbor **ret) {
200 Neighbor *existing;
201
202 assert(link);
203 assert(in);
204
205 existing = set_get(link->neighbors, in);
206 if (!existing)
207 return -ENOENT;
208
209 if (ret)
210 *ret = existing;
211 return 0;
212 }
213
214 static int neighbor_attach(Link *link, Neighbor *neighbor) {
215 int r;
216
217 assert(link);
218 assert(neighbor);
219 assert(!neighbor->link);
220
221 r = set_ensure_put(&link->neighbors, &neighbor_hash_ops_detach, neighbor);
222 if (r < 0)
223 return r;
224 if (r == 0)
225 return -EEXIST;
226
227 neighbor->link = link;
228 neighbor_ref(neighbor);
229 return 0;
230 }
231
232 static void log_neighbor_debug(const Neighbor *neighbor, const char *str, const Link *link) {
233 _cleanup_free_ char *state = NULL;
234
235 assert(neighbor);
236 assert(str);
237
238 if (!DEBUG_LOGGING)
239 return;
240
241 (void) network_config_state_to_string_alloc(neighbor->state, &state);
242
243 log_link_debug(link,
244 "%s %s neighbor (%s): lladdr: %s, dst: %s",
245 str, strna(network_config_source_to_string(neighbor->source)), strna(state),
246 HW_ADDR_TO_STR(&neighbor->ll_addr),
247 IN_ADDR_TO_STRING(neighbor->family, &neighbor->in_addr));
248 }
249
250 static int neighbor_configure(Neighbor *neighbor, Link *link, Request *req) {
251 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
252 int r;
253
254 assert(neighbor);
255 assert(link);
256 assert(link->ifindex > 0);
257 assert(link->manager);
258 assert(link->manager->rtnl);
259 assert(req);
260
261 log_neighbor_debug(neighbor, "Configuring", link);
262
263 r = sd_rtnl_message_new_neigh(link->manager->rtnl, &m, RTM_NEWNEIGH,
264 link->ifindex, neighbor->family);
265 if (r < 0)
266 return r;
267
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);
277 if (r < 0)
278 return r;
279
280 return request_call_netlink_async(link->manager->rtnl, m, req);
281 }
282
283 static int neighbor_process_request(Request *req, Link *link, Neighbor *neighbor) {
284 Neighbor *existing;
285 int r;
286
287 assert(req);
288 assert(link);
289 assert(neighbor);
290
291 if (!link_is_ready_to_configure(link, false))
292 return 0;
293
294 r = neighbor_configure(neighbor, link, req);
295 if (r < 0)
296 return log_link_warning_errno(link, r, "Failed to configure neighbor: %m");
297
298 neighbor_enter_configuring(neighbor);
299 if (neighbor_get(link, neighbor, &existing) >= 0)
300 neighbor_enter_configuring(existing);
301
302 return 1;
303 }
304
305 static int static_neighbor_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Neighbor *neighbor) {
306 int r;
307
308 assert(m);
309 assert(link);
310
311 r = sd_netlink_message_get_errno(m);
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 }
317
318 if (link->static_neighbor_messages == 0) {
319 log_link_debug(link, "Neighbors set");
320 link->static_neighbors_configured = true;
321 link_check_ready(link);
322 }
323
324 return 1;
325 }
326
327 static int link_request_neighbor(Link *link, const Neighbor *neighbor) {
328 _cleanup_(neighbor_unrefp) Neighbor *tmp = NULL;
329 Neighbor *existing = NULL;
330 int r;
331
332 assert(link);
333 assert(neighbor);
334 assert(neighbor->source != NETWORK_CONFIG_SOURCE_FOREIGN);
335
336 if (neighbor->ll_addr.length != link->hw_addr.length) {
337 log_link_debug(link,
338 "The link layer address length (%zu) for neighbor %s does not match with "
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
346 r = neighbor_dup(neighbor, &tmp);
347 if (r < 0)
348 return r;
349
350 if (neighbor_get(link, neighbor, &existing) >= 0)
351 /* Copy state for logging below. */
352 tmp->state = existing->state;
353
354 log_neighbor_debug(tmp, "Requesting", link);
355 r = link_queue_request_safe(link, REQUEST_TYPE_NEIGHBOR,
356 tmp,
357 neighbor_unref,
358 neighbor_hash_func,
359 neighbor_compare_func,
360 neighbor_process_request,
361 &link->static_neighbor_messages,
362 static_neighbor_configure_handler,
363 NULL);
364 if (r <= 0)
365 return r;
366
367 neighbor_enter_requesting(tmp);
368 if (existing)
369 neighbor_enter_requesting(existing);
370
371 TAKE_PTR(tmp);
372 return 1;
373 }
374
375 int link_request_static_neighbors(Link *link) {
376 Neighbor *neighbor;
377 int r;
378
379 assert(link);
380 assert(link->network);
381 assert(link->state != _LINK_STATE_INVALID);
382
383 link->static_neighbors_configured = false;
384
385 ORDERED_HASHMAP_FOREACH(neighbor, link->network->neighbors_by_section) {
386 r = link_request_neighbor(link, neighbor);
387 if (r < 0)
388 return log_link_warning_errno(link, r, "Could not request neighbor: %m");
389 }
390
391 if (link->static_neighbor_messages == 0) {
392 link->static_neighbors_configured = true;
393 link_check_ready(link);
394 } else {
395 log_link_debug(link, "Requesting neighbors");
396 link_set_state(link, LINK_STATE_CONFIGURING);
397 }
398
399 return 0;
400 }
401
402 static int neighbor_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, RemoveRequest *rreq) {
403 int r;
404
405 assert(m);
406 assert(rreq);
407
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;
413
414 r = sd_netlink_message_get_errno(m);
415 if (r < 0) {
416 /* Neighbor may not exist because it already got deleted, ignore that. */
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 }
432
433 return 1;
434 }
435
436 int neighbor_remove(Neighbor *neighbor, Link *link) {
437 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
438 int r;
439
440 assert(neighbor);
441 assert(link);
442 assert(link->manager);
443 assert(link->manager->rtnl);
444
445 /* If the neighbor is remembered, then use the remembered object. */
446 (void) neighbor_get(link, neighbor, &neighbor);
447
448 log_neighbor_debug(neighbor, "Removing", link);
449
450 r = sd_rtnl_message_new_neigh(link->manager->rtnl, &m, RTM_DELNEIGH,
451 link->ifindex, neighbor->family);
452 if (r < 0)
453 return log_link_error_errno(link, r, "Could not allocate RTM_DELNEIGH message: %m");
454
455 r = netlink_message_append_in_addr_union(m, NDA_DST, neighbor->family, &neighbor->in_addr);
456 if (r < 0)
457 return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m");
458
459 r = link_remove_request_add(link, neighbor, neighbor, link->manager->rtnl, m, neighbor_remove_handler);
460 if (r < 0)
461 return log_link_error_errno(link, r, "Could not queue rtnetlink message: %m");
462
463 neighbor_enter_removing(neighbor);
464 return 0;
465 }
466
467 int link_drop_foreign_neighbors(Link *link) {
468 Neighbor *neighbor;
469 int r = 0;
470
471 assert(link);
472 assert(link->network);
473
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;
479
480 /* Ignore neighbors not assigned yet or already removing. */
481 if (!neighbor_exists(neighbor))
482 continue;
483
484 neighbor_mark(neighbor);
485 }
486
487 /* Next, unmark requested neighbors. They will be configured later. */
488 ORDERED_HASHMAP_FOREACH(neighbor, link->network->neighbors_by_section) {
489 Neighbor *existing;
490
491 if (neighbor_get(link, neighbor, &existing) >= 0)
492 neighbor_unmark(existing);
493 }
494
495 SET_FOREACH(neighbor, link->neighbors) {
496 if (!neighbor_is_marked(neighbor))
497 continue;
498
499 RET_GATHER(r, neighbor_remove(neighbor, link));
500 }
501
502 return r;
503 }
504
505 int link_drop_static_neighbors(Link *link) {
506 Neighbor *neighbor;
507 int r = 0;
508
509 assert(link);
510
511 SET_FOREACH(neighbor, link->neighbors) {
512 /* Do not touch nexthops managed by kernel or other tools. */
513 if (neighbor->source != NETWORK_CONFIG_SOURCE_STATIC)
514 continue;
515
516 /* Ignore neighbors not assigned yet or already removing. */
517 if (!neighbor_exists(neighbor))
518 continue;
519
520 RET_GATHER(r, neighbor_remove(neighbor, link));
521 }
522
523 return r;
524 }
525
526 void 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
535 int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
536 _cleanup_(neighbor_unrefp) Neighbor *tmp = NULL;
537 Neighbor *neighbor = NULL;
538 Request *req = NULL;
539 uint16_t type, state;
540 bool is_new = false;
541 int ifindex, r;
542 Link *link;
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) {
567 log_warning_errno(r, "rtnl: received neighbor message with invalid state, ignoring: %m");
568 return 0;
569 } else if (!FLAGS_SET(state, NUD_PERMANENT))
570 /* Currently, we are interested in only static neighbors. */
571 return 0;
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
582 r = link_get_by_index(m, ifindex, &link);
583 if (r < 0)
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. */
586 return 0;
587
588 r = neighbor_new(&tmp);
589 if (r < 0)
590 return log_oom();
591
592 /* First, retrieve the fundamental information about the neighbor. */
593 r = sd_rtnl_message_neigh_get_family(message, &tmp->family);
594 if (r < 0) {
595 log_link_warning(link, "rtnl: received neighbor message without family, ignoring.");
596 return 0;
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)) {
601 log_link_debug(link, "rtnl: received neighbor message with invalid family '%i', ignoring.", tmp->family);
602 return 0;
603 }
604
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;
609 }
610
611 /* Then, find the managed Neighbor and Request objects corresponding to the netlink notification. */
612 (void) neighbor_get(link, tmp, &neighbor);
613 (void) neighbor_get_request(link, tmp, &req);
614
615 if (type == RTM_DELNEIGH) {
616 if (neighbor) {
617 neighbor_enter_removed(neighbor);
618 log_neighbor_debug(neighbor, "Forgetting removed", link);
619 neighbor_detach(neighbor);
620 } else
621 log_neighbor_debug(tmp, "Kernel removed unknown", link);
622
623 if (req)
624 neighbor_enter_removed(req->userdata);
625
626 return 0;
627 }
628
629 /* If we did not know the neighbor, then save it. */
630 if (!neighbor) {
631 r = neighbor_attach(link, tmp);
632 if (r < 0) {
633 log_link_warning_errno(link, r, "Failed to save received neighbor, ignoring: %m");
634 return 0;
635 }
636 neighbor = tmp;
637 is_new = true;
638 }
639
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);
657 return 1;
658 }
659
660 static int neighbor_section_verify(Neighbor *neighbor) {
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
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
677 if (neighbor->ll_addr.length == 0)
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
686 int network_drop_invalid_neighbors(Network *network) {
687 _cleanup_set_free_ Set *neighbors = NULL;
688 Neighbor *neighbor;
689 int r;
690
691 assert(network);
692
693 ORDERED_HASHMAP_FOREACH(neighbor, network->neighbors_by_section) {
694 Neighbor *dup;
695
696 if (neighbor_section_verify(neighbor) < 0) {
697 /* Drop invalid [Neighbor] sections. Note that neighbor_detach() will drop the
698 * neighbor from neighbors_by_section. */
699 neighbor_detach(neighbor);
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, "
707 "dropping the neighbor setting specified at line %u.",
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);
712 /* neighbor_detach() will drop the neighbor from neighbors_by_section. */
713 neighbor_detach(dup);
714 }
715
716 /* Use neighbor_hash_ops, instead of neighbor_hash_ops_detach. Otherwise, the Neighbor objects
717 * will be detached. */
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;
725 }
726
727
728 int 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) {
739
740 _cleanup_(neighbor_unref_or_set_invalidp) Neighbor *n = NULL;
741 Network *network = ASSERT_PTR(userdata);
742 int r;
743
744 assert(filename);
745 assert(section);
746 assert(lvalue);
747 assert(rvalue);
748
749 r = neighbor_new_static(network, filename, section_line, &n);
750 if (r < 0)
751 return log_oom();
752
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
760 r = in_addr_from_string_auto(rvalue, &n->family, &n->in_addr);
761 if (r < 0) {
762 log_syntax(unit, LOG_WARNING, filename, line, r,
763 "Neighbor Address is invalid, ignoring assignment: %s", rvalue);
764 return 0;
765 }
766
767 TAKE_PTR(n);
768 return 0;
769 }
770
771 int 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) {
782
783 _cleanup_(neighbor_unref_or_set_invalidp) Neighbor *n = NULL;
784 Network *network = ASSERT_PTR(userdata);
785 int r;
786
787 assert(filename);
788 assert(section);
789 assert(lvalue);
790 assert(rvalue);
791
792 r = neighbor_new_static(network, filename, section_line, &n);
793 if (r < 0)
794 return log_oom();
795
796 if (isempty(rvalue)) {
797 n->ll_addr = HW_ADDR_NULL;
798 TAKE_PTR(n);
799 return 0;
800 }
801
802 r = parse_hw_addr(rvalue, &n->ll_addr);
803 if (r < 0) {
804 log_syntax(unit, LOG_WARNING, filename, line, r,
805 "Neighbor %s= is invalid, ignoring assignment: %s",
806 lvalue, rvalue);
807 return 0;
808 }
809
810 TAKE_PTR(n);
811 return 0;
812 }