On Sun, Sep 14, 2014 at 11:51:07PM -0300, Rafael Zalamena wrote:
> The following patch implements the basics of the wire network interface.
> 
> --- snipped ---

I've added support for tcpdump'ing the wire interface, it will get all
data flowing through the wire without the MPLS / VPLS labels and control
word (just like enc(4) does for IPSec). If you want to see the full packet
see the interface facing your MPLS network (tcpdump needs some work to
identify the VPLS label and control word).

Partial patch (if you applied the one before this):

PATCH START
========================================================================
diff --git sys/net/if_wire.c sys/net/if_wire.c
index 41840cf..b9301fc 100644
--- sys/net/if_wire.c
+++ sys/net/if_wire.c
@@ -30,6 +30,13 @@
 #include <netinet/if_ether.h>
 #include <netmpls/mpls.h>
 
+#include "bpfilter.h"
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif /* NBPFILTER */
+
+
 void   wireattach(int);
 int    wire_clone_create(struct if_clone *, int);
 int    wire_clone_destroy(struct ifnet *);
@@ -90,6 +97,10 @@ wire_clone_create(struct if_clone *ifc, int unit)
        if_attach(ifp);
        if_alloc_sadl(ifp);
 
+#if NBPFILTER > 0
+       bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, ETHER_HDR_LEN);
+#endif
+
        s = splnet();
        LIST_INSERT_HEAD(&wire_list, sc, sc_list);
        splx(s);
@@ -253,6 +264,11 @@ wire_input(struct ifnet *ifp, struct mbuf *m)
                }
        }
 
+#if NBPFILTER > 0
+       if (sc->sc_if.if_bpf)
+               bpf_mtap(sc->sc_if.if_bpf, m, BPF_DIRECTION_IN);
+#endif
+
        eh = mtod(m, struct ether_header *);
        m_adj(m, ETHER_HDR_LEN);
 
@@ -316,6 +332,11 @@ wire_start(struct ifnet *ifp)
                        continue;
                }
 
+#if NBPFILTER > 0
+               if (sc->sc_if.if_bpf)
+                       bpf_mtap(sc->sc_if.if_bpf, m, BPF_DIRECTION_OUT);
+#endif /* NBPFILTER */
+
                rt = rtalloc1(&sc->sc_nexthop, RT_REPORT, 0);
                if (rt == NULL) {
                        m_freem(m);

========================================================================

Here is the full patch: (you still need to apply VPLS patch [1/3])

PATCH START
========================================================================
diff --git sys/conf/GENERIC sys/conf/GENERIC
index 309528e..444dcbe 100644
--- sys/conf/GENERIC
+++ sys/conf/GENERIC
@@ -95,6 +95,7 @@ pseudo-device systrace 1      # system call tracing device
 # clonable devices
 pseudo-device  bpfilter        # packet filter
 pseudo-device  bridge          # network bridging support
+pseudo-device  wire            # pseudowire support
 pseudo-device  carp            # CARP protocol support
 pseudo-device  gif             # IPv[46] over IPv[46] tunnel (RFC1933)
 pseudo-device  gre             # GRE encapsulation interface
diff --git sys/conf/files sys/conf/files
index 4220371..755b6cd 100644
--- sys/conf/files
+++ sys/conf/files
@@ -552,6 +552,7 @@ pseudo-device tun: ifnet
 pseudo-device bpfilter: ifnet
 pseudo-device enc: ifnet
 pseudo-device bridge: ifnet, ether
+pseudo-device wire: ifnet, ether
 pseudo-device vlan: ifnet, ether
 pseudo-device carp: ifnet, ether
 pseudo-device sppp: ifnet
@@ -790,6 +791,7 @@ file net/if_tun.c                   tun                     
needs-count
 file net/if_bridge.c                   bridge                  needs-count
 file net/bridgestp.c                   bridge
 file net/if_vlan.c                     vlan                    needs-count
+file net/if_wire.c                     wire                    needs-count
 file net/pipex.c                       pipex
 file net/radix.c
 file net/radix_mpath.c                 !small_kernel
diff --git sys/net/if_bridge.c sys/net/if_bridge.c
index fa40d36..6d09113 100644
--- sys/net/if_bridge.c
+++ sys/net/if_bridge.c
@@ -36,6 +36,7 @@
 #include "pf.h"
 #include "carp.h"
 #include "vlan.h"
+#include "wire.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -365,6 +366,11 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
                        /* Nothing needed */
                }
 #endif /* NGIF */
+#if NWIRE > 0
+               else if (ifs->if_type == IFT_MPLSTUNNEL) {
+                       /* Nothing needed */
+               }
+#endif /* NWIRE */
                else {
                        error = EINVAL;
                        break;
diff --git sys/net/if_wire.c sys/net/if_wire.c
new file mode 100644
index 0000000..b9301fc
--- /dev/null
+++ sys/net/if_wire.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2014 Rafael Zalamena <rzalam...@gmail.com>
+ *
+ * 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/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+
+#include <netinet/if_ether.h>
+#include <netmpls/mpls.h>
+
+#include "bpfilter.h"
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif /* NBPFILTER */
+
+
+void   wireattach(int);
+int    wire_clone_create(struct if_clone *, int);
+int    wire_clone_destroy(struct ifnet *);
+int    wire_ioctl(struct ifnet *, u_long, caddr_t);
+int    wire_output(struct ifnet *, struct mbuf *, struct sockaddr *,
+    struct rtentry *);
+void   wire_start(struct ifnet *);
+
+struct wire_softc {
+       struct          ifnet sc_if;
+       u_int32_t       sc_flags;
+       u_int32_t       sc_type;
+       struct          shim_hdr sc_lshim;
+       struct          shim_hdr sc_rshim;
+       struct          sockaddr sc_nexthop;
+
+       LIST_ENTRY(wire_softc) sc_list;
+};
+
+LIST_HEAD(, wire_softc) wire_list;
+
+struct if_clone wire_cloner =
+    IF_CLONE_INITIALIZER("wire", wire_clone_create, wire_clone_destroy);
+
+/* ARGSUSED */
+void
+wireattach(int n)
+{
+       LIST_INIT(&wire_list);
+       if_clone_attach(&wire_cloner);
+}
+
+int
+wire_clone_create(struct if_clone *ifc, int unit)
+{
+       struct  wire_softc *sc;
+       struct  ifnet *ifp;
+       int     s;
+
+       sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT | M_ZERO);
+       if (sc == NULL)
+               return (ENOMEM);
+
+       ifp = &sc->sc_if;
+       snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d",
+           ifc->ifc_name, unit);
+       ifp->if_softc = sc;
+       ifp->if_mtu = ETHERMTU;
+       ifp->if_flags = IFF_POINTOPOINT;
+       ifp->if_ioctl = wire_ioctl;
+       ifp->if_output = wire_output;
+       ifp->if_start = wire_start;
+       ifp->if_type = IFT_MPLSTUNNEL;
+       ifp->if_hdrlen = ETHER_HDR_LEN;
+       IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+       IFQ_SET_READY(&ifp->if_snd);
+
+       if_attach(ifp);
+       if_alloc_sadl(ifp);
+
+#if NBPFILTER > 0
+       bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, ETHER_HDR_LEN);
+#endif
+
+       s = splnet();
+       LIST_INSERT_HEAD(&wire_list, sc, sc_list);
+       splx(s);
+
+       return (0);
+}
+
+int
+wire_clone_destroy(struct ifnet *ifp)
+{
+       struct  wire_softc *sc = ifp->if_softc;
+       int     s;
+
+       ifp->if_flags &= ~IFF_RUNNING;
+
+       s = splnet();
+       LIST_REMOVE(sc, sc_list);
+       splx(s);
+
+       if_detach(ifp);
+       free(sc, M_DEVBUF, 0);
+
+       return (0);
+}
+
+int
+wire_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+       struct  ifreq *ifr = (struct ifreq *) data;
+       struct  ifwirereq iwr;
+       struct  wire_softc *sc;
+       int     error = 0, s;
+
+       s = splnet();
+       sc = ifp->if_softc;
+
+       switch (cmd) {
+       case SIOCSIFMTU:
+               if (ifr->ifr_mtu < MPE_MTU_MIN ||
+                   ifr->ifr_mtu > MPE_MTU_MAX)
+                       error = EINVAL;
+               else
+                       ifp->if_mtu = ifr->ifr_mtu;
+               break;
+
+       case SIOCSIFFLAGS:
+               if ((ifp->if_flags & IFF_UP))
+                       ifp->if_flags |= IFF_RUNNING;
+               else
+                       ifp->if_flags &= ~IFF_RUNNING;
+               break;
+
+       case SIOCSETWIRECFG:
+               error = suser(curproc, 0);
+               if (error != 0)
+                       break;
+
+               error = copyin(ifr->ifr_data, &iwr, sizeof(iwr));
+               if (error != 0)
+                       break;
+
+               /* Teardown all configuration if got no nexthop */
+               if (satosin(&iwr.iwr_nexthop)->sin_addr.s_addr == 0) {
+                       mpls_shim_set(ifp, &iwr.iwr_lshim, &sc->sc_lshim);
+                       bzero(&sc->sc_rshim, sizeof(sc->sc_rshim));
+                       bzero(&sc->sc_nexthop, sizeof(sc->sc_nexthop));
+                       sc->sc_flags = 0;
+                       sc->sc_type = 0;
+                       break;
+               }
+
+               /* Validate input */
+               if (satosin(&iwr.iwr_nexthop)->sin_family != AF_INET ||
+                   iwr.iwr_lshim.shim_label > MPLS_LABEL_MAX ||
+                   iwr.iwr_lshim.shim_label <= MPLS_LABEL_RESERVED_MAX ||
+                   iwr.iwr_rshim.shim_label > MPLS_LABEL_MAX ||
+                   iwr.iwr_rshim.shim_label <= MPLS_LABEL_RESERVED_MAX) {
+                       error = EINVAL;
+                       break;
+               }
+
+               /* Setup labels and create inbound route */
+               iwr.iwr_lshim.shim_label =
+                   htonl(iwr.iwr_lshim.shim_label << MPLS_LABEL_OFFSET);
+               iwr.iwr_rshim.shim_label =
+                   htonl(iwr.iwr_rshim.shim_label << MPLS_LABEL_OFFSET);
+
+               error = mpls_shim_set(ifp, &iwr.iwr_lshim, &sc->sc_lshim);
+               if (error != 0)
+                       break;
+
+               /* Apply configuration */
+               sc->sc_flags = iwr.iwr_flags;
+               sc->sc_type = iwr.iwr_type;
+               bcopy(&iwr.iwr_rshim, &sc->sc_rshim, sizeof(sc->sc_rshim));
+               sc->sc_rshim.shim_label |= MPLS_BOS_MASK;
+
+               bzero(&sc->sc_nexthop, sizeof(sc->sc_nexthop));
+               satosin(&sc->sc_nexthop)->sin_family =
+                   satosin(&iwr.iwr_nexthop)->sin_family;
+               satosin(&sc->sc_nexthop)->sin_len =
+                   sizeof(struct sockaddr_in);
+               satosin(&sc->sc_nexthop)->sin_addr.s_addr =
+                   satosin(&iwr.iwr_nexthop)->sin_addr.s_addr;
+               break;
+
+       case SIOCGETWIRECFG:
+               iwr.iwr_flags = sc->sc_flags;
+               iwr.iwr_type = sc->sc_type;
+               iwr.iwr_lshim.shim_label =
+                   ((ntohl(sc->sc_lshim.shim_label & MPLS_LABEL_MASK)) >>
+                       MPLS_LABEL_OFFSET);
+               iwr.iwr_rshim.shim_label =
+                   ((ntohl(sc->sc_rshim.shim_label & MPLS_LABEL_MASK)) >>
+                       MPLS_LABEL_OFFSET);
+               bcopy(&sc->sc_nexthop, &iwr.iwr_nexthop,
+                   sizeof(iwr.iwr_nexthop));
+
+               error = copyout(&iwr, ifr->ifr_data, sizeof(iwr));
+               break;
+
+       default:
+               error = ENOTTY;
+               break;
+       }
+       splx(s);
+       return (error);
+}
+
+void
+wire_input(struct ifnet *ifp, struct mbuf *m)
+{
+       struct ether_header *eh;
+       struct shim_hdr *shim;
+       struct wire_softc *sc;
+
+       sc = ifp->if_softc;
+       m->m_pkthdr.rcvif = ifp;
+       m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
+
+       if (sc->sc_flags & IWR_FLAG_CONTROLWORD) {
+               shim = mtod(m, struct shim_hdr *);
+               m_adj(m, MPLS_HDRLEN);
+
+               /*
+                * The first 4 bits identifies that this packet is a
+                * control word. If the control word is configured and
+                * we received an IP datagram we shall drop it.
+                */
+               if (shim->shim_label & CW_ZERO_MASK) {
+                       ifp->if_ierrors++;
+                       m_freem(m);
+                       return;
+               }
+
+               /* We don't support fragmentation just yet. */
+               if (shim->shim_label & CW_FRAG_MASK) {
+                       ifp->if_ierrors++;
+                       m_freem(m);
+                       return;
+               }
+       }
+
+#if NBPFILTER > 0
+       if (sc->sc_if.if_bpf)
+               bpf_mtap(sc->sc_if.if_bpf, m, BPF_DIRECTION_IN);
+#endif
+
+       eh = mtod(m, struct ether_header *);
+       m_adj(m, ETHER_HDR_LEN);
+
+       ether_input(ifp, eh, m);
+}
+
+int
+wire_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
+    struct rtentry *rt)
+{
+       int     error, s;
+
+       if ((ifp->if_flags & IFF_RUNNING) == 0) {
+               m_freem(m);
+               return (0);
+       }
+
+       s = splnet();
+       IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
+       if (error) {
+               splx(s);
+               ifp->if_oerrors++;
+               return (error);
+       }
+       splx(s);
+
+       if_start(ifp);
+
+       return (error);
+}
+
+void
+wire_start(struct ifnet *ifp)
+{
+       struct  mbuf *m;
+       struct  rtentry *rt;
+       struct  wire_softc *sc = ifp->if_softc;
+       struct  shim_hdr *shim;
+       struct  sockaddr sa;
+       int     s;
+
+       /* Generate destination address */
+       bzero(&sa, sizeof(sa));
+       bcopy(&sc->sc_nexthop, &sa, sizeof(sc->sc_nexthop));
+
+       /*
+        * XXX: lie about being MPLS, so mpls_output() get the TTL from
+        * the right place.
+        */
+       satosin(&sa)->sin_family = AF_MPLS;
+
+       for (;;) {
+               s = splnet();
+               IFQ_DEQUEUE(&ifp->if_snd, m);
+               splx(s);
+               if (m == NULL)
+                       return;
+
+               if ((ifp->if_flags & IFF_RUNNING) == 0) {
+                       m_freem(m);
+                       continue;
+               }
+
+#if NBPFILTER > 0
+               if (sc->sc_if.if_bpf)
+                       bpf_mtap(sc->sc_if.if_bpf, m, BPF_DIRECTION_OUT);
+#endif /* NBPFILTER */
+
+               rt = rtalloc1(&sc->sc_nexthop, RT_REPORT, 0);
+               if (rt == NULL) {
+                       m_freem(m);
+                       continue;
+               }
+
+               if (sc->sc_flags & IWR_FLAG_CONTROLWORD) {
+                       M_PREPEND(m, sizeof(*shim), M_NOWAIT);
+                       if (m == NULL) {
+                               RTFREE(rt);
+                               continue;
+                       }
+
+                       shim = mtod(m, struct shim_hdr *);
+                       bzero(shim, sizeof(*shim));
+               }
+
+               M_PREPEND(m, sizeof(*shim), M_NOWAIT);
+               if (m == NULL) {
+                       RTFREE(rt);
+                       continue;
+               }
+
+               shim = mtod(m, struct shim_hdr *);
+               bzero(shim, sizeof(*shim));
+               shim->shim_label |= htonl(mpls_defttl) & MPLS_TTL_MASK;
+               shim->shim_label |= sc->sc_rshim.shim_label;
+
+               /* XXX: MPLS only uses domain 0 */
+               m->m_pkthdr.ph_rtableid = 0;
+
+               mpls_output(rt->rt_ifp, m, &sa, rt);
+
+               RTFREE(rt);
+       }
+}
+
+int
+wire_label_exists(const struct shim_hdr *shim)
+{
+       struct  wire_softc *wr_sc;
+
+       LIST_FOREACH(wr_sc, &wire_list, sc_list)
+               if (shim->shim_label == wr_sc->sc_lshim.shim_label)
+                       return (1);
+
+       return (0);
+}
diff --git sys/netmpls/mpls.h sys/netmpls/mpls.h
index 0363d86..31ce94a 100644
--- sys/netmpls/mpls.h
+++ sys/netmpls/mpls.h
@@ -71,6 +71,9 @@ struct shim_hdr {
 #define MPLS_BOS_OFFSET                8
 #define MPLS_TTL_MASK          __MADDR(0x000000ffU)
 
+#define CW_ZERO_MASK           __MADDR(0xf0000000U)
+#define CW_FRAG_MASK           __MADDR(0x00300000U)
+
 #define MPLS_BOS_ISSET(l)      (((l) & MPLS_BOS_MASK) == MPLS_BOS_MASK)
 
 /* Reserved lavel values (RFC3032) */
@@ -140,6 +143,20 @@ struct rt_mpls {
        &mpls_mapttl_ip6 \
 }
 
+#define IWR_TYPE_NONE                  0
+#define IWR_TYPE_ETHERNET              1
+#define IWR_TYPE_ETHERNET_TAGGED       2
+
+#define IWR_FLAG_CONTROLWORD           0x1
+
+struct ifwirereq {
+       u_int32_t       iwr_flags;
+       u_int32_t       iwr_type; /* pseudowire type */
+       struct          shim_hdr iwr_lshim; /* local label */
+       struct          shim_hdr iwr_rshim; /* remote label */
+       struct          sockaddr iwr_nexthop;
+};
+
 #endif
 
 #ifdef _KERNEL
@@ -177,6 +194,8 @@ void        mpls_init(void);
 void   mplsintr(void);
 
 int             mpe_label_exists(const struct shim_hdr *);
+int             wire_label_exists(const struct shim_hdr *);
+void            wire_input(struct ifnet *, struct mbuf *);
 
 struct mbuf    *mpls_shim_pop(struct mbuf *);
 struct mbuf    *mpls_shim_swap(struct mbuf *, struct rt_mpls *);
diff --git sys/netmpls/mpls_input.c sys/netmpls/mpls_input.c
index 768de85..ff141e5 100644
--- sys/netmpls/mpls_input.c
+++ sys/netmpls/mpls_input.c
@@ -17,6 +17,7 @@
  */
 
 #include "mpe.h"
+#include "wire.h"
 
 #include <sys/param.h>
 #include <sys/mbuf.h>
@@ -236,6 +237,14 @@ do_v6:
                                /* redo lookup with next label */
                                break;
 
+                       ifp = rt->rt_ifp;
+#if NWIRE > 0
+                       if (ifp->if_type == IFT_MPLSTUNNEL) {
+                               wire_input(ifp, m);
+                               goto done;
+                       }
+#endif
+
                        if (!rt->rt_gateway) {
                                m_freem(m);
                                goto done;
@@ -278,6 +287,12 @@ do_v6:
                                goto done;
                        }
 #endif
+#if NWIRE > 0
+                       if (ifp->if_type == IFT_MPLSTUNNEL) {
+                               wire_input(ifp, m);
+                               goto done;
+                       }
+#endif
                        if (!rt->rt_gateway) {
                                m_freem(m);
                                goto done;
diff --git sys/netmpls/mpls_shim.c sys/netmpls/mpls_shim.c
index 3275dfb..2e6eb44 100644
--- sys/netmpls/mpls_shim.c
+++ sys/netmpls/mpls_shim.c
@@ -31,6 +31,7 @@
  */
 
 #include "mpe.h"
+#include "wire.h"
 
 #include <sys/param.h>
 #include <sys/mbuf.h>
@@ -110,6 +111,10 @@ mpls_shim_label_exists(const struct shim_hdr *shim)
        if (mpe_label_exists(shim))
                return (1);
 #endif /* NMPE */
+#if NWIRE > 0
+       if (wire_label_exists(shim))
+               return (1);
+#endif /* NWIRE */
 
        return (0);
 }
diff --git sys/sys/sockio.h sys/sys/sockio.h
index 625ee67..e81c6cf 100644
--- sys/sys/sockio.h
+++ sys/sys/sockio.h
@@ -190,6 +190,9 @@
 #define SIOCSLIFPHYTTL _IOW('i', 168, struct ifreq)    /* set tunnel ttl */
 #define SIOCGLIFPHYTTL _IOWR('i', 169, struct ifreq)   /* get tunnel ttl */
 
+#define SIOCSETWIRECFG _IOW('i', 170, struct ifreq) /* set wire config */
+#define SIOCGETWIRECFG _IOWR('i', 171, struct ifreq) /* get wire config */
+
 #define        SIOCSVH         _IOWR('i', 245, struct ifreq)   /* set carp 
param */
 #define        SIOCGVH         _IOWR('i', 246, struct ifreq)   /* get carp 
param */
 

Reply via email to