History

openvswitch: Eliminate memset() from flow_extract.

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

Jesse Gross committed 12 years ago

Commit 07148121 parent 0b5e8b81 file · +45 −9Browse files

Unified · Split

net/openvswitch/flow.c+45−9
@@ -462,6 +462,7 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) · 461 unmodified lines
462462 * update skb->csum here.
463463 */
464464
465+ key->eth.tci = 0;
465466 if (vlan_tx_tag_present(skb))
466467 key->eth.tci = htons(skb->vlan_tci);
467468 else if (eth->h_proto == htons(ETH_P_8021Q))
@@ -482,6 +483,8 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) · 14 unmodified lines
482483
483484 error = check_iphdr(skb);
484485 if (unlikely(error)) {
486+ memset(&key->ip, 0, sizeof(key->ip));
487+ memset(&key->ipv4, 0, sizeof(key->ipv4));
485488 if (error == -EINVAL) {
486489 skb->transport_header = skb->network_header;
487490 error = 0;
@@ -503,8 +506,10 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) · 15 unmodified lines
503506 return 0;
504507 }
505508 if (nh->frag_off & htons(IP_MF) ||
506− skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
509+ skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
507510 key->ip.frag = OVS_FRAG_TYPE_FIRST;
511+ else
512+ key->ip.frag = OVS_FRAG_TYPE_NONE;
508513
509514 /* Transport layer. */
510515 if (key->ip.proto == IPPROTO_TCP) {
@@ -513,18 +518,25 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) · 2 unmodified lines
513518 key->tp.src = tcp->source;
514519 key->tp.dst = tcp->dest;
515520 key->tp.flags = TCP_FLAGS_BE16(tcp);
521+ } else {
522+ memset(&key->tp, 0, sizeof(key->tp));
516523 }
524+
517525 } else if (key->ip.proto == IPPROTO_UDP) {
518526 if (udphdr_ok(skb)) {
519527 struct udphdr *udp = udp_hdr(skb);
520528 key->tp.src = udp->source;
521529 key->tp.dst = udp->dest;
530+ } else {
531+ memset(&key->tp, 0, sizeof(key->tp));
522532 }
523533 } else if (key->ip.proto == IPPROTO_SCTP) {
524534 if (sctphdr_ok(skb)) {
525535 struct sctphdr *sctp = sctp_hdr(skb);
526536 key->tp.src = sctp->source;
527537 key->tp.dst = sctp->dest;
538+ } else {
539+ memset(&key->tp, 0, sizeof(key->tp));
528540 }
529541 } else if (key->ip.proto == IPPROTO_ICMP) {
530542 if (icmphdr_ok(skb)) {
@@ -534,33 +546,44 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) · 3 unmodified lines
534546 * them in 16-bit network byte order. */
535547 key->tp.src = htons(icmp->type);
536548 key->tp.dst = htons(icmp->code);
549+ } else {
550+ memset(&key->tp, 0, sizeof(key->tp));
537551 }
538552 }
539553
540− } else if ((key->eth.type == htons(ETH_P_ARP) ||
541− key->eth.type == htons(ETH_P_RARP)) && arphdr_ok(skb)) {
554+ } else if (key->eth.type == htons(ETH_P_ARP) ||
555+ key->eth.type == htons(ETH_P_RARP)) {
542556 struct arp_eth_header *arp;
543557
544558 arp = (struct arp_eth_header *)skb_network_header(skb);
545559
546− if (arp->ar_hrd == htons(ARPHRD_ETHER)
547− && arp->ar_pro == htons(ETH_P_IP)
548− && arp->ar_hln == ETH_ALEN
549− && arp->ar_pln == 4) {
560+ if (arphdr_ok(skb) &&
561+ arp->ar_hrd == htons(ARPHRD_ETHER) &&
562+ arp->ar_pro == htons(ETH_P_IP) &&
563+ arp->ar_hln == ETH_ALEN &&
564+ arp->ar_pln == 4) {
550565
551566 /* We only match on the lower 8 bits of the opcode. */
552567 if (ntohs(arp->ar_op) <= 0xff)
553568 key->ip.proto = ntohs(arp->ar_op);
569+ else
570+ key->ip.proto = 0;
571+
554572 memcpy(&key->ipv4.addr.src, arp->ar_sip, sizeof(key->ipv4.addr.src));
555573 memcpy(&key->ipv4.addr.dst, arp->ar_tip, sizeof(key->ipv4.addr.dst));
556574 ether_addr_copy(key->ipv4.arp.sha, arp->ar_sha);
557575 ether_addr_copy(key->ipv4.arp.tha, arp->ar_tha);
576+ } else {
577+ memset(&key->ip, 0, sizeof(key->ip));
578+ memset(&key->ipv4, 0, sizeof(key->ipv4));
558579 }
559580 } else if (key->eth.type == htons(ETH_P_IPV6)) {
560581 int nh_len; /* IPv6 Header + Extensions */
561582
562583 nh_len = parse_ipv6hdr(skb, key);
563584 if (unlikely(nh_len < 0)) {
585+ memset(&key->ip, 0, sizeof(key->ip));
586+ memset(&key->ipv6.addr, 0, sizeof(key->ipv6.addr));
564587 if (nh_len == -EINVAL) {
565588 skb->transport_header = skb->network_header;
566589 error = 0;
@@ -582,24 +605,32 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) · 15 unmodified lines
582605 key->tp.src = tcp->source;
583606 key->tp.dst = tcp->dest;
584607 key->tp.flags = TCP_FLAGS_BE16(tcp);
608+ } else {
609+ memset(&key->tp, 0, sizeof(key->tp));
585610 }
586611 } else if (key->ip.proto == NEXTHDR_UDP) {
587612 if (udphdr_ok(skb)) {
588613 struct udphdr *udp = udp_hdr(skb);
589614 key->tp.src = udp->source;
590615 key->tp.dst = udp->dest;
616+ } else {
617+ memset(&key->tp, 0, sizeof(key->tp));
591618 }
592619 } else if (key->ip.proto == NEXTHDR_SCTP) {
593620 if (sctphdr_ok(skb)) {
594621 struct sctphdr *sctp = sctp_hdr(skb);
595622 key->tp.src = sctp->source;
596623 key->tp.dst = sctp->dest;
624+ } else {
625+ memset(&key->tp, 0, sizeof(key->tp));
597626 }
598627 } else if (key->ip.proto == NEXTHDR_ICMP) {
599628 if (icmp6hdr_ok(skb)) {
600629 error = parse_icmpv6(skb, key, nh_len);
601630 if (error)
602631 return error;
632+ } else {
633+ memset(&key->tp, 0, sizeof(key->tp));
603634 }
604635 }
605636 }
@@ -615,13 +646,19 @@ int ovs_flow_key_extract(struct ovs_key_ipv4_tunnel *tun_key, · 9 unmodified lines
615646 struct sk_buff *skb, struct sw_flow_key *key)
616647 {
617648 /* Extract metadata from packet. */
618− memset(key, 0, sizeof(*key));
619649 if (tun_key)
620650 memcpy(&key->tun_key, tun_key, sizeof(key->tun_key));
651+ else
652+ memset(&key->tun_key, 0, sizeof(key->tun_key));
621653
622654 key->phy.priority = skb->priority;
623655 key->phy.in_port = OVS_CB(skb)->input_vport->port_no;
624656 key->phy.skb_mark = skb->mark;
657+ key->ovs_flow_hash = 0;
658+ key->recirc_id = 0;
659+
660+ /* Flags are always used as part of stats */
661+ key->tp.flags = 0;
625662
626663 return key_extract(skb, key);
627664 }
@@ -632,7 +669,6 @@ int ovs_flow_key_extract_userspace(const struct nlattr *attr, · 4 unmodified lines
632669 {
633670 int err;
634671
635− memset(key, 0, sizeof(*key));
636672 /* Extract metadata from netlink attributes. */
637673 err = ovs_nla_get_flow_metadata(attr, key);
638674 if (err)