2 * Copyright (c) 2014, Bryan Venteicher <bryanv@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions, and the following
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33 #include <sys/sockio.h>
40 #include <net/ethernet.h>
42 #include <net/if_vxlan.h>
43 #include <net/route.h>
44 #include <netinet/in.h>
56 static struct ifvxlanparam params
= {
57 .vxlp_vni
= VXLAN_VNI_MAX
,
61 get_val(const char *cp
, u_long
*valp
)
67 val
= strtoul(cp
, &endptr
, 0);
68 if (cp
[0] == '\0' || endptr
[0] != '\0' || errno
== ERANGE
)
76 do_cmd(int sock
, u_long op
, void *arg
, size_t argsize
, int set
)
80 bzero(&ifd
, sizeof(ifd
));
82 strlcpy(ifd
.ifd_name
, ifr
.ifr_name
, sizeof(ifd
.ifd_name
));
84 ifd
.ifd_len
= argsize
;
87 return (ioctl(sock
, set
? SIOCSDRVSPEC
: SIOCGDRVSPEC
, &ifd
));
91 vxlan_exists(int sock
)
93 struct ifvxlancfg cfg
;
95 bzero(&cfg
, sizeof(cfg
));
97 return (do_cmd(sock
, VXLAN_CMD_GET_CONFIG
, &cfg
, sizeof(cfg
), 0) != -1);
103 struct ifvxlancfg cfg
;
104 char src
[NI_MAXHOST
], dst
[NI_MAXHOST
];
105 char srcport
[NI_MAXSERV
], dstport
[NI_MAXSERV
];
106 struct sockaddr
*lsa
, *rsa
;
109 bzero(&cfg
, sizeof(cfg
));
111 if (do_cmd(s
, VXLAN_CMD_GET_CONFIG
, &cfg
, sizeof(cfg
), 0) < 0)
115 lsa
= &cfg
.vxlc_local_sa
.sa
;
116 rsa
= &cfg
.vxlc_remote_sa
.sa
;
117 ipv6
= rsa
->sa_family
== AF_INET6
;
119 /* Just report nothing if the network identity isn't set yet. */
120 if (vni
>= VXLAN_VNI_MAX
)
123 if (getnameinfo(lsa
, lsa
->sa_len
, src
, sizeof(src
),
124 srcport
, sizeof(srcport
), NI_NUMERICHOST
| NI_NUMERICSERV
) != 0)
125 src
[0] = srcport
[0] = '\0';
126 if (getnameinfo(rsa
, rsa
->sa_len
, dst
, sizeof(dst
),
127 dstport
, sizeof(dstport
), NI_NUMERICHOST
| NI_NUMERICSERV
) != 0)
128 dst
[0] = dstport
[0] = '\0';
131 struct sockaddr_in
*sin
= (struct sockaddr_in
*)rsa
;
132 mc
= IN_MULTICAST(ntohl(sin
->sin_addr
.s_addr
));
134 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)rsa
;
135 mc
= IN6_IS_ADDR_MULTICAST(&sin6
->sin6_addr
);
138 printf("\tvxlan vni %d", vni
);
139 printf(" local %s%s%s:%s", ipv6
? "[" : "", src
, ipv6
? "]" : "",
141 printf(" %s %s%s%s:%s", mc
? "group" : "remote", ipv6
? "[" : "",
142 dst
, ipv6
? "]" : "", dstport
);
145 printf("\n\t\tconfig: ");
146 printf("%slearning portrange %d-%d ttl %d",
147 cfg
.vxlc_learn
? "" : "no", cfg
.vxlc_port_min
,
148 cfg
.vxlc_port_max
, cfg
.vxlc_ttl
);
149 printf("\n\t\tftable: ");
150 printf("cnt %d max %d timeout %d",
151 cfg
.vxlc_ftable_cnt
, cfg
.vxlc_ftable_max
,
152 cfg
.vxlc_ftable_timeout
);
158 #define _LOCAL_ADDR46 \
159 (VXLAN_PARAM_WITH_LOCAL_ADDR4 | VXLAN_PARAM_WITH_LOCAL_ADDR6)
160 #define _REMOTE_ADDR46 \
161 (VXLAN_PARAM_WITH_REMOTE_ADDR4 | VXLAN_PARAM_WITH_REMOTE_ADDR6)
164 vxlan_check_params(void)
167 if ((params
.vxlp_with
& _LOCAL_ADDR46
) == _LOCAL_ADDR46
)
168 errx(1, "cannot specify both local IPv4 and IPv6 addresses");
169 if ((params
.vxlp_with
& _REMOTE_ADDR46
) == _REMOTE_ADDR46
)
170 errx(1, "cannot specify both remote IPv4 and IPv6 addresses");
171 if ((params
.vxlp_with
& VXLAN_PARAM_WITH_LOCAL_ADDR4
&&
172 params
.vxlp_with
& VXLAN_PARAM_WITH_REMOTE_ADDR6
) ||
173 (params
.vxlp_with
& VXLAN_PARAM_WITH_LOCAL_ADDR6
&&
174 params
.vxlp_with
& VXLAN_PARAM_WITH_REMOTE_ADDR4
))
175 errx(1, "cannot mix IPv4 and IPv6 addresses");
179 #undef _REMOTE_ADDR46
182 vxlan_cb(int s
, void *arg
)
188 vxlan_create(int s
, struct ifreq
*ifr
)
191 vxlan_check_params();
193 ifr
->ifr_data
= (caddr_t
) ¶ms
;
194 if (ioctl(s
, SIOCIFCREATE2
, ifr
) < 0)
195 err(1, "SIOCIFCREATE2");
199 DECL_CMD_FUNC(setvxlan_vni
, arg
, d
)
201 struct ifvxlancmd cmd
;
204 if (get_val(arg
, &val
) < 0 || val
>= VXLAN_VNI_MAX
)
205 errx(1, "invalid network identifier: %s", arg
);
207 if (!vxlan_exists(s
)) {
208 params
.vxlp_with
|= VXLAN_PARAM_WITH_VNI
;
209 params
.vxlp_vni
= val
;
213 bzero(&cmd
, sizeof(cmd
));
214 cmd
.vxlcmd_vni
= val
;
216 if (do_cmd(s
, VXLAN_CMD_SET_VNI
, &cmd
, sizeof(cmd
), 1) < 0)
217 err(1, "VXLAN_CMD_SET_VNI");
221 DECL_CMD_FUNC(setvxlan_local
, addr
, d
)
223 struct ifvxlancmd cmd
;
228 bzero(&cmd
, sizeof(cmd
));
230 if ((error
= getaddrinfo(addr
, NULL
, NULL
, &ai
)) != 0)
231 errx(1, "error in parsing local address string: %s",
232 gai_strerror(error
));
236 switch (ai
->ai_family
) {
239 struct in_addr addr
= ((struct sockaddr_in
*) sa
)->sin_addr
;
241 if (IN_MULTICAST(ntohl(addr
.s_addr
)))
242 errx(1, "local address cannot be multicast");
244 cmd
.vxlcmd_sa
.in4
.sin_family
= AF_INET
;
245 cmd
.vxlcmd_sa
.in4
.sin_addr
= addr
;
251 struct in6_addr
*addr
= &((struct sockaddr_in6
*)sa
)->sin6_addr
;
253 if (IN6_IS_ADDR_MULTICAST(addr
))
254 errx(1, "local address cannot be multicast");
256 cmd
.vxlcmd_sa
.in6
.sin6_family
= AF_INET6
;
257 cmd
.vxlcmd_sa
.in6
.sin6_addr
= *addr
;
262 errx(1, "local address %s not supported", addr
);
267 if (!vxlan_exists(s
)) {
268 if (cmd
.vxlcmd_sa
.sa
.sa_family
== AF_INET
) {
269 params
.vxlp_with
|= VXLAN_PARAM_WITH_LOCAL_ADDR4
;
270 params
.vxlp_local_in4
= cmd
.vxlcmd_sa
.in4
.sin_addr
;
272 params
.vxlp_with
|= VXLAN_PARAM_WITH_LOCAL_ADDR6
;
273 params
.vxlp_local_in6
= cmd
.vxlcmd_sa
.in6
.sin6_addr
;
278 if (do_cmd(s
, VXLAN_CMD_SET_LOCAL_ADDR
, &cmd
, sizeof(cmd
), 1) < 0)
279 err(1, "VXLAN_CMD_SET_LOCAL_ADDR");
283 DECL_CMD_FUNC(setvxlan_remote
, addr
, d
)
285 struct ifvxlancmd cmd
;
290 bzero(&cmd
, sizeof(cmd
));
292 if ((error
= getaddrinfo(addr
, NULL
, NULL
, &ai
)) != 0)
293 errx(1, "error in parsing remote address string: %s",
294 gai_strerror(error
));
298 switch (ai
->ai_family
) {
301 struct in_addr addr
= ((struct sockaddr_in
*)sa
)->sin_addr
;
303 if (IN_MULTICAST(ntohl(addr
.s_addr
)))
304 errx(1, "remote address cannot be multicast");
306 cmd
.vxlcmd_sa
.in4
.sin_family
= AF_INET
;
307 cmd
.vxlcmd_sa
.in4
.sin_addr
= addr
;
313 struct in6_addr
*addr
= &((struct sockaddr_in6
*)sa
)->sin6_addr
;
315 if (IN6_IS_ADDR_MULTICAST(addr
))
316 errx(1, "remote address cannot be multicast");
318 cmd
.vxlcmd_sa
.in6
.sin6_family
= AF_INET6
;
319 cmd
.vxlcmd_sa
.in6
.sin6_addr
= *addr
;
324 errx(1, "remote address %s not supported", addr
);
329 if (!vxlan_exists(s
)) {
330 if (cmd
.vxlcmd_sa
.sa
.sa_family
== AF_INET
) {
331 params
.vxlp_with
|= VXLAN_PARAM_WITH_REMOTE_ADDR4
;
332 params
.vxlp_remote_in4
= cmd
.vxlcmd_sa
.in4
.sin_addr
;
334 params
.vxlp_with
|= VXLAN_PARAM_WITH_REMOTE_ADDR6
;
335 params
.vxlp_remote_in6
= cmd
.vxlcmd_sa
.in6
.sin6_addr
;
340 if (do_cmd(s
, VXLAN_CMD_SET_REMOTE_ADDR
, &cmd
, sizeof(cmd
), 1) < 0)
341 err(1, "VXLAN_CMD_SET_REMOTE_ADDR");
345 DECL_CMD_FUNC(setvxlan_group
, addr
, d
)
347 struct ifvxlancmd cmd
;
352 bzero(&cmd
, sizeof(cmd
));
354 if ((error
= getaddrinfo(addr
, NULL
, NULL
, &ai
)) != 0)
355 errx(1, "error in parsing group address string: %s",
356 gai_strerror(error
));
360 switch (ai
->ai_family
) {
363 struct in_addr addr
= ((struct sockaddr_in
*)sa
)->sin_addr
;
365 if (!IN_MULTICAST(ntohl(addr
.s_addr
)))
366 errx(1, "group address must be multicast");
368 cmd
.vxlcmd_sa
.in4
.sin_family
= AF_INET
;
369 cmd
.vxlcmd_sa
.in4
.sin_addr
= addr
;
375 struct in6_addr
*addr
= &((struct sockaddr_in6
*)sa
)->sin6_addr
;
377 if (!IN6_IS_ADDR_MULTICAST(addr
))
378 errx(1, "group address must be multicast");
380 cmd
.vxlcmd_sa
.in6
.sin6_family
= AF_INET6
;
381 cmd
.vxlcmd_sa
.in6
.sin6_addr
= *addr
;
386 errx(1, "group address %s not supported", addr
);
391 if (!vxlan_exists(s
)) {
392 if (cmd
.vxlcmd_sa
.sa
.sa_family
== AF_INET
) {
393 params
.vxlp_with
|= VXLAN_PARAM_WITH_REMOTE_ADDR4
;
394 params
.vxlp_remote_in4
= cmd
.vxlcmd_sa
.in4
.sin_addr
;
396 params
.vxlp_with
|= VXLAN_PARAM_WITH_REMOTE_ADDR6
;
397 params
.vxlp_remote_in6
= cmd
.vxlcmd_sa
.in6
.sin6_addr
;
402 if (do_cmd(s
, VXLAN_CMD_SET_REMOTE_ADDR
, &cmd
, sizeof(cmd
), 1) < 0)
403 err(1, "VXLAN_CMD_SET_REMOTE_ADDR");
407 DECL_CMD_FUNC(setvxlan_local_port
, arg
, d
)
409 struct ifvxlancmd cmd
;
412 if (get_val(arg
, &val
) < 0 || val
>= UINT16_MAX
)
413 errx(1, "invalid local port: %s", arg
);
415 if (!vxlan_exists(s
)) {
416 params
.vxlp_with
|= VXLAN_PARAM_WITH_LOCAL_PORT
;
417 params
.vxlp_local_port
= val
;
421 bzero(&cmd
, sizeof(cmd
));
422 cmd
.vxlcmd_port
= val
;
424 if (do_cmd(s
, VXLAN_CMD_SET_LOCAL_PORT
, &cmd
, sizeof(cmd
), 1) < 0)
425 err(1, "VXLAN_CMD_SET_LOCAL_PORT");
429 DECL_CMD_FUNC(setvxlan_remote_port
, arg
, d
)
431 struct ifvxlancmd cmd
;
434 if (get_val(arg
, &val
) < 0 || val
>= UINT16_MAX
)
435 errx(1, "invalid remote port: %s", arg
);
437 if (!vxlan_exists(s
)) {
438 params
.vxlp_with
|= VXLAN_PARAM_WITH_REMOTE_PORT
;
439 params
.vxlp_remote_port
= val
;
443 bzero(&cmd
, sizeof(cmd
));
444 cmd
.vxlcmd_port
= val
;
446 if (do_cmd(s
, VXLAN_CMD_SET_REMOTE_PORT
, &cmd
, sizeof(cmd
), 1) < 0)
447 err(1, "VXLAN_CMD_SET_REMOTE_PORT");
451 DECL_CMD_FUNC2(setvxlan_port_range
, arg1
, arg2
)
453 struct ifvxlancmd cmd
;
456 if (get_val(arg1
, &min
) < 0 || min
>= UINT16_MAX
)
457 errx(1, "invalid port range minimum: %s", arg1
);
458 if (get_val(arg2
, &max
) < 0 || max
>= UINT16_MAX
)
459 errx(1, "invalid port range maximum: %s", arg2
);
461 errx(1, "invalid port range");
463 if (!vxlan_exists(s
)) {
464 params
.vxlp_with
|= VXLAN_PARAM_WITH_PORT_RANGE
;
465 params
.vxlp_min_port
= min
;
466 params
.vxlp_max_port
= max
;
470 bzero(&cmd
, sizeof(cmd
));
471 cmd
.vxlcmd_port_min
= min
;
472 cmd
.vxlcmd_port_max
= max
;
474 if (do_cmd(s
, VXLAN_CMD_SET_PORT_RANGE
, &cmd
, sizeof(cmd
), 1) < 0)
475 err(1, "VXLAN_CMD_SET_PORT_RANGE");
479 DECL_CMD_FUNC(setvxlan_timeout
, arg
, d
)
481 struct ifvxlancmd cmd
;
484 if (get_val(arg
, &val
) < 0 || (val
& ~0xFFFFFFFF) != 0)
485 errx(1, "invalid timeout value: %s", arg
);
487 if (!vxlan_exists(s
)) {
488 params
.vxlp_with
|= VXLAN_PARAM_WITH_FTABLE_TIMEOUT
;
489 params
.vxlp_ftable_timeout
= val
& 0xFFFFFFFF;
493 bzero(&cmd
, sizeof(cmd
));
494 cmd
.vxlcmd_ftable_timeout
= val
& 0xFFFFFFFF;
496 if (do_cmd(s
, VXLAN_CMD_SET_FTABLE_TIMEOUT
, &cmd
, sizeof(cmd
), 1) < 0)
497 err(1, "VXLAN_CMD_SET_FTABLE_TIMEOUT");
501 DECL_CMD_FUNC(setvxlan_maxaddr
, arg
, d
)
503 struct ifvxlancmd cmd
;
506 if (get_val(arg
, &val
) < 0 || (val
& ~0xFFFFFFFF) != 0)
507 errx(1, "invalid maxaddr value: %s", arg
);
509 if (!vxlan_exists(s
)) {
510 params
.vxlp_with
|= VXLAN_PARAM_WITH_FTABLE_MAX
;
511 params
.vxlp_ftable_max
= val
& 0xFFFFFFFF;
515 bzero(&cmd
, sizeof(cmd
));
516 cmd
.vxlcmd_ftable_max
= val
& 0xFFFFFFFF;
518 if (do_cmd(s
, VXLAN_CMD_SET_FTABLE_MAX
, &cmd
, sizeof(cmd
), 1) < 0)
519 err(1, "VXLAN_CMD_SET_FTABLE_MAX");
523 DECL_CMD_FUNC(setvxlan_dev
, arg
, d
)
525 struct ifvxlancmd cmd
;
527 if (!vxlan_exists(s
)) {
528 params
.vxlp_with
|= VXLAN_PARAM_WITH_MULTICAST_IF
;
529 strlcpy(params
.vxlp_mc_ifname
, arg
,
530 sizeof(params
.vxlp_mc_ifname
));
534 bzero(&cmd
, sizeof(cmd
));
535 strlcpy(cmd
.vxlcmd_ifname
, arg
, sizeof(cmd
.vxlcmd_ifname
));
537 if (do_cmd(s
, VXLAN_CMD_SET_MULTICAST_IF
, &cmd
, sizeof(cmd
), 1) < 0)
538 err(1, "VXLAN_CMD_SET_MULTICAST_IF");
542 DECL_CMD_FUNC(setvxlan_ttl
, arg
, d
)
544 struct ifvxlancmd cmd
;
547 if (get_val(arg
, &val
) < 0 || val
> 256)
548 errx(1, "invalid TTL value: %s", arg
);
550 if (!vxlan_exists(s
)) {
551 params
.vxlp_with
|= VXLAN_PARAM_WITH_TTL
;
552 params
.vxlp_ttl
= val
;
556 bzero(&cmd
, sizeof(cmd
));
557 cmd
.vxlcmd_ttl
= val
;
559 if (do_cmd(s
, VXLAN_CMD_SET_TTL
, &cmd
, sizeof(cmd
), 1) < 0)
560 err(1, "VXLAN_CMD_SET_TTL");
564 DECL_CMD_FUNC(setvxlan_learn
, arg
, d
)
566 struct ifvxlancmd cmd
;
568 if (!vxlan_exists(s
)) {
569 params
.vxlp_with
|= VXLAN_PARAM_WITH_LEARN
;
570 params
.vxlp_learn
= d
;
574 bzero(&cmd
, sizeof(cmd
));
576 cmd
.vxlcmd_flags
|= VXLAN_CMD_FLAG_LEARN
;
578 if (do_cmd(s
, VXLAN_CMD_SET_LEARN
, &cmd
, sizeof(cmd
), 1) < 0)
579 err(1, "VXLAN_CMD_SET_LEARN");
583 setvxlan_flush(const char *val
, int d
, int s
, const struct afswtch
*afp
)
585 struct ifvxlancmd cmd
;
587 bzero(&cmd
, sizeof(cmd
));
589 cmd
.vxlcmd_flags
|= VXLAN_CMD_FLAG_FLUSH_ALL
;
591 if (do_cmd(s
, VXLAN_CMD_FLUSH
, &cmd
, sizeof(cmd
), 1) < 0)
592 err(1, "VXLAN_CMD_FLUSH");
595 static struct cmd vxlan_cmds
[] = {
597 DEF_CLONE_CMD_ARG("vxlanid", setvxlan_vni
),
598 DEF_CLONE_CMD_ARG("vxlanlocal", setvxlan_local
),
599 DEF_CLONE_CMD_ARG("vxlanremote", setvxlan_remote
),
600 DEF_CLONE_CMD_ARG("vxlangroup", setvxlan_group
),
601 DEF_CLONE_CMD_ARG("vxlanlocalport", setvxlan_local_port
),
602 DEF_CLONE_CMD_ARG("vxlanremoteport", setvxlan_remote_port
),
603 DEF_CLONE_CMD_ARG2("vxlanportrange", setvxlan_port_range
),
604 DEF_CLONE_CMD_ARG("vxlantimeout", setvxlan_timeout
),
605 DEF_CLONE_CMD_ARG("vxlanmaxaddr", setvxlan_maxaddr
),
606 DEF_CLONE_CMD_ARG("vxlandev", setvxlan_dev
),
607 DEF_CLONE_CMD_ARG("vxlanttl", setvxlan_ttl
),
608 DEF_CLONE_CMD("vxlanlearn", 1, setvxlan_learn
),
609 DEF_CLONE_CMD("-vxlanlearn", 0, setvxlan_learn
),
611 DEF_CMD_ARG("vxlanvni", setvxlan_vni
),
612 DEF_CMD_ARG("vxlanlocal", setvxlan_local
),
613 DEF_CMD_ARG("vxlanremote", setvxlan_remote
),
614 DEF_CMD_ARG("vxlangroup", setvxlan_group
),
615 DEF_CMD_ARG("vxlanlocalport", setvxlan_local_port
),
616 DEF_CMD_ARG("vxlanremoteport", setvxlan_remote_port
),
617 DEF_CMD_ARG2("vxlanportrange", setvxlan_port_range
),
618 DEF_CMD_ARG("vxlantimeout", setvxlan_timeout
),
619 DEF_CMD_ARG("vxlanmaxaddr", setvxlan_maxaddr
),
620 DEF_CMD_ARG("vxlandev", setvxlan_dev
),
621 DEF_CMD_ARG("vxlanttl", setvxlan_ttl
),
622 DEF_CMD("vxlanlearn", 1, setvxlan_learn
),
623 DEF_CMD("-vxlanlearn", 0, setvxlan_learn
),
625 DEF_CMD("vxlanflush", 0, setvxlan_flush
),
626 DEF_CMD("vxlanflushall", 1, setvxlan_flush
),
629 static struct afswtch af_vxlan
= {
630 .af_name
= "af_vxlan",
632 .af_other_status
= vxlan_status
,
635 static __constructor
void
640 for (i
= 0; i
< nitems(vxlan_cmds
); i
++)
641 cmd_register(&vxlan_cmds
[i
]);
642 af_register(&af_vxlan
);
643 callback_register(vxlan_cb
, NULL
);
644 clone_setdefcallback("vxlan", vxlan_create
);