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 afxdppinhole chain element #706

Merged
merged 1 commit into from
Apr 24, 2023
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
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.18

require (
git.fd.io/govpp.git v0.3.6-0.20210927044411-385ccc0d8ba9
github.com/cilium/ebpf v0.10.0
github.com/edwarnicke/govpp v0.0.0-20230130211138-14ef5d20b1d0
github.com/edwarnicke/serialize v1.0.7
github.com/golang/protobuf v1.5.2
Expand Down Expand Up @@ -40,7 +41,7 @@ require (
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
Expand Down
10 changes: 7 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cb
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/cilium/ebpf v0.10.0 h1:nk5HPMeoBXtOzbkZBWym+ZWq1GIiHUsBFXxwewXAHLQ=
github.com/cilium/ebpf v0.10.0/go.mod h1:DPiVdY/kT534dgc9ERmvP8mWA+9gvwgKfRvk4nNWnoE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
Expand Down Expand Up @@ -96,6 +98,7 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/foxcpp/go-mockdns v0.0.0-20210729171921-fb145fc6f897 h1:E52jfcE64UG42SwLmrW0QByONfGynWuzBvm86BoB9z8=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
Expand Down Expand Up @@ -160,8 +163,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
Expand Down Expand Up @@ -199,8 +202,8 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
Expand Down Expand Up @@ -238,6 +241,7 @@ github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5X
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
Expand Down
86 changes: 86 additions & 0 deletions pkg/networkservice/afxdppinhole/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright (c) 2023 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 afxdppinhole

import (
"context"
"os"
"path"

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

"github.com/golang/protobuf/ptypes/empty"
"github.com/networkservicemesh/api/pkg/api/networkservice"
"github.com/networkservicemesh/sdk/pkg/networkservice/core/next"
"github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata"
"github.com/networkservicemesh/sdk/pkg/tools/postpone"
)

type afxdppinholeClient struct {
elfPath string
bpfFSDir string
}

// NewClient - returns a new client that updates the UDP ports map for NSM interfaces
func NewClient(options ...Option) networkservice.NetworkServiceClient {
opts := &afxdpOptions{
elfPath: defaultElfPath,
bpfFSDir: defaultBpfFsDir,
}
for _, opt := range options {
opt(opts)
}
return &afxdppinholeClient{
elfPath: opts.elfPath,
bpfFSDir: opts.bpfFSDir,
}
}

func (c *afxdppinholeClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (*networkservice.Connection, error) {
// Check if we use af_xdp
if _, err := os.Stat(path.Join(c.bpfFSDir, defaultXDPPinholeMapName)); errors.Is(err, os.ErrNotExist) {
return next.Client(ctx).Request(ctx, request, opts...)
}

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

// Get UDP ports from the mechanism and context
keys := []uint16{
fromMechanism(conn.GetMechanism(), metadata.IsClient(c)),
fromContext(ctx, metadata.IsClient(c)),
}

if err = updateXdpPinhole(keys, c.elfPath, c.bpfFSDir); err != nil {
closeCtx, cancelClose := postponeCtxFunc()
defer cancelClose()
if _, closeErr := c.Close(closeCtx, conn, opts...); closeErr != nil {
err = errors.Wrapf(err, "connection closed with error: %s", closeErr.Error())
}
return nil, err
}

return conn, nil
}

func (c *afxdppinholeClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*empty.Empty, error) {
return next.Client(ctx).Close(ctx, conn, opts...)
}
89 changes: 89 additions & 0 deletions pkg/networkservice/afxdppinhole/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright (c) 2023 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 afxdppinhole

import (
"context"
"strconv"

"github.com/cilium/ebpf"
"github.com/networkservicemesh/api/pkg/api/networkservice"
"github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/common"

"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/pinhole"
)

type bpfObjects struct {
XdpPinhole *ebpf.Map `ebpf:"nsm_xdp_pinhole"`
}

func fromMechanism(mechanism *networkservice.Mechanism, isClient bool) uint16 {
if mechanism.GetParameters() == nil {
return 0
}
portKey := common.DstPort
if isClient {
portKey = common.SrcPort
}
portStr, ok := mechanism.GetParameters()[portKey]
if !ok {
return 0
}
port, err := strconv.ParseUint(portStr, 10, 16)
if err != nil {
return 0
}
return uint16(port)
}

func fromContext(ctx context.Context, isClient bool) uint16 {
v, ok := pinhole.LoadExtra(ctx, isClient)
if !ok {
return 0
}

return v.Port()
}

func updateXdpPinhole(keys []uint16, elfPath, bpfFSDir string) error {
for _, k := range keys {
if k == 0 {
continue
}
key := k
collectionSpec, err := ebpf.LoadCollectionSpec(elfPath)
if err != nil {
return err
}
objs := bpfObjects{}
err = collectionSpec.LoadAndAssign(&objs, &ebpf.CollectionOptions{
Maps: ebpf.MapOptions{
PinPath: bpfFSDir,
},
})
if err != nil {
return err
}

var val uint16
err = objs.XdpPinhole.Update(&key, &val, ebpf.UpdateAny)
if err != nil {
return err
}
}
return nil
}
19 changes: 19 additions & 0 deletions pkg/networkservice/afxdppinhole/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) 2023 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 afxdppinhole provides chain elements that updates the xdp pinhole map.
// This map is a list of UDP ports that the NSM is listening on (we take these values from the mechanisms)
package afxdppinhole
47 changes: 47 additions & 0 deletions pkg/networkservice/afxdppinhole/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) 2023 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 afxdppinhole

const (
defaultElfPath = "/bin/afxdp.o"
defaultBpfFsDir = "/sys/fs/bpf"
defaultXDPPinholeMapName = "nsm_xdp_pinhole"
)

type afxdpOptions struct {
// path to af_xdp object file
elfPath string
// BPF filesystem directory
bpfFSDir string
}

// Option is an option pattern for afxdppinhole chain elements
type Option func(o *afxdpOptions)

// WithElfPath sets the path of the ELF object file
func WithElfPath(p string) Option {
return func(o *afxdpOptions) {
o.elfPath = p
}
}

// WithBpfFsDir sets the dir of the BPF file system
func WithBpfFsDir(p string) Option {
return func(o *afxdpOptions) {
o.bpfFSDir = p
}
}
85 changes: 85 additions & 0 deletions pkg/networkservice/afxdppinhole/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright (c) 2023 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 afxdppinhole

import (
"context"
"os"
"path"

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

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

type afxdppinholeServer struct {
elfPath string
bpfFSDir string
}

// NewServer - returns a new client that updates the UDP ports map for NSM interfaces
func NewServer(options ...Option) networkservice.NetworkServiceServer {
opts := &afxdpOptions{
elfPath: defaultElfPath,
bpfFSDir: defaultBpfFsDir,
}
for _, opt := range options {
opt(opts)
}
return &afxdppinholeServer{
elfPath: opts.elfPath,
bpfFSDir: opts.bpfFSDir,
}
}

func (s *afxdppinholeServer) Request(ctx context.Context, request *networkservice.NetworkServiceRequest) (*networkservice.Connection, error) {
// Check if we use af_xdp
if _, err := os.Stat(path.Join(s.bpfFSDir, defaultXDPPinholeMapName)); errors.Is(err, os.ErrNotExist) {
return next.Server(ctx).Request(ctx, request)
}

postponeCtxFunc := postpone.ContextWithValues(ctx)
conn, err := next.Server(ctx).Request(ctx, request)
if err != nil {
return nil, err
}

// Get UDP ports from the mechanism and context
keys := []uint16{
fromMechanism(conn.GetMechanism(), metadata.IsClient(s)),
fromContext(ctx, metadata.IsClient(s)),
}

if err = updateXdpPinhole(keys, s.elfPath, s.bpfFSDir); err != nil {
closeCtx, cancelClose := postponeCtxFunc()
defer cancelClose()
if _, closeErr := s.Close(closeCtx, conn); closeErr != nil {
err = errors.Wrapf(err, "connection closed with error: %s", closeErr.Error())
}
return nil, err
}

return conn, nil
}

func (s *afxdppinholeServer) Close(ctx context.Context, conn *networkservice.Connection) (*empty.Empty, error) {
return next.Server(ctx).Close(ctx, conn)
}
Loading