Signed-off-by: Daniele Di Proietto <ddiproie...@vmware.com>
---
 lib/dpif-netdev.c | 238 +++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 157 insertions(+), 81 deletions(-)

diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 43bfc20..f1f8b54 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -331,14 +331,14 @@ static void dp_netdev_destroy_all_queues(struct dp_netdev 
*dp)
     OVS_REQ_WRLOCK(dp->queue_rwlock);
 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,
+static int dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf **,
+                                      int c, int queue_no, int type,
                                       const struct miniflow *,
                                       const struct nlattr *userdata);
 static void dp_netdev_execute_actions(struct dp_netdev *dp,
                                       const struct miniflow *,
-                                      struct ofpbuf *, bool may_steal,
-                                      struct pkt_metadata *,
+                                      struct ofpbuf **, int c, bool may_steal,
+                                      struct pkt_metadata **,
                                       const struct nlattr *actions,
                                       size_t actions_len);
 static void dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf **packets,
@@ -1533,7 +1533,7 @@ dpif_netdev_execute(struct dpif *dpif, struct 
dpif_execute *execute)
     miniflow_initialize(&key.flow, key.buf);
     miniflow_extract(execute->packet, md, &key.flow);
 
-    dp_netdev_execute_actions(dp, &key.flow, execute->packet, false, md,
+    dp_netdev_execute_actions(dp, &key.flow, &execute->packet, 1, false, &md,
                               execute->actions, execute->actions_len);
 
     return 0;
@@ -1986,46 +1986,108 @@ dp_netdev_count_packet(struct dp_netdev *dp, enum 
dp_stat_type type, int packets
     ovs_mutex_unlock(&bucket->mutex);
 }
 
+#define MAX_BATCH 256
+
+struct batch_pkt_execute {
+    unsigned int packet_count;
+    unsigned int byte_count;
+
+    struct dp_netdev_flow *flow;
+    struct ofpbuf *packets[MAX_BATCH];
+    struct pkt_metadata *md[MAX_BATCH];
+    const struct miniflow *mf;
+};
+
+static inline void
+packet_batch_init(struct batch_pkt_execute *batch, struct dp_netdev_flow *flow,
+                  struct ofpbuf *packet,
+                  struct pkt_metadata *md, const struct miniflow *mf)
+{
+    batch->flow = flow;
+    batch->mf = mf;
+    batch->md[0] = md;
+    batch->packets[0] = packet;
+
+    /* no need to update time and tcp_flags, its same in given input batch. */
+    batch->packet_count = 1;
+    batch->byte_count = ofpbuf_size(packet);
+}
+
+static inline void
+packet_batch_update(struct batch_pkt_execute *batch, struct ofpbuf *packet, 
struct pkt_metadata *md)
+{
+
+    batch->md[batch->packet_count] = md;
+    batch->packets[batch->packet_count++] = packet;
+    batch->byte_count += ofpbuf_size(packet);
+}
+
+static inline void
+packet_batch_execute(struct batch_pkt_execute *batch, struct dp_netdev *dp)
+{
+    struct dp_netdev_actions *actions;
+    struct dp_netdev_flow *flow = batch->flow;
+
+    dp_netdev_flow_used(batch->flow, batch->packet_count, batch->byte_count, 
batch->mf);
+
+    actions = ovsrcu_get(struct dp_netdev_actions *, &flow->actions);
+
+    dp_netdev_execute_actions(dp, batch->mf, batch->packets,
+                              batch->packet_count, true,
+                              batch->md, actions->actions, actions->size);
+
+    dp_netdev_count_packet(dp, DP_STAT_HIT, batch->packet_count);
+}
+
 static void
 dp_netdev_input(struct dp_netdev *dp, struct ofpbuf **packets, int c,
-                struct pkt_metadata *md)
+                struct pkt_metadata **md)
 {
+    struct batch_pkt_execute batch;
+
+    struct {
+        struct miniflow flow;
+        uint32_t buf[FLOW_U32S];
+    } keys[c];
+
     int i;
 
+    memset(&batch, 0, sizeof batch);
+
     for (i = 0; i < c; i++) {
         struct dp_netdev_flow *netdev_flow;
-        struct {
-            struct miniflow flow;
-            uint32_t buf[FLOW_U32S];
-        } key;
 
         if (ofpbuf_size(packets[i]) < ETH_HEADER_LEN) {
             ofpbuf_delete(packets[i]);
             continue;
         }
-        miniflow_initialize(&key.flow, key.buf);
-        miniflow_extract(packets[i], &md[i], &key.flow);
+        miniflow_initialize(&keys[i].flow, keys[i].buf);
+        miniflow_extract(packets[i], md[i], &keys[i].flow);
 
-        netdev_flow = dp_netdev_lookup_flow(dp, &key.flow);
+        netdev_flow = dp_netdev_lookup_flow(dp, &keys[i].flow);
 
         if (netdev_flow) {
-            struct dp_netdev_actions *actions;
-
-            dp_netdev_flow_used(netdev_flow, 1, ofpbuf_size(packets[i]), 
&key.flow);
-
-            actions = dp_netdev_flow_get_actions(netdev_flow);
-            dp_netdev_execute_actions(dp, &key.flow, packets[i], true, &md[i],
-                                      actions->actions, actions->size);
-            dp_netdev_count_packet(dp, DP_STAT_HIT, 1);
+            if (!batch.flow) {
+                packet_batch_init(&batch, netdev_flow, packets[i], md[i], 
&keys[i].flow);
+            } else if (batch.flow == netdev_flow) {
+                packet_batch_update(&batch, packets[i], md[i]);
+            } else {
+                packet_batch_execute(&batch, dp);
+                packet_batch_init(&batch, netdev_flow, packets[i], md[i], 
&keys[i].flow);
+            }
         } else if (dp->handler_queues) {
             dp_netdev_count_packet(dp, DP_STAT_MISS, 1);
-            dp_netdev_output_userspace(dp, packets[i],
-                                       miniflow_hash_5tuple(&key.flow, 0)
+            dp_netdev_output_userspace(dp, &packets[i], 1,
+                                       miniflow_hash_5tuple(&keys[i].flow, 0)
                                        % dp->n_handlers,
-                                       DPIF_UC_MISS, &key.flow, NULL);
+                                       DPIF_UC_MISS, &keys[i].flow, NULL);
             ofpbuf_delete(packets[i]);
         }
     }
+
+    if (batch.flow) {
+        packet_batch_execute(&batch, dp);
+    }
 }
 
 static void
@@ -2034,67 +2096,74 @@ dp_netdev_port_input(struct dp_netdev *dp, struct 
ofpbuf **packets,
 {
     uint32_t *recirc_depth = recirc_depth_get();
     struct pkt_metadata md[c];
+    struct pkt_metadata *pmd[c];
 
     int i;
 
     for (i = 0; i < c; i++) {
         md[i] = PKT_METADATA_INITIALIZER(port_no);
+        pmd[i] = &md[i];
     }
 
     *recirc_depth = 0;
-    dp_netdev_input(dp, packets, c, md);
+    dp_netdev_input(dp, packets, c, pmd);
 }
 
 static int
-dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet,
+dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf **packets, int 
c,
                            int queue_no, int type, const struct miniflow *key,
                            const struct nlattr *userdata)
 {
     struct dp_netdev_queue *q;
     int error;
+    int i;
 
     fat_rwlock_rdlock(&dp->queue_rwlock);
     q = &dp->handler_queues[queue_no];
     ovs_mutex_lock(&q->mutex);
-    if (q->head - q->tail < MAX_QUEUE_LEN) {
-        struct dp_netdev_upcall *u = &q->upcalls[q->head++ & QUEUE_MASK];
-        struct dpif_upcall *upcall = &u->upcall;
-        struct ofpbuf *buf = &u->buf;
-        size_t buf_size;
-        struct flow flow;
-
-        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));
-        }
+    for (i = 0; i < c; i++) {
+        struct ofpbuf * packet = packets[i];
+        if (q->head - q->tail < MAX_QUEUE_LEN) {
+            struct dp_netdev_upcall *u = &q->upcalls[q->head++ & QUEUE_MASK];
+            struct dpif_upcall *upcall = &u->upcall;
+            struct ofpbuf *buf = &u->buf;
+            size_t buf_size;
+            struct flow flow;
+
+            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));
+            }
 
-        ofpbuf_set_data(&upcall->packet,
-                        ofpbuf_put(buf, ofpbuf_data(packet), 
ofpbuf_size(packet)));
-        ofpbuf_set_size(&upcall->packet, ofpbuf_size(packet));
+            ofpbuf_set_data(&upcall->packet,
+                            ofpbuf_put(buf, ofpbuf_data(packet),
+                            ofpbuf_size(packet)));
+            ofpbuf_set_size(&upcall->packet, ofpbuf_size(packet));
 
-        seq_change(q->seq);
+            seq_change(q->seq);
 
-        error = 0;
-    } else {
-        dp_netdev_count_packet(dp, DP_STAT_LOST, 1);
-        error = ENOBUFS;
+            error = 0;
+        } else {
+            dp_netdev_count_packet(dp, DP_STAT_LOST, 1);
+            error = ENOBUFS;
+        }
     }
     ovs_mutex_unlock(&q->mutex);
     fat_rwlock_unlock(&dp->queue_rwlock);
@@ -2117,19 +2186,13 @@ dp_execute_cb(void *aux_, struct ofpbuf **packets, int 
c,
     int type = nl_attr_type(a);
     struct dp_netdev_port *p;
     uint32_t *depth = recirc_depth_get();
-    struct ofpbuf * packet;
-    struct pkt_metadata * md;
-    
-    ovs_assert(c==1);
-
-    packet = packets[0];
-    md = pmd[0];
+    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)));
         if (p) {
-            netdev_send(p->netdev, packet, may_steal);
+            netdev_send_batch(p->netdev, packets, c, may_steal);
         }
         break;
 
@@ -2138,14 +2201,16 @@ dp_execute_cb(void *aux_, struct ofpbuf **packets, int 
c,
 
         userdata = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA);
 
-        dp_netdev_output_userspace(aux->dp, packet,
+        dp_netdev_output_userspace(aux->dp, packets, c,
                                    miniflow_hash_5tuple(aux->key, 0)
                                        % aux->dp->n_handlers,
                                    DPIF_UC_ACTION, aux->key,
                                    userdata);
 
         if (may_steal) {
-            ofpbuf_delete(packet);
+            for (i = 0; i < c; i++) {
+                ofpbuf_delete(packets[i]);
+            }
         }
         break;
     }
@@ -2168,20 +2233,31 @@ dp_execute_cb(void *aux_, struct ofpbuf **packets, int 
c,
             hash = 2;
         }
 
-        md->dp_hash = hash;
+        for (i = 0; i < c; i++) {
+            pmd[i]->dp_hash = hash;
+        }
         break;
     }
 
     case OVS_ACTION_ATTR_RECIRC:
         if (*depth < MAX_RECIRC_DEPTH) {
-            struct pkt_metadata recirc_md = *md;
-            struct ofpbuf *recirc_packet;
+            struct pkt_metadata recirc_md[c];
+            struct pkt_metadata *recirc_pmd[c];
+            struct ofpbuf *recirc_packets[c];
 
-            recirc_packet = may_steal ? packet : ofpbuf_clone(packet);
-            recirc_md.recirc_id = nl_attr_get_u32(a);
+            if (!may_steal) {
+                for (i = 0; i < c; i++)
+                    recirc_packets[i] = ofpbuf_clone(packets[i]);
+            }
+
+            for (i = 0; i < c; i++) {
+                recirc_md[i] = *pmd[i];
+                recirc_md[i].recirc_id = nl_attr_get_u32(a);
+                recirc_pmd[i] = &recirc_md[i];
+            }
 
             (*depth)++;
-            dp_netdev_input(aux->dp, &recirc_packet, 1, &recirc_md);
+            dp_netdev_input(aux->dp, may_steal ? packets : recirc_packets, c, 
recirc_pmd);
             (*depth)--;
 
             break;
@@ -2204,13 +2280,13 @@ dp_execute_cb(void *aux_, struct ofpbuf **packets, int 
c,
 
 static void
 dp_netdev_execute_actions(struct dp_netdev *dp, const struct miniflow *key,
-                          struct ofpbuf *packet, bool may_steal,
-                          struct pkt_metadata *md,
+                          struct ofpbuf **packets, int c, bool may_steal,
+                          struct pkt_metadata **md,
                           const struct nlattr *actions, size_t actions_len)
 {
     struct dp_netdev_execute_aux aux = {dp, key};
 
-    odp_execute_actions(&aux, &packet, 1, may_steal, &md,
+    odp_execute_actions(&aux, packets, c, may_steal, md,
                         actions, actions_len, dp_execute_cb);
 }
 
-- 
2.0.0.rc0

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to