xref: /openbsd-src/sys/net/if_vxlan.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: if_vxlan.c,v 1.14 2014/07/12 18:44:22 tedu 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_dl.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 #if NPF > 0
42 #include <net/pfvar.h>
43 #endif
44 
45 #include <netinet/in.h>
46 #include <netinet/in_var.h>
47 #include <netinet/in_systm.h>
48 #include <netinet/if_ether.h>
49 #include <netinet/ip.h>
50 #include <netinet/ip_var.h>
51 #include <netinet/udp.h>
52 #include <netinet/udp_var.h>
53 #include <netinet/in_pcb.h>
54 
55 #if NBRIDGE > 0
56 #include <net/if_bridge.h>
57 #endif
58 
59 #include <net/if_vxlan.h>
60 
61 void	 vxlanattach(int);
62 int	 vxlanioctl(struct ifnet *, u_long, caddr_t);
63 void	 vxlanstart(struct ifnet *);
64 int	 vxlan_clone_create(struct if_clone *, int);
65 int	 vxlan_clone_destroy(struct ifnet *);
66 void	 vxlan_multicast_cleanup(struct ifnet *);
67 int	 vxlan_multicast_join(struct ifnet *, struct sockaddr_in *,
68 	    struct sockaddr_in *);
69 int	 vxlan_media_change(struct ifnet *);
70 void	 vxlan_media_status(struct ifnet *, struct ifmediareq *);
71 int	 vxlan_config(struct ifnet *, struct sockaddr *, struct sockaddr *);
72 int	 vxlan_output(struct ifnet *, struct mbuf *);
73 void	 vxlan_addr_change(void *);
74 void	 vxlan_if_change(void *);
75 void	 vxlan_link_change(void *);
76 
77 struct if_clone	vxlan_cloner =
78     IF_CLONE_INITIALIZER("vxlan", vxlan_clone_create, vxlan_clone_destroy);
79 
80 int	 vxlan_enable = 0;
81 u_long	 vxlan_tagmask;
82 
83 #define VXLAN_TAGHASHSIZE		 32
84 #define VXLAN_TAGHASH(tag)		 (tag & vxlan_tagmask)
85 LIST_HEAD(vxlan_taghash, vxlan_softc)	*vxlan_tagh;
86 
87 void
88 vxlanattach(int count)
89 {
90 	if ((vxlan_tagh = hashinit(VXLAN_TAGHASHSIZE, M_DEVBUF, M_NOWAIT,
91 	    &vxlan_tagmask)) == NULL)
92 		panic("vxlanattach: hashinit");
93 
94 	if_clone_attach(&vxlan_cloner);
95 }
96 
97 int
98 vxlan_clone_create(struct if_clone *ifc, int unit)
99 {
100 	struct ifnet		*ifp;
101 	struct vxlan_softc	*sc;
102 
103 	if ((sc = malloc(sizeof(*sc),
104 	    M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
105 		return (ENOMEM);
106 
107 	sc->sc_imo.imo_membership = malloc(
108 	    (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_IPMOPTS,
109 	    M_WAITOK|M_ZERO);
110 	sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS;
111 	sc->sc_dstport = htons(VXLAN_PORT);
112 	sc->sc_vnetid = 0;
113 
114 	ifp = &sc->sc_ac.ac_if;
115 	snprintf(ifp->if_xname, sizeof ifp->if_xname, "vxlan%d", unit);
116 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
117 	ether_fakeaddr(ifp);
118 
119 	ifp->if_softc = sc;
120 	ifp->if_ioctl = vxlanioctl;
121 	ifp->if_start = vxlanstart;
122 	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
123 	IFQ_SET_READY(&ifp->if_snd);
124 
125 	ifp->if_hardmtu = 0xffff;
126 	ifp->if_capabilities = IFCAP_VLAN_MTU;
127 
128 	ifmedia_init(&sc->sc_media, 0, vxlan_media_change,
129 	    vxlan_media_status);
130 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
131 	ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
132 
133 	if_attach(ifp);
134 	ether_ifattach(ifp);
135 
136 #if 0
137 	/*
138 	 * Instead of using a decreased MTU of 1450 bytes, prefer
139 	 * to use the default Ethernet-size MTU of 1500 bytes and to
140 	 * increase the MTU of the outer transport interfaces to
141 	 * at least 1550 bytes. The following is disabled by default.
142 	 */
143 	ifp->if_mtu = ETHERMTU - sizeof(struct ether_header);
144 #ifdef INET
145 	ifp->if_mtu -= sizeof(struct vxlanudpiphdr);
146 #endif
147 #endif
148 
149 	LIST_INSERT_HEAD(&vxlan_tagh[VXLAN_TAGHASH(0)], sc, sc_entry);
150 	vxlan_enable++;
151 
152 	return (0);
153 }
154 
155 int
156 vxlan_clone_destroy(struct ifnet *ifp)
157 {
158 	struct vxlan_softc	*sc = ifp->if_softc;
159 	int			 s;
160 
161 	s = splnet();
162 	vxlan_multicast_cleanup(ifp);
163 	splx(s);
164 
165 	vxlan_enable--;
166 	LIST_REMOVE(sc, sc_entry);
167 
168 	ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
169 	ether_ifdetach(ifp);
170 	if_detach(ifp);
171 	free(sc->sc_imo.imo_membership, M_IPMOPTS, 0);
172 	free(sc, M_DEVBUF, 0);
173 
174 	return (0);
175 }
176 
177 void
178 vxlan_multicast_cleanup(struct ifnet *ifp)
179 {
180 	struct vxlan_softc	*sc = (struct vxlan_softc *)ifp->if_softc;
181 	struct ip_moptions	*imo = &sc->sc_imo;
182 	struct ifnet		*mifp = imo->imo_multicast_ifp;
183 
184 	if (mifp != NULL) {
185 		if (sc->sc_ahcookie != NULL) {
186 			hook_disestablish(mifp->if_addrhooks, sc->sc_ahcookie);
187 			sc->sc_ahcookie = NULL;
188 		}
189 		if (sc->sc_lhcookie != NULL) {
190 			hook_disestablish(mifp->if_linkstatehooks,
191 			    sc->sc_lhcookie);
192 			sc->sc_lhcookie = NULL;
193 		}
194 		if (sc->sc_dhcookie != NULL) {
195 			hook_disestablish(mifp->if_detachhooks,
196 			    sc->sc_dhcookie);
197 			sc->sc_dhcookie = NULL;
198 		}
199 	}
200 
201 	if (imo->imo_num_memberships > 0) {
202 		in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
203 		imo->imo_multicast_ifp = NULL;
204 	}
205 }
206 
207 int
208 vxlan_multicast_join(struct ifnet *ifp, struct sockaddr_in *src,
209     struct sockaddr_in *dst)
210 {
211 	struct vxlan_softc	*sc = ifp->if_softc;
212 	struct ip_moptions	*imo = &sc->sc_imo;
213 	struct ifaddr		*ifa;
214 	struct ifnet		*mifp;
215 
216 	if (!IN_MULTICAST(dst->sin_addr.s_addr))
217 		return (0);
218 
219 	if (src->sin_addr.s_addr == INADDR_ANY ||
220 	    IN_MULTICAST(src->sin_addr.s_addr))
221 		return (EINVAL);
222 	if ((ifa = ifa_ifwithaddr(sintosa(src), sc->sc_rdomain)) == NULL ||
223 	    (mifp = ifa->ifa_ifp) == NULL ||
224 	    (mifp->if_flags & IFF_MULTICAST) == 0)
225 		return (EADDRNOTAVAIL);
226 
227 	if ((imo->imo_membership[0] =
228 	    in_addmulti(&dst->sin_addr, mifp)) == NULL)
229 		return (ENOBUFS);
230 
231 	imo->imo_num_memberships++;
232 	imo->imo_multicast_ifp = mifp;
233 	if (sc->sc_ttl > 0)
234 		imo->imo_multicast_ttl = sc->sc_ttl;
235 	else
236 		imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
237 	imo->imo_multicast_loop = 0;
238 
239 	/*
240 	 * Use interface hooks to track any changes on the interface
241 	 * that is used to send out the tunnel traffic as multicast.
242 	 */
243 	if ((sc->sc_ahcookie = hook_establish(mifp->if_addrhooks,
244 	    0, vxlan_addr_change, sc)) == NULL ||
245 	    (sc->sc_lhcookie = hook_establish(mifp->if_linkstatehooks,
246 	    0, vxlan_link_change, sc)) == NULL ||
247 	    (sc->sc_dhcookie = hook_establish(mifp->if_detachhooks,
248 	    0, vxlan_if_change, sc)) == NULL)
249 		panic("%s: cannot allocate interface hook",
250 		    mifp->if_xname);
251 
252 	return (0);
253 }
254 
255 void
256 vxlanstart(struct ifnet *ifp)
257 {
258 	struct mbuf		*m;
259 	int			 s;
260 
261 	for (;;) {
262 		s = splnet();
263 		IFQ_DEQUEUE(&ifp->if_snd, m);
264 		splx(s);
265 
266 		if (m == NULL)
267 			return;
268 		ifp->if_opackets++;
269 
270 #if NBPFILTER > 0
271 		if (ifp->if_bpf)
272 			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
273 #endif
274 
275 		vxlan_output(ifp, m);
276 	}
277 }
278 
279 int
280 vxlan_config(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
281 {
282 	struct vxlan_softc	*sc = (struct vxlan_softc *)ifp->if_softc;
283 #ifdef INET
284 	struct sockaddr_in	*src4, *dst4;
285 #endif
286 	int			 reset = 0, error;
287 
288 	if (src != NULL && dst != NULL) {
289 		/* XXX inet6 is not supported */
290 		if (src->sa_family != AF_INET || dst->sa_family != AF_INET)
291 			return (EAFNOSUPPORT);
292 	} else {
293 		/* Reset current configuration */
294 		src = (struct sockaddr *)&sc->sc_src;
295 		dst = (struct sockaddr *)&sc->sc_dst;
296 		reset = 1;
297 	}
298 
299 #ifdef INET
300 	src4 = satosin(src);
301 	dst4 = satosin(dst);
302 
303 	if (src4->sin_len != sizeof(*src4) || dst4->sin_len != sizeof(*dst4))
304 		return (EINVAL);
305 #endif
306 
307 	vxlan_multicast_cleanup(ifp);
308 
309 #ifdef INET
310 	if (IN_MULTICAST(dst4->sin_addr.s_addr)) {
311 		if ((error = vxlan_multicast_join(ifp, src4, dst4)) != 0)
312 			return (error);
313 	}
314 	if (dst4->sin_port)
315 		sc->sc_dstport = dst4->sin_port;
316 #endif
317 
318 	if (!reset) {
319 		bzero(&sc->sc_src, sizeof(sc->sc_src));
320 		bzero(&sc->sc_dst, sizeof(sc->sc_dst));
321 		memcpy(&sc->sc_src, src, src->sa_len);
322 		memcpy(&sc->sc_dst, dst, dst->sa_len);
323 	}
324 
325 	LIST_REMOVE(sc, sc_entry);
326 	LIST_INSERT_HEAD(&vxlan_tagh[VXLAN_TAGHASH(sc->sc_vnetid)],
327 	    sc, sc_entry);
328 
329 	return (0);
330 }
331 
332 /* ARGSUSED */
333 int
334 vxlanioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
335 {
336 	struct vxlan_softc	*sc = (struct vxlan_softc *)ifp->if_softc;
337 #ifdef INET
338 	struct ifaddr		*ifa = (struct ifaddr *)data;
339 #endif
340 	struct ifreq		*ifr = (struct ifreq *)data;
341 	struct if_laddrreq	*lifr = (struct if_laddrreq *)data;
342 	struct proc		*p = curproc;
343 	int			 error = 0, s;
344 
345 	switch (cmd) {
346 	case SIOCSIFADDR:
347 		ifp->if_flags |= IFF_UP;
348 #ifdef INET
349 		if (ifa->ifa_addr->sa_family == AF_INET)
350 			arp_ifinit(&sc->sc_ac, ifa);
351 #endif
352 		/* FALLTHROUGH */
353 
354 	case SIOCSIFFLAGS:
355 		if (ifp->if_flags & IFF_UP) {
356 			ifp->if_flags |= IFF_RUNNING;
357 		} else {
358 			ifp->if_flags &= ~IFF_RUNNING;
359 		}
360 		break;
361 
362 	case SIOCADDMULTI:
363 	case SIOCDELMULTI:
364 		break;
365 
366 	case SIOCGIFMEDIA:
367 	case SIOCSIFMEDIA:
368 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
369 		break;
370 
371 	case SIOCSLIFPHYADDR:
372 		if ((error = suser(p, 0)) != 0)
373 			break;
374 		s = splnet();
375 		error = vxlan_config(ifp,
376 		    (struct sockaddr *)&lifr->addr,
377 		    (struct sockaddr *)&lifr->dstaddr);
378 		splx(s);
379 		break;
380 
381 	case SIOCDIFPHYADDR:
382 		if ((error = suser(p, 0)) != 0)
383 			break;
384 		s = splnet();
385 		vxlan_multicast_cleanup(ifp);
386 		bzero(&sc->sc_src, sizeof(sc->sc_src));
387 		bzero(&sc->sc_dst, sizeof(sc->sc_dst));
388 		sc->sc_dstport = htons(VXLAN_PORT);
389 		splx(s);
390 		break;
391 
392 	case SIOCGLIFPHYADDR:
393 		if (sc->sc_dst.ss_family == AF_UNSPEC) {
394 			error = EADDRNOTAVAIL;
395 			break;
396 		}
397 		bzero(&lifr->addr, sizeof(lifr->addr));
398 		bzero(&lifr->dstaddr, sizeof(lifr->dstaddr));
399 		memcpy(&lifr->addr, &sc->sc_src, sc->sc_src.ss_len);
400 		memcpy(&lifr->dstaddr, &sc->sc_dst, sc->sc_dst.ss_len);
401 		break;
402 
403 	case SIOCSLIFPHYRTABLE:
404 		if ((error = suser(p, 0)) != 0)
405 			break;
406 		if (ifr->ifr_rdomainid < 0 ||
407 		    ifr->ifr_rdomainid > RT_TABLEID_MAX ||
408 		    !rtable_exists(ifr->ifr_rdomainid)) {
409 			error = EINVAL;
410 			break;
411 		}
412 		s = splnet();
413 		sc->sc_rdomain = ifr->ifr_rdomainid;
414 		(void)vxlan_config(ifp, NULL, NULL);
415 		splx(s);
416 		break;
417 
418 	case SIOCGLIFPHYRTABLE:
419 		ifr->ifr_rdomainid = sc->sc_rdomain;
420 		break;
421 
422 	case SIOCSLIFPHYTTL:
423 		if ((error = suser(p, 0)) != 0)
424 			break;
425 		if (ifr->ifr_ttl < 0 || ifr->ifr_ttl > 0xff) {
426 			error = EINVAL;
427 			break;
428 		}
429 		if (sc->sc_ttl == (u_int8_t)ifr->ifr_ttl)
430 			break;
431 		s = splnet();
432 		sc->sc_ttl = (u_int8_t)(ifr->ifr_ttl);
433 		(void)vxlan_config(ifp, NULL, NULL);
434 		splx(s);
435 		break;
436 
437 	case SIOCGLIFPHYTTL:
438 		ifr->ifr_ttl = (int)sc->sc_ttl;
439 		break;
440 
441 	case SIOCSVNETID:
442 		if ((error = suser(p, 0)) != 0)
443 			break;
444 		if (ifr->ifr_vnetid < 0 || ifr->ifr_vnetid > 0x00ffffff) {
445 			error = EINVAL;
446 			break;
447 		}
448 		s = splnet();
449 		sc->sc_vnetid = (u_int32_t)ifr->ifr_vnetid;
450 		(void)vxlan_config(ifp, NULL, NULL);
451 		splx(s);
452 		break;
453 
454 	case SIOCGVNETID:
455 		ifr->ifr_vnetid = (int)sc->sc_vnetid;
456 		break;
457 
458 	default:
459 		error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
460 		break;
461 	}
462 
463 	return (error);
464 }
465 
466 int
467 vxlan_media_change(struct ifnet *ifp)
468 {
469 	return (0);
470 }
471 
472 void
473 vxlan_media_status(struct ifnet *ifp, struct ifmediareq *imr)
474 {
475 	imr->ifm_active = IFM_ETHER | IFM_AUTO;
476 	imr->ifm_status = IFM_AVALID | IFM_ACTIVE;
477 }
478 
479 int
480 vxlan_lookup(struct mbuf *m, struct udphdr *uh, int iphlen,
481     struct sockaddr *srcsa)
482 {
483 	struct vxlan_softc	*sc = NULL;
484 	struct vxlan_header	 v;
485 	u_int32_t		 vni;
486 	struct ifnet		*ifp;
487 	int			 skip;
488 	struct ether_header	*eh;
489 #if NBRIDGE > 0
490 	struct sockaddr		*sa;
491 #endif
492 
493 	/* XXX Should verify the UDP port first before copying the packet */
494 	skip = iphlen + sizeof(*uh);
495 	if (m->m_pkthdr.len - skip < sizeof(v))
496 		return (0);
497 	m_copydata(m, skip, sizeof(v), (caddr_t)&v);
498 	skip += sizeof(v);
499 
500 	vni = ntohl(v.vxlan_id);
501 
502 	/* Validate header */
503 	if ((vni == 0) || (vni & VXLAN_RESERVED2) ||
504 	    (ntohl(v.vxlan_flags) != VXLAN_FLAGS_VNI))
505 		return (0);
506 
507 	vni >>= VXLAN_VNI_S;
508 	LIST_FOREACH(sc, &vxlan_tagh[VXLAN_TAGHASH(vni)], sc_entry) {
509 		if ((uh->uh_dport == sc->sc_dstport) &&
510 		    vni == sc->sc_vnetid &&
511 		    sc->sc_rdomain == rtable_l2(m->m_pkthdr.ph_rtableid))
512 			goto found;
513 	}
514 
515 	/* not found */
516 	return (0);
517 
518  found:
519 	m_adj(m, skip);
520 	ifp = &sc->sc_ac.ac_if;
521 	m->m_pkthdr.rcvif = ifp;
522 
523 	if ((eh = mtod(m, struct ether_header *)) == NULL)
524 		return (EINVAL);
525 
526 #if NBRIDGE > 0
527 	/* Store the peer IP address for the bridge */
528 	if (ifp->if_bridgeport != NULL &&
529 	    srcsa->sa_family != AF_UNSPEC &&
530 	    (sa = bridge_tunneltag(m, srcsa->sa_family)) != NULL)
531 		memcpy(sa, srcsa, sa->sa_len);
532 #endif
533 
534 	/* Clear multicast flag from the outer packet */
535 	if (sc->sc_imo.imo_num_memberships > 0 &&
536 	    m->m_flags & (M_MCAST) &&
537 	    !ETHER_IS_MULTICAST(eh->ether_dhost))
538 		m->m_flags &= ~M_MCAST;
539 
540 #if NBPFILTER > 0
541 	if (ifp->if_bpf)
542 		bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
543 #endif
544 
545 	m_adj(m, ETHER_HDR_LEN);
546 
547 #if NPF > 0
548 	pf_pkt_addr_changed(m);
549 #endif
550 
551 	ifp->if_ipackets++;
552 	ether_input(ifp, eh, m);
553 
554 	/* success */
555 	return (1);
556 }
557 
558 int
559 vxlan_output(struct ifnet *ifp, struct mbuf *m)
560 {
561 	struct vxlan_softc	*sc = (struct vxlan_softc *)ifp->if_softc;
562 #ifdef INET
563 	struct udpiphdr		*ui;
564 	struct vxlanudpiphdr	*vi;
565 	u_int16_t		 len = m->m_pkthdr.len;
566 	struct ip		*ip;
567 #if NBRIDGE > 0
568 	struct sockaddr_in	*sin;
569 #endif
570 #endif
571 	int			 error;
572 
573 #ifdef INET
574 	/* VXLAN header */
575 	M_PREPEND(m, sizeof(*vi), M_DONTWAIT);
576 	if (m == NULL) {
577 		ifp->if_oerrors++;
578 		return (ENOBUFS);
579 	}
580 
581 	len += sizeof(struct vxlan_header);
582 
583 	ui = mtod(m, struct udpiphdr *);
584 	ui->ui_pr = IPPROTO_UDP;
585 	ui->ui_src = ((struct sockaddr_in *)&sc->sc_src)->sin_addr;
586 	ui->ui_dst = ((struct sockaddr_in *)&sc->sc_dst)->sin_addr;
587 	ui->ui_sport = sc->sc_dstport;
588 	ui->ui_dport = sc->sc_dstport;
589 	ui->ui_ulen = htons(sizeof(struct udphdr) + len);
590 
591 	ip = (struct ip *)ui;
592 	ip->ip_v = IPVERSION;
593 	ip->ip_hl = sizeof(struct ip) >> 2;
594 	ip->ip_id = htons(ip_randomid());
595 	ip->ip_off = 0; /* htons(IP_DF); XXX should we disallow IP fragments? */
596 	ip->ip_tos = IPTOS_LOWDELAY;
597 	ip->ip_len = htons(sizeof(struct udpiphdr) + len);
598 	if (sc->sc_ttl > 0)
599 		ip->ip_ttl = sc->sc_ttl;
600 	else
601 		ip->ip_ttl = IPDEFTTL;
602 
603 #if NBRIDGE > 0
604 	if ((sin = satosin(bridge_tunnel(m))) != NULL &&
605 	    sin->sin_family == AF_INET) {
606 		ui->ui_dst = sin->sin_addr;
607 
608 		/*
609 		 * If the LINK0 flag is set, send the packet back to
610 		 * the original source port of the endport, otherwise use
611 		 * the configured VXLAN port.
612 		 */
613 		if (ifp->if_flags & IFF_LINK0)
614 			ui->ui_dport = sin->sin_port;
615 	}
616 	if (sin != NULL)
617 		bridge_tunneluntag(m);
618 #endif
619 
620 	vi = (struct vxlanudpiphdr *)ui;
621 	vi->ui_v.vxlan_flags = htonl(VXLAN_FLAGS_VNI);
622 	vi->ui_v.vxlan_id = htonl(sc->sc_vnetid << VXLAN_VNI_S);
623 
624 	/* UDP checksum should be 0 */
625 	ui->ui_sum = 0;
626 #endif
627 
628 	ifp->if_opackets++;
629 	ifp->if_obytes += m->m_pkthdr.len;
630 
631 	m->m_pkthdr.ph_rtableid = sc->sc_rdomain;
632 
633 #if NPF > 0
634 	pf_pkt_addr_changed(m);
635 #endif
636 
637 #ifdef INET
638 	if ((error =
639 	    ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL, 0))) {
640 		ifp->if_oerrors++;
641 	}
642 #endif
643 
644 	return (error);
645 }
646 
647 void
648 vxlan_addr_change(void *arg)
649 {
650 	struct vxlan_softc	*sc = arg;
651 	struct ifnet		*ifp = &sc->sc_ac.ac_if;
652 	int			 s, error;
653 
654 	/*
655 	 * Reset the configuration after resume or any possible address
656 	 * configuration changes.
657 	 */
658 	s = splnet();
659 	if ((error = vxlan_config(ifp, NULL, NULL))) {
660 		/*
661 		 * The source address of the tunnel can temporarily disappear,
662 		 * after a link state change when running the DHCP client,
663 		 * so keep it configured.
664 		 */
665 	}
666 	splx(s);
667 }
668 
669 void
670 vxlan_if_change(void *arg)
671 {
672 	struct vxlan_softc	*sc = arg;
673 	struct ifnet		*ifp = &sc->sc_ac.ac_if;
674 	int			 s, error;
675 
676 	/*
677 	 * Reset the configuration after the parent interface disappeared.
678 	 */
679 	s = splnet();
680 	if ((error = vxlan_config(ifp, NULL, NULL)) != 0) {
681 		/* The configured tunnel addresses are invalid, remove them */
682 		bzero(&sc->sc_src, sizeof(sc->sc_src));
683 		bzero(&sc->sc_dst, sizeof(sc->sc_dst));
684 	}
685 	splx(s);
686 }
687 
688 void
689 vxlan_link_change(void *arg)
690 {
691 	struct vxlan_softc	*sc = arg;
692 	struct ifnet		*ifp = &sc->sc_ac.ac_if;
693 	int			 s;
694 
695 	/*
696 	 * The machine might have lost its multicast associations after
697 	 * link state changes.  This fixes a problem with VMware after
698 	 * suspend/resume of the host or guest.
699 	 */
700 	s = splnet();
701 	(void)vxlan_config(ifp, NULL, NULL);
702 	splx(s);
703 }
704