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