[ovs-dev] [PATCH 1/7] userspace: Add packet_type in dp_packet and flow

Jan Scheurich jan.scheurich at ericsson.com
Fri Feb 3 10:38:31 UTC 2017


This commit adds a packet_type attribute to the structs dp_packet and flow
to explicitly carry the type of the packet as preparation for the
introduction of the so-called packet type-aware pipeline (PTAP) in OVS.

The packet_type is a big-endian 32 bit integer with the encoding as
specified in OpenFlow verion 1.5.

The upper 16 bits contain the packet type name space. Pre-defined values
are defined in openflow-common.h:

enum ofp_header_type_namespaces {
    OFPHTN_ONF = 0,             /* ONF namespace. */
    OFPHTN_ETHERTYPE = 1,       /* ns_type is an Ethertype. */
    OFPHTN_IP_PROTO = 2,        /* ns_type is a IP protocol number. */
    OFPHTN_UDP_TCP_PORT = 3,    /* ns_type is a TCP or UDP port. */
    OFPHTN_IPV4_OPTION = 4,     /* ns_type is an IPv4 option number. */
};

The lower 16 bits specify the actual type in the context of the name space.

Only name spaces 0 and 1 will be supported for now.

For name space OFPHTN_ONF the relevant packet type is 0 (Ethernet).
This is the default packet_type in OVS and the only one supported so far.
Packets of type (OFPHTN_ONF, 0) are called Ethernet packets.

In name space OFPHTN_ETHERTYPE the type is the Ethertype of the packet.
A packet of type (OFPHTN_ETHERTYPE, <Ethertype>) is a standard L2 packet
with the Ethernet header (and any VLAN tags) removed to expose the L3
(or L2.5) payload of the packet. These will simply be called L3 packets.

The Ethernet address fields dl_src and dl_dst in struct flow are not
applicable for an L3 packet and must be zero. However, to maintain
compatibility with the large code base, we have chosen to copy the
Ethertype of an L3 packet into the dl_type field of struct flow.

This does not mean that it will be possible to match on dl_type for L3
packets with PTAP later on. Matching must be done on packet_type instead.

New dp_packets are initialized with packet_type Ethernet. Ports that
receive L3 packets will have to explicitly adjust the packet_type.

Signed-off-by: Jean Tourrilhes <jt at labs.hpe.com>
Signed-off-by: Jan Scheurich <jan.scheurich at ericsson.com>
Co-authored-by: Zoltan Balogh <zoltan.balogh at ericsson.com>
---
 include/openflow/openflow-common.h |   9 ++++
 include/openvswitch/flow.h         |  30 +++++++++--
 include/openvswitch/ofp-print.h    |   9 +++-
 lib/dp-packet.c                    |   4 ++
 lib/dp-packet.h                    |  37 +++++++++++++-
 lib/dpif-netdev.c                  |   3 +-
 lib/dpif-netlink.c                 |  16 ++++++
 lib/dpif.c                         |   6 +--
 lib/flow.c                         | 100 +++++++++++++++++++++++--------------
 lib/flow.h                         |   9 ++++
 lib/match.c                        |   2 +-
 lib/netdev-bsd.c                   |   1 +
 lib/netdev-dummy.c                 |   5 ++
 lib/netdev-linux.c                 |   4 +-
 lib/nx-match.c                     |   2 +-
 lib/odp-util.h                     |   2 +-
 lib/ofp-print.c                    |  28 +++++++++--
 lib/ofp-util.c                     |   2 +-
 lib/packets.c                      |   4 ++
 lib/pcap-file.c                    |   4 +-
 ofproto/ofproto-dpif-rid.h         |   2 +-
 ofproto/ofproto-dpif-xlate.c       |   2 +-
 tests/test-flows.c                 |   2 +-
 23 files changed, 217 insertions(+), 66 deletions(-)

diff --git a/include/openflow/openflow-common.h b/include/openflow/openflow-common.h
index 7b619a9..2382682 100644
--- a/include/openflow/openflow-common.h
+++ b/include/openflow/openflow-common.h
@@ -454,4 +454,13 @@ enum ofp_table_config {
     OFPTC14_VACANCY_EVENTS        = 1 << 3, /* Enable vacancy events. */
 };
 
+/* Header and packet type name spaces. */
+enum ofp_header_type_namespaces {
+    OFPHTN_ONF = 0,             /* ONF namespace. */
+    OFPHTN_ETHERTYPE = 1,       /* ns_type is an Ethertype. */
+    OFPHTN_IP_PROTO = 2,        /* ns_type is a IP protocol number. */
+    OFPHTN_UDP_TCP_PORT = 3,    /* ns_type is a TCP or UDP port. */
+    OFPHTN_IPV4_OPTION = 4,     /* ns_type is an IPv4 option number. */
+};
+
 #endif /* openflow/openflow-common.h */
diff --git a/include/openvswitch/flow.h b/include/openvswitch/flow.h
index df80dfe..f16060b 100644
--- a/include/openvswitch/flow.h
+++ b/include/openvswitch/flow.h
@@ -19,11 +19,13 @@
 #include "openflow/nicira-ext.h"
 #include "openvswitch/packets.h"
 #include "openvswitch/util.h"
+#include "byte-order.h"
+#include "lib/packets.h"
 
 /* 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 36
+#define FLOW_WC_SEQ 37
 
 /* Number of Open vSwitch extension 32-bit registers. */
 #define FLOW_N_REGS 16
@@ -61,6 +63,22 @@ const char *flow_tun_flag_to_string(uint32_t flags);
 /* Maximum number of supported MPLS labels. */
 #define FLOW_MAX_MPLS_LABELS 3
 
+#define PACKET_TYPE(NS, NS_TYPE) CONSTANT_HTONL((NS) << 16 | (NS_TYPE))
+#define PT_NS(PACKET_TYPE) ntohs((PACKET_TYPE) & 0xffff)
+#define PT_NS_TYPE(PACKET_TYPE) (ntohl(PACKET_TYPE) & 0xffff)
+#define PT_NS_TYPE_BE(PACKET_TYPE) ((PACKET_TYPE) >> 16)
+
+/* Well-known packet_type field values. */
+enum packet_type {
+    PT_ETH  = PACKET_TYPE(OFPHTN_ONF, 0x0000),  /* Default: Ethernet */
+    PT_IPV4 = PACKET_TYPE(OFPHTN_ETHERTYPE, ETH_TYPE_IP),
+    PT_IPV6 = PACKET_TYPE(OFPHTN_ETHERTYPE, ETH_TYPE_IPV6),
+    PT_MPLS = PACKET_TYPE(OFPHTN_ETHERTYPE, ETH_TYPE_MPLS),
+    PT_MPLS_MC = PACKET_TYPE(OFPHTN_ETHERTYPE, ETH_TYPE_MPLS_MCAST),
+    PT_UNKNOWN = PACKET_TYPE(0xffff, 0xffff),   /* Unknown packet type. */
+};
+
+
 /*
  * A flow in the network.
  *
@@ -98,11 +116,15 @@ struct flow {
     ovs_u128 ct_label;          /* Connection label. */
     uint32_t conj_id;           /* Conjunction ID. */
     ofp_port_t actset_output;   /* Output port in action set. */
+    ovs_be32 packet_type;       /* OpenFlow packet type. */
+    uint8_t pad2[4];            /* Pad to 64 bits. */
 
     /* L2, Order the same as in the Ethernet header! (64-bit aligned) */
     struct eth_addr dl_dst;     /* Ethernet destination address. */
     struct eth_addr dl_src;     /* Ethernet source address. */
-    ovs_be16 dl_type;           /* Ethernet frame type. */
+    ovs_be16 dl_type;           /* Ethernet frame type.
+                                   Note: This also holds the Ethertype for L3
+                                   packets of type PACKET_TYPE(1, Ethertype) */
     ovs_be16 vlan_tci;          /* If 802.1Q, TCI | VLAN_CFI; otherwise 0. */
     ovs_be32 mpls_lse[ROUND_UP(FLOW_MAX_MPLS_LABELS, 2)]; /* MPLS label stack
                                                              (with padding). */
@@ -135,8 +157,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) + 248
-                  && FLOW_WC_SEQ == 36);
+                  == sizeof(struct flow_tnl) + 256
+                  && FLOW_WC_SEQ == 37);
 
 /* Incremental points at which flow classification may be performed in
  * segments.
diff --git a/include/openvswitch/ofp-print.h b/include/openvswitch/ofp-print.h
index 58fd403..517f4a0 100644
--- a/include/openvswitch/ofp-print.h
+++ b/include/openvswitch/ofp-print.h
@@ -22,6 +22,8 @@
 #include <stdint.h>
 #include <stdio.h>
 
+#include <openvswitch/types.h>
+
 struct ds;
 struct ofp10_match;
 struct ofp_flow_mod;
@@ -29,19 +31,22 @@ struct ofp_header;
 struct ofputil_flow_stats;
 struct ofputil_table_features;
 struct ofputil_table_stats;
+struct dp_packet;
 
 #ifdef  __cplusplus
 extern "C" {
 #endif
 
 void ofp_print(FILE *, const void *, size_t, int verbosity);
-void ofp_print_packet(FILE *stream, const void *data, size_t len);
+void ofp_print_packet(FILE *stream, const void *data, size_t len, ovs_be32 packet_type);
+void ofp_print_dp_packet(FILE *stream, const struct dp_packet *packet);
 
 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_be32 packet_type);
+char *ofp_dp_packet_to_string(const struct dp_packet *packet);
 
 void ofp_print_flow_stats(struct ds *, struct ofputil_flow_stats *);
 void ofp_print_version(const struct ofp_header *, struct ds *);
diff --git a/lib/dp-packet.c b/lib/dp-packet.c
index 793b54f..274cff5 100644
--- a/lib/dp-packet.c
+++ b/lib/dp-packet.c
@@ -32,6 +32,9 @@ dp_packet_init__(struct dp_packet *b, size_t allocated, enum dp_packet_source so
     pkt_metadata_init(&b->md, 0);
     dp_packet_rss_invalidate(b);
     dp_packet_reset_cutlen(b);
+    /* By default assume the packet type to be Ethernet.
+     * Packet type can be adjusted with dp_packet-set_packet_type, if needed. */
+    b->packet_type = PT_ETH;
 }
 
 static void
@@ -171,6 +174,7 @@ dp_packet_clone_with_headroom(const struct dp_packet *buffer, size_t headroom)
     new_buffer->l4_ofs = buffer->l4_ofs;
     new_buffer->md = buffer->md;
     new_buffer->cutlen = buffer->cutlen;
+    new_buffer->packet_type = buffer->packet_type;
 #ifdef DPDK_NETDEV
     new_buffer->mbuf.ol_flags = buffer->mbuf.ol_flags;
 #else
diff --git a/lib/dp-packet.h b/lib/dp-packet.h
index 17b7026..2e27149 100644
--- a/lib/dp-packet.h
+++ b/lib/dp-packet.h
@@ -29,6 +29,7 @@
 #include "openvswitch/list.h"
 #include "packets.h"
 #include "util.h"
+#include "flow.h"
 
 #ifdef  __cplusplus
 extern "C" {
@@ -46,6 +47,8 @@ enum OVS_PACKED_ENUM dp_packet_source {
 
 /* Buffer for holding packet data.  A dp_packet is automatically reallocated
  * as necessary if it grows too large for the available memory.
+ * By default the packet type is set to Ethernet (PT_ETH). It can be adjusted
+ * with dp_packet_set_packet_type() if needed.
  */
 struct dp_packet {
 #ifdef DPDK_NETDEV
@@ -67,6 +70,7 @@ struct dp_packet {
     uint16_t l4_ofs;               /* Transport-level header offset,
                                       or UINT16_MAX. */
     uint32_t cutlen;               /* length in bytes to cut from the end. */
+    ovs_be32 packet_type;          /* Packet type as defined in OpenFlow */
     union {
         struct pkt_metadata md;
         uint64_t data[DP_PACKET_CONTEXT_SIZE / 8];
@@ -86,6 +90,11 @@ static inline void dp_packet_set_allocated(struct dp_packet *, uint16_t);
 
 void *dp_packet_resize_l2(struct dp_packet *, int increment);
 void *dp_packet_resize_l2_5(struct dp_packet *, int increment);
+
+static inline ovs_be32 dp_packet_packet_type(const struct dp_packet *);
+static inline void dp_packet_set_packet_type(struct dp_packet *,
+                                             ovs_be32 packet_type);
+
 static inline void *dp_packet_l2(const struct dp_packet *);
 static inline void dp_packet_reset_offsets(struct dp_packet *);
 static inline uint8_t dp_packet_l2_pad_size(const struct dp_packet *);
@@ -262,12 +271,36 @@ 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
+static inline ovs_be32
+dp_packet_packet_type(const struct dp_packet *packet)
+{
+    return packet->packet_type;
+}
+static inline void dp_packet_set_packet_type(struct dp_packet *packet,
+                                             ovs_be32 packet_type)
+{
+    packet->packet_type = packet_type;
+}
+
+static inline bool
+dp_packet_is_l2(const struct dp_packet *b)
+{
+    return b->packet_type == PT_ETH;
+}
+
+static inline bool
+dp_packet_is_l3(const struct dp_packet *b)
+{
+    return PT_NS(b->packet_type) == OFPHTN_ETHERTYPE;
+}
+
+/* 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 void *
 dp_packet_l2(const struct dp_packet *b)
 {
-    return (b->l3_ofs != UINT16_MAX) ? dp_packet_data(b) : NULL;
+    return (dp_packet_is_l2(b) && b->l3_ofs != UINT16_MAX)
+            ? dp_packet_data(b) : NULL;
 }
 
 /* Resets all layer offsets.  'l3' offset must be set before 'l2' can be
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 719a518..b630824 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -3958,8 +3958,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);
 
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index c8b0e37..8b21d41 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -55,6 +55,7 @@
 #include "unaligned.h"
 #include "util.h"
 #include "openvswitch/vlog.h"
+#include "openvswitch/flow.h"
 
 VLOG_DEFINE_THIS_MODULE(dpif_netlink);
 #ifdef _WIN32
@@ -2034,6 +2035,21 @@ 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)) {
+        /* Ethernet frame */
+        dp_packet_set_packet_type(&upcall->packet, PT_ETH);
+    } else {
+        /* Non-Ethernet packet. Get the Ethertype from the NL attributes */
+        ovs_be16 ethertype = 0;
+        const struct nlattr *et_nla = 
+                nl_attr_find__(upcall->key, upcall->key_len, OVS_KEY_ATTR_ETHERTYPE);
+        if (et_nla) {
+            ethertype = nl_attr_get_be16(et_nla);
+        }
+        dp_packet_set_packet_type(&upcall->packet, PACKET_TYPE(OFPHTN_ETHERTYPE, ethertype));
+        dp_packet_set_l3(&upcall->packet, dp_packet_data(&upcall->packet));
+    }
+
     *dp_ifindex = ovs_header->dp_ifindex;
 
     return 0;
diff --git a/lib/dpif.c b/lib/dpif.c
index 374f013..d9816e5 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -1425,8 +1425,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);
@@ -1720,8 +1719,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-"
diff --git a/lib/flow.c b/lib/flow.c
index fb7bfeb..5899339 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -125,7 +125,7 @@ struct mf_ctx {
  * away.  Some GCC versions gave warnings on ALWAYS_INLINE, so these are
  * defined as macros. */
 
-#if (FLOW_WC_SEQ != 36)
+#if (FLOW_WC_SEQ != 37)
 #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 "
@@ -516,22 +516,31 @@ parse_ipv6_ext_hdrs(const void **datap, size_t *sizep, uint8_t *nw_proto,
     return parse_ipv6_ext_hdrs__(datap, sizep, nw_proto, nw_frag);
 }
 
-/* Initializes 'flow' members from 'packet' and 'md'
+/* Initializes 'flow' members from 'packet' and 'md', taking the packet type
+ * into account.
  *
- * 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.
+ *    - packet->l2_5_ofs to the
+ *          * the start of the MPLS shim header. Can be zero, if the
+ *            packet is of type (OFPHTN_ETHERTYPE, ETH_TYPE_MPLS).
+ *          * UINT16_MAX when there is no MPLS shim 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 is set to
+ *          * zero if the packet_type is in name space OFPHTN_ETHERTYPE
+ *            and there is no MPLS shim header.
+ *          * 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 if the packet type is Ethernet and there is
+ *            no MPLS shim header.
+ *          * just past the MPLS label stack to the first byte of the MPLS
+ *            payload if there is at least one MPLS shim header.
+ *          * UINT16_MAX if the packet type is Ethernet and 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,
- *      otherwise UINT16_MAX.
+ *    - packet->l4_ofs is set to just past the IPv4 or IPv6 header, if one is
+ *      present and the packet has at least the content used for the fields
+ *      of interest for the flow, otherwise UINT16_MAX.
  */
 void
 flow_extract(struct dp_packet *packet, struct flow *flow)
@@ -555,11 +564,12 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
     const struct pkt_metadata *md = &packet->md;
     const void *data = dp_packet_data(packet);
     size_t size = dp_packet_size(packet);
+    ovs_be32 packet_type = dp_packet_packet_type(packet);
     uint64_t *values = miniflow_values(dst);
     struct mf_ctx mf = { FLOWMAP_EMPTY_INITIALIZER, values,
                          values + FLOW_U64S };
-    const char *l2;
-    ovs_be16 dl_type;
+    const char *frame;
+    ovs_be16 dl_type = 0xffff;
     uint8_t nw_frag, nw_tos, nw_ttl, nw_proto;
 
     /* Metadata. */
@@ -608,23 +618,35 @@ 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;
-    } else {
-        ovs_be16 vlan_tci;
+    miniflow_push_be32(mf, packet_type, packet_type);
+    miniflow_pad_to_64(mf, packet_type);
+
+    if (packet_type == PT_ETH) {
+        /* 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);
+            /* 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 {
+        /* Take dl_type from packet_type. */
+        dl_type = PT_NS_TYPE_BE(packet_type);
+        miniflow_pad_from_64(mf, dl_type);
         miniflow_push_be16(mf, dl_type, dl_type);
-        miniflow_push_be16(mf, vlan_tci, vlan_tci);
+        /* Do not push vlan_tci, pad instead */
+        miniflow_pad_to_64(mf, dl_type);
     }
 
     /* Parse mpls. */
@@ -632,13 +654,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))) {
@@ -755,7 +777,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));
 
@@ -869,7 +891,7 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata)
 {
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 36);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 37);
 
     match_init_catchall(flow_metadata);
     if (flow->tunnel.tun_id != htonll(0)) {
@@ -1275,7 +1297,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 == 36);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 37);
 
     if (flow_tnl_dst_is_set(&flow->tunnel)) {
         if (flow->tunnel.flags & FLOW_TNL_F_KEY) {
@@ -1292,6 +1314,7 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
         WC_MASK_FIELD(wc, tunnel.tp_dst);
         WC_MASK_FIELD(wc, tunnel.gbp_id);
         WC_MASK_FIELD(wc, tunnel.gbp_flags);
+        WC_MASK_FIELD(wc, packet_type);
 
         if (!(flow->tunnel.flags & FLOW_TNL_F_UDPIF)) {
             if (flow->tunnel.metadata.present.map) {
@@ -1393,7 +1416,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 == 36);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 37);
 
     flowmap_init(map);
 
@@ -1424,6 +1447,7 @@ flow_wc_map(const struct flow *flow, struct flowmap *map)
     FLOWMAP_SET(map, ct_zone);
     FLOWMAP_SET(map, ct_mark);
     FLOWMAP_SET(map, ct_label);
+    FLOWMAP_SET(map, packet_type);
 
     /* Ethertype-dependent fields. */
     if (OVS_LIKELY(flow->dl_type == htons(ETH_TYPE_IP))) {
@@ -1477,7 +1501,7 @@ void
 flow_wildcards_clear_non_packet_fields(struct flow_wildcards *wc)
 {
     /* Update this function whenever struct flow changes. */
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 36);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 37);
 
     memset(&wc->masks.metadata, 0, sizeof wc->masks.metadata);
     memset(&wc->masks.regs, 0, sizeof wc->masks.regs);
@@ -1621,7 +1645,7 @@ flow_wildcards_set_xxreg_mask(struct flow_wildcards *wc, int idx,
 uint32_t
 miniflow_hash_5tuple(const struct miniflow *flow, uint32_t basis)
 {
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 36);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 37);
     uint32_t hash = basis;
 
     if (flow) {
@@ -1668,7 +1692,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 == 36);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 37);
     uint32_t hash = basis;
 
     if (flow) {
@@ -2136,7 +2160,7 @@ flow_push_mpls(struct flow *flow, int n, ovs_be16 mpls_eth_type,
 
         if (clear_flow_L3) {
             /* Clear all L3 and L4 fields and dp_hash. */
-            BUILD_ASSERT(FLOW_WC_SEQ == 36);
+            BUILD_ASSERT(FLOW_WC_SEQ == 37);
             memset((char *) flow + FLOW_SEGMENT_2_ENDS_AT, 0,
                    sizeof(struct flow) - FLOW_SEGMENT_2_ENDS_AT);
             flow->dp_hash = 0;
diff --git a/lib/flow.h b/lib/flow.h
index 62315bc..9020645 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -884,6 +884,15 @@ pkt_metadata_from_flow(struct pkt_metadata *md, const struct flow *flow)
 #define FLOW_WC_GET_AND_MASK_WC(FLOW, WC, FIELD) \
     (((WC) ? WC_MASK_FIELD(WC, FIELD) : NULL), ((FLOW)->FIELD))
 
+static inline bool is_ethernet(const struct flow *flow,
+                               struct flow_wildcards *wc)
+{
+    if (wc) {
+        WC_MASK_FIELD(wc, packet_type);
+    }
+    return flow->packet_type == PT_ETH;
+}
+
 static inline bool is_vlan(const struct flow *flow,
                            struct flow_wildcards *wc)
 {
diff --git a/lib/match.c b/lib/match.c
index 3fcaec5..57529f5 100644
--- a/lib/match.c
+++ b/lib/match.c
@@ -1075,7 +1075,7 @@ match_format(const struct match *match, struct ds *s, int priority)
 
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 36);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 37);
 
     if (priority != OFP_DEFAULT_PRIORITY) {
         ds_put_format(s, "%spriority=%s%d,",
diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c
index 94c515d..c51646a 100644
--- a/lib/netdev-bsd.c
+++ b/lib/netdev-bsd.c
@@ -630,6 +630,7 @@ netdev_bsd_rxq_recv(struct netdev_rxq *rxq_, struct dp_packet_batch *batch)
         mtu = ETH_PAYLOAD_MAX;
     }
 
+    /* Assume Ethernet port. No need to set packet_type. */
     packet = dp_packet_new_with_headroom(VLAN_ETH_HEADER_LEN + mtu,
                                            DP_NETDEV_HEADROOM);
     retval = (rxq->pcap_handle
diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c
index 0657434..ba6ecc9 100644
--- a/lib/netdev-dummy.c
+++ b/lib/netdev-dummy.c
@@ -1067,6 +1067,11 @@ netdev_dummy_send(struct netdev *netdev, int qid OVS_UNUSED,
         const void *buffer = dp_packet_data(packet);
         size_t size = dp_packet_size(packet);
 
+        if (dp_packet_packet_type(batch->packets[i]) != PT_ETH) {
+            error = EPFNOSUPPORT;
+            break;
+        }
+
         size -= dp_packet_get_cutlen(packet);
 
         if (size < ETH_HEADER_LEN) {
diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index 9ff1333..36f28b6 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -1112,6 +1112,7 @@ netdev_linux_rxq_recv(struct netdev_rxq *rxq_, struct dp_packet_batch *batch)
         mtu = ETH_PAYLOAD_MAX;
     }
 
+    /* Assume Ethernet port. No need to set packet_type. */
     buffer = dp_packet_new_with_headroom(VLAN_ETH_HEADER_LEN + mtu,
                                            DP_NETDEV_HEADROOM);
     retval = (rx->is_tap
@@ -5504,7 +5505,8 @@ get_etheraddr(const char *netdev_name, struct eth_addr *ea)
         return error;
     }
     hwaddr_family = ifr.ifr_hwaddr.sa_family;
-    if (hwaddr_family != AF_UNSPEC && hwaddr_family != ARPHRD_ETHER) {
+    if (hwaddr_family != AF_UNSPEC && hwaddr_family != ARPHRD_ETHER &&
+        hwaddr_family != ARPHRD_NONE) {
         VLOG_INFO("%s device has unknown hardware address family %d",
                   netdev_name, hwaddr_family);
         return EINVAL;
diff --git a/lib/nx-match.c b/lib/nx-match.c
index e9d649b..124e56b 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -962,7 +962,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 == 36);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 37);
 
     /* Metadata. */
     if (match->wc.masks.dp_hash) {
diff --git a/lib/odp-util.h b/lib/odp-util.h
index 42011bc..f391e2a 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -142,7 +142,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 == 36);
+BUILD_ASSERT_DECL(FLOW_WC_SEQ == 37);
 
 /* 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
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index f7f7df2..797735c 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -58,7 +58,7 @@ static void ofp_print_error(struct ds *, enum ofperr);
 /* Returns a string that represents the contents of the Ethernet frame 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_be32 packet_type)
 {
     struct ds ds = DS_EMPTY_INITIALIZER;
     struct dp_packet buf;
@@ -66,6 +66,7 @@ ofp_packet_to_string(const void *data, size_t len)
     size_t l4_size;
 
     dp_packet_use_const(&buf, data, len);
+    dp_packet_set_packet_type(&buf, packet_type);
     flow_extract(&buf, &flow);
     flow_format(&ds, &flow);
 
@@ -96,6 +97,14 @@ ofp_packet_to_string(const void *data, size_t len)
     return ds_cstr(&ds);
 }
 
+char *
+ofp_dp_packet_to_string(const struct dp_packet *packet)
+{
+    return ofp_packet_to_string(dp_packet_data(packet),
+                                dp_packet_size(packet),
+                                dp_packet_packet_type(packet));
+}
+
 static void
 format_hex_arg(struct ds *s, const uint8_t *data, size_t len)
 {
@@ -208,8 +217,10 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
     }
 
     if (verbosity > 0) {
+        /* Packet In can only carry Ethernet packets. */
         char *packet = ofp_packet_to_string(public->packet,
-                                            public->packet_len);
+                                            public->packet_len,
+                                            PT_ETH);
         ds_put_cstr(string, packet);
         free(packet);
     }
@@ -245,7 +256,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);
+            /* Packet Out can only carry Ethernet packets. */
+            char *packet = ofp_packet_to_string(po.packet, po.packet_len, PT_ETH);
             ds_put_char(string, '\n');
             ds_put_cstr(string, packet);
             free(packet);
@@ -3724,7 +3736,13 @@ ofp_print(FILE *stream, const void *oh, size_t len, int verbosity)
 /* Dumps the contents of the Ethernet frame in the 'len' bytes starting at
  * 'data' to 'stream'. */
 void
-ofp_print_packet(FILE *stream, const void *data, size_t len)
+ofp_print_packet(FILE *stream, const void *data, size_t len, ovs_be32 packet_type)
+{
+    print_and_free(stream, ofp_packet_to_string(data, len, packet_type));
+}
+
+void
+ofp_print_dp_packet(FILE *stream, const struct dp_packet *packet)
 {
-    print_and_free(stream, ofp_packet_to_string(data, len));
+    print_and_free(stream, ofp_dp_packet_to_string(packet));
 }
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 0c9343e..b8872b5 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -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 == 36);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 37);
 
     /* Initialize most of wc. */
     flow_wildcards_init_catchall(wc);
diff --git a/lib/packets.c b/lib/packets.c
index fa70df6..dec6513 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -190,6 +190,7 @@ compose_rarp(struct dp_packet *b, const struct eth_addr eth_src)
 
     dp_packet_reset_offsets(b);
     dp_packet_set_l3(b, arp);
+    dp_packet_set_packet_type(b, PT_ETH);
 }
 
 /* Insert VLAN header according to given TCI. Packet passed must be Ethernet
@@ -843,6 +844,7 @@ eth_compose(struct dp_packet *b, const struct eth_addr eth_dst,
     eth->eth_src = eth_src;
     eth->eth_type = htons(eth_type);
 
+    dp_packet_set_packet_type(b, PT_ETH);
     dp_packet_reset_offsets(b);
     dp_packet_set_l3(b, data);
 
@@ -1341,6 +1343,8 @@ compose_arp__(struct dp_packet *b)
 
     dp_packet_reset_offsets(b);
     dp_packet_set_l3(b, arp);
+
+    dp_packet_set_packet_type(b, PT_ETH);
 }
 
 /* This function expects packet with ethernet header with correct
diff --git a/lib/pcap-file.c b/lib/pcap-file.c
index dd4d229..22538ab 100644
--- a/lib/pcap-file.c
+++ b/lib/pcap-file.c
@@ -177,7 +177,7 @@ ovs_pcap_read(FILE *file, struct dp_packet **bufp, long long int *when)
         *when = ts_sec * 1000LL + ts_usec / 1000;
     }
 
-    /* Read packet. */
+    /* Read packet. Packet type is Ethernet */
     buf = dp_packet_new(len);
     data = dp_packet_put_uninit(buf, len);
     if (fread(data, len, 1, file) != 1) {
@@ -197,6 +197,8 @@ ovs_pcap_write(FILE *file, struct dp_packet *buf)
     struct pcaprec_hdr prh;
     struct timeval tv;
 
+    ovs_assert(dp_packet_packet_type(buf) == PT_ETH);
+
     xgettimeofday(&tv);
     prh.ts_sec = tv.tv_sec;
     prh.ts_usec = tv.tv_usec;
diff --git a/ofproto/ofproto-dpif-rid.h b/ofproto/ofproto-dpif-rid.h
index c357591..dfe54ff 100644
--- a/ofproto/ofproto-dpif-rid.h
+++ b/ofproto/ofproto-dpif-rid.h
@@ -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 == 36);
+BUILD_ASSERT_DECL(FLOW_WC_SEQ == 37);
 
 struct frozen_metadata {
     /* Metadata in struct flow. */
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 503a347..525cdcd 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -3087,7 +3087,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 == 36);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 37);
     memset(&flow_tnl, 0, sizeof flow_tnl);
 
     if (!xport) {
diff --git a/tests/test-flows.c b/tests/test-flows.c
index 4a1b65e..3989638 100644
--- a/tests/test-flows.c
+++ b/tests/test-flows.c
@@ -83,7 +83,7 @@ test_flows_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
             errors++;
             printf("mismatch on packet #%d (1-based).\n", n);
             printf("Packet:\n");
-            ofp_print_packet(stdout, dp_packet_data(packet), dp_packet_size(packet));
+            ofp_print_packet(stdout, dp_packet_data(packet), dp_packet_size(packet), PT_ETH);
             ovs_hex_dump(stdout, dp_packet_data(packet), dp_packet_size(packet), 0, true);
             match_print(&match);
             printf("Expected flow:\n%s\n", exp_s);
-- 
1.9.1



More information about the dev mailing list