2018-12-03 04:39:13 +08:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Copyright (C) Microsoft. All rights reserved.
|
|
|
|
// Licensed under the MIT license.
|
|
|
|
// See LICENSE.txt file in the project root for full license information.
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
|
|
|
"runtime"
|
|
|
|
"strings"
|
|
|
|
"time"
|
2019-07-19 02:30:13 +08:00
|
|
|
|
|
|
|
"github.com/microsoft/ethr/internal/cmd"
|
2019-10-08 05:24:01 +08:00
|
|
|
"github.com/microsoft/ethr/internal/ethrLog"
|
2018-12-03 04:39:13 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
const defaultLogFileName = "./ethrs.log for server, ./ethrc.log for client"
|
2019-02-03 23:53:54 +08:00
|
|
|
|
2019-10-08 05:24:01 +08:00
|
|
|
var (
|
|
|
|
gVersion string
|
|
|
|
loggingLevel ethrLog.LogLevel = ethrLog.LogLevelInfo
|
|
|
|
)
|
2018-12-03 04:39:13 +08:00
|
|
|
|
|
|
|
func main() {
|
2019-02-03 23:53:54 +08:00
|
|
|
//
|
|
|
|
// If version is not set via ldflags, then default to UNKNOWN
|
|
|
|
//
|
|
|
|
if gVersion == "" {
|
|
|
|
gVersion = "[VERSION: UNKNOWN]"
|
|
|
|
}
|
2019-01-21 01:13:47 +08:00
|
|
|
//
|
|
|
|
// Set GOMAXPROCS to 1024 as running large number of goroutines in a loop
|
|
|
|
// to send network traffic results in timer starvation, as well as unfair
|
|
|
|
// processing time across goroutines resulting in starvation of many TCP
|
|
|
|
// connections. Using a higher number of threads via GOMAXPROCS solves this
|
|
|
|
// problem.
|
|
|
|
//
|
|
|
|
runtime.GOMAXPROCS(1024)
|
|
|
|
|
2019-07-19 02:30:13 +08:00
|
|
|
flag.Usage = func() { cmd.EthrUsage(gVersion) }
|
2019-01-17 00:12:58 +08:00
|
|
|
isServer := flag.Bool("s", false, "")
|
|
|
|
clientDest := flag.String("c", "", "")
|
|
|
|
testTypePtr := flag.String("t", "", "")
|
|
|
|
thCount := flag.Int("n", 1, "")
|
|
|
|
bufLenStr := flag.String("l", "16KB", "")
|
|
|
|
protocol := flag.String("p", "tcp", "")
|
|
|
|
outputFile := flag.String("o", defaultLogFileName, "")
|
|
|
|
debug := flag.Bool("debug", false, "")
|
|
|
|
noOutput := flag.Bool("no", false, "")
|
|
|
|
duration := flag.Duration("d", 10*time.Second, "")
|
|
|
|
showUI := flag.Bool("ui", false, "")
|
|
|
|
rttCount := flag.Int("i", 1000, "")
|
|
|
|
portStr := flag.String("ports", "", "")
|
|
|
|
modeStr := flag.String("m", "", "")
|
|
|
|
use4 := flag.Bool("4", false, "")
|
|
|
|
use6 := flag.Bool("6", false, "")
|
|
|
|
gap := flag.Duration("g", 0, "")
|
2019-01-21 01:13:47 +08:00
|
|
|
reverse := flag.Bool("r", false, "")
|
|
|
|
ncs := flag.Bool("ncs", false, "")
|
2019-02-03 23:53:54 +08:00
|
|
|
ic := flag.Bool("ic", false, "")
|
2018-12-03 04:39:13 +08:00
|
|
|
|
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
//
|
|
|
|
// TODO: Handle the case if there are incorrect arguments
|
|
|
|
// fmt.Println("Number of incorrect arguments: " + strconv.Itoa(flag.NArg()))
|
|
|
|
//
|
|
|
|
|
2019-01-21 01:13:47 +08:00
|
|
|
//
|
|
|
|
// Only used in client mode, to control whether to display per connection
|
|
|
|
// statistics or not.
|
|
|
|
//
|
2019-02-03 23:53:54 +08:00
|
|
|
gNoConnectionStats = *ncs
|
|
|
|
|
|
|
|
//
|
|
|
|
// Only used in client mode to ignore HTTPS cert errors.
|
|
|
|
//
|
|
|
|
gIgnoreCert = *ic
|
2019-01-21 01:13:47 +08:00
|
|
|
|
2019-10-08 05:24:01 +08:00
|
|
|
if *debug {
|
|
|
|
loggingLevel = ethrLog.LogLevelDebug
|
|
|
|
}
|
|
|
|
|
2019-01-15 05:56:36 +08:00
|
|
|
xMode := false
|
|
|
|
switch *modeStr {
|
|
|
|
case "":
|
|
|
|
case "x":
|
|
|
|
xMode = true
|
|
|
|
default:
|
2019-07-19 02:30:13 +08:00
|
|
|
cmd.PrintUsageError("Invalid value for execution mode (-m).")
|
2019-01-15 05:56:36 +08:00
|
|
|
}
|
2019-01-02 13:12:26 +08:00
|
|
|
mode := ethrModeInv
|
2019-01-15 05:56:36 +08:00
|
|
|
|
2019-01-02 13:12:26 +08:00
|
|
|
if *isServer {
|
2019-01-15 05:56:36 +08:00
|
|
|
if *clientDest != "" {
|
2019-07-19 02:30:13 +08:00
|
|
|
cmd.PrintUsageError("Invalid arguments, \"-c\" cannot be used with \"-s\".")
|
2019-01-15 05:56:36 +08:00
|
|
|
}
|
|
|
|
if xMode {
|
|
|
|
mode = ethrModeExtServer
|
|
|
|
} else {
|
|
|
|
mode = ethrModeServer
|
2019-01-02 13:12:26 +08:00
|
|
|
}
|
|
|
|
} else if *clientDest != "" {
|
2019-01-15 05:56:36 +08:00
|
|
|
if xMode {
|
|
|
|
mode = ethrModeExtClient
|
|
|
|
} else {
|
|
|
|
mode = ethrModeClient
|
2019-01-02 13:12:26 +08:00
|
|
|
}
|
|
|
|
} else {
|
2019-07-19 02:30:13 +08:00
|
|
|
cmd.PrintUsageError("Invalid arguments, use either \"-s\" or \"-c\".")
|
2018-12-03 04:39:13 +08:00
|
|
|
}
|
|
|
|
|
2019-01-21 01:13:47 +08:00
|
|
|
if *reverse && mode != ethrModeClient {
|
2019-07-19 02:30:13 +08:00
|
|
|
cmd.PrintUsageError("Invalid arguments, \"-r\" can only be used in client mode.")
|
2019-01-21 01:13:47 +08:00
|
|
|
}
|
|
|
|
|
2019-01-04 09:25:00 +08:00
|
|
|
if *use4 && !*use6 {
|
|
|
|
ipVer = ethrIPv4
|
|
|
|
} else if *use6 && !*use4 {
|
|
|
|
ipVer = ethrIPv6
|
|
|
|
}
|
|
|
|
|
2018-12-03 04:39:13 +08:00
|
|
|
bufLen := unitToNumber(*bufLenStr)
|
|
|
|
if bufLen == 0 {
|
2019-07-19 02:30:13 +08:00
|
|
|
cmd.PrintUsageError(fmt.Sprintf("Invalid length specified: %s" + *bufLenStr))
|
2018-12-03 04:39:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if *rttCount <= 0 {
|
2019-07-19 02:30:13 +08:00
|
|
|
cmd.PrintUsageError(fmt.Sprintf("Invalid RTT count for latency test: %d", *rttCount))
|
2018-12-03 04:39:13 +08:00
|
|
|
}
|
|
|
|
|
2018-12-12 00:35:20 +08:00
|
|
|
var testType EthrTestType
|
|
|
|
switch *testTypePtr {
|
2019-01-02 13:12:26 +08:00
|
|
|
case "":
|
|
|
|
switch mode {
|
|
|
|
case ethrModeServer:
|
|
|
|
testType = All
|
2019-01-15 05:56:36 +08:00
|
|
|
case ethrModeExtServer:
|
|
|
|
testType = All
|
2019-01-02 13:12:26 +08:00
|
|
|
case ethrModeClient:
|
|
|
|
testType = Bandwidth
|
|
|
|
case ethrModeExtClient:
|
2019-02-03 23:53:54 +08:00
|
|
|
testType = ConnLatency
|
2019-01-02 13:12:26 +08:00
|
|
|
}
|
2018-12-03 04:39:13 +08:00
|
|
|
case "b":
|
2018-12-12 00:35:20 +08:00
|
|
|
testType = Bandwidth
|
2018-12-03 04:39:13 +08:00
|
|
|
case "c":
|
2018-12-12 00:35:20 +08:00
|
|
|
testType = Cps
|
2018-12-03 04:39:13 +08:00
|
|
|
case "p":
|
2018-12-12 00:35:20 +08:00
|
|
|
testType = Pps
|
2018-12-03 04:39:13 +08:00
|
|
|
case "l":
|
2018-12-12 00:35:20 +08:00
|
|
|
testType = Latency
|
2019-01-15 05:56:36 +08:00
|
|
|
case "cl":
|
|
|
|
testType = ConnLatency
|
2018-12-03 04:39:13 +08:00
|
|
|
default:
|
2019-07-19 02:30:13 +08:00
|
|
|
cmd.PrintUsageError(fmt.Sprintf("Invalid value \"%s\" specified for parameter \"-t\".\n"+
|
2019-01-15 05:56:36 +08:00
|
|
|
"Valid parameters and values are:\n", *testTypePtr))
|
2018-12-03 04:39:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
p := strings.ToUpper(*protocol)
|
2018-12-11 23:28:33 +08:00
|
|
|
proto := TCP
|
2018-12-03 04:39:13 +08:00
|
|
|
switch p {
|
|
|
|
case "TCP":
|
2018-12-11 23:28:33 +08:00
|
|
|
proto = TCP
|
2018-12-03 04:39:13 +08:00
|
|
|
case "UDP":
|
2018-12-11 23:28:33 +08:00
|
|
|
proto = UDP
|
2018-12-03 04:39:13 +08:00
|
|
|
case "HTTP":
|
2018-12-11 23:28:33 +08:00
|
|
|
proto = HTTP
|
2018-12-03 04:39:13 +08:00
|
|
|
case "HTTPS":
|
2018-12-11 23:28:33 +08:00
|
|
|
proto = HTTPS
|
2018-12-03 04:39:13 +08:00
|
|
|
case "ICMP":
|
2018-12-11 23:28:33 +08:00
|
|
|
proto = ICMP
|
2018-12-03 04:39:13 +08:00
|
|
|
default:
|
2019-07-19 02:30:13 +08:00
|
|
|
cmd.PrintUsageError(fmt.Sprintf("Invalid value \"%s\" specified for parameter \"-p\".\n"+
|
2019-01-15 05:56:36 +08:00
|
|
|
"Valid parameters and values are:\n", *protocol))
|
2018-12-03 04:39:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if *thCount <= 0 {
|
|
|
|
*thCount = runtime.NumCPU()
|
|
|
|
}
|
|
|
|
|
2018-12-12 00:35:20 +08:00
|
|
|
//
|
|
|
|
// For Pkt/s, we always override the buffer size to be just 1 byte.
|
|
|
|
// TODO: Evaluate in future, if we need to support > 1 byte packets for
|
|
|
|
// Pkt/s testing.
|
|
|
|
//
|
|
|
|
if testType == Pps {
|
2018-12-03 04:39:13 +08:00
|
|
|
bufLen = 1
|
|
|
|
}
|
|
|
|
|
2018-12-12 00:35:20 +08:00
|
|
|
testParam := EthrTestParam{EthrTestID{EthrProtocol(proto), testType},
|
2018-12-03 04:39:13 +08:00
|
|
|
uint32(*thCount),
|
|
|
|
uint32(bufLen),
|
2019-01-21 01:13:47 +08:00
|
|
|
uint32(*rttCount),
|
|
|
|
*reverse}
|
|
|
|
validateTestParam(mode, testParam)
|
2018-12-03 04:39:13 +08:00
|
|
|
|
2019-01-02 13:12:26 +08:00
|
|
|
generatePortNumbers(*portStr)
|
2018-12-18 00:52:58 +08:00
|
|
|
|
2018-12-03 04:39:13 +08:00
|
|
|
logFileName := *outputFile
|
2019-01-02 13:12:26 +08:00
|
|
|
if !*noOutput {
|
|
|
|
if logFileName == defaultLogFileName {
|
|
|
|
switch mode {
|
|
|
|
case ethrModeServer:
|
2018-12-03 04:39:13 +08:00
|
|
|
logFileName = "ethrs.log"
|
2019-01-15 05:56:36 +08:00
|
|
|
case ethrModeExtServer:
|
|
|
|
logFileName = "ethrxs.log"
|
2019-01-02 13:12:26 +08:00
|
|
|
case ethrModeClient:
|
2018-12-03 04:39:13 +08:00
|
|
|
logFileName = "ethrc.log"
|
2019-01-02 13:12:26 +08:00
|
|
|
case ethrModeExtClient:
|
|
|
|
logFileName = "ethrxc.log"
|
2018-12-03 04:39:13 +08:00
|
|
|
}
|
|
|
|
}
|
2019-10-08 05:24:01 +08:00
|
|
|
ethrLog.LogInit(logFileName)
|
2019-01-02 13:12:26 +08:00
|
|
|
}
|
|
|
|
|
2019-01-17 00:12:58 +08:00
|
|
|
clientParam := ethrClientParam{*duration, *gap}
|
2019-01-04 09:25:00 +08:00
|
|
|
serverParam := ethrServerParam{*showUI}
|
|
|
|
|
2019-01-02 13:12:26 +08:00
|
|
|
switch mode {
|
|
|
|
case ethrModeServer:
|
2019-01-04 09:25:00 +08:00
|
|
|
runServer(testParam, serverParam)
|
2019-01-15 05:56:36 +08:00
|
|
|
case ethrModeExtServer:
|
|
|
|
runXServer(testParam, serverParam)
|
2019-01-02 13:12:26 +08:00
|
|
|
case ethrModeClient:
|
2019-01-04 09:25:00 +08:00
|
|
|
runClient(testParam, clientParam, *clientDest)
|
2019-01-02 13:12:26 +08:00
|
|
|
case ethrModeExtClient:
|
2019-01-15 05:56:36 +08:00
|
|
|
runXClient(testParam, clientParam, *clientDest)
|
2018-12-03 04:39:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-12 00:35:20 +08:00
|
|
|
func emitUnsupportedTest(testParam EthrTestParam) {
|
2019-07-19 02:30:13 +08:00
|
|
|
cmd.PrintUsageError(fmt.Sprintf("\"%s\" test for \"%s\" is not supported.\n",
|
2019-01-21 01:13:47 +08:00
|
|
|
testToString(testParam.TestID.Type), protoToString(testParam.TestID.Protocol)))
|
2018-12-03 04:39:13 +08:00
|
|
|
}
|
|
|
|
|
2019-02-03 23:53:54 +08:00
|
|
|
func printReverseModeError() {
|
2019-07-19 02:30:13 +08:00
|
|
|
cmd.PrintUsageError("Reverse mode (-r) is only supported for TCP Bandwidth tests.")
|
2019-02-03 23:53:54 +08:00
|
|
|
}
|
|
|
|
|
2019-01-21 01:13:47 +08:00
|
|
|
func validateTestParam(mode ethrMode, testParam EthrTestParam) {
|
2018-12-12 00:35:20 +08:00
|
|
|
testType := testParam.TestID.Type
|
|
|
|
protocol := testParam.TestID.Protocol
|
2019-01-02 13:12:26 +08:00
|
|
|
if mode == ethrModeServer {
|
|
|
|
if testType != All || protocol != TCP {
|
2018-12-12 00:35:20 +08:00
|
|
|
emitUnsupportedTest(testParam)
|
2018-12-03 04:39:13 +08:00
|
|
|
}
|
2019-01-02 13:12:26 +08:00
|
|
|
} else if mode == ethrModeClient {
|
|
|
|
switch protocol {
|
|
|
|
case TCP:
|
|
|
|
if testType != Bandwidth && testType != Cps && testType != Latency {
|
|
|
|
emitUnsupportedTest(testParam)
|
|
|
|
}
|
2019-02-03 23:53:54 +08:00
|
|
|
if testParam.Reverse && testType != Bandwidth {
|
|
|
|
printReverseModeError()
|
|
|
|
}
|
2019-01-02 13:12:26 +08:00
|
|
|
case UDP:
|
|
|
|
if testType != Bandwidth && testType != Pps {
|
|
|
|
emitUnsupportedTest(testParam)
|
2018-12-12 00:35:20 +08:00
|
|
|
}
|
2019-01-02 13:12:26 +08:00
|
|
|
if testType == Bandwidth {
|
|
|
|
if testParam.BufferSize > (64 * 1024) {
|
2019-07-19 02:30:13 +08:00
|
|
|
cmd.PrintUsageError("Maximum supported buffer size for UDP is 64K\n")
|
2019-01-02 13:12:26 +08:00
|
|
|
}
|
|
|
|
}
|
2019-02-03 23:53:54 +08:00
|
|
|
if testParam.Reverse {
|
|
|
|
printReverseModeError()
|
|
|
|
}
|
2019-01-02 13:12:26 +08:00
|
|
|
case HTTP:
|
2019-02-05 01:39:02 +08:00
|
|
|
if testType != Bandwidth && testType != Latency {
|
2019-01-02 13:12:26 +08:00
|
|
|
emitUnsupportedTest(testParam)
|
|
|
|
}
|
2019-02-03 23:53:54 +08:00
|
|
|
if testParam.Reverse {
|
|
|
|
printReverseModeError()
|
|
|
|
}
|
2019-01-08 01:15:09 +08:00
|
|
|
case HTTPS:
|
|
|
|
if testType != Bandwidth {
|
|
|
|
emitUnsupportedTest(testParam)
|
|
|
|
}
|
2019-02-03 23:53:54 +08:00
|
|
|
if testParam.Reverse {
|
|
|
|
printReverseModeError()
|
|
|
|
}
|
2019-01-02 13:12:26 +08:00
|
|
|
default:
|
|
|
|
emitUnsupportedTest(testParam)
|
2018-12-12 00:35:20 +08:00
|
|
|
}
|
2019-01-02 13:12:26 +08:00
|
|
|
} else if mode == ethrModeExtClient {
|
2019-01-15 05:56:36 +08:00
|
|
|
if (protocol != TCP) || (testType != ConnLatency && testType != Bandwidth) {
|
2018-12-12 00:35:20 +08:00
|
|
|
emitUnsupportedTest(testParam)
|
2018-12-03 04:39:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|