xref: /openbsd-src/sys/netmpls/mpls_output.c (revision bf64af94e691781de678f955a0dd93173c3c979c)
1 /* $Id: mpls_output.c,v 1.1 2008/10/28 01:16:14 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 void
37 mpls_output(struct mbuf *m)
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 = NULL;
44 	u_int32_t		 ttl;
45 	int			 i;
46 
47 	if (!mpls_enable) {
48 		m_freem(m);
49 		return;
50 	}
51 
52 	/* reset broadcast and multicast flags, this is a P2P tunnel */
53 	m->m_flags &= ~(M_BCAST | M_MCAST);
54 
55 	if (m->m_len < sizeof(*shim))
56 		if ((m = m_pullup(m, sizeof(*shim))) == NULL)
57 			return;
58 
59 	shim = mtod(m, struct shim_hdr *);
60 
61 	/* extract TTL */
62 	ttl = shim->shim_label & MPLS_TTL_MASK;
63 
64 	for (i = 0; i < mpls_inkloop; i++) {
65 		bzero(&sa_mpls, sizeof(sa_mpls));
66 		smpls = &sa_mpls;
67 		smpls->smpls_family = AF_MPLS;
68 		smpls->smpls_len = sizeof(*smpls);
69 		smpls->smpls_in_ifindex = ifp->if_index;
70 		smpls->smpls_in_label = shim->shim_label & MPLS_LABEL_MASK;
71 
72 #ifdef MPLS_DEBUG
73 		printf("smpls af %d len %d in_label %d in_ifindex %d\n",
74 		    smpls->smpls_family, smpls->smpls_len,
75 		    MPLS_LABEL_GET(smpls->smpls_in_label),
76 		    smpls->smpls_in_ifindex);
77 #endif
78 
79 		rt = rtalloc1(smplstosa(smpls), 1, 0);
80 
81 		if (rt == NULL) {
82 			/* no entry for this label */
83 #ifdef MPLS_DEBUG
84 			printf("MPLS_DEBUG: label not found\n");
85 #endif
86 			m_freem(m);
87 			goto done;
88 		}
89 
90 		rt->rt_use++;
91 		smpls = satosmpls(rt_key(rt));
92 
93 #ifdef MPLS_DEBUG
94 		printf("route af %d len %d in_label %d in_ifindex %d\n",
95 		    smpls->smpls_family, smpls->smpls_len,
96 		    MPLS_LABEL_GET(smpls->smpls_in_label),
97 		    smpls->smpls_in_ifindex);
98 		printf("\top %d out_label %d out_ifindex %d\n",
99 		    smpls->smpls_operation,
100 		    MPLS_LABEL_GET(smpls->smpls_out_label),
101 		    smpls->smpls_out_ifindex);
102 #endif
103 
104 		switch (smpls->smpls_operation) {
105 		case MPLS_OP_POP:
106 			if (MPLS_BOS_ISSET(shim->shim_label)) {
107 				/* drop to avoid loops */
108 				m_freem(m);
109 				goto done;
110 			}
111 
112 			m = mpls_shim_pop(m);
113 			break;
114 		case MPLS_OP_PUSH:
115 			m = mpls_shim_push(m, smpls);
116 			break;
117 		case MPLS_OP_SWAP:
118 			m = mpls_shim_swap(m, smpls);
119 			break;
120 		default:
121 			m_freem(m);
122 			goto done;
123 		}
124 
125 		if (m == NULL)
126 			goto done;
127 
128 		/* refetch label */
129 		shim = mtod(m, struct shim_hdr *);
130 		ifp = rt->rt_ifp;
131 
132 		if (smpls->smpls_out_ifindex)
133 			break;
134 
135 		RTFREE(rt);
136 		rt = NULL;
137 	}
138 
139 	/* write back TTL */
140 	shim->shim_label = (shim->shim_label & ~MPLS_TTL_MASK) | ttl;
141 
142 #ifdef MPLS_DEBUG
143 	printf("MPLS: sending on %s outlabel %x dst af %d in %d out %d\n",
144 	    ifp->if_xname, ntohl(shim->shim_label), smpls->smpls_family,
145 	    MPLS_LABEL_GET(smpls->smpls_in_label),
146 	    MPLS_LABEL_GET(smpls->smpls_out_label));
147 #endif
148 
149 	(*ifp->if_output)(ifp, m, smplstosa(smpls), rt);
150 done:
151 	if (rt)
152 		RTFREE(rt);
153 }
154