Skip to content
This repository has been archived by the owner on Oct 16, 2024. It is now read-only.

Commit

Permalink
support for impl of offload pkt capturing
Browse files Browse the repository at this point in the history
  • Loading branch information
byteocean committed Nov 9, 2023
1 parent a178725 commit bb7833b
Show file tree
Hide file tree
Showing 9 changed files with 421 additions and 3 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea/**
bin/**
*.iml
*.iml
dpservice-cli
48 changes: 48 additions & 0 deletions cmd/capture.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2022 OnMetal authors
//
// 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 cmd

import (
"fmt"

"github.com/spf13/cobra"
)

func Capture(factory DPDKClientFactory) *cobra.Command {
rendererOptions := &RendererOptions{Output: "table"}

cmd := &cobra.Command{
Use: "capture",
Args: cobra.NoArgs,
RunE: SubcommandRequired,
}

rendererOptions.AddFlags(cmd.PersistentFlags())

subcommands := []*cobra.Command{
CaptureStart(factory, rendererOptions),
CaptureStop(factory, rendererOptions),
CaptureStatus(factory, rendererOptions),
}

cmd.Short = fmt.Sprintf("Gets one of %v", CommandNames(subcommands))
cmd.Long = fmt.Sprintf("Gets one of %v", CommandNames(subcommands))

cmd.AddCommand(
subcommands...,
)

return cmd
}
167 changes: 167 additions & 0 deletions cmd/capture_start.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
// Copyright 2022 OnMetal authors
//
// 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 cmd

import (
"context"
"fmt"
"net/netip"
"os"
"strconv"
"strings"

"github.com/onmetal/dpservice-cli/flag"
"github.com/onmetal/dpservice-cli/util"
"github.com/onmetal/net-dpservice-go/api"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

func CaptureStart(dpdkClientFactory DPDKClientFactory, rendererFactory RendererFactory) *cobra.Command {
var (
opts CaptureStartOptions
)

cmd := &cobra.Command{
Use: "start <--sink-node-ip> <--udp-src-port> <--udp-dst-port> [--pf] [--vf]",
Short: "Start capturing packets",
Example: "dpservice-cli capture start --sink-node-ip=fc00:2::64:0:1 --udp-src-port=30000 --udp-dst-port=30100 --pf=0(must be 0 due to hardware limitation) --vf=vm1,vm2,vm3",
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {

return RunCaptureStart(
cmd.Context(),
dpdkClientFactory,
rendererFactory,
opts,
)
},
}

opts.AddFlags(cmd.Flags())

util.Must(opts.MarkRequiredFlags(cmd))

return cmd
}

type CaptureStartOptions struct {
SinkNodeIP netip.Addr
UdpSrcPort uint32
UdpDstPort uint32
PfIndexString string
VfIndexString string
}

func (o *CaptureStartOptions) AddFlags(fs *pflag.FlagSet) {
flag.AddrVar(fs, &o.SinkNodeIP, "sink-node-ip", o.SinkNodeIP, "IP address of the sink node")
fs.Uint32Var(&o.UdpSrcPort, "udp-src-port", o.UdpSrcPort, "UDP source port")
fs.Uint32Var(&o.UdpDstPort, "udp-dst-port", o.UdpDstPort, "UDP destination port")
fs.StringVar(&o.PfIndexString, "pf", "", "PF index")
fs.StringVar(&o.VfIndexString, "vf", "", "VF index")
}

func (o *CaptureStartOptions) MarkRequiredFlags(cmd *cobra.Command) error {
for _, name := range []string{
"sink-node-ip",
"udp-src-port",
"udp-dst-port",
} {
if err := cmd.MarkFlagRequired(name); err != nil {
return err
}
}
return nil
}

func StringPFIndexToPFIndex(indexString string) ([]string, error) {
indexes := strings.Split(indexString, ",")

if len(indexes) > 2 {
return nil, fmt.Errorf("too many pf indexes specified")
}

for _, index := range indexes {
indexInt, err := strconv.Atoi(index)
if err != nil {
return nil, fmt.Errorf("error parsing pf index: %w", err)
}
if indexInt > 1 {
return nil, fmt.Errorf("pf index must be 0 or 1")
}
}

return indexes, nil
}

func StringVFIdToVFId(idString string) []string {
return strings.Split(idString, ",")
}

func RunCaptureStart(ctx context.Context, dpdkClientFactory DPDKClientFactory, rendererFactory RendererFactory, opts CaptureStartOptions) error {

dpdkClient, cleanup, err := dpdkClientFactory.NewClient(ctx)
if err != nil {
return fmt.Errorf("error creating dpdk client: %w", err)
}

defer DpdkClose(cleanup)

interfaces := make([]api.CaptureInterface, 0)

if opts.PfIndexString != "" {
pfIndexes, err := StringPFIndexToPFIndex(opts.PfIndexString)
if err != nil {
return fmt.Errorf("error converting PF indexes: %w", err)
}
for _, pfIndex := range pfIndexes {
interfaces = append(interfaces, api.CaptureInterface{
InterfaceType: "pf",
InterfaceInfo: pfIndex,
})
}
}

if opts.VfIndexString != "" {
vfIndexes := StringVFIdToVFId(opts.VfIndexString)

for _, vfIndex := range vfIndexes {
interfaces = append(interfaces, api.CaptureInterface{
InterfaceType: "vf",
InterfaceInfo: vfIndex,
})
}
}

capture, err := dpdkClient.CaptureStart(ctx, &api.CaptureStart{
TypeMeta: api.TypeMeta{Kind: api.CaptureStartKind},
CaptureStartMeta: api.CaptureStartMeta{
Config: &api.CaptureConfig{
SinkNodeIP: &opts.SinkNodeIP,
UdpSrcPort: opts.UdpSrcPort,
UdpDstPort: opts.UdpDstPort,
},
},
Spec: api.CaptureStartSpec{
Interfaces: interfaces,
},
})

if err != nil && capture.Status.Code == 0 {
return fmt.Errorf("error initializing packet capturing: %w", err)
}

return rendererFactory.RenderObject(fmt.Sprintf("Packet capturing initialized: %s\n", capture.CaptureStartMeta.Config.SinkNodeIP.String()), os.Stdout, capture)
}
65 changes: 65 additions & 0 deletions cmd/capture_status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2022 OnMetal authors
//
// 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 cmd

import (
"context"
"fmt"
"os"

"github.com/spf13/cobra"
)

func CaptureStatus(dpdkClientFactory DPDKClientFactory, rendererFactory RendererFactory) *cobra.Command {

cmd := &cobra.Command{
Use: "status",
Short: "Get the status of the packet capturing feature",
Example: "dpservice-cli capture status",
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {

return RunCaptureStatus(
cmd.Context(),
dpdkClientFactory,
rendererFactory,
)
},
}
return cmd
}

func RunCaptureStatus(
ctx context.Context,
dpdkClientFactory DPDKClientFactory,
rendererFactory RendererFactory,
) error {
client, cleanup, err := dpdkClientFactory.NewClient(ctx)
if err != nil {
return fmt.Errorf("error creating dpdk client: %w", err)
}
defer func() {
if err := cleanup(); err != nil {
fmt.Printf("Error cleaning up client: %v\n", err)
}
}()

capture, err := client.CaptureStatus(ctx)
if err != nil && capture.Status.Code == 0 {
return fmt.Errorf("error checking initialization status: %w", err)
}

return rendererFactory.RenderObject("", os.Stdout, capture)
}
60 changes: 60 additions & 0 deletions cmd/capture_stop.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2022 OnMetal authors
//
// 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 cmd

import (
"context"
"fmt"
"os"

"github.com/spf13/cobra"
)

func CaptureStop(dpdkClientFactory DPDKClientFactory, rendererFactory RendererFactory) *cobra.Command {

cmd := &cobra.Command{
Use: "stop",
Short: "Stop capturing packets for all interfaces",
Example: "dpservice-cli capture stop",
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {

return RunCaptureStop(
cmd.Context(),
dpdkClientFactory,
rendererFactory,
)
},
}
return cmd
}

func RunCaptureStop(ctx context.Context, dpdkClientFactory DPDKClientFactory, rendererFactory RendererFactory) error {

dpdkClient, cleanup, err := dpdkClientFactory.NewClient(ctx)
if err != nil {
return fmt.Errorf("error creating dpdk client: %w", err)
}

defer DpdkClose(cleanup)

captureStop, err := dpdkClient.CaptureStop(ctx)

if err != nil && captureStop.Status.Code == 0 {
return fmt.Errorf("error stopping capturing: %w", err)
}

return rendererFactory.RenderObject("Packet capturing stopped \n", os.Stdout, captureStop)
}
1 change: 1 addition & 0 deletions cmd/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func Command() *cobra.Command {
Delete(dpdkClientOptions),
Reset(dpdkClientOptions),
Init(dpdkClientOptions, rendererOptions),
Capture(dpdkClientOptions),
completionCmd,
)

Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ require (
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

replace github.com/onmetal/net-dpservice-go => github.com/onmetal/net-dpservice-go v0.1.20-0.20231109110702-c8ea585f14f0
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/onmetal/net-dpservice-go v0.1.18 h1:c4yFXzSa6i3L1JQHH18fmUv2S+mSL/guFNSGt65s2Yc=
github.com/onmetal/net-dpservice-go v0.1.18/go.mod h1:M7dg98Xx54qZqWMCWS5LUra3z0x459Pg4/l3F5He4Jk=
github.com/onmetal/net-dpservice-go v0.1.20-0.20231109110702-c8ea585f14f0 h1:KNMmUlA9p3alEbDCEQ6o+6rQEjW7fSjJ0wkaOJGEEKU=
github.com/onmetal/net-dpservice-go v0.1.20-0.20231109110702-c8ea585f14f0/go.mod h1:M7dg98Xx54qZqWMCWS5LUra3z0x459Pg4/l3F5He4Jk=
github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI=
github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
github.com/onsi/gomega v1.20.2 h1:8uQq0zMgLEfa0vRrrBgaJF2gyW9Da9BmfGV+OyUzfkY=
Expand Down
Loading

0 comments on commit bb7833b

Please sign in to comment.