Index: sys/sys/sockio.h =================================================================== RCS file: /cvs/src/sys/sys/sockio.h,v retrieving revision 1.74 diff -u -p -r1.74 sockio.h --- sys/sys/sockio.h 19 Feb 2018 00:21:31 -0000 1.74 +++ sys/sys/sockio.h 19 Feb 2018 04:37:57 -0000 @@ -194,6 +194,9 @@ #define SIOCSLIFPHYDF _IOW('i', 193, struct ifreq) /* set tunnel df/nodf */ #define SIOCGLIFPHYDF _IOWR('i', 194, struct ifreq) /* set tunnel df/nodf */ +#define SIOCSVNENTROPY _IOW('i', 195, struct ifreq) /* set vnetid entropy */ +#define SIOCGVNENTROPY _IOWR('i', 196, struct ifreq) /* get vnetid entropy */ + #define SIOCSVH _IOWR('i', 245, struct ifreq) /* set carp param */ #define SIOCGVH _IOWR('i', 246, struct ifreq) /* get carp param */ Index: sys/net/if.c =================================================================== RCS file: /cvs/src/sys/net/if.c,v retrieving revision 1.545 diff -u -p -r1.545 if.c --- sys/net/if.c 19 Feb 2018 00:24:48 -0000 1.545 +++ sys/net/if.c 19 Feb 2018 04:37:57 -0000 @@ -2119,6 +2119,7 @@ ifioctl(struct socket *so, u_long cmd, c case SIOCDELMULTI: case SIOCSIFMEDIA: case SIOCSVNETID: + case SIOCSVNENTROPY: case SIOCSIFPAIR: case SIOCSIFPARENT: case SIOCDIFPARENT: Index: sys/net/if_gre.c =================================================================== RCS file: /cvs/src/sys/net/if_gre.c,v retrieving revision 1.105 diff -u -p -r1.105 if_gre.c --- sys/net/if_gre.c 19 Feb 2018 00:46:27 -0000 1.105 +++ sys/net/if_gre.c 19 Feb 2018 04:37:57 -0000 @@ -142,6 +142,14 @@ union gre_addr { struct in6_addr in6; }; +#define GRE_KEY_MIN 0x00000000U +#define GRE_KEY_MAX 0xffffffffU +#define GRE_KEY_SHIFT 0 + +#define GRE_KEY_ENTROPY_MIN 0x00000000U +#define GRE_KEY_ENTROPY_MAX 0x00ffffffU +#define GRE_KEY_ENTROPY_SHIFT 8 + struct gre_tunnel { uint32_t t_key_mask; #define GRE_KEY_NONE htonl(0x00000000U) @@ -172,6 +180,9 @@ static int gre_set_vnetid(struct gre_tun static int gre_get_vnetid(struct gre_tunnel *, struct ifreq *); static int gre_del_vnetid(struct gre_tunnel *); +static int gre_set_vnentropy(struct gre_tunnel *, struct ifreq *); +static int gre_get_vnentropy(struct gre_tunnel *, struct ifreq *); + static struct mbuf * gre_encap(const struct gre_tunnel *, struct mbuf *, uint16_t, uint8_t, uint8_t); @@ -649,6 +660,11 @@ gre_input_key(struct mbuf **mp, int *off pf_pkt_addr_changed(m); #endif + if (sc->sc_tunnel.t_key_mask == GRE_KEY_ENTROPY) { + m->m_pkthdr.ph_flowid = M_FLOWID_VALID | + (bemtoh32(&key->t_key) & ~GRE_KEY_ENTROPY); + } + ifp->if_ipackets++; ifp->if_ibytes += m->m_pkthdr.len; @@ -709,6 +725,11 @@ egre_input(const struct gre_tunnel *key, pf_pkt_addr_changed(m); #endif + if (sc->sc_tunnel.t_key_mask == GRE_KEY_ENTROPY) { + m->m_pkthdr.ph_flowid = M_FLOWID_VALID | + (bemtoh32(&key->t_key) & ~GRE_KEY_ENTROPY); + } + ml_enqueue(&ml, m); if_input(&sc->sc_ac.ac_if, &ml); @@ -991,6 +1012,12 @@ gre_encap(const struct gre_tunnel *tunne gkh = (struct gre_h_key *)(gh + 1); gkh->gre_key = tunnel->t_key; + + if (tunnel->t_key_mask == GRE_KEY_ENTROPY && + ISSET(m->m_pkthdr.ph_flowid, M_FLOWID_VALID)) { + gkh->gre_key |= htonl(~GRE_KEY_ENTROPY & + (m->m_pkthdr.ph_flowid & M_FLOWID_MASK)); + } } switch (tunnel->t_af) { @@ -1101,6 +1128,14 @@ gre_tunnel_ioctl(struct ifnet *ifp, stru error = gre_del_vnetid(tunnel); break; + case SIOCSVNENTROPY: + error = gre_set_vnentropy(tunnel, ifr); + break; + + case SIOCGVNENTROPY: + error = gre_get_vnentropy(tunnel, ifr); + break; + case SIOCSLIFPHYADDR: error = gre_set_tunnel(tunnel, (struct if_laddrreq *)data); break; @@ -1248,6 +1283,7 @@ egre_ioctl(struct ifnet *ifp, u_long cmd case SIOCSVNETID: case SIOCDVNETID: + case SIOCSVNENTROPY: case SIOCSLIFPHYADDR: case SIOCDIFPHYADDR: case SIOCSLIFPHYRTABLE: @@ -1576,17 +1612,25 @@ static int gre_set_vnetid(struct gre_tunnel *tunnel, struct ifreq *ifr) { uint32_t key; + uint32_t min = GRE_KEY_MIN; + uint32_t max = GRE_KEY_MAX; + unsigned int shift = GRE_KEY_SHIFT; + uint32_t mask = GRE_KEY_MASK; + + if (tunnel->t_key_mask == GRE_KEY_ENTROPY) { + min = GRE_KEY_ENTROPY_MIN; + max = GRE_KEY_ENTROPY_MAX; + shift = GRE_KEY_ENTROPY_SHIFT; + mask = GRE_KEY_ENTROPY; + } - if (ifr->ifr_vnetid < 0 || ifr->ifr_vnetid > 0xffffffff) - return EINVAL; - - key = htonl(ifr->ifr_vnetid); + if (ifr->ifr_vnetid < min || ifr->ifr_vnetid > max) + return (EINVAL); - if (tunnel->t_key_mask == GRE_KEY_MASK && tunnel->t_key == key) - return (0); + key = htonl(ifr->ifr_vnetid << shift); /* commit */ - tunnel->t_key_mask = GRE_KEY_MASK; + tunnel->t_key_mask = mask; tunnel->t_key = key; return (0); @@ -1595,10 +1639,20 @@ gre_set_vnetid(struct gre_tunnel *tunnel static int gre_get_vnetid(struct gre_tunnel *tunnel, struct ifreq *ifr) { - if (tunnel->t_key_mask == GRE_KEY_NONE) + int shift; + + switch (tunnel->t_key_mask) { + case GRE_KEY_NONE: return (EADDRNOTAVAIL); + case GRE_KEY_ENTROPY: + shift = GRE_KEY_ENTROPY_SHIFT; + break; + case GRE_KEY_MASK: + shift = GRE_KEY_SHIFT; + break; + } - ifr->ifr_vnetid = (int64_t)ntohl(tunnel->t_key); + ifr->ifr_vnetid = ntohl(tunnel->t_key) >> shift; return (0); } @@ -1607,6 +1661,47 @@ static int gre_del_vnetid(struct gre_tunnel *tunnel) { tunnel->t_key_mask = GRE_KEY_NONE; + + return (0); +} + +static int +gre_set_vnentropy(struct gre_tunnel *tunnel, struct ifreq *ifr) +{ + uint32_t mask, key; + + if (tunnel->t_key_mask == GRE_KEY_NONE) + return (EADDRNOTAVAIL); + + mask = ifr->ifr_vnetid ? GRE_KEY_ENTROPY : GRE_KEY_MASK; + if (tunnel->t_key_mask == mask) { + /* nop */ + return (0); + } + + key = ntohl(tunnel->t_key); + if (mask == GRE_KEY_ENTROPY) { + if (key > GRE_KEY_ENTROPY_MAX) + return (ERANGE); + + key = htonl(key << GRE_KEY_ENTROPY_SHIFT); + } else + key = htonl(key >> GRE_KEY_ENTROPY_SHIFT); + + /* commit */ + tunnel->t_key_mask = mask; + tunnel->t_key = key; + + return (0); +} + +static int +gre_get_vnentropy(struct gre_tunnel *tunnel, struct ifreq *ifr) +{ + if (tunnel->t_key_mask == GRE_KEY_NONE) + return (EADDRNOTAVAIL); + + ifr->ifr_vnetid = tunnel->t_key_mask == GRE_KEY_ENTROPY; return (0); } Index: sbin/ifconfig/ifconfig.8 =================================================================== RCS file: /cvs/src/sbin/ifconfig/ifconfig.8,v retrieving revision 1.300 diff -u -p -r1.300 ifconfig.8 --- sbin/ifconfig/ifconfig.8 19 Feb 2018 00:23:57 -0000 1.300 +++ sbin/ifconfig/ifconfig.8 19 Feb 2018 04:37:57 -0000 @@ -1606,6 +1606,7 @@ for a complete list of the available pro .Op Oo Fl Oc Ns Cm tunneldf .Op Cm tunnelttl Ar ttl .Op Oo Fl Oc Ns Cm vnetid Ar network-id +.Op Oo Fl Oc Ns Cm vnentropy .Ek .nr nS 0 .Pp @@ -1681,6 +1682,14 @@ to accept packets with arbitrary network multipoint-to-multipoint modes). .It Cm -vnetid Clear the virtual network identifier. +.It Cm vnentropy +Enable splitting of the virtual network identifier space into a +network identifier and a flow identifier. +This may allow load balancing of the encapsulated traffic over +multiple links. +.It Cm -vnentropy +Enable splitting of the virtual network identifier space into a +network identifier and a flow identifier. .El .Sh UMB .nr nS 1 Index: sbin/ifconfig/ifconfig.c =================================================================== RCS file: /cvs/src/sbin/ifconfig/ifconfig.c,v retrieving revision 1.358 diff -u -p -r1.358 ifconfig.c --- sbin/ifconfig/ifconfig.c 19 Feb 2018 00:23:57 -0000 1.358 +++ sbin/ifconfig/ifconfig.c 19 Feb 2018 04:37:57 -0000 @@ -121,6 +121,23 @@ "\5VLAN_MTU\6VLAN_HWTAGGING\10CSUM_TCPv6" \ "\11CSUM_UDPv6\20WOL" +struct ifencap { + unsigned int ife_flags; +#define IFE_VNETID_MASK 0xf +#define IFE_VNETID_NOPE 0x0 +#define IFE_VNETID_NONE 0x1 +#define IFE_VNETID_ANY 0x2 +#define IFE_VNETID_SET 0x3 + int64_t ife_vnetid; +#define IFE_VNETID_ENTROPY 0x10 + +#define IFE_PARENT_MASK 0xf00 +#define IFE_PARENT_NOPE 0x000 +#define IFE_PARENT_NONE 0x100 +#define IFE_PARENT_SET 0x200 + char ife_parent[IFNAMSIZ]; +}; + struct ifreq ifr, ridreq; struct in_aliasreq in_addreq; struct in6_ifreq ifr6; @@ -252,6 +269,9 @@ void setpfsync_syncpeer(const char *, in void unsetpfsync_syncpeer(const char *, int); void setpfsync_defer(const char *, int); void pfsync_status(void); +void setvnentropy(const char *, int); +void delvnentropy(const char *, int); +void getvnentropy(struct ifencap *); void settunneldf(const char *, int); void settunnelnodf(const char *, int); void setpppoe_dev(const char *,int); @@ -438,6 +458,8 @@ const struct cmd { { "tunnelttl", NEXTARG, 0, settunnelttl }, { "tunneldf", 0, 0, settunneldf }, { "-tunneldf", 0, 0, settunnelnodf }, + { "vnentropy", 0, 0, setvnentropy }, + { "-vnentropy", 0, 0, delvnentropy }, { "pppoedev", NEXTARG, 0, setpppoe_dev }, { "pppoesvc", NEXTARG, 0, setpppoe_svc }, { "-pppoesvc", 1, 0, setpppoe_svc }, @@ -3312,6 +3334,40 @@ settunnelnodf(const char *ignored, int a } void +setvnentropy(const char *ignored, int alsoignored) +{ + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + ifr.ifr_vnetid = 1; + if (ioctl(s, SIOCSVNENTROPY, &ifr) < 0) + warn("SIOCSVNENTROPY"); +} + +/* ARGSUSED */ +void +delvnentropy(const char *ignored, int alsoignored) +{ + ifr.ifr_vnetid = 0; + if (ioctl(s, SIOCSVNENTROPY, &ifr) < 0) + warn("SIOCSVNENTROPY"); +} + +void +getvnentropy(struct ifencap *ife) +{ + if (strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)) >= + sizeof(ifr.ifr_name)) + errx(1, "vnentropy: name is too long"); + + if (ioctl(s, SIOCGVNENTROPY, &ifr) == -1) + return; + + if (ifr.ifr_vnetid) + ife->ife_flags |= IFE_VNETID_ENTROPY; +} + + +void mpe_status(void) { struct shim_hdr shim; @@ -3497,22 +3553,6 @@ setmpwcontrolword(const char *value, int } #endif /* SMALL */ -struct ifencap { - unsigned int ife_flags; -#define IFE_VNETID_MASK 0xf -#define IFE_VNETID_NOPE 0x0 -#define IFE_VNETID_NONE 0x1 -#define IFE_VNETID_ANY 0x2 -#define IFE_VNETID_SET 0x3 - int64_t ife_vnetid; - -#define IFE_PARENT_MASK 0xf0 -#define IFE_PARENT_NOPE 0x00 -#define IFE_PARENT_NONE 0x10 -#define IFE_PARENT_SET 0x20 - char ife_parent[IFNAMSIZ]; -}; - void setvnetid(const char *id, int param) { @@ -3564,6 +3604,12 @@ getvnetid(struct ifencap *ife) ife->ife_flags |= IFE_VNETID_SET; ife->ife_vnetid = ifr.ifr_vnetid; + + if (ioctl(s, SIOCGVNENTROPY, &ifr) == -1) + return; + + if (ifr.ifr_vnetid) + ife->ife_flags |= IFE_VNETID_ENTROPY; } void @@ -3619,6 +3665,7 @@ getencap(void) struct ifencap ife = { .ife_flags = 0 }; getvnetid(&ife); + getvnentropy(&ife); getifparent(&ife); if (ife.ife_flags == 0) @@ -3635,6 +3682,8 @@ getencap(void) break; case IFE_VNETID_SET: printf(" vnetid %lld", ife.ife_vnetid); + if (ife.ife_flags & IFE_VNETID_ENTROPY) + printf("+"); break; }