2747 lines
94 KiB
Diff
2747 lines
94 KiB
Diff
From bd251cb247ac44e4362215da826e9bf1d6c61f27 Mon Sep 17 00:00:00 2001
|
||
From: Yi Yang <yi.y.yang@intel.com>
|
||
Date: Wed, 13 Apr 2016 11:15:42 +0800
|
||
Subject: [PATCH 2/5] ovs-nsh: support push and pop actions for vxlan-gpe and
|
||
Ethernet nsh
|
||
|
||
Signed-off-by: Mengke Liu <mengke.liu@intel.com>
|
||
Signed-off-by: Ricky Li <ricky.li@intel.com>
|
||
Signed-off-by: Johnson Li <johnson.li@intel.com>
|
||
Signed-off-by: Yi Yang <yi.y.yang@intel.com>
|
||
---
|
||
datapath/actions.c | 73 ++++
|
||
datapath/datapath.h | 2 +
|
||
datapath/flow.c | 107 ++++++
|
||
datapath/flow.h | 15 +
|
||
datapath/flow_netlink.c | 81 ++++-
|
||
datapath/linux/compat/include/linux/openvswitch.h | 174 +++++++++
|
||
datapath/linux/compat/include/net/vxlan.h | 5 +-
|
||
lib/dpif-netdev.c | 4 +
|
||
lib/dpif.c | 4 +
|
||
lib/flow.c | 19 +
|
||
lib/flow.h | 21 +-
|
||
lib/match.c | 190 ++++++++++
|
||
lib/match.h | 24 ++
|
||
lib/meta-flow.c | 256 ++++++++++++-
|
||
lib/meta-flow.h | 174 +++++++++
|
||
lib/netdev-vport.c | 10 +-
|
||
lib/nx-match.c | 19 +
|
||
lib/odp-execute.c | 10 +
|
||
lib/odp-util.c | 417 +++++++++++++++++++++-
|
||
lib/odp-util.h | 10 +-
|
||
lib/ofp-actions.c | 154 +++++++-
|
||
lib/ofp-actions.h | 6 +
|
||
ofproto/ofproto-dpif-sflow.c | 2 +
|
||
ofproto/ofproto-dpif-upcall.c | 19 +
|
||
ofproto/ofproto-dpif-xlate.c | 22 ++
|
||
tests/ofproto.at | 13 +-
|
||
tests/tunnel.at | 157 ++++++++
|
||
27 files changed, 1976 insertions(+), 12 deletions(-)
|
||
|
||
diff --git a/datapath/actions.c b/datapath/actions.c
|
||
index dcf8591..16fc58f 100644
|
||
--- a/datapath/actions.c
|
||
+++ b/datapath/actions.c
|
||
@@ -252,6 +252,63 @@ static int push_vlan(struct sk_buff *skb, struct sw_flow_key *key,
|
||
ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT);
|
||
}
|
||
|
||
+static int pop_nsh(struct sk_buff *skb, struct sw_flow_key *key)
|
||
+{
|
||
+ if (!pskb_may_pull(skb, NSH_M_TYPE1_LEN))
|
||
+ return -ENOMEM;
|
||
+ else
|
||
+ __skb_pull(skb, NSH_M_TYPE1_LEN);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static int push_nsh(struct sk_buff *skb, struct sw_flow_key *key,
|
||
+ const struct ovs_action_push_nsh *nsh)
|
||
+{
|
||
+
|
||
+ if (nsh->nsh_mdtype == NSH_M_TYPE1) {
|
||
+ if (skb_cow_head(skb, NSH_M_TYPE1_LEN) < 0)
|
||
+ return -ENOMEM;
|
||
+
|
||
+ skb_push(skb, NSH_M_TYPE1_LEN);
|
||
+ OVS_CB(skb)->nsh_header = skb->data;
|
||
+ memcpy(OVS_CB(skb)->nsh_header, nsh->header, NSH_M_TYPE1_LEN);
|
||
+ }
|
||
+ else
|
||
+ return -EINVAL;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static int pop_eth(struct sk_buff *skb, struct sw_flow_key *key)
|
||
+{
|
||
+ if (!pskb_may_pull(skb, ENCAP_ETH_PUSH_HEADER_SIZE))
|
||
+ return -ENOMEM;
|
||
+ else
|
||
+ __skb_pull(skb, ENCAP_ETH_PUSH_HEADER_SIZE);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static int push_eth(struct sk_buff *skb, struct sw_flow_key *key,
|
||
+ const struct ovs_action_push_eth *encap_eth)
|
||
+{
|
||
+ if (encap_eth->encap_eth_type == htons(ETH_P_NSH)) {
|
||
+ if (skb_cow_head(skb, ENCAP_ETH_PUSH_HEADER_SIZE) < 0)
|
||
+ return -ENOMEM;
|
||
+
|
||
+ skb_push(skb, ENCAP_ETH_PUSH_HEADER_SIZE);
|
||
+ OVS_CB(skb)->encap_eth_header = skb->data;
|
||
+ memcpy(OVS_CB(skb)->encap_eth_header, encap_eth->header, ENCAP_ETH_PUSH_HEADER_SIZE);
|
||
+ }
|
||
+ else {
|
||
+ return -EINVAL;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+
|
||
/* 'src' is already properly masked. */
|
||
static void ether_addr_copy_masked(u8 *dst_, const u8 *src_, const u8 *mask_)
|
||
{
|
||
@@ -1079,6 +1136,22 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
|
||
err = pop_vlan(skb, key);
|
||
break;
|
||
|
||
+ case OVS_ACTION_ATTR_PUSH_NSH:
|
||
+ err = push_nsh(skb, key, nla_data(a));
|
||
+ break;
|
||
+
|
||
+ case OVS_ACTION_ATTR_POP_NSH:
|
||
+ err = pop_nsh(skb, key);
|
||
+ break;
|
||
+
|
||
+ case OVS_ACTION_ATTR_PUSH_ETH:
|
||
+ err = push_eth(skb, key, nla_data(a));
|
||
+ break;
|
||
+
|
||
+ case OVS_ACTION_ATTR_POP_ETH:
|
||
+ err = pop_eth(skb, key);
|
||
+ break;
|
||
+
|
||
case OVS_ACTION_ATTR_RECIRC:
|
||
err = execute_recirc(dp, skb, key, a, rem);
|
||
if (nla_is_last(a, rem)) {
|
||
diff --git a/datapath/datapath.h b/datapath/datapath.h
|
||
index ceb3372..b2d5fcd 100644
|
||
--- a/datapath/datapath.h
|
||
+++ b/datapath/datapath.h
|
||
@@ -102,6 +102,8 @@ struct datapath {
|
||
struct ovs_skb_cb {
|
||
struct vport *input_vport;
|
||
u16 mru;
|
||
+ struct nsh_hdr *nsh_header;
|
||
+ struct encap_eth_hdr *encap_eth_header;
|
||
};
|
||
#define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb)
|
||
|
||
diff --git a/datapath/flow.c b/datapath/flow.c
|
||
index c97c9c9..67b2f1d 100644
|
||
--- a/datapath/flow.c
|
||
+++ b/datapath/flow.c
|
||
@@ -44,6 +44,7 @@
|
||
#include <net/ipv6.h>
|
||
#include <net/mpls.h>
|
||
#include <net/ndisc.h>
|
||
+#include <net/vxlan.h>
|
||
|
||
#include "datapath.h"
|
||
#include "conntrack.h"
|
||
@@ -318,6 +319,32 @@ static int parse_vlan(struct sk_buff *skb, struct sw_flow_key *key)
|
||
return 0;
|
||
}
|
||
|
||
+static int parse_nsh(struct sk_buff *skb, struct sw_flow_key *key){
|
||
+ struct nsh_hdr *nsh_hdr = (struct nsh_hdr *)skb->data;
|
||
+ OVS_CB(skb)->nsh_header = nsh_hdr;
|
||
+ key->nsh.nsh_mdtype = nsh_hdr->base.mdtype;
|
||
+ if (key->nsh.nsh_mdtype != NSH_M_TYPE1)
|
||
+ return -EPERM;
|
||
+ key->nsh.nsh_np = nsh_hdr->base.proto;
|
||
+ key->nsh.nsi = nsh_hdr->base.svc_idx;
|
||
+ key->nsh.nsp = nsh_hdr->base.path_hdr << 8;
|
||
+ key->nsh.nshc1 = nsh_hdr->ctx.nshc1;
|
||
+ key->nsh.nshc2 = nsh_hdr->ctx.nshc2;
|
||
+ key->nsh.nshc3 = nsh_hdr->ctx.nshc3;
|
||
+ key->nsh.nshc4 = nsh_hdr->ctx.nshc4;
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static void parse_encap_eth(struct sk_buff *skb, struct sw_flow_key *key){
|
||
+ struct encap_eth_hdr *encap_eth_header = (struct encap_eth_hdr *)skb->data;
|
||
+ OVS_CB(skb)->encap_eth_header = encap_eth_header;
|
||
+ key->encap_eth.encap_eth_type = encap_eth_header->encap_eth_type;
|
||
+ ether_addr_copy(key->encap_eth.encap_eth_src, encap_eth_header->encap_eth_src);
|
||
+ ether_addr_copy(key->encap_eth.encap_eth_dst, encap_eth_header->encap_eth_dst);
|
||
+
|
||
+ return;
|
||
+}
|
||
+
|
||
static __be16 parse_ethertype(struct sk_buff *skb)
|
||
{
|
||
struct llc_snap_hdr {
|
||
@@ -457,6 +484,24 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
|
||
int error;
|
||
struct ethhdr *eth;
|
||
|
||
+ /* Extract ethernet+nsh if ethernet type is 0x894F */
|
||
+ eth = (struct ethhdr *)skb->data;
|
||
+ if (eth->h_proto == htons(ETH_P_NSH)) {
|
||
+ parse_encap_eth(skb, key);
|
||
+ __skb_pull(skb, ENCAP_ETH_LEN);
|
||
+
|
||
+ if (unlikely(parse_nsh(skb, key)))
|
||
+ return -EINVAL;
|
||
+ if (key->nsh.nsh_mdtype == NSH_M_TYPE1 && key->nsh.nsh_np == NSH_P_ETHERNET) {
|
||
+ __skb_pull(skb, NSH_M_TYPE1_LEN);
|
||
+ } else {
|
||
+ return -EINVAL;
|
||
+ }
|
||
+ } else {
|
||
+ void *encap_eth_hdr = &(key->encap_eth);
|
||
+ memset(encap_eth_hdr, 0, ENCAP_ETH_LEN);
|
||
+ }
|
||
+
|
||
/* Flags are always used as part of stats */
|
||
key->tp.flags = 0;
|
||
|
||
@@ -676,11 +721,54 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
|
||
}
|
||
}
|
||
}
|
||
+
|
||
+ if (key->encap_eth.encap_eth_type == htons(ETH_P_NSH))
|
||
+ __skb_push(skb, ENCAP_ETH_LEN + NSH_M_TYPE1_LEN);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static void ovs_key_nsh_init(struct sw_flow_key *key, __u16 len) {
|
||
+ void *nsh_hdr = &(key->nsh);
|
||
+ memset(nsh_hdr, 0, len);
|
||
+}
|
||
+
|
||
+static int nsh_extract(struct sk_buff *skb, struct sw_flow_key *key) {
|
||
+ int ret;
|
||
+
|
||
+ /* only support NSH MD tpye1 */
|
||
+ if (unlikely(parse_nsh(skb, key)))
|
||
+ return -EINVAL;
|
||
+ if (key->nsh.nsh_mdtype == NSH_M_TYPE1) {
|
||
+ __skb_pull(skb, NSH_M_TYPE1_LEN);
|
||
+ if(key->nsh.nsh_np == NSH_P_ETHERNET)
|
||
+ ret = key_extract(skb, key);
|
||
+ else
|
||
+ return -EINVAL;
|
||
+ __skb_push(skb, NSH_M_TYPE1_LEN);
|
||
+
|
||
+ return ret;
|
||
+ } else {
|
||
+ ovs_key_nsh_init(key, NSH_M_TYPE1_LEN);
|
||
+ }
|
||
+
|
||
return 0;
|
||
}
|
||
|
||
+static bool is_nsh_header(const void *tun_opts, __be16 tun_flags) {
|
||
+ struct vxlan_metadata *md = NULL;
|
||
+ if (tun_opts && (tun_flags & TUNNEL_VXLAN_OPT))
|
||
+ md = (struct vxlan_metadata *)tun_opts;
|
||
+
|
||
+ if (md && (md->gpe & VXLAN_GPE_NP_MASK) == VXLAN_GPE_NP_NSH)
|
||
+ return true;
|
||
+ else
|
||
+ return false;
|
||
+}
|
||
+
|
||
int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key)
|
||
{
|
||
+ ovs_key_nsh_init(key, NSH_M_TYPE1_LEN);
|
||
return key_extract(skb, key);
|
||
}
|
||
|
||
@@ -715,6 +803,15 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
|
||
key->ovs_flow_hash = 0;
|
||
key->recirc_id = 0;
|
||
|
||
+ /* Extract NSH and inner Ethernet if NSH header exists */
|
||
+ if (tun_info && is_nsh_header(ip_tunnel_info_opts(tun_info), key->tun_key.tun_flags)) {
|
||
+ int ret ;
|
||
+ ret = nsh_extract(skb, key);
|
||
+ if (key->nsh.nsh_mdtype)
|
||
+ return ret;
|
||
+ } else {
|
||
+ ovs_key_nsh_init(key, NSH_M_TYPE1_LEN);
|
||
+ }
|
||
return key_extract(skb, key);
|
||
}
|
||
|
||
@@ -729,5 +826,15 @@ int ovs_flow_key_extract_userspace(struct net *net, const struct nlattr *attr,
|
||
if (err)
|
||
return err;
|
||
|
||
+ /* Extract NSH and inner Ethernet if NSH header exists */
|
||
+ if (key && is_nsh_header(key->tun_opts, key->tun_key.tun_flags)) {
|
||
+ int ret ;
|
||
+ ret = nsh_extract(skb, key);
|
||
+ if (key->nsh.nsh_mdtype)
|
||
+ return ret;
|
||
+ } else {
|
||
+ ovs_key_nsh_init(key, NSH_M_TYPE1_LEN);
|
||
+ }
|
||
+
|
||
return key_extract(skb, key);
|
||
}
|
||
diff --git a/datapath/flow.h b/datapath/flow.h
|
||
index c0b628a..c8ccd5f 100644
|
||
--- a/datapath/flow.h
|
||
+++ b/datapath/flow.h
|
||
@@ -63,6 +63,21 @@ struct sw_flow_key {
|
||
u32 skb_mark; /* SKB mark. */
|
||
u16 in_port; /* Input switch port (or DP_MAX_PORTS). */
|
||
} __packed phy; /* Safe when right after 'tun_key'. */
|
||
+ struct {
|
||
+ u32 nshc1; /* NSH context C1-C4 */
|
||
+ u32 nshc2;
|
||
+ u32 nshc3;
|
||
+ u32 nshc4;
|
||
+ u32 nsp; /* NSH path id */
|
||
+ u8 nsi; /* NSH index */
|
||
+ u8 nsh_mdtype; /* NSH metadata type */
|
||
+ u8 nsh_np; /* NSH next protocol */
|
||
+ }__packed nsh; /* network service header */
|
||
+ struct {
|
||
+ u8 encap_eth_src[ETH_ALEN]; /* ENCAP ethernet source address. */
|
||
+ u8 encap_eth_dst[ETH_ALEN]; /* ENCAP ethernet destination address. */
|
||
+ u16 encap_eth_type; /* ENCAP ethernet type. */
|
||
+ } encap_eth;
|
||
u32 ovs_flow_hash; /* Datapath computed hash value. */
|
||
u32 recirc_id; /* Recirculation ID. */
|
||
struct {
|
||
diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c
|
||
index 351a504..ebfae37 100644
|
||
--- a/datapath/flow_netlink.c
|
||
+++ b/datapath/flow_netlink.c
|
||
@@ -284,7 +284,7 @@ size_t ovs_key_attr_size(void)
|
||
/* Whenever adding new OVS_KEY_ FIELDS, we should consider
|
||
* updating this function.
|
||
*/
|
||
- BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 26);
|
||
+ BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 28);
|
||
|
||
return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */
|
||
+ nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */
|
||
@@ -297,6 +297,8 @@ size_t ovs_key_attr_size(void)
|
||
+ nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */
|
||
+ nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */
|
||
+ nla_total_size(16) /* OVS_KEY_ATTR_CT_LABELS */
|
||
+ + nla_total_size(24) /* OVS_KEY_ATTR_NSH */
|
||
+ + nla_total_size(14) /* OVS_KEY_ATTR_ENCAP_ETH */
|
||
+ nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */
|
||
+ nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */
|
||
+ nla_total_size(4) /* OVS_KEY_ATTR_VLAN */
|
||
@@ -334,6 +336,8 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
|
||
[OVS_KEY_ATTR_PRIORITY] = { .len = sizeof(u32) },
|
||
[OVS_KEY_ATTR_IN_PORT] = { .len = sizeof(u32) },
|
||
[OVS_KEY_ATTR_SKB_MARK] = { .len = sizeof(u32) },
|
||
+ [OVS_KEY_ATTR_NSH] = { .len = sizeof(struct ovs_key_nsh) },
|
||
+ [OVS_KEY_ATTR_ENCAP_ETH] = { .len = sizeof(struct ovs_key_encap_eth) },
|
||
[OVS_KEY_ATTR_ETHERNET] = { .len = sizeof(struct ovs_key_ethernet) },
|
||
[OVS_KEY_ATTR_VLAN] = { .len = sizeof(__be16) },
|
||
[OVS_KEY_ATTR_ETHERTYPE] = { .len = sizeof(__be16) },
|
||
@@ -869,6 +873,42 @@ static int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match,
|
||
if (err)
|
||
return err;
|
||
|
||
+ if (attrs & (1ULL << OVS_KEY_ATTR_NSH)) {
|
||
+ const struct ovs_key_nsh *nsh_key;
|
||
+
|
||
+ nsh_key = nla_data(a[OVS_KEY_ATTR_NSH]);
|
||
+ SW_FLOW_KEY_PUT(match, nsh.nshc1,
|
||
+ nsh_key->nshc1, is_mask);
|
||
+ SW_FLOW_KEY_PUT(match, nsh.nshc2,
|
||
+ nsh_key->nshc2, is_mask);
|
||
+ SW_FLOW_KEY_PUT(match, nsh.nshc3,
|
||
+ nsh_key->nshc3, is_mask);
|
||
+ SW_FLOW_KEY_PUT(match, nsh.nshc4,
|
||
+ nsh_key->nshc4, is_mask);
|
||
+ SW_FLOW_KEY_PUT(match, nsh.nsh_mdtype,
|
||
+ nsh_key->nsh_mdtype, is_mask);
|
||
+ SW_FLOW_KEY_PUT(match, nsh.nsh_np,
|
||
+ nsh_key->nsh_np, is_mask);
|
||
+ SW_FLOW_KEY_PUT(match, nsh.nsp,
|
||
+ nsh_key->nsp, is_mask);
|
||
+ SW_FLOW_KEY_PUT(match, nsh.nsi,
|
||
+ nsh_key->nsi, is_mask);
|
||
+ attrs &= ~(1ULL << OVS_KEY_ATTR_NSH);
|
||
+ }
|
||
+
|
||
+ if (attrs & (1ULL << OVS_KEY_ATTR_ENCAP_ETH)) {
|
||
+ const struct ovs_key_encap_eth *encap_eth_key;
|
||
+
|
||
+ encap_eth_key = nla_data(a[OVS_KEY_ATTR_ENCAP_ETH]);
|
||
+ SW_FLOW_KEY_MEMCPY(match, encap_eth.encap_eth_src,
|
||
+ encap_eth_key->encap_eth_src, ETH_ALEN, is_mask);
|
||
+ SW_FLOW_KEY_MEMCPY(match, encap_eth.encap_eth_dst,
|
||
+ encap_eth_key->encap_eth_dst, ETH_ALEN, is_mask);
|
||
+ SW_FLOW_KEY_PUT(match, encap_eth.encap_eth_type,
|
||
+ encap_eth_key->encap_eth_type, is_mask);
|
||
+ attrs &= ~(1ULL << OVS_KEY_ATTR_ENCAP_ETH);
|
||
+ }
|
||
+
|
||
if (attrs & (1ULL << OVS_KEY_ATTR_ETHERNET)) {
|
||
const struct ovs_key_ethernet *eth_key;
|
||
|
||
@@ -1386,6 +1426,35 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey,
|
||
if (nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, output->phy.priority))
|
||
goto nla_put_failure;
|
||
|
||
+ if ((swkey->nsh.nsh_mdtype || is_mask)) {
|
||
+ struct ovs_key_nsh *nsh_key;
|
||
+
|
||
+ nla = nla_reserve(skb, OVS_KEY_ATTR_NSH, sizeof(*nsh_key));
|
||
+ if (!nla)
|
||
+ goto nla_put_failure;
|
||
+ nsh_key = nla_data(nla);
|
||
+ nsh_key->nsi = output->nsh.nsi;
|
||
+ nsh_key->nsp = output->nsh.nsp;
|
||
+ nsh_key->nsh_mdtype= output->nsh.nsh_mdtype;
|
||
+ nsh_key->nsh_np= output->nsh.nsh_np;
|
||
+ nsh_key->nshc1= output->nsh.nshc1;
|
||
+ nsh_key->nshc2 = output->nsh.nshc2;
|
||
+ nsh_key->nshc3 = output->nsh.nshc3;
|
||
+ nsh_key->nshc4 = output->nsh.nshc4;
|
||
+ }
|
||
+
|
||
+ if ((swkey->encap_eth.encap_eth_type || is_mask)) {
|
||
+ struct ovs_key_encap_eth *encap_eth_key;
|
||
+
|
||
+ nla = nla_reserve(skb, OVS_KEY_ATTR_ENCAP_ETH, sizeof(*encap_eth_key));
|
||
+ if (!nla)
|
||
+ goto nla_put_failure;
|
||
+ encap_eth_key = nla_data(nla);
|
||
+ memcpy(encap_eth_key->encap_eth_src, output->encap_eth.encap_eth_src, ETH_ALEN);
|
||
+ memcpy(encap_eth_key->encap_eth_dst, output->encap_eth.encap_eth_dst, ETH_ALEN);
|
||
+ encap_eth_key->encap_eth_type= output->encap_eth.encap_eth_type;
|
||
+ }
|
||
+
|
||
if ((swkey->tun_key.u.ipv4.dst || is_mask)) {
|
||
const void *opts = NULL;
|
||
|
||
@@ -2182,6 +2251,10 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
|
||
[OVS_ACTION_ATTR_POP_MPLS] = sizeof(__be16),
|
||
[OVS_ACTION_ATTR_PUSH_VLAN] = sizeof(struct ovs_action_push_vlan),
|
||
[OVS_ACTION_ATTR_POP_VLAN] = 0,
|
||
+ [OVS_ACTION_ATTR_PUSH_NSH] = sizeof(struct ovs_action_push_nsh),
|
||
+ [OVS_ACTION_ATTR_POP_NSH] = 0,
|
||
+ [OVS_ACTION_ATTR_PUSH_ETH] = sizeof(struct ovs_action_push_eth),
|
||
+ [OVS_ACTION_ATTR_POP_ETH] = 0,
|
||
[OVS_ACTION_ATTR_SET] = (u32)-1,
|
||
[OVS_ACTION_ATTR_SET_MASKED] = (u32)-1,
|
||
[OVS_ACTION_ATTR_SAMPLE] = (u32)-1,
|
||
@@ -2226,6 +2299,12 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
|
||
break;
|
||
}
|
||
|
||
+ case OVS_ACTION_ATTR_PUSH_NSH:
|
||
+ case OVS_ACTION_ATTR_POP_NSH:
|
||
+ case OVS_ACTION_ATTR_PUSH_ETH:
|
||
+ case OVS_ACTION_ATTR_POP_ETH:
|
||
+ break;
|
||
+
|
||
case OVS_ACTION_ATTR_POP_VLAN:
|
||
vlan_tci = htons(0);
|
||
break;
|
||
diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
|
||
index 44adb81..187bb9b 100644
|
||
--- a/datapath/linux/compat/include/linux/openvswitch.h
|
||
+++ b/datapath/linux/compat/include/linux/openvswitch.h
|
||
@@ -42,6 +42,7 @@
|
||
|
||
#include <linux/types.h>
|
||
#include <linux/if_ether.h>
|
||
+#include <asm/byteorder.h>
|
||
|
||
/**
|
||
* struct ovs_header - header for OVS Generic Netlink messages.
|
||
@@ -328,6 +329,9 @@ enum ovs_key_attr {
|
||
OVS_KEY_ATTR_ENCAP, /* Nested set of encapsulated attributes. */
|
||
OVS_KEY_ATTR_PRIORITY, /* u32 skb->priority */
|
||
OVS_KEY_ATTR_IN_PORT, /* u32 OVS dp port number */
|
||
+ OVS_KEY_ATTR_NSH, /* struct ovs_key_nsh. Only support NSH MD
|
||
+ type 1 now */
|
||
+ OVS_KEY_ATTR_ENCAP_ETH, /* struct ovs_key_encap_eth */
|
||
OVS_KEY_ATTR_ETHERNET, /* struct ovs_key_ethernet */
|
||
OVS_KEY_ATTR_VLAN, /* be16 VLAN TCI */
|
||
OVS_KEY_ATTR_ETHERTYPE, /* be16 Ethernet type */
|
||
@@ -401,6 +405,24 @@ enum ovs_frag_type {
|
||
|
||
#define OVS_FRAG_TYPE_MAX (__OVS_FRAG_TYPE_MAX - 1)
|
||
|
||
+struct ovs_key_nsh {
|
||
+ __u32 nshc1;
|
||
+ __u32 nshc2;
|
||
+ __u32 nshc3;
|
||
+ __u32 nshc4;
|
||
+ __u32 nsp;
|
||
+ __u8 nsi;
|
||
+ __u8 nsh_mdtype;
|
||
+ __u8 nsh_np;
|
||
+ __u8 reserved;
|
||
+};
|
||
+
|
||
+struct ovs_key_encap_eth {
|
||
+ __u8 encap_eth_src[ETH_ALEN];
|
||
+ __u8 encap_eth_dst[ETH_ALEN];
|
||
+ __u16 encap_eth_type;
|
||
+};
|
||
+
|
||
struct ovs_key_ethernet {
|
||
__u8 eth_src[ETH_ALEN];
|
||
__u8 eth_dst[ETH_ALEN];
|
||
@@ -630,6 +652,154 @@ struct ovs_action_push_vlan {
|
||
__be16 vlan_tci; /* 802.1Q TCI (VLAN ID and priority). */
|
||
};
|
||
|
||
+/*
|
||
+ * Network Service Header:
|
||
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
+ * |Ver|O|C|R|R|R|R|R|R| Length | MD Type | Next Proto |
|
||
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
+ * | Service Path ID | Service Index |
|
||
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
+ * Ver = The version field is used to ensure backward compatibility
|
||
+ * going forward with future NSH updates. It MUST be set to 0x0
|
||
+ * by the sender, in this first revision of NSH.
|
||
+ *
|
||
+ * O = OAM. when set to 0x1 indicates that this packet is an operations
|
||
+ * and management (OAM) packet. The receiving SFF and SFs nodes
|
||
+ * MUST examine the payload and take appropriate action.
|
||
+ *
|
||
+ * C = context. Indicates that a critical metadata TLV is present.
|
||
+ *
|
||
+ * Length : total length, in 4-byte words, of NSH including the Base
|
||
+ * Header, the Service Path Header and the optional variable
|
||
+ * TLVs.
|
||
+ * MD Type: indicates the format of NSH beyond the mandatory Base Header
|
||
+ * and the Service Path Header.
|
||
+ *
|
||
+ * Next Protocol: indicates the protocol type of the original packet. A
|
||
+ * new IANA registry will be created for protocol type.
|
||
+ *
|
||
+ * Service Path Identifier (SPI): identifies a service path.
|
||
+ * Participating nodes MUST use this identifier for Service
|
||
+ * Function Path selection.
|
||
+ *
|
||
+ * Service Index (SI): provides location within the SFP.
|
||
+ *
|
||
+ * [0] https://tools.ietf.org/html/draft-ietf-sfc-nsh-01
|
||
+ */
|
||
+
|
||
+struct nsh_base {
|
||
+#if defined(__LITTLE_ENDIAN_BITFIELD)
|
||
+
|
||
+ __u8 reserved_flags1:4;
|
||
+ __u8 context_flag:1;
|
||
+ __u8 oam_flag:1;
|
||
+ __u8 version:2;
|
||
+
|
||
+ __u8 length:6;
|
||
+ __u8 reserved_flags2:2;
|
||
+#elif defined(__BIG_ENDIAN_BITFIELD)
|
||
+
|
||
+ __u8 version:2;
|
||
+ __u8 oam_flag:1;
|
||
+ __u8 context_flag:1;
|
||
+ __u8 reserved_flags1:4;
|
||
+
|
||
+ __u8 reserved_flags2:2;
|
||
+ __u8 length:6;
|
||
+#else
|
||
+#error "Bitfield Endianess not defined."
|
||
+#endif
|
||
+ __u8 mdtype;
|
||
+ __u8 proto;
|
||
+ union {
|
||
+ struct {
|
||
+ __u8 svc_path[3];
|
||
+ __u8 svc_idx;
|
||
+ };
|
||
+ __be32 path_hdr;
|
||
+ };
|
||
+};
|
||
+
|
||
+
|
||
+/**
|
||
+ * struct nsh_ctx - Keeps track of NSH context data
|
||
+ * @c<1-4>: NSH Contexts.
|
||
+ */
|
||
+struct nsh_ctx {
|
||
+ __be32 nshc1;
|
||
+ __be32 nshc2;
|
||
+ __be32 nshc3;
|
||
+ __be32 nshc4;
|
||
+};
|
||
+
|
||
+/**
|
||
+ * struct nshdr - Network Service header
|
||
+ * @nsh_base: Network Service Base Header.
|
||
+ * @nsh_ctx: Network Service Context Header.
|
||
+ */
|
||
+struct nsh_hdr {
|
||
+ struct nsh_base base;
|
||
+ struct nsh_ctx ctx;
|
||
+};
|
||
+
|
||
+
|
||
+#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_EXP1 0xFE
|
||
+#define NSH_M_EXP2 0xFF
|
||
+
|
||
+#define NSH_DST_PORT 4790 /* UDP Port for NSH on VXLAN */
|
||
+
|
||
+#define NSH_M_TYPE1_LEN 24
|
||
+
|
||
+/* Used for masking nsp and nsi values in field nsp below */
|
||
+#define NSH_M_NSP 0x00FFFFFF
|
||
+#define NSH_M_NSI 0xFF000000
|
||
+
|
||
+/* NSH header for MD type 1. Unit is bytes */
|
||
+#define NSH_PUSH_TYPE1_HEADER_SIZE 24
|
||
+#define NSH_PUSH_HEADER_SIZE 256
|
||
+
|
||
+#define ENCAP_ETH_LEN 14
|
||
+
|
||
+/**
|
||
+ * struct encap_eth - encap ethernet header for ethernet NSH
|
||
+ * @encap_eth_src: encap ethernet source address.
|
||
+ * @encap_eth_src: encap ethernet destination address.
|
||
+ * @encap_eth_type: encap ethernet type.
|
||
+ */
|
||
+struct encap_eth_hdr {
|
||
+ __u8 encap_eth_dst[ETH_ALEN];
|
||
+ __u8 encap_eth_src[ETH_ALEN];
|
||
+ __u16 encap_eth_type;
|
||
+};
|
||
+
|
||
+#define ENCAP_ETH_PUSH_HEADER_SIZE 14
|
||
+/**
|
||
+ * struct ovs_action_push_nsh - %OVS_ACTION_ATTR_PUSH_NSH action argument.
|
||
+ * @header
|
||
+ */
|
||
+struct ovs_action_push_nsh {
|
||
+ uint8_t nsh_mdtype;
|
||
+ uint8_t header[NSH_PUSH_HEADER_SIZE];
|
||
+};
|
||
+
|
||
+/**
|
||
+ * struct ovs_action_push_nsh - %OVS_ACTION_ATTR_PUSH_NSH action argument.
|
||
+ * @header
|
||
+ */
|
||
+struct ovs_action_push_eth {
|
||
+ uint16_t encap_eth_type;
|
||
+ uint8_t header[ENCAP_ETH_PUSH_HEADER_SIZE];
|
||
+};
|
||
+
|
||
/* Data path hash algorithm for computing Datapath hash.
|
||
*
|
||
* The algorithm type only specifies the fields in a flow
|
||
@@ -793,6 +963,10 @@ enum ovs_action_attr {
|
||
OVS_ACTION_ATTR_SET, /* One nested OVS_KEY_ATTR_*. */
|
||
OVS_ACTION_ATTR_PUSH_VLAN, /* struct ovs_action_push_vlan. */
|
||
OVS_ACTION_ATTR_POP_VLAN, /* No argument. */
|
||
+ OVS_ACTION_ATTR_PUSH_NSH, /* struct ovs_action_push_nsh. */
|
||
+ OVS_ACTION_ATTR_POP_NSH, /* No argument. */
|
||
+ OVS_ACTION_ATTR_PUSH_ETH, /* struct ovs_action_push_eth. */
|
||
+ OVS_ACTION_ATTR_POP_ETH, /* No argument. */
|
||
OVS_ACTION_ATTR_SAMPLE, /* Nested OVS_SAMPLE_ATTR_*. */
|
||
OVS_ACTION_ATTR_RECIRC, /* u32 recirc_id. */
|
||
OVS_ACTION_ATTR_HASH, /* struct ovs_action_hash. */
|
||
diff --git a/datapath/linux/compat/include/net/vxlan.h b/datapath/linux/compat/include/net/vxlan.h
|
||
index 2bfc3f8..3aeac88 100644
|
||
--- a/datapath/linux/compat/include/net/vxlan.h
|
||
+++ b/datapath/linux/compat/include/net/vxlan.h
|
||
@@ -85,7 +85,7 @@ struct vxlanhdr_gbp {
|
||
#define VXLAN_GBP_ID_MASK (0xFFFF)
|
||
|
||
/*
|
||
- * VXLAN Generic Protocol Extension Extension:
|
||
+ * VXLAN Generic Protocol Extension:
|
||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
* |R|R|Ver|I|P|R|O|R|R|R|R|R|R|R|R|R|R|R|R|R|R|R|R| Next Proto |
|
||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
@@ -103,6 +103,9 @@ struct vxlanhdr_gbp {
|
||
* O = OAM Flag Bit. The O bit is set to indicate that the packet
|
||
* is an OAM packet.
|
||
*
|
||
+ * Next Protocol = This 8 bit field indicates the protocol header
|
||
+ * immediately following the VXLAN GPE header.
|
||
+ *
|
||
* [1] https://www.ietf.org/id/draft-ietf-nvo3-vxlan-gpe-01.txt
|
||
*/
|
||
|
||
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
|
||
index 119dc2d..8e67bfd 100644
|
||
--- a/lib/dpif-netdev.c
|
||
+++ b/lib/dpif-netdev.c
|
||
@@ -3874,6 +3874,10 @@ dp_execute_cb(void *aux_, struct dp_packet **packets, int cnt,
|
||
VLOG_WARN("Cannot execute conntrack action in userspace.");
|
||
break;
|
||
|
||
+ case OVS_ACTION_ATTR_PUSH_NSH:
|
||
+ case OVS_ACTION_ATTR_POP_NSH:
|
||
+ case OVS_ACTION_ATTR_PUSH_ETH:
|
||
+ case OVS_ACTION_ATTR_POP_ETH:
|
||
case OVS_ACTION_ATTR_PUSH_VLAN:
|
||
case OVS_ACTION_ATTR_POP_VLAN:
|
||
case OVS_ACTION_ATTR_PUSH_MPLS:
|
||
diff --git a/lib/dpif.c b/lib/dpif.c
|
||
index a784de7..b5265c4 100644
|
||
--- a/lib/dpif.c
|
||
+++ b/lib/dpif.c
|
||
@@ -1139,6 +1139,10 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet **packets, int cnt,
|
||
}
|
||
|
||
case OVS_ACTION_ATTR_HASH:
|
||
+ case OVS_ACTION_ATTR_PUSH_NSH:
|
||
+ case OVS_ACTION_ATTR_POP_NSH:
|
||
+ case OVS_ACTION_ATTR_PUSH_ETH:
|
||
+ case OVS_ACTION_ATTR_POP_ETH:
|
||
case OVS_ACTION_ATTR_PUSH_VLAN:
|
||
case OVS_ACTION_ATTR_POP_VLAN:
|
||
case OVS_ACTION_ATTR_PUSH_MPLS:
|
||
diff --git a/lib/flow.c b/lib/flow.c
|
||
index d24bdc9..fc8b98c 100644
|
||
--- a/lib/flow.c
|
||
+++ b/lib/flow.c
|
||
@@ -1289,6 +1289,25 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
|
||
WC_MASK_FIELD(wc, tunnel.tun_id);
|
||
}
|
||
|
||
+ /* NSH fields wildcarded */
|
||
+ if (flow->nsh_mdtype) {
|
||
+ WC_MASK_FIELD(wc, nshc1);
|
||
+ WC_MASK_FIELD(wc, nshc2);
|
||
+ WC_MASK_FIELD(wc, nshc3);
|
||
+ WC_MASK_FIELD(wc, nshc4);
|
||
+ WC_MASK_FIELD(wc, nsh_mdtype);
|
||
+ WC_MASK_FIELD(wc, nsh_np);
|
||
+ WC_MASK_FIELD(wc, nsp);
|
||
+ WC_MASK_FIELD(wc, nsi);
|
||
+ }
|
||
+
|
||
+ /* ENCAP Eth wildcarded */
|
||
+ if (flow->encap_eth_type) {
|
||
+ WC_MASK_FIELD(wc, encap_eth_src);
|
||
+ WC_MASK_FIELD(wc, encap_eth_dst);
|
||
+ WC_MASK_FIELD(wc, encap_eth_type);
|
||
+ }
|
||
+
|
||
/* metadata, regs, and conj_id wildcarded. */
|
||
|
||
WC_MASK_FIELD(wc, skb_priority);
|
||
diff --git a/lib/flow.h b/lib/flow.h
|
||
index dc7130d..a8677b1 100644
|
||
--- a/lib/flow.h
|
||
+++ b/lib/flow.h
|
||
@@ -111,6 +111,23 @@ struct flow {
|
||
ofp_port_t actset_output; /* Output port in action set. */
|
||
uint8_t pad2[2]; /* Pad to 64 bits. */
|
||
|
||
+ /* NSH (64-bit aligned) */
|
||
+ ovs_be32 nshc1;
|
||
+ ovs_be32 nshc2;
|
||
+ ovs_be32 nshc3;
|
||
+ ovs_be32 nshc4;
|
||
+ ovs_be32 nsp;
|
||
+ uint8_t nsi;
|
||
+ uint8_t nsh_mdtype;
|
||
+ uint8_t nsh_np;
|
||
+ uint8_t pad3;
|
||
+
|
||
+ /* ENCAP_ETH (64-bit aligned) */
|
||
+ struct eth_addr encap_eth_src; /* Encap ethernet source address. */
|
||
+ struct eth_addr encap_eth_dst; /* Encap ethernet destination address. */
|
||
+ ovs_be16 encap_eth_type; /* Encap ethernet frame type. */
|
||
+ uint8_t pad4[2];
|
||
+
|
||
/* L2, Order the same as in the Ethernet header! (64-bit aligned) */
|
||
struct eth_addr dl_dst; /* Ethernet destination address. */
|
||
struct eth_addr dl_src; /* Ethernet source address. */
|
||
@@ -132,7 +149,7 @@ struct flow {
|
||
struct eth_addr arp_sha; /* ARP/ND source hardware address. */
|
||
struct eth_addr arp_tha; /* ARP/ND target hardware address. */
|
||
ovs_be16 tcp_flags; /* TCP flags. With L3 to avoid matching L4. */
|
||
- ovs_be16 pad3; /* Pad to 64 bits. */
|
||
+ ovs_be16 pad5; /* Pad to 64 bits. */
|
||
|
||
/* L4 (64-bit aligned) */
|
||
ovs_be16 tp_src; /* TCP/UDP/SCTP source port/ICMP type. */
|
||
@@ -158,7 +175,7 @@ BUILD_ASSERT_DECL(sizeof(struct flow_tnl) % sizeof(uint64_t) == 0);
|
||
|
||
/* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
|
||
BUILD_ASSERT_DECL(offsetof(struct flow, igmp_group_ip4) + sizeof(uint32_t)
|
||
- == sizeof(struct flow_tnl) + 216
|
||
+ == sizeof(struct flow_tnl) + 256
|
||
&& FLOW_WC_SEQ == 35);
|
||
|
||
/* Incremental points at which flow classification may be performed in
|
||
diff --git a/lib/match.c b/lib/match.c
|
||
index 52437c9..3db2a2b 100644
|
||
--- a/lib/match.c
|
||
+++ b/lib/match.c
|
||
@@ -862,6 +862,152 @@ 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.nsp = mask;
|
||
+ match->flow.nsp = nsp & mask;
|
||
+}
|
||
+
|
||
+void
|
||
+match_set_nsi_masked(struct match *match, uint8_t nsi, uint8_t mask)
|
||
+{
|
||
+ match->wc.masks.nsi = mask;
|
||
+ match->flow.nsi = nsi & mask;
|
||
+}
|
||
+
|
||
+void
|
||
+match_set_nsh_mdtype_masked(struct match *match, uint8_t nsh_mdtype, uint8_t mask)
|
||
+{
|
||
+ match->wc.masks.nsh_mdtype = mask;
|
||
+ match->flow.nsh_mdtype = nsh_mdtype & mask;
|
||
+}
|
||
+
|
||
+void
|
||
+match_set_nsh_np_masked(struct match *match, uint8_t nsh_np, uint8_t mask)
|
||
+{
|
||
+ match->wc.masks.nsh_np = mask;
|
||
+ match->flow.nsh_np = nsh_np & mask;
|
||
+}
|
||
+
|
||
+void
|
||
+match_set_encap_eth_src_masked(struct match *match,
|
||
+ const struct eth_addr encap_eth_src,
|
||
+ const struct eth_addr mask)
|
||
+{
|
||
+ set_eth_masked(encap_eth_src, mask, &match->flow.encap_eth_src, &match->wc.masks.encap_eth_src);
|
||
+}
|
||
+
|
||
+void
|
||
+match_set_encap_eth_dst_masked(struct match *match,
|
||
+ const struct eth_addr encap_eth_dst,
|
||
+ const struct eth_addr mask)
|
||
+{
|
||
+ set_eth_masked(encap_eth_dst, mask, &match->flow.encap_eth_dst, &match->wc.masks.encap_eth_dst);
|
||
+}
|
||
+
|
||
+void
|
||
+match_set_encap_eth_type_masked(struct match *match, ovs_be16 encap_eth_type, ovs_be16 mask)
|
||
+{
|
||
+ match->wc.masks.encap_eth_type = mask;
|
||
+ match->flow.encap_eth_type = encap_eth_type & mask;
|
||
+}
|
||
+
|
||
+void
|
||
+match_set_nshc1_masked(struct match *match, ovs_be32 nshc1, ovs_be32 mask)
|
||
+{
|
||
+ match->wc.masks.nshc1 = mask;
|
||
+ match->flow.nshc1 = nshc1 & mask;
|
||
+}
|
||
+
|
||
+void
|
||
+match_set_nshc2_masked(struct match *match, ovs_be32 nshc2, ovs_be32 mask)
|
||
+{
|
||
+ match->wc.masks.nshc2 = mask;
|
||
+ match->flow.nshc2 = nshc2 & mask;
|
||
+}
|
||
+
|
||
+void
|
||
+match_set_nshc3_masked(struct match *match, ovs_be32 nshc3, ovs_be32 mask)
|
||
+{
|
||
+ match->wc.masks.nshc3 = mask;
|
||
+ match->flow.nshc3 = nshc3 & mask;
|
||
+}
|
||
+
|
||
+void
|
||
+match_set_nshc4_masked(struct match *match, ovs_be32 nshc4, ovs_be32 mask)
|
||
+{
|
||
+ match->wc.masks.nshc4 = mask;
|
||
+ match->flow.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_nsh_mdtype(struct match *match, uint8_t nsh_mdtype)
|
||
+{
|
||
+ match_set_nsh_mdtype_masked(match, nsh_mdtype, UINT8_MAX);
|
||
+}
|
||
+
|
||
+void
|
||
+match_set_nsh_np(struct match *match, uint8_t nsh_np)
|
||
+{
|
||
+ match_set_nsh_np_masked(match, nsh_np, 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);
|
||
+}
|
||
+
|
||
+void
|
||
+match_set_encap_eth_src(struct match *match, const struct eth_addr encap_eth_src)
|
||
+{
|
||
+ set_eth(encap_eth_src, &match->flow.encap_eth_src, &match->wc.masks.encap_eth_src);
|
||
+}
|
||
+
|
||
+void
|
||
+match_set_encap_eth_dst(struct match *match, const struct eth_addr encap_eth_dst)
|
||
+{
|
||
+ set_eth(encap_eth_dst, &match->flow.encap_eth_dst, &match->wc.masks.encap_eth_dst);
|
||
+}
|
||
+
|
||
+void
|
||
+match_set_encap_eth_type(struct match *match, uint16_t encap_eth_type)
|
||
+{
|
||
+ match_set_encap_eth_type_masked(match, encap_eth_type, UINT16_MAX);
|
||
+}
|
||
+
|
||
+
|
||
/* Returns true if 'a' and 'b' wildcard the same fields and have the same
|
||
* values for fixed fields, otherwise false. */
|
||
bool
|
||
@@ -1155,6 +1301,50 @@ match_format(const struct match *match, struct ds *s, int priority)
|
||
format_ct_label_masked(s, &f->ct_label, &wc->masks.ct_label);
|
||
}
|
||
|
||
+ if (wc->masks.nsi) {
|
||
+ ds_put_format(s, "nsi=%"PRIu8",", f->nsi);
|
||
+ }
|
||
+
|
||
+ if (wc->masks.nsh_mdtype) {
|
||
+ ds_put_format(s, "nsh_mdtype=%"PRIu8",", f->nsh_mdtype);
|
||
+ }
|
||
+
|
||
+ if (wc->masks.nsh_np) {
|
||
+ ds_put_format(s, "nsh_np=%"PRIu8",", f->nsh_np);
|
||
+ }
|
||
+
|
||
+ if (wc->masks.nsp) {
|
||
+ format_be32_masked(s, "nsp", f->nsp,
|
||
+ wc->masks.nsp);
|
||
+ }
|
||
+
|
||
+ if (wc->masks.nshc1) {
|
||
+ format_be32_masked(s, "nshc1", f->nshc1,
|
||
+ wc->masks.nshc1);
|
||
+ }
|
||
+
|
||
+ if (wc->masks.nshc2) {
|
||
+ format_be32_masked(s, "nshc2", f->nshc2,
|
||
+ wc->masks.nshc2);
|
||
+ }
|
||
+
|
||
+ if (wc->masks.nshc3) {
|
||
+ format_be32_masked(s, "nshc3", f->nshc3,
|
||
+ wc->masks.nshc3);
|
||
+ }
|
||
+
|
||
+ if (wc->masks.nshc4) {
|
||
+ format_be32_masked(s, "nshc4", f->nshc4,
|
||
+ wc->masks.nshc4);
|
||
+ }
|
||
+
|
||
+ if (wc->masks.encap_eth_type) {
|
||
+ ds_put_format(s, "encap_eth_type=%"PRIu16",", f->encap_eth_type);
|
||
+ }
|
||
+
|
||
+ format_eth_masked(s, "encap_eth_src", f->encap_eth_src, wc->masks.encap_eth_src);
|
||
+ format_eth_masked(s, "encap_eth_dst", f->encap_eth_dst, wc->masks.encap_eth_dst);
|
||
+
|
||
if (wc->masks.dl_type) {
|
||
skip_type = true;
|
||
if (f->dl_type == htons(ETH_TYPE_IP)) {
|
||
diff --git a/lib/match.h b/lib/match.h
|
||
index 48aa0b1..529350e 100644
|
||
--- a/lib/match.h
|
||
+++ b/lib/match.h
|
||
@@ -165,6 +165,30 @@ 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_nsh_mdtype_masked(struct match *match, uint8_t nsh_mdtype, uint8_t mask);
|
||
+void match_set_nsh_np_masked(struct match *match, uint8_t nsh_np, 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_encap_eth_src_masked(struct match *match, const struct eth_addr encap_eth_src, const struct eth_addr mask);
|
||
+void match_set_encap_eth_dst_masked(struct match *match, const struct eth_addr encap_eth_dst, const struct eth_addr mask);
|
||
+void match_set_encap_eth_type_masked(struct match *match, ovs_be16 encap_eth_type, ovs_be16 mask);
|
||
+
|
||
+void match_set_nsp(struct match *, ovs_be32 nsp);
|
||
+void match_set_nsi(struct match *match, uint8_t nsi);
|
||
+void match_set_nsh_mdtype(struct match *match, uint8_t nsh_mdtype);
|
||
+void match_set_nsh_np(struct match *match, uint8_t nsh_np);
|
||
+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);
|
||
+void match_set_encap_eth_src(struct match *match, const struct eth_addr encap_eth_src);
|
||
+void match_set_encap_eth_dst(struct match *match, const struct eth_addr encap_eth_dst);
|
||
+void match_set_encap_eth_type(struct match *match, uint16_t encap_eth_type);
|
||
+
|
||
bool match_equal(const struct match *, const struct match *);
|
||
uint32_t match_hash(const struct match *, uint32_t basis);
|
||
|
||
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
|
||
index ab77fca..648a753 100644
|
||
--- a/lib/meta-flow.c
|
||
+++ b/lib/meta-flow.c
|
||
@@ -243,7 +243,28 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
|
||
return !flow_get_xreg(&wc->masks, mf->id - MFF_XREG0);
|
||
case MFF_ACTSET_OUTPUT:
|
||
return !wc->masks.actset_output;
|
||
-
|
||
+ case MFF_NSP:
|
||
+ return !wc->masks.nsp;
|
||
+ case MFF_NSI:
|
||
+ return !wc->masks.nsi;
|
||
+ case MFF_NSH_C1:
|
||
+ return !wc->masks.nshc1;
|
||
+ case MFF_NSH_C2:
|
||
+ return !wc->masks.nshc2;
|
||
+ case MFF_NSH_C3:
|
||
+ return !wc->masks.nshc3;
|
||
+ case MFF_NSH_C4:
|
||
+ return !wc->masks.nshc4;
|
||
+ case MFF_NSH_MDTYPE:
|
||
+ return !wc->masks.nsh_mdtype;
|
||
+ case MFF_NSH_NP:
|
||
+ return !wc->masks.nsh_np;
|
||
+ case MFF_ENCAP_ETH_SRC:
|
||
+ return eth_addr_is_zero(wc->masks.encap_eth_src);
|
||
+ case MFF_ENCAP_ETH_DST:
|
||
+ return eth_addr_is_zero(wc->masks.encap_eth_dst);
|
||
+ case MFF_ENCAP_ETH_TYPE:
|
||
+ return !wc->masks.encap_eth_type;
|
||
case MFF_ETH_SRC:
|
||
return eth_addr_is_zero(wc->masks.dl_src);
|
||
case MFF_ETH_DST:
|
||
@@ -557,6 +578,17 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
|
||
case MFF_ICMPV6_TYPE:
|
||
case MFF_ICMPV6_CODE:
|
||
case MFF_ND_TARGET:
|
||
+ case MFF_NSP:
|
||
+ case MFF_NSI:
|
||
+ case MFF_NSH_MDTYPE:
|
||
+ case MFF_NSH_NP:
|
||
+ case MFF_NSH_C1:
|
||
+ case MFF_NSH_C2:
|
||
+ case MFF_NSH_C3:
|
||
+ case MFF_NSH_C4:
|
||
+ case MFF_ENCAP_ETH_SRC:
|
||
+ case MFF_ENCAP_ETH_DST:
|
||
+ case MFF_ENCAP_ETH_TYPE:
|
||
case MFF_ND_SLL:
|
||
case MFF_ND_TLL:
|
||
return true;
|
||
@@ -716,6 +748,50 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
|
||
value->be64 = htonll(flow_get_xreg(flow, mf->id - MFF_XREG0));
|
||
break;
|
||
|
||
+ case MFF_NSP:
|
||
+ value->be32 = flow->nsp;
|
||
+ break;
|
||
+
|
||
+ case MFF_NSI:
|
||
+ value->u8 = flow->nsi;
|
||
+ break;
|
||
+
|
||
+ case MFF_NSH_C1:
|
||
+ value->be32 = flow->nshc1;
|
||
+ break;
|
||
+
|
||
+ case MFF_NSH_C2:
|
||
+ value->be32 = flow->nshc2;
|
||
+ break;
|
||
+
|
||
+ case MFF_NSH_C3:
|
||
+ value->be32 = flow->nshc3;
|
||
+ break;
|
||
+
|
||
+ case MFF_NSH_C4:
|
||
+ value->be32 = flow->nshc4;
|
||
+ break;
|
||
+
|
||
+ case MFF_NSH_MDTYPE:
|
||
+ value->u8 = flow->nsh_mdtype;
|
||
+ break;
|
||
+
|
||
+ case MFF_NSH_NP:
|
||
+ value->u8 = flow->nsh_np;
|
||
+ break;
|
||
+
|
||
+ case MFF_ENCAP_ETH_SRC:
|
||
+ value->mac = flow->encap_eth_src;
|
||
+ break;
|
||
+
|
||
+ case MFF_ENCAP_ETH_DST:
|
||
+ value->mac = flow->encap_eth_dst;
|
||
+ break;
|
||
+
|
||
+ case MFF_ENCAP_ETH_TYPE:
|
||
+ value->be16 = flow->encap_eth_type;
|
||
+ break;
|
||
+
|
||
case MFF_ETH_SRC:
|
||
value->mac = flow->dl_src;
|
||
break;
|
||
@@ -1085,6 +1161,50 @@ mf_set_value(const struct mf_field *mf,
|
||
match_set_arp_sha(match, value->mac);
|
||
break;
|
||
|
||
+ case MFF_NSP:
|
||
+ match_set_nsp(match, value->be32);
|
||
+ break;
|
||
+
|
||
+ case MFF_NSI:
|
||
+ match_set_nsi(match, value->u8);
|
||
+ break;
|
||
+
|
||
+ case MFF_NSH_MDTYPE:
|
||
+ match_set_nsh_mdtype(match, value->u8);
|
||
+ break;
|
||
+
|
||
+ case MFF_NSH_NP:
|
||
+ match_set_nsh_np(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_ENCAP_ETH_SRC:
|
||
+ match_set_encap_eth_src(match, value->mac);
|
||
+ break;
|
||
+
|
||
+ case MFF_ENCAP_ETH_DST:
|
||
+ match_set_encap_eth_dst(match, value->mac);
|
||
+ break;
|
||
+
|
||
+ case MFF_ENCAP_ETH_TYPE:
|
||
+ match_set_encap_eth_type(match, value->be16);
|
||
+ break;
|
||
+
|
||
case MFF_ARP_THA:
|
||
case MFF_ND_TLL:
|
||
match_set_arp_tha(match, value->mac);
|
||
@@ -1296,6 +1416,50 @@ mf_set_flow_value(const struct mf_field *mf,
|
||
flow_set_xreg(flow, mf->id - MFF_XREG0, ntohll(value->be64));
|
||
break;
|
||
|
||
+ case MFF_NSP:
|
||
+ flow->nsp = value->be32;
|
||
+ break;
|
||
+
|
||
+ case MFF_NSI:
|
||
+ flow->nsi = value->u8;
|
||
+ break;
|
||
+
|
||
+ case MFF_NSH_C1:
|
||
+ flow->nshc1 = value->be32;
|
||
+ break;
|
||
+
|
||
+ case MFF_NSH_C2:
|
||
+ flow->nshc2 = value->be32;
|
||
+ break;
|
||
+
|
||
+ case MFF_NSH_C3:
|
||
+ flow->nshc3 = value->be32;
|
||
+ break;
|
||
+
|
||
+ case MFF_NSH_C4:
|
||
+ flow->nshc4 = value->be32;
|
||
+ break;
|
||
+
|
||
+ case MFF_NSH_MDTYPE:
|
||
+ flow->nsh_mdtype = value->u8;
|
||
+ break;
|
||
+
|
||
+ case MFF_NSH_NP:
|
||
+ flow->nsh_np = value->u8;
|
||
+ break;
|
||
+
|
||
+ case MFF_ENCAP_ETH_SRC:
|
||
+ flow->encap_eth_src = value->mac;
|
||
+ break;
|
||
+
|
||
+ case MFF_ENCAP_ETH_DST:
|
||
+ flow->encap_eth_dst = value->mac;
|
||
+ break;
|
||
+
|
||
+ case MFF_ENCAP_ETH_TYPE:
|
||
+ flow->encap_eth_type = value->be16;
|
||
+ break;
|
||
+
|
||
case MFF_ETH_SRC:
|
||
flow->dl_src = value->mac;
|
||
break;
|
||
@@ -1734,6 +1898,52 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str)
|
||
match->wc.masks.arp_sha = eth_addr_zero;
|
||
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_MDTYPE:
|
||
+ match_set_nsh_mdtype_masked(match, 0, 0);
|
||
+ break;
|
||
+
|
||
+ case MFF_NSH_NP:
|
||
+ match_set_nsh_np_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_ENCAP_ETH_SRC:
|
||
+ match->flow.encap_eth_src= eth_addr_zero;
|
||
+ match->wc.masks.encap_eth_src = eth_addr_zero;
|
||
+ break;
|
||
+
|
||
+ case MFF_ENCAP_ETH_DST:
|
||
+ match->flow.encap_eth_dst= eth_addr_zero;
|
||
+ match->wc.masks.encap_eth_dst = eth_addr_zero;
|
||
+ break;
|
||
+
|
||
+ case MFF_ENCAP_ETH_TYPE:
|
||
+ match_set_encap_eth_type_masked(match, htons(0), htons(0));
|
||
+ break;
|
||
+
|
||
case MFF_ARP_THA:
|
||
case MFF_ND_TLL:
|
||
match->flow.arp_tha = eth_addr_zero;
|
||
@@ -1929,6 +2139,50 @@ mf_set(const struct mf_field *mf,
|
||
match_set_arp_sha_masked(match, value->mac, mask->mac);
|
||
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_MDTYPE:
|
||
+ match_set_nsh_mdtype_masked(match, value->u8, mask->u8);
|
||
+ break;
|
||
+
|
||
+ case MFF_NSH_NP:
|
||
+ match_set_nsh_np_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_ENCAP_ETH_SRC:
|
||
+ match_set_encap_eth_src_masked(match, value->mac, mask->mac);
|
||
+ break;
|
||
+
|
||
+ case MFF_ENCAP_ETH_DST:
|
||
+ match_set_encap_eth_dst_masked(match, value->mac, mask->mac);
|
||
+ break;
|
||
+
|
||
+ case MFF_ENCAP_ETH_TYPE:
|
||
+ match_set_encap_eth_type_masked(match, value->be16, mask->be16);
|
||
+ break;
|
||
+
|
||
case MFF_ARP_THA:
|
||
case MFF_ND_TLL:
|
||
match_set_arp_tha_masked(match, value->mac, mask->mac);
|
||
diff --git a/lib/meta-flow.h b/lib/meta-flow.h
|
||
index 4bd9ff6..a226b79 100644
|
||
--- a/lib/meta-flow.h
|
||
+++ b/lib/meta-flow.h
|
||
@@ -1747,6 +1747,180 @@ enum OVS_PACKED_ENUM mf_field_id {
|
||
*/
|
||
MFF_ND_TLL,
|
||
|
||
+ /* "nsp".
|
||
+ *
|
||
+ * For a packet received 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(113) since v1.1.
|
||
+ * OXM: none.
|
||
+ * Prefix lookup member: nsp.
|
||
+ */
|
||
+ MFF_NSP,
|
||
+
|
||
+ /* "nsi".
|
||
+ *
|
||
+ * For a packet received, 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(114) since v1.1.
|
||
+ * OXM: none.
|
||
+ * Prefix lookup member: nsi.
|
||
+ */
|
||
+ MFF_NSI,
|
||
+
|
||
+ /* "nshc1".
|
||
+ *
|
||
+ * For a packet received 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(115) since v1.1.
|
||
+ * OXM: none.
|
||
+ * Prefix lookup member: nshc1.
|
||
+ */
|
||
+ MFF_NSH_C1,
|
||
+
|
||
+ /* "nshc2".
|
||
+ *
|
||
+ * For a packet received 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(116) since v1.1.
|
||
+ * OXM: none.
|
||
+ * Prefix lookup member: nshc2.
|
||
+ */
|
||
+ MFF_NSH_C2,
|
||
+
|
||
+ /* "nshc3".
|
||
+ *
|
||
+ * For a packet received via 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(117) since v1.1.
|
||
+ * OXM: none.
|
||
+ * Prefix lookup member: nshc3.
|
||
+ */
|
||
+ MFF_NSH_C3,
|
||
+
|
||
+ /* "nshc4".
|
||
+ *
|
||
+ * For a packet received 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(118) since v1.1.
|
||
+ * OXM: none.
|
||
+ * Prefix lookup member: nshc4.
|
||
+ */
|
||
+ MFF_NSH_C4,
|
||
+
|
||
+ /* "nsh_mdtype".
|
||
+ *
|
||
+ * For a packet received, it includes a (8-bit)
|
||
+ * nsh md-type field (md-type).
|
||
+ *
|
||
+ * Type: u8.
|
||
+ * Maskable: bitwise.
|
||
+ * Formatting: decimal.
|
||
+ * Prerequisites: none.
|
||
+ * Access: read/write.
|
||
+ * NXM: NXM_NX_NSH_MDTYPE(119) since v1.1.
|
||
+ * OXM: none.
|
||
+ */
|
||
+ MFF_NSH_MDTYPE,
|
||
+
|
||
+ /* "nsh_np".
|
||
+ *
|
||
+ * For a packet received, it includes a (8-bit)
|
||
+ * nsh next protocol field (np).
|
||
+ *
|
||
+ * Type: u8.
|
||
+ * Maskable: bitwise.
|
||
+ * Formatting: decimal.
|
||
+ * Prerequisites: none.
|
||
+ * Access: read/write.
|
||
+ * NXM: NXM_NX_NSH_NP(120) since v1.1.
|
||
+ * OXM: none.
|
||
+ */
|
||
+ MFF_NSH_NP,
|
||
+
|
||
+ /* "encap_eth_src".
|
||
+ *
|
||
+ * encap eth source address for Ethernet+NSH
|
||
+ *
|
||
+ * Type: MAC.
|
||
+ * Maskable: bitwise.
|
||
+ * Formatting: Ethernet.
|
||
+ * Prerequisites: none.
|
||
+ * Access: read/write.
|
||
+ * NXM: NXM_NX_ENCAP_ETH_SRC(121) since v1.1.
|
||
+ * OXM: none.
|
||
+ */
|
||
+ MFF_ENCAP_ETH_SRC,
|
||
+
|
||
+ /* "encap_eth_dst".
|
||
+ *
|
||
+ * encap eth destination address for Ethernet+NSH
|
||
+ *
|
||
+ * Type: MAC.
|
||
+ * Maskable: bitwise.
|
||
+ * Formatting: Ethernet.
|
||
+ * Prerequisites: none.
|
||
+ * Access: read/write.
|
||
+ * NXM: NXM_NX_ENCAP_ETH_DST(122) since v1.1.
|
||
+ * OXM: none.
|
||
+ */
|
||
+ MFF_ENCAP_ETH_DST,
|
||
+
|
||
+ /* "encap_eth_type".
|
||
+ *
|
||
+ * Encap Ethernet type.
|
||
+ *
|
||
+ * Type: be16.
|
||
+ * Maskable: no.
|
||
+ * Formatting: hexadecimal.
|
||
+ * Prerequisites: none.
|
||
+ * Access: read/write.
|
||
+ * NXM: NXM_NX_ENCAP_ETH_TYPE(123) since v1.1.
|
||
+ * OXM: none.
|
||
+ */
|
||
+ MFF_ENCAP_ETH_TYPE,
|
||
+
|
||
MFF_N_IDS
|
||
};
|
||
|
||
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
|
||
index 92ceec1..406a492 100644
|
||
--- a/lib/netdev-vport.c
|
||
+++ b/lib/netdev-vport.c
|
||
@@ -582,9 +582,15 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args)
|
||
ext = strtok_r(str, ",", &save_ptr);
|
||
while (ext) {
|
||
if (!strcmp(type, "vxlan") && !strcmp(ext, "gbp")) {
|
||
- tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GBP);
|
||
+ if (tnl_cfg.exts & (1 << OVS_VXLAN_EXT_GPE))
|
||
+ VLOG_WARN("VXLAN_GPE extension exists, VxLAN_GBP extension can't be added.");
|
||
+ else
|
||
+ tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GBP);
|
||
} else if (!strcmp(type, "vxlan") && !strcmp(ext, "gpe")) {
|
||
- tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GPE);
|
||
+ if (tnl_cfg.exts & (1 << OVS_VXLAN_EXT_GBP))
|
||
+ VLOG_WARN("VXLAN_GBP extension exists, VxLAN_GPE extension can't be added.");
|
||
+ else
|
||
+ tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GPE);
|
||
} else {
|
||
VLOG_WARN("%s: unknown extension '%s'", name, ext);
|
||
}
|
||
diff --git a/lib/nx-match.c b/lib/nx-match.c
|
||
index 0eecac7..8d2bc4b 100644
|
||
--- a/lib/nx-match.c
|
||
+++ b/lib/nx-match.c
|
||
@@ -949,6 +949,25 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
|
||
ofputil_port_to_ofp11(flow->actset_output));
|
||
}
|
||
|
||
+ /* NSH */
|
||
+ nxm_put_32m(b, MFF_NSP, oxm, flow->nsp, match->wc.masks.nsp);
|
||
+ nxm_put_8m(b, MFF_NSI, oxm, flow->nsi, match->wc.masks.nsi);
|
||
+ nxm_put_8m(b, MFF_NSH_MDTYPE, oxm, flow->nsh_mdtype, match->wc.masks.nsh_mdtype);
|
||
+ nxm_put_8m(b, MFF_NSH_NP, oxm, flow->nsh_np, match->wc.masks.nsh_np);
|
||
+ nxm_put_32m(b, MFF_NSH_C1, oxm, flow->nshc1, match->wc.masks.nshc1);
|
||
+ nxm_put_32m(b, MFF_NSH_C2, oxm, flow->nshc2, match->wc.masks.nshc2);
|
||
+ nxm_put_32m(b, MFF_NSH_C3, oxm, flow->nshc3, match->wc.masks.nshc3);
|
||
+ nxm_put_32m(b, MFF_NSH_C4, oxm, flow->nshc4, match->wc.masks.nshc4);
|
||
+
|
||
+ /* ENCAP Eth */
|
||
+ nxm_put_eth_masked(b, MFF_ENCAP_ETH_SRC, oxm,
|
||
+ flow->encap_eth_src, match->wc.masks.encap_eth_src);
|
||
+ nxm_put_eth_masked(b, MFF_ENCAP_ETH_DST, oxm,
|
||
+ flow->encap_eth_dst, match->wc.masks.encap_eth_dst);
|
||
+ nxm_put_16m(b, MFF_ENCAP_ETH_TYPE, oxm,
|
||
+ ofputil_dl_type_to_openflow(flow->encap_eth_type),
|
||
+ match->wc.masks.encap_eth_type); //uncertain
|
||
+
|
||
/* Ethernet. */
|
||
nxm_put_eth_masked(b, MFF_ETH_SRC, oxm,
|
||
flow->dl_src, match->wc.masks.dl_src);
|
||
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
|
||
index b5204b2..b6dcd98 100644
|
||
--- a/lib/odp-execute.c
|
||
+++ b/lib/odp-execute.c
|
||
@@ -434,6 +434,8 @@ odp_execute_masked_set_action(struct dp_packet *packet,
|
||
case OVS_KEY_ATTR_ETHERTYPE:
|
||
case OVS_KEY_ATTR_IN_PORT:
|
||
case OVS_KEY_ATTR_VLAN:
|
||
+ case OVS_KEY_ATTR_NSH:
|
||
+ case OVS_KEY_ATTR_ENCAP_ETH:
|
||
case OVS_KEY_ATTR_ICMP:
|
||
case OVS_KEY_ATTR_ICMPV6:
|
||
case OVS_KEY_ATTR_TCP_FLAGS:
|
||
@@ -497,6 +499,10 @@ requires_datapath_assistance(const struct nlattr *a)
|
||
|
||
case OVS_ACTION_ATTR_SET:
|
||
case OVS_ACTION_ATTR_SET_MASKED:
|
||
+ case OVS_ACTION_ATTR_PUSH_NSH:
|
||
+ case OVS_ACTION_ATTR_POP_NSH:
|
||
+ case OVS_ACTION_ATTR_PUSH_ETH:
|
||
+ case OVS_ACTION_ATTR_POP_ETH:
|
||
case OVS_ACTION_ATTR_PUSH_VLAN:
|
||
case OVS_ACTION_ATTR_POP_VLAN:
|
||
case OVS_ACTION_ATTR_SAMPLE:
|
||
@@ -623,6 +629,10 @@ odp_execute_actions(void *dp, struct dp_packet **packets, int cnt, bool steal,
|
||
}
|
||
break;
|
||
|
||
+ case OVS_ACTION_ATTR_PUSH_NSH:
|
||
+ case OVS_ACTION_ATTR_POP_NSH:
|
||
+ case OVS_ACTION_ATTR_PUSH_ETH:
|
||
+ case OVS_ACTION_ATTR_POP_ETH:
|
||
case OVS_ACTION_ATTR_OUTPUT:
|
||
case OVS_ACTION_ATTR_TUNNEL_PUSH:
|
||
case OVS_ACTION_ATTR_TUNNEL_POP:
|
||
diff --git a/lib/odp-util.c b/lib/odp-util.c
|
||
index 7983720..102dfd7 100644
|
||
--- a/lib/odp-util.c
|
||
+++ b/lib/odp-util.c
|
||
@@ -70,7 +70,8 @@ static void format_odp_key_attr(const struct nlattr *a,
|
||
const struct nlattr *ma,
|
||
const struct hmap *portno_names, struct ds *ds,
|
||
bool verbose);
|
||
-
|
||
+static void format_eth(struct ds *ds, const char *name, const struct eth_addr key,
|
||
+ const struct eth_addr *mask, bool verbose);
|
||
struct geneve_scan {
|
||
struct geneve_opt d[63];
|
||
int len;
|
||
@@ -112,6 +113,10 @@ odp_action_len(uint16_t type)
|
||
case OVS_ACTION_ATTR_USERSPACE: return ATTR_LEN_VARIABLE;
|
||
case OVS_ACTION_ATTR_PUSH_VLAN: return sizeof(struct ovs_action_push_vlan);
|
||
case OVS_ACTION_ATTR_POP_VLAN: return 0;
|
||
+ case OVS_ACTION_ATTR_PUSH_NSH: return sizeof(struct ovs_action_push_nsh);
|
||
+ case OVS_ACTION_ATTR_POP_NSH: return 0;
|
||
+ case OVS_ACTION_ATTR_PUSH_ETH: return sizeof(struct ovs_action_push_eth);
|
||
+ case OVS_ACTION_ATTR_POP_ETH: return 0;
|
||
case OVS_ACTION_ATTR_PUSH_MPLS: return sizeof(struct ovs_action_push_mpls);
|
||
case OVS_ACTION_ATTR_POP_MPLS: return sizeof(ovs_be16);
|
||
case OVS_ACTION_ATTR_RECIRC: return sizeof(uint32_t);
|
||
@@ -147,6 +152,8 @@ ovs_key_attr_to_string(enum ovs_key_attr attr, char *namebuf, size_t bufsize)
|
||
case OVS_KEY_ATTR_CT_LABELS: return "ct_label";
|
||
case OVS_KEY_ATTR_TUNNEL: return "tunnel";
|
||
case OVS_KEY_ATTR_IN_PORT: return "in_port";
|
||
+ case OVS_KEY_ATTR_ENCAP_ETH: return "encap_eth";
|
||
+ case OVS_KEY_ATTR_NSH: return "nsh";
|
||
case OVS_KEY_ATTR_ETHERNET: return "eth";
|
||
case OVS_KEY_ATTR_VLAN: return "vlan";
|
||
case OVS_KEY_ATTR_ETHERTYPE: return "eth_type";
|
||
@@ -373,6 +380,36 @@ format_vlan_tci(struct ds *ds, ovs_be16 tci, ovs_be16 mask, bool verbose)
|
||
}
|
||
|
||
static void
|
||
+format_nsh(struct ds *ds, const struct ovs_action_push_nsh * nsh)
|
||
+{
|
||
+ const struct nsh_hdr *nsh_hdr =(struct nsh_hdr *)nsh->header;
|
||
+ ds_put_format(ds, "nsh_mdtype=%"PRIu8",nsh_np=%"PRIu8",nsp=%"PRIu32
|
||
+ ",nsi=%"PRIu8",nshc1=%"PRIu32",nshc2=%"PRIu32
|
||
+ ",nshc3=%"PRIu32",nshc4=%"PRIu32")",
|
||
+ nsh_hdr->base.mdtype,
|
||
+ nsh_hdr->base.proto,
|
||
+ ntohl(nsh_hdr->base.path_hdr << 8),
|
||
+ ntohl(nsh_hdr->base.path_hdr >> 24),
|
||
+ ntohl(nsh_hdr->ctx.nshc1),
|
||
+ ntohl(nsh_hdr->ctx.nshc2),
|
||
+ ntohl(nsh_hdr->ctx.nshc3),
|
||
+ ntohl(nsh_hdr->ctx.nshc4));
|
||
+}
|
||
+
|
||
+static void
|
||
+format_encap_eth(struct ds *ds, const struct ovs_action_push_eth *encap_eth)
|
||
+{
|
||
+ const struct encap_eth_hdr *encap_eth_hdr = (struct encap_eth_hdr *)encap_eth->header;
|
||
+ ds_put_format(ds, "encap_eth_type=%"PRIu16",",
|
||
+ ntohs(encap_eth_hdr->encap_eth_type));
|
||
+ format_eth(ds, "encap_eth_src", encap_eth_hdr->encap_eth_src,
|
||
+ NULL, true);
|
||
+ format_eth(ds, "encap_eth_dst", encap_eth_hdr->encap_eth_dst,
|
||
+ NULL, true);
|
||
+ ds_put_format(ds, ")");
|
||
+}
|
||
+
|
||
+static void
|
||
format_mpls_lse(struct ds *ds, ovs_be32 mpls_lse)
|
||
{
|
||
ds_put_format(ds, "label=%"PRIu32",tc=%d,ttl=%d,bos=%d",
|
||
@@ -500,7 +537,7 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data)
|
||
gnh->oam ? "oam," : "",
|
||
gnh->critical ? "crit," : "",
|
||
ntohl(get_16aligned_be32(&gnh->vni)) >> 8);
|
||
-
|
||
+
|
||
if (gnh->opt_len) {
|
||
ds_put_cstr(ds, ",options(");
|
||
format_geneve_opts(gnh->options, NULL, gnh->opt_len * 4,
|
||
@@ -760,6 +797,8 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
|
||
{
|
||
int expected_len;
|
||
enum ovs_action_attr type = nl_attr_type(a);
|
||
+ const struct ovs_action_push_nsh *nsh;
|
||
+ const struct ovs_action_push_eth *encap_eth;
|
||
size_t size;
|
||
|
||
expected_len = odp_action_len(nl_attr_type(a));
|
||
@@ -830,6 +869,23 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
|
||
case OVS_ACTION_ATTR_POP_VLAN:
|
||
ds_put_cstr(ds, "pop_vlan");
|
||
break;
|
||
+ case OVS_ACTION_ATTR_PUSH_NSH:
|
||
+ nsh = nl_attr_get(a);
|
||
+ ds_put_cstr(ds, "push_nsh(");
|
||
+ format_nsh(ds, nsh);
|
||
+ break;
|
||
+ case OVS_ACTION_ATTR_POP_NSH:
|
||
+ ds_put_cstr(ds, "pop_nsh");
|
||
+ break;
|
||
+
|
||
+ case OVS_ACTION_ATTR_PUSH_ETH:
|
||
+ encap_eth = nl_attr_get(a);
|
||
+ ds_put_cstr(ds, "push_eth(");
|
||
+ format_encap_eth(ds, encap_eth);
|
||
+ break;
|
||
+ case OVS_ACTION_ATTR_POP_ETH:
|
||
+ ds_put_cstr(ds, "pop_eth");
|
||
+ break;
|
||
case OVS_ACTION_ATTR_PUSH_MPLS: {
|
||
const struct ovs_action_push_mpls *mpls = nl_attr_get(a);
|
||
ds_put_cstr(ds, "push_mpls(");
|
||
@@ -1618,6 +1674,72 @@ parse_odp_action(const char *s, const struct simap *port_names,
|
||
}
|
||
|
||
{
|
||
+ struct ovs_action_push_nsh push;
|
||
+ struct nsh_hdr *nsh = (struct nsh_hdr *)push.header;
|
||
+ ovs_be32 nsp, nshc1,nshc2,nshc3,nshc4;
|
||
+ uint8_t nsi, nsh_mdtype, nsh_np;
|
||
+ int n = -1;
|
||
+
|
||
+ if (ovs_scan_len(s, &n, "push_nsh(nsh_mdtype=%"SCNi8",nsh_np=%"SCNi8",nsp=0x%"SCNx32
|
||
+ ",nsi=%"SCNi8",nshc1=0x%"SCNx32",nshc2=0x%"SCNx32
|
||
+ ",nshc3=0x%"SCNx32",nshc4=0x%"SCNx32"))",
|
||
+ &nsh_mdtype, &nsh_np,
|
||
+ &nsp, &nsi,
|
||
+ &nshc1, &nshc2,
|
||
+ &nshc3, &nshc4)) {
|
||
+ if (nsh_mdtype == NSH_M_TYPE1) {
|
||
+ nsh->base.mdtype = NSH_M_TYPE1;
|
||
+ nsh->base.version = 0x01;
|
||
+ nsh->base.length = 6;
|
||
+ nsh->base.proto = nsh_np;
|
||
+ nsh->base.path_hdr= nsp;
|
||
+ nsh->base.svc_idx = nsi;
|
||
+ nsh->ctx.nshc1=nshc1;
|
||
+ nsh->ctx.nshc2=nshc2;
|
||
+ nsh->ctx.nshc3=nshc3;
|
||
+ nsh->ctx.nshc4=nshc4;
|
||
+ push.nsh_mdtype = NSH_M_TYPE1;
|
||
+ nl_msg_put_unspec(actions, OVS_ACTION_ATTR_PUSH_NSH,
|
||
+ &push, sizeof push);
|
||
+ }
|
||
+
|
||
+ return n;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (!strncmp(s, "pop_nsh", 7)) {
|
||
+ nl_msg_put_flag(actions, OVS_ACTION_ATTR_POP_NSH);
|
||
+ return 7;
|
||
+ }
|
||
+
|
||
+ {
|
||
+ struct ovs_action_push_eth push;
|
||
+ struct encap_eth_hdr *encap_eth = (struct encap_eth_hdr *)push.header;
|
||
+ uint16_t encap_eth_type;
|
||
+ int n = -1;
|
||
+
|
||
+ if (ovs_scan_len(s, &n, "push_eth(encap_eth_type=0x%"SCNx16",encap_eth_dst="ETH_ADDR_SCAN_FMT",encap_eth_src="ETH_ADDR_SCAN_FMT")",
|
||
+ &encap_eth_type,
|
||
+ ETH_ADDR_SCAN_ARGS(encap_eth->encap_eth_dst),
|
||
+ ETH_ADDR_SCAN_ARGS(encap_eth->encap_eth_src))) {
|
||
+ if (encap_eth->encap_eth_type == ETH_P_NSH) {
|
||
+ push.encap_eth_type = ETH_P_NSH;
|
||
+ encap_eth->encap_eth_type = htons(ETH_P_NSH);
|
||
+ nl_msg_put_unspec(actions, OVS_ACTION_ATTR_PUSH_ETH,
|
||
+ &push, sizeof push);
|
||
+ }
|
||
+
|
||
+ return n;
|
||
+ }
|
||
+
|
||
+ }
|
||
+
|
||
+ if (!strncmp(s, "pop_eth", 7)) {
|
||
+ nl_msg_put_flag(actions, OVS_ACTION_ATTR_POP_ETH);
|
||
+ return 7;
|
||
+ }
|
||
+
|
||
+ {
|
||
double percentage;
|
||
int n = -1;
|
||
|
||
@@ -1759,6 +1881,8 @@ static const struct attr_len_tbl ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] =
|
||
.next = ovs_tun_key_attr_lens,
|
||
.next_max = OVS_TUNNEL_KEY_ATTR_MAX },
|
||
[OVS_KEY_ATTR_IN_PORT] = { .len = 4 },
|
||
+ [OVS_KEY_ATTR_ENCAP_ETH] = { .len = 14 },
|
||
+ [OVS_KEY_ATTR_NSH] = { .len = 24 },
|
||
[OVS_KEY_ATTR_ETHERNET] = { .len = sizeof(struct ovs_key_ethernet) },
|
||
[OVS_KEY_ATTR_VLAN] = { .len = 2 },
|
||
[OVS_KEY_ATTR_ETHERTYPE] = { .len = 2 },
|
||
@@ -2146,6 +2270,23 @@ format_be64(struct ds *ds, const char *name, ovs_be64 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_ipv4(struct ds *ds, const char *name, ovs_be32 key,
|
||
const ovs_be32 *mask, bool verbose)
|
||
{
|
||
@@ -2798,6 +2939,34 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
|
||
}
|
||
break;
|
||
|
||
+ case OVS_KEY_ATTR_NSH: {
|
||
+ const struct ovs_key_nsh *mask = ma ? nl_attr_get(ma) : NULL;
|
||
+ const struct ovs_key_nsh *key = nl_attr_get(a);
|
||
+
|
||
+ format_u8u(ds, "nsi", key->nsi, MASK(mask, nsi), verbose);
|
||
+ format_be32(ds, "nsp", key->nsp, MASK(mask, nsp), verbose);
|
||
+ format_u8u(ds, "nsh_mdtype", key->nsh_mdtype, MASK(mask, nsh_mdtype), verbose);
|
||
+ format_u8u(ds, "nsh_np", key->nsh_np, MASK(mask, nsh_np), verbose);
|
||
+ format_be32(ds, "nshc1", key->nshc1, MASK(mask, nshc1), verbose);
|
||
+ format_be32(ds, "nshc2", key->nshc2, MASK(mask, nshc2), verbose);
|
||
+ format_be32(ds, "nshc3", key->nshc3, MASK(mask, nshc3), verbose);
|
||
+ format_be32(ds, "nshc4", key->nshc4, MASK(mask, nshc4), verbose);
|
||
+ ds_chomp(ds, ',');
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ case OVS_KEY_ATTR_ENCAP_ETH: {
|
||
+ const struct ovs_key_encap_eth *mask = ma ? nl_attr_get(ma) : NULL;
|
||
+ const struct ovs_key_encap_eth *key = nl_attr_get(a);
|
||
+
|
||
+ format_be16(ds, "encap_eth_type", key->encap_eth_type, MASK(mask, encap_eth_type), verbose);
|
||
+ format_eth(ds, "encap_eth_src", key->encap_eth_src, MASK(mask, encap_eth_src), verbose);
|
||
+ format_eth(ds, "encap_eth_dst", key->encap_eth_dst, MASK(mask, encap_eth_dst), verbose);
|
||
+ ds_chomp(ds, ',');
|
||
+
|
||
+ break;
|
||
+ }
|
||
+
|
||
case OVS_KEY_ATTR_ETHERNET: {
|
||
const struct ovs_key_ethernet *mask = ma ? nl_attr_get(ma) : NULL;
|
||
const struct ovs_key_ethernet *key = nl_attr_get(a);
|
||
@@ -3184,6 +3353,48 @@ scan_eth(const char *s, struct eth_addr *key, struct eth_addr *mask)
|
||
}
|
||
|
||
static int
|
||
+scan_nsp(const char *s, uint32_t *key, uint32_t *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 = UINT32_MAX;
|
||
+ }
|
||
+ }
|
||
+ return len;
|
||
+ }
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static int
|
||
+scan_encap_eth_type(const char *s, uint16_t *key, uint16_t *mask)
|
||
+{
|
||
+ int n;
|
||
+
|
||
+ if (ovs_scan(s, "%"SCNi16"%n", key, &n)) {
|
||
+ int len = n;
|
||
+ *key = htons(*key);
|
||
+ if (mask) {
|
||
+ if (ovs_scan(s + len, "/%"SCNi16"%n", mask, &n)) {
|
||
+ len += n;
|
||
+ *mask = htons(*mask);
|
||
+ } else {
|
||
+ *mask = UINT16_MAX;
|
||
+ }
|
||
+ }
|
||
+ return len;
|
||
+ }
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static int
|
||
scan_ipv4(const char *s, ovs_be32 *key, ovs_be32 *mask)
|
||
{
|
||
int n;
|
||
@@ -4123,6 +4334,23 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
|
||
SCAN_FIELD_NESTED_FUNC("flags(", uint16_t, tun_flags, tun_flags_to_attr);
|
||
} SCAN_END_NESTED();
|
||
|
||
+ SCAN_BEGIN("nsh(", struct ovs_key_nsh) {
|
||
+ SCAN_FIELD("nsh_mdtype=", u8, nsh_mdtype);
|
||
+ SCAN_FIELD("nsh_np=", u8, nsh_np);
|
||
+ SCAN_FIELD("nsp=", nsp, nsp);
|
||
+ SCAN_FIELD("nsi=", u8, nsi);
|
||
+ SCAN_FIELD("nshc1=", u32, nshc1);
|
||
+ SCAN_FIELD("nshc2=", u32, nshc2);
|
||
+ SCAN_FIELD("nshc3=", u32, nshc3);
|
||
+ SCAN_FIELD("nshc4=", u32, nshc4);
|
||
+ } SCAN_END(OVS_KEY_ATTR_NSH);
|
||
+
|
||
+ SCAN_BEGIN("encap_eth(", struct ovs_key_encap_eth) {
|
||
+ SCAN_FIELD("encap_eth_src=", eth, encap_eth_src);
|
||
+ SCAN_FIELD("encap_eth_dst=", eth, encap_eth_dst);
|
||
+ SCAN_FIELD("encap_eth_type=", encap_eth_type, encap_eth_type);
|
||
+ } SCAN_END(OVS_KEY_ATTR_ENCAP_ETH);
|
||
+
|
||
SCAN_SINGLE_PORT("in_port(", uint32_t, OVS_KEY_ATTR_IN_PORT);
|
||
|
||
SCAN_BEGIN("eth(", struct ovs_key_ethernet) {
|
||
@@ -4325,11 +4553,35 @@ union ovs_key_tp {
|
||
static void get_tp_key(const struct flow *, union ovs_key_tp *);
|
||
static void put_tp_key(const union ovs_key_tp *, struct flow *);
|
||
|
||
+void
|
||
+get_nsh_key(const struct flow *flow, struct ovs_key_nsh *nsh)
|
||
+{
|
||
+ nsh->nsi = flow->nsi;
|
||
+ nsh->nsp = flow->nsp;
|
||
+ nsh->nsh_mdtype = flow->nsh_mdtype;
|
||
+ nsh->nsh_np = flow->nsh_np;
|
||
+ nsh->reserved = 0;
|
||
+ nsh->nshc1 = flow->nshc1;
|
||
+ nsh->nshc2 = flow->nshc2;
|
||
+ nsh->nshc3 = flow->nshc3;
|
||
+ nsh->nshc4 = flow->nshc4;
|
||
+}
|
||
+
|
||
+void
|
||
+get_encap_eth_key(const struct flow *flow, struct ovs_key_encap_eth *encap_eth)
|
||
+{
|
||
+ encap_eth->encap_eth_type = flow->encap_eth_type;
|
||
+ encap_eth->encap_eth_src = flow->encap_eth_src;
|
||
+ encap_eth->encap_eth_dst = flow->encap_eth_dst;
|
||
+}
|
||
+
|
||
static void
|
||
odp_flow_key_from_flow__(const struct odp_flow_key_parms *parms,
|
||
bool export_mask, struct ofpbuf *buf)
|
||
{
|
||
struct ovs_key_ethernet *eth_key;
|
||
+ struct ovs_key_nsh *nsh_key;
|
||
+ struct ovs_key_encap_eth *encap_eth_key;
|
||
size_t encap;
|
||
const struct flow *flow = parms->flow;
|
||
const struct flow *data = export_mask ? parms->mask : parms->flow;
|
||
@@ -4368,6 +4620,18 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms *parms,
|
||
nl_msg_put_odp_port(buf, OVS_KEY_ATTR_IN_PORT, parms->odp_in_port);
|
||
}
|
||
|
||
+ if (flow->nsh_mdtype) {
|
||
+ nsh_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_NSH,
|
||
+ sizeof *nsh_key);
|
||
+ get_nsh_key(data, nsh_key);
|
||
+ }
|
||
+
|
||
+ if (flow->encap_eth_type) {
|
||
+ encap_eth_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ENCAP_ETH,
|
||
+ sizeof *encap_eth_key);
|
||
+ get_encap_eth_key(data, encap_eth_key);
|
||
+ }
|
||
+
|
||
eth_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ETHERNET,
|
||
sizeof *eth_key);
|
||
get_ethernet_key(data, eth_key);
|
||
@@ -5225,6 +5489,28 @@ odp_flow_key_to_flow__(const struct nlattr *key, size_t key_len,
|
||
flow->in_port.odp_port = ODPP_NONE;
|
||
}
|
||
|
||
+ /* NSH header. */
|
||
+ if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_NSH)) {
|
||
+ const struct ovs_key_nsh *nsh_key;
|
||
+
|
||
+ nsh_key = nl_attr_get(attrs[OVS_KEY_ATTR_NSH]);
|
||
+ put_nsh_key(nsh_key, flow);
|
||
+ if (is_mask) {
|
||
+ expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_NSH;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* ENCAP Eth header. */
|
||
+ if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ENCAP_ETH)) {
|
||
+ const struct ovs_key_encap_eth *encap_eth_key;
|
||
+
|
||
+ encap_eth_key = nl_attr_get(attrs[OVS_KEY_ATTR_ENCAP_ETH]);
|
||
+ put_encap_eth_key(encap_eth_key, flow);
|
||
+ if (is_mask) {
|
||
+ expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ENCAP_ETH;
|
||
+ }
|
||
+ }
|
||
+
|
||
/* Ethernet header. */
|
||
if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ETHERNET)) {
|
||
const struct ovs_key_ethernet *eth_key;
|
||
@@ -5526,6 +5812,41 @@ put_ethernet_key(const struct ovs_key_ethernet *eth, struct flow *flow)
|
||
flow->dl_dst = eth->eth_dst;
|
||
}
|
||
|
||
+void
|
||
+put_nsh_key(const struct ovs_key_nsh *nsh, struct flow *flow)
|
||
+{
|
||
+ flow->nsh_mdtype = nsh->nsh_mdtype;
|
||
+ flow->nsh_np = nsh->nsh_np;
|
||
+ flow->nsi = nsh->nsi;
|
||
+ flow->nsp = nsh->nsp;
|
||
+ flow->nshc1 = nsh->nshc1;
|
||
+ flow->nshc2 = nsh->nshc2;
|
||
+ flow->nshc3 = nsh->nshc3;
|
||
+ flow->nshc4 = nsh->nshc4;
|
||
+}
|
||
+
|
||
+void
|
||
+flow_zero_nsh(struct flow *flow)
|
||
+{
|
||
+ void *dst_p = &(flow->nshc1);
|
||
+ memset(dst_p, 0, 24);
|
||
+}
|
||
+
|
||
+void
|
||
+flow_zero_encap_eth(struct flow *flow)
|
||
+{
|
||
+ void *dst_p = &flow->encap_eth_src;
|
||
+ memset(dst_p, 0, 16);
|
||
+}
|
||
+
|
||
+void
|
||
+put_encap_eth_key(const struct ovs_key_encap_eth *encap_eth, struct flow *flow)
|
||
+{
|
||
+ flow->encap_eth_type = encap_eth->encap_eth_type;
|
||
+ flow->encap_eth_src = encap_eth->encap_eth_src;
|
||
+ flow->encap_eth_dst = encap_eth->encap_eth_dst;
|
||
+}
|
||
+
|
||
static void
|
||
commit_set_ether_addr_action(const struct flow *flow, struct flow *base_flow,
|
||
struct ofpbuf *odp_actions,
|
||
@@ -5577,6 +5898,94 @@ commit_vlan_action(ovs_be16 vlan_tci, struct flow *base,
|
||
base->vlan_tci = vlan_tci;
|
||
}
|
||
|
||
+static void
|
||
+commit_nsh_pop_action(const struct flow *flow, struct flow *base,
|
||
+ struct ofpbuf *odp_actions, struct flow_wildcards *wc)
|
||
+{
|
||
+ struct ovs_key_nsh flow_key, base_key;
|
||
+ get_nsh_key(flow, &flow_key);
|
||
+ get_nsh_key(base, &base_key);
|
||
+
|
||
+ if (memcmp(&flow_key, &base_key, sizeof flow_key)) {
|
||
+ memset(&wc->masks.nsh_mdtype, 0xff, sizeof wc->masks.nsh_mdtype);
|
||
+
|
||
+ if (base->nsh_mdtype) {
|
||
+ nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_NSH);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static void
|
||
+commit_nsh_push_action(const struct flow *flow, struct flow *base,
|
||
+ struct ofpbuf *odp_actions)
|
||
+{
|
||
+ struct ovs_key_nsh flow_key, base_key;
|
||
+ get_nsh_key(flow, &flow_key);
|
||
+ get_nsh_key(base, &base_key);
|
||
+
|
||
+ if (memcmp(&flow_key, &base_key, sizeof flow_key)) {
|
||
+ if (flow->nsh_mdtype) {
|
||
+ struct ovs_action_push_nsh nsh;
|
||
+ nsh.nsh_mdtype = flow->nsh_mdtype;
|
||
+ struct nsh_hdr *nsh_hdr = (struct nsh_hdr *)nsh.header;
|
||
+ memset(nsh_hdr, 0, sizeof *nsh_hdr);
|
||
+ nsh_hdr->base.length = 6;
|
||
+ nsh_hdr->base.proto = flow->nsh_np;
|
||
+ nsh_hdr->base.mdtype = flow->nsh_mdtype;
|
||
+ nsh_hdr->base.proto = flow->nsh_np;
|
||
+ nsh_hdr->base.path_hdr = flow->nsp >> 8 | flow->nsi << 24;
|
||
+ nsh_hdr->ctx.nshc1 = flow->nshc1;
|
||
+ nsh_hdr->ctx.nshc2 = flow->nshc2;
|
||
+ nsh_hdr->ctx.nshc3 = flow->nshc3;
|
||
+ nsh_hdr->ctx.nshc4 = flow->nshc4;
|
||
+ nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_PUSH_NSH,
|
||
+ &nsh, sizeof nsh);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static void
|
||
+commit_encap_eth_pop_action(const struct flow *flow, struct flow *base,
|
||
+ struct ofpbuf *odp_actions, struct flow_wildcards *wc)
|
||
+{
|
||
+ struct ovs_key_encap_eth flow_key, base_key;
|
||
+ get_encap_eth_key(flow, &flow_key);
|
||
+ get_encap_eth_key(base, &base_key);
|
||
+
|
||
+ if (memcmp(&flow_key, &base_key, sizeof flow_key)) {
|
||
+ memset(&wc->masks.encap_eth_type, 0xff, sizeof wc->masks.encap_eth_type);
|
||
+
|
||
+ if (base->encap_eth_type) {
|
||
+ nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_ETH);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static void
|
||
+commit_encap_eth_push_action(const struct flow *flow, struct flow *base,
|
||
+ struct ofpbuf *odp_actions)
|
||
+{
|
||
+ struct ovs_key_encap_eth flow_key, base_key;
|
||
+ get_encap_eth_key(flow, &flow_key);
|
||
+ get_encap_eth_key(base, &base_key);
|
||
+
|
||
+ if (memcmp(&flow_key, &base_key, sizeof flow_key)) {
|
||
+ if (flow->encap_eth_type) {
|
||
+ struct ovs_action_push_eth encap_eth;
|
||
+ encap_eth.encap_eth_type = flow->encap_eth_type;
|
||
+ struct encap_eth_hdr *encap_eth_header =
|
||
+ (struct encap_eth_hdr *)encap_eth.header;
|
||
+ void *dst_p = encap_eth_header->encap_eth_dst.ea;
|
||
+ void *src_p = encap_eth_header->encap_eth_src.ea;
|
||
+ memcpy(dst_p, flow->encap_eth_dst.ea, sizeof flow->encap_eth_dst);
|
||
+ memcpy(src_p, flow->encap_eth_src.ea, sizeof flow->encap_eth_src);
|
||
+ encap_eth_header->encap_eth_type = htons(ETH_P_NSH);
|
||
+ nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_PUSH_ETH,
|
||
+ &encap_eth, sizeof encap_eth);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
/* Wildcarding already done at action translation time. */
|
||
static void
|
||
commit_mpls_action(const struct flow *flow, struct flow *base,
|
||
@@ -6008,6 +6417,10 @@ commit_odp_actions(const struct flow *flow, struct flow *base,
|
||
slow2 = commit_set_icmp_action(flow, base, odp_actions, wc);
|
||
commit_mpls_action(flow, base, odp_actions);
|
||
commit_vlan_action(flow->vlan_tci, base, odp_actions, wc);
|
||
+ commit_encap_eth_pop_action(flow, base, odp_actions, wc);
|
||
+ commit_nsh_pop_action(flow, base, odp_actions, wc);
|
||
+ commit_nsh_push_action(flow, base, odp_actions);
|
||
+ commit_encap_eth_push_action(flow, base, odp_actions);
|
||
commit_set_priority_action(flow, base, odp_actions, wc, use_masked);
|
||
commit_set_pkt_mark_action(flow, base, odp_actions, wc, use_masked);
|
||
|
||
diff --git a/lib/odp-util.h b/lib/odp-util.h
|
||
index 51cf5c3..2cb04f1 100644
|
||
--- a/lib/odp-util.h
|
||
+++ b/lib/odp-util.h
|
||
@@ -66,7 +66,7 @@ enum slow_path_reason {
|
||
/* Mask of all slow_path_reasons. */
|
||
enum {
|
||
SLOW_PATH_REASON_MASK = 0
|
||
-#define SPR(ENUM, STRING, EXPLANATION) | 1 << ENUM##_INDEX
|
||
+#define SPR(ENUM, STRING, EXPLANATION) | 1 << ENUM##_INDEX
|
||
SLOW_PATH_REASONS
|
||
#undef SPR
|
||
};
|
||
@@ -126,6 +126,8 @@ void odp_portno_names_destroy(struct hmap *portno_names);
|
||
* OVS_KEY_ATTR_CT_ZONE 2 2 4 8
|
||
* OVS_KEY_ATTR_CT_MARK 4 -- 4 8
|
||
* OVS_KEY_ATTR_CT_LABEL 16 -- 4 20
|
||
+ * OVS_KEY_ATTR_NSH 24 -- 4 28
|
||
+ * OVS_KEY_ATTR_ENCAP 14 -- 4 18
|
||
* OVS_KEY_ATTR_ETHERNET 12 -- 4 16
|
||
* OVS_KEY_ATTR_ETHERTYPE 2 2 4 8 (outer VLAN ethertype)
|
||
* OVS_KEY_ATTR_VLAN 2 2 4 8
|
||
@@ -150,6 +152,12 @@ struct odputil_keybuf {
|
||
uint32_t keybuf[DIV_ROUND_UP(ODPUTIL_FLOW_KEY_BYTES, 4)];
|
||
};
|
||
|
||
+void put_nsh_key(const struct ovs_key_nsh *, struct flow *);
|
||
+void get_nsh_key(const struct flow *flow, struct ovs_key_nsh *nsh);
|
||
+void put_encap_eth_key(const struct ovs_key_encap_eth *encap_eth, struct flow *flow);
|
||
+void get_encap_eth_key(const struct flow *flow, struct ovs_key_encap_eth *encap_eth);
|
||
+void flow_zero_nsh(struct flow *);
|
||
+void flow_zero_encap_eth(struct flow *);
|
||
enum odp_key_fitness odp_tun_key_from_attr(const struct nlattr *, bool udpif,
|
||
struct flow_tnl *);
|
||
|
||
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
|
||
index aac4ff0..f4062b2 100644
|
||
--- a/lib/ofp-actions.c
|
||
+++ b/lib/ofp-actions.c
|
||
@@ -299,6 +299,18 @@ enum ofp_raw_action_type {
|
||
/* NX1.0+(36): struct nx_action_nat, ... */
|
||
NXAST_RAW_NAT,
|
||
|
||
+ /* NX1.0+(38): void. */
|
||
+ NXAST_RAW_PUSH_NSH,
|
||
+
|
||
+ /* NX1.0+(39): void. */
|
||
+ NXAST_RAW_POP_NSH,
|
||
+
|
||
+ /* NX1.0+(40): void. */
|
||
+ NXAST_RAW_PUSH_ETH,
|
||
+
|
||
+ /* NX1.0+(41): void. */
|
||
+ NXAST_RAW_POP_ETH,
|
||
+
|
||
/* ## ------------------ ## */
|
||
/* ## Debugging actions. ## */
|
||
/* ## ------------------ ## */
|
||
@@ -1624,7 +1636,127 @@ format_PUSH_VLAN(const struct ofpact_null *a OVS_UNUSED, struct ds *s)
|
||
ds_put_format(s, "%spush_vlan:%s%#"PRIx16,
|
||
colors.param, colors.end, ETH_TYPE_VLAN_8021Q);
|
||
}
|
||
-
|
||
+
|
||
+/* Push NSH header actions. */
|
||
+static enum ofperr
|
||
+decode_NXAST_RAW_PUSH_NSH(struct ofpbuf * out)
|
||
+{
|
||
+ ofpact_put_PUSH_NSH(out)->ofpact.raw = NXAST_RAW_PUSH_NSH;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static void
|
||
+encode_PUSH_NSH(const struct ofpact_null *null OVS_UNUSED,
|
||
+ enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out)
|
||
+{
|
||
+ put_NXAST_PUSH_NSH(out);
|
||
+}
|
||
+
|
||
+static char * OVS_WARN_UNUSED_RESULT
|
||
+parse_PUSH_NSH(char *arg OVS_UNUSED, struct ofpbuf *ofpacts,
|
||
+ enum ofputil_protocol *usable_protocols OVS_UNUSED)
|
||
+{
|
||
+ ofpact_put_PUSH_NSH(ofpacts)->ofpact.raw = NXAST_RAW_PUSH_NSH;;
|
||
+ return NULL;
|
||
+}
|
||
+
|
||
+static void
|
||
+format_PUSH_NSH(const struct ofpact_null *a OVS_UNUSED, struct ds *s)
|
||
+{
|
||
+ ds_put_format(s, "push_nsh");
|
||
+}
|
||
+
|
||
+/* Pop NSH header actions. */
|
||
+static enum ofperr
|
||
+decode_NXAST_RAW_POP_NSH(struct ofpbuf * out)
|
||
+{
|
||
+ ofpact_put_POP_NSH(out)->ofpact.raw = NXAST_RAW_POP_NSH;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static void
|
||
+encode_POP_NSH(const struct ofpact_null *null OVS_UNUSED,
|
||
+ enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out)
|
||
+{
|
||
+ put_NXAST_POP_NSH(out);
|
||
+}
|
||
+
|
||
+static char * OVS_WARN_UNUSED_RESULT
|
||
+parse_POP_NSH(char *arg OVS_UNUSED, struct ofpbuf *ofpacts,
|
||
+ enum ofputil_protocol *usable_protocols OVS_UNUSED)
|
||
+{
|
||
+ ofpact_put_POP_NSH(ofpacts)->ofpact.raw = NXAST_RAW_POP_NSH;
|
||
+ return NULL;
|
||
+}
|
||
+
|
||
+static void
|
||
+format_POP_NSH(const struct ofpact_null *a OVS_UNUSED, struct ds *s)
|
||
+{
|
||
+ ds_put_format(s, "pop_nsh");
|
||
+}
|
||
+
|
||
+/* Push ENCAP Eth header actions. */
|
||
+static enum ofperr
|
||
+decode_NXAST_RAW_PUSH_ETH(struct ofpbuf * out)
|
||
+{
|
||
+ ofpact_put_PUSH_ETH(out)->ofpact.raw = NXAST_RAW_PUSH_ETH;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static void
|
||
+encode_PUSH_ETH(const struct ofpact_null *null OVS_UNUSED,
|
||
+ enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out)
|
||
+{
|
||
+ put_NXAST_PUSH_ETH(out);
|
||
+}
|
||
+
|
||
+static char * OVS_WARN_UNUSED_RESULT
|
||
+parse_PUSH_ETH(char *arg OVS_UNUSED, struct ofpbuf *ofpacts,
|
||
+ enum ofputil_protocol *usable_protocols OVS_UNUSED)
|
||
+{
|
||
+ ofpact_put_PUSH_ETH(ofpacts)->ofpact.raw = NXAST_RAW_PUSH_ETH;;
|
||
+ return NULL;
|
||
+}
|
||
+
|
||
+static void
|
||
+format_PUSH_ETH(const struct ofpact_null *a OVS_UNUSED, struct ds *s)
|
||
+{
|
||
+ ds_put_format(s, "push_eth");
|
||
+}
|
||
+
|
||
+/* Pop ENCAP ETH header actions. */
|
||
+static enum ofperr
|
||
+decode_NXAST_RAW_POP_ETH(struct ofpbuf * out)
|
||
+{
|
||
+ ofpact_put_POP_ETH(out)->ofpact.raw = NXAST_RAW_POP_ETH;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static void
|
||
+encode_POP_ETH(const struct ofpact_null *null OVS_UNUSED,
|
||
+ enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out)
|
||
+{
|
||
+ put_NXAST_POP_ETH(out);
|
||
+}
|
||
+
|
||
+static char * OVS_WARN_UNUSED_RESULT
|
||
+parse_POP_ETH(char *arg OVS_UNUSED, struct ofpbuf *ofpacts,
|
||
+ enum ofputil_protocol *usable_protocols OVS_UNUSED)
|
||
+{
|
||
+ ofpact_put_POP_ETH(ofpacts)->ofpact.raw = NXAST_RAW_POP_ETH;
|
||
+ return NULL;
|
||
+}
|
||
+
|
||
+static void
|
||
+format_POP_ETH(const struct ofpact_null *a OVS_UNUSED, struct ds *s)
|
||
+{
|
||
+ ds_put_format(s, "pop_eth");
|
||
+}
|
||
+
|
||
/* Action structure for OFPAT10_SET_DL_SRC/DST and OFPAT11_SET_DL_SRC/DST. */
|
||
struct ofp_action_dl_addr {
|
||
ovs_be16 type; /* Type. */
|
||
@@ -5910,6 +6042,10 @@ ofpact_is_set_or_move_action(const struct ofpact *a)
|
||
case OFPACT_POP_QUEUE:
|
||
case OFPACT_PUSH_MPLS:
|
||
case OFPACT_PUSH_VLAN:
|
||
+ case OFPACT_PUSH_NSH:
|
||
+ case OFPACT_POP_NSH:
|
||
+ case OFPACT_PUSH_ETH:
|
||
+ case OFPACT_POP_ETH:
|
||
case OFPACT_RESUBMIT:
|
||
case OFPACT_SAMPLE:
|
||
case OFPACT_STACK_POP:
|
||
@@ -5937,6 +6073,10 @@ ofpact_is_allowed_in_actions_set(const struct ofpact *a)
|
||
case OFPACT_POP_MPLS:
|
||
case OFPACT_PUSH_MPLS:
|
||
case OFPACT_PUSH_VLAN:
|
||
+ case OFPACT_PUSH_NSH:
|
||
+ case OFPACT_POP_NSH:
|
||
+ case OFPACT_PUSH_ETH:
|
||
+ case OFPACT_POP_ETH:
|
||
case OFPACT_REG_MOVE:
|
||
case OFPACT_SET_FIELD:
|
||
case OFPACT_SET_ETH_DST:
|
||
@@ -6162,6 +6302,10 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type)
|
||
case OFPACT_SET_VLAN_PCP:
|
||
case OFPACT_STRIP_VLAN:
|
||
case OFPACT_PUSH_VLAN:
|
||
+ case OFPACT_PUSH_NSH:
|
||
+ case OFPACT_POP_NSH:
|
||
+ case OFPACT_PUSH_ETH:
|
||
+ case OFPACT_POP_ETH:
|
||
case OFPACT_SET_ETH_SRC:
|
||
case OFPACT_SET_ETH_DST:
|
||
case OFPACT_SET_IPV4_SRC:
|
||
@@ -6709,6 +6853,10 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a,
|
||
case OFPACT_SET_TUNNEL:
|
||
case OFPACT_SET_QUEUE:
|
||
case OFPACT_POP_QUEUE:
|
||
+ case OFPACT_PUSH_NSH:
|
||
+ case OFPACT_POP_NSH:
|
||
+ case OFPACT_PUSH_ETH:
|
||
+ case OFPACT_POP_ETH:
|
||
case OFPACT_RESUBMIT:
|
||
return 0;
|
||
|
||
@@ -7266,6 +7414,10 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port)
|
||
case OFPACT_SET_VLAN_PCP:
|
||
case OFPACT_STRIP_VLAN:
|
||
case OFPACT_PUSH_VLAN:
|
||
+ case OFPACT_PUSH_NSH:
|
||
+ case OFPACT_POP_NSH:
|
||
+ case OFPACT_PUSH_ETH:
|
||
+ case OFPACT_POP_ETH:
|
||
case OFPACT_SET_ETH_SRC:
|
||
case OFPACT_SET_ETH_DST:
|
||
case OFPACT_SET_IPV4_SRC:
|
||
diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
|
||
index 4bd8854..3897c0b 100644
|
||
--- a/lib/ofp-actions.h
|
||
+++ b/lib/ofp-actions.h
|
||
@@ -93,6 +93,12 @@
|
||
OFPACT(POP_QUEUE, ofpact_null, ofpact, "pop_queue") \
|
||
OFPACT(FIN_TIMEOUT, ofpact_fin_timeout, ofpact, "fin_timeout") \
|
||
\
|
||
+ /* NSH */ \
|
||
+ OFPACT(PUSH_NSH, ofpact_null, ofpact, "push_nsh") \
|
||
+ OFPACT(POP_NSH, ofpact_null, ofpact, "pop_nsh") \
|
||
+ OFPACT(PUSH_ETH, ofpact_null, ofpact, "push_eth") \
|
||
+ OFPACT(POP_ETH, ofpact_null, ofpact, "pop_eth") \
|
||
+ \
|
||
/* Flow table interaction. */ \
|
||
OFPACT(RESUBMIT, ofpact_resubmit, ofpact, "resubmit") \
|
||
OFPACT(LEARN, ofpact_learn, specs, "learn") \
|
||
diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
|
||
index fbc82b7..e15e8d2 100644
|
||
--- a/ofproto/ofproto-dpif-sflow.c
|
||
+++ b/ofproto/ofproto-dpif-sflow.c
|
||
@@ -976,6 +976,8 @@ sflow_read_set_action(const struct nlattr *attr,
|
||
case OVS_KEY_ATTR_IN_PORT:
|
||
case OVS_KEY_ATTR_ETHERNET:
|
||
case OVS_KEY_ATTR_VLAN:
|
||
+ case OVS_KEY_ATTR_NSH:
|
||
+ case OVS_KEY_ATTR_ENCAP_ETH:
|
||
break;
|
||
|
||
case OVS_KEY_ATTR_MPLS: {
|
||
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
|
||
index 2612b7d..f59eed8 100644
|
||
--- a/ofproto/ofproto-dpif-upcall.c
|
||
+++ b/ofproto/ofproto-dpif-upcall.c
|
||
@@ -39,6 +39,7 @@
|
||
#include "seq.h"
|
||
#include "unixctl.h"
|
||
#include "openvswitch/vlog.h"
|
||
+#include "odp-util.h"
|
||
|
||
#define MAX_QUEUE_LENGTH 512
|
||
#define UPCALL_MAX_BATCH 64
|
||
@@ -746,6 +747,9 @@ recv_upcalls(struct handler *handler)
|
||
struct upcall *upcall = &upcalls[n_upcalls];
|
||
struct flow *flow = &flows[n_upcalls];
|
||
unsigned int mru;
|
||
+ struct ovs_key_nsh reserve_nsh;
|
||
+ struct ovs_key_encap_eth reserve_encap_eth;
|
||
+ bool nsh_mdtype_flag, encap_eth_type_flag;
|
||
int error;
|
||
|
||
ofpbuf_use_stub(recv_buf, recv_stubs[n_upcalls],
|
||
@@ -796,8 +800,23 @@ recv_upcalls(struct handler *handler)
|
||
}
|
||
|
||
pkt_metadata_from_flow(&dupcall->packet.md, flow);
|
||
+
|
||
+ nsh_mdtype_flag = !!(flow->nsh_mdtype);
|
||
+ encap_eth_type_flag = !!(flow->encap_eth_type);
|
||
+ if(nsh_mdtype_flag)
|
||
+ get_nsh_key(flow, &reserve_nsh);
|
||
+
|
||
+ if(encap_eth_type_flag)
|
||
+ get_encap_eth_key(flow, &reserve_encap_eth);
|
||
+
|
||
flow_extract(&dupcall->packet, flow);
|
||
|
||
+ if(nsh_mdtype_flag)
|
||
+ put_nsh_key(&reserve_nsh, flow);
|
||
+
|
||
+ if(encap_eth_type_flag)
|
||
+ put_encap_eth_key(&reserve_encap_eth, flow);
|
||
+
|
||
error = process_upcall(udpif, upcall,
|
||
&upcall->odp_actions, &upcall->wc);
|
||
if (error) {
|
||
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
|
||
index a02dc24..4f91d0a 100644
|
||
--- a/ofproto/ofproto-dpif-xlate.c
|
||
+++ b/ofproto/ofproto-dpif-xlate.c
|
||
@@ -4240,6 +4240,10 @@ freeze_unroll_actions(const struct ofpact *a, const struct ofpact *end,
|
||
case OFPACT_SET_VLAN_PCP:
|
||
case OFPACT_STRIP_VLAN:
|
||
case OFPACT_PUSH_VLAN:
|
||
+ case OFPACT_PUSH_NSH:
|
||
+ case OFPACT_POP_NSH:
|
||
+ case OFPACT_PUSH_ETH:
|
||
+ case OFPACT_POP_ETH:
|
||
case OFPACT_SET_ETH_SRC:
|
||
case OFPACT_SET_ETH_DST:
|
||
case OFPACT_SET_IPV4_SRC:
|
||
@@ -4524,6 +4528,24 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
|
||
}
|
||
break;
|
||
|
||
+ case OFPACT_PUSH_NSH:
|
||
+ memset(&wc->masks.nsh_mdtype, 0xff, sizeof wc->masks.nsh_mdtype);
|
||
+ break;
|
||
+
|
||
+ case OFPACT_POP_NSH:
|
||
+ memset(&wc->masks.nsh_mdtype, 0xff, sizeof wc->masks.nsh_mdtype);
|
||
+ flow_zero_nsh(flow);
|
||
+ break;
|
||
+
|
||
+ case OFPACT_PUSH_ETH:
|
||
+ memset(&wc->masks.encap_eth_type, 0xff, sizeof wc->masks.encap_eth_type);
|
||
+ break;
|
||
+
|
||
+ case OFPACT_POP_ETH:
|
||
+ memset(&wc->masks.encap_eth_type, 0xff, sizeof wc->masks.encap_eth_type);
|
||
+ flow_zero_encap_eth(flow);
|
||
+ break;
|
||
+
|
||
case OFPACT_STRIP_VLAN:
|
||
memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci);
|
||
flow->vlan_tci = htons(0);
|
||
diff --git a/tests/ofproto.at b/tests/ofproto.at
|
||
index 6c7217d..7141e39 100644
|
||
--- a/tests/ofproto.at
|
||
+++ b/tests/ofproto.at
|
||
@@ -1777,7 +1777,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_ipv6_src tun_ipv6_dst tun_flags tun_gbp_id tun_gbp_flags tun_gpe_np tun_gpe_flags tun_metadata0 dnl
|
||
tun_metadata1 tun_metadata2 tun_metadata3 tun_metadata4 tun_metadata5 tun_metadata6 tun_metadata7 tun_metadata8 tun_metadata9 tun_metadata10 tun_metadata11 tun_metadata12 tun_metadata13 tun_metadata14 tun_metadata15 tun_metadata16 tun_metadata17 tun_metadata18 tun_metadata19 tun_metadata20 tun_metadata21 tun_metadata22 tun_metadata23 tun_metadata24 tun_metadata25 tun_metadata26 tun_metadata27 tun_metadata28 tun_metadata29 tun_metadata30 tun_metadata31 tun_metadata32 tun_metadata33 tun_metadata34 tun_metadata35 tun_metadata36 tun_metadata37 tun_metadata38 tun_metadata39 tun_metadata40 tun_metadata41 tun_metadata42 tun_metadata43 tun_metadata44 tun_metadata45 tun_metadata46 tun_metadata47 tun_metadata48 tun_metadata49 tun_metadata50 tun_metadata51 tun_metadata52 tun_metadata53 tun_metadata54 tun_metadata55 tun_metadata56 tun_metadata57 tun_metadata58 tun_metadata59 tun_metadata60 tun_metadata61 tun_metadata62 tun_metadata63 dnl
|
||
-metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 xreg0 xreg1 xreg2 xreg3 eth_src eth_dst vlan_tci vlan_vid vlan_pcp mpls_label mpls_tc mpls_ttl ip_src ip_dst ipv6_src ipv6_dst ipv6_label nw_tos ip_dscp nw_ecn nw_ttl arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst icmp_type icmp_code icmpv6_type icmpv6_code nd_target nd_sll nd_tll
|
||
+metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 xreg0 xreg1 xreg2 xreg3 eth_src eth_dst vlan_tci vlan_vid vlan_pcp mpls_label mpls_tc mpls_ttl ip_src ip_dst ipv6_src ipv6_dst ipv6_label nw_tos ip_dscp nw_ecn nw_ttl arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst icmp_type icmp_code icmpv6_type icmpv6_code nd_target nd_sll nd_tll nsp nsi nshc1 nshc2 nshc3 nshc4 nsh_mdtype nsh_np encap_eth_src encap_eth_dst encap_eth_type
|
||
matching:
|
||
dp_hash: arbitrary mask
|
||
recirc_id: exact match or wildcard
|
||
@@ -1917,6 +1917,17 @@ metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4
|
||
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
|
||
+ nsh_mdtype: arbitrary mask
|
||
+ nsh_np: arbitrary mask
|
||
+ encap_eth_src: arbitrary mask
|
||
+ encap_eth_dst: arbitrary mask
|
||
+ encap_eth_type: exact match or wildcard
|
||
|
||
' $1
|
||
}
|
||
diff --git a/tests/tunnel.at b/tests/tunnel.at
|
||
index 0c033da..d957574 100644
|
||
--- a/tests/tunnel.at
|
||
+++ b/tests/tunnel.at
|
||
@@ -412,6 +412,163 @@ AT_CHECK([tail -1 stdout], [0],
|
||
OVS_VSWITCHD_STOP
|
||
AT_CLEANUP
|
||
|
||
+AT_SETUP([tunnel - VXLAN-GPE and NSH - Encapsulation - kernel space])
|
||
+OVS_VSWITCHD_START([dnl
|
||
+ add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 \
|
||
+ -- add-port br0 p2 -- set Interface p2 type=vxlan options:key=flow \
|
||
+ options:remote_ip=1.1.1.1 options:dst_port=4790 ofport_request=2 \
|
||
+ options:exts=gpe])
|
||
+
|
||
+OVS_VSWITCHD_DISABLE_TUNNEL_PUSH_POP
|
||
+ADD_OF_PORTS([br0], [90])
|
||
+AT_DATA([flows.txt], [dnl
|
||
+in_port=90 actions=resubmit:1,resubmit:2
|
||
+in_port=1 actions=push_nsh,set_field:1->nsh_mdtype,set_field:0x3->nsh_np,set_field:0x112233->nsp,set_field:0x44->nsi,set_field:0x11223344->nshc1,set_field:0x55667788->nshc2,set_field:0x99aabbcc->nshc3,set_field:0xddeeff00->nshc4,output:1
|
||
+in_port=2 actions=push_nsh,set_field:1->nsh_mdtype,set_field:0x3->nsh_np,set_field:0x112233->nsp,set_field:0x44->nsi,set_field:0x11223344->nshc1,set_field:0x55667788->nshc2,set_field:0x99aabbcc->nshc3,set_field:0xddeeff00->nshc4,set_field:4->tun_gpe_np,output:2
|
||
+])
|
||
+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: push_nsh(nsh_mdtype=1,nsh_np=3,nsp=1122867,nsi=1140850688,nshc1=287454020,nshc2=1432778632,nshc3=2578103244,nshc4=3723427584),1,set(tunnel(tun_id=0x0,dst=1.1.1.1,ttl=64,vxlan(gpe(np=0x4,flags=0)),flags(df|key))),push_nsh(nsh_mdtype=1,nsh_np=3,nsp=1122867,nsi=1140850688,nshc1=287454020,nshc2=1432778632,nshc3=2578103244,nshc4=3723427584),4790
|
||
+])
|
||
+
|
||
+OVS_VSWITCHD_STOP
|
||
+AT_CLEANUP
|
||
+
|
||
+AT_SETUP([tunnel - VXLAN-GPE and NSH - Decapsulation - kernel space])
|
||
+OVS_VSWITCHD_START([dnl
|
||
+ add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 \
|
||
+ -- add-port br0 p2 -- set Interface p2 type=vxlan options:key=flow \
|
||
+ options:remote_ip=1.1.1.1 options:dst_port=4790 ofport_request=2 \
|
||
+ options:exts=gpe])
|
||
+OVS_VSWITCHD_DISABLE_TUNNEL_PUSH_POP
|
||
+
|
||
+AT_DATA([flows.txt], [dnl
|
||
+priority=200,in_port=2,tun_gpe_np=4,nsh_mdtype=1,nsh_np=3,nsi=0x44,nsp=0x112233,actions=pop_nsh,output=1
|
||
+])
|
||
+
|
||
+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/1: (dummy)
|
||
+ p2 2/4790: (vxlan: dst_port=4790, key=flow, remote_ip=1.1.1.1)
|
||
+])
|
||
+
|
||
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=1.1.1.1,dst=1.2.3.4,ttl=64,flags(),vxlan(gpe(np=4,flags=0x0c))),in_port(4790),nsh(nsh_mdtype=1,nsh_np=3,nsp=0x112233,nsi=0x44,nshc1=0x11223344,nshc2=0x55667788,nshc3=0x99aabbcc,nshc4=0xddeeff00),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: pop_nsh,1
|
||
+])
|
||
+
|
||
+OVS_VSWITCHD_STOP
|
||
+AT_CLEANUP
|
||
+
|
||
+AT_SETUP([Eth and NSH - Encapsulation - kernel space])
|
||
+OVS_VSWITCHD_START([dnl
|
||
+ add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 \
|
||
+ -- add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2])
|
||
+
|
||
+OVS_VSWITCHD_DISABLE_TUNNEL_PUSH_POP
|
||
+ADD_OF_PORTS([br0], [90])
|
||
+AT_DATA([flows.txt], [dnl
|
||
+in_port=90 actions=resubmit:1,resubmit:2
|
||
+in_port=1 actions=push_nsh,set_field:1->nsh_mdtype,set_field:0x3->nsh_np,set_field:0x112233->nsp,set_field:0x44->nsi,set_field:0x11223344->nshc1,set_field:0x55667788->nshc2,set_field:0x99aabbcc->nshc3,push_eth,set_field:0x894f->encap_eth_type,set_field:00:11:22:33:44:55->encap_eth_dst,set_field:00:66:77:88:99:aa->encap_eth_src,output:1
|
||
+in_port=2 actions=push_nsh,set_field:1->nsh_mdtype,set_field:0x3->nsh_np,set_field:0x112233->nsp,set_field:0x44->nsi,set_field:0x11223344->nshc1,set_field:0x55667788->nshc2,set_field:0x99aabbcc->nshc3,set_field:0xddeeff00->nshc4,output:2
|
||
+])
|
||
+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: push_nsh(nsh_mdtype=1,nsh_np=3,nsp=1122867,nsi=1140850688,nshc1=287454020,nshc2=1432778632,nshc3=2578103244,nshc4=0),push_eth(encap_eth_type=35151,encap_eth_src=00:66:77:88:99:aa,encap_eth_dst=00:11:22:33:44:55,),1,push_nsh(nsh_mdtype=1,nsh_np=3,nsp=1122867,nsi=1140850688,nshc1=287454020,nshc2=1432778632,nshc3=2578103244,nshc4=3723427584),push_eth(encap_eth_type=35151,encap_eth_src=00:66:77:88:99:aa,encap_eth_dst=00:11:22:33:44:55,),2
|
||
+])
|
||
+
|
||
+OVS_VSWITCHD_STOP
|
||
+AT_CLEANUP
|
||
+
|
||
+AT_SETUP([Eth and NSH - Decapsulation - kernel space])
|
||
+OVS_VSWITCHD_START([dnl
|
||
+ add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 \
|
||
+ -- add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2])
|
||
+OVS_VSWITCHD_DISABLE_TUNNEL_PUSH_POP
|
||
+
|
||
+AT_DATA([flows.txt], [dnl
|
||
+priority=200,in_port=2,nsh_mdtype=1,nsh_np=3,nsi=0x44,nsp=0x112233,encap_eth_type=0x894f,encap_eth_dst=00:11:22:33:44:55,encap_eth_src=00:66:77:88:99:aa,actions=pop_nsh,pop_eth,output=1
|
||
+])
|
||
+
|
||
+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/1: (dummy)
|
||
+ p2 2/2: (dummy)
|
||
+])
|
||
+
|
||
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy ',in_port(2),encap_eth(encap_eth_type=0x894f,encap_eth_dst=00:11:22:33:44:55,encap_eth_src=00:66:77:88:99:aa),nsh(nsh_mdtype=1,nsh_np=3,nsp=0x112233,nsi=0x44,nshc1=0x11223344,nshc2=0x55667788,nshc3=0x99aabbcc,nshc4=0xddeeff00),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: pop_eth,pop_nsh,1
|
||
+])
|
||
+
|
||
+OVS_VSWITCHD_STOP
|
||
+AT_CLEANUP
|
||
+
|
||
+AT_SETUP([VXLANGPE+NSH to Eth+NSH - kernel space])
|
||
+OVS_VSWITCHD_START([dnl
|
||
+ add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 \
|
||
+ -- add-port br0 p2 -- set Interface p2 type=vxlan options:key=flow \
|
||
+ options:remote_ip=1.1.1.1 options:dst_port=4790 ofport_request=2 \
|
||
+ options:exts=gpe])
|
||
+OVS_VSWITCHD_DISABLE_TUNNEL_PUSH_POP
|
||
+
|
||
+AT_DATA([flows.txt], [dnl
|
||
+priority=200,in_port=2,tun_gpe_np=4,nsh_mdtype=1,nsh_np=3,nsi=0x44,nsp=0x112233,actions=push_eth,set_field:0x894f->encap_eth_type,set_field:00:11:22:33:44:55->encap_eth_dst,set_field:00:66:77:88:99:aa->encap_eth_src,output:1
|
||
+
|
||
+])
|
||
+
|
||
+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/1: (dummy)
|
||
+ p2 2/4790: (vxlan: dst_port=4790, key=flow, remote_ip=1.1.1.1)
|
||
+])
|
||
+
|
||
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=1.1.1.1,dst=1.2.3.4,ttl=64,flags(),vxlan(gpe(np=4,flags=0x0c))),in_port(4790),nsh(nsh_mdtype=1,nsh_np=3,nsp=0x112233,nsi=0x44,nshc1=0x11223344,nshc2=0x55667788,nshc3=0x99aabbcc,nshc4=0xddeeff00),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: push_eth(encap_eth_type=35151,encap_eth_src=00:66:77:88:99:aa,encap_eth_dst=00:11:22:33:44:55,),1
|
||
+])
|
||
+
|
||
+OVS_VSWITCHD_STOP
|
||
+AT_CLEANUP
|
||
+
|
||
+AT_SETUP([Eth+NSH to VXLANGPE+NSH - kernel space])
|
||
+OVS_VSWITCHD_START([dnl
|
||
+ add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 \
|
||
+ -- add-port br0 p2 -- set Interface p2 type=vxlan options:key=flow \
|
||
+ options:remote_ip=1.1.1.1 options:dst_port=4790 ofport_request=2 \
|
||
+ options:exts=gpe])
|
||
+OVS_VSWITCHD_DISABLE_TUNNEL_PUSH_POP
|
||
+
|
||
+AT_DATA([flows.txt], [dnl
|
||
+priority=200,in_port=1,nsh_mdtype=1,nsh_np=3,nsi=0x44,nsp=0x112233,encap_eth_type=0x894f,encap_eth_dst=00:11:22:33:44:55,encap_eth_src=00:66:77:88:99:aa,actions=pop_eth,set_field:0x4->tun_gpe_np,output=2
|
||
+])
|
||
+
|
||
+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/1: (dummy)
|
||
+ p2 2/4790: (vxlan: dst_port=4790, key=flow, remote_ip=1.1.1.1)
|
||
+])
|
||
+
|
||
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy ',in_port(1),encap_eth(encap_eth_type=0x894f,encap_eth_dst=00:11:22:33:44:55,encap_eth_src=00:66:77:88:99:aa),,nsh(nsh_mdtype=1,nsh_np=3,nsp=0x112233,nsi=0x44,nshc1=0x11223344,nshc2=0x55667788,nshc3=0x99aabbcc,nshc4=0xddeeff00),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,vxlan(gpe(np=0x4,flags=0)),flags(df|key))),pop_eth,4790
|
||
+])
|
||
+
|
||
+OVS_VSWITCHD_STOP
|
||
+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 \
|
||
--
|
||
1.9.3
|
||
|