@@ -35,6 +35,7 @@ FORMATTING = {"decimal": ("MFS_DECIMAL", 1, 8),
"TCP flags": ("MFS_TCP_FLAGS", 2, 2)}
PREREQS = {"none": "MFP_NONE",
+ "Ethernet": "MFP_ETHERNET",
"ARP": "MFP_ARP",
"VLAN VID": "MFP_VLAN_VID",
"IPv4": "MFP_IPV4",
@@ -23,7 +23,7 @@
/* This sequence number should be incremented whenever anything involving flows
* or the wildcarding of flows changes. This will cause build assertion
* failures in places which likely need to be updated. */
-#define FLOW_WC_SEQ 35
+#define FLOW_WC_SEQ 36
/* Number of Open vSwitch extension 32-bit registers. */
#define FLOW_N_REGS 8
@@ -52,6 +52,11 @@ BUILD_ASSERT_DECL(FLOW_TNL_F_OAM == NX_TUN_FLAG_OAM);
const char *flow_tun_flag_to_string(uint32_t flags);
+enum base_layer {
+ LAYER_2 = 0,
+ LAYER_3 = 1
+};
+
/* Maximum number of supported MPLS labels. */
#define FLOW_MAX_MPLS_LABELS 3
@@ -71,6 +76,10 @@ const char *flow_tun_flag_to_string(uint32_t flags);
* lower layer fields are first used to determine if the later fields need to
* be looked at. This enables better wildcarding for datapath flows.
*
+ * The starting layer is specified by 'base_layer'. When 'base_layer' is
+ * LAYER_3, dl_src, dl_tci, and vlan_tci are not used for matching. The
+ * dl_type field is still used to specify the layer 3 protocol.
+ *
* NOTE: Order of the fields is significant, any change in the order must be
* reflected in miniflow_extract()!
*/
@@ -92,6 +101,8 @@ struct flow {
ovs_u128 ct_label; /* Connection label. */
uint32_t conj_id; /* Conjunction ID. */
ofp_port_t actset_output; /* Output port in action set. */
+ uint8_t base_layer; /* Fields start at this layer */
+ uint8_t pad2[7]; /* Pad to 64 bits. */
/* L2, Order the same as in the Ethernet header! (64-bit aligned) */
struct eth_addr dl_dst; /* Ethernet destination address. */
@@ -129,8 +140,8 @@ 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
- && FLOW_WC_SEQ == 35);
+ == sizeof(struct flow_tnl) + 224
+ && FLOW_WC_SEQ == 36);
/* Incremental points at which flow classification may be performed in
* segments.
@@ -96,6 +96,7 @@ void match_set_ct_mark(struct match *, uint32_t ct_mark);
void match_set_ct_mark_masked(struct match *, uint32_t ct_mark, uint32_t mask);
void match_set_ct_label(struct match *, ovs_u128 ct_label);
void match_set_ct_label_masked(struct match *, ovs_u128 ct_label, ovs_u128 mask);
+void match_set_base_layer(struct match *, uint8_t base_layer);
void match_set_skb_priority(struct match *, uint32_t skb_priority);
void match_set_dl_type(struct match *, ovs_be16);
void match_set_dl_src(struct match *, const struct eth_addr );
@@ -1020,7 +1020,7 @@ enum OVS_PACKED_ENUM mf_field_id {
* Type: be16.
* Maskable: bitwise.
* Formatting: hexadecimal.
- * Prerequisites: none.
+ * Prerequisites: Ethernet.
* Access: read/write.
* NXM: NXM_OF_VLAN_TCI(4) since v1.1.
* OXM: none.
@@ -1036,7 +1036,7 @@ enum OVS_PACKED_ENUM mf_field_id {
* Type: be16 (low 12 bits).
* Maskable: no.
* Formatting: decimal.
- * Prerequisites: none.
+ * Prerequisites: Ethernet.
* Access: read/write.
* NXM: none.
* OXM: none.
@@ -1054,7 +1054,7 @@ enum OVS_PACKED_ENUM mf_field_id {
* Type: be16 (low 12 bits).
* Maskable: bitwise.
* Formatting: decimal.
- * Prerequisites: none.
+ * Prerequisites: Ethernet.
* Access: read/write.
* NXM: none.
* OXM: OXM_OF_VLAN_VID(6) since OF1.2 and v1.7.
@@ -1070,7 +1070,7 @@ enum OVS_PACKED_ENUM mf_field_id {
* Type: u8 (low 3 bits).
* Maskable: no.
* Formatting: decimal.
- * Prerequisites: none.
+ * Prerequisites: Ethernet.
* Access: read/write.
* NXM: none.
* OXM: none.
@@ -1793,6 +1793,7 @@ enum OVS_PACKED_ENUM mf_prereqs {
MFP_NONE,
/* L2 requirements. */
+ MFP_ETHERNET,
MFP_ARP,
MFP_VLAN_VID,
MFP_IPV4,
@@ -21,6 +21,9 @@
#include <stdint.h>
#include <stdio.h>
+#include <stdbool.h>
+
+#include <openvswitch/types.h>
struct ds;
struct ofp10_match;
@@ -29,6 +32,7 @@ struct ofp_header;
struct ofputil_flow_stats;
struct ofputil_table_features;
struct ofputil_table_stats;
+struct dp_packet;
#ifdef __cplusplus
extern "C" {
@@ -41,7 +45,9 @@ void ofp10_match_print(struct ds *, const struct ofp10_match *, int verbosity);
char *ofp_to_string(const void *, size_t, int verbosity);
char *ofp10_match_to_string(const struct ofp10_match *, int verbosity);
-char *ofp_packet_to_string(const void *data, size_t len);
+char *ofp_packet_to_string(const void *data, size_t len,
+ ovs_be16 packet_ethertype);
+char *ofp_dp_packet_to_string(const struct dp_packet *);
void ofp_print_flow_stats(struct ds *, struct ofputil_flow_stats *);
void ofp_print_version(const struct ofp_header *, struct ds *);
@@ -256,12 +256,20 @@ dp_packet_equal(const struct dp_packet *a, const struct dp_packet *b)
!memcmp(dp_packet_data(a), dp_packet_data(b), dp_packet_size(a));
}
-/* Get the start of the Ethernet frame. 'l3_ofs' marks the end of the l2
- * headers, so return NULL if it is not set. */
+static inline bool
+dp_packet_is_l3(const struct dp_packet *b)
+{
+ return b->l3_ofs == 0 || b->l2_5_ofs == 0;
+}
+
+/* Get the start of the Ethernet frame. Return NULL if 'b' is an l3 packet
+ * or if 'l3_ofs', which marks the end of the l2 headers, is not set. */
static inline void *
dp_packet_l2(const struct dp_packet *b)
{
- return (b->l3_ofs != UINT16_MAX) ? dp_packet_data(b) : NULL;
+ return (b->l3_ofs != UINT16_MAX && !dp_packet_is_l3(b))
+ ? dp_packet_data(b)
+ : NULL;
}
/* Resets all layer offsets. 'l3' offset must be set before 'l2' can be
@@ -3530,9 +3530,7 @@ dp_netdev_upcall(struct dp_netdev_pmd_thread *pmd, struct dp_packet *packet_,
ofpbuf_init(&key, 0);
odp_flow_key_from_flow(&odp_parms, &key);
- packet_str = ofp_packet_to_string(dp_packet_data(packet_),
- dp_packet_size(packet_));
-
+ packet_str = ofp_dp_packet_to_string(packet_);
odp_flow_key_format(key.data, key.size, &ds);
VLOG_DBG("%s: %s upcall:\n%s\n%s", dp->name,
@@ -2013,6 +2013,10 @@ parse_odp_packet(const struct dpif_netlink *dpif, struct ofpbuf *buf,
(char *)dp_packet_data(&upcall->packet) + sizeof(struct nlattr));
dp_packet_set_size(&upcall->packet, nl_attr_get_size(a[OVS_PACKET_ATTR_PACKET]));
+ if (!nl_attr_find__(upcall->key, upcall->key_len, OVS_KEY_ATTR_ETHERNET)) {
+ dp_packet_set_l3(&upcall->packet, dp_packet_data(&upcall->packet));
+ }
+
*dp_ifindex = ovs_header->dp_ifindex;
return 0;
@@ -1413,9 +1413,7 @@ dpif_print_packet(struct dpif *dpif, struct dpif_upcall *upcall)
struct ds flow;
char *packet;
- packet = ofp_packet_to_string(dp_packet_data(&upcall->packet),
- dp_packet_size(&upcall->packet));
-
+ packet = ofp_dp_packet_to_string(&upcall->packet);
ds_init(&flow);
odp_flow_key_format(upcall->key, upcall->key_len, &flow);
@@ -1708,8 +1706,7 @@ log_execute_message(struct dpif *dpif, const struct dpif_execute *execute,
struct ds ds = DS_EMPTY_INITIALIZER;
char *packet;
- packet = ofp_packet_to_string(dp_packet_data(execute->packet),
- dp_packet_size(execute->packet));
+ packet = ofp_dp_packet_to_string(execute->packet);
ds_put_format(&ds, "%s: %sexecute ",
dpif_name(dpif),
(subexecute ? "sub-"
@@ -124,7 +124,7 @@ struct mf_ctx {
* away. Some GCC versions gave warnings on ALWAYS_INLINE, so these are
* defined as macros. */
-#if (FLOW_WC_SEQ != 35)
+#if (FLOW_WC_SEQ != 36)
#define MINIFLOW_ASSERT(X) ovs_assert(X)
BUILD_MESSAGE("FLOW_WC_SEQ changed: miniflow_extract() will have runtime "
"assertions enabled. Consider updating FLOW_WC_SEQ after "
@@ -439,18 +439,18 @@ invalid:
arp_buf[1] = eth_addr_zero;
}
-/* Initializes 'flow' members from 'packet' and 'md'
+/* Initializes 'flow' members from 'packet' and 'md'.
+ * Expects packet->l3_ofs to be set to 0 for layer 3 packets.
*
- * Initializes 'packet' header l2 pointer to the start of the Ethernet
- * header, and the layer offsets as follows:
+ * Initializes the layer offsets as follows:
*
* - packet->l2_5_ofs to the start of the MPLS shim header, or UINT16_MAX
- * when there is no MPLS shim header.
+ * when there is no MPLS shim header, or Ethernet header
*
- * - packet->l3_ofs to just past the Ethernet header, or just past the
- * vlan_header if one is present, to the first byte of the payload of the
- * Ethernet frame. UINT16_MAX if the frame is too short to contain an
- * Ethernet header.
+ * - packet->l3_ofs (if not 0) to just past the Ethernet header, or just
+ * past the vlan_header if one is present, to the first byte of the
+ * payload of the Ethernet frame. UINT16_MAX if the frame is too short to
+ * contain an Ethernet header.
*
* - packet->l4_ofs to just past the IPv4 header, if one is present and
* has at least the content used for the fields of interest for the flow,
@@ -481,9 +481,10 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
uint64_t *values = miniflow_values(dst);
struct mf_ctx mf = { FLOWMAP_EMPTY_INITIALIZER, values,
values + FLOW_U64S };
- const char *l2;
+ const char *frame;
ovs_be16 dl_type;
uint8_t nw_frag, nw_tos, nw_ttl, nw_proto;
+ bool is_l3 = dp_packet_is_l3(packet);
/* Metadata. */
if (flow_tnl_dst_is_set(&md->tunnel)) {
@@ -531,23 +532,39 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
}
/* Initialize packet's layer pointer and offsets. */
- l2 = data;
+ frame = data;
dp_packet_reset_offsets(packet);
- /* Must have full Ethernet header to proceed. */
- if (OVS_UNLIKELY(size < sizeof(struct eth_header))) {
- goto out;
+ if (!is_l3) {
+ /* No need to store a zero value for base_layer in the miniflow
+ * which would cost an extra word of storage. */
+ BUILD_ASSERT(LAYER_2 == 0);
+
+ /* Must have full Ethernet header to proceed. */
+ if (OVS_UNLIKELY(size < sizeof(struct eth_header))) {
+ goto out;
+ } else {
+ ovs_be16 vlan_tci;
+
+ /* Link layer. */
+ ASSERT_SEQUENTIAL(dl_dst, dl_src);
+ miniflow_push_macs(mf, dl_dst, data);
+ /* dl_type, vlan_tci. */
+ vlan_tci = parse_vlan(&data, &size);
+ dl_type = parse_ethertype(&data, &size);
+ miniflow_push_be16(mf, dl_type, dl_type);
+ miniflow_push_be16(mf, vlan_tci, vlan_tci);
+ }
} else {
- ovs_be16 vlan_tci;
+ packet->l3_ofs = 0;
+ miniflow_pad_from_64(mf, base_layer);
+ miniflow_push_uint8(mf, base_layer, LAYER_3);
+ miniflow_pad_to_64(mf, base_layer);
- /* Link layer. */
- ASSERT_SEQUENTIAL(dl_dst, dl_src);
- miniflow_push_macs(mf, dl_dst, data);
- /* dl_type, vlan_tci. */
- vlan_tci = parse_vlan(&data, &size);
- dl_type = parse_ethertype(&data, &size);
+ dl_type = packet->md.packet_ethertype;
+ miniflow_pad_from_64(mf, dl_type);
miniflow_push_be16(mf, dl_type, dl_type);
- miniflow_push_be16(mf, vlan_tci, vlan_tci);
+ miniflow_push_be16(mf, vlan_tci, 0);
}
/* Parse mpls. */
@@ -555,13 +572,13 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
int count;
const void *mpls = data;
- packet->l2_5_ofs = (char *)data - l2;
+ packet->l2_5_ofs = (char *)data - frame;
count = parse_mpls(&data, &size);
miniflow_push_words_32(mf, mpls_lse, mpls, count);
}
/* Network layer. */
- packet->l3_ofs = (char *)data - l2;
+ packet->l3_ofs = (char *)data - frame;
nw_frag = 0;
if (OVS_LIKELY(dl_type == htons(ETH_TYPE_IP))) {
@@ -738,7 +755,7 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
goto out;
}
- packet->l4_ofs = (char *)data - l2;
+ packet->l4_ofs = (char *)data - frame;
miniflow_push_be32(mf, nw_frag,
BYTES_TO_BE32(nw_frag, nw_tos, nw_ttl, nw_proto));
@@ -842,7 +859,7 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata)
{
int i;
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 36);
match_init_catchall(flow_metadata);
if (flow->tunnel.tun_id != htonll(0)) {
@@ -898,6 +915,10 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata)
if (!ovs_u128_is_zero(flow->ct_label)) {
match_set_ct_label(flow_metadata, flow->ct_label);
}
+
+ if (flow->base_layer != LAYER_2) {
+ match_set_base_layer(flow_metadata, flow->base_layer);
+ }
}
const char *ct_state_to_string(uint32_t state)
@@ -1248,7 +1269,7 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
memset(&wc->masks, 0x0, sizeof wc->masks);
/* Update this function whenever struct flow changes. */
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 36);
if (flow_tnl_dst_is_set(&flow->tunnel)) {
if (flow->tunnel.flags & FLOW_TNL_F_KEY) {
@@ -1295,10 +1316,13 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
/* actset_output wildcarded. */
- WC_MASK_FIELD(wc, dl_dst);
- WC_MASK_FIELD(wc, dl_src);
+ if (flow->base_layer == LAYER_2) {
+ WC_MASK_FIELD(wc, dl_dst);
+ WC_MASK_FIELD(wc, dl_src);
+ WC_MASK_FIELD(wc, vlan_tci);
+ }
+
WC_MASK_FIELD(wc, dl_type);
- WC_MASK_FIELD(wc, vlan_tci);
if (flow->dl_type == htons(ETH_TYPE_IP)) {
WC_MASK_FIELD(wc, nw_src);
@@ -1365,7 +1389,7 @@ void
flow_wc_map(const struct flow *flow, struct flowmap *map)
{
/* Update this function whenever struct flow changes. */
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 36);
flowmap_init(map);
@@ -1388,15 +1412,18 @@ flow_wc_map(const struct flow *flow, struct flowmap *map)
FLOWMAP_SET(map, recirc_id);
FLOWMAP_SET(map, dp_hash);
FLOWMAP_SET(map, in_port);
- FLOWMAP_SET(map, dl_dst);
- FLOWMAP_SET(map, dl_src);
FLOWMAP_SET(map, dl_type);
- FLOWMAP_SET(map, vlan_tci);
FLOWMAP_SET(map, ct_state);
FLOWMAP_SET(map, ct_zone);
FLOWMAP_SET(map, ct_mark);
FLOWMAP_SET(map, ct_label);
+ if (flow->base_layer == LAYER_2) {
+ FLOWMAP_SET(map, dl_dst);
+ FLOWMAP_SET(map, dl_src);
+ FLOWMAP_SET(map, vlan_tci);
+ }
+
/* Ethertype-dependent fields. */
if (OVS_LIKELY(flow->dl_type == htons(ETH_TYPE_IP))) {
FLOWMAP_SET(map, nw_src);
@@ -1449,12 +1476,13 @@ void
flow_wildcards_clear_non_packet_fields(struct flow_wildcards *wc)
{
/* Update this function whenever struct flow changes. */
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 36);
memset(&wc->masks.metadata, 0, sizeof wc->masks.metadata);
memset(&wc->masks.regs, 0, sizeof wc->masks.regs);
wc->masks.actset_output = 0;
wc->masks.conj_id = 0;
+ wc->masks.base_layer = 0;
}
/* Returns true if 'wc' matches every packet, false if 'wc' fixes any bits or
@@ -1584,7 +1612,7 @@ flow_wildcards_set_xreg_mask(struct flow_wildcards *wc, int idx, uint64_t mask)
uint32_t
miniflow_hash_5tuple(const struct miniflow *flow, uint32_t basis)
{
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 36);
uint32_t hash = basis;
if (flow) {
@@ -1631,7 +1659,7 @@ ASSERT_SEQUENTIAL(ipv6_src, ipv6_dst);
uint32_t
flow_hash_5tuple(const struct flow *flow, uint32_t basis)
{
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 36);
uint32_t hash = basis;
if (flow) {
@@ -2098,7 +2126,7 @@ flow_push_mpls(struct flow *flow, int n, ovs_be16 mpls_eth_type,
flow->mpls_lse[0] = set_mpls_lse_values(ttl, tc, 1, htonl(label));
/* Clear all L3 and L4 fields and dp_hash. */
- BUILD_ASSERT(FLOW_WC_SEQ == 35);
+ BUILD_ASSERT(FLOW_WC_SEQ == 36);
memset((char *) flow + FLOW_SEGMENT_2_ENDS_AT, 0,
sizeof(struct flow) - FLOW_SEGMENT_2_ENDS_AT);
flow->dp_hash = 0;
@@ -826,6 +826,8 @@ pkt_metadata_from_flow(struct pkt_metadata *md, const struct flow *flow)
md->ct_zone = flow->ct_zone;
md->ct_mark = flow->ct_mark;
md->ct_label = flow->ct_label;
+ md->base_layer = flow->base_layer;
+ md->packet_ethertype = flow->dl_type;
}
static inline bool is_ip_any(const struct flow *flow)
@@ -369,6 +369,13 @@ match_set_ct_label_masked(struct match *match, ovs_u128 value, ovs_u128 mask)
}
void
+match_set_base_layer(struct match *match, uint8_t base_layer)
+{
+ match->flow.base_layer = base_layer;
+ match->wc.masks.base_layer = UINT8_MAX;
+}
+
+void
match_set_dl_type(struct match *match, ovs_be16 dl_type)
{
match->wc.masks.dl_type = OVS_BE16_MAX;
@@ -1060,7 +1067,7 @@ match_format(const struct match *match, struct ds *s, int priority)
int i;
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 36);
if (priority != OFP_DEFAULT_PRIORITY) {
ds_put_format(s, "%spriority=%s%d,",
@@ -369,6 +369,8 @@ mf_are_prereqs_ok(const struct mf_field *mf, const struct flow *flow)
case MFP_NONE:
return true;
+ case MFP_ETHERNET:
+ return flow->base_layer == LAYER_2;
case MFP_ARP:
return (flow->dl_type == htons(ETH_TYPE_ARP) ||
flow->dl_type == htons(ETH_TYPE_RARP));
@@ -449,6 +451,9 @@ mf_mask_field_and_prereqs__(const struct mf_field *mf,
case MFP_VLAN_VID:
WC_MASK_FIELD_MASK(wc, vlan_tci, htons(VLAN_CFI));
break;
+ case MFP_ETHERNET:
+ WC_MASK_FIELD(wc, base_layer);
+ break;
case MFP_NONE:
break;
}
@@ -485,6 +490,11 @@ mf_bitmap_set_field_and_prereqs(const struct mf_field *mf, struct mf_bitmap *bm)
case MFP_VLAN_VID:
bitmap_set1(bm->bm, MFF_VLAN_TCI);
break;
+ case MFP_ETHERNET:
+ bitmap_set1(bm->bm, MFF_ETH_SRC);
+ bitmap_set1(bm->bm, MFF_ETH_DST);
+ bitmap_set1(bm->bm, MFF_ETH_TYPE);
+ break;
case MFP_NONE:
break;
}
@@ -580,6 +580,7 @@ netdev_rxq_bsd_recv_pcap(struct netdev_rxq_bsd *rxq, struct dp_packet *buffer)
if (ret > 0) {
dp_packet_set_size(buffer, dp_packet_size(buffer) + arg.retval);
+ dp_packet_reset_offsets(buffer);
return 0;
}
if (ret == -1) {
@@ -606,6 +607,7 @@ netdev_rxq_bsd_recv_tap(struct netdev_rxq_bsd *rxq, struct dp_packet *buffer)
ssize_t retval = read(rxq->fd, dp_packet_data(buffer), size);
if (retval >= 0) {
dp_packet_set_size(buffer, dp_packet_size(buffer) + retval);
+ dp_packet_reset_offsets(buffer);
return 0;
} else if (errno != EINTR) {
if (errno != EAGAIN) {
@@ -273,6 +273,7 @@ dummy_packet_stream_run(struct netdev_dummy *dev, struct dummy_packet_stream *s)
dp_packet_clone(&s->rxbuf), 0);
dp_packet_clear(&s->rxbuf);
}
+ dp_packet_reset_offsets(&s->rxbuf);
} else if (retval != -EAGAIN) {
error = (retval < 0 ? -retval
: dp_packet_size(&s->rxbuf) ? EPROTO
@@ -1047,6 +1047,7 @@ netdev_linux_rxq_recv_sock(int fd, struct dp_packet *buffer)
}
dp_packet_set_size(buffer, dp_packet_size(buffer) + retval);
+ dp_packet_reset_offsets(buffer);
for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg; cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
const struct tpacket_auxdata *aux;
@@ -1087,6 +1088,7 @@ netdev_linux_rxq_recv_tap(int fd, struct dp_packet *buffer)
}
dp_packet_set_size(buffer, dp_packet_size(buffer) + retval);
+ dp_packet_reset_offsets(buffer);
return 0;
}
@@ -917,7 +917,7 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
int match_len;
int i;
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 36);
/* Metadata. */
if (match->wc.masks.dp_hash) {
@@ -4307,7 +4307,7 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms *parms,
bool export_mask, struct ofpbuf *buf)
{
struct ovs_key_ethernet *eth_key;
- size_t encap;
+ size_t encap = 0;
const struct flow *flow = parms->flow;
const struct flow *data = export_mask ? parms->mask : parms->flow;
@@ -4345,41 +4345,43 @@ 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);
}
- eth_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ETHERNET,
- sizeof *eth_key);
- get_ethernet_key(data, eth_key);
+ if (flow->base_layer == LAYER_2) {
+ eth_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ETHERNET,
+ sizeof *eth_key);
+ get_ethernet_key(data, eth_key);
- if (flow->vlan_tci != htons(0) || flow->dl_type == htons(ETH_TYPE_VLAN)) {
- if (export_mask) {
- nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, OVS_BE16_MAX);
- } else {
- nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, htons(ETH_TYPE_VLAN));
- }
- nl_msg_put_be16(buf, OVS_KEY_ATTR_VLAN, data->vlan_tci);
- encap = nl_msg_start_nested(buf, OVS_KEY_ATTR_ENCAP);
- if (flow->vlan_tci == htons(0)) {
- goto unencap;
+ if (flow->vlan_tci != htons(0) ||
+ flow->dl_type == htons(ETH_TYPE_VLAN)) {
+ if (export_mask) {
+ nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, OVS_BE16_MAX);
+ } else {
+ nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE,
+ htons(ETH_TYPE_VLAN));
+ }
+ nl_msg_put_be16(buf, OVS_KEY_ATTR_VLAN, data->vlan_tci);
+ encap = nl_msg_start_nested(buf, OVS_KEY_ATTR_ENCAP);
+ if (flow->vlan_tci == htons(0)) {
+ goto unencap;
+ }
}
- } else {
- encap = 0;
- }
- if (ntohs(flow->dl_type) < ETH_TYPE_MIN) {
- /* For backwards compatibility with kernels that don't support
- * wildcarding, the following convention is used to encode the
- * OVS_KEY_ATTR_ETHERTYPE for key and mask:
- *
- * key mask matches
- * -------- -------- -------
- * >0x5ff 0xffff Specified Ethernet II Ethertype.
- * >0x5ff 0 Any Ethernet II or non-Ethernet II frame.
- * <none> 0xffff Any non-Ethernet II frame (except valid
- * 802.3 SNAP packet with valid eth_type).
- */
- if (export_mask) {
- nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, OVS_BE16_MAX);
+ if (ntohs(flow->dl_type) < ETH_TYPE_MIN) {
+ /* For backwards compatibility with kernels that don't support
+ * wildcarding, the following convention is used to encode the
+ * OVS_KEY_ATTR_ETHERTYPE for key and mask:
+ *
+ * key mask matches
+ * -------- -------- -------
+ * >0x5ff 0xffff Specified Ethernet II Ethertype.
+ * >0x5ff 0 Any Ethernet II or non-Ethernet II frame.
+ * <none> 0xffff Any non-Ethernet II frame (except valid
+ * 802.3 SNAP packet with valid eth_type).
+ */
+ if (export_mask) {
+ nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, OVS_BE16_MAX);
+ }
+ goto unencap;
}
- goto unencap;
}
nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, data->dl_type);
@@ -4538,6 +4540,10 @@ odp_key_from_pkt_metadata(struct ofpbuf *buf, const struct pkt_metadata *md)
if (md->in_port.odp_port != ODPP_NONE) {
nl_msg_put_odp_port(buf, OVS_KEY_ATTR_IN_PORT, md->in_port.odp_port);
}
+
+ if (md->base_layer == LAYER_3) {
+ nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, md->packet_ethertype);
+ }
}
/* Generate packet metadata from the given ODP flow key. */
@@ -4546,10 +4552,13 @@ odp_key_to_pkt_metadata(const struct nlattr *key, size_t key_len,
struct pkt_metadata *md)
{
const struct nlattr *nla;
+ ovs_be16 ethertype;
size_t left;
uint32_t wanted_attrs = 1u << OVS_KEY_ATTR_PRIORITY |
1u << OVS_KEY_ATTR_SKB_MARK | 1u << OVS_KEY_ATTR_TUNNEL |
- 1u << OVS_KEY_ATTR_IN_PORT;
+ 1u << OVS_KEY_ATTR_IN_PORT | 1u << OVS_KEY_ATTR_ETHERTYPE |
+ 1u << OVS_KEY_ATTR_ETHERNET | 1u << OVS_KEY_ATTR_IPV4 |
+ 1u << OVS_KEY_ATTR_IPV6;
pkt_metadata_init(md, ODPP_NONE);
@@ -4614,14 +4623,38 @@ odp_key_to_pkt_metadata(const struct nlattr *key, size_t key_len,
md->in_port.odp_port = nl_attr_get_odp_port(nla);
wanted_attrs &= ~(1u << OVS_KEY_ATTR_IN_PORT);
break;
+ case OVS_KEY_ATTR_ETHERNET:
+ wanted_attrs &= ~(1u << OVS_KEY_ATTR_ETHERNET);
+ break;
+ case OVS_KEY_ATTR_ETHERTYPE:
+ ethertype = nl_attr_get_be16(nla);
+ wanted_attrs &= ~(1u << OVS_KEY_ATTR_ETHERTYPE);
+ break;
+ case OVS_KEY_ATTR_IPV4:
+ wanted_attrs &= ~(1u << OVS_KEY_ATTR_IPV4);
+ break;
+ case OVS_KEY_ATTR_IPV6:
+ wanted_attrs &= ~(1u << OVS_KEY_ATTR_IPV6);
+ break;
default:
break;
}
if (!wanted_attrs) {
- return; /* Have everything. */
+ break; /* Have everything. */
}
}
+
+ /* OVS_KEY_ATTR_ETHERTYPE present and OVS_KEY_ATTR_ETHERTYPE absent
+ * indicates Layer 3. */
+ if (!(wanted_attrs & (1u << OVS_KEY_ATTR_ETHERTYPE)) &&
+ wanted_attrs & (1u << OVS_KEY_ATTR_ETHERTYPE)) {
+ md->base_layer = LAYER_3;
+ md->packet_ethertype = ethertype;
+ } else {
+ md->base_layer = LAYER_2;
+ }
+
}
uint32_t
@@ -4785,7 +4818,15 @@ parse_ethertype(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
*expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ETHERTYPE;
} else {
if (!is_mask) {
- flow->dl_type = htons(FLOW_DL_TYPE_NONE);
+ if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV4)) {
+ flow->dl_type = htons(ETH_TYPE_IP);
+ } else if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV6)) {
+ flow->dl_type = htons(ETH_TYPE_IPV6);
+ } else {
+ flow->dl_type = htons(FLOW_DL_TYPE_NONE);
+ }
+ } else if (src_flow->base_layer == LAYER_3) {
+ flow->dl_type = htons(0xffff);
} else if (ntohs(src_flow->dl_type) < ETH_TYPE_MIN) {
/* See comments in odp_flow_key_from_flow__(). */
VLOG_ERR_RL(&rl, "mask expected for non-Ethernet II frame");
@@ -5204,12 +5245,13 @@ odp_flow_key_to_flow__(const struct nlattr *key, size_t key_len,
eth_key = nl_attr_get(attrs[OVS_KEY_ATTR_ETHERNET]);
put_ethernet_key(eth_key, flow);
- if (is_mask) {
- expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ETHERNET;
- }
- }
- if (!is_mask) {
+ flow->base_layer = LAYER_2;
expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ETHERNET;
+ } else if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ETHERTYPE)) {
+ flow->base_layer = LAYER_3;
+ expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ETHERTYPE;
+ } else if (is_mask && src_flow->base_layer == LAYER_3) {
+ flow->base_layer = LAYER_3;
}
/* Get Ethertype or 802.1Q TPID or FLOW_DL_TYPE_NONE. */
@@ -141,7 +141,7 @@ void odp_portno_names_destroy(struct hmap *portno_names);
* add another field and forget to adjust this value.
*/
#define ODPUTIL_FLOW_KEY_BYTES 640
-BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35);
+BUILD_ASSERT_DECL(FLOW_WC_SEQ == 36);
/* A buffer with sufficient size and alignment to hold an nlattr-formatted flow
* key. An array of "struct nlattr" might not, in theory, be sufficiently
@@ -55,10 +55,10 @@
static void ofp_print_queue_name(struct ds *string, uint32_t port);
static void ofp_print_error(struct ds *, enum ofperr);
-/* Returns a string that represents the contents of the Ethernet frame in the
+/* Returns a string that represents the contents of the packet in the
* 'len' bytes starting at 'data'. The caller must free the returned string.*/
char *
-ofp_packet_to_string(const void *data, size_t len)
+ofp_packet_to_string(const void *data, size_t len, ovs_be16 packet_ethertype)
{
struct ds ds = DS_EMPTY_INITIALIZER;
struct dp_packet buf;
@@ -66,6 +66,11 @@ ofp_packet_to_string(const void *data, size_t len)
size_t l4_size;
dp_packet_use_const(&buf, data, len);
+ if (packet_ethertype) {
+ /* This is a layer 3 packet */
+ buf.md.packet_ethertype = packet_ethertype;
+ buf.l3_ofs = 0;
+ }
flow_extract(&buf, &flow);
flow_format(&ds, &flow);
@@ -96,6 +101,17 @@ ofp_packet_to_string(const void *data, size_t len)
return ds_cstr(&ds);
}
+/* Returns a string that represents the contents of the packet in the
+ * 'len' bytes starting at 'data'. The caller must free the returned string.*/
+char *
+ofp_dp_packet_to_string(const struct dp_packet *p)
+{
+ ovs_assert(!dp_packet_is_l3(p) || ntohs(p->md.packet_ethertype));
+ return ofp_packet_to_string(dp_packet_data(p), dp_packet_size(p),
+ dp_packet_is_l3(p) ? p->md.packet_ethertype
+ : htons(0));
+}
+
static void
format_hex_arg(struct ds *s, const uint8_t *data, size_t len)
{
@@ -200,7 +216,7 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
if (verbosity > 0) {
char *packet = ofp_packet_to_string(public->packet,
- public->packet_len);
+ public->packet_len, htons(0));
ds_put_cstr(string, packet);
free(packet);
}
@@ -236,7 +252,8 @@ ofp_print_packet_out(struct ds *string, const struct ofp_header *oh,
if (po.buffer_id == UINT32_MAX) {
ds_put_format(string, " data_len=%"PRIuSIZE, po.packet_len);
if (verbosity > 0 && po.packet_len > 0) {
- char *packet = ofp_packet_to_string(po.packet, po.packet_len);
+ char *packet = ofp_packet_to_string(po.packet, po.packet_len,
+ htons(0));
ds_put_char(string, '\n');
ds_put_cstr(string, packet);
free(packet);
@@ -3706,5 +3723,5 @@ ofp_print(FILE *stream, const void *oh, size_t len, int verbosity)
void
ofp_print_packet(FILE *stream, const void *data, size_t len)
{
- print_and_free(stream, ofp_packet_to_string(data, len));
+ print_and_free(stream, ofp_packet_to_string(data, len, htons(0)));
}
@@ -101,7 +101,7 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask)
void
ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc)
{
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 36);
/* Initialize most of wc. */
flow_wildcards_init_catchall(wc);
@@ -232,16 +232,24 @@ push_eth(struct dp_packet *packet, const struct eth_addr *dst,
eh->eth_src = *src;
}
-/* Removes Ethernet header, including all VLAN and MPLS headers, from 'packet'.
+/* Removes Ethernet header, including VLAN header, from 'packet'.
*
* Previous to calling this function, 'ofpbuf_l3(packet)' must not be NULL */
void
pop_eth(struct dp_packet *packet)
{
+ char *l2_5 = dp_packet_l2_5(packet);;
+ int increment;
+
ovs_assert(dp_packet_l3(packet) != NULL);
- dp_packet_resize_l2_5(packet, -packet->l3_ofs);
- dp_packet_set_l2_5(packet, NULL);
+ if (l2_5) {
+ increment = packet->l2_5_ofs;
+ } else {
+ increment = packet->l3_ofs;
+ }
+
+ dp_packet_resize_l2(packet, -increment);
}
/* Set ethertype of the packet. */
@@ -251,6 +259,7 @@ set_ethertype(struct dp_packet *packet, ovs_be16 eth_type)
struct eth_header *eh = dp_packet_l2(packet);
if (!eh) {
+ packet->md.packet_ethertype = eth_type;
return;
}
@@ -104,6 +104,8 @@ struct pkt_metadata {
uint32_t ct_mark; /* Connection mark. */
ovs_u128 ct_label; /* Connection label. */
union flow_in_port in_port; /* Input port. */
+ ovs_be16 packet_ethertype; /* Ethertype of the packet */
+ uint8_t base_layer; /* Packet starts at this layer */
struct flow_tnl tunnel; /* Encapsulating tunnel parameters. Note that
* if 'ip_dst' == 0, the rest of the fields may
* be uninitialized. */
@@ -99,7 +99,7 @@ struct rule;
/* Metadata for restoring pipeline context after recirculation. Helpers
* are inlined below to keep them together with the definition for easier
* updates. */
-BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35);
+BUILD_ASSERT_DECL(FLOW_WC_SEQ == 36);
struct frozen_metadata {
/* Metadata in struct flow. */
@@ -156,6 +156,7 @@ struct xport {
bool may_enable; /* May be enabled in bonds. */
bool is_tunnel; /* Is a tunnel port. */
+ bool is_layer3; /* Is a layer 3 port. */
struct cfm *cfm; /* CFM handle or null. */
struct bfd *bfd; /* BFD handle or null. */
@@ -602,7 +603,7 @@ static void xlate_xport_set(struct xport *xport, odp_port_t odp_port,
int stp_port_no, const struct rstp_port *rstp_port,
enum ofputil_port_config config,
enum ofputil_port_state state, bool is_tunnel,
- bool may_enable);
+ bool may_enable, bool is_layer3);
static void xlate_xbridge_remove(struct xlate_cfg *, struct xbridge *);
static void xlate_xbundle_remove(struct xlate_cfg *, struct xbundle *);
static void xlate_xport_remove(struct xlate_cfg *, struct xport *);
@@ -765,12 +766,13 @@ xlate_xport_set(struct xport *xport, odp_port_t odp_port,
const struct bfd *bfd, const struct lldp *lldp, int stp_port_no,
const struct rstp_port* rstp_port,
enum ofputil_port_config config, enum ofputil_port_state state,
- bool is_tunnel, bool may_enable)
+ bool is_tunnel, bool may_enable, bool is_layer3)
{
xport->config = config;
xport->state = state;
xport->stp_port_no = stp_port_no;
xport->is_tunnel = is_tunnel;
+ xport->is_layer3 = is_layer3;
xport->may_enable = may_enable;
xport->odp_port = odp_port;
@@ -861,7 +863,7 @@ xlate_xport_copy(struct xbridge *xbridge, struct xbundle *xbundle,
xlate_xport_set(new_xport, xport->odp_port, xport->netdev, xport->cfm,
xport->bfd, xport->lldp, xport->stp_port_no,
xport->rstp_port, xport->config, xport->state,
- xport->is_tunnel, xport->may_enable);
+ xport->is_tunnel, xport->may_enable, xport->is_layer3);
if (xport->peer) {
struct xport *peer = xport_lookup(new_xcfg, xport->peer->ofport);
@@ -1099,7 +1101,7 @@ xlate_ofport_set(struct ofproto_dpif *ofproto, struct ofbundle *ofbundle,
const struct ofproto_port_queue *qdscp_list, size_t n_qdscp,
enum ofputil_port_config config,
enum ofputil_port_state state, bool is_tunnel,
- bool may_enable)
+ bool may_enable, bool is_layer3)
{
size_t i;
struct xport *xport;
@@ -1120,7 +1122,7 @@ xlate_ofport_set(struct ofproto_dpif *ofproto, struct ofbundle *ofbundle,
xlate_xport_set(xport, odp_port, netdev, cfm, bfd, lldp,
stp_port_no, rstp_port, config, state, is_tunnel,
- may_enable);
+ may_enable, is_layer3);
if (xport->peer) {
xport->peer->peer = NULL;
@@ -2476,7 +2478,7 @@ xlate_normal(struct xlate_ctx *ctx)
}
/* Learn source MAC. */
- if (ctx->xin->may_learn) {
+ if (ctx->xin->may_learn && !in_port->is_layer3) {
update_learning_table(ctx->xbridge, flow, wc, vlan, in_xbundle);
}
if (ctx->xin->xcache) {
@@ -3007,7 +3009,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
/* If 'struct flow' gets additional metadata, we'll need to zero it out
* before traversing a patch port. */
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 36);
memset(&flow_tnl, 0, sizeof flow_tnl);
if (!xport) {
@@ -3045,6 +3047,14 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
}
}
+ if (xport->is_layer3) {
+ if (flow->base_layer == LAYER_2) {
+ flow->base_layer = LAYER_3;
+ }
+ } else if (flow->base_layer == LAYER_3) {
+ flow->base_layer = LAYER_2;
+ }
+
if (xport->peer) {
const struct xport *peer = xport->peer;
struct flow old_flow = ctx->xin->flow;
@@ -3675,9 +3685,14 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
uint16_t controller_id,
const uint8_t *userdata, size_t userdata_len)
{
+ struct flow *flow = &ctx->xin->flow;
struct dp_packet_batch batch;
struct dp_packet *packet;
+ if (flow->base_layer == LAYER_3) {
+ flow->base_layer = LAYER_2;
+ }
+
ctx->xout->slow |= SLOW_CONTROLLER;
xlate_commit_actions(ctx);
if (!ctx->xin->packet) {
@@ -3685,6 +3700,7 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
}
packet = dp_packet_clone(ctx->xin->packet);
+
packet_batch_init_packet(&batch, packet);
odp_execute_actions(NULL, &batch, false,
ctx->odp_actions->data, ctx->odp_actions->size, NULL);
@@ -174,7 +174,7 @@ void xlate_ofport_set(struct ofproto_dpif *, struct ofbundle *,
const struct ofproto_port_queue *qdscp,
size_t n_qdscp, enum ofputil_port_config,
enum ofputil_port_state, bool is_tunnel,
- bool may_enable);
+ bool may_enable, bool is_l3);
void xlate_ofport_remove(struct ofport_dpif *);
struct ofproto_dpif * xlate_lookup_ofproto(const struct dpif_backer *,
@@ -641,7 +641,7 @@ type_run(const char *type)
ofport->rstp_port, ofport->qdscp,
ofport->n_qdscp, ofport->up.pp.config,
ofport->up.pp.state, ofport->is_tunnel,
- ofport->may_enable);
+ ofport->may_enable, ofport->is_layer3);
}
xlate_txn_commit();
}
@@ -4683,15 +4683,15 @@ in_port=2 actions=output:1
])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
-odp_flow="in_port(p1)"
-br_flow="in_port=1"
+odp_flow="in_port(p1),eth(src=00:00:00:00:00:00,dst=00:00:00:00:00:00)"
+br_flow="in_port=1,dl_dst=00:00:00:00:00:00"
# Test command: ofproto/trace odp_flow with in_port as a name.
AT_CHECK([ovs-appctl ofproto/trace "$odp_flow"], [0], [stdout])
AT_CHECK([tail -1 stdout], [0], [dnl
Datapath actions: 2
])
-odp_flow="in_port(1)"
+odp_flow="in_port(1),eth(src=00:00:00:00:00:00,dst=00:00:00:00:00:00)"
# Test command: ofproto/trace odp_flow
AT_CHECK([ovs-appctl ofproto/trace "$odp_flow"], [0], [stdout])
AT_CHECK([tail -1 stdout], [0], [dnl
@@ -88,28 +88,28 @@ AT_CHECK([tail -1 stdout], [0],
dnl Check VXLAN tunnel push
AT_CHECK([ovs-ofctl add-flow int-br action=2])
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
[Datapath actions: tnl_push(tnl_port(4789),header(size=70,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7b)),out_port(100))
])
dnl Check VXLAN tunnel push set tunnel id by flow and checksum
AT_CHECK([ovs-ofctl add-flow int-br "actions=set_tunnel:124,4"])
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
[Datapath actions: tnl_push(tnl_port(4789),header(size=70,type=4,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::93,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7c)),out_port(100))
])
dnl Check GRE tunnel push
AT_CHECK([ovs-ofctl add-flow int-br action=3])
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
[Datapath actions: tnl_push(tnl_port(3),header(size=62,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=47,tclass=0x0,hlimit=64),gre((flags=0x2000,proto=0x6558),key=0x1c8)),out_port(100))
])
dnl Check Geneve tunnel push
AT_CHECK([ovs-ofctl add-flow int-br "actions=set_field:2001:cafe::92->tun_ipv6_dst,5"])
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
[Datapath actions: tnl_push(tnl_port(6081),header(size=70,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=6081,csum=0xffff),geneve(vni=0x7b)),out_port(100))
])
@@ -117,7 +117,7 @@ AT_CHECK([tail -1 stdout], [0],
dnl Check Geneve tunnel push with options
AT_CHECK([ovs-ofctl add-tlv-map int-br "{class=0xffff,type=0x80,len=4}->tun_metadata0"])
AT_CHECK([ovs-ofctl add-flow int-br "actions=set_field:2001:cafe::92->tun_ipv6_dst,set_field:0xa->tun_metadata0,5"])
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
[Datapath actions: tnl_push(tnl_port(6081),header(size=78,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=6081,csum=0xffff),geneve(crit,vni=0x7b,options({class=0xffff,type=0x80,len=4,0xa}))),out_port(100))
])
@@ -93,28 +93,28 @@ AT_CHECK([tail -1 stdout], [0],
dnl Check VXLAN tunnel push
AT_CHECK([ovs-ofctl add-flow int-br action=2])
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
[Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x7b)),out_port(100))
])
dnl Check VXLAN tunnel push set tunnel id by flow and checksum
AT_CHECK([ovs-ofctl add-flow int-br "actions=set_tunnel:124,4"])
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
[Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.93,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7c)),out_port(100))
])
dnl Check GRE tunnel push
AT_CHECK([ovs-ofctl add-flow int-br action=3])
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
[Datapath actions: tnl_push(tnl_port(3),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x2000,proto=0x6558),key=0x1c8)),out_port(100))
])
dnl Check Geneve tunnel push
AT_CHECK([ovs-ofctl add-flow int-br "actions=set_field:1.1.2.92->tun_dst,5"])
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
[Datapath actions: tnl_push(tnl_port(6081),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=6081,csum=0x0),geneve(vni=0x7b)),out_port(100))
])
@@ -122,7 +122,7 @@ AT_CHECK([tail -1 stdout], [0],
dnl Check Geneve tunnel push with options
AT_CHECK([ovs-ofctl add-tlv-map int-br "{class=0xffff,type=0x80,len=4}->tun_metadata0"])
AT_CHECK([ovs-ofctl add-flow int-br "actions=set_field:1.1.2.92->tun_dst,set_field:0xa->tun_metadata0,5"])
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
[Datapath actions: tnl_push(tnl_port(6081),header(size=58,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=6081,csum=0x0),geneve(crit,vni=0x7b,options({class=0xffff,type=0x80,len=4,0xa}))),out_port(100))
])
@@ -434,14 +434,14 @@ AT_CHECK([tail -1 stdout], [0],
])
dnl Option match
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=0,len=4,0xb}),flags(df|key)),in_port(6081),skb_mark(0),eth_type(0x0800),ipv4(frag=no)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=0,len=4,0xb}),flags(df|key)),in_port(6081),skb_mark(0),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(frag=no)'], [0], [stdout])
AT_CHECK([tail -2 stdout], [0],
[Megaflow: pkt_mark=0,recirc_id=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-csum+key,tun_metadata0=0xb/0xf,in_port=1,nw_frag=no
Datapath actions: 2
])
dnl Skip unknown option
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=0,len=4,0xb}{class=0xffff,type=2,len=4,0xc}),flags(df|key)),in_port(6081),skb_mark(0),eth_type(0x0800),ipv4(frag=no)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=0,len=4,0xb}{class=0xffff,type=2,len=4,0xc}),flags(df|key)),in_port(6081),skb_mark(0),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(frag=no)'], [0], [stdout])
AT_CHECK([tail -2 stdout], [0],
[Megaflow: pkt_mark=0,recirc_id=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-csum+key,tun_metadata0=0xb/0xf,in_port=1,nw_frag=no
Datapath actions: 2
@@ -475,7 +475,7 @@ AT_CHECK([ovs-ofctl del-tlv-map br0 "{class=0xffff,type=3,len=4}->tun_metadata3"
AT_CHECK([ovs-ofctl add-tlv-map br0 "{class=0xffff,type=3,len=8}->tun_metadata3"])
AT_CHECK([ovs-ofctl add-flow br0 tun_metadata3=0x1234567890abcdef,actions=2])
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=3,len=8,0x1234567890abcdef}),flags(df|key)),in_port(6081),skb_mark(0),eth_type(0x0800),ipv4(frag=no)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=3,len=8,0x1234567890abcdef}),flags(df|key)),in_port(6081),skb_mark(0),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(frag=no)'], [0], [stdout])
AT_CHECK([tail -2 stdout], [0],
[Megaflow: pkt_mark=0,recirc_id=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-csum+key,tun_metadata3=0x1234567890abcdef,in_port=1,nw_frag=no
Datapath actions: 2
@@ -510,13 +510,13 @@ AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort],
NXST_FLOW reply:
])
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=0,len=4,0x12345678}),flags(df|key)),in_port(6081),skb_mark(0),eth_type(0x0800),ipv4(frag=no)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=0,len=4,0x12345678}),flags(df|key)),in_port(6081),skb_mark(0),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(frag=no)'], [0], [stdout])
AT_CHECK([tail -2 stdout], [0],
[Megaflow: pkt_mark=0,recirc_id=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-csum+key,tun_metadata0,tun_metadata1=NP,tun_metadata2=NP,in_port=1,nw_frag=no
Datapath actions: 2
])
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=1,len=0}),flags(df|key)),in_port(6081),skb_mark(0),eth_type(0x0800),ipv4(frag=no)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=1,len=0}),flags(df|key)),in_port(6081),skb_mark(0),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(frag=no)'], [0], [stdout])
AT_CHECK([tail -2 stdout], [0],
[Megaflow: pkt_mark=0,recirc_id=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-csum+key,tun_metadata1,tun_metadata2=NP,in_port=1,nw_ecn=0,nw_frag=no
Datapath actions: set(tunnel(tun_id=0x0,dst=1.1.1.1,ttl=64,geneve({class=0xffff,type=0x1,len=0}),flags(df|key))),6081