github.com/osrg/gobgp/v3@v3.30.0/pkg/server/zclient.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 server 17 18 import ( 19 "fmt" 20 "math" 21 "net" 22 "strconv" 23 "strings" 24 "syscall" 25 "time" 26 27 "github.com/osrg/gobgp/v3/internal/pkg/table" 28 "github.com/osrg/gobgp/v3/pkg/log" 29 "github.com/osrg/gobgp/v3/pkg/packet/bgp" 30 "github.com/osrg/gobgp/v3/pkg/zebra" 31 ) 32 33 // nexthopStateCache stores a map of nexthop IP to metric value. Especially, 34 // the metric value of math.MaxUint32 means the nexthop is unreachable. 35 type nexthopStateCache map[string]uint32 36 37 func (m nexthopStateCache) applyToPathList(paths []*table.Path) []*table.Path { 38 updated := make([]*table.Path, 0, len(paths)) 39 for _, path := range paths { 40 if path == nil || path.IsWithdraw { 41 continue 42 } 43 metric, ok := m[path.GetNexthop().String()] 44 if !ok { 45 continue 46 } 47 isNexthopInvalid := metric == math.MaxUint32 48 med, err := path.GetMed() 49 if err == nil && med == metric && path.IsNexthopInvalid == isNexthopInvalid { 50 // If the nexthop state of the given path is already up to date, 51 // skips this path. 52 continue 53 } 54 newPath := path.Clone(false) 55 if isNexthopInvalid { 56 newPath.IsNexthopInvalid = true 57 } else { 58 newPath.IsNexthopInvalid = false 59 newPath.SetMed(int64(metric), true) 60 } 61 updated = append(updated, newPath) 62 } 63 return updated 64 } 65 66 func (m nexthopStateCache) updateByNexthopUpdate(body *zebra.NexthopUpdateBody) (updated bool) { 67 if len(body.Nexthops) == 0 { 68 // If NEXTHOP_UPDATE message does not contain any nexthop, the given 69 // nexthop is unreachable. 70 if _, ok := m[body.Prefix.Prefix.String()]; !ok { 71 // Zebra will send an empty NEXTHOP_UPDATE message as the fist 72 // response for the NEXTHOP_REGISTER message. Here ignores it. 73 return false 74 } 75 m[body.Prefix.Prefix.String()] = math.MaxUint32 // means unreachable 76 } else { 77 m[body.Prefix.Prefix.String()] = body.Metric 78 } 79 return true 80 } 81 82 func (m nexthopStateCache) filterPathToRegister(paths []*table.Path) []*table.Path { 83 filteredPaths := make([]*table.Path, 0, len(paths)) 84 for _, path := range paths { 85 // Here filters out: 86 // - Nil path 87 // - Withdrawn path 88 // - External path (advertised from Zebra) in order avoid sending back 89 // - Unspecified nexthop address 90 // - Already registered nexthop 91 if path == nil || path.IsWithdraw || path.IsFromExternal() { 92 continue 93 } else if nexthop := path.GetNexthop(); nexthop.IsUnspecified() { 94 continue 95 } else if _, ok := m[nexthop.String()]; ok { 96 continue 97 } 98 filteredPaths = append(filteredPaths, path) 99 } 100 return filteredPaths 101 } 102 103 func filterOutExternalPath(paths []*table.Path) []*table.Path { 104 filteredPaths := make([]*table.Path, 0, len(paths)) 105 for _, path := range paths { 106 // Here filters out: 107 // - Nil path 108 // - External path (advertised from Zebra) in order avoid sending back 109 // - Unreachable path because invalidated by Zebra 110 if path == nil || path.IsFromExternal() || path.IsNexthopInvalid { 111 continue 112 } 113 filteredPaths = append(filteredPaths, path) 114 } 115 return filteredPaths 116 } 117 118 func addLabelToNexthop(path *table.Path, z *zebraClient, msgFlags *zebra.MessageFlag, nexthop *zebra.Nexthop) { 119 rf := path.GetRouteFamily() 120 if rf == bgp.RF_IPv4_VPN || rf == bgp.RF_IPv6_VPN { 121 z.client.SetLabelFlag(msgFlags, nexthop) 122 switch rf { 123 case bgp.RF_IPv4_VPN: 124 for _, label := range path.GetNlri().(*bgp.LabeledVPNIPAddrPrefix).Labels.Labels { 125 nexthop.LabelNum++ 126 nexthop.MplsLabels = append(nexthop.MplsLabels, label) 127 } 128 case bgp.RF_IPv6_VPN: 129 for _, label := range path.GetNlri().(*bgp.LabeledVPNIPv6AddrPrefix).Labels.Labels { 130 nexthop.LabelNum++ 131 nexthop.MplsLabels = append(nexthop.MplsLabels, label) 132 } 133 } 134 } 135 } 136 137 func newIPRouteBody(dst []*table.Path, vrfID uint32, z *zebraClient) (body *zebra.IPRouteBody, isWithdraw bool) { 138 version := z.client.Version 139 paths := filterOutExternalPath(dst) 140 if len(paths) == 0 { 141 return nil, false 142 } 143 path := paths[0] 144 145 l := strings.SplitN(path.GetPrefix(), "/", 2) 146 var prefix net.IP 147 var nexthop zebra.Nexthop 148 nexthops := make([]zebra.Nexthop, 0, len(paths)) 149 msgFlags := zebra.MessageNexthop 150 switch path.GetRouteFamily() { 151 case bgp.RF_IPv4_UC: 152 prefix = path.GetNlri().(*bgp.IPAddrPrefix).IPAddrPrefixDefault.Prefix.To4() 153 case bgp.RF_IPv4_VPN: 154 prefix = path.GetNlri().(*bgp.LabeledVPNIPAddrPrefix).IPAddrPrefixDefault.Prefix.To4() 155 case bgp.RF_IPv6_UC: 156 prefix = path.GetNlri().(*bgp.IPv6AddrPrefix).IPAddrPrefixDefault.Prefix.To16() 157 case bgp.RF_IPv6_VPN: 158 prefix = path.GetNlri().(*bgp.LabeledVPNIPv6AddrPrefix).IPAddrPrefixDefault.Prefix.To16() 159 default: 160 return nil, false 161 } 162 nhVrfID := uint32(zebra.DefaultVrf) 163 for vrfPath, pathVrfID := range z.pathVrfMap { 164 if path.Equal(vrfPath) { 165 nhVrfID = pathVrfID 166 break 167 } else { 168 continue 169 } 170 } 171 for _, p := range paths { 172 nexthop.Gate = p.GetNexthop() 173 nexthop.VrfID = nhVrfID 174 if nhVrfID != vrfID { 175 addLabelToNexthop(path, z, &msgFlags, &nexthop) 176 } 177 nexthops = append(nexthops, nexthop) 178 } 179 plen, _ := strconv.ParseUint(l[1], 10, 8) 180 med, err := path.GetMed() 181 if err == nil { 182 msgFlags |= zebra.MessageMetric.ToEach(version, z.client.Software) 183 } 184 var flags zebra.Flag 185 if path.IsIBGP() { 186 flags = zebra.FlagIBGP.ToEach(z.client.Version, z.client.Software) | zebra.FlagAllowRecursion 187 } else if path.GetSource().MultihopTtl > 0 { 188 flags = zebra.FlagAllowRecursion // 0x01 189 } 190 return &zebra.IPRouteBody{ 191 Type: zebra.RouteBGP, 192 Flags: flags, 193 Safi: zebra.SafiUnicast, 194 Message: msgFlags, 195 Prefix: zebra.Prefix{ 196 Prefix: prefix, 197 PrefixLen: uint8(plen), 198 }, 199 Nexthops: nexthops, 200 Metric: med, 201 }, path.IsWithdraw 202 } 203 204 func newNexthopRegisterBody(paths []*table.Path, nexthopCache nexthopStateCache) *zebra.NexthopRegisterBody { 205 paths = nexthopCache.filterPathToRegister(paths) 206 if len(paths) == 0 { 207 return nil 208 } 209 path := paths[0] 210 211 family := path.GetRouteFamily() 212 nexthops := make([]*zebra.RegisteredNexthop, 0, len(paths)) 213 for _, p := range paths { 214 nexthop := p.GetNexthop() 215 var nh *zebra.RegisteredNexthop 216 switch family { 217 case bgp.RF_IPv4_UC, bgp.RF_IPv4_VPN: 218 nh = &zebra.RegisteredNexthop{ 219 Family: syscall.AF_INET, 220 Prefix: nexthop.To4(), 221 } 222 case bgp.RF_IPv6_UC, bgp.RF_IPv6_VPN: 223 nh = &zebra.RegisteredNexthop{ 224 Family: syscall.AF_INET6, 225 Prefix: nexthop.To16(), 226 } 227 default: 228 continue 229 } 230 nexthops = append(nexthops, nh) 231 } 232 233 // If no nexthop needs to be registered or unregistered, skips to send 234 // message. 235 if len(nexthops) == 0 { 236 return nil 237 } 238 239 return &zebra.NexthopRegisterBody{ 240 Nexthops: nexthops, 241 } 242 } 243 244 func newNexthopUnregisterBody(family uint16, prefix net.IP) *zebra.NexthopRegisterBody { 245 return &zebra.NexthopRegisterBody{ 246 Nexthops: []*zebra.RegisteredNexthop{{ 247 Family: family, 248 Prefix: prefix, 249 }}, 250 } 251 } 252 253 func newPathFromIPRouteMessage(logger log.Logger, m *zebra.Message, version uint8, software zebra.Software) *table.Path { 254 header := m.Header 255 body := m.Body.(*zebra.IPRouteBody) 256 family := body.RouteFamily(logger, version, software) 257 isWithdraw := body.IsWithdraw(version, software) 258 259 var nlri bgp.AddrPrefixInterface 260 pattr := make([]bgp.PathAttributeInterface, 0) 261 origin := bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP) 262 pattr = append(pattr, origin) 263 264 logger.Debug("create path from ip route message", 265 log.Fields{ 266 "Topic": "Zebra", 267 "RouteType": body.Type.String(), 268 "Flag": body.Flags.String(version, software), 269 "Message": body.Message, 270 "Family": body.Prefix.Family, 271 "Prefix": body.Prefix.Prefix, 272 "PrefixLength": body.Prefix.PrefixLen, 273 "Nexthop": body.Nexthops, 274 "Metric": body.Metric, 275 "Distance": body.Distance, 276 "Mtu": body.Mtu, 277 "api": header.Command.String()}) 278 279 switch family { 280 case bgp.RF_IPv4_UC: 281 nlri = bgp.NewIPAddrPrefix(body.Prefix.PrefixLen, body.Prefix.Prefix.String()) 282 if len(body.Nexthops) > 0 { 283 pattr = append(pattr, bgp.NewPathAttributeNextHop(body.Nexthops[0].Gate.String())) 284 } 285 case bgp.RF_IPv6_UC: 286 nlri = bgp.NewIPv6AddrPrefix(body.Prefix.PrefixLen, body.Prefix.Prefix.String()) 287 nexthop := "" 288 if len(body.Nexthops) > 0 { 289 nexthop = body.Nexthops[0].Gate.String() 290 } 291 pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI(nexthop, []bgp.AddrPrefixInterface{nlri})) 292 default: 293 logger.Error("unsupport address family", 294 log.Fields{ 295 "Topic": "Zebra", 296 "Family": family}) 297 return nil 298 } 299 300 med := bgp.NewPathAttributeMultiExitDisc(body.Metric) 301 pattr = append(pattr, med) 302 303 path := table.NewPath(nil, nlri, isWithdraw, pattr, time.Now(), false) 304 path.SetIsFromExternal(true) 305 return path 306 } 307 308 type mplsLabelParameter struct { 309 rangeSize uint32 310 maps map[uint64]*table.Bitmap 311 unassignedVrf []*table.Vrf //Vrfs which are not assigned MPLS label 312 } 313 314 type zebraClient struct { 315 client *zebra.Client 316 server *BgpServer 317 nexthopCache nexthopStateCache 318 pathVrfMap map[*table.Path]uint32 //vpn paths and nexthop vpn id 319 mplsLabel mplsLabelParameter 320 dead chan struct{} 321 } 322 323 func (z *zebraClient) getPathListWithNexthopUpdate(body *zebra.NexthopUpdateBody) []*table.Path { 324 rib := &table.TableManager{ 325 Tables: make(map[bgp.RouteFamily]*table.Table), 326 } 327 328 var rfList []bgp.RouteFamily 329 switch body.Prefix.Family { 330 case syscall.AF_INET: 331 rfList = []bgp.RouteFamily{bgp.RF_IPv4_UC, bgp.RF_IPv4_VPN} 332 case syscall.AF_INET6: 333 rfList = []bgp.RouteFamily{bgp.RF_IPv6_UC, bgp.RF_IPv6_VPN} 334 } 335 336 for _, rf := range rfList { 337 tbl, _, err := z.server.getRib("", rf, nil) 338 if err != nil { 339 z.server.logger.Error("failed to get global rib", 340 log.Fields{ 341 "Topic": "Zebra", 342 "Family": rf.String(), 343 "Error": err}) 344 continue 345 } 346 rib.Tables[rf] = tbl 347 } 348 349 return rib.GetPathListWithNexthop(table.GLOBAL_RIB_NAME, rfList, body.Prefix.Prefix) 350 } 351 352 func (z *zebraClient) updatePathByNexthopCache(paths []*table.Path) { 353 paths = z.nexthopCache.applyToPathList(paths) 354 if len(paths) > 0 { 355 if err := z.server.updatePath("", paths); err != nil { 356 z.server.logger.Error("failed to update nexthop reachability", 357 log.Fields{ 358 "Topic": "Zebra", 359 "PathList": paths}) 360 } 361 } 362 } 363 364 func (z *zebraClient) loop() { 365 w := z.server.watch([]watchOption{ 366 watchBestPath(true), 367 watchPostUpdate(true, "", ""), 368 }...) 369 defer w.Stop() 370 371 for { 372 select { 373 case <-z.dead: 374 return 375 case msg := <-z.client.Receive(): 376 if msg == nil { 377 break 378 } 379 switch body := msg.Body.(type) { 380 case *zebra.IPRouteBody: 381 if path := newPathFromIPRouteMessage(z.server.logger, msg, z.client.Version, z.client.Software); path != nil { 382 if err := z.server.addPathList("", []*table.Path{path}); err != nil { 383 z.server.logger.Error("failed to add path from zebra", 384 log.Fields{ 385 "Topic": "Zebra", 386 "Path": path, 387 "Error": err}) 388 } 389 } 390 case *zebra.NexthopUpdateBody: 391 if updated := z.nexthopCache.updateByNexthopUpdate(body); !updated { 392 continue 393 } 394 paths := z.getPathListWithNexthopUpdate(body) 395 if len(paths) == 0 { 396 // If there is no path bound for the given nexthop, send 397 // NEXTHOP_UNREGISTER message. 398 z.client.SendNexthopRegister(msg.Header.VrfID, newNexthopUnregisterBody(uint16(body.Prefix.Family), body.Prefix.Prefix), true) 399 delete(z.nexthopCache, body.Prefix.Prefix.String()) 400 } 401 z.updatePathByNexthopCache(paths) 402 case *zebra.GetLabelChunkBody: 403 z.server.logger.Debug("zebra GetLabelChunkBody is received", 404 log.Fields{ 405 "Topic": "Zebra", 406 "Start": body.Start, 407 "End": body.End}) 408 startEnd := uint64(body.Start)<<32 | uint64(body.End) 409 z.mplsLabel.maps[startEnd] = table.NewBitmap(int(body.End - body.Start + 1)) 410 for _, vrf := range z.mplsLabel.unassignedVrf { 411 if err := z.assignAndSendVrfMplsLabel(vrf); err != nil { 412 z.server.logger.Error("zebra failed to assign and send vrf mpls label", 413 log.Fields{ 414 "Topic": "Zebra", 415 "Error": err}) 416 } 417 } 418 z.mplsLabel.unassignedVrf = nil 419 } 420 case ev := <-w.Event(): 421 switch msg := ev.(type) { 422 case *watchEventBestPath: 423 if table.UseMultiplePaths.Enabled { 424 for _, paths := range msg.MultiPathList { 425 z.updatePathByNexthopCache(paths) 426 for i := range msg.Vrf { 427 if body, isWithdraw := newIPRouteBody(paths, i, z); body != nil { 428 z.client.SendIPRoute(i, body, isWithdraw) 429 } 430 if body := newNexthopRegisterBody(paths, z.nexthopCache); body != nil { 431 z.client.SendNexthopRegister(i, body, false) 432 } 433 } 434 } 435 } else { 436 z.updatePathByNexthopCache(msg.PathList) 437 for _, path := range msg.PathList { 438 for i := range msg.Vrf { 439 if body, isWithdraw := newIPRouteBody([]*table.Path{path}, i, z); body != nil { 440 err := z.client.SendIPRoute(i, body, isWithdraw) 441 if err != nil { 442 continue 443 } 444 } 445 if body := newNexthopRegisterBody([]*table.Path{path}, z.nexthopCache); body != nil { 446 z.client.SendNexthopRegister(i, body, false) 447 } 448 } 449 } 450 } 451 case *watchEventUpdate: 452 if body := newNexthopRegisterBody(msg.PathList, z.nexthopCache); body != nil { 453 vrfID := uint32(0) 454 for _, vrf := range z.server.listVrf() { 455 if vrf.Name == msg.Neighbor.Config.Vrf { 456 vrfID = uint32(vrf.Id) 457 } 458 } 459 z.client.SendNexthopRegister(vrfID, body, false) 460 } 461 } 462 } 463 } 464 } 465 466 func newZebraClient(s *BgpServer, url string, protos []string, version uint8, nhtEnable bool, nhtDelay uint8, mplsLabelRangeSize uint32, software zebra.Software) (*zebraClient, error) { 467 l := strings.SplitN(url, ":", 2) 468 if len(l) != 2 { 469 return nil, fmt.Errorf("unsupported url: %s", url) 470 } 471 var cli *zebra.Client 472 var err error 473 var usingVersion uint8 474 var zapivers [zebra.MaxZapiVer - zebra.MinZapiVer + 1]uint8 475 zapivers[0] = version 476 for elem, ver := 1, zebra.MinZapiVer; elem < len(zapivers) && ver <= zebra.MaxZapiVer; elem++ { 477 if version == ver && ver < zebra.MaxZapiVer { 478 ver++ 479 } 480 zapivers[elem] = ver 481 ver++ 482 } 483 for elem, ver := range zapivers { 484 cli, err = zebra.NewClient(s.logger, l[0], l[1], zebra.RouteBGP, ver, software, mplsLabelRangeSize) 485 if cli != nil && err == nil { 486 usingVersion = ver 487 break 488 } 489 // Retry with another Zebra message version 490 s.logger.Warn("cannot connect to Zebra with message version", 491 log.Fields{ 492 "Topic": "Zebra", 493 "Version": ver}) 494 if elem < len(zapivers)-1 { 495 s.logger.Warn("going to retry another version", 496 log.Fields{ 497 "Topic": "Zebra", 498 "Version": zapivers[elem+1]}) 499 } 500 } 501 if cli == nil || err != nil { 502 return nil, err 503 } 504 s.logger.Info("success to connect to Zebra", 505 log.Fields{ 506 "Topic": "Zebra", 507 "Version": usingVersion}) 508 509 // Note: HELLO/ROUTER_ID_ADD messages are automatically sent to negotiate 510 // the Zebra message version in zebra.NewClient(). 511 // cli.SendHello() 512 // cli.SendRouterIDAdd() 513 cli.SendInterfaceAdd() 514 for _, typ := range protos { 515 t, err := zebra.RouteTypeFromString(typ, version, software) 516 if err != nil { 517 return nil, err 518 } 519 cli.SendRedistribute(t, zebra.DefaultVrf) 520 } 521 w := &zebraClient{ 522 client: cli, 523 server: s, 524 nexthopCache: make(nexthopStateCache), 525 pathVrfMap: make(map[*table.Path]uint32), 526 mplsLabel: mplsLabelParameter{ 527 rangeSize: mplsLabelRangeSize, 528 maps: make(map[uint64]*table.Bitmap), 529 }, 530 dead: make(chan struct{}), 531 } 532 go w.loop() 533 if mplsLabelRangeSize > 0 && cli.SupportMpls() { 534 if err = cli.SendGetLabelChunk(&zebra.GetLabelChunkBody{ChunkSize: mplsLabelRangeSize}); err != nil { 535 return nil, err 536 } 537 } 538 return w, nil 539 } 540 541 func (z *zebraClient) assignMplsLabel() (uint32, error) { 542 if z.mplsLabel.maps == nil { 543 return 0, nil 544 } 545 var label uint32 546 for startEnd, bitmap := range z.mplsLabel.maps { 547 start := uint32(startEnd >> 32) 548 end := uint32(startEnd & 0xffffffff) 549 l, err := bitmap.FindandSetZeroBit() 550 if err == nil && start+uint32(l) <= end { 551 label = start + uint32(l) 552 break 553 } 554 } 555 if label == 0 { 556 return 0, fmt.Errorf("failed to assign new MPLS label") 557 } 558 return label, nil 559 } 560 561 func (z *zebraClient) assignAndSendVrfMplsLabel(vrf *table.Vrf) error { 562 var err error 563 if vrf.MplsLabel, err = z.assignMplsLabel(); vrf.MplsLabel > 0 { // success 564 if err = z.client.SendVrfLabel(vrf.MplsLabel, vrf.Id); err != nil { 565 return err 566 } 567 } else if vrf.MplsLabel == 0 { // GetLabelChunk is not performed 568 z.mplsLabel.unassignedVrf = append(z.mplsLabel.unassignedVrf, vrf) 569 } 570 return err 571 } 572 573 func (z *zebraClient) releaseMplsLabel(label uint32) { 574 if z.mplsLabel.maps == nil { 575 return 576 } 577 for startEnd, bitmap := range z.mplsLabel.maps { 578 start := uint32(startEnd >> 32) 579 end := uint32(startEnd & 0xffffffff) 580 if start <= label && label <= end { 581 bitmap.Unflag(uint(label - start)) 582 return 583 } 584 } 585 }