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 <ho...@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@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev