diff mbox

[ovs-dev,v11,3/5] userspace: add layer 3 support to packet metadata

Message ID 1464848661-7562-4-git-send-email-simon.horman@netronome.com
State Changes Requested
Headers show

Commit Message

Simon Horman June 2, 2016, 6:24 a.m. UTC
From: Lorand Jakab <lojakab@cisco.com>

This is needed for sending a packet back to the datapath after a miss
upcall was processed.  The presence of a layer 2 packet is signaled by
adding OVS_KEY_ATTR_ETHERNET to the packet metadata sent with the
ovs_packet netlink message.  Layer 3 packets need to be accompanied by
OVS_KEY_ATTR_PACKET_ETHERTYPE to indicate network protocol.

Signed-off-by: Lorand Jakab <lojakab@cisco.com>
Signed-off-by: Simon Horman <simon.horman@netronome.com>
Acked-by: Ben Pfaff <blp@ovn.org>

---
v11 [Simon Horman]
* Do not allow setting of OVS_KEY_ATTR_PACKET_ETHERTYPE field.
  This does not seem necessary and is not used at this time.
  If it becomes useful it can be enabled later.
* Added Ack from Ben Pfaff

v10 [Simon Horman]
* Update BUILD_BUG_ON() call in ovs_key_attr_size()
* Set packet_ethtype  in set_ethertype()
* Do not include zero-value OVS_KEY_ATTR_PACKET_ETHERTYPE attribute in flow key
  of layer 2 packets as this creates an unnecessary incompatibility with
  kernel datapaths that are unaware of that attribute.

v9 [Simon Horman]
* Rebase

v8 - v8 [Lorand Jakab]

v7 [Lorand Jakab]
* New patch
---
 datapath/flow_netlink.c                           |  2 +-
 datapath/linux/compat/include/linux/openvswitch.h |  2 ++
 include/openvswitch/match.h                       |  1 +
 lib/flow.c                                        |  4 ++++
 lib/flow.h                                        |  2 ++
 lib/match.c                                       |  7 +++++++
 lib/odp-execute.c                                 |  2 ++
 lib/odp-util.c                                    | 25 ++++++++++++++++++++++-
 lib/packets.c                                     |  1 +
 lib/packets.h                                     |  2 ++
 ofproto/ofproto-dpif-sflow.c                      |  1 +
 11 files changed, 47 insertions(+), 2 deletions(-)
diff mbox

Patch

diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c
index 6ffcc53ea1ca..c7dfb677fb86 100644
--- a/datapath/flow_netlink.c
+++ b/datapath/flow_netlink.c
@@ -284,7 +284,7 @@  size_t ovs_key_attr_size(void)
 	/* Whenever adding new OVS_KEY_ FIELDS, we should consider
 	 * updating this function.
 	 */
-	BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 26);
+	BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 27);
 
 	return    nla_total_size(4)   /* OVS_KEY_ATTR_PRIORITY */
 		+ nla_total_size(0)   /* OVS_KEY_ATTR_TUNNEL */
diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
index fd9c59d3839a..b0c7988ae9b9 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -352,6 +352,8 @@  enum ovs_key_attr {
 	OVS_KEY_ATTR_CT_ZONE,	/* u16 connection tracking zone. */
 	OVS_KEY_ATTR_CT_MARK,	/* u32 connection tracking mark */
 	OVS_KEY_ATTR_CT_LABELS,	/* 16-octet connection tracking labels */
+	OVS_KEY_ATTR_PACKET_ETHERTYPE, /* be16 Ethernet type for packet
+					* execution. */
 
 #ifdef __KERNEL__
 	/* Only used within kernel data path. */
diff --git a/include/openvswitch/match.h b/include/openvswitch/match.h
index c955753d70a9..60da412eb695 100644
--- a/include/openvswitch/match.h
+++ b/include/openvswitch/match.h
@@ -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 );
diff --git a/lib/flow.c b/lib/flow.c
index 3f6aa8c56f0b..888e3b3f6a5a 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -933,6 +933,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)
diff --git a/lib/flow.h b/lib/flow.h
index 22b245c92019..86496549672a 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -825,6 +825,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)
diff --git a/lib/match.c b/lib/match.c
index 906308b08064..0c5ca655d7d3 100644
--- a/lib/match.c
+++ b/lib/match.c
@@ -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;
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index 6d1113c5559a..48f2fc04f3c4 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -336,6 +336,7 @@  odp_execute_set_action(struct dp_packet *packet, const struct nlattr *a)
     case OVS_KEY_ATTR_CT_ZONE:
     case OVS_KEY_ATTR_CT_MARK:
     case OVS_KEY_ATTR_CT_LABELS:
+    case OVS_KEY_ATTR_PACKET_ETHERTYPE:
     case __OVS_KEY_ATTR_MAX:
     default:
         OVS_NOT_REACHED();
@@ -435,6 +436,7 @@  odp_execute_masked_set_action(struct dp_packet *packet,
     case OVS_KEY_ATTR_ICMP:
     case OVS_KEY_ATTR_ICMPV6:
     case OVS_KEY_ATTR_TCP_FLAGS:
+    case OVS_KEY_ATTR_PACKET_ETHERTYPE:
     case __OVS_KEY_ATTR_MAX:
     default:
         OVS_NOT_REACHED();
diff --git a/lib/odp-util.c b/lib/odp-util.c
index dc933fd20de4..2af401efb489 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -165,6 +165,7 @@  ovs_key_attr_to_string(enum ovs_key_attr attr, char *namebuf, size_t bufsize)
     case OVS_KEY_ATTR_MPLS: return "mpls";
     case OVS_KEY_ATTR_DP_HASH: return "dp_hash";
     case OVS_KEY_ATTR_RECIRC_ID: return "recirc_id";
+    case OVS_KEY_ATTR_PACKET_ETHERTYPE: return "pkt_eth";
 
     case __OVS_KEY_ATTR_MAX:
     default:
@@ -1813,6 +1814,7 @@  static const struct attr_len_tbl ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] =
     [OVS_KEY_ATTR_CT_ZONE]   = { .len = 2 },
     [OVS_KEY_ATTR_CT_MARK]   = { .len = 4 },
     [OVS_KEY_ATTR_CT_LABELS] = { .len = sizeof(struct ovs_key_ct_labels) },
+    [OVS_KEY_ATTR_PACKET_ETHERTYPE] = { .len = 2 },
 };
 
 /* Returns the correct length of the payload for a flow key attribute of the
@@ -2833,6 +2835,7 @@  format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
         break;
     }
     case OVS_KEY_ATTR_ETHERTYPE:
+    case OVS_KEY_ATTR_PACKET_ETHERTYPE:
         ds_put_format(ds, "0x%04"PRIx16, ntohs(nl_attr_get_be16(a)));
         if (!is_exact) {
             ds_put_format(ds, "/0x%04"PRIx16, ntohs(nl_attr_get_be16(ma)));
@@ -4514,6 +4517,11 @@  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_PACKET_ETHERTYPE,
+                        md->packet_ethertype);
+    }
 }
 
 /* Generate packet metadata from the given ODP flow key. */
@@ -4525,10 +4533,13 @@  odp_key_to_pkt_metadata(const struct nlattr *key, size_t key_len,
     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_ETHERNET |
+        1u << OVS_KEY_ATTR_IPV4 | 1u << OVS_KEY_ATTR_IPV6;
 
     pkt_metadata_init(md, ODPP_NONE);
 
+    md->base_layer = LAYER_3;
+
     NL_ATTR_FOR_EACH (nla, left, key, key_len) {
         uint16_t type = nl_attr_type(nla);
         size_t len = nl_attr_get_size(nla);
@@ -4590,6 +4601,18 @@  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:
+            md->base_layer = LAYER_2;
+            wanted_attrs &= ~(1u << OVS_KEY_ATTR_ETHERNET);
+            break;
+        case OVS_KEY_ATTR_IPV4:
+            md->packet_ethertype = htons(ETH_TYPE_IP);
+            wanted_attrs &= ~(1u << OVS_KEY_ATTR_IPV4);
+            break;
+        case OVS_KEY_ATTR_IPV6:
+            md->packet_ethertype = htons(ETH_TYPE_IPV6);
+            wanted_attrs &= ~(1u << OVS_KEY_ATTR_IPV6);
+            break;
         default:
             break;
         }
diff --git a/lib/packets.c b/lib/packets.c
index 71ae03a28961..baa59feaa5ef 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -251,6 +251,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;
     }
 
diff --git a/lib/packets.h b/lib/packets.h
index 715285fb6170..8b8152549933 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -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. */
diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
index 80cb37aa0104..29808517aeb3 100644
--- a/ofproto/ofproto-dpif-sflow.c
+++ b/ofproto/ofproto-dpif-sflow.c
@@ -976,6 +976,7 @@  sflow_read_set_action(const struct nlattr *attr,
     case OVS_KEY_ATTR_IN_PORT:
     case OVS_KEY_ATTR_ETHERNET:
     case OVS_KEY_ATTR_VLAN:
+    case OVS_KEY_ATTR_PACKET_ETHERTYPE:
         break;
 
     case OVS_KEY_ATTR_MPLS: {