1007054f0SBryan Venteicher /*-
2007054f0SBryan Venteicher * Copyright (c) 2014, Bryan Venteicher <bryanv@FreeBSD.org>
3007054f0SBryan Venteicher * All rights reserved.
4007054f0SBryan Venteicher *
5007054f0SBryan Venteicher * Redistribution and use in source and binary forms, with or without
6007054f0SBryan Venteicher * modification, are permitted provided that the following conditions
7007054f0SBryan Venteicher * are met:
8007054f0SBryan Venteicher * 1. Redistributions of source code must retain the above copyright
9007054f0SBryan Venteicher * notice unmodified, this list of conditions, and the following
10007054f0SBryan Venteicher * disclaimer.
11007054f0SBryan Venteicher * 2. Redistributions in binary form must reproduce the above copyright
12007054f0SBryan Venteicher * notice, this list of conditions and the following disclaimer in the
13007054f0SBryan Venteicher * documentation and/or other materials provided with the distribution.
14007054f0SBryan Venteicher *
15007054f0SBryan Venteicher * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16007054f0SBryan Venteicher * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17007054f0SBryan Venteicher * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18007054f0SBryan Venteicher * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19007054f0SBryan Venteicher * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20007054f0SBryan Venteicher * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21007054f0SBryan Venteicher * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22007054f0SBryan Venteicher * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23007054f0SBryan Venteicher * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24007054f0SBryan Venteicher * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25007054f0SBryan Venteicher */
26007054f0SBryan Venteicher
27007054f0SBryan Venteicher #include <sys/param.h>
28007054f0SBryan Venteicher #include <sys/ioctl.h>
29007054f0SBryan Venteicher #include <sys/socket.h>
30007054f0SBryan Venteicher #include <sys/sockio.h>
31007054f0SBryan Venteicher
32007054f0SBryan Venteicher #include <stdlib.h>
33007054f0SBryan Venteicher #include <stdint.h>
34007054f0SBryan Venteicher #include <unistd.h>
35007054f0SBryan Venteicher #include <netdb.h>
36007054f0SBryan Venteicher
37007054f0SBryan Venteicher #include <net/ethernet.h>
38007054f0SBryan Venteicher #include <net/if.h>
39007054f0SBryan Venteicher #include <net/if_vxlan.h>
40007054f0SBryan Venteicher #include <net/route.h>
41007054f0SBryan Venteicher #include <netinet/in.h>
42007054f0SBryan Venteicher
43007054f0SBryan Venteicher #include <ctype.h>
44007054f0SBryan Venteicher #include <stdio.h>
45007054f0SBryan Venteicher #include <string.h>
46007054f0SBryan Venteicher #include <stdlib.h>
47007054f0SBryan Venteicher #include <unistd.h>
48007054f0SBryan Venteicher #include <err.h>
49007054f0SBryan Venteicher #include <errno.h>
50007054f0SBryan Venteicher
51007054f0SBryan Venteicher #include "ifconfig.h"
52007054f0SBryan Venteicher
53007054f0SBryan Venteicher static struct ifvxlanparam params = {
54007054f0SBryan Venteicher .vxlp_vni = VXLAN_VNI_MAX,
55007054f0SBryan Venteicher };
56007054f0SBryan Venteicher
57007054f0SBryan Venteicher static int
get_val(const char * cp,u_long * valp)58007054f0SBryan Venteicher get_val(const char *cp, u_long *valp)
59007054f0SBryan Venteicher {
60007054f0SBryan Venteicher char *endptr;
61007054f0SBryan Venteicher u_long val;
62007054f0SBryan Venteicher
63007054f0SBryan Venteicher errno = 0;
64007054f0SBryan Venteicher val = strtoul(cp, &endptr, 0);
65007054f0SBryan Venteicher if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE)
66007054f0SBryan Venteicher return (-1);
67007054f0SBryan Venteicher
68007054f0SBryan Venteicher *valp = val;
69007054f0SBryan Venteicher return (0);
70007054f0SBryan Venteicher }
71007054f0SBryan Venteicher
72007054f0SBryan Venteicher static int
do_cmd(if_ctx * ctx,u_long op,void * arg,size_t argsize,int set)736e3a9d7fSAlexander V. Chernikov do_cmd(if_ctx *ctx, u_long op, void *arg, size_t argsize, int set)
74007054f0SBryan Venteicher {
757fa282e6SAlexander V. Chernikov struct ifdrv ifd = {};
76007054f0SBryan Venteicher
777fa282e6SAlexander V. Chernikov strlcpy(ifd.ifd_name, ctx->ifname, sizeof(ifd.ifd_name));
78007054f0SBryan Venteicher ifd.ifd_cmd = op;
79007054f0SBryan Venteicher ifd.ifd_len = argsize;
80007054f0SBryan Venteicher ifd.ifd_data = arg;
81007054f0SBryan Venteicher
827fa282e6SAlexander V. Chernikov return (ioctl_ctx(ctx, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd));
83007054f0SBryan Venteicher }
84007054f0SBryan Venteicher
85007054f0SBryan Venteicher static int
vxlan_exists(if_ctx * ctx)866e3a9d7fSAlexander V. Chernikov vxlan_exists(if_ctx *ctx)
87007054f0SBryan Venteicher {
88007054f0SBryan Venteicher struct ifvxlancfg cfg;
89007054f0SBryan Venteicher
90007054f0SBryan Venteicher bzero(&cfg, sizeof(cfg));
91007054f0SBryan Venteicher
926e3a9d7fSAlexander V. Chernikov return (do_cmd(ctx, VXLAN_CMD_GET_CONFIG, &cfg, sizeof(cfg), 0) != -1);
93007054f0SBryan Venteicher }
94007054f0SBryan Venteicher
95007054f0SBryan Venteicher static void
vxlan_status(if_ctx * ctx)966e3a9d7fSAlexander V. Chernikov vxlan_status(if_ctx *ctx)
97007054f0SBryan Venteicher {
98007054f0SBryan Venteicher struct ifvxlancfg cfg;
99007054f0SBryan Venteicher char src[NI_MAXHOST], dst[NI_MAXHOST];
100007054f0SBryan Venteicher char srcport[NI_MAXSERV], dstport[NI_MAXSERV];
101007054f0SBryan Venteicher struct sockaddr *lsa, *rsa;
102007054f0SBryan Venteicher int vni, mc, ipv6;
103007054f0SBryan Venteicher
104007054f0SBryan Venteicher bzero(&cfg, sizeof(cfg));
105007054f0SBryan Venteicher
1066e3a9d7fSAlexander V. Chernikov if (do_cmd(ctx, VXLAN_CMD_GET_CONFIG, &cfg, sizeof(cfg), 0) < 0)
107007054f0SBryan Venteicher return;
108007054f0SBryan Venteicher
109007054f0SBryan Venteicher vni = cfg.vxlc_vni;
110007054f0SBryan Venteicher lsa = &cfg.vxlc_local_sa.sa;
111007054f0SBryan Venteicher rsa = &cfg.vxlc_remote_sa.sa;
112007054f0SBryan Venteicher ipv6 = rsa->sa_family == AF_INET6;
113007054f0SBryan Venteicher
114007054f0SBryan Venteicher /* Just report nothing if the network identity isn't set yet. */
115007054f0SBryan Venteicher if (vni >= VXLAN_VNI_MAX)
116007054f0SBryan Venteicher return;
117007054f0SBryan Venteicher
118007054f0SBryan Venteicher if (getnameinfo(lsa, lsa->sa_len, src, sizeof(src),
119007054f0SBryan Venteicher srcport, sizeof(srcport), NI_NUMERICHOST | NI_NUMERICSERV) != 0)
120007054f0SBryan Venteicher src[0] = srcport[0] = '\0';
121007054f0SBryan Venteicher if (getnameinfo(rsa, rsa->sa_len, dst, sizeof(dst),
122007054f0SBryan Venteicher dstport, sizeof(dstport), NI_NUMERICHOST | NI_NUMERICSERV) != 0)
123007054f0SBryan Venteicher dst[0] = dstport[0] = '\0';
124007054f0SBryan Venteicher
125007054f0SBryan Venteicher if (!ipv6) {
12644cd85d4SAlexander V. Chernikov struct sockaddr_in *sin = satosin(rsa);
127007054f0SBryan Venteicher mc = IN_MULTICAST(ntohl(sin->sin_addr.s_addr));
128007054f0SBryan Venteicher } else {
12944cd85d4SAlexander V. Chernikov struct sockaddr_in6 *sin6 = satosin6(rsa);
130007054f0SBryan Venteicher mc = IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr);
131007054f0SBryan Venteicher }
132007054f0SBryan Venteicher
133007054f0SBryan Venteicher printf("\tvxlan vni %d", vni);
134007054f0SBryan Venteicher printf(" local %s%s%s:%s", ipv6 ? "[" : "", src, ipv6 ? "]" : "",
135007054f0SBryan Venteicher srcport);
136007054f0SBryan Venteicher printf(" %s %s%s%s:%s", mc ? "group" : "remote", ipv6 ? "[" : "",
137007054f0SBryan Venteicher dst, ipv6 ? "]" : "", dstport);
138007054f0SBryan Venteicher
139c6885dbdSAlexander V. Chernikov if (ctx->args->verbose) {
140007054f0SBryan Venteicher printf("\n\t\tconfig: ");
141007054f0SBryan Venteicher printf("%slearning portrange %d-%d ttl %d",
142007054f0SBryan Venteicher cfg.vxlc_learn ? "" : "no", cfg.vxlc_port_min,
143007054f0SBryan Venteicher cfg.vxlc_port_max, cfg.vxlc_ttl);
144007054f0SBryan Venteicher printf("\n\t\tftable: ");
145007054f0SBryan Venteicher printf("cnt %d max %d timeout %d",
146007054f0SBryan Venteicher cfg.vxlc_ftable_cnt, cfg.vxlc_ftable_max,
147007054f0SBryan Venteicher cfg.vxlc_ftable_timeout);
148007054f0SBryan Venteicher }
149007054f0SBryan Venteicher
150007054f0SBryan Venteicher putchar('\n');
151007054f0SBryan Venteicher }
152007054f0SBryan Venteicher
153007054f0SBryan Venteicher #define _LOCAL_ADDR46 \
154007054f0SBryan Venteicher (VXLAN_PARAM_WITH_LOCAL_ADDR4 | VXLAN_PARAM_WITH_LOCAL_ADDR6)
155007054f0SBryan Venteicher #define _REMOTE_ADDR46 \
156007054f0SBryan Venteicher (VXLAN_PARAM_WITH_REMOTE_ADDR4 | VXLAN_PARAM_WITH_REMOTE_ADDR6)
157007054f0SBryan Venteicher
158007054f0SBryan Venteicher static void
vxlan_check_params(void)159007054f0SBryan Venteicher vxlan_check_params(void)
160007054f0SBryan Venteicher {
161007054f0SBryan Venteicher
162007054f0SBryan Venteicher if ((params.vxlp_with & _LOCAL_ADDR46) == _LOCAL_ADDR46)
163007054f0SBryan Venteicher errx(1, "cannot specify both local IPv4 and IPv6 addresses");
164007054f0SBryan Venteicher if ((params.vxlp_with & _REMOTE_ADDR46) == _REMOTE_ADDR46)
165007054f0SBryan Venteicher errx(1, "cannot specify both remote IPv4 and IPv6 addresses");
166007054f0SBryan Venteicher if ((params.vxlp_with & VXLAN_PARAM_WITH_LOCAL_ADDR4 &&
167007054f0SBryan Venteicher params.vxlp_with & VXLAN_PARAM_WITH_REMOTE_ADDR6) ||
168007054f0SBryan Venteicher (params.vxlp_with & VXLAN_PARAM_WITH_LOCAL_ADDR6 &&
169007054f0SBryan Venteicher params.vxlp_with & VXLAN_PARAM_WITH_REMOTE_ADDR4))
170007054f0SBryan Venteicher errx(1, "cannot mix IPv4 and IPv6 addresses");
171007054f0SBryan Venteicher }
172007054f0SBryan Venteicher
173007054f0SBryan Venteicher #undef _LOCAL_ADDR46
174007054f0SBryan Venteicher #undef _REMOTE_ADDR46
175007054f0SBryan Venteicher
176007054f0SBryan Venteicher static void
vxlan_create(if_ctx * ctx,struct ifreq * ifr)17774b42611SAlexander V. Chernikov vxlan_create(if_ctx *ctx, struct ifreq *ifr)
178007054f0SBryan Venteicher {
179007054f0SBryan Venteicher
180007054f0SBryan Venteicher vxlan_check_params();
181007054f0SBryan Venteicher
182007054f0SBryan Venteicher ifr->ifr_data = (caddr_t) ¶ms;
18374b42611SAlexander V. Chernikov ifcreate_ioctl(ctx, ifr);
184007054f0SBryan Venteicher }
185007054f0SBryan Venteicher
1866e3a9d7fSAlexander V. Chernikov static void
setvxlan_vni(if_ctx * ctx,const char * arg,int dummy __unused)1876e3a9d7fSAlexander V. Chernikov setvxlan_vni(if_ctx *ctx, const char *arg, int dummy __unused)
188007054f0SBryan Venteicher {
189007054f0SBryan Venteicher struct ifvxlancmd cmd;
190007054f0SBryan Venteicher u_long val;
191007054f0SBryan Venteicher
192007054f0SBryan Venteicher if (get_val(arg, &val) < 0 || val >= VXLAN_VNI_MAX)
193007054f0SBryan Venteicher errx(1, "invalid network identifier: %s", arg);
194007054f0SBryan Venteicher
1956e3a9d7fSAlexander V. Chernikov if (!vxlan_exists(ctx)) {
196007054f0SBryan Venteicher params.vxlp_with |= VXLAN_PARAM_WITH_VNI;
197007054f0SBryan Venteicher params.vxlp_vni = val;
198007054f0SBryan Venteicher return;
199007054f0SBryan Venteicher }
200007054f0SBryan Venteicher
201007054f0SBryan Venteicher bzero(&cmd, sizeof(cmd));
202007054f0SBryan Venteicher cmd.vxlcmd_vni = val;
203007054f0SBryan Venteicher
2046e3a9d7fSAlexander V. Chernikov if (do_cmd(ctx, VXLAN_CMD_SET_VNI, &cmd, sizeof(cmd), 1) < 0)
205007054f0SBryan Venteicher err(1, "VXLAN_CMD_SET_VNI");
206007054f0SBryan Venteicher }
207007054f0SBryan Venteicher
2086e3a9d7fSAlexander V. Chernikov static void
setvxlan_local(if_ctx * ctx,const char * addr,int dummy __unused)2096e3a9d7fSAlexander V. Chernikov setvxlan_local(if_ctx *ctx, const char *addr, int dummy __unused)
210007054f0SBryan Venteicher {
211007054f0SBryan Venteicher struct ifvxlancmd cmd;
212007054f0SBryan Venteicher struct addrinfo *ai;
213*cea9f49fSMateusz Guzik #if (defined INET || defined INET6)
214007054f0SBryan Venteicher struct sockaddr *sa;
215*cea9f49fSMateusz Guzik #endif
216007054f0SBryan Venteicher int error;
217007054f0SBryan Venteicher
218007054f0SBryan Venteicher bzero(&cmd, sizeof(cmd));
219007054f0SBryan Venteicher
220007054f0SBryan Venteicher if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0)
221007054f0SBryan Venteicher errx(1, "error in parsing local address string: %s",
222007054f0SBryan Venteicher gai_strerror(error));
223007054f0SBryan Venteicher
224*cea9f49fSMateusz Guzik #if (defined INET || defined INET6)
225007054f0SBryan Venteicher sa = ai->ai_addr;
226*cea9f49fSMateusz Guzik #endif
227007054f0SBryan Venteicher
228007054f0SBryan Venteicher switch (ai->ai_family) {
229007054f0SBryan Venteicher #ifdef INET
230007054f0SBryan Venteicher case AF_INET: {
23144cd85d4SAlexander V. Chernikov struct sockaddr_in *sin = satosin(sa);
232007054f0SBryan Venteicher
23333e0d8f0SBryan Venteicher if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
234007054f0SBryan Venteicher errx(1, "local address cannot be multicast");
235007054f0SBryan Venteicher
23633e0d8f0SBryan Venteicher cmd.vxlcmd_sa.in4 = *sin;
237007054f0SBryan Venteicher break;
238007054f0SBryan Venteicher }
239007054f0SBryan Venteicher #endif
240007054f0SBryan Venteicher #ifdef INET6
241007054f0SBryan Venteicher case AF_INET6: {
24244cd85d4SAlexander V. Chernikov struct sockaddr_in6 *sin6 = satosin6(sa);
243007054f0SBryan Venteicher
24433e0d8f0SBryan Venteicher if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
245007054f0SBryan Venteicher errx(1, "local address cannot be multicast");
246007054f0SBryan Venteicher
24733e0d8f0SBryan Venteicher cmd.vxlcmd_sa.in6 = *sin6;
248007054f0SBryan Venteicher break;
249007054f0SBryan Venteicher }
250007054f0SBryan Venteicher #endif
251007054f0SBryan Venteicher default:
252007054f0SBryan Venteicher errx(1, "local address %s not supported", addr);
253007054f0SBryan Venteicher }
254007054f0SBryan Venteicher
255007054f0SBryan Venteicher freeaddrinfo(ai);
256007054f0SBryan Venteicher
2576e3a9d7fSAlexander V. Chernikov if (!vxlan_exists(ctx)) {
258007054f0SBryan Venteicher if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) {
259007054f0SBryan Venteicher params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_ADDR4;
26033e0d8f0SBryan Venteicher params.vxlp_local_sa.in4 = cmd.vxlcmd_sa.in4;
261007054f0SBryan Venteicher } else {
262007054f0SBryan Venteicher params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_ADDR6;
26333e0d8f0SBryan Venteicher params.vxlp_local_sa.in6 = cmd.vxlcmd_sa.in6;
264007054f0SBryan Venteicher }
265007054f0SBryan Venteicher return;
266007054f0SBryan Venteicher }
267007054f0SBryan Venteicher
2686e3a9d7fSAlexander V. Chernikov if (do_cmd(ctx, VXLAN_CMD_SET_LOCAL_ADDR, &cmd, sizeof(cmd), 1) < 0)
269007054f0SBryan Venteicher err(1, "VXLAN_CMD_SET_LOCAL_ADDR");
270007054f0SBryan Venteicher }
271007054f0SBryan Venteicher
2726e3a9d7fSAlexander V. Chernikov static void
setvxlan_remote(if_ctx * ctx,const char * addr,int dummy __unused)2736e3a9d7fSAlexander V. Chernikov setvxlan_remote(if_ctx *ctx, const char *addr, int dummy __unused)
274007054f0SBryan Venteicher {
275007054f0SBryan Venteicher struct ifvxlancmd cmd;
276007054f0SBryan Venteicher struct addrinfo *ai;
277*cea9f49fSMateusz Guzik #if (defined INET || defined INET6)
278007054f0SBryan Venteicher struct sockaddr *sa;
279*cea9f49fSMateusz Guzik #endif
280007054f0SBryan Venteicher int error;
281007054f0SBryan Venteicher
282007054f0SBryan Venteicher bzero(&cmd, sizeof(cmd));
283007054f0SBryan Venteicher
284007054f0SBryan Venteicher if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0)
285007054f0SBryan Venteicher errx(1, "error in parsing remote address string: %s",
286007054f0SBryan Venteicher gai_strerror(error));
287007054f0SBryan Venteicher
288*cea9f49fSMateusz Guzik #if (defined INET || defined INET6)
289007054f0SBryan Venteicher sa = ai->ai_addr;
290*cea9f49fSMateusz Guzik #endif
291007054f0SBryan Venteicher
292007054f0SBryan Venteicher switch (ai->ai_family) {
293007054f0SBryan Venteicher #ifdef INET
294007054f0SBryan Venteicher case AF_INET: {
29544cd85d4SAlexander V. Chernikov struct sockaddr_in *sin = satosin(sa);
296007054f0SBryan Venteicher
29733e0d8f0SBryan Venteicher if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
298007054f0SBryan Venteicher errx(1, "remote address cannot be multicast");
299007054f0SBryan Venteicher
30033e0d8f0SBryan Venteicher cmd.vxlcmd_sa.in4 = *sin;
301007054f0SBryan Venteicher break;
302007054f0SBryan Venteicher }
303007054f0SBryan Venteicher #endif
304007054f0SBryan Venteicher #ifdef INET6
305007054f0SBryan Venteicher case AF_INET6: {
30644cd85d4SAlexander V. Chernikov struct sockaddr_in6 *sin6 = satosin6(sa);
307007054f0SBryan Venteicher
30833e0d8f0SBryan Venteicher if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
309007054f0SBryan Venteicher errx(1, "remote address cannot be multicast");
310007054f0SBryan Venteicher
31133e0d8f0SBryan Venteicher cmd.vxlcmd_sa.in6 = *sin6;
312007054f0SBryan Venteicher break;
313007054f0SBryan Venteicher }
314007054f0SBryan Venteicher #endif
315007054f0SBryan Venteicher default:
316007054f0SBryan Venteicher errx(1, "remote address %s not supported", addr);
317007054f0SBryan Venteicher }
318007054f0SBryan Venteicher
319007054f0SBryan Venteicher freeaddrinfo(ai);
320007054f0SBryan Venteicher
3216e3a9d7fSAlexander V. Chernikov if (!vxlan_exists(ctx)) {
322007054f0SBryan Venteicher if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) {
323007054f0SBryan Venteicher params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR4;
32433e0d8f0SBryan Venteicher params.vxlp_remote_sa.in4 = cmd.vxlcmd_sa.in4;
325007054f0SBryan Venteicher } else {
326007054f0SBryan Venteicher params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR6;
32733e0d8f0SBryan Venteicher params.vxlp_remote_sa.in6 = cmd.vxlcmd_sa.in6;
328007054f0SBryan Venteicher }
329007054f0SBryan Venteicher return;
330007054f0SBryan Venteicher }
331007054f0SBryan Venteicher
3326e3a9d7fSAlexander V. Chernikov if (do_cmd(ctx, VXLAN_CMD_SET_REMOTE_ADDR, &cmd, sizeof(cmd), 1) < 0)
333007054f0SBryan Venteicher err(1, "VXLAN_CMD_SET_REMOTE_ADDR");
334007054f0SBryan Venteicher }
335007054f0SBryan Venteicher
3366e3a9d7fSAlexander V. Chernikov static void
setvxlan_group(if_ctx * ctx,const char * addr,int dummy __unused)3376e3a9d7fSAlexander V. Chernikov setvxlan_group(if_ctx *ctx, const char *addr, int dummy __unused)
338007054f0SBryan Venteicher {
339007054f0SBryan Venteicher struct ifvxlancmd cmd;
340007054f0SBryan Venteicher struct addrinfo *ai;
341*cea9f49fSMateusz Guzik #if (defined INET || defined INET6)
342007054f0SBryan Venteicher struct sockaddr *sa;
343*cea9f49fSMateusz Guzik #endif
344007054f0SBryan Venteicher int error;
345007054f0SBryan Venteicher
346007054f0SBryan Venteicher bzero(&cmd, sizeof(cmd));
347007054f0SBryan Venteicher
348007054f0SBryan Venteicher if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0)
349007054f0SBryan Venteicher errx(1, "error in parsing group address string: %s",
350007054f0SBryan Venteicher gai_strerror(error));
351007054f0SBryan Venteicher
352*cea9f49fSMateusz Guzik #if (defined INET || defined INET6)
353007054f0SBryan Venteicher sa = ai->ai_addr;
354*cea9f49fSMateusz Guzik #endif
355007054f0SBryan Venteicher
356007054f0SBryan Venteicher switch (ai->ai_family) {
357007054f0SBryan Venteicher #ifdef INET
358007054f0SBryan Venteicher case AF_INET: {
35944cd85d4SAlexander V. Chernikov struct sockaddr_in *sin = satosin(sa);
360007054f0SBryan Venteicher
36133e0d8f0SBryan Venteicher if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
362007054f0SBryan Venteicher errx(1, "group address must be multicast");
363007054f0SBryan Venteicher
36433e0d8f0SBryan Venteicher cmd.vxlcmd_sa.in4 = *sin;
365007054f0SBryan Venteicher break;
366007054f0SBryan Venteicher }
367007054f0SBryan Venteicher #endif
368007054f0SBryan Venteicher #ifdef INET6
369007054f0SBryan Venteicher case AF_INET6: {
37044cd85d4SAlexander V. Chernikov struct sockaddr_in6 *sin6 = satosin6(sa);
371007054f0SBryan Venteicher
37233e0d8f0SBryan Venteicher if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
373007054f0SBryan Venteicher errx(1, "group address must be multicast");
374007054f0SBryan Venteicher
37533e0d8f0SBryan Venteicher cmd.vxlcmd_sa.in6 = *sin6;
376007054f0SBryan Venteicher break;
377007054f0SBryan Venteicher }
378007054f0SBryan Venteicher #endif
379007054f0SBryan Venteicher default:
380007054f0SBryan Venteicher errx(1, "group address %s not supported", addr);
381007054f0SBryan Venteicher }
382007054f0SBryan Venteicher
383007054f0SBryan Venteicher freeaddrinfo(ai);
384007054f0SBryan Venteicher
3856e3a9d7fSAlexander V. Chernikov if (!vxlan_exists(ctx)) {
386007054f0SBryan Venteicher if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) {
387007054f0SBryan Venteicher params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR4;
38833e0d8f0SBryan Venteicher params.vxlp_remote_sa.in4 = cmd.vxlcmd_sa.in4;
389007054f0SBryan Venteicher } else {
390007054f0SBryan Venteicher params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR6;
39133e0d8f0SBryan Venteicher params.vxlp_remote_sa.in6 = cmd.vxlcmd_sa.in6;
392007054f0SBryan Venteicher }
393007054f0SBryan Venteicher return;
394007054f0SBryan Venteicher }
395007054f0SBryan Venteicher
3966e3a9d7fSAlexander V. Chernikov if (do_cmd(ctx, VXLAN_CMD_SET_REMOTE_ADDR, &cmd, sizeof(cmd), 1) < 0)
397007054f0SBryan Venteicher err(1, "VXLAN_CMD_SET_REMOTE_ADDR");
398007054f0SBryan Venteicher }
399007054f0SBryan Venteicher
4006e3a9d7fSAlexander V. Chernikov static void
setvxlan_local_port(if_ctx * ctx,const char * arg,int dummy __unused)4016e3a9d7fSAlexander V. Chernikov setvxlan_local_port(if_ctx *ctx, const char *arg, int dummy __unused)
402007054f0SBryan Venteicher {
403007054f0SBryan Venteicher struct ifvxlancmd cmd;
404007054f0SBryan Venteicher u_long val;
405007054f0SBryan Venteicher
406007054f0SBryan Venteicher if (get_val(arg, &val) < 0 || val >= UINT16_MAX)
407007054f0SBryan Venteicher errx(1, "invalid local port: %s", arg);
408007054f0SBryan Venteicher
4096e3a9d7fSAlexander V. Chernikov if (!vxlan_exists(ctx)) {
410007054f0SBryan Venteicher params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_PORT;
411007054f0SBryan Venteicher params.vxlp_local_port = val;
412007054f0SBryan Venteicher return;
413007054f0SBryan Venteicher }
414007054f0SBryan Venteicher
415007054f0SBryan Venteicher bzero(&cmd, sizeof(cmd));
416007054f0SBryan Venteicher cmd.vxlcmd_port = val;
417007054f0SBryan Venteicher
4186e3a9d7fSAlexander V. Chernikov if (do_cmd(ctx, VXLAN_CMD_SET_LOCAL_PORT, &cmd, sizeof(cmd), 1) < 0)
419007054f0SBryan Venteicher err(1, "VXLAN_CMD_SET_LOCAL_PORT");
420007054f0SBryan Venteicher }
421007054f0SBryan Venteicher
4226e3a9d7fSAlexander V. Chernikov static void
setvxlan_remote_port(if_ctx * ctx,const char * arg,int dummy __unused)4236e3a9d7fSAlexander V. Chernikov setvxlan_remote_port(if_ctx *ctx, const char *arg, int dummy __unused)
424007054f0SBryan Venteicher {
425007054f0SBryan Venteicher struct ifvxlancmd cmd;
426007054f0SBryan Venteicher u_long val;
427007054f0SBryan Venteicher
428007054f0SBryan Venteicher if (get_val(arg, &val) < 0 || val >= UINT16_MAX)
429007054f0SBryan Venteicher errx(1, "invalid remote port: %s", arg);
430007054f0SBryan Venteicher
4316e3a9d7fSAlexander V. Chernikov if (!vxlan_exists(ctx)) {
432007054f0SBryan Venteicher params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_PORT;
433007054f0SBryan Venteicher params.vxlp_remote_port = val;
434007054f0SBryan Venteicher return;
435007054f0SBryan Venteicher }
436007054f0SBryan Venteicher
437007054f0SBryan Venteicher bzero(&cmd, sizeof(cmd));
438007054f0SBryan Venteicher cmd.vxlcmd_port = val;
439007054f0SBryan Venteicher
4406e3a9d7fSAlexander V. Chernikov if (do_cmd(ctx, VXLAN_CMD_SET_REMOTE_PORT, &cmd, sizeof(cmd), 1) < 0)
441007054f0SBryan Venteicher err(1, "VXLAN_CMD_SET_REMOTE_PORT");
442007054f0SBryan Venteicher }
443007054f0SBryan Venteicher
4446e3a9d7fSAlexander V. Chernikov static void
setvxlan_port_range(if_ctx * ctx,const char * arg1,const char * arg2)4456e3a9d7fSAlexander V. Chernikov setvxlan_port_range(if_ctx *ctx, const char *arg1, const char *arg2)
446007054f0SBryan Venteicher {
447007054f0SBryan Venteicher struct ifvxlancmd cmd;
448007054f0SBryan Venteicher u_long min, max;
449007054f0SBryan Venteicher
450007054f0SBryan Venteicher if (get_val(arg1, &min) < 0 || min >= UINT16_MAX)
451007054f0SBryan Venteicher errx(1, "invalid port range minimum: %s", arg1);
452007054f0SBryan Venteicher if (get_val(arg2, &max) < 0 || max >= UINT16_MAX)
453007054f0SBryan Venteicher errx(1, "invalid port range maximum: %s", arg2);
454007054f0SBryan Venteicher if (max < min)
455007054f0SBryan Venteicher errx(1, "invalid port range");
456007054f0SBryan Venteicher
4576e3a9d7fSAlexander V. Chernikov if (!vxlan_exists(ctx)) {
458007054f0SBryan Venteicher params.vxlp_with |= VXLAN_PARAM_WITH_PORT_RANGE;
459007054f0SBryan Venteicher params.vxlp_min_port = min;
460007054f0SBryan Venteicher params.vxlp_max_port = max;
461007054f0SBryan Venteicher return;
462007054f0SBryan Venteicher }
463007054f0SBryan Venteicher
464007054f0SBryan Venteicher bzero(&cmd, sizeof(cmd));
465007054f0SBryan Venteicher cmd.vxlcmd_port_min = min;
466007054f0SBryan Venteicher cmd.vxlcmd_port_max = max;
467007054f0SBryan Venteicher
4686e3a9d7fSAlexander V. Chernikov if (do_cmd(ctx, VXLAN_CMD_SET_PORT_RANGE, &cmd, sizeof(cmd), 1) < 0)
469007054f0SBryan Venteicher err(1, "VXLAN_CMD_SET_PORT_RANGE");
470007054f0SBryan Venteicher }
471007054f0SBryan Venteicher
4726e3a9d7fSAlexander V. Chernikov static void
setvxlan_timeout(if_ctx * ctx,const char * arg,int dummy __unused)4736e3a9d7fSAlexander V. Chernikov setvxlan_timeout(if_ctx *ctx, const char *arg, int dummy __unused)
474007054f0SBryan Venteicher {
475007054f0SBryan Venteicher struct ifvxlancmd cmd;
476007054f0SBryan Venteicher u_long val;
477007054f0SBryan Venteicher
478007054f0SBryan Venteicher if (get_val(arg, &val) < 0 || (val & ~0xFFFFFFFF) != 0)
479007054f0SBryan Venteicher errx(1, "invalid timeout value: %s", arg);
480007054f0SBryan Venteicher
4816e3a9d7fSAlexander V. Chernikov if (!vxlan_exists(ctx)) {
482007054f0SBryan Venteicher params.vxlp_with |= VXLAN_PARAM_WITH_FTABLE_TIMEOUT;
483007054f0SBryan Venteicher params.vxlp_ftable_timeout = val & 0xFFFFFFFF;
484007054f0SBryan Venteicher return;
485007054f0SBryan Venteicher }
486007054f0SBryan Venteicher
487007054f0SBryan Venteicher bzero(&cmd, sizeof(cmd));
488007054f0SBryan Venteicher cmd.vxlcmd_ftable_timeout = val & 0xFFFFFFFF;
489007054f0SBryan Venteicher
4906e3a9d7fSAlexander V. Chernikov if (do_cmd(ctx, VXLAN_CMD_SET_FTABLE_TIMEOUT, &cmd, sizeof(cmd), 1) < 0)
491007054f0SBryan Venteicher err(1, "VXLAN_CMD_SET_FTABLE_TIMEOUT");
492007054f0SBryan Venteicher }
493007054f0SBryan Venteicher
4946e3a9d7fSAlexander V. Chernikov static void
setvxlan_maxaddr(if_ctx * ctx,const char * arg,int dummy __unused)4956e3a9d7fSAlexander V. Chernikov setvxlan_maxaddr(if_ctx *ctx, const char *arg, int dummy __unused)
496007054f0SBryan Venteicher {
497007054f0SBryan Venteicher struct ifvxlancmd cmd;
498007054f0SBryan Venteicher u_long val;
499007054f0SBryan Venteicher
500007054f0SBryan Venteicher if (get_val(arg, &val) < 0 || (val & ~0xFFFFFFFF) != 0)
501007054f0SBryan Venteicher errx(1, "invalid maxaddr value: %s", arg);
502007054f0SBryan Venteicher
5036e3a9d7fSAlexander V. Chernikov if (!vxlan_exists(ctx)) {
504007054f0SBryan Venteicher params.vxlp_with |= VXLAN_PARAM_WITH_FTABLE_MAX;
505007054f0SBryan Venteicher params.vxlp_ftable_max = val & 0xFFFFFFFF;
506007054f0SBryan Venteicher return;
507007054f0SBryan Venteicher }
508007054f0SBryan Venteicher
509007054f0SBryan Venteicher bzero(&cmd, sizeof(cmd));
510007054f0SBryan Venteicher cmd.vxlcmd_ftable_max = val & 0xFFFFFFFF;
511007054f0SBryan Venteicher
5126e3a9d7fSAlexander V. Chernikov if (do_cmd(ctx, VXLAN_CMD_SET_FTABLE_MAX, &cmd, sizeof(cmd), 1) < 0)
513007054f0SBryan Venteicher err(1, "VXLAN_CMD_SET_FTABLE_MAX");
514007054f0SBryan Venteicher }
515007054f0SBryan Venteicher
5166e3a9d7fSAlexander V. Chernikov static void
setvxlan_dev(if_ctx * ctx,const char * arg,int dummy __unused)5176e3a9d7fSAlexander V. Chernikov setvxlan_dev(if_ctx *ctx, const char *arg, int dummy __unused)
518007054f0SBryan Venteicher {
519007054f0SBryan Venteicher struct ifvxlancmd cmd;
520007054f0SBryan Venteicher
5216e3a9d7fSAlexander V. Chernikov if (!vxlan_exists(ctx)) {
522007054f0SBryan Venteicher params.vxlp_with |= VXLAN_PARAM_WITH_MULTICAST_IF;
523007054f0SBryan Venteicher strlcpy(params.vxlp_mc_ifname, arg,
524007054f0SBryan Venteicher sizeof(params.vxlp_mc_ifname));
525007054f0SBryan Venteicher return;
526007054f0SBryan Venteicher }
527007054f0SBryan Venteicher
528007054f0SBryan Venteicher bzero(&cmd, sizeof(cmd));
529007054f0SBryan Venteicher strlcpy(cmd.vxlcmd_ifname, arg, sizeof(cmd.vxlcmd_ifname));
530007054f0SBryan Venteicher
5316e3a9d7fSAlexander V. Chernikov if (do_cmd(ctx, VXLAN_CMD_SET_MULTICAST_IF, &cmd, sizeof(cmd), 1) < 0)
532007054f0SBryan Venteicher err(1, "VXLAN_CMD_SET_MULTICAST_IF");
533007054f0SBryan Venteicher }
534007054f0SBryan Venteicher
5356e3a9d7fSAlexander V. Chernikov static void
setvxlan_ttl(if_ctx * ctx,const char * arg,int dummy __unused)5366e3a9d7fSAlexander V. Chernikov setvxlan_ttl(if_ctx *ctx, const char *arg, int dummy __unused)
537007054f0SBryan Venteicher {
538007054f0SBryan Venteicher struct ifvxlancmd cmd;
539007054f0SBryan Venteicher u_long val;
540007054f0SBryan Venteicher
541007054f0SBryan Venteicher if (get_val(arg, &val) < 0 || val > 256)
542007054f0SBryan Venteicher errx(1, "invalid TTL value: %s", arg);
543007054f0SBryan Venteicher
5446e3a9d7fSAlexander V. Chernikov if (!vxlan_exists(ctx)) {
545007054f0SBryan Venteicher params.vxlp_with |= VXLAN_PARAM_WITH_TTL;
546007054f0SBryan Venteicher params.vxlp_ttl = val;
547007054f0SBryan Venteicher return;
548007054f0SBryan Venteicher }
549007054f0SBryan Venteicher
550007054f0SBryan Venteicher bzero(&cmd, sizeof(cmd));
551007054f0SBryan Venteicher cmd.vxlcmd_ttl = val;
552007054f0SBryan Venteicher
5536e3a9d7fSAlexander V. Chernikov if (do_cmd(ctx, VXLAN_CMD_SET_TTL, &cmd, sizeof(cmd), 1) < 0)
554007054f0SBryan Venteicher err(1, "VXLAN_CMD_SET_TTL");
555007054f0SBryan Venteicher }
556007054f0SBryan Venteicher
5576e3a9d7fSAlexander V. Chernikov static void
setvxlan_learn(if_ctx * ctx,const char * arg __unused,int d)5580c2beef7SAlexander V. Chernikov setvxlan_learn(if_ctx *ctx, const char *arg __unused, int d)
559007054f0SBryan Venteicher {
560007054f0SBryan Venteicher struct ifvxlancmd cmd;
561007054f0SBryan Venteicher
5626e3a9d7fSAlexander V. Chernikov if (!vxlan_exists(ctx)) {
563007054f0SBryan Venteicher params.vxlp_with |= VXLAN_PARAM_WITH_LEARN;
564007054f0SBryan Venteicher params.vxlp_learn = d;
565007054f0SBryan Venteicher return;
566007054f0SBryan Venteicher }
567007054f0SBryan Venteicher
568007054f0SBryan Venteicher bzero(&cmd, sizeof(cmd));
569007054f0SBryan Venteicher if (d != 0)
570007054f0SBryan Venteicher cmd.vxlcmd_flags |= VXLAN_CMD_FLAG_LEARN;
571007054f0SBryan Venteicher
5726e3a9d7fSAlexander V. Chernikov if (do_cmd(ctx, VXLAN_CMD_SET_LEARN, &cmd, sizeof(cmd), 1) < 0)
573007054f0SBryan Venteicher err(1, "VXLAN_CMD_SET_LEARN");
574007054f0SBryan Venteicher }
575007054f0SBryan Venteicher
576007054f0SBryan Venteicher static void
setvxlan_flush(if_ctx * ctx,const char * val __unused,int d)5776e3a9d7fSAlexander V. Chernikov setvxlan_flush(if_ctx *ctx, const char *val __unused, int d)
578007054f0SBryan Venteicher {
579007054f0SBryan Venteicher struct ifvxlancmd cmd;
580007054f0SBryan Venteicher
581007054f0SBryan Venteicher bzero(&cmd, sizeof(cmd));
582007054f0SBryan Venteicher if (d != 0)
583007054f0SBryan Venteicher cmd.vxlcmd_flags |= VXLAN_CMD_FLAG_FLUSH_ALL;
584007054f0SBryan Venteicher
5856e3a9d7fSAlexander V. Chernikov if (do_cmd(ctx, VXLAN_CMD_FLUSH, &cmd, sizeof(cmd), 1) < 0)
586007054f0SBryan Venteicher err(1, "VXLAN_CMD_FLUSH");
587007054f0SBryan Venteicher }
588007054f0SBryan Venteicher
589007054f0SBryan Venteicher static struct cmd vxlan_cmds[] = {
590007054f0SBryan Venteicher
591f53d9723SBryan Venteicher DEF_CLONE_CMD_ARG("vni", setvxlan_vni),
592c6e32006SBryan Venteicher DEF_CLONE_CMD_ARG("vxlanid", setvxlan_vni),
593c6e32006SBryan Venteicher DEF_CLONE_CMD_ARG("vxlanlocal", setvxlan_local),
594c6e32006SBryan Venteicher DEF_CLONE_CMD_ARG("vxlanremote", setvxlan_remote),
595c6e32006SBryan Venteicher DEF_CLONE_CMD_ARG("vxlangroup", setvxlan_group),
596c6e32006SBryan Venteicher DEF_CLONE_CMD_ARG("vxlanlocalport", setvxlan_local_port),
597c6e32006SBryan Venteicher DEF_CLONE_CMD_ARG("vxlanremoteport", setvxlan_remote_port),
598c6e32006SBryan Venteicher DEF_CLONE_CMD_ARG2("vxlanportrange", setvxlan_port_range),
599c6e32006SBryan Venteicher DEF_CLONE_CMD_ARG("vxlantimeout", setvxlan_timeout),
600c6e32006SBryan Venteicher DEF_CLONE_CMD_ARG("vxlanmaxaddr", setvxlan_maxaddr),
601007054f0SBryan Venteicher DEF_CLONE_CMD_ARG("vxlandev", setvxlan_dev),
602c6e32006SBryan Venteicher DEF_CLONE_CMD_ARG("vxlanttl", setvxlan_ttl),
603c6e32006SBryan Venteicher DEF_CLONE_CMD("vxlanlearn", 1, setvxlan_learn),
604c6e32006SBryan Venteicher DEF_CLONE_CMD("-vxlanlearn", 0, setvxlan_learn),
605007054f0SBryan Venteicher
606f53d9723SBryan Venteicher DEF_CMD_ARG("vni", setvxlan_vni),
607f53d9723SBryan Venteicher DEF_CMD_ARG("vxlanid", setvxlan_vni),
608c6e32006SBryan Venteicher DEF_CMD_ARG("vxlanlocal", setvxlan_local),
609c6e32006SBryan Venteicher DEF_CMD_ARG("vxlanremote", setvxlan_remote),
610c6e32006SBryan Venteicher DEF_CMD_ARG("vxlangroup", setvxlan_group),
611c6e32006SBryan Venteicher DEF_CMD_ARG("vxlanlocalport", setvxlan_local_port),
612c6e32006SBryan Venteicher DEF_CMD_ARG("vxlanremoteport", setvxlan_remote_port),
613c6e32006SBryan Venteicher DEF_CMD_ARG2("vxlanportrange", setvxlan_port_range),
614c6e32006SBryan Venteicher DEF_CMD_ARG("vxlantimeout", setvxlan_timeout),
615c6e32006SBryan Venteicher DEF_CMD_ARG("vxlanmaxaddr", setvxlan_maxaddr),
616007054f0SBryan Venteicher DEF_CMD_ARG("vxlandev", setvxlan_dev),
617c6e32006SBryan Venteicher DEF_CMD_ARG("vxlanttl", setvxlan_ttl),
618c6e32006SBryan Venteicher DEF_CMD("vxlanlearn", 1, setvxlan_learn),
619c6e32006SBryan Venteicher DEF_CMD("-vxlanlearn", 0, setvxlan_learn),
620007054f0SBryan Venteicher
621c6e32006SBryan Venteicher DEF_CMD("vxlanflush", 0, setvxlan_flush),
622c6e32006SBryan Venteicher DEF_CMD("vxlanflushall", 1, setvxlan_flush),
623830edb45SNavdeep Parhar
624830edb45SNavdeep Parhar DEF_CMD("vxlanhwcsum", IFCAP_VXLAN_HWCSUM, setifcap),
62508992b20SJohn Baldwin DEF_CMD("-vxlanhwcsum", IFCAP_VXLAN_HWCSUM, clearifcap),
626830edb45SNavdeep Parhar DEF_CMD("vxlanhwtso", IFCAP_VXLAN_HWTSO, setifcap),
62708992b20SJohn Baldwin DEF_CMD("-vxlanhwtso", IFCAP_VXLAN_HWTSO, clearifcap),
628007054f0SBryan Venteicher };
629007054f0SBryan Venteicher
630007054f0SBryan Venteicher static struct afswtch af_vxlan = {
631007054f0SBryan Venteicher .af_name = "af_vxlan",
632007054f0SBryan Venteicher .af_af = AF_UNSPEC,
633007054f0SBryan Venteicher .af_other_status = vxlan_status,
634007054f0SBryan Venteicher };
635007054f0SBryan Venteicher
636007054f0SBryan Venteicher static __constructor void
vxlan_ctor(void)637007054f0SBryan Venteicher vxlan_ctor(void)
638007054f0SBryan Venteicher {
639007054f0SBryan Venteicher size_t i;
640007054f0SBryan Venteicher
641abd71050SEnji Cooper for (i = 0; i < nitems(vxlan_cmds); i++)
642007054f0SBryan Venteicher cmd_register(&vxlan_cmds[i]);
643007054f0SBryan Venteicher af_register(&af_vxlan);
644c7cffd65SAlexander V. Chernikov clone_setdefcallback_prefix("vxlan", vxlan_create);
645007054f0SBryan Venteicher }
646