Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add interface names into NSM metrics #1572

Merged
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
35 changes: 20 additions & 15 deletions pkg/networkservice/chains/endpoint/combine_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Copyright (c) 2021-2022 Doc.ai and/or its affiliates.
//
// Copyright (c) 2024 Cisco and/or its affiliates.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -88,7 +90,7 @@ func testCombine(t *testing.T, mechanism *networkservice.Mechanism) {
kernel.MECHANISM: servers[0],
memif.MECHANISM: servers[1],
})
}, newTestEndpoint(ctx, kernel.MECHANISM), newTestEndpoint(ctx, memif.MECHANISM))
}, newTestEndpoint(ctx, kernel.MECHANISM, kernel.MECHANISM), newTestEndpoint(ctx, memif.MECHANISM, memif.MECHANISM))

cc := startEndpoint(ctx, t, e)
defer func() { _ = cc.Close() }()
Expand Down Expand Up @@ -123,11 +125,11 @@ func testCombine(t *testing.T, mechanism *networkservice.Mechanism) {
require.Equal(t, (&networkservice.ConnectionEvent{
Type: networkservice.ConnectionEventType_UPDATE,
Connections: map[string]*networkservice.Connection{
conn.GetNextPathSegment().GetId(): {
Id: conn.GetNextPathSegment().GetId(),
conn.GetCurrentPathSegment().GetId(): {
Id: conn.GetCurrentPathSegment().GetId(),
Mechanism: conn.GetMechanism(),
Path: &networkservice.Path{
Index: 1,
Index: 0,
PathSegments: conn.GetPath().GetPathSegments(),
},
},
Expand Down Expand Up @@ -166,7 +168,7 @@ func TestSwitchEndpoint_InitialStateTransfer(t *testing.T) {
kernel.MECHANISM: servers[0],
memif.MECHANISM: servers[1],
})
}, newTestEndpoint(ctx, kernel.MECHANISM), newTestEndpoint(ctx, memif.MECHANISM))
}, newTestEndpoint(ctx, kernel.MECHANISM, kernel.MECHANISM), newTestEndpoint(ctx, memif.MECHANISM, memif.MECHANISM))

cc := startEndpoint(ctx, t, e)
defer func() { _ = cc.Close() }()
Expand Down Expand Up @@ -195,11 +197,11 @@ func TestSwitchEndpoint_InitialStateTransfer(t *testing.T) {
Connections: make(map[string]*networkservice.Connection),
}
for _, conn := range conns {
expectedEvent.Connections[conn.GetNextPathSegment().GetId()] = &networkservice.Connection{
Id: conn.GetNextPathSegment().GetId(),
expectedEvent.Connections[conn.GetCurrentPathSegment().GetId()] = &networkservice.Connection{
Id: conn.GetCurrentPathSegment().GetId(),
Mechanism: conn.GetMechanism(),
Path: &networkservice.Path{
Index: 1,
Index: 0,
PathSegments: conn.GetPath().GetPathSegments(),
},
}
Expand Down Expand Up @@ -227,13 +229,14 @@ func TestSwitchEndpoint_DuplicateEndpoints(t *testing.T) {

monitorCtx, cancelMonitor := context.WithCancel(ctx)

duplicate := newTestEndpoint(monitorCtx, "duplicate")
duplicate1 := newTestEndpoint(monitorCtx, kernel.MECHANISM, "duplicate")
duplicate2 := newTestEndpoint(monitorCtx, memif.MECHANISM, "duplicate")
e := endpoint.Combine(func(servers []networkservice.NetworkServiceServer) networkservice.NetworkServiceServer {
return mechanisms.NewServer(map[string]networkservice.NetworkServiceServer{
kernel.MECHANISM: servers[0],
memif.MECHANISM: servers[1],
})
}, duplicate, duplicate)
}, duplicate1, duplicate2)

cc := startEndpoint(ctx, t, e)
defer func() { _ = cc.Close() }()
Expand Down Expand Up @@ -266,11 +269,11 @@ func TestSwitchEndpoint_DuplicateEndpoints(t *testing.T) {
require.Equal(t, (&networkservice.ConnectionEvent{
Type: networkservice.ConnectionEventType_UPDATE,
Connections: map[string]*networkservice.Connection{
conn.GetNextPathSegment().GetId(): {
Id: conn.GetNextPathSegment().GetId(),
conn.GetCurrentPathSegment().GetId(): {
Id: conn.GetCurrentPathSegment().GetId(),
Mechanism: conn.GetMechanism(),
Path: &networkservice.Path{
Index: 1,
Index: 0,
PathSegments: conn.GetPath().GetPathSegments(),
},
},
Expand Down Expand Up @@ -310,13 +313,15 @@ type testEndpoint struct {
networkservice.MonitorConnectionServer
}

func newTestEndpoint(ctx context.Context, name string) *testEndpoint {
func newTestEndpoint(ctx context.Context, mechanism, name string) *testEndpoint {
e := new(testEndpoint)
e.NetworkServiceServer = next.NewNetworkServiceServer(
updatepath.NewServer(name),
begin.NewServer(),
metadata.NewServer(),
monitor.NewServer(ctx, &e.MonitorConnectionServer),
mechanisms.NewServer(map[string]networkservice.NetworkServiceServer{
mechanism: updatepath.NewServer(name),
Copy link
Contributor

Choose a reason for hiding this comment

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

Have you tried using null.NewServer() here and leaving updatePath at the previous place?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I have. It didn't work

}),
)
return e
}
Expand Down
11 changes: 9 additions & 2 deletions pkg/networkservice/common/mechanisms/client.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Copyright (c) 2021 Doc.ai and/or its affiliates.
//
// Copyright (c) 2024 Cisco and/or its affiliates.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -44,9 +46,11 @@ func NewClient(mechanisms map[string]networkservice.NetworkServiceClient) networ
}

func (mc *mechanismsClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (*networkservice.Connection, error) {
if request.GetConnection().GetMechanism() != nil {
srv, ok := mc.mechanisms[request.GetConnection().GetMechanism().GetType()]
mech := request.GetConnection().GetMechanism()
if mech != nil {
srv, ok := mc.mechanisms[mech.GetType()]
if ok {
storeMetrics(request.GetConnection(), mech, true)
return srv.Request(ctx, request, opts...)
}
return nil, errUnsupportedMech
Expand All @@ -57,6 +61,8 @@ func (mc *mechanismsClient) Request(ctx context.Context, request *networkservice
if ok {
req := request.Clone()
var resp *networkservice.Connection
storeMetrics(req.GetConnection(), mechanism, true)

resp, respErr := cm.Request(ctx, req, opts...)
if respErr == nil {
return resp, nil
Expand All @@ -70,6 +76,7 @@ func (mc *mechanismsClient) Request(ctx context.Context, request *networkservice
func (mc *mechanismsClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*empty.Empty, error) {
c, ok := mc.mechanisms[conn.GetMechanism().GetType()]
if ok {
storeMetrics(conn, conn.GetMechanism(), true)
return c.Close(ctx, conn)
}
return nil, errCannotSupportMech
Expand Down
28 changes: 28 additions & 0 deletions pkg/networkservice/common/mechanisms/client_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Copyright (c) 2021 Doc.ai and/or its affiliates.
//
// Copyright (c) 2024 Cisco and/or its affiliates.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -18,6 +20,7 @@ package mechanisms_test

import (
"context"
"fmt"
"testing"

"github.com/pkg/errors"
Expand Down Expand Up @@ -178,3 +181,28 @@ func Test_Client_DontCallNextByItself(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, 2, len(ch))
}

const (
ifnameKey = "name"
ifname = "nsm-1"
)

func Test_Client_Metrics(t *testing.T) {
c := client()
metricsKey := "client_interface"

for _, request := range permuteOverMechanismPreferenceOrder(request()) {
request.MechanismPreferences[0].Parameters[ifnameKey] = ifname
request.Connection.Path = &networkservice.Path{
PathSegments: make([]*networkservice.PathSegment, 1),
Index: 0,
}

conn, err := c.Request(context.Background(), request)
require.NoError(t, err)
require.NotNil(t, conn.Path)
require.Len(t, conn.Path.PathSegments, 1)
require.NotNil(t, conn.Path.PathSegments[0].Metrics)
require.Equal(t, fmt.Sprintf("%s/%s", request.MechanismPreferences[0].Type, ifname), conn.Path.PathSegments[0].Metrics[metricsKey])
}
}
64 changes: 62 additions & 2 deletions pkg/networkservice/common/mechanisms/common.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2021 Doc.ai and/or its affiliates.
// Copyright (c) 2021-2023 Doc.ai and/or its affiliates.
//
// SPDX-License-Identifier: Apache-2.0
//
Expand All @@ -16,7 +16,67 @@

package mechanisms

import "github.com/pkg/errors"
import (
"fmt"

"github.com/networkservicemesh/api/pkg/api/networkservice"
"github.com/pkg/errors"
)

var errCannotSupportMech = errors.New("cannot support any of the requested mechanism")
var errUnsupportedMech = errors.New("unsupported mechanism")

const (
clientMetricKey = "client_interface"
serverMetricKey = "server_interface"
nameKey = "name"
unresolvedName = "unknown"
)

type interfacesInfo struct {
interfaceName string
interfaceType string
}

func (i *interfacesInfo) getInterfaceDetails() string {
return fmt.Sprintf("%s/%s", i.interfaceType, i.interfaceName)
}

// Save interface details in Path
func storeMetrics(conn *networkservice.Connection, mechanism *networkservice.Mechanism, isClient bool) {
path := conn.GetPath()
if path == nil {
return
}

segments := path.GetPathSegments()
if segments == nil {
return
}

segment := segments[path.Index]
params := mechanism.GetParameters()

name := unresolvedName
if params != nil {
name = params[nameKey]
}

info := &interfacesInfo{
interfaceName: name,
interfaceType: mechanism.GetType(),
}

if segment.Metrics == nil {
segment.Metrics = make(map[string]string)
}

metricKey := clientMetricKey
if !isClient {
metricKey = serverMetricKey
}

if _, ok := segment.Metrics[metricKey]; !ok {
segment.Metrics[metricKey] = info.getInterfaceDetails()
}
}
8 changes: 6 additions & 2 deletions pkg/networkservice/common/mechanisms/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,11 @@ func NewServer(mechanisms map[string]networkservice.NetworkServiceServer) networ
}

func (ms *mechanismsServer) Request(ctx context.Context, request *networkservice.NetworkServiceRequest) (*networkservice.Connection, error) {
if request.GetConnection().GetMechanism() != nil {
srv, ok := ms.mechanisms[request.GetConnection().GetMechanism().GetType()]
mech := request.GetConnection().GetMechanism()
if mech != nil {
srv, ok := ms.mechanisms[mech.GetType()]
if ok {
storeMetrics(request.GetConnection(), mech, false)
return srv.Request(ctx, request)
}
return nil, errors.WithStack(errUnsupportedMech)
Expand All @@ -70,6 +72,7 @@ func (ms *mechanismsServer) Request(ctx context.Context, request *networkservice
var resp *networkservice.Connection
resp, respErr := srv.Request(ctx, req)
if respErr == nil {
storeMetrics(resp, resp.GetMechanism(), false)
return resp, nil
}
err = errors.Wrap(err, respErr.Error())
Expand All @@ -81,6 +84,7 @@ func (ms *mechanismsServer) Request(ctx context.Context, request *networkservice
func (ms *mechanismsServer) Close(ctx context.Context, conn *networkservice.Connection) (*empty.Empty, error) {
srv, ok := ms.mechanisms[conn.GetMechanism().GetType()]
if ok {
storeMetrics(conn, conn.GetMechanism(), false)
return srv.Close(ctx, conn)
}
return nil, errCannotSupportMech
Expand Down
44 changes: 35 additions & 9 deletions pkg/networkservice/common/mechanisms/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// Copyright (c) 2021 Doc.ai and/or its affiliates.
//
// Copyright (c) 2023 Cisco and/or its affiliates.
// Copyright (c) 2023-2024 Cisco and/or its affiliates.
//
// SPDX-License-Identifier: Apache-2.0
//
Expand All @@ -22,6 +22,7 @@ package mechanisms_test

import (
"context"
"fmt"
"testing"

"github.com/pkg/errors"
Expand Down Expand Up @@ -62,20 +63,24 @@ func request() *networkservice.NetworkServiceRequest {
Connection: &networkservice.Connection{},
MechanismPreferences: []*networkservice.Mechanism{
{
Cls: cls.LOCAL,
Type: memif.MECHANISM,
Cls: cls.LOCAL,
Type: memif.MECHANISM,
Parameters: make(map[string]string),
},
{
Cls: cls.LOCAL,
Type: kernel.MECHANISM,
Cls: cls.LOCAL,
Type: kernel.MECHANISM,
Parameters: make(map[string]string),
},
{
Cls: cls.REMOTE,
Type: srv6.MECHANISM,
Cls: cls.REMOTE,
Type: srv6.MECHANISM,
Parameters: make(map[string]string),
},
{
Cls: cls.REMOTE,
Type: vxlan.MECHANISM,
Cls: cls.REMOTE,
Type: vxlan.MECHANISM,
Parameters: make(map[string]string),
},
},
}
Expand Down Expand Up @@ -239,3 +244,24 @@ func TestDontCallNextByItself(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, 2, len(ch))
}

func TestMetrics(t *testing.T) {
s := server()
metricsKey := "server_interface"

for _, request := range permuteOverMechanismPreferenceOrder(request()) {
request.MechanismPreferences[0].Parameters[ifnameKey] = ifname
request.Connection.Path = &networkservice.Path{
PathSegments: make([]*networkservice.PathSegment, 1),
Index: 0,
}

conn, err := s.Request(context.Background(), request)
require.NoError(t, err)
require.NotNil(t, conn.Path)
require.Len(t, conn.Path.PathSegments, 1)
require.NotNil(t, conn.Path.PathSegments[0].Metrics)

require.Equal(t, fmt.Sprintf("%s/%s", request.MechanismPreferences[0].Type, ifname), conn.Path.PathSegments[0].Metrics[metricsKey])
}
}
Loading