Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sbin/ifconfig/ifgeneve.c
213592 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2025-2026 Pouria Mousavizadeh Tehrani <[email protected]>
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
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
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
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
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
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
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
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
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 = {0};
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
891