1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include "sd-netlink.h"
5 #include "alloc-util.h"
6 #include "conf-parser.h"
7 #include "ether-addr-util.h"
9 #include "in-addr-util.h"
10 #include "netlink-util.h"
11 #include "networkd-link.h"
12 #include "networkd-manager.h"
13 #include "networkd-neighbor.h"
15 void neighbor_free(Neighbor
*neighbor
) {
19 if (neighbor
->network
) {
20 LIST_REMOVE(neighbors
, neighbor
->network
->neighbors
, neighbor
);
21 assert(neighbor
->network
->n_neighbors
> 0);
22 neighbor
->network
->n_neighbors
--;
24 if (neighbor
->section
) {
25 hashmap_remove(neighbor
->network
->neighbors_by_section
, neighbor
->section
);
26 network_config_section_free(neighbor
->section
);
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
;
40 assert(!!filename
== (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
);
55 neighbor
= new(Neighbor
, 1);
59 *neighbor
= (Neighbor
) {
64 LIST_APPEND(neighbors
, network
->neighbors
, neighbor
);
65 network
->n_neighbors
++;
68 neighbor
->section
= TAKE_PTR(n
);
70 r
= hashmap_ensure_allocated(&network
->neighbors_by_section
, &network_config_hash_ops
);
74 r
= hashmap_put(network
->neighbors_by_section
, neighbor
->section
, neighbor
);
79 *ret
= TAKE_PTR(neighbor
);
84 static int neighbor_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
88 assert(link
->neighbor_messages
> 0);
90 link
->neighbor_messages
--;
92 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
95 r
= sd_netlink_message_get_errno(m
);
96 if (r
< 0 && r
!= -EEXIST
)
97 log_link_warning_errno(link
, r
, "Could not set neighbor: %m");
99 if (link
->neighbor_messages
== 0) {
100 log_link_debug(link
, "Neighbors set");
101 link
->neighbors_configured
= true;
102 link_check_ready(link
);
108 int neighbor_configure(Neighbor
*neighbor
, Link
*link
, link_netlink_message_handler_t callback
) {
109 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
114 assert(link
->ifindex
> 0);
115 assert(link
->manager
);
116 assert(link
->manager
->rtnl
);
118 if (neighbor
->family
== AF_UNSPEC
)
119 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Neighbor without Address= configured");
120 if (!neighbor
->mac_configured
)
121 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Neighbor without MACAddress= configured");
123 r
= sd_rtnl_message_new_neigh(link
->manager
->rtnl
, &req
, RTM_NEWNEIGH
,
124 link
->ifindex
, neighbor
->family
);
126 return log_error_errno(r
, "Could not allocate RTM_NEWNEIGH message: %m");
128 r
= sd_rtnl_message_neigh_set_state(req
, NUD_PERMANENT
);
130 return log_error_errno(r
, "Could not set state: %m");
132 r
= sd_netlink_message_set_flags(req
, NLM_F_REQUEST
| NLM_F_CREATE
| NLM_F_REPLACE
);
134 return log_error_errno(r
, "Could not set flags: %m");
136 r
= sd_netlink_message_append_ether_addr(req
, NDA_LLADDR
, &neighbor
->mac
);
138 return log_error_errno(r
, "Could not append NDA_LLADDR attribute: %m");
140 r
= netlink_message_append_in_addr_union(req
, NDA_DST
, neighbor
->family
, &neighbor
->in_addr
);
142 return log_error_errno(r
, "Could not append NDA_DST attribute: %m");
144 r
= netlink_call_async(link
->manager
->rtnl
, NULL
, req
, callback
?: neighbor_handler
,
145 link_netlink_destroy_callback
, link
);
147 return log_error_errno(r
, "Could not send rtnetlink message: %m");
149 link
->neighbor_messages
++;
155 int config_parse_neighbor_address(const char *unit
,
156 const char *filename
,
159 unsigned section_line
,
166 Network
*network
= userdata
;
167 _cleanup_(neighbor_free_or_set_invalidp
) Neighbor
*n
= NULL
;
176 r
= neighbor_new_static(network
, filename
, section_line
, &n
);
180 r
= in_addr_from_string_auto(rvalue
, &n
->family
, &n
->in_addr
);
182 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Neighbor Address is invalid, ignoring assignment: %s", rvalue
);
191 int config_parse_neighbor_hwaddr(const char *unit
,
192 const char *filename
,
195 unsigned section_line
,
202 Network
*network
= userdata
;
203 _cleanup_(neighbor_free_or_set_invalidp
) Neighbor
*n
= NULL
;
212 r
= neighbor_new_static(network
, filename
, section_line
, &n
);
216 r
= ether_addr_from_string(rvalue
, &n
->mac
);
218 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Neighbor MACAddress is invalid, ignoring assignment: %s", rvalue
);
222 n
->mac_configured
= true;