diff --git a/pkg/networkservice/common/filtermechanisms/README.md b/pkg/networkservice/common/filtermechanisms/README.md new file mode 100644 index 000000000..fe763e1fe --- /dev/null +++ b/pkg/networkservice/common/filtermechanisms/README.md @@ -0,0 +1,94 @@ +## Intro + +Package `filtermechanisms` filters out remote mechanisms if communicating by remote url +filters out local mechanisms otherwise. Can be used with eNSMGR. + +## Options + +Supported option `WithExternalThreshold` that sets max path segments count for eNSMgrs. + +## Examples +Note: **Is local** true when path segment index less than localThreshold and nsmgr knows NSE url + + 1. Local: + ``` + Scheme: nsc-->NSMgr-->cross-nse-->NSMgr-->nse + NSMgr knows nse: true + filterMechanismsServer.localThreshold: 5 + len(request.Connection.Path.PathSegments): 4 + Is local: true +``` + + 2. Local eNSM: + ``` + Scheme: nsc-->eNSMgr-->nse + eNSMgr knows nse: true + filterMechanismsServer.localThreshold: 3 + len(request.Connection.Path.PathSegments): 2 + Is local: true +``` + + 3. Remote eNSM: + ``` + Scheme: nsc-->eNSMgr1-->eNSMgr2-->nse + eNSMgr1: + knows nse: false + filterMechanismsServer.localThreshold = 3 + len(request.Connection.Path.PathSegments) = 2 + Is local: false + + eNSMgr2: + knows nse: true + filterMechanismsServer.localThreshold = 3 + len(request.Connection.Path.PathSegments) = 3 + Is local: false +``` + + 4. Remote NSMgr + eNSMGR + ``` + Scheme: nsc-->NSMgr1-->cross-nse1-->NSMgr1-->eNSMgr1-->nse + NSMgr1: + knows nse: false + filterMechanismsServer.localThreshold = 5 + len(request.Connection.Path.PathSegments) = 4 + Is local: false + + eNSMgr1: + knows nse: true + filterMechanismsServer.localThreshold = 3 + len(request.Connection.Path.PathSegments) = 5 + Is local: false +``` + + 5. Remote eNSMGR + NSMgr + ``` + Scheme: nsc-->eNSMgr1-->NSMgr1-->cross-nse1-->NSMgr1-->eNSMgr2-->nse + eNSMgr1: + knows nse: false + filterMechanismsServer.localThreshold = 3 + len(request.Connection.Path.PathSegments) = 2 + Is local: false + + NSMgr1: + knows nse: true + filterMechanismsServer.localThreshold = 5 + len(request.Connection.Path.PathSegments) = 5 + Is local: false +``` + +6. Remote + +``` + Scheme: nsc-->NSMgr1-->cross-nse1-->NSMgr1-->NSMgr2-->cross-nse2-->NSMgr2-->nse + NSMgr2: + knows nse: false + filterMechanismsServer.localThreshold = 5 + len(request.Connection.Path.PathSegments) = 4 + Is local: false + + NSMgr1: + knows nse: true + filterMechanismsServer.localThreshold = 5 + len(request.Connection.Path.PathSegments) = 7 + Is local: false +``` \ No newline at end of file diff --git a/pkg/networkservice/common/filtermechanisms/const.go b/pkg/networkservice/common/filtermechanisms/const.go new file mode 100644 index 000000000..63be5c81b --- /dev/null +++ b/pkg/networkservice/common/filtermechanisms/const.go @@ -0,0 +1,23 @@ +// Copyright (c) 2020 Doc.ai and/or its affiliates. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package filtermechanisms + +const ( + // See at examples section in README.md + defaultThreshold = 5 + externalThreshold = 3 +) diff --git a/pkg/networkservice/common/filtermechanisms/options.go b/pkg/networkservice/common/filtermechanisms/options.go new file mode 100644 index 000000000..5b1b60647 --- /dev/null +++ b/pkg/networkservice/common/filtermechanisms/options.go @@ -0,0 +1,27 @@ +// Copyright (c) 2020 Doc.ai and/or its affiliates. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package filtermechanisms + +// Option is option applier for filterMechanismsServer +type Option func(server *filterMechanismsServer) + +// WithExternalThreshold configures filterMechanismsServer to work with external NSMgr. +func WithExternalThreshold() Option { + return Option(func(server *filterMechanismsServer) { + server.localThreshold = externalThreshold + }) +} diff --git a/pkg/networkservice/common/filtermechanisms/server.go b/pkg/networkservice/common/filtermechanisms/server.go index d23741618..8a1f75df2 100644 --- a/pkg/networkservice/common/filtermechanisms/server.go +++ b/pkg/networkservice/common/filtermechanisms/server.go @@ -33,21 +33,31 @@ import ( ) type filterMechanismsServer struct { - urls endpointurls.Set + urls endpointurls.Set + localThreshold int } // NewServer - filters out remote mechanisms if connection is received from a unix file socket, otherwise filters -// out local mechanisms -func NewServer(registryServer *registry.NetworkServiceEndpointRegistryServer) networkservice.NetworkServiceServer { - result := &filterMechanismsServer{} +// out local mechanisms. +func NewServer(registryServer *registry.NetworkServiceEndpointRegistryServer, options ...Option) networkservice.NetworkServiceServer { + result := &filterMechanismsServer{ + localThreshold: defaultThreshold, + } + for _, applyOption := range options { + applyOption(result) + } *registryServer = endpointurls.NewNetworkServiceEndpointRegistryServer(&result.urls) return result } func (f *filterMechanismsServer) Request(ctx context.Context, request *networkservice.NetworkServiceRequest) (*networkservice.Connection, error) { u := clienturlctx.ClientURL(ctx) + if _, ok := f.urls.Load(*u); ok { - request.MechanismPreferences = filterMechanismsByCls(request.GetMechanismPreferences(), cls.LOCAL) + filteredMechanisms := filterMechanismsByCls(request.GetMechanismPreferences(), cls.LOCAL) + if len(filteredMechanisms) > 0 { + request.MechanismPreferences = filteredMechanisms + } } else { request.MechanismPreferences = filterMechanismsByCls(request.GetMechanismPreferences(), cls.REMOTE) } diff --git a/pkg/networkservice/common/filtermechanisms/server_test.go b/pkg/networkservice/common/filtermechanisms/server_test.go index a433a834f..e83766132 100644 --- a/pkg/networkservice/common/filtermechanisms/server_test.go +++ b/pkg/networkservice/common/filtermechanisms/server_test.go @@ -21,6 +21,8 @@ import ( "net/url" "testing" + "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" + "github.com/networkservicemesh/api/pkg/api/networkservice" "github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/cls" "github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/kernel" @@ -34,6 +36,72 @@ import ( "github.com/networkservicemesh/sdk/pkg/tools/clienturlctx" ) +func TestFilterMechanisms_RemoteExternal(t *testing.T) { + request := &networkservice.NetworkServiceRequest{ + MechanismPreferences: []*networkservice.Mechanism{ + { + Cls: cls.REMOTE, + Type: vxlan.MECHANISM, + }, + { + Cls: cls.LOCAL, + Type: kernel.MECHANISM, + }, + }, + Connection: &networkservice.Connection{ + Path: &networkservice.Path{ + PathSegments: make([]*networkservice.PathSegment, 3), + }, + }, + } + + var localRegistryServer registry.NetworkServiceEndpointRegistryServer + localServer := filtermechanisms.NewServer(&localRegistryServer) + var remoteRegistryServer registry.NetworkServiceEndpointRegistryServer + remoteServer := filtermechanisms.NewServer(&remoteRegistryServer, filtermechanisms.WithExternalThreshold()) + u := &url.URL{Path: "test"} + _, _ = remoteRegistryServer.Register(context.Background(), ®istry.NetworkServiceEndpoint{ + Url: u.String(), + }) + _, err := next.NewNetworkServiceServer(localServer, remoteServer).Request(clienturlctx.WithClientURL(context.Background(), u), request) + require.NoError(t, err) + require.Len(t, request.MechanismPreferences, 1) + require.Equal(t, cls.REMOTE, request.MechanismPreferences[0].Cls) +} + +func TestFilterMechanisms_Remote(t *testing.T) { + request := &networkservice.NetworkServiceRequest{ + MechanismPreferences: []*networkservice.Mechanism{ + { + Cls: cls.REMOTE, + Type: vxlan.MECHANISM, + }, + { + Cls: cls.LOCAL, + Type: kernel.MECHANISM, + }, + }, + Connection: &networkservice.Connection{ + Path: &networkservice.Path{ + PathSegments: make([]*networkservice.PathSegment, 5), + }, + }, + } + + var localRegistryServer registry.NetworkServiceEndpointRegistryServer + localServer := filtermechanisms.NewServer(&localRegistryServer) + var remoteRegistryServer registry.NetworkServiceEndpointRegistryServer + remoteServer := filtermechanisms.NewServer(&remoteRegistryServer) + u := &url.URL{Path: "test"} + _, _ = remoteRegistryServer.Register(context.Background(), ®istry.NetworkServiceEndpoint{ + Url: u.String(), + }) + _, err := next.NewNetworkServiceServer(localServer, remoteServer).Request(clienturlctx.WithClientURL(context.Background(), u), request) + require.NoError(t, err) + require.Len(t, request.MechanismPreferences, 1) + require.Equal(t, cls.REMOTE, request.MechanismPreferences[0].Cls) +} + func TestFilterMechanismsServer_Request(t *testing.T) { request := func() *networkservice.NetworkServiceRequest { return &networkservice.NetworkServiceRequest{