From: Nuno Antunes Date: Mon, 7 Jul 2008 22:02:10 +0000 (+0000) Subject: Introduce experimental MPLS over ethernet support. Add 'options MPLS' X-Git-Tag: v2.0.1~202 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/9b42cabedff59ea3b351e8eccb2da9bab5cefe7e Introduce experimental MPLS over ethernet support. Add 'options MPLS' 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@. --- diff --git a/etc/mtree/BSD.include.dist b/etc/mtree/BSD.include.dist index bdf5a2b060..01297fa661 100644 --- a/etc/mtree/BSD.include.dist +++ b/etc/mtree/BSD.include.dist @@ -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 diff --git a/include/Makefile b/include/Makefile index b8634fe9be..9603f3a0cc 100644 --- a/include/Makefile +++ b/include/Makefile @@ -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 diff --git a/sbin/route/keywords b/sbin/route/keywords index 9f51fc6a4e..342584d223 100644 --- a/sbin/route/keywords +++ b/sbin/route/keywords @@ -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 diff --git a/sbin/route/route.8 b/sbin/route/route.8 index 71b17ec10d..9feaf3f54f 100644 --- a/sbin/route/route.8 +++ b/sbin/route/route.8 @@ -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 diff --git a/sbin/route/route.c b/sbin/route/route.c index fa38522a68..41ad2c8b8a 100644 --- a/sbin/route/route.c +++ b/sbin/route/route.c @@ -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 @@ -55,6 +55,8 @@ #include #include +#include + #include #include #include @@ -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) diff --git a/sys/conf/files b/sys/conf/files index b031ad2987..1a15fcfa79 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -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 diff --git a/sys/conf/options b/sys/conf/options index 5ba6b50d3b..b364013824 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -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 diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 292a36291c..c1dea46a78 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -32,13 +32,14 @@ * * @(#)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 +#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) diff --git a/sys/net/netisr.h b/sys/net/netisr.h index b94e3e6a0e..2ef61f0718 100644 --- a/sys/net/netisr.h +++ b/sys/net/netisr.h @@ -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 */ diff --git a/sys/net/route.c b/sys/net/route.c index 569d817f6e..4e36c9c5d9 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -64,10 +64,11 @@ * * @(#)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 #include @@ -91,6 +92,10 @@ #include #include +#ifdef MPLS +#include +#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 /* diff --git a/sys/net/route.h b/sys/net/route.h index 467a9ebb30..70d91f1a15 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -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 #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]; diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c index bb574c0c27..c3641668d7 100644 --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -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 */ } diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index f0979adc18..f7b0de58b5 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -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 #include @@ -65,6 +66,8 @@ #include #include +#include + 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 index 0000000000..132d178b4e --- /dev/null +++ b/sys/netproto/mpls/mpls.h @@ -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 + +#include + +/* 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 index 0000000000..af3051a837 --- /dev/null +++ b/sys/netproto/mpls/mpls_demux.c @@ -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 +#include /* ncpus2_mask */ +#include + +#include + +#include + +#include +#include + +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 index 0000000000..78a5916664 --- /dev/null +++ b/sys/netproto/mpls/mpls_input.c @@ -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 +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +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 index 0000000000..1203ec6151 --- /dev/null +++ b/sys/netproto/mpls/mpls_output.c @@ -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 +#include +#include + +#include + +#include + +#include +#include + +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 index 0000000000..e60fbe9755 --- /dev/null +++ b/sys/netproto/mpls/mpls_proto.c @@ -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 +#include /* SYSINIT via DOMAIN_SET */ +#include +#include + +#include /* rn_inithead */ + +#include +#include + +/* 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 index 0000000000..1fc310b859 --- /dev/null +++ b/sys/netproto/mpls/mpls_var.h @@ -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 +#include +#include + +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_ */ diff --git a/sys/sys/mount.h b/sys/sys/mount.h index f145930f27..719267173a 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -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 -#define AF_MAX 34 /* XXX */ +#define AF_MAX 35 /* XXX */ /* * Network address lookup element diff --git a/sys/sys/socket.h b/sys/sys/socket.h index c30cbcc2d3..5ccdd2164c 100644 --- a/sys/sys/socket.h +++ b/sys/sys/socket.h @@ -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 diff --git a/usr.bin/netstat/route.c b/usr.bin/netstat/route.c index 95b0e62272..3d4fc49925 100644 --- a/usr.bin/netstat/route.c +++ b/usr.bin/netstat/route.c @@ -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 @@ -56,6 +56,8 @@ #include #endif +#include + #include #include @@ -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; irt_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); +}