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

Jarno Rajahalme jarno.rajahalme at nsn.com
Thu Dec 27 17:25:22 UTC 2012


On Dec 27, 2012, at 7:23 , ext Simon Horman wrote:

> 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.
> 

This commit message no longer fully matches the content as this commit contains the split ovs_flow_extract() only.

> 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>
> 
> ---
> 
> 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 2290d53..b54f68c 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 2889e85..66410b4 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
> 
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev




More information about the dev mailing list