diff --git a/keywords/cloud_platform/system/ptp/ptp_readiness_keywords.py b/keywords/cloud_platform/system/ptp/ptp_readiness_keywords.py index f0b60a84..038e5a59 100644 --- a/keywords/cloud_platform/system/ptp/ptp_readiness_keywords.py +++ b/keywords/cloud_platform/system/ptp/ptp_readiness_keywords.py @@ -1,4 +1,6 @@ -from framework.validation.validation import validate_equals_with_retry +from typing import Union + +from framework.validation.validation import validate_equals_with_retry, validate_list_contains_with_retry from keywords.ptp.pmc.pmc_keywords import PMCKeywords @@ -52,13 +54,13 @@ class PTPReadinessKeywords: validate_equals_with_retry(lambda: check_port_state_in_port_data_set(name), expected_port_states, "port state in port data set", 120, 30) - def wait_for_clock_class_appear_in_grandmaster_settings_np(self, name: str, expected_clock_class: int) -> None: + def wait_for_clock_class_appear_in_grandmaster_settings_np(self, name: str, expected_clock_class: Union[int, list]) -> None: """ Waits until the clock class observed in the grandmaster settings np match the expected clock class, or times out. Args: name (str): Name of the PTP instance. - expected_clock_class (int): expected clock class to wait for. + expected_clock_class (Union[int, list]): expected clock class to wait for. Raises: Exception: If expected clock class do not appear within the timeout. @@ -84,15 +86,16 @@ class PTPReadinessKeywords: return observed_clock_class - validate_equals_with_retry(lambda: get_clock_class_in_grandmaster_settings_np(name), expected_clock_class, "clock class in grandmaster settings np", 120, 30) + exp_clock_class = expected_clock_class if isinstance(expected_clock_class, list) else [expected_clock_class] + validate_list_contains_with_retry(lambda: get_clock_class_in_grandmaster_settings_np(name), exp_clock_class, "clock class in grandmaster settings np", 120, 30) - def wait_for_gm_clock_class_appear_in_parent_data_set(self, name: str, expected_gm_clock_class: int) -> None: + def wait_for_gm_clock_class_appear_in_parent_data_set(self, name: str, expected_gm_clock_class: Union[int, list]) -> None: """ Waits until the gm clock class observed in the parent data set match the expected clock class, or times out. Args: name (str): Name of the PTP instance. - expected_gm_clock_class (int): expected gm clock class to wait for. + expected_gm_clock_class (Union[int, list]): expected gm clock class to wait for. Raises: Exception: If expected gm clock class do not appear within the timeout. @@ -118,4 +121,5 @@ class PTPReadinessKeywords: return observed_gm_clock_class - validate_equals_with_retry(lambda: get_gm_clock_class_in_parent_data_set(name), expected_gm_clock_class, "gm clock class in parent data set", 120, 30) + exp_gm_clock_class = expected_gm_clock_class if isinstance(expected_gm_clock_class, list) else [expected_gm_clock_class] + validate_list_contains_with_retry(lambda: get_gm_clock_class_in_parent_data_set(name), exp_gm_clock_class, "gm clock class in parent data set", 120, 30) diff --git a/keywords/cloud_platform/system/ptp/ptp_verify_config_keywords.py b/keywords/cloud_platform/system/ptp/ptp_verify_config_keywords.py index 1f8a2883..91736df4 100644 --- a/keywords/cloud_platform/system/ptp/ptp_verify_config_keywords.py +++ b/keywords/cloud_platform/system/ptp/ptp_verify_config_keywords.py @@ -7,7 +7,6 @@ from keywords.base_keyword import BaseKeyword from keywords.cloud_platform.fault_management.alarms.alarm_list_keywords import AlarmListKeywords from keywords.cloud_platform.ssh.lab_connection_keywords import LabConnectionKeywords from keywords.cloud_platform.system.host.system_host_list_keywords import SystemHostListKeywords -from keywords.linux.systemctl.systemctl_status_keywords import SystemCTLStatusKeywords from keywords.ptp.cat.cat_clock_conf_keywords import CatClockConfKeywords from keywords.ptp.cat.cat_ptp_cgu_keywords import CatPtpCguKeywords from keywords.ptp.cat.cat_ptp_config_keywords import CatPtpConfigKeywords @@ -504,7 +503,7 @@ class PTPVerifyConfigKeywords(BaseKeyword): ptp4l_expected_obj = self.ptp_setup.get_ptp4l_expected_by_name(name) expected_parent_data_set_obj = ptp4l_expected_obj.get_parent_data_set_for_hostname(hostname) - validate_equals(parent_data_set_obj.get_gm_clock_class(), expected_parent_data_set_obj.get_gm_clock_class(), "gm.ClockClass value within GET PARENT_DATA_SET") + validate_list_contains(parent_data_set_obj.get_gm_clock_class(), expected_parent_data_set_obj.get_gm_clock_class(), "gm.ClockClass value within GET PARENT_DATA_SET") validate_equals(parent_data_set_obj.get_gm_clock_accuracy(), expected_parent_data_set_obj.get_gm_clock_accuracy(), "gm.ClockAccuracy value within GET PARENT_DATA_SET") validate_equals(parent_data_set_obj.get_gm_offset_scaled_log_variance(), expected_parent_data_set_obj.get_gm_offset_scaled_log_variance(), "gm.OffsetScaledLogVariance value within GET PARENT_DATA_SET") @@ -626,7 +625,7 @@ class PTPVerifyConfigKeywords(BaseKeyword): expected_time_source = expected_grandmaster_settings_obj.get_time_source() expected_current_utc_offset_valid = expected_grandmaster_settings_obj.get_current_utc_offset_valid() - validate_equals(observed_clock_class, expected_clock_class, "clockClass value within GET GRANDMASTER_SETTINGS_NP") + validate_list_contains(observed_clock_class, expected_clock_class, "clockClass value within GET GRANDMASTER_SETTINGS_NP") validate_equals(observed_clock_accuracy, expected_clock_accuracy, "clockAccuracy value within GET GRANDMASTER_SETTINGS_NP") validate_equals(observed_offset_scaled_log_variance, expected_offset_scaled_log_variance, "offsetScaledLogVariance value within GET GRANDMASTER_SETTINGS_NP") validate_equals(observed_current_utc_offset_valid, expected_current_utc_offset_valid, "currentUtcOffsetValid value within GET GRANDMASTER_SETTINGS_NP") diff --git a/keywords/ptp/gnss_keywords.py b/keywords/ptp/gnss_keywords.py index 851ee71e..0b90673e 100644 --- a/keywords/ptp/gnss_keywords.py +++ b/keywords/ptp/gnss_keywords.py @@ -112,12 +112,16 @@ class GnssKeywords(BaseKeyword): raise Exception(f"GPIO switch port not configured for {hostname} {nic}") # Export GPIO pin if not already exported - export_cmd = f"if [ ! -d /sys/class/gpio/gpio{gpio_switch_port} ]; then echo {gpio_switch_port} > /sys/class/gpio/export; fi" + export_cmd = f"if [ ! -d /sys/class/gpio/gpio{gpio_switch_port} ]; then echo {gpio_switch_port} > /sys/class/gpio/export; sleep 0.5; fi" gnss_ssh_connection.send(export_cmd) + # sleep needed even with retry loop + time.sleep(1) # Set direction to output direction_cmd = f"echo out > /sys/class/gpio/gpio{gpio_switch_port}/direction" gnss_ssh_connection.send(direction_cmd) + # sleep needed even with retry loop + time.sleep(1) # Set GPIO value to 1 (power on GNSS) value_cmd = f"echo 1 > /sys/class/gpio/gpio{gpio_switch_port}/value" @@ -147,12 +151,16 @@ class GnssKeywords(BaseKeyword): raise Exception(f"GPIO switch port not configured for {hostname} {nic}") # Export GPIO pin if not already exported - export_cmd = f"if [ ! -d /sys/class/gpio/gpio{gpio_switch_port} ]; then echo {gpio_switch_port} > /sys/class/gpio/export; fi" + export_cmd = f"if [ ! -d /sys/class/gpio/gpio{gpio_switch_port} ]; then echo {gpio_switch_port} > /sys/class/gpio/export; sleep 0.5; fi" gnss_ssh_connection.send(export_cmd) + # sleep needed even with retry loop + time.sleep(1) # Set direction to output direction_cmd = f"echo out > /sys/class/gpio/gpio{gpio_switch_port}/direction" gnss_ssh_connection.send(direction_cmd) + # sleep needed even with retry loop + time.sleep(1) # Set GPIO value to 0 (power off GNSS) value_cmd = f"echo 0 > /sys/class/gpio/gpio{gpio_switch_port}/value" diff --git a/keywords/ptp/setup/object/parent_data_set.py b/keywords/ptp/setup/object/parent_data_set.py index 76027e53..50ec7f54 100644 --- a/keywords/ptp/setup/object/parent_data_set.py +++ b/keywords/ptp/setup/object/parent_data_set.py @@ -15,7 +15,8 @@ class ParentDataSet: """ if "gm_clock_class" not in expected_dict: raise Exception("Every expected dict should have a gm_clock_class.") - self.gm_clock_class = expected_dict["gm_clock_class"] + gm_clock_class = expected_dict["gm_clock_class"] + self.gm_clock_class = gm_clock_class if isinstance(gm_clock_class, list) else [gm_clock_class] if "gm_clock_accuracy" not in expected_dict: raise Exception("Every expected dict should have a gm_clock_accuracy.") @@ -25,12 +26,12 @@ class ParentDataSet: raise Exception("Every expected dict should have a gm_offset_scaled_log_variance.") self.gm_offset_scaled_log_variance = expected_dict["gm_offset_scaled_log_variance"] - def get_gm_clock_class(self) -> int: + def get_gm_clock_class(self) -> list: """ Gets the gm clock class. Returns: - int: The gm clock class. + list: The gm clock class. """ return self.gm_clock_class diff --git a/testcases/cloud_platform/regression/ptp/README.rst b/testcases/cloud_platform/regression/ptp/README.rst index 67239ea0..19284eb8 100644 --- a/testcases/cloud_platform/regression/ptp/README.rst +++ b/testcases/cloud_platform/regression/ptp/README.rst @@ -153,58 +153,6 @@ Prerequisites 3. Confirm all nodes are up and running 4. PTP services should be configured but not necessarily synchronized -Test Execution ------------- - -To run all PTP tests: - -.. code-block:: bash - - python -m pytest starlingx/testcases/cloud_platform/regression/ptp/test_ptp.py -v - -To run a specific test: - -.. code-block:: bash - - python -m pytest starlingx/testcases/cloud_platform/regression/ptp/test_ptp.py::test_ptp_operation_gnss_disable -v - -Test Cases -========= - -test_ptp_operation_gnss_disable ------------------------------ - -**Purpose**: Verify PTP behavior when GNSS signal is lost and then restored. - -**Steps**: -1. Turn off GNSS for Controller-0 NIC1 using GPIO control -2. Verify alarms are triggered (100.119) -3. Verify clock class degradation (248 for holdover mode) -4. Verify PMC configuration with GNSS off -5. Turn GNSS back on -6. Verify alarms clear -7. Verify clock class restoration (6 for normal operation) -8. Verify PMC configuration after restoration - -**Expected Results**: -- When GNSS is off, system should enter holdover mode with appropriate alarms -- When GNSS is restored, system should return to normal operation with alarms cleared - -test_ptp_operation_phc_ctl_time_change ------------------------------------- - -**Purpose**: Verify PTP behavior when hardware clocks are manually adjusted. - -**Steps**: -1. Start phc_ctl loop on controller-0 NIC1 to introduce time drift -2. Verify out-of-tolerance alarms are triggered -3. Stop the adjustment and verify alarms clear -4. Repeat the process for controller-1 NIC2 - -**Expected Results**: -- Manual clock adjustments should trigger out-of-tolerance alarms -- When adjustments stop, system should recover and alarms should clear - Common Alarms ============ @@ -293,7 +241,7 @@ Common Issues and Solutions - Check for proper delay mechanism configuration Diagnostic Commands and Interpretation --------------------------------- +================================ Below are essential commands for diagnosing PTP issues, along with explanations of what to look for in the output: @@ -350,17 +298,68 @@ Below are essential commands for diagnosing PTP issues, along with explanations **Understanding Clock Class Values:** -- **6**: Synchronized to primary reference (GNSS) - Optimal -- **7**: Synchronized to primary reference but holdover capable - Good -- **13-14**: Synchronized to application-specific source - Acceptable -- **52**: Degraded reference but synchronized - Warning +- **6**: Synchronized to primary reference (GNSS) - Highest accuracy +- **7**: Synchronized to primary reference but in holdover - Starting to drift +- **13-14**: Synchronized to application-specific source - Alternative reference +- **52**: Degraded reference but synchronized - Reduced accuracy +- **165**: Clock in holdover mode after losing synchronization - Drifting - **187**: In holdover but within specifications - Warning - **193**: In holdover, out of specifications - Problem -- **248**: Default/Holdover/Uncalibrated - Problem -- **255**: Slave-only clock - Normal for slave devices +- **248**: Default/uncalibrated clock - Worst quality, complete loss +- **255**: Slave-only clock - Receives time, never provides it + +**Clock Accuracy Values:** +- **0x20**: "±25 nanoseconds - Highest accuracy with GNSS lock", +- **0x21**: "±100 nanoseconds - Very high accuracy", +- **0x22**: "±250 nanoseconds - High accuracy", +- **0xFE**: "Unknown - Accuracy cannot be determined (typically in holdover)", +- **0xFF**: "Reserved/Invalid - Not used for synchronization" + +**Port States:** +- **MASTER**: "Port provides timing to downstream devices", +- **SLAVE**: "Port receives timing from an upstream master", +- **PASSIVE**: "Port is not currently used for synchronization", +- **LISTENING**: "Port is monitoring the network but not synchronized", +- **FAULTY**: "Port has detected a fault condition", +- **DISABLED**: "Port is administratively disabled", +- **UNCALIBRATED**: "Port is in the process of calibrating", +- **PRE_MASTER**: "Port is transitioning to MASTER state" +} + +** Flag Values:** +- **time_traceable_1**: "Time is traceable to a primary reference (GNSS/UTC)", +- **time_traceable_0**: "Time is not traceable to a primary reference", +- **frequency_traceable_1**: "Frequency is traceable to a primary reference", +- **frequency_traceable_0**: "Frequency is not traceable to a primary reference", +- **current_utc_offset_valid_1**: "The UTC offset is valid and can be trusted", +- **current_utc_offset_valid_0**: "The UTC offset is not valid and cannot be trusted" + +## Clock Accuracy Values + +| Accuracy Value | Description | Meaning in Tests | +|----------------|-------------|------------------| +| 0x20 | ±25 nanoseconds | Highest accuracy, typically with GNSS lock | +| 0x21 | ±100 nanoseconds | Very high accuracy | +| 0x22 | ±250 nanoseconds | High accuracy | +| 0xFE | Unknown | Accuracy cannot be determined (typically in holdover) | +| 0xFF | Reserved/Invalid | Not used for synchronization | + +## Port States + +| Port State | Description | Test Implications | +|------------|-------------|-------------------| +| MASTER | Port provides timing to downstream devices | Device is acting as time source | +| SLAVE | Port receives timing from an upstream master | Device is synchronizing to another clock | +| PASSIVE | Port is not currently used for synchronization | Monitoring only, not active in timing path | +| LISTENING | Port is monitoring the network but not synchronized | Initial state or recovering from error | +| FAULTY | Port has detected a fault condition | Problem with timing or physical connection | +| DISABLED | Port is administratively disabled | Not participating in PTP | +| UNCALIBRATED | Port is in the process of calibrating | Transitional state during initialization | +| PRE_MASTER | Port is transitioning to MASTER state | Temporary state before becoming MASTER | + References and Learning Resources -=========================== +================================ Standards and Specifications -------------------------- diff --git a/testcases/cloud_platform/regression/ptp/test_ptp.py b/testcases/cloud_platform/regression/ptp/test_ptp.py index e3daa58e..2fcd5c5a 100644 --- a/testcases/cloud_platform/regression/ptp/test_ptp.py +++ b/testcases/cloud_platform/regression/ptp/test_ptp.py @@ -500,6 +500,22 @@ def test_ptp_operation_gnss_off_and_on(): Preconditions: - System is set up with valid PTP configuration as defined in ptp_configuration_expectation_compute.json5. + + Notes: + When analyzing test results, pay attention to: + 1. **Clock Class Transitions**: + - 6 → 7: Brief GNSS signal loss, entering holdover + - 6 → 248: Complete GNSS signal loss, uncalibrated + - 248 → 6: GNSS signal recovery + + 2. **Port State Changes**: + - MASTER → SLAVE: Loss of reference or better clock available + - SLAVE → MASTER: Becoming best available clock + - Any state → FAULTY: Hardware or connectivity issue + + 3. **Flag Value Changes**: + - time_traceable 1 → 0: Loss of traceable time reference + - frequency_traceable 1 → 0: Loss of traceable frequency reference """ lab_connect_keywords = LabConnectionKeywords() ssh_connection = lab_connect_keywords.get_active_controller_ssh() @@ -510,45 +526,66 @@ def test_ptp_operation_gnss_off_and_on(): selected_instances = [("ptp1", "controller-0", []), ("ptp1", "controller-1", []), ("ptp3", "controller-0", []), ("ptp4", "controller-1", [])] - # controller-0 with GNSS disabled demotes itself (clockClass: 248) and becomes a SLAVE. - # controller-1 (still in degraded state but better than 248) becomes MASTER. - # Synchronization continues from controller-1 to controller-0. - # External clients (e.g., Proxmox) continue receiving PTP sync via remaining MASTER ports. - # Clock quality degradation is tracked via clock_class, accuracy, and variance. + # Flag Values: + # time_traceable=1: Time is traceable to primary reference (GNSS/UTC) + # time_traceable=0: Time is not traceable to primary reference + # frequency_traceable=1: Frequency is traceable to primary reference + # frequency_traceable=0: Frequency is not traceable to primary reference + # current_utc_offset_valid=0: UTC offset cannot be trusted without GNSS + # + # When GNSS signal is lost: + # - Controller-0 changes from clock class 6 to 7 (brief loss) or 248 (complete loss) + # - Port roles may reverse with the best available clock becoming MASTER + # - External clients continue receiving time from both controllers + # + # Role Changes During GNSS Signal Loss + # When GNSS signal is lost, the following changes occur in the PTP network: + + # 1. Controller-0 with GNSS: + # - Clock class changes from 6 (GNSS-synchronized) to 248 (uncalibrated) + # - Port state changes from MASTER to SLAVE + # - time_traceable and frequency_traceable flags change from 1 to 0 + + # 2. Controller-1 without direct GNSS: + # - Takes over as best available time source with clock class 165 + # - Port state changes from SLAVE to MASTER + # - Becomes the new reference for Controller-0 + + # 3. External Clients: + # - Continue receiving time from both controllers + # - Service availability is maintained despite degraded accuracy + + # This role reversal ensures that the best available clock is always used as the reference, + # maintaining time synchronization even when the primary reference is lost. ctrl0_nic1_gnss_disable_exp_dict = """{ "ptp4l": [ { "name": "ptp1", "controller-0": { "parent_data_set": { - "gm_clock_class": 165, // GM is in holdover or degraded mode due to GNSS loss + "gm_clock_class": 7, // GM is in holdover or degraded mode due to GNSS loss "gm_clock_accuracy": "0xfe", // Accuracy unknown due to GNSS signal loss "gm_offset_scaled_log_variance": "0xffff" // Clock stability unknown }, "time_properties_data_set": { "current_utc_offset": 37, // Standard UTC offset (can be static) "current_utc_offset_valid": 0, // UTC offset is not currently valid - "time_traceable": 0, // Time is not traceable to a valid source - "frequency_traceable": 0 // Frequency is not traceable to a valid reference + "time_traceable": 1, // Time is not traceable to a valid source + "frequency_traceable": 1 // Frequency is not traceable to a valid reference }, "grandmaster_settings": { - "clock_class": 248, // Indicates GNSS signal is lost (free-running or degraded) + "clock_class": 7, // Indicates GNSS signal is lost (free-running or degraded) "clock_accuracy": "0xfe", // Accuracy is unknown "offset_scaled_log_variance": "0xffff", // Clock variance is unknown - "time_traceable": 0, // Time not traceable - "frequency_traceable": 0, // Frequency not traceable + "time_traceable": 1, // Time not traceable + "frequency_traceable": 1, // Frequency not traceable "time_source": "0xa0", // Time source originally GNSS (0xA0) "current_utc_offset_valid": 0 // UTC offset invalid due to signal loss }, "port_data_set": [ { "interface": "{{ controller_0.nic1.nic_connection.interface }}", - "port_state": "SLAVE", // Now syncing from controller-1, no longer acting as GM - "parent_port_identity" : { - "name": "ptp1", // Source PTP instance (controller-1) - "hostname":"controller-1", // Controller now acting as GM - "interface": "{{ controller_1.nic1.nic_connection.interface }}" // Source interface on controller-1 - }, + "port_state": "MASTER", }, { "interface": "{{ controller_0.nic1.conn_to_proxmox }}", @@ -558,18 +595,18 @@ def test_ptp_operation_gnss_off_and_on(): }, "controller-1": { "parent_data_set": { - "gm_clock_class": 165, // Controller-1 is GM but in holdover/degraded state + "gm_clock_class": 7, "gm_clock_accuracy": "0xfe", // Unknown accuracy "gm_offset_scaled_log_variance": "0xffff" // Unknown clock variance }, "time_properties_data_set": { "current_utc_offset": 37, "current_utc_offset_valid": 0, - "time_traceable": 0, - "frequency_traceable": 0 + "time_traceable": 1, + "frequency_traceable": 1 }, "grandmaster_settings": { - "clock_class": 165, // Controller-1 is acting as the best available GM + "clock_class": [165,248], "clock_accuracy": "0xfe", "offset_scaled_log_variance": "0xffff", "time_traceable": 0, @@ -580,7 +617,12 @@ def test_ptp_operation_gnss_off_and_on(): "port_data_set": [ { "interface": "{{ controller_1.nic1.nic_connection.interface }}", - "port_state": "MASTER" // Now acting as the Grandmaster + "port_state": "SLAVE", + "parent_port_identity" : { + "name": "ptp1", + "hostname":"controller-0", + "interface": "{{ controller_0.nic1.nic_connection.interface }}" // ctrl-0 NIC1 is Master and ctrl-1 NIC1 is slave + }, }, { "interface": "{{ controller_1.nic1.conn_to_proxmox }}", @@ -593,34 +635,29 @@ def test_ptp_operation_gnss_off_and_on(): "name": "ptp3", "controller-0": { "parent_data_set": { - "gm_clock_class": 165, // Degraded GM status + "gm_clock_class": 7, // Lost GNSS, degraded state "gm_clock_accuracy": "0xfe", "gm_offset_scaled_log_variance": "0xffff" }, "time_properties_data_set": { "current_utc_offset": 37, "current_utc_offset_valid": 0, - "time_traceable": 0, - "frequency_traceable": 0 + "time_traceable": 1, + "frequency_traceable": 1 }, "grandmaster_settings": { - "clock_class": 248, // Lost GNSS, degraded state + "clock_class": 7, // Lost GNSS, degraded state "clock_accuracy": "0xfe", "offset_scaled_log_variance": "0xffff", - "time_traceable": 0, - "frequency_traceable": 0, + "time_traceable": 1, + "frequency_traceable": 1, "time_source": "0xa0", "current_utc_offset_valid": 0 }, "port_data_set": [ { "interface": "{{ controller_0.nic2.nic_connection.interface }}", - "port_state": "SLAVE", // Now following ptp4 on controller-1 NIC2 - "parent_port_identity" : { - "name": "ptp4", - "hostname":"controller-1", - "interface": "{{ controller_1.nic2.nic_connection.interface }}" - }, + "port_state": "MASTER", }, { "interface": "{{ controller_0.nic2.conn_to_proxmox }}", @@ -633,18 +670,18 @@ def test_ptp_operation_gnss_off_and_on(): "name": "ptp4", "controller-1": { "parent_data_set": { - "gm_clock_class": 165, + "gm_clock_class": 7, "gm_clock_accuracy": "0xfe", "gm_offset_scaled_log_variance": "0xffff" }, "time_properties_data_set": { "current_utc_offset": 37, "current_utc_offset_valid": 0, - "time_traceable": 0, - "frequency_traceable": 0 + "time_traceable": 1, + "frequency_traceable": 1 }, "grandmaster_settings": { - "clock_class": 165, + "clock_class": [165,248], "clock_accuracy": "0xfe", "offset_scaled_log_variance": "0xffff", "time_traceable": 0, @@ -655,7 +692,12 @@ def test_ptp_operation_gnss_off_and_on(): "port_data_set": [ { "interface": "{{ controller_1.nic2.nic_connection.interface }}", - "port_state": "MASTER" // Acting as GM for NIC2 + "port_state": "SLAVE", // Acting as GM for NIC2 + "parent_port_identity" : { + "name": "ptp3", + "hostname":"controller-0", + "interface": "{{ controller_0.nic2.nic_connection.interface }}" // ctrl-0 NIC2 is Master and ctrl-1 NIC2 is slave + }, }, { "interface": "{{ controller_1.nic2.conn_to_proxmox }}", @@ -679,13 +721,8 @@ def test_ptp_operation_gnss_off_and_on(): ptp1_not_locked_alarm_obj = AlarmListObject() ptp1_not_locked_alarm_obj.set_alarm_id("100.119") - ptp1_not_locked_alarm_obj.set_reason_text("controller-1 is not locked to remote PTP Grand Master") - ptp1_not_locked_alarm_obj.set_entity_id("host=controller-1.instance=ptp1.ptp=no-lock") - - ptp4_not_locked_alarm_obj = AlarmListObject() - ptp4_not_locked_alarm_obj.set_alarm_id("100.119") - ptp4_not_locked_alarm_obj.set_reason_text("controller-1 is not locked to remote PTP Grand Master") - ptp4_not_locked_alarm_obj.set_entity_id("host=controller-1.instance=ptp4.ptp=no-lock") + ptp1_not_locked_alarm_obj.set_reason_text("controller-0 is not locked to remote PTP Grand Master") + ptp1_not_locked_alarm_obj.set_entity_id("host=controller-0.instance=ptp1.ptp=no-lock") pps_signal_loss_alarm_obj = AlarmListObject() pps_signal_loss_alarm_obj.set_alarm_id("100.119") @@ -697,15 +734,15 @@ def test_ptp_operation_gnss_off_and_on(): gnss_signal_loss_alarm_obj.set_reason_text("controller-0 GNSS signal loss state: holdover") gnss_signal_loss_alarm_obj.set_entity_id(f"host=controller-0.interface={interface}.ptp=GNSS-signal-loss") - AlarmListKeywords(ssh_connection).wait_for_alarms_to_appear([ptp1_not_locked_alarm_obj, ptp4_not_locked_alarm_obj, pps_signal_loss_alarm_obj, gnss_signal_loss_alarm_obj]) + AlarmListKeywords(ssh_connection).wait_for_alarms_to_appear([ptp1_not_locked_alarm_obj, pps_signal_loss_alarm_obj, gnss_signal_loss_alarm_obj]) get_logger().log_info("Verifying clock class degradation after GNSS is off.") # The clock is in "Holdover" or "Degraded" mode ptp_readiness_keywords = PTPReadinessKeywords(LabConnectionKeywords().get_ssh_for_hostname("controller-0")) - ptp_readiness_keywords.wait_for_clock_class_appear_in_grandmaster_settings_np("ptp1", 248) - ptp_readiness_keywords.wait_for_clock_class_appear_in_grandmaster_settings_np("ptp3", 248) + ptp_readiness_keywords.wait_for_clock_class_appear_in_grandmaster_settings_np("ptp1", 7) + ptp_readiness_keywords.wait_for_clock_class_appear_in_grandmaster_settings_np("ptp3", 7) # GNSS loss - ptp_readiness_keywords.wait_for_gm_clock_class_appear_in_parent_data_set("ptp1", 165) + ptp_readiness_keywords.wait_for_gm_clock_class_appear_in_parent_data_set("ptp1", 7) get_logger().log_info("Verifying PMC configuration after GNSS is off.") ptp_verify_config_keywords = PTPVerifyConfigKeywords(ssh_connection, ctrl0_nic1_gnss_disable_exp_ptp_setup) @@ -715,7 +752,7 @@ def test_ptp_operation_gnss_off_and_on(): gnss_keywords.gnss_power_on("controller-0", "nic1") get_logger().log_info("Waiting for alarm 100.119 to clear after GNSS is back on.") - AlarmListKeywords(ssh_connection).wait_for_alarms_cleared([ptp1_not_locked_alarm_obj, ptp4_not_locked_alarm_obj, pps_signal_loss_alarm_obj, gnss_signal_loss_alarm_obj]) + AlarmListKeywords(ssh_connection).wait_for_alarms_cleared([ptp1_not_locked_alarm_obj, pps_signal_loss_alarm_obj, gnss_signal_loss_alarm_obj]) get_logger().log_info("Verifying clock class restoration after GNSS is on.") ptp_readiness_keywords.wait_for_clock_class_appear_in_grandmaster_settings_np("ptp1", 6) @@ -723,8 +760,7 @@ def test_ptp_operation_gnss_off_and_on(): ptp_readiness_keywords.wait_for_gm_clock_class_appear_in_parent_data_set("ptp1", 6) get_logger().log_info("Verifying PMC configuration after GNSS is restored.") - ctrl0_nic1_gnss_enable_exp_dict_overrides = {"ptp4l": [{"name": "ptp4", "controller-1": {"grandmaster_settings": {"clock_class": 165}}}]} - ctrl0_nic1_gnss_enable_exp_ptp_setup = ptp_setup_keywords.filter_and_render_ptp_config(ptp_setup_template_path, selected_instances, expected_dict_overrides=ctrl0_nic1_gnss_enable_exp_dict_overrides) + ctrl0_nic1_gnss_enable_exp_ptp_setup = ptp_setup_keywords.generate_ptp_setup_from_template(ptp_setup_template_path) ptp_verify_config_keywords = PTPVerifyConfigKeywords(ssh_connection, ctrl0_nic1_gnss_enable_exp_ptp_setup) ptp_verify_config_keywords.verify_ptp_pmc_values()