[ovs-dev] [PATCH 2/5] netdev: Added netdev_send_batch function

Daniele Di Proietto ddiproietto at vmware.com
Fri May 23 18:04:44 UTC 2014


The netdev_send_batch function allows netdevs to send packets
more efficiently. This will be useful for netdev-dpdk.
If a netdev does not implement send_batch, netdev_send_batch
calls send repeatedly.

Signed-off-by: Daniele Di Proietto <ddiproietto at vmware.com>
---
 lib/netdev-bsd.c      |  1 +
 lib/netdev-dpdk.c     |  1 +
 lib/netdev-dummy.c    |  1 +
 lib/netdev-linux.c    |  1 +
 lib/netdev-provider.h | 13 +++++++++++++
 lib/netdev-vport.c    |  1 +
 lib/netdev.c          | 44 ++++++++++++++++++++++++++++++++++++++++++++
 lib/netdev.h          |  1 +
 8 files changed, 63 insertions(+)

diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c
index 8dc33df..b7922ea 100644
--- a/lib/netdev-bsd.c
+++ b/lib/netdev-bsd.c
@@ -1550,6 +1550,7 @@ netdev_bsd_update_flags(struct netdev *netdev_, enum netdev_flags off,
     NULL, /* get_tunnel_config */                    \
                                                      \
     netdev_bsd_send,                                 \
+    NULL, /* send_batch */                           \
     netdev_bsd_send_wait,                            \
                                                      \
     netdev_bsd_set_etheraddr,                        \
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index fd991ab..ee811eb 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -1122,6 +1122,7 @@ static struct netdev_class netdev_dpdk_class = {
     NULL,                       /* get_tunnel_config */
 
     netdev_dpdk_send,           /* send */
+    NULL,                       /* send_batch */
     NULL,                       /* send_wait */
 
     netdev_dpdk_set_etheraddr,
diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c
index 501fb82..49ef12b 100644
--- a/lib/netdev-dummy.c
+++ b/lib/netdev-dummy.c
@@ -1004,6 +1004,7 @@ static const struct netdev_class dummy_class = {
     NULL,                       /* get_tunnel_config */
 
     netdev_dummy_send,          /* send */
+    NULL,                       /* send_batch */
     NULL,                       /* send_wait */
 
     netdev_dummy_set_etheraddr,
diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index c1d9323..1d01b4a 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -2735,6 +2735,7 @@ netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off,
     NULL,                       /* get_tunnel_config */         \
                                                                 \
     netdev_linux_send,                                          \
+    NULL,                       /* send_batch */                \
     netdev_linux_send_wait,                                     \
                                                                 \
     netdev_linux_set_etheraddr,                                 \
diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
index 37b9da3..2215eaa 100644
--- a/lib/netdev-provider.h
+++ b/lib/netdev-provider.h
@@ -270,6 +270,19 @@ struct netdev_class {
      * working properly over 'netdev'.) */
     int (*send)(struct netdev *netdev, struct ofpbuf *buffer, bool may_steal);
 
+    /* Sends a batch of buffers on 'netdev'.
+     * This is useful for DPDK and netmap-like interfaces, where sending
+     * batches is more efficient than sending single buffers.
+     *
+     * The semantics are similar to 'send'.
+     *
+     * May return EOPNOTSUPP if a network device does not implement packet
+     * transmission through this interface. This function may be set to null
+     * if it would always return EOPNOTSUPP anyhow.  (In this case
+     * netdev_send_batch will call netdev_send repeatedly.) */
+    int (*send_batch)(struct netdev *netdev, struct ofpbuf **buffers, int c,
+                bool may_steal);
+
     /* Registers with the poll loop to wake up from the next call to
      * poll_block() when the packet transmission queue for 'netdev' has
      * sufficient room to transmit a packet with netdev_send().
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index c214bf7..21bb66c 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -767,6 +767,7 @@ get_stats(const struct netdev *netdev, struct netdev_stats *stats)
     GET_TUNNEL_CONFIG,                                      \
                                                             \
     NULL,                       /* send */                  \
+    NULL,                       /* send_batch*/             \
     NULL,                       /* send_wait */             \
                                                             \
     netdev_vport_set_etheraddr,                             \
diff --git a/lib/netdev.c b/lib/netdev.c
index dd800a4..c4c28b2 100644
--- a/lib/netdev.c
+++ b/lib/netdev.c
@@ -676,6 +676,50 @@ netdev_send(struct netdev *netdev, struct ofpbuf *buffer, bool may_steal)
     return error;
 }
 
+/* Sends 'c' 'buffers' on 'netdev'. If 'netdev' supports batching, uses
+ * send_batch(), otherwise iterates through 'buffers' and uses send().
+ * Returns 0 if successful, otherwise a positive errno value.
+ *
+ * To retain ownership of 'buffer' caller can set may_steal to false.
+ *
+ * If any error occurs during the transmission of one buffer, the function
+ * stops and return the error. */
+int
+netdev_send_batch(struct netdev *netdev, struct ofpbuf **buffers, int c,
+                  bool may_steal)
+{
+    int error;
+
+    error = (netdev->netdev_class->send_batch
+             ? netdev->netdev_class->send_batch(netdev, buffers, c, may_steal)
+             : EOPNOTSUPP);
+
+    if (error == EOPNOTSUPP) {
+        int i;
+
+        for (i = 0; i < c; i++) {
+            error = (netdev->netdev_class->send
+                     ? netdev->netdev_class->send(netdev, buffers[i], may_steal)
+                     : EOPNOTSUPP);
+            if (error) {
+                break;
+            }
+        }
+
+        if (error && may_steal) {
+            int j;
+
+            for (j = (error == EOPNOTSUPP) ? i : i+1; j < c; j++) {
+                ofpbuf_delete(buffers[j]);
+            }
+        }
+    }
+    if (!error) {
+        COVERAGE_INC(netdev_sent);
+    }
+    return error;
+}
+
 /* Registers with the poll loop to wake up from the next call to poll_block()
  * when the packet transmission queue has sufficient room to transmit a packet
  * with netdev_send().
diff --git a/lib/netdev.h b/lib/netdev.h
index a4bd01a..dff516f 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -172,6 +172,7 @@ int netdev_rxq_drain(struct netdev_rxq *);
 
 /* Packet transmission. */
 int netdev_send(struct netdev *, struct ofpbuf *, bool may_steal);
+int netdev_send_batch(struct netdev *, struct ofpbuf **, int c, bool may_steal);
 void netdev_send_wait(struct netdev *);
 
 /* Hardware address. */
-- 
2.0.0.rc0




More information about the dev mailing list