/src/systemd/src/network/netdev/geneve.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
2 | | |
3 | | #include <linux/if_arp.h> |
4 | | |
5 | | #include "sd-netlink.h" |
6 | | |
7 | | #include "conf-parser.h" |
8 | | #include "geneve.h" |
9 | | #include "parse-util.h" |
10 | | #include "string-table.h" |
11 | | #include "string-util.h" |
12 | | |
13 | 430 | #define GENEVE_FLOW_LABEL_MAX_MASK 0xFFFFFU |
14 | 333 | #define DEFAULT_GENEVE_DESTINATION_PORT 6081 |
15 | | |
16 | | static const char* const geneve_df_table[_NETDEV_GENEVE_DF_MAX] = { |
17 | | [NETDEV_GENEVE_DF_NO] = "no", |
18 | | [NETDEV_GENEVE_DF_YES] = "yes", |
19 | | [NETDEV_GENEVE_DF_INHERIT] = "inherit", |
20 | | }; |
21 | | |
22 | | DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(geneve_df, GeneveDF, NETDEV_GENEVE_DF_YES); |
23 | | DEFINE_CONFIG_PARSE_ENUM(config_parse_geneve_df, geneve_df, GeneveDF); |
24 | | |
25 | 0 | static int netdev_geneve_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { |
26 | 0 | assert(m); |
27 | |
|
28 | 0 | Geneve *v = GENEVE(netdev); |
29 | 0 | int r; |
30 | |
|
31 | 0 | if (v->id <= GENEVE_VID_MAX) { |
32 | 0 | r = sd_netlink_message_append_u32(m, IFLA_GENEVE_ID, v->id); |
33 | 0 | if (r < 0) |
34 | 0 | return r; |
35 | 0 | } |
36 | | |
37 | 0 | if (in_addr_is_set(v->remote_family, &v->remote)) { |
38 | 0 | if (v->remote_family == AF_INET) |
39 | 0 | r = sd_netlink_message_append_in_addr(m, IFLA_GENEVE_REMOTE, &v->remote.in); |
40 | 0 | else |
41 | 0 | r = sd_netlink_message_append_in6_addr(m, IFLA_GENEVE_REMOTE6, &v->remote.in6); |
42 | 0 | if (r < 0) |
43 | 0 | return r; |
44 | 0 | } |
45 | | |
46 | 0 | if (v->inherit) { |
47 | 0 | r = sd_netlink_message_append_u8(m, IFLA_GENEVE_TTL_INHERIT, 1); |
48 | 0 | if (r < 0) |
49 | 0 | return r; |
50 | 0 | } else { |
51 | 0 | r = sd_netlink_message_append_u8(m, IFLA_GENEVE_TTL, v->ttl); |
52 | 0 | if (r < 0) |
53 | 0 | return r; |
54 | 0 | } |
55 | | |
56 | 0 | r = sd_netlink_message_append_u8(m, IFLA_GENEVE_TOS, v->tos); |
57 | 0 | if (r < 0) |
58 | 0 | return r; |
59 | | |
60 | 0 | r = sd_netlink_message_append_u8(m, IFLA_GENEVE_UDP_CSUM, v->udpcsum); |
61 | 0 | if (r < 0) |
62 | 0 | return r; |
63 | | |
64 | 0 | r = sd_netlink_message_append_u8(m, IFLA_GENEVE_UDP_ZERO_CSUM6_TX, v->udp6zerocsumtx); |
65 | 0 | if (r < 0) |
66 | 0 | return r; |
67 | | |
68 | 0 | r = sd_netlink_message_append_u8(m, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, v->udp6zerocsumrx); |
69 | 0 | if (r < 0) |
70 | 0 | return r; |
71 | | |
72 | 0 | if (v->dest_port != DEFAULT_GENEVE_DESTINATION_PORT) { |
73 | 0 | r = sd_netlink_message_append_u16(m, IFLA_GENEVE_PORT, htobe16(v->dest_port)); |
74 | 0 | if (r < 0) |
75 | 0 | return r; |
76 | 0 | } |
77 | | |
78 | 0 | if (v->flow_label > 0) { |
79 | 0 | r = sd_netlink_message_append_u32(m, IFLA_GENEVE_LABEL, htobe32(v->flow_label)); |
80 | 0 | if (r < 0) |
81 | 0 | return r; |
82 | 0 | } |
83 | | |
84 | 0 | if (v->inherit_inner_protocol) { |
85 | 0 | r = sd_netlink_message_append_flag(m, IFLA_GENEVE_INNER_PROTO_INHERIT); |
86 | 0 | if (r < 0) |
87 | 0 | return r; |
88 | 0 | } |
89 | | |
90 | 0 | if (v->geneve_df != _NETDEV_GENEVE_DF_INVALID) { |
91 | 0 | r = sd_netlink_message_append_u8(m, IFLA_GENEVE_DF, v->geneve_df); |
92 | 0 | if (r < 0) |
93 | 0 | return r; |
94 | 0 | } |
95 | | |
96 | 0 | return 0; |
97 | 0 | } |
98 | | |
99 | | int config_parse_geneve_vni( |
100 | | const char *unit, |
101 | | const char *filename, |
102 | | unsigned line, |
103 | | const char *section, |
104 | | unsigned section_line, |
105 | | const char *lvalue, |
106 | | int ltype, |
107 | | const char *rvalue, |
108 | | void *data, |
109 | 623 | void *userdata) { |
110 | | |
111 | 623 | assert(filename); |
112 | 623 | assert(lvalue); |
113 | 623 | assert(rvalue); |
114 | 623 | assert(data); |
115 | | |
116 | 623 | Geneve *v = ASSERT_PTR(userdata); |
117 | | |
118 | 623 | return config_parse_uint32_bounded( |
119 | 623 | unit, filename, line, section, section_line, lvalue, rvalue, |
120 | 623 | 0, GENEVE_VID_MAX, true, |
121 | 623 | &v->id); |
122 | 623 | } |
123 | | |
124 | | int config_parse_geneve_address( |
125 | | const char *unit, |
126 | | const char *filename, |
127 | | unsigned line, |
128 | | const char *section, |
129 | | unsigned section_line, |
130 | | const char *lvalue, |
131 | | int ltype, |
132 | | const char *rvalue, |
133 | | void *data, |
134 | 608 | void *userdata) { |
135 | | |
136 | 608 | assert(filename); |
137 | 608 | assert(lvalue); |
138 | 608 | assert(rvalue); |
139 | 608 | assert(data); |
140 | | |
141 | 608 | Geneve *v = ASSERT_PTR(userdata); |
142 | 608 | union in_addr_union *addr = data, buffer; |
143 | 608 | int r, f; |
144 | | |
145 | 608 | r = in_addr_from_string_auto(rvalue, &f, &buffer); |
146 | 608 | if (r < 0) { |
147 | 215 | log_syntax(unit, LOG_WARNING, filename, line, r, |
148 | 215 | "geneve '%s' address is invalid, ignoring assignment: %s", lvalue, rvalue); |
149 | 215 | return 0; |
150 | 215 | } |
151 | | |
152 | 393 | r = in_addr_is_multicast(f, &buffer); |
153 | 393 | if (r > 0) { |
154 | 195 | log_syntax(unit, LOG_WARNING, filename, line, 0, |
155 | 195 | "geneve invalid multicast '%s' address, ignoring assignment: %s", lvalue, rvalue); |
156 | 195 | return 0; |
157 | 195 | } |
158 | | |
159 | 198 | v->remote_family = f; |
160 | 198 | *addr = buffer; |
161 | | |
162 | 198 | return 0; |
163 | 393 | } |
164 | | |
165 | | int config_parse_geneve_flow_label( |
166 | | const char *unit, |
167 | | const char *filename, |
168 | | unsigned line, |
169 | | const char *section, |
170 | | unsigned section_line, |
171 | | const char *lvalue, |
172 | | int ltype, |
173 | | const char *rvalue, |
174 | | void *data, |
175 | 647 | void *userdata) { |
176 | | |
177 | 647 | assert(filename); |
178 | 647 | assert(lvalue); |
179 | 647 | assert(rvalue); |
180 | 647 | assert(data); |
181 | | |
182 | 647 | Geneve *v = ASSERT_PTR(userdata); |
183 | 647 | uint32_t f; |
184 | 647 | int r; |
185 | | |
186 | 647 | r = safe_atou32(rvalue, &f); |
187 | 647 | if (r < 0) { |
188 | 217 | log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse Geneve flow label '%s'.", rvalue); |
189 | 217 | return 0; |
190 | 217 | } |
191 | | |
192 | 430 | if (f & ~GENEVE_FLOW_LABEL_MAX_MASK) { |
193 | 216 | log_syntax(unit, LOG_WARNING, filename, line, 0, |
194 | 216 | "Geneve flow label '%s' not valid. Flow label range should be [0-1048575].", rvalue); |
195 | 216 | return 0; |
196 | 216 | } |
197 | | |
198 | 214 | v->flow_label = f; |
199 | | |
200 | 214 | return 0; |
201 | 430 | } |
202 | | |
203 | | int config_parse_geneve_ttl( |
204 | | const char *unit, |
205 | | const char *filename, |
206 | | unsigned line, |
207 | | const char *section, |
208 | | unsigned section_line, |
209 | | const char *lvalue, |
210 | | int ltype, |
211 | | const char *rvalue, |
212 | | void *data, |
213 | 649 | void *userdata) { |
214 | | |
215 | 649 | assert(filename); |
216 | 649 | assert(lvalue); |
217 | 649 | assert(rvalue); |
218 | 649 | assert(data); |
219 | | |
220 | 649 | Geneve *v = ASSERT_PTR(userdata); |
221 | 649 | int r; |
222 | | |
223 | 649 | if (streq(rvalue, "inherit")) { |
224 | 194 | v->inherit = true; |
225 | 194 | v->ttl = 0; /* unset the unused ttl field for clarity */ |
226 | 194 | return 0; |
227 | 194 | } |
228 | | |
229 | 455 | r = config_parse_uint8_bounded( |
230 | 455 | unit, filename, line, section, section_line, lvalue, rvalue, |
231 | 455 | 0, UINT8_MAX, true, |
232 | 455 | &v->ttl); |
233 | 455 | if (r <= 0) |
234 | 255 | return r; |
235 | 200 | v->inherit = false; |
236 | 200 | return 0; |
237 | 455 | } |
238 | | |
239 | 333 | static int netdev_geneve_verify(NetDev *netdev, const char *filename) { |
240 | 333 | assert(filename); |
241 | | |
242 | 333 | Geneve *v = GENEVE(netdev); |
243 | | |
244 | 333 | if (v->id > GENEVE_VID_MAX) |
245 | 294 | return log_netdev_warning_errno(netdev, SYNTHETIC_ERRNO(EINVAL), |
246 | 39 | "%s: Geneve without valid VNI (or Virtual Network Identifier) configured. Ignoring.", |
247 | 39 | filename); |
248 | 39 | return 0; |
249 | 333 | } |
250 | | |
251 | 0 | static bool geneve_can_set_mac(NetDev *netdev, const struct hw_addr_data *hw_addr) { |
252 | 0 | return true; |
253 | 0 | } |
254 | | |
255 | 333 | static void geneve_init(NetDev *netdev) { |
256 | 333 | Geneve *v = GENEVE(netdev); |
257 | | |
258 | 333 | v->id = GENEVE_VID_MAX + 1; |
259 | 333 | v->geneve_df = _NETDEV_GENEVE_DF_INVALID; |
260 | 333 | v->dest_port = DEFAULT_GENEVE_DESTINATION_PORT; |
261 | 333 | v->udpcsum = false; |
262 | 333 | v->udp6zerocsumtx = false; |
263 | 333 | v->udp6zerocsumrx = false; |
264 | 333 | } |
265 | | |
266 | | const NetDevVTable geneve_vtable = { |
267 | | .object_size = sizeof(Geneve), |
268 | | .init = geneve_init, |
269 | | .sections = NETDEV_COMMON_SECTIONS "GENEVE\0", |
270 | | .fill_message_create = netdev_geneve_fill_message_create, |
271 | | .create_type = NETDEV_CREATE_INDEPENDENT, |
272 | | .config_verify = netdev_geneve_verify, |
273 | | .can_set_mac = geneve_can_set_mac, |
274 | | .iftype = ARPHRD_ETHER, |
275 | | .generate_mac = true, |
276 | | }; |