xref: /openbsd-src/sys/netmpls/mpls_output.c (revision dc9da2d3a6c192ca187a749468ea6ae9d5e6a636)
1 /* $OpenBSD: mpls_output.c,v 1.6 2009/04/29 19:26:52 michele Exp $ */
2 
3 /*
4  * Copyright (c) 2008 Claudio Jeker <claudio@openbsd.org>
5  * Copyright (c) 2008 Michele Marchetto <michele@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/param.h>
21 #include <sys/mbuf.h>
22 #include <sys/systm.h>
23 #include <sys/socket.h>
24 
25 #include <net/if.h>
26 #include <net/route.h>
27 
28 #include <netmpls/mpls.h>
29 
30 extern int	mpls_inkloop;
31 
32 #ifdef MPLS_DEBUG
33 #define MPLS_LABEL_GET(l)	((ntohl((l) & MPLS_LABEL_MASK)) >> MPLS_LABEL_OFFSET)
34 #endif
35 
36 struct mbuf *
37 mpls_output(struct mbuf *m, struct rtentry *rt0)
38 {
39 	struct ifnet		*ifp = m->m_pkthdr.rcvif;
40 	struct sockaddr_mpls	*smpls;
41 	struct sockaddr_mpls	 sa_mpls;
42 	struct shim_hdr		*shim;
43 	struct rtentry		*rt = rt0;
44 	struct rt_mpls		*rt_mpls;
45 	//u_int32_t		 ttl;
46 	int			 i;
47 
48 	if (!mpls_enable) {
49 		m_freem(m);
50 		goto bad;
51 	}
52 
53 	/* reset broadcast and multicast flags, this is a P2P tunnel */
54 	m->m_flags &= ~(M_BCAST | M_MCAST);
55 
56 	for (i = 0; i < mpls_inkloop; i++) {
57 		if (rt == NULL) {
58 			shim = mtod(m, struct shim_hdr *);
59 
60 			bzero(&sa_mpls, sizeof(sa_mpls));
61 			smpls = &sa_mpls;
62 			smpls->smpls_family = AF_MPLS;
63 			smpls->smpls_len = sizeof(*smpls);
64 			smpls->smpls_label = shim->shim_label & MPLS_LABEL_MASK;
65 
66 			rt = rtalloc1(smplstosa(smpls), 1, 0);
67 			if (rt == NULL) {
68 				/* no entry for this label */
69 #ifdef MPLS_DEBUG
70 				printf("MPLS_DEBUG: label not found\n");
71 #endif
72 				m_freem(m);
73 				goto bad;
74 			}
75 			rt->rt_use++;
76 		}
77 
78 		rt_mpls = (struct rt_mpls *)rt->rt_llinfo;
79 		if (rt_mpls == NULL || (rt->rt_flags & RTF_MPLS) == 0) {
80 			/* no MPLS information for this entry */
81 #ifdef MPLS_DEBUG
82 			printf("MPLS_DEBUG: no MPLS information attached\n");
83 #endif
84 			m_freem(m);
85 			goto bad;
86 		}
87 
88 		switch (rt_mpls->mpls_operation & (MPLS_OP_PUSH | MPLS_OP_POP |
89 		    MPLS_OP_SWAP)) {
90 
91 		case MPLS_OP_PUSH:
92 			m = mpls_shim_push(m, rt_mpls);
93 			break;
94 		case MPLS_OP_POP:
95 			m = mpls_shim_pop(m);
96 			break;
97 		case MPLS_OP_SWAP:
98 			m = mpls_shim_swap(m, rt_mpls);
99 			break;
100 		default:
101 			m_freem(m);
102 			goto bad;
103 		}
104 
105 		if (m == NULL)
106 			goto bad;
107 
108 		/* refetch label */
109 		shim = mtod(m, struct shim_hdr *);
110 		ifp = rt->rt_ifp;
111 
112 		if (ifp != NULL)
113 			break;
114 
115 		if (rt0 != rt)
116 			RTFREE(rt);
117 
118 		rt = NULL;
119 	}
120 
121 	/* write back TTL */
122 	shim->shim_label &= ~MPLS_TTL_MASK;
123 	shim->shim_label |= MPLS_BOS_MASK | htonl(mpls_defttl);
124 
125 #ifdef MPLS_DEBUG
126 	printf("MPLS: sending on %s outshim %x outlabel %d\n",
127 	    ifp->if_xname, ntohl(shim->shim_label),
128 	    MPLS_LABEL_GET(rt_mpls->mpls_label));
129 #endif
130 
131 	if (rt != rt0)
132 		RTFREE(rt);
133 
134 	return (m);
135 bad:
136 	if (rt != rt0)
137 		RTFREE(rt);
138 
139 	return (NULL);
140 }
141