{"action":"created","comment":{"url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/comments/62657991","id":62657991,"diff_hunk":"@@ -0,0 +1,660 @@\n+/*\n+Copyright 2016 The Kubernetes Authors All rights reserved.\n+\n+Licensed under the Apache License, Version 2.0 (the \"License\");\n+you may not use this file except in compliance with the License.\n+You may obtain a copy of the License at\n+\n+    http://www.apache.org/licenses/LICENSE-2.0\n+\n+Unless required by applicable law or agreed to in writing, software\n+distributed under the License is distributed on an \"AS IS\" BASIS,\n+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+See the License for the specific language governing permissions and\n+limitations under the License.\n+*/\n+\n+/*\n+ nptest.go\n+\n+ Dual-mode program - runs as both the orchestrator and as the worker nodes depending on command line flags\n+ The RPC API is contained wholly within this file.\n+*/\n+\n+package main\n+\n+// Imports only base Golang packages\n+import (\n+\t\"bytes\"\n+\t\"flag\"\n+\t\"fmt\"\n+\t\"log\"\n+\t\"net\"\n+\t\"net/http\"\n+\t\"net/rpc\"\n+\t\"os\"\n+\t\"os/exec\"\n+\t\"regexp\"\n+\t\"strconv\"\n+\t\"sync\"\n+\t\"time\"\n+)\n+\n+type Point struct {\n+\tmss       int\n+\tbandwidth string\n+\tindex     int\n+}\n+\n+var mode string\n+var port string\n+var host string\n+var worker string\n+var kubenode string\n+var podname string\n+\n+var workerStateMap map[string]*workerState\n+\n+var iperf_tcp_output_regexp *regexp.Regexp\n+var iperf_udp_output_regexp *regexp.Regexp\n+var netperf_output_regexp *regexp.Regexp\n+\n+var dataPoints map[string][]Point\n+var dataPointKeys []string\n+var datapointsFlushed bool\n+\n+var global_lock sync.Mutex\n+\n+const (\n+\tWORKER_MODE         = \"worker\"\n+\tORCHESTRATOR_MODE   = \"orchestrator\"\n+\tIPERF3_PATH         = \"/usr/bin/iperf3\"\n+\tNETPERF_PATH        = \"/usr/local/bin/netperf\"\n+\tNETPERF_SERVER_PATH = \"/usr/local/bin/netserver\"\n+\tOUTPUT_CAPTURE_FILE = \"/tmp/output.txt\"\n+\tCSVFILE             = \"/tmp/netperf.csv\"\n+\tMSS_MIN             = 96\n+\tMSS_MAX             = 1460\n+\tMSS_STEP_SIZE       = 256\n+\tPARALLELSTREAMS     = \"8\"\n+)\n+\n+const (\n+\tIPERF_TCP_TEST = iota\n+\tIPERF_UDP_TEST = iota\n+\tNETPERF_TEST   = iota\n+)\n+\n+type NetPerfRpc int\n+type ClientRegistrationData struct {\n+\tHost     string\n+\tKubeNode string\n+\tWorker   string\n+\tIP       string\n+}\n+\n+type IperfClientWorkItem struct {\n+\tHost string\n+\tPort string\n+\tMSS  int\n+\tType int\n+}\n+\n+type IperfServerWorkItem struct {\n+\tListenPort string\n+\tTimeout    int\n+}\n+\n+type WorkItem struct {\n+\tIsClientItem bool\n+\tIsServerItem bool\n+\tIsIdle       bool\n+\tClientItem   IperfClientWorkItem\n+\tServerItem   IperfServerWorkItem\n+}\n+\n+type workerState struct {\n+\tsentServerItem bool\n+\tidle           bool\n+\tIP             string\n+\tworker         string\n+}\n+\n+type WorkerOutput struct {\n+\tOutput string\n+\tCode   int\n+\tWorker string\n+\tType   int\n+}\n+\n+type Testcase struct {\n+\tSourceNode      string\n+\tDestinationNode string\n+\tLabel           string\n+\tClusterIP       bool\n+\tFinished        bool\n+\tMSS             int\n+\tType            int\n+}\n+\n+var testcases []*Testcase\n+var currentJobIndex int\n+\n+func init() {\n+\tflag.StringVar(&mode, \"mode\", \"worker\", \"Mode for the daemon (worker | orchestrator)\")\n+\tflag.StringVar(&port, \"port\", \"5202\", \"Port to listen on (defaults to 5202)\")\n+\tflag.StringVar(&host, \"host\", \"\", \"IP address to bind to (defaults to 0.0.0.0)\")\n+\n+\tworkerStateMap = make(map[string]*workerState)\n+\ttestcases = []*Testcase{\n+\t\t{SourceNode: \"netperf-w1\", DestinationNode: \"netperf-w2\", Label: \"1 iperf TCP. Same VM using Pod IP\", Type: IPERF_TCP_TEST, ClusterIP: false, MSS: MSS_MIN},\n+\t\t{SourceNode: \"netperf-w1\", DestinationNode: \"netperf-w2\", Label: \"2 iperf TCP. Same VM using Virtual IP\", Type: IPERF_TCP_TEST, ClusterIP: true, MSS: MSS_MIN},\n+\t\t{SourceNode: \"netperf-w1\", DestinationNode: \"netperf-w3\", Label: \"3 iperf TCP. Remote VM using Pod IP\", Type: IPERF_TCP_TEST, ClusterIP: false, MSS: MSS_MIN},\n+\t\t{SourceNode: \"netperf-w3\", DestinationNode: \"netperf-w2\", Label: \"4 iperf TCP. Remote VM using Virtual IP\", Type: IPERF_TCP_TEST, ClusterIP: true, MSS: MSS_MIN},\n+\t\t{SourceNode: \"netperf-w2\", DestinationNode: \"netperf-w2\", Label: \"5 iperf TCP. Hairpin Pod to own Virtual IP\", Type: IPERF_TCP_TEST, ClusterIP: true, MSS: MSS_MIN},\n+\t\t{SourceNode: \"netperf-w1\", DestinationNode: \"netperf-w2\", Label: \"6 iperf UDP. Same VM using Pod IP\", Type: IPERF_UDP_TEST, ClusterIP: false, MSS: MSS_MAX},\n+\t\t{SourceNode: \"netperf-w1\", DestinationNode: \"netperf-w2\", Label: \"7 iperf UDP. Same VM using Virtual IP\", Type: IPERF_UDP_TEST, ClusterIP: true, MSS: MSS_MAX},\n+\t\t{SourceNode: \"netperf-w1\", DestinationNode: \"netperf-w3\", Label: \"8 iperf UDP. Remote VM using Pod IP\", Type: IPERF_UDP_TEST, ClusterIP: false, MSS: MSS_MAX},\n+\t\t{SourceNode: \"netperf-w3\", DestinationNode: \"netperf-w2\", Label: \"9 iperf UDP. Remote VM using Virtual IP\", Type: IPERF_UDP_TEST, ClusterIP: true, MSS: MSS_MAX},\n+\t\t{SourceNode: \"netperf-w1\", DestinationNode: \"netperf-w2\", Label: \"10 netperf. Same VM using Pod IP\", Type: NETPERF_TEST, ClusterIP: false},\n+\t\t{SourceNode: \"netperf-w1\", DestinationNode: \"netperf-w2\", Label: \"11 netperf. Same VM using Virtual IP\", Type: NETPERF_TEST, ClusterIP: true},\n+\t\t{SourceNode: \"netperf-w1\", DestinationNode: \"netperf-w3\", Label: \"12 netperf. Remote VM using Pod IP\", Type: NETPERF_TEST, ClusterIP: false},\n+\t\t{SourceNode: \"netperf-w3\", DestinationNode: \"netperf-w2\", Label: \"13 netperf. Remote VM using Virtual IP\", Type: NETPERF_TEST, ClusterIP: true},\n+\t}\n+\n+\tcurrentJobIndex = 0\n+\n+\t// Regexes to parse the Mbits/sec out of iperf TCP, UDP and netperf output\n+\tiperf_tcp_output_regexp = regexp.MustCompile(\"SUM.*\\\\s+(\\\\d+)\\\\sMbits/sec\\\\s+receiver\")\n+\tiperf_udp_output_regexp = regexp.MustCompile(\"\\\\s+(\\\\S+)\\\\sMbits/sec\\\\s+\\\\S+\\\\s+ms\\\\s+\")\n+\tnetperf_output_regexp = regexp.MustCompile(\"\\\\s+\\\\d+\\\\s+\\\\d+\\\\s+\\\\d+\\\\s+\\\\S+\\\\s+(\\\\S+)\\\\s+\")\n+\n+\tdataPoints = make(map[string][]Point)\n+}\n+\n+func initializeOutputFiles() {\n+\tfd, err := os.OpenFile(OUTPUT_CAPTURE_FILE, os.O_RDWR|os.O_CREATE, 0666)\n+\tif err != nil {\n+\t\tfmt.Println(\"Failed to open output capture file\", err)\n+\t\tos.Exit(2)\n+\t}\n+\tfd.Close()\n+\n+\tfd, err = os.OpenFile(CSVFILE, os.O_RDWR|os.O_CREATE, 0666)\n+\tif err != nil {\n+\t\tfmt.Println(\"Failed to open output capture file\", err)\n+\t\tos.Exit(2)\n+\t}\n+\n+\tfmt.Println(\"Netperf Test Daemon starting up...\")\n+\tfd.Close()\n+}\n+\n+func main() {\n+\tinitializeOutputFiles()\n+\tflag.Parse()\n+\tif validateParams() == false {\n+\t\tfmt.Println(\"Failed to parse cmdline args - fatal error - bailing out\")\n+\t\tos.Exit(1)\n+\n+\t}\n+\tgrabEnv()\n+\tfmt.Println(\"Running as\", mode, \"...\")\n+\tif mode == ORCHESTRATOR_MODE {\n+\t\torchestrate()\n+\t} else {\n+\t\tstart_work()\n+\t}\n+\tfmt.Println(\"Terminating npd\")\n+}\n+\n+func grabEnv() {\n+\tworker = os.Getenv(\"worker\")\n+\tkubenode = os.Getenv(\"kubenode\")\n+\tpodname = os.Getenv(\"HOSTNAME\")\n+}\n+\n+func validateParams() (rv bool) {\n+\trv = true\n+\tif mode != WORKER_MODE && mode != ORCHESTRATOR_MODE {\n+\t\tfmt.Println(\"Invalid mode\", mode)\n+\t\treturn false\n+\t}\n+\n+\tif len(port) == 0 {\n+\t\tfmt.Println(\"Invalid port\", port)\n+\t\treturn false\n+\t}\n+\n+\tif (len(host)) == 0 {\n+\t\tif mode == ORCHESTRATOR_MODE {\n+\t\t\thost = os.Getenv(\"NETPERF_ORCH_SERVICE_HOST\")\n+\t\t} else {\n+\t\t\thost = os.Getenv(\"NETPERF_ORCH_SERVICE_HOST\")\n+\t\t}\n+\t}\n+\treturn\n+}\n+\n+func allWorkersIdle() bool {\n+\tfor _, v := range workerStateMap {\n+\t\tif v.idle == false {\n+\t\t\treturn false\n+\t\t}\n+\t}\n+\treturn true\n+}\n+\n+func getWorkerPodIP(worker string) string {\n+\treturn workerStateMap[worker].IP\n+}\n+\n+func allocateWorkToClient(workerS *workerState, reply *WorkItem) {\n+\n+\tif allWorkersIdle() == false {\n+\t\treply.IsIdle = true\n+\t\treturn\n+\t}\n+\n+\t// System is all idle - pick up next work item to allocate to client\n+\tfor n, v := range testcases {\n+\n+\t\tif v.Finished == true {\n+\t\t\tcontinue\n+\t\t}\n+\n+\t\tif v.SourceNode != workerS.worker {\n+\t\t\treply.IsIdle = true\n+\t\t\treturn\n+\t\t}\n+\n+\t\t_, ok := workerStateMap[v.DestinationNode]\n+\t\tif ok == false {\n+\t\t\treply.IsIdle = true\n+\t\t\treturn\n+\t\t}\n+\t\tfmt.Println(\"Requesting jobrun '\", v.Label, \"' from\", v.SourceNode, \"to\", v.DestinationNode, \"for MSS\", v.MSS)\n+\t\treply.ClientItem.Type = v.Type\n+\t\treply.IsClientItem = true\n+\t\tworkerS.idle = false\n+\t\tcurrentJobIndex = n\n+\n+\t\tif v.ClusterIP == false {\n+\t\t\treply.ClientItem.Host = getWorkerPodIP(v.DestinationNode)\n+\t\t} else {\n+\t\t\treply.ClientItem.Host = os.Getenv(\"NETPERF_W2_SERVICE_HOST\")\n+\t\t}\n+\n+\t\tswitch {\n+\t\tcase v.Type == IPERF_TCP_TEST || v.Type == IPERF_UDP_TEST:\n+\t\t\treply.ClientItem.Port = \"5201\"\n+\t\t\treply.ClientItem.MSS = v.MSS\n+\n+\t\t\tv.MSS = v.MSS + MSS_STEP_SIZE\n+\t\t\tif v.MSS > MSS_MAX {\n+\t\t\t\tv.Finished = true\n+\t\t\t}\n+\t\t\treturn\n+\n+\t\tcase v.Type == NETPERF_TEST:\n+\t\t\treply.ClientItem.Port = \"12865\"\n+\t\t\treturn\n+\t\t}\n+\t}\n+\n+\tfor _, v := range testcases {\n+\t\tif v.Finished == false {\n+\t\t\treturn\n+\t\t}\n+\t}\n+\n+\tif datapointsFlushed == false {\n+\t\tfmt.Println(\"ALL TESTCASES AND MSS RANGES COMPLETE - WRITING CSV FILE\")\n+\t\tflushDataPointsToCsv()\n+\t\tdatapointsFlushed = true\n+\t}\n+\n+\treply.IsIdle = true\n+}\n+\n+func (t *NetPerfRpc) RegisterClient(data *ClientRegistrationData, reply *WorkItem) error {\n+\n+\tglobal_lock.Lock()\n+\tdefer global_lock.Unlock()\n+\n+\tvar workerS *workerState\n+\tworkerS, ok := workerStateMap[data.Worker]\n+\n+\tif ok != true {\n+\n+\t\t// For new clients, trigger an iperf server start immediately\n+\t\tworkerS = &workerState{sentServerItem: true, idle: true, IP: data.IP, worker: data.Worker}\n+\t\tworkerStateMap[data.Worker] = workerS\n+\t\treply.IsServerItem = true\n+\t\treply.ServerItem.ListenPort = \"5201\"\n+\t\treply.ServerItem.Timeout = 3600\n+\t\treturn nil\n+\n+\t} else {\n+\t\t// Worker defaults to idle unless the allocateWork routine below assigns an item\n+\t\tworkerS.idle = true\n+\t}\n+\n+\t// Give the worker a new work item or let it idle loop another 5 seconds\n+\tallocateWorkToClient(workerS, reply)\n+\treturn nil\n+}\n+\n+func writeOutputFile(filename, data string) {\n+\n+\tfd, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0666)\n+\tif err != nil {\n+\t\tfmt.Println(\"Failed to append to existing file\", filename, err)\n+\t\treturn\n+\t}\n+\tdefer fd.Close()\n+\n+\t_, err = fd.WriteString(data)\n+\tif err != nil {\n+\t\tfmt.Println(\"Failed to append to existing file\", filename, err)\n+\t}\n+}\n+\n+func registerDataPoint(label string, mss int, value string, index int) {\n+\n+\tsl, ok := dataPoints[label]\n+\tif ok != true {\n+\t\tdataPoints[label] = []Point{{mss: mss, bandwidth: value, index: index}}\n+\t\tdataPointKeys = append(dataPointKeys, label)\n+\t} else {\n+\t\tdataPoints[label] = append(sl, Point{mss: mss, bandwidth: value, index: index})\n+\t}\n+}\n+\n+func flushDataPointsToCsv() {\n+\n+\tvar buffer string\n+\n+\t// Write the MSS points for the X-axis before dumping all the testcase datapoints\n+\tfor _, points := range dataPoints {\n+\t\tif len(points) == 1 {\n+\t\t\tcontinue\n+\t\t}\n+\t\tbuffer = fmt.Sprintf(\"%-45s, Maximum,\", \"MSS\")\n+\t\tfor _, p := range points {\n+\t\t\tbuffer = buffer + fmt.Sprintf(\" %d,\", p.mss)\n+\t\t}\n+\t\tbreak\n+\t}\n+\tbuffer = buffer + \"\\n\"\n+\twriteOutputFile(CSVFILE, buffer)\n+\n+\tvar lines []string\n+\tfor _, label := range dataPointKeys {\n+\t\tbuffer = fmt.Sprintf(\"%-45s,\", label)\n+\t\tpoints := dataPoints[label]\n+\t\tvar max float64\n+\t\tfor _, p := range points {\n+\t\t\tfv, _ := strconv.ParseFloat(p.bandwidth, 64)\n+\t\t\tif fv > max {\n+\t\t\t\tmax = fv\n+\t\t\t}\n+\t\t}\n+\n+\t\tbuffer = buffer + fmt.Sprintf(\"%f,\", max)\n+\t\tfor _, p := range points {\n+\t\t\tbuffer = buffer + fmt.Sprintf(\"%s,\", p.bandwidth)\n+\t\t}\n+\t\tbuffer = buffer + \"\\n\"\n+\t\tlines = append(lines, buffer)\n+\t}\n+\n+\tfor _, l := range lines {\n+\t\twriteOutputFile(CSVFILE, l)\n+\t}\n+}\n+\n+func parseIperfTcpBandwidth(output string) string {\n+\t// Parses the output of iperf3 and grabs the group Mbits/sec from the output\n+\tmatch := iperf_tcp_output_regexp.FindStringSubmatch(output)\n+\tif match != nil && len(match) > 1 {\n+\t\treturn match[1]\n+\t}\n+\treturn \"0\"\n+}\n+\n+func parseIperfUdpBandwidth(output string) string {\n+\t// Parses the output of iperf3 (UDP mode) and grabs the Mbits/sec from the output\n+\tmatch := iperf_udp_output_regexp.FindStringSubmatch(output)\n+\tif match != nil && len(match) > 1 {\n+\t\treturn match[1]\n+\t}\n+\treturn \"0\"\n+}\n+\n+func parseNetperfBandwidth(output string) string {\n+\t// Parses the output of netperf and grabs the Bbits/sec from the output\n+\tmatch := netperf_output_regexp.FindStringSubmatch(output)\n+\tif match != nil && len(match) > 1 {\n+\t\treturn match[1]\n+\t}\n+\treturn \"0\"\n+}\n+\n+func (t *NetPerfRpc) ReceiveOutput(data *WorkerOutput, reply *int) error {\n+\tglobal_lock.Lock()\n+\tdefer global_lock.Unlock()\n+\n+\ttestcase := testcases[currentJobIndex]\n+\n+\tvar outputLog string\n+\tvar bw string\n+\n+\tswitch data.Type {\n+\tcase IPERF_TCP_TEST:\n+\t\tmss := testcases[currentJobIndex].MSS - MSS_STEP_SIZE\n+\t\toutputLog = outputLog + fmt.Sprintln(\"Received TCP output from worker\", data.Worker, \"for test\", testcase.Label,\n+\t\t\t\"from\", testcase.SourceNode, \"to\", testcase.DestinationNode, \"MSS:\", mss, \"\\n\") + data.Output\n+\t\tgo writeOutputFile(OUTPUT_CAPTURE_FILE, outputLog)\n+\t\tbw = parseIperfTcpBandwidth(data.Output)\n+\t\tregisterDataPoint(testcase.Label, mss, bw, currentJobIndex)\n+\n+\tcase IPERF_UDP_TEST:\n+\t\tmss := testcases[currentJobIndex].MSS - MSS_STEP_SIZE\n+\t\toutputLog = outputLog + fmt.Sprintln(\"Received UDP output from worker\", data.Worker, \"for test\", testcase.Label,\n+\t\t\t\"from\", testcase.SourceNode, \"to\", testcase.DestinationNode, \"MSS:\", mss, \"\\n\") + data.Output\n+\t\tgo writeOutputFile(OUTPUT_CAPTURE_FILE, outputLog)\n+\t\tbw = parseIperfUdpBandwidth(data.Output)\n+\t\tregisterDataPoint(testcase.Label, mss, bw, currentJobIndex)\n+\n+\tcase NETPERF_TEST:\n+\t\toutputLog = outputLog + fmt.Sprintln(\"Received netperf output from worker\", data.Worker, \"for test\", testcase.Label,\n+\t\t\t\"from\", testcase.SourceNode, \"to\", testcase.DestinationNode, \"\\n\") + data.Output\n+\t\tgo writeOutputFile(OUTPUT_CAPTURE_FILE, outputLog)\n+\t\tbw = parseNetperfBandwidth(data.Output)\n+\t\tregisterDataPoint(testcase.Label, 0, bw, currentJobIndex)\n+\t\ttestcases[currentJobIndex].Finished = true\n+\n+\t}\n+\tfmt.Println(\"Jobdone from worker\", data.Worker, \"Bandwidth was\", bw, \"Mbits/sec\")\n+\treturn nil\n+}\n+\n+func serveRpcRequests(port string) {\n+\tbaseObject := new(NetPerfRpc)\n+\trpc.Register(baseObject)\n+\trpc.HandleHTTP()\n+\tlistener, e := net.Listen(\"tcp\", \":\"+port)\n+\tif e != nil {\n+\t\tlog.Fatal(\"listen error:\", e)\n+\t}\n+\thttp.Serve(listener, nil)\n+}\n+\n+// Blocking RPC server start - only runs on the orchestrator\n+func orchestrate() {\n+\tserveRpcRequests(\"5202\")\n+}\n+\n+// Walk the list of interfaces and find the first interface that has a valid IP\n+// Inside a container, there should be only one IP-enabled interface\n+func getMyIP() string {\n+\tifaces, err := net.Interfaces()\n+\tif err != nil {\n+\t\treturn \"127.0.0.1\"\n+\t}\n+\n+\tfor _, iface := range ifaces {\n+\t\tif iface.Flags&net.FlagLoopback == 0 {\n+\t\t\taddrs, _ := iface.Addrs()\n+\t\t\tfor _, addr := range addrs {\n+\t\t\t\tvar ip net.IP\n+\t\t\t\tswitch v := addr.(type) {\n+\t\t\t\tcase *net.IPNet:\n+\t\t\t\t\tip = v.IP\n+\t\t\t\tcase *net.IPAddr:\n+\t\t\t\t\tip = v.IP\n+\t\t\t\t}\n+\t\t\t\treturn ip.String()\n+\t\t\t}\n+\t\t}\n+\t}\n+\treturn \"127.0.0.1\"\n+}\n+\n+func handle_client_work_item(client *rpc.Client, work_item *WorkItem) {\n+\tfmt.Println(\"Orchestrator requests worker run item Type:\", work_item.ClientItem.Type)\n+\tswitch {\n+\tcase work_item.ClientItem.Type == IPERF_TCP_TEST || work_item.ClientItem.Type == IPERF_UDP_TEST:\n+\t\toutputString := iperf_client(work_item.ClientItem.Host, work_item.ClientItem.Port, work_item.ClientItem.MSS, work_item.ClientItem.Type)\n+\t\tvar reply int\n+\t\tclient.Call(\"NetPerfRpc.ReceiveOutput\", WorkerOutput{Output: outputString, Worker: worker, Type: work_item.ClientItem.Type}, &reply)\n+\tcase work_item.ClientItem.Type == NETPERF_TEST:\n+\t\toutputString := netperf_client(work_item.ClientItem.Host, work_item.ClientItem.Port, work_item.ClientItem.Type)\n+\t\tvar reply int\n+\t\tclient.Call(\"NetPerfRpc.ReceiveOutput\", WorkerOutput{Output: outputString, Worker: worker, Type: work_item.ClientItem.Type}, &reply)\n+\t}\n+\t// Client COOLDOWN period before asking for next work item to replenish burst allowance policers etc\n+\ttime.Sleep(10 * time.Second)\n+}\n+\n+// start_work : Entry point to the worker infinite loop\n+func start_work() {\n+\n+\ttime.Sleep(5 * time.Second)\n+\tfor true {\n+\t\tvar timeout time.Duration\n+\t\tvar client *rpc.Client\n+\t\tvar err error\n+\n+\t\ttimeout = 5\n+\t\tfor true {\n+\t\t\tfmt.Println(\"Attempting to connect to orchestrator at\", host)\n+\t\t\tclient, err = rpc.DialHTTP(\"tcp\", host+\":\"+port)\n+\t\t\tif err == nil {\n+\t\t\t\tbreak\n+\t\t\t}\n+\t\t\tfmt.Println(\"RPC connection to \", host, \" failed:\", err)\n+\t\t\ttime.Sleep(timeout * time.Second)\n+\t\t}\n+\n+\t\tfor true {\n+\t\t\tclient_data := ClientRegistrationData{Host: podname, KubeNode: kubenode, Worker: worker, IP: getMyIP()}\n+\t\t\tvar work_item WorkItem\n+\n+\t\t\terr := client.Call(\"NetPerfRpc.RegisterClient\", client_data, &work_item)\n+\t\t\tif err == nil {\n+\t\t\t\tswitch {\n+\t\t\t\tcase work_item.IsIdle == true:\n+\t\t\t\t\ttime.Sleep(5 * time.Second)\n+\t\t\t\t\tcontinue\n+\n+\t\t\t\tcase work_item.IsServerItem == true:\n+\t\t\t\t\tfmt.Println(\"Orchestrator requests worker run iperf and netperf servers\")\n+\t\t\t\t\tgo iperf_server()\n+\t\t\t\t\tgo netperf_server()\n+\t\t\t\t\ttime.Sleep(1 * time.Second)\n+\n+\t\t\t\tcase work_item.IsClientItem == true:\n+\t\t\t\t\thandle_client_work_item(client, &work_item)\n+\t\t\t\t}\n+\n+\t\t\t} else {\n+\t\t\t\t// RPC server has probably gone away - attempt to reconnect\n+\t\t\t\tfmt.Println(\"Error attempting RPC call\", err)\n+\t\t\t\tbreak\n+\t\t\t}\n+\t\t}\n+\t}\n+}\n+\n+// Invoke and indefinitely run an iperf server\n+func iperf_server() {\n+\n+\toutput, success := CmdExec(IPERF3_PATH, []string{IPERF3_PATH, \"-s\", host, \"-J\", \"-i\", \"60\"}, 15)\n+\tif success {\n+\t\tfmt.Println(output)\n+\t}\n+}\n+\n+// Invoke and indefinitely run netperf server\n+func netperf_server() {\n+\n+\toutput, success := CmdExec(NETPERF_SERVER_PATH, []string{NETPERF_SERVER_PATH, \"-D\"}, 15)\n+\tif success {\n+\t\tfmt.Println(output)\n+\t}\n+}\n+\n+// Invoke and run an iperf client and return the output if successful.\n+func iperf_client(serverHost, serverPort string, mss int, workItemType int) (rv string) {\n+\n+\tswitch {\n+\tcase workItemType == IPERF_TCP_TEST:\n+\t\toutput, success := CmdExec(IPERF3_PATH, []string{IPERF3_PATH, \"-c\", serverHost, \"-N\", \"-i\", \"30\", \"-t\", \"10\", \"-f\", \"m\", \"-w\", \"512M\", \"-Z\", \"-P\", PARALLELSTREAMS, \"-M\", string(mss)}, 15)\n+\t\tif success {\n+\t\t\trv = output\n+\t\t}\n+\n+\tcase workItemType == IPERF_UDP_TEST:\n+\t\toutput, success := CmdExec(IPERF3_PATH, []string{IPERF3_PATH, \"-c\", serverHost, \"-i\", \"30\", \"-t\", \"10\", \"-f\", \"m\", \"-b\", \"0\", \"-u\"}, 15)\n+\t\tif success {\n+\t\t\trv = output\n+\t\t}\n+\t}\n+\treturn\n+}\n+\n+// Invoke and run a netperf client and return the output if successful.\n+func netperf_client(serverHost, serverPort string, workItemType int) (rv string) {\n+","path":"test/benchmarks/netperf/nptest.go","position":630,"original_position":630,"commit_id":"a6a088247ec4b1de776cf99271ac3b9760999a9b","original_commit_id":"a6a088247ec4b1de776cf99271ac3b9760999a9b","user":{"login":"gmarek","id":1703842,"avatar_url":"https://avatars.githubusercontent.com/u/1703842?v=3","gravatar_id":"","url":"https://api.github.com/users/gmarek","html_url":"https://github.com/gmarek","followers_url":"https://api.github.com/users/gmarek/followers","following_url":"https://api.github.com/users/gmarek/following{/other_user}","gists_url":"https://api.github.com/users/gmarek/gists{/gist_id}","starred_url":"https://api.github.com/users/gmarek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gmarek/subscriptions","organizations_url":"https://api.github.com/users/gmarek/orgs","repos_url":"https://api.github.com/users/gmarek/repos","events_url":"https://api.github.com/users/gmarek/events{/privacy}","received_events_url":"https://api.github.com/users/gmarek/received_events","type":"User","site_admin":false},"body":"remove empty line.","created_at":"2016-05-10T11:59:21Z","updated_at":"2016-05-10T11:59:21Z","html_url":"https://github.com/kubernetes/kubernetes/pull/25370#discussion_r62657991","pull_request_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/25370","_links":{"self":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/comments/62657991"},"html":{"href":"https://github.com/kubernetes/kubernetes/pull/25370#discussion_r62657991"},"pull_request":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/25370"}}},"pull_request":{"url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/25370","id":69411475,"html_url":"https://github.com/kubernetes/kubernetes/pull/25370","diff_url":"https://github.com/kubernetes/kubernetes/pull/25370.diff","patch_url":"https://github.com/kubernetes/kubernetes/pull/25370.patch","issue_url":"https://api.github.com/repos/kubernetes/kubernetes/issues/25370","number":25370,"state":"open","locked":false,"title":"Network Performance Benchmark Tests #25362","user":{"login":"girishkalele","id":18541549,"avatar_url":"https://avatars.githubusercontent.com/u/18541549?v=3","gravatar_id":"","url":"https://api.github.com/users/girishkalele","html_url":"https://github.com/girishkalele","followers_url":"https://api.github.com/users/girishkalele/followers","following_url":"https://api.github.com/users/girishkalele/following{/other_user}","gists_url":"https://api.github.com/users/girishkalele/gists{/gist_id}","starred_url":"https://api.github.com/users/girishkalele/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/girishkalele/subscriptions","organizations_url":"https://api.github.com/users/girishkalele/orgs","repos_url":"https://api.github.com/users/girishkalele/repos","events_url":"https://api.github.com/users/girishkalele/events{/privacy}","received_events_url":"https://api.github.com/users/girishkalele/received_events","type":"User","site_admin":false},"body":"\r\nThis commit represents the fire-and-forget Network Performance Test suite.\r\nSee README.md for a full description of the functionality and usage.\r\n\r\nhttps://github.com/girishkalele/kubernetes/blob/59fdf78ae653cdf27c4b53e059589361de95f97d/test/benchmarks/netperf/README.md\r\n\r\n[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/.github/PULL_REQUEST_TEMPLATE.md?pixel)]()\r\n","created_at":"2016-05-09T21:09:57Z","updated_at":"2016-05-10T11:59:21Z","closed_at":null,"merged_at":null,"merge_commit_sha":"7c65b433a94a3244b86a065a97a3ac367bb5bd34","assignee":{"login":"gmarek","id":1703842,"avatar_url":"https://avatars.githubusercontent.com/u/1703842?v=3","gravatar_id":"","url":"https://api.github.com/users/gmarek","html_url":"https://github.com/gmarek","followers_url":"https://api.github.com/users/gmarek/followers","following_url":"https://api.github.com/users/gmarek/following{/other_user}","gists_url":"https://api.github.com/users/gmarek/gists{/gist_id}","starred_url":"https://api.github.com/users/gmarek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gmarek/subscriptions","organizations_url":"https://api.github.com/users/gmarek/orgs","repos_url":"https://api.github.com/users/gmarek/repos","events_url":"https://api.github.com/users/gmarek/events{/privacy}","received_events_url":"https://api.github.com/users/gmarek/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/25370/commits","review_comments_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/25370/comments","review_comment_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/comments{/number}","comments_url":"https://api.github.com/repos/kubernetes/kubernetes/issues/25370/comments","statuses_url":"https://api.github.com/repos/kubernetes/kubernetes/statuses/a6a088247ec4b1de776cf99271ac3b9760999a9b","head":{"label":"girishkalele:np","ref":"np","sha":"a6a088247ec4b1de776cf99271ac3b9760999a9b","user":{"login":"girishkalele","id":18541549,"avatar_url":"https://avatars.githubusercontent.com/u/18541549?v=3","gravatar_id":"","url":"https://api.github.com/users/girishkalele","html_url":"https://github.com/girishkalele","followers_url":"https://api.github.com/users/girishkalele/followers","following_url":"https://api.github.com/users/girishkalele/following{/other_user}","gists_url":"https://api.github.com/users/girishkalele/gists{/gist_id}","starred_url":"https://api.github.com/users/girishkalele/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/girishkalele/subscriptions","organizations_url":"https://api.github.com/users/girishkalele/orgs","repos_url":"https://api.github.com/users/girishkalele/repos","events_url":"https://api.github.com/users/girishkalele/events{/privacy}","received_events_url":"https://api.github.com/users/girishkalele/received_events","type":"User","site_admin":false},"repo":{"id":58407800,"name":"kubernetes","full_name":"girishkalele/kubernetes","owner":{"login":"girishkalele","id":18541549,"avatar_url":"https://avatars.githubusercontent.com/u/18541549?v=3","gravatar_id":"","url":"https://api.github.com/users/girishkalele","html_url":"https://github.com/girishkalele","followers_url":"https://api.github.com/users/girishkalele/followers","following_url":"https://api.github.com/users/girishkalele/following{/other_user}","gists_url":"https://api.github.com/users/girishkalele/gists{/gist_id}","starred_url":"https://api.github.com/users/girishkalele/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/girishkalele/subscriptions","organizations_url":"https://api.github.com/users/girishkalele/orgs","repos_url":"https://api.github.com/users/girishkalele/repos","events_url":"https://api.github.com/users/girishkalele/events{/privacy}","received_events_url":"https://api.github.com/users/girishkalele/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/girishkalele/kubernetes","description":"Container Cluster Manager from Google","fork":true,"url":"https://api.github.com/repos/girishkalele/kubernetes","forks_url":"https://api.github.com/repos/girishkalele/kubernetes/forks","keys_url":"https://api.github.com/repos/girishkalele/kubernetes/keys{/key_id}","collaborators_url":"https://api.github.com/repos/girishkalele/kubernetes/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/girishkalele/kubernetes/teams","hooks_url":"https://api.github.com/repos/girishkalele/kubernetes/hooks","issue_events_url":"https://api.github.com/repos/girishkalele/kubernetes/issues/events{/number}","events_url":"https://api.github.com/repos/girishkalele/kubernetes/events","assignees_url":"https://api.github.com/repos/girishkalele/kubernetes/assignees{/user}","branches_url":"https://api.github.com/repos/girishkalele/kubernetes/branches{/branch}","tags_url":"https://api.github.com/repos/girishkalele/kubernetes/tags","blobs_url":"https://api.github.com/repos/girishkalele/kubernetes/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/girishkalele/kubernetes/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/girishkalele/kubernetes/git/refs{/sha}","trees_url":"https://api.github.com/repos/girishkalele/kubernetes/git/trees{/sha}","statuses_url":"https://api.github.com/repos/girishkalele/kubernetes/statuses/{sha}","languages_url":"https://api.github.com/repos/girishkalele/kubernetes/languages","stargazers_url":"https://api.github.com/repos/girishkalele/kubernetes/stargazers","contributors_url":"https://api.github.com/repos/girishkalele/kubernetes/contributors","subscribers_url":"https://api.github.com/repos/girishkalele/kubernetes/subscribers","subscription_url":"https://api.github.com/repos/girishkalele/kubernetes/subscription","commits_url":"https://api.github.com/repos/girishkalele/kubernetes/commits{/sha}","git_commits_url":"https://api.github.com/repos/girishkalele/kubernetes/git/commits{/sha}","comments_url":"https://api.github.com/repos/girishkalele/kubernetes/comments{/number}","issue_comment_url":"https://api.github.com/repos/girishkalele/kubernetes/issues/comments{/number}","contents_url":"https://api.github.com/repos/girishkalele/kubernetes/contents/{+path}","compare_url":"https://api.github.com/repos/girishkalele/kubernetes/compare/{base}...{head}","merges_url":"https://api.github.com/repos/girishkalele/kubernetes/merges","archive_url":"https://api.github.com/repos/girishkalele/kubernetes/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/girishkalele/kubernetes/downloads","issues_url":"https://api.github.com/repos/girishkalele/kubernetes/issues{/number}","pulls_url":"https://api.github.com/repos/girishkalele/kubernetes/pulls{/number}","milestones_url":"https://api.github.com/repos/girishkalele/kubernetes/milestones{/number}","notifications_url":"https://api.github.com/repos/girishkalele/kubernetes/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/girishkalele/kubernetes/labels{/name}","releases_url":"https://api.github.com/repos/girishkalele/kubernetes/releases{/id}","deployments_url":"https://api.github.com/repos/girishkalele/kubernetes/deployments","created_at":"2016-05-09T20:59:15Z","updated_at":"2016-05-09T20:59:30Z","pushed_at":"2016-05-10T00:23:27Z","git_url":"git://github.com/girishkalele/kubernetes.git","ssh_url":"git@github.com:girishkalele/kubernetes.git","clone_url":"https://github.com/girishkalele/kubernetes.git","svn_url":"https://github.com/girishkalele/kubernetes","homepage":"http://kubernetes.io","size":191803,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"kubernetes:master","ref":"master","sha":"ff339c77cfae61d664be3bcbe9a87a968696e545","user":{"login":"kubernetes","id":13629408,"avatar_url":"https://avatars.githubusercontent.com/u/13629408?v=3","gravatar_id":"","url":"https://api.github.com/users/kubernetes","html_url":"https://github.com/kubernetes","followers_url":"https://api.github.com/users/kubernetes/followers","following_url":"https://api.github.com/users/kubernetes/following{/other_user}","gists_url":"https://api.github.com/users/kubernetes/gists{/gist_id}","starred_url":"https://api.github.com/users/kubernetes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kubernetes/subscriptions","organizations_url":"https://api.github.com/users/kubernetes/orgs","repos_url":"https://api.github.com/users/kubernetes/repos","events_url":"https://api.github.com/users/kubernetes/events{/privacy}","received_events_url":"https://api.github.com/users/kubernetes/received_events","type":"Organization","site_admin":false},"repo":{"id":20580498,"name":"kubernetes","full_name":"kubernetes/kubernetes","owner":{"login":"kubernetes","id":13629408,"avatar_url":"https://avatars.githubusercontent.com/u/13629408?v=3","gravatar_id":"","url":"https://api.github.com/users/kubernetes","html_url":"https://github.com/kubernetes","followers_url":"https://api.github.com/users/kubernetes/followers","following_url":"https://api.github.com/users/kubernetes/following{/other_user}","gists_url":"https://api.github.com/users/kubernetes/gists{/gist_id}","starred_url":"https://api.github.com/users/kubernetes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kubernetes/subscriptions","organizations_url":"https://api.github.com/users/kubernetes/orgs","repos_url":"https://api.github.com/users/kubernetes/repos","events_url":"https://api.github.com/users/kubernetes/events{/privacy}","received_events_url":"https://api.github.com/users/kubernetes/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/kubernetes/kubernetes","description":"Container Cluster Manager from Google","fork":false,"url":"https://api.github.com/repos/kubernetes/kubernetes","forks_url":"https://api.github.com/repos/kubernetes/kubernetes/forks","keys_url":"https://api.github.com/repos/kubernetes/kubernetes/keys{/key_id}","collaborators_url":"https://api.github.com/repos/kubernetes/kubernetes/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/kubernetes/kubernetes/teams","hooks_url":"https://api.github.com/repos/kubernetes/kubernetes/hooks","issue_events_url":"https://api.github.com/repos/kubernetes/kubernetes/issues/events{/number}","events_url":"https://api.github.com/repos/kubernetes/kubernetes/events","assignees_url":"https://api.github.com/repos/kubernetes/kubernetes/assignees{/user}","branches_url":"https://api.github.com/repos/kubernetes/kubernetes/branches{/branch}","tags_url":"https://api.github.com/repos/kubernetes/kubernetes/tags","blobs_url":"https://api.github.com/repos/kubernetes/kubernetes/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/kubernetes/kubernetes/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/kubernetes/kubernetes/git/refs{/sha}","trees_url":"https://api.github.com/repos/kubernetes/kubernetes/git/trees{/sha}","statuses_url":"https://api.github.com/repos/kubernetes/kubernetes/statuses/{sha}","languages_url":"https://api.github.com/repos/kubernetes/kubernetes/languages","stargazers_url":"https://api.github.com/repos/kubernetes/kubernetes/stargazers","contributors_url":"https://api.github.com/repos/kubernetes/kubernetes/contributors","subscribers_url":"https://api.github.com/repos/kubernetes/kubernetes/subscribers","subscription_url":"https://api.github.com/repos/kubernetes/kubernetes/subscription","commits_url":"https://api.github.com/repos/kubernetes/kubernetes/commits{/sha}","git_commits_url":"https://api.github.com/repos/kubernetes/kubernetes/git/commits{/sha}","comments_url":"https://api.github.com/repos/kubernetes/kubernetes/comments{/number}","issue_comment_url":"https://api.github.com/repos/kubernetes/kubernetes/issues/comments{/number}","contents_url":"https://api.github.com/repos/kubernetes/kubernetes/contents/{+path}","compare_url":"https://api.github.com/repos/kubernetes/kubernetes/compare/{base}...{head}","merges_url":"https://api.github.com/repos/kubernetes/kubernetes/merges","archive_url":"https://api.github.com/repos/kubernetes/kubernetes/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/kubernetes/kubernetes/downloads","issues_url":"https://api.github.com/repos/kubernetes/kubernetes/issues{/number}","pulls_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls{/number}","milestones_url":"https://api.github.com/repos/kubernetes/kubernetes/milestones{/number}","notifications_url":"https://api.github.com/repos/kubernetes/kubernetes/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/kubernetes/kubernetes/labels{/name}","releases_url":"https://api.github.com/repos/kubernetes/kubernetes/releases{/id}","deployments_url":"https://api.github.com/repos/kubernetes/kubernetes/deployments","created_at":"2014-06-06T22:56:04Z","updated_at":"2016-05-10T10:52:17Z","pushed_at":"2016-05-10T11:55:13Z","git_url":"git://github.com/kubernetes/kubernetes.git","ssh_url":"git@github.com:kubernetes/kubernetes.git","clone_url":"https://github.com/kubernetes/kubernetes.git","svn_url":"https://github.com/kubernetes/kubernetes","homepage":"http://kubernetes.io","size":391765,"stargazers_count":14290,"watchers_count":14290,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":4287,"mirror_url":null,"open_issues_count":3568,"forks":4287,"open_issues":3568,"watchers":14290,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/25370"},"html":{"href":"https://github.com/kubernetes/kubernetes/pull/25370"},"issue":{"href":"https://api.github.com/repos/kubernetes/kubernetes/issues/25370"},"comments":{"href":"https://api.github.com/repos/kubernetes/kubernetes/issues/25370/comments"},"review_comments":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/25370/comments"},"review_comment":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/25370/commits"},"statuses":{"href":"https://api.github.com/repos/kubernetes/kubernetes/statuses/a6a088247ec4b1de776cf99271ac3b9760999a9b"}}}}