Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package locRIB
import (
"fmt"
"math"
"sync"
"github.com/bio-routing/bio-rd/net"
"github.com/bio-routing/bio-rd/route"
"github.com/bio-routing/bio-rd/routingtable"
)
// LocRIB represents a routing information base
type LocRIB struct {
routingtable.ClientManager
rt *routingtable.RoutingTable
mu sync.RWMutex
}
// New creates a new routing information base
func New() *LocRIB {
a := &LocRIB{
rt: routingtable.NewRoutingTable(),
}
a.ClientManager = routingtable.NewClientManager(a)
return a
}
// UpdateNewClient sends current state to a new client
func (a *LocRIB) UpdateNewClient(client routingtable.RouteTableClient) error {
a.mu.RLock()
defer a.mu.RUnlock()
routes := a.rt.Dump()
for _, r := range routes {
a.propagateChanges(&route.Route{}, r)
}
return nil
}
// AddPath replaces the path for prefix `pfx`. If the prefix doesn't exist it is added.
func (a *LocRIB) AddPath(pfx net.Prefix, p *route.Path) error {
a.mu.Lock()
defer a.mu.Unlock()
routeExisted := false
oldRoute := &route.Route{}
r := a.rt.Get(pfx)
if r != nil {
oldRoute = r.Copy()
routeExisted = true
}
// FIXME: in AddPath() we assume that the same reference of route (r) is modified (not responsibility of locRIB). If this implementation changes in the future this code will break.
a.rt.AddPath(pfx, p)
if !routeExisted {
r = a.rt.Get(pfx)
}
r.PathSelection()
newRoute := r.Copy()
a.propagateChanges(oldRoute, newRoute)
return nil
}
// RemovePath removes the path for prefix `pfx`
func (a *LocRIB) RemovePath(pfx net.Prefix, p *route.Path) bool {
a.mu.Lock()
defer a.mu.Unlock()
var oldRoute *route.Route
r := a.rt.Get(pfx)
if r != nil {
oldRoute = r.Copy()
Christoph Petrausch
committed
} else {
return true
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
}
a.rt.RemovePath(pfx, p)
r.PathSelection()
r = a.rt.Get(pfx)
newRoute := r.Copy()
a.propagateChanges(oldRoute, newRoute)
return true
}
func (a *LocRIB) propagateChanges(oldRoute *route.Route, newRoute *route.Route) {
a.removePathsFromClients(oldRoute, newRoute)
a.addPathsToClients(oldRoute, newRoute)
}
func (a *LocRIB) addPathsToClients(oldRoute *route.Route, newRoute *route.Route) {
for _, client := range a.ClientManager.Clients() {
opts := a.ClientManager.GetOptions(client)
oldMaxPaths := opts.GetMaxPaths(oldRoute.ECMPPathCount())
newMaxPaths := opts.GetMaxPaths(newRoute.ECMPPathCount())
oldPathsLimit := int(math.Min(float64(oldMaxPaths), float64(len(oldRoute.Paths()))))
newPathsLimit := int(math.Min(float64(newMaxPaths), float64(len(newRoute.Paths()))))
advertise := route.PathsDiff(newRoute.Paths()[0:newPathsLimit], oldRoute.Paths()[0:oldPathsLimit])
for _, p := range advertise {
client.AddPath(newRoute.Prefix(), p)
}
}
}
func (a *LocRIB) removePathsFromClients(oldRoute *route.Route, newRoute *route.Route) {
for _, client := range a.ClientManager.Clients() {
opts := a.ClientManager.GetOptions(client)
oldMaxPaths := opts.GetMaxPaths(oldRoute.ECMPPathCount())
newMaxPaths := opts.GetMaxPaths(newRoute.ECMPPathCount())
oldPathsLimit := int(math.Min(float64(oldMaxPaths), float64(len(oldRoute.Paths()))))
newPathsLimit := int(math.Min(float64(newMaxPaths), float64(len(newRoute.Paths()))))
withdraw := route.PathsDiff(oldRoute.Paths()[0:oldPathsLimit], newRoute.Paths()[0:newPathsLimit])
for _, p := range withdraw {
client.RemovePath(oldRoute.Prefix(), p)
Christoph Petrausch
committed
// ContainsPfxPath returns true if this prefix and path combination is
// present in this LocRIB.
func (a *LocRIB) ContainsPfxPath(pfx net.Prefix, p *route.Path) bool {
a.mu.RLock()
defer a.mu.RUnlock()
Christoph Petrausch
committed
r := a.rt.Get(pfx)
if r == nil {
return false
}
Christoph Petrausch
committed
for _, path := range r.Paths() {
if path.Compare(p) == 0 {
return true
}
}
Christoph Petrausch
committed
return false
}