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"
12 Neighbor
*neighbor_free(Neighbor
*neighbor
) {
16 if (neighbor
->network
) {
17 assert(neighbor
->section
);
18 hashmap_remove(neighbor
->network
->neighbors_by_section
, neighbor
->section
);
21 network_config_section_free(neighbor
->section
);
24 set_remove(neighbor
->link
->neighbors
, neighbor
);
25 set_remove(neighbor
->link
->neighbors_foreign
, neighbor
);
28 return mfree(neighbor
);
31 DEFINE_NETWORK_SECTION_FUNCTIONS(Neighbor
, neighbor_free
);
33 static int neighbor_new_static(Network
*network
, const char *filename
, unsigned section_line
, Neighbor
**ret
) {
34 _cleanup_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
35 _cleanup_(neighbor_freep
) Neighbor
*neighbor
= NULL
;
41 assert(section_line
> 0);
43 r
= network_config_section_new(filename
, section_line
, &n
);
47 neighbor
= hashmap_get(network
->neighbors_by_section
, n
);
49 *ret
= TAKE_PTR(neighbor
);
53 neighbor
= new(Neighbor
, 1);
57 *neighbor
= (Neighbor
) {
60 .section
= TAKE_PTR(n
),
63 r
= hashmap_ensure_allocated(&network
->neighbors_by_section
, &network_config_hash_ops
);
67 r
= hashmap_put(network
->neighbors_by_section
, neighbor
->section
, neighbor
);
71 *ret
= TAKE_PTR(neighbor
);
75 static void neighbor_hash_func(const Neighbor
*neighbor
, struct siphash
*state
) {
78 siphash24_compress(&neighbor
->family
, sizeof(neighbor
->family
), state
);
79 siphash24_compress(&neighbor
->lladdr_size
, sizeof(neighbor
->lladdr_size
), state
);
81 switch (neighbor
->family
) {
84 /* Equality of neighbors are given by the pair (addr,lladdr) */
85 siphash24_compress(&neighbor
->in_addr
, FAMILY_ADDRESS_SIZE(neighbor
->family
), state
);
88 /* treat any other address family as AF_UNSPEC */
92 siphash24_compress(&neighbor
->lladdr
, neighbor
->lladdr_size
, state
);
95 static int neighbor_compare_func(const Neighbor
*a
, const Neighbor
*b
) {
98 r
= CMP(a
->family
, b
->family
);
102 r
= CMP(a
->lladdr_size
, b
->lladdr_size
);
109 r
= memcmp(&a
->in_addr
, &b
->in_addr
, FAMILY_ADDRESS_SIZE(a
->family
));
114 return memcmp(&a
->lladdr
, &b
->lladdr
, a
->lladdr_size
);
117 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(neighbor_hash_ops
, Neighbor
, neighbor_hash_func
, neighbor_compare_func
, neighbor_free
);
119 static int neighbor_get(Link
*link
, const Neighbor
*in
, Neighbor
**ret
) {
125 existing
= set_get(link
->neighbors
, in
);
132 existing
= set_get(link
->neighbors_foreign
, in
);
142 static int neighbor_add_internal(Link
*link
, Set
**neighbors
, const Neighbor
*in
, Neighbor
**ret
) {
143 _cleanup_(neighbor_freep
) Neighbor
*neighbor
= NULL
;
150 neighbor
= new(Neighbor
, 1);
154 *neighbor
= (Neighbor
) {
155 .family
= in
->family
,
156 .in_addr
= in
->in_addr
,
157 .lladdr
= in
->lladdr
,
158 .lladdr_size
= in
->lladdr_size
,
161 r
= set_ensure_put(neighbors
, &neighbor_hash_ops
, neighbor
);
167 neighbor
->link
= link
;
176 static int neighbor_add(Link
*link
, const Neighbor
*in
, Neighbor
**ret
) {
180 r
= neighbor_get(link
, in
, &neighbor
);
182 /* Neighbor doesn't exist, make a new one */
183 r
= neighbor_add_internal(link
, &link
->neighbors
, in
, &neighbor
);
187 /* Neighbor is foreign, claim it as recognized */
188 r
= set_ensure_put(&link
->neighbors
, &neighbor_hash_ops
, neighbor
);
192 set_remove(link
->neighbors_foreign
, neighbor
);
194 /* Neighbor already exists */
203 static int neighbor_add_foreign(Link
*link
, const Neighbor
*in
, Neighbor
**ret
) {
204 return neighbor_add_internal(link
, &link
->neighbors_foreign
, in
, ret
);
207 static bool neighbor_equal(const Neighbor
*n1
, const Neighbor
*n2
) {
214 return neighbor_compare_func(n1
, n2
) == 0;
217 static int neighbor_configure_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
222 assert(link
->neighbor_messages
> 0);
224 link
->neighbor_messages
--;
226 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
229 r
= sd_netlink_message_get_errno(m
);
230 if (r
< 0 && r
!= -EEXIST
)
231 /* Neighbor may not exist yet. So, do not enter failed state here. */
232 log_link_message_warning_errno(link
, m
, r
, "Could not set neighbor, ignoring");
234 if (link
->neighbor_messages
== 0) {
235 log_link_debug(link
, "Neighbors set");
236 link
->neighbors_configured
= true;
237 link_check_ready(link
);
243 static int neighbor_configure(Neighbor
*neighbor
, Link
*link
) {
244 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
249 assert(link
->ifindex
> 0);
250 assert(link
->manager
);
251 assert(link
->manager
->rtnl
);
253 r
= sd_rtnl_message_new_neigh(link
->manager
->rtnl
, &req
, RTM_NEWNEIGH
,
254 link
->ifindex
, neighbor
->family
);
256 return log_link_error_errno(link
, r
, "Could not allocate RTM_NEWNEIGH message: %m");
258 r
= sd_rtnl_message_neigh_set_state(req
, NUD_PERMANENT
);
260 return log_link_error_errno(link
, r
, "Could not set state: %m");
262 r
= sd_netlink_message_set_flags(req
, NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_CREATE
| NLM_F_REPLACE
);
264 return log_link_error_errno(link
, r
, "Could not set flags: %m");
266 r
= sd_netlink_message_append_data(req
, NDA_LLADDR
, &neighbor
->lladdr
, neighbor
->lladdr_size
);
268 return log_link_error_errno(link
, r
, "Could not append NDA_LLADDR attribute: %m");
270 r
= netlink_message_append_in_addr_union(req
, NDA_DST
, neighbor
->family
, &neighbor
->in_addr
);
272 return log_link_error_errno(link
, r
, "Could not append NDA_DST attribute: %m");
274 r
= netlink_call_async(link
->manager
->rtnl
, NULL
, req
, neighbor_configure_handler
,
275 link_netlink_destroy_callback
, link
);
277 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
279 link
->neighbor_messages
++;
282 r
= neighbor_add(link
, neighbor
, NULL
);
284 return log_link_error_errno(link
, r
, "Could not add neighbor: %m");
289 int link_set_neighbors(Link
*link
) {
294 assert(link
->network
);
295 assert(link
->state
!= _LINK_STATE_INVALID
);
297 link
->neighbors_configured
= false;
299 HASHMAP_FOREACH(neighbor
, link
->network
->neighbors_by_section
) {
300 r
= neighbor_configure(neighbor
, link
);
302 return log_link_warning_errno(link
, r
, "Could not set neighbor: %m");
305 if (link
->neighbor_messages
== 0) {
306 link
->neighbors_configured
= true;
307 link_check_ready(link
);
309 log_link_debug(link
, "Setting neighbors");
310 link_set_state(link
, LINK_STATE_CONFIGURING
);
316 static int neighbor_remove_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
322 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
325 r
= sd_netlink_message_get_errno(m
);
326 if (r
< 0 && r
!= -ESRCH
)
327 /* Neighbor may not exist because it already got deleted, ignore that. */
328 log_link_message_warning_errno(link
, m
, r
, "Could not remove neighbor");
333 static int neighbor_remove(Neighbor
*neighbor
, Link
*link
) {
334 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
339 assert(link
->ifindex
> 0);
340 assert(link
->manager
);
341 assert(link
->manager
->rtnl
);
343 r
= sd_rtnl_message_new_neigh(link
->manager
->rtnl
, &req
, RTM_DELNEIGH
,
344 link
->ifindex
, neighbor
->family
);
346 return log_link_error_errno(link
, r
, "Could not allocate RTM_DELNEIGH message: %m");
348 r
= netlink_message_append_in_addr_union(req
, NDA_DST
, neighbor
->family
, &neighbor
->in_addr
);
350 return log_link_error_errno(link
, r
, "Could not append NDA_DST attribute: %m");
352 r
= netlink_call_async(link
->manager
->rtnl
, NULL
, req
, neighbor_remove_handler
,
353 link_netlink_destroy_callback
, link
);
355 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
362 static bool link_is_neighbor_configured(Link
*link
, Neighbor
*neighbor
) {
363 Neighbor
*net_neighbor
;
371 HASHMAP_FOREACH(net_neighbor
, link
->network
->neighbors_by_section
)
372 if (neighbor_equal(net_neighbor
, neighbor
))
378 int link_drop_foreign_neighbors(Link
*link
) {
384 SET_FOREACH(neighbor
, link
->neighbors_foreign
)
385 if (link_is_neighbor_configured(link
, neighbor
)) {
386 r
= neighbor_add(link
, neighbor
, NULL
);
390 r
= neighbor_remove(neighbor
, link
);
398 int link_drop_neighbors(Link
*link
) {
404 SET_FOREACH(neighbor
, link
->neighbors
) {
405 k
= neighbor_remove(neighbor
, link
);
413 static int manager_rtnl_process_neighbor_lladdr(sd_netlink_message
*message
, union lladdr_union
*lladdr
, size_t *size
, char **str
) {
423 r
= sd_netlink_message_read(message
, NDA_LLADDR
, sizeof(lladdr
->ip
.in6
), &lladdr
->ip
.in6
);
425 *size
= sizeof(lladdr
->ip
.in6
);
426 if (in_addr_to_string(AF_INET6
, &lladdr
->ip
, str
) < 0)
427 log_warning_errno(r
, "Could not print lower address: %m");
431 r
= sd_netlink_message_read(message
, NDA_LLADDR
, sizeof(lladdr
->mac
), &lladdr
->mac
);
433 *size
= sizeof(lladdr
->mac
);
434 *str
= new(char, ETHER_ADDR_TO_STRING_MAX
);
439 ether_addr_to_string(&lladdr
->mac
, *str
);
443 r
= sd_netlink_message_read(message
, NDA_LLADDR
, sizeof(lladdr
->ip
.in
), &lladdr
->ip
.in
);
445 *size
= sizeof(lladdr
->ip
.in
);
446 if (in_addr_to_string(AF_INET
, &lladdr
->ip
, str
) < 0)
447 log_warning_errno(r
, "Could not print lower address: %m");
454 int manager_rtnl_process_neighbor(sd_netlink
*rtnl
, sd_netlink_message
*message
, Manager
*m
) {
455 _cleanup_(neighbor_freep
) Neighbor
*tmp
= NULL
;
456 _cleanup_free_
char *addr_str
= NULL
, *lladdr_str
= NULL
;
457 Neighbor
*neighbor
= NULL
;
458 uint16_t type
, state
;
466 if (sd_netlink_message_is_error(message
)) {
467 r
= sd_netlink_message_get_errno(message
);
469 log_message_warning_errno(message
, r
, "rtnl: failed to receive neighbor message, ignoring");
474 r
= sd_netlink_message_get_type(message
, &type
);
476 log_warning_errno(r
, "rtnl: could not get message type, ignoring: %m");
478 } else if (!IN_SET(type
, RTM_NEWNEIGH
, RTM_DELNEIGH
)) {
479 log_warning("rtnl: received unexpected message type %u when processing neighbor, ignoring.", type
);
483 r
= sd_rtnl_message_neigh_get_state(message
, &state
);
485 log_warning_errno(r
, "rtnl: received neighbor message with invalid state, ignoring: %m");
487 } else if (!FLAGS_SET(state
, NUD_PERMANENT
)) {
488 log_debug("rtnl: received non-static neighbor, ignoring.");
492 r
= sd_rtnl_message_neigh_get_ifindex(message
, &ifindex
);
494 log_warning_errno(r
, "rtnl: could not get ifindex from message, ignoring: %m");
496 } else if (ifindex
<= 0) {
497 log_warning("rtnl: received neighbor message with invalid ifindex %d, ignoring.", ifindex
);
501 r
= link_get(m
, ifindex
, &link
);
502 if (r
< 0 || !link
) {
503 /* when enumerating we might be out of sync, but we will get the neighbor again, so just
506 log_warning("rtnl: received neighbor for link '%d' we don't know about, ignoring.", ifindex
);
510 tmp
= new0(Neighbor
, 1);
512 r
= sd_rtnl_message_neigh_get_family(message
, &tmp
->family
);
514 log_link_warning(link
, "rtnl: received neighbor message without family, ignoring.");
516 } else if (!IN_SET(tmp
->family
, AF_INET
, AF_INET6
)) {
517 log_link_debug(link
, "rtnl: received neighbor message with invalid family '%i', ignoring.", tmp
->family
);
521 r
= netlink_message_read_in_addr_union(message
, NDA_DST
, tmp
->family
, &tmp
->in_addr
);
523 log_link_warning_errno(link
, r
, "rtnl: received neighbor message without valid address, ignoring: %m");
527 if (in_addr_to_string(tmp
->family
, &tmp
->in_addr
, &addr_str
) < 0)
528 log_link_warning_errno(link
, r
, "Could not print address: %m");
530 r
= manager_rtnl_process_neighbor_lladdr(message
, &tmp
->lladdr
, &tmp
->lladdr_size
, &lladdr_str
);
532 log_link_warning_errno(link
, r
, "rtnl: received neighbor message with invalid lladdr, ignoring: %m");
536 (void) neighbor_get(link
, tmp
, &neighbor
);
541 log_link_debug(link
, "Received remembered neighbor: %s->%s",
542 strnull(addr_str
), strnull(lladdr_str
));
544 /* A neighbor appeared that we did not request */
545 r
= neighbor_add_foreign(link
, tmp
, NULL
);
547 log_link_warning_errno(link
, r
, "Failed to remember foreign neighbor %s->%s, ignoring: %m",
548 strnull(addr_str
), strnull(lladdr_str
));
551 log_link_debug(link
, "Remembering foreign neighbor: %s->%s",
552 strnull(addr_str
), strnull(lladdr_str
));
559 log_link_debug(link
, "Forgetting neighbor: %s->%s",
560 strnull(addr_str
), strnull(lladdr_str
));
561 (void) neighbor_free(neighbor
);
563 log_link_debug(link
, "Kernel removed a neighbor we don't remember: %s->%s, ignoring.",
564 strnull(addr_str
), strnull(lladdr_str
));
569 assert_not_reached("Received invalid RTNL message type");
575 static int neighbor_section_verify(Neighbor
*neighbor
) {
576 if (section_is_invalid(neighbor
->section
))
579 if (neighbor
->family
== AF_UNSPEC
)
580 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
581 "%s: Neighbor section without Address= configured. "
582 "Ignoring [Neighbor] section from line %u.",
583 neighbor
->section
->filename
, neighbor
->section
->line
);
585 if (neighbor
->lladdr_size
== 0)
586 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
587 "%s: Neighbor section without LinkLayerAddress= configured. "
588 "Ignoring [Neighbor] section from line %u.",
589 neighbor
->section
->filename
, neighbor
->section
->line
);
594 void network_drop_invalid_neighbors(Network
*network
) {
599 HASHMAP_FOREACH(neighbor
, network
->neighbors_by_section
)
600 if (neighbor_section_verify(neighbor
) < 0)
601 neighbor_free(neighbor
);
605 int config_parse_neighbor_address(
607 const char *filename
,
610 unsigned section_line
,
617 Network
*network
= userdata
;
618 _cleanup_(neighbor_free_or_set_invalidp
) Neighbor
*n
= NULL
;
627 r
= neighbor_new_static(network
, filename
, section_line
, &n
);
631 r
= in_addr_from_string_auto(rvalue
, &n
->family
, &n
->in_addr
);
633 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
634 "Neighbor Address is invalid, ignoring assignment: %s", rvalue
);
643 int config_parse_neighbor_lladdr(
645 const char *filename
,
648 unsigned section_line
,
655 Network
*network
= userdata
;
656 _cleanup_(neighbor_free_or_set_invalidp
) Neighbor
*n
= NULL
;
665 r
= neighbor_new_static(network
, filename
, section_line
, &n
);
669 r
= ether_addr_from_string(rvalue
, &n
->lladdr
.mac
);
671 n
->lladdr_size
= sizeof(n
->lladdr
.mac
);
673 r
= in_addr_from_string_auto(rvalue
, &family
, &n
->lladdr
.ip
);
675 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
676 "Neighbor LinkLayerAddress= is invalid, ignoring assignment: %s",
680 n
->lladdr_size
= family
== AF_INET
? sizeof(n
->lladdr
.ip
.in
) : sizeof(n
->lladdr
.ip
.in6
);
688 int config_parse_neighbor_hwaddr(
690 const char *filename
,
693 unsigned section_line
,
700 Network
*network
= userdata
;
701 _cleanup_(neighbor_free_or_set_invalidp
) Neighbor
*n
= NULL
;
710 r
= neighbor_new_static(network
, filename
, section_line
, &n
);
714 r
= ether_addr_from_string(rvalue
, &n
->lladdr
.mac
);
716 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
717 "Neighbor MACAddress= is invalid, ignoring assignment: %s", rvalue
);
721 n
->lladdr_size
= sizeof(n
->lladdr
.mac
);