github.com/fafucoder/cilium@v1.6.11/cilium/cmd/bpf_metrics_list.go (about) 1 // Copyright 2018 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package cmd 16 17 import ( 18 "fmt" 19 "os" 20 "sort" 21 "strconv" 22 "strings" 23 "text/tabwriter" 24 25 "github.com/cilium/cilium/common" 26 "github.com/cilium/cilium/pkg/command" 27 "github.com/cilium/cilium/pkg/maps/metricsmap" 28 monitorAPI "github.com/cilium/cilium/pkg/monitor/api" 29 30 "github.com/spf13/cobra" 31 ) 32 33 const ( 34 reasonTitle = "REASON" 35 directionTitle = "DIRECTION" 36 packetsTitle = "PACKETS" 37 bytesTitle = "BYTES" 38 ) 39 40 var bpfMetricsListCmd = &cobra.Command{ 41 Use: "list", 42 Short: "List BPF datapath traffic metrics", 43 Run: func(cmd *cobra.Command, args []string) { 44 common.RequireRootPrivilege("cilium bpf metrics list") 45 46 bpfMetricsList := make(map[string][]string) 47 if err := metricsmap.Metrics.Dump(bpfMetricsList); err != nil { 48 fmt.Fprintf(os.Stderr, "error dumping contents of map: %s\n", err) 49 os.Exit(1) 50 } 51 52 if command.OutputJSON() { 53 if err := command.PrintOutput(bpfMetricsList); err != nil { 54 fmt.Fprintf(os.Stderr, "error getting output of map in JSON: %s\n", err) 55 os.Exit(1) 56 } 57 return 58 } 59 60 listMetrics(bpfMetricsList) 61 }, 62 } 63 64 func listMetrics(bpfMetricsList map[string][]string) { 65 if len(bpfMetricsList) == 0 { 66 fmt.Fprintf(os.Stderr, "No entries found.\n") 67 return 68 } 69 70 w := tabwriter.NewWriter(os.Stdout, 5, 0, 3, ' ', 0) 71 fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", reasonTitle, directionTitle, packetsTitle, bytesTitle) 72 73 const numColumns = 4 74 rows := [][numColumns]string{} 75 76 for key, value := range bpfMetricsList { 77 var reason, trafficDirection, packets, bytes string 78 var keyIsValid, valueIsValid bool 79 var reasonCode, trafficDirectionCode uint8 80 81 reason, trafficDirection, keyIsValid = extractTwoValues(key) 82 83 if keyIsValid { 84 v, err := strconv.Atoi(reason) 85 reasonCode = uint8(v) 86 keyIsValid = err == nil 87 } 88 89 if keyIsValid { 90 v, err := strconv.Atoi(trafficDirection) 91 trafficDirectionCode = uint8(v) 92 keyIsValid = err == nil 93 } 94 95 if keyIsValid && len(value) == 1 { 96 packets, bytes, valueIsValid = extractTwoValues(value[0]) 97 } 98 99 if keyIsValid && valueIsValid { 100 rows = append(rows, [numColumns]string{monitorAPI.DropReason(reasonCode), metricsmap.MetricDirection(trafficDirectionCode), packets, bytes}) 101 } else { 102 // Fall back to best effort printing. 103 for i, v := range value { 104 if i == 0 { 105 rows = append(rows, [numColumns]string{key, v, "", ""}) 106 } else { 107 rows = append(rows, [numColumns]string{"", v, "", ""}) 108 } 109 } 110 } 111 } 112 113 sort.Slice(rows, func(i, j int) bool { 114 for k := 0; k < numColumns; k++ { 115 c := strings.Compare(rows[i][k], rows[j][k]) 116 117 if c != 0 { 118 return c < 0 119 } 120 } 121 122 return false 123 }) 124 125 for _, r := range rows { 126 fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", r[0], r[1], r[2], r[3]) 127 } 128 129 w.Flush() 130 } 131 132 func extractTwoValues(str string) (string, string, bool) { 133 tmp := strings.Split(str, " ") 134 if len(tmp) != 2 { 135 return "", "", false 136 } 137 138 a := strings.Split(tmp[0], ":") 139 if len(a) != 2 { 140 return "", "", false 141 } 142 143 b := strings.Split(tmp[1], ":") 144 if len(b) != 2 { 145 return "", "", false 146 } 147 148 return a[1], b[1], true 149 } 150 151 func init() { 152 bpfMetricsCmd.AddCommand(bpfMetricsListCmd) 153 command.AddJSONOutput(bpfMetricsListCmd) 154 }