github.com/osrg/gobgp@v2.0.0+incompatible/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/internal/pkg/table" 28 "github.com/osrg/gobgp/internal/pkg/zebra" 29 "github.com/osrg/gobgp/pkg/packet/bgp" 30 31 log "github.com/sirupsen/logrus" 32 ) 33 34 // nexthopStateCache stores a map of nexthop IP to metric value. Especially, 35 // the metric value of math.MaxUint32 means the nexthop is unreachable. 36 type nexthopStateCache map[string]uint32 37 38 func (m nexthopStateCache) applyToPathList(paths []*table.Path) []*table.Path { 39 updated := make([]*table.Path, 0, len(paths)) 40 for _, path := range paths { 41 if path == nil || path.IsWithdraw { 42 continue 43 } 44 metric, ok := m[path.GetNexthop().String()] 45 if !ok { 46 continue 47 } 48 isNexthopInvalid := metric == math.MaxUint32 49 med, err := path.GetMed() 50 if err == nil && med == metric && path.IsNexthopInvalid == isNexthopInvalid { 51 // If the nexthop state of the given path is already up to date, 52 // skips this path. 53 continue 54 } 55 newPath := path.Clone(false) 56 if isNexthopInvalid { 57 newPath.IsNexthopInvalid = true 58 } else { 59 newPath.IsNexthopInvalid = false 60 newPath.SetMed(int64(metric), true) 61 } 62 updated = append(updated, newPath) 63 } 64 return updated 65 } 66 67 func (m nexthopStateCache) updateByNexthopUpdate(body *zebra.NexthopUpdateBody) (updated bool) { 68 if len(body.Nexthops) == 0 { 69 // If NEXTHOP_UPDATE message does not contain any nexthop, the given 70 // nexthop is unreachable. 71 if _, ok := m[body.Prefix.Prefix.String()]; !ok { 72 // Zebra will send an empty NEXTHOP_UPDATE message as the fist 73 // response for the NEXTHOP_REGISTER message. Here ignores it. 74 return false 75 } 76 m[body.Prefix.Prefix.String()] = math.MaxUint32 // means unreachable 77 } else { 78 m[body.Prefix.Prefix.String()] = body.Metric 79 } 80 return true 81 } 82 83 func (m nexthopStateCache) filterPathToRegister(paths []*table.Path) []*table.Path { 84 filteredPaths := make([]*table.Path, 0, len(paths)) 85 for _, path := range paths { 86 // Here filters out: 87 // - Nil path 88 // - Withdrawn path 89 // - External path (advertised from Zebra) in order avoid sending back 90 // - Unspecified nexthop address 91 // - Already registered nexthop 92 if path == nil || path.IsWithdraw || path.IsFromExternal() { 93 continue 94 } else if nexthop := path.GetNexthop(); nexthop.IsUnspecified() { 95 continue 96 } else if _, ok := m[nexthop.String()]; ok { 97 continue 98 } 99 filteredPaths = append(filteredPaths, path) 100 } 101 return filteredPaths 102 } 103 104 func filterOutExternalPath(paths []*table.Path) []*table.Path { 105 filteredPaths := make([]*table.Path, 0, len(paths)) 106 for _, path := range paths { 107 // Here filters out: 108 // - Nil path 109 // - External path (advertised from Zebra) in order avoid sending back 110 // - Unreachable path because invalidated by Zebra 111 if path == nil || path.IsFromExternal() || path.IsNexthopInvalid { 112 continue 113 } 114 filteredPaths = append(filteredPaths, path) 115 } 116 return filteredPaths 117 } 118 119 func newIPRouteBody(dst []*table.Path) (body *zebra.IPRouteBody, isWithdraw bool) { 120 paths := filterOutExternalPath(dst) 121 if len(paths) == 0 { 122 return nil, false 123 } 124 path := paths[0] 125 126 l := strings.SplitN(path.GetNlri().String(), "/", 2) 127 var prefix net.IP 128 //nexthops := make([]net.IP, 0, len(paths)) 129 var nexthop zebra.Nexthop 130 nexthops := make([]zebra.Nexthop, 0, len(paths)) 131 switch path.GetRouteFamily() { 132 case bgp.RF_IPv4_UC, bgp.RF_IPv4_VPN: 133 if path.GetRouteFamily() == bgp.RF_IPv4_UC { 134 prefix = path.GetNlri().(*bgp.IPAddrPrefix).IPAddrPrefixDefault.Prefix.To4() 135 } else { 136 prefix = path.GetNlri().(*bgp.LabeledVPNIPAddrPrefix).IPAddrPrefixDefault.Prefix.To4() 137 } 138 for _, p := range paths { 139 nexthop.Gate = p.GetNexthop().To4() 140 nexthops = append(nexthops, nexthop) 141 } 142 case bgp.RF_IPv6_UC, bgp.RF_IPv6_VPN: 143 if path.GetRouteFamily() == bgp.RF_IPv6_UC { 144 prefix = path.GetNlri().(*bgp.IPv6AddrPrefix).IPAddrPrefixDefault.Prefix.To16() 145 } else { 146 prefix = path.GetNlri().(*bgp.LabeledVPNIPv6AddrPrefix).IPAddrPrefixDefault.Prefix.To16() 147 } 148 for _, p := range paths { 149 nexthop.Gate = p.GetNexthop().To16() 150 nexthops = append(nexthops, nexthop) 151 } 152 default: 153 return nil, false 154 } 155 msgFlags := zebra.MESSAGE_NEXTHOP 156 plen, _ := strconv.ParseUint(l[1], 10, 8) 157 med, err := path.GetMed() 158 if err == nil { 159 msgFlags |= zebra.MESSAGE_METRIC 160 } 161 var flags zebra.FLAG 162 if path.IsIBGP() { 163 flags = zebra.FLAG_IBGP | zebra.FLAG_INTERNAL 164 } else if path.GetSource().MultihopTtl > 0 { 165 flags = zebra.FLAG_INTERNAL 166 } 167 return &zebra.IPRouteBody{ 168 Type: zebra.ROUTE_BGP, 169 Flags: flags, 170 SAFI: zebra.SAFI_UNICAST, 171 Message: msgFlags, 172 Prefix: zebra.Prefix{ 173 Prefix: prefix, 174 PrefixLen: uint8(plen), 175 }, 176 Nexthops: nexthops, 177 Metric: med, 178 }, path.IsWithdraw 179 } 180 181 func newNexthopRegisterBody(paths []*table.Path, nexthopCache nexthopStateCache) *zebra.NexthopRegisterBody { 182 paths = nexthopCache.filterPathToRegister(paths) 183 if len(paths) == 0 { 184 return nil 185 } 186 path := paths[0] 187 188 family := path.GetRouteFamily() 189 nexthops := make([]*zebra.RegisteredNexthop, 0, len(paths)) 190 for _, p := range paths { 191 nexthop := p.GetNexthop() 192 var nh *zebra.RegisteredNexthop 193 switch family { 194 case bgp.RF_IPv4_UC, bgp.RF_IPv4_VPN: 195 nh = &zebra.RegisteredNexthop{ 196 Family: syscall.AF_INET, 197 Prefix: nexthop.To4(), 198 } 199 case bgp.RF_IPv6_UC, bgp.RF_IPv6_VPN: 200 nh = &zebra.RegisteredNexthop{ 201 Family: syscall.AF_INET6, 202 Prefix: nexthop.To16(), 203 } 204 default: 205 continue 206 } 207 nexthops = append(nexthops, nh) 208 } 209 210 // If no nexthop needs to be registered or unregistered, skips to send 211 // message. 212 if len(nexthops) == 0 { 213 return nil 214 } 215 216 return &zebra.NexthopRegisterBody{ 217 Nexthops: nexthops, 218 } 219 } 220 221 func newNexthopUnregisterBody(family uint16, prefix net.IP) *zebra.NexthopRegisterBody { 222 return &zebra.NexthopRegisterBody{ 223 Nexthops: []*zebra.RegisteredNexthop{{ 224 Family: family, 225 Prefix: prefix, 226 }}, 227 } 228 } 229 230 func newPathFromIPRouteMessage(m *zebra.Message, version uint8) *table.Path { 231 header := m.Header 232 body := m.Body.(*zebra.IPRouteBody) 233 family := body.RouteFamily(version) 234 isWithdraw := body.IsWithdraw(version) 235 236 var nlri bgp.AddrPrefixInterface 237 pattr := make([]bgp.PathAttributeInterface, 0) 238 origin := bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP) 239 pattr = append(pattr, origin) 240 241 log.WithFields(log.Fields{ 242 "Topic": "Zebra", 243 "RouteType": body.Type.String(), 244 "Flag": body.Flags.String(), 245 "Message": body.Message, 246 "Family": body.Prefix.Family, 247 "Prefix": body.Prefix.Prefix, 248 "PrefixLength": body.Prefix.PrefixLen, 249 "Nexthop": body.Nexthops, 250 "Metric": body.Metric, 251 "Distance": body.Distance, 252 "Mtu": body.Mtu, 253 "api": header.Command.String(), 254 }).Debugf("create path from ip route message.") 255 256 switch family { 257 case bgp.RF_IPv4_UC: 258 nlri = bgp.NewIPAddrPrefix(body.Prefix.PrefixLen, body.Prefix.Prefix.String()) 259 if len(body.Nexthops) > 0 { 260 pattr = append(pattr, bgp.NewPathAttributeNextHop(body.Nexthops[0].Gate.String())) 261 } 262 case bgp.RF_IPv6_UC: 263 nlri = bgp.NewIPv6AddrPrefix(body.Prefix.PrefixLen, body.Prefix.Prefix.String()) 264 nexthop := "" 265 if len(body.Nexthops) > 0 { 266 nexthop = body.Nexthops[0].Gate.String() 267 } 268 pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI(nexthop, []bgp.AddrPrefixInterface{nlri})) 269 default: 270 log.WithFields(log.Fields{ 271 "Topic": "Zebra", 272 }).Errorf("unsupport address family: %s", family) 273 return nil 274 } 275 276 med := bgp.NewPathAttributeMultiExitDisc(body.Metric) 277 pattr = append(pattr, med) 278 279 path := table.NewPath(nil, nlri, isWithdraw, pattr, time.Now(), false) 280 path.SetIsFromExternal(true) 281 return path 282 } 283 284 type zebraClient struct { 285 client *zebra.Client 286 server *BgpServer 287 nexthopCache nexthopStateCache 288 dead chan struct{} 289 } 290 291 func (z *zebraClient) getPathListWithNexthopUpdate(body *zebra.NexthopUpdateBody) []*table.Path { 292 rib := &table.TableManager{ 293 Tables: make(map[bgp.RouteFamily]*table.Table), 294 } 295 296 var rfList []bgp.RouteFamily 297 switch body.Prefix.Family { 298 case syscall.AF_INET: 299 rfList = []bgp.RouteFamily{bgp.RF_IPv4_UC, bgp.RF_IPv4_VPN} 300 case syscall.AF_INET6: 301 rfList = []bgp.RouteFamily{bgp.RF_IPv6_UC, bgp.RF_IPv6_VPN} 302 } 303 304 for _, rf := range rfList { 305 tbl, _, err := z.server.getRib("", rf, nil) 306 if err != nil { 307 log.WithFields(log.Fields{ 308 "Topic": "Zebra", 309 "Family": rf.String(), 310 "Error": err, 311 }).Error("failed to get global rib") 312 continue 313 } 314 rib.Tables[rf] = tbl 315 } 316 317 return rib.GetPathListWithNexthop(table.GLOBAL_RIB_NAME, rfList, body.Prefix.Prefix) 318 } 319 320 func (z *zebraClient) updatePathByNexthopCache(paths []*table.Path) { 321 paths = z.nexthopCache.applyToPathList(paths) 322 if len(paths) > 0 { 323 if err := z.server.updatePath("", paths); err != nil { 324 log.WithFields(log.Fields{ 325 "Topic": "Zebra", 326 "PathList": paths, 327 }).Error("failed to update nexthop reachability") 328 } 329 } 330 } 331 332 func (z *zebraClient) loop() { 333 w := z.server.watch([]watchOption{ 334 watchBestPath(true), 335 watchPostUpdate(true), 336 }...) 337 defer w.Stop() 338 339 for { 340 select { 341 case <-z.dead: 342 return 343 case msg := <-z.client.Receive(): 344 if msg == nil { 345 break 346 } 347 switch body := msg.Body.(type) { 348 case *zebra.IPRouteBody: 349 if path := newPathFromIPRouteMessage(msg, z.client.Version); path != nil { 350 if err := z.server.addPathList("", []*table.Path{path}); err != nil { 351 log.WithFields(log.Fields{ 352 "Topic": "Zebra", 353 "Path": path, 354 "Error": err, 355 }).Error("failed to add path from zebra") 356 } 357 } 358 case *zebra.NexthopUpdateBody: 359 if updated := z.nexthopCache.updateByNexthopUpdate(body); !updated { 360 continue 361 } 362 paths := z.getPathListWithNexthopUpdate(body) 363 if len(paths) == 0 { 364 // If there is no path bound for the given nexthop, send 365 // NEXTHOP_UNREGISTER message. 366 z.client.SendNexthopRegister(msg.Header.VrfId, newNexthopUnregisterBody(uint16(body.Prefix.Family), body.Prefix.Prefix), true) 367 delete(z.nexthopCache, body.Prefix.Prefix.String()) 368 } 369 z.updatePathByNexthopCache(paths) 370 } 371 case ev := <-w.Event(): 372 switch msg := ev.(type) { 373 case *watchEventBestPath: 374 if table.UseMultiplePaths.Enabled { 375 for _, paths := range msg.MultiPathList { 376 z.updatePathByNexthopCache(paths) 377 if body, isWithdraw := newIPRouteBody(paths); body != nil { 378 z.client.SendIPRoute(0, body, isWithdraw) 379 } 380 if body := newNexthopRegisterBody(paths, z.nexthopCache); body != nil { 381 z.client.SendNexthopRegister(0, body, false) 382 } 383 } 384 } else { 385 z.updatePathByNexthopCache(msg.PathList) 386 for _, path := range msg.PathList { 387 vrfs := []uint32{0} 388 if msg.Vrf != nil { 389 if v, ok := msg.Vrf[path.GetNlri().String()]; ok { 390 vrfs = append(vrfs, v) 391 } 392 } 393 for _, i := range vrfs { 394 if body, isWithdraw := newIPRouteBody([]*table.Path{path}); body != nil { 395 z.client.SendIPRoute(i, body, isWithdraw) 396 } 397 if body := newNexthopRegisterBody([]*table.Path{path}, z.nexthopCache); body != nil { 398 z.client.SendNexthopRegister(i, body, false) 399 } 400 } 401 } 402 } 403 case *watchEventUpdate: 404 if body := newNexthopRegisterBody(msg.PathList, z.nexthopCache); body != nil { 405 vrfID := uint32(0) 406 for _, vrf := range z.server.listVrf() { 407 if vrf.Name == msg.Neighbor.Config.Vrf { 408 vrfID = uint32(vrf.Id) 409 } 410 } 411 z.client.SendNexthopRegister(vrfID, body, false) 412 } 413 } 414 } 415 } 416 } 417 418 func newZebraClient(s *BgpServer, url string, protos []string, version uint8, nhtEnable bool, nhtDelay uint8) (*zebraClient, error) { 419 l := strings.SplitN(url, ":", 2) 420 if len(l) != 2 { 421 return nil, fmt.Errorf("unsupported url: %s", url) 422 } 423 var cli *zebra.Client 424 var err error 425 var usingVersion uint8 426 var zapivers [zebra.MaxZapiVer - zebra.MinZapiVer + 1]uint8 427 zapivers[0] = version 428 for elem, ver := 1, zebra.MinZapiVer; elem < len(zapivers) && ver <= zebra.MaxZapiVer; elem++ { 429 if version == ver && ver < zebra.MaxZapiVer { 430 ver++ 431 } 432 zapivers[elem] = ver 433 ver++ 434 } 435 for elem, ver := range zapivers { 436 cli, err = zebra.NewClient(l[0], l[1], zebra.ROUTE_BGP, ver) 437 if cli != nil && err == nil { 438 usingVersion = ver 439 break 440 } 441 // Retry with another Zebra message version 442 log.WithFields(log.Fields{ 443 "Topic": "Zebra", 444 }).Warnf("cannot connect to Zebra with message version %d.", ver) 445 if elem < len(zapivers)-1 { 446 log.WithFields(log.Fields{ 447 "Topic": "Zebra", 448 }).Warnf("going to retry another version %d.", zapivers[elem+1]) 449 } 450 } 451 if cli == nil || err != nil { 452 return nil, err 453 } 454 log.WithFields(log.Fields{ 455 "Topic": "Zebra", 456 }).Infof("success to connect to Zebra with message version %d.", usingVersion) 457 458 // Note: HELLO/ROUTER_ID_ADD messages are automatically sent to negotiate 459 // the Zebra message version in zebra.NewClient(). 460 // cli.SendHello() 461 // cli.SendRouterIDAdd() 462 cli.SendInterfaceAdd() 463 for _, typ := range protos { 464 t, err := zebra.RouteTypeFromString(typ, version) 465 if err != nil { 466 return nil, err 467 } 468 cli.SendRedistribute(t, zebra.VRF_DEFAULT) 469 } 470 w := &zebraClient{ 471 client: cli, 472 server: s, 473 nexthopCache: make(nexthopStateCache), 474 dead: make(chan struct{}), 475 } 476 go w.loop() 477 return w, nil 478 }