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