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