diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net/if_mpe.c | 10 | ||||
-rw-r--r-- | sys/netmpls/mpls.h | 3 | ||||
-rw-r--r-- | sys/netmpls/mpls_output.c | 153 |
3 files changed, 157 insertions, 9 deletions
diff --git a/sys/net/if_mpe.c b/sys/net/if_mpe.c index 518220355d2..20f21292570 100644 --- a/sys/net/if_mpe.c +++ b/sys/net/if_mpe.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_mpe.c,v 1.11 2008/10/18 12:30:40 michele Exp $ */ +/* $OpenBSD: if_mpe.c,v 1.12 2008/10/28 01:16:14 michele Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@spootnik.org> @@ -165,7 +165,7 @@ mpestart(struct ifnet *ifp) continue; } m->m_pkthdr.rcvif = ifp; - mpls_input(m); + mpls_output(m); } } @@ -289,9 +289,6 @@ mpe_input(struct mbuf *m, struct ifnet *ifp, struct sockaddr_mpls *smpls, bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); #endif s = splnet(); - /* - * assume we only get fed ipv4 packets for now. - */ IF_ENQUEUE(&ipintrq, m); schednetisr(NETISR_IP); splx(s); @@ -311,9 +308,6 @@ mpe_input6(struct mbuf *m, struct ifnet *ifp, struct sockaddr_mpls *smpls, bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); #endif s = splnet(); - /* - * assume we only get fed ipv4 packets for now. - */ IF_ENQUEUE(&ip6intrq, m); schednetisr(NETISR_IPV6); splx(s); diff --git a/sys/netmpls/mpls.h b/sys/netmpls/mpls.h index 0ad5fe11457..7b4b464d642 100644 --- a/sys/netmpls/mpls.h +++ b/sys/netmpls/mpls.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mpls.h,v 1.12 2008/10/14 20:43:33 michele Exp $ */ +/* $OpenBSD: mpls.h,v 1.13 2008/10/28 01:16:14 michele Exp $ */ /* * Copyright (C) 1999, 2000 and 2001 AYAME Project, WIDE Project. @@ -172,5 +172,6 @@ struct mbuf *mpls_shim_push(struct mbuf *, struct sockaddr_mpls *); int mpls_sysctl(int *, u_int, void *, size_t *, void *, size_t); void mpls_input(struct mbuf *); +void mpls_output(struct mbuf *); #endif /* _KERNEL */ diff --git a/sys/netmpls/mpls_output.c b/sys/netmpls/mpls_output.c new file mode 100644 index 00000000000..3139918be0d --- /dev/null +++ b/sys/netmpls/mpls_output.c @@ -0,0 +1,153 @@ +/* $Id: mpls_output.c,v 1.1 2008/10/28 01:16:14 michele Exp $ */ + +/* + * Copyright (c) 2008 Claudio Jeker <claudio@openbsd.org> + * Copyright (c) 2008 Michele Marchetto <michele@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/mbuf.h> +#include <sys/systm.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netmpls/mpls.h> + +extern int mpls_inkloop; + +#ifdef MPLS_DEBUG +#define MPLS_LABEL_GET(l) ((ntohl((l) & MPLS_LABEL_MASK)) >> MPLS_LABEL_OFFSET) +#endif + +void +mpls_output(struct mbuf *m) +{ + struct ifnet *ifp = m->m_pkthdr.rcvif; + struct sockaddr_mpls *smpls; + struct sockaddr_mpls sa_mpls; + struct shim_hdr *shim; + struct rtentry *rt = NULL; + u_int32_t ttl; + int i; + + if (!mpls_enable) { + m_freem(m); + return; + } + + /* reset broadcast and multicast flags, this is a P2P tunnel */ + m->m_flags &= ~(M_BCAST | M_MCAST); + + if (m->m_len < sizeof(*shim)) + if ((m = m_pullup(m, sizeof(*shim))) == NULL) + return; + + shim = mtod(m, struct shim_hdr *); + + /* extract TTL */ + ttl = shim->shim_label & MPLS_TTL_MASK; + + for (i = 0; i < mpls_inkloop; i++) { + bzero(&sa_mpls, sizeof(sa_mpls)); + smpls = &sa_mpls; + smpls->smpls_family = AF_MPLS; + smpls->smpls_len = sizeof(*smpls); + smpls->smpls_in_ifindex = ifp->if_index; + smpls->smpls_in_label = shim->shim_label & MPLS_LABEL_MASK; + +#ifdef MPLS_DEBUG + printf("smpls af %d len %d in_label %d in_ifindex %d\n", + smpls->smpls_family, smpls->smpls_len, + MPLS_LABEL_GET(smpls->smpls_in_label), + smpls->smpls_in_ifindex); +#endif + + rt = rtalloc1(smplstosa(smpls), 1, 0); + + if (rt == NULL) { + /* no entry for this label */ +#ifdef MPLS_DEBUG + printf("MPLS_DEBUG: label not found\n"); +#endif + m_freem(m); + goto done; + } + + rt->rt_use++; + smpls = satosmpls(rt_key(rt)); + +#ifdef MPLS_DEBUG + printf("route af %d len %d in_label %d in_ifindex %d\n", + smpls->smpls_family, smpls->smpls_len, + MPLS_LABEL_GET(smpls->smpls_in_label), + smpls->smpls_in_ifindex); + printf("\top %d out_label %d out_ifindex %d\n", + smpls->smpls_operation, + MPLS_LABEL_GET(smpls->smpls_out_label), + smpls->smpls_out_ifindex); +#endif + + switch (smpls->smpls_operation) { + case MPLS_OP_POP: + if (MPLS_BOS_ISSET(shim->shim_label)) { + /* drop to avoid loops */ + m_freem(m); + goto done; + } + + m = mpls_shim_pop(m); + break; + case MPLS_OP_PUSH: + m = mpls_shim_push(m, smpls); + break; + case MPLS_OP_SWAP: + m = mpls_shim_swap(m, smpls); + break; + default: + m_freem(m); + goto done; + } + + if (m == NULL) + goto done; + + /* refetch label */ + shim = mtod(m, struct shim_hdr *); + ifp = rt->rt_ifp; + + if (smpls->smpls_out_ifindex) + break; + + RTFREE(rt); + rt = NULL; + } + + /* write back TTL */ + shim->shim_label = (shim->shim_label & ~MPLS_TTL_MASK) | ttl; + +#ifdef MPLS_DEBUG + printf("MPLS: sending on %s outlabel %x dst af %d in %d out %d\n", + ifp->if_xname, ntohl(shim->shim_label), smpls->smpls_family, + MPLS_LABEL_GET(smpls->smpls_in_label), + MPLS_LABEL_GET(smpls->smpls_out_label)); +#endif + + (*ifp->if_output)(ifp, m, smplstosa(smpls), rt); +done: + if (rt) + RTFREE(rt); +} |