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