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  }