1 /* 2 * Copyright (c) 2007 The DragonFly Project. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 3. Neither the name of The DragonFly Project nor the names of its 15 * contributors may be used to endorse or promote products derived 16 * from this software without specific, prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 28 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $DragonFly: src/sys/netproto/mpls/mpls_output.c,v 1.2 2008/08/05 15:11:32 nant Exp $ 32 */ 33 34 #include <sys/param.h> 35 #include <sys/mbuf.h> 36 #include <sys/systm.h> 37 38 #include <net/if_var.h> 39 40 #include <netinet/ip.h> 41 42 #include <netproto/mpls/mpls.h> 43 #include <netproto/mpls/mpls_var.h> 44 45 static int mpls_push(struct mbuf **, mpls_label_t, 46 mpls_s_t, mpls_exp_t, mpls_ttl_t); 47 static int mpls_swap(struct mbuf *, mpls_label_t); 48 static int mpls_pop(struct mbuf *, mpls_s_t *); 49 50 int 51 mpls_output(struct mbuf *m, struct rtentry *rt) 52 { 53 struct sockaddr_mpls *smpls = NULL; 54 int error = 0, i; 55 mpls_s_t stackempty; 56 mpls_ttl_t ttl = 255; 57 struct ip *ip; 58 59 M_ASSERTPKTHDR(m); 60 61 /* 62 * Check if we are coming from an MPLS routing table lookup. 63 * The rt_key of this rtentry will have a family AF_MPLS if so. 64 */ 65 stackempty = rt_key(rt)->sa_family != AF_MPLS ? 1 : 0; 66 if (stackempty) { 67 switch (rt_key(rt)->sa_family) { 68 case AF_INET: 69 ip = mtod(m, struct ip *); 70 ttl = ip->ip_ttl; 71 break; 72 } 73 } 74 75 for (i=0; i < MPLS_MAXLOPS && rt->rt_shim[i] != NULL; ++i) { 76 smpls = (struct sockaddr_mpls *)rt->rt_shim[i]; 77 switch (smpls->smpls_op) { 78 case MPLSLOP_PUSH: 79 error = mpls_push(&m, 80 ntohl(smpls->smpls_label), 81 /* 82 * If we are the first label push, then 83 * set the bottom-of-stack bit. 84 */ 85 (stackempty && i == 0) ? 1 : 0, 86 0, 87 ttl); 88 if (error) 89 return (error); 90 stackempty = 0; 91 m->m_flags |= M_MPLSLABELED; 92 break; 93 case MPLSLOP_SWAP: 94 /* 95 * Operation is only permmited if label stack 96 * is not empty. 97 */ 98 if (stackempty) 99 return (ENOTSUP); 100 KKASSERT(m->m_flags & M_MPLSLABELED); 101 error = mpls_swap(m, ntohl(smpls->smpls_label)); 102 if (error) 103 return (error); 104 break; 105 case MPLSLOP_POP: 106 /* 107 * Operation is only permmited if label stack 108 * is not empty. 109 */ 110 if (stackempty) 111 return (ENOTSUP); 112 KKASSERT(m->m_flags & M_MPLSLABELED); 113 error = mpls_pop(m, &stackempty); 114 if (error) 115 return (error); 116 /* 117 * If we are popping out the last label then 118 * mark the mbuf as ~M_MPLSLABELED. 119 */ 120 if (stackempty) 121 m->m_flags &= ~M_MPLSLABELED; 122 break; 123 default: 124 /* Unknown label operation */ 125 return (ENOTSUP); 126 } 127 } 128 129 return (error); 130 } 131 132 /* 133 * Returns FALSE if no further output processing required. 134 */ 135 boolean_t 136 mpls_output_process(struct mbuf *m, struct rtentry *rt) 137 { 138 int error; 139 140 /* Does this route have MPLS label operations? */ 141 if (!(rt->rt_flags & RTF_MPLSOPS)) 142 return TRUE; 143 144 error = mpls_output(m, rt); 145 if (error) { 146 m_freem(m); 147 return FALSE; 148 } 149 150 return TRUE; 151 } 152 153 static int 154 mpls_push(struct mbuf **m, mpls_label_t label, mpls_s_t s, mpls_exp_t exp, mpls_ttl_t ttl) { 155 struct mpls *mpls; 156 u_int32_t buf = 0; /* Silence warning */ 157 158 M_PREPEND(*m, sizeof(struct mpls), MB_DONTWAIT); 159 if (*m == NULL) 160 return (ENOBUFS); 161 162 MPLS_SET_LABEL(buf, label); 163 MPLS_SET_STACK(buf, s); 164 MPLS_SET_EXP(buf, exp); 165 MPLS_SET_TTL(buf, ttl); 166 mpls = mtod(*m, struct mpls *); 167 mpls->mpls_shim = htonl(buf); 168 169 return (0); 170 } 171 172 static int 173 mpls_swap(struct mbuf *m, mpls_label_t label) { 174 struct mpls *mpls; 175 u_int32_t buf; 176 mpls_ttl_t ttl; 177 178 if (m->m_len < sizeof(struct mpls) && 179 (m = m_pullup(m, sizeof(struct mpls))) == NULL) 180 return (ENOBUFS); 181 182 mpls = mtod(m, struct mpls *); 183 buf = ntohl(mpls->mpls_shim); 184 ttl = MPLS_TTL(buf); 185 if (--ttl <= 0) { 186 /* XXX: should send icmp ttl expired. */ 187 mplsstat.mplss_ttlexpired++; 188 return (ETIMEDOUT); 189 } 190 MPLS_SET_LABEL(buf, label); 191 MPLS_SET_TTL(buf, ttl); /* XXX tunnel mode: uniform, pipe, short pipe */ 192 mpls->mpls_shim = htonl(buf); 193 194 return (0); 195 } 196 197 static int 198 mpls_pop(struct mbuf *m, mpls_s_t *sbit) { 199 struct mpls *mpls; 200 u_int32_t buf; 201 202 if (m->m_len < sizeof(struct mpls)) { 203 m = m_pullup(m, sizeof(struct mpls)); 204 if (m == NULL) 205 return (ENOBUFS); 206 } 207 mpls = mtod(m, struct mpls *); 208 buf = ntohl(mpls->mpls_shim); 209 *sbit = MPLS_STACK(buf); 210 211 m_adj(m, sizeof(struct mpls)); 212 213 return (0); 214 } 215