Skip to content

Commit 10ede25

Browse files
author
Georgy Borodin
committed
Speed up RTC exchange, exclude non-VPN paths from the RTC scheme
1. Add Key(RouteTarget)->uint64. 2. Add map[Key(rt)]map[*Path]{} to globalRib tables for fast making path list by RT. 3. Add map[Key(rt)]int to Adj RTC tables for fast filtering paths by RTs. 4. Add tests on pp.1-3.
1 parent 08a001e commit 10ede25

15 files changed

+1091
-74
lines changed

internal/pkg/table/adj.go

+23-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ type AdjRib struct {
3131
func NewAdjRib(logger log.Logger, rfList []bgp.RouteFamily) *AdjRib {
3232
m := make(map[bgp.RouteFamily]*Table)
3333
for _, f := range rfList {
34-
m[f] = NewTable(logger, f)
34+
m[f] = NewAdjTable(logger, f)
3535
}
3636
return &AdjRib{
3737
table: m,
@@ -40,6 +40,11 @@ func NewAdjRib(logger log.Logger, rfList []bgp.RouteFamily) *AdjRib {
4040
}
4141
}
4242

43+
func (adj *AdjRib) HasRTinRtcTable(key uint64) bool {
44+
table, found := adj.table[bgp.RF_RTC_UC]
45+
return found && table.rtc != nil && table.HasRT(key)
46+
}
47+
4348
func (adj *AdjRib) Update(pathList []*Path) {
4449
for _, path := range pathList {
4550
if path == nil || path.IsEOR() {
@@ -68,15 +73,24 @@ func (adj *AdjRib) Update(pathList []*Path) {
6873
}
6974
if !old.IsRejected() {
7075
adj.accepted[rf]--
76+
if t.rtc != nil {
77+
t.rtc.unregister(path, true)
78+
}
7179
}
7280
}
7381
path.SetDropped(true)
7482
} else {
7583
if idx != -1 {
7684
if old.IsRejected() && !path.IsRejected() {
7785
adj.accepted[rf]++
86+
if t.rtc != nil {
87+
t.rtc.register(path)
88+
}
7889
} else if !old.IsRejected() && path.IsRejected() {
7990
adj.accepted[rf]--
91+
if t.rtc != nil {
92+
t.rtc.unregister(path, true)
93+
}
8094
}
8195
if old.Equal(path) {
8296
path.setTimestamp(old.GetTimestamp())
@@ -86,6 +100,9 @@ func (adj *AdjRib) Update(pathList []*Path) {
86100
d.knownPathList = append(d.knownPathList, path)
87101
if !path.IsRejected() {
88102
adj.accepted[rf]++
103+
if t.rtc != nil {
104+
t.rtc.register(path)
105+
}
89106
}
90107
}
91108
}
@@ -107,6 +124,9 @@ func (adj *AdjRib) UpdateAdjRibOut(pathList []*Path) {
107124
t := adj.table[path.GetRouteFamily()]
108125
d := t.getOrCreateDest(path.GetNlri(), 0)
109126
d.knownPathList = append(d.knownPathList, path)
127+
if !path.IsRejected() && t.rtc != nil {
128+
t.rtc.register(path)
129+
}
110130
}
111131
}
112132

@@ -166,7 +186,7 @@ func (adj *AdjRib) Drop(rfList []bgp.RouteFamily) []*Path {
166186
return false
167187
})
168188
for _, rf := range rfList {
169-
adj.table[rf] = NewTable(adj.logger, rf)
189+
adj.table[rf] = NewAdjTable(adj.logger, rf)
170190
adj.accepted[rf] = 0
171191
}
172192
return l
@@ -233,7 +253,7 @@ func (adj *AdjRib) MarkLLGRStaleOrDrop(rfList []bgp.RouteFamily) []*Path {
233253
func (adj *AdjRib) Select(family bgp.RouteFamily, accepted bool, option ...TableSelectOption) (*Table, error) {
234254
t, ok := adj.table[family]
235255
if !ok {
236-
t = NewTable(adj.logger, family)
256+
t = NewAdjTable(adj.logger, family)
237257
}
238258
option = append(option, TableSelectOption{adj: true})
239259
return t.Select(option...)

internal/pkg/table/adj_test.go

+60
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ import (
2424
"github.com/stretchr/testify/assert"
2525
)
2626

27+
func TestCreateAdjTable(t *testing.T) {
28+
table := NewAdjTable(logger, bgp.RF_RTC_UC)
29+
assert.NotNil(t, table.rtc)
30+
_, checkType := table.rtc.(*routeFamilyRTCMap)
31+
assert.True(t, checkType)
32+
33+
table = NewAdjTable(logger, bgp.RF_FS_IPv4_VPN)
34+
assert.Nil(t, table.rtc)
35+
}
36+
2737
func TestAddPath(t *testing.T) {
2838
pi := &PeerInfo{}
2939
attrs := []bgp.PathAttributeInterface{bgp.NewPathAttributeOrigin(0)}
@@ -162,3 +172,53 @@ func TestLLGRStale(t *testing.T) {
162172
assert.Equal(t, adj.Accepted([]bgp.RouteFamily{family}), 1)
163173
assert.Equal(t, 2, len(adj.table[family].destinations))
164174
}
175+
176+
func TestAdjRTC(t *testing.T) {
177+
pi := &PeerInfo{}
178+
attrs := []bgp.PathAttributeInterface{bgp.NewPathAttributeOrigin(0)}
179+
180+
rt1, _ := bgp.ParseRouteTarget("65520:1000000")
181+
nlri1 := bgp.NewRouteTargetMembershipNLRI(65000, rt1)
182+
nlri1.SetPathIdentifier(1)
183+
hash1, err := nlri1.RouteTargetKey()
184+
assert.Nil(t, err)
185+
p1 := NewPath(pi, nlri1, false, attrs, time.Now(), false)
186+
187+
rt2, _ := bgp.ParseRouteTarget("65520:1000001")
188+
nlri2 := bgp.NewRouteTargetMembershipNLRI(65000, rt2)
189+
nlri2.SetPathIdentifier(2)
190+
hash2, err := nlri2.RouteTargetKey()
191+
assert.Nil(t, err)
192+
p2 := NewPath(pi, nlri2, false, attrs, time.Now(), false)
193+
194+
nlri3 := bgp.NewRouteTargetMembershipNLRI(0, nil)
195+
nlri3.SetPathIdentifier(3)
196+
p3 := NewPath(pi, nlri3, false, attrs, time.Now(), false)
197+
198+
family := p1.GetRouteFamily()
199+
assert.Equal(t, family, bgp.RF_RTC_UC)
200+
families := []bgp.RouteFamily{family}
201+
adj := NewAdjRib(logger, families)
202+
203+
adj.Update([]*Path{p1, p2, p3})
204+
assert.Equal(t, adj.Count([]bgp.RouteFamily{family}), 3)
205+
206+
assert.True(t, adj.HasRTinRtcTable(bgp.DefaultRT))
207+
assert.True(t, adj.HasRTinRtcTable(hash1))
208+
assert.True(t, adj.HasRTinRtcTable(hash2))
209+
210+
adj.Update([]*Path{p1.Clone(true)})
211+
assert.Equal(t, adj.Count([]bgp.RouteFamily{family}), 2)
212+
assert.True(t, adj.HasRTinRtcTable(bgp.DefaultRT))
213+
assert.True(t, !adj.HasRTinRtcTable(hash1))
214+
assert.True(t, adj.HasRTinRtcTable(hash2))
215+
216+
adj.Update([]*Path{p3.Clone(true)})
217+
assert.Equal(t, adj.Count([]bgp.RouteFamily{family}), 1)
218+
assert.True(t, !adj.HasRTinRtcTable(bgp.DefaultRT))
219+
assert.True(t, adj.HasRTinRtcTable(hash2))
220+
221+
adj.Update([]*Path{p2.Clone(true)})
222+
assert.Equal(t, adj.Count([]bgp.RouteFamily{family}), 0)
223+
assert.True(t, !adj.HasRTinRtcTable(hash2))
224+
}

internal/pkg/table/destination.go

+15-8
Original file line numberDiff line numberDiff line change
@@ -225,19 +225,23 @@ func (dd *Destination) GetMultiBestPath(id string) []*Path {
225225
//
226226
// Modifies destination's state related to stored paths. Removes withdrawn
227227
// paths from known paths. Also, adds new paths to known paths.
228-
func (dest *Destination) Calculate(logger log.Logger, newPath *Path) *Update {
228+
// Returns Update and withdrawn path if it was removed.
229+
func (dest *Destination) Calculate(logger log.Logger, newPath *Path) (*Update, *Path) {
229230
oldKnownPathList := make([]*Path, len(dest.knownPathList))
230231
copy(oldKnownPathList, dest.knownPathList)
232+
var withdrawn *Path
231233

232234
if newPath.IsWithdraw {
233-
p := dest.explicitWithdraw(logger, newPath)
234-
if p != nil && newPath.IsDropped() {
235-
if id := p.GetNlri().PathLocalIdentifier(); id != 0 {
236-
dest.localIdMap.Unflag(uint(id))
235+
withdrawn = dest.explicitWithdraw(logger, newPath)
236+
if withdrawn != nil {
237+
if newPath.IsDropped() {
238+
if id := withdrawn.GetNlri().PathLocalIdentifier(); id != 0 {
239+
dest.localIdMap.Unflag(uint(id))
240+
}
237241
}
238242
}
239243
} else {
240-
dest.implicitWithdraw(logger, newPath)
244+
withdrawn = dest.implicitWithdraw(logger, newPath)
241245
dest.knownPathList = append(dest.knownPathList, newPath)
242246
}
243247

@@ -259,7 +263,7 @@ func (dest *Destination) Calculate(logger log.Logger, newPath *Path) *Update {
259263
return &Update{
260264
KnownPathList: l,
261265
OldKnownPathList: oldKnownPathList,
262-
}
266+
}, withdrawn
263267
}
264268

265269
// Removes withdrawn paths.
@@ -316,7 +320,7 @@ func (dest *Destination) explicitWithdraw(logger log.Logger, withdraw *Path) *Pa
316320
//
317321
// Known paths will no longer have paths whose new version is present in
318322
// new paths.
319-
func (dest *Destination) implicitWithdraw(logger log.Logger, newPath *Path) {
323+
func (dest *Destination) implicitWithdraw(logger log.Logger, newPath *Path) *Path {
320324
found := -1
321325
for i, path := range dest.knownPathList {
322326
if newPath.NoImplicitWithdraw() {
@@ -341,8 +345,11 @@ func (dest *Destination) implicitWithdraw(logger log.Logger, newPath *Path) {
341345
}
342346
}
343347
if found != -1 {
348+
p := dest.knownPathList[found]
344349
dest.knownPathList = append(dest.knownPathList[:found], dest.knownPathList[found+1:]...)
350+
return p
345351
}
352+
return nil
346353
}
347354

348355
func (dest *Destination) computeKnownBestPath() (*Path, BestPathReason, error) {

internal/pkg/table/destination_test.go

+9-4
Original file line numberDiff line numberDiff line change
@@ -349,14 +349,17 @@ func TestMultipath(t *testing.T) {
349349
d := NewDestination(nlri[0], 0)
350350
d.Calculate(logger, path2)
351351

352-
best, old, multi := d.Calculate(logger, path1).GetChanges(GLOBAL_RIB_NAME, 0, false)
352+
dd, oldC := d.Calculate(logger, path1)
353+
assert.Nil(t, oldC)
354+
best, old, multi := dd.GetChanges(GLOBAL_RIB_NAME, 0, false)
353355
assert.NotNil(t, best)
354356
assert.Equal(t, old, path2)
355357
assert.Equal(t, len(multi), 2)
356358
assert.Equal(t, len(d.GetKnownPathList(GLOBAL_RIB_NAME, 0)), 2)
357359

358360
path3 := path2.Clone(true)
359-
dd := d.Calculate(logger, path3)
361+
dd, oldC = d.Calculate(logger, path3)
362+
assert.Equal(t, path2, oldC)
360363
best, old, multi = dd.GetChanges(GLOBAL_RIB_NAME, 0, false)
361364
assert.Nil(t, best)
362365
assert.Equal(t, old, path1)
@@ -374,7 +377,8 @@ func TestMultipath(t *testing.T) {
374377
}
375378
updateMsg = bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
376379
path4 := ProcessMessage(updateMsg, peer3, time.Now())[0]
377-
dd = d.Calculate(logger, path4)
380+
dd, oldDD := d.Calculate(logger, path4)
381+
assert.Nil(t, oldDD)
378382
best, _, multi = dd.GetChanges(GLOBAL_RIB_NAME, 0, false)
379383
assert.NotNil(t, best)
380384
assert.Equal(t, len(multi), 1)
@@ -389,7 +393,8 @@ func TestMultipath(t *testing.T) {
389393
}
390394
updateMsg = bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
391395
path5 := ProcessMessage(updateMsg, peer2, time.Now())[0]
392-
best, _, multi = d.Calculate(logger, path5).GetChanges(GLOBAL_RIB_NAME, 0, false)
396+
dd, _ = d.Calculate(logger, path5)
397+
best, _, multi = dd.GetChanges(GLOBAL_RIB_NAME, 0, false)
393398
assert.NotNil(t, best)
394399
assert.Equal(t, len(multi), 2)
395400
assert.Equal(t, len(d.GetKnownPathList(GLOBAL_RIB_NAME, 0)), 3)

internal/pkg/table/path.go

+78
Original file line numberDiff line numberDiff line change
@@ -1037,6 +1037,9 @@ func (lhs *Path) Equal(rhs *Path) bool {
10371037
if rhs == nil {
10381038
return false
10391039
}
1040+
if lhs == rhs {
1041+
return true
1042+
}
10401043

10411044
if !lhs.GetSource().Equal(rhs.GetSource()) {
10421045
return false
@@ -1336,3 +1339,78 @@ func nlriToIPNet(nlri bgp.AddrPrefixInterface) *net.IPNet {
13361339
}
13371340
return nil
13381341
}
1342+
1343+
func bestPathListForRT(id string, as uint32, withdraw bool, inPaths map[*Path]struct{}, outPaths []*Path) []*Path {
1344+
for p := range inPaths {
1345+
if p.IsNexthopInvalid || rsFilter(id, as, p) {
1346+
continue
1347+
}
1348+
if !p.IsWithdraw && withdraw {
1349+
p = p.Clone(true)
1350+
}
1351+
outPaths = append(outPaths, p)
1352+
}
1353+
return outPaths
1354+
}
1355+
1356+
func (t *Table) HasRT(key uint64) bool {
1357+
if t.rtc == nil {
1358+
return false
1359+
}
1360+
if rtPaths, ok := t.rtc.(*routeFamilyRTCMap); ok {
1361+
num, found := rtPaths.rts[key]
1362+
return found && num > 0
1363+
}
1364+
return false
1365+
}
1366+
1367+
func (t *Table) bestPathListForRTMaxLen(rt uint64) int {
1368+
if t.rtc == nil {
1369+
return 0
1370+
}
1371+
if vpnPaths, ok := t.rtc.(*vpnFamilyRTCMap); ok {
1372+
if rtTable, found := vpnPaths.rts[rt]; found {
1373+
return len(rtTable.paths)
1374+
}
1375+
}
1376+
return 0
1377+
}
1378+
1379+
func (t *Table) getBestsForDetachedRTFromPeer(rt uint64, peerId string, tableId string, as uint32, paths []*Path) []*Path {
1380+
if t.rtc == nil {
1381+
// Note: "return paths" means "no new paths are returned".
1382+
return paths
1383+
}
1384+
if vpnPaths, ok := t.rtc.(*vpnFamilyRTCMap); ok {
1385+
if rtTable, found := vpnPaths.rts[rt]; found {
1386+
if _, foundId := rtTable.peers[peerId]; foundId {
1387+
delete(rtTable.peers, peerId)
1388+
if !rtTable.empty() {
1389+
return bestPathListForRT(tableId, as, true, rtTable.paths, paths)
1390+
}
1391+
delete(vpnPaths.rts, rt)
1392+
}
1393+
}
1394+
}
1395+
return paths
1396+
}
1397+
1398+
func (t *Table) getBestsForNewlyAttachedRTtoPeer(rt uint64, peerId string, tableId string, as uint32, paths []*Path) []*Path {
1399+
if t.rtc == nil {
1400+
// Note: "return paths" means "no new paths are returned".
1401+
return paths
1402+
}
1403+
if vpnPaths, ok := t.rtc.(*vpnFamilyRTCMap); ok {
1404+
if rtTable, found := vpnPaths.rts[rt]; !found {
1405+
rtTable = newVpnFamilyRT()
1406+
vpnPaths.rts[rt] = rtTable
1407+
rtTable.peers[peerId] = struct{}{}
1408+
} else {
1409+
if _, foundId := rtTable.peers[peerId]; !foundId {
1410+
rtTable.peers[peerId] = struct{}{}
1411+
return bestPathListForRT(tableId, as, false, rtTable.paths, paths)
1412+
}
1413+
}
1414+
}
1415+
return paths
1416+
}

0 commit comments

Comments
 (0)