LCOV - code coverage report
Current view: top level - net - if_vxlan.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 454 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 20 0.0 %
Legend: Lines: hit not hit

          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 : }

Generated by: LCOV version 1.13