1 /* $Id: mpls_output.c,v 1.1 2008/10/28 01:16:14 michele 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 void 37 mpls_output(struct mbuf *m) 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 = NULL; 44 u_int32_t ttl; 45 int i; 46 47 if (!mpls_enable) { 48 m_freem(m); 49 return; 50 } 51 52 /* reset broadcast and multicast flags, this is a P2P tunnel */ 53 m->m_flags &= ~(M_BCAST | M_MCAST); 54 55 if (m->m_len < sizeof(*shim)) 56 if ((m = m_pullup(m, sizeof(*shim))) == NULL) 57 return; 58 59 shim = mtod(m, struct shim_hdr *); 60 61 /* extract TTL */ 62 ttl = shim->shim_label & MPLS_TTL_MASK; 63 64 for (i = 0; i < mpls_inkloop; i++) { 65 bzero(&sa_mpls, sizeof(sa_mpls)); 66 smpls = &sa_mpls; 67 smpls->smpls_family = AF_MPLS; 68 smpls->smpls_len = sizeof(*smpls); 69 smpls->smpls_in_ifindex = ifp->if_index; 70 smpls->smpls_in_label = shim->shim_label & MPLS_LABEL_MASK; 71 72 #ifdef MPLS_DEBUG 73 printf("smpls af %d len %d in_label %d in_ifindex %d\n", 74 smpls->smpls_family, smpls->smpls_len, 75 MPLS_LABEL_GET(smpls->smpls_in_label), 76 smpls->smpls_in_ifindex); 77 #endif 78 79 rt = rtalloc1(smplstosa(smpls), 1, 0); 80 81 if (rt == NULL) { 82 /* no entry for this label */ 83 #ifdef MPLS_DEBUG 84 printf("MPLS_DEBUG: label not found\n"); 85 #endif 86 m_freem(m); 87 goto done; 88 } 89 90 rt->rt_use++; 91 smpls = satosmpls(rt_key(rt)); 92 93 #ifdef MPLS_DEBUG 94 printf("route af %d len %d in_label %d in_ifindex %d\n", 95 smpls->smpls_family, smpls->smpls_len, 96 MPLS_LABEL_GET(smpls->smpls_in_label), 97 smpls->smpls_in_ifindex); 98 printf("\top %d out_label %d out_ifindex %d\n", 99 smpls->smpls_operation, 100 MPLS_LABEL_GET(smpls->smpls_out_label), 101 smpls->smpls_out_ifindex); 102 #endif 103 104 switch (smpls->smpls_operation) { 105 case MPLS_OP_POP: 106 if (MPLS_BOS_ISSET(shim->shim_label)) { 107 /* drop to avoid loops */ 108 m_freem(m); 109 goto done; 110 } 111 112 m = mpls_shim_pop(m); 113 break; 114 case MPLS_OP_PUSH: 115 m = mpls_shim_push(m, smpls); 116 break; 117 case MPLS_OP_SWAP: 118 m = mpls_shim_swap(m, smpls); 119 break; 120 default: 121 m_freem(m); 122 goto done; 123 } 124 125 if (m == NULL) 126 goto done; 127 128 /* refetch label */ 129 shim = mtod(m, struct shim_hdr *); 130 ifp = rt->rt_ifp; 131 132 if (smpls->smpls_out_ifindex) 133 break; 134 135 RTFREE(rt); 136 rt = NULL; 137 } 138 139 /* write back TTL */ 140 shim->shim_label = (shim->shim_label & ~MPLS_TTL_MASK) | ttl; 141 142 #ifdef MPLS_DEBUG 143 printf("MPLS: sending on %s outlabel %x dst af %d in %d out %d\n", 144 ifp->if_xname, ntohl(shim->shim_label), smpls->smpls_family, 145 MPLS_LABEL_GET(smpls->smpls_in_label), 146 MPLS_LABEL_GET(smpls->smpls_out_label)); 147 #endif 148 149 (*ifp->if_output)(ifp, m, smplstosa(smpls), rt); 150 done: 151 if (rt) 152 RTFREE(rt); 153 } 154