diff --git a/pkg/api/networkservice/connection.pb.go b/pkg/api/networkservice/connection.pb.go index 1b1122b..0c24e95 100644 --- a/pkg/api/networkservice/connection.pb.go +++ b/pkg/api/networkservice/connection.pb.go @@ -1,5 +1,6 @@ // Copyright 2018 Red Hat, Inc. // Copyright (c) 2018 Cisco and/or its affiliates. +// Copyright (c) 2024 Nordix Foundation. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -46,9 +47,18 @@ const ( type State int32 const ( - State_UP State = 0 - State_DOWN State = 1 - State_REFRESH_REQUESTED State = 2 + // UP - Endpoint sets the connection state to UP when it successfully + // establishes the connection. + State_UP State = 0 + // DOWN - Monitor Connection Server sets the connection state to DOWN + // when the connection is broken (for example, one of the NSM components is dead). + // Monitor Connection Server also sets the DOWN state for the deleted connections. + State_DOWN State = 1 + // REFRESH_REQUESTED - This state indicates the server's connection parameters have + // been changed and the client should make a refresh to get them. + State_REFRESH_REQUESTED State = 2 + // RESELECT_REQUESTED - This state indicates the client wants to use another endpoint + // for the connection. The client can set this state when it loses the connection. State_RESELECT_REQUESTED State = 3 ) @@ -98,9 +108,17 @@ func (State) EnumDescriptor() ([]byte, []int) { type ConnectionEventType int32 const ( + // INITIAL_STATE_TRANSFER - Monitor Connection Server immediately sends event + // with this type to a client when the client makes MonitorConnections Request. + // Event with this type contains all connections that Monitor Connection Server + // currently has. ConnectionEventType_INITIAL_STATE_TRANSFER ConnectionEventType = 0 - ConnectionEventType_UPDATE ConnectionEventType = 1 - ConnectionEventType_DELETE ConnectionEventType = 2 + // UPDATE - Monitor Connection Server sends event with this type when the + // connection changes. For exapmle, when the state of the connection has been changed. + ConnectionEventType_UPDATE ConnectionEventType = 1 + // DELETE - Monitor Connection Server sends event with this type when the connection + // has been closed. + ConnectionEventType_DELETE ConnectionEventType = 2 ) // Enum value maps for ConnectionEventType. @@ -512,7 +530,8 @@ type MonitorScopeSelector struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - PathSegments []*PathSegment `protobuf:"bytes,1,rep,name=path_segments,json=pathSegments,proto3" json:"path_segments,omitempty"` + PathSegments []*PathSegment `protobuf:"bytes,1,rep,name=path_segments,json=pathSegments,proto3" json:"path_segments,omitempty"` + NetworkServices []string `protobuf:"bytes,2,rep,name=network_services,json=networkServices,proto3" json:"network_services,omitempty"` } func (x *MonitorScopeSelector) Reset() { @@ -554,6 +573,13 @@ func (x *MonitorScopeSelector) GetPathSegments() []*PathSegment { return nil } +func (x *MonitorScopeSelector) GetNetworkServices() []string { + if x != nil { + return x.NetworkServices + } + return nil +} + var File_connection_proto protoreflect.FileDescriptor var file_connection_proto_rawDesc = []byte{ @@ -640,33 +666,36 @@ var file_connection_proto_rawDesc = []byte{ 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x54, 0x0a, 0x14, 0x4d, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x7f, 0x0a, 0x14, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x3c, 0x0a, 0x0d, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0c, 0x70, 0x61, 0x74, 0x68, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, - 0x73, 0x2a, 0x48, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x06, 0x0a, 0x02, 0x55, 0x50, - 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, - 0x52, 0x45, 0x46, 0x52, 0x45, 0x53, 0x48, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x45, - 0x44, 0x10, 0x02, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, 0x53, 0x45, 0x4c, 0x45, 0x43, 0x54, 0x5f, - 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x45, 0x44, 0x10, 0x03, 0x2a, 0x49, 0x0a, 0x13, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x5f, 0x53, 0x54, - 0x41, 0x54, 0x45, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x10, 0x00, 0x12, 0x0a, - 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, - 0x4c, 0x45, 0x54, 0x45, 0x10, 0x02, 0x32, 0x6a, 0x0a, 0x11, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, - 0x72, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x55, 0x0a, 0x12, 0x4d, - 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x4d, - 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x6f, 0x72, 0x1a, 0x1b, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x30, 0x01, 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x6d, - 0x65, 0x73, 0x68, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x12, 0x29, 0x0a, 0x10, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2a, 0x48, 0x0a, 0x05, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x06, 0x0a, 0x02, 0x55, 0x50, 0x10, 0x00, 0x12, 0x08, 0x0a, + 0x04, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, 0x52, 0x45, 0x46, 0x52, 0x45, + 0x53, 0x48, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x16, + 0x0a, 0x12, 0x52, 0x45, 0x53, 0x45, 0x4c, 0x45, 0x43, 0x54, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, + 0x53, 0x54, 0x45, 0x44, 0x10, 0x03, 0x2a, 0x49, 0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, + 0x16, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x54, + 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, + 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, + 0x02, 0x32, 0x6a, 0x0a, 0x11, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x55, 0x0a, 0x12, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, + 0x72, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x20, 0x2e, 0x63, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, + 0x72, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x1a, 0x1b, + 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x42, 0x3a, 0x5a, + 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/pkg/api/networkservice/connection.proto b/pkg/api/networkservice/connection.proto index 9fbe87e..38b7e48 100644 --- a/pkg/api/networkservice/connection.proto +++ b/pkg/api/networkservice/connection.proto @@ -1,5 +1,6 @@ // Copyright 2018 Red Hat, Inc. // Copyright (c) 2018 Cisco and/or its affiliates. +// Copyright (c) 2024 Nordix Foundation. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -91,6 +92,7 @@ message ConnectionEvent { message MonitorScopeSelector { repeated PathSegment path_segments = 1; + repeated string network_services = 2; } service MonitorConnection { diff --git a/pkg/api/networkservice/connection_helpers.go b/pkg/api/networkservice/connection_helpers.go index c37ef85..466e7ea 100644 --- a/pkg/api/networkservice/connection_helpers.go +++ b/pkg/api/networkservice/connection_helpers.go @@ -4,6 +4,8 @@ // // Copyright (c) 2023-2024 Cisco and/or its affiliates. // +// Copyright (c) 2024 Nordix Foundation. +// // SPDX-License-Identifier: Apache-2.0 // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -37,12 +39,38 @@ func (x *Connection) Clone() *Connection { return proto.Clone(x).(*Connection) } +// Iterates through the selector.NetworkServices array looking for a network service +// that matches the Connection.NetworkService. Treats an empty selector.NetworkService +// array as a wildcard - Returns true on match +func (x *Connection) matchesNetworkService(networkServices []string) bool { + if len(networkServices) == 0 { + return true + } + + for _, v := range networkServices { + if v == x.GetNetworkService() { + // matched network service + return true + } + } + + return false +} + // MatchesMonitorScopeSelector - Returns true of the connection matches the selector func (x *Connection) MatchesMonitorScopeSelector(selector *MonitorScopeSelector) bool { if x == nil { return false } // Note: Empty selector always matches a non-nil Connection + if len(selector.GetPathSegments()) == 0 && len(selector.GetNetworkServices()) == 0 { + return true + } + // Compare network service names first + if !x.matchesNetworkService(selector.GetNetworkServices()) { + return false + } + // Empty PathSegments in selector, treat as wildcard if len(selector.GetPathSegments()) == 0 { return true } diff --git a/pkg/api/networkservice/connection_helpers_test.go b/pkg/api/networkservice/connection_helpers_test.go index 2ab3fc1..399b3a9 100644 --- a/pkg/api/networkservice/connection_helpers_test.go +++ b/pkg/api/networkservice/connection_helpers_test.go @@ -1,5 +1,7 @@ // Copyright (c) 2023 Cisco and/or its affiliates. // +// Copyright (c) 2024 Nordix Foundation. +// // SPDX-License-Identifier: Apache-2.0 // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -99,3 +101,161 @@ func TestMonitorScopeSelector(t *testing.T) { }) } } + +// nolint: funlen +func TestNetworkServiceMonitorScopeSelector(t *testing.T) { + cases := []struct { + testname string + conn *networkservice.Connection + selector *networkservice.MonitorScopeSelector + matches bool + }{ + { + testname: "EmptySelector", + conn: &networkservice.Connection{ + Path: &networkservice.Path{ + PathSegments: []*networkservice.PathSegment{{Name: "s1", Id: "id1", Token: "t1"}, {Name: "s2", Id: "id2", Token: "t2"}}, + }, + NetworkService: "ns1", + }, + selector: &networkservice.MonitorScopeSelector{}, + matches: true, + }, + { + testname: "IdenticalPathsAndNetworkService", + conn: &networkservice.Connection{ + Path: &networkservice.Path{ + PathSegments: []*networkservice.PathSegment{{Name: "s1", Id: "id1", Token: "t1"}, {Name: "s2", Id: "id2", Token: "t2"}}, + }, + NetworkService: "ns1", + }, + selector: &networkservice.MonitorScopeSelector{ + PathSegments: []*networkservice.PathSegment{{Name: "s1", Id: "id1", Token: "t1"}, {Name: "s2", Id: "id2", Token: "t2"}}, + NetworkServices: []string{"ns1"}, + }, + matches: true, + }, + { + testname: "IdenticalPathsAndDifferentNetworkService", + conn: &networkservice.Connection{ + Path: &networkservice.Path{ + PathSegments: []*networkservice.PathSegment{{Name: "s1", Id: "id1", Token: "t1"}, {Name: "s2", Id: "id2", Token: "t2"}}, + }, + NetworkService: "ns1", + }, + selector: &networkservice.MonitorScopeSelector{ + PathSegments: []*networkservice.PathSegment{{Name: "s1", Id: "id1", Token: "t1"}, {Name: "s2", Id: "id2", Token: "t2"}}, + NetworkServices: []string{"ns2"}, + }, + matches: false, + }, + { + testname: "IdenticalPathsAndMatchingNetworkServiceList", + conn: &networkservice.Connection{ + Path: &networkservice.Path{ + PathSegments: []*networkservice.PathSegment{{Name: "s1", Id: "id1", Token: "t1"}, {Name: "s2", Id: "id2", Token: "t2"}}, + }, + NetworkService: "ns1", + }, + selector: &networkservice.MonitorScopeSelector{ + PathSegments: []*networkservice.PathSegment{{Name: "s1", Id: "id1", Token: "t1"}, {Name: "s2", Id: "id2", Token: "t2"}}, + NetworkServices: []string{"ns2", "ns1", "ns3"}, + }, + matches: true, + }, + { + testname: "IdenticalPathsAndNonMatchingNetworkServiceList", + conn: &networkservice.Connection{ + Path: &networkservice.Path{ + PathSegments: []*networkservice.PathSegment{{Name: "s1", Id: "id1", Token: "t1"}, {Name: "s2", Id: "id2", Token: "t2"}}, + }, + NetworkService: "ns1", + }, + selector: &networkservice.MonitorScopeSelector{ + PathSegments: []*networkservice.PathSegment{{Name: "s1", Id: "id1", Token: "t1"}, {Name: "s2", Id: "id2", Token: "t2"}}, + NetworkServices: []string{"ns2", "ns3", "ns0"}, + }, + matches: false, + }, + { + testname: "IdenticalNetworkService", + conn: &networkservice.Connection{ + Path: &networkservice.Path{ + PathSegments: []*networkservice.PathSegment{{Name: "s1", Id: "id1", Token: "t1"}, {Name: "s2", Id: "id2", Token: "t2"}}, + }, + NetworkService: "ns1", + }, + selector: &networkservice.MonitorScopeSelector{ + NetworkServices: []string{"ns1"}, + }, + matches: true, + }, + { + testname: "IdenticalNetworkServiceEmptyConnectionPath", + conn: &networkservice.Connection{ + NetworkService: "ns1", + }, + selector: &networkservice.MonitorScopeSelector{ + NetworkServices: []string{"ns1"}, + }, + matches: true, + }, + { + testname: "DifferentNetworkService", + conn: &networkservice.Connection{ + Path: &networkservice.Path{ + PathSegments: []*networkservice.PathSegment{{Name: "s1", Id: "id1", Token: "t1"}, {Name: "s2", Id: "id2", Token: "t2"}}, + }, + NetworkService: "ns1", + }, + selector: &networkservice.MonitorScopeSelector{ + NetworkServices: []string{"ns2"}, + }, + matches: false, + }, + { + testname: "DifferentNetworkServiceEmptyConnectionPath", + conn: &networkservice.Connection{ + NetworkService: "ns1", + }, + selector: &networkservice.MonitorScopeSelector{ + NetworkServices: []string{"ns2"}, + }, + matches: false, + }, + { + testname: "MatchingNetworkServiceList", + conn: &networkservice.Connection{ + Path: &networkservice.Path{ + PathSegments: []*networkservice.PathSegment{{Name: "s1", Id: "id1", Token: "t1"}, {Name: "s2", Id: "id2", Token: "t2"}}, + }, + NetworkService: "ns1", + }, + selector: &networkservice.MonitorScopeSelector{ + NetworkServices: []string{"ns2", "ns1", "ns3"}, + }, + matches: true, + }, + { + testname: "NonMatchingNetworkServiceList", + conn: &networkservice.Connection{ + Path: &networkservice.Path{ + PathSegments: []*networkservice.PathSegment{{Name: "s1", Id: "id1", Token: "t1"}, {Name: "s2", Id: "id2", Token: "t2"}}, + }, + NetworkService: "ns1", + }, + selector: &networkservice.MonitorScopeSelector{ + NetworkServices: []string{"ns2", "ns3", "ns0"}, + }, + matches: false, + }, + } + + for _, testCase := range cases { + c := testCase + t.Run(c.testname, func(t *testing.T) { + + require.Equal(t, c.conn.MatchesMonitorScopeSelector(c.selector), c.matches) + }) + } +}