733 lines
27 KiB
Diff
733 lines
27 KiB
Diff
From 5d79831435ec4e5bea20cc36c3f83eacf6fd065c Mon Sep 17 00:00:00 2001
|
||
From: Yi Yang <yi.y.yang@intel.com>
|
||
Date: Mon, 11 Apr 2016 15:58:14 +0800
|
||
Subject: [PATCH 1/6] ovs-vxlan-gpe: vxlan extension to support vxlan-gpe
|
||
tunnel port
|
||
|
||
Signed-off-by: Mengke Liu <mengke.liu@intel.com>
|
||
Signed-off-by: Ricky Li <ricky.li@intel.com>
|
||
Signed-off-by: Johnson Li <johnson.li@intel.com>
|
||
Signed-off-by: Yi Yang <yi.y.yang@intel.com>
|
||
---
|
||
datapath/flow_netlink.c | 8 +-
|
||
datapath/linux/compat/include/linux/openvswitch.h | 1 +
|
||
datapath/linux/compat/include/net/vxlan.h | 73 +++++++++++++++++++
|
||
datapath/linux/compat/vxlan.c | 30 ++++++++
|
||
datapath/vport-vxlan.c | 15 ++++
|
||
lib/flow.c | 8 ++
|
||
lib/match.c | 34 +++++++++
|
||
lib/match.h | 4 +
|
||
lib/meta-flow.c | 36 +++++++++
|
||
lib/meta-flow.h | 28 +++++++
|
||
lib/netdev-vport.c | 2 +
|
||
lib/nx-match.c | 4 +
|
||
lib/odp-util.c | 89 ++++++++++++++++++++++-
|
||
lib/packets.h | 4 +-
|
||
tests/ofproto.at | 4 +-
|
||
tests/ovs-ofctl.at | 4 +
|
||
16 files changed, 340 insertions(+), 4 deletions(-)
|
||
|
||
diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c
|
||
index 6ffcc53..351a504 100644
|
||
--- a/datapath/flow_netlink.c
|
||
+++ b/datapath/flow_netlink.c
|
||
@@ -309,6 +309,7 @@ size_t ovs_key_attr_size(void)
|
||
|
||
static const struct ovs_len_tbl ovs_vxlan_ext_key_lens[OVS_VXLAN_EXT_MAX + 1] = {
|
||
[OVS_VXLAN_EXT_GBP] = { .len = sizeof(u32) },
|
||
+ [OVS_VXLAN_EXT_GPE] = { .len = sizeof(u32) },
|
||
};
|
||
|
||
static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = {
|
||
@@ -521,6 +522,9 @@ static int vxlan_tun_opt_from_nlattr(const struct nlattr *attr,
|
||
case OVS_VXLAN_EXT_GBP:
|
||
opts.gbp = nla_get_u32(a);
|
||
break;
|
||
+ case OVS_VXLAN_EXT_GPE:
|
||
+ opts.gpe = nla_get_u32(a);
|
||
+ break;
|
||
default:
|
||
OVS_NLERR(log, "Unknown VXLAN extension attribute %d",
|
||
type);
|
||
@@ -677,7 +681,9 @@ static int vxlan_opt_to_nlattr(struct sk_buff *skb,
|
||
if (!nla)
|
||
return -EMSGSIZE;
|
||
|
||
- if (nla_put_u32(skb, OVS_VXLAN_EXT_GBP, opts->gbp) < 0)
|
||
+ if (opts->gbp && nla_put_u32(skb, OVS_VXLAN_EXT_GBP, opts->gbp) < 0)
|
||
+ return -EMSGSIZE;
|
||
+ else if (opts->gpe && nla_put_u32(skb, OVS_VXLAN_EXT_GPE, opts->gpe) < 0)
|
||
return -EMSGSIZE;
|
||
|
||
nla_nest_end(skb, nla);
|
||
diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
|
||
index 3b39ebb..44adb81 100644
|
||
--- a/datapath/linux/compat/include/linux/openvswitch.h
|
||
+++ b/datapath/linux/compat/include/linux/openvswitch.h
|
||
@@ -287,6 +287,7 @@ enum ovs_vport_attr {
|
||
enum {
|
||
OVS_VXLAN_EXT_UNSPEC,
|
||
OVS_VXLAN_EXT_GBP, /* Flag or __u32 */
|
||
+ OVS_VXLAN_EXT_GPE,
|
||
__OVS_VXLAN_EXT_MAX,
|
||
};
|
||
|
||
diff --git a/datapath/linux/compat/include/net/vxlan.h b/datapath/linux/compat/include/net/vxlan.h
|
||
index 75a5a7a..2bfc3f8 100644
|
||
--- a/datapath/linux/compat/include/net/vxlan.h
|
||
+++ b/datapath/linux/compat/include/net/vxlan.h
|
||
@@ -84,6 +84,75 @@ struct vxlanhdr_gbp {
|
||
#define VXLAN_GBP_POLICY_APPLIED (BIT(3) << 16)
|
||
#define VXLAN_GBP_ID_MASK (0xFFFF)
|
||
|
||
+/*
|
||
+ * VXLAN Generic Protocol Extension Extension:
|
||
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
+ * |R|R|Ver|I|P|R|O|R|R|R|R|R|R|R|R|R|R|R|R|R|R|R|R| Next Proto |
|
||
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
+ * | VXLAN Network Identifier (VNI) | Reserved |
|
||
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
+ * Ver = Version. Indicates VXLAN GPE protocol version. The initial
|
||
+ * version is 0. If a receiver does not support the version
|
||
+ * indicated it MUST drop the packet.
|
||
+ *
|
||
+ * I = Instance Bit. The I bit MUST be set to indicate a valid VNI.
|
||
+ *
|
||
+ * P = Next Protocol Bit. The P bit is set to indicate that the
|
||
+ * Next Protocol field is present.
|
||
+ *
|
||
+ * O = OAM Flag Bit. The O bit is set to indicate that the packet
|
||
+ * is an OAM packet.
|
||
+ *
|
||
+ * [1] https://www.ietf.org/id/draft-ietf-nvo3-vxlan-gpe-01.txt
|
||
+ */
|
||
+
|
||
+struct vxlanhdr_gpe {
|
||
+#ifdef __LITTLE_ENDIAN_BITFIELD
|
||
+ uint8_t oam_flag:1;
|
||
+ uint8_t reserved_flags1:1;
|
||
+ uint8_t np_applied:1;
|
||
+ uint8_t instance_applied:1;
|
||
+ uint8_t gpe_version:2;
|
||
+ uint8_t reserved_flags2:2;
|
||
+#elif defined(__BIG_ENDIAN_BITFIELD)
|
||
+ uint8_t reserved_flags2:2;
|
||
+ uint8_t gpe_version:2;
|
||
+ uint8_t instance_applied:1;
|
||
+ uint8_t np_applied:1;
|
||
+ uint8_t reserved_flags1:1;
|
||
+ uint8_t oam_flag:1;
|
||
+#else
|
||
+#error "Please fix <asm/byteorder.h>"
|
||
+#endif
|
||
+ uint8_t reserved_flags3;
|
||
+ uint8_t reserved_flags4;
|
||
+ uint8_t next_proto;
|
||
+ __be32 vx_vni;
|
||
+};
|
||
+
|
||
+/* VxLAN-GPE Header Next Protocol */
|
||
+#define VXLAN_GPE_NP_IPV4 0x01
|
||
+#define VXLAN_GPE_NP_IPV6 0x02
|
||
+#define VXLAN_GPE_NP_ETHERNET 0x03
|
||
+#define VXLAN_GPE_NP_NSH 0x04
|
||
+
|
||
+/* skb->mark mapping
|
||
+ *
|
||
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
+ * |R|R|Ver|I|P|R|O|R|R|R|R|R|R|R|R|R|R|R|R|R|R|R|R| Next Proto |
|
||
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
+ */
|
||
+
|
||
+#define VXLAN_GPE_OAM_FLAG (BIT(0) << 24)
|
||
+#define VXLAN_GPE_NP_APPLIED (BIT(0) << 26)
|
||
+#define VXLAN_GPE_INSTANCE_APPLIED (BIT(0) << 27)
|
||
+#define VXLAN_GPE_VERSION ((BIT(0) << 28) | (BIT(0) << 29))
|
||
+
|
||
+#define VXLAN_GPE_NP_MASK (0xFF)
|
||
+
|
||
+#define VXLAN_GPE_USED_BITS (VXLAN_GPE_OAM_FLAG | VXLAN_GPE_NP_APPLIED \
|
||
+ | VXLAN_GPE_INSTANCE_APPLIED | VXLAN_GPE_VERSION | 0xFF)
|
||
+
|
||
/* VXLAN protocol header:
|
||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
* |G|R|R|R|I|R|R|C| Reserved |
|
||
@@ -104,6 +173,7 @@ struct vxlanhdr {
|
||
#define VXLAN_HF_RCO BIT(21)
|
||
#define VXLAN_HF_VNI BIT(27)
|
||
#define VXLAN_HF_GBP BIT(31)
|
||
+#define VXLAN_HF_GPE BIT(26)
|
||
|
||
/* Remote checksum offload header option */
|
||
#define VXLAN_RCO_MASK 0x7f /* Last byte of vni field */
|
||
@@ -120,6 +190,7 @@ struct vxlanhdr {
|
||
struct vxlan_metadata {
|
||
__be32 vni;
|
||
u32 gbp;
|
||
+ u32 gpe;
|
||
};
|
||
|
||
#define VNI_HASH_BITS 10
|
||
@@ -205,11 +276,13 @@ struct vxlan_dev {
|
||
#define VXLAN_F_GBP 0x800
|
||
#define VXLAN_F_REMCSUM_NOPARTIAL 0x1000
|
||
#define VXLAN_F_COLLECT_METADATA 0x2000
|
||
+#define VXLAN_F_GPE 0x4000
|
||
|
||
/* Flags that are used in the receive path. These flags must match in
|
||
* order for a socket to be shareable
|
||
*/
|
||
#define VXLAN_F_RCV_FLAGS (VXLAN_F_GBP | \
|
||
+ VXLAN_F_GPE | \
|
||
VXLAN_F_UDP_ZERO_CSUM6_RX | \
|
||
VXLAN_F_REMCSUM_RX | \
|
||
VXLAN_F_REMCSUM_NOPARTIAL | \
|
||
diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c
|
||
index 4faa18f..7ef051c 100644
|
||
--- a/datapath/linux/compat/vxlan.c
|
||
+++ b/datapath/linux/compat/vxlan.c
|
||
@@ -971,6 +971,18 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
|
||
md->gbp |= VXLAN_GBP_POLICY_APPLIED;
|
||
|
||
flags &= ~VXLAN_GBP_USED_BITS;
|
||
+ } else if ((flags & VXLAN_HF_GPE) && (vs->flags & VXLAN_F_GPE)) {
|
||
+ struct vxlanhdr_gpe *gpe;
|
||
+
|
||
+ gpe = (struct vxlanhdr_gpe *)vxh;
|
||
+ md->gpe = ntohs(gpe->next_proto);
|
||
+
|
||
+ buf.dst.u.tun_info.key.tun_flags |= TUNNEL_VXLAN_OPT;
|
||
+
|
||
+ if (gpe->oam_flag)
|
||
+ md->gpe |= VXLAN_GPE_OAM_FLAG;
|
||
+
|
||
+ flags &= ~VXLAN_GPE_USED_BITS;
|
||
}
|
||
|
||
if (flags || vni & ~VXLAN_VNI_MASK) {
|
||
@@ -1023,6 +1035,22 @@ static void vxlan_build_gbp_hdr(struct vxlanhdr *vxh, u32 vxflags,
|
||
gbp->policy_id = htons(md->gbp & VXLAN_GBP_ID_MASK);
|
||
}
|
||
|
||
+static void vxlan_build_gpe_hdr(struct vxlanhdr *vxh, u32 vxflags,
|
||
+ struct vxlan_metadata *md)
|
||
+{
|
||
+ struct vxlanhdr_gpe *gpe;
|
||
+
|
||
+ if (!md->gpe)
|
||
+ return;
|
||
+
|
||
+ gpe = (struct vxlanhdr_gpe*)vxh;
|
||
+ vxh->vx_flags |= htonl(VXLAN_HF_GPE);
|
||
+
|
||
+ if (md->gpe & VXLAN_GPE_OAM_FLAG)
|
||
+ gpe->oam_flag = 1;
|
||
+ gpe->next_proto = md->gpe & VXLAN_GPE_NP_MASK;
|
||
+}
|
||
+
|
||
#if IS_ENABLED(CONFIG_IPV6)
|
||
static int vxlan6_xmit_skb(struct dst_entry *dst, struct sock *sk,
|
||
struct sk_buff *skb,
|
||
@@ -1106,6 +1134,8 @@ static int vxlan6_xmit_skb(struct dst_entry *dst, struct sock *sk,
|
||
|
||
if (vxflags & VXLAN_F_GBP)
|
||
vxlan_build_gbp_hdr(vxh, vxflags, md);
|
||
+ else if (vxflags & VXLAN_F_GPE)
|
||
+ vxlan_build_gpe_hdr(vxh, vxflags, md);
|
||
|
||
ovs_skb_set_inner_protocol(skb, htons(ETH_P_TEB));
|
||
|
||
diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c
|
||
index c05f5d4..5d775cc 100644
|
||
--- a/datapath/vport-vxlan.c
|
||
+++ b/datapath/vport-vxlan.c
|
||
@@ -52,6 +52,18 @@ static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb)
|
||
return -EMSGSIZE;
|
||
|
||
nla_nest_end(skb, exts);
|
||
+ } else if (vxlan->flags & VXLAN_F_GPE) {
|
||
+ struct nlattr *exts;
|
||
+
|
||
+ exts = nla_nest_start(skb, OVS_TUNNEL_ATTR_EXTENSION);
|
||
+ if (!exts)
|
||
+ return -EMSGSIZE;
|
||
+
|
||
+ if (vxlan->flags & VXLAN_F_GPE &&
|
||
+ nla_put_flag(skb, OVS_VXLAN_EXT_GPE))
|
||
+ return -EMSGSIZE;
|
||
+
|
||
+ nla_nest_end(skb, exts);
|
||
}
|
||
|
||
return 0;
|
||
@@ -59,6 +71,7 @@ static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb)
|
||
|
||
static const struct nla_policy exts_policy[OVS_VXLAN_EXT_MAX + 1] = {
|
||
[OVS_VXLAN_EXT_GBP] = { .type = NLA_FLAG, },
|
||
+ [OVS_VXLAN_EXT_GPE] = { .type = NLA_FLAG, },
|
||
};
|
||
|
||
static int vxlan_configure_exts(struct vport *vport, struct nlattr *attr,
|
||
@@ -76,6 +89,8 @@ static int vxlan_configure_exts(struct vport *vport, struct nlattr *attr,
|
||
|
||
if (exts[OVS_VXLAN_EXT_GBP])
|
||
conf->flags |= VXLAN_F_GBP;
|
||
+ else if (exts[OVS_VXLAN_EXT_GPE])
|
||
+ conf->flags |= VXLAN_F_GPE;
|
||
|
||
return 0;
|
||
}
|
||
diff --git a/lib/flow.c b/lib/flow.c
|
||
index b9ce331..d24bdc9 100644
|
||
--- a/lib/flow.c
|
||
+++ b/lib/flow.c
|
||
@@ -870,6 +870,12 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata)
|
||
if (flow->tunnel.gbp_flags) {
|
||
match_set_tun_gbp_flags(flow_metadata, flow->tunnel.gbp_flags);
|
||
}
|
||
+ if (flow->tunnel.gpe_np != htons(0)) {
|
||
+ match_set_tun_gpe_np(flow_metadata, flow->tunnel.gpe_np);
|
||
+ }
|
||
+ if (flow->tunnel.gpe_flags) {
|
||
+ match_set_tun_gpe_flags(flow_metadata, flow->tunnel.gpe_flags);
|
||
+ }
|
||
tun_metadata_get_fmd(&flow->tunnel, flow_metadata);
|
||
if (flow->metadata != htonll(0)) {
|
||
match_set_metadata(flow_metadata, flow->metadata);
|
||
@@ -1265,6 +1271,8 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
|
||
WC_MASK_FIELD(wc, tunnel.tp_dst);
|
||
WC_MASK_FIELD(wc, tunnel.gbp_id);
|
||
WC_MASK_FIELD(wc, tunnel.gbp_flags);
|
||
+ WC_MASK_FIELD(wc, tunnel.gpe_np);
|
||
+ WC_MASK_FIELD(wc, tunnel.gpe_flags);
|
||
|
||
if (!(flow->tunnel.flags & FLOW_TNL_F_UDPIF)) {
|
||
if (flow->tunnel.metadata.present.map) {
|
||
diff --git a/lib/match.c b/lib/match.c
|
||
index fd571d9..52437c9 100644
|
||
--- a/lib/match.c
|
||
+++ b/lib/match.c
|
||
@@ -289,6 +289,32 @@ match_set_tun_gbp_flags(struct match *match, uint8_t flags)
|
||
}
|
||
|
||
void
|
||
+match_set_tun_gpe_np_masked(struct match *match, uint8_t np, uint8_t mask)
|
||
+{
|
||
+ match->wc.masks.tunnel.gpe_np = mask;
|
||
+ match->flow.tunnel.gpe_np = np & mask;
|
||
+}
|
||
+
|
||
+void
|
||
+match_set_tun_gpe_np(struct match *match, uint8_t np)
|
||
+{
|
||
+ match_set_tun_gpe_np_masked(match, np, UINT8_MAX);
|
||
+}
|
||
+
|
||
+void
|
||
+match_set_tun_gpe_flags_masked(struct match *match, uint8_t flags, uint8_t mask)
|
||
+{
|
||
+ match->wc.masks.tunnel.gpe_flags = mask;
|
||
+ match->flow.tunnel.gpe_flags = flags & mask;
|
||
+}
|
||
+
|
||
+void
|
||
+match_set_tun_gpe_flags(struct match *match, uint8_t flags)
|
||
+{
|
||
+ match_set_tun_gpe_flags_masked(match, flags, UINT8_MAX);
|
||
+}
|
||
+
|
||
+void
|
||
match_set_in_port(struct match *match, ofp_port_t ofp_port)
|
||
{
|
||
match->wc.masks.in_port.ofp_port = u16_to_ofp(UINT16_MAX);
|
||
@@ -1013,6 +1039,14 @@ format_flow_tunnel(struct ds *s, const struct match *match)
|
||
ds_put_format(s, "tun_gbp_flags=%#"PRIx8",", tnl->gbp_flags);
|
||
}
|
||
|
||
+ if (wc->masks.tunnel.gpe_np) {
|
||
+ ds_put_format(s, "tun_gpe_np=%#"PRIx8",", tnl->gpe_np);
|
||
+ }
|
||
+
|
||
+ if (wc->masks.tunnel.gpe_flags) {
|
||
+ ds_put_format(s, "tun_gpe_flags=%#"PRIx8",", tnl->gpe_flags);
|
||
+ }
|
||
+
|
||
if (wc->masks.tunnel.ip_tos) {
|
||
ds_put_format(s, "tun_tos=%"PRIx8",", tnl->ip_tos);
|
||
}
|
||
diff --git a/lib/match.h b/lib/match.h
|
||
index 0a6ac29..48aa0b1 100644
|
||
--- a/lib/match.h
|
||
+++ b/lib/match.h
|
||
@@ -86,6 +86,10 @@ void match_set_tun_gbp_id_masked(struct match *match, ovs_be16 gbp_id, ovs_be16
|
||
void match_set_tun_gbp_id(struct match *match, ovs_be16 gbp_id);
|
||
void match_set_tun_gbp_flags_masked(struct match *match, uint8_t flags, uint8_t mask);
|
||
void match_set_tun_gbp_flags(struct match *match, uint8_t flags);
|
||
+void match_set_tun_gpe_np_masked(struct match *match, uint8_t gpe_np, uint8_t mask);
|
||
+void match_set_tun_gpe_np(struct match *match, uint8_t gpe_np);
|
||
+void match_set_tun_gpe_flags_masked(struct match *match, uint8_t flags, uint8_t mask);
|
||
+void match_set_tun_gpe_flags(struct match *match, uint8_t flags);
|
||
void match_set_in_port(struct match *, ofp_port_t ofp_port);
|
||
void match_set_pkt_mark(struct match *, uint32_t pkt_mark);
|
||
void match_set_pkt_mark_masked(struct match *, uint32_t pkt_mark, uint32_t mask);
|
||
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
|
||
index 721152c..ab77fca 100644
|
||
--- a/lib/meta-flow.c
|
||
+++ b/lib/meta-flow.c
|
||
@@ -213,6 +213,10 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
|
||
return !wc->masks.tunnel.gbp_id;
|
||
case MFF_TUN_GBP_FLAGS:
|
||
return !wc->masks.tunnel.gbp_flags;
|
||
+ case MFF_TUN_GPE_NP:
|
||
+ return !wc->masks.tunnel.gpe_np;
|
||
+ case MFF_TUN_GPE_FLAGS:
|
||
+ return !wc->masks.tunnel.gpe_flags;
|
||
CASE_MFF_TUN_METADATA:
|
||
return !ULLONG_GET(wc->masks.tunnel.metadata.present.map,
|
||
mf->id - MFF_TUN_METADATA0);
|
||
@@ -515,6 +519,8 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
|
||
case MFF_TUN_TTL:
|
||
case MFF_TUN_GBP_ID:
|
||
case MFF_TUN_GBP_FLAGS:
|
||
+ case MFF_TUN_GPE_NP:
|
||
+ case MFF_TUN_GPE_FLAGS:
|
||
CASE_MFF_TUN_METADATA:
|
||
case MFF_METADATA:
|
||
case MFF_IN_PORT:
|
||
@@ -648,6 +654,12 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
|
||
case MFF_TUN_GBP_FLAGS:
|
||
value->u8 = flow->tunnel.gbp_flags;
|
||
break;
|
||
+ case MFF_TUN_GPE_NP:
|
||
+ value->u8 = flow->tunnel.gpe_np;
|
||
+ break;
|
||
+ case MFF_TUN_GPE_FLAGS:
|
||
+ value->u8 = flow->tunnel.gpe_flags;
|
||
+ break;
|
||
case MFF_TUN_TTL:
|
||
value->u8 = flow->tunnel.ip_ttl;
|
||
break;
|
||
@@ -899,6 +911,12 @@ mf_set_value(const struct mf_field *mf,
|
||
case MFF_TUN_GBP_FLAGS:
|
||
match_set_tun_gbp_flags(match, value->u8);
|
||
break;
|
||
+ case MFF_TUN_GPE_NP:
|
||
+ match_set_tun_gpe_np(match, value->u8);
|
||
+ break;
|
||
+ case MFF_TUN_GPE_FLAGS:
|
||
+ match_set_tun_gpe_flags(match, value->u8);
|
||
+ break;
|
||
case MFF_TUN_TOS:
|
||
match_set_tun_tos(match, value->u8);
|
||
break;
|
||
@@ -1216,6 +1234,12 @@ mf_set_flow_value(const struct mf_field *mf,
|
||
case MFF_TUN_GBP_FLAGS:
|
||
flow->tunnel.gbp_flags = value->u8;
|
||
break;
|
||
+ case MFF_TUN_GPE_NP:
|
||
+ flow->tunnel.gpe_np= value->u8;
|
||
+ break;
|
||
+ case MFF_TUN_GPE_FLAGS:
|
||
+ flow->tunnel.gpe_flags= value->u8;
|
||
+ break;
|
||
case MFF_TUN_TOS:
|
||
flow->tunnel.ip_tos = value->u8;
|
||
break;
|
||
@@ -1535,6 +1559,12 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str)
|
||
case MFF_TUN_GBP_FLAGS:
|
||
match_set_tun_gbp_flags_masked(match, 0, 0);
|
||
break;
|
||
+ case MFF_TUN_GPE_NP:
|
||
+ match_set_tun_gpe_np_masked(match, 0, 0);
|
||
+ break;
|
||
+ case MFF_TUN_GPE_FLAGS:
|
||
+ match_set_tun_gpe_flags_masked(match, 0, 0);
|
||
+ break;
|
||
case MFF_TUN_TOS:
|
||
match_set_tun_tos_masked(match, 0, 0);
|
||
break;
|
||
@@ -1838,6 +1868,12 @@ mf_set(const struct mf_field *mf,
|
||
case MFF_TUN_GBP_FLAGS:
|
||
match_set_tun_gbp_flags_masked(match, value->u8, mask->u8);
|
||
break;
|
||
+ case MFF_TUN_GPE_NP:
|
||
+ match_set_tun_gpe_np_masked(match, value->u8, mask->u8);
|
||
+ break;
|
||
+ case MFF_TUN_GPE_FLAGS:
|
||
+ match_set_tun_gpe_flags_masked(match, value->u8, mask->u8);
|
||
+ break;
|
||
case MFF_TUN_TTL:
|
||
match_set_tun_ttl_masked(match, value->u8, mask->u8);
|
||
break;
|
||
diff --git a/lib/meta-flow.h b/lib/meta-flow.h
|
||
index c73a1af..4bd9ff6 100644
|
||
--- a/lib/meta-flow.h
|
||
+++ b/lib/meta-flow.h
|
||
@@ -491,6 +491,34 @@ enum OVS_PACKED_ENUM mf_field_id {
|
||
*/
|
||
MFF_TUN_GBP_FLAGS,
|
||
|
||
+ /* "tun_gpe_np".
|
||
+ *
|
||
+ * VXLAN Generic Protocol Extension next_proto
|
||
+ *
|
||
+ * Type: u8.
|
||
+ * Maskable: bitwise.
|
||
+ * Formatting: hexadecimal.
|
||
+ * Prerequisites: none.
|
||
+ * Access: read/write.
|
||
+ * NXM: NXM_NX_TUN_GPE_NP(111) since v2.4.
|
||
+ * OXM: none.
|
||
+ */
|
||
+ MFF_TUN_GPE_NP,
|
||
+
|
||
+ /* "tun_gpe_flags".
|
||
+ *
|
||
+ * VXLAN Generic Protocol Extension flag
|
||
+ *
|
||
+ * Type: u8.
|
||
+ * Maskable: bitwise.
|
||
+ * Formatting: hexadecimal.
|
||
+ * Prerequisites: none.
|
||
+ * Access: read/write.
|
||
+ * NXM: NXM_NX_TUN_GPE_FLAGS(112) since v2.4.
|
||
+ * OXM: none.
|
||
+ */
|
||
+ MFF_TUN_GPE_FLAGS,
|
||
+
|
||
#if TUN_METADATA_NUM_OPTS == 64
|
||
/* "tun_metadata<N>".
|
||
*
|
||
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
|
||
index e398562..92ceec1 100644
|
||
--- a/lib/netdev-vport.c
|
||
+++ b/lib/netdev-vport.c
|
||
@@ -583,6 +583,8 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args)
|
||
while (ext) {
|
||
if (!strcmp(type, "vxlan") && !strcmp(ext, "gbp")) {
|
||
tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GBP);
|
||
+ } else if (!strcmp(type, "vxlan") && !strcmp(ext, "gpe")) {
|
||
+ tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GPE);
|
||
} else {
|
||
VLOG_WARN("%s: unknown extension '%s'", name, ext);
|
||
}
|
||
diff --git a/lib/nx-match.c b/lib/nx-match.c
|
||
index 9f0f452..0eecac7 100644
|
||
--- a/lib/nx-match.c
|
||
+++ b/lib/nx-match.c
|
||
@@ -1037,6 +1037,10 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
|
||
flow->tunnel.gbp_id, match->wc.masks.tunnel.gbp_id);
|
||
nxm_put_8m(b, MFF_TUN_GBP_FLAGS, oxm,
|
||
flow->tunnel.gbp_flags, match->wc.masks.tunnel.gbp_flags);
|
||
+ nxm_put_8m(b, MFF_TUN_GPE_NP, oxm,
|
||
+ flow->tunnel.gpe_np, match->wc.masks.tunnel.gpe_np);
|
||
+ nxm_put_8m(b, MFF_TUN_GPE_FLAGS, oxm,
|
||
+ flow->tunnel.gpe_flags, match->wc.masks.tunnel.gpe_flags);
|
||
tun_metadata_to_nx_match(b, oxm, match);
|
||
|
||
/* Registers. */
|
||
diff --git a/lib/odp-util.c b/lib/odp-util.c
|
||
index b4689cc..7983720 100644
|
||
--- a/lib/odp-util.c
|
||
+++ b/lib/odp-util.c
|
||
@@ -1727,6 +1727,7 @@ odp_actions_from_string(const char *s, const struct simap *port_names,
|
||
|
||
static const struct attr_len_tbl ovs_vxlan_ext_attr_lens[OVS_VXLAN_EXT_MAX + 1] = {
|
||
[OVS_VXLAN_EXT_GBP] = { .len = 4 },
|
||
+ [OVS_VXLAN_EXT_GPE] = { .len = 4 },
|
||
};
|
||
|
||
static const struct attr_len_tbl ovs_tun_key_attr_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = {
|
||
@@ -1888,7 +1889,10 @@ odp_tun_key_from_attr__(const struct nlattr *attr,
|
||
break;
|
||
case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS: {
|
||
static const struct nl_policy vxlan_opts_policy[] = {
|
||
- [OVS_VXLAN_EXT_GBP] = { .type = NL_A_U32 },
|
||
+ [OVS_VXLAN_EXT_GBP] = { .type = NL_A_U32 ,
|
||
+ .optional = true },
|
||
+ [OVS_VXLAN_EXT_GPE] = { .type = NL_A_U32 ,
|
||
+ .optional = true },
|
||
};
|
||
struct nlattr *ext[ARRAY_SIZE(vxlan_opts_policy)];
|
||
|
||
@@ -1902,6 +1906,12 @@ odp_tun_key_from_attr__(const struct nlattr *attr,
|
||
tun->gbp_id = htons(gbp & 0xFFFF);
|
||
tun->gbp_flags = (gbp >> 16) & 0xFF;
|
||
}
|
||
+ if (ext[OVS_VXLAN_EXT_GPE]) {
|
||
+ uint32_t gpe = nl_attr_get_u32(ext[OVS_VXLAN_EXT_GPE]);
|
||
+
|
||
+ tun->gpe_np = gpe & 0xFF;
|
||
+ tun->gpe_flags = gpe >> 24;
|
||
+ }
|
||
|
||
break;
|
||
}
|
||
@@ -1988,6 +1998,13 @@ tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl *tun_key,
|
||
nl_msg_put_u32(a, OVS_VXLAN_EXT_GBP,
|
||
(tun_key->gbp_flags << 16) | ntohs(tun_key->gbp_id));
|
||
nl_msg_end_nested(a, vxlan_opts_ofs);
|
||
+ } else if (tun_key->gpe_flags || tun_key->gpe_np) {
|
||
+ size_t vxlan_opts_ofs;
|
||
+
|
||
+ vxlan_opts_ofs = nl_msg_start_nested(a, OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS);
|
||
+ nl_msg_put_u32(a, OVS_VXLAN_EXT_GPE,
|
||
+ (tun_key->gpe_flags << 24) | (tun_key->gpe_np));
|
||
+ nl_msg_end_nested(a, vxlan_opts_ofs);
|
||
}
|
||
tun_metadata_to_geneve_nlattr(tun_key, tun_flow_key, key_buf, a);
|
||
|
||
@@ -2383,6 +2400,26 @@ format_odp_tun_vxlan_opt(const struct nlattr *attr,
|
||
ds_put_cstr(ds, "),");
|
||
break;
|
||
}
|
||
+ case OVS_VXLAN_EXT_GPE: {
|
||
+ uint32_t key = nl_attr_get_u32(a);
|
||
+ uint8_t np, np_mask;
|
||
+ uint8_t flags, flags_mask;
|
||
+
|
||
+ np = key & 0xFF;
|
||
+ flags = (key >> 24) & 0xFF;
|
||
+ if (ma) {
|
||
+ uint32_t mask = nl_attr_get_u32(ma);
|
||
+ np_mask = mask & 0xFF;
|
||
+ flags_mask = (mask >> 24) & 0xFF;
|
||
+ }
|
||
+
|
||
+ ds_put_cstr(ds, "gpe(");
|
||
+ format_u8x(ds, "np", np, ma ? &np_mask : NULL, verbose);
|
||
+ format_u8x(ds, "flags", flags, ma ? &flags_mask : NULL, verbose);
|
||
+ ds_chomp(ds, ',');
|
||
+ ds_put_cstr(ds, "),");
|
||
+ break;
|
||
+ }
|
||
|
||
default:
|
||
format_unknown_key(ds, a, ma);
|
||
@@ -3670,6 +3707,40 @@ scan_vxlan_gbp(const char *s, uint32_t *key, uint32_t *mask)
|
||
}
|
||
|
||
static int
|
||
+scan_vxlan_gpe(const char *s, uint32_t *key, uint32_t *mask)
|
||
+{
|
||
+ const char *s_base = s;
|
||
+ uint8_t np = 0, np_mask = 0;
|
||
+ uint8_t flags = 0, flags_mask = 0;
|
||
+
|
||
+ if (!strncmp(s, "np=", 3)) {
|
||
+ s += 3;
|
||
+ s += scan_u8(s, &np, mask ? &np_mask : NULL);
|
||
+ }
|
||
+
|
||
+ if (s[0] == ',') {
|
||
+ s++;
|
||
+ }
|
||
+ if (!strncmp(s, "flags=", 6)) {
|
||
+ s += 6;
|
||
+ s += scan_u8(s, &flags, mask ? &flags_mask : NULL);
|
||
+ }
|
||
+
|
||
+ if (!strncmp(s, "))", 2)) {
|
||
+ s += 2;
|
||
+
|
||
+ *key = (flags << 24) | np;
|
||
+ if (mask) {
|
||
+ *mask = (flags_mask << 24) | np_mask;
|
||
+ }
|
||
+
|
||
+ return s - s_base;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static int
|
||
scan_geneve(const char *s, struct geneve_scan *key, struct geneve_scan *mask)
|
||
{
|
||
const char *s_base = s;
|
||
@@ -3796,6 +3867,21 @@ vxlan_gbp_to_attr(struct ofpbuf *a, const void *data_)
|
||
}
|
||
|
||
static void
|
||
+vxlan_gpe_to_attr(struct ofpbuf *a, const void *data_)
|
||
+{
|
||
+ const uint32_t *gpe = data_;
|
||
+
|
||
+ if (*gpe) {
|
||
+ size_t vxlan_opts_ofs;
|
||
+
|
||
+ vxlan_opts_ofs = nl_msg_start_nested(a, OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS);
|
||
+ nl_msg_put_u32(a, OVS_VXLAN_EXT_GPE, *gpe);
|
||
+ nl_msg_end_nested(a, vxlan_opts_ofs);
|
||
+ }
|
||
+}
|
||
+
|
||
+
|
||
+static void
|
||
geneve_to_attr(struct ofpbuf *a, const void *data_)
|
||
{
|
||
const struct geneve_scan *geneve = data_;
|
||
@@ -4031,6 +4117,7 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
|
||
SCAN_FIELD_NESTED("tp_src=", ovs_be16, be16, OVS_TUNNEL_KEY_ATTR_TP_SRC);
|
||
SCAN_FIELD_NESTED("tp_dst=", ovs_be16, be16, OVS_TUNNEL_KEY_ATTR_TP_DST);
|
||
SCAN_FIELD_NESTED_FUNC("vxlan(gbp(", uint32_t, vxlan_gbp, vxlan_gbp_to_attr);
|
||
+ SCAN_FIELD_NESTED_FUNC("vxlan(gpe(", uint32_t, vxlan_gpe, vxlan_gpe_to_attr);
|
||
SCAN_FIELD_NESTED_FUNC("geneve(", struct geneve_scan, geneve,
|
||
geneve_to_attr);
|
||
SCAN_FIELD_NESTED_FUNC("flags(", uint16_t, tun_flags, tun_flags_to_attr);
|
||
diff --git a/lib/packets.h b/lib/packets.h
|
||
index a8ea24b..dc97333 100644
|
||
--- a/lib/packets.h
|
||
+++ b/lib/packets.h
|
||
@@ -49,7 +49,9 @@ struct flow_tnl {
|
||
ovs_be16 tp_dst;
|
||
ovs_be16 gbp_id;
|
||
uint8_t gbp_flags;
|
||
- uint8_t pad1[5]; /* Pad to 64 bits. */
|
||
+ uint8_t gpe_np;
|
||
+ uint8_t gpe_flags;
|
||
+ uint8_t pad1[3]; /* Pad to 64 bits. */
|
||
struct tun_metadata metadata;
|
||
};
|
||
|
||
diff --git a/tests/ofproto.at b/tests/ofproto.at
|
||
index fbb6d71..6c7217d 100644
|
||
--- a/tests/ofproto.at
|
||
+++ b/tests/ofproto.at
|
||
@@ -1775,7 +1775,7 @@ head_table () {
|
||
instructions: meter,apply_actions,clear_actions,write_actions,write_metadata,goto_table
|
||
Write-Actions and Apply-Actions features:
|
||
actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue
|
||
- supported on Set-Field: tun_id tun_src tun_dst tun_ipv6_src tun_ipv6_dst tun_flags tun_gbp_id tun_gbp_flags tun_metadata0 dnl
|
||
+ supported on Set-Field: tun_id tun_src tun_dst tun_ipv6_src tun_ipv6_dst tun_flags tun_gbp_id tun_gbp_flags tun_gpe_np tun_gpe_flags tun_metadata0 dnl
|
||
tun_metadata1 tun_metadata2 tun_metadata3 tun_metadata4 tun_metadata5 tun_metadata6 tun_metadata7 tun_metadata8 tun_metadata9 tun_metadata10 tun_metadata11 tun_metadata12 tun_metadata13 tun_metadata14 tun_metadata15 tun_metadata16 tun_metadata17 tun_metadata18 tun_metadata19 tun_metadata20 tun_metadata21 tun_metadata22 tun_metadata23 tun_metadata24 tun_metadata25 tun_metadata26 tun_metadata27 tun_metadata28 tun_metadata29 tun_metadata30 tun_metadata31 tun_metadata32 tun_metadata33 tun_metadata34 tun_metadata35 tun_metadata36 tun_metadata37 tun_metadata38 tun_metadata39 tun_metadata40 tun_metadata41 tun_metadata42 tun_metadata43 tun_metadata44 tun_metadata45 tun_metadata46 tun_metadata47 tun_metadata48 tun_metadata49 tun_metadata50 tun_metadata51 tun_metadata52 tun_metadata53 tun_metadata54 tun_metadata55 tun_metadata56 tun_metadata57 tun_metadata58 tun_metadata59 tun_metadata60 tun_metadata61 tun_metadata62 tun_metadata63 dnl
|
||
metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 xreg0 xreg1 xreg2 xreg3 eth_src eth_dst vlan_tci vlan_vid vlan_pcp mpls_label mpls_tc mpls_ttl ip_src ip_dst ipv6_src ipv6_dst ipv6_label nw_tos ip_dscp nw_ecn nw_ttl arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst icmp_type icmp_code icmpv6_type icmpv6_code nd_target nd_sll nd_tll
|
||
matching:
|
||
@@ -1790,6 +1790,8 @@ metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4
|
||
tun_flags: arbitrary mask
|
||
tun_gbp_id: arbitrary mask
|
||
tun_gbp_flags: arbitrary mask
|
||
+ tun_gpe_np: arbitrary mask
|
||
+ tun_gpe_flags: arbitrary mask
|
||
tun_metadata0: arbitrary mask
|
||
tun_metadata1: arbitrary mask
|
||
tun_metadata2: arbitrary mask
|
||
diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
|
||
index f26f622..dde603d 100644
|
||
--- a/tests/ovs-ofctl.at
|
||
+++ b/tests/ovs-ofctl.at
|
||
@@ -17,6 +17,10 @@ for test_case in \
|
||
'tun_gbp_id=0/0x1 NXM,OXM' \
|
||
'tun_gbp_flags=0 NXM,OXM' \
|
||
'tun_gbp_flags=0/0x1 NXM,OXM' \
|
||
+ 'tun_gpe_np=0 NXM,OXM' \
|
||
+ 'tun_gpe_np=0/0x1 NXM,OXM' \
|
||
+ 'tun_gpe_flags=0 NXM,OXM' \
|
||
+ 'tun_gpe_flags=0/0x1 NXM,OXM' \
|
||
'tun_metadata0=0 NXM,OXM' \
|
||
'tun_metadata0=0/0x1 NXM,OXM' \
|
||
'tun_metadata0 NXM,OXM' \
|
||
--
|
||
1.9.3
|
||
|