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 32 #include <sys/param.h> 33 #include <sys/malloc.h> /* for M_NOWAIT */ 34 #include <sys/mbuf.h> 35 #include <sys/systm.h> 36 37 #include <net/if_var.h> 38 39 #include <netinet/ip.h> 40 41 #include <netproto/mpls/mpls.h> 42 #include <netproto/mpls/mpls_var.h> 43 44 static int mpls_push(struct mbuf **, mpls_label_t, 45 mpls_s_t, mpls_exp_t, mpls_ttl_t); 46 static int mpls_swap(struct mbuf *, mpls_label_t); 47 static int mpls_pop(struct mbuf *, mpls_s_t *); 48 49 int 50 mpls_output(struct mbuf *m, struct rtentry *rt) 51 { 52 struct sockaddr_mpls *smpls = NULL; 53 int error = 0, i; 54 mpls_s_t stackempty; 55 mpls_ttl_t ttl = 255; 56 struct ip *ip; 57 58 M_ASSERTPKTHDR(m); 59 60 /* 61 * Check if we are coming from an MPLS routing table lookup. 62 * The rt_key of this rtentry will have a family AF_MPLS if so. 63 */ 64 stackempty = rt_key(rt)->sa_family != AF_MPLS ? 1 : 0; 65 if (stackempty) { 66 switch (rt_key(rt)->sa_family) { 67 case AF_INET: 68 ip = mtod(m, struct ip *); 69 ttl = ip->ip_ttl; 70 break; 71 } 72 } 73 74 for (i=0; i < MPLS_MAXLOPS && rt->rt_shim[i] != NULL; ++i) { 75 smpls = (struct sockaddr_mpls *)rt->rt_shim[i]; 76 switch (smpls->smpls_op) { 77 case MPLSLOP_PUSH: 78 error = mpls_push(&m, 79 ntohl(smpls->smpls_label), 80 /* 81 * If we are the first label push, then 82 * set the bottom-of-stack bit. 83 */ 84 (stackempty && i == 0) ? 1 : 0, 85 0, 86 ttl); 87 if (error) 88 return (error); 89 stackempty = 0; 90 m->m_flags |= M_MPLSLABELED; 91 break; 92 case MPLSLOP_SWAP: 93 /* 94 * Operation is only permmited if label stack 95 * is not empty. 96 */ 97 if (stackempty) 98 return (ENOTSUP); 99 KKASSERT(m->m_flags & M_MPLSLABELED); 100 error = mpls_swap(m, ntohl(smpls->smpls_label)); 101 if (error) 102 return (error); 103 break; 104 case MPLSLOP_POP: 105 /* 106 * Operation is only permmited if label stack 107 * is not empty. 108 */ 109 if (stackempty) 110 return (ENOTSUP); 111 KKASSERT(m->m_flags & M_MPLSLABELED); 112 error = mpls_pop(m, &stackempty); 113 if (error) 114 return (error); 115 /* 116 * If we are popping out the last label then 117 * mark the mbuf as ~M_MPLSLABELED. 118 */ 119 if (stackempty) 120 m->m_flags &= ~M_MPLSLABELED; 121 break; 122 default: 123 /* Unknown label operation */ 124 return (ENOTSUP); 125 } 126 } 127 128 return (error); 129 } 130 131 /* 132 * Returns FALSE if no further output processing required. 133 */ 134 boolean_t 135 mpls_output_process(struct mbuf *m, struct rtentry *rt) 136 { 137 int error; 138 139 /* Does this route have MPLS label operations? */ 140 if (!(rt->rt_flags & RTF_MPLSOPS)) 141 return TRUE; 142 143 error = mpls_output(m, rt); 144 if (error) { 145 m_freem(m); 146 return FALSE; 147 } 148 149 return TRUE; 150 } 151 152 static int 153 mpls_push(struct mbuf **m, mpls_label_t label, mpls_s_t s, mpls_exp_t exp, mpls_ttl_t ttl) { 154 struct mpls *mpls; 155 u_int32_t buf = 0; /* Silence warning */ 156 157 M_PREPEND(*m, sizeof(struct mpls), M_NOWAIT); 158 if (*m == NULL) 159 return (ENOBUFS); 160 161 MPLS_SET_LABEL(buf, label); 162 MPLS_SET_STACK(buf, s); 163 MPLS_SET_EXP(buf, exp); 164 MPLS_SET_TTL(buf, ttl); 165 mpls = mtod(*m, struct mpls *); 166 mpls->mpls_shim = htonl(buf); 167 168 return (0); 169 } 170 171 static int 172 mpls_swap(struct mbuf *m, mpls_label_t label) { 173 struct mpls *mpls; 174 u_int32_t buf; 175 mpls_ttl_t ttl; 176 177 if (m->m_len < sizeof(struct mpls) && 178 (m = m_pullup(m, sizeof(struct mpls))) == NULL) 179 return (ENOBUFS); 180 181 mpls = mtod(m, struct mpls *); 182 buf = ntohl(mpls->mpls_shim); 183 ttl = MPLS_TTL(buf); 184 if (--ttl <= 0) { 185 /* XXX: should send icmp ttl expired. */ 186 mplsstat.mplss_ttlexpired++; 187 return (ETIMEDOUT); 188 } 189 MPLS_SET_LABEL(buf, label); 190 MPLS_SET_TTL(buf, ttl); /* XXX tunnel mode: uniform, pipe, short pipe */ 191 mpls->mpls_shim = htonl(buf); 192 193 return (0); 194 } 195 196 static int 197 mpls_pop(struct mbuf *m, mpls_s_t *sbit) { 198 struct mpls *mpls; 199 u_int32_t buf; 200 201 if (m->m_len < sizeof(struct mpls)) { 202 m = m_pullup(m, sizeof(struct mpls)); 203 if (m == NULL) 204 return (ENOBUFS); 205 } 206 mpls = mtod(m, struct mpls *); 207 buf = ntohl(mpls->mpls_shim); 208 *sbit = MPLS_STACK(buf); 209 210 m_adj(m, sizeof(struct mpls)); 211 212 return (0); 213 } 214