summaryrefslogtreecommitdiffstats
path: root/sys/netmpls/mpls_output.c
diff options
context:
space:
mode:
authormichele <michele@openbsd.org>2008-10-28 01:16:14 +0000
committermichele <michele@openbsd.org>2008-10-28 01:16:14 +0000
commitbf64af94e691781de678f955a0dd93173c3c979c (patch)
tree09b203c912208de481ba2ae0f3854b3303ad241e /sys/netmpls/mpls_output.c
parentTry to use ACPI a little bit harder. Skip it only if ncpu < 2 and the (diff)
downloadwireguard-openbsd-bf64af94e691781de678f955a0dd93173c3c979c.tar.xz
wireguard-openbsd-bf64af94e691781de678f955a0dd93173c3c979c.zip
Added mpls_output() used to output mpls packets originating from local host.
Strictly similar to mpls_input(). Input and OK claudio@, OK laurent@
Diffstat (limited to 'sys/netmpls/mpls_output.c')
-rw-r--r--sys/netmpls/mpls_output.c153
1 files changed, 153 insertions, 0 deletions
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);
+}