Skip to content
This repository was archived by the owner on Feb 29, 2024. It is now read-only.

Commit 3884afa

Browse files
authored
Merge pull request #33 from cloudflare/optimization/diff
Optimization of diff (see #32) using maps instead of N*N operation
2 parents f6f771b + 7a9ba09 commit 3884afa

File tree

5 files changed

+238
-35
lines changed

5 files changed

+238
-35
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ jobs:
77
env:
88
GO111MODULE=on
99
script:
10+
- make test
1011
- make vet
1112
# Compile
1213
- stage: compile

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ OUTPUT_GORTR := $(DIST_DIR)gortr-$(GORTR_VERSION)-$(GOOS)-$(ARCH)$(EXTENSION)
2121
vet:
2222
go vet cmd/gortr/gortr.go
2323

24+
.PHONY: test
25+
test:
26+
go test -v github.com/cloudflare/gortr/lib
27+
2428
.PHONY: prepare
2529
prepare:
2630
mkdir -p $(DIST_DIR)

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ go 1.12
55
require (
66
github.com/prometheus/client_golang v0.9.2
77
github.com/sirupsen/logrus v1.4.0
8+
github.com/stretchr/testify v1.2.2
89
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793
910
)

lib/server.go

Lines changed: 29 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -190,40 +190,43 @@ func NewServer(configuration ServerConfiguration, handler RTRServerEventHandler,
190190
}
191191
}
192192

193+
func (roa ROA) HashKey() string {
194+
return fmt.Sprintf("%v-%v-%v", roa.Prefix.String(), roa.MaxLen, roa.ASN)
195+
}
196+
197+
func ConvertROAListToMap(roas []ROA) map[string]ROA {
198+
roaMap := make(map[string]ROA, len(roas))
199+
for _, v := range roas {
200+
roaMap[v.HashKey()] = v
201+
}
202+
return roaMap
203+
}
204+
193205
func ComputeDiff(newRoas []ROA, prevRoas []ROA) ([]ROA, []ROA, []ROA) {
194206
added := make([]ROA, 0)
195207
removed := make([]ROA, 0)
196208
unchanged := make([]ROA, 0)
197209

210+
newRoasMap := ConvertROAListToMap(newRoas)
211+
prevRoasMap := ConvertROAListToMap(prevRoas)
212+
198213
for _, roa := range newRoas {
199-
var exists bool
200-
for _, croa := range prevRoas {
201-
if roa.Equals(croa) {
202-
exists = true
203-
break
204-
}
205-
}
214+
_, exists := prevRoasMap[roa.HashKey()]
206215
if !exists {
207216
rcopy := roa.Copy()
208217
rcopy.Flags = 1
209218
added = append(added, rcopy)
210219
}
211220
}
212221
for _, roa := range prevRoas {
213-
var exists bool
214-
for _, croa := range newRoas {
215-
if roa.Equals(croa) {
216-
rcopy := roa.Copy()
217-
unchanged = append(unchanged, rcopy)
218-
219-
exists = true
220-
break
221-
}
222-
}
222+
_, exists := newRoasMap[roa.HashKey()]
223223
if !exists {
224224
rcopy := roa.Copy()
225225
rcopy.Flags = 0
226226
removed = append(removed, rcopy)
227+
} else {
228+
rcopy := roa.Copy()
229+
unchanged = append(unchanged, rcopy)
227230
}
228231
}
229232

@@ -232,15 +235,11 @@ func ComputeDiff(newRoas []ROA, prevRoas []ROA) ([]ROA, []ROA, []ROA) {
232235

233236
func ApplyDiff(diff []ROA, prevRoas []ROA) []ROA {
234237
newroas := make([]ROA, 0)
238+
diffMap := ConvertROAListToMap(diff)
239+
prevRoasMap := ConvertROAListToMap(prevRoas)
235240

236241
for _, roa := range prevRoas {
237-
var exists bool
238-
for _, croa := range diff {
239-
if roa.Equals(croa) {
240-
exists = true
241-
break
242-
}
243-
}
242+
_, exists := diffMap[roa.HashKey()]
244243
if !exists {
245244
rcopy := roa.Copy()
246245
newroas = append(newroas, rcopy)
@@ -251,20 +250,15 @@ func ApplyDiff(diff []ROA, prevRoas []ROA) []ROA {
251250
rcopy := roa.Copy()
252251
newroas = append(newroas, rcopy)
253252
} else if roa.Flags == FLAG_REMOVED {
254-
var exists bool
255-
for _, croa := range prevRoas {
256-
if roa.Equals(croa) {
257-
if croa.Flags == FLAG_REMOVED {
258-
rcopy := roa.Copy()
259-
newroas = append(newroas, rcopy)
260-
}
261-
exists = true
262-
break
263-
}
264-
}
253+
croa, exists := prevRoasMap[roa.HashKey()]
265254
if !exists {
266255
rcopy := roa.Copy()
267256
newroas = append(newroas, rcopy)
257+
} else {
258+
if croa.Flags == FLAG_REMOVED {
259+
rcopy := roa.Copy()
260+
newroas = append(newroas, rcopy)
261+
}
268262
}
269263
}
270264

lib/server_test.go

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
package rtrlib
2+
3+
import (
4+
"encoding/binary"
5+
"github.com/stretchr/testify/assert"
6+
"net"
7+
"testing"
8+
)
9+
10+
func GenerateRoas(size uint32, offset uint32) []ROA {
11+
roas := make([]ROA, size)
12+
for i := uint32(0); i < size; i++ {
13+
ipFinal := make([]byte, 4)
14+
binary.BigEndian.PutUint32(ipFinal, i+offset)
15+
roas[i] = ROA{
16+
Prefix: net.IPNet{
17+
IP: net.IP(append([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ipFinal...)),
18+
Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}),
19+
},
20+
MaxLen: 128,
21+
ASN: 64496,
22+
}
23+
}
24+
return roas
25+
}
26+
27+
func BaseBench(base int, multiplier int) {
28+
benchSize1 := base * multiplier
29+
newRoas := GenerateRoas(uint32(benchSize1), uint32(0))
30+
benchSize2 := base
31+
prevRoas := GenerateRoas(uint32(benchSize2), uint32(benchSize1-benchSize2/2))
32+
ComputeDiff(newRoas, prevRoas)
33+
}
34+
35+
func BenchmarkComputeDiff1000x10(b *testing.B) {
36+
BaseBench(1000, 10)
37+
}
38+
39+
func BenchmarkComputeDiff10000x10(b *testing.B) {
40+
BaseBench(10000, 10)
41+
}
42+
43+
func BenchmarkComputeDiff100000x1(b *testing.B) {
44+
BaseBench(100000, 1)
45+
}
46+
47+
func TestComputeDiff(t *testing.T) {
48+
newRoas := []ROA{
49+
ROA{
50+
Prefix: net.IPNet{
51+
IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3}),
52+
Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}),
53+
},
54+
MaxLen: 128,
55+
ASN: 65003,
56+
},
57+
ROA{
58+
Prefix: net.IPNet{
59+
IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2}),
60+
Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}),
61+
},
62+
MaxLen: 128,
63+
ASN: 65002,
64+
},
65+
}
66+
prevRoas := []ROA{
67+
ROA{
68+
Prefix: net.IPNet{
69+
IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1}),
70+
Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}),
71+
},
72+
MaxLen: 128,
73+
ASN: 65001,
74+
},
75+
ROA{
76+
Prefix: net.IPNet{
77+
IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2}),
78+
Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}),
79+
},
80+
MaxLen: 128,
81+
ASN: 65002,
82+
},
83+
}
84+
added, removed, unchanged := ComputeDiff(newRoas, prevRoas)
85+
assert.Len(t, added, 1)
86+
assert.Len(t, removed, 1)
87+
assert.Len(t, unchanged, 1)
88+
assert.Equal(t, added[0].ASN, uint32(65003))
89+
assert.Equal(t, removed[0].ASN, uint32(65001))
90+
assert.Equal(t, unchanged[0].ASN, uint32(65002))
91+
}
92+
93+
func TestApplyDiff(t *testing.T) {
94+
diff := []ROA{
95+
ROA{
96+
Prefix: net.IPNet{
97+
IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3}),
98+
Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}),
99+
},
100+
MaxLen: 128,
101+
ASN: 65003,
102+
Flags: FLAG_ADDED,
103+
},
104+
ROA{
105+
Prefix: net.IPNet{
106+
IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2}),
107+
Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}),
108+
},
109+
MaxLen: 128,
110+
ASN: 65002,
111+
Flags: FLAG_REMOVED,
112+
},
113+
ROA{
114+
Prefix: net.IPNet{
115+
IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4}),
116+
Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}),
117+
},
118+
MaxLen: 128,
119+
ASN: 65004,
120+
Flags: FLAG_REMOVED,
121+
},
122+
ROA{
123+
Prefix: net.IPNet{
124+
IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6}),
125+
Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}),
126+
},
127+
MaxLen: 128,
128+
ASN: 65006,
129+
Flags: FLAG_REMOVED,
130+
},
131+
ROA{
132+
Prefix: net.IPNet{
133+
IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7}),
134+
Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}),
135+
},
136+
MaxLen: 128,
137+
ASN: 65007,
138+
Flags: FLAG_ADDED,
139+
},
140+
}
141+
prevRoas := []ROA{
142+
ROA{
143+
Prefix: net.IPNet{
144+
IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1}),
145+
Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}),
146+
},
147+
MaxLen: 128,
148+
ASN: 65001,
149+
Flags: FLAG_ADDED,
150+
},
151+
ROA{
152+
Prefix: net.IPNet{
153+
IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2}),
154+
Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}),
155+
},
156+
MaxLen: 128,
157+
ASN: 65002,
158+
Flags: FLAG_ADDED,
159+
},
160+
ROA{
161+
Prefix: net.IPNet{
162+
IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5}),
163+
Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}),
164+
},
165+
MaxLen: 128,
166+
ASN: 65005,
167+
Flags: FLAG_REMOVED,
168+
},
169+
ROA{
170+
Prefix: net.IPNet{
171+
IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6}),
172+
Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}),
173+
},
174+
MaxLen: 128,
175+
ASN: 65006,
176+
Flags: FLAG_REMOVED,
177+
},
178+
ROA{
179+
Prefix: net.IPNet{
180+
IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7}),
181+
Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}),
182+
},
183+
MaxLen: 128,
184+
ASN: 65007,
185+
Flags: FLAG_REMOVED,
186+
},
187+
}
188+
roas := ApplyDiff(diff, prevRoas)
189+
190+
assert.Len(t, roas, 6)
191+
assert.Equal(t, roas[0].ASN, uint32(65001))
192+
assert.Equal(t, roas[0].Flags, uint8(FLAG_ADDED))
193+
assert.Equal(t, roas[1].ASN, uint32(65005))
194+
assert.Equal(t, roas[1].Flags, uint8(FLAG_REMOVED))
195+
assert.Equal(t, roas[2].ASN, uint32(65003))
196+
assert.Equal(t, roas[2].Flags, uint8(FLAG_ADDED))
197+
assert.Equal(t, roas[3].ASN, uint32(65004))
198+
assert.Equal(t, roas[3].Flags, uint8(FLAG_REMOVED))
199+
assert.Equal(t, roas[4].ASN, uint32(65006))
200+
assert.Equal(t, roas[4].Flags, uint8(FLAG_REMOVED))
201+
assert.Equal(t, roas[5].ASN, uint32(65007))
202+
assert.Equal(t, roas[5].Flags, uint8(FLAG_ADDED))
203+
}

0 commit comments

Comments
 (0)