xref: /openbsd-src/sys/netmpls/mpls_input.c (revision 850e275390052b330d93020bf619a739a3c277ac)
1 /*	$OpenBSD: mpls_input.c,v 1.13 2008/05/23 16:06:29 thib 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 	u_int32_t ttl;
77 	int i, hasbos;
78 
79 	if (!mpls_enable) {
80 		m_freem(m);
81 		return;
82 	}
83 
84 	/* drop all broadcast and multicast packets */
85 	if (m->m_flags & (M_BCAST | M_MCAST)) {
86 		m_freem(m);
87 		return;
88 	}
89 
90 	if (m->m_len < sizeof(*shim))
91 		if ((m = m_pullup(m, sizeof(*shim))) == NULL)
92 			return;
93 
94 	shim = mtod(m, struct shim_hdr *);
95 
96 #ifdef MPLS_DEBUG
97 	printf("mpls_input: iface %s label=%d, ttl=%d BoS %d\n",
98 	    ifp->if_xname, MPLS_LABEL_GET(shim->shim_label),
99 	    MPLS_TTL_GET(shim->shim_label),
100 	    MPLS_BOS_ISSET(shim->shim_label));
101 #endif	/* MPLS_DEBUG */
102 
103 	/* check and decrement TTL */
104 	ttl = ntohl(shim->shim_label & MPLS_TTL_MASK);
105 	if (ttl <= 1) {
106 		/* TTL exceeded */
107 		/*
108 		 * XXX if possible hand packet up to network layer so that an
109 		 * ICMP TTL exceeded can be sent back.
110 		 */
111 		m_freem(m);
112 		return;
113 	}
114 	ttl = htonl(ttl - 1);
115 
116 	for (i = 0; i < mpls_inkloop; i++) {
117 		bzero(&sa_mpls, sizeof(sa_mpls));
118 		smpls = &sa_mpls;
119 		smpls->smpls_family = AF_MPLS;
120 		smpls->smpls_len = sizeof(*smpls);
121 		smpls->smpls_in_ifindex = ifp->if_index;
122 		smpls->smpls_in_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_in_label),
128 		    smpls->smpls_in_ifindex);
129 #endif
130 
131 		rt = rtalloc1(smplstosa(smpls),1, 0);
132 
133 		if (rt == NULL) {
134 			/* no entry for this label */
135 #ifdef MPLS_DEBUG
136 			printf("MPLS_DEBUG: label not found\n");
137 #endif
138 			m_freem(m);
139 			goto done;
140 		}
141 
142 		rt->rt_use++;
143 		smpls = satosmpls(rt_key(rt));
144 #ifdef MPLS_DEBUG
145 		printf("route af %d len %d in_label %d in_ifindex %d\n",
146 		    smpls->smpls_family, smpls->smpls_len,
147 		    MPLS_LABEL_GET(smpls->smpls_in_label),
148 		    smpls->smpls_in_ifindex);
149 		printf("\top %d out_label %d out_ifindex %d\n",
150 		    smpls->smpls_operation,
151 		    MPLS_LABEL_GET(smpls->smpls_out_label),
152 		    smpls->smpls_out_ifindex);
153 #endif
154 
155 		switch (smpls->smpls_operation) {
156 		case MPLS_OP_POP:
157 			hasbos = MPLS_BOS_ISSET(shim->shim_label);
158 			m = mpls_shim_pop(m);
159 			if (hasbos) {
160 #if NMPE > 0
161 				if (rt->rt_ifp->if_type == IFT_MPLS) {
162 					mpe_input(m, rt->rt_ifp, smpls, ttl);
163 					goto done;
164 				}
165 #endif
166 				/* last label but we have no clue so drop */
167 				m_freem(m);
168 				goto done;
169 			}
170 			break;
171 		case MPLS_OP_PUSH:
172 			m = mpls_shim_push(m, smpls);
173 			break;
174 		case MPLS_OP_SWAP:
175 			m = mpls_shim_swap(m, smpls);
176 			break;
177 		default:
178 			m_freem(m);
179 			goto done;
180 		}
181 
182 		if (m == NULL)
183 			goto done;
184 
185 		/* refetch label */
186 		shim = mtod(m, struct shim_hdr *);
187 		ifp = rt->rt_ifp;
188 
189 		if (smpls->smpls_out_ifindex)
190 			break;
191 
192 		RTFREE(rt);
193 		rt = NULL;
194 	}
195 
196 	/* write back TTL */
197 	shim->shim_label = (shim->shim_label & ~MPLS_TTL_MASK) | ttl;
198 
199 #ifdef MPLS_DEBUG
200 	printf("MPLS: sending on %s outlabel %x dst af %d in %d out %d\n",
201     	    ifp->if_xname, ntohl(shim->shim_label), smpls->smpls_family,
202 	    MPLS_LABEL_GET(smpls->smpls_in_label),
203 	    MPLS_LABEL_GET(smpls->smpls_out_label));
204 #endif
205 
206 	(*ifp->if_output)(ifp, m, smplstosa(smpls), rt);
207 done:
208 	if (rt)
209 		RTFREE(rt);
210 }
211