The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/if_mpls.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: if_mpls.c,v 1.41 2022/09/03 20:29:31 thorpej Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2010 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Mihai Chelaru <kefren@NetBSD.org>
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __KERNEL_RCSID(0, "$NetBSD: if_mpls.c,v 1.41 2022/09/03 20:29:31 thorpej Exp $");
   34 
   35 #ifdef _KERNEL_OPT
   36 #include "opt_inet.h"
   37 #include "opt_mpls.h"
   38 #endif
   39 
   40 #include <sys/param.h>
   41 
   42 #include <sys/errno.h>
   43 #include <sys/malloc.h>
   44 #include <sys/mbuf.h>
   45 #include <sys/sysctl.h>
   46 
   47 #include <net/bpf.h>
   48 #include <net/if.h>
   49 #include <net/if_types.h>
   50 #include <net/route.h>
   51 #include <sys/device.h>
   52 #include <sys/module.h>
   53 #include <sys/atomic.h>
   54 
   55 #ifdef INET
   56 #include <netinet/in.h>
   57 #include <netinet/in_systm.h>
   58 #include <netinet/in_var.h>
   59 #include <netinet/ip.h>
   60 #include <netinet/ip_var.h>
   61 #endif
   62 
   63 #ifdef INET6
   64 #include <netinet/ip6.h>
   65 #include <netinet6/in6_var.h>
   66 #include <netinet6/ip6_var.h>
   67 #endif
   68 
   69 #include <netmpls/mpls.h>
   70 #include <netmpls/mpls_var.h>
   71 
   72 #include "if_mpls.h"
   73 
   74 #include "ioconf.h"
   75 
   76 static int mpls_clone_create(struct if_clone *, int);
   77 static int mpls_clone_destroy(struct ifnet *);
   78 
   79 static struct if_clone mpls_if_cloner =
   80         IF_CLONE_INITIALIZER("mpls", mpls_clone_create, mpls_clone_destroy);
   81 
   82 static void mpls_input(struct ifnet *, struct mbuf *);
   83 static int mpls_output(struct ifnet *, struct mbuf *, const struct sockaddr *,
   84     const struct rtentry *);
   85 static int mpls_ioctl(struct ifnet *, u_long, void *);
   86 static int mpls_send_frame(struct mbuf *, struct ifnet *,
   87     const struct rtentry *);
   88 static int mpls_lse(struct mbuf *);
   89 
   90 #ifdef INET
   91 static struct mbuf *mpls_unlabel_inet(struct mbuf *, int *error);
   92 static struct mbuf *mpls_label_inet(struct mbuf *, union mpls_shim *, uint);
   93 #endif
   94 
   95 #ifdef INET6
   96 static struct mbuf *mpls_unlabel_inet6(struct mbuf *, int *error);
   97 static struct mbuf *mpls_label_inet6(struct mbuf *, union mpls_shim *, uint);
   98 #endif
   99 
  100 static struct mbuf *mpls_prepend_shim(struct mbuf *, union mpls_shim *);
  101 
  102 extern int mpls_defttl, mpls_mapttl_inet, mpls_mapttl_inet6, mpls_icmp_respond,
  103     mpls_forwarding, mpls_frame_accept, mpls_mapprec_inet, mpls_mapclass_inet6,
  104     mpls_rfc4182;
  105 
  106 static u_int mpls_count;
  107 
  108 void    mplsattach(int);
  109 
  110 /* ARGSUSED */
  111 void
  112 mplsattach(int count)
  113 {
  114         /*
  115          * Nothing to do here, initialization is handled by the
  116          * module initialization code in mplsinit() below).
  117          */
  118 }
  119 
  120 static void
  121 mplsinit(void)
  122 {
  123         if_clone_attach(&mpls_if_cloner);
  124 }
  125 
  126 static int
  127 mplsdetach(void)
  128 {
  129         int error = 0;
  130 
  131         if (mpls_count != 0)
  132                 error = EBUSY;
  133 
  134         if (error == 0)
  135                 if_clone_detach(&mpls_if_cloner);
  136 
  137         return error;
  138 }
  139 
  140 static int
  141 mpls_clone_create(struct if_clone *ifc, int unit)
  142 {
  143         struct mpls_softc *sc;
  144 
  145         atomic_inc_uint(&mpls_count);
  146         sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
  147 
  148         if_initname(&sc->sc_if, ifc->ifc_name, unit);
  149         sc->sc_if.if_softc = sc;
  150         sc->sc_if.if_type = IFT_MPLS;
  151         sc->sc_if.if_addrlen = 0;
  152         sc->sc_if.if_hdrlen = sizeof(union mpls_shim);
  153         sc->sc_if.if_dlt = DLT_NULL;
  154         sc->sc_if.if_mtu = 1500;
  155         sc->sc_if.if_flags = 0;
  156         sc->sc_if._if_input = mpls_input;
  157         sc->sc_if.if_output = mpls_output;
  158         sc->sc_if.if_ioctl = mpls_ioctl;
  159 
  160         if_attach(&sc->sc_if);
  161         if_alloc_sadl(&sc->sc_if);
  162         bpf_attach(&sc->sc_if, DLT_NULL, sizeof(uint32_t));
  163         return 0;
  164 }
  165 
  166 static int
  167 mpls_clone_destroy(struct ifnet *ifp)
  168 {
  169 
  170         bpf_detach(ifp);
  171         if_detach(ifp);
  172 
  173         free(ifp->if_softc, M_DEVBUF);
  174         atomic_dec_uint(&mpls_count);
  175         return 0;
  176 }
  177 
  178 static void
  179 mpls_input(struct ifnet *ifp, struct mbuf *m)
  180 {
  181 #if 0
  182         /*
  183          * TODO - kefren
  184          * I'd love to unshim the packet, guess family
  185          * and pass it to bpf
  186          */
  187         bpf_mtap_af(ifp, AF_MPLS, m, BPF_D_IN);
  188 #endif
  189 
  190         mpls_lse(m);
  191 }
  192 
  193 void
  194 mplsintr(void *arg __unused)
  195 {
  196         struct mbuf *m;
  197 
  198         while ((m = pktq_dequeue(mpls_pktq)) != NULL) {
  199                 if (((m->m_flags & M_PKTHDR) == 0) ||
  200                     (m->m_pkthdr.rcvif_index == 0))
  201                         panic("mplsintr(): no pkthdr or rcvif");
  202 
  203 #ifdef MBUFTRACE
  204                 m_claimm(m, &mpls_owner);
  205 #endif
  206                 mpls_input(m_get_rcvif_NOMPSAFE(m), m);
  207         }
  208 }
  209 
  210 /*
  211  * prepend shim and deliver
  212  */
  213 static int
  214 mpls_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
  215     const struct rtentry *rt)
  216 {
  217         union mpls_shim mh, *pms;
  218         struct rtentry *rt1;
  219         int err;
  220         uint psize = sizeof(struct sockaddr_mpls);
  221 
  222         KASSERT(KERNEL_LOCKED_P());
  223 
  224         if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
  225                 m_freem(m);
  226                 return ENETDOWN;
  227         }
  228 
  229         if (rt_gettag(rt) == NULL || rt_gettag(rt)->sa_family != AF_MPLS) {
  230                 m_freem(m);
  231                 return EINVAL;
  232         }
  233 
  234         bpf_mtap_af(ifp, dst->sa_family, m, BPF_D_OUT);
  235 
  236         memset(&mh, 0, sizeof(mh));
  237         mh.s_addr = MPLS_GETSADDR(rt);
  238         mh.shim.bos = 1;
  239         mh.shim.exp = 0;
  240         mh.shim.ttl = mpls_defttl;
  241 
  242         pms = &((struct sockaddr_mpls*)rt_gettag(rt))->smpls_addr;
  243 
  244         while (psize <= rt_gettag(rt)->sa_len - sizeof(mh)) {
  245                 pms++;
  246                 if (mh.shim.label != MPLS_LABEL_IMPLNULL &&
  247                     ((m = mpls_prepend_shim(m, &mh)) == NULL))
  248                         return ENOBUFS;
  249                 memset(&mh, 0, sizeof(mh));
  250                 mh.s_addr = ntohl(pms->s_addr);
  251                 mh.shim.bos = mh.shim.exp = 0;
  252                 mh.shim.ttl = mpls_defttl;
  253                 psize += sizeof(mh);
  254         }
  255 
  256         switch (dst->sa_family) {
  257 #ifdef INET
  258         case AF_INET:
  259                 m = mpls_label_inet(m, &mh, psize - sizeof(struct sockaddr_mpls));
  260                 break;
  261 #endif
  262 #ifdef INET6
  263         case AF_INET6:
  264                 m = mpls_label_inet6(m, &mh, psize - sizeof(struct sockaddr_mpls));
  265                 break;
  266 #endif
  267         default:
  268                 m = mpls_prepend_shim(m, &mh);
  269                 break;
  270         }
  271 
  272         if (m == NULL) {
  273                 IF_DROP(&ifp->if_snd);
  274                 if_statinc(ifp, if_oerrors);
  275                 return ENOBUFS;
  276         }
  277 
  278         if_statadd2(ifp, if_opackets, 1, if_obytes, m->m_pkthdr.len);
  279 
  280         if ((rt1 = rtalloc1(rt->rt_gateway, 1)) == NULL) {
  281                 m_freem(m);
  282                 return EHOSTUNREACH;
  283         }
  284 
  285         err = mpls_send_frame(m, rt1->rt_ifp, rt);
  286         rt_unref(rt1);
  287         return err;
  288 }
  289 
  290 static int
  291 mpls_ioctl(struct ifnet *ifp, u_long cmd, void *data)
  292 {
  293         int error = 0, s = splnet();
  294         struct ifreq *ifr = data;
  295 
  296         switch(cmd) {
  297         case SIOCINITIFADDR:
  298                 ifp->if_flags |= IFF_UP | IFF_RUNNING;
  299                 break;
  300         case SIOCSIFMTU:
  301                 if (ifr != NULL && ifr->ifr_mtu < 576) {
  302                         error = EINVAL;
  303                         break;
  304                 }
  305                 /* FALLTHROUGH */
  306         case SIOCGIFMTU:
  307                 if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
  308                         error = 0;
  309                 break;
  310         case SIOCSIFFLAGS:
  311                 if ((error = ifioctl_common(ifp, cmd, data)) != 0)
  312                         break;
  313                 if (ifp->if_flags & IFF_UP)
  314                         ifp->if_flags |= IFF_RUNNING;
  315                 break;
  316         default:
  317                 error = ifioctl_common(ifp, cmd, data);
  318                 break;
  319         }
  320         splx(s);
  321         return error;
  322 }
  323 
  324 static inline struct mbuf *
  325 mpls_trim_label(struct mbuf *m, union mpls_shim *sh)
  326 {
  327         m_adj(m, sizeof(union mpls_shim));
  328 
  329         if (m->m_len < sizeof(union mpls_shim) &&
  330             (m = m_pullup(m, sizeof(union mpls_shim))) == NULL)
  331                 return NULL;
  332 
  333         sh->s_addr = ntohl(mtod(m, union mpls_shim *)->s_addr);
  334 
  335         return m;
  336 }
  337 
  338 /*
  339  * MPLS Label Switch Engine
  340  */
  341 static int
  342 mpls_lse(struct mbuf *m)
  343 {
  344         struct sockaddr_mpls dst;
  345         union mpls_shim tshim, *htag;
  346         struct rtentry *rt = NULL;
  347         int error = ENOBUFS;
  348         uint psize = sizeof(struct sockaddr_mpls);
  349         bool push_back_alert = false;
  350 
  351         /* If we're not accepting MPLS frames, leave now. */
  352         if (!mpls_frame_accept) {
  353                 error = EINVAL;
  354                 goto done;
  355         }
  356 
  357         if (m->m_len < sizeof(union mpls_shim) &&
  358             (m = m_pullup(m, sizeof(union mpls_shim))) == NULL)
  359                 goto done;
  360 
  361         dst.smpls_len = sizeof(struct sockaddr_mpls);
  362         dst.smpls_family = AF_MPLS;
  363         dst.smpls_addr.s_addr = ntohl(mtod(m, union mpls_shim *)->s_addr);
  364 
  365         error = EINVAL;
  366 
  367         /* TTL decrement */
  368         if ((m = mpls_ttl_dec(m)) == NULL)
  369                 goto done;
  370 
  371         /* RFC 4182 */
  372         if (mpls_rfc4182 != 0) {
  373                 while ((dst.smpls_addr.shim.label == MPLS_LABEL_IPV4NULL ||
  374                     dst.smpls_addr.shim.label == MPLS_LABEL_IPV6NULL) &&
  375                     __predict_false(dst.smpls_addr.shim.bos == 0)) {
  376                         m = mpls_trim_label(m, &dst.smpls_addr);
  377                         if (m == NULL) {
  378                                 goto done;
  379                         }
  380                 }
  381         }
  382 
  383         /* RFC 3032 Section 2.1 Page 4 */
  384         if (__predict_false(dst.smpls_addr.shim.label == MPLS_LABEL_RTALERT) &&
  385             dst.smpls_addr.shim.bos == 0) {
  386                 m = mpls_trim_label(m, &dst.smpls_addr);
  387                 if (m == NULL) {
  388                         goto done;
  389                 }
  390                 push_back_alert = true;
  391         }
  392 
  393         if (dst.smpls_addr.shim.label <= MPLS_LABEL_RESMAX) {
  394                 /* Don't swap reserved labels */
  395                 switch (dst.smpls_addr.shim.label) {
  396 #ifdef INET
  397                 case MPLS_LABEL_IPV4NULL:
  398                         /* Pop shim and push mbuf to IP stack */
  399                         if (dst.smpls_addr.shim.bos) {
  400                                 m = mpls_unlabel_inet(m, &error);
  401                         }
  402                         break;
  403 #endif
  404 #ifdef INET6
  405                 case MPLS_LABEL_IPV6NULL:
  406                         /* Pop shim and push mbuf to IPv6 stack */
  407                         if (dst.smpls_addr.shim.bos) {
  408                                 m = mpls_unlabel_inet6(m, &error);
  409                         }
  410                         break;
  411 #endif
  412                 case MPLS_LABEL_RTALERT:        /* Yeah, I'm all alerted */
  413                 case MPLS_LABEL_IMPLNULL:       /* This is logical only */
  414                 default:                        /* Rest are not allowed */
  415                         break;
  416                 }
  417                 goto done;
  418         }
  419 
  420         /* Check if we should do MPLS forwarding */
  421         error = EHOSTUNREACH;
  422         if (!mpls_forwarding)
  423                 goto done;
  424 
  425         /* Get a route to dst */
  426         dst.smpls_addr.shim.ttl = 0;
  427         dst.smpls_addr.shim.bos = 0;
  428         dst.smpls_addr.shim.exp = 0;
  429         dst.smpls_addr.s_addr = htonl(dst.smpls_addr.s_addr);
  430         if ((rt = rtalloc1((const struct sockaddr*)&dst, 1)) == NULL)
  431                 goto done;
  432 
  433         /* MPLS packet with no MPLS tagged route ? */
  434         if ((rt->rt_flags & RTF_GATEWAY) == 0 ||
  435              rt_gettag(rt) == NULL ||
  436              rt_gettag(rt)->sa_family != AF_MPLS)
  437                 goto done;
  438 
  439         tshim.s_addr = MPLS_GETSADDR(rt);
  440 
  441         /* Swap labels */
  442         if ((m->m_len < sizeof(union mpls_shim)) &&
  443             (m = m_pullup(m, sizeof(union mpls_shim))) == 0) {
  444                 error = ENOBUFS;
  445                 goto done;
  446         }
  447 
  448         /* Replace only the label */
  449         htag = mtod(m, union mpls_shim *);
  450         htag->s_addr = ntohl(htag->s_addr);
  451         htag->shim.label = tshim.shim.label;
  452         htag->s_addr = htonl(htag->s_addr);
  453 
  454         /* check if there is anything more to prepend */
  455         htag = &((struct sockaddr_mpls*)rt_gettag(rt))->smpls_addr;
  456         while (psize <= rt_gettag(rt)->sa_len - sizeof(tshim)) {
  457                 htag++;
  458                 memset(&tshim, 0, sizeof(tshim));
  459                 tshim.s_addr = ntohl(htag->s_addr);
  460                 tshim.shim.bos = tshim.shim.exp = 0;
  461                 tshim.shim.ttl = mpls_defttl;
  462                 if (tshim.shim.label != MPLS_LABEL_IMPLNULL &&
  463                     ((m = mpls_prepend_shim(m, &tshim)) == NULL)) {
  464                         error = ENOBUFS;
  465                         goto done;
  466                 }
  467                 psize += sizeof(tshim);
  468         }
  469 
  470         if (__predict_false(push_back_alert == true)) {
  471                 /* re-add the router alert label */
  472                 memset(&tshim, 0, sizeof(tshim));
  473                 tshim.s_addr = MPLS_LABEL_RTALERT;
  474                 tshim.shim.bos = tshim.shim.exp = 0;
  475                 tshim.shim.ttl = mpls_defttl;
  476                 if ((m = mpls_prepend_shim(m, &tshim)) == NULL) {
  477                         error = ENOBUFS;
  478                         goto done;
  479                 }
  480         }
  481 
  482         if ((rt->rt_flags & RTF_GATEWAY) == 0) {
  483                 error = EHOSTUNREACH;
  484                 goto done;
  485         }
  486 
  487         rt->rt_use++;
  488         error = mpls_send_frame(m, rt->rt_ifp, rt);
  489 
  490 done:
  491         if (error != 0 && m != NULL)
  492                 m_freem(m);
  493         if (rt != NULL)
  494                 rt_unref(rt);
  495 
  496         return error;
  497 }
  498 
  499 static int
  500 mpls_send_frame(struct mbuf *m, struct ifnet *ifp, const struct rtentry *rt)
  501 {
  502         union mpls_shim msh;
  503         int ret;
  504 
  505         msh.s_addr = MPLS_GETSADDR(rt);
  506         if (msh.shim.label == MPLS_LABEL_IMPLNULL ||
  507             (m->m_flags & (M_MCAST | M_BCAST))) {
  508                 m_adj(m, sizeof(union mpls_shim));
  509                 m->m_pkthdr.csum_flags = 0;
  510         }
  511 
  512         switch(ifp->if_type) {
  513         /* only these are supported for now */
  514         case IFT_ETHER:
  515         case IFT_TUNNEL:
  516         case IFT_LOOP:
  517 #ifdef INET
  518                 ret = ip_if_output(ifp, m, rt->rt_gateway, rt);
  519 #else
  520                 ret = if_output_lock(ifp, ifp, m, rt->rt_gateway, rt);
  521 #endif
  522                 return ret;
  523                 break;
  524         default:
  525                 return ENETUNREACH;
  526         }
  527         return 0;
  528 }
  529 
  530 #ifdef INET
  531 static struct mbuf *
  532 mpls_unlabel_inet(struct mbuf *m, int *error)
  533 {
  534         struct ip *iph;
  535         union mpls_shim ms;
  536         int iphlen;
  537 
  538         if (mpls_mapttl_inet || mpls_mapprec_inet) {
  539                 /* get shim info */
  540                 ms.s_addr = ntohl(mtod(m, union mpls_shim *)->s_addr);
  541 
  542                 /* and get rid of it */
  543                 m_adj(m, sizeof(union mpls_shim));
  544 
  545                 /* get ip header */
  546                 if (m->m_len < sizeof(struct ip) &&
  547                     (m = m_pullup(m, sizeof(struct ip))) == NULL) {
  548                         *error = ENOBUFS;
  549                         return NULL;
  550                 }
  551 
  552                 iph = mtod(m, struct ip *);
  553                 iphlen = iph->ip_hl << 2;
  554 
  555                 /* get it all */
  556                 if (m->m_len < iphlen) {
  557                         if ((m = m_pullup(m, iphlen)) == NULL) {
  558                                 *error = ENOBUFS;
  559                                 return NULL;
  560                         }
  561                         iph = mtod(m, struct ip *);
  562                 }
  563 
  564                 /* check ipsum */
  565                 if (in_cksum(m, iphlen) != 0) {
  566                         m_freem(m);
  567                         *error = EINVAL;
  568                         return NULL;
  569                 }
  570 
  571                 /* set IP ttl from MPLS ttl */
  572                 if (mpls_mapttl_inet)
  573                         iph->ip_ttl = ms.shim.ttl;
  574 
  575                 /* set IP Precedence from MPLS Exp */
  576                 if (mpls_mapprec_inet) {
  577                         iph->ip_tos = (iph->ip_tos << 3) >> 3;
  578                         iph->ip_tos |= ms.shim.exp << 5;
  579                 }
  580 
  581                 /* reset ipsum because we modified TTL and TOS */
  582                 iph->ip_sum = 0;
  583                 iph->ip_sum = in_cksum(m, iphlen);
  584         } else {
  585                 m_adj(m, sizeof(union mpls_shim));
  586         }
  587 
  588         /* Put it on IP queue */
  589         if (__predict_false(!pktq_enqueue(ip_pktq, m, 0))) {
  590                 m_freem(m);
  591                 *error = ENOBUFS;
  592                 return NULL;
  593         }
  594 
  595         *error = 0;
  596         return m;
  597 }
  598 
  599 /*
  600  * Prepend MPLS label
  601  */
  602 static struct mbuf *
  603 mpls_label_inet(struct mbuf *m, union mpls_shim *ms, uint offset)
  604 {
  605         struct ip iphdr;
  606 
  607         if (mpls_mapttl_inet || mpls_mapprec_inet) {
  608                 /* XXX Maybe just check m->m_pkthdr.len instead? */
  609                 if ((m->m_len < offset + sizeof(struct ip)) &&
  610                     (m = m_pullup(m, offset + sizeof(struct ip))) == 0)
  611                         return NULL;
  612 
  613                 m_copydata(m, offset, sizeof(struct ip), &iphdr);
  614 
  615                 /* Map TTL */
  616                 if (mpls_mapttl_inet)
  617                         ms->shim.ttl = iphdr.ip_ttl;
  618 
  619                 /* Copy IP precedence to EXP */
  620                 if (mpls_mapprec_inet)
  621                         ms->shim.exp = ((u_int8_t)iphdr.ip_tos) >> 5;
  622         }
  623 
  624         if ((m = mpls_prepend_shim(m, ms)) == NULL)
  625                 return NULL;
  626 
  627         return m;
  628 }
  629 #endif  /* INET */
  630 
  631 #ifdef INET6
  632 static struct mbuf *
  633 mpls_unlabel_inet6(struct mbuf *m, int *error)
  634 {
  635         struct ip6_hdr *ip6hdr;
  636         union mpls_shim ms;
  637 
  638         /* TODO: mapclass */
  639         if (mpls_mapttl_inet6) {
  640                 ms.s_addr = ntohl(mtod(m, union mpls_shim *)->s_addr);
  641                 m_adj(m, sizeof(union mpls_shim));
  642 
  643                 if (m->m_len < sizeof(struct ip6_hdr) &&
  644                     (m = m_pullup(m, sizeof(struct ip6_hdr))) == 0) {
  645                         *error = ENOBUFS;
  646                         return NULL;
  647                 }
  648                 ip6hdr = mtod(m, struct ip6_hdr *);
  649 
  650                 /* Because we just decremented this in mpls_lse */
  651                 ip6hdr->ip6_hlim = ms.shim.ttl + 1;
  652         } else {
  653                 m_adj(m, sizeof(union mpls_shim));
  654         }
  655 
  656         /* Put it back on IPv6 queue. */
  657         if (__predict_false(!pktq_enqueue(ip6_pktq, m, 0))) {
  658                 m_freem(m);
  659                 *error = ENOBUFS;
  660                 return NULL;
  661         }
  662 
  663         *error = 0;
  664         return m;
  665 }
  666 
  667 static struct mbuf *
  668 mpls_label_inet6(struct mbuf *m, union mpls_shim *ms, uint offset)
  669 {
  670         struct ip6_hdr ip6h;
  671 
  672         if (mpls_mapttl_inet6 || mpls_mapclass_inet6) {
  673                 /* XXX Maybe just check m->m_pkthdr.len instead? */
  674                 if ((m->m_len < offset + sizeof(struct ip6_hdr)) &&
  675                     (m = m_pullup(m, offset + sizeof(struct ip6_hdr))) == 0)
  676                         return NULL;
  677 
  678                 m_copydata(m, offset, sizeof(struct ip6_hdr), &ip6h);
  679 
  680                 if (mpls_mapttl_inet6)
  681                         ms->shim.ttl = ip6h.ip6_hlim;
  682 
  683                 if (mpls_mapclass_inet6)
  684                         ms->shim.exp = ip6h.ip6_vfc << 1 >> 5;
  685         }
  686 
  687         if ((m = mpls_prepend_shim(m, ms)) == NULL)
  688                 return NULL;
  689 
  690         return m;
  691 }
  692 #endif  /* INET6 */
  693 
  694 static struct mbuf *
  695 mpls_prepend_shim(struct mbuf *m, union mpls_shim *ms)
  696 {
  697         union mpls_shim *shim;
  698 
  699         M_PREPEND(m, sizeof(*ms), M_DONTWAIT);
  700         if (m == NULL)
  701                 return NULL;
  702 
  703         if (m->m_len < sizeof(union mpls_shim) &&
  704             (m = m_pullup(m, sizeof(union mpls_shim))) == 0)
  705                 return NULL;
  706 
  707         shim = mtod(m, union mpls_shim *);
  708 
  709         memcpy(shim, ms, sizeof(*shim));
  710         shim->s_addr = htonl(shim->s_addr);
  711 
  712         return m;
  713 }
  714 
  715 /*
  716  * Module infrastructure
  717  */
  718 #include "if_module.h"
  719 
  720 IF_MODULE(MODULE_CLASS_DRIVER, mpls, NULL)

Cache object: f8c14875c763a3acc866d1173282cb86


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.