[ovs-dev] [PATCH 10/19] datapath: Allow repeated extraction of flow from packets

Simon Horman horms at verge.net.au
Mon Dec 24 02:35:16 UTC 2012


Actions may provide information that allows further decoding of
a packet to provide a richer match. In such cases use the richer
match to look for a more specific flow. If this fails, make
an upcall to request a most specific facet.

For example:

In the case of MPLS, L3 and L4 information may not initially be decoded
from the frame as the ethernet type of the frame is an MPLS type and no
information is known about the type of the inner frame.

However, the type of the inner frame may be provided by an mpls_pop action
in which case L3 and L4 information may be decoded providing a finer
grained match than is otherwise possible.

Signed-off-by: Simon Horman <horms at verge.net.au>
---
 datapath/flow.c |  156 ++++++++++++++++++++++++++++++++++---------------------
 datapath/flow.h |    2 +
 2 files changed, 100 insertions(+), 58 deletions(-)

diff --git a/datapath/flow.c b/datapath/flow.c
index 3c83426..7e7dc0a 100644
--- a/datapath/flow.c
+++ b/datapath/flow.c
@@ -588,7 +588,8 @@ out:
 }
 
 /**
- * ovs_flow_extract - extracts a flow key from an Ethernet frame.
+ * ovs_flow_extract_l3_onwards - extracts l3 and l4 portion of a flow key
+ * from an Ethernet frame.
  * @skb: sk_buff that contains the frame, with skb->data pointing to the
  * Ethernet header
  * @in_port: port number on which @skb was received.
@@ -596,62 +597,27 @@ out:
  * @key_lenp: length of output flow key
  *
  * The caller must ensure that skb->len >= ETH_HLEN.
+ * The caller must ensure that the rest of the flow is initialised.
+ * This, ovs_flow_extract_l3_onwards() should be called by or after
+ * vs_flow_extract().
  *
  * Returns 0 if successful, otherwise a negative errno value.
  *
  * Initializes @skb header pointers as follows:
  *
- *    - skb->mac_header: the Ethernet header.
- *
- *    - skb->network_header: just past the Ethernet header, or just past the
- *      VLAN header, to the first byte of the Ethernet payload.
- *
- *    - skb->transport_header: If key->dl_type is ETH_P_IP or ETH_P_IPV6
+ *    - skb->transport_header: If eth_type is ETH_P_IP or ETH_P_IPV6
  *      on output, then just past the IP header, if one is present and
  *      of a correct length, otherwise the same as skb->network_header.
  *      For other key->dl_type values it is left untouched.
  */
-int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
-		 int *key_lenp)
+int ovs_flow_extract_l3_onwards(struct sk_buff *skb, struct sw_flow_key *key,
+				int *key_lenp, __be16 eth_type)
 {
 	int error = 0;
-	int key_len = SW_FLOW_KEY_OFFSET(eth);
-	struct ethhdr *eth;
-
-	memset(key, 0, sizeof(*key));
-
-	key->phy.priority = skb->priority;
-	if (OVS_CB(skb)->tun_key)
-		memcpy(&key->tun_key, OVS_CB(skb)->tun_key, sizeof(key->tun_key));
-	key->phy.in_port = in_port;
-	key->phy.skb_mark = skb_get_mark(skb);
-
-	skb_reset_mac_header(skb);
-
-	/* Link layer.  We are guaranteed to have at least the 14 byte Ethernet
-	 * header in the linear data area.
-	 */
-	eth = eth_hdr(skb);
-	memcpy(key->eth.src, eth->h_source, ETH_ALEN);
-	memcpy(key->eth.dst, eth->h_dest, ETH_ALEN);
-
-	__skb_pull(skb, 2 * ETH_ALEN);
-
-	if (vlan_tx_tag_present(skb))
-		key->eth.tci = htons(vlan_get_tci(skb));
-	else if (eth->h_proto == htons(ETH_P_8021Q))
-		if (unlikely(parse_vlan(skb, key)))
-			return -ENOMEM;
-
-	key->eth.type = parse_ethertype(skb);
-	if (unlikely(key->eth.type == htons(0)))
-		return -ENOMEM;
-
-	skb_reset_network_header(skb);
-	__skb_push(skb, skb->data - skb_mac_header(skb));
+	int key_len = *key_lenp;
 
 	/* Network layer. */
-	if (key->eth.type == htons(ETH_P_IP)) {
+	if (eth_type == htons(ETH_P_IP)) {
 		struct iphdr *nh;
 		__be16 offset;
 
@@ -730,20 +696,6 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
 			memcpy(key->ipv4.arp.tha, arp->ar_tha, ETH_ALEN);
 			key_len = SW_FLOW_KEY_OFFSET(ipv4.arp);
 		}
-	} else if (key->eth.type == htons(ETH_P_MPLS_UC) ||
-				key->eth.type == htons(ETH_P_MPLS_MC)) {
-		error = check_header(skb, MPLS_HLEN);
-		if (unlikely(error))
-			goto out;
-
-		key_len = SW_FLOW_KEY_OFFSET(mpls.top_label);
-		memcpy(&key->mpls.top_label, skb_network_header(skb), MPLS_HLEN);
-
-		/* Update network and transport headers */
-		skb_set_network_header(skb, skb_network_header(skb) -
-				       skb->data + MPLS_HLEN);
-		skb_set_transport_header(skb, skb_transport_header(skb) -
-				       skb->data + MPLS_HLEN);
 	} else if (key->eth.type == htons(ETH_P_IPV6)) {
 		int nh_len;             /* IPv6 Header + Extensions */
 
@@ -791,6 +743,94 @@ out:
 	return error;
 }
 
+/**
+ * ovs_flow_extract - extracts a flow key from an Ethernet frame.
+ * @skb: sk_buff that contains the frame, with skb->data pointing to the
+ * Ethernet header
+ * @in_port: port number on which @skb was received.
+ * @key: output flow key
+ * @key_lenp: length of output flow key
+ *
+ * The caller must ensure that skb->len >= ETH_HLEN.
+ *
+ * Returns 0 if successful, otherwise a negative errno value.
+ *
+ * Initializes @skb header pointers as follows:
+ *
+ *    - skb->mac_header: the Ethernet header.
+ *
+ *    - skb->network_header: just past the Ethernet header, or just past the
+ *      VLAN header, to the first byte of the Ethernet payload.
+ *
+ *    - skb->transport_header: If key->dl_type is ETH_P_IP or ETH_P_IPV6
+ *      on output, then just past the IP header, if one is present and
+ *      of a correct length, otherwise the same as skb->network_header.
+ *      For other key->dl_type values it is left untouched.
+ */
+int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
+		     int *key_lenp)
+{
+	int error = 0;
+	int key_len = SW_FLOW_KEY_OFFSET(eth);
+	struct ethhdr *eth;
+
+	memset(key, 0, sizeof(*key));
+
+	key->phy.priority = skb->priority;
+	if (OVS_CB(skb)->tun_key)
+		memcpy(&key->tun_key, OVS_CB(skb)->tun_key, sizeof(key->tun_key));
+	key->phy.in_port = in_port;
+	key->phy.skb_mark = skb_get_mark(skb);
+
+	skb_reset_mac_header(skb);
+
+	/* Link layer.  We are guaranteed to have at least the 14 byte Ethernet
+	 * header in the linear data area.
+	 */
+	eth = eth_hdr(skb);
+	memcpy(key->eth.src, eth->h_source, ETH_ALEN);
+	memcpy(key->eth.dst, eth->h_dest, ETH_ALEN);
+
+	__skb_pull(skb, 2 * ETH_ALEN);
+
+	if (vlan_tx_tag_present(skb))
+		key->eth.tci = htons(vlan_get_tci(skb));
+	else if (eth->h_proto == htons(ETH_P_8021Q))
+		if (unlikely(parse_vlan(skb, key)))
+			return -ENOMEM;
+
+	key->eth.type = parse_ethertype(skb);
+	if (unlikely(key->eth.type == htons(0)))
+		return -ENOMEM;
+
+	skb_reset_network_header(skb);
+	__skb_push(skb, skb->data - skb_mac_header(skb));
+
+	/* MPLS */
+	if (key->eth.type == htons(ETH_P_MPLS_UC) ||
+	    key->eth.type == htons(ETH_P_MPLS_MC)) {
+		error = check_header(skb, MPLS_HLEN);
+		if (unlikely(error))
+			goto err;
+
+		key_len = SW_FLOW_KEY_OFFSET(mpls.top_label);
+		memcpy(&key->mpls.top_label, skb_network_header(skb), MPLS_HLEN);
+
+		/* Update network and transport headers */
+		skb_set_network_header(skb, skb_network_header(skb) -
+				       skb->data + MPLS_HLEN);
+		skb_set_transport_header(skb, skb_transport_header(skb) -
+				       skb->data + MPLS_HLEN);
+	}
+
+	*key_lenp = key_len;
+	return ovs_flow_extract_l3_onwards(skb, key, key_lenp,
+					   key->eth.type);
+
+err:
+	return error;
+}
+
 static u32 ovs_flow_hash(const struct sw_flow_key *key, int key_start, int key_len)
 {
 	return jhash2((u32 *)((u8 *)key + key_start),
diff --git a/datapath/flow.h b/datapath/flow.h
index 2ef4e7a..c476e82 100644
--- a/datapath/flow.h
+++ b/datapath/flow.h
@@ -141,6 +141,8 @@ void ovs_flow_free(struct sw_flow *);
 struct sw_flow_actions *ovs_flow_actions_alloc(const struct nlattr *);
 void ovs_flow_deferred_free_acts(struct sw_flow_actions *);
 
+int ovs_flow_extract_l3_onwards(struct sk_buff *, struct sw_flow_key *,
+				int *key_lenp, __be16 eth_type);
 int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *,
 		     int *key_lenp);
 void ovs_flow_used(struct sw_flow *, struct sk_buff *);
-- 
1.7.10.4




More information about the dev mailing list