249 lines
6.0 KiB
Go
249 lines
6.0 KiB
Go
// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
// implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package table
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/osrg/gobgp/pkg/packet/bgp"
|
|
)
|
|
|
|
type AdjRib struct {
|
|
accepted map[bgp.RouteFamily]int
|
|
table map[bgp.RouteFamily]*Table
|
|
}
|
|
|
|
func NewAdjRib(rfList []bgp.RouteFamily) *AdjRib {
|
|
m := make(map[bgp.RouteFamily]*Table)
|
|
for _, f := range rfList {
|
|
m[f] = NewTable(f)
|
|
}
|
|
return &AdjRib{
|
|
table: m,
|
|
accepted: make(map[bgp.RouteFamily]int),
|
|
}
|
|
}
|
|
|
|
func (adj *AdjRib) Update(pathList []*Path) {
|
|
for _, path := range pathList {
|
|
if path == nil || path.IsEOR() {
|
|
continue
|
|
}
|
|
rf := path.GetRouteFamily()
|
|
t := adj.table[path.GetRouteFamily()]
|
|
d := t.getOrCreateDest(path.GetNlri(), 0)
|
|
var old *Path
|
|
idx := -1
|
|
for i, p := range d.knownPathList {
|
|
if p.GetNlri().PathIdentifier() == path.GetNlri().PathIdentifier() {
|
|
idx = i
|
|
break
|
|
}
|
|
}
|
|
if idx != -1 {
|
|
old = d.knownPathList[idx]
|
|
}
|
|
|
|
if path.IsWithdraw {
|
|
if idx != -1 {
|
|
d.knownPathList = append(d.knownPathList[:idx], d.knownPathList[idx+1:]...)
|
|
if len(d.knownPathList) == 0 {
|
|
t.deleteDest(d)
|
|
}
|
|
if !old.IsRejected() {
|
|
adj.accepted[rf]--
|
|
}
|
|
}
|
|
path.SetDropped(true)
|
|
} else {
|
|
if idx != -1 {
|
|
if old.IsRejected() && !path.IsRejected() {
|
|
adj.accepted[rf]++
|
|
} else if !old.IsRejected() && path.IsRejected() {
|
|
adj.accepted[rf]--
|
|
}
|
|
if old.Equal(path) {
|
|
path.setTimestamp(old.GetTimestamp())
|
|
}
|
|
d.knownPathList[idx] = path
|
|
} else {
|
|
d.knownPathList = append(d.knownPathList, path)
|
|
if !path.IsRejected() {
|
|
adj.accepted[rf]++
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* The provided pathList is expected to be the real candidate routes after policy evaluation.
|
|
For routes that are filtered by policy, there could be a mismatch between display
|
|
and actual rib sent to the peer (if softreset out was not run).
|
|
Only used to display adj-out because we do not maintain a separate adj-out table
|
|
*/
|
|
func (adj *AdjRib) UpdateAdjRibOut(pathList []*Path) {
|
|
for _, path := range pathList {
|
|
if path == nil || path.IsEOR() {
|
|
continue
|
|
}
|
|
t := adj.table[path.GetRouteFamily()]
|
|
d := t.getOrCreateDest(path.GetNlri(), 0)
|
|
d.knownPathList = append(d.knownPathList, path)
|
|
}
|
|
}
|
|
|
|
func (adj *AdjRib) walk(families []bgp.RouteFamily, fn func(*Destination) bool) {
|
|
for _, f := range families {
|
|
if t, ok := adj.table[f]; ok {
|
|
for _, d := range t.destinations {
|
|
if fn(d) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (adj *AdjRib) PathList(rfList []bgp.RouteFamily, accepted bool) []*Path {
|
|
pathList := make([]*Path, 0, adj.Count(rfList))
|
|
adj.walk(rfList, func(d *Destination) bool {
|
|
for _, p := range d.knownPathList {
|
|
if accepted && p.IsRejected() {
|
|
continue
|
|
}
|
|
pathList = append(pathList, p)
|
|
}
|
|
return false
|
|
})
|
|
return pathList
|
|
}
|
|
|
|
func (adj *AdjRib) Count(rfList []bgp.RouteFamily) int {
|
|
count := 0
|
|
adj.walk(rfList, func(d *Destination) bool {
|
|
count += len(d.knownPathList)
|
|
return false
|
|
})
|
|
return count
|
|
}
|
|
|
|
func (adj *AdjRib) Accepted(rfList []bgp.RouteFamily) int {
|
|
count := 0
|
|
for _, rf := range rfList {
|
|
if n, ok := adj.accepted[rf]; ok {
|
|
count += n
|
|
}
|
|
}
|
|
return count
|
|
}
|
|
|
|
func (adj *AdjRib) Drop(rfList []bgp.RouteFamily) []*Path {
|
|
l := make([]*Path, 0, adj.Count(rfList))
|
|
adj.walk(rfList, func(d *Destination) bool {
|
|
for _, p := range d.knownPathList {
|
|
w := p.Clone(true)
|
|
w.SetDropped(true)
|
|
l = append(l, w)
|
|
}
|
|
return false
|
|
})
|
|
for _, rf := range rfList {
|
|
adj.table[rf] = NewTable(rf)
|
|
adj.accepted[rf] = 0
|
|
}
|
|
return l
|
|
}
|
|
|
|
func (adj *AdjRib) DropStale(rfList []bgp.RouteFamily) []*Path {
|
|
pathList := make([]*Path, 0, adj.Count(rfList))
|
|
adj.walk(rfList, func(d *Destination) bool {
|
|
for _, p := range d.knownPathList {
|
|
if p.IsStale() {
|
|
w := p.Clone(true)
|
|
w.SetDropped(true)
|
|
pathList = append(pathList, w)
|
|
}
|
|
}
|
|
return false
|
|
})
|
|
adj.Update(pathList)
|
|
return pathList
|
|
}
|
|
|
|
func (adj *AdjRib) StaleAll(rfList []bgp.RouteFamily) []*Path {
|
|
pathList := make([]*Path, 0, adj.Count(rfList))
|
|
adj.walk(rfList, func(d *Destination) bool {
|
|
for i, p := range d.knownPathList {
|
|
n := p.Clone(false)
|
|
n.MarkStale(true)
|
|
n.SetRejected(p.IsRejected())
|
|
d.knownPathList[i] = n
|
|
if !n.IsRejected() {
|
|
pathList = append(pathList, n)
|
|
}
|
|
}
|
|
return false
|
|
})
|
|
return pathList
|
|
}
|
|
|
|
func (adj *AdjRib) MarkLLGRStaleOrDrop(rfList []bgp.RouteFamily) []*Path {
|
|
pathList := make([]*Path, 0, adj.Count(rfList))
|
|
adj.walk(rfList, func(d *Destination) bool {
|
|
for i, p := range d.knownPathList {
|
|
if p.HasNoLLGR() {
|
|
n := p.Clone(true)
|
|
n.SetDropped(true)
|
|
pathList = append(pathList, n)
|
|
} else {
|
|
n := p.Clone(false)
|
|
n.SetRejected(p.IsRejected())
|
|
n.SetCommunities([]uint32{uint32(bgp.COMMUNITY_LLGR_STALE)}, false)
|
|
if p.IsRejected() {
|
|
d.knownPathList[i] = n
|
|
} else {
|
|
pathList = append(pathList, n)
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
})
|
|
adj.Update(pathList)
|
|
return pathList
|
|
}
|
|
|
|
func (adj *AdjRib) Select(family bgp.RouteFamily, accepted bool, option ...TableSelectOption) (*Table, error) {
|
|
t, ok := adj.table[family]
|
|
if !ok {
|
|
t = NewTable(family)
|
|
}
|
|
option = append(option, TableSelectOption{adj: true})
|
|
return t.Select(option...)
|
|
}
|
|
|
|
func (adj *AdjRib) TableInfo(family bgp.RouteFamily) (*TableInfo, error) {
|
|
if _, ok := adj.table[family]; !ok {
|
|
return nil, fmt.Errorf("%s unsupported", family)
|
|
}
|
|
c := adj.Count([]bgp.RouteFamily{family})
|
|
a := adj.Accepted([]bgp.RouteFamily{family})
|
|
return &TableInfo{
|
|
NumDestination: c,
|
|
NumPath: c,
|
|
NumAccepted: a,
|
|
}, nil
|
|
}
|