[ovs-dev] [PATCH 02/16] datapath: Split ovs_flow_extract
Simon Horman
horms at verge.net.au
Thu Jan 3 02:53:36 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.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 8215ef1..d330a57 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