On Thu, Jun 19, 2014 at 1:46 PM, Jesse Gross <[email protected]> wrote:
> On Thu, Jun 19, 2014 at 1:30 PM, Pravin Shelar <[email protected]> wrote:
>> On Tue, Jun 10, 2014 at 4:47 PM, Jesse Gross <[email protected]> wrote:
>>> As new protocols are added, the size of the flow key tends to
>>> increase although few protocols care about all of the fields. In
>>> order to optimize this for hashing and matching, OVS uses a varible
>>> length portion of the key. However, when fields are extracted from
>>> the packet we must still zero out the entire key.
>>>
>>> This is no longer necessary now that OVS implements masking. Any
>>> fields (or holes in the structure) which are not part of a given
>>> protocol will be by definition not part of the mask and zeroed out
>>> during lookup. Furthermore, since masking already uses variable
>>> length keys this zeroing operation automatically benefits as well.
>>>
>>> In principle, the only thing that needs to be done at this point
>>> is remove the memset() at the beginning of flow. However, some
>>> fields assume that they are initialized to zero, which now must be
>>> done explicitly. In addition, in the event of an error we must also
>>> zero out corresponding fields to signal that there is no valid data
>>> present. These increase the total amount of code but very little of
>>> it is executed in non-error situations.
>>>
>>> Removing the memset() reduces the profile of ovs_flow_extract()
>>> from 0.64% to 0.56% when tested with large packets on a 10G link.
>>>
>>> Suggested-by: Pravin Shelar <[email protected]>
>>> Signed-off-by: Jesse Gross <[email protected]>
>>> ---
>>> datapath/flow.c | 49 ++++++++++++++++++++++++++++++++++++++++++++-----
>>> 1 file changed, 44 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/datapath/flow.c b/datapath/flow.c
>>> index c52081b..2a839ff 100644
>>> --- a/datapath/flow.c
>>> +++ b/datapath/flow.c
>>> @@ -273,6 +273,8 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct
>>> sw_flow_key *key)
>>> key->ip.frag = OVS_FRAG_TYPE_LATER;
>>> else
>>> key->ip.frag = OVS_FRAG_TYPE_FIRST;
>>> + } else {
>>> + key->ip.frag = OVS_FRAG_TYPE_NONE;
>>> }
>>>
>>> nh_len = payload_ofs - nh_ofs;
>>> @@ -357,6 +359,7 @@ static int parse_icmpv6(struct sk_buff *skb, struct
>>> sw_flow_key *key,
>>> */
>>> key->tp.src = htons(icmp->icmp6_type);
>>> key->tp.dst = htons(icmp->icmp6_code);
>>> + memset(&key->ipv6.nd, 0, sizeof(key->ipv6.nd));
>>>
>>> if (icmp->icmp6_code == 0 &&
>>> (icmp->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION ||
>>> @@ -448,13 +451,19 @@ int ovs_flow_extract(struct sk_buff *skb, u16
>>> in_port, struct sw_flow_key *key)
>>> int error;
>>> 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));
>>> + else
>>> + memset(&key->tun_key, 0, sizeof(key->tun_key));
>>> +
>>> key->phy.in_port = in_port;
>>> key->phy.skb_mark = skb->mark;
>>> + key->ovs_flow_hash = 0;
>>> + key->recirc_id = 0;
>>> +
>>> + /* Flags are always used as part of stats. */
>>> + key->tp.flags = 0;
>>>
>>> skb_reset_mac_header(skb);
>>>
>>> @@ -469,6 +478,7 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port,
>>> struct sw_flow_key *key)
>>> /* We are going to push all headers that we pull, so no need to
>>> * update skb->csum here. */
>>>
>>> + key->eth.tci = 0;
>>> if (vlan_tx_tag_present(skb))
>>> key->eth.tci = htons(vlan_get_tci(skb));
>>> else if (eth->h_proto == htons(ETH_P_8021Q))
>>> @@ -489,6 +499,8 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port,
>>> struct sw_flow_key *key)
>>>
>>> error = check_iphdr(skb);
>>> if (unlikely(error)) {
>>> + memset(&key->ip, 0, sizeof(key->ip));
>>> + memset(&key->ipv4, 0, sizeof(key->ipv4));
>>> if (error == -EINVAL) {
>>> skb->transport_header = skb->network_header;
>>> error = 0;
>>> @@ -512,6 +524,8 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port,
>>> struct sw_flow_key *key)
>>> if (nh->frag_off & htons(IP_MF) ||
>>> skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
>>> key->ip.frag = OVS_FRAG_TYPE_FIRST;
>>> + else
>>> + key->ip.frag = OVS_FRAG_TYPE_NONE;
>>>
>>> /* Transport layer. */
>>> if (key->ip.proto == IPPROTO_TCP) {
>>> @@ -520,18 +534,24 @@ int ovs_flow_extract(struct sk_buff *skb, u16
>>> in_port, struct sw_flow_key *key)
>>> key->tp.src = tcp->source;
>>> key->tp.dst = tcp->dest;
>>> key->tp.flags = TCP_FLAGS_BE16(tcp);
>>> + } else {
>>> + memset(&key->tp, 0, sizeof(key->tp));
>>> }
>>> } else if (key->ip.proto == IPPROTO_UDP) {
>>> if (udphdr_ok(skb)) {
>>> struct udphdr *udp = udp_hdr(skb);
>>> key->tp.src = udp->source;
>>> key->tp.dst = udp->dest;
>>> + } else {
>>> + memset(&key->tp, 0, sizeof(key->tp));
>>> }
>> if we combine above if condition we can have common memset for key->tp.
>
> I'm not sure I understand what you mean here - each protocol has a
> different check for the header being present. What would a combined
> version look like?
I was thinking of something like:
if (key->ip.proto == IPPROTO_TCP && tcphdr_ok(skb)) {
struct tcphdr *tcp = tcp_hdr(skb);
key->tp.src = tcp->source;
key->tp.dst = tcp->dest;
key->tp.flags = TCP_FLAGS_BE16(tcp);
} else if (key->ip.proto == IPPROTO_UDP &&udphdr_ok(skb)) {
.....
.....
}else if (...) {
.....
} else {
memset(&key->tp, 0, sizeof(key->tp));
}
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev