-/* $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 $ */
/*
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)
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);
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;
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);
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) {
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;
case SIOCSVNETID:
case SIOCDVNETID:
+ case SIOCSVNETFLOWID:
case SIOCSLIFPHYADDR:
case SIOCDIFPHYADDR:
case SIOCSLIFPHYRTABLE:
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);
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);
}
return (0);
}
+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)
{