From d86199fda2b770d54226760a53939464e328019b Mon Sep 17 00:00:00 2001 From: Dante Su Date: Thu, 13 Jan 2022 05:57:31 +0000 Subject: [PATCH 1/8] link-training: initial commit Signed-off-by: Dante Su --- .../port-link-training-design.md | 336 ++++++++++++++++++ 1 file changed, 336 insertions(+) create mode 100644 doc/port_link_training/port-link-training-design.md diff --git a/doc/port_link_training/port-link-training-design.md b/doc/port_link_training/port-link-training-design.md new file mode 100644 index 0000000000..191ab3d108 --- /dev/null +++ b/doc/port_link_training/port-link-training-design.md @@ -0,0 +1,336 @@ +# SONiC Port Link Training Design # + +## Table of Content + +- [Revision](#revision) +- [Scope](#scope) +- [Abbreviations](#abbreviations) +- [Overview](#overview) +- [Requirements](#requirements) +- [Architecture Design](#architecture-design) +- [High-Level Design](#high-level-design) +- [SAI API Requirement](#sai-api-requirement) +- [Configuration and management ](#configuration-and-management) + - [CLI Enhancements](#cli-enhancements) + - [Config link training mode](#config-link-training-mode) + - [Show link training status](#show-link-training-status) + - [Config DB Enhancements](#config-db-enhancements) + - [Application DB Enhancements](#application-db-enhancements) + - [YANG Model Enhancements](#yang-model-enhancements) + - [DB Migration Considerations](#db-migration-considerations) + - [SWSS Enhancements](#swss-enhancements) + - [PMON xcvrd Considerations](#pmon-xcvrd-considerations) +- [Warmboot Design Impact](#warmboot-design-impact) +- [Limitations](#limitations) +- [Testing Requirements](#testing-requirements) + - [Unit Test cases](#unit-test-cases) + - [System Test cases](#system-test-cases) +- [Action items](#action-items) + +### Revision + + | Rev | Date | Author | Change Description | + |:---:|:-----------:|:------------------:|-----------------------------------| + | 0.1 | | Dante (Kuo-Jung) Su| Initial version | + +### Scope +This document is the design document for port link training feature on SONiC. This includes the requirements, DB schema change, DB migrator change, yang model change and swss change. + +### Abbreviations + + | Term | Meaning | + |:-------:|:----------------------------------------| + | ASIC | Application-Specific Integrated Circuit | + | BER | Bit Error Rate | + | FIR | Finite Impulse Response | + | SFP | Small Form-factor Pluggable transceiver | + +### Overview + +Link training is a process by which the transmitter and receiver on a high-speed serial link communicate with each other in order to tune their equalization settings. In theory, link training enables automatic tuning of the FIR filter for each channel in an ASIC to achieve the desired bit error rate (BER) + +In current SONiC implementation, user can leverage the platform-specific [media_settings.json](https://github.com/Azure/SONiC/blob/master/doc/media-settings/Media-based-Port-settings.md) to statically update the TX FIR per attached transceiver to improve BER. However, the ODM vendors rarely provide the pre-calibrated pre-emphasis for the CR/KR transceivers, which could result in the link reliability issues. + +The IEEE 802.3 standard defines a set of link training protocols for various mediums, and the feature in this document is to focus on IEEE clause 72 and 93 to dynamically improve the link quality over the SFP coppers/backplanes. + +This feature could be activated with or without port auto negotiation. + +### Requirements + +The main goal of this document is to discuss the design of following requirement: + +- Allow user to configure link training +- Allow user to get the operational link training status + +### Architecture Design + +This feature does not change the existing SONiC architecture, while it has to change the configuration flow for port link training which will be covered in orchagent. + +### High-Level Design + +- SAI API requirements is covered in section [SAI API Requirement](#sai-api-requirement). +- A few new CLI commands will be added to sonic-utilities sub module. These CLI commands support user to configure link training mode as well as show port link training status. See detail description in section [CLI Enhancements](#cli-enhancements). +- A few new fields will be added to existing table in APPL_DB and CONFIG_DB to support link training attributes. See detail description in section [Config DB Enhancements](#config-db-enhancements) and [Application DB Enhancements](#application-db-enhancements). +- YANG Model needs update according to the DB schema change. See detail description in section [YANG Model Enhancements](#yang-model-enhancements) +- PMON xcvrd needs to update transceiver capability to APPL_DB to provide a hint to swss#orchagent for the advanced port link training controls. See detail description in section [PMON xcvrd Considerations](#pmon-xcvrd-considerations) +- Port configuration setting flow will be changed in orchagent of sonic-swss. See detail description in section [SWSS Enhancements](#swss-enhancements). + +### SAI API Requirement + +Currently, SAI already defines all the necessary port attributes to support port link training. + +```cpp + /** + * @brief Enable/Disable Port Link Training + * + * @type bool + * @flags CREATE_AND_SET + * @default false + */ + SAI_PORT_ATTR_LINK_TRAINING_ENABLE, + + /** + * @brief Link training failure status and error codes + * + * @type sai_port_link_training_failure_status_t + * @flags READ_ONLY + */ + SAI_PORT_ATTR_LINK_TRAINING_FAILURE_STATUS, + + /** + * @brief Status whether the receiver trained or not trained to receive data + * + * @type sai_port_link_training_rx_status_t + * @flags READ_ONLY + */ + SAI_PORT_ATTR_LINK_TRAINING_RX_STATUS, +``` + +Vendor-specific SAI implementation is not in the scope of this document, but there are some common requirements for SAI: + +1. SAI implementation must return error code if any of the above attributes is not supported, swss and syncd must not crash. +2. SAI implementation must keep port link training disabled by default for backward compatible. As long as swss and SAI keep backward compatible, user need not change anything after this feature is implemented and available in SONiC. + +### Configuration and management + +#### CLI Enhancements + +A few new CLI commands are designed to support port link training. + +##### Config link training mode + +``` +Format: + config interface link-training + +Arguments: + interface_name: name of the interface to be configured. e.g: Ethernet0 + mode: link training mode, can be either "auto", "on" or "off" + +Example: + config interface link-training Ethernet0 auto + config interface link-training Ethernet0 off + +Return: + error message if interface_name or mode is invalid otherwise empty +``` + +##### Show link training status + +A new CLI command will be added to display the port link training status. All data of this command are fetched from **APPL_DB**. + +``` +Format: + show interfaces link-training status + +Arguments: + interface_name: optional. Name of the interface to be shown. e.g: Ethernet0. If interface_name is not given, this command shows link training status for all interfaces. + +Example: + show interfaces link-training status + show interfaces link-training status Ethernet0 + +Return: + error message if interface_name is invalid otherwise: + +admin@sonic:~$ show interfaces link-training status + Interface LT Oper LT Admin LT Failure LT RxStatus Oper Admin +----------- --------- ---------- ------------ ------------- ------ ------- + Ethernet0 on on none trained up up + Ethernet8 off off - - down up + Ethernet16 on auto none trained up up + Ethernet24 off - - - down up + Ethernet32 off - - - down up +``` + + +#### Config DB Enhancements + +A new field **link_training** will be added to **PORT** table: + + ; Defines information for port configuration + key = PORT|port_name ; configuration of the port + ; field = value + ... + link_training = STRING ; link training configuration + +Valid value of the new fields are described below: + +- link_training: +String value, the administratively specified port link training configuration. +When "link_training" is not specified, the port link training should be disabled + + | Mode | Description | + |:----:|:---------------------------------------------------------------:| + | auto | Enable link-training if applicable to the transceiver attached | + | on | Enable link-training regardless of the transceiver type | + | off | Disable link-training | + +For deployment considerations, users are encouraged to use only **auto** and **off** for the **link_training**, while the **on** mode is for test purpose, it should only be activated when the transceiver is not correctly identified by the pmon#xcvrd, and forcing link-training enabled is intended. + +#### Application DB Enhancements + +The following fields will be introduced into **PORT_TABLE** table: + + ; Defines information for port configuration + key = PORT_TABLE:port_name ; configuration of the port + ; field = value + ... + link_training = STRING ; operational link training config + link_training_status = STRING ; operational link training status + link_training_failure = STRING ; operational link training failure status + link_training_rxstatus = STRING ; operational link training rx status + xcvr_capabilities = STRING ; transceiver capabilities + +- link_training: +String value, the admin port link training config. +- link_training_status: +String value, the operational port link training status. "on" indicates port link training is enabled, otherwise disabled. +- link_training_failure: +String value, the operational port link training failure status. "none" indicates no error is detected, otherwise any of the link training failure status defined in SAI. For example: "none", "lock", "snr" and "timeout". +- link_training_rxstatus: +String value, the operational port link training rx status. any of the link training rx status defined in SAI. For example: "trained", "not-trained". +- xcvr_capabilities: +String value, the transceiver capabilities provided by pmon#xcvrd, it's a set of capabilities separated by comma, where "LT" stands for "link training". See detail description in section [PMON xcvrd Considerations](#pmon-xcvrd-considerations) + +To minimize system overhead, instead of periodically fetching the operational link training status, the corresponding fields in the APPL_DB will only be updated in the following events + +- Per-Port link status changes +In this case, only the **link_training_status** will be updated. + +- Explicitly link training status refresh requests via the notification model. +In this case, the **link_training_failure** and **link_training_rxstatus** of the selected port will be refreshed. See detail description in section [Link Training Status Refresh](#link-training-status-refresh) + +Here is the table to map the fields and SAI attributes: + +| **Parameter** | **sai_port_attr_t** +|:-----------------------|:-------------------------------------------| +| link_training | SAI_PORT_ATTR_LINK_TRAINING_ENABLE | +| link_training_failure | SAI_PORT_ATTR_LINK_TRAINING_FAILURE_STATUS | +| link_training_rxstatus | SAI_PORT_ATTR_LINK_TRAINING_RX_STATUS | + +Please note the operational port link training status in the APPL_DB could be different from the administratively configured link training configuration in the CONFIG_DB due to the hardware limitations or vendor-specific SAI software implementations. For example, port link training is only applicable to the ports with speed >= 10G, and it's not applicable for chip-to-module transceivers. + +#### YANG Model Enhancements + +The port yang model needs to update according to DB schema change. The yang model changes of new fields are described below: + +``` +leaf link_training { + type string { + pattern "auto|on|off"; + } +} +``` + +These new yang leaf will be added to sonic-port.yang. + +#### DB Migration Considerations + +By having port link training disabled if "link_training" is not specified in the CONFIG_DB, this feature is fully backward compatible. + +#### SWSS Enhancements + +##### Port Configuration Flow + +The current SONiC port configuration flow in PortsOrch can be described in following pseudo code: + +``` +port = getPort(alias) +if autoneg changed: + setPortAutoNeg(port, autoneg) +``` + +The new SONiC port configuration flow can be described in following pseudo code: + +``` +port = getPort(alias) +if autoneg changed: + setPortAutoNeg(port, autoneg) + +if link_training changed and xcvr_capabilities has LT: + setPortLinkTraining(port, link_training) +``` + +##### Link Training Status Refresh + +To refresh the operational link training status in APPL_DB, a new notification handler will be introduced to PortsOrch, the pseudo code is as follow: + +``` +portCtrlConsumer = NotificationConsumer("PORT_CTRL") +if portCtrlConsumer received 'op=port_status_refresh', 'data=EthernetXY' and 'type=link_training': + refreshPortLinkTrainingStatus(EthernetXY) +``` + +An example code snippet of initiating status refresh is as follow: + +``` +appl_db = daemon_base.db_connect("APPL_DB") +port_np = swsscommon.NotificationProducer(appl_db, "PORT_CTRL") + +fvp = swsscommon.FieldValuePairs([ + ('type', 'link_training') +]) +port_np.send('port_state_refresh', port, fvp) +``` + +#### PMON xcvrd Considerations + +Given that port link training shall not be enabled on certain transceivers. For example, a chip-to-module transceiver. It's better to have pmon#xcvrd provide a hint to the swss#orchagent for the advanced link training controls. Hence, **xcvr_capabilities** is introduced into APPL_DB. + +When **link_training=auto**, swss#orchagent should request syncd to enable port link training only if **LT** is specified in **xcvr_capabilities**. + +### Warmboot Design Impact + +SAI and lower layer must not flap port during warmboot no matter what link training parameter is given. + +### Limitations + +N/A + +### Testing Requirements + +#### Unit Test cases + +For **sonic-platform-daemons**, we will leverage the existing [test_xcvrd.py](https://github.com/Azure/sonic-platform-daemons/blob/master/sonic-xcvrd/tests/test_xcvrd.py) for this. A few new test cases will be added: + +1. Test attribute xcvr_capabilities on both SFP insertion and removal scenario. Verify xcvr_capabilities is added/dropped from APPL_DB and has correct value. +2. Test attribute xcvr_capabilities for a QSFP/QSFP-DD DAC transceiver. Verify xcvr_capabilities is in APPL_DB and with "LT". +3. Test attribute xcvr_capabilities for a QSFP/QSFP-DD DR transceiver. Verify xcvr_capabilities is in APPL_DB and without "LT". + +For **sonic-swss**, we will leverage the existing [test_port.py](https://github.com/Azure/sonic-swss/blob/master/tests/test_port.py) for this. A few new test cases will be added: + +1. Test attribute **link_training** on both direct and warm-reboot scenario. Verify SAI_PORT_ATTR_LINK_TRAINING_ENABLE, SAI_PORT_ATTR_LINK_TRAINING_FAILURE_STATUS and SAI_PORT_ATTR_LINK_TRAINING_RX_STATUS are in ASIC_DB and has correct value. + +For **sonic-utilities**, we will leverage the existing [unit test framework](https://github.com/Azure/sonic-utilities/tree/master/tests) for this. A few new test cases will be added: + +1. Test command `config interface link-training `. Verify the command return error if given invalid interface_name or mode. + +#### System Test cases + +Will leverage sonic-mgmt to test this feature. + +### Action items + +TBD + From 5d1fb59ae0eaceef199910b44f8745fe960561e6 Mon Sep 17 00:00:00 2001 From: Dante Su Date: Fri, 18 Feb 2022 14:54:31 +0000 Subject: [PATCH 2/8] Address review comments Signed-off-by: Dante Su --- .../port-link-training-design.md | 162 ++++++++++++------ 1 file changed, 106 insertions(+), 56 deletions(-) diff --git a/doc/port_link_training/port-link-training-design.md b/doc/port_link_training/port-link-training-design.md index 191ab3d108..1024c88e46 100644 --- a/doc/port_link_training/port-link-training-design.md +++ b/doc/port_link_training/port-link-training-design.md @@ -32,10 +32,13 @@ | Rev | Date | Author | Change Description | |:---:|:-----------:|:------------------:|-----------------------------------| | 0.1 | | Dante (Kuo-Jung) Su| Initial version | + | 0.2 | | Dante (Kuo-Jung) Su| Addressing code review comments | ### Scope This document is the design document for port link training feature on SONiC. This includes the requirements, DB schema change, DB migrator change, yang model change and swss change. +The link-training controls in this document is SAI specific, the Gearbox design is outside the scope of this document. + ### Abbreviations | Term | Meaning | @@ -108,8 +111,9 @@ Currently, SAI already defines all the necessary port attributes to support port Vendor-specific SAI implementation is not in the scope of this document, but there are some common requirements for SAI: -1. SAI implementation must return error code if any of the above attributes is not supported, swss and syncd must not crash. -2. SAI implementation must keep port link training disabled by default for backward compatible. As long as swss and SAI keep backward compatible, user need not change anything after this feature is implemented and available in SONiC. +1. swss must check the link-training capabilities before making the corresponding request to syncd. +2. SAI implementation must return error code if any of the above attributes is not supported, swss and syncd must not crash. +3. SAI implementation must keep port link training disabled by default for backward compatibility. As long as swss and SAI keep backward compatible, user need not change anything after this feature is implemented and available in SONiC. ### Configuration and management @@ -119,32 +123,38 @@ A few new CLI commands are designed to support port link training. ##### Config link training mode + ``` Format: - config interface link-training + config interface link-training [-f] Arguments: - interface_name: name of the interface to be configured. e.g: Ethernet0 - mode: link training mode, can be either "auto", "on" or "off" + interface_name: [mandatory] name of the interface to be configured. e.g: Ethernet0 + mode: [mandatory] link training mode, can be either "on" or "off" + -f: [optional] forcing link-training configuration on an unsupported transceiver Example: config interface link-training Ethernet0 auto config interface link-training Ethernet0 off Return: - error message if interface_name or mode is invalid otherwise empty + - error message if interface_name or mode is invalid + - error message if the link-training is not supported on the interface + - empty upon success ``` +For deployment considerations, when the link-training is enabled on a transceiver without LT capabilities, the swss#orchagent should log an error into syslog, and the config command should also report the error and get aborted, unless '-f' option is specified. + ##### Show link training status -A new CLI command will be added to display the port link training status. All data of this command are fetched from **APPL_DB**. +A new CLI command will be added to display the port link training status. All data of this command are fetched from **STATE_DB**. ``` Format: show interfaces link-training status Arguments: - interface_name: optional. Name of the interface to be shown. e.g: Ethernet0. If interface_name is not given, this command shows link training status for all interfaces. + interface_name: [optional] Name of the interface to be shown. e.g: Ethernet0. If interface_name is not given, this command shows link training status for all interfaces. Example: show interfaces link-training status @@ -154,13 +164,15 @@ Return: error message if interface_name is invalid otherwise: admin@sonic:~$ show interfaces link-training status - Interface LT Oper LT Admin LT Failure LT RxStatus Oper Admin ------------ --------- ---------- ------------ ------------- ------ ------- - Ethernet0 on on none trained up up - Ethernet8 off off - - down up - Ethernet16 on auto none trained up up - Ethernet24 off - - - down up - Ethernet32 off - - - down up + Interface LT Oper LT Admin Oper Admin Error Description +----------- ----------- ---------- ------ ------- ----------------------- + Ethernet0 trained on up up unsupported transceiver + Ethernet8 off - down up - + Ethernet16 trained on up up unsupported transceiver + Ethernet24 off - down up - + Ethernet32 not trained on down up - + Ethernet40 off - down up - + Ethernet48 off - down up - ``` @@ -182,12 +194,9 @@ When "link_training" is not specified, the port link training should be disabled | Mode | Description | |:----:|:---------------------------------------------------------------:| - | auto | Enable link-training if applicable to the transceiver attached | - | on | Enable link-training regardless of the transceiver type | + | on | Enable link-training | | off | Disable link-training | -For deployment considerations, users are encouraged to use only **auto** and **off** for the **link_training**, while the **on** mode is for test purpose, it should only be activated when the transceiver is not correctly identified by the pmon#xcvrd, and forcing link-training enabled is intended. - #### Application DB Enhancements The following fields will be introduced into **PORT_TABLE** table: @@ -196,40 +205,62 @@ The following fields will be introduced into **PORT_TABLE** table: key = PORT_TABLE:port_name ; configuration of the port ; field = value ... - link_training = STRING ; operational link training config - link_training_status = STRING ; operational link training status - link_training_failure = STRING ; operational link training failure status - link_training_rxstatus = STRING ; operational link training rx status + link_training = STRING ; operational link training admin config xcvr_capabilities = STRING ; transceiver capabilities - link_training: -String value, the admin port link training config. -- link_training_status: -String value, the operational port link training status. "on" indicates port link training is enabled, otherwise disabled. -- link_training_failure: -String value, the operational port link training failure status. "none" indicates no error is detected, otherwise any of the link training failure status defined in SAI. For example: "none", "lock", "snr" and "timeout". -- link_training_rxstatus: -String value, the operational port link training rx status. any of the link training rx status defined in SAI. For example: "trained", "not-trained". -- xcvr_capabilities: -String value, the transceiver capabilities provided by pmon#xcvrd, it's a set of capabilities separated by comma, where "LT" stands for "link training". See detail description in section [PMON xcvrd Considerations](#pmon-xcvrd-considerations) +String value, the port link training admin config. +- xcvr_capabilities: +String value, the transceiver capabilities provided by pmon#xcvrd, it's a set of capabilities separated by comma, where "LT" stands for "link training". The list of possible values is as follow + +| Capability | Description | +|:---------------:|:----------------------| +| AN | Auto Negotiation | +| LT | Link Training | To minimize system overhead, instead of periodically fetching the operational link training status, the corresponding fields in the APPL_DB will only be updated in the following events -- Per-Port link status changes -In this case, only the **link_training_status** will be updated. +#### State DB Enhancements + +A new table **LINK_TRAINING** with the following fields will be introduced into STATE_DB: + + ; Defines information for port link-training states + key = LINK_TRAINING:port_name ; port link-training states + ; field = value + status = STRING ; operational link training status + err_description = STRING ; error description from swss#orchagent + +- status: +String value, the operational port link training status. The list of possible values is as follow + + | Status | Description | + |:-----------:|:------------------------------------------------------------------:| + | off | Disabled | + | on | Enabled, while the further operational status is not yet available | + | trained | Enabled, while the pre-emphasis is tuned successfully | + | not_trained | Enabled, while the pre-emphasis is not yet tuned, no further failure is available | + | frame_lock | Enabled, while the training frame delineation is detected | + | snr_low | Enabled, while the SNR low threshold is detected | + | timeout | Enabled, while the training process is timed out | -- Explicitly link training status refresh requests via the notification model. -In this case, the **link_training_failure** and **link_training_rxstatus** of the selected port will be refreshed. See detail description in section [Link Training Status Refresh](#link-training-status-refresh) +- err_description: +String value, the error description reported by the swss#orchagent, possible values is as follow + + | err_description | Description | + |:-----------------------:|:--------------------------------------------------------:| + | none | None of failure is detected | + | feature unavailable | The link-training is not supported by the switch silicon | + | internal error | A software failure is detected in swss, syncd or SAI | + | unsupported transceiver | The link-training is not supported by the transceiver | + +#### SAI attributes Here is the table to map the fields and SAI attributes: | **Parameter** | **sai_port_attr_t** |:-----------------------|:-------------------------------------------| | link_training | SAI_PORT_ATTR_LINK_TRAINING_ENABLE | -| link_training_failure | SAI_PORT_ATTR_LINK_TRAINING_FAILURE_STATUS | -| link_training_rxstatus | SAI_PORT_ATTR_LINK_TRAINING_RX_STATUS | - -Please note the operational port link training status in the APPL_DB could be different from the administratively configured link training configuration in the CONFIG_DB due to the hardware limitations or vendor-specific SAI software implementations. For example, port link training is only applicable to the ports with speed >= 10G, and it's not applicable for chip-to-module transceivers. +| link_training_status | SAI_PORT_ATTR_LINK_TRAINING_RX_STATUS, SAI_PORT_ATTR_LINK_TRAINING_FAILURE_STATUS | #### YANG Model Enhancements @@ -238,7 +269,7 @@ The port yang model needs to update according to DB schema change. The yang mode ``` leaf link_training { type string { - pattern "auto|on|off"; + pattern "on|off"; } } ``` @@ -268,37 +299,56 @@ port = getPort(alias) if autoneg changed: setPortAutoNeg(port, autoneg) -if link_training changed and xcvr_capabilities has LT: +if link_training changed and "LT" in xcvr_capabilities: + if (link_training == "on") and (LT not in xcvr_capabilities): + log_warn("LT is not applicable to this transceiver") setPortLinkTraining(port, link_training) ``` ##### Link Training Status Refresh -To refresh the operational link training status in APPL_DB, a new notification handler will be introduced to PortsOrch, the pseudo code is as follow: +A timer will also be introduced into PortsOrch for polling link-training status: ``` -portCtrlConsumer = NotificationConsumer("PORT_CTRL") -if portCtrlConsumer received 'op=port_status_refresh', 'data=EthernetXY' and 'type=link_training': - refreshPortLinkTrainingStatus(EthernetXY) +while PortsOrch is alive: + sleep_sec(3) + for port in all_port_list: + updatePortLinkTrainingStatus(port) ``` -An example code snippet of initiating status refresh is as follow: +The updatePortLinkTrainingStatus(port) can be furtherly described in following pseudo code: ``` -appl_db = daemon_base.db_connect("APPL_DB") -port_np = swsscommon.NotificationProducer(appl_db, "PORT_CTRL") - -fvp = swsscommon.FieldValuePairs([ - ('type', 'link_training') -]) -port_np.send('port_state_refresh', port, fvp) +if port is not physical_port: + return + +status = "off" +if link-training is supported by the SAI and is enabled: + status = getLinkTrainingRxStatus(port) + if status != trained: + error = getLinkTrainingFailure(port) + if error != "none": + status = error + else: + status = "not_trained" +updateLinkTrainingStateDB(port, status) ``` #### PMON xcvrd Considerations Given that port link training shall not be enabled on certain transceivers. For example, a chip-to-module transceiver. It's better to have pmon#xcvrd provide a hint to the swss#orchagent for the advanced link training controls. Hence, **xcvr_capabilities** is introduced into APPL_DB. -When **link_training=auto**, swss#orchagent should request syncd to enable port link training only if **LT** is specified in **xcvr_capabilities**. +As of now, only CR transceivers will be identified as link-training capabile, and this will be triggered at the transceiver insertion events, the pseudo code is follow: + +``` +def get_media_capability(port): + caps = [] + info = get_transceiver_info(port) + if 'GBASE-CR' in info.get('specification_compliance'): + caps.append('LT') + return ",".join(caps) if len(caps) > 0 else 'N/A' +``` + ### Warmboot Design Impact @@ -320,7 +370,7 @@ For **sonic-platform-daemons**, we will leverage the existing [test_xcvrd.py](ht For **sonic-swss**, we will leverage the existing [test_port.py](https://github.com/Azure/sonic-swss/blob/master/tests/test_port.py) for this. A few new test cases will be added: -1. Test attribute **link_training** on both direct and warm-reboot scenario. Verify SAI_PORT_ATTR_LINK_TRAINING_ENABLE, SAI_PORT_ATTR_LINK_TRAINING_FAILURE_STATUS and SAI_PORT_ATTR_LINK_TRAINING_RX_STATUS are in ASIC_DB and has correct value. +1. Test attribute **link_training** on both direct and warm-reboot scenario. Verify SAI_PORT_ATTR_LINK_TRAINING_ENABLE is in ASIC_DB and has correct value. For **sonic-utilities**, we will leverage the existing [unit test framework](https://github.com/Azure/sonic-utilities/tree/master/tests) for this. A few new test cases will be added: From 50558604beef85cfd3cc9fa4b8d004df0446aa23 Mon Sep 17 00:00:00 2001 From: Dante Su Date: Fri, 25 Feb 2022 08:14:04 +0000 Subject: [PATCH 3/8] cosmetic updates Signed-off-by: Dante Su --- doc/port_link_training/port-link-training-design.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/port_link_training/port-link-training-design.md b/doc/port_link_training/port-link-training-design.md index 1024c88e46..ce95aac94b 100644 --- a/doc/port_link_training/port-link-training-design.md +++ b/doc/port_link_training/port-link-training-design.md @@ -134,7 +134,8 @@ Arguments: -f: [optional] forcing link-training configuration on an unsupported transceiver Example: - config interface link-training Ethernet0 auto + config interface link-training Ethernet0 on + config interface link-training Ethernet0 on -f config interface link-training Ethernet0 off Return: @@ -154,7 +155,8 @@ Format: show interfaces link-training status Arguments: - interface_name: [optional] Name of the interface to be shown. e.g: Ethernet0. If interface_name is not given, this command shows link training status for all interfaces. + interface_name: [optional] Name of the interface to be shown. e.g: Ethernet0. + If interface_name is not given, this command shows link training status for all interfaces. Example: show interfaces link-training status @@ -227,8 +229,8 @@ A new table **LINK_TRAINING** with the following fields will be introduced into ; Defines information for port link-training states key = LINK_TRAINING:port_name ; port link-training states ; field = value - status = STRING ; operational link training status - err_description = STRING ; error description from swss#orchagent + status = STRING ; hardware operational status + err_description = STRING ; software error description - status: String value, the operational port link training status. The list of possible values is as follow From ec399de723997aa4276fc7cc2b31033d4b88628f Mon Sep 17 00:00:00 2001 From: Dante Su Date: Wed, 9 Mar 2022 01:25:36 +0000 Subject: [PATCH 4/8] drop xcvrd changes, add support for LT ability query Signed-off-by: Dante Su --- .../port-link-training-design.md | 73 +++++++------------ 1 file changed, 27 insertions(+), 46 deletions(-) diff --git a/doc/port_link_training/port-link-training-design.md b/doc/port_link_training/port-link-training-design.md index ce95aac94b..0e6409b149 100644 --- a/doc/port_link_training/port-link-training-design.md +++ b/doc/port_link_training/port-link-training-design.md @@ -19,7 +19,6 @@ - [YANG Model Enhancements](#yang-model-enhancements) - [DB Migration Considerations](#db-migration-considerations) - [SWSS Enhancements](#swss-enhancements) - - [PMON xcvrd Considerations](#pmon-xcvrd-considerations) - [Warmboot Design Impact](#warmboot-design-impact) - [Limitations](#limitations) - [Testing Requirements](#testing-requirements) @@ -37,7 +36,7 @@ ### Scope This document is the design document for port link training feature on SONiC. This includes the requirements, DB schema change, DB migrator change, yang model change and swss change. -The link-training controls in this document is SAI specific, the Gearbox design is outside the scope of this document. +The link-training hardware controls in this document is SAI specific, while the Gearbox design is outside the scope of this document. ### Abbreviations @@ -75,12 +74,11 @@ This feature does not change the existing SONiC architecture, while it has to ch - A few new CLI commands will be added to sonic-utilities sub module. These CLI commands support user to configure link training mode as well as show port link training status. See detail description in section [CLI Enhancements](#cli-enhancements). - A few new fields will be added to existing table in APPL_DB and CONFIG_DB to support link training attributes. See detail description in section [Config DB Enhancements](#config-db-enhancements) and [Application DB Enhancements](#application-db-enhancements). - YANG Model needs update according to the DB schema change. See detail description in section [YANG Model Enhancements](#yang-model-enhancements) -- PMON xcvrd needs to update transceiver capability to APPL_DB to provide a hint to swss#orchagent for the advanced port link training controls. See detail description in section [PMON xcvrd Considerations](#pmon-xcvrd-considerations) - Port configuration setting flow will be changed in orchagent of sonic-swss. See detail description in section [SWSS Enhancements](#swss-enhancements). ### SAI API Requirement -Currently, SAI already defines all the necessary port attributes to support port link training. +First of all, we'll leverage the existing SAI port attributes listed below ```cpp /** @@ -109,9 +107,21 @@ Currently, SAI already defines all the necessary port attributes to support port SAI_PORT_ATTR_LINK_TRAINING_RX_STATUS, ``` +On the other hand, a new port attribute will be introduced for the link-training ability query, and please note the link-training ability could be unavailable on the certain ports on a switch silicon (e.g. The uplink/management ports), hence we need to do the query at per-port basis. + +```cpp + /** + * @brief Query link-training support + * + * @type bool + * @flags READ_ONLY + */ + SAI_PORT_ATTR_SUPPORTED_LINK_TRAINING_MODE, +``` + Vendor-specific SAI implementation is not in the scope of this document, but there are some common requirements for SAI: -1. swss must check the link-training capabilities before making the corresponding request to syncd. +1. swss must check the link-training abilities before making the corresponding request to syncd. 2. SAI implementation must return error code if any of the above attributes is not supported, swss and syncd must not crash. 3. SAI implementation must keep port link training disabled by default for backward compatibility. As long as swss and SAI keep backward compatible, user need not change anything after this feature is implemented and available in SONiC. @@ -144,7 +154,7 @@ Return: - empty upon success ``` -For deployment considerations, when the link-training is enabled on a transceiver without LT capabilities, the swss#orchagent should log an error into syslog, and the config command should also report the error and get aborted, unless '-f' option is specified. +For deployment considerations, when the link-training is enabled on a transceiver without LT capabilities, this config command should report an error and get aborted, unless '-f' option is specified. ##### Show link training status @@ -208,19 +218,9 @@ The following fields will be introduced into **PORT_TABLE** table: ; field = value ... link_training = STRING ; operational link training admin config - xcvr_capabilities = STRING ; transceiver capabilities - link_training: String value, the port link training admin config. -- xcvr_capabilities: -String value, the transceiver capabilities provided by pmon#xcvrd, it's a set of capabilities separated by comma, where "LT" stands for "link training". The list of possible values is as follow - -| Capability | Description | -|:---------------:|:----------------------| -| AN | Auto Negotiation | -| LT | Link Training | - -To minimize system overhead, instead of periodically fetching the operational link training status, the corresponding fields in the APPL_DB will only be updated in the following events #### State DB Enhancements @@ -230,7 +230,7 @@ A new table **LINK_TRAINING** with the following fields will be introduced into key = LINK_TRAINING:port_name ; port link-training states ; field = value status = STRING ; hardware operational status - err_description = STRING ; software error description + supported = STRING ; hardware link-training ability status of the switch - status: String value, the operational port link training status. The list of possible values is as follow @@ -245,15 +245,13 @@ String value, the operational port link training status. The list of possible va | snr_low | Enabled, while the SNR low threshold is detected | | timeout | Enabled, while the training process is timed out | -- err_description: -String value, the error description reported by the swss#orchagent, possible values is as follow +- supported: +String value, the hardware link-training ability status of the switch, this is a constant of the underlying switch silicon regardless of the transceivers attached, the swss#orchagent should populate this information during startup. The list of possible values is as follow - | err_description | Description | - |:-----------------------:|:--------------------------------------------------------:| - | none | None of failure is detected | - | feature unavailable | The link-training is not supported by the switch silicon | - | internal error | A software failure is detected in swss, syncd or SAI | - | unsupported transceiver | The link-training is not supported by the transceiver | + | Status | Description | + |:-----------:|:-------------:| + | yes | Supported | + | no | Not Supported | #### SAI attributes @@ -284,6 +282,10 @@ By having port link training disabled if "link_training" is not specified in the #### SWSS Enhancements +##### Port Link-Training Ability Flag + +During system startup, PortsOrch should query for the per-port link-training abilities from syncd, and populate these flags into **LINK_TRAINING** table of [STATE_DB](#state-db-enhancements) + ##### Port Configuration Flow The current SONiC port configuration flow in PortsOrch can be described in following pseudo code: @@ -336,21 +338,6 @@ if link-training is supported by the SAI and is enabled: updateLinkTrainingStateDB(port, status) ``` -#### PMON xcvrd Considerations - -Given that port link training shall not be enabled on certain transceivers. For example, a chip-to-module transceiver. It's better to have pmon#xcvrd provide a hint to the swss#orchagent for the advanced link training controls. Hence, **xcvr_capabilities** is introduced into APPL_DB. - -As of now, only CR transceivers will be identified as link-training capabile, and this will be triggered at the transceiver insertion events, the pseudo code is follow: - -``` -def get_media_capability(port): - caps = [] - info = get_transceiver_info(port) - if 'GBASE-CR' in info.get('specification_compliance'): - caps.append('LT') - return ",".join(caps) if len(caps) > 0 else 'N/A' -``` - ### Warmboot Design Impact @@ -364,12 +351,6 @@ N/A #### Unit Test cases -For **sonic-platform-daemons**, we will leverage the existing [test_xcvrd.py](https://github.com/Azure/sonic-platform-daemons/blob/master/sonic-xcvrd/tests/test_xcvrd.py) for this. A few new test cases will be added: - -1. Test attribute xcvr_capabilities on both SFP insertion and removal scenario. Verify xcvr_capabilities is added/dropped from APPL_DB and has correct value. -2. Test attribute xcvr_capabilities for a QSFP/QSFP-DD DAC transceiver. Verify xcvr_capabilities is in APPL_DB and with "LT". -3. Test attribute xcvr_capabilities for a QSFP/QSFP-DD DR transceiver. Verify xcvr_capabilities is in APPL_DB and without "LT". - For **sonic-swss**, we will leverage the existing [test_port.py](https://github.com/Azure/sonic-swss/blob/master/tests/test_port.py) for this. A few new test cases will be added: 1. Test attribute **link_training** on both direct and warm-reboot scenario. Verify SAI_PORT_ATTR_LINK_TRAINING_ENABLE is in ASIC_DB and has correct value. From caf78d8c196af64ea9ad83f9d633f0e4bc59b282 Mon Sep 17 00:00:00 2001 From: Dante Su Date: Thu, 10 Mar 2022 07:20:56 +0000 Subject: [PATCH 5/8] address review comments Signed-off-by: Dante Su --- .../port-link-training-design.md | 38 ++++++++----------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/doc/port_link_training/port-link-training-design.md b/doc/port_link_training/port-link-training-design.md index 0e6409b149..5d4d33236c 100644 --- a/doc/port_link_training/port-link-training-design.md +++ b/doc/port_link_training/port-link-training-design.md @@ -136,26 +136,21 @@ A few new CLI commands are designed to support port link training. ``` Format: - config interface link-training [-f] + config interface link-training Arguments: interface_name: [mandatory] name of the interface to be configured. e.g: Ethernet0 mode: [mandatory] link training mode, can be either "on" or "off" - -f: [optional] forcing link-training configuration on an unsupported transceiver Example: config interface link-training Ethernet0 on - config interface link-training Ethernet0 on -f config interface link-training Ethernet0 off Return: - error message if interface_name or mode is invalid - - error message if the link-training is not supported on the interface - empty upon success ``` -For deployment considerations, when the link-training is enabled on a transceiver without LT capabilities, this config command should report an error and get aborted, unless '-f' option is specified. - ##### Show link training status A new CLI command will be added to display the port link training status. All data of this command are fetched from **STATE_DB**. @@ -176,15 +171,15 @@ Return: error message if interface_name is invalid otherwise: admin@sonic:~$ show interfaces link-training status - Interface LT Oper LT Admin Oper Admin Error Description ------------ ----------- ---------- ------ ------- ----------------------- - Ethernet0 trained on up up unsupported transceiver - Ethernet8 off - down up - - Ethernet16 trained on up up unsupported transceiver - Ethernet24 off - down up - - Ethernet32 not trained on down up - - Ethernet40 off - down up - - Ethernet48 off - down up - + Interface LT Oper LT Admin Oper Admin +----------- ----------- ---------- ------ ------- + Ethernet0 trained on up up + Ethernet8 off - down up + Ethernet16 trained on up up + Ethernet24 off - down up + Ethernet32 not trained on down up + Ethernet40 off - down up + Ethernet48 off - down up ``` @@ -257,10 +252,11 @@ String value, the hardware link-training ability status of the switch, this is a Here is the table to map the fields and SAI attributes: -| **Parameter** | **sai_port_attr_t** -|:-----------------------|:-------------------------------------------| -| link_training | SAI_PORT_ATTR_LINK_TRAINING_ENABLE | -| link_training_status | SAI_PORT_ATTR_LINK_TRAINING_RX_STATUS, SAI_PORT_ATTR_LINK_TRAINING_FAILURE_STATUS | +| **Parameter** | **sai_port_attr_t** | +|:--------------------------|:-------------------------------------------| +| link_training (APPL_DB) | SAI_PORT_ATTR_LINK_TRAINING_ENABLE | +| status (STATE_DB) | SAI_PORT_ATTR_LINK_TRAINING_RX_STATUS, SAI_PORT_ATTR_LINK_TRAINING_FAILURE_STATUS | +| supported (STATE_DB) | SAI_PORT_ATTR_SUPPORTED_LINK_TRAINING_MODE | #### YANG Model Enhancements @@ -303,9 +299,7 @@ port = getPort(alias) if autoneg changed: setPortAutoNeg(port, autoneg) -if link_training changed and "LT" in xcvr_capabilities: - if (link_training == "on") and (LT not in xcvr_capabilities): - log_warn("LT is not applicable to this transceiver") +if link_training changed: setPortLinkTraining(port, link_training) ``` From 9809574eca3d6febe919ff64826261277e933a46 Mon Sep 17 00:00:00 2001 From: Dante Su Date: Thu, 17 Mar 2022 02:02:36 +0000 Subject: [PATCH 6/8] add test cases to sonic-mgmt Signed-off-by: Dante Su --- doc/port_link_training/port-link-training-design.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/port_link_training/port-link-training-design.md b/doc/port_link_training/port-link-training-design.md index 5d4d33236c..42f71eeb5d 100644 --- a/doc/port_link_training/port-link-training-design.md +++ b/doc/port_link_training/port-link-training-design.md @@ -355,7 +355,16 @@ For **sonic-utilities**, we will leverage the existing [unit test framework](htt #### System Test cases -Will leverage sonic-mgmt to test this feature. +The following tests will be introduced into **sonic-mgmt** for this feature. + +- test_link_training + Test all candidate ports by having interface/media type updated to copper followed by link-training enablement. Verification criteria: + - All ports are up when link-training is activated + - All ports are up with link-training status equals to 'trained' +- test_link_training_negative + Test all candidate ports by having interface/media type updated to fiber followed by link-training enablement. Verification criteria: + - All ports are down when link-training is activated + - All ports are down without link-training status equals to 'trained' ### Action items From 75208f5f087126b958730f2b60d8ccbbedbbab92 Mon Sep 17 00:00:00 2001 From: Dante Su Date: Mon, 18 Apr 2022 08:49:41 +0000 Subject: [PATCH 7/8] add flow diagrams and pre-emphasis restoration Signed-off-by: Dante Su --- doc/port_link_training/flow-lt-config.png | Bin 0 -> 29118 bytes doc/port_link_training/flow-lt-status.png | Bin 0 -> 27124 bytes .../port-link-training-design.md | 93 ++++++------------ 3 files changed, 32 insertions(+), 61 deletions(-) create mode 100644 doc/port_link_training/flow-lt-config.png create mode 100644 doc/port_link_training/flow-lt-status.png diff --git a/doc/port_link_training/flow-lt-config.png b/doc/port_link_training/flow-lt-config.png new file mode 100644 index 0000000000000000000000000000000000000000..82f8d337260ee7edd3966a764633f2fa92f8ef8f GIT binary patch literal 29118 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∋S__U~G<=Yo0&bl6MaoZ7%wY>j4;SGBB93DTD`X z7;o9B0-Ek;*h}Y&k2u-jS)ofI{IVPk&|YHVv6uU4U*zbUz!W?t<{x%WFpaU+T9#woa}5#a~AW26#f zJ2xJoZB9KGWfBqq2TnO|q8O1?^fys`+pCc&)elF;2_lc`C=`B zIxnxlPdtlUN5SgbH6+6TaUO4h>0;Nq_9GJrv8Ui9Oz_Sd*3U;`q*OM<*?4N@tA3N; z{_UA7z2%O1(z%~&^;S};jl;KfVRxdl=RKlTlkZ~)`yuMd1NMENeW45s)M-O!iuKG} zOv%l9P4RWK*LfNAz79o|9Lz@(!brO%E%p*t_f5~$L|QYsfbOB0P8_f7vd^8LgsStM zW;V=N2O~VcmxP$gP4_&={OVd7=|zbLHK~}T*LmOuUFfLuqm}$Lc`FrbiBlVDB3D}} z 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 O2a=Okk}8%k4*Fl?0744@ literal 0 HcmV?d00001 diff --git a/doc/port_link_training/flow-lt-status.png b/doc/port_link_training/flow-lt-status.png new file mode 100644 index 0000000000000000000000000000000000000000..133e3662ec7816eddfe86300e5a7dfcbda5d89cd GIT binary patch literal 27124 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 literal 0 HcmV?d00001 diff --git a/doc/port_link_training/port-link-training-design.md b/doc/port_link_training/port-link-training-design.md index 42f71eeb5d..4f582deae4 100644 --- a/doc/port_link_training/port-link-training-design.md +++ b/doc/port_link_training/port-link-training-design.md @@ -16,6 +16,7 @@ - [Show link training status](#show-link-training-status) - [Config DB Enhancements](#config-db-enhancements) - [Application DB Enhancements](#application-db-enhancements) + - [State DB Enhancements](#state-db-enhancements) - [YANG Model Enhancements](#yang-model-enhancements) - [DB Migration Considerations](#db-migration-considerations) - [SWSS Enhancements](#swss-enhancements) @@ -53,7 +54,7 @@ Link training is a process by which the transmitter and receiver on a high-speed In current SONiC implementation, user can leverage the platform-specific [media_settings.json](https://github.com/Azure/SONiC/blob/master/doc/media-settings/Media-based-Port-settings.md) to statically update the TX FIR per attached transceiver to improve BER. However, the ODM vendors rarely provide the pre-calibrated pre-emphasis for the CR/KR transceivers, which could result in the link reliability issues. -The IEEE 802.3 standard defines a set of link training protocols for various mediums, and the feature in this document is to focus on IEEE clause 72 and 93 to dynamically improve the link quality over the SFP coppers/backplanes. +The IEEE 802.3 standard defines a set of link training protocols for various mediums, and the feature in this document is to focus on IEEE clause 72 and 93 to dynamically improve the link quality over the SFP coppers and backplanes. This feature could be activated with or without port auto negotiation. @@ -72,7 +73,7 @@ This feature does not change the existing SONiC architecture, while it has to ch - SAI API requirements is covered in section [SAI API Requirement](#sai-api-requirement). - A few new CLI commands will be added to sonic-utilities sub module. These CLI commands support user to configure link training mode as well as show port link training status. See detail description in section [CLI Enhancements](#cli-enhancements). -- A few new fields will be added to existing table in APPL_DB and CONFIG_DB to support link training attributes. See detail description in section [Config DB Enhancements](#config-db-enhancements) and [Application DB Enhancements](#application-db-enhancements). +- A few new fields will be added to existing table in APPL_DB and CONFIG_DB to support link training attributes. See detail description in section [Config DB Enhancements](#config-db-enhancements), [Application DB Enhancements](#application-db-enhancements) and [State DB Enhancements](#state-db-enhancements) - YANG Model needs update according to the DB schema change. See detail description in section [YANG Model Enhancements](#yang-model-enhancements) - Port configuration setting flow will be changed in orchagent of sonic-swss. See detail description in section [SWSS Enhancements](#swss-enhancements). @@ -121,7 +122,7 @@ On the other hand, a new port attribute will be introduced for the link-training Vendor-specific SAI implementation is not in the scope of this document, but there are some common requirements for SAI: -1. swss must check the link-training abilities before making the corresponding request to syncd. +1. swss must check the link-training abilities before making the corresponding requests to syncd. 2. SAI implementation must return error code if any of the above attributes is not supported, swss and syncd must not crash. 3. SAI implementation must keep port link training disabled by default for backward compatibility. As long as swss and SAI keep backward compatible, user need not change anything after this feature is implemented and available in SONiC. @@ -219,15 +220,14 @@ String value, the port link training admin config. #### State DB Enhancements -A new table **LINK_TRAINING** with the following fields will be introduced into STATE_DB: +The following fields will be introduced into **PORT_TABLE** table: ; Defines information for port link-training states - key = LINK_TRAINING:port_name ; port link-training states - ; field = value - status = STRING ; hardware operational status - supported = STRING ; hardware link-training ability status of the switch + key = PORT_TABLE:port_name ; port link-training states + ; field = value + link_training_status = STRING ; port link-training operational status -- status: +- link_training_status: String value, the operational port link training status. The list of possible values is as follow | Status | Description | @@ -240,23 +240,14 @@ String value, the operational port link training status. The list of possible va | snr_low | Enabled, while the SNR low threshold is detected | | timeout | Enabled, while the training process is timed out | -- supported: -String value, the hardware link-training ability status of the switch, this is a constant of the underlying switch silicon regardless of the transceivers attached, the swss#orchagent should populate this information during startup. The list of possible values is as follow - - | Status | Description | - |:-----------:|:-------------:| - | yes | Supported | - | no | Not Supported | - #### SAI attributes Here is the table to map the fields and SAI attributes: | **Parameter** | **sai_port_attr_t** | |:--------------------------|:-------------------------------------------| -| link_training (APPL_DB) | SAI_PORT_ATTR_LINK_TRAINING_ENABLE | -| status (STATE_DB) | SAI_PORT_ATTR_LINK_TRAINING_RX_STATUS, SAI_PORT_ATTR_LINK_TRAINING_FAILURE_STATUS | -| supported (STATE_DB) | SAI_PORT_ATTR_SUPPORTED_LINK_TRAINING_MODE | +| link_training | SAI_PORT_ATTR_LINK_TRAINING_ENABLE | +| link_training_status | SAI_PORT_ATTR_LINK_TRAINING_RX_STATUS, SAI_PORT_ATTR_LINK_TRAINING_FAILURE_STATUS | #### YANG Model Enhancements @@ -280,58 +271,38 @@ By having port link training disabled if "link_training" is not specified in the ##### Port Link-Training Ability Flag -During system startup, PortsOrch should query for the per-port link-training abilities from syncd, and populate these flags into **LINK_TRAINING** table of [STATE_DB](#state-db-enhancements) - -##### Port Configuration Flow +During system startup, PortsOrch should query for the per-port link-training abilities from syncd, and have these per-port flags maintained in the **m_port_cap_lt** field of **Port** object. -The current SONiC port configuration flow in PortsOrch can be described in following pseudo code: - -``` -port = getPort(alias) -if autoneg changed: - setPortAutoNeg(port, autoneg) +i.e. +```cpp +class Port +{ + ...... + bool m_port_cap_lt = false; /* Port Capability - LinkTraining */ +}; ``` -The new SONiC port configuration flow can be described in following pseudo code: +##### Port Link-Training Configuration Flow -``` -port = getPort(alias) -if autoneg changed: - setPortAutoNeg(port, autoneg) +in PortsOrch, the port Link-Training configuration flow is as follows, the link-training may or may not be disabled when auto-negotiation is activated, it depends on the switch ASIC limitations in the individual SAI implementation, and the pre-emphasis configuration request should be saved and replayed upon link-training configuration updates: -if link_training changed: - setPortLinkTraining(port, link_training) -``` +![](flow_lt_config.png) -##### Link Training Status Refresh +##### Port Link-Training Status Poll -A timer will also be introduced into PortsOrch for polling link-training status: +A timer thread will be introduced into PortsOrch for polling link-training status, the per-port status poll will be activated upon the following events -``` -while PortsOrch is alive: - sleep_sec(3) - for port in all_port_list: - updatePortLinkTrainingStatus(port) -``` +- Link-Training is transitoned to be enabled on a port +- Link is down on a port with Link-Training enabled -The updatePortLinkTrainingStatus(port) can be furtherly described in following pseudo code: +On the other hand, the per-port status poll will be de-activated upon the following events -``` -if port is not physical_port: - return - -status = "off" -if link-training is supported by the SAI and is enabled: - status = getLinkTrainingRxStatus(port) - if status != trained: - error = getLinkTrainingFailure(port) - if error != "none": - status = error - else: - status = "not_trained" -updateLinkTrainingStateDB(port, status) -``` +- Link-Training is transitoned to be disabled on a port +- Link is up on a port with Link-Training enabled + +This timer is a single-threaded task that polls the status of all ports one by one, the program flow is as follows +![](flow_lt_status.png) ### Warmboot Design Impact From 5b8291a3c2770b84ebb1827f037c123201cb4745 Mon Sep 17 00:00:00 2001 From: Dante Su Date: Mon, 18 Apr 2022 08:54:17 +0000 Subject: [PATCH 8/8] fix the typos in filename of flow diagrams Signed-off-by: Dante Su --- doc/port_link_training/port-link-training-design.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/port_link_training/port-link-training-design.md b/doc/port_link_training/port-link-training-design.md index 4f582deae4..18db296b67 100644 --- a/doc/port_link_training/port-link-training-design.md +++ b/doc/port_link_training/port-link-training-design.md @@ -286,7 +286,7 @@ class Port in PortsOrch, the port Link-Training configuration flow is as follows, the link-training may or may not be disabled when auto-negotiation is activated, it depends on the switch ASIC limitations in the individual SAI implementation, and the pre-emphasis configuration request should be saved and replayed upon link-training configuration updates: -![](flow_lt_config.png) +![](flow-lt-config.png) ##### Port Link-Training Status Poll @@ -302,7 +302,7 @@ On the other hand, the per-port status poll will be de-activated upon the follow This timer is a single-threaded task that polls the status of all ports one by one, the program flow is as follows -![](flow_lt_status.png) +![](flow-lt-status.png) ### Warmboot Design Impact