dpdk bond
bond_ethdev_mode_set(struct rte_eth_dev *eth_dev, int mode) { struct bond_dev_private *internals; internals = eth_dev->data->dev_private; switch (mode) { case BONDING_MODE_ROUND_ROBIN: eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_round_robin; eth_dev->rx_pkt_burst = bond_ethdev_rx_burst; break; case BONDING_MODE_ACTIVE_BACKUP: eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_active_backup; eth_dev->rx_pkt_burst = bond_ethdev_rx_burst_active_backup; break; case BONDING_MODE_BALANCE: eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_balance; eth_dev->rx_pkt_burst = bond_ethdev_rx_burst; break; case BONDING_MODE_BROADCAST: eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_broadcast; eth_dev->rx_pkt_burst = bond_ethdev_rx_burst; break; case BONDING_MODE_8023AD: if (bond_mode_8023ad_enable(eth_dev) != 0) return -1; if (internals->mode4.dedicated_queues.enabled == 0) { eth_dev->rx_pkt_burst = bond_ethdev_rx_burst_8023ad; eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_8023ad; RTE_BOND_LOG(WARNING, "Using mode 4, it is necessary to do TX burst " "and RX burst at least every 100ms."); } else { /* Use flow director's optimization */ eth_dev->rx_pkt_burst = bond_ethdev_rx_burst_8023ad_fast_queue; eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_8023ad_fast_queue; } break; case BONDING_MODE_TLB: eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_tlb; eth_dev->rx_pkt_burst = bond_ethdev_rx_burst_active_backup; break; case BONDING_MODE_ALB: if (bond_mode_alb_enable(eth_dev) != 0) return -1; eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_alb; eth_dev->rx_pkt_burst = bond_ethdev_rx_burst_alb; break; default: return -1; } internals->mode = mode; return 0; }
bond_ethdev_rx_queue_setup
static int bond_ethdev_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id, uint16_t nb_rx_desc, unsigned int socket_id __rte_unused, const struct rte_eth_rxconf *rx_conf, struct rte_mempool *mb_pool) { struct bond_rx_queue *bd_rx_q = (struct bond_rx_queue *) rte_zmalloc_socket(NULL, sizeof(struct bond_rx_queue), 0, dev->data->numa_node); if (bd_rx_q == NULL) return -1; bd_rx_q->queue_id = rx_queue_id; bd_rx_q->dev_private = dev->data->dev_private; bd_rx_q->nb_rx_desc = nb_rx_desc; memcpy(&(bd_rx_q->rx_conf), rx_conf, sizeof(struct rte_eth_rxconf)); bd_rx_q->mb_pool = mb_pool; dev->data->rx_queues[rx_queue_id] = bd_rx_q; return 0; }
bond_ethdev_rx_burst
static uint16_t bond_ethdev_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) { struct bond_dev_private *internals; uint16_t num_rx_total = 0; uint16_t slave_count; uint16_t active_slave; int i; /* Cast to structure, containing bonded device's port id and queue id */ struct bond_rx_queue *bd_rx_q = (struct bond_rx_queue *)queue; internals = bd_rx_q->dev_private; slave_count = internals->active_slave_count; active_slave = internals->active_slave; for (i = 0; i < slave_count && nb_pkts; i++) { uint16_t num_rx_slave; /* Offset of pointer to *bufs increases as packets are received * from other slaves */ num_rx_slave = rte_eth_rx_burst(internals->active_slaves[active_slave], bd_rx_q->queue_id, bufs + num_rx_total, nb_pkts); num_rx_total += num_rx_slave; nb_pkts -= num_rx_slave; if (++active_slave == slave_count) active_slave = 0; } if (++internals->active_slave >= slave_count) internals->active_slave = 0; return num_rx_total; }
rte_eth_bond_slave_add
rte_eth_bond_slave_add(uint16_t bonded_port_id, uint16_t slave_port_id) { struct rte_eth_dev *bonded_eth_dev; struct bond_dev_private *internals; int retval; /* Verify that port id's are valid bonded and slave ports */ if (valid_bonded_port_id(bonded_port_id) != 0) return -1; bonded_eth_dev = &rte_eth_devices[bonded_port_id]; internals = bonded_eth_dev->data->dev_private; rte_spinlock_lock(&internals->lock); retval = __eth_bond_slave_add_lock_free(bonded_port_id, slave_port_id); rte_spinlock_unlock(&internals->lock); return retval; }
static int __eth_bond_slave_add_lock_free(uint16_t bonded_port_id, uint16_t slave_port_id) { struct rte_eth_dev *bonded_eth_dev, *slave_eth_dev; struct bond_dev_private *internals; struct rte_eth_link link_props; struct rte_eth_dev_info dev_info; int ret; bonded_eth_dev = &rte_eth_devices[bonded_port_id]; internals = bonded_eth_dev->data->dev_private; if (valid_slave_port_id(slave_port_id, internals->mode) != 0) return -1; slave_eth_dev = &rte_eth_devices[slave_port_id]; if (slave_eth_dev->data->dev_flags & RTE_ETH_DEV_BONDED_SLAVE) { RTE_BOND_LOG(ERR, "Slave device is already a slave of a bonded device"); return -1; } ret = rte_eth_dev_info_get(slave_port_id, &dev_info); if (ret != 0) { RTE_BOND_LOG(ERR, "%s: Error during getting device (port %u) info: %s\n", __func__, slave_port_id, strerror(-ret)); return ret; } if (dev_info.max_rx_pktlen < internals->max_rx_pktlen) { RTE_BOND_LOG(ERR, "Slave (port %u) max_rx_pktlen too small", slave_port_id); return -1; } slave_add(internals, slave_eth_dev); /* We need to store slaves reta_size to be able to synchronize RETA for all * slave devices even if its sizes are different. */ internals->slaves[internals->slave_count].reta_size = dev_info.reta_size; if (internals->slave_count < 1) { /* if MAC is not user defined then use MAC of first slave add to * bonded device */ if (!internals->user_defined_mac) { if (mac_address_set(bonded_eth_dev, slave_eth_dev->data->mac_addrs)) { RTE_BOND_LOG(ERR, "Failed to set MAC address"); return -1; } } /* Make primary slave */ internals->primary_port = slave_port_id; internals->current_primary_port = slave_port_id;
/* Inherit queues settings from first slave */ internals->nb_rx_queues = slave_eth_dev->data->nb_rx_queues; internals->nb_tx_queues = slave_eth_dev->data->nb_tx_queues; eth_bond_slave_inherit_dev_info_rx_first(internals, &dev_info); eth_bond_slave_inherit_dev_info_tx_first(internals, &dev_info); eth_bond_slave_inherit_desc_lim_first(&internals->rx_desc_lim, &dev_info.rx_desc_lim); eth_bond_slave_inherit_desc_lim_first(&internals->tx_desc_lim, &dev_info.tx_desc_lim); } else { int ret; eth_bond_slave_inherit_dev_info_rx_next(internals, &dev_info); eth_bond_slave_inherit_dev_info_tx_next(internals, &dev_info); ret = eth_bond_slave_inherit_desc_lim_next( &internals->rx_desc_lim, &dev_info.rx_desc_lim); if (ret != 0) return ret; ret = eth_bond_slave_inherit_desc_lim_next( &internals->tx_desc_lim, &dev_info.tx_desc_lim); if (ret != 0) return ret; } bonded_eth_dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf &= internals->flow_type_rss_offloads; if (slave_rte_flow_prepare(internals->slave_count, internals) != 0) { RTE_BOND_LOG(ERR, "Failed to prepare new slave flows: port=%d", slave_port_id); return -1; } /* Add additional MAC addresses to the slave */ if (slave_add_mac_addresses(bonded_eth_dev, slave_port_id) != 0) { RTE_BOND_LOG(ERR, "Failed to add mac address(es) to slave %hu", slave_port_id); return -1; } internals->slave_count++; if (bonded_eth_dev->data->dev_started) { if (slave_configure(bonded_eth_dev, slave_eth_dev) != 0) { internals->slave_count--; RTE_BOND_LOG(ERR, "rte_bond_slaves_configure: port=%d", slave_port_id); return -1; } } /* Update all slave devices MACs */ mac_address_slaves_update(bonded_eth_dev); /* Register link status change callback with bonded device pointer as * argument*/ rte_eth_dev_callback_register(slave_port_id, RTE_ETH_EVENT_INTR_LSC, bond_ethdev_lsc_event_callback, &bonded_eth_dev->data->port_id); /* If bonded device is started then we can add the slave to our active * slave array */ if (bonded_eth_dev->data->dev_started) { ret = rte_eth_link_get_nowait(slave_port_id, &link_props); if (ret < 0) { rte_eth_dev_callback_unregister(slave_port_id, RTE_ETH_EVENT_INTR_LSC,
/* If bonded device is started then we can add the slave to our active * slave array */ if (bonded_eth_dev->data->dev_started) { ret = rte_eth_link_get_nowait(slave_port_id, &link_props); if (ret < 0) { rte_eth_dev_callback_unregister(slave_port_id, RTE_ETH_EVENT_INTR_LSC, bond_ethdev_lsc_event_callback, &bonded_eth_dev->data->port_id); internals->slave_count--; RTE_BOND_LOG(ERR, "Slave (port %u) link get failed: %s\n", slave_port_id, rte_strerror(-ret)); return -1; } if (link_props.link_status == ETH_LINK_UP) { if (internals->active_slave_count == 0 && !internals->user_defined_primary_port) bond_ethdev_primary_set(internals, slave_port_id); } } /* Add slave details to bonded device */ slave_eth_dev->data->dev_flags |= RTE_ETH_DEV_BONDED_SLAVE; slave_vlan_filter_set(bonded_port_id, slave_port_id); return 0; }
eth_bond_slave_inherit_dev_info_rx_next
static void eth_bond_slave_inherit_dev_info_rx_next(struct bond_dev_private *internals, const struct rte_eth_dev_info *di) { struct rte_eth_rxconf *rxconf_i = &internals->default_rxconf; const struct rte_eth_rxconf *rxconf = &di->default_rxconf; internals->rx_offload_capa &= di->rx_offload_capa; internals->rx_queue_offload_capa &= di->rx_queue_offload_capa; internals->flow_type_rss_offloads &= di->flow_type_rss_offloads; /* * If at least one slave device suggests enabling this * setting by default, enable it for all slave devices * since disabling it may not be necessarily supported. */ if (rxconf->rx_drop_en == 1) rxconf_i->rx_drop_en = 1; /* * Adding a new slave device may cause some of previously inherited * offloads to be withdrawn from the internal rx_queue_offload_capa * value. Thus, the new internal value of default Rx queue offloads * has to be masked by rx_queue_offload_capa to make sure that only * commonly supported offloads are preserved from both the previous * value and the value being inhereted from the new slave device. */ rxconf_i->offloads = (rxconf_i->offloads | rxconf->offloads) & internals->rx_queue_offload_capa; /* * RETA size is GCD of all slaves RETA sizes, so, if all sizes will be * the power of 2, the lower one is GCD */ if (internals->reta_size > di->reta_size) internals->reta_size = di->reta_size; if (!internals->max_rx_pktlen && di->max_rx_pktlen < internals->candidate_max_rx_pktlen) internals->candidate_max_rx_pktlen = di->max_rx_pktlen; }
primary
bond_ethdev_primary_set(struct bond_dev_private *internals, uint16_t slave_port_id) { int i; if (internals->active_slave_count < 1) internals->current_primary_port = slave_port_id; else /* Search bonded device slave ports for new proposed primary port */ for (i = 0; i < internals->active_slave_count; i++) { if (internals->active_slaves[i] == slave_port_id) internals->current_primary_port = slave_port_id; } }
bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev) { struct bond_dev_private *internals = eth_dev->data->dev_private; int i; int ret = 0; uint16_t port_id; switch (internals->mode) { /* Promiscuous mode is propagated to all slaves */ case BONDING_MODE_ROUND_ROBIN: case BONDING_MODE_BALANCE: case BONDING_MODE_BROADCAST: case BONDING_MODE_8023AD: { unsigned int slave_ok = 0; for (i = 0; i < internals->slave_count; i++) { port_id = internals->slaves[i].port_id; ret = rte_eth_promiscuous_enable(port_id); if (ret != 0) RTE_BOND_LOG(ERR, "Failed to enable promiscuous mode for port %u: %s", port_id, rte_strerror(-ret)); else slave_ok++; } /* * Report success if operation is successful on at least * on one slave. Otherwise return last error code. */ if (slave_ok > 0) ret = 0; break; } /* Promiscuous mode is propagated only to primary slave */ case BONDING_MODE_ACTIVE_BACKUP: case BONDING_MODE_TLB: case BONDING_MODE_ALB: default: /* Do not touch promisc when there cannot be primary ports */ if (internals->slave_count == 0) break; port_id = internals->current_primary_port; ret = rte_eth_promiscuous_enable(port_id); if (ret != 0) RTE_BOND_LOG(ERR, "Failed to enable promiscuous mode for port %u: %s", port_id, rte_strerror(-ret)); } return ret; }