xref: /openbsd-src/sys/netmpls/mpls_input.c (revision e5157e49389faebcb42b7237d55fbf096d9c2523)
1 /*	$OpenBSD: mpls_input.c,v 1.40 2014/11/01 21:40:39 mpi 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/ip.h>
34 #include <netinet/ip_var.h>
35 #include <netinet/ip_icmp.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 
49 #ifdef MPLS_DEBUG
50 #define MPLS_LABEL_GET(l)	((ntohl((l) & MPLS_LABEL_MASK)) >> MPLS_LABEL_OFFSET)
51 #define MPLS_TTL_GET(l)		(ntohl((l) & MPLS_TTL_MASK))
52 #endif
53 
54 int	mpls_ip_adjttl(struct mbuf *, u_int8_t);
55 #ifdef INET6
56 int	mpls_ip6_adjttl(struct mbuf *, u_int8_t);
57 #endif
58 
59 struct mbuf	*mpls_do_error(struct mbuf *, int, int, int);
60 
61 void
62 mpls_init(void)
63 {
64 	IFQ_SET_MAXLEN(&mplsintrq, IFQ_MAXLEN);
65 }
66 
67 void
68 mplsintr(void)
69 {
70 	struct mbuf *m;
71 	int s;
72 
73 	for (;;) {
74 		/* Get next datagram of input queue */
75 		s = splnet();
76 		IF_DEQUEUE(&mplsintrq, m);
77 		splx(s);
78 		if (m == NULL)
79 			return;
80 #ifdef DIAGNOSTIC
81 		if ((m->m_flags & M_PKTHDR) == 0)
82 			panic("mplsintr no HDR");
83 #endif
84 		mpls_input(m);
85 	}
86 }
87 
88 void
89 mpls_input(struct mbuf *m)
90 {
91 	struct ifnet *ifp = m->m_pkthdr.rcvif;
92 	struct sockaddr_mpls *smpls;
93 	struct sockaddr_mpls sa_mpls;
94 	struct shim_hdr	*shim;
95 	struct rtentry *rt = NULL;
96 	struct rt_mpls *rt_mpls;
97 	u_int8_t ttl;
98 	int i, s, hasbos;
99 
100 	if (!ISSET(ifp->if_xflags, IFXF_MPLS)) {
101 		m_freem(m);
102 		return;
103 	}
104 
105 	/* drop all broadcast and multicast packets */
106 	if (m->m_flags & (M_BCAST | M_MCAST)) {
107 		m_freem(m);
108 		return;
109 	}
110 
111 	if (m->m_len < sizeof(*shim))
112 		if ((m = m_pullup(m, sizeof(*shim))) == NULL)
113 			return;
114 
115 	shim = mtod(m, struct shim_hdr *);
116 
117 #ifdef MPLS_DEBUG
118 	printf("mpls_input: iface %s label=%d, ttl=%d BoS %d\n",
119 	    ifp->if_xname, MPLS_LABEL_GET(shim->shim_label),
120 	    MPLS_TTL_GET(shim->shim_label),
121 	    MPLS_BOS_ISSET(shim->shim_label));
122 #endif
123 
124 	/* check and decrement TTL */
125 	ttl = ntohl(shim->shim_label & MPLS_TTL_MASK);
126 	if (ttl-- <= 1) {
127 		/* TTL exceeded */
128 		m = mpls_do_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0);
129 		if (m == NULL)
130 			return;
131 		shim = mtod(m, struct shim_hdr *);
132 		ttl = ntohl(shim->shim_label & MPLS_TTL_MASK);
133 	}
134 
135 	bzero(&sa_mpls, sizeof(sa_mpls));
136 	smpls = &sa_mpls;
137 	smpls->smpls_family = AF_MPLS;
138 	smpls->smpls_len = sizeof(*smpls);
139 	for (i = 0; i < mpls_inkloop; i++) {
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 			case MPLS_LABEL_IPV4NULL:
156 				/*
157 				 * RFC 4182 relaxes the position of the
158 				 * explicit NULL labels. The no longer need
159 				 * to be at the beginning of the stack.
160 				 */
161 				if (hasbos) {
162 do_v4:
163 					if (mpls_ip_adjttl(m, ttl))
164 						goto done;
165 					s = splnet();
166 					IF_INPUT_ENQUEUE(&ipintrq, m);
167 					schednetisr(NETISR_IP);
168 					splx(s);
169 					goto done;
170 				}
171 				continue;
172 #ifdef INET6
173 			case MPLS_LABEL_IPV6NULL:
174 				if (hasbos) {
175 do_v6:
176 					if (mpls_ip6_adjttl(m, ttl))
177 						goto done;
178 					s = splnet();
179 					IF_INPUT_ENQUEUE(&ip6intrq, m);
180 					schednetisr(NETISR_IPV6);
181 					splx(s);
182 					goto done;
183 				}
184 				continue;
185 #endif	/* INET6 */
186 			case MPLS_LABEL_IMPLNULL:
187 				if (hasbos) {
188 					switch (*mtod(m, u_char *) >> 4) {
189 					case IPVERSION:
190 						goto do_v4;
191 #ifdef INET6
192 					case IPV6_VERSION >> 4:
193 						goto do_v6;
194 #endif
195 					default:
196 						m_freem(m);
197 						goto done;
198 					}
199 				}
200 				/* FALLTHROUGH */
201 			default:
202 				/* Other cases are not handled for now */
203 				m_freem(m);
204 				goto done;
205 			}
206 		}
207 
208 		rt = rtalloc(smplstosa(smpls), RT_REPORT|RT_RESOLVE, 0);
209 		if (rt == NULL) {
210 			/* no entry for this label */
211 #ifdef MPLS_DEBUG
212 			printf("MPLS_DEBUG: label not found\n");
213 #endif
214 			m_freem(m);
215 			goto done;
216 		}
217 
218 		rt->rt_use++;
219 		rt_mpls = (struct rt_mpls *)rt->rt_llinfo;
220 
221 		if (rt_mpls == NULL || (rt->rt_flags & RTF_MPLS) == 0) {
222 #ifdef MPLS_DEBUG
223 			printf("MPLS_DEBUG: no MPLS information "
224 			    "attached\n");
225 #endif
226 			m_freem(m);
227 			goto done;
228 		}
229 
230 		hasbos = MPLS_BOS_ISSET(shim->shim_label);
231 		switch (rt_mpls->mpls_operation) {
232 		case MPLS_OP_LOCAL:
233 			/* Packet is for us */
234 			m = mpls_shim_pop(m);
235 			if (!hasbos)
236 				/* redo lookup with next label */
237 				break;
238 
239 			if (!rt->rt_gateway) {
240 				m_freem(m);
241 				goto done;
242 			}
243 
244 			switch(rt->rt_gateway->sa_family) {
245 			case AF_INET:
246 				if (mpls_ip_adjttl(m, ttl))
247 					break;
248 				s = splnet();
249 				IF_INPUT_ENQUEUE(&ipintrq, m);
250 				schednetisr(NETISR_IP);
251 				splx(s);
252 				break;
253 #ifdef INET6
254 			case AF_INET6:
255 				if (mpls_ip6_adjttl(m, ttl))
256 					break;
257 				s = splnet();
258 				IF_INPUT_ENQUEUE(&ip6intrq, m);
259 				schednetisr(NETISR_IPV6);
260 				splx(s);
261 				break;
262 #endif
263 			default:
264 				m_freem(m);
265 			}
266 			goto done;
267 		case MPLS_OP_POP:
268 			m = mpls_shim_pop(m);
269 			if (!hasbos)
270 				/* redo lookup with next label */
271 				break;
272 
273 			ifp = rt->rt_ifp;
274 #if NMPE > 0
275 			if (ifp->if_type == IFT_MPLS) {
276 				smpls = satosmpls(rt_key(rt));
277 				mpe_input(m, rt->rt_ifp, smpls, ttl);
278 				goto done;
279 			}
280 #endif
281 			if (!rt->rt_gateway) {
282 				m_freem(m);
283 				goto done;
284 			}
285 
286 			switch(rt->rt_gateway->sa_family) {
287 			case AF_INET:
288 				if (mpls_ip_adjttl(m, ttl))
289 					goto done;
290 				break;
291 #ifdef INET6
292 			case AF_INET6:
293 				if (mpls_ip6_adjttl(m, ttl))
294 					goto done;
295 				break;
296 #endif
297 			default:
298 				m_freem(m);
299 				goto done;
300 			}
301 
302 			/* Output iface is not MPLS-enabled */
303 			if (!ISSET(ifp->if_xflags, IFXF_MPLS)) {
304 				m_freem(m);
305 				goto done;
306 			}
307 
308 			(*ifp->if_ll_output)(ifp, m, rt->rt_gateway, rt);
309 			goto done;
310 		case MPLS_OP_PUSH:
311 			m = mpls_shim_push(m, rt_mpls);
312 			break;
313 		case MPLS_OP_SWAP:
314 			m = mpls_shim_swap(m, rt_mpls);
315 			break;
316 		}
317 
318 		if (m == NULL)
319 			goto done;
320 
321 		/* refetch label */
322 		shim = mtod(m, struct shim_hdr *);
323 
324 		ifp = rt->rt_ifp;
325 		if (ifp != NULL && rt_mpls->mpls_operation != MPLS_OP_LOCAL)
326 			break;
327 
328 		rtfree(rt);
329 		rt = NULL;
330 	}
331 
332 	if (rt == NULL) {
333 		m_freem(m);
334 		goto done;
335 	}
336 
337 	/* write back TTL */
338 	shim->shim_label = (shim->shim_label & ~MPLS_TTL_MASK) | htonl(ttl);
339 
340 #ifdef MPLS_DEBUG
341 	printf("MPLS: sending on %s outlabel %x dst af %d in %d out %d\n",
342     	    ifp->if_xname, ntohl(shim->shim_label), smpls->smpls_family,
343 	    MPLS_LABEL_GET(smpls->smpls_label),
344 	    MPLS_LABEL_GET(rt_mpls->mpls_label));
345 #endif
346 
347 	/* Output iface is not MPLS-enabled */
348 	if (!ISSET(ifp->if_xflags, IFXF_MPLS)) {
349 #ifdef MPLS_DEBUG
350 		printf("MPLS_DEBUG: interface not mpls enabled\n");
351 #endif
352 		goto done;
353 	}
354 
355 	(*ifp->if_ll_output)(ifp, m, smplstosa(smpls), rt);
356 done:
357 	if (rt)
358 		rtfree(rt);
359 }
360 
361 int
362 mpls_ip_adjttl(struct mbuf *m, u_int8_t ttl)
363 {
364 	struct ip *ip;
365 	int hlen;
366 
367 	if (mpls_mapttl_ip) {
368 		if (m->m_len < sizeof(struct ip) &&
369 		    (m = m_pullup(m, sizeof(struct ip))) == NULL)
370 			return -1;
371 		ip = mtod(m, struct ip *);
372 		hlen = ip->ip_hl << 2;
373 		if (m->m_len < hlen) {
374 			if ((m = m_pullup(m, hlen)) == NULL)
375 				return -1;
376 			ip = mtod(m, struct ip *);
377 		}
378 		/* make sure we have a valid header */
379 		if (in_cksum(m, hlen) != 0) {
380 			m_free(m);
381 			return -1;
382 		}
383 
384 		/* set IP ttl from MPLS ttl */
385 		ip->ip_ttl = ttl;
386 
387 		/* recalculate checksum */
388 		ip->ip_sum = 0;
389 		ip->ip_sum = in_cksum(m, hlen);
390 	}
391 	return 0;
392 }
393 
394 #ifdef INET6
395 int
396 mpls_ip6_adjttl(struct mbuf *m, u_int8_t ttl)
397 {
398 	struct ip6_hdr *ip6hdr;
399 
400 	if (mpls_mapttl_ip6) {
401 		if (m->m_len < sizeof(struct ip6_hdr) &&
402 		    (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL)
403 			return -1;
404 
405 		ip6hdr = mtod(m, struct ip6_hdr *);
406 
407 		/* set IPv6 ttl from MPLS ttl */
408 		ip6hdr->ip6_hlim = ttl;
409 	}
410 	return 0;
411 }
412 #endif	/* INET6 */
413 
414 struct mbuf *
415 mpls_do_error(struct mbuf *m, int type, int code, int destmtu)
416 {
417 	struct shim_hdr stack[MPLS_INKERNEL_LOOP_MAX];
418 	struct sockaddr_mpls sa_mpls;
419 	struct sockaddr_mpls *smpls;
420 	struct rtentry *rt = NULL;
421 	struct shim_hdr *shim;
422 	struct in_ifaddr *ia;
423 	struct icmp *icp;
424 	struct ip *ip;
425 	int nstk;
426 
427 	for (nstk = 0; nstk < MPLS_INKERNEL_LOOP_MAX; nstk++) {
428 		if (m->m_len < sizeof(*shim) &&
429 		    (m = m_pullup(m, sizeof(*ip))) == NULL)
430 			return (NULL);
431 		stack[nstk] = *mtod(m, struct shim_hdr *);
432 		m_adj(m, sizeof(*shim));
433 		if (MPLS_BOS_ISSET(stack[nstk].shim_label))
434 			break;
435 	}
436 	shim = &stack[0];
437 
438 	switch (*mtod(m, u_char *) >> 4) {
439 	case IPVERSION:
440 		if (m->m_len < sizeof(*ip) &&
441 		    (m = m_pullup(m, sizeof(*ip))) == NULL)
442 			return (NULL);
443 		m = icmp_do_error(m, type, code, 0, destmtu);
444 		if (m == NULL)
445 			return (NULL);
446 
447 		if (icmp_do_exthdr(m, ICMP_EXT_MPLS, 1, stack,
448 		    (nstk + 1) * sizeof(*shim)))
449 			return (NULL);
450 
451 		/* set ip_src to something usable, based on the MPLS label */
452 		bzero(&sa_mpls, sizeof(sa_mpls));
453 		smpls = &sa_mpls;
454 		smpls->smpls_family = AF_MPLS;
455 		smpls->smpls_len = sizeof(*smpls);
456 		smpls->smpls_label = shim->shim_label & MPLS_LABEL_MASK;
457 
458 		rt = rtalloc(smplstosa(smpls), RT_REPORT|RT_RESOLVE, 0);
459 		if (rt == NULL) {
460 			/* no entry for this label */
461 			m_freem(m);
462 			return (NULL);
463 		}
464 		if (rt->rt_ifa->ifa_addr->sa_family == AF_INET)
465 			ia = ifatoia(rt->rt_ifa);
466 		else {
467 			/* XXX this needs fixing, if the MPLS is on an IP
468 			 * less interface we need to find some other IP to
469 			 * use as source.
470 			 */
471 			rtfree(rt);
472 			m_freem(m);
473 			return (NULL);
474 		}
475 		rt->rt_use++;
476 		rtfree(rt);
477 		if (icmp_reflect(m, NULL, ia))
478 			return (NULL);
479 
480 		ip = mtod(m, struct ip *);
481 		/* stuff to fix up which is normaly done in ip_output */
482 		ip->ip_v = IPVERSION;
483 		ip->ip_id = htons(ip_randomid());
484 		ip->ip_sum = 0;
485 		ip->ip_sum = in_cksum(m, sizeof(*ip));
486 
487 		/* stolen from icmp_send() */
488 		icp = (struct icmp *)(mtod(m, caddr_t) + sizeof(*ip));
489 		icp->icmp_cksum = 0;
490 		icp->icmp_cksum = in4_cksum(m, 0, sizeof(*ip),
491 		    ntohs(ip->ip_len) - sizeof(*ip));
492 
493 		break;
494 #ifdef INET6
495 	case IPV6_VERSION >> 4:
496 #endif
497 	default:
498 		m_freem(m);
499 		return (NULL);
500 	}
501 
502 	/* add mpls stack back to new packet */
503 	M_PREPEND(m, (nstk + 1) * sizeof(*shim), M_NOWAIT);
504 	if (m == NULL)
505 		return (NULL);
506 	m_copyback(m, 0, (nstk + 1) * sizeof(*shim), stack, M_NOWAIT);
507 
508 	/* change TTL to default */
509 	shim = mtod(m, struct shim_hdr *);
510 	shim->shim_label =
511 	    (shim->shim_label & ~MPLS_TTL_MASK) | htonl(mpls_defttl);
512 
513 	return (m);
514 }
515