Skip to content

Commit

Permalink
Add interface names into NSM metrics (#789)
Browse files Browse the repository at this point in the history
* Add interface names into NSM metrics

Signed-off-by: Alexander Peretyatko <alexander.peretyatko@xored.com>

* Task:768 Add interface names into NSM metrics

Signed-off-by: Alexander Peretyatko <alexander.peretyatko@xored.com>

* Add interface names into NSM metrics

Signed-off-by: Nikita Skrynnik <nikita.skrynnik@xored.com>

* cleanup

Signed-off-by: Nikita Skrynnik <nikita.skrynnik@xored.com>

* change folder names

Signed-off-by: Nikita Skrynnik <nikita.skrynnik@xored.com>

---------

Signed-off-by: Alexander Peretyatko <alexander.peretyatko@xored.com>
Signed-off-by: Nikita Skrynnik <nikita.skrynnik@xored.com>
Co-authored-by: Alexander Peretyatko <alexander.peretyatko@xored.com>
  • Loading branch information
NikitaSkrynnik and Alexander Peretyatko authored Jan 16, 2024
1 parent 702ef78 commit 4c9782a
Show file tree
Hide file tree
Showing 15 changed files with 496 additions and 14 deletions.
10 changes: 5 additions & 5 deletions pkg/networkservice/chains/forwarder/options.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2022 Cisco and/or its affiliates.
// Copyright (c) 2022-2024 Cisco and/or its affiliates.
//
// SPDX-License-Identifier: Apache-2.0
//
Expand Down Expand Up @@ -29,7 +29,7 @@ import (
"github.com/networkservicemesh/sdk/pkg/networkservice/common/cleanup"

"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/vxlan"
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/stats"
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/metrics"
)

type forwarderOptions struct {
Expand All @@ -40,7 +40,7 @@ type forwarderOptions struct {
dialTimeout time.Duration
domain2Device map[string]string
mechanismPrioriyList []string
statsOpts []stats.Option
statsOpts []metrics.Option
cleanupOpts []cleanup.Option
vxlanOpts []vxlan.Option
dialOpts []grpc.DialOption
Expand Down Expand Up @@ -105,8 +105,8 @@ func WithMechanismPriority(priorityList []string) Option {
}
}

// WithStatsOptions sets stats options
func WithStatsOptions(opts ...stats.Option) Option {
// WithStatsOptions sets metrics options
func WithStatsOptions(opts ...metrics.Option) Option {
return func(o *forwarderOptions) {
o.statsOpts = opts
}
Expand Down
8 changes: 5 additions & 3 deletions pkg/networkservice/chains/forwarder/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
//
// Copyright (c) 2021-2023 Nordix Foundation.
//
// 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 @@ -66,9 +68,9 @@ import (
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/vlan"
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/vxlan"
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/wireguard"
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/metrics"
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/nsmonitor"
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/pinhole"
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/stats"
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/tag"
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/up"
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/xconnect"
Expand Down Expand Up @@ -121,7 +123,7 @@ func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, vppConn
sendfd.NewServer(),
discover.NewServer(nsClient, nseClient),
roundrobin.NewServer(),
stats.NewServer(ctx, opts.statsOpts...),
metrics.NewServer(ctx, vppConn, opts.statsOpts...),
up.NewServer(ctx, vppConn),
xconnect.NewServer(vppConn),
l2bridgedomain.NewServer(vppConn),
Expand Down Expand Up @@ -151,7 +153,7 @@ func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, vppConn
cleanup.NewClient(ctx, opts.cleanupOpts...),
mechanismtranslation.NewClient(),
connectioncontextkernel.NewClient(),
stats.NewClient(ctx, opts.statsOpts...),
metrics.NewClient(ctx, vppConn, opts.statsOpts...),
up.NewClient(ctx, vppConn),
mtu.NewClient(vppConn),
tag.NewClient(ctx, vppConn),
Expand Down
46 changes: 46 additions & 0 deletions pkg/networkservice/metrics/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) 2024 Cisco 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.

//go:build linux
// +build linux

// Package metrics provides chain elements for retrieving metrics from vpp
package metrics

import (
"context"

"go.fd.io/govpp/api"

"github.com/networkservicemesh/api/pkg/api/networkservice"
"github.com/networkservicemesh/sdk/pkg/networkservice/core/chain"

"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/metrics/ifacename"
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/metrics/stats"
)

// NewClient provides a NetworkServiceClient chain elements that retrieves vpp interface metrics and names.
func NewClient(ctx context.Context, vppConn api.Connection, options ...Option) networkservice.NetworkServiceClient {
opts := &metricsOptions{}
for _, opt := range options {
opt(opts)
}

return chain.NewNetworkServiceClient(
stats.NewClient(ctx, stats.WithSocket(opts.socket)),
ifacename.NewClient(ctx, vppConn, ifacename.WithSocket(opts.socket)),
)
}
91 changes: 91 additions & 0 deletions pkg/networkservice/metrics/ifacename/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright (c) 2024 Cisco 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.

//go:build linux
// +build linux

package ifacename

import (
"context"
"sync"

"github.com/golang/protobuf/ptypes/empty"
"go.fd.io/govpp/api"
"go.fd.io/govpp/core"
"google.golang.org/grpc"

"github.com/networkservicemesh/api/pkg/api/networkservice"
"github.com/networkservicemesh/sdk/pkg/networkservice/core/next"
"github.com/networkservicemesh/sdk/pkg/tools/log"
)

type ifaceNamesClient struct {
chainCtx context.Context
statsConn *core.StatsConnection
vppConn api.Connection
statsSock string
once sync.Once
initErr error
}

// NewClient provides a NetworkServiceClient chain elements that retrieves vpp interface metrics.
func NewClient(ctx context.Context, vppConn api.Connection, options ...Option) networkservice.NetworkServiceClient {
opts := &ifacenameOptions{}
for _, opt := range options {
opt(opts)
}

return &ifaceNamesClient{
chainCtx: ctx,
vppConn: vppConn,
statsSock: opts.Socket,
}
}

func (s *ifaceNamesClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (*networkservice.Connection, error) {
initErr := s.init()
if initErr != nil {
log.FromContext(ctx).Errorf("%v", initErr)
}

conn, err := next.Client(ctx).Request(ctx, request, opts...)
if err != nil || initErr != nil {
return conn, err
}

retrieveIfaceNames(ctx, s.statsConn, s.vppConn, conn, true)

return conn, nil
}

func (s *ifaceNamesClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*empty.Empty, error) {
rv, err := next.Client(ctx).Close(ctx, conn, opts...)
if err != nil || s.initErr != nil {
return rv, err
}

retrieveIfaceNames(ctx, s.statsConn, s.vppConn, conn, true)

return &empty.Empty{}, nil
}

func (s *ifaceNamesClient) init() error {
s.once.Do(func() {
s.statsConn, s.initErr = initFunc(s.chainCtx, s.statsSock)
})
return s.initErr
}
127 changes: 127 additions & 0 deletions pkg/networkservice/metrics/ifacename/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright (c) 2024 Cisco 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.

//go:build linux
// +build linux

package ifacename

import (
"context"
"fmt"
"io"
"strings"

"go.fd.io/govpp/adapter"
"go.fd.io/govpp/adapter/statsclient"
"go.fd.io/govpp/api"
"go.fd.io/govpp/core"

"github.com/networkservicemesh/api/pkg/api/networkservice"
interfaces "github.com/networkservicemesh/govpp/binapi/interface"
"github.com/networkservicemesh/govpp/binapi/interface_types"
"github.com/pkg/errors"

"github.com/networkservicemesh/sdk-vpp/pkg/tools/ifindex"
)

type interfacesInfo struct {
interfaceName string
interfaceType string
}

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

// Save retrieved vpp interface names in pathSegment
func retrieveIfaceNames(ctx context.Context, statsConn *core.StatsConnection, vppConn api.Connection, conn *networkservice.Connection, isClient bool) {
segment := conn.Path.PathSegments[conn.Path.Index]

swIfIndex, ok := ifindex.Load(ctx, isClient)
if !ok {
return
}
stats := new(api.InterfaceStats)
if err := statsConn.GetInterfaceStats(stats); err != nil {
return
}

info, err := getInterfacesInfo(ctx, vppConn, swIfIndex)
if err != nil {
return
}

addName := "server_"
if isClient {
addName = "client_"
}
for idx := range stats.Interfaces {
iface := &stats.Interfaces[idx]
if iface.InterfaceIndex != uint32(swIfIndex) {
continue
}

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

segment.Metrics[addName+"interface"] = info.getInterfaceDetails()
break
}
}

func initFunc(chainCtx context.Context, statsSocket string) (*core.StatsConnection, error) {
if statsSocket == "" {
statsSocket = adapter.DefaultStatsSocket
}
statsConn, err := core.ConnectStats(statsclient.NewStatsClient(statsSocket))
if err != nil {
return nil, errors.Wrap(err, "failed to connect to Stats API")
}
go func() {
<-chainCtx.Done()
statsConn.Disconnect()
}()
return statsConn, nil
}

func getInterfacesInfo(ctx context.Context, vppConn api.Connection, swIfIndex interface_types.InterfaceIndex) (*interfacesInfo, error) {
client, err := interfaces.NewServiceClient(vppConn).SwInterfaceDump(ctx, &interfaces.SwInterfaceDump{
SwIfIndex: swIfIndex,
})

if err != nil {
return nil, err
}

info := &interfacesInfo{}
for {
details, err := client.Recv()
if err == io.EOF {
break
}

if err != nil {
return nil, err
}

info.interfaceName = details.InterfaceName
info.interfaceType = strings.ToUpper(details.InterfaceDevType)
}

return info, nil
}
18 changes: 18 additions & 0 deletions pkg/networkservice/metrics/ifacename/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) 2024 Cisco 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 ifacename provides chain elements for retrieving names from vpp interfaces
package ifacename
31 changes: 31 additions & 0 deletions pkg/networkservice/metrics/ifacename/option.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) 2024 Cisco 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 ifacename

type ifacenameOptions struct {
Socket string
}

// Option is an option pattern for ifacename server/client
type Option func(o *ifacenameOptions)

// WithSocket sets stats socket name
func WithSocket(socket string) Option {
return func(o *ifacenameOptions) {
o.Socket = socket
}
}
Loading

0 comments on commit 4c9782a

Please sign in to comment.