xref: /openbsd-src/sys/netmpls/mpls_input.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /*	$OpenBSD: mpls_input.c,v 1.18 2009/01/28 22:18:44 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/route.h>
29 
30 #include <netmpls/mpls.h>
31 
32 struct ifqueue	mplsintrq;
33 int		mplsqmaxlen = IFQ_MAXLEN;
34 extern int	mpls_inkloop;
35 
36 #ifdef MPLS_DEBUG
37 #define MPLS_LABEL_GET(l)	((ntohl((l) & MPLS_LABEL_MASK)) >> MPLS_LABEL_OFFSET)
38 #define MPLS_TTL_GET(l)		(ntohl((l) & MPLS_TTL_MASK))
39 #endif
40 
41 void
42 mpls_init(void)
43 {
44 	mplsintrq.ifq_maxlen = mplsqmaxlen;
45 }
46 
47 void
48 mplsintr(void)
49 {
50 	struct mbuf *m;
51 	int s;
52 
53 	for (;;) {
54 		/* Get next datagram of input queue */
55 		s = splnet();
56 		IF_DEQUEUE(&mplsintrq, m);
57 		splx(s);
58 		if (m == NULL)
59 			return;
60 #ifdef DIAGNOSTIC
61 		if ((m->m_flags & M_PKTHDR) == 0)
62 			panic("ipintr no HDR");
63 #endif
64 		mpls_input(m);
65 	}
66 }
67 
68 void
69 mpls_input(struct mbuf *m)
70 {
71 	struct ifnet *ifp = m->m_pkthdr.rcvif;
72 	struct sockaddr_mpls *smpls;
73 	struct sockaddr_mpls sa_mpls;
74 	struct shim_hdr	*shim;
75 	struct rtentry *rt = NULL;
76 	struct rt_mpls *rt_mpls;
77 	u_int8_t ttl;
78 	int i, hasbos;
79 
80 	if (!mpls_enable) {
81 		m_freem(m);
82 		return;
83 	}
84 
85 	/* drop all broadcast and multicast packets */
86 	if (m->m_flags & (M_BCAST | M_MCAST)) {
87 		m_freem(m);
88 		return;
89 	}
90 
91 	if (m->m_len < sizeof(*shim))
92 		if ((m = m_pullup(m, sizeof(*shim))) == NULL)
93 			return;
94 
95 	shim = mtod(m, struct shim_hdr *);
96 
97 #ifdef MPLS_DEBUG
98 	printf("mpls_input: iface %s label=%d, ttl=%d BoS %d\n",
99 	    ifp->if_xname, MPLS_LABEL_GET(shim->shim_label),
100 	    MPLS_TTL_GET(shim->shim_label),
101 	    MPLS_BOS_ISSET(shim->shim_label));
102 #endif	/* MPLS_DEBUG */
103 
104 	/* check and decrement TTL */
105 	ttl = ntohl(shim->shim_label & MPLS_TTL_MASK);
106 	if (ttl <= 1) {
107 		/* TTL exceeded */
108 		/*
109 		 * XXX if possible hand packet up to network layer so that an
110 		 * ICMP TTL exceeded can be sent back.
111 		 */
112 		m_freem(m);
113 		return;
114 	}
115 	ttl--;
116 
117 	for (i = 0; i < mpls_inkloop; i++) {
118 		bzero(&sa_mpls, sizeof(sa_mpls));
119 		smpls = &sa_mpls;
120 		smpls->smpls_family = AF_MPLS;
121 		smpls->smpls_len = sizeof(*smpls);
122 		smpls->smpls_label = shim->shim_label & MPLS_LABEL_MASK;
123 
124 #ifdef MPLS_DEBUG
125 		printf("smpls af %d len %d in_label %d in_ifindex %d\n",
126 		    smpls->smpls_family, smpls->smpls_len,
127 		    MPLS_LABEL_GET(smpls->smpls_label),
128 		    ifp->if_index);
129 #endif
130 
131 		if (ntohl(smpls->smpls_label) < MPLS_LABEL_RESERVED_MAX) {
132 
133 			hasbos = MPLS_BOS_ISSET(shim->shim_label);
134 			m = mpls_shim_pop(m);
135 			shim = mtod(m, struct shim_hdr *);
136 
137 			switch (ntohl(smpls->smpls_label)) {
138 
139 			case MPLS_LABEL_IPV4NULL:
140 				if (hasbos) {
141 					mpe_input(m, NULL, smpls, ttl);
142 					goto done;
143 				} else
144 					continue;
145 
146 			case MPLS_LABEL_IPV6NULL:
147 				if (hasbos) {
148 					mpe_input6(m, NULL, smpls, ttl);
149 					goto done;
150 				} else
151 					continue;
152 			}
153 			/* Other cases are not handled for now */
154 		}
155 
156 		rt = rtalloc1(smplstosa(smpls), 1, 0);
157 
158 		if (rt == NULL) {
159 			/* no entry for this label */
160 #ifdef MPLS_DEBUG
161 			printf("MPLS_DEBUG: label not found\n");
162 #endif
163 			m_freem(m);
164 			goto done;
165 		}
166 
167 		rt->rt_use++;
168 		smpls = satosmpls(rt_key(rt));
169 		rt_mpls = (struct rt_mpls *)rt->rt_llinfo;
170 
171 		if (rt_mpls == NULL || (rt->rt_flags & RTF_MPLS) == 0) {
172 			/* no MPLS information for this entry */
173 #ifdef MPLS_DEBUG
174 			printf("MPLS_DEBUG: no MPLS information attached\n");
175 #endif
176 			m_freem(m);
177 			goto done;
178 		}
179 
180 		switch (rt_mpls->mpls_operation & (MPLS_OP_PUSH | MPLS_OP_POP |
181 		    MPLS_OP_SWAP)){
182 
183 		case MPLS_OP_POP:
184 			hasbos = MPLS_BOS_ISSET(shim->shim_label);
185 			m = mpls_shim_pop(m);
186 			if (hasbos) {
187 #if NMPE > 0
188 				if (rt->rt_ifp->if_type == IFT_MPLS) {
189 					mpe_input(m, rt->rt_ifp, smpls, ttl);
190 					goto done;
191 				}
192 #endif
193 				/* last label but we have no clue so drop */
194 				m_freem(m);
195 				goto done;
196 			}
197 			break;
198 		case MPLS_OP_PUSH:
199 			m = mpls_shim_push(m, rt_mpls);
200 			break;
201 		case MPLS_OP_SWAP:
202 			m = mpls_shim_swap(m, rt_mpls);
203 			break;
204 		default:
205 			m_freem(m);
206 			goto done;
207 		}
208 
209 		if (m == NULL)
210 			goto done;
211 
212 		/* refetch label */
213 		shim = mtod(m, struct shim_hdr *);
214 		ifp = rt->rt_ifp;
215 
216 		if (ifp != NULL)
217 			break;
218 
219 		RTFREE(rt);
220 		rt = NULL;
221 	}
222 
223 	if (rt == NULL) {
224 		m_freem(m);
225 		goto done;
226 	}
227 
228 	/* write back TTL */
229 	shim->shim_label = (shim->shim_label & ~MPLS_TTL_MASK) | htonl(ttl);
230 
231 #ifdef MPLS_DEBUG
232 	printf("MPLS: sending on %s outlabel %x dst af %d in %d out %d\n",
233     	    ifp->if_xname, ntohl(shim->shim_label), smpls->smpls_family,
234 	    MPLS_LABEL_GET(smpls->smpls_label),
235 	    MPLS_LABEL_GET(rt_mpls->mpls_label));
236 #endif
237 
238 	(*ifp->if_output)(ifp, m, smplstosa(smpls), rt);
239 done:
240 	if (rt)
241 		RTFREE(rt);
242 }
243