> -----Original Message----- > From: dev [mailto:dev-bounces at dpdk.org] On Behalf Of Daniel Mrzyglod > Sent: Friday, September 26, 2014 4:41 PM > To: dev at dpdk.org > Subject: [dpdk-dev] [PATCH v2] ADD mode 5(tlb) to link bonding pmd > > > Signed-off-by: Daniel Mrzyglod <danielx.t.mrzyglod at intel.com> > --- > app/test/test_link_bonding.c | 501 > +++++++++++++++++++++++++++- > app/test/virtual_pmd.c | 6 +- > app/test/virtual_pmd.h | 7 + > lib/librte_pmd_bond/rte_eth_bond.h | 23 ++ > lib/librte_pmd_bond/rte_eth_bond_args.c | 1 + > lib/librte_pmd_bond/rte_eth_bond_pmd.c | 161 ++++++++- > lib/librte_pmd_bond/rte_eth_bond_private.h | 3 +- > 7 files changed, 696 insertions(+), 6 deletions(-) > > diff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c > index c4fcaf7..77f791f 100644 > --- a/app/test/test_link_bonding.c > +++ b/app/test/test_link_bonding.c > @@ -41,7 +41,7 @@ > #include <errno.h> > #include <sys/queue.h> > #include <sys/time.h> > - > +#include <rte_cycles.h> > #include <rte_byteorder.h> > #include <rte_common.h> > #include <rte_debug.h> > @@ -3845,6 +3845,500 @@ testsuite_teardown(void) > return remove_slaves_and_stop_bonded_device(); > } > > +#define NINETY_PERCENT_NUMERAL 90 > +#define ONE_HUNDRED_PERCENT_DENOMINATOR 100 > +#define ONE_HUNDRED_PERCENT_AND_TEN_NUMERAL 110 > +static int > +test_tlb_tx_burst(void) > +{ > + int i, burst_size, nb_tx; > + uint64_t nb_tx2 = 0; > + struct rte_mbuf *pkt_burst[MAX_PKT_BURST]; > + struct rte_eth_stats port_stats[32]; > + uint64_t sum_ports_opackets = 0, all_bond_opackets = 0, > all_bond_obytes = 0; > + uint16_t pktlen; > + > + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves > + > (BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, 1, 3, 1), > + "Failed to initialise bonded device"); > + > + burst_size = 20 * test_params->bonded_slave_count; > + > + TEST_ASSERT(burst_size < MAX_PKT_BURST, > + "Burst size specified is greater than supported.\n"); > + > + > + /* Generate 400000 test bursts in 2s of packets to transmit */ > + for (i = 0; i < 400000; i++) { > + /*test two types of mac src own(bonding) and others */ > + if (i % 2 == 0) { > + initialize_eth_header(test_params->pkt_eth_hdr, > + (struct ether_addr *)src_mac, (struct > ether_addr *)dst_mac_0, 0, 0); > + } else { > + initialize_eth_header(test_params->pkt_eth_hdr, > + (struct ether_addr *)test_params- > >default_slave_mac, > + (struct ether_addr *)dst_mac_0, 0, 0); > + } > + pktlen = initialize_udp_header(test_params->pkt_udp_hdr, > src_port, > + dst_port_0, 16); > + pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, > src_addr, > + dst_addr_0, pktlen); > + generate_packet_burst(test_params->mbuf_pool, pkt_burst, > + test_params->pkt_eth_hdr, 0, test_params- > >pkt_ipv4_hdr, > + 1, test_params->pkt_udp_hdr, burst_size, 60, 1); > + /* Send burst on bonded port */ > + nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, > pkt_burst, > + burst_size); > + nb_tx2 += nb_tx; > + > + TEST_ASSERT_EQUAL(nb_tx, burst_size, > + "number of packet not equal burst size"); > + > + rte_delay_us(5); > + } > + > + > + /* Verify bonded port tx stats */ > + rte_eth_stats_get(test_params->bonded_port_id, &port_stats[0]); > + > + all_bond_opackets = port_stats[0].opackets; > + all_bond_obytes = port_stats[0].obytes; > + > + TEST_ASSERT_EQUAL(port_stats[0].opackets, (uint64_t)nb_tx2, > + "Bonded Port (%d) opackets value (%u) not as expected > (%d)\n", > + test_params->bonded_port_id, (unsigned > int)port_stats[0].opackets, > + burst_size); > + > + > + /* Verify slave ports tx stats */ > + for (i = 0; i < test_params->bonded_slave_count; i++) { > + rte_eth_stats_get(test_params->slave_port_ids[i], > &port_stats[i]); > + sum_ports_opackets += port_stats[i].opackets; > + } > + > + TEST_ASSERT_EQUAL(sum_ports_opackets, (uint64_t)all_bond_opackets, > + "Total packets sent by slaves is not equalto packets > sent by > bond interface"); > + > + for (i = 0; i < test_params->bonded_slave_count; i++) { > + printf("port stats:%"PRIu64"\n", port_stats[i].opackets); > + /* distribution of packets on each slave within +/- 10% of the > expected value. */ > + TEST_ASSERT(port_stats[i].obytes >= > ((all_bond_obytes*NINETY_PERCENT_NUMERAL)/ > + (test_params- > >bonded_slave_count*ONE_HUNDRED_PERCENT_DENOMINATOR)) && > + port_stats[i].obytes <= > ((all_bond_obytes*ONE_HUNDRED_PERCENT_AND_TEN_NUMERAL) / > + (test_params- > >bonded_slave_count*ONE_HUNDRED_PERCENT_DENOMINATOR)), > + "Distribution is not even"); > + } > + /* Put all slaves down and try and transmit */ > + for (i = 0; i < test_params->bonded_slave_count; i++) { > + virtual_ethdev_simulate_link_status_interrupt( > + test_params->slave_port_ids[i], 0); > + } > + > + /* Send burst on bonded port */ > + nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkt_burst, > + burst_size); > + TEST_ASSERT_EQUAL(nb_tx, 0, " bad number of packet in burst"); > + > + /* Clean ugit checkout masterp and remove slaves from bonded device */ > + return remove_slaves_and_stop_bonded_device(); > +} > + > +#define > TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT (4) > + > +static int > +test_tlb_rx_burst(void) > +{ > + struct rte_mbuf *gen_pkt_burst[MAX_PKT_BURST] = { NULL }; > + struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL }; > + > + struct rte_eth_stats port_stats; > + > + int primary_port; > + > + uint16_t i, j, nb_rx, burst_size = 17; > + > + /* Initialize bonded device with 4 slaves in transmit load balancing > mode > */ > + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( > + > BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, > + > TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT > , 1, 1), > + "Failed to initialize bonded device"); > + > + > + primary_port = rte_eth_bond_primary_get(test_params- > >bonded_port_id); > + TEST_ASSERT(primary_port >= 0, > + "failed to get primary slave for bonded port (%d)", > + test_params->bonded_port_id); > + > + for (i = 0; i < test_params->bonded_slave_count; i++) { > + /* Generate test bursts of packets to transmit */ > + TEST_ASSERT_EQUAL(generate_test_burst( > + &gen_pkt_burst[0], burst_size, 0, 1, 0, 0, 0), > burst_size, > + "burst generation failed"); > + > + /* Add rx data to slave */ > + virtual_ethdev_add_mbufs_to_rx_queue(test_params- > >slave_port_ids[i], > + &gen_pkt_burst[0], burst_size); > + > + /* Call rx burst on bonded device */ > + nb_rx = rte_eth_rx_burst(test_params->bonded_port_id, 0, > + &rx_pkt_burst[0], MAX_PKT_BURST); > + > + TEST_ASSERT_EQUAL(nb_rx,burst_size,"rte_eth_rx_burst > failed\n"); > + > + if (test_params->slave_port_ids[i] == primary_port) { > + /* Verify bonded device rx count */ > + rte_eth_stats_get(test_params->bonded_port_id, > &port_stats); > + TEST_ASSERT_EQUAL(port_stats.ipackets, > (uint64_t)burst_size, > + "Bonded Port (%d) ipackets value (%u) > not > as expected (%d)\n", > + test_params->bonded_port_id, > + (unsigned int)port_stats.ipackets, > burst_size); > + > + /* Verify bonded slave devices rx count */ > + for (j = 0; j < test_params->bonded_slave_count; j++) { > + > rte_eth_stats_get(test_params->slave_port_ids[j], > &port_stats); > + if (i == j) { > + TEST_ASSERT_EQUAL(port_stats.ipackets, > (uint64_t)burst_size, > + "Slave Port (%d) > ipackets > value (%u) not as expected (%d)\n", > + test_params- > >slave_port_ids[i], > + (unsigned > int)port_stats.ipackets, burst_size); > + } else { > + TEST_ASSERT_EQUAL(port_stats.ipackets, > (uint64_t)0, > + "Slave Port (%d) > ipackets > value (%u) not as expected (%d)\n", > + test_params- > >slave_port_ids[i], > + (unsigned > int)port_stats.ipackets, 0); > + } > + } > + } else { > + for (j = 0; j < test_params->bonded_slave_count; j++) { > + > rte_eth_stats_get(test_params->slave_port_ids[j], > &port_stats); > + TEST_ASSERT_EQUAL(port_stats.ipackets, > (uint64_t)0, > + "Slave Port (%d) ipackets value > (%u) not as expected (%d)\n", > + test_params->slave_port_ids[i], > + (unsigned > int)port_stats.ipackets, > 0); > + } > + } > + > + /* free mbufs */ > + for (i = 0; i < burst_size; i++) > + rte_pktmbuf_free(rx_pkt_burst[i]); > + > + /* reset bonded device stats */ > + rte_eth_stats_reset(test_params->bonded_port_id); > + } > + > + /* Clean up and remove slaves from bonded device */ > + return remove_slaves_and_stop_bonded_device(); > +} > + > +static int > +test_tlb_verify_promiscuous_enable_disable(void) > +{ > + int i, primary_port, promiscuous_en; > + > + /* Initialize bonded device with 4 slaves in transmit load balancing > mode > */ > + TEST_ASSERT_SUCCESS( initialize_bonded_device_with_slaves( > + > BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, 0, 4, 1), > + "Failed to initialize bonded device"); > + > + primary_port = rte_eth_bond_primary_get(test_params- > >bonded_port_id); > + TEST_ASSERT(primary_port >= 0, > + "failed to get primary slave for bonded port (%d)", > + test_params->bonded_port_id); > + > + rte_eth_promiscuous_enable(test_params->bonded_port_id); > + > + promiscuous_en = rte_eth_promiscuous_get(test_params- > >bonded_port_id); > + TEST_ASSERT_EQUAL(promiscuous_en, (int)1, > + "Port (%d) promiscuous mode not enabled\n", > + test_params->bonded_port_id); > + for (i = 0; i < test_params->bonded_slave_count; i++) { > + promiscuous_en = rte_eth_promiscuous_get( > + test_params->slave_port_ids[i]); > + if (primary_port == test_params->slave_port_ids[i]) { > + TEST_ASSERT_EQUAL(promiscuous_en, (int)1, > + "Port (%d) promiscuous mode not > enabled\n", > + test_params->bonded_port_id); > + } else { > + TEST_ASSERT_EQUAL(promiscuous_en, (int)0, > + "Port (%d) promiscuous mode enabled\n", > + test_params->bonded_port_id); > + } > + > + } > + > + rte_eth_promiscuous_disable(test_params->bonded_port_id); > + > + promiscuous_en = rte_eth_promiscuous_get(test_params- > >bonded_port_id); > + TEST_ASSERT_EQUAL(promiscuous_en, (int)0, > + "Port (%d) promiscuous mode not disabled\n", > + test_params->bonded_port_id); > + > + for (i = 0; i < test_params->bonded_slave_count; i++) { > + promiscuous_en = rte_eth_promiscuous_get( > + test_params->slave_port_ids[i]); > + TEST_ASSERT_EQUAL(promiscuous_en, (int)0, > + "slave port (%d) promiscuous mode not > disabled\n", > + test_params->slave_port_ids[i]); > + } > + > + /* Clean up and remove slaves from bonded device */ > + return remove_slaves_and_stop_bonded_device(); > +} > + > +static int > +test_tlb_verify_mac_assignment(void) > +{ > + struct ether_addr read_mac_addr, expected_mac_addr_0, > expected_mac_addr_1; > + > + rte_eth_macaddr_get(test_params->slave_port_ids[0], > &expected_mac_addr_0); > + rte_eth_macaddr_get(test_params->slave_port_ids[1], > &expected_mac_addr_1); > + > + /* Initialize bonded device with 2 slaves in active backup mode */ > + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( > + > BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, 0, 2, 1), > + "Failed to initialize bonded device"); > + > + /* Verify that bonded MACs is that of first slave and that the other > slave > + * MAC hasn't been changed */ > + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); > + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, > &read_mac_addr, > + sizeof(read_mac_addr)), > + "bonded port (%d) mac address not set to that of primary > port", > + test_params->bonded_port_id); > + > + rte_eth_macaddr_get(test_params->slave_port_ids[0], > &read_mac_addr); > + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, > &read_mac_addr, > + sizeof(read_mac_addr)), > + "slave port (%d) mac address not set to that of primary > port", > + test_params->slave_port_ids[0]); > + > + rte_eth_macaddr_get(test_params->slave_port_ids[1], > &read_mac_addr); > + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, > &read_mac_addr, > + sizeof(read_mac_addr)), > + "slave port (%d) mac address not as expected", > + test_params->slave_port_ids[1]); > + > + /* change primary and verify that MAC addresses haven't changed */ > + TEST_ASSERT_EQUAL(rte_eth_bond_primary_set(test_params- > >bonded_port_id, > + test_params->slave_port_ids[1]), 0, > + "Failed to set bonded port (%d) primary port to (%d)", > + test_params->bonded_port_id, test_params- > >slave_port_ids[1]); > + > + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); > + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, > &read_mac_addr, > + sizeof(read_mac_addr)), > + "bonded port (%d) mac address not set to that of primary > port", > + test_params->bonded_port_id); > + > + rte_eth_macaddr_get(test_params->slave_port_ids[0], > &read_mac_addr); > + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, > &read_mac_addr, > + sizeof(read_mac_addr)), > + "slave port (%d) mac address not set to that of primary > port", > + test_params->slave_port_ids[0]); > + > + rte_eth_macaddr_get(test_params->slave_port_ids[1], > &read_mac_addr); > + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, > &read_mac_addr, > + sizeof(read_mac_addr)), > + "slave port (%d) mac address not as expected", > + test_params->slave_port_ids[1]); > + > + /* stop / start bonded device and verify that primary MAC address is > + * propagated to bonded device and slaves */ > + > + rte_eth_dev_stop(test_params->bonded_port_id); > + > + TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params- > >bonded_port_id), > + "Failed to start device"); > + > + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); > + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, > &read_mac_addr, > + sizeof(read_mac_addr)), > + "bonded port (%d) mac address not set to that of primary > port", > + test_params->bonded_port_id); > + > + rte_eth_macaddr_get(test_params->slave_port_ids[0], > &read_mac_addr); > + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, > &read_mac_addr, > + sizeof(read_mac_addr)), > + "slave port (%d) mac address not as expected", > + test_params->slave_port_ids[0]); > + > + rte_eth_macaddr_get(test_params->slave_port_ids[1], > &read_mac_addr); > + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, > &read_mac_addr, > + sizeof(read_mac_addr)), > + "slave port (%d) mac address not set to that of primary > port", > + test_params->slave_port_ids[1]); > + > + > + /* Set explicit MAC address */ > + TEST_ASSERT_SUCCESS(rte_eth_bond_mac_address_set( > + test_params->bonded_port_id, (struct ether_addr > *)bonded_mac), > + "failed to set MAC addres"); > + > + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); > + TEST_ASSERT_SUCCESS(memcmp(&bonded_mac, &read_mac_addr, > + sizeof(read_mac_addr)), > + "bonded port (%d) mac address not set to that of bonded > port", > + test_params->bonded_port_id); > + > + rte_eth_macaddr_get(test_params->slave_port_ids[0], > &read_mac_addr); > + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, > &read_mac_addr, > + sizeof(read_mac_addr)), > + "slave port (%d) mac address not as expected", > + test_params->slave_port_ids[0]); > + > + rte_eth_macaddr_get(test_params->slave_port_ids[1], > &read_mac_addr); > + TEST_ASSERT_SUCCESS(memcmp(&bonded_mac, &read_mac_addr, > + sizeof(read_mac_addr)), > + "slave port (%d) mac address not set to that of bonded > port", > + test_params->slave_port_ids[1]); > + > + /* Clean up and remove slaves from bonded device */ > + return remove_slaves_and_stop_bonded_device(); > +} > + > +static int > +test_tlb_verify_slave_link_status_change_failover(void) > +{ > + struct rte_mbuf > *pkt_burst[TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_CO > UNT][MAX_PKT_BURST]; > + struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL }; > + struct rte_eth_stats port_stats; > + > + uint8_t slaves[RTE_MAX_ETHPORTS]; > + > + int i, j, burst_size, slave_count, primary_port; > + > + burst_size = 21; > + > + memset(pkt_burst, 0, sizeof(pkt_burst)); > + > + > + > + /* Initialize bonded device with 4 slaves in round robin mode */ > + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( > + > BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, 0, > + > TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT > , 1), > + "Failed to initialize bonded device with slaves"); > + > + /* Verify Current Slaves Count /Active Slave Count is */ > + slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, > slaves, > + RTE_MAX_ETHPORTS); > + TEST_ASSERT_EQUAL(slave_count, 4, > + "Number of slaves (%d) is not as expected (%d).\n", > + slave_count, 4); > + > + slave_count = rte_eth_bond_active_slaves_get(test_params- > >bonded_port_id, > + slaves, RTE_MAX_ETHPORTS); > + TEST_ASSERT_EQUAL(slave_count, (int)4, > + "Number of slaves (%d) is not as expected (%d).\n", > + slave_count, 4); > + > + primary_port = rte_eth_bond_primary_get(test_params- > >bonded_port_id); > + TEST_ASSERT_EQUAL(primary_port, test_params->slave_port_ids[0], > + "Primary port not as expected"); > + > + /* Bring 2 slaves down and verify active slave count */ > + virtual_ethdev_simulate_link_status_interrupt( > + test_params->slave_port_ids[1], 0); > + virtual_ethdev_simulate_link_status_interrupt( > + test_params->slave_port_ids[3], 0); > + > + TEST_ASSERT_EQUAL(rte_eth_bond_active_slaves_get( > + test_params->bonded_port_id, slaves, > RTE_MAX_ETHPORTS), 2, > + "Number of active slaves (%d) is not as expected (%d).", > + slave_count, 2); > + > + virtual_ethdev_simulate_link_status_interrupt( > + test_params->slave_port_ids[1], 1); > + virtual_ethdev_simulate_link_status_interrupt( > + test_params->slave_port_ids[3], 1); > + > + > + /* Bring primary port down, verify that active slave count is 3 and > primary > + * has changed */ > + virtual_ethdev_simulate_link_status_interrupt( > + test_params->slave_port_ids[0], 0); > + > + TEST_ASSERT_EQUAL(rte_eth_bond_active_slaves_get( > + test_params->bonded_port_id, slaves, > RTE_MAX_ETHPORTS), 3, > + "Number of active slaves (%d) is not as expected (%d).", > + slave_count, 3); > + > + primary_port = rte_eth_bond_primary_get(test_params- > >bonded_port_id); > + TEST_ASSERT_EQUAL(primary_port, test_params->slave_port_ids[2], > + "Primary port not as expected"); > + rte_delay_us(500000); > + /* Verify that pkts are sent on new primary slave */ > + for (i = 0; i < 4; i++) { > + TEST_ASSERT_EQUAL(generate_test_burst( > + &pkt_burst[0][0], burst_size, 0, 1, 0, 0, 0), > burst_size, > + "generate_test_burst failed\n"); > + TEST_ASSERT_EQUAL(rte_eth_tx_burst( > + test_params->bonded_port_id, 0, > &pkt_burst[0][0], burst_size), burst_size, > + "rte_eth_tx_burst failed\n"); > + rte_delay_us(11000); > + } > + > + rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats); > + TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0, > + "(%d) port_stats.opackets not as expected\n", > + test_params->slave_port_ids[2]); > + > + rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats); > + TEST_ASSERT_EQUAL(port_stats.opackets, (int8_t)0, > + "(%d) port_stats.opackets not as expected\n", > + test_params->slave_port_ids[0]); > + > + rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats); > + TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0, > + "(%d) port_stats.opackets not as expected\n", > + test_params->slave_port_ids[1]); > + > + rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats); > + TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0, > + "(%d) port_stats.opackets not as expected\n", > + test_params->slave_port_ids[3]); > + > + > + /* Generate packet burst for testing */ > + > + for (i = 0; i < > TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT; i++) { > + if (generate_test_burst(&pkt_burst[i][0], burst_size, 0, 1, 0, > 0, 0) > != > + burst_size) > + return -1; > + > + virtual_ethdev_add_mbufs_to_rx_queue( > + test_params->slave_port_ids[i], > &pkt_burst[i][0], > burst_size); > + } > + > + if (rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst, > + MAX_PKT_BURST) != burst_size) { > + printf("rte_eth_rx_burst\n"); > + return -1; > + > + } > + > + /* Verify bonded device rx count */ > + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); > + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size, > + "(%d) port_stats.ipackets not as expected\n", > + test_params->bonded_port_id); > + > + /* free mbufs */ > + > + for (i = 0; i < > TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT; i++) { > + for (j = 0; j < MAX_PKT_BURST; j++) { > + if (pkt_burst[i][j] != NULL) { > + rte_pktmbuf_free(pkt_burst[i][j]); > + pkt_burst[i][j] = NULL; > + } > + } > + } > + > + > + /* Clean up and remove slaves from bonded device */ > + return remove_slaves_and_stop_bonded_device(); > +} > + > > static struct unit_test_suite link_bonding_test_suite = { > .suite_name = "Link Bonding Unit Test Suite", > @@ -3898,6 +4392,11 @@ static struct unit_test_suite link_bonding_test_suite > = { > TEST_CASE(test_balance_verify_promiscuous_enable_disable), > TEST_CASE(test_balance_verify_mac_assignment), > > TEST_CASE(test_balance_verify_slave_link_status_change_behaviour), > + TEST_CASE(test_tlb_tx_burst), > + TEST_CASE(test_tlb_rx_burst), > + TEST_CASE(test_tlb_verify_mac_assignment), > + TEST_CASE(test_tlb_verify_promiscuous_enable_disable), > + TEST_CASE(test_tlb_verify_slave_link_status_change_failover), > TEST_CASE(test_broadcast_tx_burst), > TEST_CASE(test_broadcast_tx_burst_slave_tx_fail), > TEST_CASE(test_broadcast_rx_burst), > diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c > index fffaa35..331bec3 100644 > --- a/app/test/virtual_pmd.c > +++ b/app/test/virtual_pmd.c > @@ -359,16 +359,18 @@ virtual_ethdev_tx_burst_success(void *queue, struct > rte_mbuf **bufs, > > struct rte_eth_dev *vrtl_eth_dev; > struct virtual_ethdev_private *dev_private; > - > + uint64_t obytes = 0; > int i; > > + for (i = 0; i < nb_pkts; i++) > + obytes += rte_pktmbuf_pkt_len(bufs[i]); > vrtl_eth_dev = &rte_eth_devices[tx_q->port_id]; > dev_private = vrtl_eth_dev->data->dev_private; > > if (vrtl_eth_dev->data->dev_link.link_status) { > /* increment opacket count */ > dev_private->eth_stats.opackets += nb_pkts; > - > + dev_private->eth_stats.obytes += obytes; > /* free packets in burst */ > for (i = 0; i < nb_pkts; i++) { > rte_pktmbuf_free(bufs[i]); > diff --git a/app/test/virtual_pmd.h b/app/test/virtual_pmd.h > index 2462853..4118e3e 100644 > --- a/app/test/virtual_pmd.h > +++ b/app/test/virtual_pmd.h > @@ -94,6 +94,13 @@ void > virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count(uint8_t port_id, > uint8_t packet_fail_count); > > +/* if a value greater than zero is set for packet_fail_count then virtual > + * device tx burst function will fail that many packet from burst or all > + * packets if packet_fail_count is greater than the number of packets in the > + * burst */ > +void virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count(uint8_t port_id, > + uint8_t packet_fail_count); > + > #ifdef __cplusplus > } > #endif > diff --git a/lib/librte_pmd_bond/rte_eth_bond.h > b/lib/librte_pmd_bond/rte_eth_bond.h > index 6811c7b..682e5c7 100644 > --- a/lib/librte_pmd_bond/rte_eth_bond.h > +++ b/lib/librte_pmd_bond/rte_eth_bond.h > @@ -75,6 +75,29 @@ extern "C" { > /**< Broadcast (Mode 3). > * In this mode all transmitted packets will be transmitted on all available > * active slaves of the bonded. */ > +#define BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING (5) > +/**< Broadcast (Mode 5) > + * Adaptive transmit load balancing: channel bonding that > + * does not require any special switch support. The > + * outgoing traffic is distributed according to the > + * current load (computed relative to the speed) on each > + * slave. Incoming traffic is received by the current > + * slave. If the receiving slave fails, another slave > + * takes over the MAC address of the failed receiving > + * slave.*/ > +#define BONDING_MODE_ADAPTIVE_LOAD_BALANCING > (6) > +/** > + * Adaptive load balancing: includes balance-tlb plus > + * receive load balancing (rlb) for IPV4 traffic, and > + * does not require any special switch support. The > + * receive load balancing is achieved by ARP negotiation. > + * The bonding driver intercepts the ARP Replies sent by > + * the local system on their way out and overwrites the > + * source hardware address with the unique hardware > + * address of one of the slaves in the bond such that > + * different peers use different hardware addresses for > + * the server. */ > + > > /* Balance Mode Transmit Policies */ > #define BALANCE_XMIT_POLICY_LAYER2 (0) > diff --git a/lib/librte_pmd_bond/rte_eth_bond_args.c > b/lib/librte_pmd_bond/rte_eth_bond_args.c > index bbbc69b..7464af5 100644 > --- a/lib/librte_pmd_bond/rte_eth_bond_args.c > +++ b/lib/librte_pmd_bond/rte_eth_bond_args.c > @@ -171,6 +171,7 @@ bond_ethdev_parse_slave_mode_kvarg(const char *key > __rte_unused, > case BONDING_MODE_ACTIVE_BACKUP: > case BONDING_MODE_BALANCE: > case BONDING_MODE_BROADCAST: > + case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING: > return 0; > default: > RTE_BOND_LOG(ERR, "Invalid slave mode value (%s) specified", > value); > diff --git a/lib/librte_pmd_bond/rte_eth_bond_pmd.c > b/lib/librte_pmd_bond/rte_eth_bond_pmd.c > index 6d0fb1b..db6a934 100644 > --- a/lib/librte_pmd_bond/rte_eth_bond_pmd.c > +++ b/lib/librte_pmd_bond/rte_eth_bond_pmd.c > @@ -30,7 +30,7 @@ > * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE > USE > * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > */ > - > +#include <stdlib.h> > #include <rte_mbuf.h> > #include <rte_malloc.h> > #include <rte_ethdev.h> > @@ -41,10 +41,13 @@ > #include <rte_kvargs.h> > #include <rte_dev.h> > #include <rte_alarm.h> > +#include <rte_cycles.h> > > #include "rte_eth_bond.h" > #include "rte_eth_bond_private.h" > > +#define REORDER_PERIOD_MS 10 > + > static uint16_t > bond_ethdev_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) > { > @@ -287,6 +290,141 @@ xmit_slave_hash(const struct rte_mbuf *buf, uint8_t > slave_count, uint8_t policy) > return hash % slave_count; > } > > +struct bwg_slave { > + uint64_t bwg_left_int; > + uint64_t bwg_left_remainder; > + uint8_t slave; > +}; > + > +static int > +bandwidth_cmp(const void *a, const void *b) > +{ > + const struct bwg_slave *bwg_a = a; > + const struct bwg_slave *bwg_b = b; > + int64_t diff = (int64_t)bwg_b->bwg_left_int - (int64_t)bwg_a- > >bwg_left_int; > + int64_t diff2 = (int64_t)bwg_b->bwg_left_remainder - > + (int64_t)bwg_a->bwg_left_remainder; > + if (diff > 0) > + return 1; > + else if (diff < 0) > + return -1; > + else if (diff2 > 0) > + return 1; > + else if (diff2 < 0) > + return -1; > + else > + return 0; > +} > + > +static void > +bandwidth_left(int port_id, uint64_t load, uint8_t update_idx, struct > bwg_slave > *bwg_slave) > +{ > + struct rte_eth_link link_status; > + > + rte_eth_link_get(port_id, &link_status); > + uint64_t link_bwg = link_status.link_speed * 1000000ULL / 8; > + if (link_bwg == 0) > + return; > + link_bwg = (link_bwg * (update_idx+1) * REORDER_PERIOD_MS); > + bwg_slave->bwg_left_int = (link_bwg - 1000*load) / link_bwg; > + bwg_slave->bwg_left_remainder = (link_bwg - 1000*load) % link_bwg; > +} > + > +static void > +bond_ethdev_update_tlb_slave_cb(void *arg) > +{ > + struct bond_dev_private *internals = arg; > + struct rte_eth_stats slave_stats; > + struct bwg_slave bwg_array[RTE_MAX_ETHPORTS]; > + uint8_t slave_count; > + uint64_t tx_bytes; > + uint8_t update_stats = 0; > + int8_t i; > + > + internals->slave_update_idx++; > + > + > + if (internals->slave_update_idx >= REORDER_PERIOD_MS) > + update_stats = 1; > + > + for (i = 0; i < internals->active_slave_count; i++) { > + rte_eth_stats_get(internals->active_slaves[i], &slave_stats); > + tx_bytes = slave_stats.obytes - > + internals->slaves[i].last_obytes; > + bandwidth_left(internals->active_slaves[i], tx_bytes, > + internals->slave_update_idx, &bwg_array[i]); > + bwg_array[i].slave = internals->active_slaves[i]; > + > + if (update_stats) > + internals->slaves[i].last_obytes = slave_stats.obytes; > + } > + > + if (update_stats == 1) > + internals->slave_update_idx = 0; > + > + slave_count = i; > + qsort(bwg_array, slave_count, sizeof(bwg_array[0]), bandwidth_cmp); > + for (i = 0; i < slave_count; i++) > + internals->active_slaves[i] = bwg_array[i].slave; > + > + rte_eal_alarm_set(REORDER_PERIOD_MS * 1000, > bond_ethdev_update_tlb_slave_cb, > + (struct bond_dev_private *)internals); > +} > + > +static uint16_t > +bond_ethdev_tx_burst_tlb(void *queue, struct rte_mbuf **bufs, uint16_t > nb_pkts) > +{ > + struct bond_tx_queue *bd_tx_q = (struct bond_tx_queue *)queue; > + struct bond_dev_private *internals = bd_tx_q->dev_private; > + > + struct rte_eth_dev *primary_port = &rte_eth_devices[internals- > >primary_port]; > + uint16_t num_tx_total = 0; > + uint8_t i, j; > + > + uint8_t num_of_slaves = internals->active_slave_count; > + uint8_t slaves[RTE_MAX_ETHPORTS]; > + > + struct ether_hdr *ether_hdr; > + struct ether_addr primary_slave_addr; > + struct ether_addr active_slave_addr; > + > + if (num_of_slaves < 1) > + return num_tx_total; > + > + memcpy(slaves, internals->active_slaves, > + sizeof(internals->active_slaves[0]) * > num_of_slaves); > + > + > + ether_addr_copy(primary_port->data->mac_addrs, > &primary_slave_addr); > + > + if (nb_pkts > 3) { > + for (i = 0; i < 3; i++) > + rte_prefetch0(rte_pktmbuf_mtod(bufs[i], void*)); > + } > + > + for (i = 0; i < num_of_slaves; i++) { > + ether_addr_copy(&internals- > >slaves[slaves[i]].persisted_mac_addr, > + &active_slave_addr); > + > + for (j = num_tx_total; j < nb_pkts; j++) { > + if (j + 3 < nb_pkts) > + rte_prefetch0(rte_pktmbuf_mtod(bufs[j+3], > void*)); > + > + ether_hdr = rte_pktmbuf_mtod(bufs[j], struct ether_hdr > *); > + if (is_same_ether_addr(ðer_hdr->s_addr, > &primary_slave_addr)) > + ether_addr_copy(&active_slave_addr, > ðer_hdr->s_addr); > + } > + > + num_tx_total += rte_eth_tx_burst(slaves[i], bd_tx_q->queue_id, > + bufs + num_tx_total, nb_pkts - num_tx_total); > + > + if (num_tx_total == nb_pkts) > + break; > + } > + > + return num_tx_total; > +} > + > static uint16_t > bond_ethdev_tx_burst_balance(void *queue, struct rte_mbuf **bufs, > uint16_t nb_pkts) > @@ -495,6 +633,7 @@ mac_address_slaves_update(struct rte_eth_dev > *bonded_eth_dev) > } > break; > case BONDING_MODE_ACTIVE_BACKUP: > + case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING: > default: > for (i = 0; i < internals->slave_count; i++) { > if (internals->slaves[i].port_id == > @@ -544,6 +683,10 @@ bond_ethdev_mode_set(struct rte_eth_dev *eth_dev, > int mode) > eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_broadcast; > eth_dev->rx_pkt_burst = bond_ethdev_rx_burst; > break; > + case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING: > + eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_tlb; > + eth_dev->rx_pkt_burst = bond_ethdev_rx_burst_active_backup; > + break; > default: > return -1; > } > @@ -757,6 +900,9 @@ bond_ethdev_start(struct rte_eth_dev *eth_dev) > bond_ethdev_slave_link_status_change_monitor, > (void *)eth_dev); > > + if (internals->mode == > BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING) { > + bond_ethdev_update_tlb_slave_cb(internals); > + } > return 0; > } > > @@ -765,6 +911,9 @@ bond_ethdev_stop(struct rte_eth_dev *eth_dev) > { > struct bond_dev_private *internals = eth_dev->data->dev_private; > > + if (internals->mode == > BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING) { > + rte_eal_alarm_cancel(bond_ethdev_update_tlb_slave_cb, > internals); > + } > internals->active_slave_count = 0; > internals->link_status_polling_enabled = 0; > > @@ -775,6 +924,12 @@ bond_ethdev_stop(struct rte_eth_dev *eth_dev) > static void > bond_ethdev_close(struct rte_eth_dev *dev __rte_unused) > { > + struct bond_dev_private *internals = dev->data->dev_private; > + > + if (internals->mode == > BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING) { > + rte_eal_alarm_cancel(bond_ethdev_update_tlb_slave_cb, > internals); > + } > + internals->active_slave_count = 0; > } > > static int > @@ -884,7 +1039,7 @@ bond_ethdev_slave_link_status_change_monitor(void > *cb_arg) > > /* If device is currently being configured then don't check slaves link > * status, wait until next period */ > - if (rte_spinlock_trylock(&internals->lock)){ > + if (rte_spinlock_trylock(&internals->lock)) { > for (i = 0; i < internals->slave_count; i++) { > if (internals->slaves[i].link_status_polling_enabled) { > slave_ethdev = &rte_eth_devices[internals- > >slaves[i].port_id]; > @@ -1004,6 +1159,7 @@ bond_ethdev_promiscuous_enable(struct > rte_eth_dev *eth_dev) > break; > /* Promiscuous mode is propagated only to primary slave */ > case BONDING_MODE_ACTIVE_BACKUP: > + case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING: > default: > rte_eth_promiscuous_enable(internals->current_primary_port); > > @@ -1028,6 +1184,7 @@ bond_ethdev_promiscuous_disable(struct > rte_eth_dev *dev) > break; > /* Promiscuous mode is propagated only to primary slave */ > case BONDING_MODE_ACTIVE_BACKUP: > + case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING: > default: > rte_eth_promiscuous_disable(internals->current_primary_port); > } > diff --git a/lib/librte_pmd_bond/rte_eth_bond_private.h > b/lib/librte_pmd_bond/rte_eth_bond_private.h > index 6db5144..f7186a8 100644 > --- a/lib/librte_pmd_bond/rte_eth_bond_private.h > +++ b/lib/librte_pmd_bond/rte_eth_bond_private.h > @@ -89,7 +89,6 @@ struct bond_tx_queue { > /**< Copy of TX configuration structure for queue */ > }; > > - > /** Bonded slave devices structure */ > struct bond_ethdev_slave_ports { > uint8_t slaves[RTE_MAX_ETHPORTS]; /**< Slave port id array */ > @@ -102,6 +101,7 @@ struct bond_slave_details { > uint8_t link_status_polling_enabled; > uint8_t link_status_wait_to_complete; > uint8_t last_link_status; > + uint64_t last_obytes; > > /**< Port Id of slave eth_dev */ > struct ether_addr persisted_mac_addr; > @@ -143,6 +143,7 @@ struct bond_dev_private { > uint8_t slave_count; /**< Number of bonded slaves */ > struct bond_slave_details slaves[RTE_MAX_ETHPORTS]; > /**< Arary of bonded slaves details */ > + uint8_t slave_update_idx; > }; > > extern struct eth_dev_ops default_dev_ops; > -- > 1.7.9.5
Acked-by: Declan Doherty <declan.doherty at intel.com>