[ovs-dev] [DPDK Upcalls v2 3/3] dpif-netdev: Streamline miss handling.

Ethan Jackson ethan at nicira.com
Thu Aug 7 02:40:25 UTC 2014


This patch avoids the relatively inefficient miss handling processes
dictated by the dpif process, by calling into ofproto-dpif directly
through a callback.

Signed-off-by: Ethan Jackson <ethan at nicira.com>
---
 lib/dpif-netdev.c             | 299 ++++++++++++++++++++++++------------------
 lib/dpif-provider.h           |   5 +-
 lib/dpif.c                    |   4 +-
 lib/dpif.h                    |  18 ++-
 ofproto/ofproto-dpif-upcall.c | 109 ++++++---------
 tests/dpif-netdev.at          |  10 +-
 tests/ofproto-dpif.at         |  54 ++++----
 7 files changed, 262 insertions(+), 237 deletions(-)

diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index c637d9f..d4a30bb 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -85,14 +85,7 @@ static struct ovs_mutex dp_netdev_mutex = OVS_MUTEX_INITIALIZER;
 static struct shash dp_netdevs OVS_GUARDED_BY(dp_netdev_mutex)
     = SHASH_INITIALIZER(&dp_netdevs);
 
-struct dp_netdev_queue {
-    unsigned int packet_count;
-
-    struct dpif_upcall upcalls[NETDEV_MAX_RX_BATCH];
-    struct ofpbuf bufs[NETDEV_MAX_RX_BATCH];
-};
-
-#define DP_NETDEV_QUEUE_INITIALIZER { .packet_count = 0 }
+static struct vlog_rate_limit upcall_rl = VLOG_RATE_LIMIT_INIT(600, 600);
 
 /* Datapath based on the network device interface from netdev.h.
  *
@@ -140,7 +133,8 @@ struct dp_netdev {
     /* Protects access to ofproto-dpif-upcall interface during revalidator
      * thread synchronization. */
     struct fat_rwlock upcall_rwlock;
-    exec_upcall_cb *upcall_cb;  /* Callback function for executing upcalls. */
+    upcall_callback *upcall_cb;  /* Callback function for executing upcalls. */
+    void *upcall_aux;
 
     /* Forwarding threads. */
     struct latch exit_latch;
@@ -320,12 +314,6 @@ static void do_del_port(struct dp_netdev *dp, struct dp_netdev_port *)
     OVS_REQUIRES(dp->port_mutex);
 static int dpif_netdev_open(const struct dpif_class *, const char *name,
                             bool create, struct dpif **);
-static int dp_netdev_queue_userspace_packet(struct dp_netdev_queue *,
-                                            struct ofpbuf *, int type,
-                                            const struct miniflow *,
-                                            const struct nlattr *);
-static void dp_netdev_execute_userspace_queue(struct dp_netdev_queue *,
-                                              struct dp_netdev *);
 static void dp_netdev_execute_actions(struct dp_netdev *dp,
                                       struct dpif_packet **, int c,
                                       bool may_steal, struct pkt_metadata *,
@@ -474,6 +462,7 @@ create_dp_netdev(const char *name, const struct dpif_class *class,
 
     /* Disable upcalls by default. */
     dp_netdev_disable_upcall(dp);
+    dp->upcall_aux = NULL;
     dp->upcall_cb = NULL;
 
     ovs_mutex_lock(&dp->port_mutex);
@@ -1232,6 +1221,35 @@ dp_netdev_flow_add(struct dp_netdev *dp, struct match *match,
     classifier_insert(&dp->cls,
                       CONST_CAST(struct cls_rule *, &netdev_flow->cr));
 
+    if (OVS_UNLIKELY(VLOG_IS_DBG_ENABLED())) {
+        struct ds ds = DS_EMPTY_INITIALIZER;
+        struct ofpbuf key, mask;
+
+        ofpbuf_init(&key, 0);
+        ofpbuf_init(&mask, 0);
+
+        ds_put_cstr(&ds, "flow_add: ");
+
+        odp_flow_key_from_flow(&key, &match->flow, &match->wc.masks,
+                               match->flow.in_port.odp_port, true);
+
+        odp_flow_key_from_mask(&mask, &match->wc.masks, &match->flow,
+                               odp_to_u32(match->wc.masks.in_port.odp_port),
+                               SIZE_MAX, true);
+
+        odp_flow_format(ofpbuf_data(&key), ofpbuf_size(&key),
+                        ofpbuf_data(&mask), ofpbuf_size(&mask), NULL, &ds,
+                        true);
+
+        ds_put_cstr(&ds, ", actions:");
+        format_odp_actions(&ds, actions, actions_len);
+        VLOG_DBG("%s", ds_cstr(&ds));
+
+        ds_destroy(&ds);
+        ofpbuf_uninit(&key);
+        ofpbuf_uninit(&mask);
+    }
+
     return 0;
 }
 
@@ -1822,6 +1840,44 @@ dp_netdev_count_packet(struct dp_netdev *dp, enum dp_stat_type type, int cnt)
     ovs_mutex_unlock(&bucket->mutex);
 }
 
+static int
+dp_netdev_upcall(struct dp_netdev *dp, struct dpif_packet *packet_,
+                 struct flow *flow, struct flow_wildcards *wc,
+                 enum dpif_upcall_type type, const struct nlattr *userdata,
+                 struct ofpbuf *actions, struct ofpbuf *put_actions)
+{
+    struct ofpbuf *packet = &packet_->ofpbuf;
+
+    if (type == DPIF_UC_MISS) {
+        dp_netdev_count_packet(dp, DP_STAT_MISS, 1);
+    }
+
+    if (OVS_UNLIKELY(!VLOG_DROP_DBG(&upcall_rl))) {
+        struct ds ds = DS_EMPTY_INITIALIZER;
+        struct ofpbuf key;
+        char *packet_str;
+
+        ofpbuf_init(&key, 0);
+        odp_flow_key_from_flow(&key, flow, &wc->masks, flow->in_port.odp_port,
+                               true);
+
+        packet_str = ofp_packet_to_string(ofpbuf_data(packet),
+                                          ofpbuf_size(packet));
+
+        odp_flow_key_format(ofpbuf_data(&key), ofpbuf_size(&key), &ds);
+
+        VLOG_DBG("%s: %s upcall:\n%s\n%s", dp->name,
+                 dpif_upcall_type_to_string(type), ds_cstr(&ds), packet_str);
+
+        ofpbuf_uninit(&key);
+        free(packet_str);
+        ds_destroy(&ds);
+    }
+
+    return dp->upcall_cb(packet, flow, wc, type, userdata, actions,
+                         put_actions, dp->upcall_aux);
+}
+
 struct packet_batch {
     unsigned int packet_count;
     unsigned int byte_count;
@@ -1876,12 +1932,12 @@ static void
 dp_netdev_input(struct dp_netdev *dp, struct dpif_packet **packets, int cnt,
                 struct pkt_metadata *md)
 {
-    struct dp_netdev_queue q = DP_NETDEV_QUEUE_INITIALIZER;
     struct packet_batch batches[NETDEV_MAX_RX_BATCH];
     struct netdev_flow_key keys[NETDEV_MAX_RX_BATCH];
     const struct miniflow *mfs[NETDEV_MAX_RX_BATCH]; /* NULL at bad packets. */
     struct cls_rule *rules[NETDEV_MAX_RX_BATCH];
     size_t n_batches, i;
+    bool may_miss;
 
     for (i = 0; i < cnt; i++) {
         if (OVS_UNLIKELY(ofpbuf_size(&packets[i]->ofpbuf) < ETH_HEADER_LEN)) {
@@ -1895,7 +1951,72 @@ dp_netdev_input(struct dp_netdev *dp, struct dpif_packet **packets, int cnt,
         mfs[i] = &keys[i].flow;
     }
 
-    classifier_lookup_miniflow_batch(&dp->cls, mfs, rules, cnt);
+    may_miss = !classifier_lookup_miniflow_batch(&dp->cls, mfs, rules, cnt);
+    if (OVS_UNLIKELY(may_miss) && !fat_rwlock_tryrdlock(&dp->upcall_rwlock)) {
+        uint64_t actions_stub[512 / 8], slow_stub[512 / 8];
+        struct ofpbuf actions, put_actions;
+        struct match match;
+
+        ofpbuf_use_stub(&actions, actions_stub, sizeof actions_stub);
+        ofpbuf_use_stub(&put_actions, slow_stub, sizeof slow_stub);
+
+        for (i = 0; i < cnt; i++) {
+            const struct dp_netdev_flow *netdev_flow;
+            struct ofpbuf *add_actions;
+
+            if (OVS_LIKELY(rules[i] || !mfs[i])) {
+                continue;
+            }
+
+            /* It's possible that an earlier slow path execution installed
+             * the rule this flow needs.  In this case, it's a lot cheaper
+             * to catch it here than execute a miss. */
+            netdev_flow = dp_netdev_lookup_flow(dp, mfs[i]);
+            if (netdev_flow) {
+                rules[i] = CONST_CAST(struct cls_rule *, &netdev_flow->cr);
+                continue;
+            }
+
+            miniflow_expand(mfs[i], &match.flow);
+            flow_wildcards_init_catchall(&match.wc);
+
+            ofpbuf_clear(&actions);
+            ofpbuf_clear(&put_actions);
+
+            if (dp_netdev_upcall(dp, packets[i], &match.flow, &match.wc,
+                                 DPIF_UC_MISS, NULL, &actions, &put_actions)) {
+                continue;
+            }
+
+            /* We can't allow the packet batching in the next loop to execute
+             * the actions.  Otherwise, if there are any slow path actions,
+             * we'll send the packet up twice. */
+            dp_netdev_execute_actions(dp, &packets[i], 1, false, md,
+                                      ofpbuf_data(&actions),
+                                      ofpbuf_size(&actions));
+
+            add_actions = ofpbuf_size(&put_actions)
+                ? &put_actions
+                : &actions;
+
+            ovs_mutex_lock(&dp->flow_mutex);
+            /* XXX: There's a brief race where this flow could have already
+             * been installed since we last did the flow lookup.  This could be
+             * solved by moving the mutex lock outside the loop, but that's an
+             * awful long time to be locking everyone out of making flow
+             * installs.  If we move to a per-core classifier, it would be
+             * reasonable. */
+            if (!dp_netdev_lookup_flow(dp, mfs[i])) {
+                dp_netdev_flow_add(dp, &match, ofpbuf_data(add_actions),
+                                   ofpbuf_size(add_actions));
+            }
+            ovs_mutex_unlock(&dp->flow_mutex);
+        }
+
+        ofpbuf_uninit(&actions);
+        ofpbuf_uninit(&put_actions);
+        fat_rwlock_unlock(&dp->upcall_rwlock);
+    }
 
     n_batches = 0;
     for (i = 0; i < cnt; i++) {
@@ -1903,17 +2024,7 @@ dp_netdev_input(struct dp_netdev *dp, struct dpif_packet **packets, int cnt,
         struct packet_batch *batch;
         size_t j;
 
-        if (OVS_UNLIKELY(!mfs[i])) {
-            continue;
-        }
-
-        if (OVS_UNLIKELY(!rules[i])) {
-            struct ofpbuf *buf = &packets[i]->ofpbuf;
-
-            dp_netdev_count_packet(dp, DP_STAT_MISS, 1);
-            dp_netdev_queue_userspace_packet(&q, buf, DPIF_UC_MISS,
-                                             mfs[i], NULL);
-            dpif_packet_delete(packets[i]);
+        if (OVS_UNLIKELY(!rules[i] || !mfs[i])) {
             continue;
         }
 
@@ -1942,10 +2053,6 @@ dp_netdev_input(struct dp_netdev *dp, struct dpif_packet **packets, int cnt,
     for (i = 0; i < n_batches; i++) {
         packet_batch_execute(&batches[i], dp);
     }
-
-    if (q.packet_count) {
-        dp_netdev_execute_userspace_queue(&q, dp);
-    }
 }
 
 static void
@@ -1959,86 +2066,16 @@ dp_netdev_port_input(struct dp_netdev *dp, struct dpif_packet **packets,
     dp_netdev_input(dp, packets, cnt, &md);
 }
 
-static int
-dp_netdev_queue_userspace_packet(struct dp_netdev_queue *q,
-                                 struct ofpbuf *packet, int type,
-                                 const struct miniflow *key,
-                                 const struct nlattr *userdata)
-{
-    if (q->packet_count < NETDEV_MAX_RX_BATCH) {
-        int cnt = q->packet_count;
-        struct dpif_upcall *upcall = &q->upcalls[cnt];
-        struct ofpbuf *buf = &q->bufs[cnt];
-        size_t buf_size;
-        struct flow flow;
-        void *data;
-
-        upcall->type = type;
-
-        /* Allocate buffer big enough for everything. */
-        buf_size = ODPUTIL_FLOW_KEY_BYTES;
-        if (userdata) {
-            buf_size += NLA_ALIGN(userdata->nla_len);
-        }
-        buf_size += ofpbuf_size(packet);
-        ofpbuf_init(buf, buf_size);
-
-        /* Put ODP flow. */
-        miniflow_expand(key, &flow);
-        odp_flow_key_from_flow(buf, &flow, NULL, flow.in_port.odp_port, true);
-        upcall->key = ofpbuf_data(buf);
-        upcall->key_len = ofpbuf_size(buf);
-
-        /* Put userdata. */
-        if (userdata) {
-            upcall->userdata = ofpbuf_put(buf, userdata,
-                                          NLA_ALIGN(userdata->nla_len));
-        }
-
-        /* We have to perform a copy of the packet, because we cannot send DPDK
-         * mbufs to a non pmd thread. When the upcall processing will be done
-         * in the pmd thread, this copy can be avoided */
-        data = ofpbuf_put(buf, ofpbuf_data(packet), ofpbuf_size(packet));
-        ofpbuf_use_stub(&upcall->packet, data, ofpbuf_size(packet));
-        ofpbuf_set_size(&upcall->packet, ofpbuf_size(packet));
-
-        q->packet_count++;
-        return 0;
-    } else {
-        return ENOBUFS;
-    }
-}
-
-static void
-dp_netdev_execute_userspace_queue(struct dp_netdev_queue *q,
-                                  struct dp_netdev *dp)
-{
-    struct dpif_upcall *upcalls = q->upcalls;
-    struct ofpbuf *bufs = q->bufs;
-    int cnt = q->packet_count;
-
-    if (!fat_rwlock_tryrdlock(&dp->upcall_rwlock)) {
-        ovs_assert(dp->upcall_cb);
-        dp->upcall_cb(dp->dpif, upcalls, bufs, cnt);
-        fat_rwlock_unlock(&dp->upcall_rwlock);
-    } else {
-        int i;
-
-        for (i = 0; i < cnt; i++) {
-            ofpbuf_uninit(&bufs[i]);
-            ofpbuf_uninit(&upcalls[i].packet);
-        }
-    }
-}
-
 struct dp_netdev_execute_aux {
     struct dp_netdev *dp;
 };
 
 static void
-dpif_netdev_register_upcall_cb(struct dpif *dpif, exec_upcall_cb *cb)
+dpif_netdev_register_upcall_cb(struct dpif *dpif, upcall_callback *cb,
+                               void *aux)
 {
     struct dp_netdev *dp = get_dp_netdev(dpif);
+    dp->upcall_aux = aux;
     dp->upcall_cb = cb;
 }
 
@@ -2049,14 +2086,15 @@ dp_execute_cb(void *aux_, struct dpif_packet **packets, int cnt,
     OVS_NO_THREAD_SAFETY_ANALYSIS
 {
     struct dp_netdev_execute_aux *aux = aux_;
+    uint32_t *depth = recirc_depth_get();
+    struct dp_netdev *dp = aux->dp;
     int type = nl_attr_type(a);
     struct dp_netdev_port *p;
-    uint32_t *depth = recirc_depth_get();
     int i;
 
     switch ((enum ovs_action_attr)type) {
     case OVS_ACTION_ATTR_OUTPUT:
-        p = dp_netdev_lookup_port(aux->dp, u32_to_odp(nl_attr_get_u32(a)));
+        p = dp_netdev_lookup_port(dp, u32_to_odp(nl_attr_get_u32(a)));
         if (OVS_LIKELY(p)) {
             netdev_send(p->netdev, packets, cnt, may_steal);
         } else if (may_steal) {
@@ -2066,35 +2104,36 @@ dp_execute_cb(void *aux_, struct dpif_packet **packets, int cnt,
         }
         break;
 
-    case OVS_ACTION_ATTR_USERSPACE: {
-        const struct nlattr *userdata;
-        struct netdev_flow_key key;
-        struct dp_netdev_queue q = DP_NETDEV_QUEUE_INITIALIZER;
-
-        userdata = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA);
-
-        miniflow_initialize(&key.flow, key.buf);
-
-        for (i = 0; i < cnt; i++) {
-            struct ofpbuf *packet;
+    case OVS_ACTION_ATTR_USERSPACE:
+        if (!fat_rwlock_tryrdlock(&dp->upcall_rwlock)) {
+            const struct nlattr *userdata;
+            struct ofpbuf actions;
+            struct flow flow;
 
-            packet = &packets[i]->ofpbuf;
+            userdata = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA);
+            ofpbuf_init(&actions, 0);
 
-            miniflow_extract(packet, md, &key.flow);
+            for (i = 0; i < cnt; i++) {
+                ofpbuf_clear(&actions);
+
+                flow_extract(&packets[i]->ofpbuf, md, &flow);
+                if (!dp_netdev_upcall(dp, packets[i], &flow, NULL,
+                                      DPIF_UC_ACTION, userdata, &actions,
+                                      NULL)) {
+                    dp_netdev_execute_actions(dp, &packets[i], 1, false, md,
+                                              ofpbuf_data(&actions),
+                                              ofpbuf_size(&actions));
+                }
 
-            dp_netdev_queue_userspace_packet(&q, packet,
-                                             DPIF_UC_ACTION, &key.flow,
-                                             userdata);
-            if (may_steal) {
-                dpif_packet_delete(packets[i]);
+                if (may_steal) {
+                    dpif_packet_delete(packets[i]);
+                }
             }
+            ofpbuf_uninit(&actions);
+            fat_rwlock_unlock(&dp->upcall_rwlock);
         }
 
-        if (q.packet_count) {
-            dp_netdev_execute_userspace_queue(&q, aux->dp);
-        }
         break;
-    }
 
     case OVS_ACTION_ATTR_HASH: {
         const struct ovs_action_hash *hash_act;
@@ -2148,7 +2187,7 @@ dp_execute_cb(void *aux_, struct dpif_packet **packets, int cnt,
                 /* Hash is private to each packet */
                 recirc_md.dp_hash = packets[i]->dp_hash;
 
-                dp_netdev_input(aux->dp, &recirc_pkt, 1, &recirc_md);
+                dp_netdev_input(dp, &recirc_pkt, 1, &recirc_md);
             }
             (*depth)--;
 
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index bf24a9d..478a08b 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -419,8 +419,9 @@ struct dpif_class {
      * to register an upcall function and enable / disable upcalls.
      *
      * Registers an upcall callback function with 'dpif'. This is only used if
-     * if 'dpif' directly executes upcall functions. */
-    void (*register_upcall_cb)(struct dpif *, exec_upcall_cb *);
+     * if 'dpif' directly executes upcall functions. 'aux' is passed to the
+     * callback on invocation. */
+    void (*register_upcall_cb)(struct dpif *, upcall_callback *, void *aux);
 
     /* Enables upcalls if 'dpif' directly executes upcall functions. */
     void (*enable_upcall)(struct dpif *);
diff --git a/lib/dpif.c b/lib/dpif.c
index 43141df..c428530 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -1349,10 +1349,10 @@ dpif_handlers_set(struct dpif *dpif, uint32_t n_handlers)
 }
 
 void
-dpif_register_upcall_cb(struct dpif *dpif, exec_upcall_cb *cb)
+dpif_register_upcall_cb(struct dpif *dpif, upcall_callback *cb, void *aux)
 {
     if (dpif->dpif_class->register_upcall_cb) {
-        dpif->dpif_class->register_upcall_cb(dpif, cb);
+        dpif->dpif_class->register_upcall_cb(dpif, cb, aux);
     }
 }
 
diff --git a/lib/dpif.h b/lib/dpif.h
index f4a2a9e..4fb49d4 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -399,12 +399,13 @@ extern "C" {
 #endif
 
 struct dpif;
+struct dpif_class;
+struct dpif_flow;
 struct ds;
 struct flow;
+struct flow_wildcards;
 struct nlattr;
 struct sset;
-struct dpif_class;
-struct dpif_flow;
 
 int dp_register_provider(const struct dpif_class *);
 int dp_unregister_provider(const char *type);
@@ -670,8 +671,16 @@ struct dpif_upcall {
     struct nlattr *userdata;    /* Argument to OVS_ACTION_ATTR_USERSPACE. */
 };
 
-typedef void exec_upcall_cb(struct dpif *, struct dpif_upcall *,
-                            struct ofpbuf *, int cnt);
+/* Called by dpif-netdev to process upcalls for flow misses.  Optionally
+ * populates a wildcard mask in 'wc'.  The datapath will execute, and
+ * if 'type' is DPIF_UC_MISS, install 'actions.  May provide 'put_actions',
+ * which if populated the datapath will install instead of 'actions'. */
+typedef int upcall_callback(const struct ofpbuf *packet, const struct flow *flow,
+                            struct flow_wildcards *wc, enum dpif_upcall_type,
+                            const struct nlattr *userdata,
+                            struct ofpbuf *actions, struct ofpbuf *put_actions,
+                            void *aux);
+void dpif_register_upcall_cb(struct dpif *, upcall_callback *, void *aux);
 
 int dpif_recv_set(struct dpif *, bool enable);
 int dpif_handlers_set(struct dpif *, uint32_t n_handlers);
@@ -679,7 +688,6 @@ int dpif_recv(struct dpif *, uint32_t handler_id, struct dpif_upcall *,
               struct ofpbuf *);
 void dpif_recv_purge(struct dpif *);
 void dpif_recv_wait(struct dpif *, uint32_t handler_id);
-void dpif_register_upcall_cb(struct dpif *, exec_upcall_cb *);
 void dpif_enable_upcall(struct dpif *);
 void dpif_disable_upcall(struct dpif *);
 
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index bf10dec..4c7835b 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -246,9 +246,10 @@ static void ukey_delete(struct revalidator *, struct udpif_key *);
 static enum upcall_type classify_upcall(enum dpif_upcall_type type,
                                         const struct nlattr *userdata);
 
-static void exec_upcalls(struct dpif *, struct dpif_upcall *, struct ofpbuf *,
-                         int cnt);
-
+static int upcall_cb(const struct ofpbuf *packet, const struct flow *flow,
+                     struct flow_wildcards *wc, enum dpif_upcall_type,
+                     const struct nlattr *userdata, struct ofpbuf *actions,
+                     struct ofpbuf *put_actions, void *aux);
 static int upcall_receive(struct upcall *, const struct dpif_backer *,
                           const struct ofpbuf *packet, enum dpif_upcall_type,
                           const struct nlattr *userdata, const struct flow *);
@@ -288,7 +289,7 @@ udpif_create(struct dpif_backer *backer, struct dpif *dpif)
     atomic_init(&udpif->n_flows_timestamp, LLONG_MIN);
     ovs_mutex_init(&udpif->n_flows_mutex);
 
-    dpif_register_upcall_cb(dpif, exec_upcalls);
+    dpif_register_upcall_cb(dpif, upcall_cb, udpif);
 
     return udpif;
 }
@@ -917,77 +918,53 @@ upcall_uninit(struct upcall *upcall)
     }
 }
 
-static struct udpif *
-find_udpif(struct dpif *dpif)
-{
-    struct udpif *udpif;
-
-    LIST_FOR_EACH (udpif, list_node, &all_udpifs) {
-        if (udpif->dpif == dpif) {
-            return udpif;
-        }
-    }
-    return NULL;
-}
 
-static void
-exec_upcalls(struct dpif *dpif, struct dpif_upcall *dupcalls,
-             struct ofpbuf *bufs OVS_UNUSED, int cnt)
+static int
+upcall_cb(const struct ofpbuf *packet, const struct flow *flow,
+          struct flow_wildcards *wc, enum dpif_upcall_type type,
+          const struct nlattr *userdata, struct ofpbuf *actions,
+          struct ofpbuf *put_actions, void *aux)
 {
-    struct upcall upcalls[UPCALL_MAX_BATCH];
-    struct udpif *udpif;
-    int i, j;
-
-    udpif = find_udpif(dpif);
-    ovs_assert(udpif);
-
-    for (i = 0; i < cnt; i += UPCALL_MAX_BATCH) {
-        size_t n_upcalls = 0;
-        for (j = i; j < MIN(i + UPCALL_MAX_BATCH, cnt); j++) {
-            struct upcall *upcall = &upcalls[n_upcalls];
-            struct dpif_upcall *dupcall = &dupcalls[j];
-            struct pkt_metadata md;
-            struct flow flow;
-            int error;
-
-            dpif_print_packet(dpif, dupcall);
-
-            if (odp_flow_key_to_flow(dupcall->key, dupcall->key_len, &flow)
-                == ODP_FIT_ERROR) {
-                continue;
-            }
-
-            error = upcall_receive(upcall, udpif->backer, &dupcall->packet,
-                                   dupcall->type, dupcall->userdata, &flow);
-            if (error) {
-                goto cleanup;
-            }
-
-            upcall->key = dupcall->key;
-            upcall->key_len = dupcall->key_len;
+    struct udpif *udpif = aux;
+    unsigned int flow_limit;
+    struct upcall upcall;
+    bool megaflow;
+    int error;
 
-            md = pkt_metadata_from_flow(&flow);
-            flow_extract(&dupcall->packet, &md, &flow);
+    atomic_read(&udpif->flow_limit, &flow_limit);
+    if (udpif_get_n_flows(udpif) >= flow_limit) {
+        return ENOSPC;
+    }
 
-            error = process_upcall(udpif, upcall, NULL);
-            if (error) {
-                goto cleanup;
-            }
+    error = upcall_receive(&upcall, udpif->backer, packet, type, userdata,
+                           flow);
+    if (error) {
+        goto out;
+    }
 
-            n_upcalls++;
-            continue;
+    error = process_upcall(udpif, &upcall, actions);
+    if (error) {
+        goto out;
+    }
 
-cleanup:
-            upcall_uninit(upcall);
-        }
+    if (upcall.xout.slow && put_actions) {
+        ofpbuf_put(put_actions, ofpbuf_data(&upcall.put_actions),
+                   ofpbuf_size(&upcall.put_actions));
+    }
 
-        if (n_upcalls) {
-            handle_upcalls(udpif, upcalls, n_upcalls);
-            for (j = 0; j < n_upcalls; j++) {
-                upcall_uninit(&upcalls[j]);
-            }
+    if (wc) {
+        atomic_read(&enable_megaflows, &megaflow);
+        if (megaflow) {
+            /* XXX: This could be avoided with sufficient API changes. */
+            memcpy(wc, &upcall.xout.wc, sizeof *wc);
+        } else {
+            memset(wc, 0xff, sizeof *wc);
         }
     }
+
+out:
+    upcall_uninit(&upcall);
+    return error;
 }
 
 static int
diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at
index f887452..0545ea7 100644
--- a/tests/dpif-netdev.at
+++ b/tests/dpif-netdev.at
@@ -9,8 +9,8 @@ m4_define([STRIP_XOUT], [[sed '
     s/bytes:[0-9]*/bytes:0/
 ' | sort]])
 m4_define([FILTER_FLOW_INSTALL], [[
-grep ' put' | sed '
-    s/.*put\[create\] //
+grep 'flow_add' | sed '
+    s/.*flow_add: //
 ' | sort | uniq]])
 m4_define([FILTER_FLOW_DUMP], [[
 grep 'flow_dump ' | sed '
@@ -32,7 +32,7 @@ OVS_VSWITCHD_START(
                   fail-mode=secure -- \
    add-port br1 p2 -- set interface p2 type=dummy options:stream=unix:$OVS_RUNDIR/p0.sock ofport_request=2 -- \
    add-port br1 p8 -- set interface p8 ofport_request=8 type=dummy --])
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 
 AT_CHECK([ovs-ofctl add-flow br0 action=normal])
 AT_CHECK([ovs-ofctl add-flow br1 action=normal])
@@ -58,7 +58,7 @@ OVS_VSWITCHD_START(
   [add-port br0 p1 -- set interface p1 type=dummy options:pstream=punix:$OVS_RUNDIR/p0.sock
    set bridge br0 datapath-type=dummy other-config:datapath-id=1234 \
                   fail-mode=secure])
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 
 AT_CHECK([ovs-ofctl add-flow br0 action=normal])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
@@ -93,7 +93,7 @@ OVS_VSWITCHD_START(
   [add-port br0 p1 -- set interface p1 type=dummy options:pstream=punix:$OVS_RUNDIR/p0.sock
    set bridge br0 datapath-type=dummy other-config:datapath-id=1234 \
                   fail-mode=secure])
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 
 AT_CHECK([ovs-ofctl add-flow br0 action=normal])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 0253cb0..c1f6719 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -23,7 +23,7 @@ OVS_VSWITCHD_START(
    add-port br1 p4 -- set interface p4 type=dummy options:stream=unix:$OVS_RUNDIR/p2.sock ofport_request=4 -- \
    add-port br1 p8 -- set interface p8 ofport_request=8 type=dummy --])
 WAIT_FOR_DUMMY_PORTS([p3], [p4])
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 
 AT_CHECK([ovs-ofctl add-flow br0 action=normal])
 AT_CHECK([ovs-ofctl add-flow br1 action=normal])
@@ -4611,7 +4611,7 @@ AT_SETUP([ofproto-dpif - MPLS actions that result in a userspace action])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ON_EXIT([kill `cat ovs-ofctl.pid`])
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
@@ -4648,7 +4648,7 @@ AT_SETUP([ofproto-dpif - MPLS actions that result in a drop])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ON_EXIT([kill `cat ovs-ofctl.pid`])
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
@@ -4693,7 +4693,7 @@ ADD_OF_PORTS([br0], [2])
 ADD_OF_PORTS([br1], [3])
 
 AT_CHECK([ovs-appctl time/stop])
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 
 AT_CHECK([ovs-ofctl add-flow br0 actions=LOCAL,output:1,output:2])
 AT_CHECK([ovs-ofctl add-flow br1 actions=LOCAL,output:1,output:3])
@@ -4778,7 +4778,7 @@ AT_BANNER([ofproto-dpif -- megaflows])
 
 AT_SETUP([ofproto-dpif megaflow - port classification])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1 actions=output(2)
@@ -4796,7 +4796,7 @@ AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - L2 classification])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1,dl_src=50:54:00:00:00:09 actions=output(2)
@@ -4814,7 +4814,7 @@ AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - L3 classification])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_CHECK([ovs-vsctl set Bridge br0 flow_tables:0=@N1 -- --id=@N1 create Flow_Table name=t0 prefixes=nw_dst,nw_src], [0], [ignore], [])
 AT_DATA([flows.txt], [dnl
@@ -4833,7 +4833,7 @@ AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - IPv6 classification])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_CHECK([ovs-vsctl set Bridge br0 flow_tables:0=@N1 -- --id=@N1 create Flow_Table name=t0 prefixes=ipv6_dst,ipv6_src], [0], [ignore], [])
 AT_DATA([flows.txt], [dnl
@@ -4852,7 +4852,7 @@ AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - L4 classification])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1,icmp,icmp_type=8 actions=output(2)
@@ -4870,7 +4870,7 @@ AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - normal])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_CHECK([ovs-ofctl add-flow br0 action=normal])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
@@ -4885,7 +4885,7 @@ AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - mpls])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 dl_src=50:54:00:00:00:09 actions=push_mpls:0x8847,2
@@ -4908,7 +4908,7 @@ AT_CLEANUP
 m4_define([CHECK_MEGAFLOW_NETFLOW],
   [AT_SETUP([ofproto-dpif megaflow - netflow - $2 collector])
   OVS_VSWITCHD_START
-  AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+  AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
   ADD_OF_PORTS([br0], [1], [2])
 
   dnl NetFlow configuration disables wildcarding relevant fields
@@ -4943,7 +4943,7 @@ OVS_VSWITCHD_START(
    set interface p3 type=dummy ofport_request=3])
 AT_CHECK([ovs-appctl netdev-dummy/set-admin-state up], 0, [OK
 ])
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 
 AT_CHECK([ovs-ofctl add-flow br0 action=normal])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
@@ -4964,7 +4964,7 @@ OVS_VSWITCHD_START(
    set interface p3 type=dummy ofport_request=3])
 AT_CHECK([ovs-appctl netdev-dummy/set-admin-state up], 0, [OK
 ])
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 
 AT_CHECK([ovs-ofctl add-flow br0 action=normal])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
@@ -4999,7 +4999,7 @@ OVS_VSWITCHD_START(
 
 AT_CHECK([ovs-appctl netdev-dummy/set-admin-state up], 0, [OK
 ])
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ADD_OF_PORTS([br0], [7])
 AT_CHECK([ovs-ofctl add-flow br0 action=normal])
 AT_CHECK([ovs-ofctl add-flow br1 action=normal])
@@ -5017,7 +5017,7 @@ AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - resubmit port action])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1,ip actions=resubmit(90)
@@ -5036,7 +5036,7 @@ AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - resubmit table action])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1,ip actions=resubmit(,1)
@@ -5056,7 +5056,7 @@ AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - goto_table action])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1,ip actions=goto_table(1)
@@ -5075,7 +5075,7 @@ AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - mirroring, select_all])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ADD_OF_PORTS([br0], [1], [2], [3])
 ovs-vsctl \
         set Bridge br0 mirrors=@m --\
@@ -5098,7 +5098,7 @@ AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - mirroring, select_vlan])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ADD_OF_PORTS([br0], [1], [2], [3])
 ovs-vsctl \
         set Bridge br0 mirrors=@m --\
@@ -5121,7 +5121,7 @@ AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - move action])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1 ip,actions=move:NXM_OF_IP_SRC[[]]->NXM_NX_REG0[[]],resubmit(90)
@@ -5141,7 +5141,7 @@ AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - push action])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1 ip,actions=push:NXM_OF_IP_SRC[[]],output(2)
@@ -5159,7 +5159,7 @@ AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - learning])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1 actions=load:2->NXM_NX_REG0[[0..15]],learn(table=1,priority=65535,NXM_OF_ETH_SRC[[]],NXM_OF_VLAN_TCI[[0..11]],output:NXM_NX_REG0[[0..15]]),output:2
@@ -5187,7 +5187,7 @@ AT_CLEANUP
 AT_SETUP([ofproto-dpif megaflow - tunnels])
 OVS_VSWITCHD_START(
   [add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1])
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 AT_CHECK([ovs-vsctl add-port br0 p2 -- set Interface p2 type=gre \
      options:remote_ip=1.1.1.1 ofport_request=2 options:key=flow])
 AT_CHECK([ovs-vsctl add-port br0 p3 -- set Interface p3 type=dummy \
@@ -5219,7 +5219,7 @@ AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - dec_ttl])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_CHECK([ovs-vsctl set Bridge br0 flow_tables:0=@N1 -- --id=@N1 create Flow_Table name=t0 prefixes=nw_dst,nw_src], [0], [ignore], [])
 AT_DATA([flows.txt], [dnl
@@ -5238,7 +5238,7 @@ AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - set dl_dst])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1 actions=mod_dl_dst(50:54:00:00:00:0a),output(2)
@@ -5266,7 +5266,7 @@ AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - disabled])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-appctl vlog/set dpif:dbg])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1,ip,nw_dst=10.0.0.1 actions=output(2)
-- 
1.8.1.2




More information about the dev mailing list