k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/e2e/network/util_iperf.go (about) 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 }