[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