From c3d90d84b1a96fb297253268b9c7c42ae126a50d Mon Sep 17 00:00:00 2001 From: Laszlo Kiraly Date: Tue, 8 Mar 2022 15:19:59 +0100 Subject: [PATCH] Set the same MTU for the NSC internal interface as the base interface has Closes: #514 Signed-off-by: Laszlo Kiraly --- .../connectioncontext/mtu/common.go | 6 ++ pkg/networkservice/mechanisms/vlan/client.go | 4 +- .../mechanisms/vlan/mtu/client.go | 86 +++++++++++++++++++ .../mechanisms/vlan/mtu/common.go | 51 +++++++++++ pkg/networkservice/mechanisms/vlan/mtu/doc.go | 18 ++++ pkg/networkservice/mechanisms/vlan/mtu/gen.go | 26 ++++++ .../mechanisms/vlan/mtu/mtu_map.gen.go | 75 ++++++++++++++++ 7 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 pkg/networkservice/mechanisms/vlan/mtu/client.go create mode 100644 pkg/networkservice/mechanisms/vlan/mtu/common.go create mode 100644 pkg/networkservice/mechanisms/vlan/mtu/doc.go create mode 100644 pkg/networkservice/mechanisms/vlan/mtu/gen.go create mode 100644 pkg/networkservice/mechanisms/vlan/mtu/mtu_map.gen.go diff --git a/pkg/networkservice/connectioncontext/mtu/common.go b/pkg/networkservice/connectioncontext/mtu/common.go index c755bbd8..a9daea0d 100644 --- a/pkg/networkservice/connectioncontext/mtu/common.go +++ b/pkg/networkservice/connectioncontext/mtu/common.go @@ -1,5 +1,7 @@ // Copyright (c) 2021 Cisco and/or its affiliates. // +// Copyright (c) 2022 Nordix Foundation. +// // SPDX-License-Identifier: Apache-2.0 // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,6 +24,7 @@ import ( "git.fd.io/govpp.git/api" interfaces "github.com/edwarnicke/govpp/binapi/interface" + "github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/vlan" "github.com/networkservicemesh/sdk/pkg/tools/log" "github.com/pkg/errors" @@ -35,6 +38,9 @@ const ( ) func setVPPL2MTU(ctx context.Context, conn *networkservice.Connection, vppConn api.Connection, isClient bool) error { + if vlan.ToMechanism(conn.GetMechanism()) != nil { + return nil + } now := time.Now() swIfIndex, ok := ifindex.Load(ctx, isClient) if !ok || conn.GetContext().GetMTU() == 0 { diff --git a/pkg/networkservice/mechanisms/vlan/client.go b/pkg/networkservice/mechanisms/vlan/client.go index 66f5c761..f6870a3b 100644 --- a/pkg/networkservice/mechanisms/vlan/client.go +++ b/pkg/networkservice/mechanisms/vlan/client.go @@ -1,4 +1,4 @@ -// Copyright (c) 2021 Nordix Foundation. +// Copyright (c) 2021-2022 Nordix Foundation. // // SPDX-License-Identifier: Apache-2.0 // @@ -34,6 +34,7 @@ import ( "github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/vlan/hwaddress" "github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/vlan/l2vtr" + "github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/vlan/mtu" ) const ( @@ -49,6 +50,7 @@ type vlanClient struct { func NewClient(vppConn api.Connection, domain2Device map[string]string) networkservice.NetworkServiceClient { return chain.NewNetworkServiceClient( hwaddress.NewClient(vppConn), + mtu.NewClient(vppConn), l2vtr.NewClient(vppConn), &vlanClient{ vppConn: vppConn, diff --git a/pkg/networkservice/mechanisms/vlan/mtu/client.go b/pkg/networkservice/mechanisms/vlan/mtu/client.go new file mode 100644 index 00000000..0a269a02 --- /dev/null +++ b/pkg/networkservice/mechanisms/vlan/mtu/client.go @@ -0,0 +1,86 @@ +// Copyright (c) 2022 Nordix Foundation. +// +// 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 mtu + +import ( + "context" + + "git.fd.io/govpp.git/api" + "google.golang.org/grpc" + "google.golang.org/protobuf/types/known/emptypb" + + "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/pkg/errors" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + "github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/vlan" + + "github.com/networkservicemesh/sdk-vpp/pkg/tools/ifindex" +) + +type mtuClient struct { + vppConn api.Connection + mtu mtuMap +} + +// NewClient - returns client chain element to manage vlan MTU +func NewClient(vppConn api.Connection) networkservice.NetworkServiceClient { + return &mtuClient{ + vppConn: vppConn, + } +} + +func (m *mtuClient) 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 + } + swIfIndex, ok := ifindex.Load(ctx, metadata.IsClient(m)) + if !ok { + return conn, nil + } + if mechanism := vlan.ToMechanism(conn.GetMechanism()); mechanism != nil { + localMtu, loaded := m.mtu.Load(swIfIndex) + if !loaded { + localMtu, err = getMTU(ctx, m.vppConn, swIfIndex) + if err != nil { + closeCtx, cancelClose := postponeCtxFunc() + defer cancelClose() + if _, closeErr := m.Close(closeCtx, conn); closeErr != nil { + err = errors.Wrapf(err, "connection closed with error: %s", closeErr.Error()) + } + return nil, err + } + m.mtu.Store(swIfIndex, localMtu) + } + if conn.GetContext().GetMTU() > localMtu || conn.GetContext().GetMTU() == 0 { + if conn.GetContext() == nil { + conn.Context = &networkservice.ConnectionContext{} + } + conn.GetContext().MTU = localMtu + } + } + return conn, nil +} + +func (m *mtuClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*emptypb.Empty, error) { + return next.Client(ctx).Close(ctx, conn, opts...) +} diff --git a/pkg/networkservice/mechanisms/vlan/mtu/common.go b/pkg/networkservice/mechanisms/vlan/mtu/common.go new file mode 100644 index 00000000..1ae02d9a --- /dev/null +++ b/pkg/networkservice/mechanisms/vlan/mtu/common.go @@ -0,0 +1,51 @@ +// Copyright (c) 2022 Nordix Foundation. +// +// 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 mtu + +import ( + "context" + "time" + + "git.fd.io/govpp.git/api" + "github.com/pkg/errors" + + interfaces "github.com/edwarnicke/govpp/binapi/interface" + "github.com/edwarnicke/govpp/binapi/interface_types" + "github.com/networkservicemesh/sdk/pkg/tools/log" +) + +func getMTU(ctx context.Context, vppConn api.Connection, swIfIndex interface_types.InterfaceIndex) (uint32, error) { + now := time.Now() + dc, err := interfaces.NewServiceClient(vppConn).SwInterfaceDump(ctx, &interfaces.SwInterfaceDump{ + SwIfIndex: swIfIndex, + }) + if err != nil { + return 0, errors.Wrapf(err, "error attempting to get interface dump client to determine MTU for swIfIndex %d", swIfIndex) + } + defer func() { _ = dc.Close() }() + + details, err := dc.Recv() + if err != nil { + return 0, errors.Wrapf(err, "error attempting to get interface details to determine MTU for swIfIndex %d", swIfIndex) + } + log.FromContext(ctx). + WithField("swIfIndex", swIfIndex). + WithField("details.LinkMtu", details.LinkMtu). + WithField("duration", time.Since(now)). + WithField("vppapi", "SwInterfaceDump").Debug("completed") + return uint32(details.LinkMtu), nil +} diff --git a/pkg/networkservice/mechanisms/vlan/mtu/doc.go b/pkg/networkservice/mechanisms/vlan/mtu/doc.go new file mode 100644 index 00000000..5fcfafce --- /dev/null +++ b/pkg/networkservice/mechanisms/vlan/mtu/doc.go @@ -0,0 +1,18 @@ +// Copyright (c) 2022 Nordix Foundation. +// +// 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 mtu computes the mtu for the vlan interface and adds it to context +package mtu diff --git a/pkg/networkservice/mechanisms/vlan/mtu/gen.go b/pkg/networkservice/mechanisms/vlan/mtu/gen.go new file mode 100644 index 00000000..f5c487ba --- /dev/null +++ b/pkg/networkservice/mechanisms/vlan/mtu/gen.go @@ -0,0 +1,26 @@ +// Copyright (c) 2022 Nordix Foundation. +// +// 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 mtu + +import ( + "sync" +) + +//go:generate go-syncmap -output mtu_map.gen.go -type mtuMap + +// mtuMap - sync.Map with key type interface_types.InterfaceIndex value of int index +type mtuMap sync.Map diff --git a/pkg/networkservice/mechanisms/vlan/mtu/mtu_map.gen.go b/pkg/networkservice/mechanisms/vlan/mtu/mtu_map.gen.go new file mode 100644 index 00000000..429cb0f1 --- /dev/null +++ b/pkg/networkservice/mechanisms/vlan/mtu/mtu_map.gen.go @@ -0,0 +1,75 @@ +// Code generated by "-output mtu_map.gen.go -type mtuMap -output mtu_map.gen.go -type mtuMap"; DO NOT EDIT. +package mtu + +import ( + "sync" // Used by sync.Map. + + "github.com/edwarnicke/govpp/binapi/interface_types" +) + +// Generate code that will fail if the constants change value. +func _() { + // An "cannot convert mtuMap literal (type mtuMap) to type sync.Map" compiler error signifies that the base type have changed. + // Re-run the go-syncmap command to generate them again. + _ = (sync.Map)(mtuMap{}) +} + +var _nil_mtuMap_uint32_value = func() (val uint32) { return }() + +// Load returns the value stored in the map for a key, or nil if no +// value is present. +// The ok result indicates whether value was found in the map. +func (m *mtuMap) Load(key interface_types.InterfaceIndex) (uint32, bool) { + value, ok := (*sync.Map)(m).Load(key) + if value == nil { + return _nil_mtuMap_uint32_value, ok + } + return value.(uint32), ok +} + +// Store sets the value for a key. +func (m *mtuMap) Store(key interface_types.InterfaceIndex, value uint32) { + (*sync.Map)(m).Store(key, value) +} + +// LoadOrStore returns the existing value for the key if present. +// Otherwise, it stores and returns the given value. +// The loaded result is true if the value was loaded, false if stored. +func (m *mtuMap) LoadOrStore(key interface_types.InterfaceIndex, value uint32) (uint32, bool) { + actual, loaded := (*sync.Map)(m).LoadOrStore(key, value) + if actual == nil { + return _nil_mtuMap_uint32_value, loaded + } + return actual.(uint32), loaded +} + +// LoadAndDelete deletes the value for a key, returning the previous value if any. +// The loaded result reports whether the key was present. +func (m *mtuMap) LoadAndDelete(key interface_types.InterfaceIndex) (value uint32, loaded bool) { + actual, loaded := (*sync.Map)(m).LoadAndDelete(key) + if actual == nil { + return _nil_mtuMap_uint32_value, loaded + } + return actual.(uint32), loaded +} + +// Delete deletes the value for a key. +func (m *mtuMap) Delete(key interface_types.InterfaceIndex) { + (*sync.Map)(m).Delete(key) +} + +// Range calls f sequentially for each key and value present in the map. +// If f returns false, range stops the iteration. +// +// Range does not necessarily correspond to any consistent snapshot of the Map's +// contents: no key will be visited more than once, but if the value for any key +// is stored or deleted concurrently, Range may reflect any mapping for that key +// from any point during the Range call. +// +// Range may be O(N) with the number of elements in the map even if f returns +// false after a constant number of calls. +func (m *mtuMap) Range(f func(key interface_types.InterfaceIndex, value uint32) bool) { + (*sync.Map)(m).Range(func(key, value interface{}) bool { + return f(key.(interface_types.InterfaceIndex), value.(uint32)) + }) +}