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