...

Source file src/k8s.io/kubernetes/test/e2e/network/util_iperf.go

Documentation: k8s.io/kubernetes/test/e2e/network

     1  /*
     2  Copyright 2015 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package network
    18  
    19  // Tests network performance using iperf or other containers.
    20  import (
    21  	"bytes"
    22  	"encoding/json"
    23  	"fmt"
    24  	"math"
    25  	"strconv"
    26  	"strings"
    27  
    28  	"k8s.io/kubernetes/test/e2e/framework"
    29  )
    30  
    31  const (
    32  	megabyte = 1024 * 1024
    33  )
    34  
    35  // IPerfResults is a struct that stores some IPerfCSVResult
    36  type IPerfResults struct {
    37  	BandwidthMap map[string]int64
    38  }
    39  
    40  // IPerfCSVResult struct modelling an iperf record....
    41  // 20160314154239,172.17.0.3,34152,172.17.0.2,5001,3,0.0-10.0,33843707904,27074774092
    42  type IPerfCSVResult struct {
    43  	date          string // field 1 in the csv
    44  	cli           string // field 2 in the csv
    45  	cliPort       int64  // ...
    46  	server        string
    47  	servPort      int64
    48  	id            string
    49  	interval      string
    50  	transferBits  int64
    51  	bandwidthBits int64
    52  }
    53  
    54  func (i *IPerfCSVResult) bandwidthMB() int64 {
    55  	return int64(math.Round(float64(i.bandwidthBits) / float64(megabyte) / 8))
    56  }
    57  
    58  // Add adds a new result to the Results struct.
    59  func (i *IPerfResults) Add(ipr *IPerfCSVResult) {
    60  	if i.BandwidthMap == nil {
    61  		i.BandwidthMap = map[string]int64{}
    62  	}
    63  	i.BandwidthMap[ipr.cli] = ipr.bandwidthBits
    64  }
    65  
    66  // ToTSV exports an easily readable tab delimited format of all IPerfResults.
    67  func (i *IPerfResults) ToTSV() string {
    68  	if len(i.BandwidthMap) < 1 {
    69  		framework.Logf("Warning: no data in bandwidth map")
    70  	}
    71  
    72  	var buffer bytes.Buffer
    73  	for node, bandwidth := range i.BandwidthMap {
    74  		asJSON, _ := json.Marshal(node)
    75  		buffer.WriteString("\t " + string(asJSON) + "\t " + fmt.Sprintf("%E", float64(bandwidth)))
    76  	}
    77  	return buffer.String()
    78  }
    79  
    80  // NewIPerf parses an IPerf CSV output line into an IPerfCSVResult.
    81  func NewIPerf(csvLine string) (*IPerfCSVResult, error) {
    82  	if len(csvLine) == 0 {
    83  		return nil, fmt.Errorf("No iperf output received in csv line")
    84  	}
    85  	csvLine = strings.Trim(csvLine, "\n")
    86  	slice := StrSlice(strings.Split(csvLine, ","))
    87  	if len(slice) != 9 {
    88  		return nil, fmt.Errorf("Incorrect fields in the output: %v (%v out of 9)", slice, len(slice))
    89  	}
    90  	i := IPerfCSVResult{}
    91  	i.date = slice.get(0)
    92  	i.cli = slice.get(1)
    93  	i.cliPort = intOrFail("client port", slice.get(2))
    94  	i.server = slice.get(3)
    95  	i.servPort = intOrFail("server port", slice.get(4))
    96  	i.id = slice.get(5)
    97  	i.interval = slice.get(6)
    98  	i.transferBits = intOrFail("transfer port", slice.get(7))
    99  	i.bandwidthBits = intOrFail("bandwidth port", slice.get(8))
   100  	return &i, nil
   101  }
   102  
   103  // StrSlice represents a string slice
   104  type StrSlice []string
   105  
   106  func (s StrSlice) get(i int) string {
   107  	if i >= 0 && i < len(s) {
   108  		return s[i]
   109  	}
   110  	return ""
   111  }
   112  
   113  // intOrFail is a convenience function for parsing integers.
   114  func intOrFail(debugName string, rawValue string) int64 {
   115  	value, err := strconv.ParseInt(rawValue, 10, 64)
   116  	if err != nil {
   117  		framework.Failf("Failed parsing value %v from the string '%v' as an integer", debugName, rawValue)
   118  	}
   119  	return value
   120  }
   121  
   122  // IPerf2EnhancedCSVResults models the results produced by iperf2 when run with the -e (--enhancedreports) flag.
   123  type IPerf2EnhancedCSVResults struct {
   124  	Intervals []*IPerfCSVResult
   125  	Total     *IPerfCSVResult
   126  }
   127  
   128  // ParseIPerf2EnhancedResultsFromCSV parses results from iperf2 when given the -e (--enhancedreports)
   129  // and `--reportstyle C` options.
   130  // Example output:
   131  // 20201210141800.884,10.244.2.24,47880,10.96.114.79,6789,3,0.0-1.0,1677852672,13422821376
   132  // 20201210141801.881,10.244.2.24,47880,10.96.114.79,6789,3,1.0-2.0,1980760064,15846080512
   133  // 20201210141802.883,10.244.2.24,47880,10.96.114.79,6789,3,2.0-3.0,1886650368,15093202944
   134  // 20201210141803.882,10.244.2.24,47880,10.96.114.79,6789,3,3.0-4.0,2035417088,16283336704
   135  // 20201210141804.879,10.244.2.24,47880,10.96.114.79,6789,3,4.0-5.0,1922957312,15383658496
   136  // 20201210141805.881,10.244.2.24,47880,10.96.114.79,6789,3,5.0-6.0,2095316992,16762535936
   137  // 20201210141806.882,10.244.2.24,47880,10.96.114.79,6789,3,6.0-7.0,1741291520,13930332160
   138  // 20201210141807.879,10.244.2.24,47880,10.96.114.79,6789,3,7.0-8.0,1862926336,14903410688
   139  // 20201210141808.878,10.244.2.24,47880,10.96.114.79,6789,3,8.0-9.0,1821245440,14569963520
   140  // 20201210141809.849,10.244.2.24,47880,10.96.114.79,6789,3,0.0-10.0,18752208896,15052492511
   141  func ParseIPerf2EnhancedResultsFromCSV(output string) (*IPerf2EnhancedCSVResults, error) {
   142  	var parsedResults []*IPerfCSVResult
   143  	for _, line := range strings.Split(output, "\n") {
   144  		parsed, err := NewIPerf(line)
   145  		if err != nil {
   146  			return nil, err
   147  		}
   148  		parsedResults = append(parsedResults, parsed)
   149  	}
   150  	if parsedResults == nil || len(parsedResults) == 0 {
   151  		return nil, fmt.Errorf("no results parsed from iperf2 output")
   152  	}
   153  	// format:
   154  	// all but last lines are intervals
   155  	intervals := parsedResults[:len(parsedResults)-1]
   156  	// last line is an aggregation
   157  	total := parsedResults[len(parsedResults)-1]
   158  	return &IPerf2EnhancedCSVResults{
   159  		Intervals: intervals,
   160  		Total:     total,
   161  	}, nil
   162  }
   163  
   164  // IPerf2NodeToNodeCSVResults models the results of running iperf2 between a daemonset of clients and
   165  // a single server.  The node name of the server is captured, along with a map of client node name
   166  // to iperf2 results.
   167  type IPerf2NodeToNodeCSVResults struct {
   168  	ServerNode string
   169  	Results    map[string]*IPerf2EnhancedCSVResults
   170  }
   171  

View as plain text