1 /* $OpenBSD: mpls_input.c,v 1.18 2009/01/28 22:18:44 michele Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Claudio Jeker <claudio@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include "mpe.h" 20 21 #include <sys/param.h> 22 #include <sys/mbuf.h> 23 #include <sys/systm.h> 24 #include <sys/socket.h> 25 26 #include <net/if.h> 27 #include <net/if_types.h> 28 #include <net/route.h> 29 30 #include <netmpls/mpls.h> 31 32 struct ifqueue mplsintrq; 33 int mplsqmaxlen = IFQ_MAXLEN; 34 extern int mpls_inkloop; 35 36 #ifdef MPLS_DEBUG 37 #define MPLS_LABEL_GET(l) ((ntohl((l) & MPLS_LABEL_MASK)) >> MPLS_LABEL_OFFSET) 38 #define MPLS_TTL_GET(l) (ntohl((l) & MPLS_TTL_MASK)) 39 #endif 40 41 void 42 mpls_init(void) 43 { 44 mplsintrq.ifq_maxlen = mplsqmaxlen; 45 } 46 47 void 48 mplsintr(void) 49 { 50 struct mbuf *m; 51 int s; 52 53 for (;;) { 54 /* Get next datagram of input queue */ 55 s = splnet(); 56 IF_DEQUEUE(&mplsintrq, m); 57 splx(s); 58 if (m == NULL) 59 return; 60 #ifdef DIAGNOSTIC 61 if ((m->m_flags & M_PKTHDR) == 0) 62 panic("ipintr no HDR"); 63 #endif 64 mpls_input(m); 65 } 66 } 67 68 void 69 mpls_input(struct mbuf *m) 70 { 71 struct ifnet *ifp = m->m_pkthdr.rcvif; 72 struct sockaddr_mpls *smpls; 73 struct sockaddr_mpls sa_mpls; 74 struct shim_hdr *shim; 75 struct rtentry *rt = NULL; 76 struct rt_mpls *rt_mpls; 77 u_int8_t ttl; 78 int i, hasbos; 79 80 if (!mpls_enable) { 81 m_freem(m); 82 return; 83 } 84 85 /* drop all broadcast and multicast packets */ 86 if (m->m_flags & (M_BCAST | M_MCAST)) { 87 m_freem(m); 88 return; 89 } 90 91 if (m->m_len < sizeof(*shim)) 92 if ((m = m_pullup(m, sizeof(*shim))) == NULL) 93 return; 94 95 shim = mtod(m, struct shim_hdr *); 96 97 #ifdef MPLS_DEBUG 98 printf("mpls_input: iface %s label=%d, ttl=%d BoS %d\n", 99 ifp->if_xname, MPLS_LABEL_GET(shim->shim_label), 100 MPLS_TTL_GET(shim->shim_label), 101 MPLS_BOS_ISSET(shim->shim_label)); 102 #endif /* MPLS_DEBUG */ 103 104 /* check and decrement TTL */ 105 ttl = ntohl(shim->shim_label & MPLS_TTL_MASK); 106 if (ttl <= 1) { 107 /* TTL exceeded */ 108 /* 109 * XXX if possible hand packet up to network layer so that an 110 * ICMP TTL exceeded can be sent back. 111 */ 112 m_freem(m); 113 return; 114 } 115 ttl--; 116 117 for (i = 0; i < mpls_inkloop; i++) { 118 bzero(&sa_mpls, sizeof(sa_mpls)); 119 smpls = &sa_mpls; 120 smpls->smpls_family = AF_MPLS; 121 smpls->smpls_len = sizeof(*smpls); 122 smpls->smpls_label = shim->shim_label & MPLS_LABEL_MASK; 123 124 #ifdef MPLS_DEBUG 125 printf("smpls af %d len %d in_label %d in_ifindex %d\n", 126 smpls->smpls_family, smpls->smpls_len, 127 MPLS_LABEL_GET(smpls->smpls_label), 128 ifp->if_index); 129 #endif 130 131 if (ntohl(smpls->smpls_label) < MPLS_LABEL_RESERVED_MAX) { 132 133 hasbos = MPLS_BOS_ISSET(shim->shim_label); 134 m = mpls_shim_pop(m); 135 shim = mtod(m, struct shim_hdr *); 136 137 switch (ntohl(smpls->smpls_label)) { 138 139 case MPLS_LABEL_IPV4NULL: 140 if (hasbos) { 141 mpe_input(m, NULL, smpls, ttl); 142 goto done; 143 } else 144 continue; 145 146 case MPLS_LABEL_IPV6NULL: 147 if (hasbos) { 148 mpe_input6(m, NULL, smpls, ttl); 149 goto done; 150 } else 151 continue; 152 } 153 /* Other cases are not handled for now */ 154 } 155 156 rt = rtalloc1(smplstosa(smpls), 1, 0); 157 158 if (rt == NULL) { 159 /* no entry for this label */ 160 #ifdef MPLS_DEBUG 161 printf("MPLS_DEBUG: label not found\n"); 162 #endif 163 m_freem(m); 164 goto done; 165 } 166 167 rt->rt_use++; 168 smpls = satosmpls(rt_key(rt)); 169 rt_mpls = (struct rt_mpls *)rt->rt_llinfo; 170 171 if (rt_mpls == NULL || (rt->rt_flags & RTF_MPLS) == 0) { 172 /* no MPLS information for this entry */ 173 #ifdef MPLS_DEBUG 174 printf("MPLS_DEBUG: no MPLS information attached\n"); 175 #endif 176 m_freem(m); 177 goto done; 178 } 179 180 switch (rt_mpls->mpls_operation & (MPLS_OP_PUSH | MPLS_OP_POP | 181 MPLS_OP_SWAP)){ 182 183 case MPLS_OP_POP: 184 hasbos = MPLS_BOS_ISSET(shim->shim_label); 185 m = mpls_shim_pop(m); 186 if (hasbos) { 187 #if NMPE > 0 188 if (rt->rt_ifp->if_type == IFT_MPLS) { 189 mpe_input(m, rt->rt_ifp, smpls, ttl); 190 goto done; 191 } 192 #endif 193 /* last label but we have no clue so drop */ 194 m_freem(m); 195 goto done; 196 } 197 break; 198 case MPLS_OP_PUSH: 199 m = mpls_shim_push(m, rt_mpls); 200 break; 201 case MPLS_OP_SWAP: 202 m = mpls_shim_swap(m, rt_mpls); 203 break; 204 default: 205 m_freem(m); 206 goto done; 207 } 208 209 if (m == NULL) 210 goto done; 211 212 /* refetch label */ 213 shim = mtod(m, struct shim_hdr *); 214 ifp = rt->rt_ifp; 215 216 if (ifp != NULL) 217 break; 218 219 RTFREE(rt); 220 rt = NULL; 221 } 222 223 if (rt == NULL) { 224 m_freem(m); 225 goto done; 226 } 227 228 /* write back TTL */ 229 shim->shim_label = (shim->shim_label & ~MPLS_TTL_MASK) | htonl(ttl); 230 231 #ifdef MPLS_DEBUG 232 printf("MPLS: sending on %s outlabel %x dst af %d in %d out %d\n", 233 ifp->if_xname, ntohl(shim->shim_label), smpls->smpls_family, 234 MPLS_LABEL_GET(smpls->smpls_label), 235 MPLS_LABEL_GET(rt_mpls->mpls_label)); 236 #endif 237 238 (*ifp->if_output)(ifp, m, smplstosa(smpls), rt); 239 done: 240 if (rt) 241 RTFREE(rt); 242 } 243