1 /* $OpenBSD: mpls_output.c,v 1.5 2009/01/28 22:18:44 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 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 //u_int32_t ttl; 46 int i; 47 48 if (!mpls_enable) { 49 m_freem(m); 50 goto bad; 51 } 52 53 /* reset broadcast and multicast flags, this is a P2P tunnel */ 54 m->m_flags &= ~(M_BCAST | M_MCAST); 55 56 for (i = 0; i < mpls_inkloop; i++) { 57 if (rt == NULL) { 58 shim = mtod(m, struct shim_hdr *); 59 60 bzero(&sa_mpls, sizeof(sa_mpls)); 61 smpls = &sa_mpls; 62 smpls->smpls_family = AF_MPLS; 63 smpls->smpls_len = sizeof(*smpls); 64 smpls->smpls_label = shim->shim_label & MPLS_LABEL_MASK; 65 66 rt = rtalloc1(smplstosa(smpls), 1, 0); 67 if (rt == NULL) { 68 /* no entry for this label */ 69 #ifdef MPLS_DEBUG 70 printf("MPLS_DEBUG: label not found\n"); 71 #endif 72 m_freem(m); 73 goto bad; 74 } 75 rt->rt_use++; 76 } 77 78 rt_mpls = (struct rt_mpls *)rt->rt_llinfo; 79 if (rt_mpls == NULL || (rt->rt_flags & RTF_MPLS) == 0) { 80 /* no MPLS information for this entry */ 81 #ifdef MPLS_DEBUG 82 printf("MPLS_DEBUG: no MPLS information attached\n"); 83 #endif 84 m_freem(m); 85 goto bad; 86 } 87 88 switch (rt_mpls->mpls_operation & (MPLS_OP_PUSH | MPLS_OP_POP | 89 MPLS_OP_SWAP)) { 90 91 case MPLS_OP_PUSH: 92 m = mpls_shim_push(m, rt_mpls); 93 break; 94 case MPLS_OP_POP: 95 case MPLS_OP_SWAP: 96 /* We are entring a LSP. There isn't anything to pop 97 or swap yet. */ 98 default: 99 m_freem(m); 100 goto bad; 101 } 102 103 if (m == NULL) 104 goto bad; 105 106 /* refetch label */ 107 shim = mtod(m, struct shim_hdr *); 108 ifp = rt->rt_ifp; 109 110 if (ifp != NULL) 111 break; 112 113 if (rt0 != rt) 114 RTFREE(rt); 115 116 rt = NULL; 117 } 118 119 /* write back TTL */ 120 shim->shim_label &= ~MPLS_TTL_MASK; 121 shim->shim_label |= MPLS_BOS_MASK | htonl(mpls_defttl); 122 123 #ifdef MPLS_DEBUG 124 printf("MPLS: sending on %s outshim %x outlabel %d\n", 125 ifp->if_xname, ntohl(shim->shim_label), 126 MPLS_LABEL_GET(rt_mpls->mpls_label)); 127 #endif 128 129 if (rt != rt0) 130 RTFREE(rt); 131 132 return (m); 133 bad: 134 if (rt != rt0) 135 RTFREE(rt); 136 137 return (NULL); 138 } 139