xref: /dragonfly/sys/netproto/mpls/mpls_output.c (revision c443c74f)
19b42cabeSNuno Antunes /*
29b42cabeSNuno Antunes  * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
39b42cabeSNuno Antunes  *
49b42cabeSNuno Antunes  * Redistribution and use in source and binary forms, with or without
59b42cabeSNuno Antunes  * modification, are permitted provided that the following conditions
69b42cabeSNuno Antunes  * are met:
79b42cabeSNuno Antunes  *
89b42cabeSNuno Antunes  * 1. Redistributions of source code must retain the above copyright
99b42cabeSNuno Antunes  *    notice, this list of conditions and the following disclaimer.
109b42cabeSNuno Antunes  * 2. Redistributions in binary form must reproduce the above copyright
119b42cabeSNuno Antunes  *    notice, this list of conditions and the following disclaimer in
129b42cabeSNuno Antunes  *    the documentation and/or other materials provided with the
139b42cabeSNuno Antunes  *    distribution.
149b42cabeSNuno Antunes  * 3. Neither the name of The DragonFly Project nor the names of its
159b42cabeSNuno Antunes  *    contributors may be used to endorse or promote products derived
169b42cabeSNuno Antunes  *    from this software without specific, prior written permission.
179b42cabeSNuno Antunes  *
189b42cabeSNuno Antunes  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
199b42cabeSNuno Antunes  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
209b42cabeSNuno Antunes  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
219b42cabeSNuno Antunes  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
229b42cabeSNuno Antunes  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
239b42cabeSNuno Antunes  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
249b42cabeSNuno Antunes  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
259b42cabeSNuno Antunes  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
269b42cabeSNuno Antunes  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
279b42cabeSNuno Antunes  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
289b42cabeSNuno Antunes  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299b42cabeSNuno Antunes  * SUCH DAMAGE.
309b42cabeSNuno Antunes  */
319b42cabeSNuno Antunes 
329b42cabeSNuno Antunes #include <sys/param.h>
33*c443c74fSzrj #include <sys/malloc.h>	/* for M_NOWAIT */
349b42cabeSNuno Antunes #include <sys/mbuf.h>
359b42cabeSNuno Antunes #include <sys/systm.h>
369b42cabeSNuno Antunes 
379b42cabeSNuno Antunes #include <net/if_var.h>
389b42cabeSNuno Antunes 
399b42cabeSNuno Antunes #include <netinet/ip.h>
409b42cabeSNuno Antunes 
419b42cabeSNuno Antunes #include <netproto/mpls/mpls.h>
429b42cabeSNuno Antunes #include <netproto/mpls/mpls_var.h>
439b42cabeSNuno Antunes 
449b42cabeSNuno Antunes static int mpls_push(struct mbuf **, mpls_label_t,
459b42cabeSNuno Antunes 		     mpls_s_t, mpls_exp_t, mpls_ttl_t);
469b42cabeSNuno Antunes static int mpls_swap(struct mbuf *, mpls_label_t);
479b42cabeSNuno Antunes static int mpls_pop(struct mbuf *, mpls_s_t *);
489b42cabeSNuno Antunes 
499b42cabeSNuno Antunes int
mpls_output(struct mbuf * m,struct rtentry * rt)50cb8d752cSNuno Antunes mpls_output(struct mbuf *m, struct rtentry *rt)
519b42cabeSNuno Antunes {
529b42cabeSNuno Antunes 	struct sockaddr_mpls *smpls = NULL;
539b42cabeSNuno Antunes 	int error = 0, i;
549b42cabeSNuno Antunes 	mpls_s_t stackempty;
559b42cabeSNuno Antunes 	mpls_ttl_t ttl = 255;
569b42cabeSNuno Antunes 	struct ip *ip;
579b42cabeSNuno Antunes 
589b42cabeSNuno Antunes 	M_ASSERTPKTHDR(m);
599b42cabeSNuno Antunes 
60cb8d752cSNuno Antunes 	/*
61cb8d752cSNuno Antunes 	 * Check if we are coming from an MPLS routing table lookup.
62cb8d752cSNuno Antunes 	 * The rt_key of this rtentry will have a family AF_MPLS if so.
63cb8d752cSNuno Antunes 	 */
649b42cabeSNuno Antunes 	stackempty = rt_key(rt)->sa_family != AF_MPLS ? 1 : 0;
659b42cabeSNuno Antunes 	if (stackempty) {
669b42cabeSNuno Antunes 		switch (rt_key(rt)->sa_family) {
679b42cabeSNuno Antunes 		case AF_INET:
689b42cabeSNuno Antunes 			ip = mtod(m, struct ip *);
699b42cabeSNuno Antunes 			ttl = ip->ip_ttl;
709b42cabeSNuno Antunes 			break;
719b42cabeSNuno Antunes 		}
729b42cabeSNuno Antunes 	}
739b42cabeSNuno Antunes 
749b42cabeSNuno Antunes 	for (i=0; i < MPLS_MAXLOPS && rt->rt_shim[i] != NULL; ++i) {
759b42cabeSNuno Antunes 		smpls = (struct sockaddr_mpls *)rt->rt_shim[i];
769b42cabeSNuno Antunes 		switch (smpls->smpls_op) {
779b42cabeSNuno Antunes 		case MPLSLOP_PUSH:
789b42cabeSNuno Antunes 			error = mpls_push(&m,
799b42cabeSNuno Antunes 				  ntohl(smpls->smpls_label),
80cb8d752cSNuno Antunes 				  /*
81cb8d752cSNuno Antunes 				   * If we are the first label push, then
82cb8d752cSNuno Antunes 				   * set the bottom-of-stack bit.
83cb8d752cSNuno Antunes 				   */
84cb8d752cSNuno Antunes 				  (stackempty && i == 0) ? 1 : 0,
859b42cabeSNuno Antunes 				  0,
869b42cabeSNuno Antunes 				  ttl);
879b42cabeSNuno Antunes 			if (error)
889b42cabeSNuno Antunes 				return (error);
899b42cabeSNuno Antunes 			stackempty = 0;
90cb8d752cSNuno Antunes 			m->m_flags |= M_MPLSLABELED;
919b42cabeSNuno Antunes 			break;
929b42cabeSNuno Antunes 		case MPLSLOP_SWAP:
939b42cabeSNuno Antunes 			/*
949b42cabeSNuno Antunes 			 * Operation is only permmited if label stack
959b42cabeSNuno Antunes 			 * is not empty.
969b42cabeSNuno Antunes 			 */
979b42cabeSNuno Antunes 			if (stackempty)
989b42cabeSNuno Antunes 				return (ENOTSUP);
99cb8d752cSNuno Antunes 			KKASSERT(m->m_flags & M_MPLSLABELED);
1009b42cabeSNuno Antunes 			error = mpls_swap(m, ntohl(smpls->smpls_label));
1019b42cabeSNuno Antunes 			if (error)
1029b42cabeSNuno Antunes 				return (error);
1039b42cabeSNuno Antunes 			break;
1049b42cabeSNuno Antunes 		case MPLSLOP_POP:
1059b42cabeSNuno Antunes 			/*
1069b42cabeSNuno Antunes 			 * Operation is only permmited if label stack
1079b42cabeSNuno Antunes 			 * is not empty.
1089b42cabeSNuno Antunes 			 */
1099b42cabeSNuno Antunes 			if (stackempty)
1109b42cabeSNuno Antunes 				return (ENOTSUP);
111cb8d752cSNuno Antunes 			KKASSERT(m->m_flags & M_MPLSLABELED);
112cb8d752cSNuno Antunes 			error = mpls_pop(m, &stackempty);
113cb8d752cSNuno Antunes 			if (error)
114cb8d752cSNuno Antunes 				return (error);
115cb8d752cSNuno Antunes 			/*
116cb8d752cSNuno Antunes 			 * If we are popping out the last label then
117cb8d752cSNuno Antunes 			 * mark the mbuf as ~M_MPLSLABELED.
118cb8d752cSNuno Antunes 			 */
119cb8d752cSNuno Antunes 			if (stackempty)
120cb8d752cSNuno Antunes 				m->m_flags &= ~M_MPLSLABELED;
1219b42cabeSNuno Antunes 			break;
1229b42cabeSNuno Antunes 		default:
1239b42cabeSNuno Antunes 			/* Unknown label operation */
1249b42cabeSNuno Antunes 			return (ENOTSUP);
1259b42cabeSNuno Antunes 		}
1269b42cabeSNuno Antunes 	}
1279b42cabeSNuno Antunes 
1289b42cabeSNuno Antunes 	return (error);
1299b42cabeSNuno Antunes }
1309b42cabeSNuno Antunes 
1319b42cabeSNuno Antunes /*
1329b42cabeSNuno Antunes  * Returns FALSE if no further output processing required.
1339b42cabeSNuno Antunes  */
1349b42cabeSNuno Antunes boolean_t
mpls_output_process(struct mbuf * m,struct rtentry * rt)135cb8d752cSNuno Antunes mpls_output_process(struct mbuf *m, struct rtentry *rt)
1369b42cabeSNuno Antunes {
1379b42cabeSNuno Antunes 	int error;
1389b42cabeSNuno Antunes 
139cb8d752cSNuno Antunes 	/* Does this route have MPLS label operations? */
1409b42cabeSNuno Antunes 	if (!(rt->rt_flags & RTF_MPLSOPS))
1419b42cabeSNuno Antunes 		return TRUE;
1429b42cabeSNuno Antunes 
143cb8d752cSNuno Antunes 	error = mpls_output(m, rt);
144cb8d752cSNuno Antunes 	if (error) {
145cb8d752cSNuno Antunes 		m_freem(m);
1469b42cabeSNuno Antunes 		return FALSE;
147cb8d752cSNuno Antunes 	}
1489b42cabeSNuno Antunes 
1499b42cabeSNuno Antunes 	return TRUE;
1509b42cabeSNuno Antunes }
1519b42cabeSNuno Antunes 
1529b42cabeSNuno Antunes static int
mpls_push(struct mbuf ** m,mpls_label_t label,mpls_s_t s,mpls_exp_t exp,mpls_ttl_t ttl)1539b42cabeSNuno Antunes mpls_push(struct mbuf **m, mpls_label_t label, mpls_s_t s, mpls_exp_t exp, mpls_ttl_t ttl) {
1549b42cabeSNuno Antunes 	struct mpls *mpls;
1559b42cabeSNuno Antunes 	u_int32_t buf = 0;	/* Silence warning */
1569b42cabeSNuno Antunes 
157b5523eacSSascha Wildner 	M_PREPEND(*m, sizeof(struct mpls), M_NOWAIT);
1589b42cabeSNuno Antunes 	if (*m == NULL)
1599b42cabeSNuno Antunes 		return (ENOBUFS);
1609b42cabeSNuno Antunes 
1619b42cabeSNuno Antunes 	MPLS_SET_LABEL(buf, label);
1629b42cabeSNuno Antunes 	MPLS_SET_STACK(buf, s);
1639b42cabeSNuno Antunes 	MPLS_SET_EXP(buf, exp);
1649b42cabeSNuno Antunes 	MPLS_SET_TTL(buf, ttl);
1659b42cabeSNuno Antunes 	mpls = mtod(*m, struct mpls *);
1669b42cabeSNuno Antunes 	mpls->mpls_shim = htonl(buf);
1679b42cabeSNuno Antunes 
1689b42cabeSNuno Antunes 	return (0);
1699b42cabeSNuno Antunes }
1709b42cabeSNuno Antunes 
1719b42cabeSNuno Antunes static int
mpls_swap(struct mbuf * m,mpls_label_t label)1729b42cabeSNuno Antunes mpls_swap(struct mbuf *m, mpls_label_t label) {
1739b42cabeSNuno Antunes 	struct mpls *mpls;
1749b42cabeSNuno Antunes 	u_int32_t buf;
1759b42cabeSNuno Antunes 	mpls_ttl_t ttl;
1769b42cabeSNuno Antunes 
1779b42cabeSNuno Antunes 	if (m->m_len < sizeof(struct mpls) &&
1789b42cabeSNuno Antunes 	   (m = m_pullup(m, sizeof(struct mpls))) == NULL)
1799b42cabeSNuno Antunes 		return (ENOBUFS);
1809b42cabeSNuno Antunes 
1819b42cabeSNuno Antunes 	mpls = mtod(m, struct mpls *);
1829b42cabeSNuno Antunes 	buf = ntohl(mpls->mpls_shim);
1839b42cabeSNuno Antunes 	ttl = MPLS_TTL(buf);
184cb8d752cSNuno Antunes 	if (--ttl <= 0) {
185cb8d752cSNuno Antunes 		/* XXX: should send icmp ttl expired. */
186cb8d752cSNuno Antunes 		mplsstat.mplss_ttlexpired++;
187cb8d752cSNuno Antunes 		return (ETIMEDOUT);
188cb8d752cSNuno Antunes 	}
189cb8d752cSNuno Antunes 	MPLS_SET_LABEL(buf, label);
190cb8d752cSNuno Antunes 	MPLS_SET_TTL(buf, ttl); /* XXX tunnel mode: uniform, pipe, short pipe */
1919b42cabeSNuno Antunes 	mpls->mpls_shim = htonl(buf);
1929b42cabeSNuno Antunes 
1939b42cabeSNuno Antunes 	return (0);
1949b42cabeSNuno Antunes }
1959b42cabeSNuno Antunes 
1969b42cabeSNuno Antunes static int
mpls_pop(struct mbuf * m,mpls_s_t * sbit)1979b42cabeSNuno Antunes mpls_pop(struct mbuf *m, mpls_s_t *sbit) {
1989b42cabeSNuno Antunes 	struct mpls *mpls;
1999b42cabeSNuno Antunes 	u_int32_t buf;
2009b42cabeSNuno Antunes 
2019b42cabeSNuno Antunes 	if (m->m_len < sizeof(struct mpls)) {
2029b42cabeSNuno Antunes 		m = m_pullup(m, sizeof(struct mpls));
2039b42cabeSNuno Antunes 		if (m == NULL)
2049b42cabeSNuno Antunes 			return (ENOBUFS);
2059b42cabeSNuno Antunes 	}
2069b42cabeSNuno Antunes 	mpls = mtod(m, struct mpls *);
2079b42cabeSNuno Antunes 	buf = ntohl(mpls->mpls_shim);
2089b42cabeSNuno Antunes 	*sbit = MPLS_STACK(buf);
2099b42cabeSNuno Antunes 
2109b42cabeSNuno Antunes 	m_adj(m, sizeof(struct mpls));
2119b42cabeSNuno Antunes 
2129b42cabeSNuno Antunes 	return (0);
2139b42cabeSNuno Antunes }
214