From 055c628666927c52d80fd9fc82d870c0bd0c1d0d Mon Sep 17 00:00:00 2001 From: Nathan Ni Date: Tue, 9 Dec 2025 17:24:31 +0800 Subject: [PATCH 1/7] add SAI definitions for optical circuit switch Signed-off-by: Nathan Ni --- experimental/saiexperimentalocs.h | 453 ++++++++++++++++++++++++++++++ 1 file changed, 453 insertions(+) create mode 100644 experimental/saiexperimentalocs.h diff --git a/experimental/saiexperimentalocs.h b/experimental/saiexperimentalocs.h new file mode 100644 index 000000000..b48a8d53c --- /dev/null +++ b/experimental/saiexperimentalocs.h @@ -0,0 +1,453 @@ +/** + * Copyright (c) 2014 Microsoft Open Technologies, Inc. + * + * 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 + * + * THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT + * LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS + * FOR A PARTICULAR PURPOSE, MERCHANTABILITY OR NON-INFRINGEMENT. + * + * See the Apache Version 2.0 License for specific language governing + * permissions and limitations under the License. + * + * Microsoft would like to thank the following companies for their review and + * assistance with these files: Intel Corporation, Mellanox Technologies Ltd, + * Dell Products, L.P., Facebook, Inc., Marvell International Ltd. + * + * @file saiexperimentalocs.h + * + * @brief This module defines SAI OCS + */ + +#if !defined (__SAIEXPERIMENTALOCS_H_) +#define __SAIEXPERIMENTALOCS_H_ + +#include + +/** + * @brief List of OCS cross connect attributes + */ +typedef enum _sai_ocs_cross_connect_attr_t +{ + /** + * @brief Start of attributes + */ + SAI_OCS_CROSS_CONNECT_ATTR_START, + + /** + * @brief A side port + * + * @type sai_object_id_t + * @flags MANDATORY_ON_CREATE | CREATE_ONLY + * @objects SAI_OBJECT_TYPE_OCS_PORT + */ + SAI_OCS_CROSS_CONNECT_ATTR_A_SIDE_PORT_ID = SAI_OCS_CROSS_CONNECT_ATTR_START, + + /** + * @brief B side port + * + * @type sai_object_id_t + * @flags MANDATORY_ON_CREATE | CREATE_ONLY + * @objects SAI_OBJECT_TYPE_OCS_PORT + */ + SAI_OCS_CROSS_CONNECT_ATTR_B_SIDE_PORT_ID, + + /** + * @brief End of attributes + */ + SAI_OCS_CROSS_CONNECT_ATTR_END, + +} sai_ocs_cross_connect_attr_t; + +/** + * @brief Create cross connect entry. + * + * @param[out] ocs_cross_connect_id OCS cross connect id + * @param[in] switch_id Switch id + * @param[in] attr_count Number of attributes + * @param[in] attr_list Array of attributes + * + * @return #SAI_STATUS_SUCCESS on success, failure status code on error + */ +typedef sai_status_t (*sai_create_ocs_cross_connect_fn)( + _Out_ sai_object_id_t *ocs_cross_connect_id, + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); + +/** + * @brief Remove cross connect entry + * + * @param[in] ocs_cross_connect_id OCS cross connect Id + * + * @return #SAI_STATUS_SUCCESS on success, failure status code on error + */ +typedef sai_status_t (*sai_remove_ocs_cross_connect_fn)( + _In_ sai_object_id_t ocs_cross_connect_id); + +/** + * @brief Set cross connect entry attribute + * + * @param[in] ocs_cross_connect_id OCS cross connect id + * @param[in] attr Attribute + * + * @return #SAI_STATUS_SUCCESS on success, failure status code on error + */ +typedef sai_status_t (*sai_set_ocs_cross_connect_attribute_fn)( + _In_ sai_object_id_t ocs_cross_connect_id, + _In_ const sai_attribute_t *attr); + +/** + * @brief Get OCS cross connect entry attribute + * + * @param[in] ocs_cross_connect_id OCS cross connect id + * @param[in] attr_count Number of attributes + * @param[inout] attr_list Array of attributes + * + * @return #SAI_STATUS_SUCCESS on success, failure status code on error + */ +typedef sai_status_t (*sai_get_ocs_cross_connect_attribute_fn)( + _In_ sai_object_id_t ocs_cross_connect_id, + _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list); + +/** + * @brief Attribute data for OCS port override state parameter + */ +typedef enum _sai_ocs_port_override_state_t +{ + /** + * @brief First element that the beam hits is powered off, for testing + */ + SAI_OCS_PORT_OVERRIDE_STATE_POWERED_OFF, + + /** + * @brief Default, state to be determined by presence of cross-connect + */ + SAI_OCS_PORT_OVERRIDE_STATE_NORMAL, + + /** + * @brief Regardless of cross-connect presence state, blocks the port + */ + SAI_OCS_PORT_OVERRIDE_STATE_FORCE_BLOCKED + +} sai_ocs_port_override_state_t; + +/** + * @brief Attribute data for OCS port status parameter + */ +typedef enum _sai_ocs_port_status_t +{ + /** + * @brief Default status for any port which is with no configuration + */ + SAI_OCS_PORT_STATUS_BLOCKED, + + /** + * @brief Insertion loss is >0.5dB of target + */ + SAI_OCS_PORT_STATUS_TUNING, + + /** + * @brief Insertion loss is within 0.5dB of target + */ + SAI_OCS_PORT_STATUS_TUNED, + + /** + * @brief If there is a hardware failure + */ + SAI_OCS_PORT_STATUS_FAILED +} sai_ocs_port_status_t; + +/** + * @brief List of OCS port attributes + */ +typedef enum _sai_ocs_port_attr_t +{ + /** + * @brief Start of device port attributes + */ + SAI_OCS_PORT_ATTR_START, + + /** + * @brief Unique identifier for a port + * + * @type sai_u8_list_t + * @flags MANDATORY_ON_CREATE | CREATE_ONLY + */ + SAI_OCS_PORT_ATTR_NAME = SAI_OCS_PORT_ATTR_START, + + /** + * @brief Overrides the status imposed by the programmed cross-connects + * + * @type sai_ocs_port_override_state_t + * @flags CREATE_AND_SET + */ + SAI_OCS_PORT_ATTR_OVERRIDE_STATE, + + /** + * @brief Operational status of the port + * + * @type sai_ocs_port_status_t + * @flags READ_ONLY + */ + SAI_OCS_PORT_ATTR_OPER_STATUS, + + /** + * @brief Mapping between face plate port and OCS physical element + * + * @type sai_u8_list_t + * @flags READ_ONLY + */ + SAI_OCS_PORT_ATTR_PHYSICAL_MAPPING, + + /** + * @brief End of attributes + */ + SAI_OCS_PORT_ATTR_END, +} sai_ocs_port_attr_t; + +/** + * @brief Defines the operational status of the OCS port + */ +typedef struct _sai_ocs_port_status_notification_t +{ + /** + * @brief OCS Port id. + * + * @objects SAI_OBJECT_TYPE_OCS_PORT + */ + sai_object_id_t port_id; + + /** OCS port operational status */ + sai_ocs_port_status_t port_state; +} sai_ocs_port_status_notification_t; + +/** + * @brief Create port entry. + * + * @param[out] ocs_port_id OCS port id + * @param[in] switch_id Switch id + * @param[in] attr_count Number of attributes + * @param[in] attr_list Array of attributes + * + * @return #SAI_STATUS_SUCCESS on success, failure status code on error + */ +typedef sai_status_t (*sai_create_ocs_port_fn)( + _Out_ sai_object_id_t *ocs_port_id, + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); + +/** + * @brief Remove port entry + * + * @param[in] ocs_port_id OCS port Id + * + * @return #SAI_STATUS_SUCCESS on success, failure status code on error + */ +typedef sai_status_t (*sai_remove_ocs_port_fn)( + _In_ sai_object_id_t ocs_port_id); + +/** + * @brief Set port entry attribute + * + * @param[in] ocs_port_id OCS port id + * @param[in] attr Attribute + * + * @return #SAI_STATUS_SUCCESS on success, failure status code on error + */ +typedef sai_status_t (*sai_set_ocs_port_attribute_fn)( + _In_ sai_object_id_t ocs_port_id, + _In_ const sai_attribute_t *attr); + +/** + * @brief Get OCS port entry attribute + * + * @param[in] ocs_port_id OCS port id + * @param[in] attr_count Number of attributes + * @param[inout] attr_list Array of attributes + * + * @return #SAI_STATUS_SUCCESS on success, failure status code on error + */ +typedef sai_status_t (*sai_get_ocs_port_attribute_fn)( + _In_ sai_object_id_t ocs_port_id, + _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list); + +/** + * @brief OCS port state change notification + * + * Passed as a parameter into sai_initialize_switch() + * + * @count data[count] + * + * @param[in] count Number of notifications + * @param[in] data Array of port operational status + */ +typedef void (*sai_ocs_port_state_change_notification_fn)( + _In_ uint32_t count, + _In_ const sai_ocs_port_status_notification_t *data); + +/** + * @brief List of OCS cross connect factory data attributes. Inventory data for all possible cross-connects, + * factory insertion loss measurements + */ +typedef enum _sai_ocs_cross_connect_factory_data_attr_t +{ + /** + * @brief Start of attributes + */ + SAI_OCS_CROSS_CONNECT_FACTORY_DATA_ATTR_START, + + /** + * @brief Name of A side port in a cross connection + * + * @type sai_u8_list_t + * @flags READ_ONLY + */ + SAI_OCS_CROSS_CONNECT_FACTORY_DATA_ATTR_A_SIDE_PORT_NAME = SAI_OCS_CROSS_CONNECT_FACTORY_DATA_ATTR_START, + + /** + * @brief Name of B side port in a cross connection. + * + * @type sai_u8_list_t + * @flags READ_ONLY + */ + SAI_OCS_CROSS_CONNECT_FACTORY_DATA_ATTR_B_SIDE_PORT_NAME, + + /** + * @brief Center frequency at which insertion loss is measured, e.g., 229.1 (O-band) 193.5, use int32 for representation of decimal value + * + * List of center frequency values. Use int32 for representation of decimal value with 3 fraction digits + * + * @type sai_s32_list_t + * @flags READ_ONLY + */ + SAI_OCS_CROSS_CONNECT_FACTORY_DATA_ATTR_FREQUENCY_THZ, + + /** + * @brief Internal temperature sensor that correlates with the ambient temperature at which + * the insertion loss is measured in Celsius, e.g., 25.00 + * + * List of temperatures. Use int32 for representation of decimal value with 2 fraction digits + * + * @type sai_s32_list_t + * @flags READ_ONLY + */ + SAI_OCS_CROSS_CONNECT_FACTORY_DATA_ATTR_MEASURED_TEMPERATURE, + + /** + * @brief Factory insertion loss in dB, e.g. 1.23 + * + * List of insertion loss values. Use int32 for representation of decimal value with 2 fraction digits + * + * @type sai_s32_list_t + * @flags READ_ONLY + */ + SAI_OCS_CROSS_CONNECT_FACTORY_DATA_ATTR_INSERTION_LOSS_DB, + + /** + * @brief Factory insertion loss in dB, e.g. 1.23 + * + * List of insertion loss accuracy values. Use int32 for representation of decimal value with 2 fraction digits + * + * @type sai_s32_list_t + * @flags READ_ONLY + */ + SAI_OCS_CROSS_CONNECT_FACTORY_DATA_ATTR_INSERTION_LOSS_ACCURACY_DB, + + /** + * @brief End of attributes + */ + SAI_OCS_CROSS_CONNECT_FACTORY_DATA_ATTR_END, +} sai_ocs_cross_connect_factory_data_attr_t; + +/** + * @brief Create OCS cross connect factory data entry. + * + * @param[out] ocs_cross_connect_factory_data_id OCS cross connect factory data id + * @param[in] switch_id Switch id + * @param[in] attr_count Number of attributes + * @param[in] attr_list Array of attributes + * + * @return #SAI_STATUS_SUCCESS on success, failure status code on error + */ +typedef sai_status_t (*sai_create_ocs_cross_connect_factory_data_fn)( + _Out_ sai_object_id_t *ocs_cross_connect_factory_data_id, + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); + +/** + * @brief Remove OCS cross connect factory data entry + * + * @param[in] ocs_cross_connect_factory_data_id OCS cross connect Id + * + * @return #SAI_STATUS_SUCCESS on success, failure status code on error + */ +typedef sai_status_t (*sai_remove_ocs_cross_connect_factory_data_fn)( + _In_ sai_object_id_t ocs_cross_connect_factory_data_id); + +/** + * @brief Set OCS cross connect factory data entry attribute + * + * @param[in] ocs_cross_connect_factory_data_id OCS cross connect id + * @param[in] attr Attribute + * + * @return #SAI_STATUS_SUCCESS on success, failure status code on error + */ +typedef sai_status_t (*sai_set_ocs_cross_connect_factory_data_attribute_fn)( + _In_ sai_object_id_t ocs_cross_connect_factory_data_id, + _In_ const sai_attribute_t *attr); + +/** + * @brief Get OCS cross connect factory data attribute + * + * @param[in] ocs_cross_connect_factory_data_id OCS cross connect id + * @param[in] attr_count Number of attributes + * @param[inout] attr_list Array of attributes + * + * @return #SAI_STATUS_SUCCESS on success, failure status code on error + */ +typedef sai_status_t (*sai_get_ocs_cross_connect_factory_data_attribute_fn)( + _In_ sai_object_id_t ocs_cross_connect_factory_data_id, + _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list); + +/** + * @brief OCS methods table retrieved with sai_api_query() + */ +typedef struct _sai_ocs_api_t +{ + sai_create_ocs_port_fn create_ocs_port; + sai_remove_ocs_port_fn remove_ocs_port; + sai_set_ocs_port_attribute_fn set_ocs_port_attribute; + sai_get_ocs_port_attribute_fn get_ocs_port_attribute; + sai_bulk_object_create_fn create_ocs_ports; + sai_bulk_object_remove_fn remove_ocs_ports; + sai_bulk_object_set_attribute_fn set_ocs_ports_attribute; + sai_bulk_object_get_attribute_fn get_ocs_ports_attribute; + sai_create_ocs_cross_connect_fn create_ocs_cross_connect; + sai_remove_ocs_cross_connect_fn remove_ocs_cross_connect; + sai_set_ocs_cross_connect_attribute_fn set_ocs_cross_connect_attribute; + sai_get_ocs_cross_connect_attribute_fn get_ocs_cross_connect_attribute; + sai_bulk_object_create_fn create_ocs_cross_connects; + sai_bulk_object_remove_fn remove_ocs_cross_connects; + sai_bulk_object_set_attribute_fn set_ocs_cross_connects_attribute; + sai_bulk_object_get_attribute_fn get_ocs_cross_connects_attribute; + sai_create_ocs_cross_connect_factory_data_fn create_ocs_cross_connect_factory_data; + sai_remove_ocs_cross_connect_factory_data_fn remove_ocs_cross_connect_factory_data; + sai_set_ocs_cross_connect_factory_data_attribute_fn set_ocs_cross_connect_factory_data_attribute; + sai_get_ocs_cross_connect_factory_data_attribute_fn get_ocs_cross_connect_factory_data_attribute; + sai_bulk_object_create_fn create_ocs_cross_connect_factory_datas; + sai_bulk_object_remove_fn remove_ocs_cross_connect_factory_datas; + sai_bulk_object_set_attribute_fn set_ocs_cross_connect_factory_datas_attribute; + sai_bulk_object_get_attribute_fn get_ocs_cross_connect_factory_datas_attribute; + +} sai_ocs_api_t; + +#endif /** __SAIEXPERIMENTALOCS_H_ */ From 30c4b4f03c6e745e2ca0137369309c81af2cfd68 Mon Sep 17 00:00:00 2001 From: Nathan Ni Date: Sat, 20 Dec 2025 15:56:43 +0800 Subject: [PATCH 2/7] Add SAI definitions for optical circuit switch Signed-off-by: Nathan Ni --- doc/OCS/SAI-Proposal-OCS.md | 307 ++++++++++++++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100755 doc/OCS/SAI-Proposal-OCS.md diff --git a/doc/OCS/SAI-Proposal-OCS.md b/doc/OCS/SAI-Proposal-OCS.md new file mode 100755 index 000000000..9425bb5ea --- /dev/null +++ b/doc/OCS/SAI-Proposal-OCS.md @@ -0,0 +1,307 @@ +SAI Optical Circuit Switch API Proposal +===================== + +Title | SAI Optical Circuit Switch API Proposal +------------|---------------------- +Authors | Coherent +Status | Draft +Type | Standards track +Created | 11/20/2025 +SAI-Version | ? +------------------------------- + +# 1. Scope + +This document defines the draft technical specifications for the API in Open Compute Project Switch Abstraction Interface (SAI) used to support the configurations of OCS port and OCS cross connect in the OCS device, as well as the retrieval of OCS operational status data from OCS device. + +# 2. Overview +As AI clusters reach massive proportions, Optical Circuit Switching (OCS) is becoming essential. It slashes energy overhead, reduces network complexity, and paves the way for revolutionary data center designs and applications. OCS device can have varying capacities from different hardware or module, defined as "number of A side ports" × "number of B side ports" (e.g., 64×64, 320×320, etc.). OCS cross-connect is direct optical transmission channel between different optical links, it is provisioned between port on one side (e.g. A side) and port on the other side (e.g. B side). + +Main functions of the OCS SAI definitions include: +* Support creation and remove of OCS cross-connects, including both individual switching and simultaneous switching with multiple connections. +* Support OCS ports operation, including the ability to set a state to any specified group of ports. +* Support the retrieval of current operational status on OCS port. +* Support the retrieval of hardware-specific OCS module data, such as port physical mapping information and factory insertion loss values etc. + +# 3. OCS Port +## 3.1 OCS Port Discovery and Creation +* The capacity of OCS device (number of A side ports and number of B side ports) and corresponding default port configurations are defined in OCS device specific template/profile, example as below: +```cpp +# name state +OCS_PORT|1A normal +OCS_PORT|1B normal +OCS_PORT|2A normal +OCS_PORT|2B normal +OCS_PORT|3A normal +OCS_PORT|3B normal +OCS_PORT|4A normal +OCS_PORT|4B normal +OCS_PORT|5A normal +OCS_PORT|5B normal +OCS_PORT|6A normal +OCS_PORT|6B normal +OCS_PORT|7A normal +OCS_PORT|7B normal +OCS_PORT|8A normal +OCS_PORT|8B normal +... +``` +* OCS ports are created by upstream application using SAI API by parsing OCS device capability specific template/profile. +* After creation, OCS port is not deletable. +## 3.2 OCS Port Configuration +* The key configurable parameter is the override state (normal or force-blocked, etc.). +* Override state configuration can be changed regardless wether there's OCS cross-connect on the port. +## 3.3 OCS Port Operational Status +The OCS port operational status relies on the override state and the presence of an OCS cross-connect configuration on the port. + +![OCS Port Operational Status](images/port_status.png) +# 4. OCS Cross-Connects +OCS cross-connects are dynamically created and removed via SAI APIs. +## 4.1. Object Relationships +* The SAI object IDs of OCS ports serve as the SAI attributes for both the ingress and egress ports in OCS cross-connect SAI object. +* OCS ports are referenced to OCS cross-connect by their SAI object IDs in cross-connect attributes. +## 4.2. Cross-Connect Configuration +* To have fast switching performance, SAI bulk create/remove APIs are used for management of OCS cross-connect configurations. +* OCS cross-connect can not be provisioned between two A side ports or two B side ports. +* One OCS port can only involved in one OCS cross-connect; when switching existing OCS cross-connect, e.g. switch from 1A-1B to 1A-2B, the upstream application need to use SAI API to remove 1A-1B and then create 1A-2B. +# 5. OCS Cross-Connects Factory Data +OCS cross-connect factory data are read-only information about insertion loss measurements of all possible cross-connects. +* Factory data are measured during the manufacturing calibration phase. +* The measurement is for every possible optical path (cross-connect) with an optical spectrum (central frequency) in specific environment (temperature). + +# 6. OCS SAI Object and Attributes +| SAI Object | SAI Attributes | SAI Data Type | +| ---- | ---- | ---- | +|SAI_OBJECT_TYPE_OCS_CROSS_CONNECT | SAI_OCS_CROSS_CONNECT_ATTR_A_SIDE_PORT_ID | sai_object_id_t +| | SAI_OCS_CROSS_CONNECT_ATTR_B_SIDE_PORT_ID | sai_object_id_t +| SAI_OBJECT_TYPE_OCS_PORT | SAI_OCS_PORT_ATTR_NAME | sai_u8_list_t +| | SAI_OCS_PORT_ATTR_OVERRIDE_STATE | sai_ocs_port_override_state_t +| | SAI_OCS_PORT_ATTR_OPER_STATUS | sai_ocs_port_status_t +| | SAI_OCS_PORT_ATTR_PHYSICAL_MAPPING | sai_u8_list_t +SAI_OBJECT_TYPE_OCS_CROSS_CONNECT_FACTORY_DATA | SAI_OCS_CROSS_CONNECT_FACTORY_DATA_ATTR_A_SIDE_PORT_NAME | sai_u8_list_t +| | SAI_OCS_CROSS_CONNECT_FACTORY_DATA_ATTR_B_SIDE_PORT_NAME | sai_u8_list_t +| | SAI_OCS_CROSS_CONNECT_FACTORY_DATA_ATTR_FREQUENCY_THZ | sai_s32_list_t +| | SAI_OCS_CROSS_CONNECT_FACTORY_DATA_ATTR_MEASURED_TEMPERATURE | sai_s32_list_t +| | SAI_OCS_CROSS_CONNECT_FACTORY_DATA_ATTR_INSERTION_LOSS_DB | sai_s32_list_t +| | SAI_OCS_CROSS_CONNECT_FACTORY_DATA_ATTR_INSERTION_LOSS_ACCURACY_DB | sai_s32_list_t + +# 7. OCS SAI APIs +```cpp +** + * @brief OCS methods table retrieved with sai_api_query() + */ +typedef struct _sai_ocs_api_t +{ + sai_create_ocs_port_fn create_ocs_port; + sai_remove_ocs_port_fn remove_ocs_port; + sai_set_ocs_port_attribute_fn set_ocs_port_attribute; + sai_get_ocs_port_attribute_fn get_ocs_port_attribute; + sai_bulk_object_create_fn create_ocs_ports; + sai_bulk_object_remove_fn remove_ocs_ports; + sai_bulk_object_set_attribute_fn set_ocs_ports_attribute; + sai_bulk_object_get_attribute_fn get_ocs_ports_attribute; + sai_create_ocs_cross_connect_fn create_ocs_cross_connect; + sai_remove_ocs_cross_connect_fn remove_ocs_cross_connect; + sai_set_ocs_cross_connect_attribute_fn set_ocs_cross_connect_attribute; + sai_get_ocs_cross_connect_attribute_fn get_ocs_cross_connect_attribute; + sai_bulk_object_create_fn create_ocs_cross_connects; + sai_bulk_object_remove_fn remove_ocs_cross_connects; + sai_bulk_object_set_attribute_fn set_ocs_cross_connects_attribute; + sai_bulk_object_get_attribute_fn get_ocs_cross_connects_attribute; + sai_create_ocs_cross_connect_factory_data_fn create_ocs_cross_connect_factory_data; + sai_remove_ocs_cross_connect_factory_data_fn remove_ocs_cross_connect_factory_data; + sai_set_ocs_cross_connect_factory_data_attribute_fn set_ocs_cross_connect_factory_data_attribute; + sai_get_ocs_cross_connect_factory_data_attribute_fn get_ocs_cross_connect_factory_data_attribute; + sai_bulk_object_create_fn create_ocs_cross_connect_factory_datas; + sai_bulk_object_remove_fn remove_ocs_cross_connect_factory_datas; + sai_bulk_object_set_attribute_fn set_ocs_cross_connect_factory_datas_attribute; + sai_bulk_object_get_attribute_fn get_ocs_cross_connect_factory_datas_attribute; + +} sai_ocs_api_t; +``` + +# 8. OCS SAI API Usage Examples +## 8.1. Usage Example: Create OCS Ports +The following example demonstrates how to create OCS ports by specifying port name and port override state. Note: after OCS ports are created, the returned SAI object IDs will be buffered (_port_key_to_saiobjid_map in this example) and they will be used for following-up set/get operations on OCS ports. +```cpp + vector keys = {"1A", "1B", "2A", "2B", "3A", "3B"}; + + vector> attr_data_list; + vector attr_count_list; + vector attr_ptr_list; + + for (auto& key : keys) + { + sai_attribute_t attr; + vector attrs; + + attr.id = SAI_OCS_PORT_ATTR_NAME; + attr.value.u8list.count = (uint32_t)key.size(); + attr.value.u8list.list = (uint8_t*)const_cast(key.data()); + attrs.push_back(attr); + + attr.id = SAI_OCS_PORT_ATTR_OVERRIDE_STATE; + attr.value.u32 = (uint32_t)SAI_OCS_PORT_OVERRIDE_STATE_NORMAL; + attrs.push_back(attr); + + attr_data_list.push_back(attrs); + attr_count_list.push_back(static_cast(attr_data_list.back().size())); + attr_ptr_list.push_back(attr_data_list.back().data()); + } + + auto cnt = keys.size(); + vector oid_list(cnt, SAI_NULL_OBJECT_ID); + vector status_list(cnt, SAI_STATUS_SUCCESS); + + auto status = sai_ocs_api->create_ocs_ports( + gSwitchId, (int32_t)cnt, attr_count_list.data(), attr_ptr_list.data(), + SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR, + oid_list.data(), status_list.data() + ); + + if (SAI_STATUS_SUCCESS == status) + { + for (size_t i = 0; i < cnt; ++i) + { + _port_key_to_saiobjid_map[keys[i]] = oid_list[i]; + } + } +``` + +## 8.2. Usage Example: Change OCS Port Configuration +Following is example about how to set override status of OCS port 1A to force-blocked. +```cpp +string port_id = "1A"; +auto it = _port_key_to_saiobjid_map.find(port_id); + +if (it != _port_key_to_saiobjid_map.end()) +{ + sai_attribute_t attr; + attr.id = SAI_OCS_PORT_ATTR_OVERRIDE_STATE; + attr.value.u32 = (uint32_t)SAI_OCS_PORT_OVERRIDE_STATE_FORCE_BLOCKED; + + auto status = sai_ocs_api->set_ocs_port_attribute(it->second, &attr); +} +``` +## 8.3. Usage Example: Get an OCS Port Operational Status +Following is an example of how to get operational status of OCS port 1A +```cpp +string port = "1A"; +auto it = _port_key_to_saiobjid_map.find(port); + +if (_port_key_to_saiobjid_map.end() != it) +{ + sai_attribute_t attr; + sai_status_t status; + attr.id = SAI_OCS_PORT_ATTR_OPER_STATUS; + + status = sai_ocs_api->get_ocs_port_attribute(it->second, 1, &attr); +} +``` +## 8.4. Usage Example: Get All OCS Port Operational Status +Following is an example of how to get operational status of all OCS ports +```cpp +vector oid_list; +vector port_keys; + +for (auto& p : _port_key_to_saiobjid_map) +{ + port_keys.push_back(p.first); + oid_list.push_back(p.second); +} + +auto portNum = oid_list.size(); + +std::vector attrs(portNum); +vector attr_count_list(portNum, 1); +vector attr_ptr_list(portNum); + +for (size_t i = 0; i < (uint32_t)portNum; i++) +{ + attrs[i].id = SAI_OCS_PORT_ATTR_OPER_STATUS; + attr_ptr_list[i] = &attrs[i]; +} + +vector status_list(portNum, SAI_STATUS_SUCCESS); + +auto status = sai_ocs_api->get_ocs_ports_attribute( + (int32_t)portNum, + oid_list.data(), + attr_count_list.data(), + attr_ptr_list.data(), + SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR, + status_list.data() +); +``` +## 8.5. Usage Example: Create OCS Cross-Connects +The following example demonstrates how to create multiple OCS cross-connects: 1A-1B, 2A-2B, 3A-2B and 4A-4B. Bulk creation API is used to have fast OCS cross-connect switching performance. Note: the returned SAI object IDs need to be buffered and they will be used for remove operations. +```cpp + vector> attr_data_list; + vector attr_count_list; + vector attr_ptr_list; + + vector > conns = {make_pair("1A", "1B"), make_pair("2A", "2B"), make_pair("3A", "3B"), make_pair("4A", "4B")}; + + for (auto& conn : conns) + { + sai_attribute_t attr; + vector attrs; + + auto it_a = _port_key_to_saiobjid_map.find(conn.first); + + if (it_a == _port_key_to_saiobjid_map.end()) + { + continue; + } + + attr.id = SAI_OCS_CROSS_CONNECT_ATTR_A_SIDE_PORT_ID; + attr.value.oid = it_a->second; + attrs.push_back(attr); + + auto it_b = _port_key_to_saiobjid_map.find(conn.second); + + if (it_b == _port_key_to_saiobjid_map.end()) + { + continue; + } + + attr.id = SAI_OCS_CROSS_CONNECT_ATTR_B_SIDE_PORT_ID; + attr.value.oid = it_b->second; + attrs.push_back(attr); + + attr_data_list.push_back(attrs); + attr_count_list.push_back(static_cast(attr_data_list.back().size())); + attr_ptr_list.push_back(attr_data_list.back().data()); + } + + auto conn_num = attr_data_list.size(); + vector oid_list(conn_num, SAI_NULL_OBJECT_ID); + vector status_list(conn_num, SAI_STATUS_SUCCESS); + + auto status = sai_ocs_api->create_ocs_cross_connects( + gSwitchId, (int32_t)conn_num, attr_count_list.data(), attr_ptr_list.data(), + SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR, + oid_list.data(), status_list.data() + ); +``` +## 8.6. Usage Example: Delete OCS Cross-Connects +The following example demonstrates how to remove multiple OCS cross-connects. +```cpp +vector keys = {"1A-1B", "2A-2B"}; +vector oid_list; +vector status_list(keys.size(), SAI_STATUS_SUCCESS); + +for (auto& key : keys) +{ + auto oid = getFromCrsKeyToSaiObjIdMap(key); + + if (0 == oid) continue; + + oid_list.emplace_back(oid); +} + +auto status = sai_ocs_api->remove_ocs_cross_connects((int32_t)oid_list.size(), + oid_list.data(), + SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR, + status_list.data()); +``` \ No newline at end of file From f2cabe0825666f61713ec97cf3a79d84e0f134af Mon Sep 17 00:00:00 2001 From: Nathan Ni Date: Sat, 20 Dec 2025 16:06:01 +0800 Subject: [PATCH 3/7] Add SAI definitions for optical circuit switch Signed-off-by: Nathan Ni --- doc/OCS/images/port_status.png | Bin 0 -> 30938 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100755 doc/OCS/images/port_status.png diff --git a/doc/OCS/images/port_status.png b/doc/OCS/images/port_status.png new file mode 100755 index 0000000000000000000000000000000000000000..b470c2aa3920e9b79278a7a3e9ea5b9f9f551a73 GIT binary patch literal 30938 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 Date: Mon, 29 Dec 2025 23:05:32 +0800 Subject: [PATCH 4/7] Add SAI definitions for optical circuit switch Signed-off-by: Nathan Ni --- experimental/saiexperimentalocs.h | 13 ++++++++++++- experimental/saiextensions.h | 3 +++ experimental/saitypesextensions.h | 6 ++++++ inc/saiobject.h | 1 + inc/saiswitch.h | 11 +++++++++++ meta/acronyms.txt | 1 + 6 files changed, 34 insertions(+), 1 deletion(-) diff --git a/experimental/saiexperimentalocs.h b/experimental/saiexperimentalocs.h index b48a8d53c..bdeb8fab7 100644 --- a/experimental/saiexperimentalocs.h +++ b/experimental/saiexperimentalocs.h @@ -20,12 +20,20 @@ * @file saiexperimentalocs.h * * @brief This module defines SAI OCS + * + * @warning This module is a SAI experimental module */ #if !defined (__SAIEXPERIMENTALOCS_H_) #define __SAIEXPERIMENTALOCS_H_ -#include +#include + +/** + * @defgroup SAIEXPERIMENTALOCS SAI - Experimental: OCS specific API definitions + * + * @{ + */ /** * @brief List of OCS cross connect attributes @@ -450,4 +458,7 @@ typedef struct _sai_ocs_api_t } sai_ocs_api_t; +/** + * @} + */ #endif /** __SAIEXPERIMENTALOCS_H_ */ diff --git a/experimental/saiextensions.h b/experimental/saiextensions.h index f43ee480a..190f0970b 100644 --- a/experimental/saiextensions.h +++ b/experimental/saiextensions.h @@ -51,6 +51,7 @@ #include "saiexperimentaldashdirectionlookup.h" #include "saiexperimentaldashacl.h" #include "saiexperimentalbmtor.h" +#include "saiexperimentalocs.h" /** * @brief Extensions to SAI APIs @@ -95,6 +96,8 @@ typedef enum _sai_api_extensions_t SAI_API_DASH_TRUSTED_VNI, + SAI_API_OCS, + /* Add new experimental APIs above this line */ SAI_API_EXTENSIONS_RANGE_END diff --git a/experimental/saitypesextensions.h b/experimental/saitypesextensions.h index 09ede1f56..2a5e23d52 100644 --- a/experimental/saitypesextensions.h +++ b/experimental/saitypesextensions.h @@ -100,6 +100,12 @@ typedef enum _sai_object_type_extensions_t SAI_OBJECT_TYPE_ENI_TRUSTED_VNI_ENTRY, + SAI_OBJECT_TYPE_OCS_CROSS_CONNECT, + + SAI_OBJECT_TYPE_OCS_PORT, + + SAI_OBJECT_TYPE_OCS_CROSS_CONNECT_FACTORY_DATA, + /* Add new experimental object types above this line */ SAI_OBJECT_TYPE_EXTENSIONS_RANGE_END diff --git a/inc/saiobject.h b/inc/saiobject.h index 84dd67018..875669f33 100644 --- a/inc/saiobject.h +++ b/inc/saiobject.h @@ -55,6 +55,7 @@ #include #include #include +#include /** * @defgroup SAIOBJECT SAI - Object API definitions. diff --git a/inc/saiswitch.h b/inc/saiswitch.h index d90b10800..abb39d53e 100644 --- a/inc/saiswitch.h +++ b/inc/saiswitch.h @@ -3373,6 +3373,17 @@ typedef enum _sai_switch_attr_t */ SAI_SWITCH_ATTR_MACSEC_POST_STATUS_NOTIFY, + /** + * @brief Set Switch OCS port state change event notification callback function passed to the adapter. + * + * Use sai_ocs_port_state_change_notification_fn as notification function. + * + * @type sai_pointer_t sai_ocs_port_state_change_notification_fn + * @flags CREATE_AND_SET + * @default NULL + */ + SAI_SWITCH_ATTR_OCS_PORT_STATE_CHANGE_NOTIFY, + /** * @brief Callback for completion status of all the IPSEC ports serviced by this IPSEC engine * diff --git a/meta/acronyms.txt b/meta/acronyms.txt index c960e4ced..a54969691 100644 --- a/meta/acronyms.txt +++ b/meta/acronyms.txt @@ -109,6 +109,7 @@ NTPCLIENT - Network Time Protocol Client NTPSERVER - Network Time Protocol Server NVGRE - Network Virtualization using Generic Routing Encapsulation OAM - Operations Administration and Maintenance +OCS - Optical Circuit Switch OUI - Organizationally Unique Identifier P4RT - Programming Protocol-independent Packet Processors Runtime PAM4 - Pulse Amplitude Modulation 4-level From b9db0609c720874def632ca78772861f46f3dd39 Mon Sep 17 00:00:00 2001 From: Nathan Ni Date: Thu, 8 Jan 2026 21:16:39 +0800 Subject: [PATCH 5/7] Add attr custom range for CROSS_CONNECT; define default value for ocs PORT override state configuration Signed-off-by: Nathan Ni --- experimental/saiexperimentalocs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/experimental/saiexperimentalocs.h b/experimental/saiexperimentalocs.h index bdeb8fab7..724dde8c5 100644 --- a/experimental/saiexperimentalocs.h +++ b/experimental/saiexperimentalocs.h @@ -68,6 +68,12 @@ typedef enum _sai_ocs_cross_connect_attr_t */ SAI_OCS_CROSS_CONNECT_ATTR_END, + /** Custom range base value */ + SAI_OCS_CROSS_CONNECT_ATTR_CUSTOM_RANGE_START = 0x10000000, + + /** End of custom range base */ + SAI_OCS_CROSS_CONNECT_ATTR_CUSTOM_RANGE_END, + } sai_ocs_cross_connect_attr_t; /** @@ -193,6 +199,7 @@ typedef enum _sai_ocs_port_attr_t * * @type sai_ocs_port_override_state_t * @flags CREATE_AND_SET + * @default SAI_OCS_PORT_OVERRIDE_STATE_NORMAL */ SAI_OCS_PORT_ATTR_OVERRIDE_STATE, From b546a2b21cae4747683564928e9a6df51ab77b40 Mon Sep 17 00:00:00 2001 From: Nathan Ni Date: Tue, 20 Jan 2026 17:23:06 +0800 Subject: [PATCH 6/7] Update OCS SAI definitions and markdown document based on comments Signed-off-by: Nathan Ni --- doc/OCS/SAI-Proposal-OCS.md | 12 ++++++------ doc/OCS/images/port_status.png | Bin 30938 -> 28207 bytes experimental/saiexperimentalocs.h | 11 +++-------- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/doc/OCS/SAI-Proposal-OCS.md b/doc/OCS/SAI-Proposal-OCS.md index 9425bb5ea..d99ec31da 100755 --- a/doc/OCS/SAI-Proposal-OCS.md +++ b/doc/OCS/SAI-Proposal-OCS.md @@ -54,20 +54,20 @@ OCS_PORT|8B normal ## 3.3 OCS Port Operational Status The OCS port operational status relies on the override state and the presence of an OCS cross-connect configuration on the port. -![OCS Port Operational Status](images/port_status.png) +![OCS Port Operational Status](images/port_status.png) +The OCS port physical mapping information is about the internal port mapping to faceplate ports. # 4. OCS Cross-Connects OCS cross-connects are dynamically created and removed via SAI APIs. ## 4.1. Object Relationships * The SAI object IDs of OCS ports serve as the SAI attributes for both the ingress and egress ports in OCS cross-connect SAI object. * OCS ports are referenced to OCS cross-connect by their SAI object IDs in cross-connect attributes. ## 4.2. Cross-Connect Configuration -* To have fast switching performance, SAI bulk create/remove APIs are used for management of OCS cross-connect configurations. -* OCS cross-connect can not be provisioned between two A side ports or two B side ports. -* One OCS port can only involved in one OCS cross-connect; when switching existing OCS cross-connect, e.g. switch from 1A-1B to 1A-2B, the upstream application need to use SAI API to remove 1A-1B and then create 1A-2B. +* OCS cross-connect can be provisioned between two OCS ports such as 1A-1B, 1A-2A, etc. +* SAI bulk create/remove APIs are used for management of OCS cross-connect configurations. The backend logic under SAI can be implemented with one operation to OCS device, similar as overwrite behavior. # 5. OCS Cross-Connects Factory Data -OCS cross-connect factory data are read-only information about insertion loss measurements of all possible cross-connects. +OCS cross-connect factory data are read-only information about factory beginning-of-life measurements that serve as a baseline reference that users can compare with. * Factory data are measured during the manufacturing calibration phase. -* The measurement is for every possible optical path (cross-connect) with an optical spectrum (central frequency) in specific environment (temperature). +* The measurement is for optical paths (cross-connects) with an optical spectrum (central frequency) in specific environment (temperature). # 6. OCS SAI Object and Attributes | SAI Object | SAI Attributes | SAI Data Type | diff --git a/doc/OCS/images/port_status.png b/doc/OCS/images/port_status.png index b470c2aa3920e9b79278a7a3e9ea5b9f9f551a73..366816c596e6a93c47b6fa5dde917daef6addc1d 100755 GIT binary patch literal 28207 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 aD)~G_x!Yzrfq3NYk+g(@c)8dozyAVA_l#u# literal 30938 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.5dB of target + * @brief Status when device is performing the switching. */ SAI_OCS_PORT_STATUS_TUNING, /** - * @brief Insertion loss is within 0.5dB of target + * @brief Status when the device has finished switching. */ SAI_OCS_PORT_STATUS_TUNED, /** - * @brief If there is a hardware failure + * @brief This is not a configuration or permanent failure flag. It is meant as a status in the port tuning state machine, for example, when software fails to apply a beam steering state to the OCS module due to some communication issue. It is up to the vendor to determine what constitutes a failure in port tuning. Note that the "failed" status is not an all-inclusive status but only used at times that the software knows of a certain failure in tuning. */ SAI_OCS_PORT_STATUS_FAILED } sai_ocs_port_status_t; From 263488e8813ef43406e74b1cdb282c4fbc655fee Mon Sep 17 00:00:00 2001 From: Nathan Ni Date: Tue, 27 Jan 2026 10:00:19 +0800 Subject: [PATCH 7/7] Update based on comments Signed-off-by: Nathan Ni --- experimental/saiexperimentalocs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/saiexperimentalocs.h b/experimental/saiexperimentalocs.h index cb700adaa..85fda38ec 100644 --- a/experimental/saiexperimentalocs.h +++ b/experimental/saiexperimentalocs.h @@ -134,7 +134,7 @@ typedef sai_status_t (*sai_get_ocs_cross_connect_attribute_fn)( typedef enum _sai_ocs_port_override_state_t { /** - * @brief Default, state to be determined by presence of cross-connect + * @brief Default, port status to be determined by presence of cross-connect */ SAI_OCS_PORT_OVERRIDE_STATE_NORMAL,