]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/netdev/vxlan.c
Merge pull request #8066 from LittleCVR/udevadm-trigger-and-settle
[thirdparty/systemd.git] / src / network / netdev / vxlan.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2014 Susant Sahani
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <net/if.h>
22
23 #include "sd-netlink.h"
24
25 #include "conf-parser.h"
26 #include "alloc-util.h"
27 #include "extract-word.h"
28 #include "string-util.h"
29 #include "strv.h"
30 #include "parse-util.h"
31 #include "missing.h"
32
33 #include "networkd-link.h"
34 #include "netdev/vxlan.h"
35
36 static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
37 VxLan *v;
38 int r;
39
40 assert(netdev);
41 assert(link);
42 assert(m);
43
44 v = VXLAN(netdev);
45
46 assert(v);
47
48 if (v->id <= VXLAN_VID_MAX) {
49 r = sd_netlink_message_append_u32(m, IFLA_VXLAN_ID, v->id);
50 if (r < 0)
51 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_ID attribute: %m");
52 }
53
54 if (!in_addr_is_null(v->remote_family, &v->remote)) {
55
56 if (v->remote_family == AF_INET)
57 r = sd_netlink_message_append_in_addr(m, IFLA_VXLAN_GROUP, &v->remote.in);
58 else
59 r = sd_netlink_message_append_in6_addr(m, IFLA_VXLAN_GROUP6, &v->remote.in6);
60
61 if (r < 0)
62 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_GROUP attribute: %m");
63
64 }
65
66 if (!in_addr_is_null(v->local_family, &v->local)) {
67
68 if (v->local_family == AF_INET)
69 r = sd_netlink_message_append_in_addr(m, IFLA_VXLAN_LOCAL, &v->local.in);
70 else
71 r = sd_netlink_message_append_in6_addr(m, IFLA_VXLAN_LOCAL6, &v->local.in6);
72
73 if (r < 0)
74 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LOCAL attribute: %m");
75
76 }
77
78 r = sd_netlink_message_append_u32(m, IFLA_VXLAN_LINK, link->ifindex);
79 if (r < 0)
80 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LINK attribute: %m");
81
82 if (v->ttl) {
83 r = sd_netlink_message_append_u8(m, IFLA_VXLAN_TTL, v->ttl);
84 if (r < 0)
85 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_TTL attribute: %m");
86 }
87
88 if (v->tos) {
89 r = sd_netlink_message_append_u8(m, IFLA_VXLAN_TOS, v->tos);
90 if (r < 0)
91 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_TOS attribute: %m");
92 }
93
94 r = sd_netlink_message_append_u8(m, IFLA_VXLAN_LEARNING, v->learning);
95 if (r < 0)
96 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LEARNING attribute: %m");
97
98 r = sd_netlink_message_append_u8(m, IFLA_VXLAN_RSC, v->route_short_circuit);
99 if (r < 0)
100 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_RSC attribute: %m");
101
102 r = sd_netlink_message_append_u8(m, IFLA_VXLAN_PROXY, v->arp_proxy);
103 if (r < 0)
104 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_PROXY attribute: %m");
105
106 r = sd_netlink_message_append_u8(m, IFLA_VXLAN_L2MISS, v->l2miss);
107 if (r < 0)
108 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_L2MISS attribute: %m");
109
110 r = sd_netlink_message_append_u8(m, IFLA_VXLAN_L3MISS, v->l3miss);
111 if (r < 0)
112 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_L3MISS attribute: %m");
113
114 if (v->fdb_ageing) {
115 r = sd_netlink_message_append_u32(m, IFLA_VXLAN_AGEING, v->fdb_ageing / USEC_PER_SEC);
116 if (r < 0)
117 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_AGEING attribute: %m");
118 }
119
120 if (v->max_fdb) {
121 r = sd_netlink_message_append_u32(m, IFLA_VXLAN_LIMIT, v->max_fdb);
122 if (r < 0)
123 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LIMIT attribute: %m");
124 }
125
126 r = sd_netlink_message_append_u8(m, IFLA_VXLAN_UDP_CSUM, v->udpcsum);
127 if (r < 0)
128 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_UDP_CSUM attribute: %m");
129
130 r = sd_netlink_message_append_u8(m, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, v->udp6zerocsumtx);
131 if (r < 0)
132 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_UDP_ZERO_CSUM6_TX attribute: %m");
133
134 r = sd_netlink_message_append_u8(m, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, v->udp6zerocsumrx);
135 if (r < 0)
136 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_UDP_ZERO_CSUM6_RX attribute: %m");
137
138 r = sd_netlink_message_append_u8(m, IFLA_VXLAN_REMCSUM_TX, v->remote_csum_tx);
139 if (r < 0)
140 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_REMCSUM_TX attribute: %m");
141
142 r = sd_netlink_message_append_u8(m, IFLA_VXLAN_REMCSUM_RX, v->remote_csum_rx);
143 if (r < 0)
144 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_REMCSUM_RX attribute: %m");
145
146 r = sd_netlink_message_append_u16(m, IFLA_VXLAN_PORT, htobe16(v->dest_port));
147 if (r < 0)
148 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_PORT attribute: %m");
149
150 if (v->port_range.low || v->port_range.high) {
151 struct ifla_vxlan_port_range port_range;
152
153 port_range.low = htobe16(v->port_range.low);
154 port_range.high = htobe16(v->port_range.high);
155
156 r = sd_netlink_message_append_data(m, IFLA_VXLAN_PORT_RANGE, &port_range, sizeof(port_range));
157 if (r < 0)
158 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_PORT_RANGE attribute: %m");
159 }
160
161 r = sd_netlink_message_append_u32(m, IFLA_VXLAN_LABEL, htobe32(v->flow_label));
162 if (r < 0)
163 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LABEL attribute: %m");
164
165 if (v->group_policy) {
166 r = sd_netlink_message_append_flag(m, IFLA_VXLAN_GBP);
167 if (r < 0)
168 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_GBP attribute: %m");
169 }
170
171 return r;
172 }
173
174 int config_parse_vxlan_address(const char *unit,
175 const char *filename,
176 unsigned line,
177 const char *section,
178 unsigned section_line,
179 const char *lvalue,
180 int ltype,
181 const char *rvalue,
182 void *data,
183 void *userdata) {
184 VxLan *v = userdata;
185 union in_addr_union *addr = data, buffer;
186 int r, f;
187
188 assert(filename);
189 assert(lvalue);
190 assert(rvalue);
191 assert(data);
192
193 r = in_addr_from_string_auto(rvalue, &f, &buffer);
194 if (r < 0) {
195 log_syntax(unit, LOG_ERR, filename, line, r, "vxlan '%s' address is invalid, ignoring assignment: %s", lvalue, rvalue);
196 return 0;
197 }
198
199 r = in_addr_is_multicast(f, &buffer);
200
201 if (streq(lvalue, "Group")) {
202 if (r <= 0) {
203 log_syntax(unit, LOG_ERR, filename, line, 0, "vxlan %s invalid multicast address, ignoring assignment: %s", lvalue, rvalue);
204 return 0;
205 }
206
207 v->remote_family = f;
208 } else {
209 if (r > 0) {
210 log_syntax(unit, LOG_ERR, filename, line, 0, "vxlan %s cannot be a multicast address, ignoring assignment: %s", lvalue, rvalue);
211 return 0;
212 }
213
214 if (streq(lvalue, "Remote"))
215 v->remote_family = f;
216 else
217 v->local_family = f;
218 }
219
220 *addr = buffer;
221
222 return 0;
223 }
224
225 int config_parse_port_range(const char *unit,
226 const char *filename,
227 unsigned line,
228 const char *section,
229 unsigned section_line,
230 const char *lvalue,
231 int ltype,
232 const char *rvalue,
233 void *data,
234 void *userdata) {
235 _cleanup_free_ char *word = NULL;
236 VxLan *v = userdata;
237 unsigned low, high;
238 int r;
239
240 assert(filename);
241 assert(lvalue);
242 assert(rvalue);
243 assert(data);
244
245 r = extract_first_word(&rvalue, &word, NULL, 0);
246 if (r < 0) {
247 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract VXLAN port range, ignoring: %s", rvalue);
248 return 0;
249 }
250
251 if (r == 0)
252 return 0;
253
254 r = parse_range(word, &low, &high);
255 if (r < 0) {
256 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse VXLAN port range '%s'", word);
257 return 0;
258 }
259
260 if (low <= 0 || low > 65535 || high <= 0 || high > 65535) {
261 log_syntax(unit, LOG_ERR, filename, line, r,
262 "Failed to parse VXLAN port range '%s'. Port should be greater than 0 and less than 65535.", word);
263 return 0;
264 }
265
266 if (high < low) {
267 log_syntax(unit, LOG_ERR, filename, line, r,
268 "Failed to parse VXLAN port range '%s'. Port range %u .. %u not valid", word, low, high);
269 return 0;
270 }
271
272 v->port_range.low = low;
273 v->port_range.high = high;
274
275 return 0;
276 }
277
278 int config_parse_flow_label(const char *unit,
279 const char *filename,
280 unsigned line,
281 const char *section,
282 unsigned section_line,
283 const char *lvalue,
284 int ltype,
285 const char *rvalue,
286 void *data,
287 void *userdata) {
288 VxLan *v = userdata;
289 unsigned f;
290 int r;
291
292 assert(filename);
293 assert(lvalue);
294 assert(rvalue);
295 assert(data);
296
297 r = safe_atou(rvalue, &f);
298 if (r < 0) {
299 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse VXLAN flow label '%s'.", rvalue);
300 return 0;
301 }
302
303 if (f & ~VXLAN_FLOW_LABEL_MAX_MASK) {
304 log_syntax(unit, LOG_ERR, filename, line, r,
305 "VXLAN flow label '%s' not valid. Flow label range should be [0-1048575].", rvalue);
306 return 0;
307 }
308
309 v->flow_label = f;
310
311 return 0;
312 }
313
314 static int netdev_vxlan_verify(NetDev *netdev, const char *filename) {
315 VxLan *v = VXLAN(netdev);
316
317 assert(netdev);
318 assert(v);
319 assert(filename);
320
321 if (v->id > VXLAN_VID_MAX) {
322 log_warning("VXLAN without valid Id configured in %s. Ignoring", filename);
323 return -EINVAL;
324 }
325
326 return 0;
327 }
328
329 static void vxlan_init(NetDev *netdev) {
330 VxLan *v;
331
332 assert(netdev);
333
334 v = VXLAN(netdev);
335
336 assert(v);
337
338 v->id = VXLAN_VID_MAX + 1;
339 v->learning = true;
340 v->udpcsum = false;
341 v->udp6zerocsumtx = false;
342 v->udp6zerocsumrx = false;
343 }
344
345 const NetDevVTable vxlan_vtable = {
346 .object_size = sizeof(VxLan),
347 .init = vxlan_init,
348 .sections = "Match\0NetDev\0VXLAN\0",
349 .fill_message_create = netdev_vxlan_fill_message_create,
350 .create_type = NETDEV_CREATE_STACKED,
351 .config_verify = netdev_vxlan_verify,
352 };