On Friday 22 September 2017 02:47 AM, Nikhil Rao wrote: > Add common APIs for configuring packet transfer from ethernet Rx > queues to event devices across HW & SW packet transfer mechanisms. > A detailed description of the adapter is contained in the header's > comments. > > The adapter implementation uses eventdev PMDs to configure the packet > transfer if HW support is available and if not, it uses an EAL service > function that reads packets from ethernet Rx queues and injects these > as events into the event device. > > Signed-off-by: Nikhil Rao <nikhil....@intel.com> > Signed-off-by: Gage Eads <gage.e...@intel.com> > Signed-off-by: Abhinandan Gujjar <abhinandan.guj...@intel.com> > --- > lib/librte_eventdev/rte_event_eth_rx_adapter.h | 384 ++++++++ > lib/librte_eventdev/rte_event_eth_rx_adapter.c | 1238 > ++++++++++++++++++++++++ > lib/Makefile | 2 +- > lib/librte_eventdev/Makefile | 2 + > lib/librte_eventdev/rte_eventdev_version.map | 11 +- > 5 files changed, 1635 insertions(+), 2 deletions(-) > create mode 100644 lib/librte_eventdev/rte_event_eth_rx_adapter.h > create mode 100644 lib/librte_eventdev/rte_event_eth_rx_adapter.c > > diff --git a/lib/librte_eventdev/rte_event_eth_rx_adapter.h > b/lib/librte_eventdev/rte_event_eth_rx_adapter.h > new file mode 100644 > index 000000000..c3849ec31 > --- /dev/null > +++ b/lib/librte_eventdev/rte_event_eth_rx_adapter.h > @@ -0,0 +1,384 @@ > +/* > + * Copyright(c) 2017 Intel Corporation. All rights reserved. > + * All rights reserved. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * > + * * Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * * Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in > + * the documentation and/or other materials provided with the > + * distribution. > + * * Neither the name of Intel Corporation nor the names of its > + * contributors may be used to endorse or promote products derived > + * from this software without specific prior written permission. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT > + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > + */ > + > +#ifndef _RTE_EVENT_ETH_RX_ADAPTER_ > +#define _RTE_EVENT_ETH_RX_ADAPTER_ > + > +/** > + * @file > + * > + * RTE Event Ethernet Rx Adapter > + * > + * An eventdev-based packet processing application enqueues/dequeues mbufs > + * to/from the event device. The application uses the adapter APIs to > configure > + * the packet flow between the ethernet devices and event devices. Depending > on > + * on the capabilties of the eventdev PMD, the adapter may use a EAL service > + * core function for packet transfer or use internal PMD functions to > configure > + * the packet transfer between the ethernet device and the event device. > + * > + * The ethernet Rx event adapter's functions are: > + * - rte_event_eth_rx_adapter_create_ext() > + * - rte_event_eth_rx_adapter_create()/free() > + * - rte_event_eth_rx_adapter_queue_add()/del() > + * - rte_event_eth_rx_adapter_start()/stop() > + * - rte_event_eth_rx_adapter_stats_get()/reset() > + * > + * The applicaton creates an event to ethernet adapter using > + * rte_event_eth_rx_adapter_create_ext() or rte_event_eth_rx_adapter_create() > + * functions. > + * The adapter needs to know which ethernet rx queues to poll for mbufs as > well > + * as event device parameters such as the event queue identifier, event > + * priority and scheduling type that the adapter should use when constructing > + * events. The rte_event_eth_rx_adapter_queue_add() function is provided for > + * this purpose. > + * The servicing weight parameter in the rte_event_eth_rx_adapter_queue_conf > + * is applicable when the Rx adapter uses a service core function and is > + * intended to provide application control of the polling frequency of > ethernet > + * device receive queues, for example, the application may want to poll > higher > + * priority queues with a higher frequency but at the same time not starve > + * lower priority queues completely. If this parameter is zero and the > receive > + * interrupt is enabled when configuring the device, the receive queue is > + * interrupt driven; else, the queue is assigned a servicing weight of one. > + * > + * If the adapter uses a rte_service function, then the application is also > + * required to assign a core to the service function and control the service > + * core using the rte_service APIs. The > rte_event_eth_rx_adapter_service_id_get > + * function can be used to retrieve the service function ID of the adapter in > + * this case. > + * > + * Note: Interrupt driven receive queues are currentely unimplemented. > + */ > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +#include <stdint.h> > +#include <rte_service.h> > + > +#include "rte_eventdev.h" > + > +#define RTE_MAX_EVENT_ETH_RX_ADAPTER_INSTANCE 32 > + > +/* struct rte_event_eth_rx_adapter_queue_conf flags definitions */ > +#define RTE_EVENT_ETH_RX_ADAPTER_QUEUE_FLOW_ID_VALID 0x1 > +/**< This flag indicates the flow identifier is valid > + * @see rte_event_eth_rx_adapter_queue_conf > + */ > + > +struct rte_event_eth_rx_adapter_conf { > + uint8_t event_port_id; > + /**< Event port identifier, the adapter enqueues mbuf events to this > + * port > + */ > + uint32_t max_nb_rx; > + /**< The adapter can return early if it has processed at least > + * max_nb_rx mbufs. This isn't treated as a requirement; batching may > + * cause the adapter to process more than max_nb_rx mbufs > + */ > +}; > + > +/** > + * Function type used for adapter configuration callback. The callback is > + * used to fill in members of the struct rte_event_eth_rx_adapter_conf, this > + * callback is invoked when creating a SW service for packet transfer from > + * ethdev queues to the event device. The SW service is created within the > + * rte_event_eth_rx_adapter_queue_add() function if packet required. > + * > + * @param id > + * Adapter identifier. > + * > + * @param dev_id > + * Event device identifier. > + * > + * @conf > + * Structure that needs to be populated by this callback. > + * > + * @arg > + * Argument to the callback. This is the same as the conf_arg passed to the > + * rte_event_eth_rx_adapter_create_ext() > + */ > +typedef int (*rx_adapter_conf_cb) (uint8_t id, uint8_t dev_id, > + struct rte_event_eth_rx_adapter_conf *conf, > + void *arg); > + > +/** Rx queue configuration structure */ > +struct rte_event_eth_rx_adapter_queue_conf { > + uint32_t rx_queue_flags; > + /**< Flags for handling received packets > + * @see RTE_EVENT_ETH_RX_ADAPTER_QUEUE_FLOW_ID_VALID > + */ > + uint16_t servicing_weight; > + /**< Relative polling frequency of ethernet receive queue, if this > + * is set to zero, the Rx queue is interrupt driven (unless rx queue > + * interrupts are not enabled for the ethernet device) > + */ > + struct rte_event ev; > + /**< > + * The values from the following event fields will be used when > + * enqueuing mbuf events: > + * - event_queue_id: Targeted event queue ID for received packets. > + * - event_priority: Event priority of packets from this Rx queue in > + * the event queue relative to other events. > + * - sched_type: Scheduling type for packets from this Rx queue. > + * - flow_id: If the RTE_ETH_RX_EVENT_ADAPTER_QUEUE_FLOW_ID_VALID bit > + * is set in rx_queue_flags, this flow_id is used for all > + * packets received from this queue. Otherwise the flow ID > + * is set to the RSS hash of the src and dst IPv4/6 > + * address. > + * > + * The event adapter sets ev.event_type to RTE_EVENT_TYPE_ETHDEV in the > + * enqueued event > + */ > +}; > + > +struct rte_event_eth_rx_adapter_stats { > + uint64_t rx_poll_count; > + /**< Receive queue poll count */ > + uint64_t rx_packets; > + /**< Received packet count */ > + uint64_t rx_enq_count; > + /**< Eventdev enqueue count */ > + uint64_t rx_enq_retry; > + /**< Eventdev enqueue retry count */ > + uint64_t rx_enq_start_ts; > + /**< Rx enqueue start timestamp */ > + uint64_t rx_enq_block_cycles; > + /**< Cycles for which the service is blocked by the event device, > + * i.e, the service fails to enqueue to the event device. > + */ > + uint64_t rx_enq_end_ts; > + /**< Latest timestamp at which the service is unblocked > + * by the event device. The start, end timestamps and > + * block cycles can be used to compute the percentage of > + * cycles the service is blocked by the event device. > + */ > +}; > + > +/** > + * Create a new ethernet Rx event adapter with the specified identifier. > + * > + * @param id > + * The identifier of the ethernet Rx event adapter. > + * > + * @dev_id > + * The identifier of the device to configure. > + * > + * @eth_port_id > + * The identifier of the ethernet device. > + * > + * @param conf_cb > + * Callback function that fills in members of a > + * struct rte_event_eth_rx_adapter_conf struct passed into > + * it. > + * > + * @param conf_arg > + * Argument that is passed to the conf_cb function. > + * > + * @return > + * - 0: Success > + * - <0: Error code on failure > + */ > +int rte_event_eth_rx_adapter_create_ext(uint8_t id, uint8_t dev_id, > + rx_adapter_conf_cb conf_cb, > + void *conf_arg); > + > +/** > + * Create a new ethernet Rx event adapter with the specified identifier. > + * This function uses an internal configuration function that creates an > event > + * port. This default function reconfigures the event device with an > + * additional event port and setups up the event port using the port_config > + * parameter passed into this function. In case the application needs more > + * control in configuration of the service, it should use the > + * rte_event_eth_rx_adapter_create_ext() version. > + * > + * @param id > + * The identifier of the ethernet Rx event adapter. > + * > + * @dev_id > + * The identifier of the device to configure. > + * > + * @eth_port_id > + * The identifier of the ethernet device. > + * > + * @param conf_cb > + * Callback function that fills in members of a > + * struct rte_event_eth_rx_adapter_conf struct passed into > + * it. > + * > + * @param conf_arg > + * Argument of type *rte_event_port_conf* that is passed to the conf_cb > + * function. > + * > + * @return > + * - 0: Success > + * - <0: Error code on failure > + */ > +int rte_event_eth_rx_adapter_create(uint8_t id, uint8_t dev_id, > + struct rte_event_port_conf *port_config); > + > +/** > + * Free an event adapter > + * > + * @param id > + * Adapter identifier. > + * > + * @return > + * - 0: Success > + * - <0: Error code on failure, If the adapter still has Rx queues > + * added to it, the function returns -EBUSY. > + */ > +int rte_event_eth_rx_adapter_free(uint8_t id); > + > +/** > + * Add receive queue to an event adapter. After a queue has been > + * added to the event adapter, the result of the application calling > + * rte_eth_rx_burst(eth_dev_id, rx_queue_id, ..) is undefined. > + * > + * @param id > + * Adapter identifier. > + * > + * @param eth_dev_id > + * Port identifier of Ethernet device. > + * > + * @param rx_queue_id > + * Ethernet device receive queue index. > + * If rx_queue_id is -1, then all Rx queues configured for > + * the device are added. If the ethdev Rx queues can only be > + * connected to a single event queue then rx_queue_id is > + * required to be -1. > + * > + * @param conf > + * Additonal configuration structure of type *rte_event_eth_rx_adapte_conf* > + * > + * @see > + * @return > + * - 0: Success, Receive queue added correctly. > + * - <0: Error code on failure. > + */ > +int rte_event_eth_rx_adapter_queue_add(uint8_t id, > + uint8_t eth_dev_id, > + int32_t rx_queue_id, > + const struct rte_event_eth_rx_adapter_queue_conf *conf); > + > +/** > + * Delete receive queue from an event adapter. > + * > + * @param id > + * Adapter identifier. > + * > + * @param eth_dev_id > + * Port identifier of Ethernet device. > + * > + * @param rx_queue_id > + * Ethernet device receive queue index. > + * If rx_queue_id is -1, then all Rx queues configured for > + * the device are deleted. If the ethdev Rx queues can only be > + * connected to a single event queue then rx_queue_id is > + * required to be -1. > + * > + * @return > + * - 0: Success, Receive queue deleted correctly. > + * - <0: Error code on failure. > + */ > +int rte_event_eth_rx_adapter_queue_del(uint8_t id, uint8_t eth_dev_id, > + int32_t rx_queue_id); > + > +/** > + * Start ethernet Rx event adapter > + * > + * @param id > + * Adapter identifier. > + * > + * @return > + * - 0: Success, Adapter started correctly. > + * - <0: Error code on failure. > + */ > +int rte_event_eth_rx_adapter_start(uint8_t id); > + > +/** > + * Stop ethernet Rx event adapter > + * > + * @param id > + * Adapter identifier. > + * > + * @return > + * - 0: Success, Adapter started correctly. > + * - <0: Error code on failure. > + */ > +int rte_event_eth_rx_adapter_stop(uint8_t id); > + > +/** > + * Retrieve statistics for an adapter > + * > + * @param id > + * Adapter identifier. > + * > + * @param stats > + * A pointer to structure used to retrieve statistics for an adapter. > + * > + * @return > + * - 0: Success, retrieved successfully. > + * - <0: Error code on failure. > + */ > +int rte_event_eth_rx_adapter_stats_get(uint8_t id, > + struct rte_event_eth_rx_adapter_stats *stats); > + > +/** > + * Reset statistics for an adapter > + * > + * @param id > + * Adapter identifier. > + * > + * @return > + * - 0: Success, statistics reset successfully. > + * - <0: Error code on failure. > + */ > +int rte_event_eth_rx_adapter_stats_reset(uint8_t id); > + > +/** > + * Retrieve the service ID of an adapter. If the adapter doesn't use > + * a rte_service function, this function returns -ESRCH > + * > + * @param id > + * Adapter identifier. > + * > + * @return > + * - 0: Success, statistics reset successfully. > + * - <0: Error code on failure, if the adapter doesn't use a rte_service > + * function, this function returns -ESRCH. > + */ > +int rte_event_eth_rx_adapter_service_id_get(uint8_t id, uint32_t > *service_id); > +
In general api comment: Fix missing param definition like *service_id* above and pl. remove other unnecessary params description from api above. > +#ifdef __cplusplus > +} > +#endif > +#endif /* _RTE_EVENT_ETH_RX_ADAPTER_ */ > diff --git a/lib/librte_eventdev/rte_event_eth_rx_adapter.c > b/lib/librte_eventdev/rte_event_eth_rx_adapter.c > new file mode 100644 > index 000000000..d5b655dae > --- /dev/null > +++ b/lib/librte_eventdev/rte_event_eth_rx_adapter.c > @@ -0,0 +1,1238 @@ > +#include <rte_cycles.h> > +#include <rte_common.h> > +#include <rte_dev.h> > +#include <rte_errno.h> > +#include <rte_ethdev.h> > +#include <rte_log.h> > +#include <rte_malloc.h> > +#include <rte_service_component.h> > +#include <rte_thash.h> > + > +#include "rte_eventdev.h" > +#include "rte_eventdev_pmd.h" > +#include "rte_event_eth_rx_adapter.h" > + > +#define BATCH_SIZE 32 > +#define BLOCK_CNT_THRESHOLD 10 > +#define ETH_EVENT_BUFFER_SIZE (4*BATCH_SIZE) > + > +#define ETH_RX_ADAPTER_SERVICE_NAME_LEN 32 > +#define ETH_RX_ADAPTER_MEM_NAME_LEN 32 > + > +/* > + * There is an instance of this struct per polled Rx queue added to the > + * adapter > + */ > +struct eth_rx_poll_entry { > + /* eth port to poll */ > + uint8_t eth_dev_id; > + /* eth rx queue to poll */ > + uint16_t eth_rx_qid; > +}; > + > +/* Instance per adapter */ > +struct rte_eth_event_enqueue_buffer { > + /* Count of events in this buffer */ > + uint16_t count; > + /* Array of events in this buffer */ > + struct rte_event events[ETH_EVENT_BUFFER_SIZE]; > +}; > + > +struct rte_event_eth_rx_adapter { > + /* event device identifier */ > + uint8_t eventdev_id; > + /* per ethernet device structure */ > + struct eth_device_info *eth_devices; > + /* malloc name */ > + char mem_name[ETH_RX_ADAPTER_MEM_NAME_LEN]; > + /* socket identifier cached from eventdev */ > + int socket_id; > + > + /* elements below are used by SW service */ > + > + /* event port identifier */ > + uint8_t event_port_id; > + /* per adapter EAL service */ > + uint32_t service_id; > + /* lock to serialize config updates with service function */ > + rte_spinlock_t rx_lock; > + /* max mbufs processed in any service function invocation */ > + uint32_t max_nb_rx; > + /* Receive queues that need to be polled */ > + struct eth_rx_poll_entry *eth_rx_poll; > + /* size of the eth_rx_poll array */ > + uint16_t num_rx_polled; > + /* Weighted round robin schedule */ > + uint32_t *wrr_sched; > + /* wrr_sched[] size */ > + uint32_t wrr_len; > + /* Next entry in wrr[] to begin polling */ > + uint32_t wrr_pos; > + /* Event burst buffer */ > + struct rte_eth_event_enqueue_buffer event_enqueue_buffer; > + /* per adapter stats */ > + struct rte_event_eth_rx_adapter_stats stats; > + /* Block count, counts upto BLOCK_CNT_THRESHOLD */ > + uint16_t enq_block_count; > + /* Block start ts */ > + uint64_t rx_enq_block_start_ts; > + /* Configuration callback for rte_service configuration */ > + rx_adapter_conf_cb conf_cb; > + /* Configuration callback argument */ > + void *conf_arg; > + /* Service initialization state */ > + uint8_t service_inited; > + /* Total count of Rx queues in adapter */ > + uint32_t nb_queues; > +} __rte_cache_aligned; > + > +/* Per eth device */ > +struct eth_device_info { > + struct rte_eth_dev *dev; > + struct eth_rx_queue_info *rx_queue; > + /* Set if ethdev->eventdev packet transfer uses a > + * hardware mechanism > + */ > + uint8_t internal_event_port; > + /* set if the adapter is processing rx queues for > + * this eth device and packet processing has been > + * started, allows for the code to know if the PMD > + * rx_adapter_stop callback needs to be invoked > + */ > + uint8_t dev_rx_started; > + /* if nb_dev_queues > 0, the start callback will > + * be invoked if not already invoked > + */ > + uint16_t nb_dev_queues; > +}; > + > +/* Per Rx queue */ > +struct eth_rx_queue_info { > + int queue_enabled; /* true if added */ > + uint16_t wt; /* polling weight */ > + uint8_t event_queue_id; /* Event queue to enqueue packets to */ > + uint8_t sched_type; /* sched type for events */ > + uint8_t priority; /* event priority */ > + uint32_t flow_id; /* app provided flow identifier */ > + uint32_t flow_id_mask; /* Set to ~0 if app provides flow id else 0 */ > +}; > + > +static struct rte_event_eth_rx_adapter **rte_event_eth_rx_adapter; > +static struct rte_event_port_conf > + create_port_conf[RTE_MAX_EVENT_ETH_RX_ADAPTER_INSTANCE]; > + > +static uint8_t default_rss_key[] = { > + 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, > + 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, > + 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4, > + 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, > + 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa, > +}; > +static uint8_t *rss_key_be; > + > +static inline int > +valid_id(uint8_t id) > +{ > + return id < RTE_MAX_EVENT_ETH_RX_ADAPTER_INSTANCE; > +} > + > +#define RTE_EVENT_ETH_RX_ADAPTER_ID_VALID_OR_ERR_RET(id, retval) do { \ > + if (!valid_id(id)) { \ > + RTE_EDEV_LOG_ERR("Invalid eth Rx adapter id = %d\n", id); \ > + return retval; \ > + } \ > +} while (0) > + Worth, moving this macro to rte_eventdev_pmd.h Or How about reusing existing one ie.. RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET? > +static inline int > +sw_rx_adapter_queue_count(struct rte_event_eth_rx_adapter *rx_adapter) > +{ > + return rx_adapter->num_rx_polled; > +} > + > +/* Greatest common divisor */ > +static uint16_t gcd_u16(uint16_t a, uint16_t b) > +{ > + uint16_t r = a % b; > + > + return r ? gcd_u16(b, r) : b; > +} > + > +/* Returns the next queue in the polling sequence > + * > + * http://kb.linuxvirtualserver.org/wiki/Weighted_Round-Robin_Scheduling > + */ > +static int > +wrr_next(struct rte_event_eth_rx_adapter *rx_adapter, > + unsigned int n, int *cw, > + struct eth_rx_poll_entry *eth_rx_poll, uint16_t max_wt, > + uint16_t gcd, int prev) > +{ > + int i = prev; > + uint16_t w; > + > + while (1) { > + uint16_t q; > + uint8_t d; > + > + i = (i + 1) % n; > + if (i == 0) { > + *cw = *cw - gcd; > + if (*cw <= 0) > + *cw = max_wt; > + } > + > + q = eth_rx_poll[i].eth_rx_qid; > + d = eth_rx_poll[i].eth_dev_id; > + w = rx_adapter->eth_devices[d].rx_queue[q].wt; > + > + if ((int)w >= *cw) > + return i; > + } > +} > + > +/* Precalculate WRR polling sequence for all queues in rx_adapter */ > +static int > +eth_poll_wrr_calc(struct rte_event_eth_rx_adapter *rx_adapter) > +{ > + uint8_t d; > + uint16_t q; > + unsigned int i; > + > + /* Initialize variables for calculaton of wrr schedule */ > + uint16_t max_wrr_pos = 0; > + unsigned int poll_q = 0; > + uint16_t max_wt = 0; > + uint16_t gcd = 0; > + > + struct eth_rx_poll_entry *rx_poll = NULL; > + uint32_t *rx_wrr = NULL; > + > + if (rx_adapter->num_rx_polled) { > + size_t len = RTE_ALIGN(rx_adapter->num_rx_polled * > + sizeof(*rx_adapter->eth_rx_poll), > + RTE_CACHE_LINE_SIZE); > + rx_poll = rte_zmalloc_socket(rx_adapter->mem_name, > + len, > + RTE_CACHE_LINE_SIZE, > + rx_adapter->socket_id); > + if (!rx_poll) > + return -ENOMEM; > + > + /* Generate array of all queues to poll, the size of this > + * array is poll_q > + */ > + for (d = 0; d < rte_eth_dev_count(); d++) { > + uint16_t nb_rx_queues; > + struct eth_device_info *dev_info = > + &rx_adapter->eth_devices[d]; > + nb_rx_queues = dev_info->dev->data->nb_rx_queues; > + if (!dev_info->rx_queue) > + continue; > + for (q = 0; q < nb_rx_queues; q++) { > + struct eth_rx_queue_info *queue_info = > + &dev_info->rx_queue[q]; > + if (!queue_info->queue_enabled) > + continue; > + > + uint16_t wt = queue_info->wt; > + rx_poll[poll_q].eth_dev_id = d; > + rx_poll[poll_q].eth_rx_qid = q; > + max_wrr_pos += wt; > + max_wt = RTE_MAX(max_wt, wt); > + gcd = (gcd) ? gcd_u16(gcd, wt) : wt; > + poll_q++; > + } > + } > + > + len = RTE_ALIGN(max_wrr_pos * sizeof(*rx_wrr), > + RTE_CACHE_LINE_SIZE); > + rx_wrr = rte_zmalloc_socket(rx_adapter->mem_name, > + len, > + RTE_CACHE_LINE_SIZE, > + rx_adapter->socket_id); > + if (!rx_wrr) { > + rte_free(rx_poll); > + return -ENOMEM; > + } > + > + /* Generate polling sequence based on weights */ > + int prev = -1; > + int cw = -1; > + for (i = 0; i < max_wrr_pos; i++) { > + rx_wrr[i] = wrr_next(rx_adapter, poll_q, &cw, > + rx_poll, max_wt, gcd, prev); > + prev = rx_wrr[i]; > + } > + } > + > + rte_free(rx_adapter->eth_rx_poll); > + rte_free(rx_adapter->wrr_sched); > + > + rx_adapter->eth_rx_poll = rx_poll; > + rx_adapter->wrr_sched = rx_wrr; > + rx_adapter->wrr_len = max_wrr_pos; > + > + return 0; > +} > + > +static inline void > +mtoip(struct rte_mbuf *m, struct ipv4_hdr **ipv4_hdr, > + struct ipv6_hdr **ipv6_hdr) > +{ mtoip(), imo is more of global api, likely other modules may use in future.. perhaps move to rte_io.h Or more correct place.. thought? Thanks.