[ovs-dev] [PATCH 13/17] datapath: Split ovs_flow_extract

Simon Horman horms at verge.net.au
Thu Jan 17 06:25:11 UTC 2013


Allow repeated extraction of flow from packets

Split the L3 and above portion of ovs_flow_extract() out into
ovs_flow_extract_l3_onwards() and call ovs_flow_extract_l3_onwards()
from ovs_flow_extract().

This is to allow re-extraction of L3 and higher information using
an ethernet type supplied by actions, for example the mpls_pop.

Signed-off-by: Simon Horman <horms at verge.net.au>

---

v2.15
* No change

v2.14
* No change

v2.13
* As suggested by Jarno Rajahalme
  - Update change log to more closely reflect the extent of the
    changes in the patch

v2.12
* Rebase

v2.11
* First post
---
 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 17f9ecc..28533ef 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;
 
@@ -710,8 +676,8 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
 			}
 		}
 
-	} else if ((key->eth.type == htons(ETH_P_ARP) ||
-		   key->eth.type == htons(ETH_P_RARP)) && arphdr_ok(skb)) {
+	} else if ((eth_type == htons(ETH_P_ARP) ||
+		    eth_type == htons(ETH_P_RARP)) && arphdr_ok(skb)) {
 		struct arp_eth_header *arp;
 
 		arp = (struct arp_eth_header *)skb_network_header(skb);
@@ -730,18 +696,7 @@ 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 (eth_p_mpls(key->eth.type)) {
-		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 header */
-		skb_set_network_header(skb, skb_network_header(skb) -
-				       skb->data + MPLS_HLEN);
-	} else if (key->eth.type == htons(ETH_P_IPV6)) {
+	} else if (eth_type == htons(ETH_P_IPV6)) {
 		int nh_len;             /* IPv6 Header + Extensions */
 
 		nh_len = parse_ipv6hdr(skb, key, &key_len);
@@ -788,6 +743,91 @@ 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 (eth_p_mpls(key->eth.type)) {
+		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 transport header */
+		skb_set_network_header(skb, skb_network_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 c564115..bb80e15 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