]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
6598e046 SS |
2 | |
3 | #include <net/if.h> | |
4 | ||
5 | #include "alloc-util.h" | |
6 | #include "conf-parser.h" | |
7 | #include "extract-word.h" | |
8 | #include "geneve.h" | |
302a796f | 9 | #include "netlink-util.h" |
737f1405 | 10 | #include "networkd-manager.h" |
6598e046 | 11 | #include "parse-util.h" |
aac35019 | 12 | #include "string-table.h" |
6598e046 SS |
13 | #include "string-util.h" |
14 | #include "strv.h" | |
6598e046 SS |
15 | |
16 | #define GENEVE_FLOW_LABEL_MAX_MASK 0xFFFFFU | |
17 | #define DEFAULT_GENEVE_DESTINATION_PORT 6081 | |
18 | ||
aac35019 SS |
19 | static const char* const geneve_df_table[_NETDEV_GENEVE_DF_MAX] = { |
20 | [NETDEV_GENEVE_DF_NO] = "no", | |
21 | [NETDEV_GENEVE_DF_YES] = "yes", | |
22 | [NETDEV_GENEVE_DF_INHERIT] = "inherit", | |
23 | }; | |
24 | ||
25 | DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(geneve_df, GeneveDF, NETDEV_GENEVE_DF_YES); | |
26 | DEFINE_CONFIG_PARSE_ENUM(config_parse_geneve_df, geneve_df, GeneveDF, "Failed to parse Geneve IPDoNotFragment= setting"); | |
27 | ||
6598e046 | 28 | /* callback for geneve netdev's created without a backing Link */ |
302a796f | 29 | static int geneve_netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev *netdev) { |
6598e046 SS |
30 | int r; |
31 | ||
1046bf9b | 32 | assert(netdev); |
6598e046 SS |
33 | assert(netdev->state != _NETDEV_STATE_INVALID); |
34 | ||
35 | r = sd_netlink_message_get_errno(m); | |
36 | if (r == -EEXIST) | |
37 | log_netdev_info(netdev, "Geneve netdev exists, using existing without changing its parameters"); | |
38 | else if (r < 0) { | |
39 | log_netdev_warning_errno(netdev, r, "Geneve netdev could not be created: %m"); | |
40 | netdev_drop(netdev); | |
41 | ||
42 | return 1; | |
43 | } | |
44 | ||
45 | log_netdev_debug(netdev, "Geneve created"); | |
46 | ||
47 | return 1; | |
48 | } | |
49 | ||
50 | static int netdev_geneve_create(NetDev *netdev) { | |
51 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; | |
52 | Geneve *v; | |
53 | int r; | |
54 | ||
55 | assert(netdev); | |
56 | ||
57 | v = GENEVE(netdev); | |
58 | ||
59 | r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0); | |
60 | if (r < 0) | |
61 | return log_netdev_error_errno(netdev, r, "Could not allocate RTM_NEWLINK message: %m"); | |
62 | ||
63 | r = sd_netlink_message_append_string(m, IFLA_IFNAME, netdev->ifname); | |
64 | if (r < 0) | |
65 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_IFNAME, attribute: %m"); | |
66 | ||
67 | if (netdev->mac) { | |
68 | r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac); | |
69 | if (r < 0) | |
70 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_ADDRESS attribute: %m"); | |
71 | } | |
72 | ||
4e964aa0 | 73 | if (netdev->mtu != 0) { |
6598e046 SS |
74 | r = sd_netlink_message_append_u32(m, IFLA_MTU, netdev->mtu); |
75 | if (r < 0) | |
76 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_MTU attribute: %m"); | |
77 | } | |
78 | ||
79 | r = sd_netlink_message_open_container(m, IFLA_LINKINFO); | |
80 | if (r < 0) | |
81 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m"); | |
82 | ||
83 | r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind)); | |
84 | if (r < 0) | |
85 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m"); | |
86 | ||
87 | if (v->id <= GENEVE_VID_MAX) { | |
88 | r = sd_netlink_message_append_u32(m, IFLA_GENEVE_ID, v->id); | |
89 | if (r < 0) | |
90 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_ID attribute: %m"); | |
91 | } | |
92 | ||
d40b01e4 | 93 | if (in_addr_is_null(v->remote_family, &v->remote) == 0) { |
6598e046 SS |
94 | if (v->remote_family == AF_INET) |
95 | r = sd_netlink_message_append_in_addr(m, IFLA_GENEVE_REMOTE, &v->remote.in); | |
96 | else | |
97 | r = sd_netlink_message_append_in6_addr(m, IFLA_GENEVE_REMOTE6, &v->remote.in6); | |
6598e046 | 98 | if (r < 0) |
10490d90 | 99 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_REMOTE/IFLA_GENEVE_REMOTE6 attribute: %m"); |
6598e046 SS |
100 | } |
101 | ||
d70c9bbd SS |
102 | if (v->inherit) { |
103 | r = sd_netlink_message_append_u8(m, IFLA_GENEVE_TTL_INHERIT, 1); | |
104 | if (r < 0) | |
105 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_TTL_INHERIT attribute: %m"); | |
106 | } else { | |
6598e046 SS |
107 | r = sd_netlink_message_append_u8(m, IFLA_GENEVE_TTL, v->ttl); |
108 | if (r < 0) | |
109 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_TTL attribute: %m"); | |
110 | } | |
111 | ||
112 | r = sd_netlink_message_append_u8(m, IFLA_GENEVE_TOS, v->tos); | |
113 | if (r < 0) | |
114 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_TOS attribute: %m"); | |
115 | ||
116 | r = sd_netlink_message_append_u8(m, IFLA_GENEVE_UDP_CSUM, v->udpcsum); | |
117 | if (r < 0) | |
118 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_UDP_CSUM attribute: %m"); | |
119 | ||
120 | r = sd_netlink_message_append_u8(m, IFLA_GENEVE_UDP_ZERO_CSUM6_TX, v->udp6zerocsumtx); | |
121 | if (r < 0) | |
122 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_UDP_ZERO_CSUM6_TX attribute: %m"); | |
123 | ||
124 | r = sd_netlink_message_append_u8(m, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, v->udp6zerocsumrx); | |
125 | if (r < 0) | |
126 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_UDP_ZERO_CSUM6_RX attribute: %m"); | |
127 | ||
128 | if (v->dest_port != DEFAULT_GENEVE_DESTINATION_PORT) { | |
129 | r = sd_netlink_message_append_u16(m, IFLA_GENEVE_PORT, htobe16(v->dest_port)); | |
130 | if (r < 0) | |
131 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_PORT attribute: %m"); | |
132 | } | |
133 | ||
134 | if (v->flow_label > 0) { | |
135 | r = sd_netlink_message_append_u32(m, IFLA_GENEVE_LABEL, htobe32(v->flow_label)); | |
136 | if (r < 0) | |
137 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_LABEL attribute: %m"); | |
138 | } | |
139 | ||
aac35019 SS |
140 | if (v->geneve_df != _NETDEV_GENEVE_DF_INVALID) { |
141 | r = sd_netlink_message_append_u8(m, IFLA_GENEVE_DF, v->geneve_df); | |
142 | if (r < 0) | |
143 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_DF attribute: %m"); | |
144 | } | |
145 | ||
6598e046 SS |
146 | r = sd_netlink_message_close_container(m); |
147 | if (r < 0) | |
148 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m"); | |
149 | ||
150 | r = sd_netlink_message_close_container(m); | |
151 | if (r < 0) | |
152 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m"); | |
153 | ||
302a796f YW |
154 | r = netlink_call_async(netdev->manager->rtnl, NULL, m, geneve_netdev_create_handler, |
155 | netdev_destroy_callback, netdev); | |
6598e046 SS |
156 | if (r < 0) |
157 | return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m"); | |
158 | ||
159 | netdev_ref(netdev); | |
6598e046 SS |
160 | netdev->state = NETDEV_STATE_CREATING; |
161 | ||
162 | log_netdev_debug(netdev, "Creating"); | |
163 | ||
6598e046 SS |
164 | return r; |
165 | } | |
166 | ||
167 | int config_parse_geneve_vni(const char *unit, | |
168 | const char *filename, | |
169 | unsigned line, | |
170 | const char *section, | |
171 | unsigned section_line, | |
172 | const char *lvalue, | |
173 | int ltype, | |
174 | const char *rvalue, | |
175 | void *data, | |
176 | void *userdata) { | |
177 | Geneve *v = userdata; | |
178 | uint32_t f; | |
179 | int r; | |
180 | ||
181 | assert(filename); | |
182 | assert(lvalue); | |
183 | assert(rvalue); | |
184 | assert(data); | |
185 | ||
186 | r = safe_atou32(rvalue, &f); | |
187 | if (r < 0) { | |
188 | log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Geneve VNI '%s'.", rvalue); | |
189 | return 0; | |
190 | } | |
191 | ||
192 | if (f > GENEVE_VID_MAX){ | |
193 | log_syntax(unit, LOG_ERR, filename, line, r, "Geneve VNI out is of range '%s'.", rvalue); | |
194 | return 0; | |
195 | } | |
196 | ||
197 | v->id = f; | |
198 | ||
199 | return 0; | |
200 | } | |
201 | ||
6598e046 SS |
202 | int config_parse_geneve_address(const char *unit, |
203 | const char *filename, | |
204 | unsigned line, | |
205 | const char *section, | |
206 | unsigned section_line, | |
207 | const char *lvalue, | |
208 | int ltype, | |
209 | const char *rvalue, | |
210 | void *data, | |
211 | void *userdata) { | |
212 | Geneve *v = userdata; | |
213 | union in_addr_union *addr = data, buffer; | |
214 | int r, f; | |
215 | ||
216 | assert(filename); | |
217 | assert(lvalue); | |
218 | assert(rvalue); | |
219 | assert(data); | |
220 | ||
221 | r = in_addr_from_string_auto(rvalue, &f, &buffer); | |
222 | if (r < 0) { | |
223 | log_syntax(unit, LOG_ERR, filename, line, r, "geneve '%s' address is invalid, ignoring assignment: %s", lvalue, rvalue); | |
224 | return 0; | |
225 | } | |
226 | ||
227 | r = in_addr_is_multicast(f, &buffer); | |
228 | if (r > 0) { | |
229 | log_syntax(unit, LOG_ERR, filename, line, 0, "geneve invalid multicast '%s' address, ignoring assignment: %s", lvalue, rvalue); | |
230 | return 0; | |
231 | } | |
232 | ||
233 | v->remote_family = f; | |
234 | *addr = buffer; | |
235 | ||
236 | return 0; | |
237 | } | |
238 | ||
6598e046 SS |
239 | int config_parse_geneve_flow_label(const char *unit, |
240 | const char *filename, | |
241 | unsigned line, | |
242 | const char *section, | |
243 | unsigned section_line, | |
244 | const char *lvalue, | |
245 | int ltype, | |
246 | const char *rvalue, | |
247 | void *data, | |
248 | void *userdata) { | |
249 | Geneve *v = userdata; | |
250 | uint32_t f; | |
251 | int r; | |
252 | ||
253 | assert(filename); | |
254 | assert(lvalue); | |
255 | assert(rvalue); | |
256 | assert(data); | |
257 | ||
258 | r = safe_atou32(rvalue, &f); | |
259 | if (r < 0) { | |
260 | log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Geneve flow label '%s'.", rvalue); | |
261 | return 0; | |
262 | } | |
263 | ||
264 | if (f & ~GENEVE_FLOW_LABEL_MAX_MASK) { | |
265 | log_syntax(unit, LOG_ERR, filename, line, r, | |
266 | "Geneve flow label '%s' not valid. Flow label range should be [0-1048575].", rvalue); | |
267 | return 0; | |
268 | } | |
269 | ||
270 | v->flow_label = f; | |
271 | ||
272 | return 0; | |
273 | } | |
274 | ||
d70c9bbd SS |
275 | int config_parse_geneve_ttl(const char *unit, |
276 | const char *filename, | |
277 | unsigned line, | |
278 | const char *section, | |
279 | unsigned section_line, | |
280 | const char *lvalue, | |
281 | int ltype, | |
282 | const char *rvalue, | |
283 | void *data, | |
284 | void *userdata) { | |
285 | Geneve *v = userdata; | |
286 | unsigned f; | |
287 | int r; | |
288 | ||
289 | assert(filename); | |
290 | assert(lvalue); | |
291 | assert(rvalue); | |
292 | assert(data); | |
293 | ||
294 | if (streq(rvalue, "inherit")) | |
295 | v->inherit = true; | |
296 | else { | |
297 | r = safe_atou(rvalue, &f); | |
298 | if (r < 0) { | |
299 | log_syntax(unit, LOG_ERR, filename, line, r, | |
300 | "Failed to parse Geneve TTL '%s', ignoring assignment: %m", rvalue); | |
301 | return 0; | |
302 | } | |
303 | ||
304 | if (f > 255) { | |
305 | log_syntax(unit, LOG_ERR, filename, line, 0, | |
306 | "Invalid Geneve TTL '%s'. TTL must be <= 255. Ignoring assignment.", rvalue); | |
307 | return 0; | |
308 | } | |
309 | ||
310 | v->ttl = f; | |
311 | } | |
312 | ||
313 | return 0; | |
314 | } | |
315 | ||
3ded5bbf SS |
316 | static int netdev_geneve_verify(NetDev *netdev, const char *filename) { |
317 | Geneve *v = GENEVE(netdev); | |
318 | ||
319 | assert(netdev); | |
320 | assert(v); | |
321 | assert(filename); | |
322 | ||
328184d1 SS |
323 | if (v->id > GENEVE_VID_MAX) |
324 | return log_netdev_warning_errno(netdev, SYNTHETIC_ERRNO(EINVAL), | |
325 | "%s: Geneve without valid VNI (or Virtual Network Identifier) configured. Ignoring.", | |
326 | filename); | |
3ded5bbf SS |
327 | |
328 | return 0; | |
329 | } | |
330 | ||
6598e046 SS |
331 | static void geneve_init(NetDev *netdev) { |
332 | Geneve *v; | |
333 | ||
334 | assert(netdev); | |
335 | ||
336 | v = GENEVE(netdev); | |
337 | ||
338 | assert(v); | |
339 | ||
340 | v->id = GENEVE_VID_MAX + 1; | |
aac35019 | 341 | v->geneve_df = _NETDEV_GENEVE_DF_INVALID; |
6598e046 SS |
342 | v->dest_port = DEFAULT_GENEVE_DESTINATION_PORT; |
343 | v->udpcsum = false; | |
344 | v->udp6zerocsumtx = false; | |
345 | v->udp6zerocsumrx = false; | |
346 | } | |
347 | ||
348 | const NetDevVTable geneve_vtable = { | |
349 | .object_size = sizeof(Geneve), | |
350 | .init = geneve_init, | |
130b812f | 351 | .sections = NETDEV_COMMON_SECTIONS "GENEVE\0", |
6598e046 SS |
352 | .create = netdev_geneve_create, |
353 | .create_type = NETDEV_CREATE_INDEPENDENT, | |
3ded5bbf | 354 | .config_verify = netdev_geneve_verify, |
daf0f8ca | 355 | .generate_mac = true, |
6598e046 | 356 | }; |