+#define TEST_ALB_SLAVE_COUNT 2
+
+static uint8_t mac_client1[] = {0x00, 0xAA, 0x55, 0xFF, 0xCC, 1};
+static uint8_t mac_client2[] = {0x00, 0xAA, 0x55, 0xFF, 0xCC, 2};
+static uint8_t mac_client3[] = {0x00, 0xAA, 0x55, 0xFF, 0xCC, 3};
+static uint8_t mac_client4[] = {0x00, 0xAA, 0x55, 0xFF, 0xCC, 4};
+
+static uint32_t ip_host = IPV4_ADDR(192, 168, 0, 0);
+static uint32_t ip_client1 = IPV4_ADDR(192, 168, 0, 1);
+static uint32_t ip_client2 = IPV4_ADDR(192, 168, 0, 2);
+static uint32_t ip_client3 = IPV4_ADDR(192, 168, 0, 3);
+static uint32_t ip_client4 = IPV4_ADDR(192, 168, 0, 4);
+
+static int
+test_alb_change_mac_in_reply_sent(void)
+{
+ struct rte_mbuf *pkt;
+ struct rte_mbuf *pkts_sent[MAX_PKT_BURST];
+
+ struct ether_hdr *eth_pkt;
+ struct arp_hdr *arp_pkt;
+
+ int slave_idx, nb_pkts, pkt_idx;
+ int retval = 0;
+
+ struct ether_addr bond_mac, client_mac;
+ struct ether_addr *slave_mac1, *slave_mac2;
+
+ TEST_ASSERT_SUCCESS(
+ initialize_bonded_device_with_slaves(BONDING_MODE_ALB,
+ 0, TEST_ALB_SLAVE_COUNT, 1),
+ "Failed to initialize_bonded_device_with_slaves.");
+
+ /* Flush tx queue */
+ rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0);
+ for (slave_idx = 0; slave_idx < test_params->bonded_slave_count;
+ slave_idx++) {
+ nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+ test_params->slave_port_ids[slave_idx], pkts_sent,
+ MAX_PKT_BURST);
+ }
+
+ ether_addr_copy(
+ rte_eth_devices[test_params->bonded_port_id].data->mac_addrs,
+ &bond_mac);
+
+ /*
+ * Generating four packets with different mac and ip addresses and sending
+ * them through the bonding port.
+ */
+ pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+ memcpy(client_mac.addr_bytes, mac_client1, ETHER_ADDR_LEN);
+ eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+ initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+ 0);
+ arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+ initialize_arp_header(arp_pkt, &bond_mac, &client_mac, ip_host, ip_client1,
+ ARP_OP_REPLY);
+ rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt, 1);
+
+ pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+ memcpy(client_mac.addr_bytes, mac_client2, ETHER_ADDR_LEN);
+ eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+ initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+ 0);
+ arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+ initialize_arp_header(arp_pkt, &bond_mac, &client_mac, ip_host, ip_client2,
+ ARP_OP_REPLY);
+ rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt, 1);
+
+ pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+ memcpy(client_mac.addr_bytes, mac_client3, ETHER_ADDR_LEN);
+ eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+ initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+ 0);
+ arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+ initialize_arp_header(arp_pkt, &bond_mac, &client_mac, ip_host, ip_client3,
+ ARP_OP_REPLY);
+ rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt, 1);
+
+ pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+ memcpy(client_mac.addr_bytes, mac_client4, ETHER_ADDR_LEN);
+ eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+ initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+ 0);
+ arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+ initialize_arp_header(arp_pkt, &bond_mac, &client_mac, ip_host, ip_client4,
+ ARP_OP_REPLY);
+ rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt, 1);
+
+ slave_mac1 =
+ rte_eth_devices[test_params->slave_port_ids[0]].data->mac_addrs;
+ slave_mac2 =
+ rte_eth_devices[test_params->slave_port_ids[1]].data->mac_addrs;
+
+ /*
+ * Checking if packets are properly distributed on bonding ports. Packets
+ * 0 and 2 should be sent on port 0 and packets 1 and 3 on port 1.
+ */
+ for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) {
+ nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+ test_params->slave_port_ids[slave_idx], pkts_sent,
+ MAX_PKT_BURST);
+
+ for (pkt_idx = 0; pkt_idx < nb_pkts; pkt_idx++) {
+ eth_pkt = rte_pktmbuf_mtod(pkts_sent[pkt_idx], struct ether_hdr *);
+ arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+
+ if (slave_idx%2 == 0) {
+ if (!is_same_ether_addr(slave_mac1, &arp_pkt->arp_data.arp_sha)) {
+ retval = -1;
+ goto test_end;
+ }
+ } else {
+ if (!is_same_ether_addr(slave_mac2, &arp_pkt->arp_data.arp_sha)) {
+ retval = -1;
+ goto test_end;
+ }
+ }
+ }
+ }
+
+test_end:
+ retval += remove_slaves_and_stop_bonded_device();
+ return retval;
+}
+
+static int
+test_alb_reply_from_client(void)
+{
+ struct ether_hdr *eth_pkt;
+ struct arp_hdr *arp_pkt;
+
+ struct rte_mbuf *pkt;
+ struct rte_mbuf *pkts_sent[MAX_PKT_BURST];
+
+ int slave_idx, nb_pkts, pkt_idx, nb_pkts_sum = 0;
+ int retval = 0;
+
+ struct ether_addr bond_mac, client_mac;
+ struct ether_addr *slave_mac1, *slave_mac2;
+
+ TEST_ASSERT_SUCCESS(
+ initialize_bonded_device_with_slaves(BONDING_MODE_ALB,
+ 0, TEST_ALB_SLAVE_COUNT, 1),
+ "Failed to initialize_bonded_device_with_slaves.");
+
+ /* Flush tx queue */
+ rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0);
+ for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) {
+ nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+ test_params->slave_port_ids[slave_idx], pkts_sent,
+ MAX_PKT_BURST);
+ }
+
+ ether_addr_copy(
+ rte_eth_devices[test_params->bonded_port_id].data->mac_addrs,
+ &bond_mac);
+
+ /*
+ * Generating four packets with different mac and ip addresses and placing
+ * them in the rx queue to be received by the bonding driver on rx_burst.
+ */
+ pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+ memcpy(client_mac.addr_bytes, mac_client1, ETHER_ADDR_LEN);
+ eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+ initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+ 0);
+ arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+ initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client1, ip_host,
+ ARP_OP_REPLY);
+ virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt,
+ 1);
+
+ pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+ memcpy(client_mac.addr_bytes, mac_client2, ETHER_ADDR_LEN);
+ eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+ initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+ 0);
+ arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+ initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client2, ip_host,
+ ARP_OP_REPLY);
+ virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt,
+ 1);
+
+ pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+ memcpy(client_mac.addr_bytes, mac_client3, ETHER_ADDR_LEN);
+ eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+ initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+ 0);
+ arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+ initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client3, ip_host,
+ ARP_OP_REPLY);
+ virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt,
+ 1);
+
+ pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+ memcpy(client_mac.addr_bytes, mac_client4, ETHER_ADDR_LEN);
+ eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+ initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+ 0);
+ arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+ initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client4, ip_host,
+ ARP_OP_REPLY);
+ virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt,
+ 1);
+
+ /*
+ * Issue rx_burst and tx_burst to force bonding driver to send update ARP
+ * packets to every client in alb table.
+ */
+ rte_eth_rx_burst(test_params->bonded_port_id, 0, pkts_sent, MAX_PKT_BURST);
+ rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0);
+
+ slave_mac1 = rte_eth_devices[test_params->slave_port_ids[0]].data->mac_addrs;
+ slave_mac2 = rte_eth_devices[test_params->slave_port_ids[1]].data->mac_addrs;
+
+ /*
+ * Checking if update ARP packets were properly send on slave ports.
+ */
+ for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) {
+ nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+ test_params->slave_port_ids[slave_idx], pkts_sent, MAX_PKT_BURST);
+ nb_pkts_sum += nb_pkts;
+
+ for (pkt_idx = 0; pkt_idx < nb_pkts; pkt_idx++) {
+ eth_pkt = rte_pktmbuf_mtod(pkts_sent[pkt_idx], struct ether_hdr *);
+ arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+
+ if (slave_idx%2 == 0) {
+ if (!is_same_ether_addr(slave_mac1, &arp_pkt->arp_data.arp_sha)) {
+ retval = -1;
+ goto test_end;
+ }
+ } else {
+ if (!is_same_ether_addr(slave_mac2, &arp_pkt->arp_data.arp_sha)) {
+ retval = -1;
+ goto test_end;
+ }
+ }
+ }
+ }
+
+ /* Check if proper number of packets was send */
+ if (nb_pkts_sum < 4) {
+ retval = -1;
+ goto test_end;
+ }
+
+test_end:
+ retval += remove_slaves_and_stop_bonded_device();
+ return retval;
+}
+
+static int
+test_alb_receive_vlan_reply(void)
+{
+ struct ether_hdr *eth_pkt;
+ struct vlan_hdr *vlan_pkt;
+ struct arp_hdr *arp_pkt;
+
+ struct rte_mbuf *pkt;
+ struct rte_mbuf *pkts_sent[MAX_PKT_BURST];
+
+ int slave_idx, nb_pkts, pkt_idx;
+ int retval = 0;
+
+ struct ether_addr bond_mac, client_mac;
+
+ TEST_ASSERT_SUCCESS(
+ initialize_bonded_device_with_slaves(BONDING_MODE_ALB,
+ 0, TEST_ALB_SLAVE_COUNT, 1),
+ "Failed to initialize_bonded_device_with_slaves.");
+
+ /* Flush tx queue */
+ rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0);
+ for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) {
+ nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+ test_params->slave_port_ids[slave_idx], pkts_sent,
+ MAX_PKT_BURST);
+ }
+
+ ether_addr_copy(
+ rte_eth_devices[test_params->bonded_port_id].data->mac_addrs,
+ &bond_mac);
+
+ /*
+ * Generating packet with double VLAN header and placing it in the rx queue.
+ */
+ pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+ memcpy(client_mac.addr_bytes, mac_client1, ETHER_ADDR_LEN);
+ eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+ initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_VLAN, 0,
+ 0);
+ vlan_pkt = (struct vlan_hdr *)((char *)(eth_pkt + 1));
+ vlan_pkt->vlan_tci = rte_cpu_to_be_16(1);
+ vlan_pkt->eth_proto = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+ vlan_pkt = vlan_pkt+1;
+ vlan_pkt->vlan_tci = rte_cpu_to_be_16(2);
+ vlan_pkt->eth_proto = rte_cpu_to_be_16(ETHER_TYPE_ARP);
+ arp_pkt = (struct arp_hdr *)((char *)(vlan_pkt + 1));
+ initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client1, ip_host,
+ ARP_OP_REPLY);
+ virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt,
+ 1);
+
+ rte_eth_rx_burst(test_params->bonded_port_id, 0, pkts_sent, MAX_PKT_BURST);
+ rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0);
+
+ /*
+ * Checking if VLAN headers in generated ARP Update packet are correct.
+ */
+ for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) {
+ nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+ test_params->slave_port_ids[slave_idx], pkts_sent,
+ MAX_PKT_BURST);
+
+ for (pkt_idx = 0; pkt_idx < nb_pkts; pkt_idx++) {
+ eth_pkt = rte_pktmbuf_mtod(pkts_sent[pkt_idx], struct ether_hdr *);
+ vlan_pkt = (struct vlan_hdr *)((char *)(eth_pkt + 1));
+ if (vlan_pkt->vlan_tci != rte_cpu_to_be_16(1)) {
+ retval = -1;
+ goto test_end;
+ }
+ if (vlan_pkt->eth_proto != rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
+ retval = -1;
+ goto test_end;
+ }
+ vlan_pkt = vlan_pkt+1;
+ if (vlan_pkt->vlan_tci != rte_cpu_to_be_16(2)) {
+ retval = -1;
+ goto test_end;
+ }
+ if (vlan_pkt->eth_proto != rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+ retval = -1;
+ goto test_end;
+ }
+ }
+ }
+
+test_end:
+ retval += remove_slaves_and_stop_bonded_device();
+ return retval;
+}
+
+static int
+test_alb_ipv4_tx(void)
+{
+ int burst_size, retval, pkts_send;
+ struct rte_mbuf *pkt_burst[MAX_PKT_BURST];
+
+ retval = 0;
+
+ TEST_ASSERT_SUCCESS(
+ initialize_bonded_device_with_slaves(BONDING_MODE_ALB,
+ 0, TEST_ALB_SLAVE_COUNT, 1),
+ "Failed to initialize_bonded_device_with_slaves.");
+
+ burst_size = 32;
+
+ /* Generate test bursts of packets to transmit */
+ if (generate_test_burst(pkt_burst, burst_size, 0, 1, 0, 0, 0) != burst_size) {
+ retval = -1;
+ goto test_end;
+ }
+
+ /*
+ * Checking if ipv4 traffic is transmitted via TLB policy.
+ */
+ pkts_send = rte_eth_tx_burst(
+ test_params->bonded_port_id, 0, pkt_burst, burst_size);
+ if (pkts_send != burst_size) {
+ retval = -1;
+ goto test_end;
+ }
+
+test_end:
+ retval += remove_slaves_and_stop_bonded_device();
+ return retval;
+}