From fbc62619ac670fca3c27f5692b3328157ffd051f Mon Sep 17 00:00:00 2001 From: PFtyrant Date: Wed, 19 Aug 2020 18:09:24 +0800 Subject: [PATCH 01/17] Modify info, dump message format -Modify info, dump message format -Add all of the table flag in dump.go -Add PISC logo into version.go -Fix Makefile -Fix import path of main.go -Fix go-bfrt to pisc, bfcli to pisc-cli --- Makefile | 4 +- cmd/completion.go | 2 +- cmd/dump.go | 111 +++++++++++++----------------------- cmd/info.go | 80 +++++++++++++++++--------- cmd/root.go | 14 ++--- cmd/utils.go | 142 ++++++++++++++++++++++++++++++++++++++++++---- cmd/version.go | 34 +++++++++-- main.go | 2 +- 8 files changed, 261 insertions(+), 128 deletions(-) diff --git a/Makefile b/Makefile index 973eb33..3728e14 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ all: build build: - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bfcli main.go + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o pisc-cli main.go clean: - rm bfcli + rm pisc-cli diff --git a/cmd/completion.go b/cmd/completion.go index f768db3..0ed31a3 100644 --- a/cmd/completion.go +++ b/cmd/completion.go @@ -27,7 +27,7 @@ var completionCmd = &cobra.Command{ Short: "Generates bash completion scripts", Long: `To load completion run -. <(bfcli completion)`, +. <(pisc-cli completion)`, Run: func(cmd *cobra.Command, args []string) { rootCmd.GenBashCompletion(os.Stdout) }, diff --git a/cmd/dump.go b/cmd/dump.go index e29972a..763cd13 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -18,109 +18,73 @@ package cmd import ( "fmt" "github.com/P4Networking/pisc/util" - "github.com/P4Networking/proto/go/p4" "github.com/spf13/cobra" - "io" "log" - "reflect" "strings" ) +var ( + preFixIg = "pipe.SwitchIngress." + preFixEg = "pipe.SwitchEgress." +) + // dumpCmd represents the dump command var dumpCmd = &cobra.Command{ Use: "dump TABLE-NAME", - Args: cobra.ExactArgs(1), - Short: "Dump the existed flows in specify table", - Long: `Display all existed flows in specify table`, + Short: "Dump the existed entries in the specific table", + Long: `Display all existed entries in the specific table`, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { _, _, conn, cancel, p4Info, _ := initConfigClient() defer conn.Close() defer cancel() - argsList, _ := p4Info.GuessTableName(toComplete) - return argsList, cobra.ShellCompDirectiveNoFileComp }, Run: func(cmd *cobra.Command, args []string) { - tableName := args[0] - cliAddr, ctxAddr, conn, cancel, p4Info, _ := initConfigClient() defer conn.Close() defer cancel() cli := *cliAddr ctx := *ctxAddr - tableId := p4Info.SearchTableId(tableName) - if tableId == util.ID_NOT_FOUND { - tableList, only := p4Info.GuessTableName(tableName) - if only { - tableName = tableList[0] - } else { - fmt.Printf("Can not found table with name: %s\n", tableName) + switch all { + case false: + if len(args) <= 0{ + cmd.Help() return } - } - - req := &p4.ReadRequest{ - Entities: []*p4.Entity{ - { - Entity: &p4.Entity_TableEntry{ - TableEntry: &p4.TableEntry{ - TableId: p4Info.SearchTableId(tableName), - }, - }, - }, - }, - } - - stream, err := cli.Read(ctx, req) - if err != nil { - log.Fatalf("Got error, %v \n", err.Error()) - } - - for { - rsp, err := stream.Recv() - if err == io.EOF { - break + tableId := p4Info.SearchTableId(args[0]) + if uint32(tableId) == util.ID_NOT_FOUND { + fmt.Printf("Can not found table with name: %s\n", args[0]) + return } - if err != nil { - log.Fatalf("Got error: %v", err) + table := p4Info.SearchTableById(tableId) + if table == nil { + fmt.Printf("Can not found table with ID: %d\n", tableId) + return } - if len(rsp.GetEntities()) == 0 { - fmt.Printf("The flows in %s is null\n", tableName) + + stream, err := cli.Read(ctx, GenReadRequestWithId(uint32(table.ID))) + if err != nil { + log.Fatalf("Got error, %v \n", err.Error()) } - for _, v := range rsp.Entities { - tbl := v.GetTableEntry() - if tbl.GetKey() != nil { - for _, f := range tbl.Key.Fields { - fmt.Printf("Match field ID: %d\n", f.FieldId) - switch strings.Split(reflect.TypeOf(f.GetMatchType()).String(), ".")[1] { - case "KeyField_Exact_": - m := f.GetExact() - fmt.Printf("Match field value: %x\n", m.Value) - case "KeyField_Ternary_": - t := f.GetTernary() - fmt.Printf("Ternary field value: %x, mask: %x\n", t.Value, t.Mask) - case "KeyField_Lpm": - l := f.GetLpm() - fmt.Printf("Lpm field value: %x, prefixLen: %d\n", l.Value, l.PrefixLen) - case "KeyField_Range_": - r := f.GetRange() - fmt.Printf("Range field high value: %x, low value: %x\n", r.High, r.Low) - } + + dumpEntries(&stream, table) + case true: + for _, v := range p4Info.Tables { + if strings.HasPrefix(v.Name, preFixIg) || strings.HasPrefix(v.Name, preFixEg) { + table := p4Info.SearchTableById(v.ID) + if table == nil { + fmt.Printf("Can not found table with ID: %v\n", v.ID) + return } - } else { - fmt.Printf("Table default action:\n") - } - printNameById(tbl.Data.ActionId) - if tbl.Data.Fields != nil { - for _, d := range tbl.Data.Fields { - fmt.Printf("Action parameter field ID: %d\n", d.FieldId) - printNameById(d.FieldId) - fmt.Printf("Action parameter value: %x\n", d.GetStream()) + stream, err := cli.Read(ctx, GenReadRequestWithId(uint32(v.ID))) + if err != nil { + log.Fatalf("Got error, %v \n", err.Error()) } + + dumpEntries(&stream, table) } - fmt.Printf("------------------\n") } } }, @@ -128,6 +92,7 @@ var dumpCmd = &cobra.Command{ func init() { rootCmd.AddCommand(dumpCmd) + dumpCmd.Flags().BoolVarP(&all, "all", "a", false, "dump all of the tables") // Here you will define your flags and configuration settings. diff --git a/cmd/info.go b/cmd/info.go index 029ffa4..016bfbf 100644 --- a/cmd/info.go +++ b/cmd/info.go @@ -24,21 +24,17 @@ import ( // infoCmd represents the info command var infoCmd = &cobra.Command{ Use: "info TABLE-NAME", - Args: cobra.ExactArgs(1), Short: "Show information about table", Long: `Display the detail of table.`, + Args: cobra.ExactArgs(1), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { _, _, conn, cancel, p4Info, _ := initConfigClient() defer conn.Close() defer cancel() - argsList, _ := p4Info.GuessTableName(toComplete) - return argsList, cobra.ShellCompDirectiveNoFileComp }, Run: func(cmd *cobra.Command, args []string) { - //fmt.Printf("Got cmd: %s | and args: %s\n", cmd.Name(), args) - var tableName string _, _, conn, cancel, p4Info, nonP4Info := initConfigClient() defer conn.Close() @@ -46,37 +42,47 @@ var infoCmd = &cobra.Command{ // Guest table name via table name provide form user tableList, ok := p4Info.GuessTableName(args[0]) + if len(tableList) > 0 { + for _, v := range tableList { + if args[0] == v { + ok = true + } + } + } + + //info.go doesn't show nonP4info information. if !ok { tableList, ok = nonP4Info.GuessTableName(args[0]) if !ok { - fmt.Printf("Not found the table %s\n", args[0]) + fmt.Printf("Can not found the table %s\n", args[0]) return } } - tableName = tableList[0] - tableId := p4Info.SearchTableId(tableName) - if tableId == util.ID_NOT_FOUND { - fmt.Printf("Can not found table with name: %s\n", tableName) + tableId := p4Info.SearchTableId(args[0]) + if uint32(tableId) == util.ID_NOT_FOUND { + fmt.Printf("Can not found table with name: %s\n", args[0]) return } table := p4Info.SearchTableById(tableId) + fmt.Println("--------------------------------------------------------------------------------") + fmt.Println("Table Info") if table.Name != "" { - fmt.Printf("%-12s: %-6s\n", "Table Name", table.Name) + fmt.Printf(" %-12s: %-6s\n", "Name", table.Name) } if table.ID != 0 { - fmt.Printf("%-12s: %-6d\n", "Table ID", table.ID) + fmt.Printf(" %-12s: %-6d\n", "ID", table.ID) } if table.TableType != "" { - fmt.Printf("%-12s: %-6s\n", "Table Type", table.TableType) + fmt.Printf(" %-12s: %-6s\n", "Type", table.TableType) } if table.Size != 0 { - fmt.Printf("%-12s: %-6d\n", "Table Size", table.Size) + fmt.Printf(" %-12s: %-6d\n", "Size", table.Size) } if table.Annotations != nil { - fmt.Printf("%-12s:\n", "Table Annotations") + fmt.Printf(" %-12s:\n", "Annotations") for k, v := range table.Annotations { fmt.Printf("%d - Name: %s | Value: %s \n", k+1, v.Name, v.Value) } @@ -85,30 +91,48 @@ var infoCmd = &cobra.Command{ fmt.Printf("%-12s: %-6s\n", "Table DependsOn", table.DependsOn) } - fmt.Println("==================================================================================================================================") - fmt.Printf("%-12s:\n", "Table Key") - for _, v := range table.Key { - fmt.Printf("KeyId: %-6d, Name: %-20s, Match Type: %-10s, Mandatory: %-6t, Repeated: %-6t, Type: %-8s, Width: %-4d\n", v.ID, v.Name, v.MatchType, v.Mandatory, v.Repeated, v.Type.Type, v.Type.Width) + if table.Key != nil { + fmt.Println("--------------------------------------------------------------------------------") + fmt.Printf("%-s\n", "Match Key Info") + fmt.Printf(" %-8s %-20s %-11s %-10s %-9s %-8s %-4s", + "KeyId", "Name", "Match_type", "Mandatory", "Repeated", "Type", "Width\n") + for _, v := range table.Key { + if v.ID == 65537 || v.Name == "$MATCH_PRIORITY" { + continue + } + fmt.Printf(" %-8d %-20s %-11s %-10t %-9t %-8s %-4d\n", + v.ID, v.Name, v.MatchType, v.Mandatory, v.Repeated, v.Type.Type, v.Type.Width) + } } if table.Data != nil { - fmt.Println("==================================================================================================================================") - fmt.Printf("%-12s:\n", "Table Data") + fmt.Println("--------------------------------------------------------------------------------") + fmt.Printf("%-s\n", "Table Data Info") + fmt.Printf(" %-8s %-20s %-10s %-9s %-8s\n", + "KeyId", "Name", "Mandatory", "Repeated", "Type") for _, v := range table.Data { - fmt.Printf("KeyId: %-6d, Name: %-20s, Mandatory: %-6t, Repeated: %-6t, Type: %-8s\n", v.Singleton.ID, v.Singleton.Name, v.Mandatory, v.Singleton.Repeated, v.Singleton.Type.Type) + fmt.Printf(" %-8d %-20s %-10t %-9t %-8s\n", + v.Singleton.ID, v.Singleton.Name, v.Mandatory, v.Singleton.Repeated, v.Singleton.Type.Type) } } if table.ActionSpecs != nil { - fmt.Println("==================================================================================================================================") - fmt.Printf("%-12s:\n", "Action Specs") + fmt.Println("--------------------------------------------------------------------------------") + fmt.Printf("%-s\n", "Action Info") for _, v := range table.ActionSpecs { - fmt.Printf("Id: %-6d, Name: %-20s \n", v.ID, v.Name) - for _, d := range v.Data { - fmt.Printf("ParameterId: %-6d, Name: %-20s, Mandatory: %-6t, Repeated: %-6t, Type: %-8s, Width: %-4d\n", d.ID, d.Name, d.Mandatory, d.Repeated, d.Type.Type, d.Type.Width) + fmt.Printf(" ID: %-6d, Name: %-20s \n", v.ID, v.Name) + if v.Data != nil { + fmt.Println(" ----------------------------------------------------------------") + for _, d := range v.Data { + fmt.Printf(" %-6s %-20s %-10s %-9s %-8s %-4s\n", + "ID", "Name", "Mandatory", "Repeated", "Type", "Width") + fmt.Printf(" %-6d %-20s %-10t %-9t %-8s %-4d\n", + d.ID, d.Name, d.Mandatory, d.Repeated, d.Type.Type, d.Type.Width) + } + fmt.Println(" ----------------------------------------------------------------") } - } + fmt.Println("--------------------------------------------------------------------------------") } }, } diff --git a/cmd/root.go b/cmd/root.go index 98b1e0a..d6db7fc 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -31,10 +31,10 @@ var ( // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ - Use: "bfcli [flags] command", - Short: "A command tool to manipulate go-bfrt", - Long: `Bfcli is a CLI for manipulate go-bfrt. -bfctl can list all tables, show information of table, set/remove flow and dump + Use: "pisc-cli [flags] command", + Short: "A command tool to manipulate pisc", + Long: `pisc-cli is a CLI for manipulate pisc. +pisc-cli can list all tables, show information of table, set/remove flow and dump the existed flows.`, // Uncomment the following line if your bare application // has an action associated with it: @@ -58,7 +58,7 @@ func init() { // Here you will define your flags and configuration settings. // Cobra supports persistent flags, which, if defined here, // will be global for your application. - //rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.bfcli.yaml)") + //rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.pisc-cli.yaml)") rootCmd.PersistentFlags().StringVarP(&server, "server", "s", "", "The server address") //rootCmd.MarkPersistentFlagRequired("server") @@ -80,9 +80,9 @@ func initConfig() { os.Exit(1) } - // Search config in home directory with name ".bfcli" (without extension). + // Search config in home directory with name ".pisc-cli" (without extension). viper.AddConfigPath(home) - viper.SetConfigName(".bfcli") + viper.SetConfigName(".pisc-cli") } viper.AutomaticEnv() // read in environment variables that match diff --git a/cmd/utils.go b/cmd/utils.go index d245479..7c51baf 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -8,8 +8,41 @@ import ( "github.com/P4Networking/pisc/util" "github.com/P4Networking/proto/go/p4" "google.golang.org/grpc" + "io" "log" + "reflect" + "strings" ) +//MAC_TYPE for Exact match +//IP_TYPE for Exact match +//VALUE_TYPE for Exact match +//CIDR_TYPE for LPM match +//MASK_TYPE for Ternary match +//NON_TYPE for unexpect value comes in +const ( + MAC_TYPE = iota //0 + IP_TYPE + CIDR_TYPE + MASK_TYPE + VALUE_TYPE + HEX_TYPE + NON_TYPE //6 + + INT8 //7 + INT16 + INT32 + INT64//10 + + IP_MASK//11 + ETH_MASK + HEX_MASK + VALUE_MASK//14 +) + +type MatchSet struct { + matchType uint + bitWidth int +} var ( FOUND = true @@ -36,7 +69,7 @@ func initConfigClient() (*p4.BfRuntimeClient, *context.Context, *grpc.ClientConn rsp, err := cli.GetForwardingPipelineConfig(ctx, &p4.GetForwardingPipelineConfigRequest{DeviceId: uint32(77)}) if err != nil { - log.Fatalf("Error with", err) + log.Fatalf("Error with %v", err) } err = gob.NewDecoder(bytes.NewReader(rsp.Config[0].BfruntimeInfo)).Decode(&p4Info) @@ -51,26 +84,111 @@ func initConfigClient() (*p4.BfRuntimeClient, *context.Context, *grpc.ClientConn return &cli, &ctx, conn, cancel, &p4Info, &nonP4Info } -func printNameById(id uint32) bool { +func printNameById(id uint32) (string, bool) { var name string var ok bool name, ok = p4Info.SearchActionNameById(id) if ok == true { - fmt.Printf("Action Name: %s \n", name) - return FOUND + return name, FOUND } - name, ok = nonP4Info.SearchActionParameterNameById(id) + name, ok = p4Info.SearchDataNameById(id) if ok == true { - fmt.Printf("Action Parameter Name: %s \n", name) - return FOUND + return name, FOUND } - name, ok = p4Info.SearchDataNameById(id) - if ok == true { - fmt.Printf("Data Name: %s \n", name) - return FOUND + //name, ok = p4Info.SearchActionParameterNameById(id) + //if ok == true { + // return name, FOUND + //} + + return "",NOT_FOUND +} + +func dumpEntries(stream *p4.BfRuntime_ReadClient, p4table *util.Table) { + for { + rsp, err := (*stream).Recv() + if err == io.EOF { + break + } + if err != nil { + log.Fatalf("Got error: %v", err) + } + Entities := rsp.GetEntities() + if len(Entities) == 0 { + fmt.Printf("The \"%s\" table is empty\n", p4table.Name) + }else { + fmt.Println("--------------------------------------------------------------------------------") + fmt.Printf("Table Name : %-s\n", p4table.Name) + for k, v := range Entities { + tbl := v.GetTableEntry() + if !tbl.IsDefaultEntry { + fmt.Printf("Entry %d:\n", k) + } + fmt.Println("Match Key Info") + if tbl.GetKey() != nil { + fmt.Printf(" %-20s %-10s %-16s\n", "Field Name:", "Type:", "Value:") + for k, f := range tbl.Key.Fields { + if f.FieldId == 65537 { + continue + } + switch strings.Split(reflect.TypeOf(f.GetMatchType()).String(), ".")[1] { + case "KeyField_Exact_": + m := f.GetExact() + fmt.Printf(" %-20s %-10s %-16x\n", p4table.Key[k].Name, "Exact", m.Value) + case "KeyField_Ternary_": + t := f.GetTernary() + fmt.Printf(" %-20s %-10s %-16x Mask: %-12x\n", p4table.Key[k].Name, "Ternay", t.Value, t.Mask) + case "KeyField_Lpm": + l := f.GetLpm() + fmt.Printf(" %-20s %-10s %-16x PreFix: %-12d\n", p4table.Key[k].Name, "LPM", l.Value, l.PrefixLen) + case "KeyField_Range_": + //TODO: Implement range match + r := f.GetRange() + //fmt.Printf(" %-20s %-10s %-16x High: %-8x Low: %-8x\n", table.Key[k].Name, "LPM", r.High, r.Low) + fmt.Printf(" %-20s %-10s High: %-8x Low: %-8x\n", p4table.Key[k].Name, "LPM", r.High, r.Low) + } + } + } + + if tbl.IsDefaultEntry { + fmt.Printf("Table default action:\n") + } + actionName, _ := printNameById(tbl.Data.ActionId) + fmt.Println("Action:", actionName) + + if tbl.Data.Fields != nil { + fmt.Printf(" %-20s %-16s\n", "Field Name:", "Value:") + for _, d := range p4table.ActionSpecs { + if d.Name == actionName { + for _, data := range tbl.Data.Fields { + if d.Data[k].ID == data.FieldId{ + fmt.Printf(" %-20s %-16x\n", d.Data[k].Name, data.GetStream()) + } + } + } + } + } + if k+1 != len(Entities) { + fmt.Printf("------------------\n") + } + } + fmt.Println("--------------------------------------------------------------------------------") + } + } +} + +func GenReadRequestWithId(tableId uint32) *p4.ReadRequest { + return &p4.ReadRequest{ + Entities: []*p4.Entity{ + { + Entity: &p4.Entity_TableEntry{ + TableEntry: &p4.TableEntry{ + TableId: tableId, + }, + }, + }, + }, } - return NOT_FOUND } diff --git a/cmd/version.go b/cmd/version.go index 8a6a337..4f66bba 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -21,19 +21,45 @@ import ( "github.com/spf13/cobra" ) +var ( + logo bool + version bool + piscLogo string +) + // versionCmd represents the version command var versionCmd = &cobra.Command{ Use: "version", - Short: "Show the bfcli version information", - Long: `Show the bfcli version information`, + Short: "Show the pisc-cli version information", + Long: `Show the pisc-cli version information`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println("version called") + if logo { + callLogo() + fmt.Println(piscLogo) + } + fmt.Println("Version Called") }, } +func callLogo() { + piscLogo = + " /$$\n" + + " |__/\n" + + " /$$$$$$ /$$ /$$$$$$$ /$$$$$$$\n" + + " /$$__ $$| $$ /$$_____/ /$$_____/\n" + + "| $$ \\ $$| $$| $$$$$$ | $$\n" + + "| $$ | $$| $$ \\____ $$| $$\n" + + "| $$$$$$$/| $$ /$$$$$$$/| $$$$$$$\n" + + "| $$____/ |__/|_______/ \\_______/\n" + + "| $$\n" + + "| $$\n" + + "|__/\n" +} + + func init() { rootCmd.AddCommand(versionCmd) - + versionCmd.Flags().BoolVarP(&logo, "logo", "l", false, "") // Here you will define your flags and configuration settings. // Cobra supports Persistent Flags which will work for this command diff --git a/main.go b/main.go index f34ca19..9f2e784 100644 --- a/main.go +++ b/main.go @@ -15,7 +15,7 @@ limitations under the License. */ package main -import "github.com/P4Networking/bfcli/cmd" +import "github.com/P4Networking/pisc-cli/cmd" func main() { cmd.Execute() From e64e5aeb1b12180239801052cf50584804ccc932 Mon Sep 17 00:00:00 2001 From: PFtyrant Date: Thu, 20 Aug 2020 10:36:31 +0800 Subject: [PATCH 02/17] Fix dump bug -Fix dump error of out of range case --- cmd/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/utils.go b/cmd/utils.go index 7c51baf..510713a 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -162,7 +162,7 @@ func dumpEntries(stream *p4.BfRuntime_ReadClient, p4table *util.Table) { fmt.Printf(" %-20s %-16s\n", "Field Name:", "Value:") for _, d := range p4table.ActionSpecs { if d.Name == actionName { - for _, data := range tbl.Data.Fields { + for k, data := range tbl.Data.Fields { if d.Data[k].ID == data.FieldId{ fmt.Printf(" %-20s %-16x\n", d.Data[k].Name, data.GetStream()) } From 4a9dc2716d47aba2e844ad10ceef7e0c1d866e95 Mon Sep 17 00:00:00 2001 From: PFtyrant Date: Mon, 24 Aug 2020 17:09:06 +0800 Subject: [PATCH 03/17] Add Documents of pisc-cli - Add README.md - Add description of util's function - Remove unused variable - Fix info that error doesn't occur when table Id is not found --- README.md | 121 ++++++++++++++++++++++++++++++++++++++++++++++ cmd/completion.go | 15 ------ cmd/delFlow.go | 15 ------ cmd/doc.go | 4 ++ cmd/dump.go | 23 ++------- cmd/info.go | 43 +++++----------- cmd/log.go | 15 ------ cmd/root.go | 20 -------- cmd/setFlow.go | 15 ------ cmd/table.go | 15 ------ cmd/utils.go | 57 ++++++---------------- cmd/version.go | 15 ------ main.go | 14 +----- 13 files changed, 157 insertions(+), 215 deletions(-) create mode 100644 README.md create mode 100644 cmd/doc.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..f8c03aa --- /dev/null +++ b/README.md @@ -0,0 +1,121 @@ +# Protocol Independent Switch Control - Command Line Interface(PISC-CLI) + +## Development envinment + +- GVM(https://github.com/moovweb/gvm) 做 GO 版本管理 +- GoLand 作為 IDE +- Golang version 1.14+ +- Barefoot SDE version 9.2 + +## Function Overview +- completion : provide table name suggestion to user +- version : show version of PISC-CLI +- set-flow : insert entry into the table +- del-flow : delete entry/entries of the table +- table : list all the table name +- dump : print all entries of the table +- info : print table's information + +## Run +PISC-CLI有Completion功能,補助使用者輸入Table名稱,因此執行方式有兩種。 +1. 要使用completion功能,需要把PISC-CLI的路徑加到PATH裡頭 + ``` + cd WHERE/IS/PISC-CLI + export PATH=$PATH:$PWD + ``` + 再把PISC-CLI的Completion功能引進BASH + ``` + . <(pisc-cli completion) + ``` + 就可以使用 tab key 所提供Command與Table Name的推薦(At now, dump, info support only) + ``` + pisc-cli [command] [flags] [arguments] + ``` +2. 若不想使用completion,直接執行PISC-CLI即可 + ``` + ./pisc-cli [command] [flags] [arguments] + ``` + +## How to set a flow into device? +set-flow指令,因為table有三種不同的match方式,為了使用指令必須要按照規則,規則如下: +``` +pisc-cli set-flow [TABLE NAME] [ACTION NAME] -m "match_key, ..." -a "action_value, ..." +``` +且Match key和Action value的寫入順序必須要跟pipeline所設定的順序相同。 + + +1. Exact : smac table example + ``` + pisc-cli set-flow pipe.SwitchIngress.smac SwitchIngress.smac_hit -m "aa:aa:aa:aa:aa:aa" -a "10" + ``` + +2. LPM : rib table example。對於LPM, 必須要按照CIDR的形式輸入,否則會出現error. + ``` + pisc-cli set-flow pipe.SwitchIngress.rib SwitchIngress.hit_route -m "10.0.0.1/24" -a "10" + ``` + +3. Ternary : acl example。對於Ternary,value與mask的長度以及形式必須要相同。 + ``` + pisc-cli set-flow pipe.SwitchIngress.acl SwitchIngress.output -m "10/10, 0x0800/0xffff, fa:aa:aa:aa:aa:fa/ff:ff:ff:ff:ff:ff, 127.0.0.1/255.255.255.255, 11.1.1.2/255.255.255.255" -a "0" + + ``` + +## How to delete entry/entries from device? +``` +pisc-cli del-flow [TABLE_NAME] [Flag] [Arguments] +``` +1. reset : clear all tables + ``` + pisc-cli del-flow -r + ``` +2. all : delete all entries of the table + ``` + //Do not confuse with set-flow's "-a" flag. It's totally diffrent. + pisc-cli del-flow [TABLE_NAME] -a + pisc-cli del-flow pipe.SwitchIngress.fib -a + ``` +3. entry : delete specific entry/entries number + ``` + pisc-cli del-flow [TABLE_NAME] -e "entry_number, ..." + ``` + ``` + // Assume that we have four entries{0, 1, ,2 ,3} in rib table. + // Also, we can use "info" command to see the entry number. + // About deleting entry, we don't need to care about the order of entry number. + + pisc-cli del-flow pipe.SwitchIngress.rib -e "1, 0, 2" + + // After deleting, the entry number will change to another. + // Please check the entry number everytime after deleting. + + pisc-cli del-flow pipe.SwitchIngress.rib -e "3" - error + ``` + +## How to show the table and entries information? +``` +pisc-cli [command] [TABLE_NAME] +``` +1. table : list all table name. +``` +pisc-cli table +``` +2. dump : dump all entries of the table, also -a flag will dump all tables. +``` +pisc-cli dump +pisc-cli dump -a +``` +3. info : show table information to the user +``` +pisc-cli info [TALBE_NAME] +``` + +## Show version and logo +1. show version +``` +pisc-cli version +``` + +2. show logo of PISC +``` +pisc-cli version -l +``` \ No newline at end of file diff --git a/cmd/completion.go b/cmd/completion.go index 0ed31a3..a6e73a0 100644 --- a/cmd/completion.go +++ b/cmd/completion.go @@ -1,18 +1,3 @@ -/* -Copyright © 2020 Chun Ming Ou - -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 ( diff --git a/cmd/delFlow.go b/cmd/delFlow.go index 8da582f..619112e 100644 --- a/cmd/delFlow.go +++ b/cmd/delFlow.go @@ -1,18 +1,3 @@ -/* -Copyright © 2020 Chun Ming Ou - -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 ( diff --git a/cmd/doc.go b/cmd/doc.go new file mode 100644 index 0000000..7c8e09e --- /dev/null +++ b/cmd/doc.go @@ -0,0 +1,4 @@ +/* +Package cmd includes commands of PISC-CLI. +*/ +package cmd diff --git a/cmd/dump.go b/cmd/dump.go index 763cd13..969e70e 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -1,18 +1,3 @@ -/* -Copyright © 2020 Chun Ming Ou - -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 ( @@ -64,12 +49,12 @@ var dumpCmd = &cobra.Command{ return } - stream, err := cli.Read(ctx, GenReadRequestWithId(uint32(table.ID))) + stream, err := cli.Read(ctx, genReadRequestWithId(uint32(table.ID))) if err != nil { log.Fatalf("Got error, %v \n", err.Error()) } - dumpEntries(&stream, table) + DumpEntries(&stream, table) case true: for _, v := range p4Info.Tables { if strings.HasPrefix(v.Name, preFixIg) || strings.HasPrefix(v.Name, preFixEg) { @@ -78,12 +63,12 @@ var dumpCmd = &cobra.Command{ fmt.Printf("Can not found table with ID: %v\n", v.ID) return } - stream, err := cli.Read(ctx, GenReadRequestWithId(uint32(v.ID))) + stream, err := cli.Read(ctx, genReadRequestWithId(uint32(v.ID))) if err != nil { log.Fatalf("Got error, %v \n", err.Error()) } - dumpEntries(&stream, table) + DumpEntries(&stream, table) } } } diff --git a/cmd/info.go b/cmd/info.go index 016bfbf..81e18c6 100644 --- a/cmd/info.go +++ b/cmd/info.go @@ -1,18 +1,3 @@ -/* -Copyright © 2020 Chun Ming Ou - -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 ( @@ -36,28 +21,18 @@ var infoCmd = &cobra.Command{ }, Run: func(cmd *cobra.Command, args []string) { - _, _, conn, cancel, p4Info, nonP4Info := initConfigClient() + _, _, conn, cancel, p4Info, _ := initConfigClient() defer conn.Close() defer cancel() - // Guest table name via table name provide form user - tableList, ok := p4Info.GuessTableName(args[0]) - if len(tableList) > 0 { - for _, v := range tableList { - if args[0] == v { - ok = true - } - } - } - - //info.go doesn't show nonP4info information. + /* non-p4Info not used yet. If you need to see non-p4 object, + please open the issue to talk about this. + tableList, ok := nonP4Info.GuessTableName(args[0]) if !ok { - tableList, ok = nonP4Info.GuessTableName(args[0]) - if !ok { - fmt.Printf("Can not found the table %s\n", args[0]) - return - } + fmt.Printf("Can not found the table %s\n", args[0]) + return } + */ tableId := p4Info.SearchTableId(args[0]) if uint32(tableId) == util.ID_NOT_FOUND { @@ -66,6 +41,10 @@ var infoCmd = &cobra.Command{ } table := p4Info.SearchTableById(tableId) + if table == nil { + fmt.Printf("Can not found table with Id %d\n", tableId) + return + } fmt.Println("--------------------------------------------------------------------------------") fmt.Println("Table Info") diff --git a/cmd/log.go b/cmd/log.go index 82deee3..279ae94 100644 --- a/cmd/log.go +++ b/cmd/log.go @@ -1,18 +1,3 @@ -/* -Copyright © 2020 NAME HERE - -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 ( diff --git a/cmd/root.go b/cmd/root.go index d6db7fc..2883762 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,18 +1,3 @@ -/* -Copyright © 2020 Chun Ming Ou - -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 ( @@ -36,11 +21,6 @@ var rootCmd = &cobra.Command{ Long: `pisc-cli is a CLI for manipulate pisc. pisc-cli can list all tables, show information of table, set/remove flow and dump the existed flows.`, - // Uncomment the following line if your bare application - // has an action associated with it: - //Run: func(cmd *cobra.Command, args []string) { - // fmt.Println("Hello World") - //}, } // Execute adds all child commands to the root command and sets flags appropriately. diff --git a/cmd/setFlow.go b/cmd/setFlow.go index 600b9a5..5211e6a 100644 --- a/cmd/setFlow.go +++ b/cmd/setFlow.go @@ -1,18 +1,3 @@ -/* -Copyright © 2020 Chun Ming Ou - -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 ( diff --git a/cmd/table.go b/cmd/table.go index 2ffc455..5aad27c 100644 --- a/cmd/table.go +++ b/cmd/table.go @@ -1,18 +1,3 @@ -/* -Copyright © 2020 Chun Ming Ou - -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 ( diff --git a/cmd/utils.go b/cmd/utils.go index 510713a..f195d3b 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -13,41 +13,12 @@ import ( "reflect" "strings" ) -//MAC_TYPE for Exact match -//IP_TYPE for Exact match -//VALUE_TYPE for Exact match -//CIDR_TYPE for LPM match -//MASK_TYPE for Ternary match -//NON_TYPE for unexpect value comes in -const ( - MAC_TYPE = iota //0 - IP_TYPE - CIDR_TYPE - MASK_TYPE - VALUE_TYPE - HEX_TYPE - NON_TYPE //6 - - INT8 //7 - INT16 - INT32 - INT64//10 - - IP_MASK//11 - ETH_MASK - HEX_MASK - VALUE_MASK//14 -) - -type MatchSet struct { - matchType uint - bitWidth int -} +//PISC-CLI use 50000 port basically var ( - FOUND = true - NOT_FOUND = false DEFAULT_ADDR = ":50000" + found = true + not_found = false p4Info util.BfRtInfoStruct nonP4Info util.BfRtInfoStruct ) @@ -90,23 +61,27 @@ func printNameById(id uint32) (string, bool) { name, ok = p4Info.SearchActionNameById(id) if ok == true { - return name, FOUND + return name, found } name, ok = p4Info.SearchDataNameById(id) if ok == true { - return name, FOUND + return name, found } //name, ok = p4Info.SearchActionParameterNameById(id) //if ok == true { - // return name, FOUND + // return name, found //} - return "",NOT_FOUND + return "",not_found } -func dumpEntries(stream *p4.BfRuntime_ReadClient, p4table *util.Table) { + +// DumpEntries function print entries data of the table. +// function will terminate when the stream occurs an error. +// also, it's not show the priority information. +func DumpEntries(stream *p4.BfRuntime_ReadClient, p4table *util.Table) { for { rsp, err := (*stream).Recv() if err == io.EOF { @@ -145,9 +120,8 @@ func dumpEntries(stream *p4.BfRuntime_ReadClient, p4table *util.Table) { fmt.Printf(" %-20s %-10s %-16x PreFix: %-12d\n", p4table.Key[k].Name, "LPM", l.Value, l.PrefixLen) case "KeyField_Range_": //TODO: Implement range match - r := f.GetRange() - //fmt.Printf(" %-20s %-10s %-16x High: %-8x Low: %-8x\n", table.Key[k].Name, "LPM", r.High, r.Low) - fmt.Printf(" %-20s %-10s High: %-8x Low: %-8x\n", p4table.Key[k].Name, "LPM", r.High, r.Low) + //r := f.GetRange() + //fmt.Printf(" %-20s %-10s High: %-8x Low: %-8x\n", p4table.Key[k].Name, "LPM", r.High, r.Low) } } } @@ -179,7 +153,8 @@ func dumpEntries(stream *p4.BfRuntime_ReadClient, p4table *util.Table) { } } -func GenReadRequestWithId(tableId uint32) *p4.ReadRequest { +// genReadRequestWithId function generates the read request format to read entries of the table via table ID. +func genReadRequestWithId(tableId uint32) *p4.ReadRequest { return &p4.ReadRequest{ Entities: []*p4.Entity{ { diff --git a/cmd/version.go b/cmd/version.go index 4f66bba..743de33 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -1,18 +1,3 @@ -/* -Copyright © 2020 NAME HERE - -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 ( diff --git a/main.go b/main.go index 9f2e784..2195839 100644 --- a/main.go +++ b/main.go @@ -1,17 +1,5 @@ /* -Copyright © 2020 Chun Ming Ou - -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 PISC-CLI implements command line interface of data plane. */ package main From 665a16f1aed5766082127ff25a890994f1edffd9 Mon Sep 17 00:00:00 2001 From: PFtyrant Date: Tue, 25 Aug 2020 12:05:39 +0800 Subject: [PATCH 04/17] Fix README -Fix README blank in message -Remove unused code in utils.go --- README.md | 2 +- cmd/utils.go | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/README.md b/README.md index f8c03aa..a1e711e 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ pisc-cli del-flow [TABLE_NAME] [Flag] [Arguments] ``` 2. all : delete all entries of the table ``` - //Do not confuse with set-flow's "-a" flag. It's totally diffrent. + // Do not confuse with set-flow's "-a" flag. It's totally diffrent. pisc-cli del-flow [TABLE_NAME] -a pisc-cli del-flow pipe.SwitchIngress.fib -a ``` diff --git a/cmd/utils.go b/cmd/utils.go index f195d3b..08546b6 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -69,11 +69,6 @@ func printNameById(id uint32) (string, bool) { return name, found } - //name, ok = p4Info.SearchActionParameterNameById(id) - //if ok == true { - // return name, found - //} - return "",not_found } From 95b91e0ec7c35ee4c3af525930a4bd23674ac900 Mon Sep 17 00:00:00 2001 From: Lin_teng <36951118+PFtyrant@users.noreply.github.com> Date: Tue, 15 Dec 2020 17:53:09 +0800 Subject: [PATCH 05/17] Add set/del flow function (#3) PISC-CLI -Add set-flow, del-flow, info, table, version function. * Fixed or removed issues - Fix table completion to remove the Parser table showing up. - Fix del-flow out of index problem. - Remove feature that deleting entry by entry number * New feature - Add deleting entry by match keys - Modify the write request(delete) to delete multiple entities at once. - Modify the dump function(print format) - Add go.mod - Add table name suggestion - Add dump counts function - Add the dump count flag -c to take out a number of entries * Document related - Modify README for the new version of the flow setup method - Modify flow cheatsheet --- Flow_cheatsheet.md | 67 +++++++ README.md | 86 ++++---- cmd/completion.go | 10 - cmd/delFlow.go | 143 ++++++++++++-- cmd/dump.go | 75 ++++--- cmd/info.go | 61 ++++-- cmd/root.go | 2 +- cmd/setFlow.go | 159 +++++++++++++-- cmd/table.go | 15 +- cmd/utils.go | 477 ++++++++++++++++++++++++++++++++++++++++----- cmd/version.go | 18 +- go.mod | 17 ++ go.sum | 395 +++++++++++++++++++++++++++++++++++++ 13 files changed, 1317 insertions(+), 208 deletions(-) create mode 100644 Flow_cheatsheet.md create mode 100644 go.mod create mode 100644 go.sum diff --git a/Flow_cheatsheet.md b/Flow_cheatsheet.md new file mode 100644 index 0000000..4d82852 --- /dev/null +++ b/Flow_cheatsheet.md @@ -0,0 +1,67 @@ + + +```bash +pisc-cli set-flow pipe.SwitchIngress.rmac SwitchIngress.rmac_hit -m "ff:ff:ff:ff:ff:ff" -a "" +pisc-cli set-flow pipe.SwitchIngress.dmac SwitchIngress.dmac_hit -m "ff:ff:ff:ff:ff:ff" -a "511" +pisc-cli set-flow pipe.SwitchIngress.fib SwitchIngress.hit_route_port -m "255.255.255.255" -a "511" +pisc-cli set-flow pipe.SwitchIngress.rib_24 SwitchIngress.hit_route_port -m "255.255.255" -a "511" +pisc-cli set-flow pipe.SwitchIngress.rib_20 SwitchIngress.hit_route_port -m "15.255.255" -a "511" +pisc-cli set-flow pipe.SwitchIngress.rib_16 SwitchIngress.hit_route_port -m "255.255" -a "511" +pisc-cli set-flow pipe.SwitchIngress.rib_12 SwitchIngress.hit_route_port -m "15.255" -a "511" +pisc-cli set-flow pipe.SwitchIngress.rib_8 SwitchIngress.hit_route_port -m "255" -a "511" +pisc-cli set-flow pipe.SwitchIngress.rib SwitchIngress.hit_route_port -m "255.255.255.255/255.255.255.255, 4000" -a "511" +pisc-cli set-flow pipe.SwitchIngress.nexthop SwitchIngress.set_nexthop -m "255" -a "511, ff:ff:ff:ff:ff:ff" +pisc-cli set-flow pipe.SwitchEgress.smac_rewrite_by_portid SwitchEgress.rewrite_smac -m "511/511, 4000" -a "ff:ff:ff:ff:ff:ff" +pisc-cli set-flow pipe.SwitchIngress.arp SwitchIngress.arp_response -m "511/511, 0xffff, 0xffff, 255.255.255.255/255.255.255.255, 4000" -a "ff:ff:ff:ff:ff:ff" +pisc-cli set-flow pipe.SwitchIngress.acl SwitchIngress.output -m "511/511, 0xffff/0xffff, aa:aa:aa:aa:aa:aa/ff:ff:ff:ff:ff:ff, 255.255.255.255/255.255.255.255, 255.255.255.255/255.255.255.255, 255/255, 4000" -a "10" +pisc-cli set-flow pipe.SwitchIngress.smac SwitchIngress.smac_hit -m "ff:ff:ff:ff:ff:ff" -a "511" -t 600 + +pisc-cli set-flow rmac SwitchIngress.rmac_hit -m "ff:ff:ff:ff:ff:ff" -a "" +pisc-cli set-flow dmac SwitchIngress.dmac_hit -m "ff:ff:ff:ff:ff:ff" -a "511" +pisc-cli set-flow fib SwitchIngress.hit_route_port -m "255.255.255.255" -a "511" +pisc-cli set-flow rib_24 SwitchIngress.hit_route_port -m "255.255.255" -a "511" +pisc-cli set-flow rib_20 SwitchIngress.hit_route_port -m "15.255.255" -a "511" +pisc-cli set-flow rib_16 SwitchIngress.hit_route_port -m "255.255" -a "511" +pisc-cli set-flow rib_12 SwitchIngress.hit_route_port -m "15.255" -a "511" +pisc-cli set-flow rib_8 SwitchIngress.hit_route_port -m "255" -a "511" +pisc-cli set-flow rib SwitchIngress.hit_route_port -m "255.255.255.255/255.255.255.255, 4000" -a "511" +pisc-cli set-flow nexthop SwitchIngress.set_nexthop -m "255" -a "511, ff:ff:ff:ff:ff:ff" +pisc-cli set-flow smac_rewrite_by_portid SwitchEgress.rewrite_smac -m "511/511, 4000" -a "ff:ff:ff:ff:ff:ff" +pisc-cli set-flow arp SwitchIngress.arp_response -m "511/511, 0xffff, 0xffff, 255.255.255.255/255.255.255.255, 4000" -a "ff:ff:ff:ff:ff:ff" +pisc-cli set-flow acl SwitchIngress.output -m "511/511, 0xffff/0xffff, aa:aa:aa:aa:aa:aa/ff:ff:ff:ff:ff:ff, 255.255.255.255/255.255.255.255, 255.255.255.255/255.255.255.255, 255/255, 4000" -a "10" +pisc-cli set-flow smac SwitchIngress.smac_hit -m "ff:ff:ff:ff:ff:ff" -a "511" -t 60000 + +``` + + +```bash +pisc-cli del-flow pipe.SwitchIngress.rmac -m "ff:ff:ff:ff:ff:ff" +pisc-cli del-flow pipe.SwitchIngress.dmac -m "ff:ff:ff:ff:ff:ff" +pisc-cli del-flow pipe.SwitchIngress.fib -m "255.255.255.255" +pisc-cli del-flow pipe.SwitchIngress.rib_24 -m "255.255.255" +pisc-cli del-flow pipe.SwitchIngress.rib_20 -m "15.255.255" +pisc-cli del-flow pipe.SwitchIngress.rib_16 -m "255.255" +pisc-cli del-flow pipe.SwitchIngress.rib_12 -m "15.255" +pisc-cli del-flow pipe.SwitchIngress.rib_8 -m "255" +pisc-cli del-flow pipe.SwitchIngress.rib -m "255.255.255.255/255.255.255.255, 4000" +pisc-cli del-flow pipe.SwitchIngress.nexthop -m "255" +pisc-cli del-flow pipe.SwitchEgress.smac_rewrite_by_portid -m "511/511, 4000" +pisc-cli del-flow pipe.SwitchIngress.arp -m "511/511, 0xffff, 0xffff, 255.255.255.255/255.255.255.255, 4000" +pisc-cli del-flow pipe.SwitchIngress.acl -m "511/511, 0xffff/0xffff, aa:aa:aa:aa:aa:aa/ff:ff:ff:ff:ff:ff, 255.255.255.255/255.255.255.255, 255.255.255.255/255.255.255.255, 255/255, 4000" +pisc-cli del-flow pipe.SwitchIngress.smac -m "ff:ff:ff:ff:ff:ff" + +pisc-cli del-flow rmac -m "ff:ff:ff:ff:ff:ff" +pisc-cli del-flow dmac -m "ff:ff:ff:ff:ff:ff" +pisc-cli del-flow fib -m "255.255.255.255" +pisc-cli del-flow rib_24 -m "255.255.255" +pisc-cli del-flow rib_20 -m "15.255.255" +pisc-cli del-flow rib_16 -m "255.255" +pisc-cli del-flow rib_12 -m "15.255" +pisc-cli del-flow rib_8 -m "255" +pisc-cli del-flow rib -m "255.255.255.255/255.255.255.255, 4000" +pisc-cli del-flow nexthop -m "255" +pisc-cli del-flow smac_rewrite_by_portid -m "511/511, 4000" +pisc-cli del-flow arp -m "511/511, 0xffff, 0xffff, 255.255.255.255/255.255.255.255, 4000" +pisc-cli del-flow acl -m "511/511, 0xffff/0xffff, aa:aa:aa:aa:aa:aa/ff:ff:ff:ff:ff:ff, 255.255.255.255/255.255.255.255, 255.255.255.255/255.255.255.255, 255/255, 4000" +pisc-cli del-flow smac -m "ff:ff:ff:ff:ff:ff" +``` \ No newline at end of file diff --git a/README.md b/README.md index a1e711e..f9dd57b 100644 --- a/README.md +++ b/README.md @@ -44,20 +44,35 @@ pisc-cli set-flow [TABLE NAME] [ACTION NAME] -m "match_key, ..." -a "action_valu 且Match key和Action value的寫入順序必須要跟pipeline所設定的順序相同。 -1. Exact : smac table example +>設table key的時候請務必確認,你所設定的值是否跟table所需要的值是一致的,假如說table需要MAC Addr,但卻你下的指令是沒有格式的數字或IP, 這樣會直接設下去,且會產生問題。 + +1. Exact : smac table example. ``` pisc-cli set-flow pipe.SwitchIngress.smac SwitchIngress.smac_hit -m "aa:aa:aa:aa:aa:aa" -a "10" ``` 2. LPM : rib table example。對於LPM, 必須要按照CIDR的形式輸入,否則會出現error. ``` - pisc-cli set-flow pipe.SwitchIngress.rib SwitchIngress.hit_route -m "10.0.0.1/24" -a "10" + pisc-cli set-flow pipe.SwitchIngress.rib SwitchIngress.hit_route -m "10.0.0.1/24" -a "10" + pisc-cli set-flow rib SwitchIngress.hit_route -m "10.0.0.1/24" -a "10" ``` -3. Ternary : acl example。對於Ternary,value與mask的長度以及形式必須要相同。 +3. Ternary : acl example。對於Ternary,value與mask的長度以及形式必須要相同。Ternary match key的區分僅能靠Match key的priority的欄位。PISC-CLI利用 match flag來題共設定priority。priority的設置方式與其他match key相同,且順序也是位於match的最後面。 + ``` - pisc-cli set-flow pipe.SwitchIngress.acl SwitchIngress.output -m "10/10, 0x0800/0xffff, fa:aa:aa:aa:aa:fa/ff:ff:ff:ff:ff:ff, 127.0.0.1/255.255.255.255, 11.1.1.2/255.255.255.255" -a "0" + pisc-cli set-flow pipe.SwitchIngress.arp SwitchIngress.arp_response -m "511/511, 0xffff, ffff, 255.255.255.255/255.255.255.255, 4000(priority value)" -a "ff:ff:ff:ff:ff:ff" pisc-cli set-flow acl SwitchIngress.output -m "10/10, 0x0800/0xffff, fa:aa:aa:aa:aa:fa/ff:ff:ff:ff:ff:ff, 127.0.0.1/255.255.255.255, 11.1.1.2/255.255.255.255" -a "0" + ``` + +## TTL - table TIMEOUT value setup +SMAC table has an idle_timeout function. This function will send a notification to the controller to notify that the entry's life has expired and need to remove it. +In PISC-CLI, it delivers TTL setting by -t flag on set-flow function. +The scale of the flag is milliseconds. min, max value of the TTL need to refer PISC. +Example as following: + + ``` + pisc-cli set-flow pipe.SwitchIngress.smac SwitchIngress.smac_hit -m "ff:ff:ff:ff:ff:ff" -a "511" -t 60000 + pisc-cli set-flow smac SwitchIngress.smac_hit -m "ff:ff:ff:ff:ff:ff" -a "511" -t 60000 ``` ## How to delete entry/entries from device? @@ -73,22 +88,15 @@ pisc-cli del-flow [TABLE_NAME] [Flag] [Arguments] // Do not confuse with set-flow's "-a" flag. It's totally diffrent. pisc-cli del-flow [TABLE_NAME] -a pisc-cli del-flow pipe.SwitchIngress.fib -a + pisc-cli del-flow fib -a ``` -3. entry : delete specific entry/entries number +3. match : delete specific entry by match keys. + the match flag acts like set-flow function. + the match flag need to specify table's match keys to delete entry. ``` - pisc-cli del-flow [TABLE_NAME] -e "entry_number, ..." - ``` - ``` - // Assume that we have four entries{0, 1, ,2 ,3} in rib table. - // Also, we can use "info" command to see the entry number. - // About deleting entry, we don't need to care about the order of entry number. - - pisc-cli del-flow pipe.SwitchIngress.rib -e "1, 0, 2" - - // After deleting, the entry number will change to another. - // Please check the entry number everytime after deleting. - - pisc-cli del-flow pipe.SwitchIngress.rib -e "3" - error + pisc-cli del-flow [TABLE_NAME] -m "Match key, ..." + pisc-cli del-flow pipe.SwitchIngress.rib -m "192.168.1.7/255.255.255.255, 4000" + pisc-cli del-flow rib -m "192.168.1.7/255.255.255.255, 4000" ``` ## How to show the table and entries information? @@ -96,26 +104,34 @@ pisc-cli del-flow [TABLE_NAME] [Flag] [Arguments] pisc-cli [command] [TABLE_NAME] ``` 1. table : list all table name. -``` -pisc-cli table -``` -2. dump : dump all entries of the table, also -a flag will dump all tables. -``` -pisc-cli dump -pisc-cli dump -a -``` + ``` + pisc-cli table + ``` +2. dump : dump all entries of the table. + ``` + pisc-cli dump [TABLE_NAME] + pisc-cli dump pipe.SwitchIngress.fib or pisc-cli dump fib + ``` + ``` + // dump all tables entries + pisc-cli dump -a + // dump all entries counts of the table. + pisc-cli dump -c + // also can dump all tables entries counts. + pisc-cli dump -a -c + ``` 3. info : show table information to the user -``` -pisc-cli info [TALBE_NAME] -``` + ``` + pisc-cli info [TALBE_NAME] + ``` ## Show version and logo 1. show version -``` -pisc-cli version -``` + ``` + pisc-cli version + ``` 2. show logo of PISC -``` -pisc-cli version -l -``` \ No newline at end of file + ``` + pisc-cli version -l + ``` \ No newline at end of file diff --git a/cmd/completion.go b/cmd/completion.go index a6e73a0..6c4a938 100644 --- a/cmd/completion.go +++ b/cmd/completion.go @@ -20,14 +20,4 @@ var completionCmd = &cobra.Command{ func init() { rootCmd.AddCommand(completionCmd) - - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // completionCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // completionCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } diff --git a/cmd/delFlow.go b/cmd/delFlow.go index 619112e..785d571 100644 --- a/cmd/delFlow.go +++ b/cmd/delFlow.go @@ -2,35 +2,138 @@ package cmd import ( "fmt" - + "github.com/P4Networking/pisc/util" + "github.com/P4Networking/pisc/util/enums/id" + "github.com/P4Networking/proto/go/p4" "github.com/spf13/cobra" + "io" + "log" + "strings" +) + +var ( + reset bool + delEntry []string ) // delFlowCmd represents the delFlow command var delFlowCmd = &cobra.Command{ - Use: "del-flow", - Short: "A brief description of your command", - Long: `A longer description that spans multiple lines and likely contains examples -and usage of using your command. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, + Use: "del-flow TABLE-NAME ", + Short: "Delete entries from table", + Long: `del-flow can remove all of the entries from specific table`, + Args: cobra.MaximumNArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + _, _, conn, cancel, p4Info, _ := initConfigClient() + defer conn.Close() + defer cancel() + var argsList []string + for _, v := range p4Info.Tables { + if strings.Contains(v.Name, preFixIg) || strings.Contains(v.Name, preFixEg) { + strs := strings.Split(v.Name, ".") + if toComplete == "" || strings.Contains(toComplete, "pipe") { + argsList = append(argsList, v.Name) + } else { + argsList = append(argsList, strs[2]) + } + } + } + return argsList, cobra.ShellCompDirectiveNoFileComp + }, Run: func(cmd *cobra.Command, args []string) { - fmt.Println("delFlow called") + + if (all || len(delEntry) > 0) && len(args) <= 0 { + cmd.Help() + return + } + for a, v := range delEntry { + delEntry[a] = strings.Replace(v, " ", "", -1) + } + + cliAddr, ctxAddr, conn, cancel, p4Info, _ := initConfigClient() + defer conn.Close() + defer cancel() + cli := *cliAddr + ctx := *ctxAddr + + if !reset { + argsList, _ := p4Info.GuessTableName(args[0]) + if len(argsList) != 1 { + for _, v := range argsList { + strs := strings.Split(v, ".") + if strings.EqualFold(strs[2], args[0]) { + args[0] = v + } + } + } else { + args[0] = argsList[0] + } + } + + for _, v := range p4Info.Tables { + if strings.HasPrefix(v.Name, preFixIg) || strings.HasPrefix(v.Name, preFixEg) { + if (all || len(delEntry) > 0) && v.Name != args[0] { + continue + } + stream, err := cli.Read(ctx, genReadRequestWithId(v.ID)) + if err != nil { + log.Fatalf("Got error, %v \n", err.Error()) + return + } + + for { + rsp, err := stream.Recv() + if err == io.EOF { + break + } + if rsp != nil { + if len(rsp.GetEntities()) == 0 { + fmt.Printf("%s table is empty\n", v.Name) + break + } + var cnt []int + var err error + + if all || reset { + cnt, err = DeleteEntries(&rsp, &cli, &ctx) + if err != nil { + fmt.Printf("Failed to delete entry: table \"%s\" with fields: %s\n", v.Name, rsp.Entities[cnt[0]].GetTableEntry().Key.Fields) + } else { + fmt.Printf("%d entires of \"%s\" table have cleared\n", len(cnt), v.Name) + } + } else if len(delEntry) > 0 { + table, _ := p4Info.GetTableById(id.TableId(v.ID)) + collectedMatchTypes, ok := collectTableMatchTypes(table, &delEntry) + if !ok { + fmt.Println("Match keys are not matched") + return + } + fmt.Print("Make Match Key... ") + if match := BuildMatchKeys(&collectedMatchTypes); match != nil { + delReq := util.GenWriteRequestWithId(p4.Update_DELETE, id.TableId(v.ID), match, nil) + fmt.Print("Write Delete Reqeust... ") + _, err := cli.Write(ctx, delReq) + if err != nil { + fmt.Println(err) + return + } + fmt.Println("DONE.") + } else { + fmt.Println("Please Check match keys and inputted arguments.") + } + } + } + } + } + } + if reset { + fmt.Println("Reset complete.") + } }, } func init() { rootCmd.AddCommand(delFlowCmd) - - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // delFlowCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // delFlowCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + delFlowCmd.Flags().BoolVarP(&all, "all", "a", false, "delete all entries of the table") + delFlowCmd.Flags().BoolVarP(&reset, "reset", "r", false, "clear all of the tables") + delFlowCmd.Flags().StringSliceVarP(&delEntry, "match", "m", []string{}, "delete specific entry by given entry number") } diff --git a/cmd/dump.go b/cmd/dump.go index 969e70e..d0cb488 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -2,15 +2,15 @@ package cmd import ( "fmt" - "github.com/P4Networking/pisc/util" + "github.com/P4Networking/pisc/southbound/bfrt" + "github.com/P4Networking/pisc/util/enums/id" "github.com/spf13/cobra" "log" "strings" ) - var ( - preFixIg = "pipe.SwitchIngress." - preFixEg = "pipe.SwitchEgress." + // all bool(define in table.go) + count bool ) // dumpCmd represents the dump command @@ -22,7 +22,17 @@ var dumpCmd = &cobra.Command{ _, _, conn, cancel, p4Info, _ := initConfigClient() defer conn.Close() defer cancel() - argsList, _ := p4Info.GuessTableName(toComplete) + var argsList []string + for _, v := range p4Info.Tables { + if strings.Contains(v.Name, preFixIg) || strings.Contains(v.Name, preFixEg) { + strs := strings.Split(v.Name, ".") + if toComplete == "" || strings.Contains(toComplete, "pipe") { + argsList = append(argsList, v.Name) + } else { + argsList = append(argsList, strs[2]) + } + } + } return argsList, cobra.ShellCompDirectiveNoFileComp }, Run: func(cmd *cobra.Command, args []string) { @@ -34,41 +44,59 @@ var dumpCmd = &cobra.Command{ switch all { case false: - if len(args) <= 0{ + if len(args) <= 0 { cmd.Help() return } - tableId := p4Info.SearchTableId(args[0]) - if uint32(tableId) == util.ID_NOT_FOUND { + + argsList, _ := p4Info.GuessTableName(args[0]) + if len(argsList) != 1 { + for _, v := range argsList { + strs := strings.Split(v, ".") + if strings.EqualFold(strs[2], args[0]) { + args[0] = v + } + } + } else { + args[0] = argsList[0] + } + + tableId, ok := p4Info.GetTableId(args[0]) + if uint32(tableId) == bfrt.ID_NOT_FOUND || !ok { fmt.Printf("Can not found table with name: %s\n", args[0]) return } - table := p4Info.SearchTableById(tableId) - if table == nil { + table, ok := p4Info.GetTableById(tableId) + if !ok { fmt.Printf("Can not found table with ID: %d\n", tableId) return } - - stream, err := cli.Read(ctx, genReadRequestWithId(uint32(table.ID))) + stream, err := cli.Read(ctx, genReadRequestWithId(table.ID)) if err != nil { log.Fatalf("Got error, %v \n", err.Error()) } - - DumpEntries(&stream, table) + if count { + DumpEntriesCount(&stream, table) + } else { + DumpEntries(&stream, table) + } case true: for _, v := range p4Info.Tables { if strings.HasPrefix(v.Name, preFixIg) || strings.HasPrefix(v.Name, preFixEg) { - table := p4Info.SearchTableById(v.ID) + table, _ := p4Info.GetTableById(id.TableId(v.ID)) if table == nil { fmt.Printf("Can not found table with ID: %v\n", v.ID) return } - stream, err := cli.Read(ctx, genReadRequestWithId(uint32(v.ID))) + stream, err := cli.Read(ctx, genReadRequestWithId(v.ID)) if err != nil { log.Fatalf("Got error, %v \n", err.Error()) } - - DumpEntries(&stream, table) + if count { + DumpEntriesCount(&stream, table) + } else { + DumpEntries(&stream, table) + } } } } @@ -78,14 +106,5 @@ var dumpCmd = &cobra.Command{ func init() { rootCmd.AddCommand(dumpCmd) dumpCmd.Flags().BoolVarP(&all, "all", "a", false, "dump all of the tables") - - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // dumpCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // dumpCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + dumpCmd.Flags().BoolVarP(&count, "count", "c", false, "dump entries number of counts") } diff --git a/cmd/info.go b/cmd/info.go index 81e18c6..de882cd 100644 --- a/cmd/info.go +++ b/cmd/info.go @@ -2,8 +2,9 @@ package cmd import ( "fmt" - "github.com/P4Networking/pisc/util" + "github.com/P4Networking/pisc/southbound/bfrt" "github.com/spf13/cobra" + "strings" ) // infoCmd represents the info command @@ -16,7 +17,18 @@ var infoCmd = &cobra.Command{ _, _, conn, cancel, p4Info, _ := initConfigClient() defer conn.Close() defer cancel() - argsList, _ := p4Info.GuessTableName(toComplete) + + var argsList []string + for _, v := range p4Info.Tables { + if strings.Contains(v.Name, preFixIg) || strings.Contains(v.Name, preFixEg) { + strs := strings.Split(v.Name, ".") + if toComplete == "" || strings.Contains(toComplete, "pipe") { + argsList = append(argsList, v.Name) + } else { + argsList = append(argsList, strs[2]) + } + } + } return argsList, cobra.ShellCompDirectiveNoFileComp }, Run: func(cmd *cobra.Command, args []string) { @@ -33,14 +45,25 @@ var infoCmd = &cobra.Command{ return } */ + argsList, _ := p4Info.GuessTableName(args[0]) + if len(argsList) != 1 { + for _, v := range argsList { + strs := strings.Split(v, ".") + if strings.EqualFold(strs[2], args[0]) { + args[0] = v + } + } + } else { + args[0] = argsList[0] + } - tableId := p4Info.SearchTableId(args[0]) - if uint32(tableId) == util.ID_NOT_FOUND { - fmt.Printf("Can not found table with name: %s\n", args[0]) + tableId, _ := p4Info.GetTableId(args[0]) + if uint32(tableId) == bfrt.ID_NOT_FOUND { + fmt.Printf("Can't found table with name: %s\n", args[0]) return } - table := p4Info.SearchTableById(tableId) + table, _ := p4Info.GetTableById(tableId) if table == nil { fmt.Printf("Can not found table with Id %d\n", tableId) return @@ -63,7 +86,11 @@ var infoCmd = &cobra.Command{ if table.Annotations != nil { fmt.Printf(" %-12s:\n", "Annotations") for k, v := range table.Annotations { - fmt.Printf("%d - Name: %s | Value: %s \n", k+1, v.Name, v.Value) + if v.Value != "" { + fmt.Printf(" %d - Name: %s | Value: %s \n", k+1, v.Name, v.Value) + } else { + fmt.Printf(" %d - Name: %s \n", k+1, v.Name) + } } } if table.DependsOn != nil { @@ -76,11 +103,13 @@ var infoCmd = &cobra.Command{ fmt.Printf(" %-8s %-20s %-11s %-10s %-9s %-8s %-4s", "KeyId", "Name", "Match_type", "Mandatory", "Repeated", "Type", "Width\n") for _, v := range table.Key { - if v.ID == 65537 || v.Name == "$MATCH_PRIORITY" { - continue + if v.Name == "$MATCH_PRIORITY" { + fmt.Printf(" %-8d %-20s %-11s %-10t %-9t %-8s %-4d\n", + v.ID, v.Name, v.MatchType, v.Mandatory, v.Repeated, v.Type.Type, 32) + } else { + fmt.Printf(" %-8d %-20s %-11s %-10t %-9t %-8s %-4d\n", + v.ID, v.Name, v.MatchType, v.Mandatory, v.Repeated, v.Type.Type, v.Type.Width) } - fmt.Printf(" %-8d %-20s %-11s %-10t %-9t %-8s %-4d\n", - v.ID, v.Name, v.MatchType, v.Mandatory, v.Repeated, v.Type.Type, v.Type.Width) } } @@ -118,14 +147,4 @@ var infoCmd = &cobra.Command{ func init() { rootCmd.AddCommand(infoCmd) - - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // infoCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // infoCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } diff --git a/cmd/root.go b/cmd/root.go index 2883762..66747af 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -5,7 +5,7 @@ import ( "github.com/spf13/cobra" "os" - homedir "github.com/mitchellh/go-homedir" + "github.com/mitchellh/go-homedir" "github.com/spf13/viper" ) diff --git a/cmd/setFlow.go b/cmd/setFlow.go index 5211e6a..80abec7 100644 --- a/cmd/setFlow.go +++ b/cmd/setFlow.go @@ -2,35 +2,154 @@ package cmd import ( "fmt" - + "github.com/P4Networking/pisc/southbound/bfrt" + "github.com/P4Networking/pisc/util" + "github.com/P4Networking/proto/go/p4" "github.com/spf13/cobra" + "log" + "strconv" + "strings" +) + +var ( + matchLists []string + actionValues []string + ttl = "" ) // setFlowCmd represents the setFlow command var setFlowCmd = &cobra.Command{ - Use: "set-flow", - Short: "A brief description of your command", - Long: `A longer description that spans multiple lines and likely contains examples -and usage of using your command. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, + Use: "set-flow TABLE_NAME ACTION-NAME ", + Short: "Set flow into table", + Long: `Insert the flow to table with action`, + Args: cobra.ExactArgs(2), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + _, _, conn, cancel, p4Info, _ := initConfigClient() + defer conn.Close() + defer cancel() + argsList, _ := p4Info.GuessTableName(toComplete) + for k, v := range argsList { + if strings.Contains(v, preFixIgPar) || strings.Contains(v, preFixEgPar) { + argsList[k] = argsList[len(argsList)-1] // Copy last element to index i. + argsList[len(argsList)-1] = "" // Erase last element (write zero value). + argsList = argsList[:len(argsList)-1] + } + } + return argsList, cobra.ShellCompDirectiveNoFileComp + }, Run: func(cmd *cobra.Command, args []string) { - fmt.Println("setFlow called") + + for a, v := range matchLists { + matchLists[a] = strings.Replace(v, " ", "", -1) + } + + for a, v := range actionValues { + actionValues[a] = strings.Replace(v, " ", "", -1) + } + + cliAddr, ctxAddr, conn, cancel, p4Info, _ := initConfigClient() + defer conn.Close() + defer cancel() + cli := *cliAddr + ctx := *ctxAddr + argsList, _ := p4Info.GuessTableName(args[0]) + if len(argsList) != 1 { + for _, v := range argsList { + strs := strings.Split(v, ".") + if strings.EqualFold(strs[2], args[0]) { + args[0] = v + } + } + } else { + args[0] = argsList[0] + } + + tableName := args[0] + actionName := args[1] + tableId, ok := p4Info.GetTableId(tableName) + if uint32(tableId) == bfrt.ID_NOT_FOUND || !ok { + fmt.Printf("Can not found table with name: %s\n", tableName) + return + } + table, _ := p4Info.GetTableById(tableId) + + collectedMatchTypes, ok := collectTableMatchTypes(table, &matchLists) + if !ok { + fmt.Println("Match keys are not matched") + return + } + + actionId, ok := p4Info.GetActionId(tableName, actionName) + if actionId == bfrt.ID_NOT_FOUND || !ok { + fmt.Printf("Can not found action with names: %s\n", actionName) + return + } + dataId, ok := p4Info.GetDataId(tableName, "$ENTRY_TTL") + if ok && ttl == "" { + fmt.Printf("Please set the TTL value for table %s\n", table.Name) + return + } + + collectedActionFieldIds, err := collectActionFieldIds(table, actionId, actionValues) + if err != nil { + fmt.Println(err) + return + } + if len(collectedActionFieldIds) != len(actionValues) { + fmt.Printf("Length of action fields [%d] != Length of action args [%d]\n", len(collectedActionFieldIds), len(actionValues)) + fmt.Println("Check action arguments") + return + } + + fmt.Printf("Make Match Data...") + match := BuildMatchKeys(&collectedMatchTypes) + if match == nil { + return + } + + fmt.Printf(" Make Action Data...") + action := util.Action() + if len(collectedActionFieldIds) != 0 { + for _, v := range collectedActionFieldIds { + switch mlt, v1, _ := checkMatchListType(v.actionValue, v.parsedBitWidth); mlt { + case MAC_TYPE: + action = append(action, util.GenDataField(v.fieldId, v1.([]byte))) + case IP_TYPE: + action = append(action, util.GenDataField(v.fieldId, v1.([]byte))) + case VALUE_TYPE: + action = append(action, util.GenDataField(v.fieldId, setBitValue(v1.(int), v.parsedBitWidth))) + default: + fmt.Println("Unexpected value for action fields") + return + } + } + } + if ttl != "" { + if !ok { + fmt.Println("ttl set failed") + return + } + l, err :=strconv.ParseUint(ttl, 10 , 32) + if err != nil { + fmt.Printf("Please Check the TTL value %s.\n", ttl) + return + } + action = append(action, util.GenDataField(dataId, util.Int32ToBytes(uint32(l)))) + } + + fmt.Printf(" Make Write Request...") + var req = util.GenWriteRequestWithId(p4.Update_INSERT, tableId, match, &p4.TableData{ActionId: actionId, Fields: action}) + if _, err := cli.Write(ctx, req); err != nil { + log.Printf("Got error, %v \n", err.Error()) + } else { + fmt.Printf(" Write Done.\n") + } }, } func init() { rootCmd.AddCommand(setFlowCmd) - - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // setFlowCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // setFlowCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + setFlowCmd.Flags().StringSliceVarP(&matchLists, "match", "m", []string{}, "match arguments") + setFlowCmd.Flags().StringSliceVarP(&actionValues, "action", "a", []string{}, "action arguments") + setFlowCmd.Flags().StringVarP(&ttl, "ttl", "t", ttl, "TTL arguments") } diff --git a/cmd/table.go b/cmd/table.go index 5aad27c..688dea9 100644 --- a/cmd/table.go +++ b/cmd/table.go @@ -3,6 +3,7 @@ package cmd import ( "fmt" "github.com/spf13/cobra" + "strings" ) var ( @@ -22,7 +23,9 @@ var tableCmd = &cobra.Command{ //fmt.Println("------ The following is for P4 table ------") for _, v := range p4Info.Tables { - fmt.Println(v.Name) + if strings.Contains(v.Name, preFixIg) || strings.Contains(v.Name, preFixEg) { + fmt.Println(v.Name) + } } if all { @@ -37,14 +40,4 @@ var tableCmd = &cobra.Command{ func init() { rootCmd.AddCommand(tableCmd) tableCmd.Flags().BoolVarP(&all, "all", "a", false, "Show all tables") - - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // tableCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // tableCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } diff --git a/cmd/utils.go b/cmd/utils.go index 08546b6..f5c5a72 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -5,25 +5,73 @@ import ( "context" "encoding/gob" "fmt" + "github.com/P4Networking/pisc/southbound/bfrt" "github.com/P4Networking/pisc/util" + "github.com/P4Networking/pisc/util/enums" + "github.com/P4Networking/pisc/util/enums/id" "github.com/P4Networking/proto/go/p4" "google.golang.org/grpc" "io" "log" + "math" + "net" "reflect" + "strconv" "strings" + "unicode" ) -//PISC-CLI use 50000 port basically +// MAC_TYPE for Exact match +// IP_TYPE for Exact match +// VALUE_TYPE for Exact match +// CIDR_TYPE for LPM match +// MASK_TYPE for Ternary match +// NON_TYPE for unexpect value +const ( + MAC_TYPE = iota //0 + IP_TYPE + CIDR_TYPE + MASK_TYPE + VALUE_TYPE + HEX_TYPE + NON_TYPE //6 + + INT8 //7 + INT16 + INT32 + INT64 //10 + + IP_MASK //11 + ETH_MASK + HEX_MASK + VALUE_MASK //14 +) + +type MatchSet struct { + fieldId uint32 + matchValue string + matchType uint + bitWidth int +} +type ActionSet struct { + fieldId uint32 + actionValue string + bitWidth int + parsedBitWidth int +} + var ( DEFAULT_ADDR = ":50000" - found = true - not_found = false - p4Info util.BfRtInfoStruct - nonP4Info util.BfRtInfoStruct + + p4Info bfrt.BfRtInfo + nonP4Info bfrt.BfRtInfo + preFixIg = "pipe.SwitchIngress." + preFixEg = "pipe.SwitchEgress." + preFixIgPar = "pipe.SwitchIngressParser." + preFixEgPar = "pipe.SwitchEgressParser." ) -func initConfigClient() (*p4.BfRuntimeClient, *context.Context, *grpc.ClientConn, context.CancelFunc, *util.BfRtInfoStruct, *util.BfRtInfoStruct) { +func initConfigClient() (*p4.BfRuntimeClient, *context.Context, *grpc.ClientConn, context.CancelFunc, *bfrt.BfRtInfo, *bfrt.BfRtInfo) { if server == "" { server = DEFAULT_ADDR } @@ -35,10 +83,8 @@ func initConfigClient() (*p4.BfRuntimeClient, *context.Context, *grpc.ClientConn cli := p4.NewBfRuntimeClient(conn) // Contact the server and print out its response. - ctx, cancel := context.WithCancel(context.Background()) - - rsp, err := cli.GetForwardingPipelineConfig(ctx, &p4.GetForwardingPipelineConfigRequest{DeviceId: uint32(77)}) + rsp, err := cli.GetForwardingPipelineConfig(ctx, &p4.GetForwardingPipelineConfigRequest{DeviceId: uint32(0)}) if err != nil { log.Fatalf("Error with %v", err) } @@ -55,28 +101,286 @@ func initConfigClient() (*p4.BfRuntimeClient, *context.Context, *grpc.ClientConn return &cli, &ctx, conn, cancel, &p4Info, &nonP4Info } -func printNameById(id uint32) (string, bool) { +func printNameById(actionName string, id uint32) (string, bool) { var name string var ok bool - name, ok = p4Info.SearchActionNameById(id) + name, ok = p4Info.GetActionNameById(id) if ok == true { - return name, found + return name, true } - name, ok = p4Info.SearchDataNameById(id) + name, ok = p4Info.GetDataNameById(id) if ok == true { - return name, found + return name, true } - return "",not_found + name, ok = p4Info.GetActionParameterNameById(actionName, id) + if ok == true { + return name, true + } + + name, ok = p4Info.GetDataNameById(id) + if ok == true { + return name, true + } + + return "", false } +// collectTableMatchTypes function collects the match key's type and bit width. +// the collected type and bit width determine what kind of the input should be used. +func collectTableMatchTypes(table *bfrt.Table, matchKey *[]string) ([]MatchSet, bool) { + if len(table.Key) != len(*matchKey) { + fmt.Printf("Length of Match keys [%d] != Length of match args [%d]\n", len(table.Key), len(matchLists)) + return nil, false + } -// DumpEntries function print entries data of the table. -// function will terminate when the stream occurs an error. -// also, it's not show the priority information. -func DumpEntries(stream *p4.BfRuntime_ReadClient, p4table *util.Table) { + var m []MatchSet + for kv, v := range table.Key { + bw := parseBitWidth(v.Type.Width) + switch v.MatchType { + case "Exact": + if v.ID == 65537 || v.Name == "$MATCH_PRIORITY" { + m = append(m, MatchSet{fieldId: v.ID, matchValue: (*matchKey)[kv], matchType: enums.MATCH_EXACT, bitWidth: INT32}) + } else { + m = append(m, MatchSet{fieldId: v.ID, matchValue: (*matchKey)[kv], matchType: enums.MATCH_EXACT, bitWidth: bw}) + } + case "LPM": + m = append(m, MatchSet{fieldId: v.ID, matchValue: (*matchKey)[kv], matchType: enums.MATCH_LPM, bitWidth: bw}) + case "Range": + m = append(m, MatchSet{fieldId: v.ID, matchValue: (*matchKey)[kv], matchType: enums.MATCH_RANGE, bitWidth: bw}) + case "Ternary": + m = append(m, MatchSet{fieldId: v.ID, matchValue: (*matchKey)[kv], matchType: enums.MATCH_TERNARY, bitWidth: bw}) + default: + return nil, false + } + } + return m, true +} + +// collectActionFieldIds function collects the bit width of action data. +// the collected bit widths decide what kind of input should be used. +func collectActionFieldIds(table *bfrt.Table, id uint32, values []string) ([]ActionSet, error) { + var result []ActionSet + for _, v := range table.ActionSpecs { + if v.ID == id { + for kd, d := range v.Data { + if IsNumber(values[kd]) { + value, err := strconv.Atoi(values[kd]) + if int(math.Pow(2, float64(d.Type.Width))-1) < value { + err = fmt.Errorf("inputted action value is overflow: %s\n", values[kd]) + return nil, err + } + } + result = append(result, ActionSet{fieldId: d.ID, actionValue: values[kd], bitWidth: d.Type.Width, parsedBitWidth: parseBitWidth(d.Type.Width)}) + } + break + } + } + return result, nil +} + +// IsNumber function check that the string is numeric. +func IsNumber(s string) bool { + for _, r := range s { + if !unicode.IsNumber(r) { + return false + } + } + return true +} + +// checkMatchListType function checks that the input arguments are what kind of the match values. +func checkMatchListType(value string, bitWidth int) (uint, interface{}, interface{}) { + if _, e := net.ParseMAC(value); e == nil && bitWidth == INT64 { + return MAC_TYPE, util.MacToBytes(value), nil + } else if e := parseIPv4(value); (strings.IndexByte(value, '/') < 0) && (e != nil) && (bitWidth <= INT32) { + return IP_TYPE, e, nil + } else if i, a, e := parseCIDR(value); e && strings.IndexByte(value, '/') >= 0 { + return CIDR_TYPE, i, a + } else if maskType, arg := checkMaskType(value); maskType != -1 && arg != nil { + return MASK_TYPE, maskType, arg + } else if strings.HasPrefix(strings.ToLower(value), "0x") { + hexValue, e := strconv.ParseUint(value, 0, 16) + return HEX_TYPE, hexValue, e + } else if IsNumber(value) { + arg, _ := strconv.Atoi(value) + return VALUE_TYPE, arg, nil + } + return NON_TYPE, nil, nil +} + +/* +Four case in checkMask +case 1 : both arguments are IP presentation +case 2 : both arguments are Ether presentation +case 2 : both arguments are hex presentation (for ethertype, etc...) +case 3 : both arguments are integer +Caution : out of range of the cases are not handled. +*/ + +// checkMaskType function checks that the input arguments have what kind of the mask types. +// checkMaskType function only work with the argument what it has "/" character. +func checkMaskType(value string) (int, interface{}) { + if strings.Count(value, "/") == 1 { + var i = strings.IndexByte(value, '/') + m1, _ := net.ParseMAC(value[:i]) + m2, _ := net.ParseMAC(value[i+1:]) + if m1 != nil && m2 != nil && (len(m1) == len(m2)) { + return ETH_MASK, []string{value[:i], value[i+1:]} + } + i1 := net.ParseIP(value[:i]) + i2 := net.ParseIP(value[i+1:]) + if i1 != nil && i2 != nil && (len(i1) == len(i2)) { + return IP_MASK, []string{value[:i], value[i+1:]} + } + if strings.HasPrefix(strings.ToLower(value[:i]), "0x") && + strings.HasPrefix(strings.ToLower(value[i+1:]), "0x") { + c1, _ := strconv.ParseUint(value[:i], 0, 16) + c2, _ := strconv.ParseUint(value[i+1:], 0, 16) + return HEX_MASK, []uint16{uint16(c1), uint16(c2)} + } + if IsNumber(value[:i]) && IsNumber(value[i+1:]) { + a1, _ := strconv.Atoi(value[:i]) + a2, _ := strconv.Atoi(value[i+1:]) + return VALUE_MASK, []int{a1, a2} + } + } + return -1, nil +} + +// parseBitWidth function determines that the input value is what kind of sizes. +func parseBitWidth(value int) int { + if (value > 32) && (value <= 64) { + return INT64 + } else if (value > 16) && (value <= 32) { + return INT32 + } else if (value > 8) && (value <= 16) { + return INT16 + } else if (value > 0) && (value <= 8) { + return INT8 + } else { + return -1 + } +} + +// setBitValue function based on the input bit width to decide what size of the function should be used. +// If the function can't determine the type of the bit width, it will return nil. +func setBitValue(value int, bitWidth int) []byte { + var result []byte + switch bitWidth { + case INT32: + result = util.Int32ToBytes(uint32(value)) + case INT16: + result = util.Int16ToBytes(uint16(value)) + case INT8: + result = util.Int8ToBytes(uint8(value)) + default: + return nil + } + return result +} + +// parseCIDR function copies from net packages. +// parseCIDR function checking the input string has a "/" character or not. +// If does, the function parses the string and checks that the string is CIDR form. +// parseCIDR function only used when the collectedMatchType function has LPM type. +func parseCIDR(s string) (interface{}, int, bool) { + i := strings.IndexByte(s, '/') + if i < 0 { + return nil, -1, false + } + addr, mask := s[:i], s[i+1:] + ip := parseIPv4(addr) + n, i, ok := dtoi(mask) + if ip == nil || !ok || i != len(mask) || n < 0 || n > 32 { + return nil, -1, false + } + m, _ := strconv.Atoi(mask) + return ip, m, true +} + +// dtoi function copies from net package +// dtoi function checks character is numeric and makes it to integer than return. +func dtoi(s string) (n int, i int, ok bool) { + var big = 0xFFFFF + n = 0 + for i = 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { + n = n*10 + int(s[i]-'0') + if n >= big { + return big, i, false + } + } + if i == 0 { + return 0, 0, false + } + return n, i, true +} + +// parseIPv4 function copy form net package +// parseIPv4 function checks that the string is IPv4 form. +// the string must have three cases : "x.x", "x.x.x", "x.x.x.x" +func parseIPv4(s string) []byte { + var size = strings.Count(s, ".") + if size <= 0 || size > 3 { + return nil + } + size++ + p := make([]byte, size) + for i := 0; i < size; i++ { + if len(s) == 0 { + goto ERROR + } + if i > 0 { + if s[0] != '.' { + goto ERROR + } + s = s[1:] + } + n, c, ok := dtoi(s) + if !ok || n > 0xFF { + goto ERROR + } + s = s[c:] + p[i] = byte(n) + } + if len(s) != 0 { + goto ERROR + } + return p +ERROR: + return nil +} + +func DumpEntriesCount(stream *p4.BfRuntime_ReadClient, p4table *bfrt.Table) { + for { + rsp, err := (*stream).Recv() + if err == io.EOF { + break + } + if err != nil { + log.Fatalf("Got error: %v", err) + } + Entities := rsp.GetEntities() + cnt := 0 + if len(Entities) == 0 { + fmt.Printf("The \"%s\" table is empty\n", p4table.Name) + } else { + for _, v := range Entities { + if v.GetTableEntry().IsDefaultEntry{ + continue + } + cnt++ + } + fmt.Printf("Table \"%s\" has %d entries.\n", p4table.Name, cnt) + } + } +} + +// DumpEntries function reads entries from ReadRequest response, and the function print all of the entries. +// The function will terminate when the stream occurs an error and the response entities count has zeros. +func DumpEntries(stream *p4.BfRuntime_ReadClient, p4table *bfrt.Table) { for { rsp, err := (*stream).Recv() if err == io.EOF { @@ -88,31 +392,28 @@ func DumpEntries(stream *p4.BfRuntime_ReadClient, p4table *util.Table) { Entities := rsp.GetEntities() if len(Entities) == 0 { fmt.Printf("The \"%s\" table is empty\n", p4table.Name) - }else { + } else { fmt.Println("--------------------------------------------------------------------------------") fmt.Printf("Table Name : %-s\n", p4table.Name) - for k, v := range Entities { + for kv, v := range Entities { tbl := v.GetTableEntry() if !tbl.IsDefaultEntry { - fmt.Printf("Entry %d:\n", k) + fmt.Printf("Entry %d:\n", kv) } fmt.Println("Match Key Info") if tbl.GetKey() != nil { fmt.Printf(" %-20s %-10s %-16s\n", "Field Name:", "Type:", "Value:") - for k, f := range tbl.Key.Fields { - if f.FieldId == 65537 { - continue - } + for kf, f := range tbl.Key.Fields { switch strings.Split(reflect.TypeOf(f.GetMatchType()).String(), ".")[1] { case "KeyField_Exact_": m := f.GetExact() - fmt.Printf(" %-20s %-10s %-16x\n", p4table.Key[k].Name, "Exact", m.Value) + fmt.Printf(" %-20s %-10s %-16x\n", p4table.Key[kf].Name, "Exact", m.Value) case "KeyField_Ternary_": t := f.GetTernary() - fmt.Printf(" %-20s %-10s %-16x Mask: %-12x\n", p4table.Key[k].Name, "Ternay", t.Value, t.Mask) + fmt.Printf(" %-20s %-10s %-16x Mask: %-12x\n", p4table.Key[kf].Name, "Ternay", t.Value, t.Mask) case "KeyField_Lpm": l := f.GetLpm() - fmt.Printf(" %-20s %-10s %-16x PreFix: %-12d\n", p4table.Key[k].Name, "LPM", l.Value, l.PrefixLen) + fmt.Printf(" %-20s %-10s %-16x PreFix: %-12d\n", p4table.Key[kf].Name, "LPM", l.Value, l.PrefixLen) case "KeyField_Range_": //TODO: Implement range match //r := f.GetRange() @@ -124,22 +425,18 @@ func DumpEntries(stream *p4.BfRuntime_ReadClient, p4table *util.Table) { if tbl.IsDefaultEntry { fmt.Printf("Table default action:\n") } - actionName, _ := printNameById(tbl.Data.ActionId) + actionName, _ := p4Info.GetActionNameById(tbl.Data.ActionId) fmt.Println("Action:", actionName) - if tbl.Data.Fields != nil { fmt.Printf(" %-20s %-16s\n", "Field Name:", "Value:") - for _, d := range p4table.ActionSpecs { - if d.Name == actionName { - for k, data := range tbl.Data.Fields { - if d.Data[k].ID == data.FieldId{ - fmt.Printf(" %-20s %-16x\n", d.Data[k].Name, data.GetStream()) - } - } + for _, datafield := range tbl.Data.Fields { + an, err := printNameById(actionName, datafield.FieldId) + if err { + fmt.Printf(" %-20s %-16x\n", an, datafield.GetStream()) } } } - if k+1 != len(Entities) { + if kv+1 != len(Entities) { fmt.Printf("------------------\n") } } @@ -148,17 +445,101 @@ func DumpEntries(stream *p4.BfRuntime_ReadClient, p4table *util.Table) { } } -// genReadRequestWithId function generates the read request format to read entries of the table via table ID. +// genReadRequestWithId function generates the read request to read table's entries. func genReadRequestWithId(tableId uint32) *p4.ReadRequest { - return &p4.ReadRequest{ - Entities: []*p4.Entity{ - { - Entity: &p4.Entity_TableEntry{ - TableEntry: &p4.TableEntry{ - TableId: tableId, - }, - }, + var req = &p4.ReadRequest{} + req.Entities = append(req.Entities, genEntity(tableId)) + return req +} + +func genEntity(tableId uint32) *p4.Entity { + return &p4.Entity{ + Entity: &p4.Entity_TableEntry{ + TableEntry: &p4.TableEntry{ + TableId: tableId, }, }, } } + +// DeleteEntries function read entries from the response to delete all entries of a table +func DeleteEntries(rsp **p4.ReadResponse, cli *p4.BfRuntimeClient, ctx *context.Context) ([]int, error) { + var result []int + var delReq *p4.WriteRequest = nil + for k, e := range (*rsp).Entities { + tbl := e.GetTableEntry() + if tbl.IsDefaultEntry { + continue + } + if delReq == nil { + delReq = util.GenWriteRequestWithId(p4.Update_DELETE, id.TableId(tbl.TableId), tbl.Key.Fields, nil) + } else { + delReq.Updates = append(delReq.Updates, util.GenUpdateWithId(p4.Update_DELETE, id.TableId(tbl.TableId), tbl.Key.Fields, nil)) + } + result = append(result, k) + } + _, err := (*cli).Write(*ctx, delReq) + if err != nil { + return result, err + } + return result, nil +} + +// BuildMatchKeys function using the input arguments make the KeyField what a table need to match. +func BuildMatchKeys(collectedMatchTypes *[]MatchSet) []*p4.KeyField { + match := util.Match() + for _, v := range *collectedMatchTypes { + mlt, v1, v2 := checkMatchListType(v.matchValue, v.bitWidth) + // In EXACT case, v2 value is always nil. + if v.matchType == enums.MATCH_EXACT { + switch mlt { + case MAC_TYPE: + match = append(match, util.GenKeyField(v.matchType, v.fieldId, v1.([]byte))) + case IP_TYPE: + match = append(match, util.GenKeyField(v.matchType, v.fieldId, v1.([]byte))) + case VALUE_TYPE: + match = append(match, util.GenKeyField(v.matchType, v.fieldId, setBitValue(v1.(int), v.bitWidth))) + case HEX_TYPE: + match = append(match, util.GenKeyField(v.matchType, v.fieldId, util.HexToBytes(uint16(v1.(uint64))))) + default: + fmt.Printf("Unexpect value for EXACT_MATCH : %s\n", v.matchValue) + return nil + } + } else if v.matchType == enums.MATCH_LPM { + if mlt == CIDR_TYPE { + match = append(match, util.GenKeyField(v.matchType, v.fieldId, v1.([]byte), v2.(int))) + } else { + fmt.Printf("Unexpect value for LPM_MATCH : %s\n", v.matchValue) + return nil + } + } else if v.matchType == enums.MATCH_TERNARY { + //Ternary match only support the complete address format(aa:aa:aa:aa:aa:aa/ff:ff:ff:ff:ff:ff, x.x.x.x/255.255.255.255) + if mlt == MASK_TYPE { + switch v1.(int) { + case IP_MASK: + arg := v2.([]string) + match = append(match, util.GenKeyField(v.matchType, v.fieldId, util.Ipv4ToBytes(arg[0]), util.Ipv4ToBytes(arg[1]))) + case ETH_MASK: + arg := v2.([]string) + match = append(match, util.GenKeyField(v.matchType, v.fieldId, util.MacToBytes(arg[0]), util.MacToBytes(arg[1]))) + case HEX_MASK: + arg := v2.([]uint16) + match = append(match, util.GenKeyField(v.matchType, v.fieldId, util.HexToBytes(arg[0]), util.HexToBytes(arg[1]))) + case VALUE_MASK: + arg := v2.([]int) + match = append(match, util.GenKeyField(v.matchType, v.fieldId, setBitValue(arg[0], v.bitWidth), setBitValue(arg[1], v.bitWidth))) + } + } else { + fmt.Printf("Unexpect value for TERNARY_MATCH : %s\n", v.matchValue) + return nil + } + } else if v.matchType == enums.MATCH_RANGE { + //TODO: Implement range match + fmt.Println("Range_Match Not Supported Yet") + return nil + } else { + fmt.Println("Unexpected Match Type") + } + } + return match +} diff --git a/cmd/version.go b/cmd/version.go index 743de33..48b8e0d 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -7,8 +7,8 @@ import ( ) var ( - logo bool - version bool + logo bool + version bool piscLogo string ) @@ -16,13 +16,13 @@ var ( var versionCmd = &cobra.Command{ Use: "version", Short: "Show the pisc-cli version information", - Long: `Show the pisc-cli version information`, + Long: `Show the pisc-cli version information`, Run: func(cmd *cobra.Command, args []string) { if logo { callLogo() fmt.Println(piscLogo) } - fmt.Println("Version Called") + fmt.Println("Version : 0.1.0") }, } @@ -41,17 +41,7 @@ func callLogo() { "|__/\n" } - func init() { rootCmd.AddCommand(versionCmd) versionCmd.Flags().BoolVarP(&logo, "logo", "l", false, "") - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // versionCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // versionCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..fe9449a --- /dev/null +++ b/go.mod @@ -0,0 +1,17 @@ +module github.com/P4Networking/pisc-cli + +go 1.14 + +replace ( + github.com/P4Networking/pisc => ../pisc + github.com/P4Networking/proto => ../proto +) + +require ( + github.com/P4Networking/pisc v0.0.0-00010101000000-000000000000 + github.com/P4Networking/proto v1.0.0 + github.com/mitchellh/go-homedir v1.1.0 + github.com/spf13/cobra v1.0.0 + github.com/spf13/viper v1.7.1 + google.golang.org/grpc v1.32.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..fbb1d21 --- /dev/null +++ b/go.sum @@ -0,0 +1,395 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/P4Networking/netlink v1.1.1/go.mod h1:jphS5KWlRePmRBaqpiFy7OVXLwN971M7FiiSrXeFZ4s= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +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/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +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/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +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/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 h1:W0lCpv29Hv0UaM1LXb9QlBHLNP8UFfcKjblhVCWftOM= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200828030656-73b5761be4c5 h1:SXvXDcZm33V0P03upM01EgN1an0ggw+yntYrnvdWbCU= +google.golang.org/genproto v0.0.0-20200828030656-73b5761be4c5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0= +google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= From f34f84f3606e6d0e16350b5b4b0e9170ffed1812 Mon Sep 17 00:00:00 2001 From: PFtyrant Date: Tue, 15 Dec 2020 18:21:02 +0800 Subject: [PATCH 06/17] Fix del-flow function in tune with PISC --- cmd/utils.go | 15 +++- go.mod | 2 +- go.sum | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 214 insertions(+), 2 deletions(-) diff --git a/cmd/utils.go b/cmd/utils.go index f5c5a72..e1b3317 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -474,7 +474,20 @@ func DeleteEntries(rsp **p4.ReadResponse, cli *p4.BfRuntimeClient, ctx *context. if delReq == nil { delReq = util.GenWriteRequestWithId(p4.Update_DELETE, id.TableId(tbl.TableId), tbl.Key.Fields, nil) } else { - delReq.Updates = append(delReq.Updates, util.GenUpdateWithId(p4.Update_DELETE, id.TableId(tbl.TableId), tbl.Key.Fields, nil)) + delReq.Updates = append(delReq.Updates, &p4.Update{ + Type: p4.Update_DELETE, + Entity: &p4.Entity{ + Entity: &p4.Entity_TableEntry{ + TableEntry: &p4.TableEntry{ + TableId: tbl.TableId, + Key: &p4.TableKey{ + Fields: tbl.Key.Fields, + }, + Data: nil, + }, + }, + }, + }) } result = append(result, k) } diff --git a/go.mod b/go.mod index fe9449a..f0ee16f 100644 --- a/go.mod +++ b/go.mod @@ -13,5 +13,5 @@ require ( github.com/mitchellh/go-homedir v1.1.0 github.com/spf13/cobra v1.0.0 github.com/spf13/viper v1.7.1 - google.golang.org/grpc v1.32.0 + google.golang.org/grpc v1.33.1 ) diff --git a/go.sum b/go.sum index fbb1d21..dd39e88 100644 --- a/go.sum +++ b/go.sum @@ -5,11 +5,32 @@ cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6A cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -18,6 +39,7 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/P4Networking/netlink v1.1.1/go.mod h1:jphS5KWlRePmRBaqpiFy7OVXLwN971M7FiiSrXeFZ4s= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -28,6 +50,9 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +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/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/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -52,6 +77,8 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -60,13 +87,22 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -75,18 +111,30 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 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= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= @@ -96,6 +144,7 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1/go.mod h1:oVMjMN64nzEcepv1kdZKgx1qNYt4Ro0Gqefiq2JWdis= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -117,12 +166,15 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jinzhu/copier v0.0.0-20201025035756-632e723a6687/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= @@ -155,6 +207,7 @@ github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQz github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mostlygeek/arp v0.0.0-20170424181311-541a2129847a/go.mod h1:jZxafo9CAqaKFQE4zitrg5QNlA6CXUsjwXPlIppF3tk= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -178,6 +231,7 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +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/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= @@ -216,12 +270,20 @@ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -238,11 +300,18 @@ golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -253,10 +322,17 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -273,14 +349,37 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -293,18 +392,42 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 h1:W0lCpv29Hv0UaM1LXb9QlBHLNP8UFfcKjblhVCWftOM= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 h1:a/mKvvZr9Jcc8oKfcmgzyp7OwF73JPWsQLvH1z2Kxck= +golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -326,18 +449,58 @@ golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -347,19 +510,50 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200828030656-73b5761be4c5 h1:SXvXDcZm33V0P03upM01EgN1an0ggw+yntYrnvdWbCU= google.golang.org/genproto v0.0.0-20200828030656-73b5761be4c5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154 h1:bFFRpT+e8JJVY7lMMfvezL1ZIwqiwmPl2bsE2yx4HqM= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0= google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1 h1:DGeFlSan2f+WEtCERJ4J9GJWk15TxUi8QGagfI87Xyc= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.1/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -382,6 +576,7 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= @@ -392,4 +587,8 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= From 90e8cbd289ed1d11105321a38caf8f6052633967 Mon Sep 17 00:00:00 2001 From: PFtyrant Date: Thu, 31 Dec 2020 11:58:08 +0000 Subject: [PATCH 07/17] Add read file feature - Make pisc-cli compatible with tiny_router_v2 pipeline. - Modify dump command print format. Using tablewriter package. - Modify info command to use string concatenation instead io buffer. - Add read file feature to set-flow function *W.I.P - Show the progress using progress bar when large number of entries are come. - make the code more compact --- cmd/delFlow.go | 149 ++++++++++++++------------- cmd/dump.go | 96 ++++++------------ cmd/info.go | 122 ++++------------------- cmd/setFlow.go | 204 +++++++++++++++++++++++++------------ cmd/table.go | 13 ++- cmd/utils.go | 266 +++++++++++++++++++++++++++++++++---------------- go.mod | 2 + go.sum | 20 ++++ 8 files changed, 478 insertions(+), 394 deletions(-) diff --git a/cmd/delFlow.go b/cmd/delFlow.go index 785d571..6332663 100644 --- a/cmd/delFlow.go +++ b/cmd/delFlow.go @@ -12,7 +12,7 @@ import ( ) var ( - reset bool + clear bool delEntry []string ) @@ -40,100 +40,107 @@ var delFlowCmd = &cobra.Command{ return argsList, cobra.ShellCompDirectiveNoFileComp }, Run: func(cmd *cobra.Command, args []string) { - - if (all || len(delEntry) > 0) && len(args) <= 0 { - cmd.Help() - return - } - for a, v := range delEntry { - delEntry[a] = strings.Replace(v, " ", "", -1) - } - - cliAddr, ctxAddr, conn, cancel, p4Info, _ := initConfigClient() + cliAddr, ctxAddr, conn, cancel, _, _ := initConfigClient() defer conn.Close() defer cancel() cli := *cliAddr ctx := *ctxAddr - if !reset { - argsList, _ := p4Info.GuessTableName(args[0]) - if len(argsList) != 1 { - for _, v := range argsList { - strs := strings.Split(v, ".") - if strings.EqualFold(strs[2], args[0]) { - args[0] = v - } + if all && !clear && len(args) <= 0 && len(delEntry) <= 0 { + for _, tb := range Obj.p4Info.Tables { + if NotSupportToReadTable[tb.ID] { + continue } - } else { - args[0] = argsList[0] + Obj.table = append(Obj.table, tb) } - } - - for _, v := range p4Info.Tables { - if strings.HasPrefix(v.Name, preFixIg) || strings.HasPrefix(v.Name, preFixEg) { - if (all || len(delEntry) > 0) && v.Name != args[0] { + } else if !all && clear && len(args) > 0 && len(delEntry) <= 0 { + for _, tb := range Obj.p4Info.Tables { + if NotSupportToReadTable[tb.ID] { + continue + } + if strings.Contains(tb.Name, args[0]) { + Obj.table = append(Obj.table, tb) + } + } + } else if !all && !clear && len(args) > 0 && len(delEntry) > 0 { + for a, v := range delEntry { + delEntry[a] = strings.TrimSpace(v) + } + for _, tb := range Obj.p4Info.Tables { + if NotSupportToReadTable[tb.ID] { continue } - stream, err := cli.Read(ctx, genReadRequestWithId(v.ID)) + if strings.Contains(tb.Name, args[0]) { + Obj.table = append(Obj.table, tb) + } + } + if len(Obj.table) > 1 { + fmt.Println(fmt.Errorf("Too many tables matched.")) + for _, k := range Obj.table { + fmt.Printf("Table : %s\n", k.Name) + } + return + } + if len(Obj.table) <=0 { + fmt.Println(fmt.Errorf("No tables matched.\n")) + return + } + + collectedMatchTypes, ok := collectTableMatchTypes(&delEntry) + if !ok { + fmt.Println("Match keys are not matched") + return + } + if match := BuildMatchKeys(&collectedMatchTypes); match != nil { + delReq := util.GenWriteRequestWithId(p4.Update_DELETE, id.TableId(Obj.table[0].ID), match, nil) + _, err := cli.Write(ctx, delReq) if err != nil { - log.Fatalf("Got error, %v \n", err.Error()) + fmt.Println(err) return } + } + return + } else { + fmt.Println(fmt.Errorf("check the flag or args")) + cmd.Help() + return + } + for _, tb := range Obj.table { + stream, err := cli.Read(ctx, genReadRequestWithId(tb.ID)) + if err != nil { + log.Fatalf("Got error, %v \n", err.Error()) + return + } - for { - rsp, err := stream.Recv() - if err == io.EOF { + for { + rsp, err := stream.Recv() + if err == io.EOF { + break + } + if rsp != nil { + if len(rsp.GetEntities()) == 0 { + fmt.Printf("%s table is empty\n", tb.Name) break } - if rsp != nil { - if len(rsp.GetEntities()) == 0 { - fmt.Printf("%s table is empty\n", v.Name) - break - } - var cnt []int - var err error - if all || reset { - cnt, err = DeleteEntries(&rsp, &cli, &ctx) - if err != nil { - fmt.Printf("Failed to delete entry: table \"%s\" with fields: %s\n", v.Name, rsp.Entities[cnt[0]].GetTableEntry().Key.Fields) - } else { - fmt.Printf("%d entires of \"%s\" table have cleared\n", len(cnt), v.Name) - } - } else if len(delEntry) > 0 { - table, _ := p4Info.GetTableById(id.TableId(v.ID)) - collectedMatchTypes, ok := collectTableMatchTypes(table, &delEntry) - if !ok { - fmt.Println("Match keys are not matched") - return - } - fmt.Print("Make Match Key... ") - if match := BuildMatchKeys(&collectedMatchTypes); match != nil { - delReq := util.GenWriteRequestWithId(p4.Update_DELETE, id.TableId(v.ID), match, nil) - fmt.Print("Write Delete Reqeust... ") - _, err := cli.Write(ctx, delReq) - if err != nil { - fmt.Println(err) - return - } - fmt.Println("DONE.") - } else { - fmt.Println("Please Check match keys and inputted arguments.") - } - } + var cnt []int + var err error + cnt, err = DeleteEntries(&rsp, &cli, &ctx) + if err != nil { + fmt.Printf("Failed to delete entry: table \"%s\" with fields: %s\n", tb.Name, rsp.Entities[cnt[0]].GetTableEntry().Key.Fields) + return } + + fmt.Printf("%d entires of \"%s\" table have cleared\n", len(cnt), tb.Name) } } } - if reset { - fmt.Println("Reset complete.") - } }, } func init() { rootCmd.AddCommand(delFlowCmd) - delFlowCmd.Flags().BoolVarP(&all, "all", "a", false, "delete all entries of the table") - delFlowCmd.Flags().BoolVarP(&reset, "reset", "r", false, "clear all of the tables") + delFlowCmd.Flags().BoolVarP(&all, "all", "a", false, "delete all of the entries") + delFlowCmd.Flags().BoolVarP(&clear, "clear", "c", false, "clear the table") delFlowCmd.Flags().StringSliceVarP(&delEntry, "match", "m", []string{}, "delete specific entry by given entry number") } diff --git a/cmd/dump.go b/cmd/dump.go index d0cb488..32563bf 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -3,108 +3,72 @@ package cmd import ( "fmt" "github.com/P4Networking/pisc/southbound/bfrt" - "github.com/P4Networking/pisc/util/enums/id" "github.com/spf13/cobra" "log" "strings" ) + var ( - // all bool(define in table.go) count bool ) -// dumpCmd represents the dump command var dumpCmd = &cobra.Command{ Use: "dump TABLE-NAME", Short: "Dump the existed entries in the specific table", Long: `Display all existed entries in the specific table`, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - _, _, conn, cancel, p4Info, _ := initConfigClient() + _, _, conn, cancel, _, _ := initConfigClient() defer conn.Close() defer cancel() - var argsList []string - for _, v := range p4Info.Tables { - if strings.Contains(v.Name, preFixIg) || strings.Contains(v.Name, preFixEg) { - strs := strings.Split(v.Name, ".") - if toComplete == "" || strings.Contains(toComplete, "pipe") { - argsList = append(argsList, v.Name) - } else { - argsList = append(argsList, strs[2]) - } - } - } + argsList, _ := Obj.p4Info.GuessTableName(toComplete) return argsList, cobra.ShellCompDirectiveNoFileComp }, Run: func(cmd *cobra.Command, args []string) { - cliAddr, ctxAddr, conn, cancel, p4Info, _ := initConfigClient() + cliAddr, ctxAddr, conn, cancel, _, _ := initConfigClient() defer conn.Close() defer cancel() cli := *cliAddr ctx := *ctxAddr - switch all { - case false: - if len(args) <= 0 { - cmd.Help() - return - } + resultTables := make([]bfrt.Table, 0) + notFounded := make([]string, 0) + + if len(args) == 0 { + resultTables = Obj.p4Info.Tables + } - argsList, _ := p4Info.GuessTableName(args[0]) - if len(argsList) != 1 { - for _, v := range argsList { - strs := strings.Split(v, ".") - if strings.EqualFold(strs[2], args[0]) { - args[0] = v - } + for _, name := range args { + found := false + for _, table := range Obj.p4Info.Tables { + if strings.Contains(table.Name, name) { + resultTables = append(resultTables, table) + found = true } - } else { - args[0] = argsList[0] } - - tableId, ok := p4Info.GetTableId(args[0]) - if uint32(tableId) == bfrt.ID_NOT_FOUND || !ok { - fmt.Printf("Can not found table with name: %s\n", args[0]) - return + if !found { + notFounded = append(notFounded, name) } - table, ok := p4Info.GetTableById(tableId) - if !ok { - fmt.Printf("Can not found table with ID: %d\n", tableId) - return + } + + for _, v := range resultTables { + if NotSupportToReadTable[v.ID] { + continue } - stream, err := cli.Read(ctx, genReadRequestWithId(table.ID)) + stream, err := cli.Read(ctx, genReadRequestWithId(v.ID)) if err != nil { log.Fatalf("Got error, %v \n", err.Error()) + return } - if count { - DumpEntriesCount(&stream, table) - } else { - DumpEntries(&stream, table) - } - case true: - for _, v := range p4Info.Tables { - if strings.HasPrefix(v.Name, preFixIg) || strings.HasPrefix(v.Name, preFixEg) { - table, _ := p4Info.GetTableById(id.TableId(v.ID)) - if table == nil { - fmt.Printf("Can not found table with ID: %v\n", v.ID) - return - } - stream, err := cli.Read(ctx, genReadRequestWithId(v.ID)) - if err != nil { - log.Fatalf("Got error, %v \n", err.Error()) - } - if count { - DumpEntriesCount(&stream, table) - } else { - DumpEntries(&stream, table) - } - } - } + DumpEntries(&stream, &v) + } + + for _, v := range notFounded { + fmt.Println(fmt.Errorf("Couldn't found %s table", v)) } }, } func init() { rootCmd.AddCommand(dumpCmd) - dumpCmd.Flags().BoolVarP(&all, "all", "a", false, "dump all of the tables") dumpCmd.Flags().BoolVarP(&count, "count", "c", false, "dump entries number of counts") } diff --git a/cmd/info.go b/cmd/info.go index de882cd..7d6dd55 100644 --- a/cmd/info.go +++ b/cmd/info.go @@ -12,7 +12,6 @@ var infoCmd = &cobra.Command{ Use: "info TABLE-NAME", Short: "Show information about table", Long: `Display the detail of table.`, - Args: cobra.ExactArgs(1), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { _, _, conn, cancel, p4Info, _ := initConfigClient() defer conn.Close() @@ -21,126 +20,45 @@ var infoCmd = &cobra.Command{ var argsList []string for _, v := range p4Info.Tables { if strings.Contains(v.Name, preFixIg) || strings.Contains(v.Name, preFixEg) { - strs := strings.Split(v.Name, ".") - if toComplete == "" || strings.Contains(toComplete, "pipe") { - argsList = append(argsList, v.Name) - } else { - argsList = append(argsList, strs[2]) - } + argsList = append(argsList, v.Name) } } return argsList, cobra.ShellCompDirectiveNoFileComp }, Run: func(cmd *cobra.Command, args []string) { - - _, _, conn, cancel, p4Info, _ := initConfigClient() + _, _, conn, cancel, _, _ := initConfigClient() defer conn.Close() defer cancel() - /* non-p4Info not used yet. If you need to see non-p4 object, - please open the issue to talk about this. - tableList, ok := nonP4Info.GuessTableName(args[0]) - if !ok { - fmt.Printf("Can not found the table %s\n", args[0]) - return - } - */ - argsList, _ := p4Info.GuessTableName(args[0]) - if len(argsList) != 1 { - for _, v := range argsList { - strs := strings.Split(v, ".") - if strings.EqualFold(strs[2], args[0]) { - args[0] = v - } - } - } else { - args[0] = argsList[0] - } - - tableId, _ := p4Info.GetTableId(args[0]) - if uint32(tableId) == bfrt.ID_NOT_FOUND { - fmt.Printf("Can't found table with name: %s\n", args[0]) - return - } + resultTables := make([]bfrt.Table, 0) + notFounded := make([]string, 0) - table, _ := p4Info.GetTableById(tableId) - if table == nil { - fmt.Printf("Can not found table with Id %d\n", tableId) - return + if len(args) == 0 { + resultTables = Obj.p4Info.Tables } - fmt.Println("--------------------------------------------------------------------------------") - fmt.Println("Table Info") - if table.Name != "" { - fmt.Printf(" %-12s: %-6s\n", "Name", table.Name) - } - if table.ID != 0 { - fmt.Printf(" %-12s: %-6d\n", "ID", table.ID) - } - if table.TableType != "" { - fmt.Printf(" %-12s: %-6s\n", "Type", table.TableType) - } - if table.Size != 0 { - fmt.Printf(" %-12s: %-6d\n", "Size", table.Size) - } - if table.Annotations != nil { - fmt.Printf(" %-12s:\n", "Annotations") - for k, v := range table.Annotations { - if v.Value != "" { - fmt.Printf(" %d - Name: %s | Value: %s \n", k+1, v.Name, v.Value) - } else { - fmt.Printf(" %d - Name: %s \n", k+1, v.Name) + for _, name := range args { + found := false + for _, table := range Obj.p4Info.Tables { + if strings.Contains(table.Name, name) { + resultTables = append(resultTables, table) + found = true } } - } - if table.DependsOn != nil { - fmt.Printf("%-12s: %-6s\n", "Table DependsOn", table.DependsOn) - } - - if table.Key != nil { - fmt.Println("--------------------------------------------------------------------------------") - fmt.Printf("%-s\n", "Match Key Info") - fmt.Printf(" %-8s %-20s %-11s %-10s %-9s %-8s %-4s", - "KeyId", "Name", "Match_type", "Mandatory", "Repeated", "Type", "Width\n") - for _, v := range table.Key { - if v.Name == "$MATCH_PRIORITY" { - fmt.Printf(" %-8d %-20s %-11s %-10t %-9t %-8s %-4d\n", - v.ID, v.Name, v.MatchType, v.Mandatory, v.Repeated, v.Type.Type, 32) - } else { - fmt.Printf(" %-8d %-20s %-11s %-10t %-9t %-8s %-4d\n", - v.ID, v.Name, v.MatchType, v.Mandatory, v.Repeated, v.Type.Type, v.Type.Width) - } + if !found { + notFounded = append(notFounded, name) } } - if table.Data != nil { - fmt.Println("--------------------------------------------------------------------------------") - fmt.Printf("%-s\n", "Table Data Info") - fmt.Printf(" %-8s %-20s %-10s %-9s %-8s\n", - "KeyId", "Name", "Mandatory", "Repeated", "Type") - for _, v := range table.Data { - fmt.Printf(" %-8d %-20s %-10t %-9t %-8s\n", - v.Singleton.ID, v.Singleton.Name, v.Mandatory, v.Singleton.Repeated, v.Singleton.Type.Type) + for _, v := range resultTables { + if NotSupportToReadTable[v.ID] { + continue } + InfoEntries(v) } - if table.ActionSpecs != nil { - fmt.Println("--------------------------------------------------------------------------------") - fmt.Printf("%-s\n", "Action Info") - for _, v := range table.ActionSpecs { - fmt.Printf(" ID: %-6d, Name: %-20s \n", v.ID, v.Name) - if v.Data != nil { - fmt.Println(" ----------------------------------------------------------------") - for _, d := range v.Data { - fmt.Printf(" %-6s %-20s %-10s %-9s %-8s %-4s\n", - "ID", "Name", "Mandatory", "Repeated", "Type", "Width") - fmt.Printf(" %-6d %-20s %-10t %-9t %-8s %-4d\n", - d.ID, d.Name, d.Mandatory, d.Repeated, d.Type.Type, d.Type.Width) - } - fmt.Println(" ----------------------------------------------------------------") - } - } - fmt.Println("--------------------------------------------------------------------------------") + for _, v := range notFounded { + fmt.Println(fmt.Errorf("Couldn't found %s table", v)) } }, } diff --git a/cmd/setFlow.go b/cmd/setFlow.go index 80abec7..d742b5e 100644 --- a/cmd/setFlow.go +++ b/cmd/setFlow.go @@ -1,115 +1,189 @@ package cmd import ( + "bufio" + "flag" "fmt" - "github.com/P4Networking/pisc/southbound/bfrt" "github.com/P4Networking/pisc/util" + "github.com/P4Networking/pisc/util/enums/id" "github.com/P4Networking/proto/go/p4" "github.com/spf13/cobra" "log" + "os" "strconv" "strings" ) var ( - matchLists []string - actionValues []string - ttl = "" + matchKeyList []string + actionValues []string + ttl = "" + file string + + filedata [][]string ) // setFlowCmd represents the setFlow command var setFlowCmd = &cobra.Command{ Use: "set-flow TABLE_NAME ACTION-NAME ", Short: "Set flow into table", - Long: `Insert the flow to table with action`, - Args: cobra.ExactArgs(2), + Long: "Insert the flow to table with action", + Args: cobra.MaximumNArgs(2), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - _, _, conn, cancel, p4Info, _ := initConfigClient() + _, _, conn, cancel, _, _ := initConfigClient() defer conn.Close() defer cancel() - argsList, _ := p4Info.GuessTableName(toComplete) - for k, v := range argsList { + table, _ := Obj.p4Info.GuessTableName(toComplete) + for k, v := range table { if strings.Contains(v, preFixIgPar) || strings.Contains(v, preFixEgPar) { - argsList[k] = argsList[len(argsList)-1] // Copy last element to index i. - argsList[len(argsList)-1] = "" // Erase last element (write zero value). - argsList = argsList[:len(argsList)-1] + table[k] = table[len(table)-1] // Copy last element to index i. + table[len(table)-1] = "" // Erase last element (write zero value). + table = table[:len(table)-1] } } - return argsList, cobra.ShellCompDirectiveNoFileComp + return table, cobra.ShellCompDirectiveNoFileComp }, - Run: func(cmd *cobra.Command, args []string) { + PreRun: func(cmd *cobra.Command, args []string) { - for a, v := range matchLists { - matchLists[a] = strings.Replace(v, " ", "", -1) + if cmd.Flag("file").Changed && (cmd.Flag("match").Changed || cmd.Flag("action").Changed || cmd.Flag("ttl").Changed) { + fmt.Println(fmt.Errorf("file flag can only exist alone.")) + os.Exit(1) } - - for a, v := range actionValues { - actionValues[a] = strings.Replace(v, " ", "", -1) + if cmd.Flag("file").Changed { + fptr := flag.String("fpath", file, "file path to read from") + flag.Parse() + f, err := os.Open(*fptr) + if err != nil { + log.Fatal(err) + } + defer func() { + if err = f.Close(); err != nil { + log.Fatal(err) + } + }() + s := bufio.NewScanner(f) + for s.Scan() { + filedata = append(filedata, strings.Split(strings.ReplaceAll(s.Text(), ", ", ","), " ")) + } + err = s.Err() + if err != nil { + log.Fatal(err) + } } + }, + Run: func(cmd *cobra.Command, args []string) { + if cmd.Flag("file").Changed { + setFlowSub.Flags().StringSliceVarP(&matchKeyList, "match", "m", []string{}, "match key arguments") + setFlowSub.Flags().StringSliceVarP(&actionValues, "action", "a", []string{}, "action arguments") + setFlowSub.Flags().StringVarP(&ttl, "ttl", "t", "", "TTL arguments") + for _, line := range filedata { + err := setFlowSub.ParseFlags(line) + matchKeyList = strings.Split(matchKeyList[0], ",") + if actionValues[0] == ""{ + actionValues = nil + } else { + actionValues = strings.Split(actionValues[0], ",") + } + if err != nil { + panic(err) + } + setFlowSub.Run(cmd, line[:2]) + matchKeyList = nil + actionValues = nil + ttl = "" + } + } else { + setFlowSub.Flags().StringSliceVarP(&matchKeyList, "match", "m", matchKeyList, "match key arguments") + setFlowSub.Flags().StringSliceVarP(&actionValues, "action", "a", actionValues, "action arguments") + setFlowSub.Flags().StringVarP(&ttl, "ttl", "t", ttl, "TTL arguments") + setFlowSub.Run(cmd,args) + } + }, +} - cliAddr, ctxAddr, conn, cancel, p4Info, _ := initConfigClient() +var setFlowSub = &cobra.Command{ + Run: func(cmd *cobra.Command, args []string) { + ObjInit() + cliAddr, ctxAddr, conn, cancel, _, _ := initConfigClient() defer conn.Close() defer cancel() cli := *cliAddr ctx := *ctxAddr - argsList, _ := p4Info.GuessTableName(args[0]) - if len(argsList) != 1 { - for _, v := range argsList { - strs := strings.Split(v, ".") - if strings.EqualFold(strs[2], args[0]) { - args[0] = v - } + for a, v := range matchKeyList { + matchKeyList[a] = strings.TrimSpace(v) + } + for a, v := range actionValues { + actionValues[a] = strings.TrimSpace(v) + } + // find the table that have substring + for _, tb := range Obj.p4Info.Tables { + if strings.Contains(tb.Name, args[0]) { + Obj.table = append(Obj.table, tb) } - } else { - args[0] = argsList[0] } - - tableName := args[0] - actionName := args[1] - tableId, ok := p4Info.GetTableId(tableName) - if uint32(tableId) == bfrt.ID_NOT_FOUND || !ok { - fmt.Printf("Can not found table with name: %s\n", tableName) + if len(Obj.table) > 1 { + fmt.Println(fmt.Errorf("Too many tables matched.")) + for _, k := range Obj.table { + fmt.Printf("Table : %s\n", k.Name) + } + return + } + if len(Obj.table) <= 0 { + fmt.Println(fmt.Errorf("No tables matched.\n")) return } - table, _ := p4Info.GetTableById(tableId) - collectedMatchTypes, ok := collectTableMatchTypes(table, &matchLists) - if !ok { - fmt.Println("Match keys are not matched") + //Obj.actions = make(map[uint32]string, 0) + for _, table := range Obj.table { + for _, actionSpec := range table.ActionSpecs { + if strings.Contains(actionSpec.Name, args[1]) { + Obj.actions[actionSpec.ID] = actionSpec.Name + Obj.actionId = actionSpec.ID + Obj.actionName = actionSpec.Name + } + } + } + if len(Obj.actions) > 1 { + fmt.Println(fmt.Errorf("Too many actions matched.\n")) + return + } + if len(Obj.actions) <= 0 { + fmt.Println(fmt.Errorf("No actions have matched.\n")) return } - actionId, ok := p4Info.GetActionId(tableName, actionName) - if actionId == bfrt.ID_NOT_FOUND || !ok { - fmt.Printf("Can not found action with names: %s\n", actionName) + collectedMatchTypes, ok := collectTableMatchTypes(&matchKeyList) + if !ok { + fmt.Println("Match key length isn't match") return } - dataId, ok := p4Info.GetDataId(tableName, "$ENTRY_TTL") + + ttlId, ok := Obj.p4Info.GetDataId(Obj.table[0].Name, "$ENTRY_TTL") if ok && ttl == "" { - fmt.Printf("Please set the TTL value for table %s\n", table.Name) - return + fmt.Println("table has ttl entry but it's not set, using default value 600 for ttl") + ttl = "600" } - collectedActionFieldIds, err := collectActionFieldIds(table, actionId, actionValues) + collectedActionFieldIds, err := collectActionFieldIds(&Obj.table[0], Obj.actionId, actionValues) if err != nil { fmt.Println(err) return } if len(collectedActionFieldIds) != len(actionValues) { - fmt.Printf("Length of action fields [%d] != Length of action args [%d]\n", len(collectedActionFieldIds), len(actionValues)) + fmt.Printf("expected action field length : %d, received action filed length [%d]\n", len(collectedActionFieldIds), len(actionValues)) fmt.Println("Check action arguments") return } - fmt.Printf("Make Match Data...") + //fmt.Printf("Make Match Data...") match := BuildMatchKeys(&collectedMatchTypes) if match == nil { return } - fmt.Printf(" Make Action Data...") + //fmt.Printf(" Make Action Data...") action := util.Action() - if len(collectedActionFieldIds) != 0 { + if len(collectedActionFieldIds) > 0 { for _, v := range collectedActionFieldIds { switch mlt, v1, _ := checkMatchListType(v.actionValue, v.parsedBitWidth); mlt { case MAC_TYPE: @@ -124,32 +198,32 @@ var setFlowCmd = &cobra.Command{ } } } - if ttl != "" { - if !ok { - fmt.Println("ttl set failed") - return - } - l, err :=strconv.ParseUint(ttl, 10 , 32) + + if ok { + l, err := strconv.ParseUint(ttl, 10, 32) if err != nil { fmt.Printf("Please Check the TTL value %s.\n", ttl) return } - action = append(action, util.GenDataField(dataId, util.Int32ToBytes(uint32(l)))) + action = append(action, util.GenDataField(ttlId, util.Int32ToBytes(uint32(l)))) } - fmt.Printf(" Make Write Request...") - var req = util.GenWriteRequestWithId(p4.Update_INSERT, tableId, match, &p4.TableData{ActionId: actionId, Fields: action}) + //fmt.Printf(" Make Write Request...\n") + var req = util.GenWriteRequestWithId(p4.Update_INSERT, id.TableId(Obj.table[0].ID), match, &p4.TableData{ActionId: Obj.actionId, Fields: action}) if _, err := cli.Write(ctx, req); err != nil { - log.Printf("Got error, %v \n", err.Error()) - } else { - fmt.Printf(" Write Done.\n") + log.Printf("Got an error, %v \n", err.Error()) + return } + + fmt.Printf("Write Done.\n") }, } + func init() { rootCmd.AddCommand(setFlowCmd) - setFlowCmd.Flags().StringSliceVarP(&matchLists, "match", "m", []string{}, "match arguments") + setFlowCmd.Flags().StringVarP(&file, "file", "f", "", "read flow file to insert the flow entry") + setFlowCmd.Flags().StringSliceVarP(&matchKeyList, "match", "m", []string{}, "match key arguments") setFlowCmd.Flags().StringSliceVarP(&actionValues, "action", "a", []string{}, "action arguments") - setFlowCmd.Flags().StringVarP(&ttl, "ttl", "t", ttl, "TTL arguments") -} + setFlowCmd.Flags().StringVarP(&ttl, "ttl", "t", "", "TTL arguments") +} \ No newline at end of file diff --git a/cmd/table.go b/cmd/table.go index 688dea9..ad5b1f1 100644 --- a/cmd/table.go +++ b/cmd/table.go @@ -17,20 +17,23 @@ var tableCmd = &cobra.Command{ Short: "List all tables", Long: `List all tables in BFRTInfo which include P4 and Non-P4 tables`, Run: func(cmd *cobra.Command, args []string) { - _, _, conn, cancel, p4Info, nonP4Info := initConfigClient() + _, _, conn, cancel, _, _ := initConfigClient() defer conn.Close() defer cancel() - //fmt.Println("------ The following is for P4 table ------") - for _, v := range p4Info.Tables { + fmt.Println("------ The P4 table ------") + for _, v := range Obj.p4Info.Tables { + if NotSupportToReadTable[v.ID] { + continue + } if strings.Contains(v.Name, preFixIg) || strings.Contains(v.Name, preFixEg) { fmt.Println(v.Name) } } if all { - fmt.Println("------ The following is for non-P4 table ------") - for _, v := range nonP4Info.Tables { + fmt.Println("------ The non-P4 table ------") + for _, v := range Obj.nonP4Info.Tables { fmt.Println(v.Name) } } diff --git a/cmd/utils.go b/cmd/utils.go index e1b3317..f5d760b 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -4,17 +4,20 @@ import ( "bytes" "context" "encoding/gob" + "encoding/hex" "fmt" "github.com/P4Networking/pisc/southbound/bfrt" "github.com/P4Networking/pisc/util" "github.com/P4Networking/pisc/util/enums" "github.com/P4Networking/pisc/util/enums/id" "github.com/P4Networking/proto/go/p4" + "github.com/olekukonko/tablewriter" "google.golang.org/grpc" "io" "log" "math" "net" + "os" "reflect" "strconv" "strings" @@ -60,18 +63,49 @@ type ActionSet struct { parsedBitWidth int } +// Struct Embedding gives the capability to expand its own new method with an existing type. +type BfRtInfo struct { + bfrt.BfRtInfo +} + +type EtnryObj struct { + + p4Info BfRtInfo + nonP4Info BfRtInfo + + table []bfrt.Table + + actions map[uint32] string + actionName string + actionId uint32 +} + var ( + preFixIg = "pipe.SwitchIngress" + preFixEg = "pipe.SwitchEgress" + preFixIgPar = "pipe.SwitchIngressParser" + preFixEgPar = "pipe.SwitchEgressParser" DEFAULT_ADDR = ":50000" - p4Info bfrt.BfRtInfo - nonP4Info bfrt.BfRtInfo - preFixIg = "pipe.SwitchIngress." - preFixEg = "pipe.SwitchEgress." - preFixIgPar = "pipe.SwitchIngressParser." - preFixEgPar = "pipe.SwitchEgressParser." + // true : not support to read; false : support to read + NotSupportToReadTable = map[uint32] bool { + 2432705822 : true, // "pipe.$SNAPSHOT_EGRESS" + 2449483038 : true, // "pipe.$SNAPSHOT_EGRESS_LIVENESS" + 2432703071 : true, // "pipe.$SNAPSHOT_INGRESS" + 2449480287 : true, // "pipe.$SNAPSHOT_INGRESS_LIVENESS" + 2415950168 : true} // "pipe.SwitchIngressParser.$PORT_METADATA" + + Obj EtnryObj ) -func initConfigClient() (*p4.BfRuntimeClient, *context.Context, *grpc.ClientConn, context.CancelFunc, *bfrt.BfRtInfo, *bfrt.BfRtInfo) { +func ObjInit() { + Obj.actionId = 0 + Obj.actionName = "" + Obj.table = []bfrt.Table{} + Obj.actions = make(map[uint32]string, 0) +} + +func initConfigClient() (*p4.BfRuntimeClient, *context.Context, *grpc.ClientConn, context.CancelFunc, *BfRtInfo, *BfRtInfo) { if server == "" { server = DEFAULT_ADDR } @@ -89,38 +123,33 @@ func initConfigClient() (*p4.BfRuntimeClient, *context.Context, *grpc.ClientConn log.Fatalf("Error with %v", err) } - err = gob.NewDecoder(bytes.NewReader(rsp.Config[0].BfruntimeInfo)).Decode(&p4Info) + err = gob.NewDecoder(bytes.NewReader(rsp.Config[0].BfruntimeInfo)).Decode(&Obj.p4Info) if err != nil { log.Fatal("decode error 1:", err) } - err = gob.NewDecoder(bytes.NewReader(rsp.NonP4Config.BfruntimeInfo)).Decode(&nonP4Info) + err = gob.NewDecoder(bytes.NewReader(rsp.NonP4Config.BfruntimeInfo)).Decode(&Obj.nonP4Info) if err != nil { log.Fatal("decode error 2:", err) } - return &cli, &ctx, conn, cancel, &p4Info, &nonP4Info + return &cli, &ctx, conn, cancel, &Obj.p4Info, &Obj.nonP4Info } -func printNameById(actionName string, id uint32) (string, bool) { +func PrintNameById(actionName string, id uint32) (string, bool) { var name string var ok bool - name, ok = p4Info.GetActionNameById(id) + name, ok = Obj.p4Info.GetActionNameById(id) if ok == true { return name, true } - name, ok = p4Info.GetDataNameById(id) + name, ok = Obj.p4Info.GetDataNameById(id) if ok == true { return name, true } - name, ok = p4Info.GetActionParameterNameById(actionName, id) - if ok == true { - return name, true - } - - name, ok = p4Info.GetDataNameById(id) + name, ok = Obj.p4Info.GetActionParameterNameById(actionName, id) if ok == true { return name, true } @@ -130,9 +159,10 @@ func printNameById(actionName string, id uint32) (string, bool) { // collectTableMatchTypes function collects the match key's type and bit width. // the collected type and bit width determine what kind of the input should be used. -func collectTableMatchTypes(table *bfrt.Table, matchKey *[]string) ([]MatchSet, bool) { +func collectTableMatchTypes(matchKey *[]string) ([]MatchSet, bool) { + table := Obj.table[0] if len(table.Key) != len(*matchKey) { - fmt.Printf("Length of Match keys [%d] != Length of match args [%d]\n", len(table.Key), len(matchLists)) + fmt.Printf("expected match key length : %d, received match key length : %d\n", len(table.Key), len(*matchKey)) return nil, false } @@ -353,94 +383,163 @@ ERROR: return nil } -func DumpEntriesCount(stream *p4.BfRuntime_ReadClient, p4table *bfrt.Table) { - for { - rsp, err := (*stream).Recv() - if err == io.EOF { - break +func InfoEntries(table bfrt.Table) { + + result := fmt.Sprintln("--------------------------------------------------------------------------------") + result += "Table Info\n" + if table.Name != "" { + result += fmt.Sprintf(" %-12s: %-6s\n", "Name", table.Name) + } + if table.ID != 0 { + result += fmt.Sprintf(" %-12s: %-6d\n", "ID", table.ID) + } + if table.TableType != "" { + result += fmt.Sprintf(" %-12s: %-6s\n", "Type", table.TableType) + } + if table.Size != 0 { + result += fmt.Sprintf(" %-12s: %-6d\n", "Size", table.Size) + } + if table.Annotations != nil { + result += fmt.Sprintf(" %-12s:\n", "Annotations") + for k, v := range table.Annotations { + if v.Value != "" { + result += fmt.Sprintf(" %d - Name: %s | Value: %s \n", k+1, v.Name, v.Value) + } else { + result += fmt.Sprintf(" %d - Name: %s \n", k+1, v.Name) + } } - if err != nil { - log.Fatalf("Got error: %v", err) + } + if table.DependsOn != nil { + result += fmt.Sprintf("%-12s: %-6s\n", "Table DependsOn", table.DependsOn) + } + + if table.Key != nil { + result += fmt.Sprintln("--------------------------------------------------------------------------------") + result += fmt.Sprintf("%-s\n", "Match Key Info") + result += fmt.Sprintf(" %-8s %-20s %-11s %-10s %-9s %-8s %-4s", + "KeyId", "Name", "Match_type", "Mandatory", "Repeated", "Type", "Width\n") + for _, v := range table.Key { + if v.Name == "$MATCH_PRIORITY" { + result += fmt.Sprintf(" %-8d %-20s %-11s %-10t %-9t %-8s %-4d\n", + v.ID, v.Name, v.MatchType, v.Mandatory, v.Repeated, v.Type.Type, 32) + } else { + result += fmt.Sprintf(" %-8d %-20s %-11s %-10t %-9t %-8s %-4d\n", + v.ID, v.Name, v.MatchType, v.Mandatory, v.Repeated, v.Type.Type, v.Type.Width) + } } - Entities := rsp.GetEntities() - cnt := 0 - if len(Entities) == 0 { - fmt.Printf("The \"%s\" table is empty\n", p4table.Name) - } else { - for _, v := range Entities { - if v.GetTableEntry().IsDefaultEntry{ - continue + } + + if table.Data != nil { + result += fmt.Sprintln("--------------------------------------------------------------------------------") + result += fmt.Sprintf("%-s\n", "Table Data Info") + result += fmt.Sprintf(" %-8s %-20s %-10s %-9s %-8s\n", + "KeyId", "Name", "Mandatory", "Repeated", "Type") + for _, v := range table.Data { + result += fmt.Sprintf(" %-8d %-20s %-10t %-9t %-8s\n", + v.Singleton.ID, v.Singleton.Name, v.Mandatory, v.Singleton.Repeated, v.Singleton.Type.Type) + } + } + + if table.ActionSpecs != nil { + result += fmt.Sprintln("--------------------------------------------------------------------------------") + result += fmt.Sprintf("%-s\n", "Action Info") + for _, v := range table.ActionSpecs { + result += fmt.Sprintf(" ID: %-6d, Name: %-20s \n", v.ID, v.Name) + if v.Data != nil { + result += fmt.Sprintln(" ----------------------------------------------------------------") + for _, d := range v.Data { + result += fmt.Sprintf(" %-6s %-20s %-10s %-9s %-8s %-4s\n", + "ID", "Name", "Mandatory", "Repeated", "Type", "Width") + result += fmt.Sprintf(" %-6d %-20s %-10t %-9t %-8s %-4d\n", + d.ID, d.Name, d.Mandatory, d.Repeated, d.Type.Type, d.Type.Width) } - cnt++ + result += fmt.Sprintln(" ----------------------------------------------------------------") } - fmt.Printf("Table \"%s\" has %d entries.\n", p4table.Name, cnt) } + result += fmt.Sprintln("--------------------------------------------------------------------------------") } + fmt.Print(result) } -// DumpEntries function reads entries from ReadRequest response, and the function print all of the entries. -// The function will terminate when the stream occurs an error and the response entities count has zeros. +// DumpEntries function reads the entries from PISC via ReadRequest. func DumpEntries(stream *p4.BfRuntime_ReadClient, p4table *bfrt.Table) { for { + mkWrt := tablewriter.NewWriter(os.Stdout) + mkWrt.SetAlignment(tablewriter.ALIGN_CENTER) + + adWrt:= tablewriter.NewWriter(os.Stdout) + adWrt.SetAlignment(tablewriter.ALIGN_CENTER) + rsp, err := (*stream).Recv() if err == io.EOF { break } if err != nil { log.Fatalf("Got error: %v", err) + return } Entities := rsp.GetEntities() if len(Entities) == 0 { fmt.Printf("The \"%s\" table is empty\n", p4table.Name) + return } else { - fmt.Println("--------------------------------------------------------------------------------") - fmt.Printf("Table Name : %-s\n", p4table.Name) - for kv, v := range Entities { - tbl := v.GetTableEntry() - if !tbl.IsDefaultEntry { - fmt.Printf("Entry %d:\n", kv) - } - fmt.Println("Match Key Info") - if tbl.GetKey() != nil { - fmt.Printf(" %-20s %-10s %-16s\n", "Field Name:", "Type:", "Value:") - for kf, f := range tbl.Key.Fields { - switch strings.Split(reflect.TypeOf(f.GetMatchType()).String(), ".")[1] { - case "KeyField_Exact_": - m := f.GetExact() - fmt.Printf(" %-20s %-10s %-16x\n", p4table.Key[kf].Name, "Exact", m.Value) - case "KeyField_Ternary_": - t := f.GetTernary() - fmt.Printf(" %-20s %-10s %-16x Mask: %-12x\n", p4table.Key[kf].Name, "Ternay", t.Value, t.Mask) - case "KeyField_Lpm": - l := f.GetLpm() - fmt.Printf(" %-20s %-10s %-16x PreFix: %-12d\n", p4table.Key[kf].Name, "LPM", l.Value, l.PrefixLen) - case "KeyField_Range_": - //TODO: Implement range match - //r := f.GetRange() - //fmt.Printf(" %-20s %-10s High: %-8x Low: %-8x\n", p4table.Key[k].Name, "LPM", r.High, r.Low) + if count { + fmt.Printf("Table \"%s\" has %d entries\n", p4table.Name, len(Entities)) + } else { + str := "--------------------------------------------------------------------------------\n" + str += fmt.Sprintf("Table Name : %s", p4table.Name) + fmt.Println(str) + mkWrt.SetHeader([]string{"Field Name", "Type", "Value", "Mask/PreFix"}) + for kv, v := range Entities { + tbl := v.GetTableEntry() + fmt.Println(fmt.Sprintf("\nEntry : %d\nMatch Key Info", kv)) + // Match Keys + if tbl.GetKey() != nil { + iter := 0 + for k, mk := range p4table.Key { + f := tbl.Key.Fields[iter] + if mk.ID == f.FieldId { + switch strings.Split(reflect.TypeOf(f.GetMatchType()).String(), ".")[1] { + case "KeyField_Exact_": + m := f.GetExact() + mkWrt.Append([]string{p4table.Key[k].Name, "Exact", hex.EncodeToString(m.Value), "None"}) + case "KeyField_Ternary_": + t := f.GetTernary() + mkWrt.Append([]string{p4table.Key[k].Name, "Ternary", hex.EncodeToString(t.Value), hex.EncodeToString(t.Mask)}) + case "KeyField_Lpm": + l := f.GetLpm() + mkWrt.Append([]string{p4table.Key[k].Name, "LPM", string(l.Value), string(l.PrefixLen)}) + // TODO : Range match field + //case "KeyField_Range_": + // //r := f.GetRange() + // //fmt.Printf(" %-20s %-10s High: %-8x Low: %-8x\n", p4table.Key[k].Name, "LPM", r.High, r.Low) + } + iter++ + } else { + mkWrt.Append([]string{p4table.Key[k].Name, "None", "None", "None"}) + } } + mkWrt.Render() + mkWrt.ClearRows() } - } - if tbl.IsDefaultEntry { - fmt.Printf("Table default action:\n") - } - actionName, _ := p4Info.GetActionNameById(tbl.Data.ActionId) - fmt.Println("Action:", actionName) - if tbl.Data.Fields != nil { - fmt.Printf(" %-20s %-16s\n", "Field Name:", "Value:") - for _, datafield := range tbl.Data.Fields { - an, err := printNameById(actionName, datafield.FieldId) - if err { - fmt.Printf(" %-20s %-16x\n", an, datafield.GetStream()) + // Action Field + actionName, _ := Obj.p4Info.GetActionNameById(tbl.Data.ActionId) + fmt.Println("Action:", actionName) + if tbl.Data.Fields != nil { + adWrt.SetHeader([]string{"Field Name", "Value"}) + for _, datafield := range tbl.Data.Fields { + an, ok := PrintNameById(actionName, datafield.FieldId) + if ok { + adWrt.Append([]string{an, hex.EncodeToString(datafield.GetStream())}) + } } + adWrt.Render() + adWrt.ClearRows() } } - if kv+1 != len(Entities) { - fmt.Printf("------------------\n") - } + fmt.Println("--------------------------------------------------------------------------------") } - fmt.Println("--------------------------------------------------------------------------------") } } } @@ -468,9 +567,6 @@ func DeleteEntries(rsp **p4.ReadResponse, cli *p4.BfRuntimeClient, ctx *context. var delReq *p4.WriteRequest = nil for k, e := range (*rsp).Entities { tbl := e.GetTableEntry() - if tbl.IsDefaultEntry { - continue - } if delReq == nil { delReq = util.GenWriteRequestWithId(p4.Update_DELETE, id.TableId(tbl.TableId), tbl.Key.Fields, nil) } else { @@ -493,7 +589,7 @@ func DeleteEntries(rsp **p4.ReadResponse, cli *p4.BfRuntimeClient, ctx *context. } _, err := (*cli).Write(*ctx, delReq) if err != nil { - return result, err + return nil, err } return result, nil } diff --git a/go.mod b/go.mod index f0ee16f..cee879b 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,9 @@ replace ( require ( github.com/P4Networking/pisc v0.0.0-00010101000000-000000000000 github.com/P4Networking/proto v1.0.0 + github.com/cheggaaa/pb/v3 v3.0.5 github.com/mitchellh/go-homedir v1.1.0 + github.com/olekukonko/tablewriter v0.0.4 github.com/spf13/cobra v1.0.0 github.com/spf13/viper v1.7.1 google.golang.org/grpc v1.33.1 diff --git a/go.sum b/go.sum index dd39e88..262a293 100644 --- a/go.sum +++ b/go.sum @@ -37,6 +37,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/P4Networking/netlink v1.1.1/go.mod h1:jphS5KWlRePmRBaqpiFy7OVXLwN971M7FiiSrXeFZ4s= +github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM= +github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= @@ -50,6 +52,9 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cheggaaa/pb v1.0.29 h1:FckUN5ngEk2LpvuG0fw1GEFx6LtyY2pWI/Z2QgCnEYo= +github.com/cheggaaa/pb/v3 v3.0.5 h1:lmZOti7CraK9RSjzExsY53+WWfub9Qv13B5m4ptEoPE= +github.com/cheggaaa/pb/v3 v3.0.5/go.mod h1:X1L61/+36nz9bjIsrDU52qHKOQukUQe2Ge+YvGuquCw= 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= @@ -68,10 +73,12 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/elliotchance/orderedmap v1.3.0/go.mod h1:8hdSl6jmveQw8ScByd3AaNHNk51RhbTazdqtTty+NFw= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -190,8 +197,16 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mantyr/iterator v0.0.0-20150623090054-c4cf40066bc4/go.mod h1:wvRVLNbkJoWRDDT6LzwmLrwPcI4gclOXXGVlA3fHVJE= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -210,6 +225,8 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/mostlygeek/arp v0.0.0-20170424181311-541a2129847a/go.mod h1:jZxafo9CAqaKFQE4zitrg5QNlA6CXUsjwXPlIppF3tk= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= +github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= @@ -273,6 +290,7 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/wk8/go-ordered-map v0.2.0/go.mod h1:9ZIbRunKbuvfPKyBP1SIKLcXNlv74YCOZ3t3VTS6gRk= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -387,6 +405,7 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -400,6 +419,7 @@ golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= From f1025089696f29fc004d43501db077d801c8c17f Mon Sep 17 00:00:00 2001 From: PFtyrant Date: Fri, 8 Jan 2021 05:42:31 +0000 Subject: [PATCH 08/17] Fix readfile feature - Fix the counting error of the readfile feature - Add progress bar to del-flow command - Add progress bar to set-flow command(readfile only) - Fix del-flow bugs - Tested set-flow/del-flow performance(del-flow has performance issue, Readtable function of PISC is too slow.) W.I.P - Fix suggestion function - Adding PRE related function(non p4 Object), --- cmd/delFlow.go | 45 ++++++++++++++------------------- cmd/setFlow.go | 37 ++++++++++++++++++---------- cmd/utils.go | 67 +++++++++++++++++++++++++++++++++----------------- go.mod | 1 + go.sum | 17 +++++++++++++ 5 files changed, 104 insertions(+), 63 deletions(-) diff --git a/cmd/delFlow.go b/cmd/delFlow.go index 6332663..6b19cd8 100644 --- a/cmd/delFlow.go +++ b/cmd/delFlow.go @@ -2,9 +2,6 @@ package cmd import ( "fmt" - "github.com/P4Networking/pisc/util" - "github.com/P4Networking/pisc/util/enums/id" - "github.com/P4Networking/proto/go/p4" "github.com/spf13/cobra" "io" "log" @@ -46,14 +43,16 @@ var delFlowCmd = &cobra.Command{ cli := *cliAddr ctx := *ctxAddr - if all && !clear && len(args) <= 0 && len(delEntry) <= 0 { + if all && !clear && len(args) <= 0 && !cmd.Flag("match").Changed { + // flag "-a" Clear all tables for _, tb := range Obj.p4Info.Tables { if NotSupportToReadTable[tb.ID] { continue } Obj.table = append(Obj.table, tb) } - } else if !all && clear && len(args) > 0 && len(delEntry) <= 0 { + } else if !all && clear && len(args) > 0 && !cmd.Flag("match").Changed { + // flag "-c" Clear a table for _, tb := range Obj.p4Info.Tables { if NotSupportToReadTable[tb.ID] { continue @@ -62,10 +61,11 @@ var delFlowCmd = &cobra.Command{ Obj.table = append(Obj.table, tb) } } - } else if !all && !clear && len(args) > 0 && len(delEntry) > 0 { + } else if !all && !clear && len(args) > 0 && cmd.Flag("match").Changed { for a, v := range delEntry { delEntry[a] = strings.TrimSpace(v) } + for _, tb := range Obj.p4Info.Tables { if NotSupportToReadTable[tb.ID] { continue @@ -74,6 +74,7 @@ var delFlowCmd = &cobra.Command{ Obj.table = append(Obj.table, tb) } } + if len(Obj.table) > 1 { fmt.Println(fmt.Errorf("Too many tables matched.")) for _, k := range Obj.table { @@ -85,26 +86,12 @@ var delFlowCmd = &cobra.Command{ fmt.Println(fmt.Errorf("No tables matched.\n")) return } - - collectedMatchTypes, ok := collectTableMatchTypes(&delEntry) - if !ok { - fmt.Println("Match keys are not matched") - return - } - if match := BuildMatchKeys(&collectedMatchTypes); match != nil { - delReq := util.GenWriteRequestWithId(p4.Update_DELETE, id.TableId(Obj.table[0].ID), match, nil) - _, err := cli.Write(ctx, delReq) - if err != nil { - fmt.Println(err) - return - } - } - return } else { fmt.Println(fmt.Errorf("check the flag or args")) cmd.Help() return } + for _, tb := range Obj.table { stream, err := cli.Read(ctx, genReadRequestWithId(tb.ID)) if err != nil { @@ -125,12 +112,16 @@ var delFlowCmd = &cobra.Command{ var cnt []int var err error - cnt, err = DeleteEntries(&rsp, &cli, &ctx) + if cmd.Flag("match").Changed { + cnt, err = DeleteEntries(&rsp, &cli, &ctx, delEntry) + } else { + cnt, err = DeleteEntries(&rsp, &cli, &ctx, nil) + } if err != nil { - fmt.Printf("Failed to delete entry: table \"%s\" with fields: %s\n", tb.Name, rsp.Entities[cnt[0]].GetTableEntry().Key.Fields) + fmt.Printf("Failed to delete entry: table \"%s\" with fields: %s\n", tb.Name, delEntry) + fmt.Println(err.Error()) return } - fmt.Printf("%d entires of \"%s\" table have cleared\n", len(cnt), tb.Name) } } @@ -140,7 +131,7 @@ var delFlowCmd = &cobra.Command{ func init() { rootCmd.AddCommand(delFlowCmd) - delFlowCmd.Flags().BoolVarP(&all, "all", "a", false, "delete all of the entries") - delFlowCmd.Flags().BoolVarP(&clear, "clear", "c", false, "clear the table") - delFlowCmd.Flags().StringSliceVarP(&delEntry, "match", "m", []string{}, "delete specific entry by given entry number") + delFlowCmd.Flags().BoolVarP(&all, "all", "a", false, "Clear all the table") + delFlowCmd.Flags().BoolVarP(&clear, "clear", "c", false, "Clear a table") + delFlowCmd.Flags().StringSliceVarP(&delEntry, "match", "m", []string{}, "Delete entry by given match key") } diff --git a/cmd/setFlow.go b/cmd/setFlow.go index d742b5e..faa0345 100644 --- a/cmd/setFlow.go +++ b/cmd/setFlow.go @@ -2,11 +2,13 @@ package cmd import ( "bufio" + "context" "flag" "fmt" "github.com/P4Networking/pisc/util" "github.com/P4Networking/pisc/util/enums/id" "github.com/P4Networking/proto/go/p4" + "github.com/schollz/progressbar/v3" "github.com/spf13/cobra" "log" "os" @@ -19,7 +21,8 @@ var ( actionValues []string ttl = "" file string - + cliAddr *p4.BfRuntimeClient + ctxAddr *context.Context filedata [][]string ) @@ -63,6 +66,9 @@ var setFlowCmd = &cobra.Command{ }() s := bufio.NewScanner(f) for s.Scan() { + if s.Text() == "" { + continue + } filedata = append(filedata, strings.Split(strings.ReplaceAll(s.Text(), ", ", ","), " ")) } err = s.Err() @@ -72,14 +78,24 @@ var setFlowCmd = &cobra.Command{ } }, Run: func(cmd *cobra.Command, args []string) { + cli, ctx, conn, cancel, _, _ := initConfigClient() + cliAddr = cli + ctxAddr = ctx + defer conn.Close() + defer cancel() if cmd.Flag("file").Changed { setFlowSub.Flags().StringSliceVarP(&matchKeyList, "match", "m", []string{}, "match key arguments") setFlowSub.Flags().StringSliceVarP(&actionValues, "action", "a", []string{}, "action arguments") setFlowSub.Flags().StringVarP(&ttl, "ttl", "t", "", "TTL arguments") + cnt := 0 + bar := progressbar.Default(int64(len(filedata))) for _, line := range filedata { + if line[0] == "" { + continue + } err := setFlowSub.ParseFlags(line) matchKeyList = strings.Split(matchKeyList[0], ",") - if actionValues[0] == ""{ + if len(actionValues) < 1 || actionValues[0] == "" { actionValues = nil } else { actionValues = strings.Split(actionValues[0], ",") @@ -91,12 +107,16 @@ var setFlowCmd = &cobra.Command{ matchKeyList = nil actionValues = nil ttl = "" + cnt++ + _ = bar.Add(1) } + fmt.Printf("Have successfully wrote %d entries.\n", cnt) } else { setFlowSub.Flags().StringSliceVarP(&matchKeyList, "match", "m", matchKeyList, "match key arguments") setFlowSub.Flags().StringSliceVarP(&actionValues, "action", "a", actionValues, "action arguments") setFlowSub.Flags().StringVarP(&ttl, "ttl", "t", ttl, "TTL arguments") - setFlowSub.Run(cmd,args) + setFlowSub.Run(cmd, args) + fmt.Println("Write done.") } }, } @@ -104,11 +124,6 @@ var setFlowCmd = &cobra.Command{ var setFlowSub = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { ObjInit() - cliAddr, ctxAddr, conn, cancel, _, _ := initConfigClient() - defer conn.Close() - defer cancel() - cli := *cliAddr - ctx := *ctxAddr for a, v := range matchKeyList { matchKeyList[a] = strings.TrimSpace(v) } @@ -133,7 +148,6 @@ var setFlowSub = &cobra.Command{ return } - //Obj.actions = make(map[uint32]string, 0) for _, table := range Obj.table { for _, actionSpec := range table.ActionSpecs { if strings.Contains(actionSpec.Name, args[1]) { @@ -208,14 +222,11 @@ var setFlowSub = &cobra.Command{ action = append(action, util.GenDataField(ttlId, util.Int32ToBytes(uint32(l)))) } - //fmt.Printf(" Make Write Request...\n") var req = util.GenWriteRequestWithId(p4.Update_INSERT, id.TableId(Obj.table[0].ID), match, &p4.TableData{ActionId: Obj.actionId, Fields: action}) - if _, err := cli.Write(ctx, req); err != nil { + if _, err := (*cliAddr).Write(*ctxAddr, req); err != nil { log.Printf("Got an error, %v \n", err.Error()) return } - - fmt.Printf("Write Done.\n") }, } diff --git a/cmd/utils.go b/cmd/utils.go index f5d760b..765bfe5 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -5,6 +5,7 @@ import ( "context" "encoding/gob" "encoding/hex" + "errors" "fmt" "github.com/P4Networking/pisc/southbound/bfrt" "github.com/P4Networking/pisc/util" @@ -12,6 +13,7 @@ import ( "github.com/P4Networking/pisc/util/enums/id" "github.com/P4Networking/proto/go/p4" "github.com/olekukonko/tablewriter" + "github.com/schollz/progressbar/v3" "google.golang.org/grpc" "io" "log" @@ -562,34 +564,53 @@ func genEntity(tableId uint32) *p4.Entity { } // DeleteEntries function read entries from the response to delete all entries of a table -func DeleteEntries(rsp **p4.ReadResponse, cli *p4.BfRuntimeClient, ctx *context.Context) ([]int, error) { - var result []int +func DeleteEntries(rsp **p4.ReadResponse, cli *p4.BfRuntimeClient, ctx *context.Context, matchKey []string) ([]int, error) { + var result = make([]int, 0) + var pbcount = 0 var delReq *p4.WriteRequest = nil + + if matchKey == nil { + pbcount = len((*rsp).Entities) + } else { + pbcount = 1 + } + bar := progressbar.Default(int64(pbcount)) + for k, e := range (*rsp).Entities { tbl := e.GetTableEntry() - if delReq == nil { - delReq = util.GenWriteRequestWithId(p4.Update_DELETE, id.TableId(tbl.TableId), tbl.Key.Fields, nil) + found := false + delReq = nil + if matchKey != nil { + collectedMatchTypes, ok := collectTableMatchTypes(&matchKey) + if !ok { + fmt.Println("Match key argument are not matched") + return nil, errors.New("argument err") + } + match := BuildMatchKeys(&collectedMatchTypes) + if match == nil { + // the nil of the match variable is mean that the BuildMatchKeys function can't make the match key with the input argument. + return nil, nil + } + for kf, kv := range match { + // TODO: may be can find a better way to compare the match key. + if tbl.Key.Fields[kf].String() == kv.String() { + found = true + break + } + } } else { - delReq.Updates = append(delReq.Updates, &p4.Update{ - Type: p4.Update_DELETE, - Entity: &p4.Entity{ - Entity: &p4.Entity_TableEntry{ - TableEntry: &p4.TableEntry{ - TableId: tbl.TableId, - Key: &p4.TableKey{ - Fields: tbl.Key.Fields, - }, - Data: nil, - }, - }, - }, - }) + found = true + } + if found { + result = append(result, k) + delReq = util.GenWriteRequestWithId(p4.Update_DELETE, id.TableId(tbl.TableId), tbl.Key.Fields, tbl.Data) + _ = bar.Add(1) + + _, err := (*cli).Write(*ctx, delReq) + if err != nil { + return nil, err + } } - result = append(result, k) - } - _, err := (*cli).Write(*ctx, delReq) - if err != nil { - return nil, err } return result, nil } diff --git a/go.mod b/go.mod index cee879b..dbf8cd2 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/cheggaaa/pb/v3 v3.0.5 github.com/mitchellh/go-homedir v1.1.0 github.com/olekukonko/tablewriter v0.0.4 + github.com/schollz/progressbar/v3 v3.7.3 github.com/spf13/cobra v1.0.0 github.com/spf13/viper v1.7.1 google.golang.org/grpc v1.33.1 diff --git a/go.sum b/go.sum index 262a293..655cb47 100644 --- a/go.sum +++ b/go.sum @@ -185,6 +185,7 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -207,9 +208,13 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -252,6 +257,9 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/schollz/progressbar v1.0.0 h1:gbyFReLHDkZo8mxy/dLWMr+Mpb1MokGJ1FqCiqacjZM= +github.com/schollz/progressbar/v3 v3.7.3 h1:U0etV6FzAPBne0ZqoWwThp7FEdfcTX2lHzQYh5B7scE= +github.com/schollz/progressbar/v3 v3.7.3/go.mod h1:fBsumCeOE+GOuGKY1JldFX0eRT6gkw3sw9eZTt2bFgE= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -320,6 +328,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -416,6 +426,7 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -438,6 +449,12 @@ golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 h1:W0lCpv29Hv0UaM1LXb9QlBHLN golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 h1:a/mKvvZr9Jcc8oKfcmgzyp7OwF73JPWsQLvH1z2Kxck= golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201223074533-0d417f636930 h1:vRgIt+nup/B/BwIS0g2oC0haq0iqbV3ZA+u6+0TlNCo= +golang.org/x/sys v0.0.0-20201223074533-0d417f636930/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= +golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From 176ab280d47cdf616e59465b6332bfa1d3140ed2 Mon Sep 17 00:00:00 2001 From: PFtyrant Date: Fri, 8 Jan 2021 10:12:41 +0000 Subject: [PATCH 09/17] Add table and action suggestion -Tab completion provides table,action name when use set/del-flow, dump and info command --- cmd/delFlow.go | 22 ++++++++++++---------- cmd/dump.go | 17 +++++++++++++++-- cmd/info.go | 19 +++++++++++++------ cmd/setFlow.go | 32 +++++++++++++++++++++++--------- cmd/utils.go | 8 ++++---- 5 files changed, 67 insertions(+), 31 deletions(-) diff --git a/cmd/delFlow.go b/cmd/delFlow.go index 6b19cd8..a2664f1 100644 --- a/cmd/delFlow.go +++ b/cmd/delFlow.go @@ -20,21 +20,23 @@ var delFlowCmd = &cobra.Command{ Long: `del-flow can remove all of the entries from specific table`, Args: cobra.MaximumNArgs(1), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - _, _, conn, cancel, p4Info, _ := initConfigClient() + _, _, conn, cancel, _, _ := initConfigClient() defer conn.Close() defer cancel() - var argsList []string - for _, v := range p4Info.Tables { - if strings.Contains(v.Name, preFixIg) || strings.Contains(v.Name, preFixEg) { - strs := strings.Split(v.Name, ".") - if toComplete == "" || strings.Contains(toComplete, "pipe") { - argsList = append(argsList, v.Name) - } else { - argsList = append(argsList, strs[2]) + + ret := make([]string, 0) + if len(args) < 1 { + argsList, _ := Obj.p4Info.GuessTableName(toComplete) + for _, v := range argsList { + if strings.Contains(v, preFixIg) || strings.Contains(v, preFixEg) { + name := strings.Split(v, ".") + ret = append(ret, name[len(name)-2]+"."+name[len(name)-1]) } } + return ret, cobra.ShellCompDirectiveNoFileComp } - return argsList, cobra.ShellCompDirectiveNoFileComp + + return nil, cobra.ShellCompDirectiveNoFileComp }, Run: func(cmd *cobra.Command, args []string) { cliAddr, ctxAddr, conn, cancel, _, _ := initConfigClient() diff --git a/cmd/dump.go b/cmd/dump.go index 32563bf..a16dc90 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -16,12 +16,25 @@ var dumpCmd = &cobra.Command{ Use: "dump TABLE-NAME", Short: "Dump the existed entries in the specific table", Long: `Display all existed entries in the specific table`, + Args: cobra.MaximumNArgs(1), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { _, _, conn, cancel, _, _ := initConfigClient() defer conn.Close() defer cancel() - argsList, _ := Obj.p4Info.GuessTableName(toComplete) - return argsList, cobra.ShellCompDirectiveNoFileComp + + ret := make([]string, 0) + if len(args) < 1 { + argsList, _ := Obj.p4Info.GuessTableName(toComplete) + for _, v := range argsList { + if strings.Contains(v, preFixIg) || strings.Contains(v, preFixEg) { + name := strings.Split(v, ".") + ret = append(ret, name[len(name)-2]+"."+name[len(name)-1]) + } + } + return ret, cobra.ShellCompDirectiveNoFileComp + } + + return nil, cobra.ShellCompDirectiveNoFileComp }, Run: func(cmd *cobra.Command, args []string) { cliAddr, ctxAddr, conn, cancel, _, _ := initConfigClient() diff --git a/cmd/info.go b/cmd/info.go index 7d6dd55..85028cd 100644 --- a/cmd/info.go +++ b/cmd/info.go @@ -12,18 +12,25 @@ var infoCmd = &cobra.Command{ Use: "info TABLE-NAME", Short: "Show information about table", Long: `Display the detail of table.`, + Args: cobra.MaximumNArgs(1), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - _, _, conn, cancel, p4Info, _ := initConfigClient() + _, _, conn, cancel, _, _ := initConfigClient() defer conn.Close() defer cancel() - var argsList []string - for _, v := range p4Info.Tables { - if strings.Contains(v.Name, preFixIg) || strings.Contains(v.Name, preFixEg) { - argsList = append(argsList, v.Name) + ret := make([]string, 0) + if len(args) < 1 { + argsList, _ := Obj.p4Info.GuessTableName(toComplete) + for _, v := range argsList { + if strings.Contains(v, preFixIg) || strings.Contains(v, preFixEg) { + name := strings.Split(v, ".") + ret = append(ret, name[len(name)-2]+"."+name[len(name)-1]) + } } + return ret, cobra.ShellCompDirectiveNoFileComp } - return argsList, cobra.ShellCompDirectiveNoFileComp + + return nil, cobra.ShellCompDirectiveNoFileComp }, Run: func(cmd *cobra.Command, args []string) { _, _, conn, cancel, _, _ := initConfigClient() diff --git a/cmd/setFlow.go b/cmd/setFlow.go index faa0345..848b005 100644 --- a/cmd/setFlow.go +++ b/cmd/setFlow.go @@ -36,18 +36,33 @@ var setFlowCmd = &cobra.Command{ _, _, conn, cancel, _, _ := initConfigClient() defer conn.Close() defer cancel() - table, _ := Obj.p4Info.GuessTableName(toComplete) - for k, v := range table { - if strings.Contains(v, preFixIgPar) || strings.Contains(v, preFixEgPar) { - table[k] = table[len(table)-1] // Copy last element to index i. - table[len(table)-1] = "" // Erase last element (write zero value). - table = table[:len(table)-1] + + ret := make([]string, 0) + if len(args) < 1 { + argsList, _ := Obj.p4Info.GuessTableName(toComplete) + for _, v := range argsList { + if strings.Contains(v, preFixIg) || strings.Contains(v, preFixEg) { + name := strings.Split(v, ".") + ret = append(ret, name[len(name)-2] + "." + name[len(name)-1]) + } + } + return ret, cobra.ShellCompDirectiveNoFileComp + } else if len(args) == 1 { + for _, v := range Obj.p4Info.Tables { + //ret := make([]string, 0) + if strings.Contains(v.Name, args[0]) { + for _, action := range v.ActionSpecs { + name := strings.Split(action.Name, ".") + ret = append(ret, name[len(name)-2] + "." + name[len(name)-1]) + } + return ret, cobra.ShellCompDirectiveNoFileComp + } } } - return table, cobra.ShellCompDirectiveNoFileComp + + return nil, cobra.ShellCompDirectiveNoFileComp }, PreRun: func(cmd *cobra.Command, args []string) { - if cmd.Flag("file").Changed && (cmd.Flag("match").Changed || cmd.Flag("action").Changed || cmd.Flag("ttl").Changed) { fmt.Println(fmt.Errorf("file flag can only exist alone.")) os.Exit(1) @@ -116,7 +131,6 @@ var setFlowCmd = &cobra.Command{ setFlowSub.Flags().StringSliceVarP(&actionValues, "action", "a", actionValues, "action arguments") setFlowSub.Flags().StringVarP(&ttl, "ttl", "t", ttl, "TTL arguments") setFlowSub.Run(cmd, args) - fmt.Println("Write done.") } }, } diff --git a/cmd/utils.go b/cmd/utils.go index 765bfe5..369e58b 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -83,10 +83,10 @@ type EtnryObj struct { } var ( - preFixIg = "pipe.SwitchIngress" - preFixEg = "pipe.SwitchEgress" - preFixIgPar = "pipe.SwitchIngressParser" - preFixEgPar = "pipe.SwitchEgressParser" + preFixIg = "pipe.SwitchIngress." + preFixEg = "pipe.SwitchEgress." + preFixIgPar = "pipe.SwitchIngressParser." + preFixEgPar = "pipe.SwitchEgressParser." DEFAULT_ADDR = ":50000" // true : not support to read; false : support to read From 613e0cac532f07f3024bf93cb7990df341668bf8 Mon Sep 17 00:00:00 2001 From: PFtyrant Date: Tue, 2 Feb 2021 10:05:16 +0000 Subject: [PATCH 10/17] Add pre and port feature -Adding PRE related features(MGID, NODE, LAG, PRUNE) -Adding Port feature. Port command only support add port config now. It can't modify or delete port config. --- cmd/port.go | 160 +++++++++++++++++++++++++++++++++++++++++++++++ cmd/pre.go | 166 +++++++++++++++++++++++++++++++++++++++++++++++++ cmd/setFlow.go | 5 +- cmd/utils.go | 35 ++++++++--- 4 files changed, 355 insertions(+), 11 deletions(-) create mode 100644 cmd/port.go create mode 100644 cmd/pre.go diff --git a/cmd/port.go b/cmd/port.go new file mode 100644 index 0000000..5ae599e --- /dev/null +++ b/cmd/port.go @@ -0,0 +1,160 @@ +package cmd + +import ( + "fmt" + "github.com/P4Networking/pisc/util/enums/id" + "github.com/P4Networking/pisc/util/enums/port" + "github.com/P4Networking/proto/go/p4" + "github.com/spf13/cobra" + "log" + "strings" +) + +var ( + portNum uint16 + speed string + fec int + an uint +) + +// setPortCmd represents the add port command +var setPortCmd = &cobra.Command{ + Use: "port", + Short: "Set switch port properties", + Long: "setting switch port properties. \nport speed : 10G, 25G, 40G, 50G, 100G\nport fec : \n", + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + // WARN: the port command only support an add feature now, + // it means can't mod or delete the port information through the add command. + + cli, ctx, conn, cancel, _, _ := initConfigClient() + cliAddr = cli + ctxAddr = ctx + defer conn.Close() + defer cancel() + + // Check Port Number + if !cmd.Flag("Port Number").Changed { + fmt.Println("please set the port number.") + return + } + + // Check Port Speed + if !cmd.Flag("Port Speed").Changed { + fmt.Println("Port Speed isn't set, take the default value of speed : 100G") + speed = "100G" + } + Speed := map[string]int{ + "100G" : port.BF_SPEED_100G, + "50G" : port.BF_SPEED_50G, + "40G" : port.BF_SPEED_40G, + "25G" : port.BF_SPEED_25G, + "10G" : port.BF_SPEED_10G, + } + if Speed[speed] <= 0 { + fmt.Println("please check port speed value : 100G, 50G, 40G, 20G, 10G") + return + } + + // Check Port Fec + FEC := map[int] string { + 0 : "BF_FEC_TYP_NONE", + 1 : "BF_FEC_TYP_FIRECODE", + 2 : "BF_FEC_TYP_REED_SOLOMON", + } + if !cmd.Flag("Port Fec").Changed { + fec = 0 + fmt.Printf("Port fec isn't set, take the default value of fec : %s\n", FEC[fec]) + } else { + if fec > 2 || fec < 0 { + fmt.Printf("Fec value is out of range, please input the below value :\n" + + "\t%s(Default) : %d\n" + + "\t%s : %d\n" + + "\t%s: %d\n", + FEC[0], 0, + FEC[1], 1, + FEC[2], 2) + return + } + } + + // Check Auto-Negotiation + An := map[uint]string { + 0 : "PM_AN_FORCE_DISABLE", + 1 : "PM_AN_FORCE_ENABLE", + 2 :"PM_AN_MAX", + } + if !cmd.Flag("Auto Negotiation").Changed { + an = 0 + fmt.Printf("Auto Negotiation isn't set. take default value of Auto Negotiation : %s\n", An[an]) + } else { + if an > 2 || an < 0 { + fmt.Printf("please check the auto negotiation value.\n" + + "%s : 0\n" + + "%s : 1\n" + + "%s : 2\n" , + An[0], + An[1], + An[2]) + return + } + } + + // Check Table Name + tableName := "PORT" + found := false + for _, v:= range Obj.nonP4Info.Tables { + if strings.Contains(v.Name, tableName) { + found = true + } + } + if !found { + _ = cmd.Help() + return + } + + req := &p4.WriteRequest{ + ClientId: 0, + Target: &p4.TargetDevice{ + DeviceId: 0, + PipeId: 0xffff, + }, + Updates: []*p4.Update {}, + } + + var lanes uint32 + switch speed { + case "100G": + lanes = 4 + case "40G": + lanes = 4 + case "50G": + lanes = 2 + case "25G": + lanes = 1 + case "10G": + lanes = 1 + default: + lanes = 1 + } + req.Updates = append(req.Updates, Obj.nonP4Info.AddPort( + id.PortId(portNum), + port.PortSpeedType(Speed[speed]), + port.BF_FEC_Type(fec), + lanes, + port.BF_PM_Port_Autoneg_Policy(An[an]))) + + if _, err := (*cliAddr).Write(*ctxAddr, req); err != nil { + log.Printf("Got an error, %v \n", err.Error()) + return + } + }, +} + +func init() { + rootCmd.AddCommand(setPortCmd) + setPortCmd.Flags().Uint16VarP(&portNum,"Port Number", "p", 0, "num") + setPortCmd.Flags().StringVarP(&speed, "Port Speed", "s", "", "speed") + setPortCmd.Flags().IntVarP(&fec, "Port Fec", "f", 0, "fec") + setPortCmd.Flags().UintVarP(&an, "Auto Negotiation", "a", 0, "an") +} \ No newline at end of file diff --git a/cmd/pre.go b/cmd/pre.go new file mode 100644 index 0000000..8f46ca5 --- /dev/null +++ b/cmd/pre.go @@ -0,0 +1,166 @@ +package cmd + +import ( + "fmt" + "github.com/P4Networking/pisc/util/enums/id" + "github.com/P4Networking/proto/go/p4" + "github.com/spf13/cobra" + "log" + "strconv" + "strings" +) + +var ( + array []string + node string + mgid string + l2xid string + lag string +) + +// setPreCmd represents the Packet Replication Engine command +var setPreCmd = &cobra.Command{ + Use: "pre", + Short: "Set Packet Replication Engine (PRE) entry", + Long: "Insert the flow to table with action", + Args: cobra.MaximumNArgs(2), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + _, _, conn, cancel, _, _ := initConfigClient() + defer conn.Close() + defer cancel() + toComplete = "mirror" + ret := make([]string, 0) + if len(args) < 1 { + //argsList, _ := Obj.nonP4Info.String() + for _, v := range Obj.nonP4Info.Tables { + ret = append(ret, v.Name) + } + //ret = append(ret, Obj.nonP4Info.Tables) + return ret, cobra.ShellCompDirectiveNoFileComp + } + return nil, cobra.ShellCompDirectiveNoFileComp + }, + Run: func(cmd *cobra.Command, args []string) { + cli, ctx, conn, cancel, _, _ := initConfigClient() + cliAddr = cli + ctxAddr = ctx + defer conn.Close() + defer cancel() + + if len(args) < 1 { + fmt.Println("please checkout the table name.") + return + } + + tableName := args[0] + req := &p4.WriteRequest{ + ClientId: 0, + Target: &p4.TargetDevice{ + DeviceId: 0, + PipeId: 0xffff, + }, + Updates: []*p4.Update {}, + } + found := false + for _, v := range Obj.nonP4Info.Tables { + if NotSupportToReadTable[v.ID] { + continue + } + if strings.Contains(v.Name, tableName) && node != "" && len(array) > 0 { + portIds := make([]id.PortId, len(array)) + for k, v := range array { + v = strings.ReplaceAll(v, " ", "") + value, err := strconv.ParseUint(v, 10, 16) + if err != nil { + fmt.Println(err) + panic("Unable to convert the ports value type from string to uint32") + } + portIds[k] = id.PortId(uint16(value)) + } + value, err := strconv.ParseUint(node, 10, 32) + if err != nil { + fmt.Println(err) + panic("Unable to convert the node value type from string to uint32") + } + req.Updates = append(req.Updates, Obj.nonP4Info.SetNode(uint32(value), portIds)) + found = true + break + } else if strings.Contains(v.Name, tableName) && mgid != "" && node != "" { + mgidValue, err := strconv.ParseUint(mgid, 10, 16) + if err != nil { + fmt.Println(err) + panic("Unable to convert the mgid value type from string to uint16") + } + nodeValue, err := strconv.ParseUint(node, 10, 32) + if err != nil { + fmt.Println(err) + panic("Unable to convert the node value type from string to uint32") + } + req.Updates = append(req.Updates, Obj.nonP4Info.SetMGID(uint16(mgidValue), uint32(nodeValue))) + found = true + break + } else if strings.Contains(v.Name, tableName) && l2xid != "" && len(array) > 0 { + // pre.prune + nodeArray := make([]uint32, len(array)) + for k, v := range array { + v = strings.ReplaceAll(v, " ", "") + value, err := strconv.ParseUint(v, 10, 16) + if err != nil { + fmt.Println(err) + panic("Unable to convert the ports value type from string to uint32") + } + nodeArray[k] = uint32(value) + } + l2xidValue, err := strconv.ParseUint(l2xid, 10, 32) + if err != nil { + fmt.Println(err) + panic("Unable to convert the l2xid value type from string to uint32") + } + ret := Obj.nonP4Info.SetPrune(uint16(l2xidValue), nodeArray) + req.Updates = append(req.Updates, ret.Updates[0]) + found = true + break + } else if strings.Contains(v.Name, tableName) && lag != "" && len(array) > 0 { + // PRE.LAG, Link aggregation. + //TODO: couldn't insert the flow with the 0xff(255) entry number. + lagValue, err := strconv.ParseUint(lag, 10, 8) + if err != nil { + fmt.Println(err) + panic("Unable to convert the lag value type from string to uint32") + } + nodeArray := make([]uint32, len(array)) + for k, v := range array { + v = strings.ReplaceAll(v, " ", "") + value, err := strconv.ParseUint(v, 10, 32) + if err != nil { + fmt.Println(err) + panic("Unable to convert the ports value type from string to uint32") + } + nodeArray[k] = uint32(value) + } + ret := Obj.nonP4Info.SetLag(uint8(lagValue), nodeArray) + req.Updates = append(req.Updates, ret.Updates[0]) + found = true + break + } + } + + if !found { + _ = cmd.Help() + return + } + if _, err := (*cliAddr).Write(*ctxAddr, req); err != nil { + log.Printf("Got an error, %v \n", err.Error()) + return + } + }, +} + +func init() { + rootCmd.AddCommand(setPreCmd) + setPreCmd.Flags().StringSliceVarP(&array, "PORTS", "p", []string{}, "ports list") + setPreCmd.Flags().StringVarP(&node, "NODE ID", "n", "", "node id") + setPreCmd.Flags().StringVarP(&mgid, "MGID ID", "m", "", "mgid id") + setPreCmd.Flags().StringVarP(&l2xid, "L2XID ID", "x", "", "l2xid id") + setPreCmd.Flags().StringVarP(&lag, "LAG ID", "l", "", "lag id") +} \ No newline at end of file diff --git a/cmd/setFlow.go b/cmd/setFlow.go index 848b005..e948a73 100644 --- a/cmd/setFlow.go +++ b/cmd/setFlow.go @@ -29,7 +29,7 @@ var ( // setFlowCmd represents the setFlow command var setFlowCmd = &cobra.Command{ Use: "set-flow TABLE_NAME ACTION-NAME ", - Short: "Set flow into table", + Short: "Insert the flows", Long: "Insert the flow to table with action", Args: cobra.MaximumNArgs(2), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { @@ -49,12 +49,13 @@ var setFlowCmd = &cobra.Command{ return ret, cobra.ShellCompDirectiveNoFileComp } else if len(args) == 1 { for _, v := range Obj.p4Info.Tables { - //ret := make([]string, 0) + ret := make([]string, 0) if strings.Contains(v.Name, args[0]) { for _, action := range v.ActionSpecs { name := strings.Split(action.Name, ".") ret = append(ret, name[len(name)-2] + "." + name[len(name)-1]) } + ret = append(ret, v.Name+args[0]) return ret, cobra.ShellCompDirectiveNoFileComp } } diff --git a/cmd/utils.go b/cmd/utils.go index 369e58b..d4f4681 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -89,14 +89,31 @@ var ( preFixEgPar = "pipe.SwitchEgressParser." DEFAULT_ADDR = ":50000" - // true : not support to read; false : support to read - NotSupportToReadTable = map[uint32] bool { - 2432705822 : true, // "pipe.$SNAPSHOT_EGRESS" - 2449483038 : true, // "pipe.$SNAPSHOT_EGRESS_LIVENESS" - 2432703071 : true, // "pipe.$SNAPSHOT_INGRESS" - 2449480287 : true, // "pipe.$SNAPSHOT_INGRESS_LIVENESS" - 2415950168 : true} // "pipe.SwitchIngressParser.$PORT_METADATA" - + NotSupportToReadTable = map[uint32] bool{ + //Support + 4278321156: false,// "$pre.lag" + 4278321153: false,// "$pre.mgid" + 4278321154: false,// "$pre.node" + 4278321157: false,// "$pre.prune" + 4278255617: false,// "$PORT" + //Not support + 4278321158: true,// "$pre.port" + 4278452225: true,// "$mirror.cfg" + 4278321155: true,// "$pre.ecmp" + 2432705822: true, // "pipe.$SNAPSHOT_EGRESS" + 2449483038: true, // "pipe.$SNAPSHOT_EGRESS_LIVENESS" + 2432703071: true, // "pipe.$SNAPSHOT_INGRESS" + 2449480287: true, // "pipe.$SNAPSHOT_INGRESS_LIVENESS" + 2415950168: true, // "pipe.SwitchIngressParser.$PORT_METADATA" + 4278517761: true,// "$tm.ppg" + 4278386689: true,// "$PKTGEN_PORT_CFG" + 4278386690: true,// "$PKTGEN_APPLICATION_CFG" + 4278386691: true,// "$PKTGEN_PKT_BUFFER" + 4278255618: true,// "$PORT_STAT" + 4278255619: true,// "$PORT_HDL_INFO" + 4278255620: true,// "$PORT_FP_IDX_INFO" + 4278255621: true,// "$PORT_STR_INFO " + } Obj EtnryObj ) @@ -672,4 +689,4 @@ func BuildMatchKeys(collectedMatchTypes *[]MatchSet) []*p4.KeyField { } } return match -} +} \ No newline at end of file From 5867130b8b5b4251e1bbca5730acef09c690cfc5 Mon Sep 17 00:00:00 2001 From: PFtyrant Date: Mon, 8 Feb 2021 10:05:32 +0000 Subject: [PATCH 11/17] add VLAN features -Added the VLAN "create" and "add" features -Fixed the flag shorthand collision problem. Now, the Server flag uses the capital charactor -Modified PRE command's tab completion to suggest the table name with "pre." suffix -Modified dump function bug when pipeline table key field counts don't matched to the bfrt profile --- cmd/port.go | 18 ++--- cmd/pre.go | 15 ++-- cmd/root.go | 2 +- cmd/utils.go | 16 ++-- cmd/vlan.go | 218 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 241 insertions(+), 28 deletions(-) create mode 100644 cmd/vlan.go diff --git a/cmd/port.go b/cmd/port.go index 5ae599e..ac50643 100644 --- a/cmd/port.go +++ b/cmd/port.go @@ -3,7 +3,7 @@ package cmd import ( "fmt" "github.com/P4Networking/pisc/util/enums/id" - "github.com/P4Networking/pisc/util/enums/port" + p "github.com/P4Networking/pisc/util/enums/port" "github.com/P4Networking/proto/go/p4" "github.com/spf13/cobra" "log" @@ -45,11 +45,11 @@ var setPortCmd = &cobra.Command{ speed = "100G" } Speed := map[string]int{ - "100G" : port.BF_SPEED_100G, - "50G" : port.BF_SPEED_50G, - "40G" : port.BF_SPEED_40G, - "25G" : port.BF_SPEED_25G, - "10G" : port.BF_SPEED_10G, + "100G" : p.BF_SPEED_100G, + "50G" : p.BF_SPEED_50G, + "40G" : p.BF_SPEED_40G, + "25G" : p.BF_SPEED_25G, + "10G" : p.BF_SPEED_10G, } if Speed[speed] <= 0 { fmt.Println("please check port speed value : 100G, 50G, 40G, 20G, 10G") @@ -139,10 +139,10 @@ var setPortCmd = &cobra.Command{ } req.Updates = append(req.Updates, Obj.nonP4Info.AddPort( id.PortId(portNum), - port.PortSpeedType(Speed[speed]), - port.BF_FEC_Type(fec), + p.PortSpeedType(Speed[speed]), + p.BF_FEC_Type(fec), lanes, - port.BF_PM_Port_Autoneg_Policy(An[an]))) + p.BF_PM_Port_Autoneg_Policy(An[an]))) if _, err := (*cliAddr).Write(*ctxAddr, req); err != nil { log.Printf("Got an error, %v \n", err.Error()) diff --git a/cmd/pre.go b/cmd/pre.go index 8f46ca5..6cc7e7c 100644 --- a/cmd/pre.go +++ b/cmd/pre.go @@ -23,19 +23,19 @@ var setPreCmd = &cobra.Command{ Use: "pre", Short: "Set Packet Replication Engine (PRE) entry", Long: "Insert the flow to table with action", - Args: cobra.MaximumNArgs(2), + Args: cobra.ExactArgs(1), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { _, _, conn, cancel, _, _ := initConfigClient() defer conn.Close() defer cancel() - toComplete = "mirror" ret := make([]string, 0) if len(args) < 1 { - //argsList, _ := Obj.nonP4Info.String() for _, v := range Obj.nonP4Info.Tables { - ret = append(ret, v.Name) + if NotSupportToReadTable[v.ID] || !strings.Contains(v.Name, "pre") { + continue + } + ret = append(ret, strings.Trim(v.Name, "$")) } - //ret = append(ret, Obj.nonP4Info.Tables) return ret, cobra.ShellCompDirectiveNoFileComp } return nil, cobra.ShellCompDirectiveNoFileComp @@ -47,11 +47,6 @@ var setPreCmd = &cobra.Command{ defer conn.Close() defer cancel() - if len(args) < 1 { - fmt.Println("please checkout the table name.") - return - } - tableName := args[0] req := &p4.WriteRequest{ ClientId: 0, diff --git a/cmd/root.go b/cmd/root.go index 66747af..1d08b62 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -39,7 +39,7 @@ func init() { // Cobra supports persistent flags, which, if defined here, // will be global for your application. //rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.pisc-cli.yaml)") - rootCmd.PersistentFlags().StringVarP(&server, "server", "s", "", "The server address") + rootCmd.PersistentFlags().StringVarP(&server, "server", "S", "", "The server address") //rootCmd.MarkPersistentFlagRequired("server") // Cobra also supports local flags, which will only run diff --git a/cmd/utils.go b/cmd/utils.go index d4f4681..c113614 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -514,28 +514,28 @@ func DumpEntries(stream *p4.BfRuntime_ReadClient, p4table *bfrt.Table) { fmt.Println(fmt.Sprintf("\nEntry : %d\nMatch Key Info", kv)) // Match Keys if tbl.GetKey() != nil { - iter := 0 - for k, mk := range p4table.Key { - f := tbl.Key.Fields[iter] + for i := 0; i < len(tbl.Key.Fields); i++ { + //for k, mk := range p4table.Key { + f := tbl.Key.Fields[i] + mk := p4table.Key[i] if mk.ID == f.FieldId { switch strings.Split(reflect.TypeOf(f.GetMatchType()).String(), ".")[1] { case "KeyField_Exact_": m := f.GetExact() - mkWrt.Append([]string{p4table.Key[k].Name, "Exact", hex.EncodeToString(m.Value), "None"}) + mkWrt.Append([]string{p4table.Key[i].Name, "Exact", hex.EncodeToString(m.Value), "None"}) case "KeyField_Ternary_": t := f.GetTernary() - mkWrt.Append([]string{p4table.Key[k].Name, "Ternary", hex.EncodeToString(t.Value), hex.EncodeToString(t.Mask)}) + mkWrt.Append([]string{p4table.Key[i].Name, "Ternary", hex.EncodeToString(t.Value), hex.EncodeToString(t.Mask)}) case "KeyField_Lpm": l := f.GetLpm() - mkWrt.Append([]string{p4table.Key[k].Name, "LPM", string(l.Value), string(l.PrefixLen)}) + mkWrt.Append([]string{p4table.Key[i].Name, "LPM", string(l.Value), string(l.PrefixLen)}) // TODO : Range match field //case "KeyField_Range_": // //r := f.GetRange() // //fmt.Printf(" %-20s %-10s High: %-8x Low: %-8x\n", p4table.Key[k].Name, "LPM", r.High, r.Low) } - iter++ } else { - mkWrt.Append([]string{p4table.Key[k].Name, "None", "None", "None"}) + mkWrt.Append([]string{p4table.Key[i].Name, "None", "None", "None"}) } } mkWrt.Render() diff --git a/cmd/vlan.go b/cmd/vlan.go new file mode 100644 index 0000000..dca4e53 --- /dev/null +++ b/cmd/vlan.go @@ -0,0 +1,218 @@ +package cmd + +import ( + "fmt" + "github.com/spf13/cobra" + "io/ioutil" + "log" + "net/http" + "strconv" + "strings" +) + +var ( + vlanPort string + vlanName string + vlanType string + vlanId []string + opt map[string]interface{} + optSet []string +) + +// setVlanCmd represents the add port command +var setVlanCmd = &cobra.Command{ + Use: "vlan", + Short: "Set VLAN", + Long: "Define port where belongs to the specific VLANs", + Args: cobra.ExactArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) < 1 { + return optSet, cobra.ShellCompDirectiveNoFileComp + } + ret := make([]string,0) + for _, v := range optSet { + if strings.Contains(toComplete, v) { + ret = append(ret, v) + } + } + return ret, cobra.ShellCompDirectiveNoFileComp + }, + Run: func(cmd *cobra.Command, args []string) { + // Create(vid string, vlanName string) + // Add(type string, port string, vid []string) + // Modify(port string, vid []string) + // Delete(vName string) + // Show() + switch args[0] { + case optSet[0]: + // VLAN Create + if !cmd.Flag("id").Changed || !cmd.Flag("name").Changed { + fmt.Println("check VLAN ID and VLAN Name") + _ = cmd.Help() + return + } + opt[args[0]].(func(string, string))(vlanId[0], vlanName) + + case optSet[1]: + // VLAN Add + if !cmd.Flag("type").Changed || !cmd.Flag("port").Changed || !cmd.Flag("id").Changed { + fmt.Println("Check VLAN port, VLAN type and VLAN Id") + _ = cmd.Help() + return + } + opt[args[0]].(func(string, string, []string))(vlanType, vlanPort, vlanId) + + case optSet[2]: + // VLAN Modify + if !cmd.Flag("port").Changed || !cmd.Flag("id").Changed { + fmt.Println("Check VLAN port and VLAN Id") + _ = cmd.Help() + return + } + opt[args[0]].(func(string, []string))(vlanPort, vlanId) + + case optSet[3]: + // VLAN Delete + if !cmd.Flag("name").Changed { + fmt.Println("Check VLAN name") + _ = cmd.Help() + return + } + opt[args[0]].(func(string))(vlanName) + case optSet[4]: + // VLAN show + if !cmd.Flag("id").Changed { + fmt.Println("Check VLAN Id") + _ = cmd.Help() + return + } + opt[args[0]].(func([]string))(vlanId) + default: + _ = cmd.Help() + return + } + }, +} + +func init() { + rootCmd.AddCommand(setVlanCmd) + setVlanCmd.Flags().StringVarP(&vlanPort, "port", "p", "", "vlan port") + setVlanCmd.Flags().StringVarP(&vlanName, "name", "n", "", "vlan name") + setVlanCmd.Flags().StringVarP(&vlanType, "type", "t", "", "vlan type (Access, Trunk)") + setVlanCmd.Flags().StringArrayVarP(&vlanId, "id", "v", []string{}, "vlan id") + optSet = []string{"create","add","modify","delete","show"} + opt = map[string]interface{} { + optSet[0] : vlanCreate, + optSet[1] : vlanAdd, + optSet[2] : vlanModify, + optSet[3] : vlanDelete, + optSet[4] : vlanShow, + } +} + +func vlanCreate(vid, vlanName string) { + body := strings.NewReader(fmt.Sprintf(`{"vlanId": %s, "name": "%s"}`, vid, vlanName)) + res, err := http.Post("http://localhost:50101/v1/vlan/create","application/x-www-form-urlencoded", body) + if err != nil { + log.Fatal(err) + } + resbody, _ := ioutil.ReadAll(res.Body) + log.Println(string(resbody)) + res.Body.Close() +} + +func vlanAdd(vlanType string, port string, vid []string) { + ports := rangeSplit(port) + for _, port := range ports { + if strings.Contains(vlanType, "trunk") { + vlanSetTagged(port, vid) + return + } + vlanSetUntag(port, vid) + } +} + +func makeVlanArrayString(str []string) string { + ret := "" + for k, v := range str { + if k == 0 { + ret = v + } else { + ret = ret + "," + v + } + } + return ret +} + +func vlanSetUntag(port string, vid []string) { + body := strings.NewReader(fmt.Sprintf(`{"portId": %s, "portType": "ACCESS", "vlanIds": [%s]}`, port, makeVlanArrayString(vid))) + res, err := http.Post("http://localhost:50101/v1/vlan/portupdate","application/x-www-form-urlencoded", body) + if err != nil { + log.Fatal(err) + } + resbody, _ := ioutil.ReadAll(res.Body) + log.Println(string(resbody)) + res.Body.Close() +} + +func vlanSetTagged(port string, vid []string) { + body := strings.NewReader(fmt.Sprintf(`{"portId": %s, "portType": "TAGGED", "vlanIds": [%s]}`, port, makeVlanArrayString(vid))) + res, err := http.Post("http://localhost:50101/v1/vlan/portupdate","application/x-www-form-urlencoded", body) + if err != nil { + log.Fatal(err) + } + resbody, _ := ioutil.ReadAll(res.Body) + log.Println(string(resbody)) + res.Body.Close() +} + +func vlanModify(port string, vid []string) { + // TODO: Need to implement, it just an example of config + body := strings.NewReader(fmt.Sprintf(`{"portId": %s, "portType": "Tagged", "vlanIds": [%s]}`, port, makeVlanArrayString(vid))) + res, err := http.Post("http://localhost:50101/v1/vlan/portupdate","application/x-www-form-urlencoded", body) + if err != nil { + log.Fatal(err) + return + } + resbody, _ := ioutil.ReadAll(res.Body) + log.Println(string(resbody)) + res.Body.Close() +} + +func vlanDelete(vlanName string, vlanId []string) { + // TODO: Need to implement +} + +func vlanShow(vlanId []string) { + // TODO: Need to implement + for _, v := range vlanId { + value, _ := strconv.ParseUint(v, 10, 16) + fmt.Println(value) + } +} + +// rangeSplit function split the port range value into two values, +// the one is lower where it needs to start to add the port number, +// and the other is upper where it needs to end adding the port number. +func rangeSplit(portsRange string) []string { + spt := strings.Split(portsRange, "-") + var lower, upper int + var err error + // Check string value is digit. + if lower, err = strconv.Atoi(spt[0]); err != nil { + log.Fatal(err) + } + if upper, err = strconv.Atoi(spt[1]); err != nil { + log.Fatal(err) + } + if lower > upper { + tmp := lower + lower = upper + upper = tmp + } + ret := make([]string, 0) + for i:=lower; i <= upper; i++ { + ret = append(ret, strconv.Itoa(i)) + } + return ret +} \ No newline at end of file From 9f611bb9696392aec0cb701f93029dff606d52db Mon Sep 17 00:00:00 2001 From: PFtyrant Date: Tue, 9 Feb 2021 08:11:28 +0000 Subject: [PATCH 12/17] Implement delete feature -Add delete feature. But not fully implemet. It just deletes one vlan group now. --- cmd/vlan.go | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/cmd/vlan.go b/cmd/vlan.go index dca4e53..cf49b8b 100644 --- a/cmd/vlan.go +++ b/cmd/vlan.go @@ -78,7 +78,7 @@ var setVlanCmd = &cobra.Command{ _ = cmd.Help() return } - opt[args[0]].(func(string))(vlanName) + opt[args[0]].(func([]string))(vlanId) case optSet[4]: // VLAN show if !cmd.Flag("id").Changed { @@ -132,18 +132,6 @@ func vlanAdd(vlanType string, port string, vid []string) { } } -func makeVlanArrayString(str []string) string { - ret := "" - for k, v := range str { - if k == 0 { - ret = v - } else { - ret = ret + "," + v - } - } - return ret -} - func vlanSetUntag(port string, vid []string) { body := strings.NewReader(fmt.Sprintf(`{"portId": %s, "portType": "ACCESS", "vlanIds": [%s]}`, port, makeVlanArrayString(vid))) res, err := http.Post("http://localhost:50101/v1/vlan/portupdate","application/x-www-form-urlencoded", body) @@ -155,8 +143,8 @@ func vlanSetUntag(port string, vid []string) { res.Body.Close() } -func vlanSetTagged(port string, vid []string) { - body := strings.NewReader(fmt.Sprintf(`{"portId": %s, "portType": "TAGGED", "vlanIds": [%s]}`, port, makeVlanArrayString(vid))) +func vlanSetTagged(port string, vlanId []string) { + body := strings.NewReader(fmt.Sprintf(`{"portId": %s, "portType": "TAGGED", "vlanIds": [%s]}`, port, makeVlanArrayString(vlanId))) res, err := http.Post("http://localhost:50101/v1/vlan/portupdate","application/x-www-form-urlencoded", body) if err != nil { log.Fatal(err) @@ -166,9 +154,9 @@ func vlanSetTagged(port string, vid []string) { res.Body.Close() } -func vlanModify(port string, vid []string) { +func vlanModify(port string, vlanId []string) { // TODO: Need to implement, it just an example of config - body := strings.NewReader(fmt.Sprintf(`{"portId": %s, "portType": "Tagged", "vlanIds": [%s]}`, port, makeVlanArrayString(vid))) + body := strings.NewReader(fmt.Sprintf(`{"portId": %s, "portType": "Tagged", "vlanIds": [%s]}`, port, makeVlanArrayString(vlanId))) res, err := http.Post("http://localhost:50101/v1/vlan/portupdate","application/x-www-form-urlencoded", body) if err != nil { log.Fatal(err) @@ -179,8 +167,19 @@ func vlanModify(port string, vid []string) { res.Body.Close() } -func vlanDelete(vlanName string, vlanId []string) { +func vlanDelete(vlanId []string) { // TODO: Need to implement + for _, v := range vlanId { + body := strings.NewReader(fmt.Sprintf(`{"vlanId": %s, "name": "%s"}`, v, "")) + res, err := http.Post("http://localhost:50101/v1/vlan/delete","application/x-www-form-urlencoded", body) + if err != nil { + log.Fatal(err) + return + } + resbody, _ := ioutil.ReadAll(res.Body) + log.Println(string(resbody)) + res.Body.Close() + } } func vlanShow(vlanId []string) { @@ -215,4 +214,16 @@ func rangeSplit(portsRange string) []string { ret = append(ret, strconv.Itoa(i)) } return ret +} + +func makeVlanArrayString(str []string) string { + ret := "" + for k, v := range str { + if k == 0 { + ret = v + } else { + ret = ret + "," + v + } + } + return ret } \ No newline at end of file From 3be55fcfc17a8b9911eb6ec8196de4f94d5cb2cf Mon Sep 17 00:00:00 2001 From: PFtyrant Date: Fri, 19 Feb 2021 07:09:18 +0000 Subject: [PATCH 13/17] modify the vlan add feature to support range config, receive server response message -Now, the vlan add feature support range config -read the response message from server --- cmd/vlan.go | 54 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/cmd/vlan.go b/cmd/vlan.go index cf49b8b..e6b9721 100644 --- a/cmd/vlan.go +++ b/cmd/vlan.go @@ -73,8 +73,8 @@ var setVlanCmd = &cobra.Command{ case optSet[3]: // VLAN Delete - if !cmd.Flag("name").Changed { - fmt.Println("Check VLAN name") + if !cmd.Flag("id").Changed { + fmt.Println("Check VLAN id") _ = cmd.Help() return } @@ -124,11 +124,16 @@ func vlanCreate(vid, vlanName string) { func vlanAdd(vlanType string, port string, vid []string) { ports := rangeSplit(port) for _, port := range ports { - if strings.Contains(vlanType, "trunk") { + switch vlanType { + case "trunk": vlanSetTagged(port, vid) - return + break + case "access": + vlanSetUntag(port, vid) + break + default: + log.Fatal("check vlan type what you inputted.") } - vlanSetUntag(port, vid) } } @@ -195,23 +200,32 @@ func vlanShow(vlanId []string) { // and the other is upper where it needs to end adding the port number. func rangeSplit(portsRange string) []string { spt := strings.Split(portsRange, "-") - var lower, upper int + ret := make([]string, 0) + var lower, upper int var err error // Check string value is digit. - if lower, err = strconv.Atoi(spt[0]); err != nil { - log.Fatal(err) - } - if upper, err = strconv.Atoi(spt[1]); err != nil { - log.Fatal(err) - } - if lower > upper { - tmp := lower - lower = upper - upper = tmp - } - ret := make([]string, 0) - for i:=lower; i <= upper; i++ { - ret = append(ret, strconv.Itoa(i)) + if len(spt) > 1 { + // Take range ports + if lower, err = strconv.Atoi(spt[0]); err != nil { + log.Fatal(err) + } + if upper, err = strconv.Atoi(spt[1]); err != nil { + log.Fatal(err) + } + if lower > upper { + tmp := lower + lower = upper + upper = tmp + } + for i := lower; i <= upper; i++ { + ret = append(ret, strconv.Itoa(i)) + } + } else { + // Take only one port + if _, err = strconv.Atoi(spt[0]); err != nil { + log.Fatal(err) + } + ret = append(ret, spt[0]) } return ret } From 792fde427798d69e5e638fdeb7005514af0340e1 Mon Sep 17 00:00:00 2001 From: PFtyrant Date: Thu, 25 Feb 2021 06:04:49 +0000 Subject: [PATCH 14/17] Add the features: vlan show by port and show by vlan, fix help typo -Now, the "show" of VLAN cmd is available. vlan show has two options, one is show vlan by vlanId, the other is show vlan by portId. the usage of the "show" command please refer to the document in P4Networking/doc repo. --- cmd/port.go | 5 +++-- cmd/vlan.go | 51 ++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/cmd/port.go b/cmd/port.go index ac50643..499921e 100644 --- a/cmd/port.go +++ b/cmd/port.go @@ -21,7 +21,7 @@ var ( var setPortCmd = &cobra.Command{ Use: "port", Short: "Set switch port properties", - Long: "setting switch port properties. \nport speed : 10G, 25G, 40G, 50G, 100G\nport fec : \n", + Long: "setting switch port properties. \nport speed : 10G, 25G, 40G, 50G, 100G\nport fec : 0, 1, 2\nAuto-Negotiation : 0, 1, 2\n", Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { // WARN: the port command only support an add feature now, @@ -36,6 +36,7 @@ var setPortCmd = &cobra.Command{ // Check Port Number if !cmd.Flag("Port Number").Changed { fmt.Println("please set the port number.") + _ = cmd.Help() return } @@ -82,7 +83,7 @@ var setPortCmd = &cobra.Command{ An := map[uint]string { 0 : "PM_AN_FORCE_DISABLE", 1 : "PM_AN_FORCE_ENABLE", - 2 :"PM_AN_MAX", + 2 : "PM_AN_MAX", } if !cmd.Flag("Auto Negotiation").Changed { an = 0 diff --git a/cmd/vlan.go b/cmd/vlan.go index e6b9721..2d71f21 100644 --- a/cmd/vlan.go +++ b/cmd/vlan.go @@ -81,12 +81,15 @@ var setVlanCmd = &cobra.Command{ opt[args[0]].(func([]string))(vlanId) case optSet[4]: // VLAN show - if !cmd.Flag("id").Changed { - fmt.Println("Check VLAN Id") + if !cmd.Flag("id").Changed && !cmd.Flag("port").Changed { + fmt.Println("vlanId/portId is not set") _ = cmd.Help() return + } else if cmd.Flag("id").Changed && !cmd.Flag("port").Changed { + opt[args[0]].(func(interface{}, string))(vlanId, "vlan") + } else if !cmd.Flag("id").Changed && cmd.Flag("port").Changed { + opt[args[0]].(func(interface{}, string))(vlanPort, "port") } - opt[args[0]].(func([]string))(vlanId) default: _ = cmd.Help() return @@ -129,6 +132,9 @@ func vlanAdd(vlanType string, port string, vid []string) { vlanSetTagged(port, vid) break case "access": + if len(vid) > 1 { + log.Panic("access port can only configure with 1 vlanId") + } vlanSetUntag(port, vid) break default: @@ -137,8 +143,8 @@ func vlanAdd(vlanType string, port string, vid []string) { } } -func vlanSetUntag(port string, vid []string) { - body := strings.NewReader(fmt.Sprintf(`{"portId": %s, "portType": "ACCESS", "vlanIds": [%s]}`, port, makeVlanArrayString(vid))) +func vlanSetUntag(port string, vlanId []string) { + body := strings.NewReader(fmt.Sprintf(`{"portId": %s, "portType": "ACCESS", "vlanIds": [%s]}`, port, makeVlanArrayString(vlanId))) res, err := http.Post("http://localhost:50101/v1/vlan/portupdate","application/x-www-form-urlencoded", body) if err != nil { log.Fatal(err) @@ -148,8 +154,8 @@ func vlanSetUntag(port string, vid []string) { res.Body.Close() } -func vlanSetTagged(port string, vlanId []string) { - body := strings.NewReader(fmt.Sprintf(`{"portId": %s, "portType": "TAGGED", "vlanIds": [%s]}`, port, makeVlanArrayString(vlanId))) +func vlanSetTagged(port string, vlanIds []string) { + body := strings.NewReader(fmt.Sprintf(`{"portId": %s, "portType": "TAGGED", "vlanIds": [%s]}`, port, makeVlanArrayString(vlanIds))) res, err := http.Post("http://localhost:50101/v1/vlan/portupdate","application/x-www-form-urlencoded", body) if err != nil { log.Fatal(err) @@ -173,7 +179,6 @@ func vlanModify(port string, vlanId []string) { } func vlanDelete(vlanId []string) { - // TODO: Need to implement for _, v := range vlanId { body := strings.NewReader(fmt.Sprintf(`{"vlanId": %s, "name": "%s"}`, v, "")) res, err := http.Post("http://localhost:50101/v1/vlan/delete","application/x-www-form-urlencoded", body) @@ -187,11 +192,31 @@ func vlanDelete(vlanId []string) { } } -func vlanShow(vlanId []string) { - // TODO: Need to implement - for _, v := range vlanId { - value, _ := strconv.ParseUint(v, 10, 16) - fmt.Println(value) +func vlanShow(data interface{}, choice string ) { + if choice == "vlan" { + for _, v := range data.([]string) { + value, _ := strconv.Atoi(v) + body := strings.NewReader(fmt.Sprintf(`{"vlanId": %d, "portId": %d, "choice": "vlan"}`, value, 0)) + res, err := http.Post("http://localhost:50101/v1/vlan/get","application/x-www-form-urlencoded", body) + if err != nil { + log.Fatal(err) + return + } + resbody, _ := ioutil.ReadAll(res.Body) + log.Println(string(resbody)) + res.Body.Close() + } + } else { + value, _ := strconv.Atoi(data.(string)) + body := strings.NewReader(fmt.Sprintf(`{"vlanId": %d, "portId": %d, "choice": "port"}`, 0, value)) + res, err := http.Post("http://localhost:50101/v1/vlan/get","application/x-www-form-urlencoded", body) + if err != nil { + log.Fatal(err) + return + } + resbody, _ := ioutil.ReadAll(res.Body) + log.Println(string(resbody)) + res.Body.Close() } } From 8c29ef0b2d681c8c2d23895d37097e2fa7e170cb Mon Sep 17 00:00:00 2001 From: PFtyrant Date: Thu, 4 Mar 2021 12:44:44 +0000 Subject: [PATCH 15/17] Modify vlan delete and show features. -use JSON.marshal to decode gRPC response message. -add show all vlans features. "pisc-cli vlan show" command will show all of the vlans -add range delete feature. --- cmd/vlan.go | 132 +++++++++++++++++++++++++++++++++++++--------------- go.mod | 1 - go.sum | 36 ++++++-------- 3 files changed, 108 insertions(+), 61 deletions(-) diff --git a/cmd/vlan.go b/cmd/vlan.go index 2d71f21..02cee3f 100644 --- a/cmd/vlan.go +++ b/cmd/vlan.go @@ -1,6 +1,7 @@ package cmd import ( + "encoding/json" "fmt" "github.com/spf13/cobra" "io/ioutil" @@ -73,22 +74,26 @@ var setVlanCmd = &cobra.Command{ case optSet[3]: // VLAN Delete - if !cmd.Flag("id").Changed { - fmt.Println("Check VLAN id") + if !cmd.Flag("id").Changed && !cmd.Flag("port").Changed{ + fmt.Println("vlanId and portId are not given.") _ = cmd.Help() return } - opt[args[0]].(func([]string))(vlanId) + if cmd.Flag("id").Changed && !cmd.Flag("port").Changed { + opt[args[0]].(func([]string, string, int))(vlanId, vlanPort, 0) + } else if cmd.Flag("id").Changed && cmd.Flag("port").Changed { + opt[args[0]].(func([]string, string, int))(vlanId, vlanPort, 1) + } case optSet[4]: // VLAN show if !cmd.Flag("id").Changed && !cmd.Flag("port").Changed { - fmt.Println("vlanId/portId is not set") - _ = cmd.Help() - return + opt[args[0]].(func(interface{}, int))(0, 2) } else if cmd.Flag("id").Changed && !cmd.Flag("port").Changed { - opt[args[0]].(func(interface{}, string))(vlanId, "vlan") + opt[args[0]].(func(interface{}, int))(vlanId, 0) } else if !cmd.Flag("id").Changed && cmd.Flag("port").Changed { - opt[args[0]].(func(interface{}, string))(vlanPort, "port") + opt[args[0]].(func(interface{}, int))(vlanPort, 1) + } else { + _ = cmd.Help() } default: _ = cmd.Help() @@ -120,22 +125,22 @@ func vlanCreate(vid, vlanName string) { log.Fatal(err) } resbody, _ := ioutil.ReadAll(res.Body) - log.Println(string(resbody)) - res.Body.Close() + defer res.Body.Close() + printMessage(resbody) } func vlanAdd(vlanType string, port string, vid []string) { ports := rangeSplit(port) - for _, port := range ports { + for _, p := range ports { switch vlanType { case "trunk": - vlanSetTagged(port, vid) + vlanSetTagged(p, vid) break case "access": if len(vid) > 1 { log.Panic("access port can only configure with 1 vlanId") } - vlanSetUntag(port, vid) + vlanSetUntag(p, vid) break default: log.Fatal("check vlan type what you inputted.") @@ -149,9 +154,9 @@ func vlanSetUntag(port string, vlanId []string) { if err != nil { log.Fatal(err) } + defer res.Body.Close() resbody, _ := ioutil.ReadAll(res.Body) - log.Println(string(resbody)) - res.Body.Close() + printMessage(resbody) } func vlanSetTagged(port string, vlanIds []string) { @@ -161,8 +166,8 @@ func vlanSetTagged(port string, vlanIds []string) { log.Fatal(err) } resbody, _ := ioutil.ReadAll(res.Body) - log.Println(string(resbody)) - res.Body.Close() + defer res.Body.Close() + printMessage(resbody) } func vlanModify(port string, vlanId []string) { @@ -174,52 +179,100 @@ func vlanModify(port string, vlanId []string) { return } resbody, _ := ioutil.ReadAll(res.Body) - log.Println(string(resbody)) + printMessage(resbody) res.Body.Close() } -func vlanDelete(vlanId []string) { - for _, v := range vlanId { - body := strings.NewReader(fmt.Sprintf(`{"vlanId": %s, "name": "%s"}`, v, "")) - res, err := http.Post("http://localhost:50101/v1/vlan/delete","application/x-www-form-urlencoded", body) - if err != nil { - log.Fatal(err) - return +func vlanDelete(vlanId []string, portId string, choice int) { + switch choice { + case 0: + // delete vlan instance + for _, v := range vlanId { + body := strings.NewReader(fmt.Sprintf(`{"vlanId": %s, "port": "%s", "choice": %d}`, v, 0, 0)) + res, err := http.Post("http://localhost:50101/v1/vlan/delete","application/x-www-form-urlencoded", body) + if err != nil { + log.Fatal(err) + return + } + resbody, _ := ioutil.ReadAll(res.Body) + printMessage(resbody) + res.Body.Close() } - resbody, _ := ioutil.ReadAll(res.Body) - log.Println(string(resbody)) - res.Body.Close() + break + case 1: + // delete portId from vlan instance by portId + ports := rangeSplit(portId) + for _, p := range ports { + body := strings.NewReader(fmt.Sprintf(`{"vlanId": %s, "portId": "%s", "choice": %d}`, vlanId[0], p, 1)) + res, err := http.Post("http://localhost:50101/v1/vlan/delete","application/x-www-form-urlencoded", body) + if err != nil { + log.Fatal(err) + return + } + resbody, _ := ioutil.ReadAll(res.Body) + printMessage(resbody) + res.Body.Close() + } + break + default: + return } } -func vlanShow(data interface{}, choice string ) { - if choice == "vlan" { +func vlanShow(data interface{}, choice int ) { + switch choice { + case 0: for _, v := range data.([]string) { value, _ := strconv.Atoi(v) - body := strings.NewReader(fmt.Sprintf(`{"vlanId": %d, "portId": %d, "choice": "vlan"}`, value, 0)) + body := strings.NewReader(fmt.Sprintf(`{"vlanId": %d, "portId": %d, "choice": %d}`, value, 0, 0)) res, err := http.Post("http://localhost:50101/v1/vlan/get","application/x-www-form-urlencoded", body) if err != nil { log.Fatal(err) return } resbody, _ := ioutil.ReadAll(res.Body) - log.Println(string(resbody)) + printMessage(resbody) res.Body.Close() } - } else { + break + case 1: value, _ := strconv.Atoi(data.(string)) - body := strings.NewReader(fmt.Sprintf(`{"vlanId": %d, "portId": %d, "choice": "port"}`, 0, value)) + body := strings.NewReader(fmt.Sprintf(`{"vlanId": %d, "portId": %d, "choice": %d}`, 0, value, 1)) + res, err := http.Post("http://localhost:50101/v1/vlan/get","application/x-www-form-urlencoded", body) + if err != nil { + log.Fatal(err) + return + } + defer res.Body.Close() + + resbody, _ := ioutil.ReadAll(res.Body) + printMessage(resbody) + break + case 2: + // show all of the vlan information + body := strings.NewReader(fmt.Sprintf(`{"vlanId": %d, "portId": %d, "choice": %d}`, 0, 0, 2)) res, err := http.Post("http://localhost:50101/v1/vlan/get","application/x-www-form-urlencoded", body) if err != nil { log.Fatal(err) return } + defer res.Body.Close() + resbody, _ := ioutil.ReadAll(res.Body) - log.Println(string(resbody)) - res.Body.Close() + printMessage(resbody) + break + default: + return } } - +func printMessage(msg []byte) { + var message reponseMessage + err := json.Unmarshal(msg, &message) + if err != nil { + log.Println(err) + } + fmt.Println(message.Message) +} // rangeSplit function split the port range value into two values, // the one is lower where it needs to start to add the port number, // and the other is upper where it needs to end adding the port number. @@ -265,4 +318,9 @@ func makeVlanArrayString(str []string) string { } } return ret +} + +type reponseMessage struct { + IsSuccess bool + Message string } \ No newline at end of file diff --git a/go.mod b/go.mod index dbf8cd2..82984b2 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,6 @@ replace ( require ( github.com/P4Networking/pisc v0.0.0-00010101000000-000000000000 github.com/P4Networking/proto v1.0.0 - github.com/cheggaaa/pb/v3 v3.0.5 github.com/mitchellh/go-homedir v1.1.0 github.com/olekukonko/tablewriter v0.0.4 github.com/schollz/progressbar/v3 v3.7.3 diff --git a/go.sum b/go.sum index 655cb47..cf44c32 100644 --- a/go.sum +++ b/go.sum @@ -37,8 +37,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/P4Networking/netlink v1.1.1/go.mod h1:jphS5KWlRePmRBaqpiFy7OVXLwN971M7FiiSrXeFZ4s= -github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM= -github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= @@ -52,9 +50,6 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cheggaaa/pb v1.0.29 h1:FckUN5ngEk2LpvuG0fw1GEFx6LtyY2pWI/Z2QgCnEYo= -github.com/cheggaaa/pb/v3 v3.0.5 h1:lmZOti7CraK9RSjzExsY53+WWfub9Qv13B5m4ptEoPE= -github.com/cheggaaa/pb/v3 v3.0.5/go.mod h1:X1L61/+36nz9bjIsrDU52qHKOQukUQe2Ge+YvGuquCw= 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= @@ -73,7 +68,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/elliotchance/orderedmap v1.3.0/go.mod h1:8hdSl6jmveQw8ScByd3AaNHNk51RhbTazdqtTty+NFw= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -130,6 +124,7 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 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= @@ -150,7 +145,9 @@ github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoA github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0 h1:bM6ZAFZmc/wPFaRDi0d5L7hGEZEx/2u+Tmr2evNHDiI= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1 h1:X2vfSnm1WC8HEo0MBHZg2TcuDUHJj6kd1TmEAQncnSA= github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1/go.mod h1:oVMjMN64nzEcepv1kdZKgx1qNYt4Ro0Gqefiq2JWdis= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= @@ -176,7 +173,6 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= github.com/jinzhu/copier v0.0.0-20201025035756-632e723a6687/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -198,12 +194,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mantyr/iterator v0.0.0-20150623090054-c4cf40066bc4/go.mod h1:wvRVLNbkJoWRDDT6LzwmLrwPcI4gclOXXGVlA3fHVJE= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= @@ -257,7 +249,6 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/schollz/progressbar v1.0.0 h1:gbyFReLHDkZo8mxy/dLWMr+Mpb1MokGJ1FqCiqacjZM= github.com/schollz/progressbar/v3 v3.7.3 h1:U0etV6FzAPBne0ZqoWwThp7FEdfcTX2lHzQYh5B7scE= github.com/schollz/progressbar/v3 v3.7.3/go.mod h1:fBsumCeOE+GOuGKY1JldFX0eRT6gkw3sw9eZTt2bFgE= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -288,9 +279,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -298,7 +288,6 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/wk8/go-ordered-map v0.2.0/go.mod h1:9ZIbRunKbuvfPKyBP1SIKLcXNlv74YCOZ3t3VTS6gRk= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -352,6 +341,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -360,6 +350,7 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -415,7 +406,6 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -445,8 +435,6 @@ golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 h1:W0lCpv29Hv0UaM1LXb9QlBHLNP8UFfcKjblhVCWftOM= -golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 h1:a/mKvvZr9Jcc8oKfcmgzyp7OwF73JPWsQLvH1z2Kxck= golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -510,11 +498,13 @@ golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d h1:W07d4xkoAUSNOkOzdzXCdFGxT7o2rW4q8M34tB2i//k= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -571,6 +561,8 @@ google.golang.org/genproto v0.0.0-20200828030656-73b5761be4c5 h1:SXvXDcZm33V0P03 google.golang.org/genproto v0.0.0-20200828030656-73b5761be4c5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154 h1:bFFRpT+e8JJVY7lMMfvezL1ZIwqiwmPl2bsE2yx4HqM= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea h1:N98SvVh7Hdle2lgUVFuIkf0B3u29CUakMUQa7Hwz8Wc= +google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -585,12 +577,9 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0= -google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1 h1:DGeFlSan2f+WEtCERJ4J9GJWk15TxUi8QGagfI87Xyc= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.1/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -616,8 +605,8 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -625,6 +614,7 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= From a8c335e25af509bcd7581724a03772bc71e05945 Mon Sep 17 00:00:00 2001 From: PFtyrant Date: Fri, 5 Mar 2021 07:51:08 +0000 Subject: [PATCH 16/17] Delete the vlan modify feature -Delete the vlan modify feature. --- cmd/vlan.go | 74 +++++++++++++++++++---------------------------------- 1 file changed, 26 insertions(+), 48 deletions(-) diff --git a/cmd/vlan.go b/cmd/vlan.go index 02cee3f..91dc269 100644 --- a/cmd/vlan.go +++ b/cmd/vlan.go @@ -18,8 +18,12 @@ var ( vlanId []string opt map[string]interface{} optSet []string + protoOpt []string ) - +type reponseMessage struct { + IsSuccess bool + Message string +} // setVlanCmd represents the add port command var setVlanCmd = &cobra.Command{ Use: "vlan", @@ -39,11 +43,6 @@ var setVlanCmd = &cobra.Command{ return ret, cobra.ShellCompDirectiveNoFileComp }, Run: func(cmd *cobra.Command, args []string) { - // Create(vid string, vlanName string) - // Add(type string, port string, vid []string) - // Modify(port string, vid []string) - // Delete(vName string) - // Show() switch args[0] { case optSet[0]: // VLAN Create @@ -64,15 +63,6 @@ var setVlanCmd = &cobra.Command{ opt[args[0]].(func(string, string, []string))(vlanType, vlanPort, vlanId) case optSet[2]: - // VLAN Modify - if !cmd.Flag("port").Changed || !cmd.Flag("id").Changed { - fmt.Println("Check VLAN port and VLAN Id") - _ = cmd.Help() - return - } - opt[args[0]].(func(string, []string))(vlanPort, vlanId) - - case optSet[3]: // VLAN Delete if !cmd.Flag("id").Changed && !cmd.Flag("port").Changed{ fmt.Println("vlanId and portId are not given.") @@ -84,7 +74,7 @@ var setVlanCmd = &cobra.Command{ } else if cmd.Flag("id").Changed && cmd.Flag("port").Changed { opt[args[0]].(func([]string, string, int))(vlanId, vlanPort, 1) } - case optSet[4]: + case optSet[3]: // VLAN show if !cmd.Flag("id").Changed && !cmd.Flag("port").Changed { opt[args[0]].(func(interface{}, int))(0, 2) @@ -108,19 +98,27 @@ func init() { setVlanCmd.Flags().StringVarP(&vlanName, "name", "n", "", "vlan name") setVlanCmd.Flags().StringVarP(&vlanType, "type", "t", "", "vlan type (Access, Trunk)") setVlanCmd.Flags().StringArrayVarP(&vlanId, "id", "v", []string{}, "vlan id") - optSet = []string{"create","add","modify","delete","show"} + + // command setting + optSet = []string{"create","add", "delete","show"} opt = map[string]interface{} { optSet[0] : vlanCreate, optSet[1] : vlanAdd, - optSet[2] : vlanModify, - optSet[3] : vlanDelete, - optSet[4] : vlanShow, + optSet[2] : vlanDelete, + optSet[3] : vlanShow, } + protoOpt = []string{"create", "portupdate", "delete", "get"} +} + +func makePost(opt string, body *strings.Reader) (resp *http.Response, err error) { + httpAddr := "http://localhost:50101/v1/vlan/" + contentType := "application/x-www-form-urlencoded" + return http.Post(httpAddr+opt,contentType, body) } func vlanCreate(vid, vlanName string) { body := strings.NewReader(fmt.Sprintf(`{"vlanId": %s, "name": "%s"}`, vid, vlanName)) - res, err := http.Post("http://localhost:50101/v1/vlan/create","application/x-www-form-urlencoded", body) + res, err := makePost(protoOpt[0], body) if err != nil { log.Fatal(err) } @@ -150,7 +148,7 @@ func vlanAdd(vlanType string, port string, vid []string) { func vlanSetUntag(port string, vlanId []string) { body := strings.NewReader(fmt.Sprintf(`{"portId": %s, "portType": "ACCESS", "vlanIds": [%s]}`, port, makeVlanArrayString(vlanId))) - res, err := http.Post("http://localhost:50101/v1/vlan/portupdate","application/x-www-form-urlencoded", body) + res, err := makePost(protoOpt[1], body) if err != nil { log.Fatal(err) } @@ -161,7 +159,7 @@ func vlanSetUntag(port string, vlanId []string) { func vlanSetTagged(port string, vlanIds []string) { body := strings.NewReader(fmt.Sprintf(`{"portId": %s, "portType": "TAGGED", "vlanIds": [%s]}`, port, makeVlanArrayString(vlanIds))) - res, err := http.Post("http://localhost:50101/v1/vlan/portupdate","application/x-www-form-urlencoded", body) + res, err := makePost(protoOpt[1], body) if err != nil { log.Fatal(err) } @@ -170,26 +168,13 @@ func vlanSetTagged(port string, vlanIds []string) { printMessage(resbody) } -func vlanModify(port string, vlanId []string) { - // TODO: Need to implement, it just an example of config - body := strings.NewReader(fmt.Sprintf(`{"portId": %s, "portType": "Tagged", "vlanIds": [%s]}`, port, makeVlanArrayString(vlanId))) - res, err := http.Post("http://localhost:50101/v1/vlan/portupdate","application/x-www-form-urlencoded", body) - if err != nil { - log.Fatal(err) - return - } - resbody, _ := ioutil.ReadAll(res.Body) - printMessage(resbody) - res.Body.Close() -} - func vlanDelete(vlanId []string, portId string, choice int) { switch choice { case 0: // delete vlan instance for _, v := range vlanId { body := strings.NewReader(fmt.Sprintf(`{"vlanId": %s, "port": "%s", "choice": %d}`, v, 0, 0)) - res, err := http.Post("http://localhost:50101/v1/vlan/delete","application/x-www-form-urlencoded", body) + res, err := makePost(protoOpt[2], body) if err != nil { log.Fatal(err) return @@ -198,13 +183,12 @@ func vlanDelete(vlanId []string, portId string, choice int) { printMessage(resbody) res.Body.Close() } - break case 1: // delete portId from vlan instance by portId ports := rangeSplit(portId) for _, p := range ports { body := strings.NewReader(fmt.Sprintf(`{"vlanId": %s, "portId": "%s", "choice": %d}`, vlanId[0], p, 1)) - res, err := http.Post("http://localhost:50101/v1/vlan/delete","application/x-www-form-urlencoded", body) + res, err := makePost(protoOpt[2], body) if err != nil { log.Fatal(err) return @@ -213,7 +197,6 @@ func vlanDelete(vlanId []string, portId string, choice int) { printMessage(resbody) res.Body.Close() } - break default: return } @@ -225,7 +208,7 @@ func vlanShow(data interface{}, choice int ) { for _, v := range data.([]string) { value, _ := strconv.Atoi(v) body := strings.NewReader(fmt.Sprintf(`{"vlanId": %d, "portId": %d, "choice": %d}`, value, 0, 0)) - res, err := http.Post("http://localhost:50101/v1/vlan/get","application/x-www-form-urlencoded", body) + res, err := makePost(protoOpt[3], body) if err != nil { log.Fatal(err) return @@ -238,7 +221,7 @@ func vlanShow(data interface{}, choice int ) { case 1: value, _ := strconv.Atoi(data.(string)) body := strings.NewReader(fmt.Sprintf(`{"vlanId": %d, "portId": %d, "choice": %d}`, 0, value, 1)) - res, err := http.Post("http://localhost:50101/v1/vlan/get","application/x-www-form-urlencoded", body) + res, err := makePost(protoOpt[3], body) if err != nil { log.Fatal(err) return @@ -251,7 +234,7 @@ func vlanShow(data interface{}, choice int ) { case 2: // show all of the vlan information body := strings.NewReader(fmt.Sprintf(`{"vlanId": %d, "portId": %d, "choice": %d}`, 0, 0, 2)) - res, err := http.Post("http://localhost:50101/v1/vlan/get","application/x-www-form-urlencoded", body) + res, err := makePost(protoOpt[3], body) if err != nil { log.Fatal(err) return @@ -318,9 +301,4 @@ func makeVlanArrayString(str []string) string { } } return ret -} - -type reponseMessage struct { - IsSuccess bool - Message string } \ No newline at end of file From 731e34a795dfdb2639e92f19c37a30261c16106e Mon Sep 17 00:00:00 2001 From: PFtyrant Date: Mon, 22 Mar 2021 03:24:43 +0000 Subject: [PATCH 17/17] Fix set-flow/del-flow bugs -Modifed the set-flow error messages -Fixed that the set-flow tab completion suggests abnomaly lists. -Fixed that the del-flow can't delete the flow when using -m flag. --- cmd/delFlow.go | 8 ++++---- cmd/setFlow.go | 26 ++++++++++++-------------- cmd/utils.go | 35 ++++++++++++++--------------------- 3 files changed, 30 insertions(+), 39 deletions(-) diff --git a/cmd/delFlow.go b/cmd/delFlow.go index a2664f1..8294495 100644 --- a/cmd/delFlow.go +++ b/cmd/delFlow.go @@ -45,7 +45,7 @@ var delFlowCmd = &cobra.Command{ cli := *cliAddr ctx := *ctxAddr - if all && !clear && len(args) <= 0 && !cmd.Flag("match").Changed { + if all && !clear && !cmd.Flag("match").Changed { // flag "-a" Clear all tables for _, tb := range Obj.p4Info.Tables { if NotSupportToReadTable[tb.ID] { @@ -53,7 +53,7 @@ var delFlowCmd = &cobra.Command{ } Obj.table = append(Obj.table, tb) } - } else if !all && clear && len(args) > 0 && !cmd.Flag("match").Changed { + } else if !all && clear && !cmd.Flag("match").Changed { // flag "-c" Clear a table for _, tb := range Obj.p4Info.Tables { if NotSupportToReadTable[tb.ID] { @@ -63,7 +63,7 @@ var delFlowCmd = &cobra.Command{ Obj.table = append(Obj.table, tb) } } - } else if !all && !clear && len(args) > 0 && cmd.Flag("match").Changed { + } else if !all && !clear && cmd.Flag("match").Changed { for a, v := range delEntry { delEntry[a] = strings.TrimSpace(v) } @@ -93,7 +93,6 @@ var delFlowCmd = &cobra.Command{ cmd.Help() return } - for _, tb := range Obj.table { stream, err := cli.Read(ctx, genReadRequestWithId(tb.ID)) if err != nil { @@ -117,6 +116,7 @@ var delFlowCmd = &cobra.Command{ if cmd.Flag("match").Changed { cnt, err = DeleteEntries(&rsp, &cli, &ctx, delEntry) } else { + //all, clear cnt, err = DeleteEntries(&rsp, &cli, &ctx, nil) } if err != nil { diff --git a/cmd/setFlow.go b/cmd/setFlow.go index e948a73..1945626 100644 --- a/cmd/setFlow.go +++ b/cmd/setFlow.go @@ -37,8 +37,8 @@ var setFlowCmd = &cobra.Command{ defer conn.Close() defer cancel() - ret := make([]string, 0) if len(args) < 1 { + ret := make([]string, 0) argsList, _ := Obj.p4Info.GuessTableName(toComplete) for _, v := range argsList { if strings.Contains(v, preFixIg) || strings.Contains(v, preFixEg) { @@ -47,20 +47,19 @@ var setFlowCmd = &cobra.Command{ } } return ret, cobra.ShellCompDirectiveNoFileComp - } else if len(args) == 1 { + } + if len(args) == 1 { for _, v := range Obj.p4Info.Tables { - ret := make([]string, 0) if strings.Contains(v.Name, args[0]) { + ret := make([]string, 0) for _, action := range v.ActionSpecs { name := strings.Split(action.Name, ".") - ret = append(ret, name[len(name)-2] + "." + name[len(name)-1]) + ret = append(ret, name[len(name)-1]) } - ret = append(ret, v.Name+args[0]) return ret, cobra.ShellCompDirectiveNoFileComp } } } - return nil, cobra.ShellCompDirectiveNoFileComp }, PreRun: func(cmd *cobra.Command, args []string) { @@ -165,7 +164,7 @@ var setFlowSub = &cobra.Command{ for _, table := range Obj.table { for _, actionSpec := range table.ActionSpecs { - if strings.Contains(actionSpec.Name, args[1]) { + if strings.Compare(args[1], actionSpec.Name[strings.LastIndex(actionSpec.Name, ".")+1:]) == 0 { Obj.actions[actionSpec.ID] = actionSpec.Name Obj.actionId = actionSpec.ID Obj.actionName = actionSpec.Name @@ -187,10 +186,10 @@ var setFlowSub = &cobra.Command{ return } - ttlId, ok := Obj.p4Info.GetDataId(Obj.table[0].Name, "$ENTRY_TTL") - if ok && ttl == "" { - fmt.Println("table has ttl entry but it's not set, using default value 600 for ttl") - ttl = "600" + ttlId, ttlok := Obj.p4Info.GetDataId(Obj.table[0].Name, "$ENTRY_TTL") + if ttlok && ttl == "" { + fmt.Println("table has ttl entry but it's not set, using default value 1000 for ttl") + ttl = "1000" } collectedActionFieldIds, err := collectActionFieldIds(&Obj.table[0], Obj.actionId, actionValues) @@ -199,8 +198,7 @@ var setFlowSub = &cobra.Command{ return } if len(collectedActionFieldIds) != len(actionValues) { - fmt.Printf("expected action field length : %d, received action filed length [%d]\n", len(collectedActionFieldIds), len(actionValues)) - fmt.Println("Check action arguments") + fmt.Printf("the expected action field length is : %d, the received action filed length is : %d\n", len(collectedActionFieldIds), len(actionValues)) return } @@ -228,7 +226,7 @@ var setFlowSub = &cobra.Command{ } } - if ok { + if ttlok { l, err := strconv.ParseUint(ttl, 10, 32) if err != nil { fmt.Printf("Please Check the TTL value %s.\n", ttl) diff --git a/cmd/utils.go b/cmd/utils.go index c113614..3dd9c4d 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -583,50 +583,43 @@ func genEntity(tableId uint32) *p4.Entity { // DeleteEntries function read entries from the response to delete all entries of a table func DeleteEntries(rsp **p4.ReadResponse, cli *p4.BfRuntimeClient, ctx *context.Context, matchKey []string) ([]int, error) { var result = make([]int, 0) - var pbcount = 0 var delReq *p4.WriteRequest = nil - + var tbl *p4.TableEntry = nil + var match []*p4.KeyField = nil + var bar *progressbar.ProgressBar if matchKey == nil { - pbcount = len((*rsp).Entities) + bar = progressbar.Default(int64(len((*rsp).Entities))) } else { - pbcount = 1 + bar = progressbar.Default(int64(1)) } - bar := progressbar.Default(int64(pbcount)) - for k, e := range (*rsp).Entities { - tbl := e.GetTableEntry() - found := false - delReq = nil + var found bool = true + tbl = e.GetTableEntry() if matchKey != nil { collectedMatchTypes, ok := collectTableMatchTypes(&matchKey) if !ok { - fmt.Println("Match key argument are not matched") - return nil, errors.New("argument err") + return nil, errors.New("Match key not matched") } - match := BuildMatchKeys(&collectedMatchTypes) + match = BuildMatchKeys(&collectedMatchTypes) if match == nil { // the nil of the match variable is mean that the BuildMatchKeys function can't make the match key with the input argument. return nil, nil } - for kf, kv := range match { - // TODO: may be can find a better way to compare the match key. - if tbl.Key.Fields[kf].String() == kv.String() { - found = true + for key, v := range tbl.Key.Fields { + if v.String() != match[key].String() { + found = false break } } - } else { - found = true } if found { - result = append(result, k) delReq = util.GenWriteRequestWithId(p4.Update_DELETE, id.TableId(tbl.TableId), tbl.Key.Fields, tbl.Data) - _ = bar.Add(1) - _, err := (*cli).Write(*ctx, delReq) if err != nil { return nil, err } + _ = bar.Add(1) + result = append(result, k) } } return result, nil