dpif-netdev: Use miniflow as a flow key.
authorJarno Rajahalme <jrajahalme@nicira.com>
Fri, 18 Apr 2014 15:26:57 +0000 (08:26 -0700)
committerJarno Rajahalme <jrajahalme@nicira.com>
Fri, 18 Apr 2014 15:39:44 +0000 (08:39 -0700)
Use miniflow as a flow key in the userspace datapath classifier.  The
miniflow is expanded for upcalls, but for existing datapath flows, the
key need not be expanded.

Signed-off-by: Jarno Rajahalme <jrajahalme@nicira.com>
Reviewed-by: YAMAMOTO Takashi <yamamoto@valinux.co.jp>
lib/dpif-netdev.c
lib/flow.c
lib/flow.h

index 76141e3..790fe23 100644 (file)
@@ -353,10 +353,11 @@ static int dpif_netdev_open(const struct dpif_class *, const char *name,
                             bool create, struct dpif **);
 static int dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *,
                                       int queue_no, int type,
-                                      const struct flow *,
+                                      const struct miniflow *,
                                       const struct nlattr *userdata);
 static void dp_netdev_execute_actions(struct dp_netdev *dp,
-                                      const struct flow *, struct ofpbuf *, bool may_steal,
+                                      const struct miniflow *,
+                                      struct ofpbuf *, bool may_steal,
                                       struct pkt_metadata *,
                                       const struct nlattr *actions,
                                       size_t actions_len);
@@ -1063,13 +1064,15 @@ dp_netdev_flow_cast(const struct cls_rule *cr)
 }
 
 static struct dp_netdev_flow *
-dp_netdev_lookup_flow(const struct dp_netdev *dp, const struct flow *flow)
+dp_netdev_lookup_flow(const struct dp_netdev *dp, const struct miniflow *key)
     OVS_EXCLUDED(dp->cls.rwlock)
 {
     struct dp_netdev_flow *netdev_flow;
+    struct cls_rule *rule;
 
     fat_rwlock_rdlock(&dp->cls.rwlock);
-    netdev_flow = dp_netdev_flow_cast(classifier_lookup(&dp->cls, flow, NULL));
+    rule = classifier_lookup_miniflow_first(&dp->cls, key);
+    netdev_flow = dp_netdev_flow_cast(rule);
     fat_rwlock_unlock(&dp->cls.rwlock);
 
     return netdev_flow;
@@ -1294,6 +1297,7 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put)
     struct dp_netdev *dp = get_dp_netdev(dpif);
     struct dp_netdev_flow *netdev_flow;
     struct flow flow;
+    struct miniflow miniflow;
     struct flow_wildcards wc;
     int error;
 
@@ -1307,9 +1311,10 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put)
     if (error) {
         return error;
     }
+    miniflow_init(&miniflow, &flow);
 
     ovs_mutex_lock(&dp->flow_mutex);
-    netdev_flow = dp_netdev_lookup_flow(dp, &flow);
+    netdev_flow = dp_netdev_lookup_flow(dp, &miniflow);
     if (!netdev_flow) {
         if (put->flags & DPIF_FP_CREATE) {
             if (hmap_count(&dp->flow_table) < MAX_FLOWS) {
@@ -1522,7 +1527,8 @@ dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute)
 {
     struct dp_netdev *dp = get_dp_netdev(dpif);
     struct pkt_metadata *md = &execute->md;
-    struct flow key;
+    struct miniflow key;
+    uint32_t buf[FLOW_U32S];
 
     if (ofpbuf_size(execute->packet) < ETH_HEADER_LEN ||
         ofpbuf_size(execute->packet) > UINT16_MAX) {
@@ -1530,7 +1536,8 @@ dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute)
     }
 
     /* Extract flow key. */
-    flow_extract(execute->packet, md, &key);
+    miniflow_initialize(&key, buf);
+    miniflow_extract(execute->packet, md, &key);
 
     ovs_rwlock_rdlock(&dp->port_rwlock);
     dp_netdev_execute_actions(dp, &key, execute->packet, false, md,
@@ -1963,9 +1970,9 @@ dp_netdev_flow_stats_new_cb(void)
 static void
 dp_netdev_flow_used(struct dp_netdev_flow *netdev_flow,
                     const struct ofpbuf *packet,
-                    const struct flow *key)
+                    const struct miniflow *key)
 {
-    uint16_t tcp_flags = ntohs(key->tcp_flags);
+    uint16_t tcp_flags = miniflow_get_tcp_flags(key);
     long long int now = time_msec();
     struct dp_netdev_flow_stats *bucket;
 
@@ -2005,13 +2012,16 @@ dp_netdev_input(struct dp_netdev *dp, struct ofpbuf *packet,
     OVS_REQ_RDLOCK(dp->port_rwlock)
 {
     struct dp_netdev_flow *netdev_flow;
-    struct flow key;
+    struct miniflow key;
+    uint32_t buf[FLOW_U32S];
 
     if (ofpbuf_size(packet) < ETH_HEADER_LEN) {
         ofpbuf_delete(packet);
         return;
     }
-    flow_extract(packet, md, &key);
+    miniflow_initialize(&key, buf);
+    miniflow_extract(packet, md, &key);
+
     netdev_flow = dp_netdev_lookup_flow(dp, &key);
     if (netdev_flow) {
         struct dp_netdev_actions *actions;
@@ -2025,7 +2035,8 @@ dp_netdev_input(struct dp_netdev *dp, struct ofpbuf *packet,
     } else if (dp->handler_queues) {
         dp_netdev_count_packet(dp, DP_STAT_MISS);
         dp_netdev_output_userspace(dp, packet,
-                                   flow_hash_5tuple(&key, 0) % dp->n_handlers,
+                                   miniflow_hash_5tuple(&key, 0)
+                                   % dp->n_handlers,
                                    DPIF_UC_MISS, &key, NULL);
         ofpbuf_delete(packet);
     }
@@ -2044,7 +2055,7 @@ dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet,
 
 static int
 dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet,
-                           int queue_no, int type, const struct flow *flow,
+                           int queue_no, int type, const struct miniflow *key,
                            const struct nlattr *userdata)
 {
     struct dp_netdev_queue *q;
@@ -2058,6 +2069,7 @@ dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet,
         struct dpif_upcall *upcall = &u->upcall;
         struct ofpbuf *buf = &u->buf;
         size_t buf_size;
+        struct flow flow;
 
         upcall->type = type;
 
@@ -2070,7 +2082,8 @@ dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet,
         ofpbuf_init(buf, buf_size);
 
         /* Put ODP flow. */
-        odp_flow_key_from_flow(buf, flow, flow->in_port.odp_port);
+        miniflow_expand(key, &flow);
+        odp_flow_key_from_flow(buf, &flow, flow.in_port.odp_port);
         upcall->key = ofpbuf_data(buf);
         upcall->key_len = ofpbuf_size(buf);
 
@@ -2099,7 +2112,7 @@ dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet,
 
 struct dp_netdev_execute_aux {
     struct dp_netdev *dp;
-    const struct flow *key;
+    const struct miniflow *key;
 };
 
 static void
@@ -2127,7 +2140,7 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet,
         userdata = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA);
 
         dp_netdev_output_userspace(aux->dp, packet,
-                                   flow_hash_5tuple(aux->key, 0)
+                                   miniflow_hash_5tuple(aux->key, 0)
                                        % aux->dp->n_handlers,
                                    DPIF_UC_ACTION, aux->key,
                                    userdata);
@@ -2144,8 +2157,9 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet,
 
         hash_act = nl_attr_get(a);
         if (hash_act->hash_alg == OVS_HASH_ALG_L4) {
-
-            hash = flow_hash_symmetric_l4(aux->key, hash_act->hash_bias);
+            /* Hash need not be symmetric, nor does it need to include
+             * L2 fields. */
+            hash = miniflow_hash_5tuple(aux->key, hash_act->hash_bias);
             if (!hash) {
                 hash = 1; /* 0 is not valid */
             }
@@ -2190,7 +2204,7 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet,
 }
 
 static void
-dp_netdev_execute_actions(struct dp_netdev *dp, const struct flow *key,
+dp_netdev_execute_actions(struct dp_netdev *dp, const struct miniflow *key,
                           struct ofpbuf *packet, bool may_steal,
                           struct pkt_metadata *md,
                           const struct nlattr *actions, size_t actions_len)
index 8319dde..093dec8 100644 (file)
@@ -943,10 +943,38 @@ flow_wildcards_set_reg_mask(struct flow_wildcards *wc, int idx, uint32_t mask)
     wc->masks.regs[idx] = mask;
 }
 
+/* Calculates the 5-tuple hash from the given flow. */
+uint32_t
+miniflow_hash_5tuple(const struct miniflow *flow, uint32_t basis)
+{
+    uint32_t hash = 0;
+
+    if (!flow) {
+        return 0;
+    }
+
+    hash = mhash_add(basis,
+                     miniflow_get_u32(flow, offsetof(struct flow, nw_src)));
+    hash = mhash_add(hash,
+                     miniflow_get_u32(flow, offsetof(struct flow, nw_dst)));
+    hash = mhash_add(hash,
+                     miniflow_get_u32(flow, offsetof(struct flow, tp_src)));
+    hash = mhash_add(hash,
+                     miniflow_get_u8(flow, offsetof(struct flow, nw_proto)));
+
+    return mhash_finish(hash, 13);
+}
+
+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);
+
 /* Calculates the 5-tuple hash from the given flow. */
 uint32_t
 flow_hash_5tuple(const struct flow *flow, uint32_t basis)
 {
+    const uint32_t *flow_u32 = (const uint32_t *)flow;
     uint32_t hash = 0;
 
     if (!flow) {
@@ -955,8 +983,7 @@ flow_hash_5tuple(const struct flow *flow, uint32_t basis)
 
     hash = mhash_add(basis, (OVS_FORCE uint32_t) flow->nw_src);
     hash = mhash_add(hash, (OVS_FORCE uint32_t) flow->nw_dst);
-    hash = mhash_add(hash, ((OVS_FORCE uint32_t) flow->tp_src << 16)
-                           | (OVS_FORCE uint32_t) flow->tp_dst);
+    hash = mhash_add(hash, flow_u32[offsetof(struct flow, tp_src) / 4]);
     hash = mhash_add(hash, flow->nw_proto);
 
     return mhash_finish(hash, 13);
index e8066aa..413ecb5 100644 (file)
@@ -444,6 +444,7 @@ static inline ovs_be32 miniflow_get_be32(const struct miniflow *,
 static inline uint16_t miniflow_get_vid(const struct miniflow *);
 static inline uint16_t miniflow_get_tcp_flags(const struct miniflow *);
 static inline ovs_be64 miniflow_get_metadata(const struct miniflow *);
+static inline uint8_t miniflow_get_u8(const struct miniflow *, unsigned int ofs);
 
 bool miniflow_equal(const struct miniflow *a, const struct miniflow *b);
 bool miniflow_equal_in_minimask(const struct miniflow *a,
@@ -458,6 +459,7 @@ uint32_t miniflow_hash_in_minimask(const struct miniflow *,
 uint64_t miniflow_get_map_in_range(const struct miniflow *miniflow,
                                    uint8_t start, uint8_t end,
                                    unsigned int *offset);
+uint32_t miniflow_hash_5tuple(const struct miniflow *flow, uint32_t basis);
 
 \f
 /* Compressed flow wildcards. */