This replaces the very specialized and difficult-to-maintain miniflow assembly macros by a simpler data structure named "miniflow_builder" that is more general and easier to use.
It's not complete--it needs polishing and it mysteriously fails a few tests--but I'd like some early feedback. In particular, I know that the transformation to the current form was done for performance, so I'd like to make sure that this new code will not cause a regression. Therefore: how was the performance measured last time, so I can measure it the same way? CC: Jarno Rajahalme <jrajaha...@nicira.com> Signed-off-by: Ben Pfaff <b...@nicira.com> --- lib/flow.c | 385 ++++++++++++++++++------------------------------------------- lib/flow.h | 41 +++++++ lib/util.h | 4 +- 3 files changed, 154 insertions(+), 276 deletions(-) diff --git a/lib/flow.c b/lib/flow.c index b5ad5f8..22fcdae 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -50,41 +50,6 @@ const uint8_t flow_segment_u64s[4] = { FLOW_U64S }; -/* miniflow_extract() assumes the following to be true to optimize the - * extraction process. */ -BUILD_ASSERT_DECL(offsetof(struct flow, dl_type) + 2 - == offsetof(struct flow, vlan_tci) && - offsetof(struct flow, dl_type) / 4 - == offsetof(struct flow, vlan_tci) / 4 ); - -BUILD_ASSERT_DECL(offsetof(struct flow, nw_frag) + 3 - == offsetof(struct flow, nw_proto) && - offsetof(struct flow, nw_tos) + 2 - == offsetof(struct flow, nw_proto) && - offsetof(struct flow, nw_ttl) + 1 - == offsetof(struct flow, nw_proto) && - offsetof(struct flow, nw_frag) / 4 - == offsetof(struct flow, nw_tos) / 4 && - offsetof(struct flow, nw_ttl) / 4 - == offsetof(struct flow, nw_tos) / 4 && - offsetof(struct flow, nw_proto) / 4 - == offsetof(struct flow, nw_tos) / 4); - -/* TCP flags in the middle of a BE64, zeroes in the other half. */ -BUILD_ASSERT_DECL(offsetof(struct flow, tcp_flags) % 8 == 4); - -#if WORDS_BIGENDIAN -#define TCP_FLAGS_BE32(tcp_ctl) ((OVS_FORCE ovs_be32)TCP_FLAGS_BE16(tcp_ctl) \ - << 16) -#else -#define TCP_FLAGS_BE32(tcp_ctl) ((OVS_FORCE ovs_be32)TCP_FLAGS_BE16(tcp_ctl)) -#endif - -BUILD_ASSERT_DECL(offsetof(struct flow, tp_src) + 2 - == offsetof(struct flow, tp_dst) && - offsetof(struct flow, tp_src) / 4 - == offsetof(struct flow, tp_dst) / 4); - /* Removes 'size' bytes from the head end of '*datap', of size '*sizep', which * must contain at least 'size' bytes of data. Returns the first byte of data * removed. */ @@ -106,159 +71,6 @@ data_try_pull(const void **datap, size_t *sizep, size_t size) return OVS_LIKELY(*sizep >= size) ? data_pull(datap, sizep, size) : NULL; } -/* Context for pushing data to a miniflow. */ -struct mf_ctx { - uint64_t map; - uint64_t *data; - uint64_t * const end; -}; - -/* miniflow_push_* macros allow filling in a miniflow data values in order. - * Assertions are needed only when the layout of the struct flow is modified. - * 'ofs' is a compile-time constant, which allows most of the code be optimized - * away. Some GCC versions gave warnings on ALWAYS_INLINE, so these are - * defined as macros. */ - -#if (FLOW_WC_SEQ != 31) -#define MINIFLOW_ASSERT(X) ovs_assert(X) -BUILD_MESSAGE("FLOW_WC_SEQ changed: miniflow_extract() will have runtime " - "assertions enabled. Consider updating FLOW_WC_SEQ after " - "testing") -#else -#define MINIFLOW_ASSERT(X) -#endif - -#define miniflow_push_uint64_(MF, OFS, VALUE) \ -{ \ - MINIFLOW_ASSERT(MF.data < MF.end && (OFS) % 8 == 0 \ - && !(MF.map & (UINT64_MAX << (OFS) / 8))); \ - *MF.data++ = VALUE; \ - MF.map |= UINT64_C(1) << (OFS) / 8; \ -} - -#define miniflow_push_be64_(MF, OFS, VALUE) \ - miniflow_push_uint64_(MF, OFS, (OVS_FORCE uint64_t)(VALUE)) - -#define miniflow_push_uint32_(MF, OFS, VALUE) \ -{ \ - MINIFLOW_ASSERT(MF.data < MF.end && \ - (((OFS) % 8 == 0 && !(MF.map & (UINT64_MAX << (OFS) / 8))) \ - || ((OFS) % 8 == 4 && MF.map & (UINT64_C(1) << (OFS) / 8) \ - && !(MF.map & (UINT64_MAX << ((OFS) / 8 + 1)))))); \ - \ - if ((OFS) % 8 == 0) { \ - *(uint32_t *)MF.data = VALUE; \ - MF.map |= UINT64_C(1) << (OFS) / 8; \ - } else if ((OFS) % 8 == 4) { \ - *((uint32_t *)MF.data + 1) = VALUE; \ - MF.data++; \ - } \ -} - -#define miniflow_push_be32_(MF, OFS, VALUE) \ - miniflow_push_uint32_(MF, OFS, (OVS_FORCE uint32_t)(VALUE)) - -#define miniflow_push_uint16_(MF, OFS, VALUE) \ -{ \ - MINIFLOW_ASSERT(MF.data < MF.end && \ - (((OFS) % 8 == 0 && !(MF.map & (UINT64_MAX << (OFS) / 8))) \ - || ((OFS) % 2 == 0 && MF.map & (UINT64_C(1) << (OFS) / 8) \ - && !(MF.map & (UINT64_MAX << ((OFS) / 8 + 1)))))); \ - \ - if ((OFS) % 8 == 0) { \ - *(uint16_t *)MF.data = VALUE; \ - MF.map |= UINT64_C(1) << (OFS) / 8; \ - } else if ((OFS) % 8 == 2) { \ - *((uint16_t *)MF.data + 1) = VALUE; \ - } else if ((OFS) % 8 == 4) { \ - *((uint16_t *)MF.data + 2) = VALUE; \ - } else if ((OFS) % 8 == 6) { \ - *((uint16_t *)MF.data + 3) = VALUE; \ - MF.data++; \ - } \ -} - -#define miniflow_pad_to_64_(MF, OFS) \ -{ \ - MINIFLOW_ASSERT((OFS) % 8 != 0); \ - MINIFLOW_ASSERT(MF.map & (UINT64_C(1) << (OFS) / 8)); \ - MINIFLOW_ASSERT(!(MF.map & (UINT64_MAX << ((OFS) / 8 + 1)))); \ - \ - memset((uint8_t *)MF.data + (OFS) % 8, 0, 8 - (OFS) % 8); \ - MF.data++; \ -} - -#define miniflow_push_be16_(MF, OFS, VALUE) \ - miniflow_push_uint16_(MF, OFS, (OVS_FORCE uint16_t)VALUE); - -/* Data at 'valuep' may be unaligned. */ -#define miniflow_push_words_(MF, OFS, VALUEP, N_WORDS) \ -{ \ - int ofs64 = (OFS) / 8; \ - \ - MINIFLOW_ASSERT(MF.data + (N_WORDS) <= MF.end && (OFS) % 8 == 0 \ - && !(MF.map & (UINT64_MAX << ofs64))); \ - \ - memcpy(MF.data, (VALUEP), (N_WORDS) * sizeof *MF.data); \ - MF.data += (N_WORDS); \ - MF.map |= ((UINT64_MAX >> (64 - (N_WORDS))) << ofs64); \ -} - -/* Push 32-bit words padded to 64-bits. */ -#define miniflow_push_words_32_(MF, OFS, VALUEP, N_WORDS) \ -{ \ - int ofs64 = (OFS) / 8; \ - \ - MINIFLOW_ASSERT(MF.data + DIV_ROUND_UP(N_WORDS, 2) <= MF.end \ - && (OFS) % 8 == 0 \ - && !(MF.map & (UINT64_MAX << ofs64))); \ - \ - memcpy(MF.data, (VALUEP), (N_WORDS) * sizeof(uint32_t)); \ - MF.data += DIV_ROUND_UP(N_WORDS, 2); \ - MF.map |= ((UINT64_MAX >> (64 - DIV_ROUND_UP(N_WORDS, 2))) << ofs64); \ - if ((N_WORDS) & 1) { \ - *((uint32_t *)MF.data - 1) = 0; \ - } \ -} - -/* Data at 'valuep' may be unaligned. */ -/* MACs start 64-aligned, and must be followed by other data or padding. */ -#define miniflow_push_macs_(MF, OFS, VALUEP) \ -{ \ - int ofs64 = (OFS) / 8; \ - \ - MINIFLOW_ASSERT(MF.data + 2 <= MF.end && (OFS) % 8 == 0 \ - && !(MF.map & (UINT64_MAX << ofs64))); \ - \ - memcpy(MF.data, (VALUEP), 2 * ETH_ADDR_LEN); \ - MF.data += 1; /* First word only. */ \ - MF.map |= UINT64_C(3) << ofs64; /* Both words. */ \ -} - -#define miniflow_push_uint32(MF, FIELD, VALUE) \ - miniflow_push_uint32_(MF, offsetof(struct flow, FIELD), VALUE) - -#define miniflow_push_be32(MF, FIELD, VALUE) \ - miniflow_push_be32_(MF, offsetof(struct flow, FIELD), VALUE) - -#define miniflow_push_uint16(MF, FIELD, VALUE) \ - miniflow_push_uint16_(MF, offsetof(struct flow, FIELD), VALUE) - -#define miniflow_push_be16(MF, FIELD, VALUE) \ - miniflow_push_be16_(MF, offsetof(struct flow, FIELD), VALUE) - -#define miniflow_pad_to_64(MF, FIELD) \ - miniflow_pad_to_64_(MF, offsetof(struct flow, FIELD)) - -#define miniflow_push_words(MF, FIELD, VALUEP, N_WORDS) \ - miniflow_push_words_(MF, offsetof(struct flow, FIELD), VALUEP, N_WORDS) - -#define miniflow_push_words_32(MF, FIELD, VALUEP, N_WORDS) \ - miniflow_push_words_32_(MF, offsetof(struct flow, FIELD), VALUEP, N_WORDS) - -#define miniflow_push_macs(MF, FIELD, VALUEP) \ - miniflow_push_macs_(MF, offsetof(struct flow, FIELD), VALUEP) - /* Pulls the MPLS headers at '*datap' and returns the count of them. */ static inline int parse_mpls(const void **datap, size_t *sizep) @@ -425,49 +237,48 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst) const struct pkt_metadata *md = &packet->md; const void *data = dp_packet_data(packet); size_t size = dp_packet_size(packet); - uint64_t *values = miniflow_values(dst); - struct mf_ctx mf = { 0, values, values + FLOW_U64S }; + struct miniflow_builder b; const char *l2; ovs_be16 dl_type; - uint8_t nw_frag, nw_tos, nw_ttl, nw_proto; + + miniflow_builder_init(&b); /* Metadata. */ if (md->tunnel.ip_dst) { - miniflow_push_words(mf, tunnel, &md->tunnel, - sizeof md->tunnel / sizeof(uint64_t)); + MINIFLOW_BUILDER_PUT(&b, tunnel, md->tunnel); } if (md->skb_priority || md->pkt_mark) { - miniflow_push_uint32(mf, skb_priority, md->skb_priority); - miniflow_push_uint32(mf, pkt_mark, md->pkt_mark); + MINIFLOW_BUILDER_PUT(&b, skb_priority, md->skb_priority); + MINIFLOW_BUILDER_PUT(&b, pkt_mark, md->pkt_mark); } - miniflow_push_uint32(mf, dp_hash, md->dp_hash); - miniflow_push_uint32(mf, in_port, odp_to_u32(md->in_port.odp_port)); + MINIFLOW_BUILDER_PUT(&b, dp_hash, md->dp_hash); + MINIFLOW_BUILDER_PUT(&b, in_port.odp_port, md->in_port.odp_port); if (md->recirc_id) { - miniflow_push_uint32(mf, recirc_id, md->recirc_id); - miniflow_pad_to_64(mf, conj_id); + MINIFLOW_BUILDER_PUT(&b, recirc_id, md->recirc_id); } /* Initialize packet's layer pointer and offsets. */ l2 = data; dp_packet_reset_offsets(packet); - /* Must have full Ethernet header to proceed. */ + /* Ethernet source and destination addresses. */ if (OVS_UNLIKELY(size < sizeof(struct eth_header))) { goto out; - } else { - ovs_be16 vlan_tci; + } + memcpy(MINIFLOW_BUILDER_PUT_UNINIT(&b, dl_dst), l2, ETH_ADDR_LEN); + memcpy(MINIFLOW_BUILDER_PUT_UNINIT(&b, dl_src), l2 + ETH_ADDR_LEN, + ETH_ADDR_LEN); - /* Link layer. */ - BUILD_ASSERT(offsetof(struct flow, dl_dst) + 6 - == offsetof(struct flow, dl_src)); - miniflow_push_macs(mf, dl_dst, data); - /* dl_type, vlan_tci. */ - vlan_tci = parse_vlan(&data, &size); - dl_type = parse_ethertype(&data, &size); - miniflow_push_be16(mf, dl_type, dl_type); - miniflow_push_be16(mf, vlan_tci, vlan_tci); + /* VLAN. */ + ovs_be16 vlan_tci = parse_vlan(&data, &size); + if (vlan_tci) { + MINIFLOW_BUILDER_PUT(&b, vlan_tci, vlan_tci); } + /* Ethertype. */ + dl_type = parse_ethertype(&data, &size); + MINIFLOW_BUILDER_PUT(&b, dl_type, dl_type); + /* Parse mpls. */ if (OVS_UNLIKELY(eth_type_mpls(dl_type))) { int count; @@ -475,13 +286,13 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst) packet->l2_5_ofs = (char *)data - l2; count = parse_mpls(&data, &size); - miniflow_push_words_32(mf, mpls_lse, mpls, count); + memcpy(MINIFLOW_BUILDER_PUT_ARRAY(&b, mpls_lse, count), + mpls, count * sizeof(ovs_be32)); } /* Network layer. */ packet->l3_ofs = (char *)data - l2; - nw_frag = 0; if (OVS_LIKELY(dl_type == htons(ETH_TYPE_IP))) { const struct ip_header *nh = data; int ip_len; @@ -508,14 +319,7 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst) dp_packet_set_l2_pad_size(packet, size - tot_len); size = tot_len; /* Never pull padding. */ - /* Push both source and destination address at once. */ - miniflow_push_words(mf, nw_src, &nh->ip_src, 1); - - miniflow_push_be32(mf, ipv6_label, 0); /* Padding for IPv4. */ - - nw_tos = nh->ip_tos; - nw_ttl = nh->ip_ttl; - nw_proto = nh->ip_proto; + uint8_t nw_frag = 0; if (OVS_UNLIKELY(IP_IS_FRAGMENT(nh->ip_frag_off))) { nw_frag = FLOW_NW_FRAG_ANY; if (nh->ip_frag_off & htons(IP_FRAG_OFF_MASK)) { @@ -523,6 +327,13 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst) } } data_pull(&data, &size, ip_len); + + MINIFLOW_BUILDER_PUT(&b, nw_src, get_16aligned_be32(&nh->ip_src)); + MINIFLOW_BUILDER_PUT(&b, nw_dst, get_16aligned_be32(&nh->ip_dst)); + MINIFLOW_BUILDER_PUT(&b, nw_frag, nw_frag); + MINIFLOW_BUILDER_PUT(&b, nw_tos, nh->ip_tos); + MINIFLOW_BUILDER_PUT(&b, nw_ttl, nh->ip_ttl); + MINIFLOW_BUILDER_PUT(&b, nw_proto, nh->ip_proto); } else if (dl_type == htons(ETH_TYPE_IPV6)) { const struct ovs_16aligned_ip6_hdr *nh; ovs_be32 tc_flow; @@ -544,21 +355,14 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst) dp_packet_set_l2_pad_size(packet, size - plen); size = plen; /* Never pull padding. */ - miniflow_push_words(mf, ipv6_src, &nh->ip6_src, - sizeof nh->ip6_src / 8); - miniflow_push_words(mf, ipv6_dst, &nh->ip6_dst, - sizeof nh->ip6_dst / 8); + memcpy(MINIFLOW_BUILDER_PUT_UNINIT(&b, ipv6_src), &nh->ip6_src, 16); + memcpy(MINIFLOW_BUILDER_PUT_UNINIT(&b, ipv6_dst), &nh->ip6_dst, 16); tc_flow = get_16aligned_be32(&nh->ip6_flow); - { - ovs_be32 label = tc_flow & htonl(IPV6_LABEL_MASK); - miniflow_push_be32(mf, ipv6_label, label); - } - - nw_tos = ntohl(tc_flow) >> 20; - nw_ttl = nh->ip6_hlim; - nw_proto = nh->ip6_nxt; + MINIFLOW_BUILDER_PUT(&b, ipv6_label, tc_flow & htonl(IPV6_LABEL_MASK)); + uint8_t nw_frag = 0; + uint8_t nw_proto = nh->ip6_nxt; while (1) { if (OVS_LIKELY((nw_proto != IPPROTO_HOPOPTS) && (nw_proto != IPPROTO_ROUTING) @@ -622,10 +426,14 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst) } } } + + MINIFLOW_BUILDER_PUT(&b, nw_frag, nw_frag); + MINIFLOW_BUILDER_PUT(&b, nw_tos, ntohl(tc_flow) >> 20); + MINIFLOW_BUILDER_PUT(&b, nw_ttl, nh->ip6_hlim); + MINIFLOW_BUILDER_PUT(&b, nw_proto, nw_proto); } else { if (dl_type == htons(ETH_TYPE_ARP) || dl_type == htons(ETH_TYPE_RARP)) { - uint8_t arp_buf[2][ETH_ADDR_LEN]; const struct arp_eth_header *arp = (const struct arp_eth_header *) data_try_pull(&data, &size, ARP_ETH_HEADER_LEN); @@ -633,78 +441,71 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst) && OVS_LIKELY(arp->ar_pro == htons(ETH_TYPE_IP)) && OVS_LIKELY(arp->ar_hln == ETH_ADDR_LEN) && OVS_LIKELY(arp->ar_pln == 4)) { - miniflow_push_be32(mf, nw_src, - get_16aligned_be32(&arp->ar_spa)); - miniflow_push_be32(mf, nw_dst, - get_16aligned_be32(&arp->ar_tpa)); + MINIFLOW_BUILDER_PUT(&b, nw_src, + get_16aligned_be32(&arp->ar_spa)); + MINIFLOW_BUILDER_PUT(&b, nw_dst, + get_16aligned_be32(&arp->ar_tpa)); /* We only match on the lower 8 bits of the opcode. */ if (OVS_LIKELY(ntohs(arp->ar_op) <= 0xff)) { - miniflow_push_be32(mf, ipv6_label, 0); /* Pad with ARP. */ - miniflow_push_be32(mf, nw_frag, htonl(ntohs(arp->ar_op))); + MINIFLOW_BUILDER_PUT(&b, nw_proto, ntohs(arp->ar_op)); } /* Must be adjacent. */ BUILD_ASSERT(offsetof(struct flow, arp_sha) + 6 == offsetof(struct flow, arp_tha)); - memcpy(arp_buf[0], arp->ar_sha, ETH_ADDR_LEN); - memcpy(arp_buf[1], arp->ar_tha, ETH_ADDR_LEN); - miniflow_push_macs(mf, arp_sha, arp_buf); - miniflow_pad_to_64(mf, tcp_flags); + memcpy(MINIFLOW_BUILDER_PUT_UNINIT(&b, arp_sha), arp->ar_sha, + ETH_ADDR_LEN); + memcpy(MINIFLOW_BUILDER_PUT_UNINIT(&b, arp_tha), arp->ar_tha, + ETH_ADDR_LEN); } } goto out; } packet->l4_ofs = (char *)data - l2; - miniflow_push_be32(mf, nw_frag, - BYTES_TO_BE32(nw_frag, nw_tos, nw_ttl, nw_proto)); - if (OVS_LIKELY(!(nw_frag & FLOW_NW_FRAG_LATER))) { + if (OVS_LIKELY(!(b.flow.nw_frag & FLOW_NW_FRAG_LATER))) { + uint8_t nw_proto = b.flow.nw_proto; if (OVS_LIKELY(nw_proto == IPPROTO_TCP)) { if (OVS_LIKELY(size >= TCP_HEADER_LEN)) { const struct tcp_header *tcp = data; - miniflow_push_be32(mf, arp_tha[2], 0); - miniflow_push_be32(mf, tcp_flags, - TCP_FLAGS_BE32(tcp->tcp_ctl)); - miniflow_push_be16(mf, tp_src, tcp->tcp_src); - miniflow_push_be16(mf, tp_dst, tcp->tcp_dst); - miniflow_pad_to_64(mf, igmp_group_ip4); + MINIFLOW_BUILDER_PUT(&b, tcp_flags, + TCP_FLAGS_BE16(tcp->tcp_ctl)); + MINIFLOW_BUILDER_PUT(&b, tp_src, tcp->tcp_src); + MINIFLOW_BUILDER_PUT(&b, tp_dst, tcp->tcp_dst); } } else if (OVS_LIKELY(nw_proto == IPPROTO_UDP)) { if (OVS_LIKELY(size >= UDP_HEADER_LEN)) { const struct udp_header *udp = data; - miniflow_push_be16(mf, tp_src, udp->udp_src); - miniflow_push_be16(mf, tp_dst, udp->udp_dst); - miniflow_pad_to_64(mf, igmp_group_ip4); + MINIFLOW_BUILDER_PUT(&b, tp_src, udp->udp_src); + MINIFLOW_BUILDER_PUT(&b, tp_dst, udp->udp_dst); } } else if (OVS_LIKELY(nw_proto == IPPROTO_SCTP)) { if (OVS_LIKELY(size >= SCTP_HEADER_LEN)) { const struct sctp_header *sctp = data; - miniflow_push_be16(mf, tp_src, sctp->sctp_src); - miniflow_push_be16(mf, tp_dst, sctp->sctp_dst); - miniflow_pad_to_64(mf, igmp_group_ip4); + MINIFLOW_BUILDER_PUT(&b, tp_src, sctp->sctp_src); + MINIFLOW_BUILDER_PUT(&b, tp_dst, sctp->sctp_dst); } } else if (OVS_LIKELY(nw_proto == IPPROTO_ICMP)) { if (OVS_LIKELY(size >= ICMP_HEADER_LEN)) { const struct icmp_header *icmp = data; - miniflow_push_be16(mf, tp_src, htons(icmp->icmp_type)); - miniflow_push_be16(mf, tp_dst, htons(icmp->icmp_code)); - miniflow_pad_to_64(mf, igmp_group_ip4); + MINIFLOW_BUILDER_PUT(&b, tp_src, htons(icmp->icmp_type)); + MINIFLOW_BUILDER_PUT(&b, tp_dst, htons(icmp->icmp_code)); } } else if (OVS_LIKELY(nw_proto == IPPROTO_IGMP)) { if (OVS_LIKELY(size >= IGMP_HEADER_LEN)) { const struct igmp_header *igmp = data; - miniflow_push_be16(mf, tp_src, htons(igmp->igmp_type)); - miniflow_push_be16(mf, tp_dst, htons(igmp->igmp_code)); - miniflow_push_be32(mf, igmp_group_ip4, - get_16aligned_be32(&igmp->group)); + MINIFLOW_BUILDER_PUT(&b, tp_src, htons(igmp->igmp_type)); + MINIFLOW_BUILDER_PUT(&b, tp_dst, htons(igmp->igmp_code)); + MINIFLOW_BUILDER_PUT(&b, igmp_group_ip4, + get_16aligned_be32(&igmp->group)); } } else if (OVS_LIKELY(nw_proto == IPPROTO_ICMPV6)) { if (OVS_LIKELY(size >= sizeof(struct icmp6_hdr))) { @@ -716,20 +517,20 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst) if (OVS_LIKELY(parse_icmpv6(&data, &size, icmp, &nd_target, arp_buf))) { if (nd_target) { - miniflow_push_words(mf, nd_target, nd_target, - sizeof *nd_target / 8); + MINIFLOW_BUILDER_PUT(&b, nd_target, *nd_target); } - miniflow_push_macs(mf, arp_sha, arp_buf); - miniflow_pad_to_64(mf, tcp_flags); - miniflow_push_be16(mf, tp_src, htons(icmp->icmp6_type)); - miniflow_push_be16(mf, tp_dst, htons(icmp->icmp6_code)); - miniflow_pad_to_64(mf, igmp_group_ip4); + memcpy(MINIFLOW_BUILDER_PUT_UNINIT(&b, arp_sha), + arp_buf[0], ETH_ADDR_LEN); + memcpy(MINIFLOW_BUILDER_PUT_UNINIT(&b, arp_tha), + arp_buf[1], ETH_ADDR_LEN); + MINIFLOW_BUILDER_PUT(&b, tp_src, htons(icmp->icmp6_type)); + MINIFLOW_BUILDER_PUT(&b, tp_dst, htons(icmp->icmp6_code)); } } } } - out: - dst->map = mf.map; +out: + miniflow_builder_to_miniflow(&b, dst); } /* For every bit of a field that is wildcarded in 'wildcards', sets the @@ -899,6 +700,40 @@ flow_print(FILE *stream, const struct flow *flow) free(s); } +/* miniflow_builder */ + +void +miniflow_builder_init(struct miniflow_builder *b) +{ + b->map = 0; +} + +void +miniflow_builder_to_miniflow(struct miniflow_builder *b, + struct miniflow *miniflow) +{ + miniflow->map = 0; + + int max = count_1bits(b->map); + miniflow->values_inline = max <= MINI_N_INLINE; + if (!miniflow->values_inline) { + miniflow->offline_values = xmalloc(max + * sizeof *miniflow->offline_values); + } + + uint64_t *values = miniflow_values(miniflow); + int n = 0; + int idx; + MAP_FOR_EACH_INDEX (idx, b->map) { + uint64_t value = flow_u64_value(&b->flow, idx); + if (OVS_LIKELY(value)) { + miniflow->map |= UINT64_C(1) << idx; + values[n++] = value; + } + } +} + + /* flow_wildcards functions. */ /* Initializes 'wc' as a set of wildcards that matches every packet. */ diff --git a/lib/flow.h b/lib/flow.h index dcb5bb0..25f78ab 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -600,7 +600,48 @@ bool miniflow_equal_flow_in_minimask(const struct miniflow *a, const struct flow *b, const struct minimask *); uint32_t miniflow_hash_5tuple(const struct miniflow *flow, uint32_t basis); + +/* A data structure for efficiently building a miniflow. */ +struct miniflow_builder { + struct flow flow; + uint64_t map; +}; +void miniflow_builder_init(struct miniflow_builder *); +void miniflow_builder_to_miniflow(struct miniflow_builder *, + struct miniflow *); + +static inline void ALWAYS_INLINE +miniflow_builder_put_uninit__(struct miniflow_builder *mfb, + size_t ofs0, size_t ofs1) +{ + uint64_t *mfb_flow_u64 = (uint64_t *) &mfb->flow; + for (size_t ofs = ROUND_DOWN(ofs0, 8); ofs < ofs1; ofs += 8) { + size_t elem = ofs / 8; + uint64_t bit = UINT64_C(1) << elem; + + if (!(mfb->map & bit)) { + mfb_flow_u64[elem] = 0; + } + mfb->map |= bit; + } +} +#define MINIFLOW_BUILDER_PUT_UNINIT(MFB, FIELD) \ + (miniflow_builder_put_uninit__( \ + (MFB), \ + offsetof(struct flow, FIELD), \ + offsetof(struct flow, FIELD) + MEMBER_SIZEOF(struct flow, FIELD)), \ + &(MFB)->flow.FIELD) +#define MINIFLOW_BUILDER_PUT(MFB, FIELD, VALUE) \ + (*MINIFLOW_BUILDER_PUT_UNINIT(MFB, FIELD) = (VALUE), \ + (void) 0) +#define MINIFLOW_BUILDER_PUT_ARRAY(MFB, FIELD, COUNT) \ + (miniflow_builder_put_uninit__( \ + (MFB), \ + offsetof(struct flow, FIELD), \ + (offsetof(struct flow, FIELD) \ + + (COUNT) * MEMBER_SIZEOF(struct flow, FIELD[0]))), \ + (MFB)->flow.FIELD) /* Compressed flow wildcards. */ diff --git a/lib/util.h b/lib/util.h index 78abfd3..730d244 100644 --- a/lib/util.h +++ b/lib/util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -199,6 +199,8 @@ ovs_prefetch_range(const void *start, size_t size) ((char *) &(OBJECT)->MEMBER - (char *) (OBJECT)) #endif +#define MEMBER_SIZEOF(STRUCT, MEMBER) (sizeof (((STRUCT *) NULL)->MEMBER)) + /* Given POINTER, the address of the given MEMBER in a STRUCT object, returns the STRUCT object. */ #define CONTAINER_OF(POINTER, STRUCT, MEMBER) \ -- 2.1.3 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev