[ovs-dev] [PATCH v2 1/6] userspace: Add OXM field MFF_PACKET_TYPE
Zoltán Balogh
zoltan.balogh at ericsson.com
Fri May 19 09:23:44 UTC 2017
From: Jan Scheurich <jan.scheurich at ericsson.com>
Allow packet type namespace OFPHTN_ETHERTYPE as alternative pre-requisite
for matching L3 protocols (MPLS, IP, IPv6, ARP etc).
Change the meta-flow definition of packet_type field to use the new
custom format MFS_PACKET_TYPE representing "(NS,NS_TYPE)".
Parsing routine for MFS_PACKET_TYPE added to meta-flow.c. Formatting
routine for field packet_type extracted from match_format() and moved to
flow.c to be used from meta-flow.c for formatting MFS_PACKET_TYPE.
Updated the ovs-fields man page source meta-flow.xml with documentation
for packet-type-aware bridges and added documentation for field packet_type.
Added packet_type to the matching properties in tests/ofproto.at. Should be
removed later, when packet_type_aware bridge attribute will be introduced.
Signed-off-by: Jan Scheurich <jan.scheurich at ericsson.com>
---
build-aux/extract-ofp-fields | 3 +-
include/openvswitch/meta-flow.h | 20 ++++++++
lib/flow.c | 18 +++++++
lib/flow.h | 28 ++++++++---
lib/match.c | 52 +++++++++-----------
lib/meta-flow.c | 85 +++++++++++++++++++++++++++++---
lib/meta-flow.xml | 106 +++++++++++++++++++++++++++++++---------
lib/nx-match.c | 16 ++++--
lib/odp-util.c | 48 ++++++++++++++++--
lib/ofp-parse.c | 6 +++
lib/ofp-util.c | 42 +++++++++++-----
tests/dpif-netdev.at | 14 +++---
tests/odp.at | 1 +
tests/ofproto-dpif.at | 20 ++++----
tests/ofproto.at | 1 +
tests/pmd.at | 2 +-
tests/tunnel-push-pop-ipv6.at | 2 +-
tests/tunnel-push-pop.at | 2 +-
18 files changed, 361 insertions(+), 105 deletions(-)
diff --git a/build-aux/extract-ofp-fields b/build-aux/extract-ofp-fields
index d5b8a82..24dd756 100755
--- a/build-aux/extract-ofp-fields
+++ b/build-aux/extract-ofp-fields
@@ -36,7 +36,8 @@ FORMATTING = {"decimal": ("MFS_DECIMAL", 1, 8),
"OpenFlow 1.1+ port": ("MFS_OFP_PORT_OXM", 4, 4),
"frag": ("MFS_FRAG", 1, 1),
"tunnel flags": ("MFS_TNL_FLAGS", 2, 2),
- "TCP flags": ("MFS_TCP_FLAGS", 2, 2)}
+ "TCP flags": ("MFS_TCP_FLAGS", 2, 2),
+ "packet type": ("MFS_PACKET_TYPE", 4, 4)}
PREREQS = {"none": "MFP_NONE",
"Ethernet": "MFP_ETHERNET",
diff --git a/include/openvswitch/meta-flow.h b/include/openvswitch/meta-flow.h
index c284ec6..c6b95df 100644
--- a/include/openvswitch/meta-flow.h
+++ b/include/openvswitch/meta-flow.h
@@ -132,6 +132,11 @@ struct ofputil_tlv_table_mod;
*
* TCP flags: See the description of tcp_flags in ovs-ofctl(8).
*
+ * packet type: A pair of packet type namespace NS and NS_TYPE within
+ * that namespace "(NS,NS_TYPE)". NS and NS_TYPE are formatted in
+ * decimal or hexadecimal as and accept decimal and hexadecimal (with
+ * 0x prefix) at parsing.
+ *
* Prerequisites:
*
* The field's prerequisites. The values should be straightfoward.
@@ -247,6 +252,20 @@ enum OVS_PACKED_ENUM mf_field_id {
*/
MFF_RECIRC_ID,
+ /* "packet_type".
+ *
+ * Define the packet type in OpenFlow 1.3+.
+ *
+ * Type: be32.
+ * Maskable: no.
+ * Formatting: packet type.
+ * Prerequisites: none.
+ * Access: read-only.
+ * NXM: none.
+ * OXM: OXM_OF_PACKET_TYPE(44) since OF1.3 and v2.8.
+ */
+ MFF_PACKET_TYPE,
+
/* "conj_id".
*
* ID for "conjunction" actions. Please refer to ovs-ofctl(8)
@@ -1859,6 +1878,7 @@ enum OVS_PACKED_ENUM mf_string {
MFS_FRAG, /* no, yes, first, later, not_later */
MFS_TNL_FLAGS, /* FLOW_TNL_F_* flags */
MFS_TCP_FLAGS, /* TCP_* flags */
+ MFS_PACKET_TYPE, /* "(NS,NS_TYPE)" */
};
struct mf_field {
diff --git a/lib/flow.c b/lib/flow.c
index 7f98a46..4f7a041 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -1149,6 +1149,24 @@ format_flags_masked(struct ds *ds, const char *name,
}
}
+void
+format_packet_type_masked(struct ds *s, const ovs_be32 value, const ovs_be32 mask)
+{
+ if (pt_ns_type_be(mask) == 0) {
+ ds_put_format(s, "packet_type=(%u,*),",
+ pt_ns(value));
+ } else if (pt_ns_type_be(mask) == OVS_BE16_MAX) {
+ ds_put_format(s, "packet_type=(%u,0x%"PRIx16"),",
+ pt_ns(value),
+ pt_ns_type(value));
+ } else{
+ ds_put_format(s, "packet_type=(%u,0x%"PRIx16"/0x%"PRIx16"),",
+ pt_ns(value),
+ pt_ns_type(value),
+ pt_ns_type(mask));
+ }
+}
+
/* Scans a string 's' of flags to determine their numerical value and
* returns the number of characters parsed using 'bit_to_string' to
* lookup flag names. Scanning continues until the character 'end' is
diff --git a/lib/flow.h b/lib/flow.h
index 94c8a0c..92a7c63 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -82,6 +82,8 @@ void format_flags(struct ds *ds, const char *(*bit_to_string)(uint32_t),
void format_flags_masked(struct ds *ds, const char *name,
const char *(*bit_to_string)(uint32_t),
uint32_t flags, uint32_t mask, uint32_t max_mask);
+void format_packet_type_masked(struct ds *s, const ovs_be32 value,
+ const ovs_be32 mask);
int parse_flags(const char *s, const char *(*bit_to_string)(uint32_t),
char end, const char *field_name, char **res_string,
uint32_t *res_flags, uint32_t allowed, uint32_t *res_mask);
@@ -962,9 +964,23 @@ static inline bool is_ethernet(const struct flow *flow,
return flow->packet_type == htonl(PT_ETH);
}
+static inline ovs_be16 get_dl_type(const struct flow *flow)
+{
+ if (flow->packet_type == htonl(PT_ETH)) {
+ return flow->dl_type;
+ } else if (pt_ns(flow->packet_type) == OFPHTN_ETHERTYPE) {
+ return pt_ns_type_be(flow->packet_type);
+ } else {
+ return htons(FLOW_DL_TYPE_NONE);
+ }
+}
+
static inline bool is_vlan(const struct flow *flow,
struct flow_wildcards *wc)
{
+ if (!is_ethernet(flow, wc)) {
+ return false;
+ }
if (wc) {
WC_MASK_FIELD_MASK(wc, vlans[0].tci, htons(VLAN_CFI));
}
@@ -973,7 +989,7 @@ static inline bool is_vlan(const struct flow *flow,
static inline bool is_ip_any(const struct flow *flow)
{
- return dl_type_is_ip_any(flow->dl_type);
+ return dl_type_is_ip_any(get_dl_type(flow));
}
static inline bool is_ip_proto(const struct flow *flow, uint8_t ip_proto,
@@ -1009,7 +1025,7 @@ static inline bool is_sctp(const struct flow *flow,
static inline bool is_icmpv4(const struct flow *flow,
struct flow_wildcards *wc)
{
- if (flow->dl_type == htons(ETH_TYPE_IP)) {
+ if (get_dl_type(flow) == htons(ETH_TYPE_IP)) {
if (wc) {
memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
}
@@ -1021,7 +1037,7 @@ static inline bool is_icmpv4(const struct flow *flow,
static inline bool is_icmpv6(const struct flow *flow,
struct flow_wildcards *wc)
{
- if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
+ if (get_dl_type(flow) == htons(ETH_TYPE_IPV6)) {
if (wc) {
memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
}
@@ -1052,7 +1068,7 @@ static inline bool is_nd(const struct flow *flow,
static inline bool is_igmp(const struct flow *flow, struct flow_wildcards *wc)
{
- if (flow->dl_type == htons(ETH_TYPE_IP)) {
+ if (get_dl_type(flow) == htons(ETH_TYPE_IP)) {
if (wc) {
memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
}
@@ -1096,8 +1112,8 @@ static inline bool is_mld_report(const struct flow *flow,
static inline bool is_stp(const struct flow *flow)
{
- return (eth_addr_equals(flow->dl_dst, eth_addr_stp)
- && flow->dl_type == htons(FLOW_DL_TYPE_NONE));
+ return (flow->dl_type == htons(FLOW_DL_TYPE_NONE)
+ && eth_addr_equals(flow->dl_dst, eth_addr_stp));
}
#endif /* flow.h */
diff --git a/lib/match.c b/lib/match.c
index 4855c74..ad9927f 100644
--- a/lib/match.c
+++ b/lib/match.c
@@ -1171,8 +1171,8 @@ match_format(const struct match *match, struct ds *s, int priority)
size_t start_len = s->length;
const struct flow *f = &match->flow;
bool skip_type = false;
-
bool skip_proto = false;
+ ovs_be16 dl_type = f->dl_type;
int i;
@@ -1254,24 +1254,16 @@ match_format(const struct match *match, struct ds *s, int priority)
}
if (wc->masks.packet_type) {
- if (pt_ns_type_be(wc->masks.packet_type) == 0) {
- ds_put_format(s, "packet_type=(%u,*),",
- pt_ns(f->packet_type));
- } else if (pt_ns_type_be(wc->masks.packet_type) == OVS_BE16_MAX) {
- ds_put_format(s, "packet_type=(%u,0x%"PRIx16"),",
- pt_ns(f->packet_type),
- pt_ns_type(f->packet_type));
- } else{
- ds_put_format(s, "packet_type=(%u,0x%"PRIx16"/0x%"PRIx16"),",
- pt_ns(f->packet_type),
- pt_ns_type(f->packet_type),
- pt_ns_type(wc->masks.packet_type));
+ format_packet_type_masked(s, f->packet_type, wc->masks.packet_type);
+ if (pt_ns(f->packet_type) == OFPHTN_ETHERTYPE) {
+ dl_type = pt_ns_type_be(f->packet_type);
}
}
if (wc->masks.dl_type) {
+ dl_type = f->dl_type;
skip_type = true;
- if (f->dl_type == htons(ETH_TYPE_IP)) {
+ if (dl_type == htons(ETH_TYPE_IP)) {
if (wc->masks.nw_proto) {
skip_proto = true;
if (f->nw_proto == IPPROTO_ICMP) {
@@ -1291,7 +1283,7 @@ match_format(const struct match *match, struct ds *s, int priority)
} else {
ds_put_format(s, "%sip%s,", colors.value, colors.end);
}
- } else if (f->dl_type == htons(ETH_TYPE_IPV6)) {
+ } else if (dl_type == htons(ETH_TYPE_IPV6)) {
if (wc->masks.nw_proto) {
skip_proto = true;
if (f->nw_proto == IPPROTO_ICMPV6) {
@@ -1309,13 +1301,13 @@ match_format(const struct match *match, struct ds *s, int priority)
} else {
ds_put_format(s, "%sipv6%s,", colors.value, colors.end);
}
- } else if (f->dl_type == htons(ETH_TYPE_ARP)) {
+ } else if (dl_type == htons(ETH_TYPE_ARP)) {
ds_put_format(s, "%sarp%s,", colors.value, colors.end);
- } else if (f->dl_type == htons(ETH_TYPE_RARP)) {
+ } else if (dl_type == htons(ETH_TYPE_RARP)) {
ds_put_format(s, "%srarp%s,", colors.value, colors.end);
- } else if (f->dl_type == htons(ETH_TYPE_MPLS)) {
+ } else if (dl_type == htons(ETH_TYPE_MPLS)) {
ds_put_format(s, "%smpls%s,", colors.value, colors.end);
- } else if (f->dl_type == htons(ETH_TYPE_MPLS_MCAST)) {
+ } else if (dl_type == htons(ETH_TYPE_MPLS_MCAST)) {
ds_put_format(s, "%smplsm%s,", colors.value, colors.end);
} else {
skip_type = false;
@@ -1387,9 +1379,9 @@ match_format(const struct match *match, struct ds *s, int priority)
if (!skip_type && wc->masks.dl_type) {
ds_put_format(s, "%sdl_type=%s0x%04"PRIx16",",
- colors.param, colors.end, ntohs(f->dl_type));
+ colors.param, colors.end, ntohs(dl_type));
}
- if (f->dl_type == htons(ETH_TYPE_IPV6)) {
+ if (dl_type == htons(ETH_TYPE_IPV6)) {
format_ipv6_netmask(s, "ipv6_src", &f->ipv6_src, &wc->masks.ipv6_src);
format_ipv6_netmask(s, "ipv6_dst", &f->ipv6_dst, &wc->masks.ipv6_dst);
if (wc->masks.ipv6_label) {
@@ -1403,8 +1395,8 @@ match_format(const struct match *match, struct ds *s, int priority)
ntohl(wc->masks.ipv6_label));
}
}
- } else if (f->dl_type == htons(ETH_TYPE_ARP) ||
- f->dl_type == htons(ETH_TYPE_RARP)) {
+ } else if (dl_type == htons(ETH_TYPE_ARP) ||
+ dl_type == htons(ETH_TYPE_RARP)) {
format_ip_netmask(s, "arp_spa", f->nw_src, wc->masks.nw_src);
format_ip_netmask(s, "arp_tpa", f->nw_dst, wc->masks.nw_dst);
} else {
@@ -1412,8 +1404,8 @@ match_format(const struct match *match, struct ds *s, int priority)
format_ip_netmask(s, "nw_dst", f->nw_dst, wc->masks.nw_dst);
}
if (!skip_proto && wc->masks.nw_proto) {
- if (f->dl_type == htons(ETH_TYPE_ARP) ||
- f->dl_type == htons(ETH_TYPE_RARP)) {
+ if (dl_type == htons(ETH_TYPE_ARP) ||
+ dl_type == htons(ETH_TYPE_RARP)) {
ds_put_format(s, "%sarp_op=%s%"PRIu8",",
colors.param, colors.end, f->nw_proto);
} else {
@@ -1421,8 +1413,8 @@ match_format(const struct match *match, struct ds *s, int priority)
colors.param, colors.end, f->nw_proto);
}
}
- if (f->dl_type == htons(ETH_TYPE_ARP) ||
- f->dl_type == htons(ETH_TYPE_RARP)) {
+ if (dl_type == htons(ETH_TYPE_ARP) ||
+ dl_type == htons(ETH_TYPE_RARP)) {
format_eth_masked(s, "arp_sha", f->arp_sha, wc->masks.arp_sha);
format_eth_masked(s, "arp_tha", f->arp_tha, wc->masks.arp_tha);
}
@@ -1475,15 +1467,15 @@ match_format(const struct match *match, struct ds *s, int priority)
f->nw_frag & FLOW_NW_FRAG_LATER ? "later" : "not_later");
break;
}
- if (f->dl_type == htons(ETH_TYPE_IP) &&
+ if (dl_type == htons(ETH_TYPE_IP) &&
f->nw_proto == IPPROTO_ICMP) {
format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src);
format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst);
- } else if (f->dl_type == htons(ETH_TYPE_IP) &&
+ } else if (dl_type == htons(ETH_TYPE_IP) &&
f->nw_proto == IPPROTO_IGMP) {
format_be16_masked(s, "igmp_type", f->tp_src, wc->masks.tp_src);
format_be16_masked(s, "igmp_code", f->tp_dst, wc->masks.tp_dst);
- } else if (f->dl_type == htons(ETH_TYPE_IPV6) &&
+ } else if (dl_type == htons(ETH_TYPE_IPV6) &&
f->nw_proto == IPPROTO_ICMPV6) {
format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src);
format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst);
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index a963cce..0096917 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -205,6 +205,8 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
return !wc->masks.dp_hash;
case MFF_RECIRC_ID:
return !wc->masks.recirc_id;
+ case MFF_PACKET_TYPE:
+ return !wc->masks.packet_type;
case MFF_CONJ_ID:
return !wc->masks.conj_id;
case MFF_TUN_SRC:
@@ -401,22 +403,24 @@ mf_are_prereqs_ok__(const struct mf_field *mf, const struct flow *flow,
const struct flow_wildcards *mask,
struct flow_wildcards *wc)
{
+ ovs_be16 dl_type = get_dl_type(flow);
+
switch (mf->prereqs) {
case MFP_NONE:
return true;
case MFP_ETHERNET:
return is_ethernet(flow, wc);
case MFP_ARP:
- return (flow->dl_type == htons(ETH_TYPE_ARP) ||
- flow->dl_type == htons(ETH_TYPE_RARP));
+ return (dl_type == htons(ETH_TYPE_ARP) ||
+ dl_type == htons(ETH_TYPE_RARP));
case MFP_IPV4:
- return flow->dl_type == htons(ETH_TYPE_IP);
+ return dl_type == htons(ETH_TYPE_IP);
case MFP_IPV6:
- return flow->dl_type == htons(ETH_TYPE_IPV6);
+ return dl_type == htons(ETH_TYPE_IPV6);
case MFP_VLAN_VID:
return is_vlan(flow, wc);
case MFP_MPLS:
- return eth_type_mpls(flow->dl_type);
+ return eth_type_mpls(dl_type);
case MFP_IP_ANY:
return is_ip_any(flow);
case MFP_CT_VALID:
@@ -476,6 +480,7 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
switch (mf->id) {
case MFF_DP_HASH:
case MFF_RECIRC_ID:
+ case MFF_PACKET_TYPE:
case MFF_CONJ_ID:
case MFF_TUN_ID:
case MFF_TUN_SRC:
@@ -600,6 +605,9 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
case MFF_RECIRC_ID:
value->be32 = htonl(flow->recirc_id);
break;
+ case MFF_PACKET_TYPE:
+ value->be32 = flow->packet_type;
+ break;
case MFF_CONJ_ID:
value->be32 = htonl(flow->conj_id);
break;
@@ -883,6 +891,9 @@ mf_set_value(const struct mf_field *mf,
case MFF_RECIRC_ID:
match_set_recirc_id(match, ntohl(value->be32));
break;
+ case MFF_PACKET_TYPE:
+ match_set_packet_type(match, value->be32);
+ break;
case MFF_CONJ_ID:
match_set_conj_id(match, ntohl(value->be32));
break;
@@ -1248,6 +1259,9 @@ mf_set_flow_value(const struct mf_field *mf,
case MFF_RECIRC_ID:
flow->recirc_id = ntohl(value->be32);
break;
+ case MFF_PACKET_TYPE:
+ flow->packet_type = value->be32;
+ break;
case MFF_CONJ_ID:
flow->conj_id = ntohl(value->be32);
break;
@@ -1292,7 +1306,6 @@ mf_set_flow_value(const struct mf_field *mf,
case MFF_IN_PORT:
flow->in_port.ofp_port = u16_to_ofp(ntohs(value->be16));
break;
-
case MFF_IN_PORT_OXM:
ofputil_port_from_ofp11(value->be32, &flow->in_port.ofp_port);
break;
@@ -1598,6 +1611,10 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str)
match->flow.recirc_id = 0;
match->wc.masks.recirc_id = 0;
break;
+ case MFF_PACKET_TYPE:
+ match->flow.packet_type = 0;
+ match->wc.masks.packet_type = 0;
+ break;
case MFF_CONJ_ID:
match->flow.conj_id = 0;
match->wc.masks.conj_id = 0;
@@ -1931,6 +1948,7 @@ mf_set(const struct mf_field *mf,
case MFF_CT_TP_SRC:
case MFF_CT_TP_DST:
case MFF_RECIRC_ID:
+ case MFF_PACKET_TYPE:
case MFF_CONJ_ID:
case MFF_IN_PORT:
case MFF_IN_PORT_OXM:
@@ -2296,6 +2314,44 @@ syntax_error:
}
static char *
+mf_from_packet_type_string(const char *s, ovs_be32 *packet_type)
+{
+ char *tail;
+ const char *err_str = "";
+ int err;
+
+ if (*s != '(') {
+ err_str = "missing '('";
+ goto syntax_error;
+ }
+ s++;
+ err = parse_int_string(s, (uint8_t *)packet_type, 2, &tail);
+ if (err) {
+ err_str = "ns";
+ goto syntax_error;
+ }
+ if (*tail != ',') {
+ err_str = "missing ','";
+ goto syntax_error;
+ }
+ s = tail + 1;
+ err = parse_int_string(s, ((uint8_t *)packet_type) + 2, 2, &tail);
+ if (err) {
+ err_str = "ns_type";
+ goto syntax_error;
+ }
+ if (*tail != ')') {
+ err_str = "missing ')'";
+ goto syntax_error;
+ }
+
+ return NULL;
+
+syntax_error:
+ return xasprintf("%s: bad syntax for packet type %s", s, err_str);
+}
+
+static char *
mf_from_ethernet_string(const struct mf_field *mf, const char *s,
struct eth_addr *mac, struct eth_addr *mask)
{
@@ -2528,6 +2584,12 @@ mf_parse(const struct mf_field *mf, const char *s,
error = mf_from_tcp_flags_string(s, &value->be16, &mask->be16);
break;
+ case MFS_PACKET_TYPE:
+ ovs_assert(mf->n_bytes == sizeof(ovs_be32));
+ error = mf_from_packet_type_string(s, &value->be32);
+ mask->be32 = OVS_BE32_MAX;
+ break;
+
default:
OVS_NOT_REACHED();
}
@@ -2621,6 +2683,12 @@ mf_format_ct_state_string(ovs_be32 value, ovs_be32 mask, struct ds *s)
ntohl(mask), UINT16_MAX);
}
+static void
+mf_format_packet_type_string(ovs_be32 value, ovs_be32 mask, struct ds *s)
+{
+ format_packet_type_masked(s, value, mask);
+}
+
/* Appends to 's' a string representation of field 'mf' whose value is in
* 'value' and 'mask'. 'mask' may be NULL to indicate an exact match. */
void
@@ -2688,6 +2756,11 @@ mf_format(const struct mf_field *mf,
mask ? mask->be16 : OVS_BE16_MAX, s);
break;
+ case MFS_PACKET_TYPE:
+ mf_format_packet_type_string(value->be32,
+ mask ? mask->be32 : OVS_BE32_MAX, s);
+ break;
+
default:
OVS_NOT_REACHED();
}
diff --git a/lib/meta-flow.xml b/lib/meta-flow.xml
index 5efd431..c94288e 100644
--- a/lib/meta-flow.xml
+++ b/lib/meta-flow.xml
@@ -22,26 +22,37 @@
</p>
<p>
- Some data fields, called <dfn>root fields</dfn>, are always present as a
- consequence of the basic networking technology in use. The Ethernet header
- fields are root fields in current versions of Open vSwitch, though future
- versions might support other roots. (Currently, to support LISP tunnels,
- which do not encapsulate an Ethernet header, Open vSwitch synthesizes one.)
+ Data fields that are always present as a consequence of the basic
+ networking technology in use are called called <dfn>root fields</dfn>.
+ In earlier versions of Open vSwitch, the Ethernet header was always
+ present and, as a consequence, the Ethernet header fields were root fields.
+ This remains the default mode of operation of Open vSwitch. When packets
+ are received from a "layer3" Tunnel which does not encapsulate an Ethernet
+ header (such as LISP or GRE), Open vSwitch synthesizes one.
</p>
- <!-- future directions: EXT-112 -->
<p>
- Other data fields are not always present. A packet contains ARP fields,
- for example, only when its Ethernet header indicates the Ethertype for ARP,
+ The present version of Open vSwitch supports the concept of packet type-
+ aware pipeline introduced in OpenFlow 1.5. A bridge configured as packet
+ type-aware can handle packets of multiple networking technologies, such as
+ Ethernet, IP, ARP, MPLS, or NSH in parallel.
+ The new packet type data metadata field <cite>packet_type</cite> becomes
+ the single root field and determines the applicability of all data fields.
+ </p>
+
+ <p>
+ Non-root data fields are not always present. A packet contains ARP
+ fields, for example, only when its packet type is ARP or when it is an
+ Ethernet packet whose Ethernet header indicates the Ethertype for ARP,
0x0806. In this documentation, we say that a field is
<dfn>applicable</dfn> when it is present in a packet, and
<dfn>inapplicable</dfn> when it is not. (These are not standard terms.)
We refer to the conditions that determine whether a field is applicable as
<dfn>prerequisites</dfn>. Some VLAN-related fields are a special case:
- these fields are always applicable, but have a designated value or bit that
- indicates whether a VLAN header is present, with the remaining values or
- bits indicating the VLAN header's content (if it is present). <!-- XXX
- also ethertype -->
+ these fields are always applicable for Ethernet packets, but have a
+ designated value or bit that indicates whether a VLAN header is present,
+ with the remaining values or bits indicating the VLAN header's content
+ (if it is present). <!-- XXX also ethertype -->
</p>
<p>
@@ -51,7 +62,8 @@
example, one may match (see <cite>Matching</cite>, below) a given
field only if the match includes the field's prerequisite,
e.g. matching an ARP field is only allowed if one also matches on
- Ethertype 0x0806.
+ Ethertype 0x0806 or the packet_type for ARP in a packet type-aware
+ bridge.
</p>
<p>
@@ -317,6 +329,15 @@ tcp,tp_src=0x07c0/0xfff0
<dt><code>mplsm</code></dt> <dd><code>eth_type=0x8848</code></dd>
</dl>
+ <p>
+ These shorthand notations continue to work in packet type-aware bridges.
+ The absence of a packet_type match implies packet_type=ethernet, so that
+ shorthands match on Ethernet packets with the implied eth_type. Please
+ note that the shorthand <code>ip</code> does not match packets of packet_type
+ (1,0x800) for IPv4.
+ </p>
+
+
<h2>Evolution of OpenFlow Fields</h2>
<p>
@@ -802,20 +823,12 @@ tcp,tp_src=0x07c0/0xfff0
</p>
<ul>
+ <li>Packet type.</li>
<li>TCP flags.</li>
<li>Packet registers.</li>
<li>The output port in the OpenFlow action set.</li>
</ul>
- <p>
- OpenFlow 1.5 also added OXMs for the following fields not documented here
- and not yet implemented by Open vSwitch:
- </p>
-
- <ul>
- <li>Packet type.</li>
- </ul>
-
<h1>Fields Reference</h1>
<p>
@@ -2273,6 +2286,55 @@ actions=clone(load:0->NXM_OF_IN_PORT[],output:123)
<field id="MFF_DP_HASH" title="Datapath Hash" internal="yes"/>
<field id="MFF_RECIRC_ID" title="Datapath Recirculation ID" internal="yes"/>
+
+ <field id="MFF_PACKET_TYPE" title="Packet Type">
+ <p>
+ Holds the current type of the packet in the format specified in
+ OpenFlow 1.5. The 32-bit value consists of the name space <code>NS</code>
+ in the upper 16 bits and a type <code>NS_TYPE</code> (within that name
+ space) in the lower 16 bits. For ease of use the packet type field is
+ specified and displayed in the <code>(NS,NS_TYPE)</code> syntax.
+ </p>
+
+ <p>
+ Open vSwitch currently supports the following classes of packet types
+ for matching:
+ <dl>
+ <dt><code>(0,0)</code></dt>
+ <dd>(NS=ONF and NS_TYPE=Ethernet)</dd>
+ <dt><code>(1,xxxx)</code></dt>
+ <dd>(NS=Ethertype and xxxx=Ethertype value)</dd>
+ </dl>
+ </p>
+
+ <p>
+ Even though Open vSwitch can forward packets with any NS_TYPE value
+ for NS=Ethertype, it can only match on and process data fields for
+ the following list of supported packet types:
+ <dl>
+ <dt><code>(1,0x800)</code></dt> <dd>IPv4</dd>
+ <dt><code>(1,0x806)</code></dt> <dd>ARP</dd>
+ <dt><code>(1,0x86dd)</code></dt> <dd>IPv6</dd>
+ <dt><code>(1,0x8847)</code></dt> <dd>MPLS</dd>
+ <dt><code>(1,0x8848)</code></dt> <dd>MPLS multicast</dd>
+ <dt><code>(1,0x8035)</code></dt> <dd>RARP</dd>
+ <dt><code>(1,0x894f)</code></dt> <dd>NSH</dd>
+ </dl>
+ </p>
+
+ <p>
+ The packet type field is mandatory if the OVS bridge is configured
+ to be packet type-aware. In that case the packet type becomes a
+ pre-requisite for all matches. If it is omitted from the match,
+ it defaults to <code>(0,0)</code> (Ethernet) for backward
+ compatibility.
+ </p>
+
+ <p>
+ Open vSwitch allows any table to match this field.
+ </p>
+ </field>
+
</group>
<group title="Connection Tracking">
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 68e58d3..af19fb2 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -873,8 +873,9 @@ static void
nxm_put_ip(struct ofpbuf *b, const struct match *match, enum ofp_version oxm)
{
const struct flow *flow = &match->flow;
+ ovs_be16 dl_type = get_dl_type(flow);
- if (flow->dl_type == htons(ETH_TYPE_IP)) {
+ if (dl_type == htons(ETH_TYPE_IP)) {
nxm_put_32m(b, MFF_IPV4_SRC, oxm,
flow->nw_src, match->wc.masks.nw_src);
nxm_put_32m(b, MFF_IPV4_DST, oxm,
@@ -983,11 +984,18 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
{
const struct flow *flow = &match->flow;
const size_t start_len = b->size;
+ ovs_be16 dl_type = get_dl_type(flow);
int match_len;
int i;
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
+ /* OpenFlow Packet Type. Must be first. */
+ if (match->wc.masks.packet_type) {
+ nxm_put_32m(b, MFF_PACKET_TYPE, oxm, flow->packet_type,
+ match->wc.masks.packet_type);
+ }
+
/* Metadata. */
if (match->wc.masks.dp_hash) {
nxm_put_32m(b, MFF_DP_HASH, oxm,
@@ -1049,7 +1057,7 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
}
/* MPLS. */
- if (eth_type_mpls(flow->dl_type)) {
+ if (eth_type_mpls(dl_type)) {
if (match->wc.masks.mpls_lse[0] & htonl(MPLS_TC_MASK)) {
nxm_put_8(b, MFF_MPLS_TC, oxm,
mpls_lse_to_tc(flow->mpls_lse[0]));
@@ -1069,8 +1077,8 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
/* L3. */
if (is_ip_any(flow)) {
nxm_put_ip(b, match, oxm);
- } else if (flow->dl_type == htons(ETH_TYPE_ARP) ||
- flow->dl_type == htons(ETH_TYPE_RARP)) {
+ } else if (dl_type == htons(ETH_TYPE_ARP) ||
+ dl_type == htons(ETH_TYPE_RARP)) {
/* ARP. */
if (match->wc.masks.nw_proto) {
nxm_put_16(b, MFF_ARP_OP, oxm,
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 4d07d1c..5ddb08f 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -4350,6 +4350,50 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
return s - start;
}
+ /* Packet_type open-coded. */
+ if (strncmp(s, "packet_type(", strlen("packet_type(")) == 0) {
+ const char *start = s;
+ ovs_be32 skey = 0;
+ ovs_be32 smask = 0;
+ int len;
+ uint16_t ns = 0;
+ uint16_t ns_type = 0;
+
+ s += strlen("packet_type(");
+ if (ovs_scan(s, "ns=%"SCNu16",id=%n", &ns, &len)){
+ if (len == 0) {
+ return -EINVAL;
+ }
+ s += len;
+ if (strncmp(s, "*", 1) == 0) {
+ s++;
+ } else if (ovs_scan(s, "0x%"SCNx16"%n", &ns_type, &len)) {
+ s += len;
+ skey = PACKET_TYPE_BE(ns, ns_type);
+ if ( *s == '/' ) {
+ uint16_t ns_type_mask = 0;
+ if (ovs_scan(s, "/0x%"SCNx16"%n", &ns_type_mask, &len)) {
+ s += len;
+ smask = PACKET_TYPE_BE(ns, ns_type_mask);
+ }
+ }
+ }
+
+ if (*s++ != ')') {
+ return -EINVAL;
+ }
+
+ nl_msg_put_unspec(key, OVS_KEY_ATTR_PACKET_TYPE, &skey,
+ sizeof(skey));
+ if (mask) {
+ nl_msg_put_unspec(mask, OVS_KEY_ATTR_PACKET_TYPE, &smask,
+ sizeof(smask));
+ }
+ }
+
+ return s - start;
+ }
+
return -EINVAL;
}
@@ -4500,9 +4544,7 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms *parms,
nl_msg_put_odp_port(buf, OVS_KEY_ATTR_IN_PORT, data->in_port.odp_port);
}
- if (export_mask || flow->packet_type != htonl(PT_ETH)) {
- nl_msg_put_be32(buf, OVS_KEY_ATTR_PACKET_TYPE, data->packet_type);
- }
+ nl_msg_put_be32(buf, OVS_KEY_ATTR_PACKET_TYPE, data->packet_type);
if (OVS_UNLIKELY(parms->probe)) {
max_vlans = FLOW_MAX_VLAN_HEADERS;
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index c8cac5b..c443784 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -513,6 +513,12 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,
return error;
}
}
+ /* Copy ethertype to flow->dl_type for matches on packet_type
+ * (OFPHTN_ETHERTYPE, ethertype). */
+ if (fm->match.wc.masks.packet_type == OVS_BE32_MAX &&
+ pt_ns(fm->match.flow.packet_type) == OFPHTN_ETHERTYPE) {
+ fm->match.flow.dl_type = pt_ns_type_be(fm->match.flow.packet_type);
+ }
/* Check for usable protocol interdependencies between match fields. */
if (fm->match.flow.dl_type == htons(ETH_TYPE_IPV6)) {
const struct flow_wildcards *wc = &fm->match.wc;
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index bdf89b6..758f905 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -7431,21 +7431,37 @@ ofputil_normalize_match__(struct match *match, bool may_log)
MAY_IPV6 = 1 << 6, /* ipv6_src, ipv6_dst, ipv6_label */
MAY_ND_TARGET = 1 << 7, /* nd_target */
MAY_MPLS = 1 << 8, /* mpls label and tc */
+ MAY_ETHER = 1 << 9, /* dl_src, dl_dst */
} may_match;
- struct flow_wildcards wc;
+ struct flow_wildcards wc = match->wc;
+ ovs_be16 dl_type;
/* Figure out what fields may be matched. */
- if (match->flow.dl_type == htons(ETH_TYPE_IP)) {
- may_match = MAY_NW_PROTO | MAY_IPVx | MAY_NW_ADDR;
+ /* Check the packet_type first and extract dl_type. */
+ if (wc.masks.packet_type == 0 ||
+ (wc.masks.packet_type == OVS_BE32_MAX &&
+ match->flow.packet_type == htonl(PT_ETH))) {
+ may_match = MAY_ETHER;
+ dl_type = match->flow.dl_type;
+ } else if (wc.masks.packet_type == OVS_BE32_MAX &&
+ pt_ns(match->flow.packet_type) == OFPHTN_ETHERTYPE) {
+ may_match = 0;
+ dl_type = pt_ns_type_be(match->flow.packet_type);
+ } else {
+ may_match = 0;
+ dl_type = 0;
+ }
+ if (dl_type == htons(ETH_TYPE_IP)) {
+ may_match |= MAY_NW_PROTO | MAY_IPVx | MAY_NW_ADDR;
if (match->flow.nw_proto == IPPROTO_TCP ||
match->flow.nw_proto == IPPROTO_UDP ||
match->flow.nw_proto == IPPROTO_SCTP ||
match->flow.nw_proto == IPPROTO_ICMP) {
may_match |= MAY_TP_ADDR;
}
- } else if (match->flow.dl_type == htons(ETH_TYPE_IPV6)) {
- may_match = MAY_NW_PROTO | MAY_IPVx | MAY_IPV6;
+ } else if (dl_type == htons(ETH_TYPE_IPV6)) {
+ may_match |= MAY_NW_PROTO | MAY_IPVx | MAY_IPV6;
if (match->flow.nw_proto == IPPROTO_TCP ||
match->flow.nw_proto == IPPROTO_UDP ||
match->flow.nw_proto == IPPROTO_SCTP) {
@@ -7458,17 +7474,17 @@ ofputil_normalize_match__(struct match *match, bool may_log)
may_match |= MAY_ND_TARGET | MAY_ARP_THA;
}
}
- } else if (match->flow.dl_type == htons(ETH_TYPE_ARP) ||
- match->flow.dl_type == htons(ETH_TYPE_RARP)) {
- may_match = MAY_NW_PROTO | MAY_NW_ADDR | MAY_ARP_SHA | MAY_ARP_THA;
- } else if (eth_type_mpls(match->flow.dl_type)) {
- may_match = MAY_MPLS;
- } else {
- may_match = 0;
+ } else if (dl_type == htons(ETH_TYPE_ARP) ||
+ dl_type == htons(ETH_TYPE_RARP)) {
+ may_match |= MAY_NW_PROTO | MAY_NW_ADDR | MAY_ARP_SHA | MAY_ARP_THA;
+ } else if (eth_type_mpls(dl_type)) {
+ may_match |= MAY_MPLS;
}
/* Clear the fields that may not be matched. */
- wc = match->wc;
+ if (!(may_match & MAY_ETHER)) {
+ wc.masks.dl_src = wc.masks.dl_dst = eth_addr_zero;
+ }
if (!(may_match & MAY_NW_ADDR)) {
wc.masks.nw_src = wc.masks.nw_dst = htonl(0);
}
diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at
index 586a5b1..774619d 100644
--- a/tests/dpif-netdev.at
+++ b/tests/dpif-netdev.at
@@ -99,7 +99,7 @@ m4_define([DPIF_NETDEV_MISS_FLOW_INSTALL],
sleep 1
AT_CHECK([grep -A 1 'miss upcall' ovs-vswitchd.log | tail -n 1], [0], [dnl
-skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)
+skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0x0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)
])
AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
recirc_id(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(frag=no), actions: <del>
@@ -112,7 +112,7 @@ recirc_id(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_typ
sleep 1
AT_CHECK([grep -A 1 'miss upcall' ovs-vswitchd.log | tail -n 1], [0], [dnl
-skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)
+skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0x0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)
])
AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl
recirc_id(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(frag=no), actions: <del>
@@ -140,10 +140,10 @@ m4_define([DPIF_NETDEV_MISS_FLOW_DUMP],
sleep 1
AT_CHECK([grep -A 1 'miss upcall' ovs-vswitchd.log | tail -n 1], [0], [dnl
-skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)
+skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0x0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)
])
AT_CHECK([filter_flow_dump < ovs-vswitchd.log | strip_xout], [0], [dnl
-skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions: <del>
+skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions: <del>
])
# Now, the same again without megaflows.
@@ -155,11 +155,11 @@ skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label
sleep 1
AT_CHECK([grep -A 1 'miss upcall' ovs-vswitchd.log | tail -n 1], [0], [dnl
-skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)
+skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0x0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)
])
AT_CHECK([filter_flow_dump < ovs-vswitchd.log | strip_xout], [0], [dnl
-skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:never, actions: <del>
-skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions: <del>
+skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:never, actions: <del>
+skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions: <del>
])
OVS_VSWITCHD_STOP
diff --git a/tests/odp.at b/tests/odp.at
index e408c9f..72167ee 100644
--- a/tests/odp.at
+++ b/tests/odp.at
@@ -94,6 +94,7 @@ dnl Some fields are always printed for this test, because wildcards aren't
dnl specified. We can skip these.
sed -i 's/\(skb_mark(0)\),\(ct\)/\1,ct_state(0),ct_zone(0),\2/' odp-out.txt
sed -i 's/\(skb_mark([[^)]]*)\),\(recirc\)/\1,ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),\2/' odp-out.txt
+sed -i 's/\(in_port(1)\),\(eth\)/\1,packet_type(ns=0,id=0x0),\2/' odp-out.txt
AT_CHECK_UNQUOTED([ovstest test-odp parse-keys < odp-in.txt], [0], [`cat odp-out.txt`
])
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 1f6cd84..d4cee2f 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -7211,12 +7211,12 @@ recirc_id(0),in_port(3),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used
])
AT_CHECK([ovs-appctl dpif/dump-flows -m br0 | strip_ufid | strip_used | sort], [0], [dnl
-skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p1),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop
-skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p2),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=0/0,code=0/0), packets:0, bytes:0, used:never, actions:drop
+skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p1),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop
+skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p2),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=0/0,code=0/0), packets:0, bytes:0, used:never, actions:drop
])
AT_CHECK([ovs-appctl dpif/dump-flows -m br1 | strip_ufid | strip_used | sort], [0], [dnl
-skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p3),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop
+skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p3),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop
])
OVS_VSWITCHD_STOP
@@ -7376,10 +7376,10 @@ recirc_id(0),in_port(101),eth_type(0x0800),ipv4(frag=no), actions:100,2,3
])
AT_CHECK([grep -e 'in_port(100).*packets:9' ovs-vswitchd.log | strip_ufid | filter_flow_dump], [0], [dnl
-skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(100),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:9, bytes:378, used:0.0s, actions:101,3,2
+skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(100),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:9, bytes:378, used:0.0s, actions:101,3,2
])
AT_CHECK([grep -e 'in_port(101).*packets:4' ovs-vswitchd.log | strip_ufid | filter_flow_dump], [0], [dnl
-skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(101),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:4, bytes:168, used:0.0s, actions:100,2,3
+skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(101),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:4, bytes:168, used:0.0s, actions:100,2,3
])
AT_CHECK([ovs-ofctl dump-ports br0 pbr0], [0], [dnl
@@ -7990,8 +7990,8 @@ skb_priority(0),skb_mark(0),ct_state(-new-est-rel-rpl-inv-trk-snat-dnat),ct_zone
skb_priority(0),skb_mark(0),ct_state(-new-est-rel-rpl-inv-trk-snat-dnat),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), actions:drop
])
AT_CHECK([strip_ufid < ovs-vswitchd.log | filter_flow_dump | grep 'packets:3'], [0], [dnl
-skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:126, used:0.0s, actions:2
-skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:126, used:0.0s, actions:drop
+skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:126, used:0.0s, actions:2
+skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:126, used:0.0s, actions:drop
])
OVS_VSWITCHD_STOP
AT_CLEANUP])
@@ -8603,7 +8603,7 @@ recirc_id(0),in_port(1),eth_type(0x1234), packets:5, bytes:70, used:0.0s, action
])
AT_CHECK([grep 'modify' ovs-vswitchd.log | strip_ufid ], [0], [dnl
-dpif|DBG|dummy at ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234), actions:push_vlan(vid=4,pcp=0),100
+dpif|DBG|dummy at ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234), actions:push_vlan(vid=4,pcp=0),100
])
OVS_VSWITCHD_STOP
AT_CLEANUP
@@ -8683,8 +8683,8 @@ recirc_id(0),in_port(1),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0
# are wildcarded.
AT_CHECK([grep '\(modify\)\|\(flow_add\)' ovs-vswitchd.log | strip_ufid ], [0], [dnl
dpif_netdev|DBG|flow_add: recirc_id(0),in_port(1),eth_type(0x1234), actions:100
-dpif|DBG|dummy at ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234)
-dpif|DBG|dummy at ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234), actions:100
+dpif|DBG|dummy at ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234)
+dpif|DBG|dummy at ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234), actions:100
dpif_netdev|DBG|flow_add: recirc_id(0),in_port(1),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0x1234)), actions:drop
])
OVS_VSWITCHD_STOP
diff --git a/tests/ofproto.at b/tests/ofproto.at
index 5431f4e..246eb12 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -2390,6 +2390,7 @@ metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4
matching:
dp_hash: arbitrary mask
recirc_id: exact match or wildcard
+ packet_type: exact match or wildcard
conj_id: exact match or wildcard
tun_id: arbitrary mask
tun_src: arbitrary mask
diff --git a/tests/pmd.at b/tests/pmd.at
index 2816d45..9ba2576 100644
--- a/tests/pmd.at
+++ b/tests/pmd.at
@@ -190,7 +190,7 @@ for i in `seq 0 19`;
ovs-appctl time/warp 100
AT_CHECK([grep -A 1 'miss upcall' ovs-vswitchd.log | tail -n 1], [0], [dnl
-skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:77,dst=50:54:00:00:01:78),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)
+skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0x0),eth(src=50:54:00:00:00:77,dst=50:54:00:00:01:78),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)
])
AT_CHECK([cat ovs-vswitchd.log | filter_flow_install | strip_xout], [0], [dnl
recirc_id(0),in_port(1),eth(src=50:54:00:00:00:77,dst=50:54:00:00:01:78),eth_type(0x0800),ipv4(frag=no), actions: <del>
diff --git a/tests/tunnel-push-pop-ipv6.at b/tests/tunnel-push-pop-ipv6.at
index cbeb578..9e37845 100644
--- a/tests/tunnel-push-pop-ipv6.at
+++ b/tests/tunnel-push-pop-ipv6.at
@@ -164,7 +164,7 @@ AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port 5'], [0], [dnl
port 5: rx pkts=1, bytes=98, drop=?, errs=?, frame=?, over=?, crc=?
])
AT_CHECK([ovs-appctl dpif/dump-flows int-br | grep 'in_port(6081)'], [0], [dnl
-tunnel(tun_id=0x7b,ipv6_src=2001:cafe::92,ipv6_dst=2001:cafe::88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{class=0xffff,type=0,len=4}),flags(-df-csum+key)),recirc_id(0),in_port(6081),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(controller))
+tunnel(tun_id=0x7b,ipv6_src=2001:cafe::92,ipv6_dst=2001:cafe::88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{class=0xffff,type=0,len=4}),flags(-df-csum+key)),recirc_id(0),in_port(6081),packet_type(ns=0,id=0x0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(controller))
])
OVS_VSWITCHD_STOP
diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at
index 961ac34..bc48d31 100644
--- a/tests/tunnel-push-pop.at
+++ b/tests/tunnel-push-pop.at
@@ -215,7 +215,7 @@ AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port 5'], [0], [dnl
port 5: rx pkts=1, bytes=98, drop=?, errs=?, frame=?, over=?, crc=?
])
AT_CHECK([ovs-appctl dpif/dump-flows int-br | grep 'in_port(6081)'], [0], [dnl
-tunnel(tun_id=0x7b,src=1.1.2.92,dst=1.1.2.88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{class=0xffff,type=0,len=4}),flags(-df-csum+key)),recirc_id(0),in_port(6081),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(controller))
+tunnel(tun_id=0x7b,src=1.1.2.92,dst=1.1.2.88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{class=0xffff,type=0,len=4}),flags(-df-csum+key)),recirc_id(0),in_port(6081),packet_type(ns=0,id=0x0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(controller))
])
OVS_VSWITCHD_STOP
--
1.9.1
More information about the dev
mailing list