+static int
+test_mode4_ext_ctrl(void)
+{
+ /*
+ * configure bonded interface without the external sm enabled
+ * . try to transmit lacpdu (should fail)
+ * . try to set collecting and distributing flags (should fail)
+ * reconfigure w/external sm
+ * . transmit one lacpdu on each slave using new api
+ * . make sure each slave receives one lacpdu using the callback api
+ * . transmit one data pdu on each slave (should fail)
+ * . enable distribution and collection, send one data pdu each again
+ */
+
+ int retval;
+ struct slave_conf *slave = NULL;
+ uint8_t i;
+
+ struct rte_mbuf *lacp_tx_buf[SLAVE_COUNT];
+ struct rte_ether_addr src_mac, dst_mac;
+ struct lacpdu_header lacpdu = {
+ .lacpdu = {
+ .subtype = SLOW_SUBTYPE_LACP,
+ },
+ };
+
+ rte_ether_addr_copy(&parnter_system, &src_mac);
+ rte_ether_addr_copy(&slow_protocol_mac_addr, &dst_mac);
+
+ initialize_eth_header(&lacpdu.eth_hdr, &src_mac, &dst_mac,
+ RTE_ETHER_TYPE_SLOW, 0, 0);
+
+ for (i = 0; i < SLAVE_COUNT; i++) {
+ lacp_tx_buf[i] = rte_pktmbuf_alloc(test_params.mbuf_pool);
+ rte_memcpy(rte_pktmbuf_mtod(lacp_tx_buf[i], char *),
+ &lacpdu, sizeof(lacpdu));
+ rte_pktmbuf_pkt_len(lacp_tx_buf[i]) = sizeof(lacpdu);
+ }
+
+ retval = initialize_bonded_device_with_slaves(TEST_TX_SLAVE_COUNT, 0);
+ TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device");
+
+ FOR_EACH_SLAVE(i, slave) {
+ TEST_ASSERT_FAIL(rte_eth_bond_8023ad_ext_slowtx(
+ test_params.bonded_port_id,
+ slave->port_id, lacp_tx_buf[i]),
+ "Slave should not allow manual LACP xmit");
+ TEST_ASSERT_FAIL(rte_eth_bond_8023ad_ext_collect(
+ test_params.bonded_port_id,
+ slave->port_id, 1),
+ "Slave should not allow external state controls");
+ }
+
+ free_pkts(lacp_tx_buf, RTE_DIM(lacp_tx_buf));
+
+ retval = remove_slaves_and_stop_bonded_device();
+ TEST_ASSERT_SUCCESS(retval, "Bonded device cleanup failed.");
+
+ return TEST_SUCCESS;
+}
+
+
+static int
+test_mode4_ext_lacp(void)
+{
+ int retval;
+ struct slave_conf *slave = NULL;
+ uint8_t all_slaves_done = 0, i;
+ uint16_t nb_pkts;
+ const unsigned int delay = bond_get_update_timeout_ms();
+
+ struct rte_mbuf *lacp_tx_buf[SLAVE_COUNT];
+ struct rte_mbuf *buf[SLAVE_COUNT];
+ struct rte_ether_addr src_mac, dst_mac;
+ struct lacpdu_header lacpdu = {
+ .lacpdu = {
+ .subtype = SLOW_SUBTYPE_LACP,
+ },
+ };
+
+ rte_ether_addr_copy(&parnter_system, &src_mac);
+ rte_ether_addr_copy(&slow_protocol_mac_addr, &dst_mac);
+
+ initialize_eth_header(&lacpdu.eth_hdr, &src_mac, &dst_mac,
+ RTE_ETHER_TYPE_SLOW, 0, 0);
+
+ for (i = 0; i < SLAVE_COUNT; i++) {
+ lacp_tx_buf[i] = rte_pktmbuf_alloc(test_params.mbuf_pool);
+ rte_memcpy(rte_pktmbuf_mtod(lacp_tx_buf[i], char *),
+ &lacpdu, sizeof(lacpdu));
+ rte_pktmbuf_pkt_len(lacp_tx_buf[i]) = sizeof(lacpdu);
+ }
+
+ retval = initialize_bonded_device_with_slaves(TEST_TX_SLAVE_COUNT, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device");
+
+ memset(lacpdu_rx_count, 0, sizeof(lacpdu_rx_count));
+
+ /* Wait for new settings to be applied. */
+ for (i = 0; i < 30; ++i)
+ rte_delay_ms(delay);
+
+ FOR_EACH_SLAVE(i, slave) {
+ retval = rte_eth_bond_8023ad_ext_slowtx(
+ test_params.bonded_port_id,
+ slave->port_id, lacp_tx_buf[i]);
+ TEST_ASSERT_SUCCESS(retval,
+ "Slave should allow manual LACP xmit");
+ }
+
+ nb_pkts = bond_tx(NULL, 0);
+ TEST_ASSERT_EQUAL(nb_pkts, 0, "Packets transmitted unexpectedly");
+
+ FOR_EACH_SLAVE(i, slave) {
+ nb_pkts = slave_get_pkts(slave, buf, RTE_DIM(buf));
+ TEST_ASSERT_EQUAL(nb_pkts, 1, "found %u packets on slave %d\n",
+ nb_pkts, i);
+ slave_put_pkts(slave, buf, nb_pkts);
+ }
+
+ nb_pkts = bond_rx(buf, RTE_DIM(buf));
+ free_pkts(buf, nb_pkts);
+ TEST_ASSERT_EQUAL(nb_pkts, 0, "Packets received unexpectedly");
+
+ /* wait for the periodic callback to run */
+ for (i = 0; i < 30 && all_slaves_done == 0; ++i) {
+ uint8_t s, total = 0;
+
+ rte_delay_ms(delay);
+ FOR_EACH_SLAVE(s, slave) {
+ total += lacpdu_rx_count[slave->port_id];
+ }
+
+ if (total >= SLAVE_COUNT)
+ all_slaves_done = 1;
+ }
+
+ FOR_EACH_SLAVE(i, slave) {
+ TEST_ASSERT_EQUAL(lacpdu_rx_count[slave->port_id], 1,
+ "Slave port %u should have received 1 lacpdu (count=%u)",
+ slave->port_id,
+ lacpdu_rx_count[slave->port_id]);
+ }
+
+ retval = remove_slaves_and_stop_bonded_device();
+ TEST_ASSERT_SUCCESS(retval, "Test cleanup failed.");
+
+ return TEST_SUCCESS;
+}
+