Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions test/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
load("@rules_proto//proto:defs.bzl", "proto_library")
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")

go_library(
name = "test",
Expand All @@ -19,3 +21,45 @@ go_test(
"@com_github_golang_protobuf//proto:go_default_library",
],
)

# BlackBoxTest.
proto_library(
name = "blackbox_test_proto",
srcs = ["blackbox_test.proto"],
deps = ["//types:types_proto",
"@go_googleapis//google/rpc:status_proto",
],
)

go_proto_library(
name = "blackbox_test_go_proto",
compilers = ["@io_bazel_rules_go//proto:go_grpc"],
proto = ":blackbox_test_proto",
importpath = "github.com/openconfig/gnoi/test",
deps = ["//types:types_go_proto",
"@go_googleapis//google/rpc:status_go_proto"],
)

cc_proto_library(
name = "blackbox_test_cc_proto",
deps = [":blackbox_test_proto"],
)

# WhiteBoxTest.
proto_library(
name = "whitebox_test_proto",
srcs = ["whitebox_test.proto"],
)

go_proto_library(
name = "whitebox_test_go_proto",
compilers = ["@io_bazel_rules_go//proto:go_grpc"],
proto = ":whitebox_test_proto",
importpath = "github.com/openconfig/gnoi/test",
deps = ["//types:types_go_proto"],
)

cc_proto_library(
name = "whitebox_test_cc_proto",
deps = [":whitebox_test_proto"],
)
129 changes: 129 additions & 0 deletions test/blackbox_test.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// BlackBoxTest represents a list of test APIs that facilitates testing the
// switch/network (injecting events, mutating switch state etc.)

syntax = "proto3";

package gnoi.test;

//import "enums/enums.proto";
import "google/rpc/status.proto";
import "types/types.proto";


service BlackBoxTest {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regardless could we make this more generalized for components? In the use case you describe, a transceiver is a type of component that we could reference.
https://github.com/openconfig/public/blob/66f4ae885b54270867ea942a7d30751e9029e101/release/models/platform/openconfig-platform-transceiver.yang#L36-L39

Something like
service ComponentSoftInstall
rpc Insert
rpc Remove
rpc state

or maybe
service ComponentProvision
rpc Provision
rpc UnProvision

I think this service is more likely a configuration, not a gNOI? This is because it is a stateful property being persisted on a device. It is not a "one shot" action that is invoked (like reboot).

// This RPC allows the state of a transceiver (for both optical, and copper
// cable) to be set on the switch. The goal is to simulate the
// insertion/removal of a transceiver and verify that the switch initializes
// the transceiver correctly. This RPC maps to the `fake` removal of a
// physical module, and un-doing the `fake` removal (i.e., insert). This does
// not implement any fake insertion of a non-present module. The switch
// remembers the state of a transceiver based on this RPC (until reboot).
rpc SetTransceiverState(SetTransceiverStateRequest)
returns (SetTransceiverStateResponse) {}

// This RPC changes the state of the link connected to the specified port(s).
// The goal is to simulate a link going up/down due to factors external to the
// switch: copper cable/fiber removed, cable/fiber gone bad, etc.
rpc SetHardwareLinkState(SetHardwareLinkStateRequest)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think setting link state is also a configuration, not a gNOI?

If the goal is to simulate 'loss of light' at an optical level, then we could add a leaf to the transceiver tree
something like
/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel/config/rx-laser-softdisable. When set to true, the laser receiver would be 'soft disabled', causing that's physical channel to be simulated as down.

Alternatively, this could also be done at higher layers 2 or 3 via /interfaces. This might be more simple and cover more use cases (being neutral to things like copper/optical and physical channels). But I am not sure if your use case requires L1 optical layer simulation.

returns (SetHardwareLinkStateResponse) {}

// This RPC sets the Alarm state in the switch. The caller is able to set the
// id, resource, description, alarm severity, and type. One goal is to put the
// switch into a critical state to verify that the switch prevents write
// operations to the switch over P4RT/gNMI/gNOI and that the switch continues
// to forward packets and export telemetry.
rpc SetAlarm(SetAlarmRequest) returns (SetAlarmResponse) {}

// Switch performs an internal consistency check. It verifies if the hardware
// contents match with the corresponding software contents. If no component is
// specified, verification runs for all valid components. It performs
// verification on the supplied components otherwise. RPC fails for any
// invalid component.
rpc VerifyState(VerifyStateRequest) returns (VerifyStateResponse);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is similar to healthz.Check?

rpc Check(CheckRequest) returns (CheckResponse) {}

}

message SetTransceiverStateRequest {
message TransceiverStateRequest {
enum TransceiverState {
STATE_UNSPECIFIED = 0;
REMOVE = 1; // Remove a module.
UNDO_REMOVE = 2; // Undo removal (i.e., insertion) of a module.
}

// Path to the transceiver component.
.gnoi.types.Path transceiver = 1;
TransceiverState state = 2;
}

repeated TransceiverStateRequest transceiver_requests = 1;
}

message SetTransceiverStateResponse {
message TransceiverStateResponse {
// Path to the transceiver component.
.gnoi.types.Path transceiver = 1;
// Status of the operation. In case of failures, canonical error code and
// message show the details.
google.rpc.Status status = 2;
}

repeated TransceiverStateResponse transceiver_responses = 1;
}

message SetHardwareLinkStateRequest {
message HardwareLinkStateInfo {
// Path to the interface.
.gnoi.types.Path interface = 1;
bool enabled = 2;
}

repeated HardwareLinkStateInfo link_requests = 1;
}

message SetHardwareLinkStateResponse {
message SetHardwareLinkStateStatus {
// Path to the interface.
.gnoi.types.Path interface = 1;
// Status of the operation. In case of failures, canonical error code and
// message show the details.
google.rpc.Status status = 2;
}

repeated SetHardwareLinkStateStatus link_responses = 1;
}

message SetAlarmRequest {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: I do think this qualifies as gNOI, because Alarms are not persistent state on a device.

However, should we instead pivot to healthz? Or does your use case require simulating already existing OC alarms?

// ID associated with the alarm.
string id = 1;
// Resource that raises the alarm. Must be a valid component ID.
string resource = 2;
Comment on lines +98 to +99
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Resource that raises the alarm. Must be a valid component ID.
string resource = 2;
// Component that raises the alarm. Must be a valid component ID. ie: /components/component/state/id
string component = 2;

// Description of the alarm.
string description = 3;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the goal to set the alarm severity?

// OPENCONFIG_ALARM_SEVERITY from the OpenConfig system model.
// openconfig.enums.OpenconfigAlarmTypesOPENCONFIGALARMSEVERITY severity = 4;
// OPENCONFIG_ALARM_TYPE_ID from the OpenConfig system model.
// openconfig.enums.OpenconfigAlarmTypesOPENCONFIGALARMTYPEID type = 5;
}

message SetAlarmResponse {
}

message VerifyStateRequest {
// Resources that verify states. Must be valid component IDs.
repeated string components = 1;
}

message VerifyStateResponse {
message VerifyStateResult {
string component = 1;
// Status of the operation. In case of failures, canonical error code
// and message show the details.
google.rpc.Status status = 2;
}

// Overall (aggregated) test result. Overall result succeeds if and only
// if the test passes for all components. If it fails for any component,
// the overall result is a failure.
bool success = 1;
repeated VerifyStateResult results = 2;
}
40 changes: 40 additions & 0 deletions test/whitebox_test.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// WhiteBoxTest represents a list of test APIs that facilitates testing the
// switch/controller (injecting events, mutating switch state etc.)

syntax = "proto3";

package gnoi.gnoi;

service WhiteBoxTest {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be achieved by configuration by configuring /system/control-plane-traffic/

However, another approach might be if your use case is to completely block a gRPC service for a fixed amount of time and then allow the DUT to restore it. You could define something like:

service SystemServices
// temporarily change the state of /system/services

message InterruptServiceState
string service_name = 1;
uint32 duration = 2; // msec of interruption

// This RPC blocks or permits GNMI and P4RT connections from controller either
// on in band or out of band or on both channels.
// The goal is to simulate controller connection loss in various tests.
rpc SetControllerConnectionState(SetControllerConnectionStateRequest)
returns (SetControllerConnectionStateResponse) {}
}

message SetControllerConnectionStateRequest {
enum State {
UNKNOWN_STATE = 0;
BLOCK = 1; // Block connections to switch.
REMOVE_BLOCK = 2; // Permit connections to switch.
}

enum ConnectionType {
UNKNOWN_TYPE = 0;
ALL_CONNECTIONS = 1; // Both in band and out of band connecions.
IN_BAND = 2; // only in band connections.
OUT_OF_BAND = 3; // only out of band connections.
}

State state = 1;
ConnectionType type = 2;
// Controller ipv4 addresses in prefix format ex: 10.1.1.1/32.
repeated string ipv4_prefix = 3;

// Controller ipv6 addresses in prefix format ex: 1000::1/128.
repeated string ipv6_prefix = 4;
}

message SetControllerConnectionStateResponse {
}