@@ -458,4 +458,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 */
@@ -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 38
+#define FLOW_WC_SEQ 39
/* Number of Open vSwitch extension 32-bit registers. */
#define FLOW_N_REGS 16
@@ -108,7 +108,7 @@ struct flow {
uint8_t ct_nw_proto; /* CT orig tuple IP protocol. */
uint16_t ct_zone; /* Connection tracking zone. */
uint32_t ct_mark; /* Connection mark.*/
- uint8_t pad1[4]; /* Pad to 64 bits. */
+ ovs_be32 packet_type; /* OpenFlow packet type. */
ovs_u128 ct_label; /* Connection label. */
uint32_t conj_id; /* Conjunction ID. */
ofp_port_t actset_output; /* Output port in action set. */
@@ -116,8 +116,10 @@ struct flow {
/* 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. */
- uint8_t pad2[2]; /* Pad to 64 bits. */
+ ovs_be16 dl_type; /* Ethernet frame type.
+ Note: This also holds the Ethertype for L3
+ packets of type PACKET_TYPE(1, Ethertype) */
+ uint8_t pad1[2]; /* Pad to 64 bits. */
union flow_vlan_hdr vlans[FLOW_MAX_VLAN_HEADERS]; /* VLANs */
ovs_be32 mpls_lse[ROUND_UP(FLOW_MAX_MPLS_LABELS, 2)]; /* MPLS label stack
(with padding). */
@@ -139,7 +141,7 @@ struct flow {
struct eth_addr arp_sha; /* ARP/ND source hardware address. */
struct eth_addr arp_tha; /* ARP/ND target hardware address. */
ovs_be16 tcp_flags; /* TCP flags. With L3 to avoid matching L4. */
- ovs_be16 pad3; /* Pad to 64 bits. */
+ ovs_be16 pad2; /* Pad to 64 bits. */
/* L4 (64-bit aligned) */
ovs_be16 tp_src; /* TCP/UDP/SCTP source port/ICMP type. */
@@ -148,7 +150,7 @@ struct flow {
ovs_be16 ct_tp_dst; /* CT original tuple dst port/ICMP code. */
ovs_be32 igmp_group_ip4; /* IGMP group IPv4 address.
* Keep last for BUILD_ASSERT_DECL below. */
- ovs_be32 pad4; /* Pad to 64 bits. */
+ ovs_be32 pad3; /* Pad to 64 bits. */
};
BUILD_ASSERT_DECL(sizeof(struct flow) % sizeof(uint64_t) == 0);
BUILD_ASSERT_DECL(sizeof(struct flow_tnl) % sizeof(uint64_t) == 0);
@@ -158,7 +160,7 @@ BUILD_ASSERT_DECL(sizeof(struct flow_tnl) % sizeof(uint64_t) == 0);
/* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
BUILD_ASSERT_DECL(offsetof(struct flow, igmp_group_ip4) + sizeof(uint32_t)
== sizeof(struct flow_tnl) + 300
- && FLOW_WC_SEQ == 38);
+ && FLOW_WC_SEQ == 39);
/* Incremental points at which flow classification may be performed in
* segments.
@@ -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 *);
@@ -760,7 +760,7 @@ cfm_process_heartbeat(struct cfm *cfm, const struct dp_packet *p)
atomic_read_relaxed(&cfm->extended, &extended);
- eth = dp_packet_l2(p);
+ eth = dp_packet_eth(p);
ccm = dp_packet_at(p, (uint8_t *)dp_packet_l3(p) - (uint8_t *)dp_packet_data(p),
CCM_ACCEPT_LEN);
@@ -970,7 +970,7 @@ static bool
conn_key_extract(struct conntrack *ct, struct dp_packet *pkt, ovs_be16 dl_type,
struct conn_lookup_ctx *ctx, uint16_t zone)
{
- const struct eth_header *l2 = dp_packet_l2(pkt);
+ const struct eth_header *l2 = dp_packet_eth(pkt);
const struct ip_header *l3 = dp_packet_l3(pkt);
const char *l4 = dp_packet_l4(pkt);
const char *tail = dp_packet_tail(pkt);
@@ -32,6 +32,8 @@ 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. */
+ b->packet_type = htonl(PT_ETH);
}
static void
@@ -171,6 +173,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
@@ -29,6 +29,7 @@
#include "openvswitch/list.h"
#include "packets.h"
#include "util.h"
+#include "flow.h"
#ifdef __cplusplus
extern "C" {
@@ -46,6 +47,7 @@ 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).
*/
struct dp_packet {
#ifdef DPDK_NETDEV
@@ -67,6 +69,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,7 +89,7 @@ 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 void *dp_packet_l2(const struct dp_packet *);
+static inline void *dp_packet_eth(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 *);
static inline void dp_packet_set_l2_pad_size(struct dp_packet *, uint8_t);
@@ -262,12 +265,19 @@ 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 bool
+dp_packet_is_eth(const struct dp_packet *b)
+{
+ return b->packet_type == htonl(PT_ETH);
+}
+
+/* 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)
+dp_packet_eth(const struct dp_packet *b)
{
- return (b->l3_ofs != UINT16_MAX) ? dp_packet_data(b) : NULL;
+ return (dp_packet_is_eth(b) && b->l3_ofs != UINT16_MAX)
+ ? dp_packet_data(b) : NULL;
}
/* Resets all layer offsets. 'l3' offset must be set before 'l2' can be
@@ -4398,8 +4398,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);
@@ -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
@@ -2042,6 +2043,22 @@ 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 */
+ upcall->packet.packet_type = htonl(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);
+ }
+ upcall->packet.packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE,
+ ntohs(ethertype));
+ dp_packet_set_l3(&upcall->packet, dp_packet_data(&upcall->packet));
+ }
+
*dp_ifindex = ovs_header->dp_ifindex;
return 0;
@@ -1466,8 +1466,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);
@@ -1764,9 +1763,9 @@ log_execute_message(struct dpif *dpif, const struct dpif_execute *execute,
struct ofpbuf md = OFPBUF_STUB_INITIALIZER(stub);
packet = ofp_packet_to_string(dp_packet_data(execute->packet),
- dp_packet_size(execute->packet));
+ dp_packet_size(execute->packet),
+ execute->packet->packet_type);
odp_key_from_pkt_metadata(&md, &execute->packet->md);
-
ds_put_format(&ds, "%s: %sexecute ",
dpif_name(dpif),
(subexecute ? "sub-"
@@ -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 != 38)
+#if (FLOW_WC_SEQ != 39)
#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 "
@@ -530,22 +530,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)
@@ -569,11 +578,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 = packet->packet_type;
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 = OVS_BE16_MAX;
uint8_t nw_frag, nw_tos, nw_ttl, nw_proto;
uint8_t *ct_nw_proto_p = NULL;
ovs_be16 ct_tp_src = 0, ct_tp_dst = 0;
@@ -617,37 +627,49 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
if (md->ct_state) {
miniflow_push_uint32(mf, ct_mark, md->ct_mark);
- miniflow_pad_to_64(mf, ct_mark);
+ miniflow_push_be32(mf, packet_type, packet_type);
if (!ovs_u128_is_zero(md->ct_label)) {
miniflow_push_words(mf, ct_label, &md->ct_label,
sizeof md->ct_label / sizeof(uint64_t));
}
+ } else {
+ miniflow_pad_from_64(mf, packet_type);
+ miniflow_push_be32(mf, packet_type, packet_type);
}
/* 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 {
- /* Link layer. */
- ASSERT_SEQUENTIAL(dl_dst, dl_src);
- miniflow_push_macs(mf, dl_dst, data);
-
- /* VLAN */
- union flow_vlan_hdr vlans[FLOW_MAX_VLAN_HEADERS];
- size_t num_vlans = parse_vlan(&data, &size, vlans);
+ if (packet_type == htonl(PT_ETH)) {
+ /* Must have full Ethernet header to proceed. */
+ if (OVS_UNLIKELY(size < sizeof(struct eth_header))) {
+ goto out;
+ } else {
+ /* Link layer. */
+ ASSERT_SEQUENTIAL(dl_dst, dl_src);
+ miniflow_push_macs(mf, dl_dst, data);
+
+ /* VLAN */
+ union flow_vlan_hdr vlans[FLOW_MAX_VLAN_HEADERS];
+ size_t num_vlans = parse_vlan(&data, &size, vlans);
+
+ dl_type = parse_ethertype(&data, &size);
+ miniflow_push_be16(mf, dl_type, dl_type);
+ miniflow_pad_to_64(mf, dl_type);
+ if (num_vlans > 0) {
+ miniflow_push_words_32(mf, vlans, vlans, num_vlans);
+ }
- /* dl_type */
- dl_type = parse_ethertype(&data, &size);
+ }
+ } 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);
+ /* Do not push vlan_tci, pad instead */
miniflow_pad_to_64(mf, dl_type);
- if (num_vlans > 0) {
- miniflow_push_words_32(mf, vlans, vlans, num_vlans);
- }
}
/* Parse mpls. */
@@ -655,13 +677,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))) {
@@ -798,7 +820,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));
@@ -927,7 +949,7 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata)
{
int i;
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 38);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
match_init_catchall(flow_metadata);
if (flow->tunnel.tun_id != htonll(0)) {
@@ -1382,7 +1404,7 @@ 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 == 38);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
if (flow_tnl_dst_is_set(&flow->tunnel)) {
if (flow->tunnel.flags & FLOW_TNL_F_KEY) {
@@ -1399,6 +1421,7 @@ 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) {
@@ -1517,7 +1540,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 == 38);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
flowmap_init(map);
@@ -1548,6 +1571,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))) {
@@ -1611,7 +1635,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 == 38);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
memset(&wc->masks.metadata, 0, sizeof wc->masks.metadata);
memset(&wc->masks.regs, 0, sizeof wc->masks.regs);
@@ -1755,7 +1779,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 == 38);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
uint32_t hash = basis;
if (flow) {
@@ -1802,7 +1826,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 == 38);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
uint32_t hash = basis;
if (flow) {
@@ -2391,7 +2415,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 == 38);
+ BUILD_ASSERT(FLOW_WC_SEQ == 39);
memset((char *) flow + FLOW_SEGMENT_2_ENDS_AT, 0,
sizeof(struct flow) - FLOW_SEGMENT_2_ENDS_AT);
flow->dp_hash = 0;
@@ -2616,7 +2640,7 @@ flow_compose(struct dp_packet *p, const struct flow *flow)
/* eth_compose() sets l3 pointer and makes sure it is 32-bit aligned. */
eth_compose(p, flow->dl_dst, flow->dl_src, ntohs(flow->dl_type), 0);
if (flow->dl_type == htons(FLOW_DL_TYPE_NONE)) {
- struct eth_header *eth = dp_packet_l2(p);
+ struct eth_header *eth = dp_packet_eth(p);
eth->eth_type = htons(dp_packet_size(p));
return;
}
@@ -908,7 +908,7 @@ static inline void
pkt_metadata_from_flow(struct pkt_metadata *md, const struct flow *flow)
{
/* Update this function whenever struct flow changes. */
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 38);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
md->recirc_id = flow->recirc_id;
md->dp_hash = flow->dp_hash;
@@ -953,6 +953,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 == htonl(PT_ETH);
+}
+
static inline bool is_vlan(const struct flow *flow,
struct flow_wildcards *wc)
{
@@ -1169,7 +1169,7 @@ match_format(const struct match *match, struct ds *s, int priority)
int i;
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 38);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
if (priority != OFP_DEFAULT_PRIORITY) {
ds_put_format(s, "%spriority=%s%d,",
@@ -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
@@ -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 (batch->packets[i]->packet_type != htonl(PT_ETH)) {
+ error = EPFNOSUPPORT;
+ break;
+ }
+
size -= dp_packet_get_cutlen(packet);
if (size < ETH_HEADER_LEN) {
@@ -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;
@@ -191,7 +191,7 @@ udp_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl,
csum = csum_continue(csum, udp, dp_packet_size(packet) -
((const unsigned char *)udp -
- (const unsigned char *)dp_packet_l2(packet)
+ (const unsigned char *)dp_packet_eth(packet)
));
if (csum_finish(csum)) {
return NULL;
@@ -370,7 +370,7 @@ parse_gre_header(struct dp_packet *packet,
pkt_csum = csum(greh, dp_packet_size(packet) -
((const unsigned char *)greh -
- (const unsigned char *)dp_packet_l2(packet)));
+ (const unsigned char *)dp_packet_eth(packet)));
if (pkt_csum) {
return -EINVAL;
}
@@ -986,7 +986,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 == 38);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
/* Metadata. */
if (match->wc.masks.dp_hash) {
@@ -51,7 +51,7 @@ static void
odp_eth_set_addrs(struct dp_packet *packet, const struct ovs_key_ethernet *key,
const struct ovs_key_ethernet *mask)
{
- struct eth_header *eh = dp_packet_l2(packet);
+ struct eth_header *eh = dp_packet_eth(packet);
if (eh) {
if (!mask) {
@@ -143,7 +143,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 == 38);
+BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
/* 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
@@ -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);
+ buf.packet_type = 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),
+ packet->packet_type);
+}
+
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,
+ htonl(PT_ETH));
ds_put_cstr(string, packet);
free(packet);
}
@@ -245,7 +256,9 @@ 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,
+ htonl(PT_ETH));
ds_put_char(string, '\n');
ds_put_cstr(string, packet);
free(packet);
@@ -3733,7 +3746,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));
}
@@ -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 == 38);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
/* Initialize most of wc. */
flow_wildcards_init_catchall(wc);
@@ -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);
+ b->packet_type = htonl(PT_ETH);
}
/* Insert VLAN header according to given TCI. Packet passed must be Ethernet
@@ -215,7 +216,7 @@ eth_push_vlan(struct dp_packet *packet, ovs_be16 tpid, ovs_be16 tci)
void
eth_pop_vlan(struct dp_packet *packet)
{
- struct vlan_eth_header *veh = dp_packet_l2(packet);
+ struct vlan_eth_header *veh = dp_packet_eth(packet);
if (veh && dp_packet_size(packet) >= sizeof *veh
&& eth_type_vlan(veh->veth_type)) {
@@ -229,7 +230,7 @@ eth_pop_vlan(struct dp_packet *packet)
static void
set_ethertype(struct dp_packet *packet, ovs_be16 eth_type)
{
- struct eth_header *eh = dp_packet_l2(packet);
+ struct eth_header *eh = dp_packet_eth(packet);
if (!eh) {
return;
@@ -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);
+ b->packet_type = htonl(PT_ETH);
dp_packet_reset_offsets(b);
dp_packet_set_l3(b, data);
@@ -1307,7 +1309,7 @@ compose_arp(struct dp_packet *b, uint16_t arp_op,
{
compose_arp__(b);
- struct eth_header *eth = dp_packet_l2(b);
+ struct eth_header *eth = dp_packet_eth(b);
eth->eth_dst = broadcast ? eth_addr_broadcast : arp_tha;
eth->eth_src = arp_sha;
@@ -1341,6 +1343,8 @@ compose_arp__(struct dp_packet *b)
dp_packet_reset_offsets(b);
dp_packet_set_l3(b, arp);
+
+ b->packet_type = htonl(PT_ETH);
}
/* This function expects packet with ethernet header with correct
@@ -1130,6 +1130,44 @@ struct vxlanhdr {
#define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */
+/* Input values for PACKET_TYPE macros have to be in host byte order.
+ * The _BE postfix indicates result is in network byte order. Otherwise result
+ * is in host byte order. */
+#define PACKET_TYPE(NS, NS_TYPE) ((uint32_t) ((NS) << 16 | (NS_TYPE)))
+#define PACKET_TYPE_BE(NS, NS_TYPE) (htonl((NS) << 16 | (NS_TYPE)))
+
+/* Returns the host byte ordered namespace of 'packet type'. */
+static inline uint16_t
+pt_ns(ovs_be32 packet_type)
+{
+ return ntohl(packet_type) >> 16;
+}
+
+/* Returns the host byte ordered namespace type of 'packet type'. */
+static inline uint16_t
+pt_ns_type (ovs_be32 packet_type)
+{
+ return ntohs(be32_to_be16(packet_type));
+}
+
+/* Returns the network byte ordered namespace type of 'packet type'. */
+static inline ovs_be16
+pt_ns_type_be (ovs_be32 packet_type)
+{
+ return be32_to_be16(packet_type);
+}
+
+/* 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. */
+};
+
+
void ipv6_format_addr(const struct in6_addr *addr, struct ds *);
void ipv6_format_addr_bracket(const struct in6_addr *addr, struct ds *,
bool bracket);
@@ -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(buf->packet_type == htonl(PT_ETH));
+
xgettimeofday(&tv);
prh.ts_sec = tv.tv_sec;
prh.ts_usec = tv.tv_usec;
@@ -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 == 38);
+BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
struct frozen_metadata {
/* Metadata in struct flow. */
@@ -3397,7 +3397,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 == 38);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
memset(&flow_tnl, 0, sizeof flow_tnl);
if (!xport) {
@@ -2210,7 +2210,7 @@ rstp_send_bpdu_cb(struct dp_packet *pkt, void *ofport_, void *ofproto_)
{
struct ofproto_dpif *ofproto = ofproto_;
struct ofport_dpif *ofport = ofport_;
- struct eth_header *eth = dp_packet_l2(pkt);
+ struct eth_header *eth = dp_packet_eth(pkt);
netdev_get_etheraddr(ofport->up.netdev, ð->eth_src);
if (eth_addr_is_zero(eth->eth_src)) {
@@ -2235,7 +2235,7 @@ send_bpdu_cb(struct dp_packet *pkt, int port_num, void *ofproto_)
VLOG_WARN_RL(&rl, "%s: cannot send BPDU on unknown port %d",
ofproto->up.name, port_num);
} else {
- struct eth_header *eth = dp_packet_l2(pkt);
+ struct eth_header *eth = dp_packet_eth(pkt);
netdev_get_etheraddr(ofport->up.netdev, ð->eth_src);
if (eth_addr_is_zero(eth->eth_src)) {
@@ -143,7 +143,7 @@ pinctrl_handle_arp(const struct flow *ip_flow, const struct match *md,
dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
compose_arp__(&packet);
- struct eth_header *eth = dp_packet_l2(&packet);
+ struct eth_header *eth = dp_packet_eth(&packet);
eth->eth_dst = ip_flow->dl_dst;
eth->eth_src = ip_flow->dl_src;
@@ -361,7 +361,7 @@ pinctrl_handle_put_dhcp_opts(
/* Log the response. */
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(20, 40);
- const struct eth_header *l2 = dp_packet_l2(&pkt_out);
+ const struct eth_header *l2 = dp_packet_eth(&pkt_out);
VLOG_INFO_RL(&rl, "DHCP%s "ETH_ADDR_FMT" "IP_FMT"",
msg_type == DHCP_MSG_OFFER ? "OFFER" : "ACK",
ETH_ADDR_ARGS(l2->eth_src), IP_ARGS(*offer_ip));
@@ -641,7 +641,7 @@ pinctrl_handle_put_dhcpv6_opts(
csum = packet_csum_pseudoheader6(dp_packet_l3(&pkt_out));
csum = csum_continue(csum, out_udp, dp_packet_size(&pkt_out) -
((const unsigned char *)out_udp -
- (const unsigned char *)dp_packet_l2(&pkt_out)));
+ (const unsigned char *)dp_packet_eth(&pkt_out)));
out_udp->udp_csum = csum_finish(csum);
if (!out_udp->udp_csum) {
out_udp->udp_csum = htons(0xffff);
@@ -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), htonl(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);