]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-route-nexthop.c
network/route-nexthop: make GatewayOnLink= support an empty string
[thirdparty/systemd.git] / src / network / networkd-route-nexthop.c
CommitLineData
df8767fc
YW
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include <linux/nexthop.h>
4
5#include "alloc-util.h"
6#include "extract-word.h"
7#include "netlink-util.h"
8#include "networkd-route.h"
9#include "networkd-route-nexthop.h"
10#include "parse-util.h"
11#include "string-util.h"
12
4444c2ba
YW
13int config_parse_gateway(
14 const char *unit,
15 const char *filename,
16 unsigned line,
17 const char *section,
18 unsigned section_line,
19 const char *lvalue,
20 int ltype,
21 const char *rvalue,
22 void *data,
23 void *userdata) {
24
25 Network *network = userdata;
26 _cleanup_(route_free_or_set_invalidp) Route *route = NULL;
27 int r;
28
29 assert(filename);
30 assert(section);
31 assert(lvalue);
32 assert(rvalue);
33 assert(data);
34
35 if (streq(section, "Network")) {
36 /* we are not in an Route section, so use line number instead */
37 r = route_new_static(network, filename, line, &route);
38 if (r == -ENOMEM)
39 return log_oom();
40 if (r < 0) {
41 log_syntax(unit, LOG_WARNING, filename, line, r,
42 "Failed to allocate route, ignoring assignment: %m");
43 return 0;
44 }
45 } else {
46 r = route_new_static(network, filename, section_line, &route);
47 if (r == -ENOMEM)
48 return log_oom();
49 if (r < 0) {
50 log_syntax(unit, LOG_WARNING, filename, line, r,
51 "Failed to allocate route, ignoring assignment: %m");
52 return 0;
53 }
54
55 if (isempty(rvalue)) {
56 route->gateway_from_dhcp_or_ra = false;
57 route->gw_family = AF_UNSPEC;
58 route->gw = IN_ADDR_NULL;
59 TAKE_PTR(route);
60 return 0;
61 }
62
63 if (streq(rvalue, "_dhcp")) {
64 route->gateway_from_dhcp_or_ra = true;
65 TAKE_PTR(route);
66 return 0;
67 }
68
69 if (streq(rvalue, "_dhcp4")) {
70 route->gw_family = AF_INET;
71 route->gateway_from_dhcp_or_ra = true;
72 TAKE_PTR(route);
73 return 0;
74 }
75
76 if (streq(rvalue, "_ipv6ra")) {
77 route->gw_family = AF_INET6;
78 route->gateway_from_dhcp_or_ra = true;
79 TAKE_PTR(route);
80 return 0;
81 }
82 }
83
84 r = in_addr_from_string_auto(rvalue, &route->gw_family, &route->gw);
85 if (r < 0) {
86 log_syntax(unit, LOG_WARNING, filename, line, r,
87 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
88 return 0;
89 }
90
91 route->gateway_from_dhcp_or_ra = false;
92 TAKE_PTR(route);
93 return 0;
94}
95
96int config_parse_route_gateway_onlink(
97 const char *unit,
98 const char *filename,
99 unsigned line,
100 const char *section,
101 unsigned section_line,
102 const char *lvalue,
103 int ltype,
104 const char *rvalue,
105 void *data,
106 void *userdata) {
107
108 Network *network = userdata;
109 _cleanup_(route_free_or_set_invalidp) Route *route = NULL;
110 int r;
111
112 assert(filename);
113 assert(section);
114 assert(lvalue);
115 assert(rvalue);
116 assert(data);
117
118 r = route_new_static(network, filename, section_line, &route);
119 if (r == -ENOMEM)
120 return log_oom();
121 if (r < 0) {
122 log_syntax(unit, LOG_WARNING, filename, line, r,
123 "Failed to allocate route, ignoring assignment: %m");
124 return 0;
125 }
126
4207f6c0
YW
127 r = config_parse_tristate(unit, filename, line, section, section_line, lvalue, ltype, rvalue,
128 &route->gateway_onlink, network);
129 if (r <= 0)
130 return r;
4444c2ba
YW
131
132 TAKE_PTR(route);
133 return 0;
134}
135
df8767fc
YW
136int config_parse_route_nexthop(
137 const char *unit,
138 const char *filename,
139 unsigned line,
140 const char *section,
141 unsigned section_line,
142 const char *lvalue,
143 int ltype,
144 const char *rvalue,
145 void *data,
146 void *userdata) {
147
148 Network *network = userdata;
149 _cleanup_(route_free_or_set_invalidp) Route *route = NULL;
150 uint32_t id;
151 int r;
152
153 assert(filename);
154 assert(section);
155 assert(lvalue);
156 assert(rvalue);
157 assert(data);
158
159 r = route_new_static(network, filename, section_line, &route);
160 if (r == -ENOMEM)
161 return log_oom();
162 if (r < 0) {
163 log_syntax(unit, LOG_WARNING, filename, line, r,
164 "Failed to allocate route, ignoring assignment: %m");
165 return 0;
166 }
167
168 if (isempty(rvalue)) {
169 route->nexthop_id = 0;
170 TAKE_PTR(route);
171 return 0;
172 }
173
174 r = safe_atou32(rvalue, &id);
175 if (r < 0) {
176 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse nexthop ID, ignoring assignment: %s", rvalue);
177 return 0;
178 }
179 if (id == 0) {
180 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid nexthop ID, ignoring assignment: %s", rvalue);
181 return 0;
182 }
183
184 route->nexthop_id = id;
185 TAKE_PTR(route);
186 return 0;
187}
188
189int config_parse_multipath_route(
190 const char *unit,
191 const char *filename,
192 unsigned line,
193 const char *section,
194 unsigned section_line,
195 const char *lvalue,
196 int ltype,
197 const char *rvalue,
198 void *data,
199 void *userdata) {
200
201 _cleanup_(multipath_route_freep) MultipathRoute *m = NULL;
202 _cleanup_(route_free_or_set_invalidp) Route *route = NULL;
203 _cleanup_free_ char *word = NULL;
204 Network *network = userdata;
205 union in_addr_union a;
206 int family, r;
207 const char *p;
208 char *dev;
209
210 assert(filename);
211 assert(section);
212 assert(lvalue);
213 assert(rvalue);
214 assert(data);
215
216 r = route_new_static(network, filename, section_line, &route);
217 if (r == -ENOMEM)
218 return log_oom();
219 if (r < 0) {
220 log_syntax(unit, LOG_WARNING, filename, line, r,
221 "Failed to allocate route, ignoring assignment: %m");
222 return 0;
223 }
224
225 if (isempty(rvalue)) {
226 route->multipath_routes = ordered_set_free_with_destructor(route->multipath_routes, multipath_route_free);
227 TAKE_PTR(route);
228 return 0;
229 }
230
231 m = new0(MultipathRoute, 1);
232 if (!m)
233 return log_oom();
234
235 p = rvalue;
236 r = extract_first_word(&p, &word, NULL, 0);
237 if (r == -ENOMEM)
238 return log_oom();
239 if (r <= 0) {
240 log_syntax(unit, LOG_WARNING, filename, line, r,
241 "Invalid multipath route option, ignoring assignment: %s", rvalue);
242 return 0;
243 }
244
245 dev = strchr(word, '@');
246 if (dev) {
247 *dev++ = '\0';
248
249 r = parse_ifindex(dev);
250 if (r > 0)
251 m->ifindex = r;
252 else {
253 if (!ifname_valid_full(dev, IFNAME_VALID_ALTERNATIVE)) {
254 log_syntax(unit, LOG_WARNING, filename, line, 0,
255 "Invalid interface name '%s' in %s=, ignoring: %s", dev, lvalue, rvalue);
256 return 0;
257 }
258
259 m->ifname = strdup(dev);
260 if (!m->ifname)
261 return log_oom();
262 }
263 }
264
265 r = in_addr_from_string_auto(word, &family, &a);
266 if (r < 0) {
267 log_syntax(unit, LOG_WARNING, filename, line, r,
268 "Invalid multipath route gateway '%s', ignoring assignment: %m", rvalue);
269 return 0;
270 }
271 m->gateway.address = a;
272 m->gateway.family = family;
273
274 if (!isempty(p)) {
275 r = safe_atou32(p, &m->weight);
276 if (r < 0) {
277 log_syntax(unit, LOG_WARNING, filename, line, r,
278 "Invalid multipath route weight, ignoring assignment: %s", p);
279 return 0;
280 }
281 /* ip command takes weight in the range 1…255, while kernel takes the value in the
282 * range 0…254. MultiPathRoute= setting also takes weight in the same range which ip
283 * command uses, then networkd decreases by one and stores it to match the range which
284 * kernel uses. */
285 if (m->weight == 0 || m->weight > 256) {
286 log_syntax(unit, LOG_WARNING, filename, line, 0,
287 "Invalid multipath route weight, ignoring assignment: %s", p);
288 return 0;
289 }
290 m->weight--;
291 }
292
293 r = ordered_set_ensure_put(&route->multipath_routes, NULL, m);
294 if (r == -ENOMEM)
295 return log_oom();
296 if (r < 0) {
297 log_syntax(unit, LOG_WARNING, filename, line, r,
298 "Failed to store multipath route, ignoring assignment: %m");
299 return 0;
300 }
301
302 TAKE_PTR(m);
303 TAKE_PTR(route);
304 return 0;
305}