@@ -39,9 +39,18 @@ struct sk_buff;
#define OVS_TUNNEL_KEY_SIZE \
(offsetof(struct ovs_key_ipv4_tunnel, tp_dst) + \
FIELD_SIZEOF(struct ovs_key_ipv4_tunnel, tp_dst))
+/* Used for masking nsp and nsi values in field nsp below */
+#define NSH_M_NSP 0xFFFFFF00
+#define NSH_M_NSI 0x000000FF
+
struct ovs_key_ipv4_tunnel {
__be64 tun_id;
+ __be32 nsp; /* it contains (nsp - 24 bits | nsi - 8 bits) here */
+ __be32 nshc1; /* NSH context headers */
+ __be32 nshc2;
+ __be32 nshc3;
+ __be32 nshc4;
__be32 ipv4_src;
__be32 ipv4_dst;
__be16 tun_flags;
@@ -72,11 +81,21 @@ static inline void __ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info,
__be16 tp_src,
__be16 tp_dst,
__be64 tun_id,
+ __be32 nsp,
+ __be32 nshc1,
+ __be32 nshc2,
+ __be32 nshc3,
+ __be32 nshc4,
__be16 tun_flags,
const void *opts,
u8 opts_len)
{
tun_info->tunnel.tun_id = tun_id;
+ tun_info->tunnel.nsp = nsp;
+ tun_info->tunnel.nshc1 = nshc1;
+ tun_info->tunnel.nshc2 = nshc2;
+ tun_info->tunnel.nshc3 = nshc3;
+ tun_info->tunnel.nshc4 = nshc4;
tun_info->tunnel.ipv4_src = saddr;
tun_info->tunnel.ipv4_dst = daddr;
tun_info->tunnel.ipv4_tos = tos;
@@ -104,6 +123,11 @@ static inline void ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info,
__be16 tp_src,
__be16 tp_dst,
__be64 tun_id,
+ __be32 nsp,
+ __be32 nshc1,
+ __be32 nshc2,
+ __be32 nshc3,
+ __be32 nshc4,
__be16 tun_flags,
const void *opts,
u8 opts_len)
@@ -111,8 +135,10 @@ static inline void ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info,
__ovs_flow_tun_info_init(tun_info, iph->saddr, iph->daddr,
iph->tos, iph->ttl,
tp_src, tp_dst,
- tun_id, tun_flags,
- opts, opts_len);
+ tun_id, nsp,
+ nshc1, nshc2,
+ nshc3, nshc4,
+ tun_flags,opts, opts_len);
}
#define OVS_SW_FLOW_KEY_METADATA_SIZE \
@@ -51,6 +51,8 @@
#include "flow_netlink.h"
#include "vport-vxlan.h"
+#define NSH_M_NSI 0x000000FF
+
struct ovs_len_tbl {
int len;
const struct ovs_len_tbl *next;
@@ -269,6 +271,12 @@ size_t ovs_tun_key_attr_size(void)
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_OAM */
+ + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_NSP */
+ + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_NSI */
+ + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_NC1 */
+ + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_NC2 */
+ + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_NC3 */
+ + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_NC4 */
+ nla_total_size(256) /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */
/* OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS is mutually exclusive with
* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS and covered by it.
@@ -316,6 +324,12 @@ static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1]
[OVS_TUNNEL_KEY_ATTR_TP_SRC] = { .len = sizeof(u16) },
[OVS_TUNNEL_KEY_ATTR_TP_DST] = { .len = sizeof(u16) },
[OVS_TUNNEL_KEY_ATTR_OAM] = { .len = 0 },
+ [OVS_TUNNEL_KEY_ATTR_NSP] = sizeof(u32),
+ [OVS_TUNNEL_KEY_ATTR_NSI] = 1,
+ [OVS_TUNNEL_KEY_ATTR_NSH_C1] = sizeof(u32),
+ [OVS_TUNNEL_KEY_ATTR_NSH_C2] = sizeof(u32),
+ [OVS_TUNNEL_KEY_ATTR_NSH_C3] = sizeof(u32),
+ [OVS_TUNNEL_KEY_ATTR_NSH_C4] = sizeof(u32),
[OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_VARIABLE },
[OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = OVS_ATTR_NESTED,
.next = ovs_vxlan_ext_key_lens },
@@ -543,6 +557,12 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
bool ttl = false;
__be16 tun_flags = 0;
int opts_type = 0;
+ __be32 nsp = 0;
+ __be32 nshc1 = 0;
+ __be32 nshc2 = 0;
+ __be32 nshc3 = 0;
+ __be32 nshc4 = 0;
+
nla_for_each_nested(a, attr, rem) {
int type = nla_type(a);
@@ -601,6 +621,30 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
case OVS_TUNNEL_KEY_ATTR_OAM:
tun_flags |= TUNNEL_OAM;
break;
+ case OVS_TUNNEL_KEY_ATTR_NSP:
+ nsp |= htonl(be32_to_cpu(nla_get_be32(a)) << 8);
+ tun_flags |= TUNNEL_NSP;
+ break;
+ case OVS_TUNNEL_KEY_ATTR_NSI:
+ nsp |= htonl(nla_get_u8(a));
+ tun_flags |= TUNNEL_NSI;
+ break;
+ case OVS_TUNNEL_KEY_ATTR_NSH_C1:
+ nshc1 = nla_get_be32(a);
+ tun_flags |= TUNNEL_NSHC;
+ break;
+ case OVS_TUNNEL_KEY_ATTR_NSH_C2:
+ nshc2 = nla_get_be32(a);
+ tun_flags |= TUNNEL_NSHC;
+ break;
+ case OVS_TUNNEL_KEY_ATTR_NSH_C3:
+ nshc3 = nla_get_be32(a);
+ tun_flags |= TUNNEL_NSHC;
+ break;
+ case OVS_TUNNEL_KEY_ATTR_NSH_C4:
+ nshc4 = nla_get_be32(a);
+ tun_flags |= TUNNEL_NSHC;
+ break;
case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS:
if (opts_type) {
OVS_NLERR(log, "Multiple metadata blocks provided");
@@ -634,6 +678,11 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
}
}
+ SW_FLOW_KEY_PUT(match, tun_key.nsp, nsp, is_mask);
+ SW_FLOW_KEY_PUT(match, tun_key.nshc1, nshc1, is_mask);
+ SW_FLOW_KEY_PUT(match, tun_key.nshc2, nshc2, is_mask);
+ SW_FLOW_KEY_PUT(match, tun_key.nshc3, nshc3, is_mask);
+ SW_FLOW_KEY_PUT(match, tun_key.nshc4, nshc4, is_mask);
SW_FLOW_KEY_PUT(match, tun_key.tun_flags, tun_flags, is_mask);
if (rem > 0) {
@@ -678,6 +727,9 @@ static int __ipv4_tun_to_nlattr(struct sk_buff *skb,
const struct ovs_key_ipv4_tunnel *output,
const void *tun_opts, int swkey_tun_opts_len)
{
+ __be32 nsp = cpu_to_be32(ntohl(output->nsp) >> 8);
+ u8 nsi = ntohl(output->nsp) & NSH_M_NSI;
+
if (output->tun_flags & TUNNEL_KEY &&
nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, output->tun_id))
return -EMSGSIZE;
@@ -707,6 +759,24 @@ static int __ipv4_tun_to_nlattr(struct sk_buff *skb,
if ((output->tun_flags & TUNNEL_OAM) &&
nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM))
return -EMSGSIZE;
+ if (output->tun_flags & TUNNEL_NSP &&
+ nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_NSP, nsp))
+ return -EMSGSIZE;
+ if (output->tun_flags & TUNNEL_NSI &&
+ nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_NSI, nsi))
+ return -EMSGSIZE;
+ if (output->tun_flags & TUNNEL_NSHC &&
+ nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_NSH_C1, output->nshc1))
+ return -EMSGSIZE;
+ if (output->tun_flags & TUNNEL_NSHC &&
+ nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_NSH_C2, output->nshc2))
+ return -EMSGSIZE;
+ if (output->tun_flags & TUNNEL_NSHC &&
+ nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_NSH_C3, output->nshc3))
+ return -EMSGSIZE;
+ if (output->tun_flags & TUNNEL_NSHC &&
+ nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_NSH_C4, output->nshc4))
+ return -EMSGSIZE;
if (tun_opts) {
if (output->tun_flags & TUNNEL_GENEVE_OPT &&
nla_put(skb, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS,
@@ -79,5 +79,6 @@ openvswitch_headers += \
linux/compat/include/net/sock.h \
linux/compat/include/net/stt.h \
linux/compat/include/net/vxlan.h \
+ linux/compat/include/net/nsh.h \
linux/compat/include/net/sctp/checksum.h
EXTRA_DIST += linux/compat/build-aux/export-check-whitelist
@@ -366,6 +366,12 @@ enum ovs_tunnel_key_attr {
OVS_TUNNEL_KEY_ATTR_TP_SRC, /* be16 src Transport Port. */
OVS_TUNNEL_KEY_ATTR_TP_DST, /* be16 dst Transport Port. */
OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS, /* Nested OVS_VXLAN_EXT_* */
+ OVS_TUNNEL_KEY_ATTR_NSP, /* be32 NSH svc path (lower 24 bits) */
+ OVS_TUNNEL_KEY_ATTR_NSI, /* u8 NSH service index*/
+ OVS_TUNNEL_KEY_ATTR_NSH_C1, /* be32 nshc1 */
+ OVS_TUNNEL_KEY_ATTR_NSH_C2, /* be32 nshc2 */
+ OVS_TUNNEL_KEY_ATTR_NSH_C3, /* be32 nshc3 */
+ OVS_TUNNEL_KEY_ATTR_NSH_C4, /* be32 nshc4 */
__OVS_TUNNEL_KEY_ATTR_MAX
};
@@ -80,6 +80,14 @@ struct tnl_ptk_info {
#undef TUNNEL_OPTIONS_PRESENT
#define TUNNEL_OPTIONS_PRESENT (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT)
+#ifndef TUNNEL_NSP
+#define TUNNEL_NSP __cpu_to_be16(0x2000)
+#define TUNNEL_NSI __cpu_to_be16(0x4000)
+#endif
+#ifndef TUNNEL_NSHC
+#define TUNNEL_NSHC __cpu_to_be16(0x8000)
+#endif
+
#define skb_is_encapsulated ovs_skb_is_encapsulated
bool ovs_skb_is_encapsulated(struct sk_buff *skb);
new file mode 100644
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2013, 2014 Cisco Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#ifndef NSH_H
+#define NSH_H 1
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+
+/**
+ * struct nsh_bhdr - Network Service Base Header.
+ * @o: Operations and Management Packet indicator bit
+ * @c: If this bit is set then one or more contexts are in use.
+ * @proto: IEEE Ethertypes to indicate the frame within.
+ * @svc_idx: TTL functionality and location within service path.
+ * @svc_path: To uniquely identify service path.
+ */
+struct nsh_base {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 res1:4;
+ __u8 c:1;
+ __u8 o:1;
+ __u8 ver:2;
+
+ __u8 len:6;
+ __u8 res2:2;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ __u8 ver:2;
+ __u8 o:1;
+ __u8 c:1;
+ __u8 res1:4;
+
+ __u8 res2:2;
+ __u8 len:6;
+#else
+#error "Bitfield Endianess not defined."
+#endif
+ __u8 mdtype;
+ __u8 proto;
+ union {
+ struct {
+ __u8 svc_path[3];
+ __u8 svc_idx;
+ };
+ __be32 b2;
+ };
+};
+
+/**
+ * struct nsh_ctx - Keeps track of NSH context data
+ * @c<1-4>: NSH Contexts.
+ */
+struct nsh_ctx {
+ __be32 c1;
+ __be32 c2;
+ __be32 c3;
+ __be32 c4;
+};
+
+/**
+ * struct nshdr - Network Service header
+ * @nsh_base: Network Service Base Header.
+ * @nsh_ctx: Network Service Context Header.
+ */
+struct nshhdr {
+ struct nsh_base b;
+ struct nsh_ctx c;
+};
+
+
+#define ETH_P_NSH 0x894F /* Ethertype for NSH */
+
+/* NSH Base Header Next Protocol */
+#define NSH_P_IPV4 0x01
+#define NSH_P_IPV6 0x02
+#define NSH_P_ETHERNET 0x03
+
+/* MD Type Registry */
+#define NSH_M_TYPE1 0x01
+#define NSH_M_TYPE2 0x02
+#define NSH_M_EXP1 0xFE
+#define NSH_M_EXP2 0xFF
+
+#define NSH_DST_PORT 4790 /* UDP Port for NSH on VXLAN */
+
+
+#endif /* nsh.h */
@@ -4,8 +4,10 @@
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/udp.h>
+#include <net/nsh.h>
#include <net/gre.h>
+
#include <linux/version.h>
#ifdef HAVE_VXLAN_METADATA
@@ -17,6 +19,14 @@
#ifndef VXLAN_HLEN
/* VXLAN header flags. */
#define VXLAN_HF_VNI 0x08000000
+/* VXLAN-GPE header flags. */
+#define VXLAN_GPE_HF_P 0x04000000
+#define VXLAN_GPE_HF_O 0x01000000
+#define VXLAN_GPE_HF_VER 0x00C00000
+#define VXLAN_GPE_HF_NP 0x0000000F
+
+#define VXLAN_GPE_NP_IS_NSH 4
+
#ifndef VXLAN_HF_GBP
#define VXLAN_HF_GBP 0x80000000
#endif
@@ -24,6 +34,10 @@
#define VXLAN_N_VID (1u << 24)
#define VXLAN_VID_MASK (VXLAN_N_VID - 1)
#define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr))
+#define NSH_HLEN (sizeof(struct udphdr) + \
+ sizeof(struct vxlanhdr) + \
+ sizeof(struct nshhdr))
+
#endif
#ifndef VXLAN_GBP_USED_BITS
@@ -119,7 +133,8 @@ struct rpl_vxlan_sock;
#define vxlan_rcv_t rpl_vxlan_rcv_t
typedef void (vxlan_rcv_t)(struct vxlan_sock *vh, struct sk_buff *skb,
- struct vxlan_metadata *md);
+ struct vxlan_metadata *md, __be32 nsp, __be32 nshc1, __be32 nshc2,
+ __be32 nshc3, __be32 nshc4);
/* per UDP socket information */
struct vxlan_sock {
@@ -144,7 +159,8 @@ void rpl_vxlan_sock_release(struct vxlan_sock *vs);
int rpl_vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb,
__be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df,
__be16 src_port, __be16 dst_port,
- struct vxlan_metadata *md, bool xnet, u32 vxflags);
+ struct vxlan_metadata *md, bool xnet, u32 vxflags,
+ __be32 nsp, __be32 nshc1, __be32 nshc2, __be32 nshc3, __be32 nshc4);
#endif /* !HAVE_VXLAN_METADATA */
#endif
@@ -54,6 +54,7 @@
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/vxlan.h>
+#include <net/nsh.h>
#include "compat.h"
#include "datapath.h"
@@ -68,6 +69,16 @@ struct vxlanhdr {
__be32 vx_vni;
};
+static inline struct vxlanhdr *vxlan_hdr(const struct sk_buff *skb)
+{
+ return (struct vxlanhdr *)(udp_hdr(skb) + 1);
+}
+
+static inline struct nshhdr *nsh_hdr(const struct sk_buff *skb)
+{
+ return (struct nshhdr *)(vxlan_hdr(skb) + 1);
+}
+
/* Callback from net/ipv4/udp.c to receive packets */
static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
{
@@ -75,23 +86,62 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
struct vxlanhdr *vxh;
u32 flags, vni;
struct vxlan_metadata md = {0};
+ struct udphdr *udp;
+ bool isnsh = false;
+ __be32 nsp = 0;
+ __be32 c1 = 0;
+ __be32 c2 = 0;
+ __be32 c3 = 0;
+ __be32 c4 = 0;
+
+ udp = (struct udphdr *)udp_hdr(skb);
+ if (udp->dest == htons(NSH_DST_PORT))
+ isnsh = true;
/* Need Vxlan and inner Ethernet header to be present */
- if (!pskb_may_pull(skb, VXLAN_HLEN))
+ if (!pskb_may_pull(skb, isnsh ? NSH_HLEN : VXLAN_HLEN))
goto error;
- vxh = (struct vxlanhdr *)(udp_hdr(skb) + 1);
+ vxh = vxlan_hdr(skb);
flags = ntohl(vxh->vx_flags);
vni = ntohl(vxh->vx_vni);
- if (flags & VXLAN_HF_VNI) {
- flags &= ~VXLAN_HF_VNI;
- } else {
+ if (isnsh) {
+ if((flags & VXLAN_GPE_HF_P) && ((flags & VXLAN_GPE_HF_NP) == VXLAN_GPE_NP_IS_NSH)){
+ flags &= ~(VXLAN_HF_VNI | VXLAN_GPE_HF_P | VXLAN_GPE_HF_O | VXLAN_GPE_HF_VER | VXLAN_GPE_HF_NP);
+ }
+ else {
+ /* need to set vxlan-gpe header flag for nsh correctly */
+ goto bad_flags;
+ }
+ }
+ else {
+ if (flags & VXLAN_HF_VNI) {
+ flags &= ~VXLAN_HF_VNI;
+ }
+ else {
/* VNI flag always required to be set */
goto bad_flags;
- }
-
- if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB)))
+ }
+ }
+
+ if (isnsh) {
+ struct nshhdr *nsh = nsh_hdr(skb);
+ if (unlikely(nsh->b.svc_idx == 0 || nsh->b.ver ||
+ nsh->b.len != 6 || nsh->b.mdtype != 0x01 ||
+ nsh->b.proto != NSH_P_ETHERNET)) {
+ pr_warn("NSH service index reached zero or not supported\n");
+ goto drop;
+ }
+
+ nsp = nsh->b.b2; /* same as svc_path | htonl(svc_idx) */
+ c1 = nsh->c.c1; /* NSH Contexts */
+ c2 = nsh->c.c2;
+ c3 = nsh->c.c3;
+ c4 = nsh->c.c4;
+ }
+
+ if (iptunnel_pull_header(skb, isnsh ? NSH_HLEN : VXLAN_HLEN, htons(ETH_P_TEB)))
goto drop;
vs = rcu_dereference_sk_user_data(sk);
@@ -101,7 +151,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
/* For backwards compatibility, only allow reserved fields to be
* used by VXLAN extensions if explicitly requested.
*/
- if ((flags & VXLAN_HF_GBP) && (vs->flags & VXLAN_F_GBP)) {
+ if (!isnsh && (flags & VXLAN_HF_GBP) && (vs->flags & VXLAN_F_GBP)) {
struct vxlanhdr_gbp *gbp;
gbp = (struct vxlanhdr_gbp *)vxh;
@@ -130,7 +180,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
}
md.vni = vxh->vx_vni;
- vs->rcv(vs, skb, &md);
+ vs->rcv(vs, skb, &md,nsp, c1, c2, c3, c4);
return 0;
drop:
@@ -183,15 +233,17 @@ static void vxlan_build_gbp_hdr(struct vxlanhdr *vxh, u32 vxflags,
int rpl_vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb,
__be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df,
__be16 src_port, __be16 dst_port,
- struct vxlan_metadata *md, bool xnet, u32 vxflags)
+ struct vxlan_metadata *md, bool xnet, u32 vxflags,
+ __be32 nsp, __be32 nshc1, __be32 nshc2, __be32 nshc3, __be32 nshc4)
{
+ bool isnsh = (dst_port == htons(NSH_DST_PORT));
struct vxlanhdr *vxh;
int min_headroom;
int err;
bool udp_sum = !!(vxflags & VXLAN_F_UDP_CSUM);
min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len
- + VXLAN_HLEN + sizeof(struct iphdr)
+ + (isnsh ? NSH_HLEN : VXLAN_HLEN) + sizeof(struct iphdr)
+ (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0);
/* Need space for new headers (invalidates iph ptr) */
@@ -208,9 +260,28 @@ int rpl_vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb,
skb = udp_tunnel_handle_offloads(skb, udp_sum, true);
if (IS_ERR(skb))
return PTR_ERR(skb);
+ if (isnsh) {
+ struct nshhdr *nsh;
+ uint8_t nsi = ntohl(nsp) & NSH_M_NSI;
+ nsh = (struct nshhdr *) __skb_push(skb, sizeof(*nsh));
+ memset(&nsh->b, 0, sizeof nsh->b);
+ nsh->b.len = 6;
+ nsh->b.mdtype = NSH_M_TYPE1;
+ nsh->b.proto = NSH_P_ETHERNET;
+ /* b2 should precede svc_idx, else svc_idx will be zero */
+ nsh->b.b2 = nsp & htonl(NSH_M_NSP);
+ nsh->b.svc_idx = nsi ? nsi : 0x01;
+ nsh->c.c1 = nshc1;
+ nsh->c.c2 = nshc2;
+ nsh->c.c3 = nshc3;
+ nsh->c.c4 = nshc4;
+ }
vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh));
- vxh->vx_flags = htonl(VXLAN_HF_VNI);
+ if(isnsh)
+ vxh->vx_flags = htonl(VXLAN_GPE_HF_P | (VXLAN_GPE_HF_NP & VXLAN_GPE_NP_IS_NSH)); //set vxlan_gpe nsh header flag
+ else
+ vxh->vx_flags = htonl(VXLAN_HF_VNI);
vxh->vx_vni = md->vni;
if (vxflags & VXLAN_F_GBP)
@@ -92,7 +92,7 @@ static void geneve_rcv(struct geneve_sock *gs, struct sk_buff *skb)
ovs_flow_tun_info_init(&tun_info, ip_hdr(skb),
udp_hdr(skb)->source, udp_hdr(skb)->dest,
- key, flags,
+ key, 0, 0, 0, 0, 0, flags,
geneveh->options, opts_len);
ovs_vport_receive(vport, skb, &tun_info);
@@ -111,7 +111,7 @@ static int gre_rcv(struct sk_buff *skb,
return PACKET_REJECT;
key = key_to_tunnel_id(tpi->key, tpi->seq);
- ovs_flow_tun_info_init(&tun_info, ip_hdr(skb), 0, 0, key,
+ ovs_flow_tun_info_init(&tun_info, ip_hdr(skb), 0, 0, key, 0, 0, 0, 0, 0,
filter_tnl_flags(tpi->flags), NULL, 0);
ovs_vport_receive(vport, skb, &tun_info);
@@ -249,7 +249,7 @@ static int lisp_rcv(struct sock *sk, struct sk_buff *skb)
iph = ip_hdr(skb);
ovs_flow_tun_info_init(&tun_info, iph,
udp_hdr(skb)->source, udp_hdr(skb)->dest,
- key, TUNNEL_KEY, NULL, 0);
+ key, 0, 0, 0, 0, 0, TUNNEL_KEY, NULL, 0);
/* Drop non-IP inner packets */
inner_iph = (struct iphdr *)(lisph + 1);
@@ -53,7 +53,7 @@ static void stt_rcv(struct stt_sock *stt_sock, struct sk_buff *skb)
ovs_flow_tun_info_init(&tun_info, ip_hdr(skb),
tcp_hdr(skb)->source, tcp_hdr(skb)->dest,
- get_unaligned(&stth->key),
+ get_unaligned(&stth->key), 0, 0, 0, 0, 0,
TUNNEL_KEY | TUNNEL_CSUM,
NULL, 0);
do {
@@ -63,7 +63,8 @@ static inline struct vxlan_port *vxlan_vport(const struct vport *vport)
}
static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
- struct vxlan_metadata *md)
+ struct vxlan_metadata *md, __be32 nsp, __be32 nshc1, __be32 nshc2,
+ __be32 nshc3, __be32 nshc4)
{
struct ovs_tunnel_info tun_info;
struct vxlan_port *vxlan_port;
@@ -75,7 +76,7 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
__be64 key;
__be16 flags;
- flags = TUNNEL_KEY | (udp_hdr(skb)->check != 0 ? TUNNEL_CSUM : 0);
+ flags = TUNNEL_KEY |TUNNEL_NSP |TUNNEL_NSI |TUNNEL_NSHC | (udp_hdr(skb)->check != 0 ? TUNNEL_CSUM : 0);
vxlan_port = vxlan_vport(vport);
if (vxlan_port->exts & VXLAN_F_GBP && md->gbp)
flags |= TUNNEL_VXLAN_OPT;
@@ -85,7 +86,8 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
key = cpu_to_be64(ntohl(md->vni) >> 8);
ovs_flow_tun_info_init(&tun_info, iph,
udp_hdr(skb)->source, udp_hdr(skb)->dest,
- key, flags, &opts, sizeof(opts));
+ key, nsp, nshc1, nshc2, nshc3, nshc4,
+ flags, &opts, sizeof(opts));
ovs_vport_receive(vport, skb, &tun_info);
}
@@ -265,7 +267,12 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
tun_key->ipv4_tos,
tun_key->ipv4_ttl, df,
src_port, dst_port,
- &md, false, vxflags);
+ &md, false, vxflags,
+ tun_key->nsp,
+ tun_key->nshc1,
+ tun_key->nshc2,
+ tun_key->nshc3,
+ tun_key->nshc4);
if (err < 0)
ip_rt_put(rt);
return err;
@@ -624,6 +624,11 @@ int ovs_tunnel_get_egress_info(struct ovs_tunnel_info *egress_tun_info,
tun_key->ipv4_ttl,
tp_src, tp_dst,
tun_key->tun_id,
+ tun_key->nsp,
+ tun_key->nshc1,
+ tun_key->nshc2,
+ tun_key->nshc3,
+ tun_key->nshc4,
tun_key->tun_flags,
tun_info->options,
tun_info->options_len);
@@ -854,6 +854,18 @@ flow_tun_flag_to_string(uint32_t flags)
return "key";
case FLOW_TNL_F_OAM:
return "oam";
+ case FLOW_TNL_F_NSP:
+ return "nsp";
+ case FLOW_TNL_F_NSI:
+ return "nsi";
+ case FLOW_TNL_F_NSH_C1:
+ return "nshc1";
+ case FLOW_TNL_F_NSH_C2:
+ return "nshc2";
+ case FLOW_TNL_F_NSH_C3:
+ return "nshc3";
+ case FLOW_TNL_F_NSH_C4:
+ return "nshc4";
default:
return NULL;
}
@@ -1152,6 +1164,24 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
if (flow->tunnel.flags & FLOW_TNL_F_KEY) {
WC_MASK_FIELD(wc, tunnel.tun_id);
}
+ if (flow->tunnel.flags & FLOW_TNL_F_NSP) {
+ WC_MASK_FIELD(wc, tunnel.nsp);
+ }
+ if (flow->tunnel.flags & FLOW_TNL_F_NSI) {
+ WC_MASK_FIELD(wc, tunnel.nsi);
+ }
+ if (flow->tunnel.flags & FLOW_TNL_F_NSH_C1) {
+ WC_MASK_FIELD(wc, tunnel.nshc1);
+ }
+ if (flow->tunnel.flags & FLOW_TNL_F_NSH_C2) {
+ WC_MASK_FIELD(wc, tunnel.nshc2);
+ }
+ if (flow->tunnel.flags & FLOW_TNL_F_NSH_C3) {
+ WC_MASK_FIELD(wc, tunnel.nshc3);
+ }
+ if (flow->tunnel.flags & FLOW_TNL_F_NSH_C4) {
+ WC_MASK_FIELD(wc, tunnel.nshc4);
+ }
WC_MASK_FIELD(wc, tunnel.ip_src);
WC_MASK_FIELD(wc, tunnel.ip_dst);
WC_MASK_FIELD(wc, tunnel.flags);
@@ -1177,6 +1207,24 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
WC_MASK_FIELD(wc, tunnel.tun_id);
}
+ if (flow->tunnel.nsp) {
+ WC_MASK_FIELD(wc, tunnel.nsp);
+ }
+ if (flow->tunnel.nsi) {
+ WC_MASK_FIELD(wc, tunnel.nsi);
+ }
+ if (flow->tunnel.nshc1) {
+ WC_MASK_FIELD(wc, tunnel.nshc1);
+ }
+ if (flow->tunnel.nshc2) {
+ WC_MASK_FIELD(wc, tunnel.nshc2);
+ }
+ if (flow->tunnel.nshc3) {
+ WC_MASK_FIELD(wc, tunnel.nshc3);
+ }
+ if (flow->tunnel.nshc4) {
+ WC_MASK_FIELD(wc, tunnel.nshc4);
+ }
/* metadata, regs, and conj_id wildcarded. */
WC_MASK_FIELD(wc, skb_priority);
@@ -736,6 +736,86 @@ match_set_nd_target_masked(struct match *match,
match->wc.masks.nd_target = *mask;
}
+void
+match_set_nsp_masked(struct match *match, ovs_be32 nsp, ovs_be32 mask)
+{
+ match->wc.masks.tunnel.nsp = mask;
+ match->flow.tunnel.nsp = nsp & mask;
+}
+
+void
+match_set_nsi_masked(struct match *match, uint8_t nsi, uint8_t mask)
+{
+ match->wc.masks.tunnel.nsi = mask;
+ match->flow.tunnel.nsi = nsi & mask;
+}
+
+void
+match_set_nshc1_masked(struct match *match, ovs_be32 nshc1, ovs_be32 mask)
+{
+ match->wc.masks.tunnel.nshc1 = mask;
+ match->flow.tunnel.nshc1 = nshc1 & mask;
+}
+
+void
+match_set_nshc2_masked(struct match *match, ovs_be32 nshc2, ovs_be32 mask)
+{
+ match->wc.masks.tunnel.nshc2 = mask;
+ match->flow.tunnel.nshc2 = nshc2 & mask;
+}
+
+void
+match_set_nshc3_masked(struct match *match, ovs_be32 nshc3, ovs_be32 mask)
+{
+ match->wc.masks.tunnel.nshc3 = mask;
+ match->flow.tunnel.nshc3 = nshc3 & mask;
+}
+
+void
+match_set_nshc4_masked(struct match *match, ovs_be32 nshc4, ovs_be32 mask)
+{
+ match->wc.masks.tunnel.nshc4 = mask;
+ match->flow.tunnel.nshc4 = nshc4 & mask;
+}
+
+void
+match_set_nsp(struct match *match, ovs_be32 nsp)
+{
+ match_set_nsp_masked(match, nsp, OVS_BE32_MAX);
+}
+
+
+void
+match_set_nsi(struct match *match, uint8_t nsi)
+{
+ match_set_nsi_masked(match, nsi, UINT8_MAX);
+}
+
+void
+match_set_nshc1(struct match *match, ovs_be32 nshc1)
+{
+ match_set_nshc1_masked(match, nshc1, OVS_BE32_MAX);
+}
+
+void
+match_set_nshc2(struct match *match, ovs_be32 nshc2)
+{
+ match_set_nshc2_masked(match, nshc2, OVS_BE32_MAX);
+}
+
+void
+match_set_nshc3(struct match *match, ovs_be32 nshc3)
+{
+ match_set_nshc3_masked(match, nshc3, OVS_BE32_MAX);
+}
+
+void
+match_set_nshc4(struct match *match, ovs_be32 nshc4)
+{
+ match_set_nshc4_masked(match, nshc4, OVS_BE32_MAX);
+}
+
+
/* Returns true if 'a' and 'b' wildcard the same fields and have the same
* values for fixed fields, otherwise false. */
bool
@@ -880,6 +960,16 @@ format_flow_tunnel(struct ds *s, const struct match *match)
const struct flow_tnl *tnl = &match->flow.tunnel;
format_be64_masked(s, "tun_id", tnl->tun_id, wc->masks.tunnel.tun_id);
+ format_be32_masked(s, "nsp", tnl->nsp, wc->masks.tunnel.nsp);
+ format_be32_masked(s, "nshc1", tnl->nshc1, wc->masks.tunnel.nshc1);
+ format_be32_masked(s, "nshc2", tnl->nshc2, wc->masks.tunnel.nshc2);
+ format_be32_masked(s, "nshc3", tnl->nshc3, wc->masks.tunnel.nshc3);
+ format_be32_masked(s, "nshc4", tnl->nshc4, wc->masks.tunnel.nshc4);
+
+ if (wc->masks.tunnel.nsi) {
+ ds_put_format(s, "nsi=%"PRIu8",", tnl->nsi);
+ }
+
format_ip_netmask(s, "tun_src", tnl->ip_src, wc->masks.tunnel.ip_src);
format_ip_netmask(s, "tun_dst", tnl->ip_dst, wc->masks.tunnel.ip_dst);
@@ -146,6 +146,20 @@ void match_set_nd_target(struct match *, const struct in6_addr *);
void match_set_nd_target_masked(struct match *, const struct in6_addr *,
const struct in6_addr *);
+void match_set_nsp_masked(struct match *, ovs_be32 nsp, ovs_be32 mask);
+void match_set_nsi_masked(struct match *match, uint8_t nsi, uint8_t mask);
+void match_set_nshc1_masked(struct match *, ovs_be32 nshc1, ovs_be32 mask);
+void match_set_nshc2_masked(struct match *, ovs_be32 nshc2, ovs_be32 mask);
+void match_set_nshc3_masked(struct match *, ovs_be32 nshc3, ovs_be32 mask);
+void match_set_nshc4_masked(struct match *, ovs_be32 nshc4, ovs_be32 mask);
+
+void match_set_nsp(struct match *, ovs_be32 nsp);
+void match_set_nsi(struct match *match, uint8_t nsi);
+void match_set_nshc1(struct match *, ovs_be32 nshc1);
+void match_set_nshc2(struct match *, ovs_be32 nshc2);
+void match_set_nshc3(struct match *, ovs_be32 nshc3);
+void match_set_nshc4(struct match *, ovs_be32 nshc4);
+
bool match_equal(const struct match *, const struct match *);
uint32_t match_hash(const struct match *, uint32_t basis);
@@ -205,6 +205,18 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
CASE_MFF_TUN_METADATA:
return !ULLONG_GET(wc->masks.tunnel.metadata.present.map,
mf->id - MFF_TUN_METADATA0);
+ case MFF_NSP:
+ return !wc->masks.tunnel.nsp;
+ case MFF_NSI:
+ return !wc->masks.tunnel.nsi;
+ case MFF_NSH_C1:
+ return !wc->masks.tunnel.nshc1;
+ case MFF_NSH_C2:
+ return !wc->masks.tunnel.nshc2;
+ case MFF_NSH_C3:
+ return !wc->masks.tunnel.nshc3;
+ case MFF_NSH_C4:
+ return !wc->masks.tunnel.nshc4;
case MFF_METADATA:
return !wc->masks.metadata;
case MFF_IN_PORT:
@@ -526,6 +538,12 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
case MFF_ND_TARGET:
case MFF_ND_SLL:
case MFF_ND_TLL:
+ case MFF_NSP:
+ case MFF_NSI:
+ case MFF_NSH_C1:
+ case MFF_NSH_C2:
+ case MFF_NSH_C3:
+ case MFF_NSH_C4:
return true;
case MFF_IN_PORT_OXM:
@@ -788,6 +806,27 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
value->ipv6 = flow->nd_target;
break;
+ case MFF_NSP:
+ value->be32 = flow->tunnel.nsp;
+ break;
+
+ case MFF_NSI:
+ value->u8 = flow->tunnel.nsi;
+ break;
+
+ case MFF_NSH_C1:
+ value->be32 = flow->tunnel.nshc1;
+ break;
+ case MFF_NSH_C2:
+ value->be32 = flow->tunnel.nshc2;
+ break;
+ case MFF_NSH_C3:
+ value->be32 = flow->tunnel.nshc3;
+ break;
+ case MFF_NSH_C4:
+ value->be32 = flow->tunnel.nshc4;
+ break;
+
case MFF_N_IDS:
default:
OVS_NOT_REACHED();
@@ -1020,6 +1059,30 @@ mf_set_value(const struct mf_field *mf,
match_set_nd_target(match, &value->ipv6);
break;
+ case MFF_NSP:
+ match_set_nsp(match, value->be32);
+ break;
+
+ case MFF_NSI:
+ match_set_nsi(match, value->u8);
+ break;
+
+ case MFF_NSH_C1:
+ match_set_nshc1(match, value->be32);
+ break;
+
+ case MFF_NSH_C2:
+ match_set_nshc2(match, value->be32);
+ break;
+
+ case MFF_NSH_C3:
+ match_set_nshc3(match, value->be32);
+ break;
+
+ case MFF_NSH_C4:
+ match_set_nshc4(match, value->be32);
+ break;
+
case MFF_N_IDS:
default:
OVS_NOT_REACHED();
@@ -1307,6 +1370,30 @@ mf_set_flow_value(const struct mf_field *mf,
flow->nd_target = value->ipv6;
break;
+ case MFF_NSP:
+ flow->tunnel.nsp = value->be32;
+ break;
+
+ case MFF_NSI:
+ flow->tunnel.nsi = value->u8;
+ break;
+
+ case MFF_NSH_C1:
+ flow->tunnel.nshc1 = value->be32;
+ break;
+
+ case MFF_NSH_C2:
+ flow->tunnel.nshc2 = value->be32;
+ break;
+
+ case MFF_NSH_C3:
+ flow->tunnel.nshc3 = value->be32;
+ break;
+
+ case MFF_NSH_C4:
+ flow->tunnel.nshc4 = value->be32;
+ break;
+
case MFF_N_IDS:
default:
OVS_NOT_REACHED();
@@ -1595,6 +1682,30 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str)
memset(&match->flow.nd_target, 0, sizeof match->flow.nd_target);
break;
+ case MFF_NSP:
+ match_set_nsp_masked(match, htonl(0), htonl(0));
+ break;
+
+ case MFF_NSI:
+ match_set_nsi_masked(match, 0, 0);
+ break;
+
+ case MFF_NSH_C1:
+ match_set_nshc1_masked(match, htonl(0), htonl(0));
+ break;
+
+ case MFF_NSH_C2:
+ match_set_nshc2_masked(match, htonl(0), htonl(0));
+ break;
+
+ case MFF_NSH_C3:
+ match_set_nshc3_masked(match, htonl(0), htonl(0));
+ break;
+
+ case MFF_NSH_C4:
+ match_set_nshc4_masked(match, htonl(0), htonl(0));
+ break;
+
case MFF_N_IDS:
default:
OVS_NOT_REACHED();
@@ -1793,6 +1904,30 @@ mf_set(const struct mf_field *mf,
match_set_tcp_flags_masked(match, value->be16, mask->be16);
break;
+ case MFF_NSP:
+ match_set_nsp_masked(match, value->be32, mask->be32);
+ break;
+
+ case MFF_NSI:
+ match_set_nsi_masked(match, value->u8, mask->u8);
+ break;
+
+ case MFF_NSH_C1:
+ match_set_nshc1_masked(match, value->be32, mask->be32);
+ break;
+
+ case MFF_NSH_C2:
+ match_set_nshc2_masked(match, value->be32, mask->be32);
+ break;
+
+ case MFF_NSH_C3:
+ match_set_nshc3_masked(match, value->be32, mask->be32);
+ break;
+
+ case MFF_NSH_C4:
+ match_set_nshc4_masked(match, value->be32, mask->be32);
+ break;
+
case MFF_N_IDS:
default:
OVS_NOT_REACHED();
@@ -1566,6 +1566,108 @@ enum OVS_PACKED_ENUM mf_field_id {
*/
MFF_ND_TLL,
+ /* "nsp".
+ *
+ * For a packet received via a VXLAN tunnel including a (32-bit)
+ * network service header service path (nsp), the nsp is stored
+ * in the low 24-bits and the high bits are zeroed. For
+ * other packets, the value is 0.
+ *
+ * Type: be32.
+ * Maskable: bitwise.
+ * Formatting: hexadecimal.
+ * Prerequisites: none.
+ * Access: read/write.
+ * NXM: NXM_NX_NSP(105) since v1.1.
+ * OXM: none.
+ * Prefix lookup member: tunnel.nsp.
+ */
+ MFF_NSP,
+
+ /* "nsi".
+ *
+ * For a packet received via a VXLAN tunnel, it includes a (8-bit)
+ * network service header service index (nsi).
+ *
+ * Type: u8.
+ * Maskable: bitwise.
+ * Formatting: decimal.
+ * Prerequisites: none.
+ * Access: read/write.
+ * NXM: NXM_NX_NSI(106) since v1.1.
+ * OXM: none.
+ * Prefix lookup member: tunnel.nsi.
+ */
+ MFF_NSI,
+
+ /* "nshc1".
+ *
+ * For a packet received via a VXLAN tunnel including a (32-bit)
+ * Network Platform Context (nshc1), the nshc1 is stored
+ * in the 32-bits. For other packets, the value is 0.
+ *
+ * Type: be32.
+ * Maskable: bitwise.
+ * Formatting: hexadecimal.
+ * Prerequisites: none.
+ * Access: read/write.
+ * NXM: NXM_NX_NSH_C1(107) since v1.1.
+ * OXM: none.
+ * Prefix lookup member: tunnel.nshc1.
+ */
+ MFF_NSH_C1,
+
+ /* "nshc2".
+ *
+ * For a packet received via a VXLAN tunnel including a (32-bit)
+ * Network Shared Context (nshc2), the nshc2 is stored
+ * in the 32-bits. For other packets, the value is 0.
+ *
+ * Type: be32.
+ * Maskable: bitwise.
+ * Formatting: hexadecimal.
+ * Prerequisites: none.
+ * Access: read/write.
+ * NXM: NXM_NX_NSH_C2(108) since v1.1.
+ * OXM: none.
+ * Prefix lookup member: tunnel.nshc2.
+ */
+ MFF_NSH_C2,
+
+ /* "nshc3".
+ *
+ * For a packet received via a VXLAN tunnel including a (32-bit)
+ * Service Platform Context (nshc3), the nshc3 is stored
+ * in the 32-bits. For other packets, the value is 0.
+ *
+ * Type: be32.
+ * Maskable: bitwise.
+ * Formatting: hexadecimal.
+ * Prerequisites: none.
+ * Access: read/write.
+ * NXM: NXM_NX_NSH_C3(109) since v1.1.
+ * OXM: none.
+ * Prefix lookup member: tunnel.nshc3.
+ */
+ MFF_NSH_C3,
+
+ /* "nshc4".
+ *
+ * For a packet received via a VXLAN tunnel including a (32-bit)
+ * Service Shared Context (nshc4), the nshc4 is stored
+ * in the 32-bits. For other packets, the value is 0.
+ *
+ * Type: be32.
+ * Maskable: bitwise.
+ * Formatting: hexadecimal.
+ * Prerequisites: none.
+ * Access: read/write.
+ * NXM: NXM_NX_NSH_C4(110) since v1.1.
+ * OXM: none.
+ * Prefix lookup member: tunnel.nshc4.
+ */
+ MFF_NSH_C4,
+
MFF_N_IDS
};
@@ -424,6 +424,86 @@ parse_key(const struct smap *args, const char *name,
}
}
+static ovs_be32
+parse_nsp(const struct smap *args, const char *name,
+ bool *present, bool *flow)
+{
+ const char *s;
+
+ *present = false;
+ *flow = false;
+
+ s = smap_get(args, name);
+ if (!s) {
+ s = smap_get(args, "nsp");
+ if (!s) {
+ return 0;
+ }
+ }
+
+ *present = true;
+
+ if (!strcmp(s, "flow")) {
+ *flow = true;
+ return 0;
+ } else {
+ return htonl(strtoul(s, NULL, 0));
+ }
+}
+static uint8_t
+parse_nsi(const struct smap *args, const char *name,
+ bool *present, bool *flow)
+{
+ const char *s;
+
+ *present = false;
+ *flow = false;
+
+ s = smap_get(args, name);
+ if (!s) {
+ s = smap_get(args, "nsi");
+ if (!s) {
+ return 0;
+ }
+ }
+
+ *present = true;
+
+ if (!strcmp(s, "flow")) {
+ *flow = true;
+ return 0;
+ } else {
+ return strtoul(s, NULL, 0);
+ }
+}
+
+static ovs_be32
+parse_nshc(const struct smap *args, const char *nsh_ele,const char *name,
+ bool *present, bool *flow)
+{
+ const char *s;
+
+ *present = false;
+ *flow = false;
+
+ s = smap_get(args, name);
+ if (!s) {
+ s = smap_get(args, nsh_ele);
+ if (!s) {
+ return 0;
+ }
+ }
+
+ *present = true;
+
+ if (!strcmp(s, "flow")) {
+ *flow = true;
+ return 0;
+ } else {
+ return htonl(strtoul(s, NULL, 0));
+ }
+}
+
static int
set_tunnel_config(struct netdev *dev_, const struct smap *args)
{
@@ -563,6 +643,30 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args)
}
free(str);
+ } else if (!strcmp(node->key, "nsp") ||
+ !strcmp(node->key, "in_nsp") ||
+ !strcmp(node->key, "out_nsp")) {
+ /* Handled separately below. */
+ } else if (!strcmp(node->key, "nsi") ||
+ !strcmp(node->key, "in_nsi") ||
+ !strcmp(node->key, "out_nsi")) {
+ /* Handled separately below. */
+ } else if (!strcmp(node->key, "nshc1") ||
+ !strcmp(node->key, "in_nshc1") ||
+ !strcmp(node->key, "out_nshc1")) {
+ /* Handled separately below. */
+ } else if (!strcmp(node->key, "nshc2") ||
+ !strcmp(node->key, "in_nshc2") ||
+ !strcmp(node->key, "out_nshc2")) {
+ /* Handled separately below. */
+ } else if (!strcmp(node->key, "nshc3") ||
+ !strcmp(node->key, "in_nshc3") ||
+ !strcmp(node->key, "out_nshc3")) {
+ /* Handled separately below. */
+ } else if (!strcmp(node->key, "nshc4") ||
+ !strcmp(node->key, "in_nshc4") ||
+ !strcmp(node->key, "out_nshc4")) {
+ /* Handled separately below. */
} else {
VLOG_WARN("%s: unknown %s argument '%s'", name, type, node->key);
}
@@ -623,6 +727,65 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args)
&tnl_cfg.out_key_present,
&tnl_cfg.out_key_flow);
+ if (tnl_cfg.dst_port == htons(VXGPE_DST_PORT)) {
+ tnl_cfg.in_nsp = parse_nsp(args, "in_nsp",
+ &tnl_cfg.in_nsp_present,
+ &tnl_cfg.in_nsp_flow);
+
+ tnl_cfg.out_nsp = parse_nsp(args, "out_nsp",
+ &tnl_cfg.out_nsp_present,
+ &tnl_cfg.out_nsp_flow);
+
+ tnl_cfg.in_nsi = parse_nsi(args, "in_nsi",
+ &tnl_cfg.in_nsi_present,
+ &tnl_cfg.in_nsi_flow);
+
+ tnl_cfg.out_nsi = parse_nsi(args, "out_nsi",
+ &tnl_cfg.out_nsi_present,
+ &tnl_cfg.out_nsi_flow);
+
+ tnl_cfg.in_nshc1 = parse_nshc(args, "nshc1", "in_nshc1",
+ &tnl_cfg.in_nshc1_present,
+ &tnl_cfg.in_nshc1_flow);
+
+ tnl_cfg.out_nshc1 = parse_nshc(args, "nshc1", "out_nshc1",
+ &tnl_cfg.out_nshc1_present,
+ &tnl_cfg.out_nshc1_flow);
+
+ tnl_cfg.in_nshc2 = parse_nshc(args, "nshc2", "in_nshc2",
+ &tnl_cfg.in_nshc2_present,
+ &tnl_cfg.in_nshc2_flow);
+
+ tnl_cfg.out_nshc2 = parse_nshc(args, "nshc2", "out_nshc2",
+ &tnl_cfg.out_nshc2_present,
+ &tnl_cfg.out_nshc2_flow);
+
+ tnl_cfg.in_nshc3 = parse_nshc(args, "nshc3", "in_nshc3",
+ &tnl_cfg.in_nshc3_present,
+ &tnl_cfg.in_nshc3_flow);
+
+ tnl_cfg.out_nshc3 = parse_nshc(args, "nshc3", "out_nshc3",
+ &tnl_cfg.out_nshc3_present,
+ &tnl_cfg.out_nshc3_flow);
+
+ tnl_cfg.in_nshc4 = parse_nshc(args, "nshc4", "in_nshc4",
+ &tnl_cfg.in_nshc4_present,
+ &tnl_cfg.in_nshc4_flow);
+
+ tnl_cfg.out_nshc4 = parse_nshc(args, "nshc4", "out_nshc4",
+ &tnl_cfg.out_nshc4_present,
+ &tnl_cfg.out_nshc4_flow);
+
+ /* Default nsh service index is 1, if lower packet is dropped */
+ if (!tnl_cfg.in_nsi) {
+ tnl_cfg.in_nsi = 1;
+ }
+
+ if (!tnl_cfg.out_nsi) {
+ tnl_cfg.out_nsi = 1;
+ }
+ }
+
ovs_mutex_lock(&dev->mutex);
if (memcmp(&dev->tnl_cfg, &tnl_cfg, sizeof tnl_cfg)) {
dev->tnl_cfg = tnl_cfg;
@@ -709,6 +872,130 @@ get_tunnel_config(const struct netdev *dev, struct smap *args)
smap_add(args, "df_default", "false");
}
+ if (tnl_cfg.in_nsp_flow && tnl_cfg.out_nsp_flow) {
+ smap_add(args, "nsp", "flow");
+ } else if (tnl_cfg.in_nsp_present && tnl_cfg.out_nsp_present
+ && tnl_cfg.in_nsp == tnl_cfg.out_nsp) {
+ smap_add_format(args, "nsp", "%#"PRIx32, ntohl(tnl_cfg.in_nsp));
+ } else {
+ if (tnl_cfg.in_nsp_flow) {
+ smap_add(args, "in_nsp", "flow");
+ } else if (tnl_cfg.in_nsp_present) {
+ smap_add_format(args, "in_nsp", "%#"PRIx32,
+ ntohl(tnl_cfg.in_nsp));
+ }
+
+ if (tnl_cfg.out_nsp_flow) {
+ smap_add(args, "out_nsp", "flow");
+ } else if (tnl_cfg.out_nsp_present) {
+ smap_add_format(args, "out_nsp", "%#"PRIx32,
+ ntohl(tnl_cfg.out_nsp));
+ }
+ }
+
+ if (tnl_cfg.in_nsi_flow && tnl_cfg.out_nsi_flow) {
+ smap_add(args, "nsi", "flow");
+ } else if (tnl_cfg.in_nsi_present && tnl_cfg.out_nsi_present
+ && tnl_cfg.in_nsi == tnl_cfg.out_nsi) {
+ smap_add_format(args, "nsi", "%"PRIu8, tnl_cfg.in_nsi);
+ } else {
+ if (tnl_cfg.in_nsi_flow) {
+ smap_add(args, "in_nsi", "flow");
+ } else if (tnl_cfg.in_nsi_present) {
+ smap_add_format(args, "in_nsi", "%"PRIu8, tnl_cfg.in_nsi);
+ }
+
+ if (tnl_cfg.out_nsi_flow) {
+ smap_add(args, "out_nsi", "flow");
+ } else if (tnl_cfg.out_nsi_present) {
+ smap_add_format(args, "out_nsi", "%"PRIu8, tnl_cfg.out_nsi);
+ }
+ }
+
+ if (tnl_cfg.in_nshc1_flow && tnl_cfg.out_nshc1_flow) {
+ smap_add(args, "nshc1", "flow");
+ } else if (tnl_cfg.in_nshc1_present && tnl_cfg.out_nshc1_present
+ && tnl_cfg.in_nshc1 == tnl_cfg.out_nshc1) {
+ smap_add_format(args, "nshc1", "%#"PRIx32, ntohl(tnl_cfg.in_nshc1));
+ } else {
+ if (tnl_cfg.in_nshc1_flow) {
+ smap_add(args, "in_nshc1", "flow");
+ } else if (tnl_cfg.in_nshc1_present) {
+ smap_add_format(args, "in_nshc1", "%#"PRIx32,
+ ntohl(tnl_cfg.in_nshc1));
+ }
+
+ if (tnl_cfg.out_nshc1_flow) {
+ smap_add(args, "out_nshc1", "flow");
+ } else if (tnl_cfg.out_nshc1_present) {
+ smap_add_format(args, "out_nshc1", "%#"PRIx32,
+ ntohl(tnl_cfg.out_nshc1));
+ }
+ }
+
+ if (tnl_cfg.in_nshc2_flow && tnl_cfg.out_nshc2_flow) {
+ smap_add(args, "nshc2", "flow");
+ } else if (tnl_cfg.in_nshc2_present && tnl_cfg.out_nshc2_present
+ && tnl_cfg.in_nshc2 == tnl_cfg.out_nshc2) {
+ smap_add_format(args, "nshc2", "%#"PRIx32, ntohl(tnl_cfg.in_nshc2));
+ } else {
+ if (tnl_cfg.in_nshc2_flow) {
+ smap_add(args, "in_nshc2", "flow");
+ } else if (tnl_cfg.in_nshc2_present) {
+ smap_add_format(args, "in_nshc2", "%#"PRIx32,
+ ntohl(tnl_cfg.in_nshc2));
+ }
+
+ if (tnl_cfg.out_nshc2_flow) {
+ smap_add(args, "out_nshc2", "flow");
+ } else if (tnl_cfg.out_nshc2_present) {
+ smap_add_format(args, "out_nshc2", "%#"PRIx32,
+ ntohl(tnl_cfg.out_nshc2));
+ }
+ }
+
+ if (tnl_cfg.in_nshc3_flow && tnl_cfg.out_nshc3_flow) {
+ smap_add(args, "nshc3", "flow");
+ } else if (tnl_cfg.in_nshc3_present && tnl_cfg.out_nshc3_present
+ && tnl_cfg.in_nshc3 == tnl_cfg.out_nshc3) {
+ smap_add_format(args, "nshc3", "%#"PRIx32, ntohl(tnl_cfg.in_nshc3));
+ } else {
+ if (tnl_cfg.in_nshc3_flow) {
+ smap_add(args, "in_nshc3", "flow");
+ } else if (tnl_cfg.in_nshc3_present) {
+ smap_add_format(args, "in_nshc3", "%#"PRIx32,
+ ntohl(tnl_cfg.in_nshc3));
+ }
+
+ if (tnl_cfg.out_nshc3_flow) {
+ smap_add(args, "out_nshc3", "flow");
+ } else if (tnl_cfg.out_nshc3_present) {
+ smap_add_format(args, "out_nshc3", "%#"PRIx32,
+ ntohl(tnl_cfg.out_nshc3));
+ }
+ }
+
+ if (tnl_cfg.in_nshc4_flow && tnl_cfg.out_nshc4_flow) {
+ smap_add(args, "nshc4", "flow");
+ } else if (tnl_cfg.in_nshc4_present && tnl_cfg.out_nshc4_present
+ && tnl_cfg.in_nshc4 == tnl_cfg.out_nshc4) {
+ smap_add_format(args, "nshc4", "%#"PRIx32, ntohl(tnl_cfg.in_nshc4));
+ } else {
+ if (tnl_cfg.in_nshc4_flow) {
+ smap_add(args, "in_nshc4", "flow");
+ } else if (tnl_cfg.in_nshc4_present) {
+ smap_add_format(args, "in_nshc4", "%#"PRIx32,
+ ntohl(tnl_cfg.in_nshc4));
+ }
+
+ if (tnl_cfg.out_nshc4_flow) {
+ smap_add(args, "out_nshc4", "flow");
+ } else if (tnl_cfg.out_nshc4_present) {
+ smap_add_format(args, "out_nshc4", "%#"PRIx32,
+ ntohl(tnl_cfg.out_nshc4));
+ }
+ }
+
return 0;
}
@@ -1356,7 +1643,6 @@ netdev_vport_range(struct unixctl_conn *conn, int argc,
unixctl_command_reply(conn, "OK");
}
-
#define VPORT_FUNCTIONS(GET_CONFIG, SET_CONFIG, \
GET_TUNNEL_CONFIG, GET_STATUS, \
BUILD_HEADER, \
@@ -1427,6 +1713,7 @@ netdev_vport_range(struct unixctl_conn *conn, int argc,
NULL, /* rx_drain */
+
#define TUNNEL_CLASS(NAME, DPIF_PORT, BUILD_HEADER, PUSH_HEADER, POP_HEADER) \
{ DPIF_PORT, \
{ NAME, VPORT_FUNCTIONS(get_tunnel_config, \
@@ -106,6 +106,22 @@ struct netdev_stats {
/* Configuration specific to tunnels. */
struct netdev_tunnel_config {
+ bool in_nsp_present;
+ bool in_nsp_flow;
+ ovs_be32 in_nsp; /* incoming NSH service path */
+
+ bool out_nsp_present;
+ bool out_nsp_flow;
+ ovs_be32 out_nsp; /* outgoing NSH service path */
+
+ bool in_nsi_present;
+ bool in_nsi_flow;
+ uint8_t in_nsi; /* incoming NSH service index */
+
+ bool out_nsi_present;
+ bool out_nsi_flow;
+ uint8_t out_nsi; /* outgoing NSH service index */
+
bool in_key_present;
bool in_key_flow;
ovs_be64 in_key;
@@ -132,6 +148,39 @@ struct netdev_tunnel_config {
bool csum;
bool ipsec;
bool dont_fragment;
+
+ bool in_nshc1_present;
+ bool in_nshc1_flow;
+ ovs_be32 in_nshc1; /* incoming NSH context c1 */
+
+ bool out_nshc1_present;
+ bool out_nshc1_flow;
+ ovs_be32 out_nshc1; /* outgoing NSH context c1 */
+
+ bool in_nshc2_present;
+ bool in_nshc2_flow;
+ ovs_be32 in_nshc2; /* incoming NSH context c2 */
+
+ bool out_nshc2_present;
+ bool out_nshc2_flow;
+ ovs_be32 out_nshc2; /* outgoing NSH context c2 */
+
+ bool in_nshc3_present;
+ bool in_nshc3_flow;
+ ovs_be32 in_nshc3; /* incoming NSH context c3 */
+
+ bool out_nshc3_present;
+ bool out_nshc3_flow;
+ ovs_be32 out_nshc3; /* outgoing NSH context c3 */
+
+ bool in_nshc4_present;
+ bool in_nshc4_flow;
+ ovs_be32 in_nshc4; /* incoming NSH context c4 */
+
+ bool out_nshc4_present;
+ bool out_nshc4_flow;
+ ovs_be32 out_nshc4; /* outgoing NSH context c4 */
+
};
void netdev_run(void);
@@ -1004,6 +1004,12 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
/* Tunnel ID. */
nxm_put_64m(b, MFF_TUN_ID, oxm,
flow->tunnel.tun_id, match->wc.masks.tunnel.tun_id);
+ nxm_put_32m(b, MFF_NSP, oxm, flow->tunnel.nsp, match->wc.masks.tunnel.nsp);
+ nxm_put_8m(b, MFF_NSI, oxm, flow->tunnel.nsi, match->wc.masks.tunnel.nsi);
+ nxm_put_32m(b, MFF_NSH_C1, oxm, flow->tunnel.nshc1, match->wc.masks.tunnel.nshc1);
+ nxm_put_32m(b, MFF_NSH_C2, oxm, flow->tunnel.nshc2, match->wc.masks.tunnel.nshc2);
+ nxm_put_32m(b, MFF_NSH_C3, oxm, flow->tunnel.nshc3, match->wc.masks.tunnel.nshc3);
+ nxm_put_32m(b, MFF_NSH_C4, oxm, flow->tunnel.nshc4, match->wc.masks.tunnel.nshc4);
/* Other tunnel metadata. */
nxm_put_16m(b, MFF_TUN_FLAGS, oxm,
@@ -1181,6 +1181,12 @@ static const struct attr_len_tbl ovs_tun_key_attr_lens[OVS_TUNNEL_KEY_ATTR_MAX +
[OVS_TUNNEL_KEY_ATTR_TP_SRC] = { .len = 2 },
[OVS_TUNNEL_KEY_ATTR_TP_DST] = { .len = 2 },
[OVS_TUNNEL_KEY_ATTR_OAM] = { .len = 0 },
+ [OVS_TUNNEL_KEY_ATTR_NSP] = { .len = 4 },
+ [OVS_TUNNEL_KEY_ATTR_NSI] = { .len = 1 },
+ [OVS_TUNNEL_KEY_ATTR_NSH_C1] = { .len = 4 },
+ [OVS_TUNNEL_KEY_ATTR_NSH_C2] = { .len = 4 },
+ [OVS_TUNNEL_KEY_ATTR_NSH_C3] = { .len = 4 },
+ [OVS_TUNNEL_KEY_ATTR_NSH_C4] = { .len = 4 },
[OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = ATTR_LEN_VARIABLE },
[OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = ATTR_LEN_NESTED,
.next = ovs_vxlan_ext_attr_lens ,
@@ -1340,7 +1346,30 @@ odp_tun_key_from_attr__(const struct nlattr *attr,
return ODP_FIT_ERROR;
}
break;
-
+ case OVS_TUNNEL_KEY_ATTR_NSP:
+ tun->nsp = nl_attr_get_be32(a);
+ tun->flags |= FLOW_TNL_F_NSP;
+ break;
+ case OVS_TUNNEL_KEY_ATTR_NSI:
+ tun->nsi = nl_attr_get_u8(a);
+ tun->flags |= FLOW_TNL_F_NSI;
+ break;
+ case OVS_TUNNEL_KEY_ATTR_NSH_C1:
+ tun->nshc1 = nl_attr_get_be32(a);
+ tun->flags |= FLOW_TNL_F_NSH_C1;
+ break;
+ case OVS_TUNNEL_KEY_ATTR_NSH_C2:
+ tun->nshc2 = nl_attr_get_be32(a);
+ tun->flags |= FLOW_TNL_F_NSH_C2;
+ break;
+ case OVS_TUNNEL_KEY_ATTR_NSH_C3:
+ tun->nshc3 = nl_attr_get_be32(a);
+ tun->flags |= FLOW_TNL_F_NSH_C3;
+ break;
+ case OVS_TUNNEL_KEY_ATTR_NSH_C4:
+ tun->nshc4 = nl_attr_get_be32(a);
+ tun->flags |= FLOW_TNL_F_NSH_C4;
+ break;
default:
/* Allow this to show up as unexpected, if there are unknown
* tunnel attribute, eventually resulting in ODP_FIT_TOO_MUCH. */
@@ -1413,6 +1442,24 @@ tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl *tun_key,
nl_msg_end_nested(a, vxlan_opts_ofs);
}
tun_metadata_to_geneve_nlattr(tun_key, tun_flow_key, key_buf, a);
+ if (tun_key->nsp || tun_key->flags & FLOW_TNL_F_NSP) {
+ nl_msg_put_be32(a, OVS_TUNNEL_KEY_ATTR_NSP, tun_key->nsp);
+ }
+ if (tun_key->nsi || tun_key->flags & FLOW_TNL_F_NSI) {
+ nl_msg_put_u8(a, OVS_TUNNEL_KEY_ATTR_NSI, tun_key->nsi);
+ }
+ if (tun_key->nshc1 || tun_key->flags & FLOW_TNL_F_NSH_C1) {
+ nl_msg_put_be32(a, OVS_TUNNEL_KEY_ATTR_NSH_C1, tun_key->nshc1);
+ }
+ if (tun_key->nshc2 || tun_key->flags & FLOW_TNL_F_NSH_C2) {
+ nl_msg_put_be32(a, OVS_TUNNEL_KEY_ATTR_NSH_C2, tun_key->nshc2);
+ }
+ if (tun_key->nshc3 || tun_key->flags & FLOW_TNL_F_NSH_C3) {
+ nl_msg_put_be32(a, OVS_TUNNEL_KEY_ATTR_NSH_C3, tun_key->nshc3);
+ }
+ if (tun_key->nshc4 || tun_key->flags & FLOW_TNL_F_NSH_C4) {
+ nl_msg_put_be32(a, OVS_TUNNEL_KEY_ATTR_NSH_C4, tun_key->nshc4);
+ }
nl_msg_end_nested(a, tun_key_ofs);
}
@@ -1677,6 +1724,24 @@ format_be16x(struct ds *ds, const char *name, ovs_be16 key,
}
}
+
+static void
+format_be32(struct ds *ds, const char *name, ovs_be32 key,
+ const ovs_be32 *mask, bool verbose)
+{
+ bool mask_empty = mask && !*mask;
+
+ if (verbose || !mask_empty) {
+ bool mask_full = !mask || *mask == OVS_BE32_MAX;
+
+ ds_put_format(ds, "%s=%"PRIx32, name, ntohl(key));
+ if (!mask_full) { /* Partially masked. */
+ ds_put_format(ds, "/%#"PRIx32, ntohl(*mask));
+ }
+ ds_put_char(ds, ',');
+ }
+}
+
static void
format_tun_flags(struct ds *ds, const char *name, uint16_t key,
const uint16_t *mask, bool verbose)
@@ -1953,6 +2018,54 @@ format_odp_tun_attr(const struct nlattr *attr, const struct nlattr *mask_attr,
format_be16(ds, "tp_dst", nl_attr_get_be16(a),
ma ? nl_attr_get(ma) : NULL, verbose);
break;
+ case OVS_TUNNEL_KEY_ATTR_NSP:
+ format_be32(ds, "nsp", nl_attr_get_be32(a),
+ ma ? nl_attr_get(ma) : NULL, verbose);
+ flags |= FLOW_TNL_F_NSP;
+ if (ma) {
+ mask_flags |= FLOW_TNL_F_NSP;
+ }
+ break;
+ case OVS_TUNNEL_KEY_ATTR_NSI:
+ format_u8u(ds, "nsi", nl_attr_get_u8(a),
+ ma ? nl_attr_get(ma) : NULL, verbose);
+ flags |= FLOW_TNL_F_NSI;
+ if (ma) {
+ mask_flags |= FLOW_TNL_F_NSI;
+ }
+ break;
+ case OVS_TUNNEL_KEY_ATTR_NSH_C1:
+ format_be32(ds, "nshc1", nl_attr_get_be32(a),
+ ma ? nl_attr_get(ma) : NULL, verbose);
+ flags |= FLOW_TNL_F_NSH_C1;
+ if (ma) {
+ mask_flags |= FLOW_TNL_F_NSH_C1;
+ }
+ break;
+ case OVS_TUNNEL_KEY_ATTR_NSH_C2:
+ format_be32(ds, "nshc2", nl_attr_get_be32(a),
+ ma ? nl_attr_get(ma) : NULL, verbose);
+ flags |= FLOW_TNL_F_NSH_C2;
+ if (ma) {
+ mask_flags |= FLOW_TNL_F_NSH_C2;
+ }
+ break;
+ case OVS_TUNNEL_KEY_ATTR_NSH_C3:
+ format_be32(ds, "nshc3", nl_attr_get_be32(a),
+ ma ? nl_attr_get(ma) : NULL, verbose);
+ flags |= FLOW_TNL_F_NSH_C3;
+ if (ma) {
+ mask_flags |= FLOW_TNL_F_NSH_C3;
+ }
+ break;
+ case OVS_TUNNEL_KEY_ATTR_NSH_C4:
+ format_be32(ds, "nshc4", nl_attr_get_be32(a),
+ ma ? nl_attr_get(ma) : NULL, verbose);
+ flags |= FLOW_TNL_F_NSH_C4;
+ if (ma) {
+ mask_flags |= FLOW_TNL_F_NSH_C4;
+ }
+ break;
case OVS_TUNNEL_KEY_ATTR_OAM:
flags |= FLOW_TNL_F_OAM;
break;
@@ -2016,6 +2129,8 @@ format_frag(struct ds *ds, const char *name, uint8_t key,
}
}
+
+
static void
format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
const struct hmap *portno_names, struct ds *ds,
@@ -2546,6 +2661,29 @@ scan_be16(const char *s, ovs_be16 *key, ovs_be16 *mask)
}
static int
+scan_be32(const char *s, ovs_be32 *key, ovs_be32 *mask)
+{
+ uint32_t key_, mask_;
+ int n;
+
+ if (ovs_scan(s, "%"SCNi32"%n", &key_, &n)) {
+ int len = n;
+
+ *key = htonl(key_);
+ if (mask) {
+ if (ovs_scan(s + len, "/%"SCNi32"%n", &mask_, &n)) {
+ len += n;
+ *mask = htonl(mask_);
+ } else {
+ *mask = OVS_BE32_MAX;
+ }
+ }
+ return len;
+ }
+ return 0;
+}
+
+static int
scan_be64(const char *s, ovs_be64 *key, ovs_be64 *mask)
{
uint64_t key_, mask_;
@@ -3135,12 +3273,19 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
SCAN_FIELD_NESTED("ttl=", uint8_t, u8, OVS_TUNNEL_KEY_ATTR_TTL);
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("nsi=", uint8_t, u8, OVS_TUNNEL_KEY_ATTR_NSI);
+ SCAN_FIELD_NESTED("nsp=", ovs_be32, be32, OVS_TUNNEL_KEY_ATTR_NSP);
+ SCAN_FIELD_NESTED("nshc1=", ovs_be32, be32, OVS_TUNNEL_KEY_ATTR_NSH_C1);
+ SCAN_FIELD_NESTED("nshc2=", ovs_be32, be32, OVS_TUNNEL_KEY_ATTR_NSH_C2);
+ SCAN_FIELD_NESTED("nshc3=", ovs_be32, be32, OVS_TUNNEL_KEY_ATTR_NSH_C3);
+ SCAN_FIELD_NESTED("nshc4=", ovs_be32, be32, OVS_TUNNEL_KEY_ATTR_NSH_C4);
SCAN_FIELD_NESTED_FUNC("vxlan(gbp(", uint32_t, vxlan_gbp, vxlan_gbp_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);
} SCAN_END_NESTED();
+
SCAN_SINGLE_PORT("in_port(", uint32_t, OVS_KEY_ATTR_IN_PORT);
SCAN_BEGIN("eth(", struct ovs_key_ethernet) {
@@ -116,6 +116,12 @@ void odp_portno_names_destroy(struct hmap *portno_names);
* - OVS_TUNNEL_KEY_ATTR_OAM 0 -- 4 4
* - OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS 256 -- 4 260
* - OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS - -- - - (shared with _GENEVE_OPTS)
+ * - OVS_TUNNEL_KEY_ATTR_NSP 4 -- 4 8
+ * - OVS_TUNNEL_KEY_ATTR_NSI 1 3 4 8
+ * - OVS_TUNNEL_KEY_ATTR_NSH_C1 4 -- 4 8
+ * - OVS_TUNNEL_KEY_ATTR_NSH_C2 4 -- 4 8
+ * - OVS_TUNNEL_KEY_ATTR_NSH_C3 4 -- 4 8
+ * - OVS_TUNNEL_KEY_ATTR_NSH_C4 4 -- 4 8
* OVS_KEY_ATTR_IN_PORT 4 -- 4 8
* OVS_KEY_ATTR_SKB_MARK 4 -- 4 8
* OVS_KEY_ATTR_DP_HASH 4 -- 4 8
@@ -129,7 +135,7 @@ void odp_portno_names_destroy(struct hmap *portno_names);
* OVS_KEY_ATTR_ICMPV6 2 2 4 8
* OVS_KEY_ATTR_ND 28 -- 4 32
* ----------------------------------------------------------
- * total 488
+ * total 536
*
* We include some slack space in case the calculation isn't quite right or we
* add another field and forget to adjust this value.
@@ -286,6 +286,24 @@ enum ofp_raw_action_type {
/* NX1.0+(34): struct nx_action_conjunction. */
NXAST_RAW_CONJUNCTION,
+ /* NX1.0+(106): uint8_t. */
+ NXAST_RAW_SET_NSI,
+
+ /* NX1.0+(105): ovs_be32. */
+ NXAST_RAW_SET_NSP,
+
+ /* NX1.0+(107): ovs_be32. */
+ NXAST_RAW_SET_NSH_C1,
+
+ /* NX1.0+(108): ovs_be32. */
+ NXAST_RAW_SET_NSH_C2,
+
+ /* NX1.0+(109): ovs_be32. */
+ NXAST_RAW_SET_NSH_C3,
+
+ /* NX1.0+(110): ovs_be32. */
+ NXAST_RAW_SET_NSH_C4,
+
/* ## ------------------ ## */
/* ## Debugging actions. ## */
/* ## ------------------ ## */
@@ -3179,7 +3197,310 @@ format_SET_TUNNEL(const struct ofpact_tunnel *a, struct ds *s)
|| a->ofpact.raw == NXAST_RAW_SET_TUNNEL64 ? "64" : ""),
a->tun_id);
}
-
+
+/* Action structure for NXAST_SET_NSP.
+ *
+ * Sets the encapsulating NSH service path ID to a 32-bit value. */
+
+/* Set NSI actions. */
+static enum ofperr
+decode_NXAST_RAW_SET_NSI(const uint8_t nsi, struct ofpbuf * out)
+{
+ struct ofpact_nsi *pnsi = ofpact_put_SET_NSI(out);
+ pnsi->ofpact.raw = NXAST_RAW_SET_NSI;
+ pnsi->nsi = nsi;
+
+ return 0;
+}
+
+static void
+encode_SET_NSI(const struct ofpact_nsi *pnsi,
+ enum ofp_version ofp_version, struct ofpbuf *out)
+{
+ uint8_t nsi = pnsi->nsi;
+
+ if (ofp_version < OFP12_VERSION) {
+ put_NXAST_SET_NSI(out, nsi);
+ } else {
+ ofpact_put_set_field(out, ofp_version, MFF_NSI, nsi);
+ }
+}
+
+static char * OVS_WARN_UNUSED_RESULT
+parse_set_nsi(char *arg, struct ofpbuf *ofpacts,
+ enum ofp_raw_action_type raw)
+{
+ struct ofpact_nsi *pnsi;
+
+ pnsi = ofpact_put_SET_NSI(ofpacts);
+ pnsi->ofpact.raw = raw;
+
+ return str_to_u8(arg, "nsi", &pnsi->nsi);
+}
+
+static char * OVS_WARN_UNUSED_RESULT
+parse_SET_NSI(char *arg, struct ofpbuf *ofpacts,
+ enum ofputil_protocol *usable_protocols OVS_UNUSED)
+{
+ return parse_set_nsi(arg, ofpacts, NXAST_RAW_SET_NSI);
+}
+
+static void
+format_SET_NSI(const struct ofpact_nsi *a, struct ds *s)
+{
+ ds_put_format(s, "set_nsi:%d", a->nsi);
+}
+
+/* Set NSP actions. */
+static enum ofperr
+decode_NXAST_RAW_SET_NSP(const ovs_be32 nsp, struct ofpbuf * out)
+{
+ struct ofpact_nsp *pnsp = ofpact_put_SET_NSP(out);
+ pnsp->ofpact.raw = NXAST_RAW_SET_NSP;
+ pnsp->nsp = nsp;
+
+ return 0;
+}
+
+static void
+encode_SET_NSP(const struct ofpact_nsp *pnsp,
+ enum ofp_version ofp_version, struct ofpbuf *out)
+{
+ uint32_t nsp = pnsp->nsp;
+
+ if (ofp_version < OFP12_VERSION) {
+ put_NXAST_SET_NSP(out, nsp);
+ } else {
+ ofpact_put_set_field(out, ofp_version, MFF_NSP, nsp);
+ }
+}
+
+static char * OVS_WARN_UNUSED_RESULT
+parse_set_nsp(char *arg, struct ofpbuf *ofpacts,
+ enum ofp_raw_action_type raw)
+{
+ struct ofpact_nsp *pnsp;
+
+ pnsp = ofpact_put_SET_NSP(ofpacts);
+ pnsp->ofpact.raw = raw;
+
+ return str_to_be32(arg, &pnsp->nsp);
+}
+
+static char * OVS_WARN_UNUSED_RESULT
+parse_SET_NSP(char *arg, struct ofpbuf *ofpacts,
+ enum ofputil_protocol *usable_protocols OVS_UNUSED)
+{
+ return parse_set_nsp(arg, ofpacts, NXAST_RAW_SET_NSP);
+}
+
+static void
+format_SET_NSP(const struct ofpact_nsp *a, struct ds *s)
+{
+ ds_put_format(s, "set_nsp:%#"PRIx32, ntohl(a->nsp));
+}
+
+
+/* Set NSH_C1 actions. */
+static enum ofperr
+decode_NXAST_RAW_SET_NSH_C1(const ovs_be32 nshc1, struct ofpbuf * out)
+{
+ struct ofpact_nshc1 *pnshc1= ofpact_put_SET_NSH_C1(out);
+ pnshc1->ofpact.raw = NXAST_RAW_SET_NSH_C1;
+ pnshc1->nshc1 = nshc1;
+
+ return 0;
+}
+
+static void
+encode_SET_NSH_C1(const struct ofpact_nshc1 *pnshc1,
+ enum ofp_version ofp_version, struct ofpbuf *out)
+{
+ uint32_t nshc1 = pnshc1->nshc1;
+
+ if (ofp_version < OFP12_VERSION) {
+ put_NXAST_SET_NSH_C1(out, nshc1);
+ } else {
+ ofpact_put_set_field(out, ofp_version, MFF_NSH_C1, nshc1);
+ }
+}
+
+static char * OVS_WARN_UNUSED_RESULT
+parse_set_nshc1(char *arg, struct ofpbuf *ofpacts,
+ enum ofp_raw_action_type raw)
+{
+ struct ofpact_nshc1 *pnshc1;
+
+ pnshc1 = ofpact_put_SET_NSH_C1(ofpacts);
+ pnshc1->ofpact.raw = raw;
+
+ return str_to_be32(arg, &pnshc1->nshc1);
+}
+
+static char * OVS_WARN_UNUSED_RESULT
+parse_SET_NSH_C1(char *arg, struct ofpbuf *ofpacts,
+ enum ofputil_protocol *usable_protocols OVS_UNUSED)
+{
+ return parse_set_nshc1(arg, ofpacts, NXAST_RAW_SET_NSH_C1);
+}
+
+static void
+format_SET_NSH_C1(const struct ofpact_nshc1 *a, struct ds *s)
+{
+ ds_put_format(s, "set_nshc1:%#"PRIx32, ntohl(a->nshc1));
+}
+
+
+/* Set NSH_C2 actions. */
+static enum ofperr
+decode_NXAST_RAW_SET_NSH_C2(const ovs_be32 nshc2, struct ofpbuf * out)
+{
+ struct ofpact_nshc2 *pnshc2= ofpact_put_SET_NSH_C2(out);
+ pnshc2->ofpact.raw = NXAST_RAW_SET_NSH_C2;
+ pnshc2->nshc2 = nshc2;
+
+ return 0;
+}
+
+static void
+encode_SET_NSH_C2(const struct ofpact_nshc2 *pnshc2,
+ enum ofp_version ofp_version, struct ofpbuf *out)
+{
+ uint32_t nshc2 = pnshc2->nshc2;
+
+ if (ofp_version < OFP12_VERSION) {
+ put_NXAST_SET_NSH_C2(out, nshc2);
+ } else {
+ ofpact_put_set_field(out, ofp_version, MFF_NSH_C2, nshc2);
+ }
+}
+
+static char * OVS_WARN_UNUSED_RESULT
+parse_set_nshc2(char *arg, struct ofpbuf *ofpacts,
+ enum ofp_raw_action_type raw)
+{
+ struct ofpact_nshc2 *pnshc2;
+
+ pnshc2 = ofpact_put_SET_NSH_C2(ofpacts);
+ pnshc2->ofpact.raw = raw;
+
+ return str_to_be32(arg, &pnshc2->nshc2);
+}
+
+static char * OVS_WARN_UNUSED_RESULT
+parse_SET_NSH_C2(char *arg, struct ofpbuf *ofpacts,
+ enum ofputil_protocol *usable_protocols OVS_UNUSED)
+{
+ return parse_set_nshc2(arg, ofpacts, NXAST_RAW_SET_NSH_C2);
+}
+
+static void
+format_SET_NSH_C2(const struct ofpact_nshc2 *a, struct ds *s)
+{
+ ds_put_format(s, "set_nshc2:%#"PRIx32, ntohl(a->nshc2));
+}
+
+
+/* Set NSH_C3 actions. */
+static enum ofperr
+decode_NXAST_RAW_SET_NSH_C3(const ovs_be32 nshc3, struct ofpbuf * out)
+{
+ struct ofpact_nshc3 *pnshc3= ofpact_put_SET_NSH_C3(out);
+ pnshc3->ofpact.raw = NXAST_RAW_SET_NSH_C3;
+ pnshc3->nshc3 = nshc3;
+
+ return 0;
+}
+
+static void
+encode_SET_NSH_C3(const struct ofpact_nshc3 *pnshc3,
+ enum ofp_version ofp_version, struct ofpbuf *out)
+{
+ uint32_t nshc3 = pnshc3->nshc3;
+
+ if (ofp_version < OFP12_VERSION) {
+ put_NXAST_SET_NSH_C3(out, nshc3);
+ } else {
+ ofpact_put_set_field(out, ofp_version, MFF_NSH_C3, nshc3);
+ }
+}
+
+static char * OVS_WARN_UNUSED_RESULT
+parse_set_nshc3(char *arg, struct ofpbuf *ofpacts,
+ enum ofp_raw_action_type raw)
+{
+ struct ofpact_nshc3 *pnshc3;
+
+ pnshc3 = ofpact_put_SET_NSH_C3(ofpacts);
+ pnshc3->ofpact.raw = raw;
+
+ return str_to_be32(arg, &pnshc3->nshc3);
+}
+
+static char * OVS_WARN_UNUSED_RESULT
+parse_SET_NSH_C3(char *arg, struct ofpbuf *ofpacts,
+ enum ofputil_protocol *usable_protocols OVS_UNUSED)
+{
+ return parse_set_nshc3(arg, ofpacts, NXAST_RAW_SET_NSH_C3);
+}
+
+static void
+format_SET_NSH_C3(const struct ofpact_nshc3 *a, struct ds *s)
+{
+ ds_put_format(s, "set_nshc3:%#"PRIx32, ntohl(a->nshc3));
+}
+
+
+
+/* Set NSH_C4 actions. */
+static enum ofperr
+decode_NXAST_RAW_SET_NSH_C4(const ovs_be32 nshc4, struct ofpbuf * out)
+{
+ struct ofpact_nshc4 *pnshc4= ofpact_put_SET_NSH_C4(out);
+ pnshc4->ofpact.raw = NXAST_RAW_SET_NSH_C4;
+ pnshc4->nshc4 = nshc4;
+
+ return 0;
+}
+
+static void
+encode_SET_NSH_C4(const struct ofpact_nshc4 *pnshc4,
+ enum ofp_version ofp_version, struct ofpbuf *out)
+{
+ uint32_t nshc4 = pnshc4->nshc4;
+
+ if (ofp_version < OFP12_VERSION) {
+ put_NXAST_SET_NSH_C4(out, nshc4);
+ } else {
+ ofpact_put_set_field(out, ofp_version, MFF_NSH_C4, nshc4);
+ }
+}
+
+static char * OVS_WARN_UNUSED_RESULT
+parse_set_nshc4(char *arg, struct ofpbuf *ofpacts,
+ enum ofp_raw_action_type raw)
+{
+ struct ofpact_nshc4 *pnshc4;
+
+ pnshc4 = ofpact_put_SET_NSH_C4(ofpacts);
+ pnshc4->ofpact.raw = raw;
+
+ return str_to_be32(arg, &pnshc4->nshc4);
+}
+
+static char * OVS_WARN_UNUSED_RESULT
+parse_SET_NSH_C4(char *arg, struct ofpbuf *ofpacts,
+ enum ofputil_protocol *usable_protocols OVS_UNUSED)
+{
+ return parse_set_nshc4(arg, ofpacts, NXAST_RAW_SET_NSH_C4);
+}
+
+static void
+format_SET_NSH_C4(const struct ofpact_nshc4 *a, struct ds *s)
+{
+ ds_put_format(s, "set_nshc4:%#"PRIx32, ntohl(a->nshc4));
+}
+
/* Set queue action. */
static enum ofperr
@@ -4831,6 +5152,12 @@ ofpact_is_set_or_move_action(const struct ofpact *a)
case OFPACT_SET_TUNNEL:
case OFPACT_SET_VLAN_PCP:
case OFPACT_SET_VLAN_VID:
+ case OFPACT_SET_NSP:
+ case OFPACT_SET_NSI:
+ case OFPACT_SET_NSH_C1:
+ case OFPACT_SET_NSH_C2:
+ case OFPACT_SET_NSH_C3:
+ case OFPACT_SET_NSH_C4:
return true;
case OFPACT_BUNDLE:
case OFPACT_CLEAR_ACTIONS:
@@ -4900,6 +5227,12 @@ ofpact_is_allowed_in_actions_set(const struct ofpact *a)
case OFPACT_SET_VLAN_PCP:
case OFPACT_SET_VLAN_VID:
case OFPACT_STRIP_VLAN:
+ case OFPACT_SET_NSP:
+ case OFPACT_SET_NSI:
+ case OFPACT_SET_NSH_C1:
+ case OFPACT_SET_NSH_C2:
+ case OFPACT_SET_NSH_C3:
+ case OFPACT_SET_NSH_C4:
return true;
/* In general these actions are excluded because they are not part of
@@ -5136,6 +5469,12 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type)
case OFPACT_EXIT:
case OFPACT_UNROLL_XLATE:
case OFPACT_SAMPLE:
+ case OFPACT_SET_NSP:
+ case OFPACT_SET_NSI:
+ case OFPACT_SET_NSH_C1:
+ case OFPACT_SET_NSH_C2:
+ case OFPACT_SET_NSH_C3:
+ case OFPACT_SET_NSH_C4:
case OFPACT_DEBUG_RECIRC:
default:
return OVSINST_OFPIT11_APPLY_ACTIONS;
@@ -5654,6 +5993,12 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a,
case OFPACT_SET_QUEUE:
case OFPACT_POP_QUEUE:
case OFPACT_RESUBMIT:
+ case OFPACT_SET_NSP:
+ case OFPACT_SET_NSI:
+ case OFPACT_SET_NSH_C1:
+ case OFPACT_SET_NSH_C2:
+ case OFPACT_SET_NSH_C3:
+ case OFPACT_SET_NSH_C4:
return 0;
case OFPACT_FIN_TIMEOUT:
@@ -6161,6 +6506,12 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port)
case OFPACT_GOTO_TABLE:
case OFPACT_METER:
case OFPACT_GROUP:
+ case OFPACT_SET_NSI:
+ case OFPACT_SET_NSP:
+ case OFPACT_SET_NSH_C1:
+ case OFPACT_SET_NSH_C2:
+ case OFPACT_SET_NSH_C3:
+ case OFPACT_SET_NSH_C4:
case OFPACT_DEBUG_RECIRC:
default:
return false;
@@ -92,6 +92,12 @@
OFPACT(SET_QUEUE, ofpact_queue, ofpact, "set_queue") \
OFPACT(POP_QUEUE, ofpact_null, ofpact, "pop_queue") \
OFPACT(FIN_TIMEOUT, ofpact_fin_timeout, ofpact, "fin_timeout") \
+ OFPACT(SET_NSI, ofpact_nsi, ofpact, "set_nsi") \
+ OFPACT(SET_NSP, ofpact_nsp, ofpact, "set_nsp") \
+ OFPACT(SET_NSH_C1, ofpact_nshc1, ofpact, "set_nshc1") \
+ OFPACT(SET_NSH_C2, ofpact_nshc2, ofpact, "set_nshc2") \
+ OFPACT(SET_NSH_C3, ofpact_nshc3, ofpact, "set_nshc3") \
+ OFPACT(SET_NSH_C4, ofpact_nshc4, ofpact, "set_nshc4") \
\
/* Flow table interaction. */ \
OFPACT(RESUBMIT, ofpact_resubmit, ofpact, "resubmit") \
@@ -425,6 +431,48 @@ struct ofpact_tunnel {
uint64_t tun_id;
};
+/* OFPACT_SET_NSI.
+ * Used for NXAST_SET_NSI */
+struct ofpact_nsi {
+ struct ofpact ofpact;
+ uint8_t nsi;
+};
+
+/* OFPACT_SET_NSP.
+ * Used for NXAST_SET_NSP */
+struct ofpact_nsp {
+ struct ofpact ofpact;
+ ovs_be32 nsp;
+};
+
+/* OFPACT_SET_NSH_C1.
+ * Used for NXAST_SET_NSH_C1 */
+struct ofpact_nshc1 {
+ struct ofpact ofpact;
+ ovs_be32 nshc1;
+};
+
+/* OFPACT_SET_NSH_C2.
+ * Used for NXAST_SET_NSH_C2 */
+struct ofpact_nshc2 {
+ struct ofpact ofpact;
+ ovs_be32 nshc2;
+};
+
+/* OFPACT_SET_NSH_C3.
+ * Used for NXAST_SET_NSH_C3 */
+struct ofpact_nshc3 {
+ struct ofpact ofpact;
+ ovs_be32 nshc3;
+};
+
+/* OFPACT_SET_NSH_C4.
+ * Used for NXAST_SET_NSH_C4 */
+struct ofpact_nshc4 {
+ struct ofpact ofpact;
+ ovs_be32 nshc4;
+};
+
/* OFPACT_SET_QUEUE.
*
* Used for NXAST_SET_QUEUE. */
@@ -139,6 +139,19 @@ str_to_be64(const char *str, ovs_be64 *valuep)
return error;
}
+char * OVS_WARN_UNUSED_RESULT
+str_to_be32(const char *str, ovs_be32 *valuep)
+{
+ uint32_t value = 0;
+ char *error;
+
+ error = str_to_u32(str, &value);
+ if (!error) {
+ *valuep = htonl(value);
+ }
+ return error;
+}
+
/* Parses 'str' as an Ethernet address into 'mac'.
*
* Returns NULL if successful, otherwise a malloc()'d string describing the
@@ -98,6 +98,7 @@ char *str_to_u32(const char *str, uint32_t *valuep) OVS_WARN_UNUSED_RESULT;
char *str_to_u64(const char *str, uint64_t *valuep) OVS_WARN_UNUSED_RESULT;
char *str_to_be64(const char *str, ovs_be64 *valuep) OVS_WARN_UNUSED_RESULT;
char *str_to_mac(const char *str, struct eth_addr *mac) OVS_WARN_UNUSED_RESULT;
+char *str_to_be32(const char *str, ovs_be32 *valuep) OVS_WARN_UNUSED_RESULT;
char *str_to_ip(const char *str, ovs_be32 *ip) OVS_WARN_UNUSED_RESULT;
#endif /* ofp-parse.h */
@@ -45,7 +45,12 @@ 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 nsi;
+ ovs_be32 nsp;
+ ovs_be32 nshc1;
+ ovs_be32 nshc2;
+ ovs_be32 nshc3;
+ ovs_be32 nshc4;
struct tun_metadata metadata;
};
@@ -69,6 +74,12 @@ struct flow_tnl {
/* Tunnel information is in userspace datapath format. */
#define FLOW_TNL_F_UDPIF (1 << 4)
+#define FLOW_TNL_F_NSP (1 << 5)
+#define FLOW_TNL_F_NSI (1 << 6)
+#define FLOW_TNL_F_NSH_C1 (1 << 7)
+#define FLOW_TNL_F_NSH_C2 (1 << 8)
+#define FLOW_TNL_F_NSH_C3 (1 << 9)
+#define FLOW_TNL_F_NSH_C4 (1 << 10)
/* Returns an offset to 'src' covering all the meaningful fields in 'src'. */
static inline size_t
@@ -899,6 +910,9 @@ struct vxlanhdr {
ovs_16aligned_be32 vx_vni;
};
+/* VXLAN GPE UDP DST PORT */
+#define VXGPE_DST_PORT 4790
+
#define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */
void format_ipv6_addr(char *addr_str, const struct in6_addr *addr);
@@ -4032,7 +4032,6 @@ recirc_put_unroll_xlate(struct xlate_ctx *ctx)
}
}
-
/* Copy remaining actions to the action_set to be executed after recirculation.
* UNROLL_XLATE action is inserted, if not already done so, before actions that
* may generate PACKET_INs from the current table and without matching another
@@ -4096,6 +4095,12 @@ recirc_unroll_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
case OFPACT_METER:
case OFPACT_SAMPLE:
case OFPACT_DEBUG_RECIRC:
+ case OFPACT_SET_NSP:
+ case OFPACT_SET_NSI:
+ case OFPACT_SET_NSH_C1:
+ case OFPACT_SET_NSH_C2:
+ case OFPACT_SET_NSH_C3:
+ case OFPACT_SET_NSH_C4:
break;
/* These need not be copied for restoration. */
@@ -4284,6 +4289,30 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
flow->tunnel.tun_id = htonll(ofpact_get_SET_TUNNEL(a)->tun_id);
break;
+ case OFPACT_SET_NSP:
+ flow->tunnel.nsp = ofpact_get_SET_NSP(a)->nsp;
+ break;
+
+ case OFPACT_SET_NSI:
+ flow->tunnel.nsi = ofpact_get_SET_NSI(a)->nsi;
+ break;
+
+ case OFPACT_SET_NSH_C1:
+ flow->tunnel.nshc1 = ofpact_get_SET_NSH_C1(a)->nshc1;
+ break;
+
+ case OFPACT_SET_NSH_C2:
+ flow->tunnel.nshc2 = ofpact_get_SET_NSH_C2(a)->nshc2;
+ break;
+
+ case OFPACT_SET_NSH_C3:
+ flow->tunnel.nshc3 = ofpact_get_SET_NSH_C3(a)->nshc3;
+ break;
+
+ case OFPACT_SET_NSH_C4:
+ flow->tunnel.nshc4 = ofpact_get_SET_NSH_C4(a)->nshc4;
+ break;
+
case OFPACT_SET_QUEUE:
memset(&wc->masks.skb_priority, 0xff,
sizeof wc->masks.skb_priority);
@@ -47,13 +47,25 @@ VLOG_DEFINE_THIS_MODULE(tunnel);
struct tnl_match {
ovs_be64 in_key;
+ ovs_be32 in_nsp;
+ ovs_be32 in_nshc1;
+ ovs_be32 in_nshc2;
+ ovs_be32 in_nshc3;
+ ovs_be32 in_nshc4;
ovs_be32 ip_src;
ovs_be32 ip_dst;
odp_port_t odp_port;
uint32_t pkt_mark;
+ uint8_t in_nsi;
bool in_key_flow;
+ bool in_nsp_flow;
+ bool in_nshc1_flow;
+ bool in_nshc2_flow;
+ bool in_nshc3_flow;
+ bool in_nshc4_flow;
bool ip_src_flow;
bool ip_dst_flow;
+ bool in_nsi_flow;
};
struct tnl_port {
@@ -85,17 +97,41 @@ static struct fat_rwlock rwlock;
* (ip_dst_flow == false) or arrange for the destination IP to be matched
* as tunnel.ip_dst in the OpenFlow flow (ip_dst_flow == true).
*
+ * - in_nsp: A vport may match a specific NSH service path (in_nsp_flow ==
+ * false) or arrange for the service path to be matched as tunnel.in_nsp
+ * in the OpenFlow flow (in_nsp_flow == true).
+ *
+ * - in_nsi: A vport may match a specific NSH service index (in_nsi_flow ==
+ * false) or arrange for the service index to be matched as tunnel.in_nsi
+ * in the OpenFlow flow (in_nsi_flow == true).
+ *
+ * - in_nshc1: A vport may match a specific NSH_C1 (in_nshc1_flow ==
+ * false) or arrange for the NSH_C1 to be matched as tunnel.in_nshc1
+ * in the OpenFlow flow (in_nshc1_flow == true).
+ *
+ * - in_nshc2: A vport may match a specific NSH_C2 (in_nshc1_flow ==
+ * false) or arrange for the NSH_C2 to be matched as tunnel.in_nshc2
+ * in the OpenFlow flow (in_nshc2_flow == true).
+ *
+ * - in_nshc3: A vport may match a specific NSH_C3 (in_nshc1_flow ==
+ * false) or arrange for the NSH_C3 to be matched as tunnel.in_nshc3
+ * in the OpenFlow flow (in_nshc3_flow == true).
+ *
+ * - in_nshc4: A vport may match a specific NSH_C4 (in_nshc1_flow ==
+ * false) or arrange for the NSH_C4 to be matched as tunnel.in_nshc4
+ * in the OpenFlow flow (in_nshc4_flow == true).
+ *
* - ip_src: A vport may match a specific IP source address (ip_src_flow ==
* false, ip_src != 0), wildcard all source addresses (ip_src_flow ==
* false, ip_src == 0), or arrange for the IP source address to be
* handled in the OpenFlow flow table (ip_src_flow == true).
*
- * Thus, there are 2 * 2 * 3 == 12 possible ways a vport can match against a
- * tunnel packet. We number the possibilities for each field in increasing
- * order as listed in each bullet above. We order the 12 overall combinations
- * in lexicographic order considering in_key first, then ip_dst, then
- * ip_src. */
-#define N_MATCH_TYPES (2 * 2 * 3)
+ * Thus, there are 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 3 == 768 possible ways a vport can match
+ * against a tunnel packet. We number the possibilities for each field in
+ * increasing order as listed in each bullet above. We order the 768 overall
+ * combinations in lexicographic order considering in_key first, then ip_dst,
+ * then in_nsp, then in_nsi, then ip_src. */
+#define N_MATCH_TYPES (2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 3)
/* The three possibilities (see above) for vport ip_src matches. */
enum ip_src_type {
@@ -110,6 +146,10 @@ enum ip_src_type {
static struct hmap *tnl_match_maps[N_MATCH_TYPES] OVS_GUARDED_BY(rwlock);
static struct hmap **tnl_match_map(const struct tnl_match *);
+static unsigned int tnl_match_m_to_idx(const struct tnl_match *);
+static void tnl_match_idx_to_m(const struct flow *, unsigned int,
+ struct tnl_match *);
+
static struct hmap ofport_map__ = HMAP_INITIALIZER(&ofport_map__);
static struct hmap *ofport_map OVS_GUARDED_BY(rwlock) = &ofport_map__;
@@ -121,7 +161,10 @@ static struct tnl_port *tnl_find_exact(struct tnl_match *, struct hmap *)
OVS_REQ_RDLOCK(rwlock);
static struct tnl_port *tnl_find_ofport(const struct ofport_dpif *)
OVS_REQ_RDLOCK(rwlock);
-
+static struct tnl_port *tnl_find_odp_port(odp_port_t odp_port)
+ OVS_REQ_RDLOCK(rwlock);
+static struct tnl_port *tnl_find_exact_odp_port(odp_port_t, struct hmap *)
+ OVS_REQ_RDLOCK(rwlock);
static uint32_t tnl_hash(struct tnl_match *);
static void tnl_match_fmt(const struct tnl_match *, struct ds *);
static char *tnl_port_fmt(const struct tnl_port *) OVS_REQ_RDLOCK(rwlock);
@@ -161,12 +204,24 @@ tnl_port_add__(const struct ofport_dpif *ofport, const struct netdev *netdev,
tnl_port->change_seq = netdev_get_change_seq(tnl_port->netdev);
tnl_port->match.in_key = cfg->in_key;
+ tnl_port->match.in_nsp = cfg->in_nsp;
+ tnl_port->match.in_nsi = cfg->in_nsi;
+ tnl_port->match.in_nshc1 = cfg->in_nshc1;
+ tnl_port->match.in_nshc2 = cfg->in_nshc2;
+ tnl_port->match.in_nshc3 = cfg->in_nshc3;
+ tnl_port->match.in_nshc4 = cfg->in_nshc4;
tnl_port->match.ip_src = cfg->ip_src;
tnl_port->match.ip_dst = cfg->ip_dst;
tnl_port->match.ip_src_flow = cfg->ip_src_flow;
tnl_port->match.ip_dst_flow = cfg->ip_dst_flow;
tnl_port->match.pkt_mark = cfg->ipsec ? IPSEC_MARK : 0;
tnl_port->match.in_key_flow = cfg->in_key_flow;
+ tnl_port->match.in_nsp_flow = cfg->in_nsp_flow;
+ tnl_port->match.in_nsi_flow = cfg->in_nsi_flow;
+ tnl_port->match.in_nshc1_flow = cfg->in_nshc1_flow;
+ tnl_port->match.in_nshc2_flow = cfg->in_nshc2_flow;
+ tnl_port->match.in_nshc3_flow = cfg->in_nshc3_flow;
+ tnl_port->match.in_nshc4_flow = cfg->in_nshc4_flow;
tnl_port->match.odp_port = odp_port;
map = tnl_match_map(&tnl_port->match);
@@ -437,6 +492,28 @@ tnl_port_send(const struct ofport_dpif *ofport, struct flow *flow,
flow->tunnel.ip_tos = cfg->tos;
}
+ if (!cfg->out_key_flow) {
+ flow->tunnel.tun_id = cfg->out_key;
+ }
+ if (!cfg->out_nsp_flow) {
+ flow->tunnel.nsp = cfg->out_nsp;
+ }
+ if (!cfg->out_nsi_flow) {
+ flow->tunnel.nsi = cfg->out_nsi;
+ }
+ if (!cfg->out_nshc1_flow) {
+ flow->tunnel.nshc1 = cfg->out_nshc1;
+ }
+ if (!cfg->out_nshc2_flow) {
+ flow->tunnel.nshc2 = cfg->out_nshc2;
+ }
+ if (!cfg->out_nshc3_flow) {
+ flow->tunnel.nshc3 = cfg->out_nshc3;
+ }
+ if (!cfg->out_nshc4_flow) {
+ flow->tunnel.nshc4 = cfg->out_nshc4;
+ }
+
/* ECN fields are always inherited. */
if (is_ip_any(flow)) {
wc->masks.nw_tos |= IP_ECN_MASK;
@@ -450,6 +527,12 @@ tnl_port_send(const struct ofport_dpif *ofport, struct flow *flow,
flow->tunnel.flags |= (cfg->dont_fragment ? FLOW_TNL_F_DONT_FRAGMENT : 0)
| (cfg->csum ? FLOW_TNL_F_CSUM : 0)
+ | (cfg->out_nsp_present ? FLOW_TNL_F_NSP : 0)
+ | (cfg->out_nsi_present ? FLOW_TNL_F_NSI : 0)
+ | (cfg->out_nshc1_present ? FLOW_TNL_F_NSH_C1 : 0)
+ | (cfg->out_nshc2_present ? FLOW_TNL_F_NSH_C2 : 0)
+ | (cfg->out_nshc3_present ? FLOW_TNL_F_NSH_C3 : 0)
+ | (cfg->out_nshc4_present ? FLOW_TNL_F_NSH_C4 : 0)
| (cfg->out_key_present ? FLOW_TNL_F_KEY : 0);
if (pre_flow_str) {
@@ -512,57 +595,122 @@ tnl_find_exact(struct tnl_match *match, struct hmap *map)
static struct tnl_port *
tnl_find(const struct flow *flow) OVS_REQ_RDLOCK(rwlock)
{
- enum ip_src_type ip_src;
- int in_key_flow;
- int ip_dst_flow;
- int i;
-
- i = 0;
- for (in_key_flow = 0; in_key_flow < 2; in_key_flow++) {
- for (ip_dst_flow = 0; ip_dst_flow < 2; ip_dst_flow++) {
- for (ip_src = 0; ip_src < 3; ip_src++) {
- struct hmap *map = tnl_match_maps[i];
-
- if (map) {
- struct tnl_port *tnl_port;
- struct tnl_match match;
-
- memset(&match, 0, sizeof match);
-
- /* The apparent mix-up of 'ip_dst' and 'ip_src' below is
- * correct, because "struct tnl_match" is expressed in
- * terms of packets being sent out, but we are using it
- * here as a description of how to treat received
- * packets. */
- match.in_key = in_key_flow ? 0 : flow->tunnel.tun_id;
- match.ip_src = (ip_src == IP_SRC_CFG
- ? flow->tunnel.ip_dst
- : 0);
- match.ip_dst = ip_dst_flow ? 0 : flow->tunnel.ip_src;
- match.odp_port = flow->in_port.odp_port;
- match.pkt_mark = flow->pkt_mark;
- match.in_key_flow = in_key_flow;
- match.ip_dst_flow = ip_dst_flow;
- match.ip_src_flow = ip_src == IP_SRC_FLOW;
-
- tnl_port = tnl_find_exact(&match, map);
- if (tnl_port) {
- return tnl_port;
- }
- }
-
- i++;
+ int i;
+
+ for (i = 0; i < N_MATCH_TYPES; i++) {
+ struct hmap *map = tnl_match_maps[i];
+
+ if (map) {
+ struct tnl_port *tnl_port;
+ struct tnl_match match;
+
+ memset(&match, 0, sizeof match);
+
+ tnl_match_idx_to_m(flow, i, &match);
+ tnl_port = tnl_find_exact(&match, map);
+ if (tnl_port) {
+ return tnl_port;
}
}
- }
+ }
return NULL;
}
-/* Returns a pointer to the 'tnl_match_maps' element corresponding to 'm''s
- * matching criteria. */
-static struct hmap **
-tnl_match_map(const struct tnl_match *m)
+/* Coverts a index to corresponding matching criteria 'm'. */
+static void
+tnl_match_idx_to_m(const struct flow *flow, unsigned int idx,
+ struct tnl_match *m)
+{
+ enum ip_src_type ip_src;
+ bool in_key_flow;
+ bool ip_dst_flow;
+ bool in_nsp_flow;
+ bool in_nsi_flow;
+ bool in_nshc1_flow;
+ bool in_nshc2_flow;
+ bool in_nshc3_flow;
+ bool in_nshc4_flow;
+
+ if (!m)
+ return;
+
+ in_key_flow = (idx < (N_MATCH_TYPES / 2)) ? false : true;
+
+ if (idx >= (N_MATCH_TYPES / 2))
+ idx -= (N_MATCH_TYPES / 2);
+
+ ip_dst_flow = (idx < (N_MATCH_TYPES / (2 * 2))) ? false : true;
+
+ if (idx >= (N_MATCH_TYPES / (2 * 2)))
+ idx -= (N_MATCH_TYPES / (2 * 2));
+
+ in_nsp_flow = (idx < (N_MATCH_TYPES / (2 * 2 * 2))) ? false : true;
+
+ if (idx >= (N_MATCH_TYPES / (2 * 2 * 2)))
+ idx -= (N_MATCH_TYPES / (2 * 2 * 2));
+
+ in_nsi_flow = (idx < (N_MATCH_TYPES / (2 * 2 * 2 * 2))) ? false : true;
+
+ if (idx >= (N_MATCH_TYPES / (2 * 2 * 2 * 2)))
+ idx -= (N_MATCH_TYPES / (2 * 2 * 2 * 2));
+
+ in_nshc1_flow = (idx < (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2))) ? false : true;
+
+ if (idx >= (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2)))
+ idx -= (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2));
+
+ in_nshc2_flow = (idx < (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2))) ? false : true;
+
+ if (idx >= (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2)))
+ idx -= (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2));
+
+ in_nshc3_flow = (idx < (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2 * 2))) ? false : true;
+
+ if (idx >= (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2 * 2)))
+ idx -= (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2 * 2));
+
+ in_nshc4_flow = (idx < (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2 * 2 * 2))) ? false : true;
+
+ if (idx >= (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2 * 2 * 2)))
+ idx -= (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2 * 2 * 2));
+
+ ip_src = idx;
+
+ /* The apparent mix-up of 'ip_dst' and 'ip_src' below is
+ * correct, because "struct tnl_match" is expressed in
+ * terms of packets being sent out, but we are using it
+ * here as a description of how to treat received
+ * packets. */
+ m->in_key = in_key_flow ? 0 : flow->tunnel.tun_id;
+ m->ip_src = (ip_src == IP_SRC_CFG
+ ? flow->tunnel.ip_dst
+ : 0);
+ m->in_nsp = in_nsp_flow ? 0 : flow->tunnel.nsp;
+ m->in_nsi = in_nsi_flow ? 1 : flow->tunnel.nsi;
+ m->in_nshc1 = in_nshc1_flow ? 0 : flow->tunnel.nshc1;
+ m->in_nshc2 = in_nshc2_flow ? 0 : flow->tunnel.nshc2;
+ m->in_nshc3 = in_nshc3_flow ? 0 : flow->tunnel.nshc3;
+ m->in_nshc4 = in_nshc4_flow ? 0 : flow->tunnel.nshc4;
+ m->ip_dst = ip_dst_flow ? 0 : flow->tunnel.ip_src;
+ m->odp_port = flow->in_port.odp_port;
+ m->pkt_mark = flow->pkt_mark;
+ m->in_key_flow = in_key_flow;
+ m->ip_dst_flow = ip_dst_flow;
+ m->in_nsp_flow = in_nsp_flow;
+ m->in_nsi_flow = in_nsi_flow;
+ m->in_nshc1_flow = in_nshc1_flow;
+ m->in_nshc2_flow = in_nshc2_flow;
+ m->in_nshc3_flow = in_nshc3_flow;
+ m->in_nshc4_flow = in_nshc4_flow;
+
+ m->ip_src_flow = ip_src == IP_SRC_FLOW;
+
+}
+
+/* Returns a index corresponding to 'm''s matching criteria. */
+static unsigned int
+tnl_match_m_to_idx(const struct tnl_match *m)
{
enum ip_src_type ip_src;
@@ -570,7 +718,23 @@ tnl_match_map(const struct tnl_match *m)
: m->ip_src ? IP_SRC_CFG
: IP_SRC_ANY);
- return &tnl_match_maps[6 * m->in_key_flow + 3 * m->ip_dst_flow + ip_src];
+ return (m->in_key_flow * (N_MATCH_TYPES / 2) +
+ m->ip_dst_flow * (N_MATCH_TYPES / (2 * 2)) +
+ m->in_nsp_flow * (N_MATCH_TYPES / (2 * 2 * 2)) +
+ m->in_nsi_flow * (N_MATCH_TYPES / (2 * 2 * 2 * 2)) +
+ m->in_nshc1_flow * (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2)) +
+ m->in_nshc2_flow * (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2)) +
+ m->in_nshc3_flow * (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2 * 2)) +
+ m->in_nshc4_flow * (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2 * 2 * 2)) +
+ ip_src);
+}
+
+/* Returns a pointer to the 'tnl_match_maps' element corresponding to 'm''s
+ * matching criteria. */
+static struct hmap **
+tnl_match_map(const struct tnl_match *m)
+{
+ return &tnl_match_maps[tnl_match_m_to_idx(m)];
}
static void
@@ -592,6 +756,37 @@ tnl_match_fmt(const struct tnl_match *match, struct ds *ds)
ds_put_format(ds, ", key=%#"PRIx64, ntohll(match->in_key));
}
+ if (match->in_nsp_flow) {
+ ds_put_cstr(ds, ", nsp=flow");
+ } else {
+ ds_put_format(ds, ", nsp=%#"PRIx32, ntohl(match->in_nsp));
+ }
+ if (match->in_nsi_flow) {
+ ds_put_cstr(ds, ", nsi=flow");
+ } else {
+ ds_put_format(ds, ", nsi=%"PRIu8, match->in_nsi);
+ }
+ if (match->in_nshc1_flow) {
+ ds_put_cstr(ds, ", nshc1=flow");
+ } else {
+ ds_put_format(ds, ", nshc1=%#"PRIx32, ntohl(match->in_nshc1));
+ }
+ if (match->in_nshc2_flow) {
+ ds_put_cstr(ds, ", nshc2=flow");
+ } else {
+ ds_put_format(ds, ", nshc2=%#"PRIx32, ntohl(match->in_nshc2));
+ }
+ if (match->in_nshc3_flow) {
+ ds_put_cstr(ds, ", nshc3=flow");
+ } else {
+ ds_put_format(ds, ", nshc3=%#"PRIx32, ntohl(match->in_nshc3));
+ }
+ if (match->in_nshc4_flow) {
+ ds_put_cstr(ds, ", nshc4=flow");
+ } else {
+ ds_put_format(ds, ", nshc4=%#"PRIx32, ntohl(match->in_nshc4));
+ }
+
ds_put_format(ds, ", dp port=%"PRIu32, match->odp_port);
ds_put_format(ds, ", pkt mark=%"PRIu32, match->pkt_mark);
}
@@ -635,6 +830,79 @@ tnl_port_fmt(const struct tnl_port *tnl_port) OVS_REQ_RDLOCK(rwlock)
}
}
+ if (cfg->out_nsp != cfg->in_nsp ||
+ cfg->out_nsp_present != cfg->in_nsp_present ||
+ cfg->out_nsp_flow != cfg->in_nsp_flow) {
+ ds_put_cstr(&ds, ", out_nsp=");
+ if (!cfg->out_nsp_present) {
+ ds_put_cstr(&ds, "none");
+ } else if (cfg->out_nsp_flow) {
+ ds_put_cstr(&ds, "flow");
+ } else {
+ ds_put_format(&ds, "%#"PRIx32, ntohl(cfg->out_nsp));
+ }
+ }
+ if (cfg->out_nsi != cfg->in_nsi ||
+ cfg->out_nsi_present != cfg->in_nsi_present ||
+ cfg->out_nsi_flow != cfg->in_nsi_flow) {
+ ds_put_cstr(&ds, ", out_nsi=");
+ if (!cfg->out_nsi_present) {
+ ds_put_cstr(&ds, "none");
+ } else if (cfg->out_nsi_flow) {
+ ds_put_cstr(&ds, "flow");
+ } else {
+ ds_put_format(&ds, "%"PRIu8, cfg->out_nsi);
+ }
+ }
+ if (cfg->out_nshc1 != cfg->in_nshc1 ||
+ cfg->out_nshc1_present != cfg->in_nshc1_present ||
+ cfg->out_nshc1_flow != cfg->in_nshc1_flow) {
+ ds_put_cstr(&ds, ", out_nshc1=");
+ if (!cfg->out_nshc1_present) {
+ ds_put_cstr(&ds, "none");
+ } else if (cfg->out_nshc1_flow) {
+ ds_put_cstr(&ds, "flow");
+ } else {
+ ds_put_format(&ds, "%#"PRIx32, ntohl(cfg->out_nshc1));
+ }
+ }
+ if (cfg->out_nshc2 != cfg->in_nshc2 ||
+ cfg->out_nshc2_present != cfg->in_nshc2_present ||
+ cfg->out_nshc2_flow != cfg->in_nshc2_flow) {
+ ds_put_cstr(&ds, ", out_nshc2=");
+ if (!cfg->out_nshc2_present) {
+ ds_put_cstr(&ds, "none");
+ } else if (cfg->out_nshc2_flow) {
+ ds_put_cstr(&ds, "flow");
+ } else {
+ ds_put_format(&ds, "%#"PRIx32, ntohl(cfg->out_nshc2));
+ }
+ }
+ if (cfg->out_nshc3 != cfg->in_nshc3 ||
+ cfg->out_nshc3_present != cfg->in_nshc3_present ||
+ cfg->out_nshc3_flow != cfg->in_nshc3_flow) {
+ ds_put_cstr(&ds, ", out_nshc3=");
+ if (!cfg->out_nshc3_present) {
+ ds_put_cstr(&ds, "none");
+ } else if (cfg->out_nshc3_flow) {
+ ds_put_cstr(&ds, "flow");
+ } else {
+ ds_put_format(&ds, "%#"PRIx32, ntohl(cfg->out_nshc3));
+ }
+ }
+ if (cfg->out_nshc4 != cfg->in_nshc4 ||
+ cfg->out_nshc4_present != cfg->in_nshc4_present ||
+ cfg->out_nshc4_flow != cfg->in_nshc4_flow) {
+ ds_put_cstr(&ds, ", out_nshc4=");
+ if (!cfg->out_nshc4_present) {
+ ds_put_cstr(&ds, "none");
+ } else if (cfg->out_nshc4_flow) {
+ ds_put_cstr(&ds, "flow");
+ } else {
+ ds_put_format(&ds, "%#"PRIx32, ntohl(cfg->out_nshc4));
+ }
+ }
+
if (cfg->ttl_inherit) {
ds_put_cstr(&ds, ", ttl=inherit");
} else {
@@ -55,5 +55,4 @@ int tnl_port_build_header(const struct ofport_dpif *ofport,
const struct eth_addr dmac,
const struct eth_addr smac,
ovs_be32 ip_src, struct ovs_action_push_tnl *data);
-
#endif /* tunnel.h */
@@ -1531,7 +1531,7 @@ head_table () {
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_flags tun_gbp_id tun_gbp_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 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 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 nd_target nd_sll nd_tll
+metadata in_port in_port_oxm pkt_mark 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 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 nd_target nd_sll nd_tll nsp nsi nshc1 nshc2 nshc3 nshc4
matching:
dp_hash: arbitrary mask
recirc_id: exact match or wildcard
@@ -1662,6 +1662,12 @@ metadata in_port in_port_oxm pkt_mark reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 xr
nd_target: arbitrary mask
nd_sll: arbitrary mask
nd_tll: arbitrary mask
+ nsp: arbitrary mask
+ nsi: arbitrary mask
+ nshc1: arbitrary mask
+ nshc2: arbitrary mask
+ nshc3: arbitrary mask
+ nshc4: arbitrary mask
' $1
}
@@ -4068,7 +4074,7 @@ vconn|DBG|unix: negotiated OpenFlow version 0x01 (we support version 0x06 and ea
vconn|DBG|unix: received: NXT_SET_FLOW_FORMAT: format=nxm
vconn|DBG|unix: received: OFPT_BARRIER_REQUEST:
vconn|DBG|unix: sent (Success): OFPT_BARRIER_REPLY:
-vconn|DBG|unix: received: NXST_FLOW request:
+vconn|DBG|unix: received: NXST_FLOW request:
vconn|DBG|unix: sent (Success): NXST_FLOW reply:
idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=output:8
in_port=2,dl_src=00:66:77:88:99:aa actions=drop
@@ -412,6 +412,121 @@ AT_CHECK([tail -1 stdout], [0],
OVS_VSWITCHD_STOP
AT_CLEANUP
+AT_SETUP([tunnel - VXLAN-GPE NSH kernel space])
+OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=vxlan \
+ options:remote_ip=1.1.1.1 ofport_request=1 options:dst_port=4790])
+
+AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
+ br0 65534/100: (dummy)
+ p1 1/4790: (vxlan: dst_port=4790, remote_ip=1.1.1.1)
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([tunnel VXLAN-GPE NSH - encap - nsh/nsi/nshc kernel space])
+OVS_VSWITCHD_START([dnl
+ add-port br0 p1 -- set Interface p1 type=vxlan options:key=flow \
+ options:remote_ip=1.1.1.1 options:dst_port=4790 ofport_request=1 \
+ -- add-port br0 p2 -- set Interface p2 type=vxlan options:key=flow \
+ options:remote_ip=flow options:dst_port=4790 ofport_request=2 \
+ -- add-port br0 p3 -- set Interface p3 type=vxlan options:key=flow \
+ options:remote_ip=2.2.2.2 options:dst_port=4790 options:nsp=111 options:nsi=11 options:nshc1=11 options:nshc2=12 options:nshc3=13 options:nshc4=14 ofport_request=3 \
+ -- add-port br0 p4 -- set Interface p4 type=vxlan options:key=flow \
+ options:remote_ip=3.3.3.3 options:dst_port=4790 options:nsp=222 options:nsi=22 options:nshc1=flow options:nshc2=flow options:nshc3=flow options:nshc4=flow ofport_request=4 \
+ -- add-port br0 p5 -- set Interface p5 type=vxlan options:key=flow \
+ options:remote_ip=4.4.4.4 options:dst_port=4790 options:nsp=flow options:nsi=flow options:nshc1=flow options:nshc2=flow options:nshc3=flow options:nshc4=flow ofport_request=5 \
+ -- add-port br0 p6 -- set Interface p6 type=vxlan options:key=flow \
+ options:remote_ip=flow options:dst_port=4790 options:nsp=flow options:nsi=flow options:nshc1=flow options:nshc2=flow options:nshc3=flow options:nshc4=flow ofport_request=6])
+
+OVS_VSWITCHD_DISABLE_TUNNEL_PUSH_POP
+ADD_OF_PORTS([br0], [90])
+AT_DATA([flows.txt], [dnl
+in_port=90 actions=resubmit:1,resubmit:2,resubmit:3,resubmit:4,resubmit:5
+in_port=1 actions=set_field:42->tun_id,output:1
+in_port=2 actions=set_field:3.3.3.3->tun_dst,output:2
+in_port=3 actions=output:3
+in_port=4 actions=set_nshc1:22,set_nshc2:23,set_nshc3:24,set_nshc4:25,output:4
+in_port=5 actions=set_nsp:333,set_nsi:33,set_nshc1:33,set_nshc2:34,set_nshc3:35,set_nshc4:36,output:5
+in_port=6 actions=set_field:5.5.5.5->tun_dst,set_nsp:444,set_nsi:44,set_nshc1:44,set_nshc2:45,set_nshc3:46,set_nshc4:47,output:6
+])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: set(tunnel(tun_id=0x2a,dst=1.1.1.1,ttl=64,nsi=1,flags(df|key|nsi))),4790,set(tunnel(tun_id=0x2a,dst=3.3.3.3,ttl=64,nsi=1,flags(df|key|nsi))),4790,set(tunnel(tun_id=0x2a,dst=2.2.2.2,ttl=64,nsp=6f,nsi=11,nshc1=b,nshc2=c,nshc3=d,nshc4=e,flags(df|key|nsp|nsi|nshc1|nshc2|nshc3|nshc4))),4790,set(tunnel(tun_id=0x2a,dst=3.3.3.3,ttl=64,nsp=de,nsi=22,nshc1=16,nshc2=17,nshc3=18,nshc4=19,flags(df|key|nsp|nsi|nshc1|nshc2|nshc3|nshc4))),4790,set(tunnel(tun_id=0x2a,dst=4.4.4.4,ttl=64,nsp=14d,nsi=33,nshc1=21,nshc2=22,nshc3=23,nshc4=24,flags(df|key|nsp|nsi|nshc1|nshc2|nshc3|nshc4))),4790
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([tunnel - VXLAN-GPE NSH decap - decap-encap - remote_ip nsp nsi nshc* kernel space])
+OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=vxlan options:key=flow \
+ options:remote_ip=1.1.1.1 options:dst_port=4790 ofport_request=1 \
+ -- add-port br0 p2 -- set Interface p2 type=vxlan options:key=flow \
+ options:remote_ip=2.2.2.2 options:dst_port=4790 options:nsp=111 options:nsi=11 options:nshc1=11 options:nshc2=12 options:nshc3=13 options:nshc4=14 ofport_request=2 \
+ -- add-port br0 p3 -- set Interface p3 type=vxlan options:key=flow \
+ options:remote_ip=3.3.3.3 options:dst_port=4790 options:nsp=flow options:nsi=flow options:nshc1=flow options:nshc2=flow options:nshc3=flow options:nshc4=flow ofport_request=3 \
+ -- add-port br0 p4 -- set Interface p4 type=vxlan options:key=flow \
+ options:remote_ip=4.4.4.4 options:dst_port=4790 options:in_nsp=221 options:out_nsp=flow options:in_nsi=3 options:out_nsi=flow options:nshc1=flow options:nshc2=flow options:nshc3=flow options:nshc4=flow ofport_request=4 \
+ -- add-port br0 p5 -- set Interface p5 type=vxlan options:key=flow \
+ options:remote_ip=flow options:dst_port=4790 options:nsp=flow options:nsi=flow options:nshc1=flow options:nshc2=flow options:nshc3=flow options:nshc4=flow ofport_request=5])
+AT_DATA([flows.txt], [dnl
+priority=16,in_port=1,actions=IN_PORT
+priority=16,in_port=2,actions=IN_PORT
+priority=16,in_port=3,actions=set_nsp:111,set_nsi=11,set_nshc1:22,set_nshc2:23,set_nshc3:24,set_nshc4:25,IN_PORT
+priority=16,in_port=4,actions=set_nsp:222,set_nsi=22,set_nshc1:32,set_nshc2:33,set_nshc3:34,set_nshc4:35,IN_PORT
+priority=16,in_port=5,nsp=311,nsi=31,actions=set_nsp:322,set_nsi=33,set_nshc1:42,set_nshc2:43,set_nshc3:44,set_nshc4:45,set_field:6.6.6.6->tun_dst,IN_PORT
+])
+OVS_VSWITCHD_DISABLE_TUNNEL_PUSH_POP
+
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+
+AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
+ br0 65534/100: (dummy)
+ p1 1/4790: (vxlan: dst_port=4790, key=flow, remote_ip=1.1.1.1)
+ p2 2/4790: (vxlan: dst_port=4790, key=flow, nshc1=0xb, nshc2=0xc, nshc3=0xd, nshc4=0xe, nsi=11, nsp=0x6f, remote_ip=2.2.2.2)
+ p3 3/4790: (vxlan: dst_port=4790, key=flow, nshc1=flow, nshc2=flow, nshc3=flow, nshc4=flow, nsi=flow, nsp=flow, remote_ip=3.3.3.3)
+ p4 4/4790: (vxlan: dst_port=4790, in_nsi=3, in_nsp=0xdd, key=flow, nshc1=flow, nshc2=flow, nshc3=flow, nshc4=flow, out_nsi=flow, out_nsp=flow, remote_ip=4.4.4.4)
+ p5 5/4790: (vxlan: dst_port=4790, key=flow, nshc1=flow, nshc2=flow, nshc3=flow, nshc4=flow, nsi=flow, nsp=flow, remote_ip=flow)
+])
+
+dnl remote_ip p1
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=1.1.1.1,dst=1.2.3.4,nsi=1,ttl=64,flags()),in_port(4790),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: set(tunnel(tun_id=0x0,dst=1.1.1.1,ttl=64,nsi=1,flags(df|key|nsi))),4790
+])
+
+dnl remote_ip nsp nsi nshc* p2
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=2.2.2.2,dst=1.2.3.4,nsi=11,nsp=111,nshc1=11,nshc2=12,nshc3=13,nshc4=14,ttl=64,flags()),in_port(4790),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: set(tunnel(tun_id=0x0,dst=2.2.2.2,ttl=64,nsp=6f,nsi=11,nshc1=b,nshc2=c,nshc3=d,nshc4=e,flags(df|key|nsp|nsi|nshc1|nshc2|nshc3|nshc4))),4790
+])
+
+dnl remote_ip nsp=flow nsi=flow nshc*=flow p3
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=3.3.3.3,dst=1.2.3.4,ttl=64,flags()),in_port(4790),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: set(tunnel(tun_id=0x0,dst=3.3.3.3,ttl=64,nsp=6f,nsi=11,nshc1=16,nshc2=17,nshc3=18,nshc4=19,flags(df|key|nsp|nsi|nshc1|nshc2|nshc3|nshc4))),4790
+])
+
+dnl remote_ip nshc*=flow p4
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=4.4.4.4,dst=1.2.3.4,nsp=221,nsi=3,ttl=64,flags()),in_port(4790),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: set(tunnel(tun_id=0x0,dst=4.4.4.4,ttl=64,nsp=de,nsi=22,nshc1=20,nshc2=21,nshc3=22,nshc4=23,flags(df|key|nsp|nsi|nshc1|nshc2|nshc3|nshc4))),4790
+])
+
+dnl remote_ip nshc*=flow p4 not matched
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=4.4.4.4,dst=1.2.3.4,nsp=223,nsi=3,ttl=64,flags()),in_port(4790),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: drop
+])
+
+dnl remote_ip remote_ip=flow nsp=flow nsi=flow nshc*=flow p5
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=5.5.5.5,dst=1.2.3.4,nsp=311,nsi=31,ttl=64,flags()),in_port(4790),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: set(tunnel(tun_id=0x0,dst=6.6.6.6,ttl=64,nsp=142,nsi=33,nshc1=2a,nshc2=2b,nshc3=2c,nshc4=2d,flags(df|key|nsp|nsi|nshc1|nshc2|nshc3|nshc4))),4790
+])
+
+OVS_VSWITCHD_STOP(["/receive tunnel port not found/d"])
+AT_CLEANUP
+
AT_SETUP([tunnel - Geneve metadata])
OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=geneve \
options:remote_ip=1.1.1.1 ofport_request=1 \