Documentation ¶
Index ¶
- Variables
- func CommonTimeItVisitor(ctx *VisitorContext, cmd *cobra.Command, specPtr *skbtrace.TimeSpec)
- func NewDeviceFilter(itfName string) *skbtrace.Filter
- func PassCommonOptions(ctx *VisitorContext, cmd *cobra.Command, dst, src *skbtrace.CommonOptions)
- func PassTimeCommonOptions(ctx *VisitorContext, cmd *cobra.Command, dst, src *skbtrace.TimeCommonOptions)
- func PassTraceCommonOptions(ctx *VisitorContext, cmd *cobra.Command, dst, src *skbtrace.TraceCommonOptions)
- func RegisterAggregateCommonOptions(flags *pflag.FlagSet, opts *skbtrace.AggregateCommonOptions)
- func RegisterAggregateOptions(flags *pflag.FlagSet, opts *skbtrace.TraceAggregateOptions)
- func RegisterCommonDumpOptions(flags *pflag.FlagSet, opt *skbtrace.CommonDumpOptions)
- func RegisterFilterOptions(flags *pflag.FlagSet, options *skbtrace.FilterOptions)
- func RegisterInterfaceOptions(ctx *VisitorContext, cmd *cobra.Command, options *skbtrace.FilterOptions)
- func RegisterTimeIntervalArg(ctx *VisitorContext, cmd *cobra.Command, interval *time.Duration)
- func RegisterTracerContextOptions(flags *pflag.FlagSet, opts *skbtrace.TraceCommonOptions)
- func RegisterTracerProbeOptions(flags *pflag.FlagSet, opts *skbtrace.TraceCommonOptions)
- type AggregateTracerCommand
- type CommandBuilder
- type CommandProducer
- type CommandRunFunc
- type Dependencies
- type DumpTracerCommand
- type PreRunEChain
- type PreRunEFunc
- type TracerCommandVisitor
- type VisitorContext
Constants ¶
This section is empty.
Variables ¶
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, }, }
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) }, }, }
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) }, }, }
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) }) }, }
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, }, }
var DefaultTimeSubcommands = []*CommandProducer{ TimeAggregateCommand, TimeOutlierDumpSubcommand, TimeEventCountSubcommand, }
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() } }, }
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, }
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() } }, }
var RootCommand = CommandProducer{ Base: &cobra.Command{ Use: "skbtrace", Short: rootShortHelp, Long: rootHelp, }, Children: []*CommandProducer{ CommonDumpTracerCommand, CommonAggregateCommand, CommonTimeItFromCommand, CommonDuplicateCommand, ProbesCommand, FieldsCommand, }, }
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, }
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, }
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) }) }, }
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) }) }, }
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) }) }, }
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 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 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 ¶
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 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