diff options
Diffstat (limited to 'sys/net/if_gre.c')
-rw-r--r-- | sys/net/if_gre.c | 115 |
1 files changed, 105 insertions, 10 deletions
diff --git a/sys/net/if_gre.c b/sys/net/if_gre.c index cf743c93148..57102ae31bb 100644 --- a/sys/net/if_gre.c +++ b/sys/net/if_gre.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_gre.c,v 1.105 2018/02/19 00:46:27 dlg Exp $ */ +/* $OpenBSD: if_gre.c,v 1.106 2018/02/20 03:53:54 dlg Exp $ */ /* $NetBSD: if_gre.c,v 1.9 1999/10/25 19:18:11 drochner Exp $ */ /* @@ -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_tunnel *, struct ifreq *); static int gre_get_vnetid(struct gre_tunnel *, struct ifreq *); static int gre_del_vnetid(struct gre_tunnel *); +static int gre_set_vnetflowid(struct gre_tunnel *, struct ifreq *); +static int gre_get_vnetflowid(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 *offp, int type, int af, 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, struct mbuf *m, int hlen) 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 *tunnel, struct mbuf *m, uint16_t proto, 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, struct gre_tunnel *tunnel, error = gre_del_vnetid(tunnel); break; + case SIOCSVNETFLOWID: + error = gre_set_vnetflowid(tunnel, ifr); + break; + + case SIOCGVNETFLOWID: + error = gre_get_vnetflowid(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, caddr_t data) case SIOCSVNETID: case SIOCDVNETID: + case SIOCSVNETFLOWID: 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, struct ifreq *ifr) 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); } @@ -1612,6 +1666,47 @@ gre_del_vnetid(struct gre_tunnel *tunnel) } static int +gre_set_vnetflowid(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_vnetflowid(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); +} + +static int egre_up(struct egre_softc *sc) { if (sc->sc_tunnel.t_af == AF_UNSPEC) |