xref: /openbsd-src/sys/netmpls/mpls_input.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: mpls_input.c,v 1.20 2009/04/28 12:07:43 michele Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Claudio Jeker <claudio@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include "mpe.h"
20 
21 #include <sys/param.h>
22 #include <sys/mbuf.h>
23 #include <sys/systm.h>
24 #include <sys/socket.h>
25 
26 #include <net/if.h>
27 #include <net/if_types.h>
28 #include <net/netisr.h>
29 #include <net/route.h>
30 
31 #ifdef  INET
32 #include <netinet/in.h>
33 #include <netinet/in_var.h>
34 #include <netinet/in_systm.h>
35 #include <netinet/ip.h>
36 #endif
37 
38 #ifdef INET6
39 #include <netinet/ip6.h>
40 #ifndef INET
41 #include <netinet/in.h>
42 #endif
43 #endif /* INET6 */
44 
45 #include <netmpls/mpls.h>
46 
47 struct ifqueue	mplsintrq;
48 int		mplsqmaxlen = IFQ_MAXLEN;
49 extern int	mpls_inkloop;
50 
51 #ifdef MPLS_DEBUG
52 #define MPLS_LABEL_GET(l)	((ntohl((l) & MPLS_LABEL_MASK)) >> MPLS_LABEL_OFFSET)
53 #define MPLS_TTL_GET(l)		(ntohl((l) & MPLS_TTL_MASK))
54 #endif
55 
56 extern int	mpls_mapttl_ip;
57 extern int	mpls_mapttl_ip6;
58 
59 void
60 mpls_init(void)
61 {
62 	mplsintrq.ifq_maxlen = mplsqmaxlen;
63 }
64 
65 void
66 mplsintr(void)
67 {
68 	struct mbuf *m;
69 	int s;
70 
71 	for (;;) {
72 		/* Get next datagram of input queue */
73 		s = splnet();
74 		IF_DEQUEUE(&mplsintrq, m);
75 		splx(s);
76 		if (m == NULL)
77 			return;
78 #ifdef DIAGNOSTIC
79 		if ((m->m_flags & M_PKTHDR) == 0)
80 			panic("ipintr no HDR");
81 #endif
82 		mpls_input(m);
83 	}
84 }
85 
86 void
87 mpls_input(struct mbuf *m)
88 {
89 	struct ifnet *ifp = m->m_pkthdr.rcvif;
90 	struct sockaddr_mpls *smpls;
91 	struct sockaddr_mpls sa_mpls;
92 	struct shim_hdr	*shim;
93 	struct rtentry *rt = NULL;
94 	struct rt_mpls *rt_mpls;
95 	u_int8_t ttl;
96 	int i, hasbos;
97 
98 	if (!mpls_enable) {
99 		m_freem(m);
100 		return;
101 	}
102 
103 	/* drop all broadcast and multicast packets */
104 	if (m->m_flags & (M_BCAST | M_MCAST)) {
105 		m_freem(m);
106 		return;
107 	}
108 
109 	if (m->m_len < sizeof(*shim))
110 		if ((m = m_pullup(m, sizeof(*shim))) == NULL)
111 			return;
112 
113 	shim = mtod(m, struct shim_hdr *);
114 
115 #ifdef MPLS_DEBUG
116 	printf("mpls_input: iface %s label=%d, ttl=%d BoS %d\n",
117 	    ifp->if_xname, MPLS_LABEL_GET(shim->shim_label),
118 	    MPLS_TTL_GET(shim->shim_label),
119 	    MPLS_BOS_ISSET(shim->shim_label));
120 #endif	/* MPLS_DEBUG */
121 
122 	/* check and decrement TTL */
123 	ttl = ntohl(shim->shim_label & MPLS_TTL_MASK);
124 	if (ttl <= 1) {
125 		/* TTL exceeded */
126 		/*
127 		 * XXX if possible hand packet up to network layer so that an
128 		 * ICMP TTL exceeded can be sent back.
129 		 */
130 		m_freem(m);
131 		return;
132 	}
133 	ttl--;
134 
135 	for (i = 0; i < mpls_inkloop; i++) {
136 		bzero(&sa_mpls, sizeof(sa_mpls));
137 		smpls = &sa_mpls;
138 		smpls->smpls_family = AF_MPLS;
139 		smpls->smpls_len = sizeof(*smpls);
140 		smpls->smpls_label = shim->shim_label & MPLS_LABEL_MASK;
141 
142 #ifdef MPLS_DEBUG
143 		printf("smpls af %d len %d in_label %d in_ifindex %d\n",
144 		    smpls->smpls_family, smpls->smpls_len,
145 		    MPLS_LABEL_GET(smpls->smpls_label),
146 		    ifp->if_index);
147 #endif
148 
149 		if (ntohl(smpls->smpls_label) < MPLS_LABEL_RESERVED_MAX) {
150 			hasbos = MPLS_BOS_ISSET(shim->shim_label);
151 			m = mpls_shim_pop(m);
152 			shim = mtod(m, struct shim_hdr *);
153 
154 			switch (ntohl(smpls->smpls_label)) {
155 
156 			case MPLS_LABEL_IPV4NULL:
157 				if (hasbos) {
158 					mpls_ip_input(m, ttl);
159 					goto done;
160 				} else
161 					continue;
162 
163 			case MPLS_LABEL_IPV6NULL:
164 				if (hasbos) {
165 					mpls_ip6_input(m, ttl);
166 					goto done;
167 				} else
168 					continue;
169 			default:
170 				m_freem(m);
171 				goto done;
172 			}
173 			/* Other cases are not handled for now */
174 		}
175 
176 		rt = rtalloc1(smplstosa(smpls), 1, 0);
177 
178 		if (rt == NULL) {
179 			/* no entry for this label */
180 #ifdef MPLS_DEBUG
181 			printf("MPLS_DEBUG: label not found\n");
182 #endif
183 			m_freem(m);
184 			goto done;
185 		}
186 
187 		rt->rt_use++;
188 		smpls = satosmpls(rt_key(rt));
189 		rt_mpls = (struct rt_mpls *)rt->rt_llinfo;
190 
191 		if (rt_mpls == NULL || (rt->rt_flags & RTF_MPLS) == 0) {
192 #ifdef MPLS_DEBUG
193 			printf("MPLS_DEBUG: no MPLS information "
194 			    "attached\n");
195 #endif
196 			m_freem(m);
197 			goto done;
198 		}
199 
200 		if (rt_mpls->mpls_operation == MPLS_OP_LOCAL) {
201 			/* Packet is for us */
202 			hasbos = MPLS_BOS_ISSET(shim->shim_label);
203 			if (!hasbos) {
204 #ifdef MPLS_DEBUG
205 				printf("MPLS_DEBUG: packet malformed\n");
206 #endif
207 				m_freem(m);
208 				goto done;
209 			}
210 			m = mpls_shim_pop(m);
211 
212 			if (!rt->rt_gateway) {
213 #ifdef MPLS_DEBUG
214 				printf("MPLS_DEBUG: no layer 3 informations "
215 				    "attached\n");
216 #endif
217 				m_freem(m);
218 				goto done;
219 			}
220 
221 			switch(rt->rt_gateway->sa_family) {
222 			case AF_INET:
223 				mpls_ip_input(m, ttl);
224 				break;
225 			case AF_INET6:
226 				mpls_ip6_input(m, ttl);
227 				break;
228 			default:
229 				m_freem(m);
230 			}
231 
232 			goto done;
233 		}
234 
235 		switch (rt_mpls->mpls_operation & (MPLS_OP_PUSH | MPLS_OP_POP |
236 		    MPLS_OP_SWAP)){
237 
238 		case MPLS_OP_POP:
239 			hasbos = MPLS_BOS_ISSET(shim->shim_label);
240 			m = mpls_shim_pop(m);
241 			if (hasbos) {
242 #if NMPE > 0
243 				if (rt->rt_ifp->if_type == IFT_MPLS) {
244 					mpe_input(m, rt->rt_ifp, smpls, ttl);
245 					goto done;
246 				}
247 #endif
248 				/* last label but we have no clue so drop */
249 				m_freem(m);
250 				goto done;
251 			}
252 			break;
253 		case MPLS_OP_PUSH:
254 			m = mpls_shim_push(m, rt_mpls);
255 			break;
256 		case MPLS_OP_SWAP:
257 			m = mpls_shim_swap(m, rt_mpls);
258 			break;
259 		default:
260 			m_freem(m);
261 			goto done;
262 		}
263 
264 		if (m == NULL)
265 			goto done;
266 
267 		/* refetch label */
268 		shim = mtod(m, struct shim_hdr *);
269 		ifp = rt->rt_ifp;
270 
271 		if (ifp != NULL)
272 			break;
273 
274 		RTFREE(rt);
275 		rt = NULL;
276 	}
277 
278 	if (rt == NULL) {
279 		m_freem(m);
280 		goto done;
281 	}
282 
283 	/* write back TTL */
284 	shim->shim_label = (shim->shim_label & ~MPLS_TTL_MASK) | htonl(ttl);
285 
286 #ifdef MPLS_DEBUG
287 	printf("MPLS: sending on %s outlabel %x dst af %d in %d out %d\n",
288     	    ifp->if_xname, ntohl(shim->shim_label), smpls->smpls_family,
289 	    MPLS_LABEL_GET(smpls->smpls_label),
290 	    MPLS_LABEL_GET(rt_mpls->mpls_label));
291 #endif
292 
293 	(*ifp->if_output)(ifp, m, smplstosa(smpls), rt);
294 done:
295 	if (rt)
296 		RTFREE(rt);
297 }
298 
299 void
300 mpls_ip_input(struct mbuf *m, u_int8_t ttl)
301 {
302 	struct ip	*ip;
303 	int		 s, hlen;
304 
305 	if (mpls_mapttl_ip) {
306 		if (m->m_len < sizeof (struct ip) &&
307 		    (m = m_pullup(m, sizeof(struct ip))) == NULL)
308 			return;
309 		ip = mtod(m, struct ip *);
310 		hlen = ip->ip_hl << 2;
311 		if (m->m_len < hlen) {
312 			if ((m = m_pullup(m, hlen)) == NULL)
313 				return;
314 			ip = mtod(m, struct ip *);
315 		}
316 
317 		if (in_cksum(m, hlen) != 0) {
318 			m_free(m);
319 			return;
320 		}
321 
322 		/* set IP ttl from MPLS ttl */
323 		ip->ip_ttl = ttl;
324 
325 		/* recalculate checksum */
326 		ip->ip_sum = 0;
327 		ip->ip_sum = in_cksum(m, hlen);
328 	}
329 
330 	s = splnet();
331 	IF_ENQUEUE(&ipintrq, m);
332 	schednetisr(NETISR_IP);
333 	splx(s);
334 }
335 
336 void
337 mpls_ip6_input(struct mbuf *m, u_int8_t ttl)
338 {
339 	struct ip6_hdr *ip6hdr;
340 	int		s;
341 
342 	if (mpls_mapttl_ip6) {
343 		if (m->m_len < sizeof (struct ip6_hdr) &&
344 		    (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL)
345 			return;
346 
347 		ip6hdr = mtod(m, struct ip6_hdr *);
348 
349 		/* set IPv6 ttl from MPLS ttl */
350 		ip6hdr->ip6_hlim = ttl;
351 	}
352 
353 	s = splnet();
354 	IF_ENQUEUE(&ip6intrq, m);
355 	schednetisr(NETISR_IPV6);
356 	splx(s);
357 }
358