Line data Source code
1 : /* $OpenBSD: if_vxlan.c,v 1.68 2018/08/17 01:53:31 dlg Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2013 Reyk Floeter <reyk@openbsd.org>
5 : *
6 : * Permission to use, copy, modify, and distribute this software for any
7 : * purpose with or without fee is hereby granted, provided that the above
8 : * copyright notice and this permission notice appear in all copies.
9 : *
10 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 : */
18 :
19 : #include "bpfilter.h"
20 : #include "vxlan.h"
21 : #include "vlan.h"
22 : #include "pf.h"
23 : #include "bridge.h"
24 :
25 : #include <sys/param.h>
26 : #include <sys/systm.h>
27 : #include <sys/mbuf.h>
28 : #include <sys/socket.h>
29 : #include <sys/sockio.h>
30 : #include <sys/ioctl.h>
31 :
32 : #include <net/if.h>
33 : #include <net/if_var.h>
34 : #include <net/if_media.h>
35 : #include <net/route.h>
36 :
37 : #if NBPFILTER > 0
38 : #include <net/bpf.h>
39 : #endif
40 :
41 : #include <netinet/in.h>
42 : #include <netinet/in_var.h>
43 : #include <netinet/if_ether.h>
44 : #include <netinet/ip.h>
45 : #include <netinet/ip_var.h>
46 : #include <netinet/udp.h>
47 : #include <netinet/udp_var.h>
48 : #include <netinet/in_pcb.h>
49 :
50 : #if NPF > 0
51 : #include <net/pfvar.h>
52 : #endif
53 :
54 : #if NBRIDGE > 0
55 : #include <net/if_bridge.h>
56 : #endif
57 :
58 : #include <net/if_vxlan.h>
59 :
60 : struct vxlan_softc {
61 : struct arpcom sc_ac;
62 : struct ifmedia sc_media;
63 :
64 : struct ip_moptions sc_imo;
65 : void *sc_ahcookie;
66 : void *sc_lhcookie;
67 : void *sc_dhcookie;
68 :
69 : struct sockaddr_storage sc_src;
70 : struct sockaddr_storage sc_dst;
71 : in_port_t sc_dstport;
72 : u_int sc_rdomain;
73 : int64_t sc_vnetid;
74 : uint16_t sc_df;
75 : u_int8_t sc_ttl;
76 :
77 : struct task sc_sendtask;
78 :
79 : LIST_ENTRY(vxlan_softc) sc_entry;
80 : };
81 :
82 : void vxlanattach(int);
83 : int vxlanioctl(struct ifnet *, u_long, caddr_t);
84 : void vxlanstart(struct ifnet *);
85 : int vxlan_clone_create(struct if_clone *, int);
86 : int vxlan_clone_destroy(struct ifnet *);
87 : void vxlan_multicast_cleanup(struct ifnet *);
88 : int vxlan_multicast_join(struct ifnet *, struct sockaddr *,
89 : struct sockaddr *);
90 : int vxlan_media_change(struct ifnet *);
91 : void vxlan_media_status(struct ifnet *, struct ifmediareq *);
92 : int vxlan_config(struct ifnet *, struct sockaddr *, struct sockaddr *);
93 : int vxlan_output(struct ifnet *, struct mbuf *);
94 : void vxlan_addr_change(void *);
95 : void vxlan_if_change(void *);
96 : void vxlan_link_change(void *);
97 : void vxlan_send_dispatch(void *);
98 :
99 : int vxlan_sockaddr_cmp(struct sockaddr *, struct sockaddr *);
100 : uint16_t vxlan_sockaddr_port(struct sockaddr *);
101 :
102 : struct if_clone vxlan_cloner =
103 : IF_CLONE_INITIALIZER("vxlan", vxlan_clone_create, vxlan_clone_destroy);
104 :
105 : int vxlan_enable = 0;
106 : u_long vxlan_tagmask;
107 :
108 : #define VXLAN_TAGHASHSIZE 32
109 : #define VXLAN_TAGHASH(tag) ((unsigned int)tag & vxlan_tagmask)
110 : LIST_HEAD(vxlan_taghash, vxlan_softc) *vxlan_tagh, vxlan_any;
111 :
112 : void
113 0 : vxlanattach(int count)
114 : {
115 : /* Regular vxlan interfaces with a VNI */
116 0 : if ((vxlan_tagh = hashinit(VXLAN_TAGHASHSIZE, M_DEVBUF, M_NOWAIT,
117 0 : &vxlan_tagmask)) == NULL)
118 0 : panic("vxlanattach: hashinit");
119 :
120 : /* multipoint-to-multipoint interfaces that accept any VNI */
121 0 : LIST_INIT(&vxlan_any);
122 :
123 0 : if_clone_attach(&vxlan_cloner);
124 0 : }
125 :
126 : int
127 0 : vxlan_clone_create(struct if_clone *ifc, int unit)
128 : {
129 : struct ifnet *ifp;
130 : struct vxlan_softc *sc;
131 :
132 0 : sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
133 0 : sc->sc_imo.imo_membership = malloc(
134 : (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_IPMOPTS,
135 : M_WAITOK|M_ZERO);
136 0 : sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS;
137 0 : sc->sc_dstport = htons(VXLAN_PORT);
138 0 : sc->sc_vnetid = VXLAN_VNI_UNSET;
139 0 : sc->sc_df = htons(0);
140 0 : task_set(&sc->sc_sendtask, vxlan_send_dispatch, sc);
141 :
142 0 : ifp = &sc->sc_ac.ac_if;
143 0 : snprintf(ifp->if_xname, sizeof ifp->if_xname, "vxlan%d", unit);
144 0 : ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
145 0 : ether_fakeaddr(ifp);
146 :
147 0 : ifp->if_softc = sc;
148 0 : ifp->if_ioctl = vxlanioctl;
149 0 : ifp->if_start = vxlanstart;
150 0 : IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
151 :
152 0 : ifp->if_hardmtu = ETHER_MAX_HARDMTU_LEN;
153 0 : ifp->if_capabilities = IFCAP_VLAN_MTU;
154 :
155 0 : ifmedia_init(&sc->sc_media, 0, vxlan_media_change,
156 : vxlan_media_status);
157 0 : ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
158 0 : ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
159 :
160 0 : if_attach(ifp);
161 0 : ether_ifattach(ifp);
162 :
163 : #if 0
164 : /*
165 : * Instead of using a decreased MTU of 1450 bytes, prefer
166 : * to use the default Ethernet-size MTU of 1500 bytes and to
167 : * increase the MTU of the outer transport interfaces to
168 : * at least 1550 bytes. The following is disabled by default.
169 : */
170 : ifp->if_mtu = ETHERMTU - sizeof(struct ether_header);
171 : ifp->if_mtu -= sizeof(struct vxlanudphdr) + sizeof(struct ipovly);
172 : #endif
173 :
174 0 : LIST_INSERT_HEAD(&vxlan_tagh[VXLAN_TAGHASH(0)], sc, sc_entry);
175 0 : vxlan_enable++;
176 :
177 0 : return (0);
178 : }
179 :
180 : int
181 0 : vxlan_clone_destroy(struct ifnet *ifp)
182 : {
183 0 : struct vxlan_softc *sc = ifp->if_softc;
184 :
185 0 : NET_LOCK();
186 0 : vxlan_multicast_cleanup(ifp);
187 0 : NET_UNLOCK();
188 :
189 0 : vxlan_enable--;
190 0 : LIST_REMOVE(sc, sc_entry);
191 :
192 0 : ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
193 0 : ether_ifdetach(ifp);
194 0 : if_detach(ifp);
195 :
196 0 : if (!task_del(net_tq(ifp->if_index), &sc->sc_sendtask))
197 0 : taskq_barrier(net_tq(ifp->if_index));
198 :
199 0 : free(sc->sc_imo.imo_membership, M_IPMOPTS, 0);
200 0 : free(sc, M_DEVBUF, sizeof(*sc));
201 :
202 0 : return (0);
203 : }
204 :
205 : void
206 0 : vxlan_multicast_cleanup(struct ifnet *ifp)
207 : {
208 0 : struct vxlan_softc *sc = (struct vxlan_softc *)ifp->if_softc;
209 0 : struct ip_moptions *imo = &sc->sc_imo;
210 : struct ifnet *mifp;
211 :
212 0 : mifp = if_get(imo->imo_ifidx);
213 0 : if (mifp != NULL) {
214 0 : if (sc->sc_ahcookie != NULL) {
215 0 : hook_disestablish(mifp->if_addrhooks, sc->sc_ahcookie);
216 0 : sc->sc_ahcookie = NULL;
217 0 : }
218 0 : if (sc->sc_lhcookie != NULL) {
219 0 : hook_disestablish(mifp->if_linkstatehooks,
220 : sc->sc_lhcookie);
221 0 : sc->sc_lhcookie = NULL;
222 0 : }
223 0 : if (sc->sc_dhcookie != NULL) {
224 0 : hook_disestablish(mifp->if_detachhooks,
225 : sc->sc_dhcookie);
226 0 : sc->sc_dhcookie = NULL;
227 0 : }
228 :
229 0 : if_put(mifp);
230 0 : }
231 :
232 0 : if (imo->imo_num_memberships > 0) {
233 0 : in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
234 0 : imo->imo_ifidx = 0;
235 0 : }
236 0 : }
237 :
238 : int
239 0 : vxlan_multicast_join(struct ifnet *ifp, struct sockaddr *src,
240 : struct sockaddr *dst)
241 : {
242 0 : struct vxlan_softc *sc = ifp->if_softc;
243 0 : struct ip_moptions *imo = &sc->sc_imo;
244 : struct sockaddr_in *src4, *dst4;
245 : #ifdef INET6
246 : struct sockaddr_in6 *dst6;
247 : #endif /* INET6 */
248 : struct ifaddr *ifa;
249 : struct ifnet *mifp;
250 :
251 0 : switch (dst->sa_family) {
252 : case AF_INET:
253 0 : dst4 = satosin(dst);
254 0 : if (!IN_MULTICAST(dst4->sin_addr.s_addr))
255 0 : return (0);
256 : break;
257 : #ifdef INET6
258 : case AF_INET6:
259 0 : dst6 = satosin6(dst);
260 0 : if (!IN6_IS_ADDR_MULTICAST(&dst6->sin6_addr))
261 0 : return (0);
262 :
263 : /* Multicast mode is currently not supported for IPv6 */
264 0 : return (EAFNOSUPPORT);
265 : #endif /* INET6 */
266 : default:
267 0 : return (EAFNOSUPPORT);
268 : }
269 :
270 0 : src4 = satosin(src);
271 0 : dst4 = satosin(dst);
272 :
273 0 : if (src4->sin_addr.s_addr == INADDR_ANY ||
274 0 : IN_MULTICAST(src4->sin_addr.s_addr))
275 0 : return (EINVAL);
276 0 : if ((ifa = ifa_ifwithaddr(src, sc->sc_rdomain)) == NULL ||
277 0 : (mifp = ifa->ifa_ifp) == NULL ||
278 0 : (mifp->if_flags & IFF_MULTICAST) == 0)
279 0 : return (EADDRNOTAVAIL);
280 :
281 0 : if ((imo->imo_membership[0] =
282 0 : in_addmulti(&dst4->sin_addr, mifp)) == NULL)
283 0 : return (ENOBUFS);
284 :
285 0 : imo->imo_num_memberships++;
286 0 : imo->imo_ifidx = mifp->if_index;
287 0 : if (sc->sc_ttl > 0)
288 0 : imo->imo_ttl = sc->sc_ttl;
289 : else
290 0 : imo->imo_ttl = IP_DEFAULT_MULTICAST_TTL;
291 0 : imo->imo_loop = 0;
292 :
293 : /*
294 : * Use interface hooks to track any changes on the interface
295 : * that is used to send out the tunnel traffic as multicast.
296 : */
297 0 : if ((sc->sc_ahcookie = hook_establish(mifp->if_addrhooks,
298 0 : 0, vxlan_addr_change, sc)) == NULL ||
299 0 : (sc->sc_lhcookie = hook_establish(mifp->if_linkstatehooks,
300 0 : 0, vxlan_link_change, sc)) == NULL ||
301 0 : (sc->sc_dhcookie = hook_establish(mifp->if_detachhooks,
302 0 : 0, vxlan_if_change, sc)) == NULL)
303 0 : panic("%s: cannot allocate interface hook",
304 0 : mifp->if_xname);
305 :
306 0 : return (0);
307 0 : }
308 :
309 : void
310 0 : vxlanstart(struct ifnet *ifp)
311 : {
312 0 : struct vxlan_softc *sc = (struct vxlan_softc *)ifp->if_softc;
313 :
314 0 : task_add(net_tq(ifp->if_index), &sc->sc_sendtask);
315 0 : }
316 :
317 : void
318 0 : vxlan_send_dispatch(void *xsc)
319 : {
320 0 : struct vxlan_softc *sc = xsc;
321 0 : struct ifnet *ifp = &sc->sc_ac.ac_if;
322 : struct mbuf *m;
323 0 : struct mbuf_list ml;
324 :
325 0 : ml_init(&ml);
326 0 : for (;;) {
327 0 : IFQ_DEQUEUE(&ifp->if_snd, m);
328 0 : if (m == NULL)
329 : break;
330 :
331 : #if NBPFILTER > 0
332 0 : if (ifp->if_bpf)
333 0 : bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
334 : #endif
335 :
336 0 : ml_enqueue(&ml, m);
337 : }
338 :
339 0 : if (ml_empty(&ml))
340 0 : return;
341 :
342 0 : NET_RLOCK();
343 0 : while ((m = ml_dequeue(&ml)) != NULL) {
344 0 : vxlan_output(ifp, m);
345 : }
346 0 : NET_RUNLOCK();
347 0 : }
348 :
349 :
350 : int
351 0 : vxlan_config(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
352 : {
353 0 : struct vxlan_softc *sc = (struct vxlan_softc *)ifp->if_softc;
354 : int reset = 0, error, af;
355 : socklen_t slen;
356 : in_port_t port;
357 : struct vxlan_taghash *tagh;
358 :
359 0 : if (src != NULL && dst != NULL) {
360 0 : if ((af = src->sa_family) != dst->sa_family)
361 0 : return (EAFNOSUPPORT);
362 : } else {
363 : /* Reset current configuration */
364 0 : af = sc->sc_src.ss_family;
365 0 : src = sstosa(&sc->sc_src);
366 0 : dst = sstosa(&sc->sc_dst);
367 : reset = 1;
368 : }
369 :
370 0 : switch (af) {
371 : case AF_INET:
372 : slen = sizeof(struct sockaddr_in);
373 0 : break;
374 : #ifdef INET6
375 : case AF_INET6:
376 : slen = sizeof(struct sockaddr_in6);
377 0 : break;
378 : #endif /* INET6 */
379 : default:
380 0 : return (EAFNOSUPPORT);
381 : }
382 :
383 0 : if (src->sa_len != slen || dst->sa_len != slen)
384 0 : return (EINVAL);
385 :
386 0 : vxlan_multicast_cleanup(ifp);
387 :
388 : /* returns without error if multicast is not configured */
389 0 : if ((error = vxlan_multicast_join(ifp, src, dst)) != 0)
390 0 : return (error);
391 :
392 0 : if ((port = vxlan_sockaddr_port(dst)) != 0)
393 0 : sc->sc_dstport = port;
394 :
395 0 : if (!reset) {
396 0 : bzero(&sc->sc_src, sizeof(sc->sc_src));
397 0 : bzero(&sc->sc_dst, sizeof(sc->sc_dst));
398 0 : memcpy(&sc->sc_src, src, src->sa_len);
399 0 : memcpy(&sc->sc_dst, dst, dst->sa_len);
400 0 : }
401 :
402 0 : if (sc->sc_vnetid == VXLAN_VNI_ANY) {
403 : /*
404 : * If the interface accepts any VNI, put it into a separate
405 : * list that is not part of the main hash.
406 : */
407 : tagh = &vxlan_any;
408 0 : } else
409 0 : tagh = &vxlan_tagh[VXLAN_TAGHASH(sc->sc_vnetid)];
410 :
411 0 : LIST_REMOVE(sc, sc_entry);
412 0 : LIST_INSERT_HEAD(tagh, sc, sc_entry);
413 :
414 0 : return (0);
415 0 : }
416 :
417 : int
418 0 : vxlanioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
419 : {
420 0 : struct vxlan_softc *sc = (struct vxlan_softc *)ifp->if_softc;
421 0 : struct ifreq *ifr = (struct ifreq *)data;
422 0 : struct if_laddrreq *lifr = (struct if_laddrreq *)data;
423 : int error = 0;
424 :
425 0 : switch (cmd) {
426 : case SIOCSIFADDR:
427 0 : ifp->if_flags |= IFF_UP;
428 : /* FALLTHROUGH */
429 :
430 : case SIOCSIFFLAGS:
431 0 : if (ifp->if_flags & IFF_UP) {
432 0 : ifp->if_flags |= IFF_RUNNING;
433 0 : } else {
434 0 : ifp->if_flags &= ~IFF_RUNNING;
435 : }
436 : break;
437 :
438 : case SIOCADDMULTI:
439 : case SIOCDELMULTI:
440 : break;
441 :
442 : case SIOCGIFMEDIA:
443 : case SIOCSIFMEDIA:
444 0 : error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
445 0 : break;
446 :
447 : case SIOCSLIFPHYADDR:
448 0 : error = vxlan_config(ifp,
449 0 : sstosa(&lifr->addr),
450 0 : sstosa(&lifr->dstaddr));
451 0 : break;
452 :
453 : case SIOCDIFPHYADDR:
454 0 : vxlan_multicast_cleanup(ifp);
455 0 : bzero(&sc->sc_src, sizeof(sc->sc_src));
456 0 : bzero(&sc->sc_dst, sizeof(sc->sc_dst));
457 0 : sc->sc_dstport = htons(VXLAN_PORT);
458 0 : break;
459 :
460 : case SIOCGLIFPHYADDR:
461 0 : if (sc->sc_dst.ss_family == AF_UNSPEC) {
462 : error = EADDRNOTAVAIL;
463 0 : break;
464 : }
465 0 : bzero(&lifr->addr, sizeof(lifr->addr));
466 0 : bzero(&lifr->dstaddr, sizeof(lifr->dstaddr));
467 0 : memcpy(&lifr->addr, &sc->sc_src, sc->sc_src.ss_len);
468 0 : memcpy(&lifr->dstaddr, &sc->sc_dst, sc->sc_dst.ss_len);
469 0 : break;
470 :
471 : case SIOCSLIFPHYRTABLE:
472 0 : if (ifr->ifr_rdomainid < 0 ||
473 0 : ifr->ifr_rdomainid > RT_TABLEID_MAX ||
474 0 : !rtable_exists(ifr->ifr_rdomainid)) {
475 : error = EINVAL;
476 0 : break;
477 : }
478 0 : sc->sc_rdomain = ifr->ifr_rdomainid;
479 0 : (void)vxlan_config(ifp, NULL, NULL);
480 0 : break;
481 :
482 : case SIOCGLIFPHYRTABLE:
483 0 : ifr->ifr_rdomainid = sc->sc_rdomain;
484 0 : break;
485 :
486 : case SIOCSLIFPHYTTL:
487 0 : if (ifr->ifr_ttl < 0 || ifr->ifr_ttl > 0xff) {
488 : error = EINVAL;
489 0 : break;
490 : }
491 0 : if (sc->sc_ttl == (u_int8_t)ifr->ifr_ttl)
492 : break;
493 0 : sc->sc_ttl = (u_int8_t)(ifr->ifr_ttl);
494 0 : (void)vxlan_config(ifp, NULL, NULL);
495 0 : break;
496 :
497 : case SIOCGLIFPHYTTL:
498 0 : ifr->ifr_ttl = (int)sc->sc_ttl;
499 0 : break;
500 :
501 : case SIOCSLIFPHYDF:
502 : /* commit */
503 0 : sc->sc_df = ifr->ifr_df ? htons(IP_DF) : htons(0);
504 0 : break;
505 : case SIOCGLIFPHYDF:
506 0 : ifr->ifr_df = sc->sc_df ? 1 : 0;
507 0 : break;
508 :
509 : case SIOCSVNETID:
510 0 : if (sc->sc_vnetid == ifr->ifr_vnetid)
511 : break;
512 :
513 0 : if ((ifr->ifr_vnetid != VXLAN_VNI_ANY) &&
514 0 : (ifr->ifr_vnetid > VXLAN_VNI_MAX ||
515 0 : ifr->ifr_vnetid < VXLAN_VNI_MIN)) {
516 : error = EINVAL;
517 0 : break;
518 : }
519 :
520 0 : sc->sc_vnetid = (int)ifr->ifr_vnetid;
521 0 : (void)vxlan_config(ifp, NULL, NULL);
522 0 : break;
523 :
524 : case SIOCGVNETID:
525 0 : if ((sc->sc_vnetid != VXLAN_VNI_ANY) &&
526 0 : (sc->sc_vnetid > VXLAN_VNI_MAX ||
527 0 : sc->sc_vnetid < VXLAN_VNI_MIN)) {
528 : error = EADDRNOTAVAIL;
529 0 : break;
530 : }
531 :
532 0 : ifr->ifr_vnetid = sc->sc_vnetid;
533 0 : break;
534 :
535 : case SIOCDVNETID:
536 0 : sc->sc_vnetid = VXLAN_VNI_UNSET;
537 0 : (void)vxlan_config(ifp, NULL, NULL);
538 0 : break;
539 :
540 : default:
541 0 : error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
542 0 : break;
543 : }
544 :
545 0 : return (error);
546 : }
547 :
548 : int
549 0 : vxlan_media_change(struct ifnet *ifp)
550 : {
551 0 : return (0);
552 : }
553 :
554 : void
555 0 : vxlan_media_status(struct ifnet *ifp, struct ifmediareq *imr)
556 : {
557 0 : imr->ifm_status = IFM_AVALID | IFM_ACTIVE;
558 0 : }
559 :
560 : int
561 0 : vxlan_sockaddr_cmp(struct sockaddr *srcsa, struct sockaddr *dstsa)
562 : {
563 : struct sockaddr_in *src4, *dst4;
564 : #ifdef INET6
565 : struct sockaddr_in6 *src6, *dst6;
566 : #endif /* INET6 */
567 :
568 0 : if (srcsa->sa_family != dstsa->sa_family)
569 0 : return (1);
570 :
571 0 : switch (dstsa->sa_family) {
572 : case AF_INET:
573 0 : src4 = satosin(srcsa);
574 0 : dst4 = satosin(dstsa);
575 0 : if (src4->sin_addr.s_addr == dst4->sin_addr.s_addr)
576 0 : return (0);
577 : break;
578 : #ifdef INET6
579 : case AF_INET6:
580 0 : src6 = satosin6(srcsa);
581 0 : dst6 = satosin6(dstsa);
582 0 : if (IN6_ARE_ADDR_EQUAL(&src6->sin6_addr, &dst6->sin6_addr) &&
583 0 : src6->sin6_scope_id == dst6->sin6_scope_id)
584 0 : return (0);
585 : break;
586 : #endif /* INET6 */
587 : }
588 :
589 0 : return (1);
590 0 : }
591 :
592 : uint16_t
593 0 : vxlan_sockaddr_port(struct sockaddr *sa)
594 : {
595 : struct sockaddr_in *sin4;
596 : #ifdef INET6
597 : struct sockaddr_in6 *sin6;
598 : #endif /* INET6 */
599 :
600 0 : switch (sa->sa_family) {
601 : case AF_INET:
602 0 : sin4 = satosin(sa);
603 0 : return (sin4->sin_port);
604 : #ifdef INET6
605 : case AF_INET6:
606 0 : sin6 = satosin6(sa);
607 0 : return (sin6->sin6_port);
608 : #endif /* INET6 */
609 : default:
610 : break;
611 : }
612 :
613 0 : return (0);
614 0 : }
615 :
616 : int
617 0 : vxlan_lookup(struct mbuf *m, struct udphdr *uh, int iphlen,
618 : struct sockaddr *srcsa, struct sockaddr *dstsa)
619 : {
620 0 : struct mbuf_list ml = MBUF_LIST_INITIALIZER();
621 : struct vxlan_softc *sc = NULL, *sc_cand = NULL;
622 0 : struct vxlan_header v;
623 : int vni;
624 : struct ifnet *ifp;
625 : int skip;
626 : #if NBRIDGE > 0
627 : struct bridge_tunneltag *brtag;
628 : #endif
629 : struct mbuf *n;
630 0 : int off;
631 :
632 : /* XXX Should verify the UDP port first before copying the packet */
633 0 : skip = iphlen + sizeof(*uh);
634 0 : if (m->m_pkthdr.len - skip < sizeof(v))
635 0 : return (0);
636 0 : m_copydata(m, skip, sizeof(v), (caddr_t)&v);
637 0 : skip += sizeof(v);
638 :
639 0 : if (v.vxlan_flags & htonl(VXLAN_RESERVED1) ||
640 0 : v.vxlan_id & htonl(VXLAN_RESERVED2))
641 0 : return (0);
642 :
643 0 : vni = ntohl(v.vxlan_id) >> VXLAN_VNI_S;
644 0 : if ((v.vxlan_flags & htonl(VXLAN_FLAGS_VNI)) == 0) {
645 0 : if (vni != 0)
646 0 : return (0);
647 :
648 : vni = VXLAN_VNI_UNSET;
649 0 : }
650 :
651 0 : NET_ASSERT_LOCKED();
652 : /* First search for a vxlan(4) interface with the packet's VNI */
653 0 : LIST_FOREACH(sc, &vxlan_tagh[VXLAN_TAGHASH(vni)], sc_entry) {
654 0 : if ((uh->uh_dport == sc->sc_dstport) &&
655 0 : vni == sc->sc_vnetid &&
656 0 : sc->sc_rdomain == rtable_l2(m->m_pkthdr.ph_rtableid)) {
657 : sc_cand = sc;
658 0 : if (vxlan_sockaddr_cmp(srcsa, sstosa(&sc->sc_dst)) == 0)
659 : goto found;
660 : }
661 : }
662 :
663 : /*
664 : * Now loop through all the vxlan(4) interfaces that are configured
665 : * to accept any VNI and operating in multipoint-to-multipoint mode
666 : * that is used in combination with bridge(4) or switch(4).
667 : * If a vxlan(4) interface has been found for the packet's VNI, this
668 : * code is not reached as the other interface is more specific.
669 : */
670 0 : LIST_FOREACH(sc, &vxlan_any, sc_entry) {
671 0 : if ((uh->uh_dport == sc->sc_dstport) &&
672 0 : (sc->sc_rdomain == rtable_l2(m->m_pkthdr.ph_rtableid))) {
673 : sc_cand = sc;
674 0 : goto found;
675 : }
676 : }
677 :
678 0 : if (sc_cand) {
679 : sc = sc_cand;
680 0 : goto found;
681 : }
682 :
683 : /* not found */
684 0 : return (0);
685 :
686 : found:
687 0 : if (m->m_pkthdr.len < skip + sizeof(struct ether_header)) {
688 0 : m_freem(m);
689 0 : return (EINVAL);
690 : }
691 :
692 0 : m_adj(m, skip);
693 0 : ifp = &sc->sc_ac.ac_if;
694 :
695 : #if NBRIDGE > 0
696 : /* Store the tunnel src/dst IP and vni for the bridge or switch */
697 0 : if ((ifp->if_bridgeport != NULL || ifp->if_switchport != NULL) &&
698 0 : srcsa->sa_family != AF_UNSPEC &&
699 0 : ((brtag = bridge_tunneltag(m)) != NULL)) {
700 0 : memcpy(&brtag->brtag_peer.sa, srcsa, srcsa->sa_len);
701 0 : memcpy(&brtag->brtag_local.sa, dstsa, dstsa->sa_len);
702 0 : brtag->brtag_id = vni;
703 0 : }
704 : #endif
705 :
706 0 : m->m_flags &= ~(M_BCAST|M_MCAST);
707 :
708 : #if NPF > 0
709 0 : pf_pkt_addr_changed(m);
710 : #endif
711 0 : if ((m->m_len < sizeof(struct ether_header)) &&
712 0 : (m = m_pullup(m, sizeof(struct ether_header))) == NULL)
713 0 : return (ENOBUFS);
714 :
715 0 : n = m_getptr(m, sizeof(struct ether_header), &off);
716 0 : if (n == NULL) {
717 0 : m_freem(m);
718 0 : return (EINVAL);
719 : }
720 : if (!ALIGNED_POINTER(mtod(n, caddr_t) + off, uint32_t)) {
721 : n = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT);
722 : /* Dispose of the original mbuf chain */
723 : m_freem(m);
724 : if (n == NULL)
725 : return (ENOBUFS);
726 : m = n;
727 : }
728 :
729 0 : ml_enqueue(&ml, m);
730 0 : if_input(ifp, &ml);
731 :
732 : /* success */
733 0 : return (1);
734 0 : }
735 :
736 : struct mbuf *
737 0 : vxlan_encap4(struct ifnet *ifp, struct mbuf *m,
738 : struct sockaddr *src, struct sockaddr *dst)
739 : {
740 0 : struct vxlan_softc *sc = (struct vxlan_softc *)ifp->if_softc;
741 : struct ip *ip;
742 :
743 : /*
744 : * Remove multicast and broadcast flags or encapsulated packet
745 : * ends up as multicast or broadcast packet.
746 : */
747 0 : m->m_flags &= ~(M_BCAST|M_MCAST);
748 :
749 0 : M_PREPEND(m, sizeof(*ip), M_DONTWAIT);
750 0 : if (m == NULL)
751 0 : return (NULL);
752 :
753 0 : ip = mtod(m, struct ip *);
754 0 : ip->ip_v = IPVERSION;
755 0 : ip->ip_hl = sizeof(struct ip) >> 2;
756 0 : ip->ip_id = htons(ip_randomid());
757 0 : ip->ip_off = sc->sc_df;
758 0 : ip->ip_p = IPPROTO_UDP;
759 0 : ip->ip_tos = IPTOS_LOWDELAY;
760 0 : ip->ip_len = htons(m->m_pkthdr.len);
761 :
762 0 : ip->ip_src = satosin(src)->sin_addr;
763 0 : ip->ip_dst = satosin(dst)->sin_addr;
764 :
765 0 : if (sc->sc_ttl > 0)
766 0 : ip->ip_ttl = sc->sc_ttl;
767 : else
768 0 : ip->ip_ttl = IPDEFTTL;
769 :
770 0 : return (m);
771 0 : }
772 :
773 : #ifdef INET6
774 : struct mbuf *
775 0 : vxlan_encap6(struct ifnet *ifp, struct mbuf *m,
776 : struct sockaddr *src, struct sockaddr *dst)
777 : {
778 0 : struct vxlan_softc *sc = (struct vxlan_softc *)ifp->if_softc;
779 : struct ip6_hdr *ip6;
780 0 : struct in6_addr *in6a;
781 :
782 : /*
783 : * Remove multicast and broadcast flags or encapsulated packet
784 : * ends up as multicast or broadcast packet.
785 : */
786 0 : m->m_flags &= ~(M_BCAST|M_MCAST);
787 :
788 0 : M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
789 0 : if (m == NULL)
790 0 : return (NULL);
791 :
792 0 : ip6 = mtod(m, struct ip6_hdr *);
793 0 : ip6->ip6_flow = 0;
794 0 : ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
795 0 : ip6->ip6_vfc |= IPV6_VERSION;
796 0 : ip6->ip6_nxt = IPPROTO_UDP;
797 0 : ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
798 0 : if (in6_embedscope(&ip6->ip6_src, satosin6(src), NULL) != 0)
799 : goto drop;
800 0 : if (in6_embedscope(&ip6->ip6_dst, satosin6(dst), NULL) != 0)
801 : goto drop;
802 :
803 0 : if (sc->sc_ttl > 0)
804 0 : ip6->ip6_hlim = sc->sc_ttl;
805 : else
806 0 : ip6->ip6_hlim = ip6_defhlim;
807 :
808 0 : if (IN6_IS_ADDR_UNSPECIFIED(&satosin6(src)->sin6_addr)) {
809 0 : if (in6_selectsrc(&in6a, satosin6(dst), NULL,
810 0 : sc->sc_rdomain) != 0)
811 : goto drop;
812 :
813 0 : ip6->ip6_src = *in6a;
814 0 : }
815 :
816 0 : if (sc->sc_df)
817 0 : SET(m->m_pkthdr.csum_flags, M_IPV6_DF_OUT);
818 :
819 : /*
820 : * The UDP checksum of VXLAN packets should be set to zero,
821 : * but the IPv6 UDP checksum is not optional. There is an RFC 6539
822 : * to relax the IPv6 UDP checksum requirement for tunnels, but it
823 : * is currently not supported by most implementations.
824 : */
825 0 : m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT;
826 :
827 0 : return (m);
828 :
829 : drop:
830 0 : m_freem(m);
831 0 : return (NULL);
832 0 : }
833 : #endif /* INET6 */
834 :
835 : int
836 0 : vxlan_output(struct ifnet *ifp, struct mbuf *m)
837 : {
838 0 : struct vxlan_softc *sc = (struct vxlan_softc *)ifp->if_softc;
839 : struct vxlanudphdr *vu;
840 : struct sockaddr *src, *dst;
841 : #if NBRIDGE > 0
842 : struct bridge_tunneltag *brtag;
843 : #endif
844 : int error, af;
845 : uint32_t tag;
846 : struct mbuf *m0;
847 :
848 : /* VXLAN header */
849 0 : MGETHDR(m0, M_DONTWAIT, m->m_type);
850 0 : if (m0 == NULL) {
851 0 : ifp->if_oerrors++;
852 0 : return (ENOBUFS);
853 : }
854 0 : M_MOVE_PKTHDR(m0, m);
855 0 : m0->m_next = m;
856 : m = m0;
857 0 : MH_ALIGN(m, sizeof(*vu));
858 0 : m->m_len = sizeof(*vu);
859 0 : m->m_pkthdr.len += sizeof(*vu);
860 :
861 0 : src = sstosa(&sc->sc_src);
862 0 : dst = sstosa(&sc->sc_dst);
863 0 : af = src->sa_family;
864 :
865 0 : vu = mtod(m, struct vxlanudphdr *);
866 0 : vu->vu_u.uh_sport = sc->sc_dstport;
867 0 : vu->vu_u.uh_dport = sc->sc_dstport;
868 0 : vu->vu_u.uh_ulen = htons(m->m_pkthdr.len);
869 0 : vu->vu_u.uh_sum = 0;
870 0 : tag = sc->sc_vnetid;
871 :
872 : #if NBRIDGE > 0
873 0 : if ((brtag = bridge_tunnel(m)) != NULL) {
874 0 : dst = &brtag->brtag_peer.sa;
875 :
876 : /* If accepting any VNI, source ip address is from brtag */
877 0 : if (sc->sc_vnetid == VXLAN_VNI_ANY) {
878 0 : src = &brtag->brtag_local.sa;
879 0 : tag = (uint32_t)brtag->brtag_id;
880 0 : af = src->sa_family;
881 0 : }
882 :
883 0 : if (dst->sa_family != af) {
884 0 : ifp->if_oerrors++;
885 0 : m_freem(m);
886 0 : return (EINVAL);
887 : }
888 : } else
889 : #endif
890 0 : if (sc->sc_vnetid == VXLAN_VNI_ANY) {
891 : /*
892 : * If accepting any VNI, build the vxlan header only by
893 : * bridge_tunneltag or drop packet if the tag does not exist.
894 : */
895 0 : ifp->if_oerrors++;
896 0 : m_freem(m);
897 0 : return (ENETUNREACH);
898 : }
899 :
900 0 : if (sc->sc_vnetid != VXLAN_VNI_UNSET) {
901 0 : vu->vu_v.vxlan_flags = htonl(VXLAN_FLAGS_VNI);
902 0 : vu->vu_v.vxlan_id = htonl(tag << VXLAN_VNI_S);
903 0 : } else {
904 0 : vu->vu_v.vxlan_flags = htonl(0);
905 0 : vu->vu_v.vxlan_id = htonl(0);
906 : }
907 :
908 0 : switch (af) {
909 : case AF_INET:
910 0 : m = vxlan_encap4(ifp, m, src, dst);
911 0 : break;
912 : #ifdef INET6
913 : case AF_INET6:
914 0 : m = vxlan_encap6(ifp, m, src, dst);
915 0 : break;
916 : #endif /* INET6 */
917 : default:
918 0 : m_freem(m);
919 : m = NULL;
920 0 : }
921 :
922 0 : if (m == NULL) {
923 0 : ifp->if_oerrors++;
924 0 : return (ENOBUFS);
925 : }
926 :
927 : #if NBRIDGE > 0
928 0 : if (brtag != NULL)
929 0 : bridge_tunneluntag(m);
930 : #endif
931 :
932 0 : m->m_pkthdr.ph_rtableid = sc->sc_rdomain;
933 :
934 : #if NPF > 0
935 0 : pf_pkt_addr_changed(m);
936 : #endif
937 :
938 0 : switch (af) {
939 : case AF_INET:
940 0 : error = ip_output(m, NULL, NULL, IP_RAWOUTPUT,
941 0 : &sc->sc_imo, NULL, 0);
942 0 : break;
943 : #ifdef INET6
944 : case AF_INET6:
945 0 : error = ip6_output(m, 0, NULL, IPV6_MINMTU, 0, NULL);
946 0 : break;
947 : #endif /* INET6 */
948 : default:
949 0 : m_freem(m);
950 : error = EAFNOSUPPORT;
951 0 : }
952 :
953 0 : if (error)
954 0 : ifp->if_oerrors++;
955 :
956 0 : return (error);
957 0 : }
958 :
959 : void
960 0 : vxlan_addr_change(void *arg)
961 : {
962 0 : struct vxlan_softc *sc = arg;
963 0 : struct ifnet *ifp = &sc->sc_ac.ac_if;
964 : int error;
965 :
966 : /*
967 : * Reset the configuration after resume or any possible address
968 : * configuration changes.
969 : */
970 0 : if ((error = vxlan_config(ifp, NULL, NULL))) {
971 : /*
972 : * The source address of the tunnel can temporarily disappear,
973 : * after a link state change when running the DHCP client,
974 : * so keep it configured.
975 : */
976 : }
977 0 : }
978 :
979 : void
980 0 : vxlan_if_change(void *arg)
981 : {
982 0 : struct vxlan_softc *sc = arg;
983 0 : struct ifnet *ifp = &sc->sc_ac.ac_if;
984 :
985 : /*
986 : * Reset the configuration after the parent interface disappeared.
987 : */
988 0 : vxlan_multicast_cleanup(ifp);
989 0 : memset(&sc->sc_src, 0, sizeof(sc->sc_src));
990 0 : memset(&sc->sc_dst, 0, sizeof(sc->sc_dst));
991 0 : sc->sc_dstport = htons(VXLAN_PORT);
992 0 : }
993 :
994 : void
995 0 : vxlan_link_change(void *arg)
996 : {
997 0 : struct vxlan_softc *sc = arg;
998 0 : struct ifnet *ifp = &sc->sc_ac.ac_if;
999 :
1000 : /*
1001 : * The machine might have lost its multicast associations after
1002 : * link state changes. This fixes a problem with VMware after
1003 : * suspend/resume of the host or guest.
1004 : */
1005 0 : (void)vxlan_config(ifp, NULL, NULL);
1006 0 : }
|