From 423bea508cb3a295e5d565b19aa6be97628c0ffa Mon Sep 17 00:00:00 2001 From: isabelmsft Date: Wed, 27 Mar 2024 22:36:11 +0000 Subject: [PATCH 01/11] add gNOI HLD --- .../SONiC_GNOI_Server_Interface_Design.md | 643 ++++++++++++++++++ doc/mgmt/gnmi/images/filename_gnoi.png | Bin 0 -> 78618 bytes doc/mgmt/gnmi/images/filename_gnoi.svg | 1 + doc/mgmt/gnmi/images/gnoi_gnmi_overview.svg | 1 + doc/mgmt/gnmi/images/gnoi_write_threads.svg | 1 + doc/mgmt/gnmi/images/update_dpu_firmware.svg | 1 + 6 files changed, 647 insertions(+) create mode 100644 doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md create mode 100644 doc/mgmt/gnmi/images/filename_gnoi.png create mode 100644 doc/mgmt/gnmi/images/filename_gnoi.svg create mode 100644 doc/mgmt/gnmi/images/gnoi_gnmi_overview.svg create mode 100644 doc/mgmt/gnmi/images/gnoi_write_threads.svg create mode 100644 doc/mgmt/gnmi/images/update_dpu_firmware.svg diff --git a/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md b/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md new file mode 100644 index 0000000000..617baa07d9 --- /dev/null +++ b/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md @@ -0,0 +1,643 @@ +# SONiC GNOI Server Interface Design + +# High Level Design Document + +#### Rev 0.1 + +# Table of Contents +- [Table of Contents](#table-of-contents) +- [Revision](#revision) +- [About this Document](#about-this-document) +- [Definition/Abbreviation](#definitionabbreviation) +- [Background](#background) +- [Scope](#scope) +- [1 Project Goal Summary](#1-project-goal-summary) +- [2 Requirements](#2-requirements) +- [3 Architecture Design](#3-architecture-design) +- [4 High Level Design](#4-high-level-design) +- [5 Typical Scenarios](#5-typical-scenarios) +- [6 Testing](#6-testing) + + + +# Revision + +| Rev | Date | Author | Change Description | +|:---:|:-----------:|:------------------:|---------------------| +| 0.1 | 03/27/2024 | Isabel Li | Initial version | + +# About this Document +This document provides a detailed description on the strategy to implement the SONiC GNOI Server Interface. + +# Definition/Abbreviation +| **Term** | **Meaning** | +| -------- | -------------------------- | +| API | Application Programming Interface | +| CLI | Command Line Interface | +| gRPC | A modern open-source high performance Remote Procedure Call (RPC) framework that can run in any environment | +| gNMI | gRPC Network Management Interface, used to retrieve or manipulate the state of a device via telemetry or configuration data | +| gNOI | gRPC Network Operations Interface | +| NE | Network Engineers | + +# Background +Software for Open Networking in the Cloud (SONiC) is an open source network operating system (NOS) based on Linux that runs on switches from multiple vendors and ASICs. SONiC offers a full suite of network functionality, like BGP and RDMA, that has been production-hardened in the data centers of some of the largest cloud service providers. + +Currently, most SONiC operation and configuration management requires directly using CLI on the device. This document proposes the addition of gNOI API to SONiC to modernize SONiC operation management. + +# Scope +This document describes the high level design of SONiC GNOI Server Interface. + +## 1 Project Goal Summary +Network engineers (NE) currently rely on command line interfaces (CLI) to operate SONiC devices. We plan to replace CLI by GNOI API, which will help minimize network engineers’ manual touches on SONiC devices. + +## 2 Requirements +We plan to use GNOI API to replace the most common NE CLI used for SONiC operation management. These APIs can sit behind a website frontend that NEs interact with directly, which enables NEs to execute common tasks with a simple webpage interaction. This saves time and reduces errors. + +Support for commonly used SONiC operation management CLI +* sudo sonic_installer install +* sudo reboot +* sudo systemctl restart +* sudo config bgp shutdown all +* sudo config bgp startup all + +Support for commonly used Linux system management CLI +* mv +* cp +* rm + +Support for other commonly used SONiC operations +* cert installation +* firmware upgrade +* Traffic shift away (TSA), traffic shift back (TSB) + +## 3 Architecture Design + +The GNOI/GNMI server uses DBUS to communicate with the SONiC host services, which are responsible for executing various commands on the device. Some of these commands are "config reload", "reboot", "sonic-installer install", "cp", "mv", and "rm". + +All the introduced features will be part of the sonic-telemetry package installed in sonic-telemetry container. + +gnmi-server + +## 4 High Level Design + +### 4.1. GNOI RPC API +We need to implement these GNOI APIs to support SONiC operations. + +#### OS.Activate +We can use this API to select the image which will be used after reboot. + +Arguments: OS version string to be activated after reboot, Boolean flag to determine whether the reboot process should be initiated immediately after changing the OS version string +``` +rpc Activate(ActivateRequest) returns (ActivateResponse); + +message ActivateRequest { + // The version that is required to be activated and optionally immediattely + // booted. + string version = 1; + // For dual Supervisors setting this flag instructs the Target to perform the + // action on the Standby Supervisor. + bool standby_supervisor = 2; + // If set to 'False' the Target will initiate the reboot process immediatelly + // after changing the next bootable OS version. + // If set to 'True' a separate action to reboot the Target and start using + // the activated OS version is required. This action CAN be executing + // the gNOI.system.Reboot() RPC. + bool no_reboot = 3; +} + +message ActivateResponse { + oneof response { + ActivateOK activate_ok = 1; + ActivateError activate_error = 2; + } +} + +``` +#### OS.Verify +We can use this API to verify the running OS version. + +Arguments: None +``` +rpc Verify(VerifyRequest) returns (VerifyResponse); + +message VerifyRequest { +} + +message VerifyResponse { + // The OS version currently running. This string should match OC path + // /system/state/software-version + string version = 1; + // Informational message describing fail details of the last boot. This MUST + // be set when a newly transferred OS fails to boot and the system falls back + // to the previously running OS version. It MUST be cleared whenever the + // systems successfully boots the activated OS version. + string activation_fail_message = 2; + + VerifyStandby verify_standby = 3; + // Dual Supervisor Targets that require the Install/Activate/Verify process + // executed once per supervisor reply with individual_supervisor_install set + // to true + bool individual_supervisor_install = 4; +} +``` + +#### File.Get +We can use this API to get a file from SONiC device. + +Arguments: absolute path string to an existing remote file +``` +rpc Get(GetRequest) returns (stream GetResponse) {} + +message GetRequest { + string remote_file = 1; +} + +message GetResponse { + oneof response { + bytes contents = 1; + gnoi.types.HashType hash = 2; // hash of the file. + } +} +``` + +#### File.Put +We can use this API to put a file to SONiC device. Since File API is verify powerful, we will check client role. Only read-write clients can upload files. +Arguments: absolute path string on target where file should be written, file permissions, contents to be written to target + +Arguments: absolute path string on target where file should be written, file permissions, contents to be written to target + +``` +rpc Put(stream PutRequest) returns (PutResponse) {} + +message PutRequest { + message Details { + string remote_file = 1; + // Permissions are represented as the octal format of standard UNIX + // file permissions. + // ex. 775: user read/write/execute, group read/write/execute, + // global read/execute. + uint32 permissions = 2; + } + oneof request { + Details open = 1; + bytes contents = 2; + gnoi.types.HashType hash = 3; // hash of the file. + } +} + +message PutResponse { +} +``` + +#### File.Stat +We can use this API to get file size, permission etc. + +Arguments: path string for which we want to retrieve file(s) info +``` +rpc Stat(StatRequest) returns (StatResponse) {} + +message StatRequest { + string path = 1; +} + +message StatResponse { + repeated StatInfo stats = 1; +} +``` + +#### File.Remove +We can use this API to remove a file from SONiC device. We will check client role, only read-write clients can remove file. + +Arguments: path string of file to be removed from target +``` +rpc Remove(RemoveRequest) returns (RemoveResponse) {} + +// A RemoveRequest specifies a file to be removed from the target. +message RemoveRequest { + string remote_file = 1; +} + +message RemoveResponse { +} +``` + +#### FactoryReset.Start +We can use this API to clean up all the configurations and decommission device. + +Arguments: Booleans to instruct target to rollback to original OS version, zero fill persistent storage state data, and retain certificates +``` +rpc Start(StartRequest) returns (StartResponse); + +message StartRequest { + // Instructs the Target to rollback the OS to the same version as it shipped + // from factory. + bool factory_os = 1; + // Instructs the Target to zero fill persistent storage state data. + bool zero_fill = 2; + // Instructs the Target to retain certificates + bool retain_certs = 3; +} + +message StartResponse { + oneof response { + // Reset will be executed. + ResetSuccess reset_success = 1; + // Reset will not be executed. + ResetError reset_error = 2; + } +} +``` + +#### CertificateManagement.Install +We can use this API to install bootstrap certificate. + +Arguments: parameters to generate and store new certificates +``` +rpc Install(stream InstallCertificateRequest) + returns (stream InstallCertificateResponse); +// Request messages to install new certificates on the target. + +message InstallCertificateRequest { + // Request Messages. + oneof install_request { + GenerateCSRRequest generate_csr = 1; + LoadCertificateRequest load_certificate = 2; + } +} + +// Response Messages from the target for the InstallCertificateRequest. +message InstallCertificateResponse { + // Response messages. + oneof install_response { + GenerateCSRResponse generated_csr = 1; + LoadCertificateResponse load_certificate = 2; + } +} +``` + +#### System.SetPackage +We can use this API to download an image or package from remote and install this image or package, and we can also use this API to send image from GNOI client to SONiC device. + +Arguments: destination path and filename of the package, version of the package, Boolean to indicate whether the package should be made active after receipt on the device, package contents, hash of file contents +``` +rpc SetPackage(stream SetPackageRequest) returns (SetPackageResponse) {} + +message SetPackageRequest { + oneof request { + Package package = 1; + bytes contents = 2; + types.HashType hash = 3; // Verification hash of data. + } +} + +message SetPackageResponse { +} +``` + +#### System.Reboot +We can use this API to support warm reboot and cold reboot, and restart individual services. + +Arguments: type of reboot (cold, warm, etc.), delay before issuing reboot, string describing reason for reboot, option to force reboot if sanity checks fail +``` +rpc Reboot(RebootRequest) returns (RebootResponse) {} + +message RebootRequest { + RebootMethod method = 1; + // Delay in nanoseconds before issuing reboot. + uint64 delay = 2; + // Informational reason for the reboot. + string message = 3; + // Optional sub-components to reboot. + repeated types.Path subcomponents = 4; + // Force reboot if sanity checks fail. (ex. uncommited configuration) + bool force = 5; +} + +message RebootResponse { +} +``` +For SONiC cold reboot, we can use COLD method. +For SONiC warm reboot, we can use WARM method. +For SONiC fast reboot, we can use NSF method. +For SONiC config reload, we can use reserved method. + +#### System.KillProcess +We can use this API to kill an OS process, and optionally restart. + +Arguments: process ID of process to be killed, name of process to be killed, termination signal sent to process (SIGNAL_TERM, SIGNAL_KILL, etc.) +``` +rpc KillProcess(KillProcessRequest) returns (KillProcessResponse) {} + +message KillProcessRequest { + // Process ID of the process to be killed. + uint32 pid = 1; + // Name of the process to be killed. + string name = 2; + // Termination signal sent to the process. + enum Signal { + SIGNAL_UNSPECIFIED = 0; // Invalid default. + SIGNAL_TERM = 1; // Terminate the process gracefully. + SIGNAL_KILL = 2; // Terminate the process immediately. + SIGNAL_HUP = 3; // Reload the process configuration. + // Terminate the process immediately and dump a core file. + SIGNAL_ABRT = 4; + } + + Signal signal = 3; + // Whether the process should be restarted after termination. + // This value is ignored when the termination signal is SIGHUP. + bool restart = 4; +} + +message KillProcessResponse { +} +``` + +#### Containerz.StartContainer +We can use this API to start a SONiC container. Note: a new API needs to be added to support non-containerized service restarts + +Arguments: image tag, image name of container to start +``` +rpc StartContainer(StartContainerRequest) returns (StartContainerResponse) {} + +message StartContainerRequest { + // The name and tag of the container to start. + string image_name = 1; + string tag = 2; + string cmd = 3; + + // Optional. The name to give the running container. If none is specified, + // the target should assign one. + string instance_name = 4; + message Port { + uint32 internal = 1; + uint32 external = 2; + } + + // List of internal ports to expose outside the container. + repeated Port ports = 5; + + // Environment to set in the container. + map environment = 6; + + // List of volumes that should be attached to the container. + repeated Volume volumes = 7; + + // Other container properties will be added as it becomes necessary. +} + +message StartContainerResponse { + oneof response { + StartOK start_ok = 1; + StartError start_error = 2; + } +} + +``` + +#### Containerz.StopContainer +We can use this API to stop or restart a SONiC container. + +Arguments: container name, bool force to determine whether the process should be forcibly killed, bool restart to determine if the service should be started immediately after stopping it +``` +rpc StopContainer(StopContainerRequest) returns (StopContainerResponse) {} + +message StopContainerRequest { + string instance_name = 1; + + // If force is set, the target should attempt to forcibly kill the container. + bool force = 2; + + // If restart is set, the target should start the container immediately + // after stopping it. + bool restart = 3; +} + +message StopContainerResponse { + enum Code { + // An unspecified error. The details field should provide more information. + UNSPECIFIED = 0; + + // Container is busy. + BUSY = 1; + + // Instance was not found on the target. + NOT_FOUND = 2; + + // The container was removed. + SUCCESS = 3; + } + + Code code = 1; + string details = 2; +} +``` + +#### Containerz.Deploy +We can use this API to set a new container image on the target + +Arguments: container image name, tag, remote download URL or image file content +``` +rpc Deploy(stream DeployRequest) returns (stream DeployResponse) {} + +message DeployRequest { + oneof request { + ImageTransfer image_transfer = 1; + bytes content = 2; + ImageTransferEnd image_transfer_end = 3; + } +} + +message DeployResponse { + oneof response { + ImageTransferReady image_transfer_ready = 1; + ImageTransferProgress image_transfer_progress = 2; + ImageTransferSuccess image_transfer_success = 3; + google.rpc.Status image_transfer_error = 4; + } +} +``` + +#### Containerz.RemoveContainer +We can use this API to remove an unused container image + +Arguments: container image name to be removed, container tag to be removed, force boolean +``` +rpc RemoveContainer(RemoveContainerRequest) returns (RemoveContainerResponse) {} + +message RemoveContainerRequest { + // The container image name to be removed. + string name = 1; + + // The container tag to be removed. + string tag = 2; + + // If force is set, the target should attempt to forcibly remove the + // container. + bool force = 3; +} + +message RemoveContainerResponse { + enum Code { + // An unspecified error. Must use the detail value to describe the issue. + UNSPECIFIED = 0; + + // Indicates the image was not found in the remote location. + NOT_FOUND = 1; + + // Indicates that a container using this image is running. + RUNNING = 2; + + // The container image was successfully removed. + SUCCESS = 3; + } + + Code code = 1; + string detail = 2; +} +``` + +Additionally, some [private SONiC APIs](https://github.com/sonic-net/sonic-gnmi/blob/master/proto/gnoi/sonic_gnoi.proto#L11) have been defined: +``` +service SonicService { + rpc ShowTechsupport (TechsupportRequest) returns (TechsupportResponse) {} + rpc CopyConfig(CopyConfigRequest) returns (CopyConfigResponse) {} + rpc ImageInstall(ImageInstallRequest) returns (ImageInstallResponse) {} + rpc ImageRemove(ImageRemoveRequest) returns (ImageRemoveResponse) {} + rpc ImageDefault(ImageDefaultRequest) returns (ImageDefaultResponse) {} +} +``` +We plan to add support for ShowTechsupport. We also plan to add APIs to support additional use cases: +* #### Start Process +GNOI System.proto defines only KillProcess, which can optionally restart a process. There is not yet an API specific to starting a process. +* #### TSA, TSB +GNOI bgp API is related, but does not meet our requirements. We need to add an API which supports modifying route-map + +### 4.2. Authentication + +A GNOI/GNMI server needs to validate the user role before executing any operation. Depending on the user role, the server may allow or deny different types of operations. For example, some users can only run read-only operations, such as get or subscribe, while some users can run read-write operations, such as set or reboot. + +We plan to use CNAME in client certificates to determine user roles. +For example, CNAME is ro.gnmi.sonic.gbl for read-only user, and CNAME is rw.gnmi.sonic.gbl for read-write user. +#### PROS: +There’s no dependency on an external service, and GNOI client does not need to provide username and password. + +### 4.3. Parallel Operations +SONiC GNOI/GNMI server does not support parallel write operations. We will put the GNOI/GNMI write requests in a queue and serve them with a single worker. +gnoi-write-threads + +### 4.4. Docker to Host Communication +Some commands are desired to run on the host, such as `systemctl restart `, `config apply-patch` and `config reload`. For several reasons, it is difficult to support these operations in a container: +1. These commands will update redis database and restart container, when they restart gnmi, bgp, syncd and swss, the ongoing gNOI operation will be broken. +2. 'config reload' will stop service at first, run some other operations, and then restart service. If we run this command in a container, it will be broken at the stop service step. +3. These commands will execute some host scripts and use systemctl to restart service, so it would be dangerous to support these operations in a container. +The solution is to add host services for `config apply-patch` and `config reload` on the host. GNOI/GNMI server can then use dbus method to invoke these host services. + +## 5 Typical Scenarios +### 5.1. Upgrade DPU Firmware + +upgrade-dpu-firmware +We need the below steps to upgrade DPU firmware: + +* GNMI Get +Read current DPU firmware. If it's not golden firmware, we need to ugprade. +* GNOI System.SetPackage +The SetPackage API downloads DPU firmware from remote host to local filesystem. Filename is used to specify DPU firmware and DPU id, and firmware is not activated by default. The below chart shows possible firmware types and proposed file paths that will be supported by System.SetPackage. This example is for SONiC image running on DPU; the relevant row is marked with Filename SONiC/DPU0/default. + +| Filename | Version | Activate | Firmware type | Proposed file location | +|-------------------------|------------|----------|----------------------------|-----------------------------------------------------| +| SONiC/localhost/default | 20230531.10| False | SONiC image | /tmp/sonic-20230531.10.bin | +| SONiC/DPU0/default | 20230531.10| False | SONiC image to run on DPU0 | /usr/share/sonic/dpu/dpu-sonic-20230531.10.bin | +| DPU/DPU0/default | 20230531.10| False | DPU firmware for DPU0 | /usr/share/sonic/dpu/dpu-20230531.10.bin | +| CABLE/Ethernet0/default | 1.1 | False | Cable firmware for Ethernet0| /usr/share/sonic/firmware/cable-1.1.bin | +| ASIC/ASIC0/default | 1.0 | False | ASIC firmware for ASIC0 | /usr/share/sonic/asic/asic-1.0.bin | +| CPLD/localhost/default | 1.0 | False | CPLD firmware for localhost| /usr/share/sonic/cpld/cpld-1.0.bin | +| CPLD/DPU0/default | 1.0 | False | CPLD firmware for DPU0 | /usr/share/sonic/dpu/cpld/cpld-1.0.bin | + +GNOI API will use the below rules for Filename in System.SetPackage. Each part of filename is split by slash. +1. The first part is type, it can be SONIC, DPU, CABLE, CPLD and ASIC, we might support other types like CPU microcode. +2. The second part is device name, it can be DPU0 for DPU, and it can be Ethernet0 or ASIC0-Ethernet1 for cable. It’s possible to have embedded device name, for example, DPU0/Ethernet0. +3. The last part is default for now, we will use this part for future extension. + +filename-gnoi + +* GNOI System.SetPackage +We will use the same GNOI API to activate existing DPU firmware and reboot DPU, activate is True and remote_download is empty for activate operation. + +``` +// Package defines a single package file to be placed on the target. +message Package { + // Destination path and filename of the package. + string filename = 1; + // Version of the package. (vendor internal name) + string version = 4; + // Indicates that the package should be made active after receipt on + // the device. For system image packages, the new image is expected to + // be active after a reboot. + bool activate = 5; + // Details for the device to download the package from a remote location. + common.RemoteDownload remote_download = 6; +} + +// SetPackageRequest will place the package onto the target and optionally mark +// it as the next bootable image. The initial message must be a package +// message containing the filename and information about the file. Following the +// initial message the contents are then streamed in maximum 64k chunks. The +// final message must be a hash message contains the hash of the file contents. +message SetPackageRequest { + oneof request { + Package package = 1; + bytes contents = 2; + types.HashType hash = 3; // Verification hash of data. + } +} + +message SetPackageResponse { +} +``` +Note: The OS.Activate API is not suitable for our use case, because it does not have a field to specify the subcomponent that we want to activate. + +* GNOI System.Reboot +We can use System.Reboot API to reboot one or more DPU, and the RebootRequest has a subcomponents field that allows us to specify which DPU we want to reboot. +We will use the same rule as GNOI System.SetPackage to determine device. +``` +message RebootRequest { + RebootMethod method = 1; + // Delay in nanoseconds before issuing reboot. + uint64 delay = 2; + // Informational reason for the reboot. + string message = 3; + // Optional sub-components to reboot. + repeated types.Path subcomponents = 4; + // Force reboot if sanity checks fail. (ex. uncommited configuration) + bool force = 5; +} +message Path { + string origin = 2; // Label to disambiguate path. + repeated PathElem elem = 3; // Elements of the path. +} +message PathElem { + string name = 1; // The name of the element in the path. + map key = 2; // Map of key (attribute) name to value. +} +``` +### 5.2. Upgrade Cable Firmware +We need the below steps to upgrade cable firmware: +* GNMI Get +Read current cable firmware for port from StateDB. If not golden firmware, we need to upgrade. + +* GNOI System.SetPackage +Download cable firmware from remote to host file system, file name is used to specify cable firmware and port, and firmware is not activated by default + +* GNOI System.SetPackage +We will use the same GNOI API to activate existing cable firmware, activate is True and remote_download is empty for activate operation. + +### 5.3. Isolate SONiC Device +Use new GNOI API to support TSA and TSB + +## 6 Testing +(WIP, detailed list pending) +### 6.1. Unit Testing +Unit tests will be added for each new supported gNOI API +### 6.2. E2E Testing +E2E tests will be added to [sonic-mgmt](https://github.com/sonic-net/sonic-mgmt.git) for each new supported gNOI API \ No newline at end of file diff --git a/doc/mgmt/gnmi/images/filename_gnoi.png b/doc/mgmt/gnmi/images/filename_gnoi.png new file mode 100644 index 0000000000000000000000000000000000000000..ef0fe6aff2fcc380d25d5d75164ac17b06ac00bb GIT binary patch literal 78618 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 R+Vci*=x7+K*Q(jS`9Jlw` \ No newline at end of file diff --git a/doc/mgmt/gnmi/images/gnoi_gnmi_overview.svg b/doc/mgmt/gnmi/images/gnoi_gnmi_overview.svg new file mode 100644 index 0000000000..60fc38bacc --- /dev/null +++ b/doc/mgmt/gnmi/images/gnoi_gnmi_overview.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/doc/mgmt/gnmi/images/gnoi_write_threads.svg b/doc/mgmt/gnmi/images/gnoi_write_threads.svg new file mode 100644 index 0000000000..9d52a344b7 --- /dev/null +++ b/doc/mgmt/gnmi/images/gnoi_write_threads.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/doc/mgmt/gnmi/images/update_dpu_firmware.svg b/doc/mgmt/gnmi/images/update_dpu_firmware.svg new file mode 100644 index 0000000000..af8f98dc29 --- /dev/null +++ b/doc/mgmt/gnmi/images/update_dpu_firmware.svg @@ -0,0 +1 @@ + \ No newline at end of file From 21eecb063418315ceba774b477bbe3d295c6c130 Mon Sep 17 00:00:00 2001 From: isabelmsft Date: Mon, 1 Apr 2024 04:06:46 +0000 Subject: [PATCH 02/11] update hld --- .../SONiC_GNOI_Server_Interface_Design.md | 92 ++++++++++++++----- 1 file changed, 67 insertions(+), 25 deletions(-) diff --git a/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md b/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md index 617baa07d9..845bfc0c27 100644 --- a/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md +++ b/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md @@ -45,20 +45,21 @@ Software for Open Networking in the Cloud (SONiC) is an open source network oper Currently, most SONiC operation and configuration management requires directly using CLI on the device. This document proposes the addition of gNOI API to SONiC to modernize SONiC operation management. # Scope -This document describes the high level design of SONiC GNOI Server Interface. +This document describes the high level design of SONiC gNOI Server Interface. + +GNOI support comes as a natural extension to preexisting gNMI support. GNOI RPCs are exposed on the same port as the gNMI server. For more information regarding gNMI, please refer to the [gNMI HLD](https://github.com/ganglyu/SONiC/blob/012afe049a707da87ac258c8aca5c501172d0f33/doc/mgmt/gnmi/SONiC_GNMI_Server_Interface_Design.md). ## 1 Project Goal Summary Network engineers (NE) currently rely on command line interfaces (CLI) to operate SONiC devices. We plan to replace CLI by GNOI API, which will help minimize network engineers’ manual touches on SONiC devices. -## 2 Requirements We plan to use GNOI API to replace the most common NE CLI used for SONiC operation management. These APIs can sit behind a website frontend that NEs interact with directly, which enables NEs to execute common tasks with a simple webpage interaction. This saves time and reduces errors. +## 2 Requirements + Support for commonly used SONiC operation management CLI * sudo sonic_installer install * sudo reboot * sudo systemctl restart -* sudo config bgp shutdown all -* sudo config bgp startup all Support for commonly used Linux system management CLI * mv @@ -68,15 +69,15 @@ Support for commonly used Linux system management CLI Support for other commonly used SONiC operations * cert installation * firmware upgrade -* Traffic shift away (TSA), traffic shift back (TSB) ## 3 Architecture Design -The GNOI/GNMI server uses DBUS to communicate with the SONiC host services, which are responsible for executing various commands on the device. Some of these commands are "config reload", "reboot", "sonic-installer install", "cp", "mv", and "rm". +All the introduced features are part of the sonic-telemetry package installed in sonic-telemetry container. + +The GNOI/GNMI server uses [DBUS](https://github.com/sonic-net/SONiC/blob/master/doc/mgmt/Docker%20to%20Host%20communication.md) to communicate with the SONiC host services, which are responsible for executing various commands on the device. Some of these commands are "config reload", "reboot", "sonic-installer install", "cp", "mv", and "rm". -All the introduced features will be part of the sonic-telemetry package installed in sonic-telemetry container. -gnmi-server +gnmi-server ## 4 High Level Design @@ -162,7 +163,6 @@ message GetResponse { #### File.Put We can use this API to put a file to SONiC device. Since File API is verify powerful, we will check client role. Only read-write clients can upload files. -Arguments: absolute path string on target where file should be written, file permissions, contents to be written to target Arguments: absolute path string on target where file should be written, file permissions, contents to be written to target @@ -510,26 +510,31 @@ service SonicService { We plan to add support for ShowTechsupport. We also plan to add APIs to support additional use cases: * #### Start Process GNOI System.proto defines only KillProcess, which can optionally restart a process. There is not yet an API specific to starting a process. -* #### TSA, TSB -GNOI bgp API is related, but does not meet our requirements. We need to add an API which supports modifying route-map ### 4.2. Authentication +GNMI already supports three authentication mechanisms that are naturally extended to gNOI: +* Basic Authentication - Requires passing of username and password in the gRPC metadata via the username and password keys. +* JSON Web Tokens (JWT) - Requires initial authentication via either basic or certificate authentication using the gNOI Authenticate RPC, afterwhich a token is recieved that can be used with future requests to avoid further authentication. The JWT token is sent in the metadata of the gRPC requests with the access_token key. +* Certificate - A valid client certificate is used with the username embedded in the certificate CN field. This allows the requests to be authenticaed against the CA certificate and the username can be used for authorization. + A GNOI/GNMI server needs to validate the user role before executing any operation. Depending on the user role, the server may allow or deny different types of operations. For example, some users can only run read-only operations, such as get or subscribe, while some users can run read-write operations, such as set or reboot. -We plan to use CNAME in client certificates to determine user roles. -For example, CNAME is ro.gnmi.sonic.gbl for read-only user, and CNAME is rw.gnmi.sonic.gbl for read-write user. -#### PROS: -There’s no dependency on an external service, and GNOI client does not need to provide username and password. +We plan to use CNAME in client certificates to determine user roles. The benefit of this is that there's no dependency on an external service, and GNOI client does not need to provide username and password. +* CNAME is ro.gnmi.sonic.gbl for read-only user +* CNAME is rw.gnmi.sonic.gbl for read-write user. + ### 4.3. Parallel Operations -SONiC GNOI/GNMI server does not support parallel write operations. We will put the GNOI/GNMI write requests in a queue and serve them with a single worker. +The GNOI/GNMI server accepts concurrent requests. Parallel reads and sequential writes are permitted. + +The GNOI/GNMI server does not support parallel write operations. GNOI/GNMI write requests are placed in a queue and served with a single worker. gnoi-write-threads ### 4.4. Docker to Host Communication -Some commands are desired to run on the host, such as `systemctl restart `, `config apply-patch` and `config reload`. For several reasons, it is difficult to support these operations in a container: -1. These commands will update redis database and restart container, when they restart gnmi, bgp, syncd and swss, the ongoing gNOI operation will be broken. -2. 'config reload' will stop service at first, run some other operations, and then restart service. If we run this command in a container, it will be broken at the stop service step. +Some commands are designed to run on the host, such as `systemctl restart `, `config apply-patch` and `config reload`. For several reasons, it is difficult to support these operations in a container: +1. These commands update redis database and may restart a container. When they restart gnmi, bgp, syncd, or swss, the ongoing gNOI operation will be broken. +2. 'config reload' will stop services, run some other operations, and then restart services. If we run this command in a container, it will break at the stop service step. 3. These commands will execute some host scripts and use systemctl to restart service, so it would be dangerous to support these operations in a container. The solution is to add host services for `config apply-patch` and `config reload` on the host. GNOI/GNMI server can then use dbus method to invoke these host services. @@ -542,7 +547,7 @@ We need the below steps to upgrade DPU firmware: * GNMI Get Read current DPU firmware. If it's not golden firmware, we need to ugprade. * GNOI System.SetPackage -The SetPackage API downloads DPU firmware from remote host to local filesystem. Filename is used to specify DPU firmware and DPU id, and firmware is not activated by default. The below chart shows possible firmware types and proposed file paths that will be supported by System.SetPackage. This example is for SONiC image running on DPU; the relevant row is marked with Filename SONiC/DPU0/default. +The SetPackage API downloads DPU firmware from remote host to local filesystem. Filename is used to specify DPU firmware and DPU id, and firmware is not activated by default. The below chart shows possible firmware types and proposed filenames that will be supported by System.SetPackage. This example is for SONiC image running on DPU; the relevant row is the second row, marked with filename SONiC/DPU0/default. | Filename | Version | Activate | Firmware type | Proposed file location | |-------------------------|------------|----------|----------------------------|-----------------------------------------------------| @@ -599,7 +604,6 @@ Note: The OS.Activate API is not suitable for our use case, because it does not * GNOI System.Reboot We can use System.Reboot API to reboot one or more DPU, and the RebootRequest has a subcomponents field that allows us to specify which DPU we want to reboot. -We will use the same rule as GNOI System.SetPackage to determine device. ``` message RebootRequest { RebootMethod method = 1; @@ -621,6 +625,7 @@ message PathElem { map key = 2; // Map of key (attribute) name to value. } ``` + ### 5.2. Upgrade Cable Firmware We need the below steps to upgrade cable firmware: * GNMI Get @@ -632,12 +637,49 @@ Download cable firmware from remote to host file system, file name is used to sp * GNOI System.SetPackage We will use the same GNOI API to activate existing cable firmware, activate is True and remote_download is empty for activate operation. -### 5.3. Isolate SONiC Device -Use new GNOI API to support TSA and TSB ## 6 Testing (WIP, detailed list pending) ### 6.1. Unit Testing -Unit tests will be added for each new supported gNOI API +| Test Case | Description | +| ---- | ---- | +| 1 | UT for OS.Activate | +| 2 | UT for OS.Verify | +| 3 | UT for File.Get | +| 4 | UT for File.Put | +| 5 | UT for File.Stat | +| 6 | UT for File.Remove | +| 7 | UT for FactoryReset.Start | +| 8 | UT for CertificateManagement.Install | +| 9 | UT for System.SetPackage | +| 10 | UT for System.Reboot | +| 11 | UT for Containerz.StartContainer | +| 12 | UT for Containerz.StopContainer | +| 13 | UT for Containerz.Deploy | +| 14 | UT for Containerz.RemoveContainer | +| 15 | UT for System.KillProcess | +| 16 | UT for dbus client initialization | +| 17 | UT for dbus config reload API call | +| 18 | UT for dbus service restart API call | + + ### 6.2. E2E Testing -E2E tests will be added to [sonic-mgmt](https://github.com/sonic-net/sonic-mgmt.git) for each new supported gNOI API \ No newline at end of file +E2E tests will be added to [sonic-mgmt](https://github.com/sonic-net/sonic-mgmt.git) +| Test Case | Description | +| ---- | ---- | +| 1 | E2E test for OS.Activate | +| 2 | E2E test for OS.Verify | +| 3 | E2E test for File.Get | +| 4 | E2E test for File.Put | +| 5 | E2E test for File.Stat | +| 6 | E2E test for File.Remove | +| 7 | E2E test for FactoryReset.Start | +| 8 | E2E test for CertificateManagement.Install | +| 9 | E2E test for System.SetPackage | +| 10 | E2E test for System.Reboot | +| 11 | E2E test for Containerz.StartContainer | +| 12 | E2E test for Containerz.StopContainer | +| 13 | E2E test for Containerz.Deploy | +| 14 | E2E test for Containerz.RemoveContainer | +| 15 | E2E test for System.KillProcess | +| 16 | E2E test to verify that required gNOI/gNMI parameters are in ConfigDB (certs, port) | \ No newline at end of file From 2608cb30816bd4d13c5dae57d887767939086962 Mon Sep 17 00:00:00 2001 From: isabelmsft Date: Mon, 1 Apr 2024 05:22:43 +0000 Subject: [PATCH 03/11] rm CNAME --- doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md b/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md index 845bfc0c27..89aa5bfb8c 100644 --- a/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md +++ b/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md @@ -47,7 +47,7 @@ Currently, most SONiC operation and configuration management requires directly u # Scope This document describes the high level design of SONiC gNOI Server Interface. -GNOI support comes as a natural extension to preexisting gNMI support. GNOI RPCs are exposed on the same port as the gNMI server. For more information regarding gNMI, please refer to the [gNMI HLD](https://github.com/ganglyu/SONiC/blob/012afe049a707da87ac258c8aca5c501172d0f33/doc/mgmt/gnmi/SONiC_GNMI_Server_Interface_Design.md). +GNOI support comes as a natural extension to preexisting gNMI support. GNOI RPCs are exposed on the same server/port as the gNMI server. For more information regarding gNMI, please refer to the [gNMI HLD](https://github.com/ganglyu/SONiC/blob/012afe049a707da87ac258c8aca5c501172d0f33/doc/mgmt/gnmi/SONiC_GNMI_Server_Interface_Design.md). ## 1 Project Goal Summary Network engineers (NE) currently rely on command line interfaces (CLI) to operate SONiC devices. We plan to replace CLI by GNOI API, which will help minimize network engineers’ manual touches on SONiC devices. @@ -520,11 +520,6 @@ GNMI already supports three authentication mechanisms that are naturally extende A GNOI/GNMI server needs to validate the user role before executing any operation. Depending on the user role, the server may allow or deny different types of operations. For example, some users can only run read-only operations, such as get or subscribe, while some users can run read-write operations, such as set or reboot. -We plan to use CNAME in client certificates to determine user roles. The benefit of this is that there's no dependency on an external service, and GNOI client does not need to provide username and password. -* CNAME is ro.gnmi.sonic.gbl for read-only user -* CNAME is rw.gnmi.sonic.gbl for read-write user. - - ### 4.3. Parallel Operations The GNOI/GNMI server accepts concurrent requests. Parallel reads and sequential writes are permitted. From 8aa65b8c206c309070451d57aa0ebecc81d3c1d0 Mon Sep 17 00:00:00 2001 From: isabelmsft Date: Mon, 1 Apr 2024 22:29:03 +0000 Subject: [PATCH 04/11] update --- .../SONiC_GNOI_Server_Interface_Design.md | 78 +- .../gnmi/images/dpu_firmware_apis_hld.svg | 666 ++++++++++++++++++ 2 files changed, 681 insertions(+), 63 deletions(-) create mode 100644 doc/mgmt/gnmi/images/dpu_firmware_apis_hld.svg diff --git a/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md b/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md index 89aa5bfb8c..df07e08288 100644 --- a/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md +++ b/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md @@ -44,8 +44,10 @@ Software for Open Networking in the Cloud (SONiC) is an open source network oper Currently, most SONiC operation and configuration management requires directly using CLI on the device. This document proposes the addition of gNOI API to SONiC to modernize SONiC operation management. +GNOI (gRPC network operations interface) is supported through OpenConfig. All gNOI services and documentation are available on the [OpenConfig page](https://github.com/openconfig/gnoi). OpenConfig defines and implements a common, vendor-independent software layer for managing network devices. + # Scope -This document describes the high level design of SONiC gNOI Server Interface. +This document describes the high level design of SONiC gNOI Server Interface, as well as the gNOI APIs necessary for SONiC operation management. GNOI support comes as a natural extension to preexisting gNMI support. GNOI RPCs are exposed on the same server/port as the gNMI server. For more information regarding gNMI, please refer to the [gNMI HLD](https://github.com/ganglyu/SONiC/blob/012afe049a707da87ac258c8aca5c501172d0f33/doc/mgmt/gnmi/SONiC_GNMI_Server_Interface_Design.md). @@ -81,66 +83,16 @@ The GNOI/GNMI server uses [DBUS](https://github.com/sonic-net/SONiC/blob/master/ ## 4 High Level Design +GNOI is composed of services, each of which is organized into related RPCs. We plan to add support for the following services: +* File - provides an interface for file operations on the target, including file transfer to and from the target node. +* FactoryReset - provides an interface for factory resetting the target node. +* CertificateManagement - provides an interface to install certificates on the target node. +* System - provides an interface for the management system-related operations on the target node. +* Containerz - provides an interface to perform container operations on a network device. + ### 4.1. GNOI RPC API We need to implement these GNOI APIs to support SONiC operations. -#### OS.Activate -We can use this API to select the image which will be used after reboot. - -Arguments: OS version string to be activated after reboot, Boolean flag to determine whether the reboot process should be initiated immediately after changing the OS version string -``` -rpc Activate(ActivateRequest) returns (ActivateResponse); - -message ActivateRequest { - // The version that is required to be activated and optionally immediattely - // booted. - string version = 1; - // For dual Supervisors setting this flag instructs the Target to perform the - // action on the Standby Supervisor. - bool standby_supervisor = 2; - // If set to 'False' the Target will initiate the reboot process immediatelly - // after changing the next bootable OS version. - // If set to 'True' a separate action to reboot the Target and start using - // the activated OS version is required. This action CAN be executing - // the gNOI.system.Reboot() RPC. - bool no_reboot = 3; -} - -message ActivateResponse { - oneof response { - ActivateOK activate_ok = 1; - ActivateError activate_error = 2; - } -} - -``` -#### OS.Verify -We can use this API to verify the running OS version. - -Arguments: None -``` -rpc Verify(VerifyRequest) returns (VerifyResponse); - -message VerifyRequest { -} - -message VerifyResponse { - // The OS version currently running. This string should match OC path - // /system/state/software-version - string version = 1; - // Informational message describing fail details of the last boot. This MUST - // be set when a newly transferred OS fails to boot and the system falls back - // to the previously running OS version. It MUST be cleared whenever the - // systems successfully boots the activated OS version. - string activation_fail_message = 2; - - VerifyStandby verify_standby = 3; - // Dual Supervisor Targets that require the Install/Activate/Verify process - // executed once per supervisor reply with individual_supervisor_install set - // to true - bool individual_supervisor_install = 4; -} -``` #### File.Get We can use this API to get a file from SONiC device. @@ -535,14 +487,13 @@ The solution is to add host services for `config apply-patch` and `config reload ## 5 Typical Scenarios ### 5.1. Upgrade DPU Firmware - -upgrade-dpu-firmware +upgrade-dpu-firmware We need the below steps to upgrade DPU firmware: * GNMI Get Read current DPU firmware. If it's not golden firmware, we need to ugprade. * GNOI System.SetPackage -The SetPackage API downloads DPU firmware from remote host to local filesystem. Filename is used to specify DPU firmware and DPU id, and firmware is not activated by default. The below chart shows possible firmware types and proposed filenames that will be supported by System.SetPackage. This example is for SONiC image running on DPU; the relevant row is the second row, marked with filename SONiC/DPU0/default. +The SetPackage API downloads DPU firmware from remote host to local filesystem. Filename is used to specify DPU firmware and DPU id. The below chart shows possible firmware types and proposed filenames that will be supported by System.SetPackage. This example is for SONiC image running on DPU; the relevant row is the second row, marked with filename SONiC/DPU0/default. | Filename | Version | Activate | Firmware type | Proposed file location | |-------------------------|------------|----------|----------------------------|-----------------------------------------------------| @@ -561,8 +512,7 @@ GNOI API will use the below rules for Filename in System.SetPackage. Each part o filename-gnoi -* GNOI System.SetPackage -We will use the same GNOI API to activate existing DPU firmware and reboot DPU, activate is True and remote_download is empty for activate operation. +We will use the same GNOI API call to activate existing DPU firmware and reboot DPU by setting activate to True. ``` // Package defines a single package file to be placed on the target. @@ -620,6 +570,8 @@ message PathElem { map key = 2; // Map of key (attribute) name to value. } ``` +* GNMI Get +Read current DPU firmware. If it's equal to target version, then upgrade was successful. ### 5.2. Upgrade Cable Firmware We need the below steps to upgrade cable firmware: diff --git a/doc/mgmt/gnmi/images/dpu_firmware_apis_hld.svg b/doc/mgmt/gnmi/images/dpu_firmware_apis_hld.svg new file mode 100644 index 0000000000..a108d69a2b --- /dev/null +++ b/doc/mgmt/gnmi/images/dpu_firmware_apis_hld.svg @@ -0,0 +1,666 @@ + + + + + + + + + + + + + + + + + + + + + + + + Page-1 + + + + + + + + + + Object lifeline.415 + GNOI/GNMI Server + + Sheet.2 + + + + Sheet.3 + + + + Sheet.4 + + + Sheet.5 + + + + + + + GNOI/GNMI Server + + + + + + + + + Script.420 + + Sheet.7 + + + + Sheet.8 + + + + Sheet.9 + + + + Sheet.10 + + + + Sheet.11 + + + + Sheet.12 + + + + Sheet.13 + + + + Sheet.14 + + + + Sheet.15 + + + + + Activation.430 + + + + + + + Return Message.431 + + + + + + + + + + Activation.432 + + + + + + + Sheet.19 + Download firmware from URL + + + + Download firmware from URL + + Self Message.435 + + + + + + + + + + Sheet.21 + If DPU firmware != target version, need to upgrade + + + + If DPU firmware != target version, need to upgrade + + + + + + + Object lifeline.437 + GNMI/GNOI client + + Sheet.23 + + + + Sheet.24 + + + + Sheet.25 + + + Sheet.26 + + + + + + + GNMI/GNOI client + + + + + + + + + User.442 + + Sheet.28 + + Sheet.29 + + + + Sheet.30 + + + + + + Activation.446 + + + + + + + Message.448 + GNMI get request DPU firmware verion + + + + + + + + + + + GNMI get requestDPU firmware verion + + Message.451 + GNOI system setpackage install/activate DPU firmware + + + + + + + + + + + GNOI system setpackageinstall/activate DPU firmware + + + + + + + + Database.462 + + Sheet.35 + + Sheet.36 + + + + Sheet.37 + + + + Sheet.38 + + + + Sheet.39 + + + + + + + + + + + Object lifeline.468 + database + + Sheet.41 + + + + Sheet.42 + + + + Sheet.43 + + + Sheet.44 + + + + + + + database + + + Activation.473 + + + + + + + Message.474 + Read StateDB + + + + + + + + + + + Read StateDB + + Return Message.475 + + + + + + + + + + Self Message.476 + + + + + + + + + + + + + + + Object lifeline.477 + SONiC host services + + Sheet.50 + + + + Sheet.51 + + + + Sheet.52 + + + Sheet.53 + + + + + + + SONiC host services + + + + + + + + + Script.482 + + Sheet.55 + + + + Sheet.56 + + + + Sheet.57 + + + + Sheet.58 + + + + Sheet.59 + + + + Sheet.60 + + + + Sheet.61 + + + + Sheet.62 + + + + Sheet.63 + + + + + Activation.492 + + + + + + + Message.493 + DBUS install DPU firmware + + + + + + + + + + + DBUSinstall DPU firmware + + Sheet.66 + Install DPU firmware + + + + Install DPU firmware + + Self Message.495 + + + + + + + + + + Return Message.496 + + + + + + + + + + Return Message.497 + + + + + + + + + + Message.498 + GNOI os.reboot Reboot DPU + + + + + + + + + + + GNOI os.reboot Reboot DPU + + Activation.500 + + + + + + + Activation.501 + + + + + + + Message.502 + DBUS Reboot DPU + + + + + + + + + + + DBUSReboot DPU + + Self Message.503 + + + + + + + + + + Sheet.75 + Reboot DPU + + + + Reboot DPU + + Return Message.506 + + + + + + + + + + Message.511 + GNMI get request DPU firmware verion + + + + + + + + + + + GNMI get requestDPU firmware verion + + Activation.512 + + + + + + + Message.513 + Read StateDB + + + + + + + + + + + Read StateDB + + Return Message.514 + + + + + + + + + + Activation.515 + + + + + + + Return Message.516 + + + + + + + + + + Sheet.83 + If DPU firmware version == target version, Upgrade Successful + + + + If DPU firmware version == target version, Upgrade Successful + + Self Message.518 + + + + + + + + + + From 6b5fd305b2dad0a1b4eaaa63410add0ad6e45066 Mon Sep 17 00:00:00 2001 From: isabelmsft Date: Tue, 2 Apr 2024 06:01:26 +0000 Subject: [PATCH 05/11] update HLD --- .../SONiC_GNOI_Server_Interface_Design.md | 155 +-- doc/mgmt/gnmi/images/gnoi_gnmi_arch.svg | 982 ++++++++++++++++++ doc/mgmt/gnmi/images/gnoi_gnmi_overview.svg | 1 - .../images/install_sonic_image_apis_flow.svg | 668 ++++++++++++ 4 files changed, 1738 insertions(+), 68 deletions(-) create mode 100644 doc/mgmt/gnmi/images/gnoi_gnmi_arch.svg delete mode 100644 doc/mgmt/gnmi/images/gnoi_gnmi_overview.svg create mode 100644 doc/mgmt/gnmi/images/install_sonic_image_apis_flow.svg diff --git a/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md b/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md index df07e08288..f3897b7135 100644 --- a/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md +++ b/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md @@ -15,7 +15,7 @@ - [2 Requirements](#2-requirements) - [3 Architecture Design](#3-architecture-design) - [4 High Level Design](#4-high-level-design) -- [5 Typical Scenarios](#5-typical-scenarios) +- [5 Sample Scenario](#5-sample-scenario) - [6 Testing](#6-testing) @@ -49,7 +49,7 @@ GNOI (gRPC network operations interface) is supported through OpenConfig. All gN # Scope This document describes the high level design of SONiC gNOI Server Interface, as well as the gNOI APIs necessary for SONiC operation management. -GNOI support comes as a natural extension to preexisting gNMI support. GNOI RPCs are exposed on the same server/port as the gNMI server. For more information regarding gNMI, please refer to the [gNMI HLD](https://github.com/ganglyu/SONiC/blob/012afe049a707da87ac258c8aca5c501172d0f33/doc/mgmt/gnmi/SONiC_GNMI_Server_Interface_Design.md). +GNOI support comes as a natural extension to preexisting gNMI support. GNOI RPCs are exposed on the same server/port as the gNMI server. For more information regarding gNMI, please refer to the [gNMI HLD](https://github.com/sonic-net/SONiC/blob/master/doc/mgmt/gnmi/SONiC_GNMI_Server_Interface_Design.md). ## 1 Project Goal Summary Network engineers (NE) currently rely on command line interfaces (CLI) to operate SONiC devices. We plan to replace CLI by GNOI API, which will help minimize network engineers’ manual touches on SONiC devices. @@ -59,14 +59,14 @@ We plan to use GNOI API to replace the most common NE CLI used for SONiC operati ## 2 Requirements Support for commonly used SONiC operation management CLI -* sudo sonic_installer install -* sudo reboot -* sudo systemctl restart +* `sudo sonic_installer install` +* `sudo reboot` +* `sudo systemctl restart ` Support for commonly used Linux system management CLI -* mv -* cp -* rm +* `mv` +* `cp` +* `rm` Support for other commonly used SONiC operations * cert installation @@ -74,12 +74,12 @@ Support for other commonly used SONiC operations ## 3 Architecture Design -All the introduced features are part of the sonic-telemetry package installed in sonic-telemetry container. +All the introduced features are part of the sonic-gnmi package installed in the sonic-gnmi container. The GNOI/GNMI server uses [DBUS](https://github.com/sonic-net/SONiC/blob/master/doc/mgmt/Docker%20to%20Host%20communication.md) to communicate with the SONiC host services, which are responsible for executing various commands on the device. Some of these commands are "config reload", "reboot", "sonic-installer install", "cp", "mv", and "rm". -gnmi-server +gnmi-server ## 4 High Level Design @@ -95,7 +95,7 @@ We need to implement these GNOI APIs to support SONiC operations. #### File.Get -We can use this API to get a file from SONiC device. +We can use this API to get a file from a SONiC device. Arguments: absolute path string to an existing remote file ``` @@ -142,19 +142,40 @@ message PutResponse { ``` #### File.Stat -We can use this API to get file size, permission etc. +We can use this API to get metadata about a file including size, permission etc. Arguments: path string for which we want to retrieve file(s) info ``` rpc Stat(StatRequest) returns (StatResponse) {} +// StatRequest will list files at the provided path. message StatRequest { string path = 1; } +// StatResponse contains list of stat info of the provided path. message StatResponse { repeated StatInfo stats = 1; } + +// StatInfo provides a file system information about a particular path. +message StatInfo { + string path = 1; + uint64 last_modified = 2; // Nanoseconds since epoch. + // Permissions are represented as the octal format of standard UNIX + // file permissions. + // ex. 775: user read/write/execute, group read/write/execute, + // global read/execute. + // The value returned in this field should be the octal number. No base + // conversion should be required to read the value. For example, 0755 + // should result in the permissions field holding the value 755, 4644 + // results in the permissions field being 4644, and so on. + uint32 permissions = 3; + uint64 size = 4; + // Default file creation mask. Represented as the octal format of + // standard UNIX mask. + uint32 umask = 5; +} ``` #### File.Remove @@ -228,9 +249,9 @@ message InstallCertificateResponse { ``` #### System.SetPackage -We can use this API to download an image or package from remote and install this image or package, and we can also use this API to send image from GNOI client to SONiC device. +We can use this API to download an image or package from remote (or passed directly in client request) and install this image or package. -Arguments: destination path and filename of the package, version of the package, Boolean to indicate whether the package should be made active after receipt on the device, package contents, hash of file contents +Arguments: filename of the package, version of the package, Boolean to indicate whether the package should be made active after receipt on the device, package contents, hash of file contents ``` rpc SetPackage(stream SetPackageRequest) returns (SetPackageResponse) {} @@ -242,12 +263,46 @@ message SetPackageRequest { } } +// Package defines a single package file to be placed on the target. +message Package { + // filename of the package. + string filename = 1; + // Version of the package. (vendor internal name) + string version = 4; + // Indicates that the package should be made active after receipt on + // the device. For system image packages, the new image is expected to + // be active after a reboot. + bool activate = 5; + // Details for the device to download the package from a remote location. + common.RemoteDownload remote_download = 6; +} + message SetPackageResponse { } ``` +The SetPackage API downloads an image or package from a remote host to the local filesystem. Because multiple targets are possible (SONiC image, cable firmware, etc.), filename in the `SetPackageRequest` is used to identify the target. The below table demonstrates how the target is specified through filename. Additionally, through SetPackage API implementation logic, the filename is then translated to a proposed file location. If filename is not in the expected format, the client's request is rejected. This process ensures that client-requested firmware upgrade files are in the expected path. + +| Filename | Version | Activate | Firmware type | Proposed file location | +|-------------------------|------------|----------|----------------------------|-----------------------------------------------------| +| SONiC/localhost/default | 20230531.10| False | SONiC image | /tmp/sonic-20230531.10.bin | +| SONiC/DPU0/default | 20230531.10| False | SONiC image to run on DPU0 | /usr/share/sonic/dpu/dpu-sonic-20230531.10.bin | +| DPU/DPU0/default | 20230531.10| False | DPU firmware for DPU0 | /usr/share/sonic/dpu/dpu-20230531.10.bin | +| CABLE/Ethernet0/default | 1.1 | False | Cable firmware for Ethernet0| /usr/share/sonic/firmware/cable-1.1.bin | +| ASIC/ASIC0/default | 1.0 | False | ASIC firmware for ASIC0 | /usr/share/sonic/asic/asic-1.0.bin | +| CPLD/localhost/default | 1.0 | False | CPLD firmware for localhost| /usr/share/sonic/cpld/cpld-1.0.bin | +| CPLD/DPU0/default | 1.0 | False | CPLD firmware for DPU0 | /usr/share/sonic/dpu/cpld/cpld-1.0.bin | + +GNOI API will use the below rules for Filename in System.SetPackage. Each part of filename is split by slash. +1. The first part is type. This may be SONIC, DPU, CABLE, CPLD or ASIC. +2. The second part is device name. This may be DPU0 for DPU, or Ethernet0 for cable. It’s possible to have embedded device name, for example, DPU0/Ethernet0. +3. The last part is default for now, we will use this part for future extension. + +filename-gnoi + + #### System.Reboot -We can use this API to support warm reboot and cold reboot, and restart individual services. +We can use this API to support various reboot methods. Arguments: type of reboot (cold, warm, etc.), delay before issuing reboot, string describing reason for reboot, option to force reboot if sanity checks fail ``` @@ -269,8 +324,11 @@ message RebootResponse { } ``` For SONiC cold reboot, we can use COLD method. + For SONiC warm reboot, we can use WARM method. + For SONiC fast reboot, we can use NSF method. + For SONiC config reload, we can use reserved method. #### System.KillProcess @@ -453,66 +511,40 @@ Additionally, some [private SONiC APIs](https://github.com/sonic-net/sonic-gnmi/ ``` service SonicService { rpc ShowTechsupport (TechsupportRequest) returns (TechsupportResponse) {} - rpc CopyConfig(CopyConfigRequest) returns (CopyConfigResponse) {} - rpc ImageInstall(ImageInstallRequest) returns (ImageInstallResponse) {} - rpc ImageRemove(ImageRemoveRequest) returns (ImageRemoveResponse) {} - rpc ImageDefault(ImageDefaultRequest) returns (ImageDefaultResponse) {} } ``` -We plan to add support for ShowTechsupport. We also plan to add APIs to support additional use cases: +We plan to add support for ShowTechsupport. We also plan to an additional API not yet included in OpenConfig gNOI: * #### Start Process -GNOI System.proto defines only KillProcess, which can optionally restart a process. There is not yet an API specific to starting a process. +GNOI System.proto defines only KillProcess, which can optionally restart a process. There is no API specific to starting a process. ### 4.2. Authentication -GNMI already supports three authentication mechanisms that are naturally extended to gNOI: -* Basic Authentication - Requires passing of username and password in the gRPC metadata via the username and password keys. -* JSON Web Tokens (JWT) - Requires initial authentication via either basic or certificate authentication using the gNOI Authenticate RPC, afterwhich a token is recieved that can be used with future requests to avoid further authentication. The JWT token is sent in the metadata of the gRPC requests with the access_token key. -* Certificate - A valid client certificate is used with the username embedded in the certificate CN field. This allows the requests to be authenticaed against the CA certificate and the username can be used for authorization. - -A GNOI/GNMI server needs to validate the user role before executing any operation. Depending on the user role, the server may allow or deny different types of operations. For example, some users can only run read-only operations, such as get or subscribe, while some users can run read-write operations, such as set or reboot. +GNOI shares the same authentication methods as GNMI, as described in the [GNMI HLD](https://github.com/sonic-net/SONiC/blob/master/doc/mgmt/gnmi/SONiC_GNMI_Server_Interface_Design.md#1218-authentication). ### 4.3. Parallel Operations The GNOI/GNMI server accepts concurrent requests. Parallel reads and sequential writes are permitted. -The GNOI/GNMI server does not support parallel write operations. GNOI/GNMI write requests are placed in a queue and served with a single worker. -gnoi-write-threads +The GNOI server does not support parallel write operations. GNOI write requests are placed in a queue and served with a single worker. + ### 4.4. Docker to Host Communication Some commands are designed to run on the host, such as `systemctl restart `, `config apply-patch` and `config reload`. For several reasons, it is difficult to support these operations in a container: -1. These commands update redis database and may restart a container. When they restart gnmi, bgp, syncd, or swss, the ongoing gNOI operation will be broken. +1. These command may involve restarting a container. When they restart gnmi, bgp, syncd, or swss, the ongoing gNOI operation will be broken. 2. 'config reload' will stop services, run some other operations, and then restart services. If we run this command in a container, it will break at the stop service step. 3. These commands will execute some host scripts and use systemctl to restart service, so it would be dangerous to support these operations in a container. The solution is to add host services for `config apply-patch` and `config reload` on the host. GNOI/GNMI server can then use dbus method to invoke these host services. -## 5 Typical Scenarios -### 5.1. Upgrade DPU Firmware -upgrade-dpu-firmware -We need the below steps to upgrade DPU firmware: +## 5 Sample Scenario +### Upgrade SONiC image +upgrade-dpu-firmware +We need the below steps to upgrade DPU firmware: * GNMI Get -Read current DPU firmware. If it's not golden firmware, we need to ugprade. -* GNOI System.SetPackage -The SetPackage API downloads DPU firmware from remote host to local filesystem. Filename is used to specify DPU firmware and DPU id. The below chart shows possible firmware types and proposed filenames that will be supported by System.SetPackage. This example is for SONiC image running on DPU; the relevant row is the second row, marked with filename SONiC/DPU0/default. +Read current SONiC image version. If it's not golden version, we need to ugprade. -| Filename | Version | Activate | Firmware type | Proposed file location | -|-------------------------|------------|----------|----------------------------|-----------------------------------------------------| -| SONiC/localhost/default | 20230531.10| False | SONiC image | /tmp/sonic-20230531.10.bin | -| SONiC/DPU0/default | 20230531.10| False | SONiC image to run on DPU0 | /usr/share/sonic/dpu/dpu-sonic-20230531.10.bin | -| DPU/DPU0/default | 20230531.10| False | DPU firmware for DPU0 | /usr/share/sonic/dpu/dpu-20230531.10.bin | -| CABLE/Ethernet0/default | 1.1 | False | Cable firmware for Ethernet0| /usr/share/sonic/firmware/cable-1.1.bin | -| ASIC/ASIC0/default | 1.0 | False | ASIC firmware for ASIC0 | /usr/share/sonic/asic/asic-1.0.bin | -| CPLD/localhost/default | 1.0 | False | CPLD firmware for localhost| /usr/share/sonic/cpld/cpld-1.0.bin | -| CPLD/DPU0/default | 1.0 | False | CPLD firmware for DPU0 | /usr/share/sonic/dpu/cpld/cpld-1.0.bin | - -GNOI API will use the below rules for Filename in System.SetPackage. Each part of filename is split by slash. -1. The first part is type, it can be SONIC, DPU, CABLE, CPLD and ASIC, we might support other types like CPU microcode. -2. The second part is device name, it can be DPU0 for DPU, and it can be Ethernet0 or ASIC0-Ethernet1 for cable. It’s possible to have embedded device name, for example, DPU0/Ethernet0. -3. The last part is default for now, we will use this part for future extension. - -filename-gnoi +* GNOI System.SetPackage -We will use the same GNOI API call to activate existing DPU firmware and reboot DPU by setting activate to True. +We will use the SetPackage API to install and activate the new SONiC image. ``` // Package defines a single package file to be placed on the target. @@ -548,7 +580,7 @@ message SetPackageResponse { Note: The OS.Activate API is not suitable for our use case, because it does not have a field to specify the subcomponent that we want to activate. * GNOI System.Reboot -We can use System.Reboot API to reboot one or more DPU, and the RebootRequest has a subcomponents field that allows us to specify which DPU we want to reboot. +We will use System.Reboot API to reboot the device. ``` message RebootRequest { RebootMethod method = 1; @@ -571,22 +603,11 @@ message PathElem { } ``` * GNMI Get -Read current DPU firmware. If it's equal to target version, then upgrade was successful. - -### 5.2. Upgrade Cable Firmware -We need the below steps to upgrade cable firmware: -* GNMI Get -Read current cable firmware for port from StateDB. If not golden firmware, we need to upgrade. +Read current SONiC image version. If it's equal to target version, then upgrade was successful. -* GNOI System.SetPackage -Download cable firmware from remote to host file system, file name is used to specify cable firmware and port, and firmware is not activated by default - -* GNOI System.SetPackage -We will use the same GNOI API to activate existing cable firmware, activate is True and remote_download is empty for activate operation. ## 6 Testing -(WIP, detailed list pending) ### 6.1. Unit Testing | Test Case | Description | | ---- | ---- | diff --git a/doc/mgmt/gnmi/images/gnoi_gnmi_arch.svg b/doc/mgmt/gnmi/images/gnoi_gnmi_arch.svg new file mode 100644 index 0000000000..364d7f4832 --- /dev/null +++ b/doc/mgmt/gnmi/images/gnoi_gnmi_arch.svg @@ -0,0 +1,982 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Page-1 + + + + + + + + Process.35 + GNMI client + + + + + + + + + + + + + + + + + + + GNMI client + + Sheet.73 + Get + + + + Get + + Process.75 + GNMI/GNOI server + + + + + + + + + + + + + + + + + + + GNMI/GNOI server + + 1-D single.81 + + + + + + + Sheet.82 + Set + + + + Set + + Sheet.84 + + + + 1-D single.140 + + + + + + + Process.1009 + GNOI client + + + + + + + + + + + + + + + + + + + GNOI client + + 1-D single.1010 + + + + + + + Sheet.1011 + Os intall System reboot File transfer + + + + Os intallSystem rebootFile transfer + + Process + + + + + + + + + + + + + + + + + + + Sheet.1013 + SONiC gnmi docker + + + + SONiC gnmi docker + + Process.91 + ZMQ + + + + + + + + + + + + + + + + + + + ZMQ + + Process.1015 + DBUS + + + + + + + + + + + + + + + + + + + DBUS + + Dynamic connector.1016 + + + + Dynamic connector.1017 + + + + Dynamic connector.1018 + + + + Sheet.1019 + CONFIG_DB + + + + CONFIG_DB + + Sheet.1020 + APPL_DB + + + + APPL_DB + + Sheet.1021 + + Datastore + ApplDB + + + + + + + + + + + + + + + + + + + + + + ApplDB + + Dynamic connector.41 + + + + + Sheet.1024 + + Datastore + StateDB + + + + + + + + + + + + + + + + + + + + + + StateDB + + Dynamic connector.41 + + + + + Sheet.1027 + + Datastore + CountersDB + + + + + + + + + + + + + + + + + + + + + + CountersDB + + Dynamic connector.41 + + + + + Sheet.1030 + + Datastore + ConfigDB + + + + + + + + + + + + + + + + + + + + + + ConfigDB + + Dynamic connector.41 + + + + + Sheet.1033 + + Datastore + ... + + + + + + + + + + + + + + + + + + + + + + ... + + Dynamic connector.41 + + + + + Side brace + + + + + + + + + + + + + + + + + Dynamic connector.1037 + + + + Dynamic connector.1038 + + + + Document.1027 + Platform data + + + + + + + + + + + + + + + + + + + Platform data + + Document.1028 + Proc data + + + + + + + + + + + + + + + + + + + Proc data + + Document.1029 + ASIC data + + + + + + + + + + + + + + + + + + + ASIC data + + Side brace.1042 + + + + + + + + + + + + + + + + + Dynamic connector.1043 + + + + Process.1044 + + + + + + + + + + + + + + + + + + + Sheet.1045 + SONiC host services + + + + SONiC host services + + Dynamic connector.1051 + + + + Process.1052 + GCU + + + + + + + + + + + + + + + + + + + GCU + + Process.1053 + systemctl restart <service> + + + + + + + + + + + + + + + + + + + systemctl restart <service> + + Process.1054 + cp/mv/rm + + + + + + + + + + + + + + + + + + + cp/mv/rm + + Process.1055 + sonic-installer install + + + + + + + + + + + + + + + + + + + sonic-installer install + + Process.1056 + reboot + + + + + + + + + + + + + + + + + + + reboot + + Process.1057 + config reload + + + + + + + + + + + + + + + + + + + config reload + + Dynamic connector.1059 + + + + Document.1113 + YANG models + + + + + + + + + + + + + + + + + + + YANG models + + Sheet.1114 + From SONiC host + + + + From SONiC host + + diff --git a/doc/mgmt/gnmi/images/gnoi_gnmi_overview.svg b/doc/mgmt/gnmi/images/gnoi_gnmi_overview.svg deleted file mode 100644 index 60fc38bacc..0000000000 --- a/doc/mgmt/gnmi/images/gnoi_gnmi_overview.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/doc/mgmt/gnmi/images/install_sonic_image_apis_flow.svg b/doc/mgmt/gnmi/images/install_sonic_image_apis_flow.svg new file mode 100644 index 0000000000..d5efc55ed7 --- /dev/null +++ b/doc/mgmt/gnmi/images/install_sonic_image_apis_flow.svg @@ -0,0 +1,668 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Page-1 + + + + + + + + + + Object lifeline.415 + GNOI/GNMI Server + + Sheet.2 + + + + Sheet.3 + + + + Sheet.4 + + + Sheet.5 + + + + + + + GNOI/GNMI Server + + + + + + + + + Script.420 + + Sheet.7 + + + + Sheet.8 + + + + Sheet.9 + + + + Sheet.10 + + + + Sheet.11 + + + + Sheet.12 + + + + Sheet.13 + + + + Sheet.14 + + + + Sheet.15 + + + + + Activation.430 + + + + + + + Return Message.431 + + + + + + + + + + Activation.432 + + + + + + + Sheet.19 + Download image from URL + + + + Download image from URL + + Self Message.435 + + + + + + + + + + Sheet.21 + If SONiC version != target version, need to upgrade + + + + If SONiC version != target version, need to upgrade + + + + + + + Object lifeline.437 + GNOI/GNMI client + + Sheet.23 + + + + Sheet.24 + + + + Sheet.25 + + + Sheet.26 + + + + + + + GNOI/GNMI client + + + + + + + + + User.442 + + Sheet.28 + + Sheet.29 + + + + Sheet.30 + + + + + + Activation.446 + + + + + + + Message.448 + GNMI get request Get SONiC version + + + + + + + + + + + GNMI get requestGet SONiC version + + Message.451 + GNOI system.SetPackage install/activate new SONiC image + + + + + + + + + + + GNOI system.SetPackageinstall/activate new SONiC image + + + + + + + + Database.462 + + Sheet.35 + + Sheet.36 + + + + Sheet.37 + + + + Sheet.38 + + + + Sheet.39 + + + + + + + + + + + Object lifeline.468 + database + + Sheet.41 + + + + Sheet.42 + + + + Sheet.43 + + + Sheet.44 + + + + + + + database + + + Activation.473 + + + + + + + Message.474 + Read StateDB + + + + + + + + + + + Read StateDB + + Return Message.475 + + + + + + + + + + Self Message.476 + + + + + + + + + + + + + + + Object lifeline.477 + SONiC host services + + Sheet.50 + + + + Sheet.51 + + + + Sheet.52 + + + Sheet.53 + + + + + + + SONiC host services + + + + + + + + + Script.482 + + Sheet.55 + + + + Sheet.56 + + + + Sheet.57 + + + + Sheet.58 + + + + Sheet.59 + + + + Sheet.60 + + + + Sheet.61 + + + + Sheet.62 + + + + Sheet.63 + + + + + Activation.492 + + + + + + + Message.493 + DBUS install SONiC image + + + + + + + + + + + DBUSinstall SONiC image + + Sheet.66 + Install SONiC image + + + + Install SONiC image + + Self Message.495 + + + + + + + + + + Return Message.496 + + + + + + + + + + Return Message.497 + + + + + + + + + + Message.498 + GNOI os.reboot Reboot SONiC + + + + + + + + + + + GNOI os.reboot Reboot SONiC + + Activation.500 + + + + + + + Activation.501 + + + + + + + Message.502 + DBUS Reboot SONiC + + + + + + + + + + + DBUSReboot SONiC + + Self Message.503 + + + + + + + + + + Sheet.75 + Reboot SONiC + + + + Reboot SONiC + + Return Message.506 + + + + + + + + + + Message.511 + GNMI get request Get SONiC version + + + + + + + + + + + GNMI get requestGet SONiC version + + Activation.512 + + + + + + + Message.513 + Read StateDB + + + + + + + + + + + Read StateDB + + Return Message.514 + + + + + + + + + + Activation.515 + + + + + + + Return Message.516 + + + + + + + + + + Sheet.83 + If SONiC version == target version, Upgrade Successful + + + + If SONiC version == target version, Upgrade Successful + + Self Message.518 + + + + + + + + + + From de08cff885c92437ac5089c6de13cc0a01bb2683 Mon Sep 17 00:00:00 2001 From: isabelmsft Date: Tue, 2 Apr 2024 06:14:22 +0000 Subject: [PATCH 06/11] update HLD --- .../SONiC_GNOI_Server_Interface_Design.md | 10 +- doc/mgmt/gnmi/images/gnoi_gnmi_arch.svg | 361 ++++++++--------- .../images/install_sonic_image_apis_flow.svg | 369 +++++++++--------- 3 files changed, 369 insertions(+), 371 deletions(-) diff --git a/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md b/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md index f3897b7135..8d54fed523 100644 --- a/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md +++ b/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md @@ -79,7 +79,7 @@ All the introduced features are part of the sonic-gnmi package installed in the The GNOI/GNMI server uses [DBUS](https://github.com/sonic-net/SONiC/blob/master/doc/mgmt/Docker%20to%20Host%20communication.md) to communicate with the SONiC host services, which are responsible for executing various commands on the device. Some of these commands are "config reload", "reboot", "sonic-installer install", "cp", "mv", and "rm". -gnmi-server +gnmi-server ## 4 High Level Design @@ -519,7 +519,7 @@ GNOI System.proto defines only KillProcess, which can optionally restart a proce ### 4.2. Authentication -GNOI shares the same authentication methods as GNMI, as described in the [GNMI HLD](https://github.com/sonic-net/SONiC/blob/master/doc/mgmt/gnmi/SONiC_GNMI_Server_Interface_Design.md#1218-authentication). +GNOI shares the same authentication methods as GNMI, as described in the [gNMI HLD](https://github.com/sonic-net/SONiC/blob/master/doc/mgmt/gnmi/SONiC_GNMI_Server_Interface_Design.md#1218-authentication). ### 4.3. Parallel Operations The GNOI/GNMI server accepts concurrent requests. Parallel reads and sequential writes are permitted. @@ -528,11 +528,7 @@ The GNOI server does not support parallel write operations. GNOI write requests ### 4.4. Docker to Host Communication -Some commands are designed to run on the host, such as `systemctl restart `, `config apply-patch` and `config reload`. For several reasons, it is difficult to support these operations in a container: -1. These command may involve restarting a container. When they restart gnmi, bgp, syncd, or swss, the ongoing gNOI operation will be broken. -2. 'config reload' will stop services, run some other operations, and then restart services. If we run this command in a container, it will break at the stop service step. -3. These commands will execute some host scripts and use systemctl to restart service, so it would be dangerous to support these operations in a container. -The solution is to add host services for `config apply-patch` and `config reload` on the host. GNOI/GNMI server can then use dbus method to invoke these host services. +As described in the [gNMI HLD](https://github.com/sonic-net/SONiC/blob/master/doc/mgmt/gnmi/SONiC_GNMI_Server_Interface_Design.md#1218-authentication), we utilize dbus to execute some commands designed to run on the host, such as `systemctl restart `, `config apply-patch` and `config reload`. ## 5 Sample Scenario diff --git a/doc/mgmt/gnmi/images/gnoi_gnmi_arch.svg b/doc/mgmt/gnmi/images/gnoi_gnmi_arch.svg index 364d7f4832..571e27b93c 100644 --- a/doc/mgmt/gnmi/images/gnoi_gnmi_arch.svg +++ b/doc/mgmt/gnmi/images/gnoi_gnmi_arch.svg @@ -2,8 +2,8 @@ + xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="15.5539in" height="8.7756in" + viewBox="0 0 1119.88 631.843" xml:space="preserve" color-interpolation-filters="sRGB" class="st28"> @@ -87,7 +87,7 @@ - + Process.35 GNMI client @@ -114,17 +114,17 @@ - - - GNMI client - + + + GNMI client + Sheet.73 Get - - - Get - + + + Get + Process.75 GNMI/GNOI server @@ -151,37 +151,38 @@ - - - GNMI/GNOI server - + + + GNMI/GNOI server + 1-D single.81 - + - + Sheet.82 Set - - - Set - + + + Set + Sheet.84 - + - + 1-D single.140 - + - + Process.1009 GNOI client @@ -208,27 +209,27 @@ - - - GNOI client + + + GNOI client + transform="translate(1413.04,72.2567) rotate(90)"> 1-D single.1010 - + - + Sheet.1011 Os intall System reboot File transfer - - - Os intall + + Os intallSystem rebootFile transfer - + Process - + - + Sheet.1013 SONiC gnmi docker - - - SONiC + + SONiC gnmi docker - + Process.91 ZMQ @@ -290,10 +291,10 @@ - - - ZMQ - + + + ZMQ + Process.1015 DBUS @@ -320,36 +321,36 @@ - - - DBUS - + + + DBUS + Dynamic connector.1016 - + - + Dynamic connector.1017 - + - + Dynamic connector.1018 - + - + Sheet.1019 CONFIG_DB - - - CONFIG_DB - + + + CONFIG_DB + Sheet.1020 APPL_DB - - - APPL_DB - + + + APPL_DB + Sheet.1021 Datastore @@ -382,19 +383,19 @@ - - - - - ApplDB + + + + + ApplDB Dynamic connector.41 - + - + Sheet.1024 Datastore @@ -427,19 +428,19 @@ - - - - - StateDB + + + + + StateDB Dynamic connector.41 - + - + Sheet.1027 Datastore @@ -472,19 +473,19 @@ - - - - - CountersDB + + + + + CountersDB Dynamic connector.41 - + - + Sheet.1030 Datastore @@ -517,19 +518,19 @@ - - - - - ConfigDB + + + + + ConfigDB Dynamic connector.41 - + - + Sheet.1033 Datastore @@ -562,19 +563,19 @@ - - - - - ... + + + + + ... Dynamic connector.41 - + - + Side brace @@ -589,19 +590,19 @@ - - + Dynamic connector.1037 - + - + Dynamic connector.1038 - + - + Document.1027 Platform data @@ -628,11 +629,11 @@ - - - Platform data - + + + Platform data + Document.1028 Proc data @@ -659,11 +660,11 @@ - - - Proc data - + + + Proc data + Document.1029 ASIC data @@ -690,11 +691,11 @@ - - - ASIC data - + + + ASIC data + Side brace.1042 @@ -709,15 +710,15 @@ - - + Dynamic connector.1043 - + - + Process.1044 - + - + Sheet.1045 SONiC host services - - - SONiC host services - + + + SONiC host services + Dynamic connector.1051 - + - + Process.1052 GCU @@ -782,10 +783,10 @@ - - - GCU - + + + GCU + Process.1053 systemctl restart <service> @@ -812,10 +813,10 @@ - - - systemctl restart <service> - + + + systemctl restart <service> + Process.1054 cp/mv/rm @@ -842,10 +843,10 @@ - - - cp/mv/rm - + + + cp/mv/rm + Process.1055 sonic-installer install @@ -872,10 +873,10 @@ - - - sonic-installer install - + + + sonic-installer install + Process.1056 reboot @@ -902,10 +903,10 @@ - - - reboot - + + + reboot + Process.1057 config reload @@ -932,14 +933,14 @@ - - - config reload - + + + config reload + Dynamic connector.1059 - + - + Document.1113 YANG models @@ -966,17 +967,17 @@ - - - YANG models - + + + YANG models + Sheet.1114 From SONiC host - - - From + + From SONiC host diff --git a/doc/mgmt/gnmi/images/install_sonic_image_apis_flow.svg b/doc/mgmt/gnmi/images/install_sonic_image_apis_flow.svg index d5efc55ed7..4076afa1be 100644 --- a/doc/mgmt/gnmi/images/install_sonic_image_apis_flow.svg +++ b/doc/mgmt/gnmi/images/install_sonic_image_apis_flow.svg @@ -2,8 +2,8 @@ + xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="7.12801in" height="7.6756in" + viewBox="0 0 513.217 552.643" xml:space="preserve" color-interpolation-filters="sRGB" class="st15"> @@ -25,7 +25,8 @@ .st11 {marker-end:url(#mrkr4-52);stroke:#4672c4;stroke-linecap:round;stroke-linejoin:round;stroke-width:1} .st12 {fill:#ffffff;stroke:none;stroke-linecap:butt;stroke-width:7.2} .st13 {fill:#3d64ac;font-family:Calibri;font-size:0.666664em} - .st14 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3} + .st14 {fill:#ffffff;stroke:none;stroke-linecap:butt} + .st15 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3} ]]> @@ -51,7 +52,7 @@ v:shadowOffsetY="-8.50394"/> - + @@ -61,26 +62,26 @@ GNOI/GNMI Server Sheet.2 - + Sheet.3 - + Sheet.4 - + Sheet.5 - + - - - GNOI/GNMI Server + + + GNOI/GNMI Server - + @@ -90,53 +91,53 @@ Script.420 Sheet.7 - + Sheet.8 - + Sheet.9 - + Sheet.10 - + Sheet.11 - + Sheet.12 - + Sheet.13 - + Sheet.14 - + Sheet.15 - + - + Activation.430 - + - + Return Message.431 @@ -144,24 +145,24 @@ - + - + Activation.432 - + - + Sheet.19 Download image from URL - - - Download image + + Download image from URL - + Self Message.435 @@ -169,17 +170,17 @@ - + - + Sheet.21 If SONiC version != target version, need to upgrade - - - If SONiC version != + + If SONiC version != target version, need to upgrade - + @@ -189,27 +190,27 @@ GNOI/GNMI client Sheet.23 - + Sheet.24 - + Sheet.25 - + Sheet.26 - + - - - GNOI/GNMI + + GNOI/GNMI client - + @@ -221,24 +222,24 @@ Sheet.28 Sheet.29 - + Sheet.30 - + - + Activation.446 - + - + Message.448 GNMI get request Get SONiC version @@ -248,12 +249,12 @@ - - - - GNMI get request + + + GNMI get requestGet SONiC version - + Message.451 GNOI system.SetPackage install/activate new SONiC image @@ -263,12 +264,12 @@ - - - - GNOI system.SetPackage + + + GNOI system.SetPackageinstall/activate new SONiC image - + @@ -280,32 +281,32 @@ Sheet.35 Sheet.36 - + Sheet.37 - + Sheet.38 - + Sheet.39 - + - + @@ -315,33 +316,33 @@ database Sheet.41 - + Sheet.42 - + Sheet.43 - + Sheet.44 - + - - - database + + + database - + Activation.473 - + - + Message.474 Read StateDB @@ -351,11 +352,11 @@ - - - - Read StateDB - + + + + Read StateDB + Return Message.475 @@ -363,9 +364,9 @@ - + - + Self Message.476 @@ -373,9 +374,9 @@ - + - + @@ -385,26 +386,26 @@ SONiC host services Sheet.50 - + Sheet.51 - + Sheet.52 - + Sheet.53 - + - - - SONiC host services + + + SONiC host services - + @@ -414,53 +415,53 @@ Script.482 Sheet.55 - + Sheet.56 - + Sheet.57 - + Sheet.58 - + Sheet.59 - + Sheet.60 - + Sheet.61 - + Sheet.62 - + Sheet.63 - + - + Activation.492 - + - + Message.493 DBUS install SONiC image @@ -470,19 +471,19 @@ - - - - DBUS + + + DBUSinstall SONiC image - + Sheet.66 Install SONiC image - - - Install SONiC image - + + + Install SONiC image + Self Message.495 @@ -490,9 +491,9 @@ - + - + Return Message.496 @@ -500,9 +501,9 @@ - + - + Return Message.497 @@ -510,9 +511,9 @@ - + - + Message.498 GNOI os.reboot Reboot SONiC @@ -522,26 +523,26 @@ - - - - GNOI os.reboot + + + GNOI os.reboot Reboot SONiC - + Activation.500 - + - + Activation.501 - + - + Message.502 DBUS Reboot SONiC @@ -551,12 +552,12 @@ - - - - DBUS + + + DBUSReboot SONiC - + Self Message.503 @@ -564,16 +565,16 @@ - + - + Sheet.75 Reboot SONiC - - - Reboot SONiC - + + + Reboot SONiC + Return Message.506 @@ -581,9 +582,9 @@ - + - + Message.511 GNMI get request Get SONiC version @@ -593,19 +594,19 @@ - - - - GNMI get request + + + GNMI get requestGet SONiC version - + Activation.512 - + - + Message.513 Read StateDB @@ -615,11 +616,11 @@ - - - - Read StateDB - + + + + Read StateDB + Return Message.514 @@ -627,16 +628,16 @@ - + - + Activation.515 - + - + Return Message.516 @@ -644,17 +645,17 @@ - + - + Sheet.83 If SONiC version == target version, Upgrade Successful - - - If SONiC version == + + If SONiC version == target version, Upgrade Successful - + Self Message.518 @@ -662,7 +663,7 @@ - + From 188ede0498b4d39feff0f8a912bb3894b59bf6ca Mon Sep 17 00:00:00 2001 From: isabelmsft Date: Tue, 2 Apr 2024 06:32:03 +0000 Subject: [PATCH 07/11] update HLD --- doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md b/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md index 8d54fed523..a857a3dec7 100644 --- a/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md +++ b/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md @@ -83,6 +83,7 @@ The GNOI/GNMI server uses [DBUS](https://github.com/sonic-net/SONiC/blob/master/ ## 4 High Level Design +### 4.1. GNOI RPC APIs GNOI is composed of services, each of which is organized into related RPCs. We plan to add support for the following services: * File - provides an interface for file operations on the target, including file transfer to and from the target node. * FactoryReset - provides an interface for factory resetting the target node. @@ -90,7 +91,6 @@ GNOI is composed of services, each of which is organized into related RPCs. We p * System - provides an interface for the management system-related operations on the target node. * Containerz - provides an interface to perform container operations on a network device. -### 4.1. GNOI RPC API We need to implement these GNOI APIs to support SONiC operations. From 537a723ad2a452c40aefac5a8a9e3d0f8615a096 Mon Sep 17 00:00:00 2001 From: isabelmsft Date: Tue, 2 Apr 2024 06:53:28 +0000 Subject: [PATCH 08/11] update diagram --- doc/mgmt/gnmi/images/install_sonic_image_apis_flow.svg | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/mgmt/gnmi/images/install_sonic_image_apis_flow.svg b/doc/mgmt/gnmi/images/install_sonic_image_apis_flow.svg index 4076afa1be..48750abdbe 100644 --- a/doc/mgmt/gnmi/images/install_sonic_image_apis_flow.svg +++ b/doc/mgmt/gnmi/images/install_sonic_image_apis_flow.svg @@ -515,7 +515,7 @@ Message.498 - GNOI os.reboot Reboot SONiC + GNOI system.reboot Reboot SONiC @@ -523,10 +523,10 @@ - + - - GNOI os.reboot + GNOI system.reboot Reboot SONiC Activation.500 @@ -618,7 +618,7 @@ - + Read StateDB Return Message.514 From 5b4332a601089dd932c69c77bae3fe83f43bfe5b Mon Sep 17 00:00:00 2001 From: isabelmsft Date: Tue, 2 Apr 2024 06:56:45 +0000 Subject: [PATCH 09/11] formatting fix --- doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md b/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md index a857a3dec7..e4885f9f5c 100644 --- a/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md +++ b/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md @@ -535,7 +535,9 @@ As described in the [gNMI HLD](https://github.com/sonic-net/SONiC/blob/master/do ### Upgrade SONiC image upgrade-dpu-firmware We need the below steps to upgrade DPU firmware: + * GNMI Get + Read current SONiC image version. If it's not golden version, we need to ugprade. * GNOI System.SetPackage @@ -576,6 +578,7 @@ message SetPackageResponse { Note: The OS.Activate API is not suitable for our use case, because it does not have a field to specify the subcomponent that we want to activate. * GNOI System.Reboot + We will use System.Reboot API to reboot the device. ``` message RebootRequest { @@ -599,6 +602,7 @@ message PathElem { } ``` * GNMI Get + Read current SONiC image version. If it's equal to target version, then upgrade was successful. From f14509c7800860020c1fc62966c6c5bfa8247ca8 Mon Sep 17 00:00:00 2001 From: isabelmsft Date: Thu, 4 Apr 2024 20:33:06 +0000 Subject: [PATCH 10/11] update config reload --- doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md b/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md index e4885f9f5c..a249f1f813 100644 --- a/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md +++ b/doc/mgmt/gnmi/SONiC_GNOI_Server_Interface_Design.md @@ -329,8 +329,6 @@ For SONiC warm reboot, we can use WARM method. For SONiC fast reboot, we can use NSF method. -For SONiC config reload, we can use reserved method. - #### System.KillProcess We can use this API to kill an OS process, and optionally restart. @@ -513,9 +511,12 @@ service SonicService { rpc ShowTechsupport (TechsupportRequest) returns (TechsupportResponse) {} } ``` -We plan to add support for ShowTechsupport. We also plan to an additional API not yet included in OpenConfig gNOI: +We plan to add support for ShowTechsupport. We also plan to add additional APIs not currently supported by OpenConfig gNOI: * #### Start Process GNOI System.proto defines only KillProcess, which can optionally restart a process. There is no API specific to starting a process. +* #### Config Reload +GNOI System.reboot has the option for config reload supported through "WARM" reboot method. However, SONiC warm reboot is its own reboot type. Thus, we need separate, specific support for the SONiC config reload use case + ### 4.2. Authentication From 62324bd4dfd676aa2ae4ab4720807752415c495c Mon Sep 17 00:00:00 2001 From: isabelmsft Date: Thu, 4 Apr 2024 20:39:04 +0000 Subject: [PATCH 11/11] rm unused image files --- .../gnmi/images/dpu_firmware_apis_hld.svg | 666 ------------------ doc/mgmt/gnmi/images/filename_gnoi.png | Bin 78618 -> 0 bytes doc/mgmt/gnmi/images/gnoi_write_threads.svg | 1 - doc/mgmt/gnmi/images/update_dpu_firmware.svg | 1 - 4 files changed, 668 deletions(-) delete mode 100644 doc/mgmt/gnmi/images/dpu_firmware_apis_hld.svg delete mode 100644 doc/mgmt/gnmi/images/filename_gnoi.png delete mode 100644 doc/mgmt/gnmi/images/gnoi_write_threads.svg delete mode 100644 doc/mgmt/gnmi/images/update_dpu_firmware.svg diff --git a/doc/mgmt/gnmi/images/dpu_firmware_apis_hld.svg b/doc/mgmt/gnmi/images/dpu_firmware_apis_hld.svg deleted file mode 100644 index a108d69a2b..0000000000 --- a/doc/mgmt/gnmi/images/dpu_firmware_apis_hld.svg +++ /dev/null @@ -1,666 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - Page-1 - - - - - - - - - - Object lifeline.415 - GNOI/GNMI Server - - Sheet.2 - - - - Sheet.3 - - - - Sheet.4 - - - Sheet.5 - - - - - - - GNOI/GNMI Server - - - - - - - - - Script.420 - - Sheet.7 - - - - Sheet.8 - - - - Sheet.9 - - - - Sheet.10 - - - - Sheet.11 - - - - Sheet.12 - - - - Sheet.13 - - - - Sheet.14 - - - - Sheet.15 - - - - - Activation.430 - - - - - - - Return Message.431 - - - - - - - - - - Activation.432 - - - - - - - Sheet.19 - Download firmware from URL - - - - Download firmware from URL - - Self Message.435 - - - - - - - - - - Sheet.21 - If DPU firmware != target version, need to upgrade - - - - If DPU firmware != target version, need to upgrade - - - - - - - Object lifeline.437 - GNMI/GNOI client - - Sheet.23 - - - - Sheet.24 - - - - Sheet.25 - - - Sheet.26 - - - - - - - GNMI/GNOI client - - - - - - - - - User.442 - - Sheet.28 - - Sheet.29 - - - - Sheet.30 - - - - - - Activation.446 - - - - - - - Message.448 - GNMI get request DPU firmware verion - - - - - - - - - - - GNMI get requestDPU firmware verion - - Message.451 - GNOI system setpackage install/activate DPU firmware - - - - - - - - - - - GNOI system setpackageinstall/activate DPU firmware - - - - - - - - Database.462 - - Sheet.35 - - Sheet.36 - - - - Sheet.37 - - - - Sheet.38 - - - - Sheet.39 - - - - - - - - - - - Object lifeline.468 - database - - Sheet.41 - - - - Sheet.42 - - - - Sheet.43 - - - Sheet.44 - - - - - - - database - - - Activation.473 - - - - - - - Message.474 - Read StateDB - - - - - - - - - - - Read StateDB - - Return Message.475 - - - - - - - - - - Self Message.476 - - - - - - - - - - - - - - - Object lifeline.477 - SONiC host services - - Sheet.50 - - - - Sheet.51 - - - - Sheet.52 - - - Sheet.53 - - - - - - - SONiC host services - - - - - - - - - Script.482 - - Sheet.55 - - - - Sheet.56 - - - - Sheet.57 - - - - Sheet.58 - - - - Sheet.59 - - - - Sheet.60 - - - - Sheet.61 - - - - Sheet.62 - - - - Sheet.63 - - - - - Activation.492 - - - - - - - Message.493 - DBUS install DPU firmware - - - - - - - - - - - DBUSinstall DPU firmware - - Sheet.66 - Install DPU firmware - - - - Install DPU firmware - - Self Message.495 - - - - - - - - - - Return Message.496 - - - - - - - - - - Return Message.497 - - - - - - - - - - Message.498 - GNOI os.reboot Reboot DPU - - - - - - - - - - - GNOI os.reboot Reboot DPU - - Activation.500 - - - - - - - Activation.501 - - - - - - - Message.502 - DBUS Reboot DPU - - - - - - - - - - - DBUSReboot DPU - - Self Message.503 - - - - - - - - - - Sheet.75 - Reboot DPU - - - - Reboot DPU - - Return Message.506 - - - - - - - - - - Message.511 - GNMI get request DPU firmware verion - - - - - - - - - - - GNMI get requestDPU firmware verion - - Activation.512 - - - - - - - Message.513 - Read StateDB - - - - - - - - - - - Read StateDB - - Return Message.514 - - - - - - - - - - Activation.515 - - - - - - - Return Message.516 - - - - - - - - - - Sheet.83 - If DPU firmware version == target version, Upgrade Successful - - - - If DPU firmware version == target version, Upgrade Successful - - Self Message.518 - - - - - - - - - - diff --git a/doc/mgmt/gnmi/images/filename_gnoi.png b/doc/mgmt/gnmi/images/filename_gnoi.png deleted file mode 100644 index ef0fe6aff2fcc380d25d5d75164ac17b06ac00bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 78618 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 R+Vci*=x7+K*Q(jS`9Jlw` \ No newline at end of file diff --git a/doc/mgmt/gnmi/images/update_dpu_firmware.svg b/doc/mgmt/gnmi/images/update_dpu_firmware.svg deleted file mode 100644 index af8f98dc29..0000000000 --- a/doc/mgmt/gnmi/images/update_dpu_firmware.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file