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 <ddiproie...@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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev