1 /* $OpenBSD: mpls_output.c,v 1.8 2010/05/07 13:33:17 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2008 Michele Marchetto <michele@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/param.h> 21 #include <sys/mbuf.h> 22 #include <sys/systm.h> 23 #include <sys/socket.h> 24 25 #include <net/if.h> 26 #include <net/route.h> 27 28 #include <netmpls/mpls.h> 29 30 extern int mpls_inkloop; 31 32 #ifdef MPLS_DEBUG 33 #define MPLS_LABEL_GET(l) ((ntohl((l) & MPLS_LABEL_MASK)) >> MPLS_LABEL_OFFSET) 34 #endif 35 36 struct mbuf * 37 mpls_output(struct mbuf *m, struct rtentry *rt0) 38 { 39 struct ifnet *ifp = m->m_pkthdr.rcvif; 40 struct sockaddr_mpls *smpls; 41 struct sockaddr_mpls sa_mpls; 42 struct shim_hdr *shim; 43 struct rtentry *rt = rt0; 44 struct rt_mpls *rt_mpls; 45 int i; 46 47 if (!mpls_enable) { 48 m_freem(m); 49 goto bad; 50 } 51 52 /* reset broadcast and multicast flags, this is a P2P tunnel */ 53 m->m_flags &= ~(M_BCAST | M_MCAST); 54 55 for (i = 0; i < mpls_inkloop; i++) { 56 if (rt == NULL) { 57 shim = mtod(m, struct shim_hdr *); 58 59 bzero(&sa_mpls, sizeof(sa_mpls)); 60 smpls = &sa_mpls; 61 smpls->smpls_family = AF_MPLS; 62 smpls->smpls_len = sizeof(*smpls); 63 smpls->smpls_label = shim->shim_label & MPLS_LABEL_MASK; 64 65 rt = rtalloc1(smplstosa(smpls), RT_REPORT, 0); 66 if (rt == NULL) { 67 /* no entry for this label */ 68 #ifdef MPLS_DEBUG 69 printf("MPLS_DEBUG: label not found\n"); 70 #endif 71 m_freem(m); 72 goto bad; 73 } 74 rt->rt_use++; 75 } 76 77 rt_mpls = (struct rt_mpls *)rt->rt_llinfo; 78 if (rt_mpls == NULL || (rt->rt_flags & RTF_MPLS) == 0) { 79 /* no MPLS information for this entry */ 80 #ifdef MPLS_DEBUG 81 printf("MPLS_DEBUG: no MPLS information attached\n"); 82 #endif 83 m_freem(m); 84 goto bad; 85 } 86 87 switch (rt_mpls->mpls_operation & (MPLS_OP_PUSH | MPLS_OP_POP | 88 MPLS_OP_SWAP)) { 89 90 case MPLS_OP_PUSH: 91 m = mpls_shim_push(m, rt_mpls); 92 break; 93 case MPLS_OP_POP: 94 m = mpls_shim_pop(m); 95 break; 96 case MPLS_OP_SWAP: 97 m = mpls_shim_swap(m, rt_mpls); 98 break; 99 default: 100 m_freem(m); 101 goto bad; 102 } 103 104 if (m == NULL) 105 goto bad; 106 107 /* refetch label */ 108 shim = mtod(m, struct shim_hdr *); 109 ifp = rt->rt_ifp; 110 111 if (ifp != NULL) 112 break; 113 114 if (rt0 != rt) 115 RTFREE(rt); 116 117 rt = NULL; 118 } 119 120 /* write back TTL */ 121 shim->shim_label &= ~MPLS_TTL_MASK; 122 shim->shim_label |= MPLS_BOS_MASK | htonl(mpls_defttl); 123 124 #ifdef MPLS_DEBUG 125 printf("MPLS: sending on %s outshim %x outlabel %d\n", 126 ifp->if_xname, ntohl(shim->shim_label), 127 MPLS_LABEL_GET(rt_mpls->mpls_label)); 128 #endif 129 130 if (rt != rt0) 131 RTFREE(rt); 132 133 return (m); 134 bad: 135 if (rt != rt0) 136 RTFREE(rt); 137 138 return (NULL); 139 } 140