1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "alloc-util.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"
13 static Neighbor
* neighbor_detach_impl(Neighbor
*neighbor
) {
15 assert(!neighbor
->link
|| !neighbor
->network
);
17 if (neighbor
->network
) {
18 assert(neighbor
->section
);
19 ordered_hashmap_remove(neighbor
->network
->neighbors_by_section
, neighbor
->section
);
20 neighbor
->network
= NULL
;
25 set_remove(neighbor
->link
->neighbors
, neighbor
);
26 neighbor
->link
= NULL
;
33 static void neighbor_detach(Neighbor
*neighbor
) {
34 neighbor_unref(neighbor_detach_impl(neighbor
));
37 static Neighbor
* neighbor_free(Neighbor
*neighbor
) {
41 neighbor_detach_impl(neighbor
);
43 config_section_free(neighbor
->section
);
44 return mfree(neighbor
);
47 DEFINE_TRIVIAL_REF_UNREF_FUNC(Neighbor
, neighbor
, neighbor_free
);
48 DEFINE_SECTION_CLEANUP_FUNCTIONS(Neighbor
, neighbor_unref
);
50 static void neighbor_hash_func(const Neighbor
*neighbor
, struct siphash
*state
);
51 static int neighbor_compare_func(const Neighbor
*a
, const Neighbor
*b
);
53 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
54 neighbor_hash_ops_detach
,
57 neighbor_compare_func
,
60 DEFINE_PRIVATE_HASH_OPS(
64 neighbor_compare_func
);
66 DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
67 neighbor_section_hash_ops
,
69 config_section_hash_func
,
70 config_section_compare_func
,
74 static int neighbor_new(Neighbor
**ret
) {
79 neighbor
= new(Neighbor
, 1);
83 *neighbor
= (Neighbor
) {
87 *ret
= TAKE_PTR(neighbor
);
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
;
99 assert(section_line
> 0);
101 r
= config_section_new(filename
, section_line
, &n
);
105 neighbor
= ordered_hashmap_get(network
->neighbors_by_section
, n
);
107 *ret
= TAKE_PTR(neighbor
);
111 r
= neighbor_new(&neighbor
);
115 neighbor
->network
= network
;
116 neighbor
->section
= TAKE_PTR(n
);
117 neighbor
->source
= NETWORK_CONFIG_SOURCE_STATIC
;
119 r
= ordered_hashmap_ensure_put(&network
->neighbors_by_section
, &neighbor_section_hash_ops
, neighbor
->section
, neighbor
);
123 *ret
= TAKE_PTR(neighbor
);
127 static int neighbor_dup(const Neighbor
*neighbor
, Neighbor
**ret
) {
128 _cleanup_(neighbor_unrefp
) Neighbor
*dest
= NULL
;
133 dest
= newdup(Neighbor
, neighbor
, 1);
137 /* Clear the reference counter and all pointers */
140 dest
->network
= NULL
;
141 dest
->section
= NULL
;
143 *ret
= TAKE_PTR(dest
);
147 static void neighbor_hash_func(const Neighbor
*neighbor
, struct siphash
*state
) {
150 siphash24_compress_typesafe(neighbor
->family
, state
);
152 if (!IN_SET(neighbor
->family
, AF_INET
, AF_INET6
))
153 /* treat any other address family as AF_UNSPEC */
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
);
161 static int neighbor_compare_func(const Neighbor
*a
, const Neighbor
*b
) {
164 r
= CMP(a
->family
, b
->family
);
168 if (!IN_SET(a
->family
, AF_INET
, AF_INET6
))
169 /* treat any other address family as AF_UNSPEC */
172 return memcmp(&a
->in_addr
, &b
->in_addr
, FAMILY_ADDRESS_SIZE(a
->family
));
175 static int neighbor_get_request(Link
*link
, const Neighbor
*neighbor
, Request
**ret
) {
179 assert(link
->manager
);
182 req
= ordered_set_get(
183 link
->manager
->request_queue
,
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
,
199 int neighbor_get(Link
*link
, const Neighbor
*in
, Neighbor
**ret
) {
205 existing
= set_get(link
->neighbors
, in
);
214 static int neighbor_attach(Link
*link
, Neighbor
*neighbor
) {
219 assert(!neighbor
->link
);
221 r
= set_ensure_put(&link
->neighbors
, &neighbor_hash_ops_detach
, neighbor
);
227 neighbor
->link
= link
;
228 neighbor_ref(neighbor
);
232 static void log_neighbor_debug(const Neighbor
*neighbor
, const char *str
, const Link
*link
) {
233 _cleanup_free_
char *state
= NULL
;
241 (void) network_config_state_to_string_alloc(neighbor
->state
, &state
);
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
));
250 static int neighbor_configure(Neighbor
*neighbor
, Link
*link
, Request
*req
) {
251 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
256 assert(link
->ifindex
> 0);
257 assert(link
->manager
);
258 assert(link
->manager
->rtnl
);
261 log_neighbor_debug(neighbor
, "Configuring", link
);
263 r
= sd_rtnl_message_new_neigh(link
->manager
->rtnl
, &m
, RTM_NEWNEIGH
,
264 link
->ifindex
, neighbor
->family
);
268 r
= sd_rtnl_message_neigh_set_state(m
, NUD_PERMANENT
);
272 r
= netlink_message_append_hw_addr(m
, NDA_LLADDR
, &neighbor
->ll_addr
);
276 r
= netlink_message_append_in_addr_union(m
, NDA_DST
, neighbor
->family
, &neighbor
->in_addr
);
280 return request_call_netlink_async(link
->manager
->rtnl
, m
, req
);
283 static int neighbor_process_request(Request
*req
, Link
*link
, Neighbor
*neighbor
) {
291 if (!link_is_ready_to_configure(link
, false))
294 r
= neighbor_configure(neighbor
, link
, req
);
296 return log_link_warning_errno(link
, r
, "Failed to configure neighbor: %m");
298 neighbor_enter_configuring(neighbor
);
299 if (neighbor_get(link
, neighbor
, &existing
) >= 0)
300 neighbor_enter_configuring(existing
);
305 static int static_neighbor_configure_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Neighbor
*neighbor
) {
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
);
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
);
327 static int link_request_neighbor(Link
*link
, const Neighbor
*neighbor
) {
328 _cleanup_(neighbor_unrefp
) Neighbor
*tmp
= NULL
;
329 Neighbor
*existing
= NULL
;
334 assert(neighbor
->source
!= NETWORK_CONFIG_SOURCE_FOREIGN
);
336 if (neighbor
->ll_addr
.length
!= link
->hw_addr
.length
) {
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
);
346 r
= neighbor_dup(neighbor
, &tmp
);
350 if (neighbor_get(link
, neighbor
, &existing
) >= 0)
351 /* Copy state for logging below. */
352 tmp
->state
= existing
->state
;
354 log_neighbor_debug(tmp
, "Requesting", link
);
355 r
= link_queue_request_safe(link
, REQUEST_TYPE_NEIGHBOR
,
359 neighbor_compare_func
,
360 neighbor_process_request
,
361 &link
->static_neighbor_messages
,
362 static_neighbor_configure_handler
,
367 neighbor_enter_requesting(tmp
);
369 neighbor_enter_requesting(existing
);
375 int link_request_static_neighbors(Link
*link
) {
380 assert(link
->network
);
381 assert(link
->state
!= _LINK_STATE_INVALID
);
383 link
->static_neighbors_configured
= false;
385 ORDERED_HASHMAP_FOREACH(neighbor
, link
->network
->neighbors_by_section
) {
386 r
= link_request_neighbor(link
, neighbor
);
388 return log_link_warning_errno(link
, r
, "Could not request neighbor: %m");
391 if (link
->static_neighbor_messages
== 0) {
392 link
->static_neighbors_configured
= true;
393 link_check_ready(link
);
395 log_link_debug(link
, "Requesting neighbors");
396 link_set_state(link
, LINK_STATE_CONFIGURING
);
402 static int neighbor_remove_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, RemoveRequest
*rreq
) {
408 Link
*link
= ASSERT_PTR(rreq
->link
);
409 Neighbor
*neighbor
= ASSERT_PTR(rreq
->userdata
);
411 if (link
->state
== LINK_STATE_LINGER
)
414 r
= sd_netlink_message_get_errno(m
);
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");
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
);
426 if (neighbor_get_request(link
, neighbor
, &req
) >= 0)
427 neighbor_enter_removed(req
->userdata
);
429 neighbor_detach(neighbor
);
436 int neighbor_remove(Neighbor
*neighbor
, Link
*link
) {
437 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
442 assert(link
->manager
);
443 assert(link
->manager
->rtnl
);
445 /* If the neighbor is remembered, then use the remembered object. */
446 (void) neighbor_get(link
, neighbor
, &neighbor
);
448 log_neighbor_debug(neighbor
, "Removing", link
);
450 r
= sd_rtnl_message_new_neigh(link
->manager
->rtnl
, &m
, RTM_DELNEIGH
,
451 link
->ifindex
, neighbor
->family
);
453 return log_link_error_errno(link
, r
, "Could not allocate RTM_DELNEIGH message: %m");
455 r
= netlink_message_append_in_addr_union(m
, NDA_DST
, neighbor
->family
, &neighbor
->in_addr
);
457 return log_link_error_errno(link
, r
, "Could not append NDA_DST attribute: %m");
459 r
= link_remove_request_add(link
, neighbor
, neighbor
, link
->manager
->rtnl
, m
, neighbor_remove_handler
);
461 return log_link_error_errno(link
, r
, "Could not queue rtnetlink message: %m");
463 neighbor_enter_removing(neighbor
);
467 int link_drop_foreign_neighbors(Link
*link
) {
472 assert(link
->network
);
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
)
480 /* Ignore neighbors not assigned yet or already removing. */
481 if (!neighbor_exists(neighbor
))
484 neighbor_mark(neighbor
);
487 /* Next, unmark requested neighbors. They will be configured later. */
488 ORDERED_HASHMAP_FOREACH(neighbor
, link
->network
->neighbors_by_section
) {
491 if (neighbor_get(link
, neighbor
, &existing
) >= 0)
492 neighbor_unmark(existing
);
495 SET_FOREACH(neighbor
, link
->neighbors
) {
496 if (!neighbor_is_marked(neighbor
))
499 RET_GATHER(r
, neighbor_remove(neighbor
, link
));
505 int link_drop_static_neighbors(Link
*link
) {
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
)
516 /* Ignore neighbors not assigned yet or already removing. */
517 if (!neighbor_exists(neighbor
))
520 RET_GATHER(r
, neighbor_remove(neighbor
, link
));
526 void link_foreignize_neighbors(Link
*link
) {
531 SET_FOREACH(neighbor
, link
->neighbors
)
532 neighbor
->source
= NETWORK_CONFIG_SOURCE_FOREIGN
;
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
;
539 uint16_t type
, state
;
548 if (sd_netlink_message_is_error(message
)) {
549 r
= sd_netlink_message_get_errno(message
);
551 log_message_warning_errno(message
, r
, "rtnl: failed to receive neighbor message, ignoring");
556 r
= sd_netlink_message_get_type(message
, &type
);
558 log_warning_errno(r
, "rtnl: could not get message type, ignoring: %m");
560 } else if (!IN_SET(type
, RTM_NEWNEIGH
, RTM_DELNEIGH
)) {
561 log_warning("rtnl: received unexpected message type %u when processing neighbor, ignoring.", type
);
565 r
= sd_rtnl_message_neigh_get_state(message
, &state
);
567 log_warning_errno(r
, "rtnl: received neighbor message with invalid state, ignoring: %m");
569 } else if (!FLAGS_SET(state
, NUD_PERMANENT
))
570 /* Currently, we are interested in only static neighbors. */
573 r
= sd_rtnl_message_neigh_get_ifindex(message
, &ifindex
);
575 log_warning_errno(r
, "rtnl: could not get ifindex from message, ignoring: %m");
577 } else if (ifindex
<= 0) {
578 log_warning("rtnl: received neighbor message with invalid ifindex %d, ignoring.", ifindex
);
582 r
= link_get_by_index(m
, ifindex
, &link
);
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. */
588 r
= neighbor_new(&tmp
);
592 /* First, retrieve the fundamental information about the neighbor. */
593 r
= sd_rtnl_message_neigh_get_family(message
, &tmp
->family
);
595 log_link_warning(link
, "rtnl: received neighbor message without family, ignoring.");
598 if (tmp
->family
== AF_BRIDGE
) /* Currently, we do not support it. */
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
);
605 r
= netlink_message_read_in_addr_union(message
, NDA_DST
, tmp
->family
, &tmp
->in_addr
);
607 log_link_warning_errno(link
, r
, "rtnl: received neighbor message without valid address, ignoring: %m");
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
);
615 if (type
== RTM_DELNEIGH
) {
617 neighbor_enter_removed(neighbor
);
618 log_neighbor_debug(neighbor
, "Forgetting removed", link
);
619 neighbor_detach(neighbor
);
621 log_neighbor_debug(tmp
, "Kernel removed unknown", link
);
624 neighbor_enter_removed(req
->userdata
);
629 /* If we did not know the neighbor, then save it. */
631 r
= neighbor_attach(link
, tmp
);
633 log_link_warning_errno(link
, r
, "Failed to save received neighbor, ignoring: %m");
640 /* Also update information that cannot be obtained through netlink notification. */
641 if (req
&& req
->waiting_reply
) {
642 Neighbor
*n
= ASSERT_PTR(req
->userdata
);
644 neighbor
->source
= n
->source
;
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");
652 neighbor_enter_configured(neighbor
);
654 neighbor_enter_configured(req
->userdata
);
656 log_neighbor_debug(neighbor
, is_new
? "Remembering" : "Received remembered", link
);
660 static int neighbor_section_verify(Neighbor
*neighbor
) {
661 if (section_is_invalid(neighbor
->section
))
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
);
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
);
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
);
686 int network_drop_invalid_neighbors(Network
*network
) {
687 _cleanup_set_free_ Set
*neighbors
= NULL
;
693 ORDERED_HASHMAP_FOREACH(neighbor
, network
->neighbors_by_section
) {
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
);
703 /* Always use the setting specified later. So, remove the previously assigned setting. */
704 dup
= set_remove(neighbors
, neighbor
);
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
);
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
);
728 int config_parse_neighbor_address(
730 const char *filename
,
733 unsigned section_line
,
740 _cleanup_(neighbor_unref_or_set_invalidp
) Neighbor
*n
= NULL
;
741 Network
*network
= ASSERT_PTR(userdata
);
749 r
= neighbor_new_static(network
, filename
, section_line
, &n
);
753 if (isempty(rvalue
)) {
754 n
->family
= AF_UNSPEC
;
755 n
->in_addr
= IN_ADDR_NULL
;
760 r
= in_addr_from_string_auto(rvalue
, &n
->family
, &n
->in_addr
);
762 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
763 "Neighbor Address is invalid, ignoring assignment: %s", rvalue
);
771 int config_parse_neighbor_lladdr(
773 const char *filename
,
776 unsigned section_line
,
783 _cleanup_(neighbor_unref_or_set_invalidp
) Neighbor
*n
= NULL
;
784 Network
*network
= ASSERT_PTR(userdata
);
792 r
= neighbor_new_static(network
, filename
, section_line
, &n
);
796 if (isempty(rvalue
)) {
797 n
->ll_addr
= HW_ADDR_NULL
;
802 r
= parse_hw_addr(rvalue
, &n
->ll_addr
);
804 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
805 "Neighbor %s= is invalid, ignoring assignment: %s",