cli

package
v0.0.0-...-7b3c993 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 14, 2022 License: MIT Imports: 15 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var BaseTcpCommand = &CommandProducer{
	Base: &cobra.Command{
		Use:   "tcp",
		Short: "Measures tcp-related timings and outliers",
	},
	TimeVisitor: func(ctx *VisitorContext, cmd *cobra.Command, commonOpts *skbtrace.TimeCommonOptions) {
		var opts tcpOptions
		RegisterInterfaceOptions(ctx, cmd, &opts.filterOpts)
		registerTcpOptions(cmd.PersistentFlags(), &opts)

		ctx.AddPreRun(cmd, func(cmd *cobra.Command, args []string) error {
			var extraKeys []string
			if cmd.Use == "retransmit" {
				extraKeys = tcpExtraKeysRetransmit
			}
			return buildTcpTimeOptions(&opts, commonOpts, extraKeys)
		})
	},
	Children: []*CommandProducer{
		TcpHandshakeCommand,
		TcpLifetimeCommand,
		TcpRetransmitsCommand,
	},
}
View Source
var CommonAggregateCommand = &CommandProducer{
	Base: &cobra.Command{
		Use:     "aggregate -P PROBE... -f FUNC [-a ARG] -k KEYS [INTERVAL]",
		Example: "aggregate -6 -P xmit -i eth1 -F 'inner-src == 2a02:6b8:...' -k outer-dst 2s",
		Short:   "Aggregates probe firings by specified set of keys",
		Aliases: []string{"aggr"},
		Args:    cobra.RangeArgs(0, 1),
	},

	TracerVisitor: &AggregateTracerCommand{
		Visitor: func(ctx *VisitorContext, cmd *cobra.Command, opts *skbtrace.TraceAggregateOptions) {
			flags := cmd.Flags()
			RegisterAggregateOptions(flags, opts)
			RegisterAggregateCommonOptions(flags, &opts.AggregateCommonOptions)
			RegisterTimeIntervalArg(ctx, cmd, &opts.Interval)
		},
	},
}
View Source
var CommonDumpTracerCommand = &CommandProducer{
	Base: &cobra.Command{
		Use:     "dump -P PROBE...",
		Example: "dump -6 -P free -F 'dst == 2a02:6b8:...' -K -o ipv6",
		Short:   "Prints requested rows each time probe is fired",
	},
	TracerVisitor: &DumpTracerCommand{
		Visitor: func(ctx *VisitorContext, cmd *cobra.Command, opts *skbtrace.TraceDumpOptions) {
			RegisterCommonDumpOptions(cmd.Flags(), &opts.CommonDumpOptions)
		},
	},
}
View Source
var CommonDuplicateCommand = &CommandProducer{
	Base: &cobra.Command{
		Use:     "duplicate",
		Short:   "Dumps objects when hit twice with the same set of keys",
		Aliases: []string{"dup"},
	},
	CommonVisitor: func(ctx *VisitorContext, cmd *cobra.Command, commonOpts *skbtrace.CommonOptions) {
		var opts skbtrace.DuplicateEventOptions
		PassCommonOptions(ctx, cmd, &opts.CommonOptions, commonOpts)

		flags := cmd.Flags()
		RegisterCommonDumpOptions(flags, &opts.CommonDumpOptions)
		flags.BoolVar(&opts.Exit, "exit", false,
			"exit after dumping first outlier.")

		cmd.Run = NewRun(ctx, func() (*skbtrace.Program, error) {
			return ctx.Builder.BuildDuplicateEvent(opts)
		})
	},
}
View Source
var CommonTimeItFromCommand = &CommandProducer{
	Base: &cobra.Command{
		Use:   "timeit",
		Short: "Measures time delta between two distinct events 'from' and 'to'",
	},
	TimeVisitor: func(ctx *VisitorContext, cmd *cobra.Command, opts *skbtrace.TimeCommonOptions) {

	},
	Children: []*CommandProducer{
		timeItFromCommand,
		ForwardCommand,
		BaseTcpCommand,
	},
}
View Source
var FieldsCommand = &CommandProducer{
	Base: &cobra.Command{
		Use:   "fields [ROW]",
		Short: "Shows list of known fields",
	},

	InfoVisitor: func(ctx *VisitorContext, cmd *cobra.Command) {
		cmd.Run = func(cmd *cobra.Command, args []string) {
			fieldGroups := ctx.Builder.FieldGroups()

			tw := tablewriter.NewWriter(ctx.Dependencies.Output())
			tw.SetHeader([]string{"ROW", "OBJECT", "FIELD", "KEY", "HELP"})
			tw.SetAutoMergeCells(true)
			tw.SetColWidth(80)
			tw.SetColMinWidth(4, 60)
			tw.SetRowLine(true)
			for _, fg := range fieldGroups {
				if fg.BaseFieldGroup != "" {
					help := fmt.Sprintf("Same fields as in %s (%s)", fg.Row, fg.Object)
					if fg.FieldAliasPrefix != "" {
						help = fmt.Sprintf("%s. Field aliases use prefix %s-*",
							help, fg.FieldAliasPrefix)
					}

					row := []string{
						fg.Row, fg.Object, "", "", help,
					}
					tw.Append(row)
					continue
				}

				for _, field := range fg.Fields {
					fieldName := field.Name
					if field.Alias != "" {
						fieldName = fmt.Sprintf("%s (%s)", field.Alias, fieldName)
					}

					row := []string{
						fg.Row, fg.Object, fieldName, field.FmtKey, field.Help,
					}
					tw.Append(row)
				}
			}
			tw.Render()
		}
	},
}
View Source
var ForwardCommand = &CommandProducer{
	Base: &cobra.Command{
		Use:     "forward {{--ingress|--egress} -i ITF|-i INITF -i OUTITF} [OPTIONS]",
		Example: "forward --ingress -i tapxx-0 -6",
		Short:   "Measures time spent forwarding a packet from ingress interface to egress interface",
	},
	TimeVisitor: func(ctx *VisitorContext, cmd *cobra.Command, opts *skbtrace.TimeCommonOptions) {
		var fwdOpts forwardOptions
		registerForwardOptions(cmd.PersistentFlags(), &fwdOpts)

		ctx.AddPreRun(cmd, func(cmd *cobra.Command, args []string) error {
			err := handleForwardFiltersInterface(ctx, &opts.FromSpec, skb.ProbeRecv,
				&opts.CommonOptions, &fwdOpts)
			if err != nil {
				return err
			}
			return handleForwardFiltersInterface(ctx, &opts.ToSpec, skb.ProbeXmit,
				&opts.CommonOptions, &fwdOpts)
		})

		cmd.Run = NewDefaultAggregateRun(ctx, opts)
	},
	Children: DefaultTimeSubcommands,
}
View Source
var ProbesCommand = &CommandProducer{
	Base: &cobra.Command{
		Use:   "probes",
		Short: "Shows list of known probes",
	},

	InfoVisitor: func(ctx *VisitorContext, cmd *cobra.Command) {
		cmd.Run = func(cmd *cobra.Command, args []string) {
			probes := ctx.Builder.Probes()

			tw := tablewriter.NewWriter(ctx.Dependencies.Output())
			tw.SetHeader([]string{"PROBE", "ARGS", "HELP"})
			tw.SetColWidth(80)
			tw.SetColMinWidth(2, 60)
			for _, probe := range probes {
				row := make([]string, 3)

				if len(probe.Aliases) == 0 {
					row[0] = probe.Name
				} else {
					row[0] = fmt.Sprintf("%s (%s)", probe.Aliases[0],
						strings.Join(append(probe.Aliases[1:], probe.Name), ", "))
				}

				var argNames []string
				for arg, obj := range probe.Args {
					argNames = append(argNames, fmt.Sprintf("%s(%s)", arg, obj))
				}
				row[1] = strings.Join(argNames, ", ")

				row[2] = probe.Help
				tw.Append(row)
			}
			tw.Render()
		}
	},
}
View Source
var RootCommand = CommandProducer{
	Base: &cobra.Command{
		Use:   "skbtrace",
		Short: rootShortHelp,
		Long:  rootHelp,
	},
	Children: []*CommandProducer{
		CommonDumpTracerCommand,
		CommonAggregateCommand,
		CommonTimeItFromCommand,
		CommonDuplicateCommand,
		ProbesCommand,
		FieldsCommand,
	},
}
View Source
var TcpHandshakeCommand = &CommandProducer{
	Base: &cobra.Command{
		Use:     "handshake {--inbound|--outbound} [--underlay] -i ITF",
		Example: "handshake --inbound -i tapxx-0 -6",
		Short:   "Measures time for TCP handshake",
	},
	TimeVisitor: func(ctx *VisitorContext, cmd *cobra.Command, opts *skbtrace.TimeCommonOptions) {
		ctx.AddPreRun(cmd, func(cmd *cobra.Command, args []string) error {
			opts.FromSpec.RawFilters = append(opts.FromSpec.RawFilters, "tcp-flags == S")
			opts.ToSpec.RawFilters = append(opts.ToSpec.RawFilters, "tcp-flags == A")
			return nil
		})
		cmd.Run = NewDefaultAggregateRun(ctx, opts)
	},
	Children: DefaultTimeSubcommands,
}
View Source
var TcpLifetimeCommand = &CommandProducer{
	Base: &cobra.Command{
		Use:   "lifetime {--inbound|--outbound}",
		Short: "Measures TCP connection lifetime from SYN to FIN/RST in the same direction",
	},
	TimeVisitor: func(ctx *VisitorContext, cmd *cobra.Command, opts *skbtrace.TimeCommonOptions) {
		ctx.AddPreRun(cmd, func(cmd *cobra.Command, args []string) error {
			opts.FromSpec.RawFilters = append(opts.FromSpec.RawFilters, "tcp-flags == S")
			opts.ToSpec.RawFilters = append(opts.ToSpec.RawFilters, "tcp-flags == F|FA|R")
			return nil
		})

		cmd.Run = NewDefaultAggregateRun(ctx, opts)
	},
	Children: DefaultTimeSubcommands,
}
View Source
var TcpRetransmitsCommand = &CommandProducer{
	Base: &cobra.Command{
		Use:   "retransmit",
		Short: "Detects duplicate packets",
	},
	TimeVisitor: func(ctx *VisitorContext, cmd *cobra.Command, commonOpts *skbtrace.TimeCommonOptions) {
		var opts skbtrace.DuplicateEventOptions
		RegisterCommonDumpOptions(cmd.Flags(), &opts.CommonDumpOptions)

		ctx.AddPreRun(cmd, func(cmd *cobra.Command, args []string) error {
			opts.CommonOptions = commonOpts.CommonOptions
			opts.Spec = commonOpts.FromSpec
			opts.Spec.Keys = append(opts.Spec.Keys, tcpExtraKeysRetransmit...)
			return nil
		})

		cmd.Run = NewRun(ctx, func() (*skbtrace.Program, error) {
			return ctx.Builder.BuildDuplicateEvent(opts)
		})
	},
}
View Source
var TimeAggregateCommand = &CommandProducer{
	Base: &cobra.Command{
		Use:     "aggregate [-f FUNC] [INTERVAL]",
		Aliases: []string{"aggr"},
		Short:   "Aggregates time delta using specified function",
		Args:    cobra.RangeArgs(0, 1),
	},
	TimeVisitor: func(ctx *VisitorContext, cmd *cobra.Command, commonOpts *skbtrace.TimeCommonOptions) {
		opts := skbtrace.TimeAggregateOptions{
			AggregateCommonOptions: skbtrace.AggregateCommonOptions{
				Interval: time.Second,
			},
			Func: skbtrace.AFHist,
		}

		flags := cmd.Flags()
		RegisterTimeIntervalArg(ctx, cmd, &opts.Interval)
		RegisterAggregateCommonOptions(flags, &opts.AggregateCommonOptions)
		PassTimeCommonOptions(ctx, cmd, &opts.TimeCommonOptions, commonOpts)

		cmd.Run = NewRun(ctx, func() (*skbtrace.Program, error) {
			return ctx.Builder.BuildTimeAggregate(opts)
		})
	},
}
View Source
var TimeEventCountSubcommand = &CommandProducer{
	Base: &cobra.Command{
		Use:   "evcount",
		Short: "Counts each time from or to probe is hit. Useful for testing filters.",
	},
	TimeVisitor: func(ctx *VisitorContext, cmd *cobra.Command, commonOpts *skbtrace.TimeCommonOptions) {
		cmd.Run = NewRun(ctx, func() (*skbtrace.Program, error) {
			return ctx.Builder.BuildTimeEventCount(*commonOpts)
		})
	},
}
View Source
var TimeOutlierDumpSubcommand = &CommandProducer{
	Base: &cobra.Command{
		Use:   "outliers -t THRESHOLD",
		Short: "Dumps structures that exceed specified threshold",
	},
	TimeVisitor: func(ctx *VisitorContext, cmd *cobra.Command, commonOpts *skbtrace.TimeCommonOptions) {
		var opts skbtrace.TimeOutlierDumpOptions
		PassTimeCommonOptions(ctx, cmd, &opts.TimeCommonOptions, commonOpts)

		flags := cmd.Flags()
		RegisterCommonDumpOptions(flags, &opts.CommonDumpOptions)
		flags.DurationVarP(&opts.OutlierThreshold, "threshold", "t",
			100*time.Millisecond,
			"Threshold for time delta. If hit, probe firing is considered an outlier.")
		flags.BoolVar(&opts.Exit, "exit", false,
			"Exit after dumping first outlier.")

		cmd.Run = NewRun(ctx, func() (*skbtrace.Program, error) {
			return ctx.Builder.BuildTimeOutlierDump(opts)
		})
	},
}

Functions

func CommonTimeItVisitor

func CommonTimeItVisitor(
	ctx *VisitorContext, cmd *cobra.Command, specPtr *skbtrace.TimeSpec,
)

func NewDeviceFilter

func NewDeviceFilter(itfName string) *skbtrace.Filter

func PassCommonOptions

func PassCommonOptions(ctx *VisitorContext, cmd *cobra.Command, dst, src *skbtrace.CommonOptions)

func PassTimeCommonOptions

func PassTimeCommonOptions(ctx *VisitorContext, cmd *cobra.Command, dst, src *skbtrace.TimeCommonOptions)

func PassTraceCommonOptions

func PassTraceCommonOptions(
	ctx *VisitorContext, cmd *cobra.Command, dst, src *skbtrace.TraceCommonOptions,
)

func RegisterAggregateCommonOptions

func RegisterAggregateCommonOptions(flags *pflag.FlagSet, opts *skbtrace.AggregateCommonOptions)

func RegisterAggregateOptions

func RegisterAggregateOptions(flags *pflag.FlagSet, opts *skbtrace.TraceAggregateOptions)

func RegisterCommonDumpOptions

func RegisterCommonDumpOptions(flags *pflag.FlagSet, opt *skbtrace.CommonDumpOptions)

func RegisterFilterOptions

func RegisterFilterOptions(flags *pflag.FlagSet, options *skbtrace.FilterOptions)

func RegisterInterfaceOptions

func RegisterInterfaceOptions(
	ctx *VisitorContext, cmd *cobra.Command, options *skbtrace.FilterOptions,
)

func RegisterTimeIntervalArg

func RegisterTimeIntervalArg(ctx *VisitorContext, cmd *cobra.Command, interval *time.Duration)

func RegisterTracerContextOptions

func RegisterTracerContextOptions(flags *pflag.FlagSet, opts *skbtrace.TraceCommonOptions)

func RegisterTracerProbeOptions

func RegisterTracerProbeOptions(flags *pflag.FlagSet, opts *skbtrace.TraceCommonOptions)

Types

type AggregateTracerCommand

type AggregateTracerCommand struct {
	Visitor func(ctx *VisitorContext, cmd *cobra.Command, opts *skbtrace.TraceAggregateOptions)
}

func (*AggregateTracerCommand) Visit

func (dumper *AggregateTracerCommand) Visit(
	ctx *VisitorContext, cmd *cobra.Command,
	commonOpts *skbtrace.TraceCommonOptions,
)

type CommandBuilder

type CommandBuilder func() (*skbtrace.Program, error)

type CommandProducer

type CommandProducer struct {
	Base     *cobra.Command
	Children []*CommandProducer

	InfoVisitor   func(ctx *VisitorContext, cmd *cobra.Command)
	CommonVisitor func(ctx *VisitorContext, cmd *cobra.Command, opts *skbtrace.CommonOptions)
	TracerVisitor TracerCommandVisitor
	TimeVisitor   func(ctx *VisitorContext, cmd *cobra.Command, opts *skbtrace.TimeCommonOptions)
}

CommandProducer workarounds cobra limitations, specifically:

  • lack of ability to inject parsed data structures (and tending to use global structures)
  • "persistent" methods are being inherited, but overridden, wherever skbtrace requires a combination of both.

To avoid that, each node in CommandProducer tree implements one of the *Visitor methods which receives:

  • current visitor context including some global options
  • command to register options, pre-run and run methods
  • pointer to most-specific set of options (not filled yet, as parsing is done on command execution).

Each Visitor method might produce even more specific options structure and link another pre-run function that will copy options parsed by prior commands to it or even create unique options structure such as tcpOptions and process into raw TimeCommonOptions in pre-run. Note that all options processing is done in pre-run (so after argument parsing).

Finally, leaf CommandProducers register cmd.Run in their visitors adding real implementation to the command supplied.

func (*CommandProducer) NewRootCommand

func (root *CommandProducer) NewRootCommand(deps Dependencies) *cobra.Command

NewRootCommand creates a root command with all of its children rendered into cobra.Command structures.

type CommandRunFunc

type CommandRunFunc func(cmd *cobra.Command, args []string)

func NewDefaultAggregateRun

func NewDefaultAggregateRun(ctx *VisitorContext, commonOpts *skbtrace.TimeCommonOptions) CommandRunFunc

func NewRun

func NewRun(ctx *VisitorContext, builder CommandBuilder) CommandRunFunc

type Dependencies

type Dependencies interface {
	AddFlags(flags *pflag.FlagSet)
	Setup(ctx *VisitorContext)

	// Returns output for runner interface
	Output() io.Writer
	ErrorOutput() io.Writer

	// Exits command line in case of error
	Exit(code int)

	// PreprocessInterface preprocesses interface name specified by -i
	// to support alternative spellings such as container name automatically
	// converted to the linux device name
	PreprocessInterface(itfName string) (string, error)

	// GuessUnderlayDeviceFilters guesses which filters should be applied to
	// probe specification which are suitable for the interface, for example
	// multiple underlay interfaces with differing labels might exist
	GuessUnderlayDeviceFilters(itfName string) ([]*skbtrace.Filter, error)
}

type DumpTracerCommand

type DumpTracerCommand struct {
	Visitor func(ctx *VisitorContext, cmd *cobra.Command, opts *skbtrace.TraceDumpOptions)
}

func (*DumpTracerCommand) Visit

func (dumper *DumpTracerCommand) Visit(
	ctx *VisitorContext, cmd *cobra.Command,
	commonOpts *skbtrace.TraceCommonOptions,
)

type PreRunEChain

type PreRunEChain []PreRunEFunc

type PreRunEFunc

type PreRunEFunc func(cmd *cobra.Command, args []string) error

type TracerCommandVisitor

type TracerCommandVisitor interface {
	Visit(ctx *VisitorContext, cmd *cobra.Command, opts *skbtrace.TraceCommonOptions)
}

type VisitorContext

type VisitorContext struct {
	Builder      *skbtrace.Builder
	Dependencies Dependencies

	RunnerOptions skbtrace.RunnerOptions

	IsIPv6        bool
	EncapType     string
	StructKeyword string

	PreRunEChain PreRunEChain
}

func (*VisitorContext) AddPreRun

func (ctx *VisitorContext) AddPreRun(cmd *cobra.Command, impl PreRunEFunc)

func (*VisitorContext) Restore

func (ctx *VisitorContext) Restore(chain PreRunEChain)

func (*VisitorContext) Save

func (ctx *VisitorContext) Save() PreRunEChain

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL