Introduce experimental MPLS over ethernet support. Add 'options MPLS'
authorNuno Antunes <nant@dragonflybsd.org>
Mon, 7 Jul 2008 22:02:10 +0000 (22:02 +0000)
committerNuno Antunes <nant@dragonflybsd.org>
Mon, 7 Jul 2008 22:02:10 +0000 (22:02 +0000)
to the kernel config file to enable it. This modification increases
the footprint of each route in the FIB by 12 bytes, used to hold up
to 3 label operations per route.

Hints-from: Ayame, NiSTswitch implementations.
Reviewed-by: dillon@, sephe@, hsu@, hasso@.
22 files changed:
etc/mtree/BSD.include.dist
include/Makefile
sbin/route/keywords
sbin/route/route.8
sbin/route/route.c
sys/conf/files
sys/conf/options
sys/net/if_ethersubr.c
sys/net/netisr.h
sys/net/route.c
sys/net/route.h
sys/net/rtsock.c
sys/netinet/ip_output.c
sys/netproto/mpls/mpls.h [new file with mode: 0644]
sys/netproto/mpls/mpls_demux.c [new file with mode: 0644]
sys/netproto/mpls/mpls_input.c [new file with mode: 0644]
sys/netproto/mpls/mpls_output.c [new file with mode: 0644]
sys/netproto/mpls/mpls_proto.c [new file with mode: 0644]
sys/netproto/mpls/mpls_var.h [new file with mode: 0644]
sys/sys/mount.h
sys/sys/socket.h
usr.bin/netstat/route.c

index bdf5a2b..01297fa 100644 (file)
@@ -1,5 +1,5 @@
 # $FreeBSD: src/etc/mtree/BSD.include.dist,v 1.32.2.14 2003/01/24 09:47:07 roam Exp $
-# $DragonFly: src/etc/mtree/BSD.include.dist,v 1.27 2008/01/12 15:47:43 swildner Exp $
+# $DragonFly: src/etc/mtree/BSD.include.dist,v 1.28 2008/07/07 22:02:09 nant Exp $
 #
 # Please see the file src/etc/mtree/README before making changes to this file.
 #
@@ -63,6 +63,8 @@
         ..
         key
         ..
+        mpls
+        ..
         natm
         ..
         ncp
index b8634fe..9603f3a 100644 (file)
@@ -1,6 +1,6 @@
 #      @(#)Makefile    8.2 (Berkeley) 1/4/94
 # $FreeBSD: src/include/Makefile,v 1.109.2.27 2003/01/24 05:12:29 sam Exp $
-# $DragonFly: src/include/Makefile,v 1.38 2007/12/30 20:02:56 hasso Exp $
+# $DragonFly: src/include/Makefile,v 1.39 2008/07/07 22:02:09 nant Exp $
 #
 # Doing a make install builds /usr/include
 #
@@ -62,7 +62,7 @@ LSUBDIRS=     bus/cam bus/cam/scsi \
        netproto/atalk netproto/atm netproto/ipsec netproto/ipx \
        netproto/key netproto/natm netproto/ncp netproto/ns netproto/smb \
        netproto/atm/ipatm netproto/atm/sigpvc netproto/atm/spans \
-       netproto/atm/uni netproto/802_11
+       netproto/atm/uni netproto/802_11 netproto/mpls
 
 LSUBDIRS3= vfs/isofs/cd9660 net/i4b/include \
        dev/misc/lpt dev/netif/wi dev/video/bktr dev/video/meteor
index 9f51fc6..342584d 100644 (file)
@@ -1,6 +1,6 @@
 #      @(#)keywords    8.2 (Berkeley) 3/19/94
 # $FreeBSD: src/sbin/route/keywords,v 1.4.2.1 2001/10/02 10:04:01 ru Exp $
-# $DragonFly: src/sbin/route/keywords,v 1.3 2004/03/23 17:56:29 dillon Exp $
+# $DragonFly: src/sbin/route/keywords,v 1.4 2008/07/07 22:02:09 nant Exp $
 
 add
 atalk
@@ -29,15 +29,18 @@ lock
 lockrest
 mask
 monitor
+mpls
 mtu
 net
 netmask
 nostatic
 osi
+pop
 prefixlen
 proto1
 proto2
 proxy
+push
 recvpipe
 reject
 rtt
@@ -47,6 +50,7 @@ sendpipe
 show
 ssthresh
 static
+swap
 x25
 xns
 xresolve
index 71b17ec..9feaf3f 100644 (file)
@@ -31,7 +31,7 @@
 .\"
 .\"     @(#)route.8    8.3 (Berkeley) 3/19/94
 .\" $FreeBSD: src/sbin/route/route.8,v 1.17.2.9 2003/02/24 00:56:43 trhodes Exp $
-.\" $DragonFly: src/sbin/route/route.8,v 1.5 2006/01/19 22:19:30 dillon Exp $
+.\" $DragonFly: src/sbin/route/route.8,v 1.6 2008/07/07 22:02:09 nant Exp $
 .\"
 .Dd June 8, 2001
 .Dt ROUTE 8
@@ -226,12 +226,14 @@ itself may be given, in which case the route remains valid even
 if the local or remote addresses change.
 .Pp
 The optional modifiers
+.Fl mpls ,
 .Fl xns ,
 .Fl osi ,
 .Fl atalk ,
 and
 .Fl link
 specify that all subsequent addresses are in the
+.Tn MPLS ,
 .Tn XNS ,
 .Tn OSI ,
 or
@@ -350,6 +352,71 @@ If this lookup fails,
 .Xr getnetbyname 3
 is then used to interpret the name as that of a network.
 .Pp
+The optional
+.Fl push ,
+.Fl pop ,
+and
+.Fl swap
+modifiers may be used to specify the desired mpls label
+operations for the route. Each route may have up to 3
+label operations assigned to it. The label operations
+may be combined between them, but specifically the
+.Fl push
+and
+.Fl pop
+operations may be repeated if the intent is to push or pop
+more than one label at once. The
+.Fl swap
+operation always swaps the outer label and may not be
+repeated. 
+Here are some MPLS route examples:
+.Pp
+Add an normal inet route, but push an mpls
+.Ar label
+to the packet:
+.Pp
+.Bd -ragged -offset indent -compact
+.Nm
+.Cm add
+.Ar destination gateway
+.Fl push
+.Ar label
+.Ed
+.Pp
+Add an normal inet route, but double-push an mpls
+.Ar inner-label
+and an
+.Ar outer-label
+to the packet:
+.Pp
+.Bd -ragged -offset indent -compact
+.Nm
+.Cm add
+.Ar destination gateway
+.Fl push
+.Ar inner-label
+.Fl push
+.Ar outer-label
+.Ed
+.Pp
+Add an mpls route for an
+.Ar incoming-label
+to be forwarded to
+.Ar gateway
+and swap that label with
+.Ar new-label :
+.Pp
+.Bd -ragged -offset indent -compact
+.Nm
+.Cm add
+.Fl mpls
+.Ar incoming-label
+.Fl inet
+.Ar gateway
+.Fl swap
+.Ar new-label
+.Ed
+.Pp
 The
 .Nm
 utility uses a routing socket and the new message types
index fa38522..41ad2c8 100644 (file)
@@ -33,7 +33,7 @@
  * @(#) Copyright (c) 1983, 1989, 1991, 1993 The Regents of the University of California.  All rights reserved.
  * @(#)route.c 8.6 (Berkeley) 4/28/95
  * $FreeBSD: src/sbin/route/route.c,v 1.40.2.11 2003/02/27 23:10:10 ru Exp $
- * $DragonFly: src/sbin/route/route.c,v 1.16 2007/09/10 15:13:55 dillon Exp $
+ * $DragonFly: src/sbin/route/route.c,v 1.17 2008/07/07 22:02:09 nant Exp $
  */
 
 #include <sys/param.h>
@@ -55,6 +55,8 @@
 #include <arpa/inet.h>
 #include <netdb.h>
 
+#include <netproto/mpls/mpls.h>
+
 #include <ctype.h>
 #include <err.h>
 #include <errno.h>
@@ -79,10 +81,12 @@ union       sockunion {
 #ifdef NS
        struct  sockaddr_ns sns;
 #endif
+       struct  sockaddr_mpls smpls;
        struct  sockaddr_dl sdl;
        struct  sockaddr_inarp sinarp;
        struct  sockaddr_storage ss; /* added to avoid memory overrun */
-} so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
+} so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp, so_mpls1,
+       so_mpls2, so_mpls3;
 
 typedef union sockunion *sup;
 
@@ -96,6 +100,7 @@ static int   s;
 static int     forcehost, forcenet, af, qflag, tflag;
 static int     iflag, verbose, aflen = sizeof(struct sockaddr_in);
 static int     locking, lockrest, debugonly;
+static int     mplsop, popcount, pushcount, swapcount;
 static u_long  rtm_inits;
 static uid_t   uid;
 #ifdef NS
@@ -254,6 +259,9 @@ flushroutes(int argc, char **argv)
                        case K_LINK:
                                af = AF_LINK;
                                break;
+                       case K_MPLS:
+                               af = AF_MPLS;
+                               break;
                        default:
                                goto bad;
                } else
@@ -740,6 +748,64 @@ newroute(int argc, char **argv)
                                        ishost = 0;
                                }
                                break;
+                       case K_MPLS:
+                               af = AF_MPLS;
+                               aflen = sizeof(struct sockaddr_mpls);
+                               break;
+                       case K_POP:
+                               flags |= RTF_MPLSOPS;
+                               af = AF_MPLS;
+                               mplsop = MPLSLOP_POP;
+                               switch(++popcount){
+                                       case 1:
+                                               getaddr(RTA_MPLS1, "", 0);
+                                               break;
+                                       case 2:
+                                               getaddr(RTA_MPLS2, "", 0);
+                                               break;
+                                       case 3:
+                                               getaddr(RTA_MPLS3, "", 0);
+                                               break;
+                               }
+                               break;
+                       case K_PUSH:
+                       case K_SWAP:
+                               if (popcount > 0) {
+                                       warnx("Push or swap after pop. Ignoring.");
+                                       break;
+                               }
+                               if (key == K_PUSH) {
+                                       mplsop = MPLSLOP_PUSH;
+                                       ++pushcount;
+                               } else {
+                                       if (pushcount > 0) {
+                                               warnx("Swap after push. Ignoring.");
+                                               break;
+                                       }
+                                       if (swapcount > 0) {
+                                               warnx("Too many swaps. Ignoring.");
+                                               break;
+                                       }
+                                       mplsop = MPLSLOP_SWAP;
+                                       ++swapcount;
+                               }
+                               flags |= RTF_MPLSOPS;
+                               af = AF_MPLS;
+                               aflen = sizeof(struct sockaddr_mpls);
+                               if (--argc == 0)
+                                       usage((char *)NULL);
+                               switch(pushcount + swapcount){
+                                       case 1:
+                                               getaddr(RTA_MPLS1, *++argv, 0);
+                                               break;
+                                       case 2:
+                                               getaddr(RTA_MPLS2, *++argv, 0);
+                                               break;
+                                       case 3:
+                                               getaddr(RTA_MPLS3, *++argv, 0);
+                                               break;
+                               }
+                               break;
                        case K_MTU:
                        case K_HOPCOUNT:
                        case K_EXPIRE:
@@ -993,6 +1059,15 @@ getaddr(int which, char *str, struct hostent **hpp)
        case RTA_IFA:
                su = &so_ifa;
                break;
+       case RTA_MPLS1:
+               su = &so_mpls1;
+               break;
+       case RTA_MPLS2:
+               su = &so_mpls2;
+               break;
+       case RTA_MPLS3:
+               su = &so_mpls3;
+               break;
        default:
                usage("internal error");
                /*NOTREACHED*/
@@ -1069,7 +1144,6 @@ getaddr(int which, char *str, struct hostent **hpp)
                return(!ns_nullhost(su->sns.sns_addr));
 #endif
 
-
        case AF_APPLETALK:
                if (!atalk_aton(str, &su->sat.sat_addr))
                        errx(EX_NOHOST, "bad address: %s", str);
@@ -1080,12 +1154,28 @@ getaddr(int which, char *str, struct hostent **hpp)
                link_addr(str, &su->sdl);
                return(1);
 
-
        case PF_ROUTE:
                su->sa.sa_len = sizeof(*su);
                sockaddr(str, &su->sa);
                return(1);
 
+       case AF_MPLS:
+       {
+               mpls_label_t label;
+
+               bzero(su, sizeof(*su));
+               su->sa.sa_len = sizeof(*su);
+               su->sa.sa_family = AF_MPLS;
+               su->smpls.smpls_op = mplsop;
+               if (mplsop != MPLSLOP_POP && mplsop != MPLSLOP_POPALL &&
+                   *str != '\0') {
+                       if (sscanf(str, "%u", &label) != 1)
+                               errx(EX_NOHOST, "bad address: %s", str);
+                       su->smpls.smpls_label = htonl(label);
+               }
+               return(1);
+       }
+
        case AF_INET:
        default:
                break;
@@ -1327,6 +1417,9 @@ rtmsg(int cmd, int flags)
        NEXTADDR(RTA_GENMASK, so_genmask);
        NEXTADDR(RTA_IFP, so_ifp);
        NEXTADDR(RTA_IFA, so_ifa);
+       NEXTADDR(RTA_MPLS1, so_mpls1);
+       NEXTADDR(RTA_MPLS2, so_mpls2);
+       NEXTADDR(RTA_MPLS3, so_mpls3);
        rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
        if (verbose)
                print_rtmsg(&rtm, l);
@@ -1418,7 +1511,8 @@ char ifnetflags[] =
 "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
 "\017LINK2\020MULTICAST";
 char addrnames[] =
-"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
+"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD"
+"\011MPLS1\012MPLS2\013MPLS3";
 
 static void
 print_rtmsg(struct rt_msghdr *rtm, int msglen __unused)
index b031ad2..1a15fcf 100644 (file)
@@ -1,5 +1,5 @@
 # $FreeBSD: src/sys/conf/files,v 1.340.2.137 2003/06/04 17:10:30 sam Exp $
-# $DragonFly: src/sys/conf/files,v 1.221 2008/06/28 17:59:46 dillon Exp $
+# $DragonFly: src/sys/conf/files,v 1.222 2008/07/07 22:02:09 nant Exp $
 #
 # The long compile-with and dependency lines are required because of
 # limitations in config: backslash-newline doesn't work in strings, and
@@ -1104,6 +1104,10 @@ netproto/key/key.c               optional ipsec
 netproto/key/key_debug.c       optional ipsec
 netproto/key/keydb.c           optional ipsec
 netproto/key/keysock.c         optional ipsec
+netproto/mpls/mpls_demux.c     optional mpls
+netproto/mpls/mpls_input.c     optional mpls
+netproto/mpls/mpls_output.c    optional mpls
+netproto/mpls/mpls_proto.c     optional mpls
 netproto/natm/natm.c           optional natm
 netproto/natm/natm_pcb.c       optional natm
 netproto/natm/natm_proto.c     optional natm
index 5ba6b50..b364013 100644 (file)
@@ -1,5 +1,5 @@
 # $FreeBSD: src/sys/conf/options,v 1.191.2.53 2003/06/04 17:56:58 sam Exp $
-# $DragonFly: src/sys/conf/options,v 1.90 2008/06/26 23:24:11 dillon Exp $
+# $DragonFly: src/sys/conf/options,v 1.91 2008/07/07 22:02:09 nant Exp $
 #
 #        On the handling of kernel options
 #
@@ -303,6 +303,7 @@ IPX                 opt_ipx.h
 IPXIP                  opt_ipx.h
 IPTUNNEL               opt_ipx.h
 LIBMCHAIN
+MPLS                   opt_mpls.h
 NCP                    opt_ncp.h
 NETATALK               opt_atalk.h
 NS                     opt_ns.h
index 292a362..c1dea46 100644 (file)
  *
  *     @(#)if_ethersubr.c      8.1 (Berkeley) 6/10/93
  * $FreeBSD: src/sys/net/if_ethersubr.c,v 1.70.2.33 2003/04/28 15:45:53 archie Exp $
- * $DragonFly: src/sys/net/if_ethersubr.c,v 1.74 2008/06/25 11:45:07 sephe Exp $
+ * $DragonFly: src/sys/net/if_ethersubr.c,v 1.75 2008/07/07 22:02:10 nant Exp $
  */
 
 #include "opt_atalk.h"
 #include "opt_inet.h"
 #include "opt_inet6.h"
 #include "opt_ipx.h"
+#include "opt_mpls.h"
 #include "opt_netgraph.h"
 #include "opt_carp.h"
 #include "opt_ethernet.h"
@@ -111,6 +112,10 @@ extern u_char      at_org_code[3];
 extern u_char  aarp_org_code[3];
 #endif /* NETATALK */
 
+#ifdef MPLS
+#include <netproto/mpls/mpls.h>
+#endif
+
 /* netgraph node hooks for ng_ether(4) */
 void   (*ng_ether_input_p)(struct ifnet *ifp, struct mbuf **mp);
 void   (*ng_ether_input_orphan_p)(struct ifnet *ifp,
@@ -302,6 +307,33 @@ ether_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
                if (bcmp(edst, &ns_broadhost, ETHER_ADDR_LEN) == 0)
                        m->m_flags |= M_BCAST;
                break;
+#endif
+#ifdef MPLS
+       case AF_MPLS:
+       {
+               struct sockaddr *sa_gw;
+
+               if (rt)
+                       sa_gw = (struct sockaddr *)rt->rt_gateway;
+               else {
+                       /* We realy need a gateway. */
+                       m_freem(m);
+                       return (0);
+               }
+
+               switch (sa_gw->sa_family) {
+                       case AF_INET:
+                               if (!arpresolve(ifp, rt, m, sa_gw, edst))
+                                       return (0);
+                               break;
+                       default:
+                               kprintf("ether_output: address family not supported to forward mpls packets: %d.\n", sa_gw->sa_family);
+                               m_freem(m);
+                               return (0);
+               }
+               eh->ether_type = htons(ETHERTYPE_MPLS); /* XXX how about multicast? */
+               break;
+       }
 #endif
        case pseudo_AF_HDRCMPLT:
        case AF_UNSPEC:
@@ -788,6 +820,13 @@ post_stats:
                break;
 #endif
 
+#ifdef MPLS
+       case ETHERTYPE_MPLS:
+       case ETHERTYPE_MPLS_MCAST:
+               isr = NETISR_MPLS;
+               break;
+#endif
+
        default:
 #ifdef IPX
                if (ef_inputp && ef_inputp(ifp, &save_eh, m) == 0)
index b94e3e6..2ef61f0 100644 (file)
@@ -65,7 +65,7 @@
  *
  *     @(#)netisr.h    8.1 (Berkeley) 6/10/93
  * $FreeBSD: src/sys/net/netisr.h,v 1.21.2.5 2002/02/09 23:02:39 luigi Exp $
- * $DragonFly: src/sys/net/netisr.h,v 1.33 2008/06/23 11:57:19 sephe Exp $
+ * $DragonFly: src/sys/net/netisr.h,v 1.34 2008/07/07 22:02:10 nant Exp $
  */
 
 #ifndef _NET_NETISR_H_
@@ -93,6 +93,7 @@
 #define        NETISR_ATALK2   16              /* Appletalk phase 2 */
 #define        NETISR_ATALK1   17              /* Appletalk phase 1 */
 #define        NETISR_ARP      18              /* same as AF_LINK */
+#define        NETISR_MPLS     21              /* MPLS */
 #define        NETISR_IPX      23              /* same as AF_IPX */
 #define        NETISR_USB      25              /* USB soft interrupt */
 #define        NETISR_PPP      27              /* PPP soft interrupt */
index 569d817..4e36c9c 100644 (file)
  *
  *     @(#)route.c     8.3 (Berkeley) 1/9/95
  * $FreeBSD: src/sys/net/route.c,v 1.59.2.10 2003/01/17 08:04:00 ru Exp $
- * $DragonFly: src/sys/net/route.c,v 1.34 2008/06/05 15:29:47 sephe Exp $
+ * $DragonFly: src/sys/net/route.c,v 1.35 2008/07/07 22:02:10 nant Exp $
  */
 
 #include "opt_inet.h"
+#include "opt_mpls.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/msgport2.h>
 #include <net/netmsg2.h>
 
+#ifdef MPLS
+#include <netproto/mpls/mpls.h>
+#endif
+
 static struct rtstatistics rtstatistics_percpu[MAXCPU];
 #ifdef SMP
 #define rtstat rtstatistics_percpu[mycpuid]
@@ -113,6 +118,8 @@ static void rtredirect_msghandler(struct netmsg *netmsg);
 static void rtrequest1_msghandler(struct netmsg *netmsg);
 #endif
 
+static int rt_setshims(struct rtentry *, struct sockaddr **);
+
 SYSCTL_NODE(_net, OID_AUTO, route, CTLFLAG_RW, 0, "Routing");
 
 #ifdef ROUTE_DEBUG
@@ -846,6 +853,9 @@ rtrequest1(int req, struct rt_addrinfo *rtinfo, struct rtentry **ret_nrt)
                rtinfo->rti_info[RTAX_GATEWAY] = rt->rt_gateway;
                if ((rtinfo->rti_info[RTAX_NETMASK] = rt->rt_genmask) == NULL)
                        rtinfo->rti_flags |= RTF_HOST;
+               rtinfo->rti_info[RTAX_MPLS1] = rt->rt_shim[0];
+               rtinfo->rti_info[RTAX_MPLS2] = rt->rt_shim[1];
+               rtinfo->rti_info[RTAX_MPLS3] = rt->rt_shim[2];
                goto makeroute;
 
        case RTM_ADD:
@@ -876,6 +886,9 @@ makeroute:
                else
                        bcopy(dst, ndst, dst->sa_len);
 
+               if (rtinfo->rti_info[RTAX_MPLS1] != NULL)
+                       rt_setshims(rt, rtinfo->rti_info);
+
                /*
                 * Note that we now have a reference to the ifa.
                 * This moved from below so that rnh->rnh_addaddr() can
@@ -1276,6 +1289,25 @@ rt_llroute(struct sockaddr *dst, struct rtentry *rt0, struct rtentry **drt)
        return 0;
 }
 
+static int
+rt_setshims(struct rtentry *rt, struct sockaddr **rt_shim){
+       int i;
+       
+       for (i=0; i<3; i++) {
+               struct sockaddr *shim = rt_shim[RTAX_MPLS1 + i];
+               int shimlen;
+
+               if (shim == NULL)
+                       break;
+
+               shimlen = ROUNDUP(shim->sa_len);
+               R_Malloc(rt->rt_shim[i], struct sockaddr_mpls *, shimlen);
+               bcopy(shim, rt->rt_shim[i], shimlen);
+       }
+
+       return 0;
+}
+
 #ifdef ROUTE_DEBUG
 
 /*
index 467a9eb..70d91f1 100644 (file)
@@ -64,7 +64,7 @@
  *
  *     @(#)route.h     8.4 (Berkeley) 1/9/95
  * $FreeBSD: src/sys/net/route.h,v 1.36.2.5 2002/02/01 11:48:01 ru Exp $
- * $DragonFly: src/sys/net/route.h,v 1.22 2008/06/05 15:29:47 sephe Exp $
+ * $DragonFly: src/sys/net/route.h,v 1.23 2008/07/07 22:02:10 nant Exp $
  */
 
 #ifndef _NET_ROUTE_H_
@@ -80,7 +80,6 @@
 #include <sys/socket.h>
 #endif
 
-
 /*
  * Kernel resident routing tables.
  *
@@ -161,6 +160,7 @@ struct rtentry {
                                        /* output routine for this (rt,if) */
        struct  rtentry *rt_parent;     /* cloning parent of this route */
        int     rt_cpuid;               /* owner cpu */
+       struct  sockaddr *rt_shim[3];   /* mpls label / operation array */
 };
 
 /*
@@ -203,7 +203,8 @@ struct ortentry {
 #define        RTF_LOCAL       0x200000        /* route represents a local address */
 #define        RTF_BROADCAST   0x400000        /* route represents a bcast address */
 #define        RTF_MULTICAST   0x800000        /* route represents a mcast address */
-                                       /* 0x1000000 and up unassigned */
+#define        RTF_MPLSOPS     0x1000000       /* route uses mpls label operations */
+                                       /* 0x2000000 and up unassigned */
 
 /*
  * Routing statistics.
@@ -233,7 +234,7 @@ struct rt_msghdr {
        struct  rt_metrics rtm_rmx; /* metrics themselves */
 };
 
-#define RTM_VERSION    5       /* Up the ante and ignore older versions */
+#define RTM_VERSION    6       /* Up the ante and ignore older versions */
 
 /*
  * Message types.
@@ -280,6 +281,9 @@ struct rt_msghdr {
 #define RTA_IFA                0x20    /* interface addr sockaddr present */
 #define RTA_AUTHOR     0x40    /* sockaddr for author of redirect */
 #define RTA_BRD                0x80    /* for NEWADDR, broadcast or p-p dest addr */
+#define RTA_MPLS1      0x100   /* mpls label and/or operation present */
+#define RTA_MPLS2      0x200   /* mpls label and/or operation present */
+#define RTA_MPLS3      0x400   /* mpls label and/or operation present */
 
 /*
  * Index offsets for sockaddr array for alternate internal encoding.
@@ -292,7 +296,10 @@ struct rt_msghdr {
 #define RTAX_IFA       5       /* interface addr sockaddr present */
 #define RTAX_AUTHOR    6       /* sockaddr for author of redirect */
 #define RTAX_BRD       7       /* for NEWADDR, broadcast or p-p dest addr */
-#define RTAX_MAX       8       /* size of array to allocate */
+#define RTAX_MPLS1     8       /* mpls label and/or operation present */
+#define RTAX_MPLS2     9       /* mpls label and/or operation present */
+#define RTAX_MPLS3     10      /* mpls label and/or operation present */
+#define RTAX_MAX       11      /* size of array to allocate */
 
 struct rt_addrinfo {
        int              rti_addrs;
@@ -312,6 +319,9 @@ struct rt_addrinfo {
 #define        rti_ifaaddr     rti_info[RTAX_IFA]
 #define        rti_author      rti_info[RTAX_AUTHOR]
 #define        rti_bcastaddr   rti_info[RTAX_BRD]
+#define        rti_mpls1       rti_info[RTAX_MPLS1]
+#define        rti_mpls2       rti_info[RTAX_MPLS2]
+#define        rti_mpls3       rti_info[RTAX_MPLS3]
 
 extern struct radix_node_head *rt_tables[MAXCPU][AF_MAX+1];
 extern struct lwkt_port *rt_ports[MAXCPU];
index bb574c0..c364166 100644 (file)
@@ -64,7 +64,7 @@
  *
  *     @(#)rtsock.c    8.7 (Berkeley) 10/12/95
  * $FreeBSD: src/sys/net/rtsock.c,v 1.44.2.11 2002/12/04 14:05:41 ru Exp $
- * $DragonFly: src/sys/net/rtsock.c,v 1.43 2008/03/07 11:34:19 sephe Exp $
+ * $DragonFly: src/sys/net/rtsock.c,v 1.44 2008/07/07 22:02:10 nant Exp $
  */
 
 #include "opt_sctp.h"
@@ -748,6 +748,7 @@ rt_xaddrs(char *cp, char *cplim, struct rt_addrinfo *rtinfo)
                        };
 
                        rtinfo->rti_info[i] = &sa_zero;
+                       kprintf("rtsock: received more addr bits than sockaddrs.\n");
                        return (0); /* should be EINVAL but for compat */
                }
 
index f0979ad..f7b0de5 100644 (file)
@@ -28,7 +28,7 @@
  *
  *     @(#)ip_output.c 8.3 (Berkeley) 1/21/94
  * $FreeBSD: src/sys/netinet/ip_output.c,v 1.99.2.37 2003/04/15 06:44:45 silby Exp $
- * $DragonFly: src/sys/netinet/ip_output.c,v 1.45 2008/06/17 20:50:11 aggelos Exp $
+ * $DragonFly: src/sys/netinet/ip_output.c,v 1.46 2008/07/07 22:02:10 nant Exp $
  */
 
 #define _IP_VHL
@@ -39,6 +39,7 @@
 #include "opt_ipfilter.h"
 #include "opt_ipsec.h"
 #include "opt_mbuf_stress_test.h"
+#include "opt_mpls.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -65,6 +66,8 @@
 #include <netinet/in_var.h>
 #include <netinet/ip_var.h>
 
+#include <netproto/mpls/mpls_var.h>
+
 static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options");
 
 #ifdef IPSEC
@@ -1021,6 +1024,13 @@ pass:
                        m->m_pkthdr.len = tmp;
                }
 #endif
+
+#ifdef MPLS
+               struct rtentry *send_route = ro->ro_rt; /* copy-in/copy-out parameter */
+
+               if (!mpls_output_process(ifp, m, &dst, send_route))
+                       goto done;
+#endif
                error = ifp->if_output(ifp, m, (struct sockaddr *)dst,
                                       ro->ro_rt);
                goto done;
@@ -1064,6 +1074,12 @@ pass:
                                ia->ia_ifa.if_opackets++;
                                ia->ia_ifa.if_obytes += m->m_pkthdr.len;
                        }
+#ifdef MPLS
+               struct rtentry *send_route = ro->ro_rt; /* copy-in/copy-out parameter */
+
+               if (!mpls_output_process(ifp, m, &dst, send_route))
+                       goto done;
+#endif
                        error = ifp->if_output(ifp, m, (struct sockaddr *)dst,
                                               ro->ro_rt);
                } else {
diff --git a/sys/netproto/mpls/mpls.h b/sys/netproto/mpls/mpls.h
new file mode 100644 (file)
index 0000000..132d178
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $DragonFly: src/sys/netproto/mpls/mpls.h,v 1.1 2008/07/07 22:02:10 nant Exp $
+ */
+
+#ifndef _NETMPLS_MPLS_H_
+#define _NETMPLS_MPLS_H_
+
+#include <arpa/inet.h>
+
+#include <sys/types.h>
+
+/* should any of the folowing be moved to sys/types.h? */
+typedef u_int32_t      mpls_label_t;
+typedef u_int8_t       mpls_exp_t;
+typedef u_int8_t       mpls_s_t;
+typedef u_int8_t       mpls_ttl_t;
+
+struct mpls {
+       u_int32_t       mpls_shim;
+};
+#define MPLS_LABEL_MASK                0xfffff000
+#define MPLS_EXP_MASK          0x00000e00
+#define MPLS_STACK_MASK                0x00000100
+#define MPLS_TTL_MASK          0x000000ff
+#define MPLS_LABEL(shim)       (((shim) & MPLS_LABEL_MASK) >> 12)
+#define MPLS_EXP(shim)         (((shim) & MPLS_EXP_MASK) >> 9)
+#define MPLS_STACK(shim)       (((shim) & MPLS_STACK_MASK) >> 8)
+#define MPLS_TTL(shim)         ((shim) & MPLS_TTL_MASK)
+#define MPLS_SET_LABEL(shim, x)                                        \
+               do {                                            \
+                       shim &= ~MPLS_LABEL_MASK;               \
+                       shim |= ((x) << 12) & MPLS_LABEL_MASK;  \
+               } while(0)
+#define MPLS_SET_EXP(shim, x)                                  \
+               do {                                            \
+                       shim &= ~MPLS_EXP_MASK;                 \
+                       shim |= ((x) << 9) & MPLS_EXP_MASK;     \
+               } while(0)
+#define MPLS_SET_STACK(shim, x)                                        \
+               do {                                            \
+                       shim &= ~MPLS_STACK_MASK;                       \
+                       shim |= ((x) << 8) & MPLS_STACK_MASK;   \
+               } while(0)
+#define MPLS_SET_TTL(shim, x)                                  \
+               do {                                            \
+                       shim &= ~MPLS_TTL_MASK;                 \
+                       shim |= (x) & MPLS_TTL_MASK;            \
+               } while(0)
+
+struct mpls_addr {
+       mpls_label_t    ma_label;
+};
+
+struct sockaddr_mpls {
+       u_int8_t                smpls_len;
+       u_int8_t                smpls_family;
+       u_int8_t                smpls_op;       /* label op. push, pop, swap */
+       mpls_exp_t              smpls_exp;
+       struct mpls_addr        smpls_addr;
+};
+#define        smpls_label     smpls_addr.ma_label
+
+#define MPLSLOP_PUSH   1
+#define MPLSLOP_POP    2
+#define MPLSLOP_SWAP   3
+#define MPLSLOP_POPALL 4
+
+#define MPLS_MAXLOPS   3
+
+/*
+ * Definitions for mpls sysctl operations.
+ */
+#define CTL_MPLSPROTO_NAMES {          \
+       { "mpls", CTLTYPE_NODE },       \
+       {0, 0}                          \
+}
+
+/*
+ * Names for MPLS sysctl objects.
+ */
+#define MPLSCTL_FORWARDING     1
+
+#endif /* _NETMPLS_MPLS_H_ */
+
diff --git a/sys/netproto/mpls/mpls_demux.c b/sys/netproto/mpls/mpls_demux.c
new file mode 100644 (file)
index 0000000..af3051a
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $DragonFly: src/sys/netproto/mpls/mpls_demux.c,v 1.1 2008/07/07 22:02:10 nant Exp $
+ */
+
+#include <sys/mbuf.h>
+#include <sys/systm.h>         /* ncpus2_mask */
+#include <sys/types.h>
+
+#include <net/netisr.h>
+
+#include <netinet/in_var.h>
+
+#include <netproto/mpls/mpls.h>
+#include <netproto/mpls/mpls_var.h>
+
+extern struct thread netisr_cpu[];
+
+static __inline int
+MPLSP_MPORT_HASH(mpls_label_t label, u_short if_index)
+{
+       /* Use low order byte (demux up to 256 cpus) */
+       KASSERT(ncpus2 < 256, ("need different hash function"));  /* XXX */
+#if BYTE_ORDER == LITTLE_ENDIAN
+       label &= 0x00ff0000;
+       label = label >> 16;
+#endif
+        return ((label ^ if_index) & ncpus2_mask);
+}
+
+boolean_t
+mpls_lengthcheck(struct mbuf **mp)
+{
+       struct mbuf *m = *mp;
+
+       /* The packet must be at least the size of an MPLS header. */
+       if (m->m_pkthdr.len < sizeof(struct mpls)) {
+               mplsstat.mplss_tooshort++;
+               m_free(m);
+               return FALSE;
+       }
+
+       /* The MPLS header must reside completely in the first mbuf. */
+       if (m->m_len < sizeof(struct mpls)) {
+               m = m_pullup(m, sizeof(struct mpls));
+               if (m == NULL) {
+                       mplsstat.mplss_toosmall++;
+                       return FALSE;
+               }
+       }
+
+       *mp = m;
+       return TRUE;
+}
+
+struct lwkt_port *
+mpls_mport(struct mbuf **mp)
+{
+       struct mbuf *m = *mp;
+       struct mpls *mpls;
+       mpls_label_t label;
+       struct ifnet *ifp;
+       int cpu;
+       lwkt_port_t port;
+
+       if (!mpls_lengthcheck(mp)) {
+               *mp = NULL;
+               return (NULL);
+       }
+
+       mpls = mtod(m, struct mpls *);
+
+       label = MPLS_LABEL(ntohl(mpls->mpls_shim));
+       ifp = m->m_pkthdr.rcvif;
+       cpu = MPLSP_MPORT_HASH(label, ifp->if_index);
+       port = &netisr_cpu[cpu].td_msgport;
+
+       return (port);
+}
+
+
diff --git a/sys/netproto/mpls/mpls_input.c b/sys/netproto/mpls/mpls_input.c
new file mode 100644 (file)
index 0000000..78a5916
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $DragonFly: src/sys/netproto/mpls/mpls_input.c,v 1.1 2008/07/07 22:02:10 nant Exp $
+ */
+
+#include <sys/globaldata.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+
+#include <net/if_var.h>
+#include <net/netisr.h>
+#include <net/route.h>
+
+#include <netproto/mpls/mpls.h>
+#include <netproto/mpls/mpls_var.h>
+
+struct mpls_stats      mplsstats_percpu[MAXCPU];
+struct route           mplsforward_rt[MAXCPU];
+
+int mplsforwarding = 1;
+/*
+SYSCTL_INT(_net_mpls, OID_AUTO, forwarding, CTLFLAG_RW,
+    &mplsforwarding, 0, "Enable MPLS forwarding between interfaces");
+*/
+
+static void    mpls_input_handler(struct netmsg *);
+static void    mpls_forward(struct mbuf *);
+
+void
+mpls_init(void)
+{
+#ifdef SMP
+       int cpu;
+#endif
+
+       /*
+        * Initialize MPLS statistics counters for each CPU.
+        *
+        */
+#ifdef SMP
+       for (cpu = 0; cpu < ncpus; ++cpu) {
+               bzero(&mplsstats_percpu[cpu], sizeof(struct mpls_stats));
+       }
+#else
+       bzero(&mplsstat, sizeof(struct mpls_stats));
+#endif
+
+       netisr_register(NETISR_MPLS, mpls_mport, mpls_input_handler);
+}
+
+static void
+mpls_input_handler(struct netmsg *msg0)
+{
+        struct mbuf *m = ((struct netmsg_packet *)msg0)->nm_packet;
+
+        mpls_input(m);
+}
+
+void
+mpls_input(struct mbuf *m)
+{
+       struct mpls *mpls = NULL;
+       mpls_label_t label;
+
+       M_ASSERTPKTHDR(m);
+
+       mplsstat.mplss_total++;
+
+       /* length checks already performed at mpls_demux() */
+       KASSERT(m->m_pkthdr.len >= sizeof(struct mpls),
+           ("mpls_input: mpls header too small"));
+       
+again:
+       if (m->m_len < sizeof(struct mpls)) {
+               m = m_pullup(m, sizeof(struct mpls));
+               if (m == NULL) {
+                       mplsstat.mplss_toosmall++;
+                       return;
+               }
+       }
+
+       mpls = mtod(m, struct mpls*);
+       label = MPLS_LABEL(ntohl(mpls->mpls_shim));
+       switch (label) {
+       case 0:
+               /* 
+                * Label 0: represents "IPv4 Explicit NULL Label".
+                */
+               if (MPLS_STACK(ntohl(mpls->mpls_shim))) {
+                       /* Decapsulate the ip datagram from the mpls frame. */
+                       m_adj(m, sizeof(struct mpls));
+/*
+                       ip_input(m);
+*/
+                       netisr_dispatch(NETISR_IP, m);
+                       return;
+               }
+               goto again; /* If not the bottom label, per RFC4182. */
+
+       case 1:
+               /*
+                * Label 1: represents "Router Alert Label" and is valid 
+                * anywhere except at the bottom of the stack.
+                */
+               break;
+
+       case 2:
+               /* 
+                * Label 2: represents "IPv6 Explicit NULL Label".
+                */
+               if (MPLS_STACK(ntohl(mpls->mpls_shim))) {
+                       /* Decapsulate the ip datagram from the mpls frame. */
+                       m_adj(m, sizeof(struct mpls));
+                       netisr_dispatch(NETISR_IPV6, m);
+                       return;
+               }
+               goto again; /* If not the bottom label, per RFC4182. */
+
+       case 3:
+               /*
+                * Label 3: represents the "Implicit NULL Label" and must not 
+                * appear on the wire.
+                */
+               break;
+       default:
+               /*
+                * Labels 4 - 15: reserved, drop them.
+                */
+               if (label <= 15) {
+                       mplsstat.mplss_reserved++;
+                       m_freem(m);
+                       return;
+               }
+               if (mplsforwarding) {
+                       mpls_forward(m);
+                       return;
+               } else {
+                       mplsstat.mplss_cantforward++;
+                       m_freem(m);
+                       return;
+               }
+       }
+
+       mplsstat.mplss_invalid++;
+       m_freem(m);
+}
+
+static void
+mpls_forward(struct mbuf *m)
+{
+       struct sockaddr_mpls *smpls;
+       struct mpls *mpls;
+       struct route *cache_rt = &mplsforward_rt[mycpuid];
+       mpls_label_t label;
+       struct ifnet *ifp;
+       struct sockaddr *dst;
+
+       KASSERT(m->m_len >= sizeof(struct mpls),
+           ("mpls_input: mpls header not in one mbuf"));
+
+       mpls = mtod(m, struct mpls *);
+       label = MPLS_LABEL(ntohl(mpls->mpls_shim));
+
+       smpls = (struct sockaddr_mpls *) &cache_rt->ro_dst;
+       if (cache_rt->ro_rt == NULL || smpls->smpls_label != label) {
+               if (cache_rt->ro_rt != NULL) {
+                       RTFREE(cache_rt->ro_rt);
+                       cache_rt->ro_rt = NULL;
+               }
+               smpls->smpls_family = AF_MPLS;
+               smpls->smpls_len = sizeof(struct sockaddr_mpls);
+               smpls->smpls_label = htonl(label);
+               rtalloc(cache_rt);
+               if (cache_rt->ro_rt == NULL) {
+                       /* route not found */
+                       return;
+               }
+       }
+
+       ifp = cache_rt->ro_rt->rt_ifp;
+       dst = cache_rt->ro_rt->rt_gateway;
+
+       if (mpls_output(ifp, m, dst, cache_rt->ro_rt) != 0)
+               m_freem(m);
+       else
+               mplsstat.mplss_forwarded++;
+}
diff --git a/sys/netproto/mpls/mpls_output.c b/sys/netproto/mpls/mpls_output.c
new file mode 100644 (file)
index 0000000..1203ec6
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $DragonFly: src/sys/netproto/mpls/mpls_output.c,v 1.1 2008/07/07 22:02:10 nant Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/systm.h>
+
+#include <net/if_var.h>
+
+#include <netinet/ip.h>
+
+#include <netproto/mpls/mpls.h>
+#include <netproto/mpls/mpls_var.h>
+
+static int mpls_push(struct mbuf **, mpls_label_t,
+                    mpls_s_t, mpls_exp_t, mpls_ttl_t);
+static int mpls_swap(struct mbuf *, mpls_label_t);
+static int mpls_pop(struct mbuf *, mpls_s_t *);
+
+int
+mpls_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
+            struct rtentry *rt)
+{
+       struct sockaddr_mpls *smpls = NULL;
+       int error=0, i;
+       struct sockaddr *sa = NULL;
+       mpls_s_t stackempty;
+       mpls_ttl_t ttl = 255;
+       struct ip *ip;
+
+       M_ASSERTPKTHDR(m);
+
+       KASSERT(ifp != NULL, ("mpls_output: ifp can't be NULL"));
+
+       /* Check if we are coming from an MPLS routing table lookup */
+       stackempty = rt_key(rt)->sa_family != AF_MPLS ? 1 : 0;
+       if (stackempty) {
+               switch (rt_key(rt)->sa_family) {
+               case AF_INET:
+                       ip = mtod(m, struct ip *);
+                       ttl = ip->ip_ttl;
+                       break;
+               }
+       }
+
+       for (i=0; i < MPLS_MAXLOPS && rt->rt_shim[i] != NULL; ++i) {
+               smpls = (struct sockaddr_mpls *)rt->rt_shim[i];
+               switch (smpls->smpls_op) {
+               case MPLSLOP_PUSH:
+                       error = mpls_push(&m,
+                                 ntohl(smpls->smpls_label),
+                                 (i==0 && dst->sa_family != AF_MPLS) ? 1 : 0,
+                                 0,
+                                 ttl);
+                       if (error)
+                               return (error);
+                       stackempty = 0;
+                       sa = (struct sockaddr *)smpls;
+                       break;
+               case MPLSLOP_SWAP:
+                       /*
+                        * Operation is only permmited if label stack
+                        * is not empty.
+                        */
+                       if (stackempty)
+                               return (ENOTSUP);
+                       error = mpls_swap(m, ntohl(smpls->smpls_label));
+                       if (error)
+                               return (error);
+                       sa = (struct sockaddr *)smpls;
+                       break;
+               case MPLSLOP_POP:
+                       /*
+                        * Operation is only permmited if label stack
+                        * is not empty.
+                        */
+                       if (stackempty)
+                               return (ENOTSUP);
+                       mpls_pop(m, &stackempty);
+                       /* If not bottom label */
+                       if (!stackempty)
+                               sa = (struct sockaddr *)smpls;
+                       else
+                               sa = dst;
+                       break;
+               default:
+                       /* Unknown label operation */
+                       return (ENOTSUP);
+               }
+       }
+       
+       error = (*ifp->if_output)(ifp, m, sa, rt);
+
+       return (error);
+}
+
+/*
+ * Returns FALSE if no further output processing required.
+ */
+boolean_t
+mpls_output_process(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
+                struct rtentry *rt)
+{
+       int error;
+
+       if (!(rt->rt_flags & RTF_MPLSOPS))
+               return TRUE;
+
+       error = mpls_output(ifp, m,
+                       (struct sockaddr *)dst,
+                       rt);
+       if (error)
+               return FALSE;
+
+       return TRUE;
+}
+
+static int
+mpls_push(struct mbuf **m, mpls_label_t label, mpls_s_t s, mpls_exp_t exp, mpls_ttl_t ttl) {
+       struct mpls *mpls;
+       u_int32_t buf = 0;      /* Silence warning */
+
+       M_PREPEND(*m, sizeof(struct mpls), MB_DONTWAIT);
+       if (*m == NULL)
+               return (ENOBUFS);
+
+       MPLS_SET_LABEL(buf, label);
+       MPLS_SET_STACK(buf, s);
+       MPLS_SET_EXP(buf, exp);
+       MPLS_SET_TTL(buf, ttl);
+       mpls = mtod(*m, struct mpls *);
+       mpls->mpls_shim = htonl(buf);
+       
+       return (0);
+}
+
+static int
+mpls_swap(struct mbuf *m, mpls_label_t label) {
+       struct mpls *mpls;
+       u_int32_t buf;
+       mpls_ttl_t ttl;
+
+       if (m->m_len < sizeof(struct mpls) &&
+          (m = m_pullup(m, sizeof(struct mpls))) == NULL)
+               return (ENOBUFS);
+
+       mpls = mtod(m, struct mpls *);
+       buf = ntohl(mpls->mpls_shim);
+       MPLS_SET_LABEL(buf, label);
+       ttl = MPLS_TTL(buf);
+       MPLS_SET_TTL(buf, --ttl); /* XXX tunnel mode: uniform, pipe, short pipe */
+       mpls->mpls_shim = htonl(buf);
+       
+       return (0);
+}
+
+static int
+mpls_pop(struct mbuf *m, mpls_s_t *sbit) {
+       struct mpls *mpls;
+       u_int32_t buf;
+
+       if (m->m_len < sizeof(struct mpls)) {
+               m = m_pullup(m, sizeof(struct mpls));
+               if (m == NULL)
+                       return (ENOBUFS);
+       }
+       mpls = mtod(m, struct mpls *);
+       buf = ntohl(mpls->mpls_shim);
+       *sbit = MPLS_STACK(buf);
+
+       m_adj(m, sizeof(struct mpls));
+
+       return (0);
+}
diff --git a/sys/netproto/mpls/mpls_proto.c b/sys/netproto/mpls/mpls_proto.c
new file mode 100644 (file)
index 0000000..e60fbe9
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $DragonFly: src/sys/netproto/mpls/mpls_proto.c,v 1.1 2008/07/07 22:02:10 nant Exp $
+ */
+
+#include <sys/domain.h>
+#include <sys/kernel.h>                /* SYSINIT via DOMAIN_SET */
+#include <sys/protosw.h>
+#include <sys/socket.h>
+
+#include <net/radix.h>         /* rn_inithead */
+
+#include <netproto/mpls/mpls.h>
+#include <netproto/mpls/mpls_var.h>
+
+/* forward declarations */
+static struct domain mplsdomain;
+static struct pr_usrreqs nousrreqs;  /* XXX use this for something */
+
+struct protosw mplssw[] = {
+{ 0,           &mplsdomain,    0,      0,
+  0,           0,              0,      0,
+  cpu0_soport,
+  mpls_init,   0,              0,      0,
+  &nousrreqs
+},
+{ SOCK_RAW,    &mplsdomain,    0,      PR_ATOMIC|PR_ADDR,
+  0,           0,              0,      0,
+  cpu0_soport,
+  0,           0,              0,      0,
+  &nousrreqs
+},
+};
+
+static struct  domain mplsdomain = {
+       AF_MPLS,                        /* dom_family */
+       "mpls",                         /* dom_name */
+       NULL,                           /* dom_init */
+       NULL,                           /* dom_externalize */
+       NULL,                           /* dom_dispose */
+       mplssw,                         /* dom_protosw */
+       &mplssw[sizeof(mplssw) / sizeof(mplssw[0])],
+                                       /* dom_protoswNPROTOSW */
+       SLIST_ENTRY_INITIALIZER,        /* dom_next */
+       rn_inithead,                    /* dom_rtattach */
+       32,                             /* dom_rtoffset */
+       sizeof(struct sockaddr_mpls),   /* dom_maxrtkey */
+       NULL,                           /* dom_ifattach */
+       NULL                            /* dom_ifdetach */
+};
+
+DOMAIN_SET(mpls);
+
+#if 0
+SYSCTL_NODE(_net,      PF_MPLS,        mpls,   CTLFLAG_RW,     0,
+       "MPLS Family");
+#endif
+
diff --git a/sys/netproto/mpls/mpls_var.h b/sys/netproto/mpls/mpls_var.h
new file mode 100644 (file)
index 0000000..1fc310b
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $DragonFly: src/sys/netproto/mpls/mpls_var.h,v 1.1 2008/07/07 22:02:10 nant Exp $
+ */
+
+#ifndef _NETMPLS_MPLS_VAR_H_
+#define _NETMPLS_MPLS_VAR_H_
+
+#include <sys/types.h>
+#include <net/route.h>
+#include <netproto/mpls/mpls.h>
+
+struct mpls_stats {
+       u_long  mplss_total;
+       u_long  mplss_tooshort;
+       u_long  mplss_toosmall;
+       u_long  mplss_invalid;
+       u_long  mplss_reserved;
+       u_long  mplss_cantforward;
+       u_long  mplss_forwarded;
+};
+
+#ifdef _KERNEL
+
+#if defined(SMP)
+#define mplsstat mplsstats_percpu[mycpuid]
+#else /* !SMP */
+#define mplsstat mplsstats_percpu[0]
+#endif
+
+extern struct mpls_stats  mplsstats_percpu[MAXCPU];
+
+void                   mpls_init(void);
+boolean_t              mpls_lengthcheck(struct mbuf **);
+struct lwkt_port *     mpls_mport(struct mbuf **);
+void                   mpls_input(struct mbuf *);
+int                    mpls_output(struct ifnet *, struct mbuf *,
+                                   struct sockaddr *,
+                                   struct rtentry *);
+boolean_t              mpls_output_process(struct ifnet *, struct mbuf *,
+                                           struct sockaddr *,
+                                           struct rtentry *);
+
+#endif /* _KERNEL */
+
+#endif /* _NETMPLS_MPLS_VAR_H_ */
index f145930..7192671 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)mount.h     8.21 (Berkeley) 5/20/95
  * $FreeBSD: src/sys/sys/mount.h,v 1.89.2.7 2003/04/04 20:35:57 tegge Exp $
- * $DragonFly: src/sys/sys/mount.h,v 1.45 2008/07/07 16:02:36 dillon Exp $
+ * $DragonFly: src/sys/sys/mount.h,v 1.46 2008/07/07 22:02:10 nant Exp $
  */
 
 #ifndef _SYS_MOUNT_H_
@@ -499,7 +499,7 @@ struct vfsops {
 
 #include <net/radix.h>
 
-#define        AF_MAX          34      /* XXX */
+#define        AF_MAX          35      /* XXX */
 
 /*
  * Network address lookup element
index c30cbcc..5ccdd21 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)socket.h    8.4 (Berkeley) 2/21/94
  * $FreeBSD: src/sys/sys/socket.h,v 1.39.2.7 2001/07/03 11:02:01 ume Exp $
- * $DragonFly: src/sys/sys/socket.h,v 1.21 2008/05/27 01:10:47 dillon Exp $
+ * $DragonFly: src/sys/sys/socket.h,v 1.22 2008/07/07 22:02:10 nant Exp $
  */
 
 #ifndef _SYS_SOCKET_H_
@@ -162,8 +162,9 @@ struct      accept_filter_arg {
                                         */
 #define        AF_NETGRAPH     32              /* Netgraph sockets */
 #define        AF_BLUETOOTH    33              /* Bluetooth */
+#define        AF_MPLS         34              /* Multi-Protocol Label Switching */
 
-#define        AF_MAX          34
+#define        AF_MAX          35
 
 /*
  * Structure used by kernel to store most
index 95b0e62..3d4fc49 100644 (file)
@@ -32,7 +32,7 @@
  *
  * @(#)route.c 8.6 (Berkeley) 4/28/95
  * $FreeBSD: src/usr.bin/netstat/route.c,v 1.41.2.14 2002/07/17 02:22:22 kbyanc Exp $
- * $DragonFly: src/usr.bin/netstat/route.c,v 1.12 2007/09/30 12:45:05 sephe Exp $
+ * $DragonFly: src/usr.bin/netstat/route.c,v 1.13 2008/07/07 22:02:10 nant Exp $
  */
 
 #include <sys/param.h>
@@ -56,6 +56,8 @@
 #include <netns/ns.h>
 #endif
 
+#include <netproto/mpls/mpls.h>
+
 #include <sys/sysctl.h>
 
 #include <arpa/inet.h>
@@ -103,6 +105,7 @@ struct bits {
        { RTF_PROTO3,   '3' },
        { RTF_BLACKHOLE,'B' },
        { RTF_BROADCAST,'b' },
+       { RTF_MPLSOPS,  'm' },
        { 0 }
 };
 
@@ -138,6 +141,7 @@ static const char *fmt_flags(int f);
 static void p_rtentry (struct rtentry *);
 static u_long forgemask (u_long);
 static void domask (char *, u_long, u_long);
+static const char *labelops(struct rtentry *);
 
 /*
  * Print routing tables.
@@ -221,6 +225,9 @@ pr_family(int af)
        case AF_NETGRAPH:
                afname = "Netgraph";
                break;
+       case AF_MPLS:
+               afname = "MPLS";
+               break;
        default:
                afname = NULL;
                break;
@@ -252,6 +259,7 @@ static int wid_use;
 static int wid_mtu;
 static int wid_if;
 static int wid_expire;
+static int wid_mplslops;
 
 static void
 size_cols(int ef, struct radix_node *rn)
@@ -264,6 +272,7 @@ size_cols(int ef, struct radix_node *rn)
        wid_mtu = 6;
        wid_if = WID_IF_DEFAULT(ef);
        wid_expire = 6;
+       wid_mplslops = 7;
 
        if (Wflag)
                size_cols_tree(rn);
@@ -297,7 +306,7 @@ size_cols_rtentry(struct rtentry *rt)
        const char *bp;
        struct sockaddr *sa;
        sa_u addr, mask;
-       int len;
+       int len, i;
 
        /*
         * Don't print protocol-cloned routes unless -a.
@@ -355,6 +364,9 @@ size_cols_rtentry(struct rtentry *rt)
                        }
                }
        }
+       if (rt->rt_shim[0] != NULL)
+               len = strlen(labelops(rt));
+       wid_mplslops = MAX(len, wid_mplslops);
 }
 
 
@@ -369,7 +381,7 @@ pr_rthdr(int af)
                printf("%-8.8s ","Address");
        if (af == AF_INET || Wflag) {
                if (Wflag) {
-                       printf("%-*.*s %-*.*s %-*.*s %*.*s %*.*s %*.*s %*.*s %*s\n",
+                       printf("%-*.*s %-*.*s %-*.*s %*.*s %*.*s %*.*s %*.*s %*s %-*s\n",
                                wid_dst,        wid_dst,        "Destination",
                                wid_gw,         wid_gw,         "Gateway",
                                wid_flags,      wid_flags,      "Flags",
@@ -377,7 +389,8 @@ pr_rthdr(int af)
                                wid_use,        wid_use,        "Use",
                                wid_mtu,        wid_mtu,        "Mtu",
                                wid_if,         wid_if,         "Netif",
-                               wid_expire,                     "Expire");
+                               wid_expire,                     "Expire",
+                               wid_mplslops,                   "Labelops");
                } else {
                        printf("%-*.*s %-*.*s %-*.*s %*.*s %*.*s %*.*s %*s\n",
                                wid_dst,        wid_dst,        "Destination",
@@ -687,6 +700,14 @@ fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags)
                break;
            }
 
+       case AF_MPLS:
+           {
+               struct sockaddr_mpls *smpls = (struct sockaddr_mpls *)sa;
+
+               (void) sprintf(workbuf, "%d", ntohl(smpls->smpls_label));
+               break;
+           }
+               
        default:
            {
                u_char *s = (u_char *)sa->sa_data, *slim;
@@ -778,10 +799,16 @@ p_rtentry(struct rtentry *rt)
                        if ((expire_time =
                            rt->rt_rmx.rmx_expire - time((time_t *)0)) > 0)
                                printf(" %*d", wid_expire, (int)expire_time);
+               } else {
+                       printf("%*s ", wid_expire, "");
                }
                if (rt->rt_nodes[0].rn_dupedkey)
                        printf(" =>");
        }
+       if (Wflag) {
+               if (rt->rt_shim[0] != NULL)
+                       printf(" %-*s", wid_mplslops, labelops(rt));
+       }
        putchar('\n');
 }
 
@@ -1197,3 +1224,40 @@ upHex(char *p0)
                        break;
                }
 }
+
+static const char *
+labelops(struct rtentry *rt)
+{
+       char *lops[] = { "push", "pop", "swap", "pop all" };
+       static char buffer[100];
+       char *cp = buffer;
+       struct sockaddr_mpls *smpls;
+       int i;
+
+       for (i=0; i<MPLS_MAXLOPS; ++i) {
+
+               if (rt->rt_shim[i] == NULL)
+                       break;
+               if (i>0) {
+                       cp += snprintf(cp,
+                                      sizeof(buffer) - (cp - buffer),
+                                      ", ");
+               }
+               smpls = (struct sockaddr_mpls *)kgetsa(rt->rt_shim[i]);
+               if (smpls->smpls_op != MPLSLOP_POP &&
+                   smpls->smpls_op != MPLSLOP_POPALL){
+                       cp += snprintf(cp,
+                                      sizeof(buffer) - (cp - buffer),
+                                      "%s %d",
+                                      lops[smpls->smpls_op - 1],
+                                      ntohl(smpls->smpls_label));
+               } else {
+                       cp += snprintf(cp,
+                                      sizeof(buffer) - (cp - buffer),
+                                      "%s",
+                                      lops[smpls->smpls_op - 1]);
+               }
+       }
+
+       return (buffer);
+}