Skip to content

Commit d9408a0

Browse files
constant bit rate tester (#191)
* constant bit rate tester * instantaneous bandwidth reported * fix calculation of number of packets per second (client) * pattern into packets. Write a fixed string into the payload of the packets for easy identification. * default value for bw Co-authored-by: Jonas Gessner <[email protected]> * Add timeout option to cbrtester, print out packet throughput and gap * Add burster * Add burster to Makefile * Typo * gofmt * typo * Print out full address in cbrtester and burster * minor fixes from review * alphabetically sorted in Makefile * brief description about burster and cbrtester in main README Co-authored-by: Jonas Gessner <[email protected]>
1 parent a29edc0 commit d9408a0

File tree

6 files changed

+345
-0
lines changed

6 files changed

+345
-0
lines changed

Makefile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ all: lint build
1616

1717
build: scion-bat \
1818
scion-bwtestclient scion-bwtestserver \
19+
scion-burster \
20+
scion-cbrtester \
1921
scion-imagefetcher scion-imageserver \
2022
scion-netcat \
2123
scion-sensorfetcher scion-sensorserver \
@@ -61,6 +63,14 @@ scion-bwtestclient:
6163
scion-bwtestserver:
6264
go build -tags=$(TAGS) -o $(BIN)/$@ ./bwtester/bwtestserver/
6365

66+
.PHONY: scion-burster
67+
scion-burster:
68+
go build -tags=$(TAGS) -o $(BIN)/$@ ./burster/
69+
70+
.PHONY: scion-cbrtester
71+
scion-cbrtester:
72+
go build -tags=$(TAGS) -o $(BIN)/$@ ./cbrtester/
73+
6474
.PHONY: scion-imagefetcher
6575
scion-imagefetcher:
6676
go build -tags=$(TAGS) -o $(BIN)/$@ ./camerapp/imagefetcher/

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,13 @@ The bandwidth testing application bwtester enables a variety of bandwidth tests
115115
Installation and usage information is available on the [SCION Tutorials web page for bwtester](https://docs.scionlab.org/content/apps/bwtester.html).
116116

117117

118+
## burster
119+
120+
A tool that helps identifying problems with border routers dropping packets. It can also be used to add load to border routers. [README](burster/README.md).
121+
122+
## cbrtester
123+
124+
A tool intended to detect conditions on border routers, where packets are delayed more than the ordinary. [README](cbrtester/README.md).
118125
## camerapp
119126

120127
Camerapp contains image fetcher and server applications, using the SCION network. Documentation of the code is available in the [camerapp README](camerapp/README.md).

burster/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Burster
2+
3+
Sends and receives gapless bursts of packets in 5s intervals.
4+
5+
The client chooses the packet size, the burst size and the path, and the server
6+
prints out the number of received packets per burst. If any loss occurred then the number of received packets will be lower than the burst size set on the client.

burster/burster.go

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
// Copyright 2020 ETH Zurich
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+
// burster application
16+
// For more documentation on the application see:
17+
// https://github.com/netsec-ethz/scion-apps/blob/master/README.md
18+
// https://github.com/netsec-ethz/scion-apps/blob/master/bwtester/README.md
19+
20+
package main
21+
22+
import (
23+
"flag"
24+
"fmt"
25+
"os"
26+
"time"
27+
28+
"github.com/scionproto/scion/go/lib/serrors"
29+
"github.com/scionproto/scion/go/lib/snet"
30+
31+
"github.com/netsec-ethz/scion-apps/pkg/appnet"
32+
)
33+
34+
func main() {
35+
port := flag.Uint("port", 0, "[Server] Local port to listen on")
36+
size := flag.Uint("size", 300, "[Client] Burst size")
37+
payload := flag.Uint("payload", 100, "[Client] Size of each packet in bytes")
38+
interactive := flag.Bool("interactive", false, "[Client] Select the path interactively")
39+
40+
remoteAddr := flag.String("remote", "", "[Client] Remote (i.e. the server's) SCION Address (e.g. 17-ffaa:1:1,[127.0.0.1]:12345)")
41+
flag.Parse()
42+
43+
if (*port > 0) == (len(*remoteAddr) > 0) {
44+
fmt.Println("Either specify -port for server or -remote for client")
45+
os.Exit(1)
46+
}
47+
48+
var err error
49+
if *port > 0 {
50+
err = runServer(int(*port))
51+
} else {
52+
err = runClient(*remoteAddr, int(*size), int(*payload), *interactive)
53+
}
54+
if err != nil {
55+
fmt.Println("err", err)
56+
os.Exit(1)
57+
}
58+
}
59+
60+
func runClient(address string, burstSize int, payloadSize int, interactive bool) error {
61+
addr, err := appnet.ResolveUDPAddr(address)
62+
if err != nil {
63+
return err
64+
}
65+
var path snet.Path
66+
if interactive {
67+
path, err = appnet.ChoosePathInteractive(addr.IA)
68+
if err != nil {
69+
return err
70+
}
71+
appnet.SetPath(addr, path)
72+
} else {
73+
paths, err := appnet.QueryPaths(addr.IA)
74+
if err != nil {
75+
return err
76+
}
77+
path = paths[0]
78+
}
79+
80+
conn, err := appnet.DialAddr(addr)
81+
if err != nil {
82+
return err
83+
}
84+
defer conn.Close()
85+
86+
fmt.Printf("Running client using payload size %v and burst size %v via %v\n", payloadSize, burstSize, path)
87+
88+
if err != nil {
89+
return err
90+
}
91+
92+
buffer := make([]byte, payloadSize)
93+
94+
for {
95+
fmt.Println("Sending burst")
96+
buffer[0] = 1
97+
98+
for i := 0; i < burstSize; i++ {
99+
_, err := conn.Write(buffer)
100+
101+
if err != nil {
102+
fmt.Println(err)
103+
}
104+
}
105+
106+
fmt.Println("Sleeping...")
107+
108+
// Send reset message twice
109+
time.Sleep(500 * time.Millisecond)
110+
111+
buffer[0] = 2
112+
_, err := conn.Write(buffer)
113+
if err != nil {
114+
fmt.Println(err)
115+
}
116+
117+
time.Sleep(4 * time.Second)
118+
119+
buffer[0] = 2
120+
_, errr := conn.Write(buffer)
121+
if errr != nil {
122+
fmt.Println(errr)
123+
}
124+
125+
time.Sleep(500 * time.Millisecond)
126+
}
127+
}
128+
129+
func runServer(port int) error {
130+
listener, err := appnet.ListenPort(uint16(port))
131+
if err != nil {
132+
return serrors.WrapStr("can't listen:", err)
133+
}
134+
defer listener.Close()
135+
fmt.Printf("%v,%v\n", appnet.DefNetwork().IA, listener.LocalAddr())
136+
137+
buffer := make([]byte, 16*1024)
138+
receivedCount := 0
139+
reset := true
140+
for {
141+
count, _, err := listener.ReadFrom(buffer)
142+
if err != nil {
143+
fmt.Println(err)
144+
continue
145+
}
146+
147+
if !reset && count > 0 && buffer[0] == 2 {
148+
fmt.Printf("Received %v packets in burst\n", receivedCount)
149+
receivedCount = 0
150+
reset = true
151+
} else if count > 0 && buffer[0] != 2 {
152+
receivedCount += 1
153+
reset = false
154+
}
155+
}
156+
}

cbrtester/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Constant Bit Rate Tester
2+
3+
Sends at a constant rate using the specified path.
4+
5+
The client chooses the packet size, the rate and the path, and the server
6+
prints out the receive rate and stalls (freezes) if any are detected.

cbrtester/cbrtester.go

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
// Copyright 2020 ETH Zurich
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+
// cbrtester application
16+
// For more documentation on the application see:
17+
// https://github.com/netsec-ethz/scion-apps/blob/master/README.md
18+
// https://github.com/netsec-ethz/scion-apps/blob/master/bwtester/README.md
19+
20+
package main
21+
22+
import (
23+
"flag"
24+
"fmt"
25+
"os"
26+
"time"
27+
28+
"github.com/scionproto/scion/go/lib/serrors"
29+
"github.com/scionproto/scion/go/lib/snet"
30+
31+
"github.com/netsec-ethz/scion-apps/pkg/appnet"
32+
)
33+
34+
func main() {
35+
port := flag.Uint("port", 0, "[Server] Local port to listen on")
36+
timeout := flag.Uint("timeout", 100, "[Server] Size of gap between subsequent packets that is considered a freeze (in ms)")
37+
38+
bw := flag.Uint("bw", 1024*1024, "[Client] Rate to send at (in bps)")
39+
payload := flag.Uint("payload", 100, "[Client] Size of each packet in bytes")
40+
interactive := flag.Bool("interactive", false, "[Client] Select the path interactively")
41+
remoteAddr := flag.String("remote", "", "[Client] Remote (i.e. the server's) SCION Address (e.g. 17-ffaa:1:1,[127.0.0.1]:12345)")
42+
43+
flag.Parse()
44+
45+
if (*port > 0) == (len(*remoteAddr) > 0) {
46+
fmt.Println("Either specify -port for server or -remote for client")
47+
os.Exit(1)
48+
}
49+
50+
var err error
51+
if *port > 0 {
52+
err = runServer(int(*port), int64(*timeout))
53+
} else {
54+
err = runClient(*remoteAddr, int(*bw), int(*payload), *interactive)
55+
}
56+
if err != nil {
57+
fmt.Println("err", err)
58+
os.Exit(1)
59+
}
60+
}
61+
62+
func runClient(address string, desiredThroughput int, payloadSize int, interactive bool) error {
63+
addr, err := appnet.ResolveUDPAddr(address)
64+
if err != nil {
65+
return err
66+
}
67+
var path snet.Path
68+
if interactive {
69+
path, err = appnet.ChoosePathInteractive(addr.IA)
70+
if err != nil {
71+
return err
72+
}
73+
appnet.SetPath(addr, path)
74+
} else {
75+
paths, err := appnet.QueryPaths(addr.IA)
76+
if err != nil {
77+
return err
78+
}
79+
path = paths[0]
80+
}
81+
82+
conn, err := appnet.DialAddr(addr)
83+
if err != nil {
84+
return err
85+
}
86+
defer conn.Close()
87+
fmt.Printf("Running client using payload size %v and rate %v via %v\n", payloadSize, desiredThroughput, path)
88+
89+
numberOfPacketsPerSecond := float64(desiredThroughput) / 8. / float64(payloadSize)
90+
interval := time.Duration(float64(time.Second) / numberOfPacketsPerSecond)
91+
92+
fmt.Printf("Sending %v packets per second with a gap of %v\n", numberOfPacketsPerSecond, interval)
93+
94+
buffer := make([]byte, payloadSize)
95+
copy(buffer, []byte("cbrtester")) // allow easy identification of packets
96+
97+
for {
98+
before := time.Now()
99+
_, err = conn.Write(buffer)
100+
if err != nil {
101+
fmt.Println("error writing", err)
102+
}
103+
took := time.Since(before)
104+
105+
sleepAmount := interval - took
106+
107+
if sleepAmount > 0 {
108+
time.Sleep(sleepAmount)
109+
}
110+
}
111+
}
112+
113+
func runServer(port int, timeout int64) error {
114+
listener, err := appnet.ListenPort(uint16(port))
115+
if err != nil {
116+
return serrors.WrapStr("can't listen:", err)
117+
}
118+
defer listener.Close()
119+
fmt.Printf("%v,%v\n", appnet.DefNetwork().IA, listener.LocalAddr())
120+
121+
lastReceived := time.Now().Add(999 * time.Hour) // avoids elapsed > timeout in the 1st iter
122+
123+
buffer := make([]byte, 16*1024)
124+
125+
start := time.Now()
126+
started := false
127+
totalByteCount := 0
128+
instaByteCount := 0
129+
lastBWReport := time.Now()
130+
for {
131+
count, _, err := listener.ReadFrom(buffer)
132+
if err != nil {
133+
fmt.Println(err)
134+
continue
135+
}
136+
137+
totalByteCount += count
138+
instaByteCount += count
139+
140+
if !started {
141+
start = time.Now()
142+
started = true
143+
}
144+
145+
elapsed := time.Since(lastReceived).Milliseconds()
146+
if elapsed > timeout {
147+
fmt.Printf("Freeze: %.3f s\n", float64(elapsed)/1000.0)
148+
}
149+
150+
if time.Since(lastBWReport) > 5*time.Second {
151+
fmt.Printf("ave. bandwidth: %.3f kbps, insta. bandwidth: %.3f\n",
152+
float64(totalByteCount)*8./1024./time.Since(start).Seconds(),
153+
float64(instaByteCount)*8./1024./float64(time.Since(lastBWReport).Seconds()))
154+
155+
lastBWReport = time.Now()
156+
instaByteCount = 0
157+
}
158+
lastReceived = time.Now()
159+
}
160+
}

0 commit comments

Comments
 (0)