[ovs-dev] [PATCH 4/7] lib/flow: Add miniflow_extract_from_flow

Jarno Rajahalme jrajahalme at nicira.com
Wed Oct 1 23:02:34 UTC 2014


miniflow_extract_from_flow() is faster than miniflow_init(), since it
does not scan the fields not significant for the packet type. More
importantly, it produces the same layout as miniflow_extract, which
does not try to compress zero-valued packet header fields.

Signed-off-by: Jarno Rajahalme <jrajahalme at nicira.com>
---
 lib/flow.c |   88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/flow.h |    1 +
 2 files changed, 89 insertions(+)

diff --git a/lib/flow.c b/lib/flow.c
index 14a3350..6fe4eae 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -638,6 +638,94 @@ miniflow_extract(struct ofpbuf *packet, const struct pkt_metadata *md,
     dst->map = mf.map;
 }
 
+/* This mirrors miniflow_extract(), but the input is from a struct flow. */
+void
+miniflow_extract_from_flow(struct miniflow *dst, const struct flow *flow)
+{
+    uint32_t *values = miniflow_values(dst);
+    struct mf_ctx mf = { 0, values, values + FLOW_U32S };
+
+    /* Metadata. */
+    if (flow->tunnel.ip_dst) {
+        miniflow_push_words(mf, tunnel, &flow->tunnel,
+                            sizeof flow->tunnel / 4);
+    }
+    miniflow_push_uint32_check(mf, skb_priority, flow->skb_priority);
+    miniflow_push_uint32_check(mf, pkt_mark, flow->pkt_mark);
+    miniflow_push_uint32_check(mf, recirc_id, flow->recirc_id);
+    miniflow_push_uint32(mf, in_port, odp_to_u32(flow->in_port.odp_port));
+
+    /* Link layer. */
+    miniflow_push_words(mf, dl_dst, &flow->dl_dst, ETH_ADDR_LEN * 2 / 4);
+    miniflow_push_be16(mf, dl_type, flow->dl_type);
+    miniflow_push_be16(mf, vlan_tci, flow->vlan_tci);
+
+    if (OVS_UNLIKELY(eth_type_mpls(flow->dl_type))) {
+        int count;
+
+        for (count = 0; count < FLOW_MAX_MPLS_LABELS; count++) {
+            if (mpls_lse_to_bos(flow->mpls_lse[count])) {
+                break;
+            }
+        }
+        count++;
+        miniflow_push_words(mf, mpls_lse, flow->mpls_lse, count);
+        goto out;
+    } else if (OVS_LIKELY(flow->dl_type == htons(ETH_TYPE_IP))) {
+        /* Push both source and destination address at once. */
+        miniflow_push_words(mf, nw_src, &flow->nw_src, 2);
+    } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
+        miniflow_push_words(mf, ipv6_src, &flow->ipv6_src,
+                            sizeof flow->ipv6_src / 4);
+        miniflow_push_words(mf, ipv6_dst, &flow->ipv6_dst,
+                            sizeof flow->ipv6_dst / 4);
+
+        miniflow_push_be32(mf, ipv6_label, flow->ipv6_label);
+    } else {
+        if (flow->dl_type == htons(ETH_TYPE_ARP) ||
+            flow->dl_type == htons(ETH_TYPE_RARP)) {
+
+            miniflow_push_words(mf, nw_src, &flow->nw_src, 1);
+            miniflow_push_words(mf, nw_dst, &flow->nw_dst, 1);
+            miniflow_push_be32(mf, nw_frag, htonl(flow->nw_proto));
+            miniflow_push_words(mf, arp_sha, &flow->arp_sha,
+                                ETH_ADDR_LEN * 2 / 4);
+        }
+        goto out;
+    }
+
+    miniflow_push_uint32(mf, nw_frag,
+                         BYTES_TO_BE32(flow->nw_frag, flow->nw_tos,
+                                       flow->nw_ttl, flow->nw_proto));
+
+    if (OVS_LIKELY(!(flow->nw_frag & FLOW_NW_FRAG_LATER))) {
+        if (OVS_LIKELY(flow->nw_proto == IPPROTO_TCP)) {
+            miniflow_push_words(mf, tcp_flags, &flow->tcp_flags, 1);
+            miniflow_push_words(mf, tp_src, &flow->tp_src, 1);
+        } else if (OVS_LIKELY(flow->nw_proto == IPPROTO_UDP)) {
+            miniflow_push_words(mf, tp_src, &flow->tp_src, 1);
+        } else if (OVS_LIKELY(flow->nw_proto == IPPROTO_SCTP)) {
+            miniflow_push_words(mf, tp_src, &flow->tp_src, 1);
+        } else if (OVS_LIKELY(flow->nw_proto == IPPROTO_ICMP)) {
+            miniflow_push_words(mf, tp_src, &flow->tp_src, 1);
+        } else if (OVS_LIKELY(flow->nw_proto == IPPROTO_IGMP)) {
+            miniflow_push_words(mf, tp_src, &flow->tp_src, 1);
+            miniflow_push_be32(mf, igmp_group_ip4, flow->igmp_group_ip4);
+        } else if (OVS_LIKELY(flow->nw_proto == IPPROTO_ICMPV6)) {
+            miniflow_push_words(mf, arp_sha, &flow->arp_sha,
+                                ETH_ADDR_LEN * 2 / 4);
+            if (!ipv6_addr_equals(&flow->nd_target, &in6addr_any)) {
+                miniflow_push_words(mf, nd_target, &flow->nd_target,
+                                    sizeof flow->nd_target / 4);
+            }
+            miniflow_push_words(mf, tp_src, &flow->tp_src, 1);
+        }
+    }
+    miniflow_push_uint32_check(mf, dp_hash, flow->dp_hash);
+ out:
+    dst->map = mf.map;
+}
+
 /* For every bit of a field that is wildcarded in 'wildcards', sets the
  * corresponding bit in 'flow' to zero. */
 void
diff --git a/lib/flow.h b/lib/flow.h
index b9c9f1b..9bb9a58 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -444,6 +444,7 @@ struct pkt_metadata;
  * indicate which fields were extracted. */
 void miniflow_extract(struct ofpbuf *packet, const struct pkt_metadata *,
                       struct miniflow *dst);
+void miniflow_extract_from_flow(struct miniflow *dst, const struct flow *);
 void miniflow_init(struct miniflow *, const struct flow *);
 void miniflow_init_with_minimask(struct miniflow *, const struct flow *,
                                  const struct minimask *);
-- 
1.7.10.4




More information about the dev mailing list