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

Set memif_rx_mode on a separate chain element #670

Merged
merged 1 commit into from
Dec 14, 2022
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
2 changes: 1 addition & 1 deletion pkg/networkservice/chains/forwarder/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, vppConn
mtu.NewClient(vppConn),
tag.NewClient(ctx, vppConn),
// mechanisms
memif.NewClient(vppConn,
memif.NewClient(ctx, vppConn,
memif.WithChangeNetNS(),
),
kernel.NewClient(vppConn),
Expand Down
4 changes: 3 additions & 1 deletion pkg/networkservice/mechanisms/memif/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
"github.com/networkservicemesh/sdk/pkg/tools/postpone"

"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/memif/memifproxy"
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/memif/memifrxmode"
)

type memifClient struct {
Expand All @@ -47,13 +48,14 @@ type memifClient struct {
}

// NewClient provides a NetworkServiceClient chain elements that support the memif Mechanism
func NewClient(vppConn api.Connection, options ...Option) networkservice.NetworkServiceClient {
func NewClient(chainCtx context.Context, vppConn Connection, options ...Option) networkservice.NetworkServiceClient {
opts := &memifOptions{}
for _, o := range options {
o(opts)
}

return chain.NewNetworkServiceClient(
memifrxmode.NewClient(chainCtx, vppConn),
&memifClient{
vppConn: vppConn,
changeNetNS: opts.changeNetNS,
Expand Down
4 changes: 2 additions & 2 deletions pkg/networkservice/mechanisms/memif/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import (
)

func Test_MemifClient_ShouldAppendMechanismIfMemifMechanismMissed(t *testing.T) {
c := chain.NewNetworkServiceClient(metadata.NewClient(), memif.NewClient(nil))
c := chain.NewNetworkServiceClient(metadata.NewClient(), memif.NewClient(context.Background(), nil))

req := &networkservice.NetworkServiceRequest{
MechanismPreferences: []*networkservice.Mechanism{},
Expand All @@ -56,7 +56,7 @@ func Test_MemifClient_ShouldAppendMechanismIfMemifMechanismMissed(t *testing.T)
}

func Test_MemifClient_ShouldNotDuplicateMechanisms(t *testing.T) {
c := chain.NewNetworkServiceClient(metadata.NewClient(), memif.NewClient(nil))
c := chain.NewNetworkServiceClient(metadata.NewClient(), memif.NewClient(context.Background(), nil))

req := &networkservice.NetworkServiceRequest{
MechanismPreferences: []*networkservice.Mechanism{
Expand Down
21 changes: 6 additions & 15 deletions pkg/networkservice/mechanisms/memif/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ import (
"time"

"git.fd.io/govpp.git/api"
interfaces "github.com/edwarnicke/govpp/binapi/interface"
"github.com/edwarnicke/govpp/binapi/interface_types"
"github.com/edwarnicke/govpp/binapi/memif"
"github.com/networkservicemesh/api/pkg/api/networkservice"
memifMech "github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/memif"
Expand All @@ -44,6 +42,12 @@ import (
"github.com/networkservicemesh/sdk-vpp/pkg/tools/ifindex"
)

// Connection aggregates the api.Connection and api.ChannelProvider interfaces
type Connection interface {
api.Connection
api.ChannelProvider
}

// NetNSInfo contains shared info for server and client
type NetNSInfo struct {
netNS netns.NsHandle
Expand Down Expand Up @@ -151,19 +155,6 @@ func createMemif(ctx context.Context, vppConn api.Connection, socketID uint32, m
WithField("vppapi", "MemifCreate").Debug("completed")
ifindex.Store(ctx, isClient, rsp.SwIfIndex)

now = time.Now()
if _, err := interfaces.NewServiceClient(vppConn).SwInterfaceSetRxMode(ctx, &interfaces.SwInterfaceSetRxMode{
SwIfIndex: rsp.SwIfIndex,
Mode: interface_types.RX_MODE_API_ADAPTIVE,
}); err != nil {
return errors.WithStack(err)
}
log.FromContext(ctx).
WithField("swIfIndex", rsp.SwIfIndex).
WithField("mode", interface_types.RX_MODE_API_ADAPTIVE).
WithField("duration", time.Since(now)).
WithField("vppapi", "SwInterfaceSetRxMode").Debug("completed")

if isClient {
up.Store(ctx, isClient, true)
}
Expand Down
88 changes: 88 additions & 0 deletions pkg/networkservice/mechanisms/memif/memifrxmode/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright (c) 2022 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

package memifrxmode

import (
"context"

"github.com/pkg/errors"
"google.golang.org/grpc"

"github.com/golang/protobuf/ptypes/empty"

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

memifMech "github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/memif"
"github.com/networkservicemesh/sdk/pkg/networkservice/core/next"
"github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata"
"github.com/networkservicemesh/sdk/pkg/tools/postpone"

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

type memifrxmodeClient struct {
chainCtx context.Context
vppConn Connection
}

// NewClient provides a NetworkServiceClient chain elements that support the memif Mechanism
func NewClient(chainCtx context.Context, vppConn Connection) networkservice.NetworkServiceClient {
return &memifrxmodeClient{
chainCtx: chainCtx,
vppConn: vppConn,
}
}

func (m *memifrxmodeClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (*networkservice.Connection, error) {
postponeCtxFunc := postpone.ContextWithValues(ctx)

conn, err := next.Client(ctx).Request(ctx, request, opts...)
if err != nil {
return nil, err
}
if mechanism := memifMech.ToMechanism(conn.GetMechanism()); mechanism == nil {
return conn, err
}

if ok := load(ctx, metadata.IsClient(m)); !ok {
swIfIndex, _ := ifindex.Load(ctx, metadata.IsClient(m))

cancelCtx, cancel := context.WithCancel(m.chainCtx)
store(ctx, metadata.IsClient(m), cancel)

if err := setRxMode(cancelCtx, m.vppConn, swIfIndex); err != nil {
closeCtx, cancelClose := postponeCtxFunc()
defer cancelClose()

if _, closeErr := m.Close(closeCtx, conn, opts...); closeErr != nil {
err = errors.Wrapf(err, "connection closed with error: %s", closeErr.Error())
}

return nil, err
}
}
return conn, nil
}

func (m *memifrxmodeClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*empty.Empty, error) {
if oldCancel, loaded := loadAndDelete(ctx, metadata.IsClient(m)); loaded {
oldCancel()
}
return next.Client(ctx).Close(ctx, conn, opts...)
}
86 changes: 86 additions & 0 deletions pkg/networkservice/mechanisms/memif/memifrxmode/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright (c) 2022 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

package memifrxmode

import (
"context"
"time"

"git.fd.io/govpp.git/api"

interfaces "github.com/edwarnicke/govpp/binapi/interface"
"github.com/edwarnicke/govpp/binapi/interface_types"

"github.com/networkservicemesh/sdk/pkg/tools/log"
)

// Connection aggregates the api.Connection and api.ChannelProvider interfaces
type Connection interface {
api.Connection
api.ChannelProvider
}

func setRxMode(ctx context.Context, vppConn Connection, swIfIndex interface_types.InterfaceIndex) error {
apiChannel, err := vppConn.NewAPIChannelBuffered(256, 256)
if err != nil {
return err
}

notifCh := make(chan api.Message, 256)
subscription, err := apiChannel.SubscribeNotification(notifCh, &interfaces.SwInterfaceEvent{})
if err != nil {
return err
}

go func() {
defer apiChannel.Close()
defer func() { _ = subscription.Unsubscribe() }()
for {
select {
case <-ctx.Done():
return
case rawMsg := <-notifCh:
if msg, ok := rawMsg.(*interfaces.SwInterfaceEvent); ok &&
msg.SwIfIndex == swIfIndex &&
msg.Flags&interface_types.IF_STATUS_API_FLAG_LINK_UP != 0 {
now := time.Now()
_, err = interfaces.NewServiceClient(vppConn).SwInterfaceSetRxMode(ctx, &interfaces.SwInterfaceSetRxMode{
SwIfIndex: swIfIndex,
Mode: interface_types.RX_MODE_API_ADAPTIVE,
})
if err != nil {
log.FromContext(ctx).
WithField("swIfIndex", swIfIndex).
WithField("mode", interface_types.RX_MODE_API_ADAPTIVE).
WithField("duration", time.Since(now)).
WithField("vppapi", "SwInterfaceSetRxMode").Debugf("error: %v", err.Error())
return
}
log.FromContext(ctx).
WithField("swIfIndex", swIfIndex).
WithField("mode", interface_types.RX_MODE_API_ADAPTIVE).
WithField("duration", time.Since(now)).
WithField("vppapi", "SwInterfaceSetRxMode").Debug("completed")
return
}
}
}
}()
return nil
}
18 changes: 18 additions & 0 deletions pkg/networkservice/mechanisms/memif/memifrxmode/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) 2022 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 memifrxmode provides a NetworkService chain elements to set ADAPTIVE rx mode for memif interfaces
package memifrxmode
54 changes: 54 additions & 0 deletions pkg/networkservice/mechanisms/memif/memifrxmode/metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) 2020-2022 Cisco and/or its affiliates.
//
// Copyright (c) 2021-2022 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.

//go:build linux

package memifrxmode

import (
"context"

"github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata"
)

type key struct{}

// store sets the context.CancelFunc stored in per Connection.Id metadata.
func store(ctx context.Context, isClient bool, cancel context.CancelFunc) {
metadata.Map(ctx, isClient).Store(key{}, cancel)
}

// loadAndDelete deletes the context.CancelFunc stored in per Connection.Id metadata.
func loadAndDelete(ctx context.Context, isClient bool) (value context.CancelFunc, ok bool) {
rawValue, ok := metadata.Map(ctx, isClient).LoadAndDelete(key{})
if !ok {
return
}
value, ok = rawValue.(context.CancelFunc)
return value, ok
}

// load returns the context.CancelFunc stored in per Connection.Id metadata.
func load(ctx context.Context, isClient bool) (ok bool) {
rawValue, ok := metadata.Map(ctx, isClient).Load(key{})
if !ok {
return
}
_, ok = rawValue.(context.CancelFunc)
return ok
}
Loading