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