odp_port_t port_no;
struct netdev *netdev;
struct netdev_saved_flags *sf;
- struct netdev_rxq *rxq;
+ struct netdev_rxq **rxq;
struct ovs_refcount ref_cnt;
char *type; /* Port type as requested by user. */
};
enum netdev_flags flags;
const char *open_type;
int error;
+ int i;
/* XXX reject devices already in some dp_netdev. */
port = xzalloc(sizeof *port);
port->port_no = port_no;
port->netdev = netdev;
+ port->rxq = xmalloc(sizeof *port->rxq * netdev_n_rxq(netdev));
port->type = xstrdup(type);
- error = netdev_rxq_open(netdev, &port->rxq);
- if (error
- && !(error == EOPNOTSUPP && dpif_netdev_class_is_dummy(dp->class))) {
- VLOG_ERR("%s: cannot receive packets on this network device (%s)",
- devname, ovs_strerror(errno));
- netdev_close(netdev);
- return error;
+ for (i = 0; i < netdev_n_rxq(netdev); i++) {
+ error = netdev_rxq_open(netdev, &port->rxq[i], i);
+ if (error
+ && !(error == EOPNOTSUPP && dpif_netdev_class_is_dummy(dp->class))) {
+ VLOG_ERR("%s: cannot receive packets on this network device (%s)",
+ devname, ovs_strerror(errno));
+ netdev_close(netdev);
+ return error;
+ }
}
error = netdev_turn_flags_on(netdev, NETDEV_PROMISC, &sf);
if (error) {
- netdev_rxq_close(port->rxq);
+ for (i = 0; i < netdev_n_rxq(netdev); i++) {
+ netdev_rxq_close(port->rxq[i]);
+ }
netdev_close(netdev);
free(port->rxq);
free(port);
port_unref(struct dp_netdev_port *port)
{
if (port && ovs_refcount_unref(&port->ref_cnt) == 1) {
+ int i;
+
netdev_close(port->netdev);
netdev_restore_flags(port->sf);
- netdev_rxq_close(port->rxq);
+
+ for (i = 0; i < netdev_n_rxq(port->netdev); i++) {
+ netdev_rxq_close(port->rxq[i]);
+ }
free(port->type);
free(port);
}
ovs_rwlock_rdlock(&dp->port_rwlock);
HMAP_FOR_EACH (port, node, &dp->ports) {
- if (port->rxq && !netdev_is_pmd(port->netdev)) {
- dp_netdev_process_rxq_port(dp, port, port->rxq);
+ if (!netdev_is_pmd(port->netdev)) {
+ int i;
+
+ for (i = 0; i < netdev_n_rxq(port->netdev); i++) {
+ dp_netdev_process_rxq_port(dp, port, port->rxq[i]);
+ }
}
}
ovs_rwlock_rdlock(&dp->port_rwlock);
HMAP_FOR_EACH (port, node, &dp->ports) {
- if (port->rxq && !netdev_is_pmd(port->netdev)) {
- netdev_rxq_wait(port->rxq);
+ if (!netdev_is_pmd(port->netdev)) {
+ int i;
+
+ for (i = 0; i < netdev_n_rxq(port->netdev); i++) {
+ netdev_rxq_wait(port->rxq[i]);
+ }
}
}
ovs_rwlock_unlock(&dp->port_rwlock);
struct rxq_poll {
struct dp_netdev_port *port;
+ struct netdev_rxq *rx;
};
static int
HMAP_FOR_EACH (port, node, &f->dp->ports) {
if (netdev_is_pmd(port->netdev)) {
- if ((index % dp->n_pmd_threads) == id) {
- poll_list = xrealloc(poll_list, sizeof *poll_list * (poll_cnt + 1));
+ int i;
+
+ for (i = 0; i < netdev_n_rxq(port->netdev); i++) {
+ if ((index % dp->n_pmd_threads) == id) {
+ poll_list = xrealloc(poll_list, sizeof *poll_list * (poll_cnt + 1));
- port_ref(port);
- poll_list[poll_cnt++].port = port;
+ port_ref(port);
+ poll_list[poll_cnt].port = port;
+ poll_list[poll_cnt].rx = port->rxq[i];
+ poll_cnt++;
+ }
+ index++;
}
- index++;
}
}
int i;
for (i = 0; i < poll_cnt; i++) {
- dp_netdev_process_rxq_port(dp, poll_list[i].port, poll_list[i].port->rxq);
+ dp_netdev_process_rxq_port(dp, poll_list[i].port, poll_list[i].rx);
}
if (lc++ > 1024) {
this device. */
/* The following are protected by 'netdev_mutex' (internal to netdev.c). */
+ int n_rxq;
int ref_cnt; /* Times this devices was opened. */
struct shash_node *node; /* Pointer to element in global map. */
struct list saved_flags_list; /* Contains "struct netdev_saved_flags". */
* None of these members change during the lifetime of a struct netdev_rxq. */
struct netdev_rxq {
struct netdev *netdev; /* Owns a reference to the netdev. */
+ int queue_id;
};
struct netdev *netdev_rxq_get_netdev(const struct netdev_rxq *);
* implementation must not refer to base or derived state in the data
* structure, because it has already been uninitialized.
*
+ * If netdev support multi-queue IO then netdev->construct should set initialize
+ * netdev->n_rxq to number of queues.
+ *
* Each "alloc" function allocates and returns a new instance of the respective
* data structure. The "alloc" function is not given any information about the
* use of the new data structure, so it cannot perform much initialization.
static void restore_all_flags(void *aux OVS_UNUSED);
void update_device_args(struct netdev *, const struct shash *args);
+int
+netdev_n_rxq(const struct netdev *netdev)
+{
+ return netdev->n_rxq;
+}
+
bool
netdev_is_pmd(const struct netdev *netdev)
{
netdev->netdev_class = rc->class;
netdev->name = xstrdup(name);
netdev->node = shash_add(&netdev_shash, name, netdev);
+
+ /* By default enable one rx queue per netdev. */
+ if (netdev->netdev_class->rxq_alloc) {
+ netdev->n_rxq = 1;
+ } else {
+ netdev->n_rxq = 0;
+ }
list_init(&netdev->saved_flags_list);
error = rc->class->construct(netdev);
* Some kinds of network devices might not support receiving packets. This
* function returns EOPNOTSUPP in that case.*/
int
-netdev_rxq_open(struct netdev *netdev, struct netdev_rxq **rxp)
+netdev_rxq_open(struct netdev *netdev, struct netdev_rxq **rxp, int id)
OVS_EXCLUDED(netdev_mutex)
{
int error;
- if (netdev->netdev_class->rxq_alloc) {
+ if (netdev->netdev_class->rxq_alloc && id < netdev->n_rxq) {
struct netdev_rxq *rx = netdev->netdev_class->rxq_alloc();
if (rx) {
rx->netdev = netdev;
+ rx->queue_id = id;
error = netdev->netdev_class->rxq_construct(rx);
if (!error) {
ovs_mutex_lock(&netdev_mutex);