bond: support link status polling
authorDeclan Doherty <declan.doherty@intel.com>
Mon, 24 Nov 2014 16:33:41 +0000 (16:33 +0000)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Mon, 24 Nov 2014 20:44:02 +0000 (21:44 +0100)
Signed-off-by: Declan Doherty <declan.doherty@intel.com>
Acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
Tested-by: SunX Jiajia <sunx.jiajia@intel.com>
app/test-pmd/cmdline.c
app/test/test.h
app/test/test_link_bonding.c
app/test/virtual_pmd.c
app/test/virtual_pmd.h
doc/guides/testpmd_app_ug/testpmd_funcs.rst
lib/librte_pmd_bond/rte_eth_bond.h
lib/librte_pmd_bond/rte_eth_bond_api.c
lib/librte_pmd_bond/rte_eth_bond_args.c
lib/librte_pmd_bond/rte_eth_bond_pmd.c
lib/librte_pmd_bond/rte_eth_bond_private.h

index ef8e9cd..9c6632d 100644 (file)
@@ -462,6 +462,9 @@ static void cmd_help_long_parsed(void *parsed_result,
 
                        "set bonding xmit_balance_policy (port_id) (l2|l23|l34)\n"
                        "       Set the transmit balance policy for bonded device running in balance mode.\n\n"
+
+                       "set bonding mon_period (port_id) (value)\n"
+                       "       Set the bonding link status monitoring polling period in ms.\n\n"
 #endif
                        "set link-up port (port_id)\n"
                        "       Set link up for a port.\n\n"
@@ -3738,6 +3741,65 @@ cmdline_parse_inst_t cmd_set_bond_mac_addr = {
                }
 };
 
+
+/* *** SET LINK STATUS MONITORING POLLING PERIOD ON BONDED DEVICE *** */
+struct cmd_set_bond_mon_period_result {
+       cmdline_fixed_string_t set;
+       cmdline_fixed_string_t bonding;
+       cmdline_fixed_string_t mon_period;
+       uint8_t port_num;
+       uint32_t period_ms;
+};
+
+static void cmd_set_bond_mon_period_parsed(void *parsed_result,
+               __attribute__((unused))  struct cmdline *cl,
+               __attribute__((unused)) void *data)
+{
+       struct cmd_set_bond_mon_period_result *res = parsed_result;
+       int ret;
+
+       if (res->port_num >= nb_ports) {
+               printf("Port id %d must be less than %d\n", res->port_num, nb_ports);
+               return;
+       }
+
+       ret = rte_eth_bond_link_monitoring_set(res->port_num, res->period_ms);
+
+       /* check the return value and print it if is < 0 */
+       if (ret < 0)
+               printf("set_bond_mac_addr error: (%s)\n", strerror(-ret));
+}
+
+cmdline_parse_token_string_t cmd_set_bond_mon_period_set =
+               TOKEN_STRING_INITIALIZER(struct cmd_set_bond_mon_period_result,
+                               set, "set");
+cmdline_parse_token_string_t cmd_set_bond_mon_period_bonding =
+               TOKEN_STRING_INITIALIZER(struct cmd_set_bond_mon_period_result,
+                               bonding, "bonding");
+cmdline_parse_token_string_t cmd_set_bond_mon_period_mon_period =
+               TOKEN_STRING_INITIALIZER(struct cmd_set_bond_mon_period_result,
+                               mon_period,     "mon_period");
+cmdline_parse_token_num_t cmd_set_bond_mon_period_portnum =
+               TOKEN_NUM_INITIALIZER(struct cmd_set_bond_mon_period_result,
+                               port_num, UINT8);
+cmdline_parse_token_num_t cmd_set_bond_mon_period_period_ms =
+               TOKEN_NUM_INITIALIZER(struct cmd_set_bond_mon_period_result,
+                               period_ms, UINT32);
+
+cmdline_parse_inst_t cmd_set_bond_mon_period = {
+               .f = cmd_set_bond_mon_period_parsed,
+               .data = (void *) 0,
+               .help_str = "set bonding mon_period (port_id) (period_ms): ",
+               .tokens = {
+                               (void *)&cmd_set_bond_mon_period_set,
+                               (void *)&cmd_set_bond_mon_period_bonding,
+                               (void *)&cmd_set_bond_mon_period_mon_period,
+                               (void *)&cmd_set_bond_mon_period_portnum,
+                               (void *)&cmd_set_bond_mon_period_period_ms,
+                               NULL
+               }
+};
+
 #endif /* RTE_LIBRTE_PMD_BOND */
 
 /* *** SET FORWARDING MODE *** */
@@ -7792,6 +7854,7 @@ cmdline_parse_ctx_t main_ctx[] = {
        (cmdline_parse_inst_t *) &cmd_create_bonded_device,
        (cmdline_parse_inst_t *) &cmd_set_bond_mac_addr,
        (cmdline_parse_inst_t *) &cmd_set_balance_xmit_policy,
+       (cmdline_parse_inst_t *) &cmd_set_bond_mon_period,
 #endif
        (cmdline_parse_inst_t *)&cmd_vlan_offload,
        (cmdline_parse_inst_t *)&cmd_vlan_tpid,
index bd44a7f..d5b6951 100644 (file)
 
 #define TEST_ASSERT_SUCCESS(val, msg, ...) do {                                        \
                if (!(val == 0)) {                                                                              \
-                       printf("TestCase %s() line %d failed: "                 \
-                               msg "\n", __func__, __LINE__, ##__VA_ARGS__);   \
+                       printf("TestCase %s() line %d failed (err %d): "        \
+                               msg "\n", __func__, __LINE__, val,                              \
+                               ##__VA_ARGS__);                                                                 \
                        return -1;                                                                                      \
                }                                                                                                               \
 } while (0)
 
 #define TEST_ASSERT_FAIL(val, msg, ...) do {                                   \
-               if (!(val != -1)) {                                                                             \
+               if (!(val != 0)) {                                                                              \
                        printf("TestCase %s() line %d failed: "                 \
                                msg "\n", __func__, __LINE__, ##__VA_ARGS__);   \
                        return -1;                                                                                      \
index c11a0bc..2411125 100644 (file)
@@ -234,42 +234,34 @@ configure_ethdev(uint8_t port_id, uint8_t start, uint8_t en_isr)
        else
                default_pmd_conf.intr_conf.lsc = 0;
 
-       if (rte_eth_dev_configure(port_id, test_params->nb_rx_q,
-                       test_params->nb_tx_q, &default_pmd_conf) != 0) {
-               goto error;
-       }
+       TEST_ASSERT_SUCCESS(rte_eth_dev_configure(port_id, test_params->nb_rx_q,
+                       test_params->nb_tx_q, &default_pmd_conf),
+                       "rte_eth_dev_configure for port %d failed", port_id);
 
-       for (q_id = 0; q_id < test_params->nb_rx_q; q_id++) {
-               if (rte_eth_rx_queue_setup(port_id, q_id, RX_RING_SIZE,
+       for (q_id = 0; q_id < test_params->nb_rx_q; q_id++)
+               TEST_ASSERT_SUCCESS(rte_eth_rx_queue_setup(port_id, q_id, RX_RING_SIZE,
                                rte_eth_dev_socket_id(port_id), &rx_conf_default,
-                               test_params->mbuf_pool) < 0) {
-                       goto error;
-               }
-       }
+                               test_params->mbuf_pool) ,
+                               "rte_eth_rx_queue_setup for port %d failed", port_id);
 
-       for (q_id = 0; q_id < test_params->nb_tx_q; q_id++) {
-               if (rte_eth_tx_queue_setup(port_id, q_id, TX_RING_SIZE,
-                               rte_eth_dev_socket_id(port_id), &tx_conf_default) < 0) {
-                       printf("Failed to setup tx queue (%d).\n", q_id);
-                       goto error;
-               }
-       }
+       for (q_id = 0; q_id < test_params->nb_tx_q; q_id++)
+               TEST_ASSERT_SUCCESS(rte_eth_tx_queue_setup(port_id, q_id, TX_RING_SIZE,
+                               rte_eth_dev_socket_id(port_id), &tx_conf_default),
+                               "rte_eth_tx_queue_setup for port %d failed", port_id);
 
-       if (start) {
-               if (rte_eth_dev_start(port_id) < 0) {
-                       printf("Failed to start device (%d).\n", port_id);
-                       goto error;
-               }
-       }
-       return 0;
+       if (start)
+               TEST_ASSERT_SUCCESS(rte_eth_dev_start(port_id),
+                               "rte_eth_dev_start for port %d failed", port_id);
 
-error:
-       printf("Failed to configure ethdev %d\n", port_id);
-       return -1;
+       return 0;
 }
 
 static int slaves_initialized;
 
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t cvar = PTHREAD_COND_INITIALIZER;
+
+
 static int
 test_setup(void)
 {
@@ -310,7 +302,7 @@ test_setup(void)
                        snprintf(pmd_name, RTE_ETH_NAME_MAX_LEN, "eth_virt_%d", i);
 
                        test_params->slave_port_ids[i] = virtual_ethdev_create(pmd_name,
-                                       mac_addr, rte_socket_id());
+                                       mac_addr, rte_socket_id(), 1);
                        if (test_params->slave_port_ids[i] < 0) {
                                printf("Failed to create virtual virtual ethdev %s\n", pmd_name);
                                return -1;
@@ -414,34 +406,27 @@ test_create_bonded_device_with_invalid_params(void)
 static int
 test_add_slave_to_bonded_device(void)
 {
-       int retval, current_slave_count;
+       int current_slave_count;
 
        uint8_t slaves[RTE_MAX_ETHPORTS];
 
-       retval = rte_eth_bond_slave_add(test_params->bonded_port_id,
-                       test_params->slave_port_ids[test_params->bonded_slave_count]);
-       if (retval != 0) {
-               printf("Failed to add slave (%d) to bonded port (%d).\n",
-                               test_params->bonded_port_id,
-                               test_params->slave_port_ids[test_params->bonded_slave_count]);
-               return -1;
-       }
+       TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params->bonded_port_id,
+                       test_params->slave_port_ids[test_params->bonded_slave_count]),
+                       "Failed to add slave (%d) to bonded port (%d).",
+                       test_params->slave_port_ids[test_params->bonded_slave_count],
+                       test_params->bonded_port_id);
 
        current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
                        slaves, RTE_MAX_ETHPORTS);
-       if (current_slave_count != test_params->bonded_slave_count + 1) {
-               printf("Number of slaves (%d) is greater than expected (%d).\n",
-                               current_slave_count, test_params->bonded_slave_count + 1);
-               return -1;
-       }
+       TEST_ASSERT_EQUAL(current_slave_count, test_params->bonded_slave_count + 1,
+                       "Number of slaves (%d) is greater than expected (%d).",
+                       current_slave_count, test_params->bonded_slave_count + 1);
 
        current_slave_count = rte_eth_bond_active_slaves_get(
                        test_params->bonded_port_id, slaves, RTE_MAX_ETHPORTS);
-       if (current_slave_count != 0) {
-               printf("Number of active slaves (%d) is not as expected (%d).\n",
-                               current_slave_count, 0);
-               return -1;
-       }
+       TEST_ASSERT_EQUAL(current_slave_count, 0,
+                                       "Number of active slaves (%d) is not as expected (%d).\n",
+                                       current_slave_count, 0);
 
        test_params->bonded_slave_count++;
 
@@ -476,27 +461,23 @@ test_add_slave_to_invalid_bonded_device(void)
 static int
 test_remove_slave_from_bonded_device(void)
 {
-       int retval, current_slave_count;
+       int current_slave_count;
        struct ether_addr read_mac_addr, *mac_addr;
        uint8_t slaves[RTE_MAX_ETHPORTS];
 
-       retval = rte_eth_bond_slave_remove(test_params->bonded_port_id,
-                       test_params->slave_port_ids[test_params->bonded_slave_count-1]);
-       if (retval != 0) {
-               printf("\t Failed to remove slave %d from bonded port (%d).\n",
-                               test_params->slave_port_ids[test_params->bonded_slave_count-1],
-                               test_params->bonded_port_id);
-               return -1;
-       }
+       TEST_ASSERT_SUCCESS(rte_eth_bond_slave_remove(test_params->bonded_port_id,
+                       test_params->slave_port_ids[test_params->bonded_slave_count-1]),
+                       "Failed to remove slave %d from bonded port (%d).",
+                       test_params->slave_port_ids[test_params->bonded_slave_count-1],
+                       test_params->bonded_port_id);
 
 
        current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
                        slaves, RTE_MAX_ETHPORTS);
-       if (current_slave_count != test_params->bonded_slave_count - 1) {
-               printf("Number of slaves (%d) is great than expected (%d).\n",
-                               current_slave_count, 0);
-               return -1;
-       }
+
+       TEST_ASSERT_EQUAL(current_slave_count, test_params->bonded_slave_count - 1,
+                       "Number of slaves (%d) is great than expected (%d).\n",
+                       current_slave_count, test_params->bonded_slave_count - 1);
 
 
        mac_addr = (struct ether_addr *)slave_mac;
@@ -506,10 +487,8 @@ test_remove_slave_from_bonded_device(void)
        rte_eth_macaddr_get(
                        test_params->slave_port_ids[test_params->bonded_slave_count-1],
                        &read_mac_addr);
-       if (memcmp(mac_addr, &read_mac_addr, sizeof(read_mac_addr))) {
-               printf("bonded port mac address not set to that of primary port\n");
-               return -1;
-       }
+       TEST_ASSERT_SUCCESS(memcmp(mac_addr, &read_mac_addr, sizeof(read_mac_addr)),
+                       "bonded port mac address not set to that of primary port\n");
 
        rte_eth_stats_reset(
                        test_params->slave_port_ids[test_params->bonded_slave_count-1]);
@@ -891,21 +870,20 @@ test_set_primary_slave(void)
                return -1;
        }
 
+       /* Non bonded device */
+       retval = rte_eth_bond_primary_set(test_params->slave_port_ids[i],
+                       test_params->slave_port_ids[i]);
+       if (retval == 0) {
+               printf("Expected call to failed as invalid port specified.\n");
+               return -1;
+       }
+
        /* Set slave as primary
         * Verify slave it is now primary slave
         * Verify that MAC address of bonded device is that of primary slave
         * Verify that MAC address of all bonded slaves are that of primary slave
         */
        for (i = 0; i < 4; i++) {
-
-               /* Non bonded device */
-               retval = rte_eth_bond_primary_set(test_params->slave_port_ids[i],
-                               test_params->slave_port_ids[i]);
-               if (retval == 0) {
-                       printf("Expected call to failed as invalid port specified.\n");
-                       return -1;
-               }
-
                retval = rte_eth_bond_primary_set(test_params->bonded_port_id,
                                test_params->slave_port_ids[i]);
                if (retval != 0) {
@@ -929,6 +907,7 @@ test_set_primary_slave(void)
 
                /* stop/start bonded eth dev to apply new MAC */
                rte_eth_dev_stop(test_params->bonded_port_id);
+
                if (rte_eth_dev_start(test_params->bonded_port_id) != 0)
                        return -1;
 
@@ -1093,19 +1072,18 @@ static int
 initialize_bonded_device_with_slaves(uint8_t bonding_mode, uint8_t bond_en_isr,
                uint8_t number_of_slaves, uint8_t enable_slave)
 {
-       /* configure bonded device */
+       /* Configure bonded device */
        TEST_ASSERT_SUCCESS(configure_ethdev(test_params->bonded_port_id, 0,
                        bond_en_isr), "Failed to configure bonding port (%d) in mode %d "
                        "with (%d) slaves.", test_params->bonded_port_id, bonding_mode,
                        number_of_slaves);
 
-       while (number_of_slaves > test_params->bonded_slave_count) {
-               /* Add slaves to bonded device */
+       /* Add slaves to bonded device */
+       while (number_of_slaves > test_params->bonded_slave_count)
                TEST_ASSERT_SUCCESS(test_add_slave_to_bonded_device(),
                                "Failed to add slave (%d to  bonding port (%d).",
                                test_params->bonded_slave_count - 1,
                                test_params->bonded_port_id);
-       }
 
        /* Set link bonding mode  */
        TEST_ASSERT_SUCCESS(rte_eth_bond_mode_set(test_params->bonded_port_id,
@@ -1128,9 +1106,9 @@ test_adding_slave_after_bonded_device_started(void)
 {
        int i;
 
-       if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 0, 4, 0)
-                       != 0)
-               return -1;
+       TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves(
+                       BONDING_MODE_ROUND_ROBIN, 0, 4, 0),
+                       "Failed to add slaves to bonded device");
 
        /* Enabled slave devices */
        for (i = 0; i < test_params->bonded_slave_count + 1; i++) {
@@ -1138,12 +1116,9 @@ test_adding_slave_after_bonded_device_started(void)
                                test_params->slave_port_ids[i], 1);
        }
 
-       if (rte_eth_bond_slave_add(test_params->bonded_port_id,
-                       test_params->slave_port_ids[test_params->bonded_slave_count]) !=
-                                       0) {
-               printf("\t Failed to add slave to bonded port.\n");
-               return -1;
-       }
+       TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params->bonded_port_id,
+                       test_params->slave_port_ids[test_params->bonded_slave_count]),
+                       "Failed to add slave to bonded port.\n");
 
        rte_eth_stats_reset(
                        test_params->slave_port_ids[test_params->bonded_slave_count]);
@@ -1158,8 +1133,6 @@ test_adding_slave_after_bonded_device_started(void)
 
 int test_lsc_interrupt_count;
 
-static pthread_mutex_t mutex;
-static pthread_cond_t cvar;
 
 static void
 test_bonding_lsc_event_callback(uint8_t port_id __rte_unused,
@@ -1183,7 +1156,7 @@ lsc_timeout(int wait_us)
        gettimeofday(&tp, NULL);
 
        /* Convert from timeval to timespec */
-       ts.tv_sec  = tp.tv_sec;
+       ts.tv_sec = tp.tv_sec;
        ts.tv_nsec = tp.tv_usec * 1000;
        ts.tv_nsec += wait_us * 1000;
 
@@ -1193,6 +1166,9 @@ lsc_timeout(int wait_us)
 
        pthread_mutex_unlock(&mutex);
 
+       if (retval == 0 && test_lsc_interrupt_count < 1)
+               return -1;
+
        return retval;
 }
 
@@ -1202,9 +1178,6 @@ test_status_interrupt(void)
        int slave_count;
        uint8_t slaves[RTE_MAX_ETHPORTS];
 
-       pthread_mutex_init(&mutex, NULL);
-       pthread_cond_init(&cvar, NULL);
-
        /* initialized bonding device with T slaves */
        if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 1,
                        TEST_STATUS_INTERRUPT_SLAVE_COUNT, 1) != 0)
@@ -1284,9 +1257,6 @@ test_status_interrupt(void)
                                RTE_ETH_EVENT_INTR_LSC, test_bonding_lsc_event_callback,
                                &test_params->bonded_port_id);
 
-       pthread_mutex_destroy(&mutex);
-       pthread_cond_destroy(&cvar);
-
        /* Clean up and remove slaves from bonded device */
        return remove_slaves_and_stop_bonded_device();
 }
@@ -1419,6 +1389,7 @@ test_roundrobin_tx_burst(void)
        return remove_slaves_and_stop_bonded_device();
 }
 
+#ifdef RTE_MBUF_REFCNT
 static int
 verify_mbufs_ref_count(struct rte_mbuf **mbufs, int nb_mbufs, int val)
 {
@@ -1432,6 +1403,7 @@ verify_mbufs_ref_count(struct rte_mbuf **mbufs, int nb_mbufs, int val)
        }
        return 0;
 }
+#endif
 
 
 static void
@@ -1537,11 +1509,12 @@ test_roundrobin_tx_burst_slave_tx_fail(void)
                                (unsigned int)port_stats.opackets, slave_expected_tx_count);
        }
 
+#ifdef RTE_MBUF_REFCNT
        /* Verify that all mbufs have a ref value of zero */
        TEST_ASSERT_SUCCESS(verify_mbufs_ref_count(&pkt_burst[tx_count],
                        TEST_RR_SLAVE_TX_FAIL_PACKETS_COUNT, 1),
                        "mbufs refcnts not as expected");
-
+#endif
        free_mbufs(&pkt_burst[tx_count], TEST_RR_SLAVE_TX_FAIL_PACKETS_COUNT);
 
        /* Clean up and remove slaves from bonded device */
@@ -2028,6 +2001,101 @@ test_roundrobin_verify_slave_link_status_change_behaviour(void)
        return remove_slaves_and_stop_bonded_device();
 }
 
+#define TEST_RR_POLLING_LINK_STATUS_SLAVE_COUNT (2)
+
+uint8_t polling_slave_mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00 };
+
+#include "unistd.h"
+
+int polling_test_slaves[TEST_RR_POLLING_LINK_STATUS_SLAVE_COUNT] = { -1, -1 };
+
+static int
+test_roundrobin_verfiy_polling_slave_link_status_change(void)
+{
+       struct ether_addr *mac_addr = (struct ether_addr *)polling_slave_mac;
+       char slave_name[RTE_ETH_NAME_MAX_LEN];
+
+       int i;
+
+       for (i = 0; i < TEST_RR_POLLING_LINK_STATUS_SLAVE_COUNT; i++) {
+               /* Generate slave name / MAC address */
+               snprintf(slave_name, RTE_ETH_NAME_MAX_LEN, "eth_virt_poll_%d", i);
+               mac_addr->addr_bytes[ETHER_ADDR_LEN-1] = i;
+
+               /* Create slave devices with no ISR Support */
+               if (polling_test_slaves[i] == -1) {
+                       polling_test_slaves[i] = virtual_ethdev_create(slave_name, mac_addr,
+                                       rte_socket_id(), 0);
+                       TEST_ASSERT(polling_test_slaves[i] >= 0,
+                                       "Failed to create virtual virtual ethdev %s\n", slave_name);
+
+                       /* Configure slave */
+                       TEST_ASSERT_SUCCESS(configure_ethdev(polling_test_slaves[i], 0, 0),
+                                       "Failed to configure virtual ethdev %s(%d)", slave_name,
+                                       polling_test_slaves[i]);
+               }
+
+               /* Add slave to bonded device */
+               TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params->bonded_port_id,
+                               polling_test_slaves[i]),
+                               "Failed to add slave %s(%d) to bonded device %d",
+                               slave_name, polling_test_slaves[i], test_params->bonded_port_id);
+       }
+
+       /* Initialize bonded device */
+       TEST_ASSERT_SUCCESS(configure_ethdev(test_params->bonded_port_id, 1, 1),
+                       "Failed to configure bonded device %d",
+                       test_params->bonded_port_id);
+
+
+       /* Register link status change interrupt callback */
+       rte_eth_dev_callback_register(test_params->bonded_port_id,
+                       RTE_ETH_EVENT_INTR_LSC, test_bonding_lsc_event_callback,
+                       &test_params->bonded_port_id);
+
+       /* link status change callback for first slave link up */
+       test_lsc_interrupt_count = 0;
+
+       virtual_ethdev_set_link_status(polling_test_slaves[0], 1);
+
+       TEST_ASSERT_SUCCESS(lsc_timeout(15000), "timed out waiting for interrupt");
+
+
+       /* no link status change callback for second slave link up */
+       test_lsc_interrupt_count = 0;
+
+       virtual_ethdev_set_link_status(polling_test_slaves[1], 1);
+
+       TEST_ASSERT_FAIL(lsc_timeout(15000), "unexpectedly succeeded");
+
+       /* link status change callback for both slave links down */
+       test_lsc_interrupt_count = 0;
+
+       virtual_ethdev_set_link_status(polling_test_slaves[0], 0);
+       virtual_ethdev_set_link_status(polling_test_slaves[1], 0);
+
+       TEST_ASSERT_SUCCESS(lsc_timeout(20000), "timed out waiting for interrupt");
+
+       /* Un-Register link status change interrupt callback */
+       rte_eth_dev_callback_unregister(test_params->bonded_port_id,
+                       RTE_ETH_EVENT_INTR_LSC, test_bonding_lsc_event_callback,
+                       &test_params->bonded_port_id);
+
+
+       /* Clean up and remove slaves from bonded device */
+       for (i = 0; i < TEST_RR_POLLING_LINK_STATUS_SLAVE_COUNT; i++) {
+
+               TEST_ASSERT_SUCCESS(
+                               rte_eth_bond_slave_remove(test_params->bonded_port_id,
+                                               polling_test_slaves[i]),
+                               "Failed to remove slave %d from bonded port (%d)",
+                               polling_test_slaves[i], test_params->bonded_port_id);
+       }
+
+       return remove_slaves_and_stop_bonded_device();
+}
+
+
 /** Active Backup Mode Tests */
 
 static int
@@ -3160,10 +3228,12 @@ test_balance_tx_burst_slave_tx_fail(void)
                                (unsigned int)port_stats.opackets,
                                TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_2);
 
+#ifdef RTE_MBUF_REFCNT
        /* Verify that all mbufs have a ref value of zero */
        TEST_ASSERT_SUCCESS(verify_mbufs_ref_count(&pkts_burst_1[tx_count_1],
                        TEST_BAL_SLAVE_TX_FAIL_PACKETS_COUNT, 1),
                        "mbufs refcnts not as expected");
+#endif
 
        free_mbufs(&pkts_burst_1[tx_count_1],
                        TEST_BAL_SLAVE_TX_FAIL_PACKETS_COUNT);
@@ -4315,6 +4385,7 @@ static struct unit_test_suite link_bonding_test_suite  = {
                TEST_CASE(test_roundrobin_verify_promiscuous_enable_disable),
                TEST_CASE(test_roundrobin_verify_mac_assignment),
                TEST_CASE(test_roundrobin_verify_slave_link_status_change_behaviour),
+               TEST_CASE(test_roundrobin_verfiy_polling_slave_link_status_change),
                TEST_CASE(test_activebackup_tx_burst),
                TEST_CASE(test_activebackup_rx_burst),
                TEST_CASE(test_activebackup_verify_promiscuous_enable_disable),
index 81d4be3..e7be98b 100644 (file)
@@ -455,6 +455,14 @@ virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count(uint8_t port_id,
        dev_private->tx_burst_fail_count = packet_fail_count;
 }
 
+void
+virtual_ethdev_set_link_status(uint8_t port_id, uint8_t link_status)
+{
+       struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+       vrtl_eth_dev->data->dev_link.link_status = link_status;
+}
+
 void
 virtual_ethdev_simulate_link_status_interrupt(uint8_t port_id,
                uint8_t link_status)
@@ -503,7 +511,7 @@ get_number_of_sockets(void)
 
 int
 virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
-               uint8_t socket_id)
+               uint8_t socket_id, uint8_t isr_support)
 {
        struct rte_pci_device *pci_dev = NULL;
        struct rte_eth_dev *eth_dev = NULL;
@@ -553,7 +561,12 @@ virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
        pci_dev->numa_node = socket_id;
        pci_drv->name = virtual_ethdev_driver_name;
        pci_drv->id_table = id_table;
-       pci_drv->drv_flags = RTE_PCI_DRV_INTR_LSC;
+
+       if (isr_support)
+               pci_drv->drv_flags |= RTE_PCI_DRV_INTR_LSC;
+       else
+               pci_drv->drv_flags &= ~RTE_PCI_DRV_INTR_LSC;
+
 
        eth_drv->pci_drv = (struct rte_pci_driver)(*pci_drv);
        eth_dev->driver = eth_drv;
index 3b5c911..2462853 100644 (file)
@@ -40,38 +40,58 @@ extern "C" {
 
 #include <rte_ether.h>
 
-int virtual_ethdev_init(void);
+int
+virtual_ethdev_init(void);
 
-int virtual_ethdev_create(const char *name, struct ether_addr *mac_addr, uint8_t socket_id);
+int
+virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
+               uint8_t socket_id, uint8_t isr_support);
 
-void virtual_ethdev_simulate_link_status_interrupt(uint8_t port_id, uint8_t link_status);
+void
+virtual_ethdev_set_link_status(uint8_t port_id, uint8_t link_status);
 
-void virtual_ethdev_add_mbufs_to_rx_queue(uint8_t port_id, struct rte_mbuf **pkts_burst, int burst_length);
+void
+virtual_ethdev_simulate_link_status_interrupt(uint8_t port_id,
+               uint8_t link_status);
 
+void
+virtual_ethdev_add_mbufs_to_rx_queue(uint8_t port_id,
+               struct rte_mbuf **pkts_burst, int burst_length);
 
-/** Control methods for the dev_ops functions pointer to control the behavior of the Virtual PMD */
 
-void virtual_ethdev_start_fn_set_success(uint8_t port_id, uint8_t success);
+/** Control methods for the dev_ops functions pointer to control the behavior
+ *  of the Virtual PMD */
 
-void virtual_ethdev_stop_fn_set_success(uint8_t port_id, uint8_t success);
+void
+virtual_ethdev_start_fn_set_success(uint8_t port_id, uint8_t success);
 
-void virtual_ethdev_configure_fn_set_success(uint8_t port_id, uint8_t success);
+void
+virtual_ethdev_stop_fn_set_success(uint8_t port_id, uint8_t success);
 
-void virtual_ethdev_rx_queue_setup_fn_set_success(uint8_t port_id, uint8_t success);
+void
+virtual_ethdev_configure_fn_set_success(uint8_t port_id, uint8_t success);
 
-void virtual_ethdev_tx_queue_setup_fn_set_success(uint8_t port_id, uint8_t success);
+void
+virtual_ethdev_rx_queue_setup_fn_set_success(uint8_t port_id, uint8_t success);
 
-void virtual_ethdev_link_update_fn_set_success(uint8_t port_id, uint8_t success);
+void
+virtual_ethdev_tx_queue_setup_fn_set_success(uint8_t port_id, uint8_t success);
 
-void virtual_ethdev_rx_burst_fn_set_success(uint8_t port_id, uint8_t success);
+void
+virtual_ethdev_link_update_fn_set_success(uint8_t port_id, uint8_t success);
 
-void virtual_ethdev_tx_burst_fn_set_success(uint8_t port_id, uint8_t success);
+void
+virtual_ethdev_rx_burst_fn_set_success(uint8_t port_id, uint8_t success);
+
+void
+virtual_ethdev_tx_burst_fn_set_success(uint8_t port_id, uint8_t success);
 
 /* 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,
+void
+virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count(uint8_t port_id,
                uint8_t packet_fail_count);
 
 #ifdef __cplusplus
index c0d0033..93fd3d4 100644 (file)
@@ -1479,6 +1479,25 @@ For example, set a Link Bonding device (port 10) to use a balance policy of laye
 
     testpmd> set bonding xmit_balance_policy 10 l34
 
+
+set bonding mon_period
+~~~~~~~~~~~~~~~~~~~~~~
+
+Set the link status monitoring polling period in milliseconds for a bonding devicie.
+
+This adds support for PMD slave devices which do not support link status interrupts.
+When the mon_period is set to a value greater than 0 then all PMD's which do not support
+link status ISR will be queried every polling interval to check if their link status has changed.
+
+set bonding mon_period (port_id) (value)
+
+For example, to set the link status monitoring polling period of bonded device (port 5) to 150ms
+
+.. code-block:: console
+
+    testpmd> set bonding mon_period 5 150
+
+
 show bonding config
 ~~~~~~~~~~~~~~~~~~~
 
index 344ca1e..2ed4f7c 100644 (file)
@@ -249,6 +249,86 @@ rte_eth_bond_xmit_policy_set(uint8_t bonded_port_id, uint8_t policy);
 int
 rte_eth_bond_xmit_policy_get(uint8_t bonded_port_id);
 
+/**
+ * Set the link monitoring frequency (in ms) for monitoring the link status of
+ * slave devices
+ *
+ * @param bonded_port_id       Port ID of bonded device.
+ * @param internal_ms          Monitoring interval in milliseconds
+ *
+ * @return
+ *     0 on success, negative value otherwise.
+ */
+
+int
+rte_eth_bond_link_monitoring_set(uint8_t bonded_port_id, uint32_t internal_ms);
+
+/**
+ * Get the current link monitoring frequency (in ms) for monitoring of the link
+ * status of slave devices
+ *
+ * @param bonded_port_id       Port ID of bonded device.
+ *
+ * @return
+ *     Monitoring interval on success, negative value otherwise.
+ */
+int
+rte_eth_bond_link_monitoring_get(uint8_t bonded_port_id);
+
+
+/**
+ * Set the period in milliseconds for delaying the disabling of a bonded link
+ * when the link down status has been detected
+ *
+ * @param bonded_port_id       Port ID of bonded device.
+ * @param delay_ms                     Delay period in milliseconds.
+ *
+ * @return
+ *  0 on success, negative value otherwise.
+ */
+int
+rte_eth_bond_link_down_prop_delay_set(uint8_t bonded_port_id, uint32_t delay_ms);
+
+/**
+ * Get the period in milliseconds set for delaying the disabling of a bonded
+ * link when the link down status has been detected
+ *
+ * @param bonded_port_id       Port ID of bonded device.
+ * @param delay_ms                     Delay period in milliseconds.
+ *
+ * @return
+ *  Delay period on success, negative value otherwise.
+ */
+int
+rte_eth_bond_link_down_prop_delay_get(uint8_t bonded_port_id);
+
+/**
+ * Set the period in milliseconds for delaying the enabling of a bonded link
+ * when the link up status has been detected
+ *
+ * @param bonded_port_id       Port ID of bonded device.
+ * @param delay_ms                     Delay period in milliseconds.
+ *
+ * @return
+ *  0 on success, negative value otherwise.
+ */
+int
+rte_eth_bond_link_up_prop_delay_set(uint8_t bonded_port_id, uint32_t delay_ms);
+
+/**
+ * Get the period in milliseconds set for delaying the enabling of a bonded
+ * link when the link up status has been detected
+ *
+ * @param bonded_port_id       Port ID of bonded device.
+ * @param delay_ms                     Delay period in milliseconds.
+ *
+ * @return
+ *  Delay period on success, negative value otherwise.
+ */
+int
+rte_eth_bond_link_up_prop_delay_get(uint8_t bonded_port_id);
+
+
 #ifdef __cplusplus
 }
 #endif
index dd33119..f146bda 100644 (file)
@@ -39,6 +39,8 @@
 #include "rte_eth_bond.h"
 #include "rte_eth_bond_private.h"
 
+#define DEFAULT_POLLING_INTERVAL_10_MS (10)
+
 int
 valid_bonded_ethdev(struct rte_eth_dev *eth_dev)
 {
@@ -63,9 +65,8 @@ valid_port_id(uint8_t port_id)
        /* Verify that port id is valid */
        int ethdev_count = rte_eth_dev_count();
        if (port_id >= ethdev_count) {
-               RTE_LOG(ERR, PMD,
-                               "%s: port Id %d is greater than rte_eth_dev_count %d\n",
-                               __func__, port_id, ethdev_count);
+               RTE_BOND_LOG(ERR, "Port Id %d is greater than rte_eth_dev_count %d",
+                               port_id, ethdev_count);
                return -1;
        }
 
@@ -81,9 +82,8 @@ valid_bonded_port_id(uint8_t port_id)
 
        /* Verify that bonded_port_id refers to a bonded port */
        if (valid_bonded_ethdev(&rte_eth_devices[port_id])) {
-               RTE_LOG(ERR, PMD,
-                               "%s: Specified port Id %d is not a bonded eth_dev device\n",
-                               __func__, port_id);
+               RTE_BOND_LOG(ERR, "Specified port Id %d is not a bonded eth_dev device",
+                               port_id);
                return -1;
        }
 
@@ -136,37 +136,36 @@ rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id)
         */
 
        if (name == NULL) {
-               RTE_LOG(ERR, PMD, "Invalid name specified\n");
+               RTE_BOND_LOG(ERR, "Invalid name specified");
                goto err;
        }
 
        if (socket_id >= number_of_sockets()) {
-               RTE_LOG(ERR, PMD,
-                               "%s: invalid socket id specified to create bonded device on.\n",
-                               __func__);
+               RTE_BOND_LOG(ERR,
+                               "Invalid socket id specified to create bonded device on.");
                goto err;
        }
 
        pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, socket_id);
        if (pci_dev == NULL) {
-               RTE_LOG(ERR, PMD, "Unable to malloc pci dev on socket\n");
+               RTE_BOND_LOG(ERR, "Unable to malloc pci dev on socket");
                goto err;
        }
 
        eth_drv = rte_zmalloc_socket(name, sizeof(*eth_drv), 0, socket_id);
        if (eth_drv == NULL) {
-               RTE_LOG(ERR, PMD, "Unable to malloc eth_drv on socket\n");
+               RTE_BOND_LOG(ERR, "Unable to malloc eth_drv on socket");
                goto err;
        }
 
        pci_drv = rte_zmalloc_socket(name, sizeof(*pci_drv), 0, socket_id);
        if (pci_drv == NULL) {
-               RTE_LOG(ERR, PMD, "Unable to malloc pci_drv on socket\n");
+               RTE_BOND_LOG(ERR, "Unable to malloc pci_drv on socket");
                goto err;
        }
        pci_id_table = rte_zmalloc_socket(name, sizeof(*pci_id_table), 0, socket_id);
        if (pci_drv == NULL) {
-               RTE_LOG(ERR, PMD, "Unable to malloc pci_id_table on socket\n");
+               RTE_BOND_LOG(ERR, "Unable to malloc pci_id_table on socket");
                goto err;
        }
 
@@ -181,14 +180,14 @@ rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id)
 
        internals = rte_zmalloc_socket(name, sizeof(*internals), 0, socket_id);
        if (internals == NULL) {
-               RTE_LOG(ERR, PMD, "Unable to malloc internals on socket\n");
+               RTE_BOND_LOG(ERR, "Unable to malloc internals on socket");
                goto err;
        }
 
        /* reserve an ethdev entry */
        eth_dev = rte_eth_dev_allocate(name);
        if (eth_dev == NULL) {
-               RTE_LOG(ERR, PMD, "Unable to allocate rte_eth_dev\n");
+               RTE_BOND_LOG(ERR, "Unable to allocate rte_eth_dev");
                goto err;
        }
 
@@ -218,25 +217,31 @@ rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id)
        eth_dev->pci_dev = pci_dev;
 
        if (bond_ethdev_mode_set(eth_dev, mode)) {
-               RTE_LOG(ERR, PMD,
-                               "%s: failed to set bonded device %d mode too %d\n",
-                               __func__, eth_dev->data->port_id, mode);
+               RTE_BOND_LOG(ERR, "Failed to set bonded device %d mode too %d",
+                                eth_dev->data->port_id, mode);
                goto err;
        }
 
+       rte_spinlock_init(&internals->lock);
+
+       internals->port_id = eth_dev->data->port_id;
        internals->current_primary_port = 0;
        internals->balance_xmit_policy = BALANCE_XMIT_POLICY_LAYER2;
        internals->user_defined_mac = 0;
        internals->link_props_set = 0;
+
+       internals->link_status_polling_enabled = 0;
+
+       internals->link_status_polling_interval_ms = DEFAULT_POLLING_INTERVAL_10_MS;
+       internals->link_down_delay_ms = 0;
+       internals->link_up_delay_ms = 0;
+
        internals->slave_count = 0;
        internals->active_slave_count = 0;
 
        memset(internals->active_slaves, 0, sizeof(internals->active_slaves));
        memset(internals->slaves, 0, sizeof(internals->slaves));
 
-       memset(internals->presisted_slaves_conf, 0,
-                       sizeof(internals->presisted_slaves_conf));
-
        return eth_dev->data->port_id;
 
 err:
@@ -253,8 +258,8 @@ err:
        return -1;
 }
 
-int
-rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t slave_port_id)
+static int
+__eth_bond_slave_add_lock_free(uint8_t bonded_port_id, uint8_t slave_port_id)
 {
        struct rte_eth_dev *bonded_eth_dev, *slave_eth_dev;
        struct bond_dev_private *internals;
@@ -263,56 +268,43 @@ rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t slave_port_id)
 
        int i, j;
 
-       /* Verify that port id's are valid bonded and slave ports */
-       if (valid_bonded_port_id(bonded_port_id) != 0)
-               goto err_add;
-
        if (valid_slave_port_id(slave_port_id) != 0)
-               goto err_add;
+               return -1;
+
+       bonded_eth_dev = &rte_eth_devices[bonded_port_id];
+       internals = bonded_eth_dev->data->dev_private;
 
-       /*
-        * Verify that new slave device is not already a slave of another bonded
-        * device */
+       /* Verify that new slave device is not already a slave of another
+        * bonded device */
        for (i = rte_eth_dev_count()-1; i >= 0; i--) {
                if (valid_bonded_ethdev(&rte_eth_devices[i]) == 0) {
                        temp_internals = rte_eth_devices[i].data->dev_private;
+
                        for (j = 0; j < temp_internals->slave_count; j++) {
                                /* Device already a slave of a bonded device */
-                               if (temp_internals->slaves[j] == slave_port_id)
-                                       goto err_add;
+                               if (temp_internals->slaves[j].port_id == slave_port_id) {
+                                       RTE_BOND_LOG(ERR, "Slave port %d is already a slave",
+                                                       slave_port_id);
+                                       return -1;
+                               }
                        }
                }
        }
 
-       bonded_eth_dev = &rte_eth_devices[bonded_port_id];
-       internals = bonded_eth_dev->data->dev_private;
-
        slave_eth_dev = &rte_eth_devices[slave_port_id];
 
-       if (internals->slave_count > 0) {
-               /* Check that new slave device is the same type as the other slaves
-                * and not repetitive */
-               for (i = 0; i < internals->slave_count; i++) {
-                       if (slave_eth_dev->pci_dev->driver->id_table->device_id !=
-                                       rte_eth_devices[internals->slaves[i]].pci_dev->driver->id_table->device_id ||
-                               internals->slaves[i] == slave_port_id)
-                               goto err_add;
-               }
-       }
-
        /* Add slave details to bonded device */
-       internals->slaves[internals->slave_count] = slave_port_id;
-
-       slave_config_store(internals, slave_eth_dev);
+       slave_add(internals, slave_eth_dev);
 
        if (internals->slave_count < 1) {
-               /* if MAC is not user defined then use MAC of first slave add to bonded
-                * device */
+               /* if MAC is not user defined then use MAC of first slave add to
+                * bonded device */
                if (!internals->user_defined_mac)
                        mac_address_set(bonded_eth_dev, slave_eth_dev->data->mac_addrs);
 
                /* Inherit eth dev link properties from first slave */
-               link_properties_set(bonded_eth_dev, &(slave_eth_dev->data->dev_link));
+               link_properties_set(bonded_eth_dev,
+                               &(slave_eth_dev->data->dev_link));
 
                /* Make primary slave */
                internals->primary_port = slave_port_id;
@@ -322,10 +314,10 @@ rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t slave_port_id)
                if (internals->link_props_set) {
                        if (link_properties_valid(&(bonded_eth_dev->data->dev_link),
                                                                          &(slave_eth_dev->data->dev_link))) {
-                               RTE_LOG(ERR, PMD,
-                                               "%s: Slave port %d link speed/duplex not supported\n",
-                                               __func__, slave_port_id);
-                               goto err_add;
+                               RTE_BOND_LOG(ERR,
+                                               "Slave port %d link speed/duplex not supported",
+                                               slave_port_id);
+                               return -1;
                        }
                } else {
                        link_properties_set(bonded_eth_dev,
@@ -340,9 +332,9 @@ rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t slave_port_id)
 
        if (bonded_eth_dev->data->dev_started) {
                if (slave_configure(bonded_eth_dev, slave_eth_dev) != 0) {
-                       RTE_LOG(ERR, PMD, "rte_bond_slaves_configure: port=%d\n",
+                       RTE_BOND_LOG(ERR, "rte_bond_slaves_configure: port=%d",
                                        slave_port_id);
-                       goto err_add;
+                       return -1;
                }
        }
 
@@ -356,65 +348,79 @@ rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t slave_port_id)
        if (bonded_eth_dev->data->dev_started) {
                rte_eth_link_get_nowait(slave_port_id, &link_props);
 
-                if (link_props.link_status == 1) {
+                if (link_props.link_status == 1)
                        internals->active_slaves[internals->active_slave_count++] =
                                        slave_port_id;
-               }
        }
-
        return 0;
 
-err_add:
-       RTE_LOG(ERR, PMD, "Failed to add port %d as slave\n", slave_port_id);
-       return -1;
-
 }
 
+
 int
-rte_eth_bond_slave_remove(uint8_t bonded_port_id, uint8_t slave_port_id)
+rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t slave_port_id)
 {
+       struct rte_eth_dev *bonded_eth_dev;
        struct bond_dev_private *internals;
-       struct slave_conf *slave_conf;
 
-       int i;
-       int pos = -1;
+       int retval;
 
        /* Verify that port id's are valid bonded and slave ports */
        if (valid_bonded_port_id(bonded_port_id) != 0)
-               goto err_del;
+               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_remove_lock_free(uint8_t bonded_port_id, uint8_t slave_port_id)
+{
+       struct bond_dev_private *internals;
+
+       int i, slave_idx = -1;
 
        if (valid_slave_port_id(slave_port_id) != 0)
-               goto err_del;
+               return -1;
 
        internals = rte_eth_devices[bonded_port_id].data->dev_private;
 
        /* first remove from active slave list */
        for (i = 0; i < internals->active_slave_count; i++) {
                if (internals->active_slaves[i] == slave_port_id)
-                       pos = i;
+                       slave_idx = i;
 
                /* shift active slaves up active array list */
-               if (pos >= 0 && i < (internals->active_slave_count - 1))
+               if (slave_idx >= 0 && i < (internals->active_slave_count - 1))
                        internals->active_slaves[i] = internals->active_slaves[i+1];
        }
 
-       if (pos >= 0)
+       if (slave_idx >= 0)
                internals->active_slave_count--;
 
-       pos = -1;
-       /* now remove from slave list */
-       for (i = 0; i < internals->slave_count; i++) {
-               if (internals->slaves[i] == slave_port_id)
-                       pos = i;
+       slave_idx = -1;
+       /* now find in slave list */
+       for (i = 0; i < internals->slave_count; i++)
+               if (internals->slaves[i].port_id == slave_port_id) {
+                       slave_idx = i;
+                       break;
+               }
 
-               /* shift slaves up list */
-               if (pos >= 0 && i < internals->slave_count)
-                       internals->slaves[i] = internals->slaves[i+1];
+       if (slave_idx < 0) {
+               RTE_BOND_LOG(ERR, "Couldn't find slave in port list, slave count %d",
+                               internals->slave_count);
+               return -1;
        }
 
-       if (pos < 0)
-               goto err_del;
-
        /* Un-register link status change callback with bonded device pointer as
         * argument*/
        rte_eth_dev_callback_unregister(slave_port_id, RTE_ETH_EVENT_INTR_LSC,
@@ -422,13 +428,10 @@ rte_eth_bond_slave_remove(uint8_t bonded_port_id, uint8_t slave_port_id)
                        &rte_eth_devices[bonded_port_id].data->port_id);
 
        /* Restore original MAC address of slave device */
-       slave_conf = slave_config_get(internals, slave_port_id);
+       mac_address_set(&rte_eth_devices[slave_port_id],
+                       &(internals->slaves[slave_idx].persisted_mac_addr));
 
-       mac_address_set(&rte_eth_devices[slave_port_id], &(slave_conf->mac_addr));
-
-       slave_config_clear(internals, &rte_eth_devices[slave_port_id]);
-
-       internals->slave_count--;
+       slave_remove(internals, &rte_eth_devices[slave_port_id]);
 
        /*  first slave in the active list will be the primary by default,
         *  otherwise use first device in list */
@@ -436,7 +439,7 @@ rte_eth_bond_slave_remove(uint8_t bonded_port_id, uint8_t slave_port_id)
                if (internals->active_slave_count > 0)
                        internals->current_primary_port = internals->active_slaves[0];
                else if (internals->slave_count > 0)
-                       internals->current_primary_port = internals->slaves[0];
+                       internals->current_primary_port = internals->slaves[0].port_id;
                else
                        internals->primary_port = 0;
        }
@@ -454,12 +457,28 @@ rte_eth_bond_slave_remove(uint8_t bonded_port_id, uint8_t slave_port_id)
        }
 
        return 0;
+}
 
-err_del:
-       RTE_LOG(ERR, PMD,
-                       "Cannot remove slave device (not present in bonded device)\n");
-       return -1;
+int
+rte_eth_bond_slave_remove(uint8_t bonded_port_id, uint8_t slave_port_id)
+{
+       struct rte_eth_dev *bonded_eth_dev;
+       struct bond_dev_private *internals;
+       int retval;
+
+       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_remove_lock_free(bonded_port_id, slave_port_id);
+
+       rte_spinlock_unlock(&internals->lock);
 
+       return retval;
 }
 
 int
@@ -524,6 +543,7 @@ int
 rte_eth_bond_slaves_get(uint8_t bonded_port_id, uint8_t slaves[], uint8_t len)
 {
        struct bond_dev_private *internals;
+       int i;
 
        if (valid_bonded_port_id(bonded_port_id) != 0)
                return -1;
@@ -536,10 +556,10 @@ rte_eth_bond_slaves_get(uint8_t bonded_port_id, uint8_t slaves[], uint8_t len)
        if (internals->slave_count > len)
                return -1;
 
-       memcpy(slaves, internals->slaves, internals->slave_count);
+       for (i = 0; i < internals->slave_count; i++)
+               slaves[i] = internals->slaves[i].port_id;
 
        return internals->slave_count;
-
 }
 
 int
@@ -605,13 +625,13 @@ rte_eth_bond_mac_address_reset(uint8_t bonded_port_id)
        internals->user_defined_mac = 0;
 
        if (internals->slave_count > 0) {
-               struct slave_conf *conf;
-               conf = slave_config_get(internals, internals->primary_port);
-
                /* Set MAC Address of Bonded Device */
-               if (mac_address_set(bonded_eth_dev, &conf->mac_addr) != 0)
+               if (mac_address_set(bonded_eth_dev,
+                               &internals->slaves[internals->primary_port].persisted_mac_addr)
+                               != 0) {
+                       RTE_BOND_LOG(ERR, "Failed to set MAC address on bonded device");
                        return -1;
-
+               }
                /* Update all slave devices MAC addresses */
                return mac_address_slaves_update(bonded_eth_dev);
        }
@@ -654,3 +674,88 @@ rte_eth_bond_xmit_policy_get(uint8_t bonded_port_id)
 
        return internals->balance_xmit_policy;
 }
+
+
+int
+rte_eth_bond_link_monitoring_set(uint8_t bonded_port_id, uint32_t internal_ms)
+{
+       struct bond_dev_private *internals;
+
+       if (valid_bonded_port_id(bonded_port_id) != 0)
+               return -1;
+
+       internals = rte_eth_devices[bonded_port_id].data->dev_private;
+       internals->link_status_polling_interval_ms = internal_ms;
+
+       return 0;
+}
+
+int
+rte_eth_bond_link_monitoring_get(uint8_t bonded_port_id)
+{
+       struct bond_dev_private *internals;
+
+       if (valid_bonded_port_id(bonded_port_id) != 0)
+               return -1;
+
+       internals = rte_eth_devices[bonded_port_id].data->dev_private;
+
+       return internals->link_status_polling_interval_ms;
+}
+
+int
+rte_eth_bond_link_down_prop_delay_set(uint8_t bonded_port_id, uint32_t delay_ms)
+
+{
+       struct bond_dev_private *internals;
+
+       if (valid_bonded_port_id(bonded_port_id) != 0)
+               return -1;
+
+       internals = rte_eth_devices[bonded_port_id].data->dev_private;
+       internals->link_down_delay_ms = delay_ms;
+
+       return 0;
+}
+
+int
+rte_eth_bond_link_down_prop_delay_get(uint8_t bonded_port_id)
+{
+       struct bond_dev_private *internals;
+
+       if (valid_bonded_port_id(bonded_port_id) != 0)
+               return -1;
+
+       internals = rte_eth_devices[bonded_port_id].data->dev_private;
+
+       return internals->link_down_delay_ms;
+}
+
+
+int
+rte_eth_bond_link_up_prop_delay_set(uint8_t bonded_port_id, uint32_t delay_ms)
+
+{
+       struct bond_dev_private *internals;
+
+       if (valid_bonded_port_id(bonded_port_id) != 0)
+               return -1;
+
+       internals = rte_eth_devices[bonded_port_id].data->dev_private;
+       internals->link_up_delay_ms = delay_ms;
+
+       return 0;
+}
+
+int
+rte_eth_bond_link_up_prop_delay_get(uint8_t bonded_port_id)
+{
+       struct bond_dev_private *internals;
+
+       if (valid_bonded_port_id(bonded_port_id) != 0)
+               return -1;
+
+       internals = rte_eth_devices[bonded_port_id].data->dev_private;
+
+       return internals->link_up_delay_ms;
+}
index 05a2b07..d8ce681 100644 (file)
@@ -118,7 +118,7 @@ parse_port_id(const char *port_str)
        }
 
        if (port_id < 0 || port_id > RTE_MAX_ETHPORTS) {
-               RTE_LOG(ERR, PMD, "Invalid slave port value (%s) specified.\n",
+               RTE_BOND_LOG(ERR, "Slave port specified (%s) outside expected range",
                                port_str);
                return -1;
        }
@@ -138,9 +138,10 @@ bond_ethdev_parse_slave_port_kvarg(const char *key __rte_unused,
 
        if (strcmp(key, PMD_BOND_SLAVE_PORT_KVARG) == 0) {
                int port_id = parse_port_id(value);
-               if (port_id < 0)
+               if (port_id < 0) {
+                       RTE_BOND_LOG(ERR, "Invalid slave port value (%s) specified", value);
                        return -1;
-               else
+               else
                        slave_ports->slaves[slave_ports->slave_count++] =
                                        (uint8_t)port_id;
        }
@@ -174,6 +175,7 @@ bond_ethdev_parse_slave_mode_kvarg(const char *key __rte_unused,
 #endif
                return 0;
        default:
+               RTE_BOND_LOG(ERR, "Invalid slave mode value (%s) specified", value);
                return -1;
        }
 }
@@ -252,3 +254,23 @@ bond_ethdev_parse_bond_mac_addr_kvarg(const char *key __rte_unused,
        /* Parse MAC */
        return cmdline_parse_etheraddr(NULL, value, extra_args);
 }
+
+int
+bond_ethdev_parse_time_ms_kvarg(const char *key __rte_unused,
+               const char *value, void *extra_args)
+{
+       uint32_t time_ms;
+       char *endptr;
+
+       if (value == NULL || extra_args == NULL)
+               return -1;
+
+       errno = 0;
+       time_ms = (uint32_t)strtol(value, &endptr, 10);
+       if (*endptr != 0 || errno != 0)
+               return -1;
+
+       *(uint32_t *)extra_args = time_ms;
+
+       return 0;
+}
index 2a86402..cf2fbab 100644 (file)
@@ -40,6 +40,7 @@
 #include <rte_devargs.h>
 #include <rte_kvargs.h>
 #include <rte_dev.h>
+#include <rte_alarm.h>
 
 #include "rte_eth_bond.h"
 #include "rte_eth_bond_private.h"
@@ -457,16 +458,16 @@ mac_address_set(struct rte_eth_dev *eth_dev, struct ether_addr *new_mac_addr)
        mac_addr = eth_dev->data->mac_addrs;
 
        if (eth_dev == NULL) {
-               RTE_LOG(ERR, PMD, "%s: NULL pointer eth_dev specified\n", __func__);
+               RTE_BOND_LOG(ERR,  "NULL pointer eth_dev specified");
                return -1;
        }
 
        if (new_mac_addr == NULL) {
-               RTE_LOG(ERR, PMD, "%s: NULL pointer MAC specified\n", __func__);
+               RTE_BOND_LOG(ERR, "NULL pointer MAC specified");
                return -1;
        }
 
-       /* if new MAC is different to current MAC then update */
+       /* If new MAC is different to current MAC then update */
        if (memcmp(mac_addr, new_mac_addr, sizeof(*mac_addr)) != 0)
                memcpy(mac_addr, new_mac_addr, sizeof(*mac_addr));
 
@@ -490,11 +491,10 @@ mac_address_slaves_update(struct rte_eth_dev *bonded_eth_dev)
        case BONDING_MODE_BROADCAST:
 #endif
                for (i = 0; i < internals->slave_count; i++) {
-                       if (mac_address_set(&rte_eth_devices[internals->slaves[i]],
+                       if (mac_address_set(&rte_eth_devices[internals->slaves[i].port_id],
                                        bonded_eth_dev->data->mac_addrs)) {
-                               RTE_LOG(ERR, PMD,
-                                               "%s: Failed to update port Id %d MAC address\n",
-                                               __func__, internals->slaves[i]);
+                               RTE_BOND_LOG(ERR, "Failed to update port Id %d MAC address",
+                                               internals->slaves[i].port_id);
                                return -1;
                        }
                }
@@ -502,23 +502,20 @@ mac_address_slaves_update(struct rte_eth_dev *bonded_eth_dev)
        case BONDING_MODE_ACTIVE_BACKUP:
        default:
                for (i = 0; i < internals->slave_count; i++) {
-                       if (internals->slaves[i] == internals->current_primary_port) {
+                       if (internals->slaves[i].port_id ==
+                                       internals->current_primary_port) {
                                if (mac_address_set(&rte_eth_devices[internals->primary_port],
                                                bonded_eth_dev->data->mac_addrs)) {
-                                       RTE_LOG(ERR, PMD,
-                                                       "%s: Failed to update port Id %d MAC address\n",
-                                                       __func__, internals->current_primary_port);
+                                       RTE_BOND_LOG(ERR, "Failed to update port Id %d MAC address",
+                                                       internals->current_primary_port);
+                                       return -1;
                                }
                        } else {
-                               struct slave_conf *conf =
-                                               slave_config_get(internals, internals->slaves[i]);
-
-                               if (mac_address_set(&rte_eth_devices[internals->slaves[i]],
-                                               &conf->mac_addr)) {
-                                       RTE_LOG(ERR, PMD,
-                                                       "%s: Failed to update port Id %d MAC address\n",
-                                                       __func__, internals->slaves[i]);
-
+                               if (mac_address_set(
+                                               &rte_eth_devices[internals->slaves[i].port_id],
+                                               &internals->slaves[i].persisted_mac_addr)) {
+                                       RTE_BOND_LOG(ERR, "Failed to update port Id %d MAC address",
+                                                       internals->slaves[i].port_id);
                                        return -1;
                                }
                        }
@@ -570,34 +567,39 @@ slave_configure(struct rte_eth_dev *bonded_eth_dev,
        struct bond_rx_queue *bd_rx_q;
        struct bond_tx_queue *bd_tx_q;
 
-       int q_id;
+       int errval, q_id;
 
        /* Stop slave */
        rte_eth_dev_stop(slave_eth_dev->data->port_id);
 
-       /* Enable interrupts on slave device */
-       slave_eth_dev->data->dev_conf.intr_conf.lsc = 1;
+       /* Enable interrupts on slave device if supported */
+       if (slave_eth_dev->driver->pci_drv.drv_flags & RTE_PCI_DRV_INTR_LSC)
+               slave_eth_dev->data->dev_conf.intr_conf.lsc = 1;
 
-       if (rte_eth_dev_configure(slave_eth_dev->data->port_id,
+       /* Configure device */
+       errval = rte_eth_dev_configure(slave_eth_dev->data->port_id,
                        bonded_eth_dev->data->nb_rx_queues,
                        bonded_eth_dev->data->nb_tx_queues,
-                       &(slave_eth_dev->data->dev_conf)) != 0) {
-               RTE_LOG(ERR, PMD, "Cannot configure slave device: port=%u\n",
-                               slave_eth_dev->data->port_id);
-               return -1;
+                       &(slave_eth_dev->data->dev_conf));
+       if (errval != 0) {
+               RTE_BOND_LOG(ERR, "Cannot configure slave device: port %u , err (%d)",
+                               slave_eth_dev->data->port_id, errval);
+               return errval;
        }
 
        /* Setup Rx Queues */
        for (q_id = 0; q_id < bonded_eth_dev->data->nb_rx_queues; q_id++) {
                bd_rx_q = (struct bond_rx_queue *)bonded_eth_dev->data->rx_queues[q_id];
 
-               if (rte_eth_rx_queue_setup(slave_eth_dev->data->port_id, q_id,
+               errval = rte_eth_rx_queue_setup(slave_eth_dev->data->port_id, q_id,
                                bd_rx_q->nb_rx_desc,
                                rte_eth_dev_socket_id(slave_eth_dev->data->port_id),
-                               &(bd_rx_q->rx_conf), bd_rx_q->mb_pool) != 0) {
-                       RTE_LOG(ERR, PMD, "rte_eth_rx_queue_setup: port=%d queue_id %d\n",
-                                       slave_eth_dev->data->port_id, q_id);
-                       return -1;
+                               &(bd_rx_q->rx_conf), bd_rx_q->mb_pool);
+               if (errval != 0) {
+                       RTE_BOND_LOG(ERR,
+                                       "rte_eth_rx_queue_setup: port=%d queue_id %d, err (%d)",
+                                       slave_eth_dev->data->port_id, q_id, errval);
+                       return errval;
                }
        }
 
@@ -605,69 +607,77 @@ slave_configure(struct rte_eth_dev *bonded_eth_dev,
        for (q_id = 0; q_id < bonded_eth_dev->data->nb_tx_queues; q_id++) {
                bd_tx_q = (struct bond_tx_queue *)bonded_eth_dev->data->tx_queues[q_id];
 
-               if (rte_eth_tx_queue_setup(slave_eth_dev->data->port_id, q_id,
+               errval = rte_eth_tx_queue_setup(slave_eth_dev->data->port_id, q_id,
                                bd_tx_q->nb_tx_desc,
                                rte_eth_dev_socket_id(slave_eth_dev->data->port_id),
-                               &bd_tx_q->tx_conf) != 0) {
-                       RTE_LOG(ERR, PMD, "rte_eth_tx_queue_setup: port=%d queue_id %d\n",
-                                       slave_eth_dev->data->port_id, q_id);
-                       return -1;
+                               &bd_tx_q->tx_conf);
+               if (errval != 0) {
+                       RTE_BOND_LOG(ERR,
+                                       "rte_eth_tx_queue_setup: port=%d queue_id %d, err (%d)",
+                                       slave_eth_dev->data->port_id, q_id, errval);
+                       return errval;
                }
        }
 
        /* Start device */
-       if (rte_eth_dev_start(slave_eth_dev->data->port_id) != 0) {
-               RTE_LOG(ERR, PMD, "rte_eth_dev_start: port=%u\n",
-                               slave_eth_dev->data->port_id);
+       errval = rte_eth_dev_start(slave_eth_dev->data->port_id);
+       if (errval != 0) {
+               RTE_BOND_LOG(ERR, "rte_eth_dev_start: port=%u, err (%d)",
+                               slave_eth_dev->data->port_id, errval);
                return -1;
        }
 
        return 0;
 }
 
-struct slave_conf *
-slave_config_get(struct bond_dev_private *internals, uint8_t slave_port_id)
-{
-       int i;
-
-       for (i = 0; i < internals->slave_count; i++) {
-               if (internals->presisted_slaves_conf[i].port_id == slave_port_id)
-                       return &internals->presisted_slaves_conf[i];
-       }
-       return NULL;
-}
-
 void
-slave_config_clear(struct bond_dev_private *internals,
+slave_remove(struct bond_dev_private *internals,
                struct rte_eth_dev *slave_eth_dev)
 {
        int i, found = 0;
 
        for (i = 0; i < internals->slave_count; i++) {
-               if (internals->presisted_slaves_conf[i].port_id ==
-                               slave_eth_dev->data->port_id) {
+               if (internals->slaves[i].port_id ==     slave_eth_dev->data->port_id)
                        found = 1;
-                       memset(&internals->presisted_slaves_conf[i], 0,
-                                       sizeof(internals->presisted_slaves_conf[i]));
-               }
-               if (found && i < (internals->slave_count - 1)) {
-                       memcpy(&internals->presisted_slaves_conf[i],
-                                       &internals->presisted_slaves_conf[i+1],
-                                       sizeof(internals->presisted_slaves_conf[i]));
-               }
+
+               if (found && i < (internals->slave_count - 1))
+                       memcpy(&internals->slaves[i], &internals->slaves[i+1],
+                                       sizeof(internals->slaves[i]));
        }
+
+       internals->slave_count--;
 }
 
+static void
+bond_ethdev_slave_link_status_change_monitor(void *cb_arg);
+
 void
-slave_config_store(struct bond_dev_private *internals,
+slave_add(struct bond_dev_private *internals,
                struct rte_eth_dev *slave_eth_dev)
 {
-       struct slave_conf *presisted_slave_conf =
-                       &internals->presisted_slaves_conf[internals->slave_count];
+       struct bond_slave_details *slave_details =
+                       &internals->slaves[internals->slave_count];
+
+       slave_details->port_id = slave_eth_dev->data->port_id;
+       slave_details->last_link_status = 0;
+
+       /* If slave device doesn't support interrupts then we need to enabled
+        * polling to monitor link status */
+       if (!(slave_eth_dev->pci_dev->driver->drv_flags & RTE_PCI_DRV_INTR_LSC)) {
+               slave_details->link_status_poll_enabled = 1;
+
+               if (!internals->link_status_polling_enabled) {
+                       internals->link_status_polling_enabled = 1;
 
-       presisted_slave_conf->port_id = slave_eth_dev->data->port_id;
+                       rte_eal_alarm_set(internals->link_status_polling_interval_ms * 1000,
+                                       bond_ethdev_slave_link_status_change_monitor,
+                                       (void *)&rte_eth_devices[internals->port_id]);
+               }
+       }
 
-       memcpy(&(presisted_slave_conf->mac_addr), slave_eth_dev->data->mac_addrs,
+       slave_details->link_status_wait_to_complete = 0;
+
+       memcpy(&(slave_details->persisted_mac_addr), slave_eth_dev->data->mac_addrs,
                        sizeof(struct ether_addr));
 }
 
@@ -698,31 +708,33 @@ bond_ethdev_start(struct rte_eth_dev *eth_dev)
 
        /* slave eth dev will be started by bonded device */
        if (valid_bonded_ethdev(eth_dev)) {
-               RTE_LOG(ERR, PMD,
-                               "%s: user tried to explicitly start a slave eth_dev (%d) of the bonded eth_dev\n",
-                               __func__, eth_dev->data->port_id);
+               RTE_BOND_LOG(ERR, "User tried to explicitly start a slave eth_dev (%d)",
+                               eth_dev->data->port_id);
                return -1;
        }
 
-       eth_dev->data->dev_link.link_status = 1;
+       eth_dev->data->dev_link.link_status = 0;
        eth_dev->data->dev_started = 1;
 
        internals = eth_dev->data->dev_private;
 
        if (internals->slave_count == 0) {
-               RTE_LOG(ERR, PMD,
-                               "%s: Cannot start port since there are no slave devices\n",
-                               __func__);
+               RTE_BOND_LOG(ERR, "Cannot start port since there are no slave devices");
                return -1;
        }
 
        if (internals->user_defined_mac == 0) {
-               struct slave_conf *conf = slave_config_get(internals,
-                               internals->primary_port);
+               struct ether_addr *new_mac_addr = NULL;
+
+               for (i = 0; i < internals->slave_count; i++)
+                       if (internals->slaves[i].port_id == internals->primary_port)
+                               new_mac_addr = &internals->slaves[i].persisted_mac_addr;
+
+               if (new_mac_addr == NULL)
+                       return -1;
 
-               if (mac_address_set(eth_dev, &(conf->mac_addr)) != 0) {
-                       RTE_LOG(ERR, PMD,
-                                       "bonded port (%d) failed to update mac address",
+               if (mac_address_set(eth_dev, new_mac_addr) != 0) {
+                       RTE_BOND_LOG(ERR, "bonded port (%d) failed to update MAC address",
                                        eth_dev->data->port_id);
                        return -1;
                }
@@ -738,11 +750,11 @@ bond_ethdev_start(struct rte_eth_dev *eth_dev)
 
        /* Reconfigure each slave device if starting bonded device */
        for (i = 0; i < internals->slave_count; i++) {
-               if (slave_configure(eth_dev, &(rte_eth_devices[internals->slaves[i]]))
-                               != 0) {
-                       RTE_LOG(ERR, PMD, "bonded port "
-                                       "(%d) failed to reconfigure slave device (%d)\n)",
-                                       eth_dev->data->port_id, internals->slaves[i]);
+               if (slave_configure(eth_dev,
+                               &(rte_eth_devices[internals->slaves[i].port_id])) != 0) {
+                       RTE_BOND_LOG(ERR,
+                                       "bonded port (%d) failed to reconfigure slave device (%d)",
+                                       eth_dev->data->port_id, internals->slaves[i].port_id);
                        return -1;
                }
        }
@@ -759,6 +771,7 @@ bond_ethdev_stop(struct rte_eth_dev *eth_dev)
        struct bond_dev_private *internals = eth_dev->data->dev_private;
 
        internals->active_slave_count = 0;
+       internals->link_status_polling_enabled = 0;
 
        eth_dev->data->dev_link.link_status = 0;
        eth_dev->data->dev_started = 0;
@@ -852,6 +865,65 @@ bond_ethdev_tx_queue_release(void *queue)
        rte_free(queue);
 }
 
+
+static void
+bond_ethdev_slave_link_status_change_monitor(void *cb_arg)
+{
+       struct rte_eth_dev *bonded_ethdev, *slave_ethdev;
+       struct bond_dev_private *internals;
+
+       /* Default value for polling slave found is true as we don't want to
+        * disable the polling thread if we cannot get the lock */
+       int i, polling_slave_found = 1;
+
+       if (cb_arg == NULL)
+               return;
+
+       bonded_ethdev = (struct rte_eth_dev *)cb_arg;
+       internals = (struct bond_dev_private *)bonded_ethdev->data->dev_private;
+
+       if (!bonded_ethdev->data->dev_started ||
+               !internals->link_status_polling_enabled)
+               return;
+
+       /* If device is currently being configured then don't check slaves link
+        * status, wait until next period */
+       if (rte_spinlock_trylock(&internals->lock)) {
+               if (internals->slave_count > 0)
+                       polling_slave_found = 0;
+
+               for (i = 0; i < internals->slave_count; i++) {
+                       if (!internals->slaves[i].link_status_poll_enabled)
+                               continue;
+
+                       slave_ethdev = &rte_eth_devices[internals->slaves[i].port_id];
+                       polling_slave_found = 1;
+
+                       /* Update slave link status */
+                       (*slave_ethdev->dev_ops->link_update)(slave_ethdev,
+                                       internals->slaves[i].link_status_wait_to_complete);
+
+                       /* if link status has changed since last checked then call lsc
+                        * event callback */
+                       if (slave_ethdev->data->dev_link.link_status !=
+                                       internals->slaves[i].last_link_status) {
+                               internals->slaves[i].last_link_status =
+                                               slave_ethdev->data->dev_link.link_status;
+
+                               bond_ethdev_lsc_event_callback(internals->slaves[i].port_id,
+                                               RTE_ETH_EVENT_INTR_LSC,
+                                               &bonded_ethdev->data->port_id);
+                       }
+               }
+               rte_spinlock_unlock(&internals->lock);
+       }
+
+       if (polling_slave_found)
+               /* Set alarm to continue monitoring link status of slave ethdev's */
+               rte_eal_alarm_set(internals->link_status_polling_interval_ms * 1000,
+                               bond_ethdev_slave_link_status_change_monitor, cb_arg);
+}
+
 static int
 bond_ethdev_link_update(struct rte_eth_dev *bonded_eth_dev,
                int wait_to_complete)
@@ -895,7 +967,7 @@ bond_ethdev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
        memset(stats, 0, sizeof(*stats));
 
        for (i = 0; i < internals->slave_count; i++) {
-               rte_eth_stats_get(internals->slaves[i], &slave_stats);
+               rte_eth_stats_get(internals->slaves[i].port_id, &slave_stats);
 
                stats->ipackets += slave_stats.ipackets;
                stats->opackets += slave_stats.opackets;
@@ -921,7 +993,7 @@ bond_ethdev_stats_reset(struct rte_eth_dev *dev)
        int i;
 
        for (i = 0; i < internals->slave_count; i++)
-               rte_eth_stats_reset(internals->slaves[i]);
+               rte_eth_stats_reset(internals->slaves[i].port_id);
 }
 
 static void
@@ -940,7 +1012,7 @@ bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev)
        case BONDING_MODE_BROADCAST:
 #endif
                for (i = 0; i < internals->slave_count; i++)
-                       rte_eth_promiscuous_enable(internals->slaves[i]);
+                       rte_eth_promiscuous_enable(internals->slaves[i].port_id);
                break;
        /* Promiscuous mode is propagated only to primary slave */
        case BONDING_MODE_ACTIVE_BACKUP:
@@ -966,7 +1038,7 @@ bond_ethdev_promiscuous_disable(struct rte_eth_dev *dev)
        case BONDING_MODE_BROADCAST:
 #endif
                for (i = 0; i < internals->slave_count; i++)
-                       rte_eth_promiscuous_disable(internals->slaves[i]);
+                       rte_eth_promiscuous_disable(internals->slaves[i].port_id);
                break;
        /* Promiscuous mode is propagated only to primary slave */
        case BONDING_MODE_ACTIVE_BACKUP:
@@ -975,6 +1047,16 @@ bond_ethdev_promiscuous_disable(struct rte_eth_dev *dev)
        }
 }
 
+static void
+bond_ethdev_delayed_lsc_propagation(void *arg)
+{
+       if (arg == NULL)
+               return;
+
+       _rte_eth_dev_callback_process((struct rte_eth_dev *)arg,
+                       RTE_ETH_EVENT_INTR_LSC);
+}
+
 void
 bond_ethdev_lsc_event_callback(uint8_t port_id, enum rte_eth_event_type type,
                void *param)
@@ -1003,7 +1085,7 @@ bond_ethdev_lsc_event_callback(uint8_t port_id, enum rte_eth_event_type type,
 
        /* verify that port_id is a valid slave of bonded port */
        for (i = 0; i < internals->slave_count; i++) {
-               if (internals->slaves[i] == port_id) {
+               if (internals->slaves[i].port_id == port_id) {
                        valid_slave = 1;
                        break;
                }
@@ -1072,8 +1154,32 @@ bond_ethdev_lsc_event_callback(uint8_t port_id, enum rte_eth_event_type type,
                }
        }
 
-       if (lsc_flag)
-               _rte_eth_dev_callback_process(bonded_eth_dev, RTE_ETH_EVENT_INTR_LSC);
+       if (lsc_flag) {
+               /* Cancel any possible outstanding interrupts if delays are enabled */
+               if (internals->link_up_delay_ms > 0 ||
+                       internals->link_down_delay_ms > 0)
+                       rte_eal_alarm_cancel(bond_ethdev_delayed_lsc_propagation,
+                                       bonded_eth_dev);
+
+               if (bonded_eth_dev->data->dev_link.link_status) {
+                       if (internals->link_up_delay_ms > 0)
+                               rte_eal_alarm_set(internals->link_up_delay_ms * 1000,
+                                               bond_ethdev_delayed_lsc_propagation,
+                                               (void *)bonded_eth_dev);
+                       else
+                               _rte_eth_dev_callback_process(bonded_eth_dev,
+                                               RTE_ETH_EVENT_INTR_LSC);
+
+               } else {
+                       if (internals->link_down_delay_ms > 0)
+                               rte_eal_alarm_set(internals->link_down_delay_ms * 1000,
+                                               bond_ethdev_delayed_lsc_propagation,
+                                               (void *)bonded_eth_dev);
+                       else
+                               _rte_eth_dev_callback_process(bonded_eth_dev,
+                                               RTE_ETH_EVENT_INTR_LSC);
+               }
+       }
 }
 
 struct eth_dev_ops default_dev_ops = {
@@ -1223,8 +1329,8 @@ bond_ethdev_configure(struct rte_eth_dev *dev)
                }
        } else if (arg_count > 1) {
                RTE_LOG(ERR, EAL,
-                               "Transmit policy can be specified only once for bonded device %s\n",
-                               name);
+                               "Transmit policy can be specified only once for bonded device"
+                               " %s\n", name);
                return -1;
        }
 
@@ -1266,8 +1372,8 @@ bond_ethdev_configure(struct rte_eth_dev *dev)
                                &bond_ethdev_parse_primary_slave_port_id_kvarg,
                                &primary_slave_port_id) < 0) {
                        RTE_LOG(INFO, EAL,
-                                       "Invalid primary slave port id specified for bonded device %s\n",
-                                       name);
+                                       "Invalid primary slave port id specified for bonded device"
+                                       " %s\n", name);
                        return -1;
                }
 
@@ -1281,8 +1387,97 @@ bond_ethdev_configure(struct rte_eth_dev *dev)
                }
        } else if (arg_count > 1) {
                RTE_LOG(INFO, EAL,
-                               "Primary slave can be specified only once for bonded device %s\n",
-                               name);
+                               "Primary slave can be specified only once for bonded device"
+                               " %s\n", name);
+               return -1;
+       }
+
+       /* Parse link status monitor polling interval */
+       arg_count = rte_kvargs_count(kvlist, PMD_BOND_LSC_POLL_PERIOD_KVARG);
+       if (arg_count == 1) {
+               uint32_t lsc_poll_interval_ms;
+
+               if (rte_kvargs_process(kvlist,
+                               PMD_BOND_LSC_POLL_PERIOD_KVARG,
+                               &bond_ethdev_parse_time_ms_kvarg,
+                               &lsc_poll_interval_ms) < 0) {
+                       RTE_LOG(INFO, EAL,
+                                       "Invalid lsc polling interval value specified for bonded"
+                                       " device %s\n", name);
+                       return -1;
+               }
+
+               if (rte_eth_bond_link_monitoring_set(port_id, lsc_poll_interval_ms)
+                               != 0) {
+                       RTE_LOG(ERR, EAL,
+                                       "Failed to set lsc monitor polling interval (%u ms) on"
+                                       " bonded device %s\n", lsc_poll_interval_ms, name);
+                       return -1;
+               }
+       } else if (arg_count > 1) {
+               RTE_LOG(INFO, EAL,
+                               "LSC polling interval can be specified only once for bonded"
+                               " device %s\n", name);
+               return -1;
+       }
+
+       /* Parse link up interrupt propagation delay */
+       arg_count = rte_kvargs_count(kvlist, PMD_BOND_LINK_UP_PROP_DELAY_KVARG);
+       if (arg_count == 1) {
+               uint32_t link_up_delay_ms;
+
+               if (rte_kvargs_process(kvlist,
+                               PMD_BOND_LINK_UP_PROP_DELAY_KVARG,
+                               &bond_ethdev_parse_time_ms_kvarg,
+                               &link_up_delay_ms) < 0) {
+                       RTE_LOG(INFO, EAL,
+                                       "Invalid link up propagation delay value specified for"
+                                       " bonded device %s\n", name);
+                       return -1;
+               }
+
+               /* Set balance mode transmit policy*/
+               if (rte_eth_bond_link_up_prop_delay_set(port_id, link_up_delay_ms)
+                               != 0) {
+                       RTE_LOG(ERR, EAL,
+                                       "Failed to set link up propagation delay (%u ms) on bonded"
+                                       " device %s\n", link_up_delay_ms, name);
+                       return -1;
+               }
+       } else if (arg_count > 1) {
+               RTE_LOG(INFO, EAL,
+                               "Link up propagation delay can be specified only once for"
+                               " bonded device %s\n", name);
+               return -1;
+       }
+
+       /* Parse link down interrupt propagation delay */
+       arg_count = rte_kvargs_count(kvlist, PMD_BOND_LINK_DOWN_PROP_DELAY_KVARG);
+       if (arg_count == 1) {
+               uint32_t link_down_delay_ms;
+
+               if (rte_kvargs_process(kvlist,
+                               PMD_BOND_LINK_DOWN_PROP_DELAY_KVARG,
+                               &bond_ethdev_parse_time_ms_kvarg,
+                               &link_down_delay_ms) < 0) {
+                       RTE_LOG(INFO, EAL,
+                                       "Invalid link down propagation delay value specified for"
+                                       " bonded device %s\n", name);
+                       return -1;
+               }
+
+               /* Set balance mode transmit policy*/
+               if (rte_eth_bond_link_down_prop_delay_set(port_id, link_down_delay_ms)
+                               != 0) {
+                       RTE_LOG(ERR, EAL,
+                                       "Failed to set link down propagation delay (%u ms) on"
+                                       " bonded device %s\n", link_down_delay_ms, name);
+                       return -1;
+               }
+       } else if (arg_count > 1) {
+               RTE_LOG(INFO, EAL,
+                               "Link down propagation delay can be specified only once for"
+                               " bonded device %s\n", name);
                return -1;
        }
 
index 1db6e4d..6254c84 100644 (file)
@@ -39,20 +39,27 @@ extern "C" {
 #endif
 
 #include <rte_ethdev.h>
+#include <rte_spinlock.h>
 
 #include "rte_eth_bond.h"
 
-#define PMD_BOND_SLAVE_PORT_KVARG              ("slave")
-#define PMD_BOND_PRIMARY_SLAVE_KVARG   ("primary")
-#define PMD_BOND_MODE_KVARG                            ("mode")
-#define PMD_BOND_XMIT_POLICY_KVARG             ("xmit_policy")
-#define PMD_BOND_SOCKET_ID_KVARG               ("socket_id")
-#define PMD_BOND_MAC_ADDR_KVARG                        ("mac")
+#define PMD_BOND_SLAVE_PORT_KVARG                      ("slave")
+#define PMD_BOND_PRIMARY_SLAVE_KVARG           ("primary")
+#define PMD_BOND_MODE_KVARG                                    ("mode")
+#define PMD_BOND_XMIT_POLICY_KVARG                     ("xmit_policy")
+#define PMD_BOND_SOCKET_ID_KVARG                       ("socket_id")
+#define PMD_BOND_MAC_ADDR_KVARG                                ("mac")
+#define PMD_BOND_LSC_POLL_PERIOD_KVARG         ("lsc_poll_period_ms")
+#define PMD_BOND_LINK_UP_PROP_DELAY_KVARG      ("up_delay")
+#define PMD_BOND_LINK_DOWN_PROP_DELAY_KVARG    ("down_delay")
 
 #define PMD_BOND_XMIT_POLICY_LAYER2_KVARG      ("l2")
 #define PMD_BOND_XMIT_POLICY_LAYER23_KVARG     ("l23")
 #define PMD_BOND_XMIT_POLICY_LAYER34_KVARG     ("l34")
 
+#define RTE_BOND_LOG(lvl, msg, ...)            \
+       RTE_LOG(lvl, PMD, "%s(%d) - " msg "\n", __func__, __LINE__, ##__VA_ARGS__)
+
 extern const char *pmd_bond_init_valid_arguments[];
 
 extern const char *driver_name;
@@ -82,27 +89,36 @@ struct bond_tx_queue {
        /**< Copy of TX configuration structure for queue */
 };
 
-/** Persisted Slave Configuration Structure */
-struct slave_conf {
-       uint8_t port_id;
-       /**< Port Id of slave eth_dev */
-       struct ether_addr mac_addr;
-       /**< Slave eth_dev original MAC address */
-};
+
 /** Bonded slave devices structure */
 struct bond_ethdev_slave_ports {
        uint8_t slaves[RTE_MAX_ETHPORTS];       /**< Slave port id array */
        uint8_t slave_count;                            /**< Number of slaves */
 };
 
+struct bond_slave_details {
+       uint8_t port_id;
+
+       uint8_t link_status_poll_enabled;
+       uint8_t link_status_wait_to_complete;
+       uint8_t last_link_status;
+
+       /**< Port Id of slave eth_dev */
+       struct ether_addr persisted_mac_addr;
+};
+
 /** Link Bonding PMD device private configuration Structure */
 struct bond_dev_private {
+       uint8_t port_id;                                        /**< Port Id of Bonded Port */
        uint8_t mode;                                           /**< Link Bonding Mode */
 
+       rte_spinlock_t lock;
+
        uint8_t primary_port;                           /**< Primary Slave Port */
        uint8_t current_primary_port;           /**< Primary Slave Port */
        uint8_t user_defined_primary_port;
        /**< Flag for whether primary port is user defined or not */
+
        uint8_t balance_xmit_policy;
        /**< Transmit policy - l2 / l23 / l34 for operation in balance mode */
        uint8_t user_defined_mac;
@@ -110,19 +126,23 @@ struct bond_dev_private {
        uint8_t promiscuous_en;
        /**< Enabled/disable promiscuous mode on slave devices */
        uint8_t link_props_set;
-       /**< Bonded eth_dev link properties set */
+       /**< flag to denote if the link properties are set */
+
+       uint8_t link_status_polling_enabled;
+       uint32_t link_status_polling_interval_ms;
+
+       uint32_t link_down_delay_ms;
+       uint32_t link_up_delay_ms;
 
        uint16_t nb_rx_queues;                  /**< Total number of rx queues */
        uint16_t nb_tx_queues;                  /**< Total number of tx queues*/
 
-       uint8_t slave_count;                    /**< Number of active slaves */
-       uint8_t active_slave_count;             /**< Number of slaves */
-
+       uint8_t active_slave_count;             /**< Number of active slaves */
        uint8_t active_slaves[RTE_MAX_ETHPORTS];        /**< Active slave list */
-       uint8_t slaves[RTE_MAX_ETHPORTS];                       /**< Slave list */
 
-       /** Persisted configuration of slaves */
-       struct slave_conf presisted_slaves_conf[RTE_MAX_ETHPORTS];
+       uint8_t slave_count;                    /**< Number of bonded slaves */
+       struct bond_slave_details slaves[RTE_MAX_ETHPORTS];
+       /**< Arary of bonded slaves details */
 
        struct rte_kvargs *kvlist;
 };
@@ -168,16 +188,13 @@ slave_configure(struct rte_eth_dev *bonded_eth_dev,
                struct rte_eth_dev *slave_eth_dev);
 
 void
-slave_config_clear(struct bond_dev_private *internals,
+slave_remove(struct bond_dev_private *internals,
                struct rte_eth_dev *slave_eth_dev);
 
 void
-slave_config_store(struct bond_dev_private *internals,
+slave_add(struct bond_dev_private *internals,
                struct rte_eth_dev *slave_eth_dev);
 
-struct slave_conf *
-slave_config_get(struct bond_dev_private *internals, uint8_t slave_port_id);
-
 void
 bond_ethdev_primary_set(struct bond_dev_private *internals,
                uint8_t slave_port_id);
@@ -210,6 +227,10 @@ int
 bond_ethdev_parse_bond_mac_addr_kvarg(const char *key __rte_unused,
                const char *value, void *extra_args);
 
+int
+bond_ethdev_parse_time_ms_kvarg(const char *key __rte_unused,
+               const char *value, void *extra_args);
+
 #ifdef __cplusplus
 }
 #endif