github.com/osrg/gobgp/v3@v3.30.0/internal/pkg/table/adj.go (about) 1 // Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. 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 12 // implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 package table 17 18 import ( 19 "fmt" 20 21 "github.com/osrg/gobgp/v3/pkg/log" 22 "github.com/osrg/gobgp/v3/pkg/packet/bgp" 23 ) 24 25 type AdjRib struct { 26 accepted map[bgp.RouteFamily]int 27 table map[bgp.RouteFamily]*Table 28 logger log.Logger 29 } 30 31 func NewAdjRib(logger log.Logger, rfList []bgp.RouteFamily) *AdjRib { 32 m := make(map[bgp.RouteFamily]*Table) 33 for _, f := range rfList { 34 m[f] = NewTable(logger, f) 35 } 36 return &AdjRib{ 37 table: m, 38 accepted: make(map[bgp.RouteFamily]int), 39 logger: logger, 40 } 41 } 42 43 func (adj *AdjRib) Update(pathList []*Path) { 44 for _, path := range pathList { 45 if path == nil || path.IsEOR() { 46 continue 47 } 48 rf := path.GetRouteFamily() 49 t := adj.table[path.GetRouteFamily()] 50 d := t.getOrCreateDest(path.GetNlri(), 0) 51 var old *Path 52 idx := -1 53 for i, p := range d.knownPathList { 54 if p.GetNlri().PathIdentifier() == path.GetNlri().PathIdentifier() { 55 idx = i 56 break 57 } 58 } 59 if idx != -1 { 60 old = d.knownPathList[idx] 61 } 62 63 if path.IsWithdraw { 64 if idx != -1 { 65 d.knownPathList = append(d.knownPathList[:idx], d.knownPathList[idx+1:]...) 66 if len(d.knownPathList) == 0 { 67 t.deleteDest(d) 68 } 69 if !old.IsRejected() { 70 adj.accepted[rf]-- 71 } 72 } 73 path.SetDropped(true) 74 } else { 75 if idx != -1 { 76 if old.IsRejected() && !path.IsRejected() { 77 adj.accepted[rf]++ 78 } else if !old.IsRejected() && path.IsRejected() { 79 adj.accepted[rf]-- 80 } 81 if old.Equal(path) { 82 path.setTimestamp(old.GetTimestamp()) 83 } 84 d.knownPathList[idx] = path 85 } else { 86 d.knownPathList = append(d.knownPathList, path) 87 if !path.IsRejected() { 88 adj.accepted[rf]++ 89 } 90 } 91 } 92 } 93 } 94 95 /* 96 The provided pathList is expected to be the real candidate routes after policy evaluation. 97 98 For routes that are filtered by policy, there could be a mismatch between display 99 and actual rib sent to the peer (if softreset out was not run). 100 Only used to display adj-out because we do not maintain a separate adj-out table 101 */ 102 func (adj *AdjRib) UpdateAdjRibOut(pathList []*Path) { 103 for _, path := range pathList { 104 if path == nil || path.IsEOR() { 105 continue 106 } 107 t := adj.table[path.GetRouteFamily()] 108 d := t.getOrCreateDest(path.GetNlri(), 0) 109 d.knownPathList = append(d.knownPathList, path) 110 } 111 } 112 113 func (adj *AdjRib) walk(families []bgp.RouteFamily, fn func(*Destination) bool) { 114 for _, f := range families { 115 if t, ok := adj.table[f]; ok { 116 for _, d := range t.destinations { 117 if fn(d) { 118 return 119 } 120 } 121 } 122 } 123 } 124 125 func (adj *AdjRib) PathList(rfList []bgp.RouteFamily, accepted bool) []*Path { 126 pathList := make([]*Path, 0, adj.Count(rfList)) 127 adj.walk(rfList, func(d *Destination) bool { 128 for _, p := range d.knownPathList { 129 if accepted && p.IsRejected() { 130 continue 131 } 132 pathList = append(pathList, p) 133 } 134 return false 135 }) 136 return pathList 137 } 138 139 func (adj *AdjRib) Count(rfList []bgp.RouteFamily) int { 140 count := 0 141 adj.walk(rfList, func(d *Destination) bool { 142 count += len(d.knownPathList) 143 return false 144 }) 145 return count 146 } 147 148 func (adj *AdjRib) Accepted(rfList []bgp.RouteFamily) int { 149 count := 0 150 for _, rf := range rfList { 151 if n, ok := adj.accepted[rf]; ok { 152 count += n 153 } 154 } 155 return count 156 } 157 158 func (adj *AdjRib) Drop(rfList []bgp.RouteFamily) []*Path { 159 l := make([]*Path, 0, adj.Count(rfList)) 160 adj.walk(rfList, func(d *Destination) bool { 161 for _, p := range d.knownPathList { 162 w := p.Clone(true) 163 w.SetDropped(true) 164 l = append(l, w) 165 } 166 return false 167 }) 168 for _, rf := range rfList { 169 adj.table[rf] = NewTable(adj.logger, rf) 170 adj.accepted[rf] = 0 171 } 172 return l 173 } 174 175 func (adj *AdjRib) DropStale(rfList []bgp.RouteFamily) []*Path { 176 pathList := make([]*Path, 0, adj.Count(rfList)) 177 adj.walk(rfList, func(d *Destination) bool { 178 for _, p := range d.knownPathList { 179 if p.IsStale() { 180 w := p.Clone(true) 181 w.SetDropped(true) 182 pathList = append(pathList, w) 183 } 184 } 185 return false 186 }) 187 adj.Update(pathList) 188 return pathList 189 } 190 191 func (adj *AdjRib) StaleAll(rfList []bgp.RouteFamily) []*Path { 192 pathList := make([]*Path, 0, adj.Count(rfList)) 193 adj.walk(rfList, func(d *Destination) bool { 194 for i, p := range d.knownPathList { 195 n := p.Clone(false) 196 n.MarkStale(true) 197 n.SetRejected(p.IsRejected()) 198 d.knownPathList[i] = n 199 if !n.IsRejected() { 200 pathList = append(pathList, n) 201 } 202 } 203 return false 204 }) 205 return pathList 206 } 207 208 func (adj *AdjRib) MarkLLGRStaleOrDrop(rfList []bgp.RouteFamily) []*Path { 209 pathList := make([]*Path, 0, adj.Count(rfList)) 210 adj.walk(rfList, func(d *Destination) bool { 211 for i, p := range d.knownPathList { 212 if p.HasNoLLGR() { 213 n := p.Clone(true) 214 n.SetDropped(true) 215 pathList = append(pathList, n) 216 } else { 217 n := p.Clone(false) 218 n.SetRejected(p.IsRejected()) 219 n.SetCommunities([]uint32{uint32(bgp.COMMUNITY_LLGR_STALE)}, false) 220 if p.IsRejected() { 221 d.knownPathList[i] = n 222 } else { 223 pathList = append(pathList, n) 224 } 225 } 226 } 227 return false 228 }) 229 adj.Update(pathList) 230 return pathList 231 } 232 233 func (adj *AdjRib) Select(family bgp.RouteFamily, accepted bool, option ...TableSelectOption) (*Table, error) { 234 t, ok := adj.table[family] 235 if !ok { 236 t = NewTable(adj.logger, family) 237 } 238 option = append(option, TableSelectOption{adj: true}) 239 return t.Select(option...) 240 } 241 242 func (adj *AdjRib) TableInfo(family bgp.RouteFamily) (*TableInfo, error) { 243 if _, ok := adj.table[family]; !ok { 244 return nil, fmt.Errorf("%s unsupported", family) 245 } 246 c := adj.Count([]bgp.RouteFamily{family}) 247 a := adj.Accepted([]bgp.RouteFamily{family}) 248 return &TableInfo{ 249 NumDestination: c, 250 NumPath: c, 251 NumAccepted: a, 252 }, nil 253 }