From patchwork Mon Nov 24 16:33:41 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Doherty, Declan" X-Patchwork-Id: 1500 Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id B0027811E; Mon, 24 Nov 2014 17:23:41 +0100 (CET) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by dpdk.org (Postfix) with ESMTP id 6142480DA for ; Mon, 24 Nov 2014 17:23:08 +0100 (CET) Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga103.jf.intel.com with ESMTP; 24 Nov 2014 08:30:58 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.07,449,1413270000"; d="scan'208";a="613190965" Received: from irvmail001.ir.intel.com ([163.33.26.43]) by orsmga001.jf.intel.com with ESMTP; 24 Nov 2014 08:33:54 -0800 Received: from sivswdev02.ir.intel.com (sivswdev02.ir.intel.com [10.237.217.46]) by irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id sAOGXrN1010685; Mon, 24 Nov 2014 16:33:53 GMT Received: from sivswdev02.ir.intel.com (localhost [127.0.0.1]) by sivswdev02.ir.intel.com with ESMTP id sAOGXrmm028092; Mon, 24 Nov 2014 16:33:53 GMT Received: (from dwdohert@localhost) by sivswdev02.ir.intel.com with id sAOGXrOu028088; Mon, 24 Nov 2014 16:33:53 GMT From: Declan Doherty To: dev@dpdk.org Date: Mon, 24 Nov 2014 16:33:41 +0000 Message-Id: <1416846822-26897-7-git-send-email-declan.doherty@intel.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1416846822-26897-1-git-send-email-declan.doherty@intel.com> References: <1416832054-24086-1-git-send-email-declan.doherty@intel.com> <1416846822-26897-1-git-send-email-declan.doherty@intel.com> Subject: [dpdk-dev] [PATCH v8 6/7] bond: lsc polling support X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Signed-off-by: Declan Doherty --- app/test-pmd/cmdline.c | 63 +++++ app/test/test.h | 7 +- app/test/test_link_bonding.c | 265 ++++++++++++------- app/test/virtual_pmd.c | 17 +- app/test/virtual_pmd.h | 48 +++- doc/guides/testpmd_app_ug/testpmd_funcs.rst | 19 ++ lib/librte_pmd_bond/rte_eth_bond.h | 80 ++++++ lib/librte_pmd_bond/rte_eth_bond_api.c | 315 ++++++++++++++------- lib/librte_pmd_bond/rte_eth_bond_args.c | 28 ++- lib/librte_pmd_bond/rte_eth_bond_pmd.c | 393 ++++++++++++++++++++------- lib/librte_pmd_bond/rte_eth_bond_private.h | 71 +++-- 11 files changed, 958 insertions(+), 348 deletions(-) diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index be12c13..af8f907 100644 --- a/app/test-pmd/cmdline.c +++ b/app/test-pmd/cmdline.c @@ -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 , list_pkt_forwarding_modes() @@ -3733,6 +3736,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 *** */ @@ -7787,6 +7849,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, diff --git a/app/test/test.h b/app/test/test.h index bd44a7f..d5b6951 100644 --- a/app/test/test.h +++ b/app/test/test.h @@ -62,14 +62,15 @@ #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; \ diff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c index c11a0bc..2411125 100644 --- a/app/test/test_link_bonding.c +++ b/app/test/test_link_bonding.c @@ -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), diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c index 81d4be3..e7be98b 100644 --- a/app/test/virtual_pmd.c +++ b/app/test/virtual_pmd.c @@ -456,6 +456,14 @@ virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count(uint8_t port_id, } 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; diff --git a/app/test/virtual_pmd.h b/app/test/virtual_pmd.h index 3b5c911..2462853 100644 --- a/app/test/virtual_pmd.h +++ b/app/test/virtual_pmd.h @@ -40,38 +40,58 @@ extern "C" { #include -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 diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst index c0d0033..93fd3d4 100644 --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst @@ -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 ~~~~~~~~~~~~~~~~~~~ diff --git a/lib/librte_pmd_bond/rte_eth_bond.h b/lib/librte_pmd_bond/rte_eth_bond.h index 344ca1e..2ed4f7c 100644 --- a/lib/librte_pmd_bond/rte_eth_bond.h +++ b/lib/librte_pmd_bond/rte_eth_bond.h @@ -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 diff --git a/lib/librte_pmd_bond/rte_eth_bond_api.c b/lib/librte_pmd_bond/rte_eth_bond_api.c index dd33119..f146bda 100644 --- a/lib/librte_pmd_bond/rte_eth_bond_api.c +++ b/lib/librte_pmd_bond/rte_eth_bond_api.c @@ -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; +} diff --git a/lib/librte_pmd_bond/rte_eth_bond_args.c b/lib/librte_pmd_bond/rte_eth_bond_args.c index 05a2b07..d8ce681 100644 --- a/lib/librte_pmd_bond/rte_eth_bond_args.c +++ b/lib/librte_pmd_bond/rte_eth_bond_args.c @@ -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; +} diff --git a/lib/librte_pmd_bond/rte_eth_bond_pmd.c b/lib/librte_pmd_bond/rte_eth_bond_pmd.c index 2a86402..be87390 100644 --- a/lib/librte_pmd_bond/rte_eth_bond_pmd.c +++ b/lib/librte_pmd_bond/rte_eth_bond_pmd.c @@ -40,6 +40,7 @@ #include #include #include +#include #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; } diff --git a/lib/librte_pmd_bond/rte_eth_bond_private.h b/lib/librte_pmd_bond/rte_eth_bond_private.h index 1db6e4d..030d143 100644 --- a/lib/librte_pmd_bond/rte_eth_bond_private.h +++ b/lib/librte_pmd_bond/rte_eth_bond_private.h @@ -39,20 +39,27 @@ extern "C" { #endif #include +#include #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