Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F157886732
D55184.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
26 KB
Referenced Files
None
Subscribers
None
D55184.diff
View Options
diff --git a/lib/libifconfig/libifconfig.c b/lib/libifconfig/libifconfig.c
--- a/lib/libifconfig/libifconfig.c
+++ b/lib/libifconfig/libifconfig.c
@@ -562,7 +562,9 @@
(strncmp(name, "vlan",
strlen("vlan")) == 0) ||
(strncmp(name, "vxlan",
- strlen("vxlan")) == 0)) {
+ strlen("vxlan")) == 0) ||
+ (strncmp(name, "geneve",
+ strlen("geneve")) == 0)) {
h->error.errtype = OTHER;
h->error.errcode = ENOSYS;
return (-1);
diff --git a/sbin/ifconfig/Makefile b/sbin/ifconfig/Makefile
--- a/sbin/ifconfig/Makefile
+++ b/sbin/ifconfig/Makefile
@@ -30,6 +30,7 @@
SRCS+= iffib.c # non-default FIB support
SRCS+= ifvlan.c # SIOC[GS]ETVLAN support
SRCS+= ifvxlan.c # VXLAN support
+SRCS+= ifgeneve.c # GENEVE support
SRCS+= ifgre.c # GRE keys etc
SRCS+= ifgif.c # GIF reversed header workaround
SRCS+= ifipsec.c # IPsec VTI
diff --git a/sbin/ifconfig/ifgeneve.c b/sbin/ifconfig/ifgeneve.c
new file mode 100644
--- /dev/null
+++ b/sbin/ifconfig/ifgeneve.c
@@ -0,0 +1,889 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025-2026 Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/nv.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <netdb.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_strings.h>
+#include <netinet/in.h>
+#include <net/if_geneve.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "ifconfig.h"
+#include "ifconfig_netlink.h"
+
+struct nl_parsed_geneve {
+ /* essential */
+ uint32_t ifla_vni;
+ uint16_t ifla_proto;
+ struct sockaddr *ifla_local;
+ struct sockaddr *ifla_remote;
+ uint16_t ifla_local_port;
+ uint16_t ifla_remote_port;
+
+ /* optional */
+ struct ifla_geneve_port_range *ifla_port_range;
+ enum ifla_geneve_df ifla_df;
+ uint8_t ifla_ttl;
+ bool ifla_ttl_inherit;
+ bool ifla_dscp_inherit;
+ bool ifla_external;
+
+ /* l2 specific */
+ bool ifla_ftable_learn;
+ bool ifla_ftable_flush;
+ uint32_t ifla_ftable_max;
+ uint32_t ifla_ftable_timeout;
+ uint32_t ifla_ftable_count;
+ uint32_t ifla_ftable_nospace;
+ uint32_t ifla_ftable_lock_upgrade_failed;
+
+ /* multicast specific */
+ char *ifla_mc_ifname;
+ uint32_t ifla_mc_ifindex;
+
+ /* csum info */
+ uint64_t ifla_stats_txcsum;
+ uint64_t ifla_stats_tso;
+ uint64_t ifla_stats_rxcsum;
+};
+
+static struct geneve_params gnvp = {
+ .ifla_proto = GENEVE_PROTO_ETHER,
+};
+
+static int
+get_proto(const char *cp, uint16_t *valp)
+{
+ uint16_t val;
+
+ if (!strcmp(cp, "l2"))
+ val = GENEVE_PROTO_ETHER;
+ else if (!strcmp(cp, "l3"))
+ val = GENEVE_PROTO_INHERIT;
+ else
+ return (-1);
+
+ *valp = val;
+ return (0);
+}
+
+static int
+get_val(const char *cp, u_long *valp)
+{
+ char *endptr;
+ u_long val;
+
+ errno = 0;
+ val = strtoul(cp, &endptr, 0);
+ if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE)
+ return (-1);
+
+ *valp = val;
+ return (0);
+}
+
+static int
+get_df(const char *cp, enum ifla_geneve_df *valp)
+{
+ enum ifla_geneve_df df;
+
+ if (!strcmp(cp, "set"))
+ df = IFLA_GENEVE_DF_SET;
+ else if (!strcmp(cp, "inherit"))
+ df = IFLA_GENEVE_DF_INHERIT;
+ else if (!strcmp(cp, "unset"))
+ df = IFLA_GENEVE_DF_UNSET;
+ else
+ return (-1);
+
+ *valp = df;
+ return (0);
+}
+
+static bool
+is_multicast(struct addrinfo *ai)
+{
+#if (defined INET || defined INET6)
+ struct sockaddr *sa;
+ sa = ai->ai_addr;
+#endif
+
+ switch (ai->ai_family) {
+#ifdef INET
+ case AF_INET: {
+ struct sockaddr_in *sin = satosin(sa);
+
+ return (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)));
+ }
+#endif
+#ifdef INET6
+ case AF_INET6: {
+ struct sockaddr_in6 *sin6 = satosin6(sa);
+
+ return (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr));
+ }
+#endif
+ default:
+ errx(1, "address family not supported");
+ }
+}
+
+/*
+ * geneve mode is read-only after creation,
+ * therefore there is no need for separate netlink implementation
+ */
+static void
+setgeneve_mode_clone(if_ctx *ctx __unused, const char *arg, int dummy __unused)
+{
+ uint16_t val;
+
+ if (get_proto(arg, &val) < 0)
+ errx(1, "invalid inner protocol: %s", arg);
+
+ gnvp.ifla_proto = val;
+}
+
+struct nla_geneve_info {
+ const char *kind;
+ struct nl_parsed_geneve data;
+};
+
+struct nla_geneve_link {
+ uint32_t ifi_index;
+ struct nla_geneve_info linkinfo;
+};
+
+static inline void
+geneve_nl_init(if_ctx *ctx, struct snl_writer *nw, uint32_t flags)
+{
+ struct nlmsghdr *hdr;
+
+ snl_init_writer(ctx->io_ss, nw);
+ hdr = snl_create_msg_request(nw, NL_RTM_NEWLINK);
+ hdr->nlmsg_flags |= flags;
+ snl_reserve_msg_object(nw, struct ifinfomsg);
+ snl_add_msg_attr_string(nw, IFLA_IFNAME, ctx->ifname);
+}
+
+static inline void
+geneve_nl_fini(if_ctx *ctx, struct snl_writer *nw)
+{
+ struct nlmsghdr *hdr;
+ struct snl_errmsg_data errmsg = {};
+
+ hdr = snl_finalize_msg(nw);
+ if (hdr == NULL || !snl_send_message(ctx->io_ss, hdr))
+ err(1, "unable to send netlink message");
+
+ if (!snl_read_reply_code(ctx->io_ss, hdr->nlmsg_seq, &errmsg))
+ errx(errmsg.error, "%s", errmsg.error_str);
+}
+
+#define _OUT(_field) offsetof(struct nl_parsed_geneve, _field)
+static const struct snl_attr_parser nla_geneve_linkinfo_data[] = {
+ { .type = IFLA_GENEVE_ID, .off = _OUT(ifla_vni), .cb = snl_attr_get_uint32 },
+ { .type = IFLA_GENEVE_PROTOCOL, .off = _OUT(ifla_proto), .cb = snl_attr_get_uint16 },
+ { .type = IFLA_GENEVE_LOCAL, .off = _OUT(ifla_local), .cb = snl_attr_get_ip },
+ { .type = IFLA_GENEVE_REMOTE, .off = _OUT(ifla_remote), .cb = snl_attr_get_ip },
+ { .type = IFLA_GENEVE_LOCAL_PORT, .off = _OUT(ifla_local_port), .cb = snl_attr_get_uint16 },
+ { .type = IFLA_GENEVE_PORT, .off = _OUT(ifla_remote_port), .cb = snl_attr_get_uint16 },
+ { .type = IFLA_GENEVE_PORT_RANGE, .off = _OUT(ifla_port_range), .cb = snl_attr_dup_struct },
+ { .type = IFLA_GENEVE_DF, .off = _OUT(ifla_df), .cb = snl_attr_get_uint8 },
+ { .type = IFLA_GENEVE_TTL, .off = _OUT(ifla_ttl), .cb = snl_attr_get_uint8 },
+ { .type = IFLA_GENEVE_TTL_INHERIT, .off = _OUT(ifla_ttl_inherit), .cb = snl_attr_get_bool },
+ { .type = IFLA_GENEVE_DSCP_INHERIT, .off = _OUT(ifla_dscp_inherit), .cb = snl_attr_get_bool },
+ { .type = IFLA_GENEVE_COLLECT_METADATA, .off = _OUT(ifla_external), .cb = snl_attr_get_bool },
+ { .type = IFLA_GENEVE_FTABLE_LEARN, .off = _OUT(ifla_ftable_learn), .cb = snl_attr_get_bool },
+ { .type = IFLA_GENEVE_FTABLE_FLUSH, .off = _OUT(ifla_ftable_flush), .cb = snl_attr_get_bool },
+ { .type = IFLA_GENEVE_FTABLE_MAX, .off = _OUT(ifla_ftable_max), .cb = snl_attr_get_uint32 },
+ { .type = IFLA_GENEVE_FTABLE_TIMEOUT, .off = _OUT(ifla_ftable_timeout), .cb = snl_attr_get_uint32 },
+ { .type = IFLA_GENEVE_FTABLE_COUNT, .off = _OUT(ifla_ftable_count), .cb = snl_attr_get_uint32 },
+ { .type = IFLA_GENEVE_FTABLE_NOSPACE_CNT, .off = _OUT(ifla_ftable_nospace), .cb = snl_attr_get_uint32 },
+ { .type = IFLA_GENEVE_FTABLE_LOCK_UP_FAIL_CNT, .off = _OUT(ifla_ftable_lock_upgrade_failed), .cb = snl_attr_get_uint32 },
+ { .type = IFLA_GENEVE_MC_IFNAME, .off = _OUT(ifla_mc_ifname), .cb = snl_attr_get_string },
+ { .type = IFLA_GENEVE_MC_IFINDEX, .off = _OUT(ifla_mc_ifindex), .cb = snl_attr_get_uint32 },
+ { .type = IFLA_GENEVE_TXCSUM_CNT, .off = _OUT(ifla_stats_txcsum), .cb = snl_attr_get_uint64 },
+ { .type = IFLA_GENEVE_TSO_CNT, .off = _OUT(ifla_stats_tso), .cb = snl_attr_get_uint64 },
+ { .type = IFLA_GENEVE_RXCSUM_CNT, .off = _OUT(ifla_stats_rxcsum), .cb = snl_attr_get_uint64 },
+};
+#undef _OUT
+SNL_DECLARE_ATTR_PARSER(geneve_linkinfo_data_parser, nla_geneve_linkinfo_data);
+
+#define _OUT(_field) offsetof(struct nla_geneve_info, _field)
+static const struct snl_attr_parser ap_geneve_linkinfo[] = {
+ { .type = IFLA_INFO_KIND, .off = _OUT(kind), .cb = snl_attr_get_string },
+ { .type = IFLA_INFO_DATA, .off = _OUT(data),
+ .arg = &geneve_linkinfo_data_parser, .cb = snl_attr_get_nested },
+};
+#undef _OUT
+SNL_DECLARE_ATTR_PARSER(geneve_linkinfo_parser, ap_geneve_linkinfo);
+
+#define _IN(_field) offsetof(struct ifinfomsg, _field)
+#define _OUT(_field) offsetof(struct nla_geneve_link, _field)
+static const struct snl_attr_parser ap_geneve_link[] = {
+ { .type = IFLA_LINKINFO, .off = _OUT(linkinfo),
+ .arg = &geneve_linkinfo_parser, .cb = snl_attr_get_nested },
+};
+
+static const struct snl_field_parser fp_geneve_link[] = {
+ { .off_in = _IN(ifi_index), .off_out = _OUT(ifi_index), .cb = snl_field_get_uint32 },
+};
+#undef _IN
+#undef _OUT
+SNL_DECLARE_PARSER(geneve_parser, struct ifinfomsg, fp_geneve_link, ap_geneve_link);
+
+static const struct snl_hdr_parser *all_parsers[] = {
+ &geneve_linkinfo_data_parser,
+ &geneve_linkinfo_parser,
+ &geneve_parser,
+};
+
+static void
+geneve_status_nl(if_ctx *ctx)
+{
+ struct snl_writer nw;
+ struct nlmsghdr *hdr;
+ struct snl_errmsg_data errmsg;
+ struct nla_geneve_link geneve_link;
+ char src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN];
+ struct sockaddr *lsa, *rsa;
+ int mc;
+ bool ipv6 = false;
+
+ if (strncmp(ctx->ifname, "geneve", sizeof("geneve") - 1) != 0)
+ return;
+
+ snl_init_writer(ctx->io_ss, &nw);
+ hdr = snl_create_msg_request(&nw, NL_RTM_GETLINK);
+ hdr->nlmsg_flags |= NLM_F_DUMP;
+ snl_reserve_msg_object(&nw, struct ifinfomsg);
+ snl_add_msg_attr_string(&nw, IFLA_IFNAME, ctx->ifname);
+
+ if (!(hdr = snl_finalize_msg(&nw)) || (!snl_send_message(ctx->io_ss, hdr)))
+ return;
+
+ hdr = snl_read_reply(ctx->io_ss, hdr->nlmsg_seq);
+ if (hdr->nlmsg_type != NL_RTM_NEWLINK) {
+ if (!snl_parse_errmsg(ctx->io_ss, hdr, &errmsg))
+ errx(EINVAL, "(NETLINK)");
+ if (errmsg.error_str != NULL)
+ errx(errmsg.error, "(NETLINK) %s", errmsg.error_str);
+ }
+
+ if (!snl_parse_nlmsg(ctx->io_ss, hdr, &geneve_parser, &geneve_link))
+ return;
+
+ struct nla_geneve_info geneve_info = geneve_link.linkinfo;
+ struct nl_parsed_geneve geneve_data = geneve_info.data;
+
+ printf("\tgeneve mode: ");
+ switch (geneve_data.ifla_proto) {
+ case GENEVE_PROTO_INHERIT:
+ printf("l3");
+ break;
+ case GENEVE_PROTO_ETHER:
+ default:
+ printf("l2");
+ break;
+ }
+
+ printf("\n\tgeneve config:\n");
+ /* Just report nothing if the network identity isn't set yet. */
+ if (geneve_data.ifla_vni >= GENEVE_VNI_MAX) {
+ printf("\t\tvirtual network identifier (vni): not configured\n");
+ return;
+ }
+
+ lsa = geneve_data.ifla_local;
+ rsa = geneve_data.ifla_remote;
+
+ if ((lsa == NULL) ||
+ (getnameinfo(lsa, lsa->sa_len, src, sizeof(src),
+ NULL, 0, NI_NUMERICHOST) != 0))
+ src[0] = '\0';
+ if ((rsa == NULL) ||
+ (getnameinfo(rsa, rsa->sa_len, dst, sizeof(dst),
+ NULL, 0, NI_NUMERICHOST) != 0))
+ dst[0] = '\0';
+ else {
+ ipv6 = rsa->sa_family == AF_INET6;
+ if (!ipv6) {
+ struct sockaddr_in *sin = satosin(rsa);
+ mc = IN_MULTICAST(ntohl(sin->sin_addr.s_addr));
+ } else {
+ struct sockaddr_in6 *sin6 = satosin6(rsa);
+ mc = IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr);
+ }
+ }
+
+ printf("\t\tvirtual network identifier (vni): %d", geneve_data.ifla_vni);
+ if (src[0] != '\0')
+ printf("\n\t\tlocal: %s%s%s:%u", ipv6 ? "[" : "", src, ipv6 ? "]" : "",
+ geneve_data.ifla_local_port);
+ if (dst[0] != '\0') {
+ printf("\n\t\t%s: %s%s%s:%u", mc ? "group" : "remote", ipv6 ? "[" : "",
+ dst, ipv6 ? "]" : "", geneve_data.ifla_local_port);
+ if (mc)
+ printf(", dev: %s", geneve_data.ifla_mc_ifname);
+ }
+
+ if (ctx->args->verbose) {
+ printf("\n\t\tportrange: %u-%u",
+ geneve_data.ifla_port_range->low,
+ geneve_data.ifla_port_range->high);
+
+ if (geneve_data.ifla_ttl_inherit)
+ printf(", ttl: inherit");
+ else
+ printf(", ttl: %d", geneve_data.ifla_ttl);
+
+ if (geneve_data.ifla_dscp_inherit)
+ printf(", dscp: inherit");
+
+ if (geneve_data.ifla_df == IFLA_GENEVE_DF_INHERIT)
+ printf(", df: inherit");
+ else if (geneve_data.ifla_df == IFLA_GENEVE_DF_SET)
+ printf(", df: set");
+ else if (geneve_data.ifla_df == IFLA_GENEVE_DF_UNSET)
+ printf(", df: unset");
+
+ if (geneve_data.ifla_external)
+ printf(", externally controlled");
+
+ if (geneve_data.ifla_proto == GENEVE_PROTO_ETHER) {
+ printf("\n\t\tftable mode: %slearning",
+ geneve_data.ifla_ftable_learn ? "" : "no");
+ printf(", count: %d, max: %d, timeout: %d",
+ geneve_data.ifla_ftable_count,
+ geneve_data.ifla_ftable_max,
+ geneve_data.ifla_ftable_timeout);
+ printf(", nospace: %u",
+ geneve_data.ifla_ftable_nospace);
+ }
+
+ printf("\n\t\tstats: tso %lu, txcsum %lu, rxcsum %lu",
+ geneve_data.ifla_stats_tso,
+ geneve_data.ifla_stats_txcsum,
+ geneve_data.ifla_stats_rxcsum);
+ }
+
+ putchar('\n');
+}
+
+
+static void
+geneve_create_nl(if_ctx *ctx, struct ifreq *ifr)
+{
+ struct snl_writer nw = {};
+ struct nlmsghdr *hdr;
+ int off, off2;
+
+ snl_init_writer(ctx->io_ss, &nw);
+ hdr = snl_create_msg_request(&nw, RTM_NEWLINK);
+ hdr->nlmsg_flags |= (NLM_F_CREATE | NLM_F_EXCL);
+ snl_reserve_msg_object(&nw, struct ifinfomsg);
+ snl_add_msg_attr_string(&nw, IFLA_IFNAME, ifr->ifr_name);
+
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
+
+ off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
+ snl_add_msg_attr_u16(&nw, IFLA_GENEVE_PROTOCOL, gnvp.ifla_proto);
+
+ snl_end_attr_nested(&nw, off2);
+ snl_end_attr_nested(&nw, off);
+
+ geneve_nl_fini(ctx, &nw);
+}
+
+static void
+setgeneve_vni_nl(if_ctx *ctx, const char *arg, int dummy __unused)
+{
+ struct snl_writer nw = {};
+ int off, off2;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || val >= GENEVE_VNI_MAX)
+ errx(1, "invalid network identifier: %s", arg);
+
+ geneve_nl_init(ctx, &nw, 0);
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
+
+ off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
+ snl_add_msg_attr_u32(&nw, IFLA_GENEVE_ID, val);
+
+ snl_end_attr_nested(&nw, off2);
+ snl_end_attr_nested(&nw, off);
+
+ geneve_nl_fini(ctx, &nw);
+}
+
+static void
+setgeneve_local_nl(if_ctx *ctx, const char *addr, int dummy __unused)
+{
+ struct snl_writer nw = {};
+ int off, off2;
+ struct addrinfo *ai;
+ const struct sockaddr *sa;
+ int error;
+
+ if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0)
+ errx(1, "error in parsing local address string: %s",
+ gai_strerror(error));
+
+ if (is_multicast(ai))
+ errx(1, "local address cannot be multicast");
+
+ geneve_nl_init(ctx, &nw, 0);
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
+
+ off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
+
+ sa = ai->ai_addr;
+ snl_add_msg_attr_ip(&nw, IFLA_GENEVE_LOCAL, sa);
+
+ snl_end_attr_nested(&nw, off2);
+ snl_end_attr_nested(&nw, off);
+
+ geneve_nl_fini(ctx, &nw);
+}
+
+static void
+setgeneve_remote_nl(if_ctx *ctx, const char *addr, int dummy __unused)
+{
+ struct snl_writer nw = {};
+ int off, off2;
+ struct addrinfo *ai;
+ const struct sockaddr *sa;
+ int error;
+
+ if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0)
+ errx(1, "error in parsing remote address string: %s",
+ gai_strerror(error));
+
+ if (is_multicast(ai))
+ errx(1, "remote address cannot be multicast");
+
+ geneve_nl_init(ctx, &nw, 0);
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
+
+ off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
+
+ sa = ai->ai_addr;
+ snl_add_msg_attr_ip(&nw, IFLA_GENEVE_REMOTE, sa);
+
+ snl_end_attr_nested(&nw, off2);
+ snl_end_attr_nested(&nw, off);
+
+ geneve_nl_fini(ctx, &nw);
+}
+
+static void
+setgeneve_group_nl(if_ctx *ctx, const char *addr, int dummy __unused)
+{
+ struct snl_writer nw = {};
+ int off, off2;
+ struct addrinfo *ai;
+ struct sockaddr *sa;
+ int error;
+
+ if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0)
+ errx(1, "error in parsing local address string: %s",
+ gai_strerror(error));
+
+ if (!is_multicast(ai))
+ errx(1, "group address must be multicast");
+
+ geneve_nl_init(ctx, &nw, 0);
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
+
+ off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
+
+ sa = ai->ai_addr;
+ snl_add_msg_attr_ip(&nw, IFLA_GENEVE_REMOTE, sa);
+
+ snl_end_attr_nested(&nw, off2);
+ snl_end_attr_nested(&nw, off);
+
+ geneve_nl_fini(ctx, &nw);
+}
+
+
+static void
+setgeneve_local_port_nl(if_ctx *ctx, const char *arg, int dummy __unused)
+{
+ struct snl_writer nw = {};
+ int off, off2;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || val >= UINT16_MAX)
+ errx(1, "invalid local port: %s", arg);
+
+ geneve_nl_init(ctx, &nw, 0);
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
+
+ off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
+
+ snl_add_msg_attr_u16(&nw, IFLA_GENEVE_LOCAL_PORT, val);
+
+ snl_end_attr_nested(&nw, off2);
+ snl_end_attr_nested(&nw, off);
+
+ geneve_nl_fini(ctx, &nw);
+}
+
+static void
+setgeneve_remote_port_nl(if_ctx *ctx, const char *arg, int dummy __unused)
+{
+ struct snl_writer nw = {};
+ int off, off2;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || val >= UINT16_MAX)
+ errx(1, "invalid remote port: %s", arg);
+
+ geneve_nl_init(ctx, &nw, 0);
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
+
+ off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
+
+ snl_add_msg_attr_u16(&nw, IFLA_GENEVE_PORT, val);
+
+ snl_end_attr_nested(&nw, off2);
+ snl_end_attr_nested(&nw, off);
+
+ geneve_nl_fini(ctx, &nw);
+}
+
+static void
+setgeneve_port_range_nl(if_ctx *ctx, const char *arg1, const char *arg2)
+{
+ struct snl_writer nw = {};
+ int off, off2;
+ u_long min, max;
+
+ if (get_val(arg1, &min) < 0 || min >= UINT16_MAX)
+ errx(1, "invalid port range minimum: %s", arg1);
+ if (get_val(arg2, &max) < 0 || max >= UINT16_MAX)
+ errx(1, "invalid port range maximum: %s", arg2);
+ if (max < min)
+ errx(1, "invalid port range");
+
+ const struct ifla_geneve_port_range port_range = {
+ .low = min,
+ .high = max
+ };
+
+ geneve_nl_init(ctx, &nw, 0);
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
+
+ off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
+
+ snl_add_msg_attr(&nw, IFLA_GENEVE_PORT_RANGE,
+ sizeof(port_range), (const void *)&port_range);
+
+ snl_end_attr_nested(&nw, off2);
+ snl_end_attr_nested(&nw, off);
+
+ geneve_nl_fini(ctx, &nw);
+}
+
+static void
+setgeneve_timeout_nl(if_ctx *ctx, const char *arg, int dummy __unused)
+{
+ struct snl_writer nw = {};
+ int off, off2;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || (val & ~0xFFFFFFFF) != 0)
+ errx(1, "invalid timeout value: %s", arg);
+
+ geneve_nl_init(ctx, &nw, 0);
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
+
+ off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
+
+ snl_add_msg_attr_u32(&nw, IFLA_GENEVE_FTABLE_TIMEOUT, val);
+
+ snl_end_attr_nested(&nw, off2);
+ snl_end_attr_nested(&nw, off);
+
+ geneve_nl_fini(ctx, &nw);
+}
+
+static void
+setgeneve_maxaddr_nl(if_ctx *ctx, const char *arg, int dummy __unused)
+{
+ struct snl_writer nw = {};
+ int off, off2;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || (val & ~0xFFFFFFFF) != 0)
+ errx(1, "invalid maxaddr value: %s", arg);
+
+ geneve_nl_init(ctx, &nw, 0);
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
+
+ off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
+
+ snl_add_msg_attr_u32(&nw, IFLA_GENEVE_FTABLE_MAX, val);
+
+ snl_end_attr_nested(&nw, off2);
+ snl_end_attr_nested(&nw, off);
+
+ geneve_nl_fini(ctx, &nw);
+}
+
+static void
+setgeneve_dev_nl(if_ctx *ctx, const char *arg, int dummy __unused)
+{
+ struct snl_writer nw = {};
+ int off, off2;
+
+ geneve_nl_init(ctx, &nw, 0);
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
+
+ off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
+
+ snl_add_msg_attr_string(&nw, IFLA_GENEVE_MC_IFNAME, arg);
+
+ snl_end_attr_nested(&nw, off2);
+ snl_end_attr_nested(&nw, off);
+
+ geneve_nl_fini(ctx, &nw);
+}
+
+static void
+setgeneve_ttl_nl(if_ctx *ctx, const char *arg, int dummy __unused)
+{
+ struct snl_writer nw = {};
+ int off, off2;
+ u_long val;
+
+ geneve_nl_init(ctx, &nw, 0);
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
+
+ off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
+ if ((get_val(arg, &val) < 0 || val > 256) == 0) {
+ snl_add_msg_attr_u8(&nw, IFLA_GENEVE_TTL, val);
+ snl_add_msg_attr_bool(&nw, IFLA_GENEVE_TTL_INHERIT, false);
+ } else if (!strcmp(arg, "inherit")) {
+ snl_add_msg_attr_bool(&nw, IFLA_GENEVE_TTL_INHERIT, true);
+ } else
+ errx(1, "invalid TTL value: %s", arg);
+
+ snl_end_attr_nested(&nw, off2);
+ snl_end_attr_nested(&nw, off);
+
+ geneve_nl_fini(ctx, &nw);
+}
+
+static void
+setgeneve_df_nl(if_ctx *ctx, const char *arg, int dummy __unused)
+{
+ struct snl_writer nw = {};
+ int off, off2;
+ enum ifla_geneve_df df;
+
+ if (get_df(arg, &df) < 0)
+ errx(1, "invalid df value: %s", arg);
+
+ geneve_nl_init(ctx, &nw, 0);
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
+
+ off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
+
+ snl_add_msg_attr_u8(&nw, IFLA_GENEVE_DF, df);
+
+ snl_end_attr_nested(&nw, off2);
+ snl_end_attr_nested(&nw, off);
+
+ geneve_nl_fini(ctx, &nw);
+}
+
+static void
+setgeneve_inherit_dscp_nl(if_ctx *ctx, const char *arg __unused, int d)
+{
+ struct snl_writer nw = {};
+ int off, off2;
+
+ geneve_nl_init(ctx, &nw, 0);
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
+
+ off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
+
+ snl_add_msg_attr_bool(&nw, IFLA_GENEVE_DSCP_INHERIT, d != 0);
+
+ snl_end_attr_nested(&nw, off2);
+ snl_end_attr_nested(&nw, off);
+
+ geneve_nl_fini(ctx, &nw);
+}
+
+static void
+setgeneve_learn_nl(if_ctx *ctx, const char *arg __unused, int d)
+{
+ struct snl_writer nw = {};
+ int off, off2;
+
+ geneve_nl_init(ctx, &nw, 0);
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
+
+ off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
+
+ snl_add_msg_attr_bool(&nw, IFLA_GENEVE_FTABLE_LEARN, d != 0);
+
+ snl_end_attr_nested(&nw, off2);
+ snl_end_attr_nested(&nw, off);
+
+ geneve_nl_fini(ctx, &nw);
+}
+
+static void
+setgeneve_flush_nl(if_ctx *ctx, const char *val __unused, int d)
+{
+ struct snl_writer nw = {};
+ int off, off2;
+
+ geneve_nl_init(ctx, &nw, 0);
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
+
+ off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
+
+ snl_add_msg_attr_bool(&nw, IFLA_GENEVE_FTABLE_FLUSH, d != 0);
+
+ snl_end_attr_nested(&nw, off2);
+ snl_end_attr_nested(&nw, off);
+
+ geneve_nl_fini(ctx, &nw);
+}
+
+static void
+setgeneve_external_nl(if_ctx *ctx, const char *val __unused, int d)
+{
+ struct snl_writer nw = {};
+ int off, off2;
+
+ geneve_nl_init(ctx, &nw, 0);
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "geneve");
+
+ off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
+
+ snl_add_msg_attr_bool(&nw, IFLA_GENEVE_COLLECT_METADATA, d != 0);
+
+ snl_end_attr_nested(&nw, off2);
+ snl_end_attr_nested(&nw, off);
+
+ geneve_nl_fini(ctx, &nw);
+}
+
+static struct cmd geneve_cmds[] = {
+
+ DEF_CLONE_CMD_ARG("genevemode", setgeneve_mode_clone),
+
+ DEF_CMD_ARG("geneveid", setgeneve_vni_nl),
+ DEF_CMD_ARG("genevelocal", setgeneve_local_nl),
+ DEF_CMD_ARG("geneveremote", setgeneve_remote_nl),
+ DEF_CMD_ARG("genevegroup", setgeneve_group_nl),
+ DEF_CMD_ARG("genevelocalport", setgeneve_local_port_nl),
+ DEF_CMD_ARG("geneveremoteport", setgeneve_remote_port_nl),
+ DEF_CMD_ARG2("geneveportrange", setgeneve_port_range_nl),
+ DEF_CMD_ARG("genevetimeout", setgeneve_timeout_nl),
+ DEF_CMD_ARG("genevemaxaddr", setgeneve_maxaddr_nl),
+ DEF_CMD_ARG("genevedev", setgeneve_dev_nl),
+ DEF_CMD_ARG("genevettl", setgeneve_ttl_nl),
+ DEF_CMD_ARG("genevedf", setgeneve_df_nl),
+ DEF_CMD("genevedscpinherit", 1, setgeneve_inherit_dscp_nl),
+ DEF_CMD("-genevedscpinherit", 0, setgeneve_inherit_dscp_nl),
+ DEF_CMD("genevelearn", 1, setgeneve_learn_nl),
+ DEF_CMD("-genevelearn", 0, setgeneve_learn_nl),
+ DEF_CMD("geneveflushall", 0, setgeneve_flush_nl),
+ DEF_CMD("geneveflush", 1, setgeneve_flush_nl),
+ DEF_CMD("geneveexternal", 1, setgeneve_external_nl),
+ DEF_CMD("-geneveexternal", 0, setgeneve_external_nl),
+
+ DEF_CMD_SARG("genevehwcsum", IFCAP2_GENEVE_HWCSUM_NAME,
+ setifcapnv),
+ DEF_CMD_SARG("-genevehwcsum", "-"IFCAP2_GENEVE_HWCSUM_NAME,
+ setifcapnv),
+ DEF_CMD_SARG("genevehwtso", IFCAP2_GENEVE_HWTSO_NAME,
+ setifcapnv),
+ DEF_CMD_SARG("-genevehwtso", "-"IFCAP2_GENEVE_HWTSO_NAME,
+ setifcapnv),
+};
+
+static struct afswtch af_geneve = {
+ .af_name = "af_geneve",
+ .af_af = AF_UNSPEC,
+ .af_other_status = geneve_status_nl,
+};
+
+static __constructor void
+geneve_ctor(void)
+{
+ size_t i;
+
+ for (i = 0; i < nitems(geneve_cmds); i++)
+ cmd_register(&geneve_cmds[i]);
+ af_register(&af_geneve);
+ clone_setdefcallback_prefix("geneve", geneve_create_nl);
+ SNL_VERIFY_PARSERS(all_parsers);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, May 27, 4:25 AM (14 h, 41 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33546593
Default Alt Text
D55184.diff (26 KB)
Attached To
Mode
D55184: ifconfig: Add support for geneve (netlink)
Attached
Detach File
Event Timeline
Log In to Comment