1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2025-2026 Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/param.h>
30 #include <sys/ioctl.h>
31 #include <sys/nv.h>
32 #include <sys/socket.h>
33 #include <sys/sockio.h>
34
35 #include <stdlib.h>
36 #include <stdint.h>
37 #include <unistd.h>
38 #include <netdb.h>
39
40 #include <net/ethernet.h>
41 #include <net/if.h>
42 #include <net/if_strings.h>
43 #include <netinet/in.h>
44 #include <net/if_geneve.h>
45
46 #include <stdio.h>
47 #include <string.h>
48 #include <stdlib.h>
49 #include <unistd.h>
50 #include <err.h>
51 #include <errno.h>
52
53 #include "ifconfig.h"
54 #include "ifconfig_netlink.h"
55
56 struct nl_parsed_geneve {
57 /* essential */
58 uint32_t ifla_vni;
59 uint16_t ifla_proto;
60 struct sockaddr *ifla_local;
61 struct sockaddr *ifla_remote;
62 uint16_t ifla_local_port;
63 uint16_t ifla_remote_port;
64
65 /* optional */
66 struct ifla_geneve_port_range *ifla_port_range;
67 enum ifla_geneve_df ifla_df;
68 uint8_t ifla_ttl;
69 bool ifla_ttl_inherit;
70 bool ifla_dscp_inherit;
71 bool ifla_external;
72
73 /* l2 specific */
74 bool ifla_ftable_learn;
75 bool ifla_ftable_flush;
76 uint32_t ifla_ftable_max;
77 uint32_t ifla_ftable_timeout;
78 uint32_t ifla_ftable_count;
79 uint32_t ifla_ftable_nospace;
80 uint32_t ifla_ftable_lock_upgrade_failed;
81
82 /* multicast specific */
83 char *ifla_mc_ifname;
84 uint32_t ifla_mc_ifindex;
85
86 /* csum info */
87 uint64_t ifla_stats_txcsum;
88 uint64_t ifla_stats_tso;
89 uint64_t ifla_stats_rxcsum;
90 };
91
92 static struct geneve_params gnvp = {
93 .ifla_proto = GENEVE_PROTO_ETHER,
94 };
95
96 static int
get_proto(const char * cp,uint16_t * valp)97 get_proto(const char *cp, uint16_t *valp)
98 {
99 uint16_t val;
100
101 if (!strcmp(cp, "l2"))
102 val = GENEVE_PROTO_ETHER;
103 else if (!strcmp(cp, "l3"))
104 val = GENEVE_PROTO_INHERIT;
105 else
106 return (-1);
107
108 *valp = val;
109 return (0);
110 }
111
112 static int
get_val(const char * cp,u_long * valp)113 get_val(const char *cp, u_long *valp)
114 {
115 char *endptr;
116 u_long val;
117
118 errno = 0;
119 val = strtoul(cp, &endptr, 0);
120 if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE)
121 return (-1);
122
123 *valp = val;
124 return (0);
125 }
126
127 static int
get_df(const char * cp,enum ifla_geneve_df * valp)128 get_df(const char *cp, enum ifla_geneve_df *valp)
129 {
130 enum ifla_geneve_df df;
131
132 if (!strcmp(cp, "set"))
133 df = IFLA_GENEVE_DF_SET;
134 else if (!strcmp(cp, "inherit"))
135 df = IFLA_GENEVE_DF_INHERIT;
136 else if (!strcmp(cp, "unset"))
137 df = IFLA_GENEVE_DF_UNSET;
138 else
139 return (-1);
140
141 *valp = df;
142 return (0);
143 }
144
145 static bool
is_multicast(struct addrinfo * ai)146 is_multicast(struct addrinfo *ai)
147 {
148 #if (defined INET || defined INET6)
149 struct sockaddr *sa;
150 sa = ai->ai_addr;
151 #endif
152
153 switch (ai->ai_family) {
154 #ifdef INET
155 case AF_INET: {
156 struct sockaddr_in *sin = satosin(sa);
157
158 return (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)));
159 }
160 #endif
161 #ifdef INET6
162 case AF_INET6: {
163 struct sockaddr_in6 *sin6 = satosin6(sa);
164
165 return (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr));
166 }
167 #endif
168 default:
169 errx(1, "address family not supported");
170 }
171 }
172
173 /*
174 * geneve mode is read-only after creation,
175 * therefore there is no need for separate netlink implementation
176 */
177 static void
setgeneve_mode_clone(if_ctx * ctx __unused,const char * arg,int dummy __unused)178 setgeneve_mode_clone(if_ctx *ctx __unused, const char *arg, int dummy __unused)
179 {
180 uint16_t val;
181
182 if (get_proto(arg, &val) < 0)
183 errx(1, "invalid inner protocol: %s", arg);
184
185 gnvp.ifla_proto = val;
186 }
187
188 struct nla_geneve_info {
189 const char *kind;
190 struct nl_parsed_geneve data;
191 };
192
193 struct nla_geneve_link {
194 uint32_t ifi_index;
195 struct nla_geneve_info linkinfo;
196 };
197
198 static inline void
geneve_nl_init(if_ctx * ctx,struct snl_writer * nw,uint32_t flags)199 geneve_nl_init(if_ctx *ctx, struct snl_writer *nw, uint32_t flags)
200 {
201 struct nlmsghdr *hdr;
202
203 snl_init_writer(ctx->io_ss, nw);
204 hdr = snl_create_msg_request(nw, NL_RTM_NEWLINK);
205 hdr->nlmsg_flags |= flags;
206 snl_reserve_msg_object(nw, struct ifinfomsg);
207 snl_add_msg_attr_string(nw, IFLA_IFNAME, ctx->ifname);
208 }
209
210 static inline void
geneve_nl_fini(if_ctx * ctx,struct snl_writer * nw)211 geneve_nl_fini(if_ctx *ctx, struct snl_writer *nw)
212 {
213 struct nlmsghdr *hdr;
214 struct snl_errmsg_data errmsg = {};
215
216 hdr = snl_finalize_msg(nw);
217 if (hdr == NULL || !snl_send_message(ctx->io_ss, hdr))
218 err(1, "unable to send netlink message");
219
220 if (!snl_read_reply_code(ctx->io_ss, hdr->nlmsg_seq, &errmsg))
221 errx(errmsg.error, "%s", errmsg.error_str);
222 }
223
224 #define _OUT(_field) offsetof(struct nl_parsed_geneve, _field)
225 static const struct snl_attr_parser nla_geneve_linkinfo_data[] = {
226 { .type = IFLA_GENEVE_ID, .off = _OUT(ifla_vni), .cb = snl_attr_get_uint32 },
227 { .type = IFLA_GENEVE_PROTOCOL, .off = _OUT(ifla_proto), .cb = snl_attr_get_uint16 },
228 { .type = IFLA_GENEVE_LOCAL, .off = _OUT(ifla_local), .cb = snl_attr_get_ip },
229 { .type = IFLA_GENEVE_REMOTE, .off = _OUT(ifla_remote), .cb = snl_attr_get_ip },
230 { .type = IFLA_GENEVE_LOCAL_PORT, .off = _OUT(ifla_local_port), .cb = snl_attr_get_uint16 },
231 { .type = IFLA_GENEVE_PORT, .off = _OUT(ifla_remote_port), .cb = snl_attr_get_uint16 },
232 { .type = IFLA_GENEVE_PORT_RANGE, .off = _OUT(ifla_port_range), .cb = snl_attr_dup_struct },
233 { .type = IFLA_GENEVE_DF, .off = _OUT(ifla_df), .cb = snl_attr_get_uint8 },
234 { .type = IFLA_GENEVE_TTL, .off = _OUT(ifla_ttl), .cb = snl_attr_get_uint8 },
235 { .type = IFLA_GENEVE_TTL_INHERIT, .off = _OUT(ifla_ttl_inherit), .cb = snl_attr_get_bool },
236 { .type = IFLA_GENEVE_DSCP_INHERIT, .off = _OUT(ifla_dscp_inherit), .cb = snl_attr_get_bool },
237 { .type = IFLA_GENEVE_COLLECT_METADATA, .off = _OUT(ifla_external), .cb = snl_attr_get_bool },
238 { .type = IFLA_GENEVE_FTABLE_LEARN, .off = _OUT(ifla_ftable_learn), .cb = snl_attr_get_bool },
239 { .type = IFLA_GENEVE_FTABLE_FLUSH, .off = _OUT(ifla_ftable_flush), .cb = snl_attr_get_bool },
240 { .type = IFLA_GENEVE_FTABLE_MAX, .off = _OUT(ifla_ftable_max), .cb = snl_attr_get_uint32 },
241 { .type = IFLA_GENEVE_FTABLE_TIMEOUT, .off = _OUT(ifla_ftable_timeout), .cb = snl_attr_get_uint32 },
242 { .type = IFLA_GENEVE_FTABLE_COUNT, .off = _OUT(ifla_ftable_count), .cb = snl_attr_get_uint32 },
243 { .type = IFLA_GENEVE_FTABLE_NOSPACE_CNT, .off = _OUT(ifla_ftable_nospace), .cb = snl_attr_get_uint32 },
244 { .type = IFLA_GENEVE_FTABLE_LOCK_UP_FAIL_CNT, .off = _OUT(ifla_ftable_lock_upgrade_failed), .cb = snl_attr_get_uint32 },
245 { .type = IFLA_GENEVE_MC_IFNAME, .off = _OUT(ifla_mc_ifname), .cb = snl_attr_get_string },
246 { .type = IFLA_GENEVE_MC_IFINDEX, .off = _OUT(ifla_mc_ifindex), .cb = snl_attr_get_uint32 },
247 { .type = IFLA_GENEVE_TXCSUM_CNT, .off = _OUT(ifla_stats_txcsum), .cb = snl_attr_get_uint64 },
248 { .type = IFLA_GENEVE_TSO_CNT, .off = _OUT(ifla_stats_tso), .cb = snl_attr_get_uint64 },
249 { .type = IFLA_GENEVE_RXCSUM_CNT, .off = _OUT(ifla_stats_rxcsum), .cb = snl_attr_get_uint64 },
250 };
251 #undef _OUT
252 SNL_DECLARE_ATTR_PARSER(geneve_linkinfo_data_parser, nla_geneve_linkinfo_data);
253
254 #define _OUT(_field) offsetof(struct nla_geneve_info, _field)
255 static const struct snl_attr_parser ap_geneve_linkinfo[] = {
256 { .type = IFLA_INFO_KIND, .off = _OUT(kind), .cb = snl_attr_get_string },
257 { .type = IFLA_INFO_DATA, .off = _OUT(data),
258 .arg = &geneve_linkinfo_data_parser, .cb = snl_attr_get_nested },
259 };
260 #undef _OUT
261 SNL_DECLARE_ATTR_PARSER(geneve_linkinfo_parser, ap_geneve_linkinfo);
262
263 #define _IN(_field) offsetof(struct ifinfomsg, _field)
264 #define _OUT(_field) offsetof(struct nla_geneve_link, _field)
265 static const struct snl_attr_parser ap_geneve_link[] = {
266 { .type = IFLA_LINKINFO, .off = _OUT(linkinfo),
267 .arg = &geneve_linkinfo_parser, .cb = snl_attr_get_nested },
268 };
269
270 static const struct snl_field_parser fp_geneve_link[] = {
271 { .off_in = _IN(ifi_index), .off_out = _OUT(ifi_index), .cb = snl_field_get_uint32 },
272 };
273 #undef _IN
274 #undef _OUT
275 SNL_DECLARE_PARSER(geneve_parser, struct ifinfomsg, fp_geneve_link, ap_geneve_link);
276
277 static const struct snl_hdr_parser *all_parsers[] = {
278 &geneve_linkinfo_data_parser,
279 &geneve_linkinfo_parser,
280 &geneve_parser,
281 };
282
283 static void
geneve_status_nl(if_ctx * ctx)284 geneve_status_nl(if_ctx *ctx)
285 {
286 struct snl_writer nw;
287 struct nlmsghdr *hdr;
288 struct snl_errmsg_data errmsg;
289 struct nla_geneve_link geneve_link;
290 char src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN];
291 struct sockaddr *lsa, *rsa;
292 int mc;
293 bool ipv6 = false;
294
295 if (strncmp(ctx->ifname, "geneve", sizeof("geneve") - 1) != 0)
296 return;
297
298 snl_init_writer(ctx->io_ss, &nw);
299 hdr = snl_create_msg_request(&nw, NL_RTM_GETLINK);
300 hdr->nlmsg_flags |= NLM_F_DUMP;
301 snl_reserve_msg_object(&nw, struct ifinfomsg);
302 snl_add_msg_attr_string(&nw, IFLA_IFNAME, ctx->ifname);
303
304 if (!(hdr = snl_finalize_msg(&nw)) || (!snl_send_message(ctx->io_ss, hdr)))
305 return;
306
307 hdr = snl_read_reply(ctx->io_ss, hdr->nlmsg_seq);
308 if (hdr->nlmsg_type != NL_RTM_NEWLINK) {
309 if (!snl_parse_errmsg(ctx->io_ss, hdr, &errmsg))
310 errx(EINVAL, "(NETLINK)");
311 if (errmsg.error_str != NULL)
312 errx(errmsg.error, "(NETLINK) %s", errmsg.error_str);
313 }
314
315 if (!snl_parse_nlmsg(ctx->io_ss, hdr, &geneve_parser, &geneve_link))
316 return;
317
318 struct nla_geneve_info geneve_info = geneve_link.linkinfo;
319 struct nl_parsed_geneve geneve_data = geneve_info.data;
320
321 printf("\tgeneve mode: ");
322 switch (geneve_data.ifla_proto) {
323 case GENEVE_PROTO_INHERIT:
324 printf("l3");
325 break;
326 case GENEVE_PROTO_ETHER:
327 default:
328 printf("l2");
329 break;
330 }
331
332 printf("\n\tgeneve config:\n");
333 /* Just report nothing if the network identity isn't set yet. */
334 if (geneve_data.ifla_vni >= GENEVE_VNI_MAX) {
335 printf("\t\tvirtual network identifier (vni): not configured\n");
336 return;
337 }
338
339 lsa = geneve_data.ifla_local;
340 rsa = geneve_data.ifla_remote;
341
342 if ((lsa == NULL) ||
343 (getnameinfo(lsa, lsa->sa_len, src, sizeof(src),
344 NULL, 0, NI_NUMERICHOST) != 0))
345 src[0] = '\0';
346 if ((rsa == NULL) ||
347 (getnameinfo(rsa, rsa->sa_len, dst, sizeof(dst),
348 NULL, 0, NI_NUMERICHOST) != 0))
349 dst[0] = '\0';
350 else {
351 ipv6 = rsa->sa_family == AF_INET6;
352 if (!ipv6) {
353 struct sockaddr_in *sin = satosin(rsa);
354 mc = IN_MULTICAST(ntohl(sin->sin_addr.s_addr));
355 } else {
356 struct sockaddr_in6 *sin6 = satosin6(rsa);
357 mc = IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr);
358 }
359 }
360
361 printf("\t\tvirtual network identifier (vni): %d", geneve_data.ifla_vni);
362 if (src[0] != '\0')
363 printf("\n\t\tlocal: %s%s%s:%u", ipv6 ? "[" : "", src, ipv6 ? "]" : "",
364 geneve_data.ifla_local_port);
365 if (dst[0] != '\0') {
366 printf("\n\t\t%s: %s%s%s:%u", mc ? "group" : "remote", ipv6 ? "[" : "",
367 dst, ipv6 ? "]" : "", geneve_data.ifla_local_port);
368 if (mc)
369 printf(", dev: %s", geneve_data.ifla_mc_ifname);
370 }
371
372 if (ctx->args->verbose) {
373 printf("\n\t\tportrange: %u-%u",
374 geneve_data.ifla_port_range->low,
375 geneve_data.ifla_port_range->high);
376
377 if (geneve_data.ifla_ttl_inherit)
378 printf(", ttl: inherit");
379 else
380 printf(", ttl: %d", geneve_data.ifla_ttl);
381
382 if (geneve_data.ifla_dscp_inherit)
383 printf(", dscp: inherit");
384
385 if (geneve_data.ifla_df == IFLA_GENEVE_DF_INHERIT)
386 printf(", df: inherit");
387 else if (geneve_data.ifla_df == IFLA_GENEVE_DF_SET)
388 printf(", df: set");
389 else if (geneve_data.ifla_df == IFLA_GENEVE_DF_UNSET)
390 printf(", df: unset");
391
392 if (geneve_data.ifla_external)
393 printf(", externally controlled");
394
395 if (geneve_data.ifla_proto == GENEVE_PROTO_ETHER) {
396 printf("\n\t\tftable mode: %slearning",
397 geneve_data.ifla_ftable_learn ? "" : "no");
398 printf(", count: %d, max: %d, timeout: %d",
399 geneve_data.ifla_ftable_count,
400 geneve_data.ifla_ftable_max,
401 geneve_data.ifla_ftable_timeout);
402 printf(", nospace: %u",
403 geneve_data.ifla_ftable_nospace);
404 }
405
406 printf("\n\t\tstats: tso %ju, txcsum %ju, rxcsum %ju",
407 (uintmax_t)geneve_data.ifla_stats_tso,
408 (uintmax_t)geneve_data.ifla_stats_txcsum,
409 (uintmax_t)geneve_data.ifla_stats_rxcsum);
410 }
411
412 putchar('\n');
413 }
414
415
416 static void
geneve_create_nl(if_ctx * ctx,struct ifreq * ifr)417 geneve_create_nl(if_ctx *ctx, struct ifreq *ifr)
418 {
419 struct snl_writer nw = {};
420 struct nlmsghdr *hdr;
421 int off, off2;
422
423 snl_init_writer(ctx->io_ss, &nw);
424 hdr = snl_create_msg_request(&nw, RTM_NEWLINK);
425 hdr->nlmsg_flags |= (NLM_F_CREATE | NLM_F_EXCL);
426 snl_reserve_msg_object(&nw, struct ifinfomsg);
427 snl_add_msg_attr_string(&nw, IFLA_IFNAME, ifr->ifr_name);
428
429 off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
430 snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
431
432 off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
433 snl_add_msg_attr_u16(&nw, IFLA_GENEVE_PROTOCOL, gnvp.ifla_proto);
434
435 snl_end_attr_nested(&nw, off2);
436 snl_end_attr_nested(&nw, off);
437
438 geneve_nl_fini(ctx, &nw);
439 }
440
441 static void
setgeneve_vni_nl(if_ctx * ctx,const char * arg,int dummy __unused)442 setgeneve_vni_nl(if_ctx *ctx, const char *arg, int dummy __unused)
443 {
444 struct snl_writer nw = {};
445 int off, off2;
446 u_long val;
447
448 if (get_val(arg, &val) < 0 || val >= GENEVE_VNI_MAX)
449 errx(1, "invalid network identifier: %s", arg);
450
451 geneve_nl_init(ctx, &nw, 0);
452 off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
453 snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
454
455 off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
456 snl_add_msg_attr_u32(&nw, IFLA_GENEVE_ID, val);
457
458 snl_end_attr_nested(&nw, off2);
459 snl_end_attr_nested(&nw, off);
460
461 geneve_nl_fini(ctx, &nw);
462 }
463
464 static void
setgeneve_local_nl(if_ctx * ctx,const char * addr,int dummy __unused)465 setgeneve_local_nl(if_ctx *ctx, const char *addr, int dummy __unused)
466 {
467 struct snl_writer nw = {};
468 int off, off2;
469 struct addrinfo *ai;
470 const struct sockaddr *sa;
471 int error;
472
473 if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0)
474 errx(1, "error in parsing local address string: %s",
475 gai_strerror(error));
476
477 if (is_multicast(ai))
478 errx(1, "local address cannot be multicast");
479
480 geneve_nl_init(ctx, &nw, 0);
481 off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
482 snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
483
484 off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
485
486 sa = ai->ai_addr;
487 snl_add_msg_attr_ip(&nw, IFLA_GENEVE_LOCAL, sa);
488
489 snl_end_attr_nested(&nw, off2);
490 snl_end_attr_nested(&nw, off);
491
492 geneve_nl_fini(ctx, &nw);
493 }
494
495 static void
setgeneve_remote_nl(if_ctx * ctx,const char * addr,int dummy __unused)496 setgeneve_remote_nl(if_ctx *ctx, const char *addr, int dummy __unused)
497 {
498 struct snl_writer nw = {};
499 int off, off2;
500 struct addrinfo *ai;
501 const struct sockaddr *sa;
502 int error;
503
504 if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0)
505 errx(1, "error in parsing remote address string: %s",
506 gai_strerror(error));
507
508 if (is_multicast(ai))
509 errx(1, "remote address cannot be multicast");
510
511 geneve_nl_init(ctx, &nw, 0);
512 off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
513 snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
514
515 off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
516
517 sa = ai->ai_addr;
518 snl_add_msg_attr_ip(&nw, IFLA_GENEVE_REMOTE, sa);
519
520 snl_end_attr_nested(&nw, off2);
521 snl_end_attr_nested(&nw, off);
522
523 geneve_nl_fini(ctx, &nw);
524 }
525
526 static void
setgeneve_group_nl(if_ctx * ctx,const char * addr,int dummy __unused)527 setgeneve_group_nl(if_ctx *ctx, const char *addr, int dummy __unused)
528 {
529 struct snl_writer nw = {};
530 int off, off2;
531 struct addrinfo *ai;
532 struct sockaddr *sa;
533 int error;
534
535 if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0)
536 errx(1, "error in parsing local address string: %s",
537 gai_strerror(error));
538
539 if (!is_multicast(ai))
540 errx(1, "group address must be multicast");
541
542 geneve_nl_init(ctx, &nw, 0);
543 off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
544 snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
545
546 off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
547
548 sa = ai->ai_addr;
549 snl_add_msg_attr_ip(&nw, IFLA_GENEVE_REMOTE, sa);
550
551 snl_end_attr_nested(&nw, off2);
552 snl_end_attr_nested(&nw, off);
553
554 geneve_nl_fini(ctx, &nw);
555 }
556
557
558 static void
setgeneve_local_port_nl(if_ctx * ctx,const char * arg,int dummy __unused)559 setgeneve_local_port_nl(if_ctx *ctx, const char *arg, int dummy __unused)
560 {
561 struct snl_writer nw = {};
562 int off, off2;
563 u_long val;
564
565 if (get_val(arg, &val) < 0 || val >= UINT16_MAX)
566 errx(1, "invalid local port: %s", arg);
567
568 geneve_nl_init(ctx, &nw, 0);
569 off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
570 snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
571
572 off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
573
574 snl_add_msg_attr_u16(&nw, IFLA_GENEVE_LOCAL_PORT, val);
575
576 snl_end_attr_nested(&nw, off2);
577 snl_end_attr_nested(&nw, off);
578
579 geneve_nl_fini(ctx, &nw);
580 }
581
582 static void
setgeneve_remote_port_nl(if_ctx * ctx,const char * arg,int dummy __unused)583 setgeneve_remote_port_nl(if_ctx *ctx, const char *arg, int dummy __unused)
584 {
585 struct snl_writer nw = {};
586 int off, off2;
587 u_long val;
588
589 if (get_val(arg, &val) < 0 || val >= UINT16_MAX)
590 errx(1, "invalid remote port: %s", arg);
591
592 geneve_nl_init(ctx, &nw, 0);
593 off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
594 snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
595
596 off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
597
598 snl_add_msg_attr_u16(&nw, IFLA_GENEVE_PORT, val);
599
600 snl_end_attr_nested(&nw, off2);
601 snl_end_attr_nested(&nw, off);
602
603 geneve_nl_fini(ctx, &nw);
604 }
605
606 static void
setgeneve_port_range_nl(if_ctx * ctx,const char * arg1,const char * arg2)607 setgeneve_port_range_nl(if_ctx *ctx, const char *arg1, const char *arg2)
608 {
609 struct snl_writer nw = {};
610 int off, off2;
611 u_long min, max;
612
613 if (get_val(arg1, &min) < 0 || min >= UINT16_MAX)
614 errx(1, "invalid port range minimum: %s", arg1);
615 if (get_val(arg2, &max) < 0 || max >= UINT16_MAX)
616 errx(1, "invalid port range maximum: %s", arg2);
617 if (max < min)
618 errx(1, "invalid port range");
619
620 const struct ifla_geneve_port_range port_range = {
621 .low = min,
622 .high = max
623 };
624
625 geneve_nl_init(ctx, &nw, 0);
626 off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
627 snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
628
629 off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
630
631 snl_add_msg_attr(&nw, IFLA_GENEVE_PORT_RANGE,
632 sizeof(port_range), (const void *)&port_range);
633
634 snl_end_attr_nested(&nw, off2);
635 snl_end_attr_nested(&nw, off);
636
637 geneve_nl_fini(ctx, &nw);
638 }
639
640 static void
setgeneve_timeout_nl(if_ctx * ctx,const char * arg,int dummy __unused)641 setgeneve_timeout_nl(if_ctx *ctx, const char *arg, int dummy __unused)
642 {
643 struct snl_writer nw = {};
644 int off, off2;
645 u_long val;
646
647 if (get_val(arg, &val) < 0 || (val & ~0xFFFFFFFF) != 0)
648 errx(1, "invalid timeout value: %s", arg);
649
650 geneve_nl_init(ctx, &nw, 0);
651 off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
652 snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
653
654 off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
655
656 snl_add_msg_attr_u32(&nw, IFLA_GENEVE_FTABLE_TIMEOUT, val);
657
658 snl_end_attr_nested(&nw, off2);
659 snl_end_attr_nested(&nw, off);
660
661 geneve_nl_fini(ctx, &nw);
662 }
663
664 static void
setgeneve_maxaddr_nl(if_ctx * ctx,const char * arg,int dummy __unused)665 setgeneve_maxaddr_nl(if_ctx *ctx, const char *arg, int dummy __unused)
666 {
667 struct snl_writer nw = {};
668 int off, off2;
669 u_long val;
670
671 if (get_val(arg, &val) < 0 || (val & ~0xFFFFFFFF) != 0)
672 errx(1, "invalid maxaddr value: %s", arg);
673
674 geneve_nl_init(ctx, &nw, 0);
675 off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
676 snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
677
678 off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
679
680 snl_add_msg_attr_u32(&nw, IFLA_GENEVE_FTABLE_MAX, val);
681
682 snl_end_attr_nested(&nw, off2);
683 snl_end_attr_nested(&nw, off);
684
685 geneve_nl_fini(ctx, &nw);
686 }
687
688 static void
setgeneve_dev_nl(if_ctx * ctx,const char * arg,int dummy __unused)689 setgeneve_dev_nl(if_ctx *ctx, const char *arg, int dummy __unused)
690 {
691 struct snl_writer nw = {};
692 int off, off2;
693
694 geneve_nl_init(ctx, &nw, 0);
695 off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
696 snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
697
698 off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
699
700 snl_add_msg_attr_string(&nw, IFLA_GENEVE_MC_IFNAME, arg);
701
702 snl_end_attr_nested(&nw, off2);
703 snl_end_attr_nested(&nw, off);
704
705 geneve_nl_fini(ctx, &nw);
706 }
707
708 static void
setgeneve_ttl_nl(if_ctx * ctx,const char * arg,int dummy __unused)709 setgeneve_ttl_nl(if_ctx *ctx, const char *arg, int dummy __unused)
710 {
711 struct snl_writer nw = {};
712 int off, off2;
713 u_long val;
714
715 geneve_nl_init(ctx, &nw, 0);
716 off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
717 snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
718
719 off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
720 if ((get_val(arg, &val) < 0 || val > 256) == 0) {
721 snl_add_msg_attr_u8(&nw, IFLA_GENEVE_TTL, val);
722 snl_add_msg_attr_bool(&nw, IFLA_GENEVE_TTL_INHERIT, false);
723 } else if (!strcmp(arg, "inherit")) {
724 snl_add_msg_attr_bool(&nw, IFLA_GENEVE_TTL_INHERIT, true);
725 } else
726 errx(1, "invalid TTL value: %s", arg);
727
728 snl_end_attr_nested(&nw, off2);
729 snl_end_attr_nested(&nw, off);
730
731 geneve_nl_fini(ctx, &nw);
732 }
733
734 static void
setgeneve_df_nl(if_ctx * ctx,const char * arg,int dummy __unused)735 setgeneve_df_nl(if_ctx *ctx, const char *arg, int dummy __unused)
736 {
737 struct snl_writer nw = {};
738 int off, off2;
739 enum ifla_geneve_df df;
740
741 if (get_df(arg, &df) < 0)
742 errx(1, "invalid df value: %s", arg);
743
744 geneve_nl_init(ctx, &nw, 0);
745 off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
746 snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
747
748 off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
749
750 snl_add_msg_attr_u8(&nw, IFLA_GENEVE_DF, df);
751
752 snl_end_attr_nested(&nw, off2);
753 snl_end_attr_nested(&nw, off);
754
755 geneve_nl_fini(ctx, &nw);
756 }
757
758 static void
setgeneve_inherit_dscp_nl(if_ctx * ctx,const char * arg __unused,int d)759 setgeneve_inherit_dscp_nl(if_ctx *ctx, const char *arg __unused, int d)
760 {
761 struct snl_writer nw = {};
762 int off, off2;
763
764 geneve_nl_init(ctx, &nw, 0);
765 off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
766 snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
767
768 off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
769
770 snl_add_msg_attr_bool(&nw, IFLA_GENEVE_DSCP_INHERIT, d != 0);
771
772 snl_end_attr_nested(&nw, off2);
773 snl_end_attr_nested(&nw, off);
774
775 geneve_nl_fini(ctx, &nw);
776 }
777
778 static void
setgeneve_learn_nl(if_ctx * ctx,const char * arg __unused,int d)779 setgeneve_learn_nl(if_ctx *ctx, const char *arg __unused, int d)
780 {
781 struct snl_writer nw = {};
782 int off, off2;
783
784 geneve_nl_init(ctx, &nw, 0);
785 off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
786 snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
787
788 off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
789
790 snl_add_msg_attr_bool(&nw, IFLA_GENEVE_FTABLE_LEARN, d != 0);
791
792 snl_end_attr_nested(&nw, off2);
793 snl_end_attr_nested(&nw, off);
794
795 geneve_nl_fini(ctx, &nw);
796 }
797
798 static void
setgeneve_flush_nl(if_ctx * ctx,const char * val __unused,int d)799 setgeneve_flush_nl(if_ctx *ctx, const char *val __unused, int d)
800 {
801 struct snl_writer nw = {};
802 int off, off2;
803
804 geneve_nl_init(ctx, &nw, 0);
805 off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
806 snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
807
808 off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
809
810 snl_add_msg_attr_bool(&nw, IFLA_GENEVE_FTABLE_FLUSH, d != 0);
811
812 snl_end_attr_nested(&nw, off2);
813 snl_end_attr_nested(&nw, off);
814
815 geneve_nl_fini(ctx, &nw);
816 }
817
818 static void
setgeneve_external_nl(if_ctx * ctx,const char * val __unused,int d)819 setgeneve_external_nl(if_ctx *ctx, const char *val __unused, int d)
820 {
821 struct snl_writer nw = {};
822 int off, off2;
823
824 geneve_nl_init(ctx, &nw, 0);
825 off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
826 snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
827
828 off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
829
830 snl_add_msg_attr_bool(&nw, IFLA_GENEVE_COLLECT_METADATA, d != 0);
831
832 snl_end_attr_nested(&nw, off2);
833 snl_end_attr_nested(&nw, off);
834
835 geneve_nl_fini(ctx, &nw);
836 }
837
838 static struct cmd geneve_cmds[] = {
839
840 DEF_CLONE_CMD_ARG("genevemode", setgeneve_mode_clone),
841
842 DEF_CMD_ARG("geneveid", setgeneve_vni_nl),
843 DEF_CMD_ARG("genevelocal", setgeneve_local_nl),
844 DEF_CMD_ARG("geneveremote", setgeneve_remote_nl),
845 DEF_CMD_ARG("genevegroup", setgeneve_group_nl),
846 DEF_CMD_ARG("genevelocalport", setgeneve_local_port_nl),
847 DEF_CMD_ARG("geneveremoteport", setgeneve_remote_port_nl),
848 DEF_CMD_ARG2("geneveportrange", setgeneve_port_range_nl),
849 DEF_CMD_ARG("genevetimeout", setgeneve_timeout_nl),
850 DEF_CMD_ARG("genevemaxaddr", setgeneve_maxaddr_nl),
851 DEF_CMD_ARG("genevedev", setgeneve_dev_nl),
852 DEF_CMD_ARG("genevettl", setgeneve_ttl_nl),
853 DEF_CMD_ARG("genevedf", setgeneve_df_nl),
854 DEF_CMD("genevedscpinherit", 1, setgeneve_inherit_dscp_nl),
855 DEF_CMD("-genevedscpinherit", 0, setgeneve_inherit_dscp_nl),
856 DEF_CMD("genevelearn", 1, setgeneve_learn_nl),
857 DEF_CMD("-genevelearn", 0, setgeneve_learn_nl),
858 DEF_CMD("geneveflushall", 0, setgeneve_flush_nl),
859 DEF_CMD("geneveflush", 1, setgeneve_flush_nl),
860 DEF_CMD("geneveexternal", 1, setgeneve_external_nl),
861 DEF_CMD("-geneveexternal", 0, setgeneve_external_nl),
862
863 DEF_CMD_SARG("genevehwcsum", IFCAP2_GENEVE_HWCSUM_NAME,
864 setifcapnv),
865 DEF_CMD_SARG("-genevehwcsum", "-"IFCAP2_GENEVE_HWCSUM_NAME,
866 setifcapnv),
867 DEF_CMD_SARG("genevehwtso", IFCAP2_GENEVE_HWTSO_NAME,
868 setifcapnv),
869 DEF_CMD_SARG("-genevehwtso", "-"IFCAP2_GENEVE_HWTSO_NAME,
870 setifcapnv),
871 };
872
873 static struct afswtch af_geneve = {
874 .af_name = "af_geneve",
875 .af_af = AF_UNSPEC,
876 .af_other_status = geneve_status_nl,
877 };
878
879 static __constructor void
geneve_ctor(void)880 geneve_ctor(void)
881 {
882 size_t i;
883
884 for (i = 0; i < nitems(geneve_cmds); i++)
885 cmd_register(&geneve_cmds[i]);
886 af_register(&af_geneve);
887 clone_setdefcallback_prefix("geneve", geneve_create_nl);
888 SNL_VERIFY_PARSERS(all_parsers);
889 }
890