From 548d70de68a4156d5bd4148e50a81555a0ef169f Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Thu, 30 Jan 2020 20:47:37 +0100 Subject: misc: deprecate dpdk hqos Not in functional state for a long time ... Type: refactor Change-Id: I2cc1525a6d49518cbc94faf6afbf0d2d0d515f56 Signed-off-by: Damjan Marion --- extras/deprecated/dpdk-hqos/api/dpdk.api | 82 ++ extras/deprecated/dpdk-hqos/api/dpdk_api.c | 248 ++++ extras/deprecated/dpdk-hqos/api/dpdk_test.c | 285 +++++ extras/deprecated/dpdk-hqos/dpdk-hqos.diff | 1726 +++++++++++++++++++++++++++ extras/deprecated/dpdk-hqos/hqos.c | 771 ++++++++++++ extras/deprecated/dpdk-hqos/qos_doc.md | 411 +++++++ src/plugins/dpdk/CMakeLists.txt | 9 - src/plugins/dpdk/api/dpdk.api | 82 -- src/plugins/dpdk/api/dpdk_api.c | 248 ---- src/plugins/dpdk/api/dpdk_test.c | 285 ----- src/plugins/dpdk/device/cli.c | 1357 --------------------- src/plugins/dpdk/device/device.c | 15 - src/plugins/dpdk/device/dpdk.h | 81 -- src/plugins/dpdk/device/format.c | 19 - src/plugins/dpdk/device/init.c | 77 -- src/plugins/dpdk/hqos/hqos.c | 771 ------------ src/plugins/dpdk/hqos/qos_doc.md | 411 ------- 17 files changed, 3523 insertions(+), 3355 deletions(-) create mode 100644 extras/deprecated/dpdk-hqos/api/dpdk.api create mode 100755 extras/deprecated/dpdk-hqos/api/dpdk_api.c create mode 100644 extras/deprecated/dpdk-hqos/api/dpdk_test.c create mode 100644 extras/deprecated/dpdk-hqos/dpdk-hqos.diff create mode 100644 extras/deprecated/dpdk-hqos/hqos.c create mode 100644 extras/deprecated/dpdk-hqos/qos_doc.md delete mode 100644 src/plugins/dpdk/api/dpdk.api delete mode 100755 src/plugins/dpdk/api/dpdk_api.c delete mode 100644 src/plugins/dpdk/api/dpdk_test.c delete mode 100644 src/plugins/dpdk/hqos/hqos.c delete mode 100644 src/plugins/dpdk/hqos/qos_doc.md diff --git a/extras/deprecated/dpdk-hqos/api/dpdk.api b/extras/deprecated/dpdk-hqos/api/dpdk.api new file mode 100644 index 00000000000..40bc7369af4 --- /dev/null +++ b/extras/deprecated/dpdk-hqos/api/dpdk.api @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +option version = "1.0.0"; +import "vnet/interface_types.api"; + +/** \brief DPDK interface HQoS pipe profile set request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sw_if_index - the interface + @param subport - subport ID + @param pipe - pipe ID within its subport + @param profile - pipe profile ID +*/ +autoreply define sw_interface_set_dpdk_hqos_pipe { + u32 client_index; + u32 context; + vl_api_interface_index_t sw_if_index; + u32 subport; + u32 pipe; + u32 profile; + option vat_help = "rx sw_if_index subport pipe profile "; +}; + +/** \brief DPDK interface HQoS subport parameters set request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sw_if_index - the interface + @param subport - subport ID + @param tb_rate - subport token bucket rate (measured in bytes/second) + @param tb_size - subport token bucket size (measured in credits) + @param tc_rate - subport traffic class 0 .. 3 rates (measured in bytes/second) + @param tc_period - enforcement period for rates (measured in milliseconds) +*/ +autoreply define sw_interface_set_dpdk_hqos_subport { + u32 client_index; + u32 context; + vl_api_interface_index_t sw_if_index; + u32 subport; + u32 tb_rate; + u32 tb_size; + u32 tc_rate[4]; + u32 tc_period; + option vat_help = "rx sw_if_index subport [rate ] [bktsize ] [tc0 ] [tc1 ] [tc2 ] [tc3 ] [period ]\n"; +}; + +/** \brief DPDK interface HQoS tctbl entry set request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sw_if_index - the interface + @param entry - entry index ID + @param tc - traffic class (0 .. 3) + @param queue - traffic class queue (0 .. 3) +*/ +autoreply define sw_interface_set_dpdk_hqos_tctbl { + u32 client_index; + u32 context; + vl_api_interface_index_t sw_if_index; + u32 entry; + u32 tc; + u32 queue; + option vat_help = "rx sw_if_index entry tc queue "; +}; + +/* + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ + diff --git a/extras/deprecated/dpdk-hqos/api/dpdk_api.c b/extras/deprecated/dpdk-hqos/api/dpdk_api.c new file mode 100755 index 00000000000..8b22c650c82 --- /dev/null +++ b/extras/deprecated/dpdk-hqos/api/dpdk_api.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +/* define message IDs */ +#include +#include + +#include + +static void + vl_api_sw_interface_set_dpdk_hqos_pipe_t_handler + (vl_api_sw_interface_set_dpdk_hqos_pipe_t * mp) +{ + vl_api_sw_interface_set_dpdk_hqos_pipe_reply_t *rmp; + int rv = 0; + + dpdk_main_t *dm = &dpdk_main; + dpdk_device_t *xd; + + u32 sw_if_index = ntohl (mp->sw_if_index); + u32 subport = ntohl (mp->subport); + u32 pipe = ntohl (mp->pipe); + u32 profile = ntohl (mp->profile); + vnet_hw_interface_t *hw; + + VALIDATE_SW_IF_INDEX (mp); + + /* hw_if & dpdk device */ + hw = vnet_get_sup_hw_interface (dm->vnet_main, sw_if_index); + + xd = vec_elt_at_index (dm->devices, hw->dev_instance); + + rv = rte_sched_pipe_config (xd->hqos_ht->hqos, subport, pipe, profile); + + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO (VL_API_SW_INTERFACE_SET_DPDK_HQOS_PIPE_REPLY); +} + +static void *vl_api_sw_interface_set_dpdk_hqos_pipe_t_print + (vl_api_sw_interface_set_dpdk_hqos_pipe_t * mp, void *handle) +{ + u8 *s; + + s = format (0, "SCRIPT: sw_interface_set_dpdk_hqos_pipe "); + + s = format (s, "sw_if_index %u ", ntohl (mp->sw_if_index)); + + s = format (s, "subport %u pipe %u profile %u ", + ntohl (mp->subport), ntohl (mp->pipe), ntohl (mp->profile)); + + FINISH; +} + +static void + vl_api_sw_interface_set_dpdk_hqos_subport_t_handler + (vl_api_sw_interface_set_dpdk_hqos_subport_t * mp) +{ + vl_api_sw_interface_set_dpdk_hqos_subport_reply_t *rmp; + int rv = 0; + + dpdk_main_t *dm = &dpdk_main; + dpdk_device_t *xd; + struct rte_sched_subport_params p; + + u32 sw_if_index = ntohl (mp->sw_if_index); + u32 subport = ntohl (mp->subport); + p.tb_rate = ntohl (mp->tb_rate); + p.tb_size = ntohl (mp->tb_size); + p.tc_rate[0] = ntohl (mp->tc_rate[0]); + p.tc_rate[1] = ntohl (mp->tc_rate[1]); + p.tc_rate[2] = ntohl (mp->tc_rate[2]); + p.tc_rate[3] = ntohl (mp->tc_rate[3]); + p.tc_period = ntohl (mp->tc_period); + + vnet_hw_interface_t *hw; + + VALIDATE_SW_IF_INDEX (mp); + + /* hw_if & dpdk device */ + hw = vnet_get_sup_hw_interface (dm->vnet_main, sw_if_index); + + xd = vec_elt_at_index (dm->devices, hw->dev_instance); + + rv = rte_sched_subport_config (xd->hqos_ht->hqos, subport, &p); + + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO (VL_API_SW_INTERFACE_SET_DPDK_HQOS_SUBPORT_REPLY); +} + +static void *vl_api_sw_interface_set_dpdk_hqos_subport_t_print + (vl_api_sw_interface_set_dpdk_hqos_subport_t * mp, void *handle) +{ + u8 *s; + + s = format (0, "SCRIPT: sw_interface_set_dpdk_hqos_subport "); + + s = format (s, "sw_if_index %u ", ntohl (mp->sw_if_index)); + + s = + format (s, + "subport %u rate %u bkt_size %u tc0 %u tc1 %u tc2 %u tc3 %u period %u", + ntohl (mp->subport), ntohl (mp->tb_rate), ntohl (mp->tb_size), + ntohl (mp->tc_rate[0]), ntohl (mp->tc_rate[1]), + ntohl (mp->tc_rate[2]), ntohl (mp->tc_rate[3]), + ntohl (mp->tc_period)); + + FINISH; +} + +static void + vl_api_sw_interface_set_dpdk_hqos_tctbl_t_handler + (vl_api_sw_interface_set_dpdk_hqos_tctbl_t * mp) +{ + vl_api_sw_interface_set_dpdk_hqos_tctbl_reply_t *rmp; + int rv = 0; + + dpdk_main_t *dm = &dpdk_main; + vlib_thread_main_t *tm = vlib_get_thread_main (); + dpdk_device_t *xd; + + u32 sw_if_index = ntohl (mp->sw_if_index); + u32 entry = ntohl (mp->entry); + u32 tc = ntohl (mp->tc); + u32 queue = ntohl (mp->queue); + u32 val, i; + + vnet_hw_interface_t *hw; + + VALIDATE_SW_IF_INDEX (mp); + + /* hw_if & dpdk device */ + hw = vnet_get_sup_hw_interface (dm->vnet_main, sw_if_index); + + xd = vec_elt_at_index (dm->devices, hw->dev_instance); + + if (tc >= RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE) + { + clib_warning ("invalid traffic class !!"); + rv = VNET_API_ERROR_INVALID_VALUE; + goto done; + } + if (queue >= RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS) + { + clib_warning ("invalid queue !!"); + rv = VNET_API_ERROR_INVALID_VALUE; + goto done; + } + + /* Detect the set of worker threads */ + uword *p = hash_get_mem (tm->thread_registrations_by_name, "workers"); + + if (p == 0) + { + clib_warning ("worker thread registration AWOL !!"); + rv = VNET_API_ERROR_INVALID_VALUE_2; + goto done; + } + + vlib_thread_registration_t *tr = (vlib_thread_registration_t *) p[0]; + int worker_thread_first = tr->first_index; + int worker_thread_count = tr->count; + + val = tc * RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS + queue; + for (i = 0; i < worker_thread_count; i++) + xd->hqos_wt[worker_thread_first + i].hqos_tc_table[entry] = val; + + BAD_SW_IF_INDEX_LABEL; +done: + + REPLY_MACRO (VL_API_SW_INTERFACE_SET_DPDK_HQOS_TCTBL_REPLY); +} + +static void *vl_api_sw_interface_set_dpdk_hqos_tctbl_t_print + (vl_api_sw_interface_set_dpdk_hqos_tctbl_t * mp, void *handle) +{ + u8 *s; + + s = format (0, "SCRIPT: sw_interface_set_dpdk_hqos_tctbl "); + + s = format (s, "sw_if_index %u ", ntohl (mp->sw_if_index)); + + s = format (s, "entry %u tc %u queue %u", + ntohl (mp->entry), ntohl (mp->tc), ntohl (mp->queue)); + + FINISH; +} + +#include +static clib_error_t * +dpdk_api_init (vlib_main_t * vm) +{ + dpdk_main_t *dm = &dpdk_main; + + /* Ask for a correctly-sized block of API message decode slots */ + dm->msg_id_base = setup_message_id_table (); + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_INIT_FUNCTION (dpdk_api_init) = +{ + .runs_after = VLIB_INITS ("dpdk_init"), +/* *INDENT-OFF* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/extras/deprecated/dpdk-hqos/api/dpdk_test.c b/extras/deprecated/dpdk-hqos/api/dpdk_test.c new file mode 100644 index 00000000000..951082faaf9 --- /dev/null +++ b/extras/deprecated/dpdk-hqos/api/dpdk_test.c @@ -0,0 +1,285 @@ + +/* + * dpdk_test.c - skeleton vpp-api-test plug-in + * + * Copyright (c) + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include + +uword unformat_sw_if_index (unformat_input_t * input, va_list * args); + +/* Declare message IDs */ +#include +#include + +typedef struct { + /* API message ID base */ + u16 msg_id_base; + vat_main_t *vat_main; +} dpdk_test_main_t; + +dpdk_test_main_t dpdk_test_main; + +/* M: construct, but don't yet send a message */ +#define M(T,t) \ +do { \ + vam->result_ready = 0; \ + mp = vl_msg_api_alloc(sizeof(*mp)); \ + clib_memset (mp, 0, sizeof (*mp)); \ + mp->_vl_msg_id = ntohs (VL_API_##T + dm->msg_id_base); \ + mp->client_index = vam->my_client_index; \ +} while(0); + +#define M2(T,t,n) \ +do { \ + vam->result_ready = 0; \ + mp = vl_msg_api_alloc(sizeof(*mp)+(n)); \ + clib_memset (mp, 0, sizeof (*mp)); \ + mp->_vl_msg_id = ntohs (VL_API_##T + dm->msg_id_base); \ + mp->client_index = vam->my_client_index; \ +} while(0); + +/* S: send a message */ +#define S (vl_msg_api_send_shmem (vam->vl_input_queue, (u8 *)&mp)) + +/* W: wait for results, with timeout */ +#define W \ +do { \ + timeout = vat_time_now (vam) + 1.0; \ + \ + while (vat_time_now (vam) < timeout) { \ + if (vam->result_ready == 1) { \ + return (vam->retval); \ + } \ + } \ + return -99; \ +} while(0); + +static int +api_sw_interface_set_dpdk_hqos_pipe (vat_main_t * vam) +{ + dpdk_test_main_t * dm = &dpdk_test_main; + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_dpdk_hqos_pipe_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u32 subport; + u8 subport_set = 0; + u32 pipe; + u8 pipe_set = 0; + u32 profile; + u8 profile_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "rx sw_if_index %u", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "subport %u", &subport)) + subport_set = 1; + else if (unformat (i, "pipe %u", &pipe)) + pipe_set = 1; + else if (unformat (i, "profile %u", &profile)) + profile_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (subport_set == 0) + { + errmsg ("missing subport "); + return -99; + } + + if (pipe_set == 0) + { + errmsg ("missing pipe"); + return -99; + } + + if (profile_set == 0) + { + errmsg ("missing profile"); + return -99; + } + + M (SW_INTERFACE_SET_DPDK_HQOS_PIPE, sw_interface_set_dpdk_hqos_pipe); + + mp->sw_if_index = ntohl (sw_if_index); + mp->subport = ntohl (subport); + mp->pipe = ntohl (pipe); + mp->profile = ntohl (profile); + + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_sw_interface_set_dpdk_hqos_subport (vat_main_t * vam) +{ + dpdk_test_main_t * dm = &dpdk_test_main; + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_dpdk_hqos_subport_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u32 subport; + u8 subport_set = 0; + u32 tb_rate = 1250000000; /* 10GbE */ + u32 tb_size = 1000000; + u32 tc_rate[] = { 1250000000, 1250000000, 1250000000, 1250000000 }; + u32 tc_period = 10; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "rx sw_if_index %u", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "subport %u", &subport)) + subport_set = 1; + else if (unformat (i, "rate %u", &tb_rate)) + { + u32 tc_id; + + for (tc_id = 0; tc_id < (sizeof (tc_rate) / sizeof (tc_rate[0])); + tc_id++) + tc_rate[tc_id] = tb_rate; + } + else if (unformat (i, "bktsize %u", &tb_size)) + ; + else if (unformat (i, "tc0 %u", &tc_rate[0])) + ; + else if (unformat (i, "tc1 %u", &tc_rate[1])) + ; + else if (unformat (i, "tc2 %u", &tc_rate[2])) + ; + else if (unformat (i, "tc3 %u", &tc_rate[3])) + ; + else if (unformat (i, "period %u", &tc_period)) + ; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (subport_set == 0) + { + errmsg ("missing subport "); + return -99; + } + + M (SW_INTERFACE_SET_DPDK_HQOS_SUBPORT, sw_interface_set_dpdk_hqos_subport); + + mp->sw_if_index = ntohl (sw_if_index); + mp->subport = ntohl (subport); + mp->tb_rate = ntohl (tb_rate); + mp->tb_size = ntohl (tb_size); + mp->tc_rate[0] = ntohl (tc_rate[0]); + mp->tc_rate[1] = ntohl (tc_rate[1]); + mp->tc_rate[2] = ntohl (tc_rate[2]); + mp->tc_rate[3] = ntohl (tc_rate[3]); + mp->tc_period = ntohl (tc_period); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_sw_interface_set_dpdk_hqos_tctbl (vat_main_t * vam) +{ + dpdk_test_main_t * dm = &dpdk_test_main; + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_dpdk_hqos_tctbl_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 entry_set = 0; + u8 tc_set = 0; + u8 queue_set = 0; + u32 entry, tc, queue; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "rx sw_if_index %u", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "entry %d", &entry)) + entry_set = 1; + else if (unformat (i, "tc %d", &tc)) + tc_set = 1; + else if (unformat (i, "queue %d", &queue)) + queue_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (entry_set == 0) + { + errmsg ("missing entry "); + return -99; + } + + if (tc_set == 0) + { + errmsg ("missing traffic class "); + return -99; + } + + if (queue_set == 0) + { + errmsg ("missing queue "); + return -99; + } + + M (SW_INTERFACE_SET_DPDK_HQOS_TCTBL, sw_interface_set_dpdk_hqos_tctbl); + + mp->sw_if_index = ntohl (sw_if_index); + mp->entry = ntohl (entry); + mp->tc = ntohl (tc); + mp->queue = ntohl (queue); + + S; + W; + /* NOTREACHED */ + return 0; +} + +#include diff --git a/extras/deprecated/dpdk-hqos/dpdk-hqos.diff b/extras/deprecated/dpdk-hqos/dpdk-hqos.diff new file mode 100644 index 00000000000..1493461a277 --- /dev/null +++ b/extras/deprecated/dpdk-hqos/dpdk-hqos.diff @@ -0,0 +1,1726 @@ +diff --git a/src/plugins/dpdk/CMakeLists.txt b/src/plugins/dpdk/CMakeLists.txt +index e0122d928..af8c80d8f 100644 +--- a/src/plugins/dpdk/CMakeLists.txt ++++ b/src/plugins/dpdk/CMakeLists.txt +@@ -118,8 +118,6 @@ add_vpp_plugin(dpdk + buffer.c + main.c + thread.c +-# api/dpdk_api.c +-# api/dpdk_test.c + device/cli.c + device/common.c + device/device.c +@@ -127,7 +125,6 @@ add_vpp_plugin(dpdk + device/format.c + device/init.c + device/node.c +-# hqos/hqos.c + ipsec/cli.c + ipsec/crypto_node.c + ipsec/esp_decrypt.c +@@ -142,12 +139,6 @@ add_vpp_plugin(dpdk + ipsec/esp_decrypt.c + ipsec/esp_encrypt.c + +-# API_FILES +-# api/dpdk.api +- +-# API_TEST_SOURCES +-# api/dpdk_test.c +- + INSTALL_HEADERS + device/dpdk.h + ipsec/ipsec.h +diff --git a/src/plugins/dpdk/device/cli.c b/src/plugins/dpdk/device/cli.c +index 416d97360..0f771c6ba 100644 +--- a/src/plugins/dpdk/device/cli.c ++++ b/src/plugins/dpdk/device/cli.c +@@ -40,61 +40,6 @@ + */ + + +-#if 0 +-static clib_error_t * +-get_hqos (u32 hw_if_index, u32 subport_id, dpdk_device_t ** xd, +- dpdk_device_config_t ** devconf) +-{ +- dpdk_main_t *dm = &dpdk_main; +- vnet_hw_interface_t *hw; +- struct rte_eth_dev_info dev_info; +- struct rte_pci_device *pci_dev; +- uword *p = 0; +- clib_error_t *error = NULL; +- +- +- if (hw_if_index == (u32) ~ 0) +- { +- error = clib_error_return (0, "please specify valid interface name"); +- goto done; +- } +- +- if (subport_id != 0) +- { +- error = clib_error_return (0, "Invalid subport"); +- goto done; +- } +- +- hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); +- *xd = vec_elt_at_index (dm->devices, hw->dev_instance); +- +- rte_eth_dev_info_get ((*xd)->port_id, &dev_info); +- +- pci_dev = dpdk_get_pci_device (&dev_info); +- +- if (pci_dev) +- { +- vlib_pci_addr_t pci_addr; +- +- pci_addr.domain = pci_dev->addr.domain; +- pci_addr.bus = pci_dev->addr.bus; +- pci_addr.slot = pci_dev->addr.devid; +- pci_addr.function = pci_dev->addr.function; +- +- p = +- hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32); +- } +- +- if (p) +- (*devconf) = pool_elt_at_index (dm->conf->dev_confs, p[0]); +- else +- (*devconf) = &dm->conf->default_devconf; +- +-done: +- return error; +-} +-#endif +- + static clib_error_t * + show_dpdk_buffer (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) +@@ -408,1308 +353,6 @@ VLIB_CLI_COMMAND (cmd_set_dpdk_if_desc,static) = { + }; + /* *INDENT-ON* */ + +-#if 0 +-static int +-dpdk_device_queue_sort (void *a1, void *a2) +-{ +- dpdk_device_and_queue_t *dq1 = a1; +- dpdk_device_and_queue_t *dq2 = a2; +- +- if (dq1->device > dq2->device) +- return 1; +- else if (dq1->device < dq2->device) +- return -1; +- else if (dq1->queue_id > dq2->queue_id) +- return 1; +- else if (dq1->queue_id < dq2->queue_id) +- return -1; +- else +- return 0; +-} +- +- +-static clib_error_t * +-show_dpdk_if_hqos_placement (vlib_main_t * vm, unformat_input_t * input, +- vlib_cli_command_t * cmd) +-{ +- vlib_thread_main_t *tm = vlib_get_thread_main (); +- dpdk_main_t *dm = &dpdk_main; +- dpdk_device_and_queue_t *dq; +- int cpu; +- +- if (tm->n_vlib_mains == 1) +- vlib_cli_output (vm, "All interfaces are handled by main thread"); +- +- for (cpu = 0; cpu < vec_len (dm->devices_by_hqos_cpu); cpu++) +- { +- if (cpu >= dm->hqos_cpu_first_index && +- cpu < (dm->hqos_cpu_first_index + dm->hqos_cpu_count)) +- vlib_cli_output (vm, "Thread %u (%s at lcore %u):", cpu, +- vlib_worker_threads[cpu].name, +- vlib_worker_threads[cpu].cpu_id); +- +- vec_foreach (dq, dm->devices_by_hqos_cpu[cpu]) +- { +- u32 hw_if_index = dm->devices[dq->device].hw_if_index; +- vnet_hw_interface_t *hi = +- vnet_get_hw_interface (dm->vnet_main, hw_if_index); +- vlib_cli_output (vm, " %v queue %u", hi->name, dq->queue_id); +- } +- } +- return 0; +-} +- +-/*? +- * This command is used to display the thread and core each +- * DPDK output interface and HQoS queue is assigned too. +- * +- * @cliexpar +- * Example of how to display the DPDK output interface and HQoS queue placement: +- * @cliexstart{show dpdk interface hqos placement} +- * Thread 1 (vpp_hqos-threads_0 at lcore 3): +- * GigabitEthernet0/8/0 queue 0 +- * Thread 2 (vpp_hqos-threads_1 at lcore 4): +- * GigabitEthernet0/9/0 queue 0 +- * @cliexend +-?*/ +-/* *INDENT-OFF* */ +-VLIB_CLI_COMMAND (cmd_show_dpdk_if_hqos_placement, static) = { +- .path = "show dpdk interface hqos placement", +- .short_help = "show dpdk interface hqos placement", +- .function = show_dpdk_if_hqos_placement, +-}; +-/* *INDENT-ON* */ +- +-static clib_error_t * +-set_dpdk_if_hqos_placement (vlib_main_t * vm, unformat_input_t * input, +- vlib_cli_command_t * cmd) +-{ +- unformat_input_t _line_input, *line_input = &_line_input; +- dpdk_main_t *dm = &dpdk_main; +- dpdk_device_and_queue_t *dq; +- vnet_hw_interface_t *hw; +- dpdk_device_t *xd; +- u32 hw_if_index = (u32) ~ 0; +- u32 cpu = (u32) ~ 0; +- int i; +- clib_error_t *error = NULL; +- +- if (!unformat_user (input, unformat_line_input, line_input)) +- return 0; +- +- while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) +- { +- if (unformat +- (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main, +- &hw_if_index)) +- ; +- else if (unformat (line_input, "thread %d", &cpu)) +- ; +- else +- { +- error = clib_error_return (0, "parse error: '%U'", +- format_unformat_error, line_input); +- goto done; +- } +- } +- +- if (hw_if_index == (u32) ~ 0) +- return clib_error_return (0, "please specify valid interface name"); +- +- if (cpu < dm->hqos_cpu_first_index || +- cpu >= (dm->hqos_cpu_first_index + dm->hqos_cpu_count)) +- { +- error = clib_error_return (0, "please specify valid thread id"); +- goto done; +- } +- +- hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); +- xd = vec_elt_at_index (dm->devices, hw->dev_instance); +- +- for (i = 0; i < vec_len (dm->devices_by_hqos_cpu); i++) +- { +- vec_foreach (dq, dm->devices_by_hqos_cpu[i]) +- { +- if (hw_if_index == dm->devices[dq->device].hw_if_index) +- { +- if (cpu == i) /* nothing to do */ +- goto done; +- +- vec_del1 (dm->devices_by_hqos_cpu[i], +- dq - dm->devices_by_hqos_cpu[i]); +- vec_add2 (dm->devices_by_hqos_cpu[cpu], dq, 1); +- dq->queue_id = 0; +- dq->device = xd->device_index; +- +- vec_sort_with_function (dm->devices_by_hqos_cpu[i], +- dpdk_device_queue_sort); +- +- vec_sort_with_function (dm->devices_by_hqos_cpu[cpu], +- dpdk_device_queue_sort); +- +- goto done; +- } +- } +- } +- +- error = clib_error_return (0, "not found"); +- +-done: +- unformat_free (line_input); +- +- return error; +-} +- +-/*? +- * This command is used to assign a given DPDK output interface and +- * HQoS queue to a different thread. This will not create a thread, +- * so the thread must already exist. Use '/etc/vpp/startup.conf' +- * for the initial thread creation. See @ref qos_doc for more details. +- * +- * @cliexpar +- * Example of how to display the DPDK output interface and HQoS queue placement: +- * @cliexstart{show dpdk interface hqos placement} +- * Thread 1 (vpp_hqos-threads_0 at lcore 3): +- * GigabitEthernet0/8/0 queue 0 +- * Thread 2 (vpp_hqos-threads_1 at lcore 4): +- * GigabitEthernet0/9/0 queue 0 +- * @cliexend +- * Example of how to assign a DPDK output interface and HQoS queue to a thread: +- * @cliexcmd{set dpdk interface hqos placement GigabitEthernet0/8/0 thread 2} +-?*/ +-/* *INDENT-OFF* */ +-VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_placement, static) = { +- .path = "set dpdk interface hqos placement", +- .short_help = "set dpdk interface hqos placement thread ", +- .function = set_dpdk_if_hqos_placement, +-}; +-/* *INDENT-ON* */ +- +-static clib_error_t * +-set_dpdk_if_hqos_pipe (vlib_main_t * vm, unformat_input_t * input, +- vlib_cli_command_t * cmd) +-{ +- unformat_input_t _line_input, *line_input = &_line_input; +- dpdk_main_t *dm = &dpdk_main; +- vnet_hw_interface_t *hw; +- dpdk_device_t *xd; +- u32 hw_if_index = (u32) ~ 0; +- u32 subport_id = (u32) ~ 0; +- u32 pipe_id = (u32) ~ 0; +- u32 profile_id = (u32) ~ 0; +- int rv; +- clib_error_t *error = NULL; +- +- if (!unformat_user (input, unformat_line_input, line_input)) +- return 0; +- +- while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) +- { +- if (unformat +- (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main, +- &hw_if_index)) +- ; +- else if (unformat (line_input, "subport %d", &subport_id)) +- ; +- else if (unformat (line_input, "pipe %d", &pipe_id)) +- ; +- else if (unformat (line_input, "profile %d", &profile_id)) +- ; +- else +- { +- error = clib_error_return (0, "parse error: '%U'", +- format_unformat_error, line_input); +- goto done; +- } +- } +- +- if (hw_if_index == (u32) ~ 0) +- { +- error = clib_error_return (0, "please specify valid interface name"); +- goto done; +- } +- +- hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); +- xd = vec_elt_at_index (dm->devices, hw->dev_instance); +- +- rv = +- rte_sched_pipe_config (xd->hqos_ht->hqos, subport_id, pipe_id, +- profile_id); +- if (rv) +- { +- error = clib_error_return (0, "pipe configuration failed"); +- goto done; +- } +- +-done: +- unformat_free (line_input); +- +- return error; +-} +- +-/*? +- * This command is used to change the profile associate with a HQoS pipe. The +- * '' is zero based. Use the command +- * 'show dpdk interface hqos' to display the content of each profile. +- * See @ref qos_doc for more details. +- * +- * @note +- * Currently there is not an API to create a new HQoS pipe profile. One is +- * created by default in the code (search for 'hqos_pipe_params_default''). +- * Additional profiles can be created in code and code recompiled. Then use this +- * command to assign it. +- * +- * @cliexpar +- * Example of how to assign a new profile to a HQoS pipe: +- * @cliexcmd{set dpdk interface hqos pipe GigabitEthernet0/8/0 subport 0 pipe 2 profile 1} +-?*/ +-/* *INDENT-OFF* */ +-VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_pipe, static) = +-{ +- .path = "set dpdk interface hqos pipe", +- .short_help = "set dpdk interface hqos pipe subport pipe " +- "profile ", +- .function = set_dpdk_if_hqos_pipe, +-}; +-/* *INDENT-ON* */ +- +-static clib_error_t * +-set_dpdk_if_hqos_subport (vlib_main_t * vm, unformat_input_t * input, +- vlib_cli_command_t * cmd) +-{ +- unformat_input_t _line_input, *line_input = &_line_input; +- dpdk_main_t *dm = &dpdk_main; +- dpdk_device_t *xd = NULL; +- u32 hw_if_index = (u32) ~ 0; +- u32 subport_id = (u32) ~ 0; +- struct rte_sched_subport_params p; +- int rv; +- clib_error_t *error = NULL; +- u32 tb_rate = (u32) ~ 0; +- u32 tb_size = (u32) ~ 0; +- u32 tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE] = +- { (u32) ~ 0, (u32) ~ 0, (u32) ~ 0, (u32) ~ 0 }; +- u32 tc_period = (u32) ~ 0; +- dpdk_device_config_t *devconf = NULL; +- +- if (!unformat_user (input, unformat_line_input, line_input)) +- return 0; +- +- while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) +- { +- if (unformat +- (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main, +- &hw_if_index)) +- ; +- else if (unformat (line_input, "subport %d", &subport_id)) +- ; +- else if (unformat (line_input, "rate %d", &tb_rate)) +- ; +- else if (unformat (line_input, "bktsize %d", &tb_size)) +- ; +- else if (unformat (line_input, "tc0 %d", &tc_rate[0])) +- ; +- else if (unformat (line_input, "tc1 %d", &tc_rate[1])) +- ; +- else if (unformat (line_input, "tc2 %d", &tc_rate[2])) +- ; +- else if (unformat (line_input, "tc3 %d", &tc_rate[3])) +- ; +- else if (unformat (line_input, "period %d", &tc_period)) +- ; +- else +- { +- error = clib_error_return (0, "parse error: '%U'", +- format_unformat_error, line_input); +- goto done; +- } +- } +- +- error = get_hqos (hw_if_index, subport_id, &xd, &devconf); +- +- if (error == NULL) +- { +- /* Copy the current values over to local structure. */ +- memcpy (&p, &devconf->hqos.subport[subport_id], sizeof (p)); +- +- /* Update local structure with input values. */ +- if (tb_rate != (u32) ~ 0) +- { +- p.tb_rate = tb_rate; +- p.tc_rate[0] = tb_rate; +- p.tc_rate[1] = tb_rate; +- p.tc_rate[2] = tb_rate; +- p.tc_rate[3] = tb_rate; +- } +- if (tb_size != (u32) ~ 0) +- { +- p.tb_size = tb_size; +- } +- if (tc_rate[0] != (u32) ~ 0) +- { +- p.tc_rate[0] = tc_rate[0]; +- } +- if (tc_rate[1] != (u32) ~ 0) +- { +- p.tc_rate[1] = tc_rate[1]; +- } +- if (tc_rate[2] != (u32) ~ 0) +- { +- p.tc_rate[2] = tc_rate[2]; +- } +- if (tc_rate[3] != (u32) ~ 0) +- { +- p.tc_rate[3] = tc_rate[3]; +- } +- if (tc_period != (u32) ~ 0) +- { +- p.tc_period = tc_period; +- } +- +- /* Apply changes. */ +- rv = rte_sched_subport_config (xd->hqos_ht->hqos, subport_id, &p); +- if (rv) +- { +- error = clib_error_return (0, "subport configuration failed"); +- goto done; +- } +- else +- { +- /* Successfully applied, so save of the input values. */ +- memcpy (&devconf->hqos.subport[subport_id], &p, sizeof (p)); +- } +- } +- +-done: +- unformat_free (line_input); +- +- return error; +-} +- +-/*? +- * This command is used to set the subport level parameters such as token +- * bucket rate (bytes per seconds), token bucket size (bytes), traffic class +- * rates (bytes per seconds) and token update period (Milliseconds). +- * +- * By default, the 'rate' is set to 1250000000 bytes/second (10GbE +- * rate) and each of the four traffic classes is set to 100% of the port rate. +- * If the 'rate' is updated by this command, all four traffic classes +- * are assigned the same value. Each of the four traffic classes can be updated +- * individually. +- * +- * @cliexpar +- * Example of how modify the subport attributes for a 1GbE link: +- * @cliexcmd{set dpdk interface hqos subport GigabitEthernet0/8/0 subport 0 rate 125000000} +-?*/ +-/* *INDENT-OFF* */ +-VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_subport, static) = { +- .path = "set dpdk interface hqos subport", +- .short_help = "set dpdk interface hqos subport subport " +- "[rate ] [bktsize ] [tc0 ] [tc1 ] [tc2 ] [tc3 ] " +- "[period ]", +- .function = set_dpdk_if_hqos_subport, +-}; +-/* *INDENT-ON* */ +- +-static clib_error_t * +-set_dpdk_if_hqos_tctbl (vlib_main_t * vm, unformat_input_t * input, +- vlib_cli_command_t * cmd) +-{ +- unformat_input_t _line_input, *line_input = &_line_input; +- vlib_thread_main_t *tm = vlib_get_thread_main (); +- dpdk_main_t *dm = &dpdk_main; +- vnet_hw_interface_t *hw; +- dpdk_device_t *xd; +- u32 hw_if_index = (u32) ~ 0; +- u32 tc = (u32) ~ 0; +- u32 queue = (u32) ~ 0; +- u32 entry = (u32) ~ 0; +- u32 val, i; +- clib_error_t *error = NULL; +- +- if (!unformat_user (input, unformat_line_input, line_input)) +- return 0; +- +- while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) +- { +- if (unformat +- (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main, +- &hw_if_index)) +- ; +- else if (unformat (line_input, "entry %d", &entry)) +- ; +- else if (unformat (line_input, "tc %d", &tc)) +- ; +- else if (unformat (line_input, "queue %d", &queue)) +- ; +- else +- { +- error = clib_error_return (0, "parse error: '%U'", +- format_unformat_error, line_input); +- goto done; +- } +- } +- +- if (hw_if_index == (u32) ~ 0) +- { +- error = clib_error_return (0, "please specify valid interface name"); +- goto done; +- } +- if (entry >= 64) +- { +- error = clib_error_return (0, "invalid entry"); +- goto done; +- } +- if (tc >= RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE) +- { +- error = clib_error_return (0, "invalid traffic class"); +- goto done; +- } +- if (queue >= RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS) +- { +- error = clib_error_return (0, "invalid traffic class queue"); +- goto done; +- } +- +- hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); +- xd = vec_elt_at_index (dm->devices, hw->dev_instance); +- +- /* Detect the set of worker threads */ +- uword *p = hash_get_mem (tm->thread_registrations_by_name, "workers"); +- /* Should never happen, shut up Coverity warning */ +- if (p == 0) +- { +- error = clib_error_return (0, "no worker registrations?"); +- goto done; +- } +- +- vlib_thread_registration_t *tr = (vlib_thread_registration_t *) p[0]; +- int worker_thread_first = tr->first_index; +- int worker_thread_count = tr->count; +- +- val = tc * RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS + queue; +- for (i = 0; i < worker_thread_count; i++) +- xd->hqos_wt[worker_thread_first + i].hqos_tc_table[entry] = val; +- +-done: +- unformat_free (line_input); +- +- return error; +-} +- +-/*? +- * This command is used to set the traffic class translation table. The +- * traffic class translation table is used to map 64 values (0-63) to one of +- * four traffic class and one of four HQoS input queue. Use the 'show +- * dpdk interface hqos' command to display the traffic class translation +- * table. See @ref qos_doc for more details. +- * +- * This command has the following parameters: +- * +- * - - Used to specify the output interface. +- * +- * - entry - Mapped value (0-63) to assign traffic class and queue to. +- * +- * - tc - Traffic class (0-3) to be used by the provided mapped value. +- * +- * - queue - HQoS input queue (0-3) to be used by the provided mapped value. +- * +- * @cliexpar +- * Example of how modify the traffic class translation table: +- * @cliexcmd{set dpdk interface hqos tctbl GigabitEthernet0/8/0 entry 16 tc 2 queue 2} +-?*/ +-/* *INDENT-OFF* */ +-VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_tctbl, static) = { +- .path = "set dpdk interface hqos tctbl", +- .short_help = "set dpdk interface hqos tctbl entry tc queue ", +- .function = set_dpdk_if_hqos_tctbl, +-}; +-/* *INDENT-ON* */ +- +-static clib_error_t * +-set_dpdk_if_hqos_pktfield (vlib_main_t * vm, unformat_input_t * input, +- vlib_cli_command_t * cmd) +-{ +- unformat_input_t _line_input, *line_input = &_line_input; +- vlib_thread_main_t *tm = vlib_get_thread_main (); +- dpdk_main_t *dm = &dpdk_main; +- clib_error_t *error = NULL; +- +- /* Device specific data */ +- struct rte_eth_dev_info dev_info; +- struct rte_pci_device *pci_dev; +- dpdk_device_config_t *devconf = 0; +- vnet_hw_interface_t *hw; +- dpdk_device_t *xd; +- u32 hw_if_index = (u32) ~ 0; +- +- /* Detect the set of worker threads */ +- uword *p = hash_get_mem (tm->thread_registrations_by_name, "workers"); +- /* Should never happen, shut up Coverity warning */ +- if (p == 0) +- return clib_error_return (0, "no worker registrations?"); +- +- vlib_thread_registration_t *tr = (vlib_thread_registration_t *) p[0]; +- int worker_thread_first = tr->first_index; +- int worker_thread_count = tr->count; +- +- /* Packet field configuration */ +- u64 mask = (u64) ~ 0; +- u32 id = (u32) ~ 0; +- u32 offset = (u32) ~ 0; +- +- /* HQoS params */ +- u32 n_subports_per_port, n_pipes_per_subport, tctbl_size; +- +- u32 i; +- +- /* Parse input arguments */ +- if (!unformat_user (input, unformat_line_input, line_input)) +- return 0; +- +- while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) +- { +- if (unformat +- (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main, +- &hw_if_index)) +- ; +- else if (unformat (line_input, "id subport")) +- id = 0; +- else if (unformat (line_input, "id pipe")) +- id = 1; +- else if (unformat (line_input, "id tc")) +- id = 2; +- else if (unformat (line_input, "id %d", &id)) +- ; +- else if (unformat (line_input, "offset %d", &offset)) +- ; +- else if (unformat (line_input, "mask %llx", &mask)) +- ; +- else +- { +- error = clib_error_return (0, "parse error: '%U'", +- format_unformat_error, line_input); +- goto done; +- } +- } +- +- /* Get interface */ +- if (hw_if_index == (u32) ~ 0) +- { +- error = clib_error_return (0, "please specify valid interface name"); +- goto done; +- } +- +- hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); +- xd = vec_elt_at_index (dm->devices, hw->dev_instance); +- +- rte_eth_dev_info_get (xd->port_id, &dev_info); +- +- pci_dev = dpdk_get_pci_device (&dev_info); +- +- if (pci_dev) +- { +- vlib_pci_addr_t pci_addr; +- +- pci_addr.domain = pci_dev->addr.domain; +- pci_addr.bus = pci_dev->addr.bus; +- pci_addr.slot = pci_dev->addr.devid; +- pci_addr.function = pci_dev->addr.function; +- +- p = +- hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32); +- } +- +- if (p) +- devconf = pool_elt_at_index (dm->conf->dev_confs, p[0]); +- else +- devconf = &dm->conf->default_devconf; +- +- if (devconf->hqos_enabled == 0) +- { +- vlib_cli_output (vm, "HQoS disabled for this interface"); +- goto done; +- } +- +- n_subports_per_port = devconf->hqos.port.n_subports_per_port; +- n_pipes_per_subport = devconf->hqos.port.n_pipes_per_subport; +- tctbl_size = RTE_DIM (devconf->hqos.tc_table); +- +- /* Validate packet field configuration: id, offset and mask */ +- if (id >= 3) +- { +- error = clib_error_return (0, "invalid packet field id"); +- goto done; +- } +- +- switch (id) +- { +- case 0: +- if (dpdk_hqos_validate_mask (mask, n_subports_per_port) != 0) +- { +- error = clib_error_return (0, "invalid subport ID mask " +- "(n_subports_per_port = %u)", +- n_subports_per_port); +- goto done; +- } +- break; +- case 1: +- if (dpdk_hqos_validate_mask (mask, n_pipes_per_subport) != 0) +- { +- error = clib_error_return (0, "invalid pipe ID mask " +- "(n_pipes_per_subport = %u)", +- n_pipes_per_subport); +- goto done; +- } +- break; +- case 2: +- default: +- if (dpdk_hqos_validate_mask (mask, tctbl_size) != 0) +- { +- error = clib_error_return (0, "invalid TC table index mask " +- "(TC table size = %u)", tctbl_size); +- goto done; +- } +- } +- +- /* Propagate packet field configuration to all workers */ +- for (i = 0; i < worker_thread_count; i++) +- switch (id) +- { +- case 0: +- xd->hqos_wt[worker_thread_first + i].hqos_field0_slabpos = offset; +- xd->hqos_wt[worker_thread_first + i].hqos_field0_slabmask = mask; +- xd->hqos_wt[worker_thread_first + i].hqos_field0_slabshr = +- count_trailing_zeros (mask); +- break; +- case 1: +- xd->hqos_wt[worker_thread_first + i].hqos_field1_slabpos = offset; +- xd->hqos_wt[worker_thread_first + i].hqos_field1_slabmask = mask; +- xd->hqos_wt[worker_thread_first + i].hqos_field1_slabshr = +- count_trailing_zeros (mask); +- break; +- case 2: +- default: +- xd->hqos_wt[worker_thread_first + i].hqos_field2_slabpos = offset; +- xd->hqos_wt[worker_thread_first + i].hqos_field2_slabmask = mask; +- xd->hqos_wt[worker_thread_first + i].hqos_field2_slabshr = +- count_trailing_zeros (mask); +- } +- +-done: +- unformat_free (line_input); +- +- return error; +-} +- +-/*? +- * This command is used to set the packet fields required for classifying the +- * incoming packet. As a result of classification process, packet field +- * information will be mapped to 5 tuples (subport, pipe, traffic class, pipe, +- * color) and stored in packet mbuf. +- * +- * This command has the following parameters: +- * +- * - - Used to specify the output interface. +- * +- * - id subport|pipe|tc - Classification occurs across three fields. +- * This parameter indicates which of the three masks are being configured. Legacy +- * code used 0-2 to represent these three fields, so 0-2 is still accepted. +- * - subport|0 - Currently only one subport is supported, so only +- * an empty mask is supported for the subport classification. +- * - pipe|1 - Currently, 4096 pipes per subport are supported, so a +- * 12-bit mask should be configure to map to the 0-4095 pipes. +- * - tc|2 - The translation table (see 'set dpdk interface hqos +- * tctbl' command) maps each value (0-63) into one of the 4 traffic classes +- * per pipe. A 6-bit mask should be configure to map this field to a traffic class. +- * +- * - offset - Offset in the packet to apply the 64-bit mask for classification. +- * The offset should be on an 8-byte boundary (0,8,16,24..). +- * +- * - mask - 64-bit mask to apply to packet at the given 'offset'. +- * Bits must be contiguous and should not include '0x'. +- * +- * The default values for the 'pktfield' assumes Ethernet/IPv4/UDP packets with +- * no VLAN. Adjust based on expected packet format and desired classification field. +- * - 'subport' is always empty (offset 0 mask 0000000000000000) +- * - By default, 'pipe' maps to the UDP payload bits 12 .. 23 (offset 40 +- * mask 0000000fff000000) +- * - By default, 'tc' maps to the DSCP field in IP header (offset 48 mask +- * 00000000000000fc) +- * +- * @cliexpar +- * Example of how modify the 'pipe' classification filter to match VLAN: +- * @cliexcmd{set dpdk interface hqos pktfield GigabitEthernet0/8/0 id pipe offset 8 mask 0000000000000FFF} +-?*/ +-/* *INDENT-OFF* */ +-VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_pktfield, static) = { +- .path = "set dpdk interface hqos pktfield", +- .short_help = "set dpdk interface hqos pktfield id subport|pipe|tc offset " +- "mask ", +- .function = set_dpdk_if_hqos_pktfield, +-}; +-/* *INDENT-ON* */ +- +-static clib_error_t * +-show_dpdk_if_hqos (vlib_main_t * vm, unformat_input_t * input, +- vlib_cli_command_t * cmd) +-{ +- unformat_input_t _line_input, *line_input = &_line_input; +- vlib_thread_main_t *tm = vlib_get_thread_main (); +- dpdk_main_t *dm = &dpdk_main; +- vnet_hw_interface_t *hw; +- dpdk_device_t *xd; +- dpdk_device_config_hqos_t *cfg; +- dpdk_device_hqos_per_hqos_thread_t *ht; +- dpdk_device_hqos_per_worker_thread_t *wk; +- u32 *tctbl; +- u32 hw_if_index = (u32) ~ 0; +- u32 profile_id, subport_id, i; +- struct rte_eth_dev_info dev_info; +- struct rte_pci_device *pci_dev; +- dpdk_device_config_t *devconf = 0; +- vlib_thread_registration_t *tr; +- uword *p = 0; +- clib_error_t *error = NULL; +- +- if (!unformat_user (input, unformat_line_input, line_input)) +- return 0; +- +- while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) +- { +- if (unformat +- (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main, +- &hw_if_index)) +- ; +- else +- { +- error = clib_error_return (0, "parse error: '%U'", +- format_unformat_error, line_input); +- goto done; +- } +- } +- +- if (hw_if_index == (u32) ~ 0) +- { +- error = clib_error_return (0, "please specify interface name!!"); +- goto done; +- } +- +- hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); +- xd = vec_elt_at_index (dm->devices, hw->dev_instance); +- +- rte_eth_dev_info_get (xd->port_id, &dev_info); +- +- pci_dev = dpdk_get_pci_device (&dev_info); +- +- if (pci_dev) +- { +- vlib_pci_addr_t pci_addr; +- +- pci_addr.domain = pci_dev->addr.domain; +- pci_addr.bus = pci_dev->addr.bus; +- pci_addr.slot = pci_dev->addr.devid; +- pci_addr.function = pci_dev->addr.function; +- +- p = +- hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32); +- } +- +- if (p) +- devconf = pool_elt_at_index (dm->conf->dev_confs, p[0]); +- else +- devconf = &dm->conf->default_devconf; +- +- if (devconf->hqos_enabled == 0) +- { +- vlib_cli_output (vm, "HQoS disabled for this interface"); +- goto done; +- } +- +- /* Detect the set of worker threads */ +- p = hash_get_mem (tm->thread_registrations_by_name, "workers"); +- +- /* Should never happen, shut up Coverity warning */ +- if (p == 0) +- { +- error = clib_error_return (0, "no worker registrations?"); +- goto done; +- } +- +- tr = (vlib_thread_registration_t *) p[0]; +- +- cfg = &devconf->hqos; +- ht = xd->hqos_ht; +- wk = &xd->hqos_wt[tr->first_index]; +- tctbl = wk->hqos_tc_table; +- +- vlib_cli_output (vm, " Thread:"); +- vlib_cli_output (vm, " Input SWQ size = %u packets", cfg->swq_size); +- vlib_cli_output (vm, " Enqueue burst size = %u packets", +- ht->hqos_burst_enq); +- vlib_cli_output (vm, " Dequeue burst size = %u packets", +- ht->hqos_burst_deq); +- +- vlib_cli_output (vm, +- " Packet field 0: slab position = %4u, slab bitmask = 0x%016llx (subport)", +- wk->hqos_field0_slabpos, wk->hqos_field0_slabmask); +- vlib_cli_output (vm, +- " Packet field 1: slab position = %4u, slab bitmask = 0x%016llx (pipe)", +- wk->hqos_field1_slabpos, wk->hqos_field1_slabmask); +- vlib_cli_output (vm, +- " Packet field 2: slab position = %4u, slab bitmask = 0x%016llx (tc)", +- wk->hqos_field2_slabpos, wk->hqos_field2_slabmask); +- vlib_cli_output (vm, +- " Packet field 2 tc translation table: ([Mapped Value Range]: tc/queue tc/queue ...)"); +- vlib_cli_output (vm, +- " [ 0 .. 15]: " +- "%u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u", +- tctbl[0] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[0] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[1] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[1] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[2] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[2] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[3] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[3] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[4] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[4] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[5] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[5] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[6] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[6] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[7] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[7] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[8] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[8] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[9] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[9] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[10] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[10] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[11] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[11] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[12] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[12] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[13] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[13] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[14] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[14] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[15] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[15] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS); +- vlib_cli_output (vm, +- " [16 .. 31]: " +- "%u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u", +- tctbl[16] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[16] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[17] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[17] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[18] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[18] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[19] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[19] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[20] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[20] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[21] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[21] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[22] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[22] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[23] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[23] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[24] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[24] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[25] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[25] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[26] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[26] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[27] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[27] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[28] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[28] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[29] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[29] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[30] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[30] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[31] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[31] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS); +- vlib_cli_output (vm, +- " [32 .. 47]: " +- "%u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u", +- tctbl[32] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[32] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[33] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[33] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[34] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[34] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[35] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[35] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[36] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[36] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[37] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[37] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[38] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[38] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[39] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[39] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[40] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[40] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[41] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[41] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[42] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[42] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[43] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[43] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[44] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[44] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[45] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[45] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[46] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[46] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[47] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[47] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS); +- vlib_cli_output (vm, +- " [48 .. 63]: " +- "%u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u", +- tctbl[48] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[48] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[49] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[49] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[50] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[50] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[51] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[51] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[52] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[52] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[53] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[53] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[54] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[54] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[55] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[55] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[56] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[56] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[57] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[57] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[58] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[58] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[59] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[59] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[60] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[60] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[61] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[61] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[62] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[62] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[63] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, +- tctbl[63] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS); +- vlib_cli_output (vm, " Port:"); +- vlib_cli_output (vm, " Rate = %u bytes/second", cfg->port.rate); +- vlib_cli_output (vm, " MTU = %u bytes", cfg->port.mtu); +- vlib_cli_output (vm, " Frame overhead = %u bytes", +- cfg->port.frame_overhead); +- vlib_cli_output (vm, " Number of subports = %u", +- cfg->port.n_subports_per_port); +- vlib_cli_output (vm, " Number of pipes per subport = %u", +- cfg->port.n_pipes_per_subport); +- vlib_cli_output (vm, +- " Packet queue size: TC0 = %u, TC1 = %u, TC2 = %u, TC3 = %u packets", +- cfg->port.qsize[0], cfg->port.qsize[1], cfg->port.qsize[2], +- cfg->port.qsize[3]); +- vlib_cli_output (vm, " Number of pipe profiles = %u", +- cfg->port.n_pipe_profiles); +- +- for (subport_id = 0; subport_id < vec_len (cfg->subport); subport_id++) +- { +- vlib_cli_output (vm, " Subport %u:", subport_id); +- vlib_cli_output (vm, " Rate = %u bytes/second", +- cfg->subport[subport_id].tb_rate); +- vlib_cli_output (vm, " Token bucket size = %u bytes", +- cfg->subport[subport_id].tb_size); +- vlib_cli_output (vm, +- " Traffic class rate: TC0 = %u, TC1 = %u, TC2 = %u, TC3 = %u bytes/second", +- cfg->subport[subport_id].tc_rate[0], +- cfg->subport[subport_id].tc_rate[1], +- cfg->subport[subport_id].tc_rate[2], +- cfg->subport[subport_id].tc_rate[3]); +- vlib_cli_output (vm, " TC period = %u milliseconds", +- cfg->subport[subport_id].tc_period); +- } +- +- for (profile_id = 0; profile_id < vec_len (cfg->pipe); profile_id++) +- { +- vlib_cli_output (vm, " Pipe profile %u:", profile_id); +- vlib_cli_output (vm, " Rate = %u bytes/second", +- cfg->pipe[profile_id].tb_rate); +- vlib_cli_output (vm, " Token bucket size = %u bytes", +- cfg->pipe[profile_id].tb_size); +- vlib_cli_output (vm, +- " Traffic class rate: TC0 = %u, TC1 = %u, TC2 = %u, TC3 = %u bytes/second", +- cfg->pipe[profile_id].tc_rate[0], +- cfg->pipe[profile_id].tc_rate[1], +- cfg->pipe[profile_id].tc_rate[2], +- cfg->pipe[profile_id].tc_rate[3]); +- vlib_cli_output (vm, " TC period = %u milliseconds", +- cfg->pipe[profile_id].tc_period); +-#ifdef RTE_SCHED_SUBPORT_TC_OV +- vlib_cli_output (vm, " TC3 oversubscription_weight = %u", +- cfg->pipe[profile_id].tc_ov_weight); +-#endif +- +- for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) +- { +- vlib_cli_output (vm, +- " TC%u WRR weights: Q0 = %u, Q1 = %u, Q2 = %u, Q3 = %u", +- i, cfg->pipe[profile_id].wrr_weights[i * 4], +- cfg->pipe[profile_id].wrr_weights[i * 4 + 1], +- cfg->pipe[profile_id].wrr_weights[i * 4 + 2], +- cfg->pipe[profile_id].wrr_weights[i * 4 + 3]); +- } +- } +- +-#ifdef RTE_SCHED_RED +- vlib_cli_output (vm, " Weighted Random Early Detection (WRED):"); +- for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) +- { +- vlib_cli_output (vm, " TC%u min: G = %u, Y = %u, R = %u", i, +- cfg->port.red_params[i][e_RTE_METER_GREEN].min_th, +- cfg->port.red_params[i][e_RTE_METER_YELLOW].min_th, +- cfg->port.red_params[i][e_RTE_METER_RED].min_th); +- +- vlib_cli_output (vm, " TC%u max: G = %u, Y = %u, R = %u", i, +- cfg->port.red_params[i][e_RTE_METER_GREEN].max_th, +- cfg->port.red_params[i][e_RTE_METER_YELLOW].max_th, +- cfg->port.red_params[i][e_RTE_METER_RED].max_th); +- +- vlib_cli_output (vm, +- " TC%u inverted probability: G = %u, Y = %u, R = %u", +- i, cfg->port.red_params[i][e_RTE_METER_GREEN].maxp_inv, +- cfg->port.red_params[i][e_RTE_METER_YELLOW].maxp_inv, +- cfg->port.red_params[i][e_RTE_METER_RED].maxp_inv); +- +- vlib_cli_output (vm, " TC%u weight: R = %u, Y = %u, R = %u", i, +- cfg->port.red_params[i][e_RTE_METER_GREEN].wq_log2, +- cfg->port.red_params[i][e_RTE_METER_YELLOW].wq_log2, +- cfg->port.red_params[i][e_RTE_METER_RED].wq_log2); +- } +-#endif +- +-done: +- unformat_free (line_input); +- +- return error; +-} +- +-/*? +- * This command is used to display details of an output interface's HQoS +- * settings. +- * +- * @cliexpar +- * Example of how to display HQoS settings for an interfaces: +- * @cliexstart{show dpdk interface hqos GigabitEthernet0/8/0} +- * Thread: +- * Input SWQ size = 4096 packets +- * Enqueue burst size = 256 packets +- * Dequeue burst size = 220 packets +- * Packet field 0: slab position = 0, slab bitmask = 0x0000000000000000 (subport) +- * Packet field 1: slab position = 40, slab bitmask = 0x0000000fff000000 (pipe) +- * Packet field 2: slab position = 8, slab bitmask = 0x00000000000000fc (tc) +- * Packet field 2 tc translation table: ([Mapped Value Range]: tc/queue tc/queue ...) +- * [ 0 .. 15]: 0/0 0/1 0/2 0/3 1/0 1/1 1/2 1/3 2/0 2/1 2/2 2/3 3/0 3/1 3/2 3/3 +- * [16 .. 31]: 0/0 0/1 0/2 0/3 1/0 1/1 1/2 1/3 2/0 2/1 2/2 2/3 3/0 3/1 3/2 3/3 +- * [32 .. 47]: 0/0 0/1 0/2 0/3 1/0 1/1 1/2 1/3 2/0 2/1 2/2 2/3 3/0 3/1 3/2 3/3 +- * [48 .. 63]: 0/0 0/1 0/2 0/3 1/0 1/1 1/2 1/3 2/0 2/1 2/2 2/3 3/0 3/1 3/2 3/3 +- * Port: +- * Rate = 1250000000 bytes/second +- * MTU = 1514 bytes +- * Frame overhead = 24 bytes +- * Number of subports = 1 +- * Number of pipes per subport = 4096 +- * Packet queue size: TC0 = 64, TC1 = 64, TC2 = 64, TC3 = 64 packets +- * Number of pipe profiles = 2 +- * Subport 0: +- * Rate = 1250000000 bytes/second +- * Token bucket size = 1000000 bytes +- * Traffic class rate: TC0 = 1250000000, TC1 = 1250000000, TC2 = 1250000000, TC3 = 1250000000 bytes/second +- * TC period = 10 milliseconds +- * Pipe profile 0: +- * Rate = 305175 bytes/second +- * Token bucket size = 1000000 bytes +- * Traffic class rate: TC0 = 305175, TC1 = 305175, TC2 = 305175, TC3 = 305175 bytes/second +- * TC period = 40 milliseconds +- * TC0 WRR weights: Q0 = 1, Q1 = 1, Q2 = 1, Q3 = 1 +- * TC1 WRR weights: Q0 = 1, Q1 = 1, Q2 = 1, Q3 = 1 +- * TC2 WRR weights: Q0 = 1, Q1 = 1, Q2 = 1, Q3 = 1 +- * TC3 WRR weights: Q0 = 1, Q1 = 1, Q2 = 1, Q3 = 1 +- * @cliexend +-?*/ +-/* *INDENT-OFF* */ +-VLIB_CLI_COMMAND (cmd_show_dpdk_if_hqos, static) = { +- .path = "show dpdk interface hqos", +- .short_help = "show dpdk interface hqos ", +- .function = show_dpdk_if_hqos, +-}; +- +-/* *INDENT-ON* */ +- +-static clib_error_t * +-show_dpdk_hqos_queue_stats (vlib_main_t * vm, unformat_input_t * input, +- vlib_cli_command_t * cmd) +-{ +- unformat_input_t _line_input, *line_input = &_line_input; +- clib_error_t *error = NULL; +-#ifdef RTE_SCHED_COLLECT_STATS +- dpdk_main_t *dm = &dpdk_main; +- u32 hw_if_index = (u32) ~ 0; +- u32 subport = (u32) ~ 0; +- u32 pipe = (u32) ~ 0; +- u32 tc = (u32) ~ 0; +- u32 tc_q = (u32) ~ 0; +- vnet_hw_interface_t *hw; +- dpdk_device_t *xd; +- uword *p = 0; +- struct rte_eth_dev_info dev_info; +- struct rte_pci_device *pci_dev; +- dpdk_device_config_t *devconf = 0; +- u32 qindex; +- struct rte_sched_queue_stats stats; +- u16 qlen; +- +- if (!unformat_user (input, unformat_line_input, line_input)) +- return 0; +- +- while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) +- { +- if (unformat +- (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main, +- &hw_if_index)) +- ; +- +- else if (unformat (line_input, "subport %d", &subport)) +- ; +- +- else if (unformat (line_input, "pipe %d", &pipe)) +- ; +- +- else if (unformat (line_input, "tc %d", &tc)) +- ; +- +- else if (unformat (line_input, "tc_q %d", &tc_q)) +- ; +- +- else +- { +- error = clib_error_return (0, "parse error: '%U'", +- format_unformat_error, line_input); +- goto done; +- } +- } +- +- if (hw_if_index == (u32) ~ 0) +- { +- error = clib_error_return (0, "please specify interface name!!"); +- goto done; +- } +- +- hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); +- xd = vec_elt_at_index (dm->devices, hw->dev_instance); +- +- rte_eth_dev_info_get (xd->port_id, &dev_info); +- +- pci_dev = dpdk_get_pci_device (&dev_info); +- +- if (pci_dev) +- { /* bonded interface has no pci info */ +- vlib_pci_addr_t pci_addr; +- +- pci_addr.domain = pci_dev->addr.domain; +- pci_addr.bus = pci_dev->addr.bus; +- pci_addr.slot = pci_dev->addr.devid; +- pci_addr.function = pci_dev->addr.function; +- +- p = +- hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32); +- } +- +- if (p) +- devconf = pool_elt_at_index (dm->conf->dev_confs, p[0]); +- else +- devconf = &dm->conf->default_devconf; +- +- if (devconf->hqos_enabled == 0) +- { +- vlib_cli_output (vm, "HQoS disabled for this interface"); +- goto done; +- } +- +- /* +- * Figure out which queue to query. cf rte_sched_port_qindex. (Not sure why +- * that method isn't made public by DPDK - how _should_ we get the queue ID?) +- */ +- qindex = subport * devconf->hqos.port.n_pipes_per_subport + pipe; +- qindex = qindex * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE + tc; +- qindex = qindex * RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS + tc_q; +- +- if (rte_sched_queue_read_stats (xd->hqos_ht->hqos, qindex, &stats, &qlen) != +- 0) +- { +- error = clib_error_return (0, "failed to read stats"); +- goto done; +- } +- +- vlib_cli_output (vm, "%=24s%=16s", "Stats Parameter", "Value"); +- vlib_cli_output (vm, "%=24s%=16d", "Packets", stats.n_pkts); +- vlib_cli_output (vm, "%=24s%=16d", "Packets dropped", stats.n_pkts_dropped); +-#ifdef RTE_SCHED_RED +- vlib_cli_output (vm, "%=24s%=16d", "Packets dropped (RED)", +- stats.n_pkts_red_dropped); +-#endif +- vlib_cli_output (vm, "%=24s%=16d", "Bytes", stats.n_bytes); +- vlib_cli_output (vm, "%=24s%=16d", "Bytes dropped", stats.n_bytes_dropped); +- +-#else +- +- /* Get a line of input */ +- if (!unformat_user (input, unformat_line_input, line_input)) +- return 0; +- +- vlib_cli_output (vm, "RTE_SCHED_COLLECT_STATS disabled in DPDK"); +- goto done; +- +-#endif +- +-done: +- unformat_free (line_input); +- +- return error; +-} +- +-/*? +- * This command is used to display statistics associated with a HQoS traffic class +- * queue. +- * +- * @note +- * Statistic collection by the scheduler is disabled by default in DPDK. In order to +- * turn it on, add the following line to '../vpp/dpdk/Makefile': +- * - $(call set,RTE_SCHED_COLLECT_STATS,y) +- * +- * @cliexpar +- * Example of how to display statistics of HQoS a HQoS traffic class queue: +- * @cliexstart{show dpdk hqos queue GigabitEthernet0/9/0 subport 0 pipe 3181 tc 0 tc_q 0} +- * Stats Parameter Value +- * Packets 140 +- * Packets dropped 0 +- * Bytes 8400 +- * Bytes dropped 0 +- * @cliexend +-?*/ +-/* *INDENT-OFF* */ +-VLIB_CLI_COMMAND (cmd_show_dpdk_hqos_queue_stats, static) = { +- .path = "show dpdk hqos queue", +- .short_help = "show dpdk hqos queue subport pipe tc tc_q ", +- .function = show_dpdk_hqos_queue_stats, +-}; +-/* *INDENT-ON* */ +-#endif +- + static clib_error_t * + show_dpdk_version_command_fn (vlib_main_t * vm, + unformat_input_t * input, +diff --git a/src/plugins/dpdk/device/device.c b/src/plugins/dpdk/device/device.c +index 323149043..c355edf6a 100644 +--- a/src/plugins/dpdk/device/device.c ++++ b/src/plugins/dpdk/device/device.c +@@ -180,21 +180,6 @@ static_always_inline + queue_id = (queue_id + 1) % xd->tx_q_used; + } + +-#if 0 +- if (PREDICT_FALSE (xd->flags & DPDK_DEVICE_FLAG_HQOS)) /* HQoS ON */ +- { +- /* no wrap, transmit in one burst */ +- dpdk_device_hqos_per_worker_thread_t *hqos = +- &xd->hqos_wt[vm->thread_index]; +- +- ASSERT (hqos->swq != NULL); +- +- dpdk_hqos_metadata_set (hqos, mb, n_left); +- n_sent = rte_ring_sp_enqueue_burst (hqos->swq, (void **) mb, +- n_left, 0); +- } +- else +-#endif + if (PREDICT_TRUE (xd->flags & DPDK_DEVICE_FLAG_PMD)) + { + /* no wrap, transmit in one burst */ +diff --git a/src/plugins/dpdk/device/dpdk.h b/src/plugins/dpdk/device/dpdk.h +index ab28ac06a..68d9e712b 100644 +--- a/src/plugins/dpdk/device/dpdk.h ++++ b/src/plugins/dpdk/device/dpdk.h +@@ -119,40 +119,6 @@ typedef enum + + typedef uint16_t dpdk_portid_t; + +-typedef struct +-{ +- /* Required for vec_validate_aligned */ +- CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); +- +- struct rte_ring *swq; +- +- u64 hqos_field0_slabmask; +- u32 hqos_field0_slabpos; +- u32 hqos_field0_slabshr; +- u64 hqos_field1_slabmask; +- u32 hqos_field1_slabpos; +- u32 hqos_field1_slabshr; +- u64 hqos_field2_slabmask; +- u32 hqos_field2_slabpos; +- u32 hqos_field2_slabshr; +- u32 hqos_tc_table[64]; +-} dpdk_device_hqos_per_worker_thread_t; +- +-typedef struct +-{ +- /* Required for vec_validate_aligned */ +- CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); +- struct rte_ring **swq; +- struct rte_mbuf **pkts_enq; +- struct rte_mbuf **pkts_deq; +- struct rte_sched_port *hqos; +- u32 hqos_burst_enq; +- u32 hqos_burst_deq; +- u32 pkts_enq_len; +- u32 swq_pos; +- u32 flush_count; +-} dpdk_device_hqos_per_hqos_thread_t; +- + #define foreach_dpdk_device_flags \ + _( 0, ADMIN_UP, "admin-up") \ + _( 1, PROMISC, "promisc") \ +@@ -160,7 +126,6 @@ typedef struct + _( 3, PMD_INIT_FAIL, "pmd-init-fail") \ + _( 4, MAYBE_MULTISEG, "maybe-multiseg") \ + _( 5, HAVE_SUBIF, "subif") \ +- _( 6, HQOS, "hqos") \ + _( 9, TX_OFFLOAD, "tx-offload") \ + _(10, INTEL_PHDR_CKSUM, "intel-phdr-cksum") \ + _(11, RX_FLOW_OFFLOAD, "rx-flow-offload") \ +@@ -235,10 +200,6 @@ typedef struct + u32 parked_loop_count; + struct rte_flow_error last_flow_error; + +- /* HQoS related */ +- dpdk_device_hqos_per_worker_thread_t *hqos_wt; +- dpdk_device_hqos_per_hqos_thread_t *hqos_ht; +- + /* af_packet instance number */ + u16 af_packet_instance_num; + +@@ -278,39 +239,6 @@ typedef struct + #define HQOS_FLUSH_COUNT_THRESHOLD 100000 + #endif + +-typedef struct dpdk_device_config_hqos_t +-{ +- u32 hqos_thread; +- u32 hqos_thread_valid; +- +- u32 swq_size; +- u32 burst_enq; +- u32 burst_deq; +- +- u32 pktfield0_slabpos; +- u32 pktfield1_slabpos; +- u32 pktfield2_slabpos; +- u64 pktfield0_slabmask; +- u64 pktfield1_slabmask; +- u64 pktfield2_slabmask; +- u32 tc_table[64]; +- +- struct rte_sched_port_params port; +- struct rte_sched_subport_params *subport; +- struct rte_sched_pipe_params *pipe; +- uint32_t *pipe_map; +-} dpdk_device_config_hqos_t; +- +-int dpdk_hqos_validate_mask (u64 mask, u32 n); +-void dpdk_device_config_hqos_pipe_profile_default (dpdk_device_config_hqos_t * +- hqos, u32 pipe_profile_id); +-#if 0 +-void dpdk_device_config_hqos_default (dpdk_device_config_hqos_t * hqos); +-#endif +-clib_error_t *dpdk_port_setup_hqos (dpdk_device_t * xd, +- dpdk_device_config_hqos_t * hqos); +-void dpdk_hqos_metadata_set (dpdk_device_hqos_per_worker_thread_t * hqos, +- struct rte_mbuf **pkts, u32 n_pkts); + + #define foreach_dpdk_device_config_item \ + _ (num_rx_queues) \ +@@ -333,8 +261,6 @@ typedef struct + foreach_dpdk_device_config_item + #undef _ + clib_bitmap_t * workers; +- u32 hqos_enabled; +- dpdk_device_config_hqos_t hqos; + u8 tso; + u8 *devargs; + +@@ -397,7 +323,6 @@ typedef struct + + /* Devices */ + dpdk_device_t *devices; +- dpdk_device_and_queue_t **devices_by_hqos_cpu; + dpdk_per_thread_data_t *per_thread_data; + + /* buffer flags template, configurable to enable/disable tcp / udp cksum */ +@@ -409,10 +334,6 @@ typedef struct + */ + u8 admin_up_down_in_progress; + +- /* which cpus are running I/O TX */ +- int hqos_cpu_first_index; +- int hqos_cpu_count; +- + /* control interval of dpdk link state and stat polling */ + f64 link_state_poll_interval; + f64 stat_poll_interval; +@@ -502,8 +423,6 @@ format_function_t format_dpdk_tx_offload_caps; + vnet_flow_dev_ops_function_t dpdk_flow_ops_fn; + + clib_error_t *unformat_rss_fn (unformat_input_t * input, uword * rss_fn); +-clib_error_t *unformat_hqos (unformat_input_t * input, +- dpdk_device_config_hqos_t * hqos); + + struct rte_pci_device *dpdk_get_pci_device (const struct rte_eth_dev_info + *info); +diff --git a/src/plugins/dpdk/device/format.c b/src/plugins/dpdk/device/format.c +index 20493eb77..8ef46512c 100644 +--- a/src/plugins/dpdk/device/format.c ++++ b/src/plugins/dpdk/device/format.c +@@ -913,25 +913,6 @@ unformat_rss_fn (unformat_input_t * input, uword * rss_fn) + return 0; + } + +-clib_error_t * +-unformat_hqos (unformat_input_t * input, dpdk_device_config_hqos_t * hqos) +-{ +- clib_error_t *error = 0; +- +- while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) +- { +- if (unformat (input, "hqos-thread %u", &hqos->hqos_thread)) +- hqos->hqos_thread_valid = 1; +- else +- { +- error = clib_error_return (0, "unknown input `%U'", +- format_unformat_error, input); +- break; +- } +- } +- +- return error; +-} + + /* + * fd.io coding-style-patch-verification: OFF +diff --git a/src/plugins/dpdk/device/init.c b/src/plugins/dpdk/device/init.c +index d0125e939..5d0e5a260 100644 +--- a/src/plugins/dpdk/device/init.c ++++ b/src/plugins/dpdk/device/init.c +@@ -214,29 +214,9 @@ dpdk_lib_init (dpdk_main_t * dm) + dpdk_device_t *xd; + vlib_pci_addr_t last_pci_addr; + u32 last_pci_addr_port = 0; +- vlib_thread_registration_t *tr_hqos; +- uword *p_hqos; +- +- u32 next_hqos_cpu = 0; + u8 af_packet_instance_num = 0; + last_pci_addr.as_u32 = ~0; + +- dm->hqos_cpu_first_index = 0; +- dm->hqos_cpu_count = 0; +- +- /* find out which cpus will be used for I/O TX */ +- p_hqos = hash_get_mem (tm->thread_registrations_by_name, "hqos-threads"); +- tr_hqos = p_hqos ? (vlib_thread_registration_t *) p_hqos[0] : 0; +- +- if (tr_hqos && tr_hqos->count > 0) +- { +- dm->hqos_cpu_first_index = tr_hqos->first_index; +- dm->hqos_cpu_count = tr_hqos->count; +- } +- +- vec_validate_aligned (dm->devices_by_hqos_cpu, tm->n_vlib_mains - 1, +- CLIB_CACHE_LINE_BYTES); +- + nports = rte_eth_dev_count_avail (); + + if (nports < 1) +@@ -596,38 +576,6 @@ dpdk_lib_init (dpdk_main_t * dm) + /* assign interface to input thread */ + int q; + +- if (devconf->hqos_enabled) +- { +- xd->flags |= DPDK_DEVICE_FLAG_HQOS; +- +- int cpu; +- if (devconf->hqos.hqos_thread_valid) +- { +- if (devconf->hqos.hqos_thread >= dm->hqos_cpu_count) +- return clib_error_return (0, "invalid HQoS thread index"); +- +- cpu = dm->hqos_cpu_first_index + devconf->hqos.hqos_thread; +- } +- else +- { +- if (dm->hqos_cpu_count == 0) +- return clib_error_return (0, "no HQoS threads available"); +- +- cpu = dm->hqos_cpu_first_index + next_hqos_cpu; +- +- next_hqos_cpu++; +- if (next_hqos_cpu == dm->hqos_cpu_count) +- next_hqos_cpu = 0; +- +- devconf->hqos.hqos_thread_valid = 1; +- devconf->hqos.hqos_thread = cpu; +- } +- +- dpdk_device_and_queue_t *dq; +- vec_add2 (dm->devices_by_hqos_cpu[cpu], dq, 1); +- dq->device = xd->device_index; +- dq->queue_id = 0; +- } + + error = ethernet_register_interface + (dm->vnet_main, dpdk_device_class.index, xd->device_index, +@@ -770,14 +718,6 @@ dpdk_lib_init (dpdk_main_t * dm) + format_dpdk_device_name, i, + format_dpdk_device_errors, xd); + +- if (devconf->hqos_enabled) +- { +- clib_error_t *rv; +- rv = dpdk_port_setup_hqos (xd, &devconf->hqos); +- if (rv) +- return rv; +- } +- + /* + * A note on Cisco VIC (PMD_ENIC) and VLAN: + * +@@ -1060,11 +1000,7 @@ dpdk_device_config (dpdk_config_main_t * conf, vlib_pci_addr_t pci_addr, + } + + devconf->pci_addr.as_u32 = pci_addr.as_u32; +- devconf->hqos_enabled = 0; + devconf->tso = DPDK_DEVICE_TSO_DEFAULT; +-#if 0 +- dpdk_device_config_hqos_default (&devconf->hqos); +-#endif + + if (!input) + return 0; +@@ -1097,19 +1033,6 @@ dpdk_device_config (dpdk_config_main_t * conf, vlib_pci_addr_t pci_addr, + devconf->vlan_strip_offload = DPDK_DEVICE_VLAN_STRIP_OFF; + else if (unformat (input, "vlan-strip-offload on")) + devconf->vlan_strip_offload = DPDK_DEVICE_VLAN_STRIP_ON; +- else +- if (unformat +- (input, "hqos %U", unformat_vlib_cli_sub_input, &sub_input)) +- { +- devconf->hqos_enabled = 1; +- error = unformat_hqos (&sub_input, &devconf->hqos); +- if (error) +- break; +- } +- else if (unformat (input, "hqos")) +- { +- devconf->hqos_enabled = 1; +- } + else if (unformat (input, "tso on")) + { + devconf->tso = DPDK_DEVICE_TSO_ON; diff --git a/extras/deprecated/dpdk-hqos/hqos.c b/extras/deprecated/dpdk-hqos/hqos.c new file mode 100644 index 00000000000..1a8dd6d98fe --- /dev/null +++ b/extras/deprecated/dpdk-hqos/hqos.c @@ -0,0 +1,771 @@ +/* + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include /* enumerate all vlib messages */ + +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) +#define vl_printfun +#include +#undef vl_printfun + +#include + +/*** + * + * HQoS default configuration values + * + ***/ + +static dpdk_device_config_hqos_t hqos_params_default = { + .hqos_thread_valid = 0, + + .swq_size = 4096, + .burst_enq = 256, + .burst_deq = 220, + + /* + * Packet field to identify the subport. + * + * Default value: Since only one subport is defined by default (see below: + * n_subports_per_port = 1), the subport ID is hardcoded to 0. + */ + .pktfield0_slabpos = 0, + .pktfield0_slabmask = 0, + + /* + * Packet field to identify the pipe. + * + * Default value: Assuming Ethernet/IPv4/UDP packets, UDP payload bits 12 .. 23 + */ + .pktfield1_slabpos = 40, + .pktfield1_slabmask = 0x0000000FFF000000LLU, + + /* Packet field used as index into TC translation table to identify the traffic + * class and queue. + * + * Default value: Assuming Ethernet/IPv4 packets, IPv4 DSCP field + */ + .pktfield2_slabpos = 8, + .pktfield2_slabmask = 0x00000000000000FCLLU, + .tc_table = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + }, + + /* port */ + .port = { + .name = NULL, /* Set at init */ + .socket = 0, /* Set at init */ + .rate = 1250000000, /* Assuming 10GbE port */ + .mtu = 14 + 1500, /* Assuming Ethernet/IPv4 pkt (Ethernet FCS not included) */ + .frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT, + .n_subports_per_port = 1, + .n_pipes_per_subport = 4096, + .qsize = {64, 64, 64, 64}, + .pipe_profiles = NULL, /* Set at config */ + .n_pipe_profiles = 1, + +#ifdef RTE_SCHED_RED + .red_params = { + /* Traffic Class 0 Colors Green / Yellow / Red */ + [0][0] = {.min_th = 48,.max_th = 64,.maxp_inv = + 10,.wq_log2 = 9}, + [0][1] = {.min_th = 40,.max_th = 64,.maxp_inv = + 10,.wq_log2 = 9}, + [0][2] = {.min_th = 32,.max_th = 64,.maxp_inv = + 10,.wq_log2 = 9}, + + /* Traffic Class 1 - Colors Green / Yellow / Red */ + [1][0] = {.min_th = 48,.max_th = 64,.maxp_inv = + 10,.wq_log2 = 9}, + [1][1] = {.min_th = 40,.max_th = 64,.maxp_inv = + 10,.wq_log2 = 9}, + [1][2] = {.min_th = 32,.max_th = 64,.maxp_inv = + 10,.wq_log2 = 9}, + + /* Traffic Class 2 - Colors Green / Yellow / Red */ + [2][0] = {.min_th = 48,.max_th = 64,.maxp_inv = + 10,.wq_log2 = 9}, + [2][1] = {.min_th = 40,.max_th = 64,.maxp_inv = + 10,.wq_log2 = 9}, + [2][2] = {.min_th = 32,.max_th = 64,.maxp_inv = + 10,.wq_log2 = 9}, + + /* Traffic Class 3 - Colors Green / Yellow / Red */ + [3][0] = {.min_th = 48,.max_th = 64,.maxp_inv = + 10,.wq_log2 = 9}, + [3][1] = {.min_th = 40,.max_th = 64,.maxp_inv = + 10,.wq_log2 = 9}, + [3][2] = {.min_th = 32,.max_th = 64,.maxp_inv = + 10,.wq_log2 = 9} + }, +#endif /* RTE_SCHED_RED */ + }, +}; + +static struct rte_sched_subport_params hqos_subport_params_default = { + .tb_rate = 1250000000, /* 10GbE line rate (measured in bytes/second) */ + .tb_size = 1000000, + .tc_rate = {1250000000, 1250000000, 1250000000, 1250000000}, + .tc_period = 10, +}; + +static struct rte_sched_pipe_params hqos_pipe_params_default = { + .tb_rate = 305175, /* 10GbE line rate divided by 4K pipes */ + .tb_size = 1000000, + .tc_rate = {305175, 305175, 305175, 305175}, + .tc_period = 40, +#ifdef RTE_SCHED_SUBPORT_TC_OV + .tc_ov_weight = 1, +#endif + .wrr_weights = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, +}; + +/*** + * + * HQoS configuration + * + ***/ + +int +dpdk_hqos_validate_mask (u64 mask, u32 n) +{ + int count = __builtin_popcountll (mask); + int pos_lead = sizeof (u64) * 8 - count_leading_zeros (mask); + int pos_trail = count_trailing_zeros (mask); + int count_expected = __builtin_popcount (n - 1); + + /* Handle the exceptions */ + if (n == 0) + return -1; /* Error */ + + if ((mask == 0) && (n == 1)) + return 0; /* OK */ + + if (((mask == 0) && (n != 1)) || ((mask != 0) && (n == 1))) + return -2; /* Error */ + + /* Check that mask is contiguous */ + if ((pos_lead - pos_trail) != count) + return -3; /* Error */ + + /* Check that mask contains the expected number of bits set */ + if (count != count_expected) + return -4; /* Error */ + + return 0; /* OK */ +} + +void +dpdk_device_config_hqos_pipe_profile_default (dpdk_device_config_hqos_t * + hqos, u32 pipe_profile_id) +{ + memcpy (&hqos->pipe[pipe_profile_id], &hqos_pipe_params_default, + sizeof (hqos_pipe_params_default)); +} + +void +dpdk_device_config_hqos_default (dpdk_device_config_hqos_t * hqos) +{ + struct rte_sched_subport_params *subport_params; + struct rte_sched_pipe_params *pipe_params; + u32 *pipe_map; + u32 i; + + memcpy (hqos, &hqos_params_default, sizeof (hqos_params_default)); + + /* pipe */ + vec_add2 (hqos->pipe, pipe_params, hqos->port.n_pipe_profiles); + + for (i = 0; i < vec_len (hqos->pipe); i++) + memcpy (&pipe_params[i], + &hqos_pipe_params_default, sizeof (hqos_pipe_params_default)); + + hqos->port.pipe_profiles = hqos->pipe; + + /* subport */ + vec_add2 (hqos->subport, subport_params, hqos->port.n_subports_per_port); + + for (i = 0; i < vec_len (hqos->subport); i++) + memcpy (&subport_params[i], + &hqos_subport_params_default, + sizeof (hqos_subport_params_default)); + + /* pipe profile */ + vec_add2 (hqos->pipe_map, + pipe_map, + hqos->port.n_subports_per_port * hqos->port.n_pipes_per_subport); + + for (i = 0; i < vec_len (hqos->pipe_map); i++) + pipe_map[i] = 0; +} + +/*** + * + * HQoS init + * + ***/ + +clib_error_t * +dpdk_port_setup_hqos (dpdk_device_t * xd, dpdk_device_config_hqos_t * hqos) +{ + vlib_thread_main_t *tm = vlib_get_thread_main (); + char name[32]; + u32 subport_id, i; + int rv; + + /* Detect the set of worker threads */ + int worker_thread_first = 0; + int worker_thread_count = 0; + + uword *p = hash_get_mem (tm->thread_registrations_by_name, "workers"); + vlib_thread_registration_t *tr = + p ? (vlib_thread_registration_t *) p[0] : 0; + + if (tr && tr->count > 0) + { + worker_thread_first = tr->first_index; + worker_thread_count = tr->count; + } + + /* Allocate the per-thread device data array */ + vec_validate_aligned (xd->hqos_wt, tm->n_vlib_mains - 1, + CLIB_CACHE_LINE_BYTES); + clib_memset (xd->hqos_wt, 0, tm->n_vlib_mains * sizeof (xd->hqos_wt[0])); + + vec_validate_aligned (xd->hqos_ht, 0, CLIB_CACHE_LINE_BYTES); + clib_memset (xd->hqos_ht, 0, sizeof (xd->hqos_ht[0])); + + /* Allocate space for one SWQ per worker thread in the I/O TX thread data structure */ + vec_validate (xd->hqos_ht->swq, worker_thread_count); + + /* SWQ */ + for (i = 0; i < worker_thread_count + 1; i++) + { + u32 swq_flags = RING_F_SP_ENQ | RING_F_SC_DEQ; + + snprintf (name, sizeof (name), "SWQ-worker%u-to-device%u", i, + xd->port_id); + xd->hqos_ht->swq[i] = + rte_ring_create (name, hqos->swq_size, xd->cpu_socket, swq_flags); + if (xd->hqos_ht->swq[i] == NULL) + return clib_error_return (0, + "SWQ-worker%u-to-device%u: rte_ring_create err", + i, xd->port_id); + } + + /* + * HQoS + */ + + /* HQoS port */ + snprintf (name, sizeof (name), "HQoS%u", xd->port_id); + hqos->port.name = strdup (name); + if (hqos->port.name == NULL) + return clib_error_return (0, "HQoS%u: strdup err", xd->port_id); + + hqos->port.socket = rte_eth_dev_socket_id (xd->port_id); + if (hqos->port.socket == SOCKET_ID_ANY) + hqos->port.socket = 0; + + xd->hqos_ht->hqos = rte_sched_port_config (&hqos->port); + if (xd->hqos_ht->hqos == NULL) + return clib_error_return (0, "HQoS%u: rte_sched_port_config err", + xd->port_id); + + /* HQoS subport */ + for (subport_id = 0; subport_id < hqos->port.n_subports_per_port; + subport_id++) + { + u32 pipe_id; + + rv = + rte_sched_subport_config (xd->hqos_ht->hqos, subport_id, + &hqos->subport[subport_id]); + if (rv) + return clib_error_return (0, + "HQoS%u subport %u: rte_sched_subport_config err (%d)", + xd->port_id, subport_id, rv); + + /* HQoS pipe */ + for (pipe_id = 0; pipe_id < hqos->port.n_pipes_per_subport; pipe_id++) + { + u32 pos = subport_id * hqos->port.n_pipes_per_subport + pipe_id; + u32 profile_id = hqos->pipe_map[pos]; + + rv = + rte_sched_pipe_config (xd->hqos_ht->hqos, subport_id, pipe_id, + profile_id); + if (rv) + return clib_error_return (0, + "HQoS%u subport %u pipe %u: rte_sched_pipe_config err (%d)", + xd->port_id, subport_id, pipe_id, rv); + } + } + + /* Set up per-thread device data for the I/O TX thread */ + xd->hqos_ht->hqos_burst_enq = hqos->burst_enq; + xd->hqos_ht->hqos_burst_deq = hqos->burst_deq; + vec_validate (xd->hqos_ht->pkts_enq, 2 * hqos->burst_enq - 1); + vec_validate (xd->hqos_ht->pkts_deq, hqos->burst_deq - 1); + xd->hqos_ht->pkts_enq_len = 0; + xd->hqos_ht->swq_pos = 0; + xd->hqos_ht->flush_count = 0; + + /* Set up per-thread device data for each worker thread */ + for (i = 0; i < worker_thread_count + 1; i++) + { + u32 tid; + if (i) + tid = worker_thread_first + (i - 1); + else + tid = i; + + xd->hqos_wt[tid].swq = xd->hqos_ht->swq[i]; + xd->hqos_wt[tid].hqos_field0_slabpos = hqos->pktfield0_slabpos; + xd->hqos_wt[tid].hqos_field0_slabmask = hqos->pktfield0_slabmask; + xd->hqos_wt[tid].hqos_field0_slabshr = + count_trailing_zeros (hqos->pktfield0_slabmask); + xd->hqos_wt[tid].hqos_field1_slabpos = hqos->pktfield1_slabpos; + xd->hqos_wt[tid].hqos_field1_slabmask = hqos->pktfield1_slabmask; + xd->hqos_wt[tid].hqos_field1_slabshr = + count_trailing_zeros (hqos->pktfield1_slabmask); + xd->hqos_wt[tid].hqos_field2_slabpos = hqos->pktfield2_slabpos; + xd->hqos_wt[tid].hqos_field2_slabmask = hqos->pktfield2_slabmask; + xd->hqos_wt[tid].hqos_field2_slabshr = + count_trailing_zeros (hqos->pktfield2_slabmask); + memcpy (xd->hqos_wt[tid].hqos_tc_table, hqos->tc_table, + sizeof (hqos->tc_table)); + } + + return 0; +} + +/*** + * + * HQoS run-time + * + ***/ +/* + * dpdk_hqos_thread - Contains the main loop of an HQoS thread. + * + * w + * Information for the current thread + */ +static_always_inline void +dpdk_hqos_thread_internal_hqos_dbg_bypass (vlib_main_t * vm) +{ + dpdk_main_t *dm = &dpdk_main; + u32 thread_index = vm->thread_index; + u32 dev_pos; + + dev_pos = 0; + while (1) + { + vlib_worker_thread_barrier_check (); + + u32 n_devs = vec_len (dm->devices_by_hqos_cpu[thread_index]); + if (dev_pos >= n_devs) + dev_pos = 0; + + dpdk_device_and_queue_t *dq = + vec_elt_at_index (dm->devices_by_hqos_cpu[thread_index], dev_pos); + dpdk_device_t *xd = vec_elt_at_index (dm->devices, dq->device); + + dpdk_device_hqos_per_hqos_thread_t *hqos = xd->hqos_ht; + u32 device_index = xd->port_id; + u16 queue_id = dq->queue_id; + + struct rte_mbuf **pkts_enq = hqos->pkts_enq; + u32 pkts_enq_len = hqos->pkts_enq_len; + u32 swq_pos = hqos->swq_pos; + u32 n_swq = vec_len (hqos->swq), i; + u32 flush_count = hqos->flush_count; + + for (i = 0; i < n_swq; i++) + { + /* Get current SWQ for this device */ + struct rte_ring *swq = hqos->swq[swq_pos]; + + /* Read SWQ burst to packet buffer of this device */ + pkts_enq_len += rte_ring_sc_dequeue_burst (swq, + (void **) + &pkts_enq[pkts_enq_len], + hqos->hqos_burst_enq, 0); + + /* Get next SWQ for this device */ + swq_pos++; + if (swq_pos >= n_swq) + swq_pos = 0; + hqos->swq_pos = swq_pos; + + /* HWQ TX enqueue when burst available */ + if (pkts_enq_len >= hqos->hqos_burst_enq) + { + u32 n_pkts = rte_eth_tx_burst (device_index, + (uint16_t) queue_id, + pkts_enq, + (uint16_t) pkts_enq_len); + + for (; n_pkts < pkts_enq_len; n_pkts++) + rte_pktmbuf_free (pkts_enq[n_pkts]); + + pkts_enq_len = 0; + flush_count = 0; + break; + } + } + if (pkts_enq_len) + { + flush_count++; + if (PREDICT_FALSE (flush_count == HQOS_FLUSH_COUNT_THRESHOLD)) + { + rte_sched_port_enqueue (hqos->hqos, pkts_enq, pkts_enq_len); + + pkts_enq_len = 0; + flush_count = 0; + } + } + hqos->pkts_enq_len = pkts_enq_len; + hqos->flush_count = flush_count; + + /* Advance to next device */ + dev_pos++; + } +} + +static_always_inline void +dpdk_hqos_thread_internal (vlib_main_t * vm) +{ + dpdk_main_t *dm = &dpdk_main; + u32 thread_index = vm->thread_index; + u32 dev_pos; + + dev_pos = 0; + while (1) + { + vlib_worker_thread_barrier_check (); + + u32 n_devs = vec_len (dm->devices_by_hqos_cpu[thread_index]); + if (PREDICT_FALSE (n_devs == 0)) + { + dev_pos = 0; + continue; + } + if (dev_pos >= n_devs) + dev_pos = 0; + + dpdk_device_and_queue_t *dq = + vec_elt_at_index (dm->devices_by_hqos_cpu[thread_index], dev_pos); + dpdk_device_t *xd = vec_elt_at_index (dm->devices, dq->device); + + dpdk_device_hqos_per_hqos_thread_t *hqos = xd->hqos_ht; + u32 device_index = xd->port_id; + u16 queue_id = dq->queue_id; + + struct rte_mbuf **pkts_enq = hqos->pkts_enq; + struct rte_mbuf **pkts_deq = hqos->pkts_deq; + u32 pkts_enq_len = hqos->pkts_enq_len; + u32 swq_pos = hqos->swq_pos; + u32 n_swq = vec_len (hqos->swq), i; + u32 flush_count = hqos->flush_count; + + /* + * SWQ dequeue and HQoS enqueue for current device + */ + for (i = 0; i < n_swq; i++) + { + /* Get current SWQ for this device */ + struct rte_ring *swq = hqos->swq[swq_pos]; + + /* Read SWQ burst to packet buffer of this device */ + pkts_enq_len += rte_ring_sc_dequeue_burst (swq, + (void **) + &pkts_enq[pkts_enq_len], + hqos->hqos_burst_enq, 0); + + /* Get next SWQ for this device */ + swq_pos++; + if (swq_pos >= n_swq) + swq_pos = 0; + hqos->swq_pos = swq_pos; + + /* HQoS enqueue when burst available */ + if (pkts_enq_len >= hqos->hqos_burst_enq) + { + rte_sched_port_enqueue (hqos->hqos, pkts_enq, pkts_enq_len); + + pkts_enq_len = 0; + flush_count = 0; + break; + } + } + if (pkts_enq_len) + { + flush_count++; + if (PREDICT_FALSE (flush_count == HQOS_FLUSH_COUNT_THRESHOLD)) + { + rte_sched_port_enqueue (hqos->hqos, pkts_enq, pkts_enq_len); + + pkts_enq_len = 0; + flush_count = 0; + } + } + hqos->pkts_enq_len = pkts_enq_len; + hqos->flush_count = flush_count; + + /* + * HQoS dequeue and HWQ TX enqueue for current device + */ + { + u32 pkts_deq_len, n_pkts; + + pkts_deq_len = rte_sched_port_dequeue (hqos->hqos, + pkts_deq, + hqos->hqos_burst_deq); + + for (n_pkts = 0; n_pkts < pkts_deq_len;) + n_pkts += rte_eth_tx_burst (device_index, + (uint16_t) queue_id, + &pkts_deq[n_pkts], + (uint16_t) (pkts_deq_len - n_pkts)); + } + + /* Advance to next device */ + dev_pos++; + } +} + +void +dpdk_hqos_thread (vlib_worker_thread_t * w) +{ + vlib_main_t *vm; + vlib_thread_main_t *tm = vlib_get_thread_main (); + dpdk_main_t *dm = &dpdk_main; + + vm = vlib_get_main (); + + ASSERT (vm->thread_index == vlib_get_thread_index ()); + + clib_time_init (&vm->clib_time); + clib_mem_set_heap (w->thread_mheap); + + /* Wait until the dpdk init sequence is complete */ + while (tm->worker_thread_release == 0) + vlib_worker_thread_barrier_check (); + + if (vec_len (dm->devices_by_hqos_cpu[vm->thread_index]) == 0) + return + clib_error + ("current I/O TX thread does not have any devices assigned to it"); + + if (DPDK_HQOS_DBG_BYPASS) + dpdk_hqos_thread_internal_hqos_dbg_bypass (vm); + else + dpdk_hqos_thread_internal (vm); +} + +void +dpdk_hqos_thread_fn (void *arg) +{ + vlib_worker_thread_t *w = (vlib_worker_thread_t *) arg; + vlib_worker_thread_init (w); + dpdk_hqos_thread (w); +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_THREAD (hqos_thread_reg, static) = +{ + .name = "hqos-threads", + .short_name = "hqos-threads", + .function = dpdk_hqos_thread_fn, +}; +/* *INDENT-ON* */ + +/* + * HQoS run-time code to be called by the worker threads + */ +#define BITFIELD(byte_array, slab_pos, slab_mask, slab_shr) \ +({ \ + u64 slab = *((u64 *) &byte_array[slab_pos]); \ + u64 val = (rte_be_to_cpu_64(slab) & slab_mask) >> slab_shr; \ + val; \ +}) + +#define RTE_SCHED_PORT_HIERARCHY(subport, pipe, traffic_class, queue, color) \ + ((((u64) (queue)) & 0x3) | \ + ((((u64) (traffic_class)) & 0x3) << 2) | \ + ((((u64) (color)) & 0x3) << 4) | \ + ((((u64) (subport)) & 0xFFFF) << 16) | \ + ((((u64) (pipe)) & 0xFFFFFFFF) << 32)) + +void +dpdk_hqos_metadata_set (dpdk_device_hqos_per_worker_thread_t * hqos, + struct rte_mbuf **pkts, u32 n_pkts) +{ + u32 i; + + for (i = 0; i < (n_pkts & (~0x3)); i += 4) + { + struct rte_mbuf *pkt0 = pkts[i]; + struct rte_mbuf *pkt1 = pkts[i + 1]; + struct rte_mbuf *pkt2 = pkts[i + 2]; + struct rte_mbuf *pkt3 = pkts[i + 3]; + + u8 *pkt0_data = rte_pktmbuf_mtod (pkt0, u8 *); + u8 *pkt1_data = rte_pktmbuf_mtod (pkt1, u8 *); + u8 *pkt2_data = rte_pktmbuf_mtod (pkt2, u8 *); + u8 *pkt3_data = rte_pktmbuf_mtod (pkt3, u8 *); + + u64 pkt0_subport = BITFIELD (pkt0_data, hqos->hqos_field0_slabpos, + hqos->hqos_field0_slabmask, + hqos->hqos_field0_slabshr); + u64 pkt0_pipe = BITFIELD (pkt0_data, hqos->hqos_field1_slabpos, + hqos->hqos_field1_slabmask, + hqos->hqos_field1_slabshr); + u64 pkt0_dscp = BITFIELD (pkt0_data, hqos->hqos_field2_slabpos, + hqos->hqos_field2_slabmask, + hqos->hqos_field2_slabshr); + u32 pkt0_tc = hqos->hqos_tc_table[pkt0_dscp & 0x3F] >> 2; + u32 pkt0_tc_q = hqos->hqos_tc_table[pkt0_dscp & 0x3F] & 0x3; + + u64 pkt1_subport = BITFIELD (pkt1_data, hqos->hqos_field0_slabpos, + hqos->hqos_field0_slabmask, + hqos->hqos_field0_slabshr); + u64 pkt1_pipe = BITFIELD (pkt1_data, hqos->hqos_field1_slabpos, + hqos->hqos_field1_slabmask, + hqos->hqos_field1_slabshr); + u64 pkt1_dscp = BITFIELD (pkt1_data, hqos->hqos_field2_slabpos, + hqos->hqos_field2_slabmask, + hqos->hqos_field2_slabshr); + u32 pkt1_tc = hqos->hqos_tc_table[pkt1_dscp & 0x3F] >> 2; + u32 pkt1_tc_q = hqos->hqos_tc_table[pkt1_dscp & 0x3F] & 0x3; + + u64 pkt2_subport = BITFIELD (pkt2_data, hqos->hqos_field0_slabpos, + hqos->hqos_field0_slabmask, + hqos->hqos_field0_slabshr); + u64 pkt2_pipe = BITFIELD (pkt2_data, hqos->hqos_field1_slabpos, + hqos->hqos_field1_slabmask, + hqos->hqos_field1_slabshr); + u64 pkt2_dscp = BITFIELD (pkt2_data, hqos->hqos_field2_slabpos, + hqos->hqos_field2_slabmask, + hqos->hqos_field2_slabshr); + u32 pkt2_tc = hqos->hqos_tc_table[pkt2_dscp & 0x3F] >> 2; + u32 pkt2_tc_q = hqos->hqos_tc_table[pkt2_dscp & 0x3F] & 0x3; + + u64 pkt3_subport = BITFIELD (pkt3_data, hqos->hqos_field0_slabpos, + hqos->hqos_field0_slabmask, + hqos->hqos_field0_slabshr); + u64 pkt3_pipe = BITFIELD (pkt3_data, hqos->hqos_field1_slabpos, + hqos->hqos_field1_slabmask, + hqos->hqos_field1_slabshr); + u64 pkt3_dscp = BITFIELD (pkt3_data, hqos->hqos_field2_slabpos, + hqos->hqos_field2_slabmask, + hqos->hqos_field2_slabshr); + u32 pkt3_tc = hqos->hqos_tc_table[pkt3_dscp & 0x3F] >> 2; + u32 pkt3_tc_q = hqos->hqos_tc_table[pkt3_dscp & 0x3F] & 0x3; + + u64 pkt0_sched = RTE_SCHED_PORT_HIERARCHY (pkt0_subport, + pkt0_pipe, + pkt0_tc, + pkt0_tc_q, + 0); + u64 pkt1_sched = RTE_SCHED_PORT_HIERARCHY (pkt1_subport, + pkt1_pipe, + pkt1_tc, + pkt1_tc_q, + 0); + u64 pkt2_sched = RTE_SCHED_PORT_HIERARCHY (pkt2_subport, + pkt2_pipe, + pkt2_tc, + pkt2_tc_q, + 0); + u64 pkt3_sched = RTE_SCHED_PORT_HIERARCHY (pkt3_subport, + pkt3_pipe, + pkt3_tc, + pkt3_tc_q, + 0); + + pkt0->hash.sched.lo = pkt0_sched & 0xFFFFFFFF; + pkt0->hash.sched.hi = pkt0_sched >> 32; + pkt1->hash.sched.lo = pkt1_sched & 0xFFFFFFFF; + pkt1->hash.sched.hi = pkt1_sched >> 32; + pkt2->hash.sched.lo = pkt2_sched & 0xFFFFFFFF; + pkt2->hash.sched.hi = pkt2_sched >> 32; + pkt3->hash.sched.lo = pkt3_sched & 0xFFFFFFFF; + pkt3->hash.sched.hi = pkt3_sched >> 32; + } + + for (; i < n_pkts; i++) + { + struct rte_mbuf *pkt = pkts[i]; + + u8 *pkt_data = rte_pktmbuf_mtod (pkt, u8 *); + + u64 pkt_subport = BITFIELD (pkt_data, hqos->hqos_field0_slabpos, + hqos->hqos_field0_slabmask, + hqos->hqos_field0_slabshr); + u64 pkt_pipe = BITFIELD (pkt_data, hqos->hqos_field1_slabpos, + hqos->hqos_field1_slabmask, + hqos->hqos_field1_slabshr); + u64 pkt_dscp = BITFIELD (pkt_data, hqos->hqos_field2_slabpos, + hqos->hqos_field2_slabmask, + hqos->hqos_field2_slabshr); + u32 pkt_tc = hqos->hqos_tc_table[pkt_dscp & 0x3F] >> 2; + u32 pkt_tc_q = hqos->hqos_tc_table[pkt_dscp & 0x3F] & 0x3; + + u64 pkt_sched = RTE_SCHED_PORT_HIERARCHY (pkt_subport, + pkt_pipe, + pkt_tc, + pkt_tc_q, + 0); + + pkt->hash.sched.lo = pkt_sched & 0xFFFFFFFF; + pkt->hash.sched.hi = pkt_sched >> 32; + } +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/extras/deprecated/dpdk-hqos/qos_doc.md b/extras/deprecated/dpdk-hqos/qos_doc.md new file mode 100644 index 00000000000..fe3bb1bcd4b --- /dev/null +++ b/extras/deprecated/dpdk-hqos/qos_doc.md @@ -0,0 +1,411 @@ +# QoS Hierarchical Scheduler {#qos_doc} + +The Quality-of-Service (QoS) scheduler performs egress-traffic management by +prioritizing the transmission of the packets of different type services and +subscribers based on the Service Level Agreements (SLAs). The QoS scheduler can +be enabled on one or more NIC output interfaces depending upon the +requirement. + + +## Overview + +The QoS scheduler supports a number of scheduling and shaping levels which +construct hierarchical-tree. The first level in the hierarchy is port (i.e. +the physical interface) that constitutes the root node of the tree. The +subsequent level is subport which represents the group of the +users/subscribers. The individual user/subscriber is represented by the pipe +at the next level. Each user can have different traffic type based on the +criteria of specific loss rate, jitter, and latency. These traffic types are +represented at the traffic-class level in the form of different traffic- +classes. The last level contains number of queues which are grouped together +to host the packets of the specific class type traffic. + +The QoS scheduler implementation requires flow classification, enqueue and +dequeue operations. The flow classification is mandatory stage for HQoS where +incoming packets are classified by mapping the packet fields information to +5-tuple (HQoS subport, pipe, traffic class, queue within traffic class, and +color) and storing that information in mbuf sched field. The enqueue operation +uses this information to determine the queue for storing the packet, and at +this stage, if the specific queue is full, QoS drops the packet. The dequeue +operation consists of scheduling the packet based on its length and available +credits, and handing over the scheduled packet to the output interface. + +For more information on QoS Scheduler, please refer DPDK Programmer's Guide- +http://dpdk.org/doc/guides/prog_guide/qos_framework.html + + +### QoS Scheduler Parameters + +Following illustrates the default HQoS configuration for each 10GbE output +port: + +Single subport (subport 0): + - Subport rate set to 100% of port rate + - Each of the 4 traffic classes has rate set to 100% of port rate + +4K pipes per subport 0 (pipes 0 .. 4095) with identical configuration: + - Pipe rate set to 1/4K of port rate + - Each of the 4 traffic classes has rate set to 100% of pipe rate + - Within each traffic class, the byte-level WRR weights for the 4 queues are set to 1:1:1:1 + + +#### Port configuration + +``` +port { + rate 1250000000 /* Assuming 10GbE port */ + frame_overhead 24 /* Overhead fields per Ethernet frame: + * 7B (Preamble) + + * 1B (Start of Frame Delimiter (SFD)) + + * 4B (Frame Check Sequence (FCS)) + + * 12B (Inter Frame Gap (IFG)) + */ + mtu 1522 /* Assuming Ethernet/IPv4 pkt (FCS not included) */ + n_subports_per_port 1 /* Number of subports per output interface */ + n_pipes_per_subport 4096 /* Number of pipes (users/subscribers) */ + queue_sizes 64 64 64 64 /* Packet queue size for each traffic class. + * All queues within the same pipe traffic class + * have the same size. Queues from different + * pipes serving the same traffic class have + * the same size. */ +} +``` + + +#### Subport configuration + +``` +subport 0 { + tb_rate 1250000000 /* Subport level token bucket rate (bytes per second) */ + tb_size 1000000 /* Subport level token bucket size (bytes) */ + tc0_rate 1250000000 /* Subport level token bucket rate for traffic class 0 (bytes per second) */ + tc1_rate 1250000000 /* Subport level token bucket rate for traffic class 1 (bytes per second) */ + tc2_rate 1250000000 /* Subport level token bucket rate for traffic class 2 (bytes per second) */ + tc3_rate 1250000000 /* Subport level token bucket rate for traffic class 3 (bytes per second) */ + tc_period 10 /* Time interval for refilling the token bucket associated with traffic class (Milliseconds) */ + pipe 0 4095 profile 0 /* pipes (users/subscribers) configured with pipe profile 0 */ +} +``` + + +#### Pipe configuration + +``` +pipe_profile 0 { + tb_rate 305175 /* Pipe level token bucket rate (bytes per second) */ + tb_size 1000000 /* Pipe level token bucket size (bytes) */ + tc0_rate 305175 /* Pipe level token bucket rate for traffic class 0 (bytes per second) */ + tc1_rate 305175 /* Pipe level token bucket rate for traffic class 1 (bytes per second) */ + tc2_rate 305175 /* Pipe level token bucket rate for traffic class 2 (bytes per second) */ + tc3_rate 305175 /* Pipe level token bucket rate for traffic class 3 (bytes per second) */ + tc_period 40 /* Time interval for refilling the token bucket associated with traffic class at pipe level (Milliseconds) */ + tc3_oversubscription_weight 1 /* Weight traffic class 3 oversubscription */ + tc0_wrr_weights 1 1 1 1 /* Pipe queues WRR weights for traffic class 0 */ + tc1_wrr_weights 1 1 1 1 /* Pipe queues WRR weights for traffic class 1 */ + tc2_wrr_weights 1 1 1 1 /* Pipe queues WRR weights for traffic class 2 */ + tc3_wrr_weights 1 1 1 1 /* Pipe queues WRR weights for traffic class 3 */ +} +``` + + +#### Random Early Detection (RED) parameters per traffic class and color (Green / Yellow / Red) + +``` +red { + tc0_wred_min 48 40 32 /* Minimum threshold for traffic class 0 queue (min_th) in number of packets */ + tc0_wred_max 64 64 64 /* Maximum threshold for traffic class 0 queue (max_th) in number of packets */ + tc0_wred_inv_prob 10 10 10 /* Inverse of packet marking probability for traffic class 0 queue (maxp = 1 / maxp_inv) */ + tc0_wred_weight 9 9 9 /* Traffic Class 0 queue weight */ + tc1_wred_min 48 40 32 /* Minimum threshold for traffic class 1 queue (min_th) in number of packets */ + tc1_wred_max 64 64 64 /* Maximum threshold for traffic class 1 queue (max_th) in number of packets */ + tc1_wred_inv_prob 10 10 10 /* Inverse of packet marking probability for traffic class 1 queue (maxp = 1 / maxp_inv) */ + tc1_wred_weight 9 9 9 /* Traffic Class 1 queue weight */ + tc2_wred_min 48 40 32 /* Minimum threshold for traffic class 2 queue (min_th) in number of packets */ + tc2_wred_max 64 64 64 /* Maximum threshold for traffic class 2 queue (max_th) in number of packets */ + tc2_wred_inv_prob 10 10 10 /* Inverse of packet marking probability for traffic class 2 queue (maxp = 1 / maxp_inv) */ + tc2_wred_weight 9 9 9 /* Traffic Class 2 queue weight */ + tc3_wred_min 48 40 32 /* Minimum threshold for traffic class 3 queue (min_th) in number of packets */ + tc3_wred_max 64 64 64 /* Maximum threshold for traffic class 3 queue (max_th) in number of packets */ + tc3_wred_inv_prob 10 10 10 /* Inverse of packet marking probability for traffic class 3 queue (maxp = 1 / maxp_inv) */ + tc3_wred_weight 9 9 9 /* Traffic Class 3 queue weight */ +} +``` + + +### DPDK QoS Scheduler Integration in VPP + +The Hierarchical Quality-of-Service (HQoS) scheduler object could be seen as +part of the logical NIC output interface. To enable HQoS on specific output +interface, vpp startup.conf file has to be configured accordingly. The output +interface that requires HQoS, should have "hqos" parameter specified in dpdk +section. Another optional parameter "hqos-thread" has been defined which can +be used to associate the output interface with specific hqos thread. In cpu +section of the config file, "corelist-hqos-threads" is introduced to assign +logical cpu cores to run the HQoS threads. A HQoS thread can run multiple HQoS +objects each associated with different output interfaces. All worker threads +instead of writing packets to NIC TX queue directly, write the packets to a +software queues. The hqos_threads read the software queues, and enqueue the +packets to HQoS objects, as well as dequeue packets from HQOS objects and +write them to NIC output interfaces. The worker threads need to be able to +send the packets to any output interface, therefore, each HQoS object +associated with NIC output interface should have software queues equal to +worker threads count. + +Following illustrates the sample startup configuration file with 4x worker +threads feeding 2x hqos threads that handle each QoS scheduler for 1x output +interface. + +``` +dpdk { + socket-mem 16384,16384 + + dev 0000:02:00.0 { + num-rx-queues 2 + hqos + } + dev 0000:06:00.0 { + num-rx-queues 2 + hqos + } + + num-mbufs 1000000 +} + +cpu { + main-core 0 + corelist-workers 1, 2, 3, 4 + corelist-hqos-threads 5, 6 +} +``` + + +### QoS scheduler CLI Commands + +Each QoS scheduler instance is initialised with default parameters required to +configure hqos port, subport, pipe and queues. Some of the parameters can be +re-configured in run-time through CLI commands. + + +#### Configuration + +Following commands can be used to configure QoS scheduler parameters. + +The command below can be used to set the subport level parameters such as +token bucket rate (bytes per seconds), token bucket size (bytes), traffic +class rates (bytes per seconds) and token update period (Milliseconds). + +``` +set dpdk interface hqos subport subport [rate ] + [bktsize ] [tc0 ] [tc1 ] [tc2 ] [tc3 ] [period ] +``` + +For setting the pipe profile, following command can be used. + +``` +set dpdk interface hqos pipe subport pipe + profile +``` + +To assign QoS scheduler instance to the specific thread, following command can +be used. + +``` +set dpdk interface hqos placement thread +``` + +The command below is used to set the packet fields required for classifying +the incoming packet. As a result of classification process, packet field +information will be mapped to 5 tuples (subport, pipe, traffic class, pipe, +color) and stored in packet mbuf. + +``` +set dpdk interface hqos pktfield id subport|pipe|tc offset + mask +``` + +The DSCP table entries used for identifying the traffic class and queue can be set using the command below; + +``` +set dpdk interface hqos tctbl entry tc queue +``` + + +#### Show Command + +The QoS Scheduler configuration can displayed using the command below. + +``` + vpp# show dpdk interface hqos TenGigabitEthernet2/0/0 + Thread: + Input SWQ size = 4096 packets + Enqueue burst size = 256 packets + Dequeue burst size = 220 packets + Packet field 0: slab position = 0, slab bitmask = 0x0000000000000000 (subport) + Packet field 1: slab position = 40, slab bitmask = 0x0000000fff000000 (pipe) + Packet field 2: slab position = 8, slab bitmask = 0x00000000000000fc (tc) + Packet field 2 tc translation table: ([Mapped Value Range]: tc/queue tc/queue ...) + [ 0 .. 15]: 0/0 0/1 0/2 0/3 1/0 1/1 1/2 1/3 2/0 2/1 2/2 2/3 3/0 3/1 3/2 3/3 + [16 .. 31]: 0/0 0/1 0/2 0/3 1/0 1/1 1/2 1/3 2/0 2/1 2/2 2/3 3/0 3/1 3/2 3/3 + [32 .. 47]: 0/0 0/1 0/2 0/3 1/0 1/1 1/2 1/3 2/0 2/1 2/2 2/3 3/0 3/1 3/2 3/3 + [48 .. 63]: 0/0 0/1 0/2 0/3 1/0 1/1 1/2 1/3 2/0 2/1 2/2 2/3 3/0 3/1 3/2 3/3 + Port: + Rate = 1250000000 bytes/second + MTU = 1514 bytes + Frame overhead = 24 bytes + Number of subports = 1 + Number of pipes per subport = 4096 + Packet queue size: TC0 = 64, TC1 = 64, TC2 = 64, TC3 = 64 packets + Number of pipe profiles = 1 + Subport 0: + Rate = 120000000 bytes/second + Token bucket size = 1000000 bytes + Traffic class rate: TC0 = 120000000, TC1 = 120000000, TC2 = 120000000, TC3 = 120000000 bytes/second + TC period = 10 milliseconds + Pipe profile 0: + Rate = 305175 bytes/second + Token bucket size = 1000000 bytes + Traffic class rate: TC0 = 305175, TC1 = 305175, TC2 = 305175, TC3 = 305175 bytes/second + TC period = 40 milliseconds + TC0 WRR weights: Q0 = 1, Q1 = 1, Q2 = 1, Q3 = 1 + TC1 WRR weights: Q0 = 1, Q1 = 1, Q2 = 1, Q3 = 1 + TC2 WRR weights: Q0 = 1, Q1 = 1, Q2 = 1, Q3 = 1 + TC3 WRR weights: Q0 = 1, Q1 = 1, Q2 = 1, Q3 = 1 +``` + +The QoS Scheduler placement over the logical cpu cores can be displayed using +below command. + +``` + vpp# show dpdk interface hqos placement + Thread 5 (vpp_hqos-threads_0 at lcore 5): + TenGigabitEthernet2/0/0 queue 0 + Thread 6 (vpp_hqos-threads_1 at lcore 6): + TenGigabitEthernet4/0/1 queue 0 +``` + + +### QoS Scheduler Binary APIs + +This section explains the available binary APIs for configuring QoS scheduler +parameters in run-time. + +The following API can be used to set the pipe profile of a pipe that belongs +to a given subport: + +``` +sw_interface_set_dpdk_hqos_pipe rx | sw_if_index + subport pipe profile +``` + +The data structures used for set the pipe profile parameter are as follows; + +``` + /** \\brief DPDK interface HQoS pipe profile set request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sw_if_index - the interface + @param subport - subport ID + @param pipe - pipe ID within its subport + @param profile - pipe profile ID + */ + define sw_interface_set_dpdk_hqos_pipe { + u32 client_index; + u32 context; + u32 sw_if_index; + u32 subport; + u32 pipe; + u32 profile; + }; + + /** \\brief DPDK interface HQoS pipe profile set reply + @param context - sender context, to match reply w/ request + @param retval - request return code + */ + define sw_interface_set_dpdk_hqos_pipe_reply { + u32 context; + i32 retval; + }; +``` + +The following API can be used to set the subport level parameters, for +example- token bucket rate (bytes per seconds), token bucket size (bytes), +traffic class rate (bytes per seconds) and tokens update period. + +``` +sw_interface_set_dpdk_hqos_subport rx | sw_if_index + subport [rate ] [bktsize ] + [tc0 ] [tc1 ] [tc2 ] [tc3 ] [period ] +``` + +The data structures used for set the subport level parameter are as follows; + +``` + /** \\brief DPDK interface HQoS subport parameters set request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sw_if_index - the interface + @param subport - subport ID + @param tb_rate - subport token bucket rate (measured in bytes/second) + @param tb_size - subport token bucket size (measured in credits) + @param tc_rate - subport traffic class 0 .. 3 rates (measured in bytes/second) + @param tc_period - enforcement period for rates (measured in milliseconds) + */ + define sw_interface_set_dpdk_hqos_subport { + u32 client_index; + u32 context; + u32 sw_if_index; + u32 subport; + u32 tb_rate; + u32 tb_size; + u32 tc_rate[4]; + u32 tc_period; + }; + + /** \\brief DPDK interface HQoS subport parameters set reply + @param context - sender context, to match reply w/ request + @param retval - request return code + */ + define sw_interface_set_dpdk_hqos_subport_reply { + u32 context; + i32 retval; + }; +``` + +The following API can be used set the DSCP table entry. The DSCP table have +64 entries to map the packet DSCP field onto traffic class and hqos input +queue. + +``` +sw_interface_set_dpdk_hqos_tctbl rx | sw_if_index + entry tc queue +``` + +The data structures used for setting DSCP table entries are given below. + +``` + /** \\brief DPDK interface HQoS tctbl entry set request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sw_if_index - the interface + @param entry - entry index ID + @param tc - traffic class (0 .. 3) + @param queue - traffic class queue (0 .. 3) + */ + define sw_interface_set_dpdk_hqos_tctbl { + u32 client_index; + u32 context; + u32 sw_if_index; + u32 entry; + u32 tc; + u32 queue; + }; + + /** \\brief DPDK interface HQoS tctbl entry set reply + @param context - sender context, to match reply w/ request + @param retval - request return code + */ + define sw_interface_set_dpdk_hqos_tctbl_reply { + u32 context; + i32 retval; + }; +``` diff --git a/src/plugins/dpdk/CMakeLists.txt b/src/plugins/dpdk/CMakeLists.txt index e0122d92814..af8c80d8fa3 100644 --- a/src/plugins/dpdk/CMakeLists.txt +++ b/src/plugins/dpdk/CMakeLists.txt @@ -118,8 +118,6 @@ add_vpp_plugin(dpdk buffer.c main.c thread.c -# api/dpdk_api.c -# api/dpdk_test.c device/cli.c device/common.c device/device.c @@ -127,7 +125,6 @@ add_vpp_plugin(dpdk device/format.c device/init.c device/node.c -# hqos/hqos.c ipsec/cli.c ipsec/crypto_node.c ipsec/esp_decrypt.c @@ -142,12 +139,6 @@ add_vpp_plugin(dpdk ipsec/esp_decrypt.c ipsec/esp_encrypt.c -# API_FILES -# api/dpdk.api - -# API_TEST_SOURCES -# api/dpdk_test.c - INSTALL_HEADERS device/dpdk.h ipsec/ipsec.h diff --git a/src/plugins/dpdk/api/dpdk.api b/src/plugins/dpdk/api/dpdk.api deleted file mode 100644 index 40bc7369af4..00000000000 --- a/src/plugins/dpdk/api/dpdk.api +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2015-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -option version = "1.0.0"; -import "vnet/interface_types.api"; - -/** \brief DPDK interface HQoS pipe profile set request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param sw_if_index - the interface - @param subport - subport ID - @param pipe - pipe ID within its subport - @param profile - pipe profile ID -*/ -autoreply define sw_interface_set_dpdk_hqos_pipe { - u32 client_index; - u32 context; - vl_api_interface_index_t sw_if_index; - u32 subport; - u32 pipe; - u32 profile; - option vat_help = "rx sw_if_index subport pipe profile "; -}; - -/** \brief DPDK interface HQoS subport parameters set request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param sw_if_index - the interface - @param subport - subport ID - @param tb_rate - subport token bucket rate (measured in bytes/second) - @param tb_size - subport token bucket size (measured in credits) - @param tc_rate - subport traffic class 0 .. 3 rates (measured in bytes/second) - @param tc_period - enforcement period for rates (measured in milliseconds) -*/ -autoreply define sw_interface_set_dpdk_hqos_subport { - u32 client_index; - u32 context; - vl_api_interface_index_t sw_if_index; - u32 subport; - u32 tb_rate; - u32 tb_size; - u32 tc_rate[4]; - u32 tc_period; - option vat_help = "rx sw_if_index subport [rate ] [bktsize ] [tc0 ] [tc1 ] [tc2 ] [tc3 ] [period ]\n"; -}; - -/** \brief DPDK interface HQoS tctbl entry set request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param sw_if_index - the interface - @param entry - entry index ID - @param tc - traffic class (0 .. 3) - @param queue - traffic class queue (0 .. 3) -*/ -autoreply define sw_interface_set_dpdk_hqos_tctbl { - u32 client_index; - u32 context; - vl_api_interface_index_t sw_if_index; - u32 entry; - u32 tc; - u32 queue; - option vat_help = "rx sw_if_index entry tc queue "; -}; - -/* - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ - diff --git a/src/plugins/dpdk/api/dpdk_api.c b/src/plugins/dpdk/api/dpdk_api.c deleted file mode 100755 index 8b22c650c82..00000000000 --- a/src/plugins/dpdk/api/dpdk_api.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (c) 2017 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -/* define message IDs */ -#include -#include - -#include - -static void - vl_api_sw_interface_set_dpdk_hqos_pipe_t_handler - (vl_api_sw_interface_set_dpdk_hqos_pipe_t * mp) -{ - vl_api_sw_interface_set_dpdk_hqos_pipe_reply_t *rmp; - int rv = 0; - - dpdk_main_t *dm = &dpdk_main; - dpdk_device_t *xd; - - u32 sw_if_index = ntohl (mp->sw_if_index); - u32 subport = ntohl (mp->subport); - u32 pipe = ntohl (mp->pipe); - u32 profile = ntohl (mp->profile); - vnet_hw_interface_t *hw; - - VALIDATE_SW_IF_INDEX (mp); - - /* hw_if & dpdk device */ - hw = vnet_get_sup_hw_interface (dm->vnet_main, sw_if_index); - - xd = vec_elt_at_index (dm->devices, hw->dev_instance); - - rv = rte_sched_pipe_config (xd->hqos_ht->hqos, subport, pipe, profile); - - BAD_SW_IF_INDEX_LABEL; - - REPLY_MACRO (VL_API_SW_INTERFACE_SET_DPDK_HQOS_PIPE_REPLY); -} - -static void *vl_api_sw_interface_set_dpdk_hqos_pipe_t_print - (vl_api_sw_interface_set_dpdk_hqos_pipe_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: sw_interface_set_dpdk_hqos_pipe "); - - s = format (s, "sw_if_index %u ", ntohl (mp->sw_if_index)); - - s = format (s, "subport %u pipe %u profile %u ", - ntohl (mp->subport), ntohl (mp->pipe), ntohl (mp->profile)); - - FINISH; -} - -static void - vl_api_sw_interface_set_dpdk_hqos_subport_t_handler - (vl_api_sw_interface_set_dpdk_hqos_subport_t * mp) -{ - vl_api_sw_interface_set_dpdk_hqos_subport_reply_t *rmp; - int rv = 0; - - dpdk_main_t *dm = &dpdk_main; - dpdk_device_t *xd; - struct rte_sched_subport_params p; - - u32 sw_if_index = ntohl (mp->sw_if_index); - u32 subport = ntohl (mp->subport); - p.tb_rate = ntohl (mp->tb_rate); - p.tb_size = ntohl (mp->tb_size); - p.tc_rate[0] = ntohl (mp->tc_rate[0]); - p.tc_rate[1] = ntohl (mp->tc_rate[1]); - p.tc_rate[2] = ntohl (mp->tc_rate[2]); - p.tc_rate[3] = ntohl (mp->tc_rate[3]); - p.tc_period = ntohl (mp->tc_period); - - vnet_hw_interface_t *hw; - - VALIDATE_SW_IF_INDEX (mp); - - /* hw_if & dpdk device */ - hw = vnet_get_sup_hw_interface (dm->vnet_main, sw_if_index); - - xd = vec_elt_at_index (dm->devices, hw->dev_instance); - - rv = rte_sched_subport_config (xd->hqos_ht->hqos, subport, &p); - - BAD_SW_IF_INDEX_LABEL; - - REPLY_MACRO (VL_API_SW_INTERFACE_SET_DPDK_HQOS_SUBPORT_REPLY); -} - -static void *vl_api_sw_interface_set_dpdk_hqos_subport_t_print - (vl_api_sw_interface_set_dpdk_hqos_subport_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: sw_interface_set_dpdk_hqos_subport "); - - s = format (s, "sw_if_index %u ", ntohl (mp->sw_if_index)); - - s = - format (s, - "subport %u rate %u bkt_size %u tc0 %u tc1 %u tc2 %u tc3 %u period %u", - ntohl (mp->subport), ntohl (mp->tb_rate), ntohl (mp->tb_size), - ntohl (mp->tc_rate[0]), ntohl (mp->tc_rate[1]), - ntohl (mp->tc_rate[2]), ntohl (mp->tc_rate[3]), - ntohl (mp->tc_period)); - - FINISH; -} - -static void - vl_api_sw_interface_set_dpdk_hqos_tctbl_t_handler - (vl_api_sw_interface_set_dpdk_hqos_tctbl_t * mp) -{ - vl_api_sw_interface_set_dpdk_hqos_tctbl_reply_t *rmp; - int rv = 0; - - dpdk_main_t *dm = &dpdk_main; - vlib_thread_main_t *tm = vlib_get_thread_main (); - dpdk_device_t *xd; - - u32 sw_if_index = ntohl (mp->sw_if_index); - u32 entry = ntohl (mp->entry); - u32 tc = ntohl (mp->tc); - u32 queue = ntohl (mp->queue); - u32 val, i; - - vnet_hw_interface_t *hw; - - VALIDATE_SW_IF_INDEX (mp); - - /* hw_if & dpdk device */ - hw = vnet_get_sup_hw_interface (dm->vnet_main, sw_if_index); - - xd = vec_elt_at_index (dm->devices, hw->dev_instance); - - if (tc >= RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE) - { - clib_warning ("invalid traffic class !!"); - rv = VNET_API_ERROR_INVALID_VALUE; - goto done; - } - if (queue >= RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS) - { - clib_warning ("invalid queue !!"); - rv = VNET_API_ERROR_INVALID_VALUE; - goto done; - } - - /* Detect the set of worker threads */ - uword *p = hash_get_mem (tm->thread_registrations_by_name, "workers"); - - if (p == 0) - { - clib_warning ("worker thread registration AWOL !!"); - rv = VNET_API_ERROR_INVALID_VALUE_2; - goto done; - } - - vlib_thread_registration_t *tr = (vlib_thread_registration_t *) p[0]; - int worker_thread_first = tr->first_index; - int worker_thread_count = tr->count; - - val = tc * RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS + queue; - for (i = 0; i < worker_thread_count; i++) - xd->hqos_wt[worker_thread_first + i].hqos_tc_table[entry] = val; - - BAD_SW_IF_INDEX_LABEL; -done: - - REPLY_MACRO (VL_API_SW_INTERFACE_SET_DPDK_HQOS_TCTBL_REPLY); -} - -static void *vl_api_sw_interface_set_dpdk_hqos_tctbl_t_print - (vl_api_sw_interface_set_dpdk_hqos_tctbl_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: sw_interface_set_dpdk_hqos_tctbl "); - - s = format (s, "sw_if_index %u ", ntohl (mp->sw_if_index)); - - s = format (s, "entry %u tc %u queue %u", - ntohl (mp->entry), ntohl (mp->tc), ntohl (mp->queue)); - - FINISH; -} - -#include -static clib_error_t * -dpdk_api_init (vlib_main_t * vm) -{ - dpdk_main_t *dm = &dpdk_main; - - /* Ask for a correctly-sized block of API message decode slots */ - dm->msg_id_base = setup_message_id_table (); - - return 0; -} - -/* *INDENT-OFF* */ -VLIB_INIT_FUNCTION (dpdk_api_init) = -{ - .runs_after = VLIB_INITS ("dpdk_init"), -/* *INDENT-OFF* */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/dpdk/api/dpdk_test.c b/src/plugins/dpdk/api/dpdk_test.c deleted file mode 100644 index 951082faaf9..00000000000 --- a/src/plugins/dpdk/api/dpdk_test.c +++ /dev/null @@ -1,285 +0,0 @@ - -/* - * dpdk_test.c - skeleton vpp-api-test plug-in - * - * Copyright (c) - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include - -uword unformat_sw_if_index (unformat_input_t * input, va_list * args); - -/* Declare message IDs */ -#include -#include - -typedef struct { - /* API message ID base */ - u16 msg_id_base; - vat_main_t *vat_main; -} dpdk_test_main_t; - -dpdk_test_main_t dpdk_test_main; - -/* M: construct, but don't yet send a message */ -#define M(T,t) \ -do { \ - vam->result_ready = 0; \ - mp = vl_msg_api_alloc(sizeof(*mp)); \ - clib_memset (mp, 0, sizeof (*mp)); \ - mp->_vl_msg_id = ntohs (VL_API_##T + dm->msg_id_base); \ - mp->client_index = vam->my_client_index; \ -} while(0); - -#define M2(T,t,n) \ -do { \ - vam->result_ready = 0; \ - mp = vl_msg_api_alloc(sizeof(*mp)+(n)); \ - clib_memset (mp, 0, sizeof (*mp)); \ - mp->_vl_msg_id = ntohs (VL_API_##T + dm->msg_id_base); \ - mp->client_index = vam->my_client_index; \ -} while(0); - -/* S: send a message */ -#define S (vl_msg_api_send_shmem (vam->vl_input_queue, (u8 *)&mp)) - -/* W: wait for results, with timeout */ -#define W \ -do { \ - timeout = vat_time_now (vam) + 1.0; \ - \ - while (vat_time_now (vam) < timeout) { \ - if (vam->result_ready == 1) { \ - return (vam->retval); \ - } \ - } \ - return -99; \ -} while(0); - -static int -api_sw_interface_set_dpdk_hqos_pipe (vat_main_t * vam) -{ - dpdk_test_main_t * dm = &dpdk_test_main; - unformat_input_t *i = vam->input; - vl_api_sw_interface_set_dpdk_hqos_pipe_t *mp; - f64 timeout; - u32 sw_if_index; - u8 sw_if_index_set = 0; - u32 subport; - u8 subport_set = 0; - u32 pipe; - u8 pipe_set = 0; - u32 profile; - u8 profile_set = 0; - - /* Parse args required to build the message */ - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "rx sw_if_index %u", &sw_if_index)) - sw_if_index_set = 1; - else if (unformat (i, "subport %u", &subport)) - subport_set = 1; - else if (unformat (i, "pipe %u", &pipe)) - pipe_set = 1; - else if (unformat (i, "profile %u", &profile)) - profile_set = 1; - else - break; - } - - if (sw_if_index_set == 0) - { - errmsg ("missing interface name or sw_if_index"); - return -99; - } - - if (subport_set == 0) - { - errmsg ("missing subport "); - return -99; - } - - if (pipe_set == 0) - { - errmsg ("missing pipe"); - return -99; - } - - if (profile_set == 0) - { - errmsg ("missing profile"); - return -99; - } - - M (SW_INTERFACE_SET_DPDK_HQOS_PIPE, sw_interface_set_dpdk_hqos_pipe); - - mp->sw_if_index = ntohl (sw_if_index); - mp->subport = ntohl (subport); - mp->pipe = ntohl (pipe); - mp->profile = ntohl (profile); - - - S; - W; - /* NOTREACHED */ - return 0; -} - -static int -api_sw_interface_set_dpdk_hqos_subport (vat_main_t * vam) -{ - dpdk_test_main_t * dm = &dpdk_test_main; - unformat_input_t *i = vam->input; - vl_api_sw_interface_set_dpdk_hqos_subport_t *mp; - f64 timeout; - u32 sw_if_index; - u8 sw_if_index_set = 0; - u32 subport; - u8 subport_set = 0; - u32 tb_rate = 1250000000; /* 10GbE */ - u32 tb_size = 1000000; - u32 tc_rate[] = { 1250000000, 1250000000, 1250000000, 1250000000 }; - u32 tc_period = 10; - - /* Parse args required to build the message */ - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "rx sw_if_index %u", &sw_if_index)) - sw_if_index_set = 1; - else if (unformat (i, "subport %u", &subport)) - subport_set = 1; - else if (unformat (i, "rate %u", &tb_rate)) - { - u32 tc_id; - - for (tc_id = 0; tc_id < (sizeof (tc_rate) / sizeof (tc_rate[0])); - tc_id++) - tc_rate[tc_id] = tb_rate; - } - else if (unformat (i, "bktsize %u", &tb_size)) - ; - else if (unformat (i, "tc0 %u", &tc_rate[0])) - ; - else if (unformat (i, "tc1 %u", &tc_rate[1])) - ; - else if (unformat (i, "tc2 %u", &tc_rate[2])) - ; - else if (unformat (i, "tc3 %u", &tc_rate[3])) - ; - else if (unformat (i, "period %u", &tc_period)) - ; - else - break; - } - - if (sw_if_index_set == 0) - { - errmsg ("missing interface name or sw_if_index"); - return -99; - } - - if (subport_set == 0) - { - errmsg ("missing subport "); - return -99; - } - - M (SW_INTERFACE_SET_DPDK_HQOS_SUBPORT, sw_interface_set_dpdk_hqos_subport); - - mp->sw_if_index = ntohl (sw_if_index); - mp->subport = ntohl (subport); - mp->tb_rate = ntohl (tb_rate); - mp->tb_size = ntohl (tb_size); - mp->tc_rate[0] = ntohl (tc_rate[0]); - mp->tc_rate[1] = ntohl (tc_rate[1]); - mp->tc_rate[2] = ntohl (tc_rate[2]); - mp->tc_rate[3] = ntohl (tc_rate[3]); - mp->tc_period = ntohl (tc_period); - - S; - W; - /* NOTREACHED */ - return 0; -} - -static int -api_sw_interface_set_dpdk_hqos_tctbl (vat_main_t * vam) -{ - dpdk_test_main_t * dm = &dpdk_test_main; - unformat_input_t *i = vam->input; - vl_api_sw_interface_set_dpdk_hqos_tctbl_t *mp; - f64 timeout; - u32 sw_if_index; - u8 sw_if_index_set = 0; - u8 entry_set = 0; - u8 tc_set = 0; - u8 queue_set = 0; - u32 entry, tc, queue; - - /* Parse args required to build the message */ - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "rx sw_if_index %u", &sw_if_index)) - sw_if_index_set = 1; - else if (unformat (i, "entry %d", &entry)) - entry_set = 1; - else if (unformat (i, "tc %d", &tc)) - tc_set = 1; - else if (unformat (i, "queue %d", &queue)) - queue_set = 1; - else - break; - } - - if (sw_if_index_set == 0) - { - errmsg ("missing interface name or sw_if_index"); - return -99; - } - - if (entry_set == 0) - { - errmsg ("missing entry "); - return -99; - } - - if (tc_set == 0) - { - errmsg ("missing traffic class "); - return -99; - } - - if (queue_set == 0) - { - errmsg ("missing queue "); - return -99; - } - - M (SW_INTERFACE_SET_DPDK_HQOS_TCTBL, sw_interface_set_dpdk_hqos_tctbl); - - mp->sw_if_index = ntohl (sw_if_index); - mp->entry = ntohl (entry); - mp->tc = ntohl (tc); - mp->queue = ntohl (queue); - - S; - W; - /* NOTREACHED */ - return 0; -} - -#include diff --git a/src/plugins/dpdk/device/cli.c b/src/plugins/dpdk/device/cli.c index 416d973604f..0f771c6ba77 100644 --- a/src/plugins/dpdk/device/cli.c +++ b/src/plugins/dpdk/device/cli.c @@ -40,61 +40,6 @@ */ -#if 0 -static clib_error_t * -get_hqos (u32 hw_if_index, u32 subport_id, dpdk_device_t ** xd, - dpdk_device_config_t ** devconf) -{ - dpdk_main_t *dm = &dpdk_main; - vnet_hw_interface_t *hw; - struct rte_eth_dev_info dev_info; - struct rte_pci_device *pci_dev; - uword *p = 0; - clib_error_t *error = NULL; - - - if (hw_if_index == (u32) ~ 0) - { - error = clib_error_return (0, "please specify valid interface name"); - goto done; - } - - if (subport_id != 0) - { - error = clib_error_return (0, "Invalid subport"); - goto done; - } - - hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); - *xd = vec_elt_at_index (dm->devices, hw->dev_instance); - - rte_eth_dev_info_get ((*xd)->port_id, &dev_info); - - pci_dev = dpdk_get_pci_device (&dev_info); - - if (pci_dev) - { - vlib_pci_addr_t pci_addr; - - pci_addr.domain = pci_dev->addr.domain; - pci_addr.bus = pci_dev->addr.bus; - pci_addr.slot = pci_dev->addr.devid; - pci_addr.function = pci_dev->addr.function; - - p = - hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32); - } - - if (p) - (*devconf) = pool_elt_at_index (dm->conf->dev_confs, p[0]); - else - (*devconf) = &dm->conf->default_devconf; - -done: - return error; -} -#endif - static clib_error_t * show_dpdk_buffer (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) @@ -408,1308 +353,6 @@ VLIB_CLI_COMMAND (cmd_set_dpdk_if_desc,static) = { }; /* *INDENT-ON* */ -#if 0 -static int -dpdk_device_queue_sort (void *a1, void *a2) -{ - dpdk_device_and_queue_t *dq1 = a1; - dpdk_device_and_queue_t *dq2 = a2; - - if (dq1->device > dq2->device) - return 1; - else if (dq1->device < dq2->device) - return -1; - else if (dq1->queue_id > dq2->queue_id) - return 1; - else if (dq1->queue_id < dq2->queue_id) - return -1; - else - return 0; -} - - -static clib_error_t * -show_dpdk_if_hqos_placement (vlib_main_t * vm, unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - vlib_thread_main_t *tm = vlib_get_thread_main (); - dpdk_main_t *dm = &dpdk_main; - dpdk_device_and_queue_t *dq; - int cpu; - - if (tm->n_vlib_mains == 1) - vlib_cli_output (vm, "All interfaces are handled by main thread"); - - for (cpu = 0; cpu < vec_len (dm->devices_by_hqos_cpu); cpu++) - { - if (cpu >= dm->hqos_cpu_first_index && - cpu < (dm->hqos_cpu_first_index + dm->hqos_cpu_count)) - vlib_cli_output (vm, "Thread %u (%s at lcore %u):", cpu, - vlib_worker_threads[cpu].name, - vlib_worker_threads[cpu].cpu_id); - - vec_foreach (dq, dm->devices_by_hqos_cpu[cpu]) - { - u32 hw_if_index = dm->devices[dq->device].hw_if_index; - vnet_hw_interface_t *hi = - vnet_get_hw_interface (dm->vnet_main, hw_if_index); - vlib_cli_output (vm, " %v queue %u", hi->name, dq->queue_id); - } - } - return 0; -} - -/*? - * This command is used to display the thread and core each - * DPDK output interface and HQoS queue is assigned too. - * - * @cliexpar - * Example of how to display the DPDK output interface and HQoS queue placement: - * @cliexstart{show dpdk interface hqos placement} - * Thread 1 (vpp_hqos-threads_0 at lcore 3): - * GigabitEthernet0/8/0 queue 0 - * Thread 2 (vpp_hqos-threads_1 at lcore 4): - * GigabitEthernet0/9/0 queue 0 - * @cliexend -?*/ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (cmd_show_dpdk_if_hqos_placement, static) = { - .path = "show dpdk interface hqos placement", - .short_help = "show dpdk interface hqos placement", - .function = show_dpdk_if_hqos_placement, -}; -/* *INDENT-ON* */ - -static clib_error_t * -set_dpdk_if_hqos_placement (vlib_main_t * vm, unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - dpdk_main_t *dm = &dpdk_main; - dpdk_device_and_queue_t *dq; - vnet_hw_interface_t *hw; - dpdk_device_t *xd; - u32 hw_if_index = (u32) ~ 0; - u32 cpu = (u32) ~ 0; - int i; - clib_error_t *error = NULL; - - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat - (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main, - &hw_if_index)) - ; - else if (unformat (line_input, "thread %d", &cpu)) - ; - else - { - error = clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); - goto done; - } - } - - if (hw_if_index == (u32) ~ 0) - return clib_error_return (0, "please specify valid interface name"); - - if (cpu < dm->hqos_cpu_first_index || - cpu >= (dm->hqos_cpu_first_index + dm->hqos_cpu_count)) - { - error = clib_error_return (0, "please specify valid thread id"); - goto done; - } - - hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); - xd = vec_elt_at_index (dm->devices, hw->dev_instance); - - for (i = 0; i < vec_len (dm->devices_by_hqos_cpu); i++) - { - vec_foreach (dq, dm->devices_by_hqos_cpu[i]) - { - if (hw_if_index == dm->devices[dq->device].hw_if_index) - { - if (cpu == i) /* nothing to do */ - goto done; - - vec_del1 (dm->devices_by_hqos_cpu[i], - dq - dm->devices_by_hqos_cpu[i]); - vec_add2 (dm->devices_by_hqos_cpu[cpu], dq, 1); - dq->queue_id = 0; - dq->device = xd->device_index; - - vec_sort_with_function (dm->devices_by_hqos_cpu[i], - dpdk_device_queue_sort); - - vec_sort_with_function (dm->devices_by_hqos_cpu[cpu], - dpdk_device_queue_sort); - - goto done; - } - } - } - - error = clib_error_return (0, "not found"); - -done: - unformat_free (line_input); - - return error; -} - -/*? - * This command is used to assign a given DPDK output interface and - * HQoS queue to a different thread. This will not create a thread, - * so the thread must already exist. Use '/etc/vpp/startup.conf' - * for the initial thread creation. See @ref qos_doc for more details. - * - * @cliexpar - * Example of how to display the DPDK output interface and HQoS queue placement: - * @cliexstart{show dpdk interface hqos placement} - * Thread 1 (vpp_hqos-threads_0 at lcore 3): - * GigabitEthernet0/8/0 queue 0 - * Thread 2 (vpp_hqos-threads_1 at lcore 4): - * GigabitEthernet0/9/0 queue 0 - * @cliexend - * Example of how to assign a DPDK output interface and HQoS queue to a thread: - * @cliexcmd{set dpdk interface hqos placement GigabitEthernet0/8/0 thread 2} -?*/ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_placement, static) = { - .path = "set dpdk interface hqos placement", - .short_help = "set dpdk interface hqos placement thread ", - .function = set_dpdk_if_hqos_placement, -}; -/* *INDENT-ON* */ - -static clib_error_t * -set_dpdk_if_hqos_pipe (vlib_main_t * vm, unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - dpdk_main_t *dm = &dpdk_main; - vnet_hw_interface_t *hw; - dpdk_device_t *xd; - u32 hw_if_index = (u32) ~ 0; - u32 subport_id = (u32) ~ 0; - u32 pipe_id = (u32) ~ 0; - u32 profile_id = (u32) ~ 0; - int rv; - clib_error_t *error = NULL; - - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat - (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main, - &hw_if_index)) - ; - else if (unformat (line_input, "subport %d", &subport_id)) - ; - else if (unformat (line_input, "pipe %d", &pipe_id)) - ; - else if (unformat (line_input, "profile %d", &profile_id)) - ; - else - { - error = clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); - goto done; - } - } - - if (hw_if_index == (u32) ~ 0) - { - error = clib_error_return (0, "please specify valid interface name"); - goto done; - } - - hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); - xd = vec_elt_at_index (dm->devices, hw->dev_instance); - - rv = - rte_sched_pipe_config (xd->hqos_ht->hqos, subport_id, pipe_id, - profile_id); - if (rv) - { - error = clib_error_return (0, "pipe configuration failed"); - goto done; - } - -done: - unformat_free (line_input); - - return error; -} - -/*? - * This command is used to change the profile associate with a HQoS pipe. The - * '' is zero based. Use the command - * 'show dpdk interface hqos' to display the content of each profile. - * See @ref qos_doc for more details. - * - * @note - * Currently there is not an API to create a new HQoS pipe profile. One is - * created by default in the code (search for 'hqos_pipe_params_default''). - * Additional profiles can be created in code and code recompiled. Then use this - * command to assign it. - * - * @cliexpar - * Example of how to assign a new profile to a HQoS pipe: - * @cliexcmd{set dpdk interface hqos pipe GigabitEthernet0/8/0 subport 0 pipe 2 profile 1} -?*/ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_pipe, static) = -{ - .path = "set dpdk interface hqos pipe", - .short_help = "set dpdk interface hqos pipe subport pipe " - "profile ", - .function = set_dpdk_if_hqos_pipe, -}; -/* *INDENT-ON* */ - -static clib_error_t * -set_dpdk_if_hqos_subport (vlib_main_t * vm, unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - dpdk_main_t *dm = &dpdk_main; - dpdk_device_t *xd = NULL; - u32 hw_if_index = (u32) ~ 0; - u32 subport_id = (u32) ~ 0; - struct rte_sched_subport_params p; - int rv; - clib_error_t *error = NULL; - u32 tb_rate = (u32) ~ 0; - u32 tb_size = (u32) ~ 0; - u32 tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE] = - { (u32) ~ 0, (u32) ~ 0, (u32) ~ 0, (u32) ~ 0 }; - u32 tc_period = (u32) ~ 0; - dpdk_device_config_t *devconf = NULL; - - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat - (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main, - &hw_if_index)) - ; - else if (unformat (line_input, "subport %d", &subport_id)) - ; - else if (unformat (line_input, "rate %d", &tb_rate)) - ; - else if (unformat (line_input, "bktsize %d", &tb_size)) - ; - else if (unformat (line_input, "tc0 %d", &tc_rate[0])) - ; - else if (unformat (line_input, "tc1 %d", &tc_rate[1])) - ; - else if (unformat (line_input, "tc2 %d", &tc_rate[2])) - ; - else if (unformat (line_input, "tc3 %d", &tc_rate[3])) - ; - else if (unformat (line_input, "period %d", &tc_period)) - ; - else - { - error = clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); - goto done; - } - } - - error = get_hqos (hw_if_index, subport_id, &xd, &devconf); - - if (error == NULL) - { - /* Copy the current values over to local structure. */ - memcpy (&p, &devconf->hqos.subport[subport_id], sizeof (p)); - - /* Update local structure with input values. */ - if (tb_rate != (u32) ~ 0) - { - p.tb_rate = tb_rate; - p.tc_rate[0] = tb_rate; - p.tc_rate[1] = tb_rate; - p.tc_rate[2] = tb_rate; - p.tc_rate[3] = tb_rate; - } - if (tb_size != (u32) ~ 0) - { - p.tb_size = tb_size; - } - if (tc_rate[0] != (u32) ~ 0) - { - p.tc_rate[0] = tc_rate[0]; - } - if (tc_rate[1] != (u32) ~ 0) - { - p.tc_rate[1] = tc_rate[1]; - } - if (tc_rate[2] != (u32) ~ 0) - { - p.tc_rate[2] = tc_rate[2]; - } - if (tc_rate[3] != (u32) ~ 0) - { - p.tc_rate[3] = tc_rate[3]; - } - if (tc_period != (u32) ~ 0) - { - p.tc_period = tc_period; - } - - /* Apply changes. */ - rv = rte_sched_subport_config (xd->hqos_ht->hqos, subport_id, &p); - if (rv) - { - error = clib_error_return (0, "subport configuration failed"); - goto done; - } - else - { - /* Successfully applied, so save of the input values. */ - memcpy (&devconf->hqos.subport[subport_id], &p, sizeof (p)); - } - } - -done: - unformat_free (line_input); - - return error; -} - -/*? - * This command is used to set the subport level parameters such as token - * bucket rate (bytes per seconds), token bucket size (bytes), traffic class - * rates (bytes per seconds) and token update period (Milliseconds). - * - * By default, the 'rate' is set to 1250000000 bytes/second (10GbE - * rate) and each of the four traffic classes is set to 100% of the port rate. - * If the 'rate' is updated by this command, all four traffic classes - * are assigned the same value. Each of the four traffic classes can be updated - * individually. - * - * @cliexpar - * Example of how modify the subport attributes for a 1GbE link: - * @cliexcmd{set dpdk interface hqos subport GigabitEthernet0/8/0 subport 0 rate 125000000} -?*/ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_subport, static) = { - .path = "set dpdk interface hqos subport", - .short_help = "set dpdk interface hqos subport subport " - "[rate ] [bktsize ] [tc0 ] [tc1 ] [tc2 ] [tc3 ] " - "[period ]", - .function = set_dpdk_if_hqos_subport, -}; -/* *INDENT-ON* */ - -static clib_error_t * -set_dpdk_if_hqos_tctbl (vlib_main_t * vm, unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - vlib_thread_main_t *tm = vlib_get_thread_main (); - dpdk_main_t *dm = &dpdk_main; - vnet_hw_interface_t *hw; - dpdk_device_t *xd; - u32 hw_if_index = (u32) ~ 0; - u32 tc = (u32) ~ 0; - u32 queue = (u32) ~ 0; - u32 entry = (u32) ~ 0; - u32 val, i; - clib_error_t *error = NULL; - - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat - (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main, - &hw_if_index)) - ; - else if (unformat (line_input, "entry %d", &entry)) - ; - else if (unformat (line_input, "tc %d", &tc)) - ; - else if (unformat (line_input, "queue %d", &queue)) - ; - else - { - error = clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); - goto done; - } - } - - if (hw_if_index == (u32) ~ 0) - { - error = clib_error_return (0, "please specify valid interface name"); - goto done; - } - if (entry >= 64) - { - error = clib_error_return (0, "invalid entry"); - goto done; - } - if (tc >= RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE) - { - error = clib_error_return (0, "invalid traffic class"); - goto done; - } - if (queue >= RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS) - { - error = clib_error_return (0, "invalid traffic class queue"); - goto done; - } - - hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); - xd = vec_elt_at_index (dm->devices, hw->dev_instance); - - /* Detect the set of worker threads */ - uword *p = hash_get_mem (tm->thread_registrations_by_name, "workers"); - /* Should never happen, shut up Coverity warning */ - if (p == 0) - { - error = clib_error_return (0, "no worker registrations?"); - goto done; - } - - vlib_thread_registration_t *tr = (vlib_thread_registration_t *) p[0]; - int worker_thread_first = tr->first_index; - int worker_thread_count = tr->count; - - val = tc * RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS + queue; - for (i = 0; i < worker_thread_count; i++) - xd->hqos_wt[worker_thread_first + i].hqos_tc_table[entry] = val; - -done: - unformat_free (line_input); - - return error; -} - -/*? - * This command is used to set the traffic class translation table. The - * traffic class translation table is used to map 64 values (0-63) to one of - * four traffic class and one of four HQoS input queue. Use the 'show - * dpdk interface hqos' command to display the traffic class translation - * table. See @ref qos_doc for more details. - * - * This command has the following parameters: - * - * - - Used to specify the output interface. - * - * - entry - Mapped value (0-63) to assign traffic class and queue to. - * - * - tc - Traffic class (0-3) to be used by the provided mapped value. - * - * - queue - HQoS input queue (0-3) to be used by the provided mapped value. - * - * @cliexpar - * Example of how modify the traffic class translation table: - * @cliexcmd{set dpdk interface hqos tctbl GigabitEthernet0/8/0 entry 16 tc 2 queue 2} -?*/ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_tctbl, static) = { - .path = "set dpdk interface hqos tctbl", - .short_help = "set dpdk interface hqos tctbl entry tc queue ", - .function = set_dpdk_if_hqos_tctbl, -}; -/* *INDENT-ON* */ - -static clib_error_t * -set_dpdk_if_hqos_pktfield (vlib_main_t * vm, unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - vlib_thread_main_t *tm = vlib_get_thread_main (); - dpdk_main_t *dm = &dpdk_main; - clib_error_t *error = NULL; - - /* Device specific data */ - struct rte_eth_dev_info dev_info; - struct rte_pci_device *pci_dev; - dpdk_device_config_t *devconf = 0; - vnet_hw_interface_t *hw; - dpdk_device_t *xd; - u32 hw_if_index = (u32) ~ 0; - - /* Detect the set of worker threads */ - uword *p = hash_get_mem (tm->thread_registrations_by_name, "workers"); - /* Should never happen, shut up Coverity warning */ - if (p == 0) - return clib_error_return (0, "no worker registrations?"); - - vlib_thread_registration_t *tr = (vlib_thread_registration_t *) p[0]; - int worker_thread_first = tr->first_index; - int worker_thread_count = tr->count; - - /* Packet field configuration */ - u64 mask = (u64) ~ 0; - u32 id = (u32) ~ 0; - u32 offset = (u32) ~ 0; - - /* HQoS params */ - u32 n_subports_per_port, n_pipes_per_subport, tctbl_size; - - u32 i; - - /* Parse input arguments */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat - (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main, - &hw_if_index)) - ; - else if (unformat (line_input, "id subport")) - id = 0; - else if (unformat (line_input, "id pipe")) - id = 1; - else if (unformat (line_input, "id tc")) - id = 2; - else if (unformat (line_input, "id %d", &id)) - ; - else if (unformat (line_input, "offset %d", &offset)) - ; - else if (unformat (line_input, "mask %llx", &mask)) - ; - else - { - error = clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); - goto done; - } - } - - /* Get interface */ - if (hw_if_index == (u32) ~ 0) - { - error = clib_error_return (0, "please specify valid interface name"); - goto done; - } - - hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); - xd = vec_elt_at_index (dm->devices, hw->dev_instance); - - rte_eth_dev_info_get (xd->port_id, &dev_info); - - pci_dev = dpdk_get_pci_device (&dev_info); - - if (pci_dev) - { - vlib_pci_addr_t pci_addr; - - pci_addr.domain = pci_dev->addr.domain; - pci_addr.bus = pci_dev->addr.bus; - pci_addr.slot = pci_dev->addr.devid; - pci_addr.function = pci_dev->addr.function; - - p = - hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32); - } - - if (p) - devconf = pool_elt_at_index (dm->conf->dev_confs, p[0]); - else - devconf = &dm->conf->default_devconf; - - if (devconf->hqos_enabled == 0) - { - vlib_cli_output (vm, "HQoS disabled for this interface"); - goto done; - } - - n_subports_per_port = devconf->hqos.port.n_subports_per_port; - n_pipes_per_subport = devconf->hqos.port.n_pipes_per_subport; - tctbl_size = RTE_DIM (devconf->hqos.tc_table); - - /* Validate packet field configuration: id, offset and mask */ - if (id >= 3) - { - error = clib_error_return (0, "invalid packet field id"); - goto done; - } - - switch (id) - { - case 0: - if (dpdk_hqos_validate_mask (mask, n_subports_per_port) != 0) - { - error = clib_error_return (0, "invalid subport ID mask " - "(n_subports_per_port = %u)", - n_subports_per_port); - goto done; - } - break; - case 1: - if (dpdk_hqos_validate_mask (mask, n_pipes_per_subport) != 0) - { - error = clib_error_return (0, "invalid pipe ID mask " - "(n_pipes_per_subport = %u)", - n_pipes_per_subport); - goto done; - } - break; - case 2: - default: - if (dpdk_hqos_validate_mask (mask, tctbl_size) != 0) - { - error = clib_error_return (0, "invalid TC table index mask " - "(TC table size = %u)", tctbl_size); - goto done; - } - } - - /* Propagate packet field configuration to all workers */ - for (i = 0; i < worker_thread_count; i++) - switch (id) - { - case 0: - xd->hqos_wt[worker_thread_first + i].hqos_field0_slabpos = offset; - xd->hqos_wt[worker_thread_first + i].hqos_field0_slabmask = mask; - xd->hqos_wt[worker_thread_first + i].hqos_field0_slabshr = - count_trailing_zeros (mask); - break; - case 1: - xd->hqos_wt[worker_thread_first + i].hqos_field1_slabpos = offset; - xd->hqos_wt[worker_thread_first + i].hqos_field1_slabmask = mask; - xd->hqos_wt[worker_thread_first + i].hqos_field1_slabshr = - count_trailing_zeros (mask); - break; - case 2: - default: - xd->hqos_wt[worker_thread_first + i].hqos_field2_slabpos = offset; - xd->hqos_wt[worker_thread_first + i].hqos_field2_slabmask = mask; - xd->hqos_wt[worker_thread_first + i].hqos_field2_slabshr = - count_trailing_zeros (mask); - } - -done: - unformat_free (line_input); - - return error; -} - -/*? - * This command is used to set the packet fields required for classifying the - * incoming packet. As a result of classification process, packet field - * information will be mapped to 5 tuples (subport, pipe, traffic class, pipe, - * color) and stored in packet mbuf. - * - * This command has the following parameters: - * - * - - Used to specify the output interface. - * - * - id subport|pipe|tc - Classification occurs across three fields. - * This parameter indicates which of the three masks are being configured. Legacy - * code used 0-2 to represent these three fields, so 0-2 is still accepted. - * - subport|0 - Currently only one subport is supported, so only - * an empty mask is supported for the subport classification. - * - pipe|1 - Currently, 4096 pipes per subport are supported, so a - * 12-bit mask should be configure to map to the 0-4095 pipes. - * - tc|2 - The translation table (see 'set dpdk interface hqos - * tctbl' command) maps each value (0-63) into one of the 4 traffic classes - * per pipe. A 6-bit mask should be configure to map this field to a traffic class. - * - * - offset - Offset in the packet to apply the 64-bit mask for classification. - * The offset should be on an 8-byte boundary (0,8,16,24..). - * - * - mask - 64-bit mask to apply to packet at the given 'offset'. - * Bits must be contiguous and should not include '0x'. - * - * The default values for the 'pktfield' assumes Ethernet/IPv4/UDP packets with - * no VLAN. Adjust based on expected packet format and desired classification field. - * - 'subport' is always empty (offset 0 mask 0000000000000000) - * - By default, 'pipe' maps to the UDP payload bits 12 .. 23 (offset 40 - * mask 0000000fff000000) - * - By default, 'tc' maps to the DSCP field in IP header (offset 48 mask - * 00000000000000fc) - * - * @cliexpar - * Example of how modify the 'pipe' classification filter to match VLAN: - * @cliexcmd{set dpdk interface hqos pktfield GigabitEthernet0/8/0 id pipe offset 8 mask 0000000000000FFF} -?*/ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_pktfield, static) = { - .path = "set dpdk interface hqos pktfield", - .short_help = "set dpdk interface hqos pktfield id subport|pipe|tc offset " - "mask ", - .function = set_dpdk_if_hqos_pktfield, -}; -/* *INDENT-ON* */ - -static clib_error_t * -show_dpdk_if_hqos (vlib_main_t * vm, unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - vlib_thread_main_t *tm = vlib_get_thread_main (); - dpdk_main_t *dm = &dpdk_main; - vnet_hw_interface_t *hw; - dpdk_device_t *xd; - dpdk_device_config_hqos_t *cfg; - dpdk_device_hqos_per_hqos_thread_t *ht; - dpdk_device_hqos_per_worker_thread_t *wk; - u32 *tctbl; - u32 hw_if_index = (u32) ~ 0; - u32 profile_id, subport_id, i; - struct rte_eth_dev_info dev_info; - struct rte_pci_device *pci_dev; - dpdk_device_config_t *devconf = 0; - vlib_thread_registration_t *tr; - uword *p = 0; - clib_error_t *error = NULL; - - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat - (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main, - &hw_if_index)) - ; - else - { - error = clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); - goto done; - } - } - - if (hw_if_index == (u32) ~ 0) - { - error = clib_error_return (0, "please specify interface name!!"); - goto done; - } - - hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); - xd = vec_elt_at_index (dm->devices, hw->dev_instance); - - rte_eth_dev_info_get (xd->port_id, &dev_info); - - pci_dev = dpdk_get_pci_device (&dev_info); - - if (pci_dev) - { - vlib_pci_addr_t pci_addr; - - pci_addr.domain = pci_dev->addr.domain; - pci_addr.bus = pci_dev->addr.bus; - pci_addr.slot = pci_dev->addr.devid; - pci_addr.function = pci_dev->addr.function; - - p = - hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32); - } - - if (p) - devconf = pool_elt_at_index (dm->conf->dev_confs, p[0]); - else - devconf = &dm->conf->default_devconf; - - if (devconf->hqos_enabled == 0) - { - vlib_cli_output (vm, "HQoS disabled for this interface"); - goto done; - } - - /* Detect the set of worker threads */ - p = hash_get_mem (tm->thread_registrations_by_name, "workers"); - - /* Should never happen, shut up Coverity warning */ - if (p == 0) - { - error = clib_error_return (0, "no worker registrations?"); - goto done; - } - - tr = (vlib_thread_registration_t *) p[0]; - - cfg = &devconf->hqos; - ht = xd->hqos_ht; - wk = &xd->hqos_wt[tr->first_index]; - tctbl = wk->hqos_tc_table; - - vlib_cli_output (vm, " Thread:"); - vlib_cli_output (vm, " Input SWQ size = %u packets", cfg->swq_size); - vlib_cli_output (vm, " Enqueue burst size = %u packets", - ht->hqos_burst_enq); - vlib_cli_output (vm, " Dequeue burst size = %u packets", - ht->hqos_burst_deq); - - vlib_cli_output (vm, - " Packet field 0: slab position = %4u, slab bitmask = 0x%016llx (subport)", - wk->hqos_field0_slabpos, wk->hqos_field0_slabmask); - vlib_cli_output (vm, - " Packet field 1: slab position = %4u, slab bitmask = 0x%016llx (pipe)", - wk->hqos_field1_slabpos, wk->hqos_field1_slabmask); - vlib_cli_output (vm, - " Packet field 2: slab position = %4u, slab bitmask = 0x%016llx (tc)", - wk->hqos_field2_slabpos, wk->hqos_field2_slabmask); - vlib_cli_output (vm, - " Packet field 2 tc translation table: ([Mapped Value Range]: tc/queue tc/queue ...)"); - vlib_cli_output (vm, - " [ 0 .. 15]: " - "%u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u", - tctbl[0] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[0] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[1] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[1] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[2] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[2] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[3] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[3] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[4] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[4] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[5] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[5] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[6] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[6] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[7] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[7] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[8] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[8] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[9] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[9] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[10] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[10] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[11] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[11] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[12] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[12] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[13] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[13] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[14] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[14] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[15] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[15] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS); - vlib_cli_output (vm, - " [16 .. 31]: " - "%u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u", - tctbl[16] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[16] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[17] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[17] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[18] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[18] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[19] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[19] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[20] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[20] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[21] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[21] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[22] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[22] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[23] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[23] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[24] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[24] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[25] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[25] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[26] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[26] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[27] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[27] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[28] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[28] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[29] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[29] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[30] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[30] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[31] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[31] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS); - vlib_cli_output (vm, - " [32 .. 47]: " - "%u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u", - tctbl[32] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[32] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[33] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[33] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[34] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[34] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[35] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[35] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[36] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[36] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[37] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[37] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[38] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[38] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[39] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[39] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[40] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[40] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[41] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[41] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[42] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[42] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[43] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[43] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[44] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[44] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[45] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[45] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[46] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[46] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[47] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[47] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS); - vlib_cli_output (vm, - " [48 .. 63]: " - "%u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u", - tctbl[48] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[48] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[49] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[49] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[50] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[50] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[51] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[51] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[52] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[52] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[53] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[53] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[54] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[54] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[55] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[55] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[56] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[56] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[57] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[57] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[58] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[58] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[59] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[59] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[60] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[60] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[61] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[61] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[62] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[62] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[63] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS, - tctbl[63] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS); - vlib_cli_output (vm, " Port:"); - vlib_cli_output (vm, " Rate = %u bytes/second", cfg->port.rate); - vlib_cli_output (vm, " MTU = %u bytes", cfg->port.mtu); - vlib_cli_output (vm, " Frame overhead = %u bytes", - cfg->port.frame_overhead); - vlib_cli_output (vm, " Number of subports = %u", - cfg->port.n_subports_per_port); - vlib_cli_output (vm, " Number of pipes per subport = %u", - cfg->port.n_pipes_per_subport); - vlib_cli_output (vm, - " Packet queue size: TC0 = %u, TC1 = %u, TC2 = %u, TC3 = %u packets", - cfg->port.qsize[0], cfg->port.qsize[1], cfg->port.qsize[2], - cfg->port.qsize[3]); - vlib_cli_output (vm, " Number of pipe profiles = %u", - cfg->port.n_pipe_profiles); - - for (subport_id = 0; subport_id < vec_len (cfg->subport); subport_id++) - { - vlib_cli_output (vm, " Subport %u:", subport_id); - vlib_cli_output (vm, " Rate = %u bytes/second", - cfg->subport[subport_id].tb_rate); - vlib_cli_output (vm, " Token bucket size = %u bytes", - cfg->subport[subport_id].tb_size); - vlib_cli_output (vm, - " Traffic class rate: TC0 = %u, TC1 = %u, TC2 = %u, TC3 = %u bytes/second", - cfg->subport[subport_id].tc_rate[0], - cfg->subport[subport_id].tc_rate[1], - cfg->subport[subport_id].tc_rate[2], - cfg->subport[subport_id].tc_rate[3]); - vlib_cli_output (vm, " TC period = %u milliseconds", - cfg->subport[subport_id].tc_period); - } - - for (profile_id = 0; profile_id < vec_len (cfg->pipe); profile_id++) - { - vlib_cli_output (vm, " Pipe profile %u:", profile_id); - vlib_cli_output (vm, " Rate = %u bytes/second", - cfg->pipe[profile_id].tb_rate); - vlib_cli_output (vm, " Token bucket size = %u bytes", - cfg->pipe[profile_id].tb_size); - vlib_cli_output (vm, - " Traffic class rate: TC0 = %u, TC1 = %u, TC2 = %u, TC3 = %u bytes/second", - cfg->pipe[profile_id].tc_rate[0], - cfg->pipe[profile_id].tc_rate[1], - cfg->pipe[profile_id].tc_rate[2], - cfg->pipe[profile_id].tc_rate[3]); - vlib_cli_output (vm, " TC period = %u milliseconds", - cfg->pipe[profile_id].tc_period); -#ifdef RTE_SCHED_SUBPORT_TC_OV - vlib_cli_output (vm, " TC3 oversubscription_weight = %u", - cfg->pipe[profile_id].tc_ov_weight); -#endif - - for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) - { - vlib_cli_output (vm, - " TC%u WRR weights: Q0 = %u, Q1 = %u, Q2 = %u, Q3 = %u", - i, cfg->pipe[profile_id].wrr_weights[i * 4], - cfg->pipe[profile_id].wrr_weights[i * 4 + 1], - cfg->pipe[profile_id].wrr_weights[i * 4 + 2], - cfg->pipe[profile_id].wrr_weights[i * 4 + 3]); - } - } - -#ifdef RTE_SCHED_RED - vlib_cli_output (vm, " Weighted Random Early Detection (WRED):"); - for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) - { - vlib_cli_output (vm, " TC%u min: G = %u, Y = %u, R = %u", i, - cfg->port.red_params[i][e_RTE_METER_GREEN].min_th, - cfg->port.red_params[i][e_RTE_METER_YELLOW].min_th, - cfg->port.red_params[i][e_RTE_METER_RED].min_th); - - vlib_cli_output (vm, " TC%u max: G = %u, Y = %u, R = %u", i, - cfg->port.red_params[i][e_RTE_METER_GREEN].max_th, - cfg->port.red_params[i][e_RTE_METER_YELLOW].max_th, - cfg->port.red_params[i][e_RTE_METER_RED].max_th); - - vlib_cli_output (vm, - " TC%u inverted probability: G = %u, Y = %u, R = %u", - i, cfg->port.red_params[i][e_RTE_METER_GREEN].maxp_inv, - cfg->port.red_params[i][e_RTE_METER_YELLOW].maxp_inv, - cfg->port.red_params[i][e_RTE_METER_RED].maxp_inv); - - vlib_cli_output (vm, " TC%u weight: R = %u, Y = %u, R = %u", i, - cfg->port.red_params[i][e_RTE_METER_GREEN].wq_log2, - cfg->port.red_params[i][e_RTE_METER_YELLOW].wq_log2, - cfg->port.red_params[i][e_RTE_METER_RED].wq_log2); - } -#endif - -done: - unformat_free (line_input); - - return error; -} - -/*? - * This command is used to display details of an output interface's HQoS - * settings. - * - * @cliexpar - * Example of how to display HQoS settings for an interfaces: - * @cliexstart{show dpdk interface hqos GigabitEthernet0/8/0} - * Thread: - * Input SWQ size = 4096 packets - * Enqueue burst size = 256 packets - * Dequeue burst size = 220 packets - * Packet field 0: slab position = 0, slab bitmask = 0x0000000000000000 (subport) - * Packet field 1: slab position = 40, slab bitmask = 0x0000000fff000000 (pipe) - * Packet field 2: slab position = 8, slab bitmask = 0x00000000000000fc (tc) - * Packet field 2 tc translation table: ([Mapped Value Range]: tc/queue tc/queue ...) - * [ 0 .. 15]: 0/0 0/1 0/2 0/3 1/0 1/1 1/2 1/3 2/0 2/1 2/2 2/3 3/0 3/1 3/2 3/3 - * [16 .. 31]: 0/0 0/1 0/2 0/3 1/0 1/1 1/2 1/3 2/0 2/1 2/2 2/3 3/0 3/1 3/2 3/3 - * [32 .. 47]: 0/0 0/1 0/2 0/3 1/0 1/1 1/2 1/3 2/0 2/1 2/2 2/3 3/0 3/1 3/2 3/3 - * [48 .. 63]: 0/0 0/1 0/2 0/3 1/0 1/1 1/2 1/3 2/0 2/1 2/2 2/3 3/0 3/1 3/2 3/3 - * Port: - * Rate = 1250000000 bytes/second - * MTU = 1514 bytes - * Frame overhead = 24 bytes - * Number of subports = 1 - * Number of pipes per subport = 4096 - * Packet queue size: TC0 = 64, TC1 = 64, TC2 = 64, TC3 = 64 packets - * Number of pipe profiles = 2 - * Subport 0: - * Rate = 1250000000 bytes/second - * Token bucket size = 1000000 bytes - * Traffic class rate: TC0 = 1250000000, TC1 = 1250000000, TC2 = 1250000000, TC3 = 1250000000 bytes/second - * TC period = 10 milliseconds - * Pipe profile 0: - * Rate = 305175 bytes/second - * Token bucket size = 1000000 bytes - * Traffic class rate: TC0 = 305175, TC1 = 305175, TC2 = 305175, TC3 = 305175 bytes/second - * TC period = 40 milliseconds - * TC0 WRR weights: Q0 = 1, Q1 = 1, Q2 = 1, Q3 = 1 - * TC1 WRR weights: Q0 = 1, Q1 = 1, Q2 = 1, Q3 = 1 - * TC2 WRR weights: Q0 = 1, Q1 = 1, Q2 = 1, Q3 = 1 - * TC3 WRR weights: Q0 = 1, Q1 = 1, Q2 = 1, Q3 = 1 - * @cliexend -?*/ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (cmd_show_dpdk_if_hqos, static) = { - .path = "show dpdk interface hqos", - .short_help = "show dpdk interface hqos ", - .function = show_dpdk_if_hqos, -}; - -/* *INDENT-ON* */ - -static clib_error_t * -show_dpdk_hqos_queue_stats (vlib_main_t * vm, unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - clib_error_t *error = NULL; -#ifdef RTE_SCHED_COLLECT_STATS - dpdk_main_t *dm = &dpdk_main; - u32 hw_if_index = (u32) ~ 0; - u32 subport = (u32) ~ 0; - u32 pipe = (u32) ~ 0; - u32 tc = (u32) ~ 0; - u32 tc_q = (u32) ~ 0; - vnet_hw_interface_t *hw; - dpdk_device_t *xd; - uword *p = 0; - struct rte_eth_dev_info dev_info; - struct rte_pci_device *pci_dev; - dpdk_device_config_t *devconf = 0; - u32 qindex; - struct rte_sched_queue_stats stats; - u16 qlen; - - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat - (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main, - &hw_if_index)) - ; - - else if (unformat (line_input, "subport %d", &subport)) - ; - - else if (unformat (line_input, "pipe %d", &pipe)) - ; - - else if (unformat (line_input, "tc %d", &tc)) - ; - - else if (unformat (line_input, "tc_q %d", &tc_q)) - ; - - else - { - error = clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); - goto done; - } - } - - if (hw_if_index == (u32) ~ 0) - { - error = clib_error_return (0, "please specify interface name!!"); - goto done; - } - - hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); - xd = vec_elt_at_index (dm->devices, hw->dev_instance); - - rte_eth_dev_info_get (xd->port_id, &dev_info); - - pci_dev = dpdk_get_pci_device (&dev_info); - - if (pci_dev) - { /* bonded interface has no pci info */ - vlib_pci_addr_t pci_addr; - - pci_addr.domain = pci_dev->addr.domain; - pci_addr.bus = pci_dev->addr.bus; - pci_addr.slot = pci_dev->addr.devid; - pci_addr.function = pci_dev->addr.function; - - p = - hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32); - } - - if (p) - devconf = pool_elt_at_index (dm->conf->dev_confs, p[0]); - else - devconf = &dm->conf->default_devconf; - - if (devconf->hqos_enabled == 0) - { - vlib_cli_output (vm, "HQoS disabled for this interface"); - goto done; - } - - /* - * Figure out which queue to query. cf rte_sched_port_qindex. (Not sure why - * that method isn't made public by DPDK - how _should_ we get the queue ID?) - */ - qindex = subport * devconf->hqos.port.n_pipes_per_subport + pipe; - qindex = qindex * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE + tc; - qindex = qindex * RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS + tc_q; - - if (rte_sched_queue_read_stats (xd->hqos_ht->hqos, qindex, &stats, &qlen) != - 0) - { - error = clib_error_return (0, "failed to read stats"); - goto done; - } - - vlib_cli_output (vm, "%=24s%=16s", "Stats Parameter", "Value"); - vlib_cli_output (vm, "%=24s%=16d", "Packets", stats.n_pkts); - vlib_cli_output (vm, "%=24s%=16d", "Packets dropped", stats.n_pkts_dropped); -#ifdef RTE_SCHED_RED - vlib_cli_output (vm, "%=24s%=16d", "Packets dropped (RED)", - stats.n_pkts_red_dropped); -#endif - vlib_cli_output (vm, "%=24s%=16d", "Bytes", stats.n_bytes); - vlib_cli_output (vm, "%=24s%=16d", "Bytes dropped", stats.n_bytes_dropped); - -#else - - /* Get a line of input */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - vlib_cli_output (vm, "RTE_SCHED_COLLECT_STATS disabled in DPDK"); - goto done; - -#endif - -done: - unformat_free (line_input); - - return error; -} - -/*? - * This command is used to display statistics associated with a HQoS traffic class - * queue. - * - * @note - * Statistic collection by the scheduler is disabled by default in DPDK. In order to - * turn it on, add the following line to '../vpp/dpdk/Makefile': - * - $(call set,RTE_SCHED_COLLECT_STATS,y) - * - * @cliexpar - * Example of how to display statistics of HQoS a HQoS traffic class queue: - * @cliexstart{show dpdk hqos queue GigabitEthernet0/9/0 subport 0 pipe 3181 tc 0 tc_q 0} - * Stats Parameter Value - * Packets 140 - * Packets dropped 0 - * Bytes 8400 - * Bytes dropped 0 - * @cliexend -?*/ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (cmd_show_dpdk_hqos_queue_stats, static) = { - .path = "show dpdk hqos queue", - .short_help = "show dpdk hqos queue subport pipe tc tc_q ", - .function = show_dpdk_hqos_queue_stats, -}; -/* *INDENT-ON* */ -#endif - static clib_error_t * show_dpdk_version_command_fn (vlib_main_t * vm, unformat_input_t * input, diff --git a/src/plugins/dpdk/device/device.c b/src/plugins/dpdk/device/device.c index 323149043a5..c355edf6a4b 100644 --- a/src/plugins/dpdk/device/device.c +++ b/src/plugins/dpdk/device/device.c @@ -180,21 +180,6 @@ static_always_inline queue_id = (queue_id + 1) % xd->tx_q_used; } -#if 0 - if (PREDICT_FALSE (xd->flags & DPDK_DEVICE_FLAG_HQOS)) /* HQoS ON */ - { - /* no wrap, transmit in one burst */ - dpdk_device_hqos_per_worker_thread_t *hqos = - &xd->hqos_wt[vm->thread_index]; - - ASSERT (hqos->swq != NULL); - - dpdk_hqos_metadata_set (hqos, mb, n_left); - n_sent = rte_ring_sp_enqueue_burst (hqos->swq, (void **) mb, - n_left, 0); - } - else -#endif if (PREDICT_TRUE (xd->flags & DPDK_DEVICE_FLAG_PMD)) { /* no wrap, transmit in one burst */ diff --git a/src/plugins/dpdk/device/dpdk.h b/src/plugins/dpdk/device/dpdk.h index ab28ac06a0a..68d9e712b4e 100644 --- a/src/plugins/dpdk/device/dpdk.h +++ b/src/plugins/dpdk/device/dpdk.h @@ -119,40 +119,6 @@ typedef enum typedef uint16_t dpdk_portid_t; -typedef struct -{ - /* Required for vec_validate_aligned */ - CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); - - struct rte_ring *swq; - - u64 hqos_field0_slabmask; - u32 hqos_field0_slabpos; - u32 hqos_field0_slabshr; - u64 hqos_field1_slabmask; - u32 hqos_field1_slabpos; - u32 hqos_field1_slabshr; - u64 hqos_field2_slabmask; - u32 hqos_field2_slabpos; - u32 hqos_field2_slabshr; - u32 hqos_tc_table[64]; -} dpdk_device_hqos_per_worker_thread_t; - -typedef struct -{ - /* Required for vec_validate_aligned */ - CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); - struct rte_ring **swq; - struct rte_mbuf **pkts_enq; - struct rte_mbuf **pkts_deq; - struct rte_sched_port *hqos; - u32 hqos_burst_enq; - u32 hqos_burst_deq; - u32 pkts_enq_len; - u32 swq_pos; - u32 flush_count; -} dpdk_device_hqos_per_hqos_thread_t; - #define foreach_dpdk_device_flags \ _( 0, ADMIN_UP, "admin-up") \ _( 1, PROMISC, "promisc") \ @@ -160,7 +126,6 @@ typedef struct _( 3, PMD_INIT_FAIL, "pmd-init-fail") \ _( 4, MAYBE_MULTISEG, "maybe-multiseg") \ _( 5, HAVE_SUBIF, "subif") \ - _( 6, HQOS, "hqos") \ _( 9, TX_OFFLOAD, "tx-offload") \ _(10, INTEL_PHDR_CKSUM, "intel-phdr-cksum") \ _(11, RX_FLOW_OFFLOAD, "rx-flow-offload") \ @@ -235,10 +200,6 @@ typedef struct u32 parked_loop_count; struct rte_flow_error last_flow_error; - /* HQoS related */ - dpdk_device_hqos_per_worker_thread_t *hqos_wt; - dpdk_device_hqos_per_hqos_thread_t *hqos_ht; - /* af_packet instance number */ u16 af_packet_instance_num; @@ -278,39 +239,6 @@ typedef struct #define HQOS_FLUSH_COUNT_THRESHOLD 100000 #endif -typedef struct dpdk_device_config_hqos_t -{ - u32 hqos_thread; - u32 hqos_thread_valid; - - u32 swq_size; - u32 burst_enq; - u32 burst_deq; - - u32 pktfield0_slabpos; - u32 pktfield1_slabpos; - u32 pktfield2_slabpos; - u64 pktfield0_slabmask; - u64 pktfield1_slabmask; - u64 pktfield2_slabmask; - u32 tc_table[64]; - - struct rte_sched_port_params port; - struct rte_sched_subport_params *subport; - struct rte_sched_pipe_params *pipe; - uint32_t *pipe_map; -} dpdk_device_config_hqos_t; - -int dpdk_hqos_validate_mask (u64 mask, u32 n); -void dpdk_device_config_hqos_pipe_profile_default (dpdk_device_config_hqos_t * - hqos, u32 pipe_profile_id); -#if 0 -void dpdk_device_config_hqos_default (dpdk_device_config_hqos_t * hqos); -#endif -clib_error_t *dpdk_port_setup_hqos (dpdk_device_t * xd, - dpdk_device_config_hqos_t * hqos); -void dpdk_hqos_metadata_set (dpdk_device_hqos_per_worker_thread_t * hqos, - struct rte_mbuf **pkts, u32 n_pkts); #define foreach_dpdk_device_config_item \ _ (num_rx_queues) \ @@ -333,8 +261,6 @@ typedef struct foreach_dpdk_device_config_item #undef _ clib_bitmap_t * workers; - u32 hqos_enabled; - dpdk_device_config_hqos_t hqos; u8 tso; u8 *devargs; @@ -397,7 +323,6 @@ typedef struct /* Devices */ dpdk_device_t *devices; - dpdk_device_and_queue_t **devices_by_hqos_cpu; dpdk_per_thread_data_t *per_thread_data; /* buffer flags template, configurable to enable/disable tcp / udp cksum */ @@ -409,10 +334,6 @@ typedef struct */ u8 admin_up_down_in_progress; - /* which cpus are running I/O TX */ - int hqos_cpu_first_index; - int hqos_cpu_count; - /* control interval of dpdk link state and stat polling */ f64 link_state_poll_interval; f64 stat_poll_interval; @@ -502,8 +423,6 @@ format_function_t format_dpdk_tx_offload_caps; vnet_flow_dev_ops_function_t dpdk_flow_ops_fn; clib_error_t *unformat_rss_fn (unformat_input_t * input, uword * rss_fn); -clib_error_t *unformat_hqos (unformat_input_t * input, - dpdk_device_config_hqos_t * hqos); struct rte_pci_device *dpdk_get_pci_device (const struct rte_eth_dev_info *info); diff --git a/src/plugins/dpdk/device/format.c b/src/plugins/dpdk/device/format.c index 20493eb77da..8ef46512c6f 100644 --- a/src/plugins/dpdk/device/format.c +++ b/src/plugins/dpdk/device/format.c @@ -913,25 +913,6 @@ unformat_rss_fn (unformat_input_t * input, uword * rss_fn) return 0; } -clib_error_t * -unformat_hqos (unformat_input_t * input, dpdk_device_config_hqos_t * hqos) -{ - clib_error_t *error = 0; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "hqos-thread %u", &hqos->hqos_thread)) - hqos->hqos_thread_valid = 1; - else - { - error = clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); - break; - } - } - - return error; -} /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/dpdk/device/init.c b/src/plugins/dpdk/device/init.c index d0125e93936..5d0e5a2605d 100644 --- a/src/plugins/dpdk/device/init.c +++ b/src/plugins/dpdk/device/init.c @@ -214,29 +214,9 @@ dpdk_lib_init (dpdk_main_t * dm) dpdk_device_t *xd; vlib_pci_addr_t last_pci_addr; u32 last_pci_addr_port = 0; - vlib_thread_registration_t *tr_hqos; - uword *p_hqos; - - u32 next_hqos_cpu = 0; u8 af_packet_instance_num = 0; last_pci_addr.as_u32 = ~0; - dm->hqos_cpu_first_index = 0; - dm->hqos_cpu_count = 0; - - /* find out which cpus will be used for I/O TX */ - p_hqos = hash_get_mem (tm->thread_registrations_by_name, "hqos-threads"); - tr_hqos = p_hqos ? (vlib_thread_registration_t *) p_hqos[0] : 0; - - if (tr_hqos && tr_hqos->count > 0) - { - dm->hqos_cpu_first_index = tr_hqos->first_index; - dm->hqos_cpu_count = tr_hqos->count; - } - - vec_validate_aligned (dm->devices_by_hqos_cpu, tm->n_vlib_mains - 1, - CLIB_CACHE_LINE_BYTES); - nports = rte_eth_dev_count_avail (); if (nports < 1) @@ -596,38 +576,6 @@ dpdk_lib_init (dpdk_main_t * dm) /* assign interface to input thread */ int q; - if (devconf->hqos_enabled) - { - xd->flags |= DPDK_DEVICE_FLAG_HQOS; - - int cpu; - if (devconf->hqos.hqos_thread_valid) - { - if (devconf->hqos.hqos_thread >= dm->hqos_cpu_count) - return clib_error_return (0, "invalid HQoS thread index"); - - cpu = dm->hqos_cpu_first_index + devconf->hqos.hqos_thread; - } - else - { - if (dm->hqos_cpu_count == 0) - return clib_error_return (0, "no HQoS threads available"); - - cpu = dm->hqos_cpu_first_index + next_hqos_cpu; - - next_hqos_cpu++; - if (next_hqos_cpu == dm->hqos_cpu_count) - next_hqos_cpu = 0; - - devconf->hqos.hqos_thread_valid = 1; - devconf->hqos.hqos_thread = cpu; - } - - dpdk_device_and_queue_t *dq; - vec_add2 (dm->devices_by_hqos_cpu[cpu], dq, 1); - dq->device = xd->device_index; - dq->queue_id = 0; - } error = ethernet_register_interface (dm->vnet_main, dpdk_device_class.index, xd->device_index, @@ -770,14 +718,6 @@ dpdk_lib_init (dpdk_main_t * dm) format_dpdk_device_name, i, format_dpdk_device_errors, xd); - if (devconf->hqos_enabled) - { - clib_error_t *rv; - rv = dpdk_port_setup_hqos (xd, &devconf->hqos); - if (rv) - return rv; - } - /* * A note on Cisco VIC (PMD_ENIC) and VLAN: * @@ -1060,11 +1000,7 @@ dpdk_device_config (dpdk_config_main_t * conf, vlib_pci_addr_t pci_addr, } devconf->pci_addr.as_u32 = pci_addr.as_u32; - devconf->hqos_enabled = 0; devconf->tso = DPDK_DEVICE_TSO_DEFAULT; -#if 0 - dpdk_device_config_hqos_default (&devconf->hqos); -#endif if (!input) return 0; @@ -1097,19 +1033,6 @@ dpdk_device_config (dpdk_config_main_t * conf, vlib_pci_addr_t pci_addr, devconf->vlan_strip_offload = DPDK_DEVICE_VLAN_STRIP_OFF; else if (unformat (input, "vlan-strip-offload on")) devconf->vlan_strip_offload = DPDK_DEVICE_VLAN_STRIP_ON; - else - if (unformat - (input, "hqos %U", unformat_vlib_cli_sub_input, &sub_input)) - { - devconf->hqos_enabled = 1; - error = unformat_hqos (&sub_input, &devconf->hqos); - if (error) - break; - } - else if (unformat (input, "hqos")) - { - devconf->hqos_enabled = 1; - } else if (unformat (input, "tso on")) { devconf->tso = DPDK_DEVICE_TSO_ON; diff --git a/src/plugins/dpdk/hqos/hqos.c b/src/plugins/dpdk/hqos/hqos.c deleted file mode 100644 index 1a8dd6d98fe..00000000000 --- a/src/plugins/dpdk/hqos/hqos.c +++ /dev/null @@ -1,771 +0,0 @@ -/* - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include /* enumerate all vlib messages */ - -#define vl_typedefs /* define message structures */ -#include -#undef vl_typedefs - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) -#define vl_printfun -#include -#undef vl_printfun - -#include - -/*** - * - * HQoS default configuration values - * - ***/ - -static dpdk_device_config_hqos_t hqos_params_default = { - .hqos_thread_valid = 0, - - .swq_size = 4096, - .burst_enq = 256, - .burst_deq = 220, - - /* - * Packet field to identify the subport. - * - * Default value: Since only one subport is defined by default (see below: - * n_subports_per_port = 1), the subport ID is hardcoded to 0. - */ - .pktfield0_slabpos = 0, - .pktfield0_slabmask = 0, - - /* - * Packet field to identify the pipe. - * - * Default value: Assuming Ethernet/IPv4/UDP packets, UDP payload bits 12 .. 23 - */ - .pktfield1_slabpos = 40, - .pktfield1_slabmask = 0x0000000FFF000000LLU, - - /* Packet field used as index into TC translation table to identify the traffic - * class and queue. - * - * Default value: Assuming Ethernet/IPv4 packets, IPv4 DSCP field - */ - .pktfield2_slabpos = 8, - .pktfield2_slabmask = 0x00000000000000FCLLU, - .tc_table = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - }, - - /* port */ - .port = { - .name = NULL, /* Set at init */ - .socket = 0, /* Set at init */ - .rate = 1250000000, /* Assuming 10GbE port */ - .mtu = 14 + 1500, /* Assuming Ethernet/IPv4 pkt (Ethernet FCS not included) */ - .frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT, - .n_subports_per_port = 1, - .n_pipes_per_subport = 4096, - .qsize = {64, 64, 64, 64}, - .pipe_profiles = NULL, /* Set at config */ - .n_pipe_profiles = 1, - -#ifdef RTE_SCHED_RED - .red_params = { - /* Traffic Class 0 Colors Green / Yellow / Red */ - [0][0] = {.min_th = 48,.max_th = 64,.maxp_inv = - 10,.wq_log2 = 9}, - [0][1] = {.min_th = 40,.max_th = 64,.maxp_inv = - 10,.wq_log2 = 9}, - [0][2] = {.min_th = 32,.max_th = 64,.maxp_inv = - 10,.wq_log2 = 9}, - - /* Traffic Class 1 - Colors Green / Yellow / Red */ - [1][0] = {.min_th = 48,.max_th = 64,.maxp_inv = - 10,.wq_log2 = 9}, - [1][1] = {.min_th = 40,.max_th = 64,.maxp_inv = - 10,.wq_log2 = 9}, - [1][2] = {.min_th = 32,.max_th = 64,.maxp_inv = - 10,.wq_log2 = 9}, - - /* Traffic Class 2 - Colors Green / Yellow / Red */ - [2][0] = {.min_th = 48,.max_th = 64,.maxp_inv = - 10,.wq_log2 = 9}, - [2][1] = {.min_th = 40,.max_th = 64,.maxp_inv = - 10,.wq_log2 = 9}, - [2][2] = {.min_th = 32,.max_th = 64,.maxp_inv = - 10,.wq_log2 = 9}, - - /* Traffic Class 3 - Colors Green / Yellow / Red */ - [3][0] = {.min_th = 48,.max_th = 64,.maxp_inv = - 10,.wq_log2 = 9}, - [3][1] = {.min_th = 40,.max_th = 64,.maxp_inv = - 10,.wq_log2 = 9}, - [3][2] = {.min_th = 32,.max_th = 64,.maxp_inv = - 10,.wq_log2 = 9} - }, -#endif /* RTE_SCHED_RED */ - }, -}; - -static struct rte_sched_subport_params hqos_subport_params_default = { - .tb_rate = 1250000000, /* 10GbE line rate (measured in bytes/second) */ - .tb_size = 1000000, - .tc_rate = {1250000000, 1250000000, 1250000000, 1250000000}, - .tc_period = 10, -}; - -static struct rte_sched_pipe_params hqos_pipe_params_default = { - .tb_rate = 305175, /* 10GbE line rate divided by 4K pipes */ - .tb_size = 1000000, - .tc_rate = {305175, 305175, 305175, 305175}, - .tc_period = 40, -#ifdef RTE_SCHED_SUBPORT_TC_OV - .tc_ov_weight = 1, -#endif - .wrr_weights = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, -}; - -/*** - * - * HQoS configuration - * - ***/ - -int -dpdk_hqos_validate_mask (u64 mask, u32 n) -{ - int count = __builtin_popcountll (mask); - int pos_lead = sizeof (u64) * 8 - count_leading_zeros (mask); - int pos_trail = count_trailing_zeros (mask); - int count_expected = __builtin_popcount (n - 1); - - /* Handle the exceptions */ - if (n == 0) - return -1; /* Error */ - - if ((mask == 0) && (n == 1)) - return 0; /* OK */ - - if (((mask == 0) && (n != 1)) || ((mask != 0) && (n == 1))) - return -2; /* Error */ - - /* Check that mask is contiguous */ - if ((pos_lead - pos_trail) != count) - return -3; /* Error */ - - /* Check that mask contains the expected number of bits set */ - if (count != count_expected) - return -4; /* Error */ - - return 0; /* OK */ -} - -void -dpdk_device_config_hqos_pipe_profile_default (dpdk_device_config_hqos_t * - hqos, u32 pipe_profile_id) -{ - memcpy (&hqos->pipe[pipe_profile_id], &hqos_pipe_params_default, - sizeof (hqos_pipe_params_default)); -} - -void -dpdk_device_config_hqos_default (dpdk_device_config_hqos_t * hqos) -{ - struct rte_sched_subport_params *subport_params; - struct rte_sched_pipe_params *pipe_params; - u32 *pipe_map; - u32 i; - - memcpy (hqos, &hqos_params_default, sizeof (hqos_params_default)); - - /* pipe */ - vec_add2 (hqos->pipe, pipe_params, hqos->port.n_pipe_profiles); - - for (i = 0; i < vec_len (hqos->pipe); i++) - memcpy (&pipe_params[i], - &hqos_pipe_params_default, sizeof (hqos_pipe_params_default)); - - hqos->port.pipe_profiles = hqos->pipe; - - /* subport */ - vec_add2 (hqos->subport, subport_params, hqos->port.n_subports_per_port); - - for (i = 0; i < vec_len (hqos->subport); i++) - memcpy (&subport_params[i], - &hqos_subport_params_default, - sizeof (hqos_subport_params_default)); - - /* pipe profile */ - vec_add2 (hqos->pipe_map, - pipe_map, - hqos->port.n_subports_per_port * hqos->port.n_pipes_per_subport); - - for (i = 0; i < vec_len (hqos->pipe_map); i++) - pipe_map[i] = 0; -} - -/*** - * - * HQoS init - * - ***/ - -clib_error_t * -dpdk_port_setup_hqos (dpdk_device_t * xd, dpdk_device_config_hqos_t * hqos) -{ - vlib_thread_main_t *tm = vlib_get_thread_main (); - char name[32]; - u32 subport_id, i; - int rv; - - /* Detect the set of worker threads */ - int worker_thread_first = 0; - int worker_thread_count = 0; - - uword *p = hash_get_mem (tm->thread_registrations_by_name, "workers"); - vlib_thread_registration_t *tr = - p ? (vlib_thread_registration_t *) p[0] : 0; - - if (tr && tr->count > 0) - { - worker_thread_first = tr->first_index; - worker_thread_count = tr->count; - } - - /* Allocate the per-thread device data array */ - vec_validate_aligned (xd->hqos_wt, tm->n_vlib_mains - 1, - CLIB_CACHE_LINE_BYTES); - clib_memset (xd->hqos_wt, 0, tm->n_vlib_mains * sizeof (xd->hqos_wt[0])); - - vec_validate_aligned (xd->hqos_ht, 0, CLIB_CACHE_LINE_BYTES); - clib_memset (xd->hqos_ht, 0, sizeof (xd->hqos_ht[0])); - - /* Allocate space for one SWQ per worker thread in the I/O TX thread data structure */ - vec_validate (xd->hqos_ht->swq, worker_thread_count); - - /* SWQ */ - for (i = 0; i < worker_thread_count + 1; i++) - { - u32 swq_flags = RING_F_SP_ENQ | RING_F_SC_DEQ; - - snprintf (name, sizeof (name), "SWQ-worker%u-to-device%u", i, - xd->port_id); - xd->hqos_ht->swq[i] = - rte_ring_create (name, hqos->swq_size, xd->cpu_socket, swq_flags); - if (xd->hqos_ht->swq[i] == NULL) - return clib_error_return (0, - "SWQ-worker%u-to-device%u: rte_ring_create err", - i, xd->port_id); - } - - /* - * HQoS - */ - - /* HQoS port */ - snprintf (name, sizeof (name), "HQoS%u", xd->port_id); - hqos->port.name = strdup (name); - if (hqos->port.name == NULL) - return clib_error_return (0, "HQoS%u: strdup err", xd->port_id); - - hqos->port.socket = rte_eth_dev_socket_id (xd->port_id); - if (hqos->port.socket == SOCKET_ID_ANY) - hqos->port.socket = 0; - - xd->hqos_ht->hqos = rte_sched_port_config (&hqos->port); - if (xd->hqos_ht->hqos == NULL) - return clib_error_return (0, "HQoS%u: rte_sched_port_config err", - xd->port_id); - - /* HQoS subport */ - for (subport_id = 0; subport_id < hqos->port.n_subports_per_port; - subport_id++) - { - u32 pipe_id; - - rv = - rte_sched_subport_config (xd->hqos_ht->hqos, subport_id, - &hqos->subport[subport_id]); - if (rv) - return clib_error_return (0, - "HQoS%u subport %u: rte_sched_subport_config err (%d)", - xd->port_id, subport_id, rv); - - /* HQoS pipe */ - for (pipe_id = 0; pipe_id < hqos->port.n_pipes_per_subport; pipe_id++) - { - u32 pos = subport_id * hqos->port.n_pipes_per_subport + pipe_id; - u32 profile_id = hqos->pipe_map[pos]; - - rv = - rte_sched_pipe_config (xd->hqos_ht->hqos, subport_id, pipe_id, - profile_id); - if (rv) - return clib_error_return (0, - "HQoS%u subport %u pipe %u: rte_sched_pipe_config err (%d)", - xd->port_id, subport_id, pipe_id, rv); - } - } - - /* Set up per-thread device data for the I/O TX thread */ - xd->hqos_ht->hqos_burst_enq = hqos->burst_enq; - xd->hqos_ht->hqos_burst_deq = hqos->burst_deq; - vec_validate (xd->hqos_ht->pkts_enq, 2 * hqos->burst_enq - 1); - vec_validate (xd->hqos_ht->pkts_deq, hqos->burst_deq - 1); - xd->hqos_ht->pkts_enq_len = 0; - xd->hqos_ht->swq_pos = 0; - xd->hqos_ht->flush_count = 0; - - /* Set up per-thread device data for each worker thread */ - for (i = 0; i < worker_thread_count + 1; i++) - { - u32 tid; - if (i) - tid = worker_thread_first + (i - 1); - else - tid = i; - - xd->hqos_wt[tid].swq = xd->hqos_ht->swq[i]; - xd->hqos_wt[tid].hqos_field0_slabpos = hqos->pktfield0_slabpos; - xd->hqos_wt[tid].hqos_field0_slabmask = hqos->pktfield0_slabmask; - xd->hqos_wt[tid].hqos_field0_slabshr = - count_trailing_zeros (hqos->pktfield0_slabmask); - xd->hqos_wt[tid].hqos_field1_slabpos = hqos->pktfield1_slabpos; - xd->hqos_wt[tid].hqos_field1_slabmask = hqos->pktfield1_slabmask; - xd->hqos_wt[tid].hqos_field1_slabshr = - count_trailing_zeros (hqos->pktfield1_slabmask); - xd->hqos_wt[tid].hqos_field2_slabpos = hqos->pktfield2_slabpos; - xd->hqos_wt[tid].hqos_field2_slabmask = hqos->pktfield2_slabmask; - xd->hqos_wt[tid].hqos_field2_slabshr = - count_trailing_zeros (hqos->pktfield2_slabmask); - memcpy (xd->hqos_wt[tid].hqos_tc_table, hqos->tc_table, - sizeof (hqos->tc_table)); - } - - return 0; -} - -/*** - * - * HQoS run-time - * - ***/ -/* - * dpdk_hqos_thread - Contains the main loop of an HQoS thread. - * - * w - * Information for the current thread - */ -static_always_inline void -dpdk_hqos_thread_internal_hqos_dbg_bypass (vlib_main_t * vm) -{ - dpdk_main_t *dm = &dpdk_main; - u32 thread_index = vm->thread_index; - u32 dev_pos; - - dev_pos = 0; - while (1) - { - vlib_worker_thread_barrier_check (); - - u32 n_devs = vec_len (dm->devices_by_hqos_cpu[thread_index]); - if (dev_pos >= n_devs) - dev_pos = 0; - - dpdk_device_and_queue_t *dq = - vec_elt_at_index (dm->devices_by_hqos_cpu[thread_index], dev_pos); - dpdk_device_t *xd = vec_elt_at_index (dm->devices, dq->device); - - dpdk_device_hqos_per_hqos_thread_t *hqos = xd->hqos_ht; - u32 device_index = xd->port_id; - u16 queue_id = dq->queue_id; - - struct rte_mbuf **pkts_enq = hqos->pkts_enq; - u32 pkts_enq_len = hqos->pkts_enq_len; - u32 swq_pos = hqos->swq_pos; - u32 n_swq = vec_len (hqos->swq), i; - u32 flush_count = hqos->flush_count; - - for (i = 0; i < n_swq; i++) - { - /* Get current SWQ for this device */ - struct rte_ring *swq = hqos->swq[swq_pos]; - - /* Read SWQ burst to packet buffer of this device */ - pkts_enq_len += rte_ring_sc_dequeue_burst (swq, - (void **) - &pkts_enq[pkts_enq_len], - hqos->hqos_burst_enq, 0); - - /* Get next SWQ for this device */ - swq_pos++; - if (swq_pos >= n_swq) - swq_pos = 0; - hqos->swq_pos = swq_pos; - - /* HWQ TX enqueue when burst available */ - if (pkts_enq_len >= hqos->hqos_burst_enq) - { - u32 n_pkts = rte_eth_tx_burst (device_index, - (uint16_t) queue_id, - pkts_enq, - (uint16_t) pkts_enq_len); - - for (; n_pkts < pkts_enq_len; n_pkts++) - rte_pktmbuf_free (pkts_enq[n_pkts]); - - pkts_enq_len = 0; - flush_count = 0; - break; - } - } - if (pkts_enq_len) - { - flush_count++; - if (PREDICT_FALSE (flush_count == HQOS_FLUSH_COUNT_THRESHOLD)) - { - rte_sched_port_enqueue (hqos->hqos, pkts_enq, pkts_enq_len); - - pkts_enq_len = 0; - flush_count = 0; - } - } - hqos->pkts_enq_len = pkts_enq_len; - hqos->flush_count = flush_count; - - /* Advance to next device */ - dev_pos++; - } -} - -static_always_inline void -dpdk_hqos_thread_internal (vlib_main_t * vm) -{ - dpdk_main_t *dm = &dpdk_main; - u32 thread_index = vm->thread_index; - u32 dev_pos; - - dev_pos = 0; - while (1) - { - vlib_worker_thread_barrier_check (); - - u32 n_devs = vec_len (dm->devices_by_hqos_cpu[thread_index]); - if (PREDICT_FALSE (n_devs == 0)) - { - dev_pos = 0; - continue; - } - if (dev_pos >= n_devs) - dev_pos = 0; - - dpdk_device_and_queue_t *dq = - vec_elt_at_index (dm->devices_by_hqos_cpu[thread_index], dev_pos); - dpdk_device_t *xd = vec_elt_at_index (dm->devices, dq->device); - - dpdk_device_hqos_per_hqos_thread_t *hqos = xd->hqos_ht; - u32 device_index = xd->port_id; - u16 queue_id = dq->queue_id; - - struct rte_mbuf **pkts_enq = hqos->pkts_enq; - struct rte_mbuf **pkts_deq = hqos->pkts_deq; - u32 pkts_enq_len = hqos->pkts_enq_len; - u32 swq_pos = hqos->swq_pos; - u32 n_swq = vec_len (hqos->swq), i; - u32 flush_count = hqos->flush_count; - - /* - * SWQ dequeue and HQoS enqueue for current device - */ - for (i = 0; i < n_swq; i++) - { - /* Get current SWQ for this device */ - struct rte_ring *swq = hqos->swq[swq_pos]; - - /* Read SWQ burst to packet buffer of this device */ - pkts_enq_len += rte_ring_sc_dequeue_burst (swq, - (void **) - &pkts_enq[pkts_enq_len], - hqos->hqos_burst_enq, 0); - - /* Get next SWQ for this device */ - swq_pos++; - if (swq_pos >= n_swq) - swq_pos = 0; - hqos->swq_pos = swq_pos; - - /* HQoS enqueue when burst available */ - if (pkts_enq_len >= hqos->hqos_burst_enq) - { - rte_sched_port_enqueue (hqos->hqos, pkts_enq, pkts_enq_len); - - pkts_enq_len = 0; - flush_count = 0; - break; - } - } - if (pkts_enq_len) - { - flush_count++; - if (PREDICT_FALSE (flush_count == HQOS_FLUSH_COUNT_THRESHOLD)) - { - rte_sched_port_enqueue (hqos->hqos, pkts_enq, pkts_enq_len); - - pkts_enq_len = 0; - flush_count = 0; - } - } - hqos->pkts_enq_len = pkts_enq_len; - hqos->flush_count = flush_count; - - /* - * HQoS dequeue and HWQ TX enqueue for current device - */ - { - u32 pkts_deq_len, n_pkts; - - pkts_deq_len = rte_sched_port_dequeue (hqos->hqos, - pkts_deq, - hqos->hqos_burst_deq); - - for (n_pkts = 0; n_pkts < pkts_deq_len;) - n_pkts += rte_eth_tx_burst (device_index, - (uint16_t) queue_id, - &pkts_deq[n_pkts], - (uint16_t) (pkts_deq_len - n_pkts)); - } - - /* Advance to next device */ - dev_pos++; - } -} - -void -dpdk_hqos_thread (vlib_worker_thread_t * w) -{ - vlib_main_t *vm; - vlib_thread_main_t *tm = vlib_get_thread_main (); - dpdk_main_t *dm = &dpdk_main; - - vm = vlib_get_main (); - - ASSERT (vm->thread_index == vlib_get_thread_index ()); - - clib_time_init (&vm->clib_time); - clib_mem_set_heap (w->thread_mheap); - - /* Wait until the dpdk init sequence is complete */ - while (tm->worker_thread_release == 0) - vlib_worker_thread_barrier_check (); - - if (vec_len (dm->devices_by_hqos_cpu[vm->thread_index]) == 0) - return - clib_error - ("current I/O TX thread does not have any devices assigned to it"); - - if (DPDK_HQOS_DBG_BYPASS) - dpdk_hqos_thread_internal_hqos_dbg_bypass (vm); - else - dpdk_hqos_thread_internal (vm); -} - -void -dpdk_hqos_thread_fn (void *arg) -{ - vlib_worker_thread_t *w = (vlib_worker_thread_t *) arg; - vlib_worker_thread_init (w); - dpdk_hqos_thread (w); -} - -/* *INDENT-OFF* */ -VLIB_REGISTER_THREAD (hqos_thread_reg, static) = -{ - .name = "hqos-threads", - .short_name = "hqos-threads", - .function = dpdk_hqos_thread_fn, -}; -/* *INDENT-ON* */ - -/* - * HQoS run-time code to be called by the worker threads - */ -#define BITFIELD(byte_array, slab_pos, slab_mask, slab_shr) \ -({ \ - u64 slab = *((u64 *) &byte_array[slab_pos]); \ - u64 val = (rte_be_to_cpu_64(slab) & slab_mask) >> slab_shr; \ - val; \ -}) - -#define RTE_SCHED_PORT_HIERARCHY(subport, pipe, traffic_class, queue, color) \ - ((((u64) (queue)) & 0x3) | \ - ((((u64) (traffic_class)) & 0x3) << 2) | \ - ((((u64) (color)) & 0x3) << 4) | \ - ((((u64) (subport)) & 0xFFFF) << 16) | \ - ((((u64) (pipe)) & 0xFFFFFFFF) << 32)) - -void -dpdk_hqos_metadata_set (dpdk_device_hqos_per_worker_thread_t * hqos, - struct rte_mbuf **pkts, u32 n_pkts) -{ - u32 i; - - for (i = 0; i < (n_pkts & (~0x3)); i += 4) - { - struct rte_mbuf *pkt0 = pkts[i]; - struct rte_mbuf *pkt1 = pkts[i + 1]; - struct rte_mbuf *pkt2 = pkts[i + 2]; - struct rte_mbuf *pkt3 = pkts[i + 3]; - - u8 *pkt0_data = rte_pktmbuf_mtod (pkt0, u8 *); - u8 *pkt1_data = rte_pktmbuf_mtod (pkt1, u8 *); - u8 *pkt2_data = rte_pktmbuf_mtod (pkt2, u8 *); - u8 *pkt3_data = rte_pktmbuf_mtod (pkt3, u8 *); - - u64 pkt0_subport = BITFIELD (pkt0_data, hqos->hqos_field0_slabpos, - hqos->hqos_field0_slabmask, - hqos->hqos_field0_slabshr); - u64 pkt0_pipe = BITFIELD (pkt0_data, hqos->hqos_field1_slabpos, - hqos->hqos_field1_slabmask, - hqos->hqos_field1_slabshr); - u64 pkt0_dscp = BITFIELD (pkt0_data, hqos->hqos_field2_slabpos, - hqos->hqos_field2_slabmask, - hqos->hqos_field2_slabshr); - u32 pkt0_tc = hqos->hqos_tc_table[pkt0_dscp & 0x3F] >> 2; - u32 pkt0_tc_q = hqos->hqos_tc_table[pkt0_dscp & 0x3F] & 0x3; - - u64 pkt1_subport = BITFIELD (pkt1_data, hqos->hqos_field0_slabpos, - hqos->hqos_field0_slabmask, - hqos->hqos_field0_slabshr); - u64 pkt1_pipe = BITFIELD (pkt1_data, hqos->hqos_field1_slabpos, - hqos->hqos_field1_slabmask, - hqos->hqos_field1_slabshr); - u64 pkt1_dscp = BITFIELD (pkt1_data, hqos->hqos_field2_slabpos, - hqos->hqos_field2_slabmask, - hqos->hqos_field2_slabshr); - u32 pkt1_tc = hqos->hqos_tc_table[pkt1_dscp & 0x3F] >> 2; - u32 pkt1_tc_q = hqos->hqos_tc_table[pkt1_dscp & 0x3F] & 0x3; - - u64 pkt2_subport = BITFIELD (pkt2_data, hqos->hqos_field0_slabpos, - hqos->hqos_field0_slabmask, - hqos->hqos_field0_slabshr); - u64 pkt2_pipe = BITFIELD (pkt2_data, hqos->hqos_field1_slabpos, - hqos->hqos_field1_slabmask, - hqos->hqos_field1_slabshr); - u64 pkt2_dscp = BITFIELD (pkt2_data, hqos->hqos_field2_slabpos, - hqos->hqos_field2_slabmask, - hqos->hqos_field2_slabshr); - u32 pkt2_tc = hqos->hqos_tc_table[pkt2_dscp & 0x3F] >> 2; - u32 pkt2_tc_q = hqos->hqos_tc_table[pkt2_dscp & 0x3F] & 0x3; - - u64 pkt3_subport = BITFIELD (pkt3_data, hqos->hqos_field0_slabpos, - hqos->hqos_field0_slabmask, - hqos->hqos_field0_slabshr); - u64 pkt3_pipe = BITFIELD (pkt3_data, hqos->hqos_field1_slabpos, - hqos->hqos_field1_slabmask, - hqos->hqos_field1_slabshr); - u64 pkt3_dscp = BITFIELD (pkt3_data, hqos->hqos_field2_slabpos, - hqos->hqos_field2_slabmask, - hqos->hqos_field2_slabshr); - u32 pkt3_tc = hqos->hqos_tc_table[pkt3_dscp & 0x3F] >> 2; - u32 pkt3_tc_q = hqos->hqos_tc_table[pkt3_dscp & 0x3F] & 0x3; - - u64 pkt0_sched = RTE_SCHED_PORT_HIERARCHY (pkt0_subport, - pkt0_pipe, - pkt0_tc, - pkt0_tc_q, - 0); - u64 pkt1_sched = RTE_SCHED_PORT_HIERARCHY (pkt1_subport, - pkt1_pipe, - pkt1_tc, - pkt1_tc_q, - 0); - u64 pkt2_sched = RTE_SCHED_PORT_HIERARCHY (pkt2_subport, - pkt2_pipe, - pkt2_tc, - pkt2_tc_q, - 0); - u64 pkt3_sched = RTE_SCHED_PORT_HIERARCHY (pkt3_subport, - pkt3_pipe, - pkt3_tc, - pkt3_tc_q, - 0); - - pkt0->hash.sched.lo = pkt0_sched & 0xFFFFFFFF; - pkt0->hash.sched.hi = pkt0_sched >> 32; - pkt1->hash.sched.lo = pkt1_sched & 0xFFFFFFFF; - pkt1->hash.sched.hi = pkt1_sched >> 32; - pkt2->hash.sched.lo = pkt2_sched & 0xFFFFFFFF; - pkt2->hash.sched.hi = pkt2_sched >> 32; - pkt3->hash.sched.lo = pkt3_sched & 0xFFFFFFFF; - pkt3->hash.sched.hi = pkt3_sched >> 32; - } - - for (; i < n_pkts; i++) - { - struct rte_mbuf *pkt = pkts[i]; - - u8 *pkt_data = rte_pktmbuf_mtod (pkt, u8 *); - - u64 pkt_subport = BITFIELD (pkt_data, hqos->hqos_field0_slabpos, - hqos->hqos_field0_slabmask, - hqos->hqos_field0_slabshr); - u64 pkt_pipe = BITFIELD (pkt_data, hqos->hqos_field1_slabpos, - hqos->hqos_field1_slabmask, - hqos->hqos_field1_slabshr); - u64 pkt_dscp = BITFIELD (pkt_data, hqos->hqos_field2_slabpos, - hqos->hqos_field2_slabmask, - hqos->hqos_field2_slabshr); - u32 pkt_tc = hqos->hqos_tc_table[pkt_dscp & 0x3F] >> 2; - u32 pkt_tc_q = hqos->hqos_tc_table[pkt_dscp & 0x3F] & 0x3; - - u64 pkt_sched = RTE_SCHED_PORT_HIERARCHY (pkt_subport, - pkt_pipe, - pkt_tc, - pkt_tc_q, - 0); - - pkt->hash.sched.lo = pkt_sched & 0xFFFFFFFF; - pkt->hash.sched.hi = pkt_sched >> 32; - } -} - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/dpdk/hqos/qos_doc.md b/src/plugins/dpdk/hqos/qos_doc.md deleted file mode 100644 index fe3bb1bcd4b..00000000000 --- a/src/plugins/dpdk/hqos/qos_doc.md +++ /dev/null @@ -1,411 +0,0 @@ -# QoS Hierarchical Scheduler {#qos_doc} - -The Quality-of-Service (QoS) scheduler performs egress-traffic management by -prioritizing the transmission of the packets of different type services and -subscribers based on the Service Level Agreements (SLAs). The QoS scheduler can -be enabled on one or more NIC output interfaces depending upon the -requirement. - - -## Overview - -The QoS scheduler supports a number of scheduling and shaping levels which -construct hierarchical-tree. The first level in the hierarchy is port (i.e. -the physical interface) that constitutes the root node of the tree. The -subsequent level is subport which represents the group of the -users/subscribers. The individual user/subscriber is represented by the pipe -at the next level. Each user can have different traffic type based on the -criteria of specific loss rate, jitter, and latency. These traffic types are -represented at the traffic-class level in the form of different traffic- -classes. The last level contains number of queues which are grouped together -to host the packets of the specific class type traffic. - -The QoS scheduler implementation requires flow classification, enqueue and -dequeue operations. The flow classification is mandatory stage for HQoS where -incoming packets are classified by mapping the packet fields information to -5-tuple (HQoS subport, pipe, traffic class, queue within traffic class, and -color) and storing that information in mbuf sched field. The enqueue operation -uses this information to determine the queue for storing the packet, and at -this stage, if the specific queue is full, QoS drops the packet. The dequeue -operation consists of scheduling the packet based on its length and available -credits, and handing over the scheduled packet to the output interface. - -For more information on QoS Scheduler, please refer DPDK Programmer's Guide- -http://dpdk.org/doc/guides/prog_guide/qos_framework.html - - -### QoS Scheduler Parameters - -Following illustrates the default HQoS configuration for each 10GbE output -port: - -Single subport (subport 0): - - Subport rate set to 100% of port rate - - Each of the 4 traffic classes has rate set to 100% of port rate - -4K pipes per subport 0 (pipes 0 .. 4095) with identical configuration: - - Pipe rate set to 1/4K of port rate - - Each of the 4 traffic classes has rate set to 100% of pipe rate - - Within each traffic class, the byte-level WRR weights for the 4 queues are set to 1:1:1:1 - - -#### Port configuration - -``` -port { - rate 1250000000 /* Assuming 10GbE port */ - frame_overhead 24 /* Overhead fields per Ethernet frame: - * 7B (Preamble) + - * 1B (Start of Frame Delimiter (SFD)) + - * 4B (Frame Check Sequence (FCS)) + - * 12B (Inter Frame Gap (IFG)) - */ - mtu 1522 /* Assuming Ethernet/IPv4 pkt (FCS not included) */ - n_subports_per_port 1 /* Number of subports per output interface */ - n_pipes_per_subport 4096 /* Number of pipes (users/subscribers) */ - queue_sizes 64 64 64 64 /* Packet queue size for each traffic class. - * All queues within the same pipe traffic class - * have the same size. Queues from different - * pipes serving the same traffic class have - * the same size. */ -} -``` - - -#### Subport configuration - -``` -subport 0 { - tb_rate 1250000000 /* Subport level token bucket rate (bytes per second) */ - tb_size 1000000 /* Subport level token bucket size (bytes) */ - tc0_rate 1250000000 /* Subport level token bucket rate for traffic class 0 (bytes per second) */ - tc1_rate 1250000000 /* Subport level token bucket rate for traffic class 1 (bytes per second) */ - tc2_rate 1250000000 /* Subport level token bucket rate for traffic class 2 (bytes per second) */ - tc3_rate 1250000000 /* Subport level token bucket rate for traffic class 3 (bytes per second) */ - tc_period 10 /* Time interval for refilling the token bucket associated with traffic class (Milliseconds) */ - pipe 0 4095 profile 0 /* pipes (users/subscribers) configured with pipe profile 0 */ -} -``` - - -#### Pipe configuration - -``` -pipe_profile 0 { - tb_rate 305175 /* Pipe level token bucket rate (bytes per second) */ - tb_size 1000000 /* Pipe level token bucket size (bytes) */ - tc0_rate 305175 /* Pipe level token bucket rate for traffic class 0 (bytes per second) */ - tc1_rate 305175 /* Pipe level token bucket rate for traffic class 1 (bytes per second) */ - tc2_rate 305175 /* Pipe level token bucket rate for traffic class 2 (bytes per second) */ - tc3_rate 305175 /* Pipe level token bucket rate for traffic class 3 (bytes per second) */ - tc_period 40 /* Time interval for refilling the token bucket associated with traffic class at pipe level (Milliseconds) */ - tc3_oversubscription_weight 1 /* Weight traffic class 3 oversubscription */ - tc0_wrr_weights 1 1 1 1 /* Pipe queues WRR weights for traffic class 0 */ - tc1_wrr_weights 1 1 1 1 /* Pipe queues WRR weights for traffic class 1 */ - tc2_wrr_weights 1 1 1 1 /* Pipe queues WRR weights for traffic class 2 */ - tc3_wrr_weights 1 1 1 1 /* Pipe queues WRR weights for traffic class 3 */ -} -``` - - -#### Random Early Detection (RED) parameters per traffic class and color (Green / Yellow / Red) - -``` -red { - tc0_wred_min 48 40 32 /* Minimum threshold for traffic class 0 queue (min_th) in number of packets */ - tc0_wred_max 64 64 64 /* Maximum threshold for traffic class 0 queue (max_th) in number of packets */ - tc0_wred_inv_prob 10 10 10 /* Inverse of packet marking probability for traffic class 0 queue (maxp = 1 / maxp_inv) */ - tc0_wred_weight 9 9 9 /* Traffic Class 0 queue weight */ - tc1_wred_min 48 40 32 /* Minimum threshold for traffic class 1 queue (min_th) in number of packets */ - tc1_wred_max 64 64 64 /* Maximum threshold for traffic class 1 queue (max_th) in number of packets */ - tc1_wred_inv_prob 10 10 10 /* Inverse of packet marking probability for traffic class 1 queue (maxp = 1 / maxp_inv) */ - tc1_wred_weight 9 9 9 /* Traffic Class 1 queue weight */ - tc2_wred_min 48 40 32 /* Minimum threshold for traffic class 2 queue (min_th) in number of packets */ - tc2_wred_max 64 64 64 /* Maximum threshold for traffic class 2 queue (max_th) in number of packets */ - tc2_wred_inv_prob 10 10 10 /* Inverse of packet marking probability for traffic class 2 queue (maxp = 1 / maxp_inv) */ - tc2_wred_weight 9 9 9 /* Traffic Class 2 queue weight */ - tc3_wred_min 48 40 32 /* Minimum threshold for traffic class 3 queue (min_th) in number of packets */ - tc3_wred_max 64 64 64 /* Maximum threshold for traffic class 3 queue (max_th) in number of packets */ - tc3_wred_inv_prob 10 10 10 /* Inverse of packet marking probability for traffic class 3 queue (maxp = 1 / maxp_inv) */ - tc3_wred_weight 9 9 9 /* Traffic Class 3 queue weight */ -} -``` - - -### DPDK QoS Scheduler Integration in VPP - -The Hierarchical Quality-of-Service (HQoS) scheduler object could be seen as -part of the logical NIC output interface. To enable HQoS on specific output -interface, vpp startup.conf file has to be configured accordingly. The output -interface that requires HQoS, should have "hqos" parameter specified in dpdk -section. Another optional parameter "hqos-thread" has been defined which can -be used to associate the output interface with specific hqos thread. In cpu -section of the config file, "corelist-hqos-threads" is introduced to assign -logical cpu cores to run the HQoS threads. A HQoS thread can run multiple HQoS -objects each associated with different output interfaces. All worker threads -instead of writing packets to NIC TX queue directly, write the packets to a -software queues. The hqos_threads read the software queues, and enqueue the -packets to HQoS objects, as well as dequeue packets from HQOS objects and -write them to NIC output interfaces. The worker threads need to be able to -send the packets to any output interface, therefore, each HQoS object -associated with NIC output interface should have software queues equal to -worker threads count. - -Following illustrates the sample startup configuration file with 4x worker -threads feeding 2x hqos threads that handle each QoS scheduler for 1x output -interface. - -``` -dpdk { - socket-mem 16384,16384 - - dev 0000:02:00.0 { - num-rx-queues 2 - hqos - } - dev 0000:06:00.0 { - num-rx-queues 2 - hqos - } - - num-mbufs 1000000 -} - -cpu { - main-core 0 - corelist-workers 1, 2, 3, 4 - corelist-hqos-threads 5, 6 -} -``` - - -### QoS scheduler CLI Commands - -Each QoS scheduler instance is initialised with default parameters required to -configure hqos port, subport, pipe and queues. Some of the parameters can be -re-configured in run-time through CLI commands. - - -#### Configuration - -Following commands can be used to configure QoS scheduler parameters. - -The command below can be used to set the subport level parameters such as -token bucket rate (bytes per seconds), token bucket size (bytes), traffic -class rates (bytes per seconds) and token update period (Milliseconds). - -``` -set dpdk interface hqos subport subport [rate ] - [bktsize ] [tc0 ] [tc1 ] [tc2 ] [tc3 ] [period ] -``` - -For setting the pipe profile, following command can be used. - -``` -set dpdk interface hqos pipe subport pipe - profile -``` - -To assign QoS scheduler instance to the specific thread, following command can -be used. - -``` -set dpdk interface hqos placement thread -``` - -The command below is used to set the packet fields required for classifying -the incoming packet. As a result of classification process, packet field -information will be mapped to 5 tuples (subport, pipe, traffic class, pipe, -color) and stored in packet mbuf. - -``` -set dpdk interface hqos pktfield id subport|pipe|tc offset - mask -``` - -The DSCP table entries used for identifying the traffic class and queue can be set using the command below; - -``` -set dpdk interface hqos tctbl entry tc queue -``` - - -#### Show Command - -The QoS Scheduler configuration can displayed using the command below. - -``` - vpp# show dpdk interface hqos TenGigabitEthernet2/0/0 - Thread: - Input SWQ size = 4096 packets - Enqueue burst size = 256 packets - Dequeue burst size = 220 packets - Packet field 0: slab position = 0, slab bitmask = 0x0000000000000000 (subport) - Packet field 1: slab position = 40, slab bitmask = 0x0000000fff000000 (pipe) - Packet field 2: slab position = 8, slab bitmask = 0x00000000000000fc (tc) - Packet field 2 tc translation table: ([Mapped Value Range]: tc/queue tc/queue ...) - [ 0 .. 15]: 0/0 0/1 0/2 0/3 1/0 1/1 1/2 1/3 2/0 2/1 2/2 2/3 3/0 3/1 3/2 3/3 - [16 .. 31]: 0/0 0/1 0/2 0/3 1/0 1/1 1/2 1/3 2/0 2/1 2/2 2/3 3/0 3/1 3/2 3/3 - [32 .. 47]: 0/0 0/1 0/2 0/3 1/0 1/1 1/2 1/3 2/0 2/1 2/2 2/3 3/0 3/1 3/2 3/3 - [48 .. 63]: 0/0 0/1 0/2 0/3 1/0 1/1 1/2 1/3 2/0 2/1 2/2 2/3 3/0 3/1 3/2 3/3 - Port: - Rate = 1250000000 bytes/second - MTU = 1514 bytes - Frame overhead = 24 bytes - Number of subports = 1 - Number of pipes per subport = 4096 - Packet queue size: TC0 = 64, TC1 = 64, TC2 = 64, TC3 = 64 packets - Number of pipe profiles = 1 - Subport 0: - Rate = 120000000 bytes/second - Token bucket size = 1000000 bytes - Traffic class rate: TC0 = 120000000, TC1 = 120000000, TC2 = 120000000, TC3 = 120000000 bytes/second - TC period = 10 milliseconds - Pipe profile 0: - Rate = 305175 bytes/second - Token bucket size = 1000000 bytes - Traffic class rate: TC0 = 305175, TC1 = 305175, TC2 = 305175, TC3 = 305175 bytes/second - TC period = 40 milliseconds - TC0 WRR weights: Q0 = 1, Q1 = 1, Q2 = 1, Q3 = 1 - TC1 WRR weights: Q0 = 1, Q1 = 1, Q2 = 1, Q3 = 1 - TC2 WRR weights: Q0 = 1, Q1 = 1, Q2 = 1, Q3 = 1 - TC3 WRR weights: Q0 = 1, Q1 = 1, Q2 = 1, Q3 = 1 -``` - -The QoS Scheduler placement over the logical cpu cores can be displayed using -below command. - -``` - vpp# show dpdk interface hqos placement - Thread 5 (vpp_hqos-threads_0 at lcore 5): - TenGigabitEthernet2/0/0 queue 0 - Thread 6 (vpp_hqos-threads_1 at lcore 6): - TenGigabitEthernet4/0/1 queue 0 -``` - - -### QoS Scheduler Binary APIs - -This section explains the available binary APIs for configuring QoS scheduler -parameters in run-time. - -The following API can be used to set the pipe profile of a pipe that belongs -to a given subport: - -``` -sw_interface_set_dpdk_hqos_pipe rx | sw_if_index - subport pipe profile -``` - -The data structures used for set the pipe profile parameter are as follows; - -``` - /** \\brief DPDK interface HQoS pipe profile set request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param sw_if_index - the interface - @param subport - subport ID - @param pipe - pipe ID within its subport - @param profile - pipe profile ID - */ - define sw_interface_set_dpdk_hqos_pipe { - u32 client_index; - u32 context; - u32 sw_if_index; - u32 subport; - u32 pipe; - u32 profile; - }; - - /** \\brief DPDK interface HQoS pipe profile set reply - @param context - sender context, to match reply w/ request - @param retval - request return code - */ - define sw_interface_set_dpdk_hqos_pipe_reply { - u32 context; - i32 retval; - }; -``` - -The following API can be used to set the subport level parameters, for -example- token bucket rate (bytes per seconds), token bucket size (bytes), -traffic class rate (bytes per seconds) and tokens update period. - -``` -sw_interface_set_dpdk_hqos_subport rx | sw_if_index - subport [rate ] [bktsize ] - [tc0 ] [tc1 ] [tc2 ] [tc3 ] [period ] -``` - -The data structures used for set the subport level parameter are as follows; - -``` - /** \\brief DPDK interface HQoS subport parameters set request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param sw_if_index - the interface - @param subport - subport ID - @param tb_rate - subport token bucket rate (measured in bytes/second) - @param tb_size - subport token bucket size (measured in credits) - @param tc_rate - subport traffic class 0 .. 3 rates (measured in bytes/second) - @param tc_period - enforcement period for rates (measured in milliseconds) - */ - define sw_interface_set_dpdk_hqos_subport { - u32 client_index; - u32 context; - u32 sw_if_index; - u32 subport; - u32 tb_rate; - u32 tb_size; - u32 tc_rate[4]; - u32 tc_period; - }; - - /** \\brief DPDK interface HQoS subport parameters set reply - @param context - sender context, to match reply w/ request - @param retval - request return code - */ - define sw_interface_set_dpdk_hqos_subport_reply { - u32 context; - i32 retval; - }; -``` - -The following API can be used set the DSCP table entry. The DSCP table have -64 entries to map the packet DSCP field onto traffic class and hqos input -queue. - -``` -sw_interface_set_dpdk_hqos_tctbl rx | sw_if_index - entry tc queue -``` - -The data structures used for setting DSCP table entries are given below. - -``` - /** \\brief DPDK interface HQoS tctbl entry set request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param sw_if_index - the interface - @param entry - entry index ID - @param tc - traffic class (0 .. 3) - @param queue - traffic class queue (0 .. 3) - */ - define sw_interface_set_dpdk_hqos_tctbl { - u32 client_index; - u32 context; - u32 sw_if_index; - u32 entry; - u32 tc; - u32 queue; - }; - - /** \\brief DPDK interface HQoS tctbl entry set reply - @param context - sender context, to match reply w/ request - @param retval - request return code - */ - define sw_interface_set_dpdk_hqos_tctbl_reply { - u32 context; - i32 retval; - }; -``` -- cgit 1.2.3-korg