summaryrefslogtreecommitdiff
path: root/sys/net/if_gre.c
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2018-11-29 00:14:30 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2018-11-29 00:14:30 +0000
commitaa1f4efa4af4fae5f0812878bf5dc80f94e5d119 (patch)
tree476f42f1869f6765073864d5c32ecd66741277eb /sys/net/if_gre.c
parent3c5f0a55988a1eb3e46b6d86ddf298461b3d2351 (diff)
allow configuration of ecn processing
this is a step toward better rfc6040 support ok claudio@
Diffstat (limited to 'sys/net/if_gre.c')
-rw-r--r--sys/net/if_gre.c130
1 files changed, 118 insertions, 12 deletions
diff --git a/sys/net/if_gre.c b/sys/net/if_gre.c
index 6aea800a0c4..49a1bda48d9 100644
--- a/sys/net/if_gre.c
+++ b/sys/net/if_gre.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_gre.c,v 1.139 2018/11/15 00:05:00 dlg Exp $ */
+/* $OpenBSD: if_gre.c,v 1.140 2018/11/29 00:14:29 dlg Exp $ */
/* $NetBSD: if_gre.c,v 1.9 1999/10/25 19:18:11 drochner Exp $ */
/*
@@ -67,6 +67,7 @@
#include <netinet/if_ether.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
+#include <netinet/ip_ecn.h>
#ifdef INET6
#include <netinet/ip6.h>
@@ -192,6 +193,7 @@ struct gre_tunnel {
#define t_dst6 t_dst.in6
int t_ttl;
int t_txhprio;
+ int t_ecn;
uint16_t t_df;
sa_family_t t_af;
};
@@ -289,9 +291,19 @@ static int gre_up(struct gre_softc *);
static int gre_down(struct gre_softc *);
static void gre_link_state(struct ifnet *, unsigned int);
-static int gre_input_key(struct mbuf **, int *, int, int,
+static int gre_input_key(struct mbuf **, int *, int, int, uint8_t,
struct gre_tunnel *);
+static struct mbuf *
+ gre_ipv4_patch(const struct gre_tunnel *, struct mbuf *,
+ uint8_t);
+static struct mbuf *
+ gre_ipv6_patch(const struct gre_tunnel *, struct mbuf *,
+ uint8_t);
+static struct mbuf *
+ gre_mpls_patch(const struct gre_tunnel *, struct mbuf *,
+ uint8_t);
+
static void gre_keepalive_send(void *);
static void gre_keepalive_recv(struct ifnet *ifp, struct mbuf *);
static void gre_keepalive_hold(void *);
@@ -586,6 +598,7 @@ gre_clone_create(struct if_clone *ifc, int unit)
sc->sc_tunnel.t_ttl = ip_defttl;
sc->sc_tunnel.t_txhprio = IF_HDRPRIO_PAYLOAD;
sc->sc_tunnel.t_df = htons(0);
+ sc->sc_tunnel.t_ecn = ECN_ALLOWED;
timeout_set(&sc->sc_ka_send, gre_keepalive_send, sc);
timeout_set_proc(&sc->sc_ka_hold, gre_keepalive_hold, sc);
@@ -652,6 +665,7 @@ mgre_clone_create(struct if_clone *ifc, int unit)
sc->sc_tunnel.t_ttl = ip_defttl;
sc->sc_tunnel.t_txhprio = IF_HDRPRIO_PAYLOAD;
sc->sc_tunnel.t_df = htons(0);
+ sc->sc_tunnel.t_ecn = ECN_ALLOWED;
if_attach(ifp);
if_alloc_sadl(ifp);
@@ -884,7 +898,7 @@ gre_input(struct mbuf **mp, int *offp, int type, int af)
key.t_src4 = ip->ip_dst;
key.t_dst4 = ip->ip_src;
- if (gre_input_key(mp, offp, type, af, &key) == -1)
+ if (gre_input_key(mp, offp, type, af, ip->ip_tos, &key) == -1)
return (rip_input(mp, offp, type, af));
return (IPPROTO_DONE);
@@ -897,6 +911,7 @@ gre_input6(struct mbuf **mp, int *offp, int type, int af)
struct mbuf *m = *mp;
struct gre_tunnel key;
struct ip6_hdr *ip6;
+ uint32_t flow;
ip6 = mtod(m, struct ip6_hdr *);
@@ -906,7 +921,9 @@ gre_input6(struct mbuf **mp, int *offp, int type, int af)
key.t_src6 = ip6->ip6_dst;
key.t_dst6 = ip6->ip6_src;
- if (gre_input_key(mp, offp, type, af, &key) == -1)
+ flow = bemtoh32(&ip6->ip6_flow);
+
+ if (gre_input_key(mp, offp, type, af, flow >> 20, &key) == -1)
return (rip6_input(mp, offp, type, af));
return (IPPROTO_DONE);
@@ -970,7 +987,7 @@ gre_input_1(struct gre_tunnel *key, struct mbuf *m,
}
static int
-gre_input_key(struct mbuf **mp, int *offp, int type, int af,
+gre_input_key(struct mbuf **mp, int *offp, int type, int af, uint8_t otos,
struct gre_tunnel *key)
{
struct mbuf *m = *mp;
@@ -981,6 +998,8 @@ gre_input_key(struct mbuf **mp, int *offp, int type, int af,
struct gre_header *gh;
struct gre_h_key *gkh;
void (*input)(struct ifnet *, struct mbuf *);
+ struct mbuf *(*patch)(const struct gre_tunnel *,
+ struct mbuf *, uint8_t);
int bpf_af = AF_UNSPEC; /* bpf */
int mcast = 0;
@@ -1086,6 +1105,7 @@ gre_input_key(struct mbuf **mp, int *offp, int type, int af,
#if NBPFILTER > 0
bpf_af = AF_INET;
#endif
+ patch = gre_ipv4_patch;
input = ipv4_input;
break;
#ifdef INET6
@@ -1093,6 +1113,7 @@ gre_input_key(struct mbuf **mp, int *offp, int type, int af,
#if NBPFILTER > 0
bpf_af = AF_INET6;
#endif
+ patch = gre_ipv6_patch;
input = ipv6_input;
break;
#endif
@@ -1104,6 +1125,7 @@ gre_input_key(struct mbuf **mp, int *offp, int type, int af,
#if NBPFILTER > 0
bpf_af = AF_MPLS;
#endif
+ patch = gre_mpls_patch;
input = mpls_input;
break;
#endif
@@ -1127,6 +1149,10 @@ gre_input_key(struct mbuf **mp, int *offp, int type, int af,
tunnel = ifp->if_softc; /* gre and mgre tunnel info is at the front */
+ m = (*patch)(tunnel, m, otos);
+ if (m == NULL)
+ return (IPPROTO_DONE);
+
if (tunnel->t_key_mask == GRE_KEY_ENTROPY) {
m->m_pkthdr.ph_flowid = M_FLOWID_VALID |
(bemtoh32(&key->t_key) & ~GRE_KEY_ENTROPY);
@@ -1156,6 +1182,69 @@ decline:
return (-1);
}
+static struct mbuf *
+gre_ipv4_patch(const struct gre_tunnel *tunnel, struct mbuf *m, uint8_t otos)
+{
+ struct ip *ip;
+ uint8_t itos;
+
+ m = m_pullup(m, sizeof(*ip));
+ if (m == NULL)
+ return (NULL);
+
+ ip = mtod(m, struct ip *);
+
+ itos = ip->ip_tos;
+ if (ip_ecn_egress(tunnel->t_ecn, &otos, &itos) == 0) {
+ m_freem(m);
+ return (NULL);
+ }
+ if (itos != ip->ip_tos)
+ ip_tos_patch(ip, itos);
+
+ return (m);
+}
+
+static struct mbuf *
+gre_ipv6_patch(const struct gre_tunnel *tunnel, struct mbuf *m, uint8_t otos)
+{
+ struct ip6_hdr *ip6;
+ uint32_t flow;
+ uint8_t itos;
+
+ m = m_pullup(m, sizeof(*ip6));
+ if (m == NULL)
+ return (NULL);
+
+ ip6 = mtod(m, struct ip6_hdr *);
+
+ flow = bemtoh32(&ip6->ip6_flow);
+ itos = flow >> 20;
+ if (ip_ecn_egress(tunnel->t_ecn, &otos, &itos) == 0) {
+ m_freem(m);
+ return (NULL);
+ }
+
+ CLR(flow, 0xff << 20);
+ SET(flow, itos << 20);
+ htobem32(&ip6->ip6_flow, flow);
+
+ return (m);
+}
+
+static struct mbuf *
+gre_mpls_patch(const struct gre_tunnel *tunnel, struct mbuf *m, uint8_t otos)
+{
+ uint8_t itos = 0;
+
+ if (ip_ecn_egress(tunnel->t_ecn, &otos, &itos) == 0) {
+ m_freem(m);
+ return (NULL);
+ }
+
+ return (m);
+}
+
static int
egre_input(const struct gre_tunnel *key, struct mbuf *m, int hlen)
{
@@ -1876,7 +1965,7 @@ gre_l3_encap_dst(const struct gre_tunnel *tunnel, const void *dst,
struct mbuf *m, sa_family_t af)
{
uint16_t proto;
- uint8_t ttl, tos;
+ uint8_t ttl, itos, otos;
int tttl = tunnel->t_ttl;
int ttloff;
@@ -1889,7 +1978,7 @@ gre_l3_encap_dst(const struct gre_tunnel *tunnel, const void *dst,
return (NULL);
ip = mtod(m, struct ip *);
- tos = ip->ip_tos;
+ itos = ip->ip_tos;
ttloff = offsetof(struct ip, ip_ttl);
proto = htons(ETHERTYPE_IP);
@@ -1904,7 +1993,7 @@ gre_l3_encap_dst(const struct gre_tunnel *tunnel, const void *dst,
return (NULL);
ip6 = mtod(m, struct ip6_hdr *);
- tos = (ntohl(ip6->ip6_flow) & 0x0ff00000) >> 20;
+ itos = (ntohl(ip6->ip6_flow) & 0x0ff00000) >> 20;
ttloff = offsetof(struct ip6_hdr, ip6_hlim);
proto = htons(ETHERTYPE_IPV6);
@@ -1920,7 +2009,7 @@ gre_l3_encap_dst(const struct gre_tunnel *tunnel, const void *dst,
return (NULL);
shim = bemtoh32(mtod(m, uint32_t *)) & MPLS_EXP_MASK;
- tos = (shim >> MPLS_EXP_OFFSET) << 5;
+ itos = (shim >> MPLS_EXP_OFFSET) << 5;
ttloff = 3;
@@ -1942,9 +2031,10 @@ gre_l3_encap_dst(const struct gre_tunnel *tunnel, const void *dst,
} else
ttl = tttl;
- tos = gre_l3_tos(tunnel, m, tos);
+ itos = gre_l3_tos(tunnel, m, itos);
+ ip_ecn_ingress(tunnel->t_ecn, &otos, &itos);
- return (gre_encap_dst(tunnel, dst, m, proto, ttl, tos));
+ return (gre_encap_dst(tunnel, dst, m, proto, ttl, otos));
}
static struct mbuf *
@@ -2212,7 +2302,7 @@ gre_l3_tos(const struct gre_tunnel *t, const struct mbuf *m, uint8_t tos)
break;
}
- return (IFQ_PRIO2TOS(prio));
+ return (IFQ_PRIO2TOS(prio) | (tos & IPTOS_ECN_MASK));
}
static int
@@ -2289,6 +2379,14 @@ gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
ifr->ifr_ttl = sc->sc_tunnel.t_ttl;
break;
+ case SIOCSLIFPHYECN:
+ sc->sc_tunnel.t_ecn =
+ ifr->ifr_metric ? ECN_ALLOWED : ECN_FORBIDDEN;
+ break;
+ case SIOCGLIFPHYECN:
+ ifr->ifr_metric = (sc->sc_tunnel.t_ecn == ECN_ALLOWED);
+ break;
+
case SIOCSTXHPRIO:
error = gre_l3_txhprio(&sc->sc_tunnel, ifr->ifr_hdrprio);
break;
@@ -2341,6 +2439,14 @@ mgre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
ifr->ifr_ttl = sc->sc_tunnel.t_ttl;
break;
+ case SIOCSLIFPHYECN:
+ sc->sc_tunnel.t_ecn =
+ ifr->ifr_metric ? ECN_ALLOWED : ECN_FORBIDDEN;
+ break;
+ case SIOCGLIFPHYECN:
+ ifr->ifr_metric = (sc->sc_tunnel.t_ecn == ECN_ALLOWED);
+ break;
+
case SIOCSLIFPHYADDR:
if (ISSET(ifp->if_flags, IFF_RUNNING)) {
error = EBUSY;