]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-neighbor.c
network: make link enter failed state when a configuration fails
[thirdparty/systemd.git] / src / network / networkd-neighbor.c
CommitLineData
e4a71bf3
WKI
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include "sd-netlink.h"
4
5#include "alloc-util.h"
6#include "conf-parser.h"
7#include "ether-addr-util.h"
8#include "hashmap.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"
14
15void neighbor_free(Neighbor *neighbor) {
16 if (!neighbor)
17 return;
18
19 if (neighbor->network) {
20 LIST_REMOVE(neighbors, neighbor->network->neighbors, neighbor);
21 assert(neighbor->network->n_neighbors > 0);
22 neighbor->network->n_neighbors--;
23
24 if (neighbor->section) {
25 hashmap_remove(neighbor->network->neighbors_by_section, neighbor->section);
26 network_config_section_free(neighbor->section);
27 }
28 }
29
30 free(neighbor);
31}
32
33static 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;
36 int r;
37
38 assert(network);
39 assert(ret);
40 assert(!!filename == (section_line > 0));
41
42 if (filename) {
43 r = network_config_section_new(filename, section_line, &n);
44 if (r < 0)
45 return r;
46
47 neighbor = hashmap_get(network->neighbors_by_section, n);
48 if (neighbor) {
49 *ret = TAKE_PTR(neighbor);
50
51 return 0;
52 }
53 }
54
55 neighbor = new(Neighbor, 1);
56 if (!neighbor)
57 return -ENOMEM;
58
59 *neighbor = (Neighbor) {
60 .network = network,
61 .family = AF_UNSPEC,
b956364d 62 .lladdr_type = _NEIGHBOR_LLADDR_INVALID,
e4a71bf3
WKI
63 };
64
65 LIST_APPEND(neighbors, network->neighbors, neighbor);
66 network->n_neighbors++;
67
68 if (filename) {
69 neighbor->section = TAKE_PTR(n);
70
71 r = hashmap_ensure_allocated(&network->neighbors_by_section, &network_config_hash_ops);
72 if (r < 0)
73 return r;
74
75 r = hashmap_put(network->neighbors_by_section, neighbor->section, neighbor);
76 if (r < 0)
77 return r;
78 }
79
80 *ret = TAKE_PTR(neighbor);
81
82 return 0;
83}
84
85static int neighbor_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
86 int r;
87
88 assert(link);
89 assert(link->neighbor_messages > 0);
90
91 link->neighbor_messages--;
92
93 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
94 return 1;
95
96 r = sd_netlink_message_get_errno(m);
97 if (r < 0 && r != -EEXIST)
4ff296b0
YW
98 /* Neighbor may not exist yet. So, do not enter failed state here. */
99 log_link_warning_errno(link, r, "Could not set neighbor, ignoring: %m");
e4a71bf3
WKI
100
101 if (link->neighbor_messages == 0) {
102 log_link_debug(link, "Neighbors set");
103 link->neighbors_configured = true;
104 link_check_ready(link);
105 }
106
107 return 1;
108}
109
110int neighbor_configure(Neighbor *neighbor, Link *link, link_netlink_message_handler_t callback) {
111 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
112 int r;
113
114 assert(neighbor);
115 assert(link);
116 assert(link->ifindex > 0);
117 assert(link->manager);
118 assert(link->manager->rtnl);
119
e4a71bf3
WKI
120 r = sd_rtnl_message_new_neigh(link->manager->rtnl, &req, RTM_NEWNEIGH,
121 link->ifindex, neighbor->family);
122 if (r < 0)
123 return log_error_errno(r, "Could not allocate RTM_NEWNEIGH message: %m");
124
125 r = sd_rtnl_message_neigh_set_state(req, NUD_PERMANENT);
126 if (r < 0)
127 return log_error_errno(r, "Could not set state: %m");
128
129 r = sd_netlink_message_set_flags(req, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE);
130 if (r < 0)
131 return log_error_errno(r, "Could not set flags: %m");
132
b956364d
YW
133 if (neighbor->lladdr_type == NEIGHBOR_LLADDR_MAC)
134 r = sd_netlink_message_append_data(req, NDA_LLADDR, &neighbor->lladdr.mac, sizeof(neighbor->lladdr.mac));
135 else
136 r = sd_netlink_message_append_data(req, NDA_LLADDR, &neighbor->lladdr.ip.in, sizeof(neighbor->lladdr.ip.in));
e4a71bf3
WKI
137 if (r < 0)
138 return log_error_errno(r, "Could not append NDA_LLADDR attribute: %m");
139
43409486
YW
140 r = netlink_message_append_in_addr_union(req, NDA_DST, neighbor->family, &neighbor->in_addr);
141 if (r < 0)
142 return log_error_errno(r, "Could not append NDA_DST attribute: %m");
e4a71bf3
WKI
143
144 r = netlink_call_async(link->manager->rtnl, NULL, req, callback ?: neighbor_handler,
145 link_netlink_destroy_callback, link);
146 if (r < 0)
147 return log_error_errno(r, "Could not send rtnetlink message: %m");
148
149 link->neighbor_messages++;
150 link_ref(link);
151
152 return 0;
153}
154
044d4b40
YW
155int neighbor_section_verify(Neighbor *neighbor) {
156 if (section_is_invalid(neighbor->section))
157 return -EINVAL;
158
159 if (neighbor->family == AF_UNSPEC)
160 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
161 "%s: Neighbor section without Address= configured. "
162 "Ignoring [Neighbor] section from line %u.",
163 neighbor->section->filename, neighbor->section->line);
164
165 if (neighbor->lladdr_type < 0)
166 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
167 "%s: Neighbor section without LinkLayerAddress= configured. "
168 "Ignoring [Neighbor] section from line %u.",
169 neighbor->section->filename, neighbor->section->line);
170
171 return 0;
172}
173
b956364d
YW
174int config_parse_neighbor_address(
175 const char *unit,
176 const char *filename,
177 unsigned line,
178 const char *section,
179 unsigned section_line,
180 const char *lvalue,
181 int ltype,
182 const char *rvalue,
183 void *data,
184 void *userdata) {
e4a71bf3
WKI
185
186 Network *network = userdata;
fcbf4cb7 187 _cleanup_(neighbor_free_or_set_invalidp) Neighbor *n = NULL;
e4a71bf3
WKI
188 int r;
189
190 assert(filename);
191 assert(section);
192 assert(lvalue);
193 assert(rvalue);
194 assert(data);
195
196 r = neighbor_new_static(network, filename, section_line, &n);
197 if (r < 0)
198 return r;
199
200 r = in_addr_from_string_auto(rvalue, &n->family, &n->in_addr);
201 if (r < 0) {
202 log_syntax(unit, LOG_ERR, filename, line, r, "Neighbor Address is invalid, ignoring assignment: %s", rvalue);
203 return 0;
204 }
205
206 TAKE_PTR(n);
207
208 return 0;
209}
210
b956364d
YW
211int config_parse_neighbor_lladdr(
212 const char *unit,
213 const char *filename,
214 unsigned line,
215 const char *section,
216 unsigned section_line,
217 const char *lvalue,
218 int ltype,
219 const char *rvalue,
220 void *data,
221 void *userdata) {
e4a71bf3
WKI
222
223 Network *network = userdata;
fcbf4cb7 224 _cleanup_(neighbor_free_or_set_invalidp) Neighbor *n = NULL;
e4a71bf3
WKI
225 int r;
226
227 assert(filename);
228 assert(section);
229 assert(lvalue);
230 assert(rvalue);
231 assert(data);
232
233 r = neighbor_new_static(network, filename, section_line, &n);
234 if (r < 0)
235 return r;
236
b956364d
YW
237 r = ether_addr_from_string(rvalue, &n->lladdr.mac);
238 if (r >= 0)
239 n->lladdr_type = NEIGHBOR_LLADDR_MAC;
240 else {
241 r = in_addr_from_string(AF_INET, rvalue, &n->lladdr.ip);
242 if (r < 0) {
243 log_syntax(unit, LOG_ERR, filename, line, r, "Neighbor LinkLayerAddress= is invalid, ignoring assignment: %s", rvalue);
244 return 0;
245 }
246 n->lladdr_type = NEIGHBOR_LLADDR_IP;
247 }
248
249 TAKE_PTR(n);
250
251 return 0;
252}
253
254int config_parse_neighbor_hwaddr(
255 const char *unit,
256 const char *filename,
257 unsigned line,
258 const char *section,
259 unsigned section_line,
260 const char *lvalue,
261 int ltype,
262 const char *rvalue,
263 void *data,
264 void *userdata) {
265
266 Network *network = userdata;
267 _cleanup_(neighbor_free_or_set_invalidp) Neighbor *n = NULL;
268 int r;
269
270 assert(filename);
271 assert(section);
272 assert(lvalue);
273 assert(rvalue);
274 assert(data);
275
276 r = neighbor_new_static(network, filename, section_line, &n);
277 if (r < 0)
278 return r;
279
280 r = ether_addr_from_string(rvalue, &n->lladdr.mac);
e4a71bf3 281 if (r < 0) {
b956364d 282 log_syntax(unit, LOG_ERR, filename, line, r, "Neighbor MACAddress= is invalid, ignoring assignment: %s", rvalue);
e4a71bf3
WKI
283 return 0;
284 }
285
b956364d 286 n->lladdr_type = NEIGHBOR_LLADDR_MAC;
e4a71bf3
WKI
287 TAKE_PTR(n);
288
289 return 0;
290}