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 #789

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
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
Loading