From 5d79831435ec4e5bea20cc36c3f83eacf6fd065c Mon Sep 17 00:00:00 2001 From: Yi Yang 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 Signed-off-by: Ricky Li Signed-off-by: Johnson Li Signed-off-by: Yi Yang --- 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 " +#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". * 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