github.com/osrg/gobgp/v3@v3.30.0/internal/pkg/table/table_manager.go (about) 1 // Copyright (C) 2014 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 "bytes" 20 "fmt" 21 "net" 22 "time" 23 24 farm "github.com/dgryski/go-farm" 25 26 "github.com/osrg/gobgp/v3/pkg/log" 27 "github.com/osrg/gobgp/v3/pkg/packet/bgp" 28 ) 29 30 const ( 31 GLOBAL_RIB_NAME = "global" 32 ) 33 34 func ProcessMessage(m *bgp.BGPMessage, peerInfo *PeerInfo, timestamp time.Time) []*Path { 35 update := m.Body.(*bgp.BGPUpdate) 36 37 if y, f := update.IsEndOfRib(); y { 38 // this message has no normal updates or withdrawals. 39 return []*Path{NewEOR(f)} 40 } 41 42 adds := make([]bgp.AddrPrefixInterface, 0, len(update.NLRI)) 43 for _, nlri := range update.NLRI { 44 adds = append(adds, nlri) 45 } 46 47 dels := make([]bgp.AddrPrefixInterface, 0, len(update.WithdrawnRoutes)) 48 for _, nlri := range update.WithdrawnRoutes { 49 dels = append(dels, nlri) 50 } 51 52 attrs := make([]bgp.PathAttributeInterface, 0, len(update.PathAttributes)) 53 var reach *bgp.PathAttributeMpReachNLRI 54 for _, attr := range update.PathAttributes { 55 switch a := attr.(type) { 56 case *bgp.PathAttributeMpReachNLRI: 57 reach = a 58 case *bgp.PathAttributeMpUnreachNLRI: 59 l := make([]bgp.AddrPrefixInterface, 0, len(a.Value)) 60 l = append(l, a.Value...) 61 dels = append(dels, l...) 62 default: 63 // update msg may not contain next_hop (type:3) in attr 64 // due to it uses MpReachNLRI and it also has empty update.NLRI 65 attrs = append(attrs, attr) 66 } 67 } 68 69 listLen := len(adds) + len(dels) 70 if reach != nil { 71 listLen += len(reach.Value) 72 } 73 74 var hash uint32 75 if len(adds) > 0 || reach != nil { 76 total := bytes.NewBuffer(make([]byte, 0)) 77 for _, a := range attrs { 78 b, _ := a.Serialize() 79 total.Write(b) 80 } 81 hash = farm.Hash32(total.Bytes()) 82 } 83 84 pathList := make([]*Path, 0, listLen) 85 for _, nlri := range adds { 86 p := NewPath(peerInfo, nlri, false, attrs, timestamp, false) 87 p.SetHash(hash) 88 pathList = append(pathList, p) 89 } 90 if reach != nil { 91 reachAttrs := make([]bgp.PathAttributeInterface, len(attrs)+1) 92 copy(reachAttrs, attrs) 93 // we sort attributes when creating a bgp message from paths 94 reachAttrs[len(reachAttrs)-1] = reach 95 96 for _, nlri := range reach.Value { 97 // when build path from reach 98 // reachAttrs might not contain next_hop if `attrs` does not have one 99 // this happens when a MP peer send update to gobgp 100 // However nlri is always populated because how we build the path 101 // path.info{nlri: nlri} 102 p := NewPath(peerInfo, nlri, false, reachAttrs, timestamp, false) 103 p.SetHash(hash) 104 pathList = append(pathList, p) 105 } 106 } 107 for _, nlri := range dels { 108 p := NewPath(peerInfo, nlri, true, []bgp.PathAttributeInterface{}, timestamp, false) 109 pathList = append(pathList, p) 110 } 111 return pathList 112 } 113 114 type TableManager struct { 115 Tables map[bgp.RouteFamily]*Table 116 Vrfs map[string]*Vrf 117 rfList []bgp.RouteFamily 118 logger log.Logger 119 } 120 121 func NewTableManager(logger log.Logger, rfList []bgp.RouteFamily) *TableManager { 122 t := &TableManager{ 123 Tables: make(map[bgp.RouteFamily]*Table), 124 Vrfs: make(map[string]*Vrf), 125 rfList: rfList, 126 logger: logger, 127 } 128 for _, rf := range rfList { 129 t.Tables[rf] = NewTable(logger, rf) 130 } 131 return t 132 } 133 134 func (manager *TableManager) GetRFlist() []bgp.RouteFamily { 135 return manager.rfList 136 } 137 138 func (manager *TableManager) AddVrf(name string, id uint32, rd bgp.RouteDistinguisherInterface, importRt, exportRt []bgp.ExtendedCommunityInterface, info *PeerInfo) ([]*Path, error) { 139 if _, ok := manager.Vrfs[name]; ok { 140 return nil, fmt.Errorf("vrf %s already exists", name) 141 } 142 manager.logger.Debug("add vrf", 143 log.Fields{ 144 "Topic": "Vrf", 145 "Key": name, 146 "Rd": rd, 147 "ImportRt": importRt, 148 "ExportRt": exportRt}) 149 manager.Vrfs[name] = &Vrf{ 150 Name: name, 151 Id: id, 152 Rd: rd, 153 ImportRt: importRt, 154 ExportRt: exportRt, 155 } 156 msgs := make([]*Path, 0, len(importRt)) 157 nexthop := "0.0.0.0" 158 for _, target := range importRt { 159 nlri := bgp.NewRouteTargetMembershipNLRI(info.AS, target) 160 pattr := make([]bgp.PathAttributeInterface, 0, 2) 161 pattr = append(pattr, bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP)) 162 pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI(nexthop, []bgp.AddrPrefixInterface{nlri})) 163 msgs = append(msgs, NewPath(info, nlri, false, pattr, time.Now(), false)) 164 } 165 return msgs, nil 166 } 167 168 func (manager *TableManager) DeleteVrf(name string) ([]*Path, error) { 169 if _, ok := manager.Vrfs[name]; !ok { 170 return nil, fmt.Errorf("vrf %s not found", name) 171 } 172 msgs := make([]*Path, 0) 173 vrf := manager.Vrfs[name] 174 for _, t := range manager.Tables { 175 msgs = append(msgs, t.deletePathsByVrf(vrf)...) 176 } 177 manager.logger.Debug("delete vrf", 178 log.Fields{ 179 "Topic": "Vrf", 180 "Key": vrf.Name, 181 "Rd": vrf.Rd, 182 "ImportRt": vrf.ImportRt, 183 "ExportRt": vrf.ExportRt, 184 "MplsLabel": vrf.MplsLabel}) 185 delete(manager.Vrfs, name) 186 rtcTable := manager.Tables[bgp.RF_RTC_UC] 187 msgs = append(msgs, rtcTable.deleteRTCPathsByVrf(vrf, manager.Vrfs)...) 188 return msgs, nil 189 } 190 191 func (manager *TableManager) Update(newPath *Path) []*Update { 192 if newPath == nil || newPath.IsEOR() { 193 return nil 194 } 195 196 // Except for a special case with EVPN, we'll have one destination. 197 updates := make([]*Update, 0, 1) 198 family := newPath.GetRouteFamily() 199 if table, ok := manager.Tables[family]; ok { 200 updates = append(updates, table.update(newPath)) 201 202 if family == bgp.RF_EVPN { 203 for _, p := range manager.handleMacMobility(newPath) { 204 updates = append(updates, table.update(p)) 205 } 206 } 207 } 208 return updates 209 } 210 211 // EVPN MAC MOBILITY HANDLING 212 // 213 // RFC7432 15. MAC Mobility 214 // 215 // A PE receiving a MAC/IP Advertisement route for a MAC address with a 216 // different Ethernet segment identifier and a higher sequence number 217 // than that which it had previously advertised withdraws its MAC/IP 218 // Advertisement route. 219 // ...... 220 // If the PE is the originator of the MAC route and it receives the same 221 // MAC address with the same sequence number that it generated, it will 222 // compare its own IP address with the IP address of the remote PE and 223 // will select the lowest IP. If its own route is not the best one, it 224 // will withdraw the route. 225 func (manager *TableManager) handleMacMobility(path *Path) []*Path { 226 pathList := make([]*Path, 0) 227 nlri := path.GetNlri().(*bgp.EVPNNLRI) 228 if path.IsWithdraw || path.IsLocal() || nlri.RouteType != bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT { 229 return nil 230 } 231 232 f := func(p *Path) (bgp.EthernetSegmentIdentifier, uint32, net.HardwareAddr, int, net.IP) { 233 nlri := p.GetNlri().(*bgp.EVPNNLRI) 234 d := nlri.RouteTypeData.(*bgp.EVPNMacIPAdvertisementRoute) 235 ecs := p.GetExtCommunities() 236 seq := -1 237 for _, ec := range ecs { 238 if t, st := ec.GetTypes(); t == bgp.EC_TYPE_EVPN && st == bgp.EC_SUBTYPE_MAC_MOBILITY { 239 seq = int(ec.(*bgp.MacMobilityExtended).Sequence) 240 break 241 } 242 } 243 return d.ESI, d.ETag, d.MacAddress, seq, p.GetSource().Address 244 } 245 e1, et1, m1, s1, i1 := f(path) 246 247 // Extract the route targets to scope the lookup to the MAC-VRF with the MAC address. 248 // This will help large EVPN instances where a single MAC is present in a lot of MAC-VRFs (e.g. 249 // an anycast router). 250 // A route may have multiple route targets, to target multiple MAC-VRFs (e.g. in both an L2VNI 251 // and L3VNI in the VXLAN case). 252 var paths []*Path 253 for _, ec := range path.GetRouteTargets() { 254 paths = append(paths, manager.GetPathListWithMac(GLOBAL_RIB_NAME, 0, []bgp.RouteFamily{bgp.RF_EVPN}, ec, m1)...) 255 } 256 257 for _, path2 := range paths { 258 if !path2.IsLocal() || path2.GetNlri().(*bgp.EVPNNLRI).RouteType != bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT { 259 continue 260 } 261 e2, et2, m2, s2, i2 := f(path2) 262 if et1 == et2 && bytes.Equal(m1, m2) && !bytes.Equal(e1.Value, e2.Value) { 263 if s1 > s2 || s1 == s2 && bytes.Compare(i1, i2) < 0 { 264 pathList = append(pathList, path2.Clone(true)) 265 } 266 } 267 } 268 return pathList 269 } 270 271 func (manager *TableManager) tables(list ...bgp.RouteFamily) []*Table { 272 l := make([]*Table, 0, len(manager.Tables)) 273 if len(list) == 0 { 274 for _, v := range manager.Tables { 275 l = append(l, v) 276 } 277 return l 278 } 279 for _, f := range list { 280 if t, ok := manager.Tables[f]; ok { 281 l = append(l, t) 282 } 283 } 284 return l 285 } 286 287 func (manager *TableManager) getDestinationCount(rfList []bgp.RouteFamily) int { 288 count := 0 289 for _, t := range manager.tables(rfList...) { 290 count += len(t.GetDestinations()) 291 } 292 return count 293 } 294 295 func (manager *TableManager) GetBestPathList(id string, as uint32, rfList []bgp.RouteFamily) []*Path { 296 if SelectionOptions.DisableBestPathSelection { 297 // Note: If best path selection disabled, there is no best path. 298 return nil 299 } 300 paths := make([]*Path, 0, manager.getDestinationCount(rfList)) 301 for _, t := range manager.tables(rfList...) { 302 paths = append(paths, t.Bests(id, as)...) 303 } 304 return paths 305 } 306 307 func (manager *TableManager) GetBestMultiPathList(id string, rfList []bgp.RouteFamily) [][]*Path { 308 if !UseMultiplePaths.Enabled || SelectionOptions.DisableBestPathSelection { 309 // Note: If multi path not enabled or best path selection disabled, 310 // there is no best multi path. 311 return nil 312 } 313 paths := make([][]*Path, 0, manager.getDestinationCount(rfList)) 314 for _, t := range manager.tables(rfList...) { 315 paths = append(paths, t.MultiBests(id)...) 316 } 317 return paths 318 } 319 320 func (manager *TableManager) GetPathList(id string, as uint32, rfList []bgp.RouteFamily) []*Path { 321 paths := make([]*Path, 0, manager.getDestinationCount(rfList)) 322 for _, t := range manager.tables(rfList...) { 323 paths = append(paths, t.GetKnownPathList(id, as)...) 324 } 325 return paths 326 } 327 328 func (manager *TableManager) GetPathListWithMac(id string, as uint32, rfList []bgp.RouteFamily, rt bgp.ExtendedCommunityInterface, mac net.HardwareAddr) []*Path { 329 var paths []*Path 330 for _, t := range manager.tables(rfList...) { 331 paths = append(paths, t.GetKnownPathListWithMac(id, as, rt, mac, false)...) 332 } 333 return paths 334 } 335 336 func (manager *TableManager) GetPathListWithNexthop(id string, rfList []bgp.RouteFamily, nexthop net.IP) []*Path { 337 paths := make([]*Path, 0, manager.getDestinationCount(rfList)) 338 for _, rf := range rfList { 339 if t, ok := manager.Tables[rf]; ok { 340 for _, path := range t.GetKnownPathList(id, 0) { 341 if path.GetNexthop().Equal(nexthop) { 342 paths = append(paths, path) 343 } 344 } 345 } 346 } 347 return paths 348 } 349 350 func (manager *TableManager) GetPathListWithSource(id string, rfList []bgp.RouteFamily, source *PeerInfo) []*Path { 351 paths := make([]*Path, 0, manager.getDestinationCount(rfList)) 352 for _, rf := range rfList { 353 if t, ok := manager.Tables[rf]; ok { 354 for _, path := range t.GetKnownPathList(id, 0) { 355 if path.GetSource().Equal(source) { 356 paths = append(paths, path) 357 } 358 } 359 } 360 } 361 return paths 362 } 363 364 func (manager *TableManager) GetDestination(path *Path) *Destination { 365 if path == nil { 366 return nil 367 } 368 family := path.GetRouteFamily() 369 t, ok := manager.Tables[family] 370 if !ok { 371 return nil 372 } 373 return t.GetDestination(path.GetNlri()) 374 }