1 /* $OpenBSD: mpls_input.c,v 1.13 2008/05/23 16:06:29 thib 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 u_int32_t ttl; 77 int i, hasbos; 78 79 if (!mpls_enable) { 80 m_freem(m); 81 return; 82 } 83 84 /* drop all broadcast and multicast packets */ 85 if (m->m_flags & (M_BCAST | M_MCAST)) { 86 m_freem(m); 87 return; 88 } 89 90 if (m->m_len < sizeof(*shim)) 91 if ((m = m_pullup(m, sizeof(*shim))) == NULL) 92 return; 93 94 shim = mtod(m, struct shim_hdr *); 95 96 #ifdef MPLS_DEBUG 97 printf("mpls_input: iface %s label=%d, ttl=%d BoS %d\n", 98 ifp->if_xname, MPLS_LABEL_GET(shim->shim_label), 99 MPLS_TTL_GET(shim->shim_label), 100 MPLS_BOS_ISSET(shim->shim_label)); 101 #endif /* MPLS_DEBUG */ 102 103 /* check and decrement TTL */ 104 ttl = ntohl(shim->shim_label & MPLS_TTL_MASK); 105 if (ttl <= 1) { 106 /* TTL exceeded */ 107 /* 108 * XXX if possible hand packet up to network layer so that an 109 * ICMP TTL exceeded can be sent back. 110 */ 111 m_freem(m); 112 return; 113 } 114 ttl = htonl(ttl - 1); 115 116 for (i = 0; i < mpls_inkloop; i++) { 117 bzero(&sa_mpls, sizeof(sa_mpls)); 118 smpls = &sa_mpls; 119 smpls->smpls_family = AF_MPLS; 120 smpls->smpls_len = sizeof(*smpls); 121 smpls->smpls_in_ifindex = ifp->if_index; 122 smpls->smpls_in_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_in_label), 128 smpls->smpls_in_ifindex); 129 #endif 130 131 rt = rtalloc1(smplstosa(smpls),1, 0); 132 133 if (rt == NULL) { 134 /* no entry for this label */ 135 #ifdef MPLS_DEBUG 136 printf("MPLS_DEBUG: label not found\n"); 137 #endif 138 m_freem(m); 139 goto done; 140 } 141 142 rt->rt_use++; 143 smpls = satosmpls(rt_key(rt)); 144 #ifdef MPLS_DEBUG 145 printf("route af %d len %d in_label %d in_ifindex %d\n", 146 smpls->smpls_family, smpls->smpls_len, 147 MPLS_LABEL_GET(smpls->smpls_in_label), 148 smpls->smpls_in_ifindex); 149 printf("\top %d out_label %d out_ifindex %d\n", 150 smpls->smpls_operation, 151 MPLS_LABEL_GET(smpls->smpls_out_label), 152 smpls->smpls_out_ifindex); 153 #endif 154 155 switch (smpls->smpls_operation) { 156 case MPLS_OP_POP: 157 hasbos = MPLS_BOS_ISSET(shim->shim_label); 158 m = mpls_shim_pop(m); 159 if (hasbos) { 160 #if NMPE > 0 161 if (rt->rt_ifp->if_type == IFT_MPLS) { 162 mpe_input(m, rt->rt_ifp, smpls, ttl); 163 goto done; 164 } 165 #endif 166 /* last label but we have no clue so drop */ 167 m_freem(m); 168 goto done; 169 } 170 break; 171 case MPLS_OP_PUSH: 172 m = mpls_shim_push(m, smpls); 173 break; 174 case MPLS_OP_SWAP: 175 m = mpls_shim_swap(m, smpls); 176 break; 177 default: 178 m_freem(m); 179 goto done; 180 } 181 182 if (m == NULL) 183 goto done; 184 185 /* refetch label */ 186 shim = mtod(m, struct shim_hdr *); 187 ifp = rt->rt_ifp; 188 189 if (smpls->smpls_out_ifindex) 190 break; 191 192 RTFREE(rt); 193 rt = NULL; 194 } 195 196 /* write back TTL */ 197 shim->shim_label = (shim->shim_label & ~MPLS_TTL_MASK) | ttl; 198 199 #ifdef MPLS_DEBUG 200 printf("MPLS: sending on %s outlabel %x dst af %d in %d out %d\n", 201 ifp->if_xname, ntohl(shim->shim_label), smpls->smpls_family, 202 MPLS_LABEL_GET(smpls->smpls_in_label), 203 MPLS_LABEL_GET(smpls->smpls_out_label)); 204 #endif 205 206 (*ifp->if_output)(ifp, m, smplstosa(smpls), rt); 207 done: 208 if (rt) 209 RTFREE(rt); 210 } 211