ethdev: add buffered Tx

Many sample apps include internal buffering for single-packet-at-a-time
operation. Since this is such a common paradigm, this functionality is
better suited to being implemented in the ethdev API.

The new APIs in the ethdev library are:
* rte_eth_tx_buffer_init - initialize buffer
* rte_eth_tx_buffer - buffer up a single packet for future transmission
* rte_eth_tx_buffer_flush - flush any unsent buffered packets
* rte_eth_tx_buffer_set_err_callback - set up a callback to be called in
  case transmitting a buffered burst fails. By default, we just free the
  unsent packets.

As well as these, an additional reference callbacks are provided, which
frees the packets:

* rte_eth_tx_buffer_drop_callback - silently drop packets (default
  behavior)
* rte_eth_tx_buffer_count_callback - drop and update user-provided counter
  to track the number of dropped packets

Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
Acked-by: Thomas Monjalon <thomas.monjalon@6wind.com>
This commit is contained in:
Tomasz Kulasek 2016-03-10 18:19:34 +01:00 committed by Thomas Monjalon
parent fd2fca6f6b
commit d6c99e62c8
3 changed files with 261 additions and 1 deletions

View File

@ -1270,6 +1270,52 @@ rte_eth_tx_queue_setup(uint8_t port_id, uint16_t tx_queue_id,
socket_id, tx_conf);
}
void
rte_eth_tx_buffer_drop_callback(struct rte_mbuf **pkts, uint16_t unsent,
void *userdata __rte_unused)
{
unsigned i;
for (i = 0; i < unsent; i++)
rte_pktmbuf_free(pkts[i]);
}
void
rte_eth_tx_buffer_count_callback(struct rte_mbuf **pkts, uint16_t unsent,
void *userdata)
{
uint64_t *count = userdata;
unsigned i;
for (i = 0; i < unsent; i++)
rte_pktmbuf_free(pkts[i]);
*count += unsent;
}
int
rte_eth_tx_buffer_set_err_callback(struct rte_eth_dev_tx_buffer *buffer,
buffer_tx_error_fn cbfn, void *userdata)
{
buffer->error_callback = cbfn;
buffer->error_userdata = userdata;
return 0;
}
int
rte_eth_tx_buffer_init(struct rte_eth_dev_tx_buffer *buffer, uint16_t size)
{
if (buffer == NULL)
return -EINVAL;
buffer->size = size;
if (buffer->error_callback == NULL)
rte_eth_tx_buffer_set_err_callback(buffer,
rte_eth_tx_buffer_drop_callback, NULL);
return 0;
}
void
rte_eth_promiscuous_enable(uint8_t port_id)
{

View File

@ -1,7 +1,7 @@
/*-
* BSD LICENSE
*
* Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
* Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -2655,6 +2655,210 @@ rte_eth_tx_burst(uint8_t port_id, uint16_t queue_id,
return (*dev->tx_pkt_burst)(dev->data->tx_queues[queue_id], tx_pkts, nb_pkts);
}
typedef void (*buffer_tx_error_fn)(struct rte_mbuf **unsent, uint16_t count,
void *userdata);
/**
* Structure used to buffer packets for future TX
* Used by APIs rte_eth_tx_buffer and rte_eth_tx_buffer_flush
*/
struct rte_eth_dev_tx_buffer {
buffer_tx_error_fn error_callback;
void *error_userdata;
uint16_t size; /**< Size of buffer for buffered tx */
uint16_t length; /**< Number of packets in the array */
struct rte_mbuf *pkts[];
/**< Pending packets to be sent on explicit flush or when full */
};
/**
* Calculate the size of the tx buffer.
*
* @param sz
* Number of stored packets.
*/
#define RTE_ETH_TX_BUFFER_SIZE(sz) \
(sizeof(struct rte_eth_dev_tx_buffer) + (sz) * sizeof(struct rte_mbuf *))
/**
* Initialize default values for buffered transmitting
*
* @param buffer
* Tx buffer to be initialized.
* @param size
* Buffer size
* @return
* 0 if no error
*/
int
rte_eth_tx_buffer_init(struct rte_eth_dev_tx_buffer *buffer, uint16_t size);
/**
* Send any packets queued up for transmission on a port and HW queue
*
* This causes an explicit flush of packets previously buffered via the
* rte_eth_tx_buffer() function. It returns the number of packets successfully
* sent to the NIC, and calls the error callback for any unsent packets. Unless
* explicitly set up otherwise, the default callback simply frees the unsent
* packets back to the owning mempool.
*
* @param port_id
* The port identifier of the Ethernet device.
* @param queue_id
* The index of the transmit queue through which output packets must be
* sent.
* The value must be in the range [0, nb_tx_queue - 1] previously supplied
* to rte_eth_dev_configure().
* @param buffer
* Buffer of packets to be transmit.
* @return
* The number of packets successfully sent to the Ethernet device. The error
* callback is called for any packets which could not be sent.
*/
static inline uint16_t
rte_eth_tx_buffer_flush(uint8_t port_id, uint16_t queue_id,
struct rte_eth_dev_tx_buffer *buffer)
{
uint16_t sent;
uint16_t to_send = buffer->length;
if (to_send == 0)
return 0;
sent = rte_eth_tx_burst(port_id, queue_id, buffer->pkts, to_send);
buffer->length = 0;
/* All packets sent, or to be dealt with by callback below */
if (unlikely(sent != to_send))
buffer->error_callback(&buffer->pkts[sent], to_send - sent,
buffer->error_userdata);
return sent;
}
/**
* Buffer a single packet for future transmission on a port and queue
*
* This function takes a single mbuf/packet and buffers it for later
* transmission on the particular port and queue specified. Once the buffer is
* full of packets, an attempt will be made to transmit all the buffered
* packets. In case of error, where not all packets can be transmitted, a
* callback is called with the unsent packets as a parameter. If no callback
* is explicitly set up, the unsent packets are just freed back to the owning
* mempool. The function returns the number of packets actually sent i.e.
* 0 if no buffer flush occurred, otherwise the number of packets successfully
* flushed
*
* @param port_id
* The port identifier of the Ethernet device.
* @param queue_id
* The index of the transmit queue through which output packets must be
* sent.
* The value must be in the range [0, nb_tx_queue - 1] previously supplied
* to rte_eth_dev_configure().
* @param buffer
* Buffer used to collect packets to be sent.
* @param tx_pkt
* Pointer to the packet mbuf to be sent.
* @return
* 0 = packet has been buffered for later transmission
* N > 0 = packet has been buffered, and the buffer was subsequently flushed,
* causing N packets to be sent, and the error callback to be called for
* the rest.
*/
static inline uint16_t __attribute__((always_inline))
rte_eth_tx_buffer(uint8_t port_id, uint16_t queue_id,
struct rte_eth_dev_tx_buffer *buffer, struct rte_mbuf *tx_pkt)
{
buffer->pkts[buffer->length++] = tx_pkt;
if (buffer->length < buffer->size)
return 0;
return rte_eth_tx_buffer_flush(port_id, queue_id, buffer);
}
/**
* Configure a callback for buffered packets which cannot be sent
*
* Register a specific callback to be called when an attempt is made to send
* all packets buffered on an ethernet port, but not all packets can
* successfully be sent. The callback registered here will be called only
* from calls to rte_eth_tx_buffer() and rte_eth_tx_buffer_flush() APIs.
* The default callback configured for each queue by default just frees the
* packets back to the calling mempool. If additional behaviour is required,
* for example, to count dropped packets, or to retry transmission of packets
* which cannot be sent, this function should be used to register a suitable
* callback function to implement the desired behaviour.
* The example callback "rte_eth_count_unsent_packet_callback()" is also
* provided as reference.
*
* @param buffer
* The port identifier of the Ethernet device.
* @param callback
* The function to be used as the callback.
* @param userdata
* Arbitrary parameter to be passed to the callback function
* @return
* 0 on success, or -1 on error with rte_errno set appropriately
*/
int
rte_eth_tx_buffer_set_err_callback(struct rte_eth_dev_tx_buffer *buffer,
buffer_tx_error_fn callback, void *userdata);
/**
* Callback function for silently dropping unsent buffered packets.
*
* This function can be passed to rte_eth_tx_buffer_set_err_callback() to
* adjust the default behavior when buffered packets cannot be sent. This
* function drops any unsent packets silently and is used by tx buffered
* operations as default behavior.
*
* NOTE: this function should not be called directly, instead it should be used
* as a callback for packet buffering.
*
* NOTE: when configuring this function as a callback with
* rte_eth_tx_buffer_set_err_callback(), the final, userdata parameter
* should point to an uint64_t value.
*
* @param pkts
* The previously buffered packets which could not be sent
* @param unsent
* The number of unsent packets in the pkts array
* @param userdata
* Not used
*/
void
rte_eth_tx_buffer_drop_callback(struct rte_mbuf **pkts, uint16_t unsent,
void *userdata);
/**
* Callback function for tracking unsent buffered packets.
*
* This function can be passed to rte_eth_tx_buffer_set_err_callback() to
* adjust the default behavior when buffered packets cannot be sent. This
* function drops any unsent packets, but also updates a user-supplied counter
* to track the overall number of packets dropped. The counter should be an
* uint64_t variable.
*
* NOTE: this function should not be called directly, instead it should be used
* as a callback for packet buffering.
*
* NOTE: when configuring this function as a callback with
* rte_eth_tx_buffer_set_err_callback(), the final, userdata parameter
* should point to an uint64_t value.
*
* @param pkts
* The previously buffered packets which could not be sent
* @param unsent
* The number of unsent packets in the pkts array
* @param userdata
* Pointer to an uint64_t value, which will be incremented by unsent
*/
void
rte_eth_tx_buffer_count_callback(struct rte_mbuf **pkts, uint16_t unsent,
void *userdata);
/**
* The eth device event type for interrupt, and maybe others in the future.
*/

View File

@ -117,3 +117,13 @@ DPDK_2.2 {
local: *;
};
DPDK_16.04 {
global:
rte_eth_tx_buffer_count_callback;
rte_eth_tx_buffer_drop_callback;
rte_eth_tx_buffer_init;
rte_eth_tx_buffer_set_err_callback;
} DPDK_2.2;