github.com/osrg/gobgp/v3@v3.30.0/pkg/zebra/zapi.go (about) 1 // Copyright (C) 2014, 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 zebra 17 18 import ( 19 "encoding/binary" 20 "errors" 21 "fmt" 22 "io" 23 "math" 24 "net" 25 "regexp" 26 "strconv" 27 "strings" 28 "syscall" 29 30 "github.com/osrg/gobgp/v3/pkg/log" 31 "github.com/osrg/gobgp/v3/pkg/packet/bgp" 32 ) 33 34 const ( 35 // MinZapiVer is minimum zebra api version which is referred in zclient 36 MinZapiVer uint8 = 2 37 // MaxZapiVer is maximum zebra api version which is referredd in zclient 38 MaxZapiVer uint8 = 6 39 // DefaultVrf is default vrf id is referredd in zclient and server 40 DefaultVrf = 0 41 ) 42 43 var ( 44 MaxSoftware = NewSoftware(MaxZapiVer, "frr8.2") 45 ) 46 47 const ( 48 headerMarker uint8 = 255 49 frrHeaderMarker uint8 = 254 50 interfaceNameSize = 20 51 osIfNameSize = 16 52 maxPathNum = 64 53 maxMplsLabel = 16 54 ) 55 56 // Internal Interface Status. 57 type interfaceStatus uint8 58 59 const ( 60 interfaceActive interfaceStatus = 0x01 61 interfaceSub interfaceStatus = 0x02 62 interfaceLinkDetection interfaceStatus = 0x04 63 interfaceVrfLoopback interfaceStatus = 0x08 64 ) 65 66 // Interface Link Layer Types. 67 // 68 //go:generate stringer -type=linkType 69 type linkType uint32 70 71 const ( 72 linkTypeUnknown linkType = iota 73 linkTypeEther 74 linkTypeEEther 75 linkTypeAX25 76 linkTypePRONET 77 linkTypeIeee802 78 linkTypeARCNET 79 linkTypeAPPLETLK 80 linkTypeDLCI 81 linkTypeATM 82 linkTypeMetricOM 83 linkTypeIeee1394 84 linkTypeEUI64 85 linkTypeINFINIBAND 86 linkTypeSLIP 87 linkTypeCSLIP 88 linkTypeSLIP6 89 linkTypeCSLIP6 90 linkTypeRSRVD 91 linkTypeADAPT 92 linkTypeROSE 93 linkTypeX25 94 linkTypePPP 95 linkTypeCHDLC 96 linkTypeLAPB 97 linkTypeRAWHDLC 98 linkTypeIPIP 99 linkTypeIPIP6 100 linkTypeFRAD 101 linkTypeSKIP 102 linkTypeLOOPBACK 103 linkTypeLOCALTLK 104 linkTypeFDDI 105 linkTypeSIT 106 linkTypeIPDDP 107 linkTypeIPGRE 108 linkTypeIP6GRE 109 linkTypePIMREG 110 linkTypeHIPPI 111 linkTypeECONET 112 linkTypeIRDA 113 linkTypeFCPP 114 linkTypeFCAL 115 linkTypeFCPL 116 linkTypeFCFABRIC 117 linkTypeIeee802Tr 118 linkTypeIeee80211 119 linkTypeIeee80211RadioTap 120 linkTypeIeee802154 121 linkTypeIeee802154Phy 122 ) 123 124 // HeaderSize returns suitable header size from version 125 func HeaderSize(version uint8) uint16 { 126 switch version { 127 case 3, 4: 128 return 8 129 case 5, 6: 130 return 10 131 } 132 return 6 // version == 2 133 } 134 135 // HeaderMarker returns suitable header marker from version 136 func HeaderMarker(version uint8) uint8 { 137 if version > 3 { 138 return frrHeaderMarker 139 } 140 return headerMarker 141 } 142 143 func (t interfaceStatus) String() string { 144 ss := make([]string, 0, 3) 145 if t&interfaceActive > 0 { 146 ss = append(ss, "Active") 147 } 148 if t&interfaceSub > 0 { 149 ss = append(ss, "Sub") 150 } 151 if t&interfaceLinkDetection > 0 { 152 ss = append(ss, "LinkDetection") 153 } 154 if t&interfaceVrfLoopback > 0 { 155 ss = append(ss, "VrfLoopback") 156 } 157 return strings.Join(ss, "|") 158 } 159 160 // Interface Connected Address Flags 161 type interfaceAddressFlag uint8 162 163 const ( 164 interfaceAddressSecondary interfaceAddressFlag = 0x01 165 interfaceAddressPeer interfaceAddressFlag = 0x02 166 interfaceAddressUnnumbered interfaceAddressFlag = 0x04 167 ) 168 169 func (t interfaceAddressFlag) String() string { 170 ss := make([]string, 0, 3) 171 if t&interfaceAddressSecondary > 0 { 172 ss = append(ss, "SECONDARY") 173 } 174 if t&interfaceAddressPeer > 0 { 175 ss = append(ss, "PEER") 176 } 177 if t&interfaceAddressUnnumbered > 0 { 178 ss = append(ss, "UNNUMBERED") 179 } 180 return strings.Join(ss, "|") 181 } 182 183 // Address Family IDentifier. 184 // 185 //go:generate stringer -type=afi 186 type afi uint8 187 188 const ( 189 afiIP afi = 1 190 afiIP6 afi = 2 191 afiEther afi = 3 192 afiMax afi = 4 193 ) 194 195 // Safi is Subsequent Address Family IDentifier. 196 // 197 //go:generate stringer -type=Safi 198 type Safi uint8 199 200 // Safi definition in Zebra of FRRouting 4.x, 5.x, 6.x, 7.x, and 8.x(lib/zebra.h) 201 const ( 202 safiUnspec Safi = iota // added in FRRouting version 7.2 (Zapi 6) 203 SafiUnicast 204 safiMulticast 205 safiMplsVpn 206 safiEncap 207 safiEvpn 208 safiLabeledUnicast 209 safiFlowspec // added in FRRouting version 5 (Zapi 5) 210 safiMax 211 ) 212 213 // Safi definition in Zebra of Quagga and FRRouting 3.x 214 const ( 215 zapi4SafiMplsVpn Safi = iota + safiMulticast + 1 // SafiRESERVED_3 in quagga 216 zapi3SafiMplsVpn // SafiRESERVED_4 in FRRouting 3.x 217 zapi4SafiEncap 218 zapi4SafiEvpn 219 zapi3SafiEncap // SafiMax in FRRouting 3.x 220 ) 221 222 var zapi3SafiMap = map[Safi]Safi{ 223 zapi3SafiMplsVpn: safiMplsVpn, 224 zapi3SafiEncap: safiEncap, 225 } 226 var zapi4SafiMap = map[Safi]Safi{ 227 zapi4SafiMplsVpn: safiMplsVpn, 228 zapi4SafiEncap: safiEncap, 229 zapi4SafiEvpn: safiEvpn, 230 } 231 var safiRouteFamilyIPv4Map = map[Safi]bgp.RouteFamily{ 232 safiUnspec: bgp.RF_OPAQUE, 233 SafiUnicast: bgp.RF_IPv4_UC, 234 safiMulticast: bgp.RF_IPv4_MC, 235 safiMplsVpn: bgp.RF_IPv4_VPN, 236 safiEncap: bgp.RF_IPv4_ENCAP, 237 safiLabeledUnicast: bgp.RF_IPv4_MPLS, 238 safiFlowspec: bgp.RF_FS_IPv4_UC, 239 } 240 var safiRouteFamilyIPv6Map = map[Safi]bgp.RouteFamily{ 241 safiUnspec: bgp.RF_OPAQUE, 242 SafiUnicast: bgp.RF_IPv6_UC, 243 safiMulticast: bgp.RF_IPv6_MC, 244 safiMplsVpn: bgp.RF_IPv6_VPN, 245 safiEncap: bgp.RF_IPv6_ENCAP, 246 safiLabeledUnicast: bgp.RF_IPv6_MPLS, 247 safiFlowspec: bgp.RF_FS_IPv6_UC, 248 } 249 250 // APIType is referred in zclient_test. 251 // 252 //go:generate stringer -type=APIType 253 type APIType uint16 254 255 // For FRRouting version 8.1 (ZAPI version 6) 256 const ( 257 interfaceAdd APIType = iota // 0 // same ID in frr3, 4, 5, 6, 7.0, 7.1. 7.2. 7.3, 7.4, 7.5, 8.0, 8.1, 8.2 258 interfaceDelete // same ID in frr3, 4, 5, 6, 7.0, 7.1. 7.2. 7.3, 7.4, 7.5, 8.0, 8.1, 8.2 259 interfaceAddressAdd // same ID in frr3, 4, 5, 6, 7.0, 7.1. 7.2. 7.3, 7.4, 7.5, 8.0, 8.1, 8.2 260 interfaceAddressDelete // same ID in frr3, 4, 5, 6, 7.0, 7.1. 7.2. 7.3, 7.4, 7.5, 8.0, 8.1, 8.2 261 interfaceUp // same ID in frr3, 4, 5, 6, 7.0, 7.1. 7.2. 7.3, 7.4, 7.5, 8.0, 8.1, 8.2 262 interfaceDown // same ID in frr3, 4, 5, 6, 7.0, 7.1. 7.2. 7.3, 7.4, 7.5, 8.0, 8.1, 8.2 263 _interfaceSetMaster 264 _interfaceSetProtoDown // Add in frr 7.2 265 RouteAdd // RouteAdd is referred in zclient_test 266 RouteDelete // RouteDelete is referred in zclient_test 267 _routeNotifyOwner // 10 268 redistributeAdd 269 _redistributeDelete 270 _redistributeDefaultAdd 271 _redistributeDefaultDelete 272 routerIDAdd 273 _routerIDDelete 274 routerIDUpdate 275 Hello 276 _capabilities // added in frr5 277 nexthopRegister // 20 278 nexthopUnregister 279 nexthopUpdate 280 _interfaceNBRAddressAdd 281 _interfaceNBRAddressDelete 282 _interfaceBFDDestUpdate 283 _importRouteRegister // 25 in frr6, 26 in frr7.x, frr8&8.1, deleted in frr8.2 284 _importRouteUnregister // 26 in frr6, 27 in frr7.x, frr8&8.1, deleted in frr8.2 285 _importCheckUpdate // 27 in frr6, 28 in frr7.x, frr8&8.1, deleted in frr8.2 286 _bfdDestRegister 287 _bfdDestDeregister // 30 288 _bfdDestUpdate 289 _bfdDestReplay 290 RedistributeRouteAdd // 33 // 30 in frr8.2 291 RedistributeRouteDel 292 _vrfUnregister 293 _vrfAdd 294 _vrfDelete 295 vrfLabel // added in frr5 296 _interfaceVRFUpdate 297 _bfdClientRegister // 40 298 _bfdClientDeregister 299 _interfaceEnableRADV 300 _interfaceDisableRADV // 43 // 50 in frr8.2 301 ipv4NexthopLookupMRIB 302 _interfaceLinkParams 303 _mplsLabelsAdd 304 _mplsLabelsDelete 305 _mplsLabelsReplace // added in frr7.3 306 _srPolicySet // added in frr7.5 307 _srPolicyDelete // 50 // added in frr7.5 308 _srPolicyNotifyStatus // added in frr7.5 309 _ipmrRouteStats 310 labelManagerConnect // 53 // 50 in frr8.2 311 labelManagerConnectAsync // added in frr5 312 getLabelChunk 313 releaseLabelChunk 314 _fecRegister 315 _fecUnregister 316 _fecUpdate 317 _advertiseDefaultGW // 60 318 _advertiseSviMACIP // added in frr7.1 319 _advertiseSubnet 320 _advertiseAllVNI // 63 // 60 in frr8.2 321 _localESAdd 322 _localESDel 323 _remoteESVTEPAdd // added in frr7.5 324 _remoteESVTEPDel // added in frr7.5 325 _localESEVIAdd // added in frr7.5 326 _localESEVIDel // added in frr7.5 327 _vniAdd // 70 328 _vniDel 329 _l3VNIAdd 330 _l3VNIDel // 73 // 70 in frr8.2 331 _remoteVTEPAdd 332 _remoteVTEPDel 333 _macIPAdd 334 _macIPDel 335 _ipPrefixRouteAdd 336 _ipPrefixRouteDel 337 _remoteMACIPAdd // 80 338 _remoteMACIPDel 339 _duplicateAddrDetection 340 _pwAdd // 83 // 80 in frr8.2 341 _pwDelete 342 _pwSet 343 _pwUnset 344 _pwStatusUpdate 345 _ruleAdd 346 _ruleDelete 347 _ruleNotifyOwner // 90 348 _tableManagerConnect 349 _getTableChunk 350 _releaseTableChunk // 93 // 90 in frr8.2 351 _ipSetCreate 352 _ipSetDestroy 353 _ipSetEntryAdd 354 _ipSetEntryDelete 355 _ipSetNotifyOwner 356 _ipSetEntryNotifyOwner 357 _ipTableAdd // 100 358 _ipTableDelete 359 _ipTableNotifyOwner 360 _vxlanFloodControl // 103 // 100 in frr8.2 361 _vxlanSgAdd 362 _vxlanSgDel 363 _vxlanSgReplay 364 _mlagProcessUp // added in frr7.3 365 _mlagProcessDown // added in frr7.3 366 _mlagClientRegister // added in frr7.3 367 _mlagClientUnregister // 110 // added in frr7.3 368 _mlagClientForwardMsg // added in frr7.3 369 _nhgAdd // added in frr8 370 _nhgDel // 113 // 110 in frr8.2 // added in frr8 371 _nhgNotifyOwner // added in frr8 372 _nhgEvpnRemoteNhAdd // added in frr8 373 _nhgEvpnRemoteNhDel // added in frr8 374 _srv6LocatorAdd // added in frr8.1 375 _srv6LocatorDelete // added in frr8.1 376 _srv6ManagerGetLocatorChunk // added in frr8.1 377 _srv6ManagerReleaseLocatorChunk // 120 //added in frr8.1 378 zebraError // added in frr7.3 379 _clientCapabilities // added in frr7.4 380 _opaqueMessage // 123 // 120 in frr8.2 // added in frr7.5 381 _opaqueRegister // added in frr7.5 382 _opaqueUnregister // added in frr7.5 383 _neighDiscover // added in frr7.5 384 _RouteNotifyRequest // added in frr8 385 _ClientCloseNotify // added in frr8 386 _NhrpNeighAdded // added in frr8 387 _NhrpNeighRemoved // 130 // added in frr8 388 _NhrpNeighGet // added in frr8 389 _NhrpNeighRegister // added in frr8 390 _NhrpNeighUnregister // 133// 130 in frr8.2 // added in frr8 391 _NeighIPAdd // added in frr8 392 _NeighIPDel // added in frr8 393 _ConfigureArp // added in frr8 394 _GreGet // added in frr8 395 _GreUpdate // added in frr8 396 _GreSourceSet // added in frr8 397 // BackwardIPv6RouteAdd is referred in zclient_test 398 BackwardIPv6RouteAdd // quagga, frr3, frr4, frr5 399 // BackwardIPv6RouteDelete is referred in zclient_test 400 BackwardIPv6RouteDelete // quagga, frr3, frr4, frr5 401 ) 402 403 // Difference default version (frr8.1) and older version 404 const ( 405 zapi6Frr8dot2MinDifferentAPIType APIType = 26 //frr8.2(zapi6) 406 zapi6Frr7dot3MinDifferentAPIType APIType = 49 //frr7.3(zapi6) 407 zapi6Frr7dot2MinDifferentAPIType APIType = 48 //frr7.2(zapi6) 408 zapi6Frr6MinDifferentAPIType APIType = 7 //frr6&7.0&7.1(zapi6) 409 zapi5ClMinDifferentAPIType APIType = 19 //cumuluslinux3.7.7, zebra4.0+cl3u13(zapi5) 410 zapi5MinDifferentAPIType APIType = 7 //frr4&5(zapi5), frr6&7.0&7.1(zapi6) 411 zapi4MinDifferentAPIType APIType = 6 412 zapi3MinDifferentAPIType APIType = 0 413 ) 414 415 func minDifferentAPIType(version uint8, software Software) APIType { 416 if version < 4 { 417 return zapi3MinDifferentAPIType 418 } else if version == 4 { 419 return zapi4MinDifferentAPIType 420 } else if version == 5 && software.name == "cumulus" { 421 return zapi5ClMinDifferentAPIType 422 } else if version == 5 || 423 (version == 6 && software.name == "frr" && software.version < 7.2) { 424 return zapi5MinDifferentAPIType 425 } else if version == 6 && software.name == "frr" && software.version == 7.2 { 426 return zapi6Frr7dot2MinDifferentAPIType 427 } else if version == 6 && software.name == "frr" && software.version < 7.5 { 428 return zapi6Frr7dot3MinDifferentAPIType 429 } 430 return zapi6Frr8dot2MinDifferentAPIType 431 } 432 433 const ( 434 zapi6Frr8dot2RedistributeRouteAdd APIType = 30 435 zapi6Frr8dot2RedistributeRouteDel APIType = 31 436 zapi6Frr8dot2VrfLabel APIType = 35 437 zapi6Frr8dot2Ipv4NexthopLookupMRIB APIType = 41 438 zapi6Frr8dot2LabelManagerConnect APIType = 50 439 zapi6Frr8dot2LabelManagerConnectAsync APIType = 51 440 zapi6Frr8dot2GetLabelChunk APIType = 52 441 zapi6Frr8dot2ReleaseLabelChunk APIType = 53 442 ) 443 444 var apiTypeZapi6Frr8dot2Map = map[APIType]APIType{ // frr8.2 445 RedistributeRouteAdd: zapi6Frr8dot2RedistributeRouteAdd, 446 RedistributeRouteDel: zapi6Frr8dot2RedistributeRouteDel, 447 vrfLabel: zapi6Frr8dot2VrfLabel, 448 ipv4NexthopLookupMRIB: zapi6Frr8dot2Ipv4NexthopLookupMRIB, 449 labelManagerConnect: zapi6Frr8dot2LabelManagerConnect, 450 labelManagerConnectAsync: zapi6Frr8dot2LabelManagerConnectAsync, 451 getLabelChunk: zapi6Frr8dot2GetLabelChunk, 452 releaseLabelChunk: zapi6Frr8dot2ReleaseLabelChunk, 453 } 454 455 const ( 456 zapi6Frr7dot3LabelManagerConnect APIType = 50 // difference from frr8.1 457 zapi6Frr7dot3LabelManagerConnectAsync APIType = 51 // difference from frr8.1 458 zapi6Frr7dot3GetLabelChunk APIType = 52 // difference from frr8.1 459 zapi6Frr7dot3ReleaseLabelChunk APIType = 53 // difference from frr8.1 460 ) 461 462 var apiTypeZapi6Frr7dot3Map = map[APIType]APIType{ 463 labelManagerConnect: zapi6Frr7dot3LabelManagerConnect, 464 labelManagerConnectAsync: zapi6Frr7dot3LabelManagerConnectAsync, 465 getLabelChunk: zapi6Frr7dot3GetLabelChunk, 466 releaseLabelChunk: zapi6Frr7dot3ReleaseLabelChunk, 467 } 468 469 const ( 470 zapi6Frr7dot2LabelManagerConnect APIType = 49 // difference from frr8.1 471 zapi6Frr7dot2LabelManagerConnectAsync APIType = 50 // difference from frr8.1 472 zapi6Frr7dot2GetLabelChunk APIType = 51 // difference from frr8.1 473 zapi6Frr7dot2ReleaseLabelChunk APIType = 52 // difference from frr8.1 474 ) 475 476 var apiTypeZapi6Frr7dot2Map = map[APIType]APIType{ 477 labelManagerConnect: zapi6Frr7dot2LabelManagerConnect, 478 labelManagerConnectAsync: zapi6Frr7dot2LabelManagerConnectAsync, 479 getLabelChunk: zapi6Frr7dot2GetLabelChunk, 480 releaseLabelChunk: zapi6Frr7dot2ReleaseLabelChunk, 481 } 482 483 const ( // frr7.0, 7.1 484 zapi6Frr7RouteAdd APIType = 7 485 zapi6Frr7RouteDelete APIType = 8 486 zapi6Frr7RedistributAdd APIType = 10 487 zapi6Frr7RouterIDAdd APIType = 14 488 zapi6Frr7RouterIDUpdate APIType = 16 489 zapi6Frr7Hello APIType = 17 490 zapi6Frr7NexthopRegister APIType = 19 491 zapi6Frr7NexthopUnregister APIType = 20 492 zapi6Frr7NexthopUpdate APIType = 21 493 zapi6Frr7RedistributeRouteAdd APIType = 32 494 zapi6Frr7RedistributeRouteDel APIType = 33 495 zapi6Frr7VrfLabel APIType = 37 496 zapi6Frr7Ipv4NexthopLookupMRIB APIType = 43 497 zapi6Frr7LabelManagerConnect APIType = 48 498 zapi6Frr7LabelManagerConnectAsync APIType = 49 499 zapi6Frr7GetLabelChunk APIType = 50 500 zapi6Frr7ReleaseLabelChunk APIType = 51 501 ) 502 503 var apiTypeZapi6Frr7Map = map[APIType]APIType{ // frr7.0, 7.1 504 RouteAdd: zapi6Frr7RouteAdd, 505 RouteDelete: zapi6Frr7RouteDelete, 506 redistributeAdd: zapi6Frr7RedistributAdd, 507 routerIDAdd: zapi6Frr7RouterIDAdd, 508 routerIDUpdate: zapi6Frr7RouterIDUpdate, 509 Hello: zapi6Frr7Hello, 510 nexthopRegister: zapi6Frr7NexthopRegister, 511 nexthopUnregister: zapi6Frr7NexthopUnregister, 512 nexthopUpdate: zapi6Frr7NexthopUpdate, 513 RedistributeRouteAdd: zapi6Frr7RedistributeRouteAdd, 514 RedistributeRouteDel: zapi6Frr7RedistributeRouteDel, 515 vrfLabel: zapi6Frr7VrfLabel, 516 ipv4NexthopLookupMRIB: zapi6Frr7Ipv4NexthopLookupMRIB, 517 labelManagerConnect: zapi6Frr7LabelManagerConnect, 518 labelManagerConnectAsync: zapi6Frr7LabelManagerConnectAsync, 519 getLabelChunk: zapi6Frr7GetLabelChunk, 520 releaseLabelChunk: zapi6Frr7ReleaseLabelChunk, 521 } 522 523 var apiTypeZapi6Frr6Map = map[APIType]APIType{ 524 RouteAdd: zapi6Frr7RouteAdd, // same as frr7.0&7.1 525 RouteDelete: zapi6Frr7RouteDelete, // same as frr7.0&7.1 526 redistributeAdd: zapi6Frr7RedistributAdd, // same as frr7.0&7.1 527 routerIDAdd: zapi6Frr7RouterIDAdd, // same as frr7.0&7.1 528 routerIDUpdate: zapi6Frr7RouterIDUpdate, // same as frr7.0&7.1 529 Hello: zapi6Frr7Hello, // same as frr7.0&7.1 530 nexthopRegister: zapi6Frr7NexthopRegister, // same as frr7.0&7.1 531 nexthopUnregister: zapi6Frr7NexthopUnregister, // same as frr7.0&7.1 532 nexthopUpdate: zapi6Frr7NexthopUpdate, // same as frr7.0&7.1 533 RedistributeRouteAdd: RedistributeRouteAdd, // same as frr7.2&7.3 534 RedistributeRouteDel: RedistributeRouteDel, // same as frr7.2&7.3 535 vrfLabel: vrfLabel, // same as frr7.2&7.3 536 ipv4NexthopLookupMRIB: ipv4NexthopLookupMRIB, // same as frr7.2&7.3 537 labelManagerConnect: zapi6Frr7dot2LabelManagerConnect, // same as frr7.2 538 labelManagerConnectAsync: zapi6Frr7dot2LabelManagerConnectAsync, // same as frr7.2 539 getLabelChunk: zapi6Frr7dot2GetLabelChunk, // same as frr7.2 540 releaseLabelChunk: zapi6Frr7dot2ReleaseLabelChunk, // same as frr7.2 541 } 542 543 const ( // For Cumulus Linux 3.7.7, zebra 4.0+cl3u13 (ZAPI version 5) 544 zapi5ClIpv4NexthopLookupMRIB APIType = 42 545 zapi5ClLabelManagerConnect APIType = 47 546 zapi5ClGetLabelChunk APIType = 48 547 zapi5ClReleaseLabelChunk APIType = 49 548 ) 549 550 var apiTypeZapi5ClMap = map[APIType]APIType{ 551 nexthopRegister: zapi6Frr7NexthopRegister, // same as frr7.0&7.1 552 nexthopUnregister: zapi6Frr7NexthopUnregister, // same as frr7.0&7.1 553 nexthopUpdate: zapi6Frr7NexthopUpdate, // same as frr7.0&7.1 554 RedistributeRouteAdd: zapi6Frr7RedistributeRouteAdd, // same as frr7.0&7.1 555 RedistributeRouteDel: zapi6Frr7RedistributeRouteDel, // same as frr7.0&7.1 556 vrfLabel: zapi6Frr7VrfLabel, // same as frr7.0&7.1 557 labelManagerConnect: zapi5ClLabelManagerConnect, 558 getLabelChunk: zapi5ClGetLabelChunk, 559 releaseLabelChunk: zapi5ClReleaseLabelChunk, 560 } 561 562 const ( 563 zapi5RedistributAdd APIType = 14 564 zapi5RouterIDAdd APIType = 18 565 zapi5RouterIDUpdate APIType = 20 566 zapi5Hello APIType = 21 567 zapi5Frr5NexthopRegister APIType = 23 568 zapi5Frr5NexthopUnregister APIType = 24 569 zapi5Frr5NexthopUpdate APIType = 25 570 zapi5Frr5RedistributeRouteAdd APIType = 37 571 zapi5Frr5RedistributeRouteDel APIType = 38 572 zapi5Frr5VrfLabel APIType = 42 573 zapi5Frr5Ipv4NexthopLookupMRIB APIType = 47 574 zapi5Frr5LabelManagerConnect APIType = 52 575 zapi5Frr5LabelManagerConnectAsync APIType = 53 576 zapi5Frr5GetLabelChunk APIType = 54 577 zapi5Frr5ReleaseLabelChunk APIType = 55 578 ) 579 580 var apiTypeZapi5Frr5Map = map[APIType]APIType{ 581 RouteAdd: zapi6Frr7RouteAdd, // same as frr7.0&7.1 582 RouteDelete: zapi6Frr7RouteDelete, // same as frr7.0&7.1 583 redistributeAdd: zapi5RedistributAdd, 584 routerIDAdd: zapi5RouterIDAdd, 585 routerIDUpdate: zapi5RouterIDUpdate, 586 Hello: zapi5Hello, 587 nexthopRegister: zapi5Frr5NexthopRegister, 588 nexthopUnregister: zapi5Frr5NexthopUnregister, 589 nexthopUpdate: zapi5Frr5NexthopUpdate, 590 RedistributeRouteAdd: zapi5Frr5RedistributeRouteAdd, 591 RedistributeRouteDel: zapi5Frr5RedistributeRouteDel, 592 vrfLabel: zapi5Frr5VrfLabel, 593 ipv4NexthopLookupMRIB: zapi5Frr5Ipv4NexthopLookupMRIB, 594 labelManagerConnect: zapi5Frr5LabelManagerConnect, 595 labelManagerConnectAsync: zapi5Frr5LabelManagerConnectAsync, 596 getLabelChunk: zapi5Frr5GetLabelChunk, 597 releaseLabelChunk: zapi5Frr5ReleaseLabelChunk, 598 } 599 600 const ( 601 zapi5Frr4NexthopRegister APIType = 22 602 zapi5Frr4NexthopUnregister APIType = 23 603 zapi5Frr4NexthopUpdate APIType = 24 604 zapi5Frr4RedistributeRouteAdd APIType = 36 605 zapi5Frr4RedistributeRouteDel APIType = 37 606 zapi5Frr4Ipv4NexthopLookupMRIB APIType = 45 607 zapi5Frr4LabelManagerConnect APIType = 50 608 zapi5Frr4GetLabelChunk APIType = 51 609 zapi5Frr4ReleaseLabelChunk APIType = 52 610 ) 611 612 var apiTypeZapi5Frr4Map = map[APIType]APIType{ 613 RouteAdd: zapi6Frr7RouteAdd, // same as frr7.0&7.1 614 RouteDelete: zapi6Frr7RouteDelete, // same as frr7.0&7.1 615 redistributeAdd: zapi5RedistributAdd, 616 routerIDAdd: zapi5RouterIDAdd, 617 routerIDUpdate: zapi5RouterIDUpdate, 618 Hello: zapi5Hello, 619 nexthopRegister: zapi5Frr4NexthopRegister, 620 nexthopUnregister: zapi5Frr4NexthopUnregister, 621 nexthopUpdate: zapi5Frr4NexthopUpdate, 622 RedistributeRouteAdd: zapi5Frr4RedistributeRouteAdd, 623 RedistributeRouteDel: zapi5Frr4RedistributeRouteDel, 624 ipv4NexthopLookupMRIB: zapi5Frr4Ipv4NexthopLookupMRIB, 625 labelManagerConnect: zapi5Frr4LabelManagerConnect, 626 getLabelChunk: zapi5Frr4GetLabelChunk, 627 releaseLabelChunk: zapi5Frr4ReleaseLabelChunk, 628 } 629 630 const ( 631 zapi4IPv4RouteAdd APIType = 6 // deleted in zapi6 632 zapi4IPv4RouteDelete APIType = 7 // deleted in zapi6 633 zapi4IPv6RouteAdd APIType = 8 // deleted in zapi6 634 zapi4IPv6RouteDelete APIType = 9 // deleted in zapi6 635 zapi4RedistributAdd APIType = 10 636 zapi4RouterIDAdd APIType = 14 637 zapi4RouterIDUpdate APIType = 16 638 zapi4Hello APIType = 17 639 zapi4NexthopRegister APIType = 18 640 zapi4NexthopUnregister APIType = 19 641 zapi4NexthopUpdate APIType = 20 642 zapi4RedistributeIPv4Add APIType = 32 // deleted in zapi6 643 zapi4RedistributeIPv4Del APIType = 33 // deleted in zapi6 644 zapi4RedistributeIPv6Add APIType = 34 // deleted in zapi6 645 zapi4RedistributeIPv6Del APIType = 35 // deleted in zapi6 646 zapi4LabelManagerConnect APIType = 52 647 zapi4GetLabelChunk APIType = 53 648 zapi4ReleaseLabelChunk APIType = 54 649 ) 650 651 var apiTypeZapi4Map = map[APIType]APIType{ 652 RouteAdd: zapi4IPv4RouteAdd, // deleted in zapi5 653 RouteDelete: zapi4IPv4RouteDelete, // deleted in zapi5 654 redistributeAdd: zapi4RedistributAdd, 655 routerIDAdd: zapi4RouterIDAdd, 656 routerIDUpdate: zapi4RouterIDUpdate, 657 Hello: zapi4Hello, 658 nexthopRegister: zapi4NexthopRegister, 659 nexthopUnregister: zapi4NexthopUnregister, 660 nexthopUpdate: zapi4NexthopUpdate, 661 RedistributeRouteAdd: zapi4RedistributeIPv4Add, // deleted in zapi5 662 RedistributeRouteDel: zapi4RedistributeIPv4Del, // deleted in zapi5 663 ipv4NexthopLookupMRIB: zapi6Frr7Ipv4NexthopLookupMRIB, // same as frr7.0&7.1 664 labelManagerConnect: zapi4LabelManagerConnect, 665 getLabelChunk: zapi4GetLabelChunk, 666 releaseLabelChunk: zapi4ReleaseLabelChunk, 667 BackwardIPv6RouteAdd: zapi4IPv6RouteAdd, 668 BackwardIPv6RouteDelete: zapi4IPv6RouteDelete, 669 } 670 671 const ( 672 zapi3InterfaceAdd APIType = 1 673 zapi3InterfaceDelete APIType = 2 674 zapi3InterfaceAddressAdd APIType = 3 675 zapi3InterfaceAddressDelete APIType = 4 676 zapi3InterfaceUp APIType = 5 677 zapi3InterfaceDown APIType = 6 678 zapi3IPv4RouteAdd APIType = 7 // deleted in zapi5 679 zapi3IPv4RouteDelete APIType = 8 // deleted in zapi5 680 zapi3IPv6RouteAdd APIType = 9 // deleted in zapi5 681 zapi3IPv6RouteDelete APIType = 10 // deleted in zapi5 682 zapi3RedistributeAdd APIType = 11 683 zapi3IPv4NexthopLookup APIType = 15 // zapi3(quagga) only 684 zapi3IPv6NexthopLookup APIType = 16 // zapi3(quagga) only 685 zapi3IPv4ImportLookup APIType = 17 // zapi3(quagga) only 686 zapi3RouterIDAdd APIType = 20 687 zapi3RouterIDUpdate APIType = 22 688 zapi3Hello APIType = 23 689 zapi3Ipv4NexthopLookupMRIB APIType = 24 690 zapi3NexthopRegister APIType = 27 691 zapi3NexthopUnregister APIType = 28 692 zapi3NexthopUpdate APIType = 29 693 ) 694 695 var apiTypeZapi3Map = map[APIType]APIType{ 696 interfaceAdd: zapi3InterfaceAdd, 697 interfaceDelete: zapi3InterfaceDelete, 698 interfaceAddressAdd: zapi3InterfaceAddressAdd, 699 interfaceAddressDelete: zapi3InterfaceAddressDelete, 700 interfaceUp: zapi3InterfaceUp, 701 interfaceDown: zapi3InterfaceDown, 702 RouteAdd: zapi3IPv4RouteAdd, // deleted in zapi5 703 RouteDelete: zapi3IPv4RouteDelete, // deleted in zapi5 704 redistributeAdd: zapi3RedistributeAdd, 705 routerIDAdd: zapi3RouterIDAdd, 706 routerIDUpdate: zapi3RouterIDUpdate, 707 Hello: zapi3Hello, 708 nexthopRegister: zapi3NexthopRegister, 709 nexthopUnregister: zapi3NexthopUnregister, 710 nexthopUpdate: zapi3NexthopUpdate, 711 BackwardIPv6RouteAdd: zapi3IPv6RouteAdd, 712 BackwardIPv6RouteDelete: zapi3IPv6RouteDelete, 713 } 714 715 func (t APIType) doesNeedConversion(version uint8, software Software) bool { 716 if (version == 6 && software.name == "frr" && 717 software.version >= 7.5 && software.version < 8.2) || 718 t < minDifferentAPIType(version, software) { 719 return false 720 } 721 return true 722 } 723 func apiTypeMap(version uint8, software Software) map[APIType]APIType { 724 if version == 6 && software.name == "frr" && software.version >= 7.3 && software.version < 7.5 { 725 return apiTypeZapi6Frr7dot3Map 726 } else if version == 6 && software.name == "frr" && software.version == 7.2 { 727 return apiTypeZapi6Frr7dot2Map 728 } else if version == 6 && software.name == "frr" && software.version >= 7 && software.version < 7.2 { 729 return apiTypeZapi6Frr7Map 730 } else if version == 6 && software.name == "frr" && software.version >= 6 && software.version < 7 { 731 return apiTypeZapi6Frr6Map 732 } else if version == 5 { 733 if software.name == "frr" && software.version == 4 { 734 return apiTypeZapi5Frr4Map 735 } else if software.name == "cumulus" { 736 return apiTypeZapi5ClMap 737 } 738 return apiTypeZapi5Frr5Map 739 } else if version == 4 { 740 return apiTypeZapi4Map 741 } else if version < 4 { 742 return apiTypeZapi3Map 743 } 744 return apiTypeZapi6Frr8dot2Map 745 } 746 747 // ToEach is referred in zclient_test 748 func (t APIType) ToEach(version uint8, software Software) APIType { 749 if !t.doesNeedConversion(version, software) { 750 return t 751 } 752 apiMap := apiTypeMap(version, software) 753 backward, ok := apiMap[t] 754 if !ok { 755 backward = zebraError // fail to convert and error value 756 } 757 return backward // success to convert 758 } 759 func (t APIType) ToCommon(version uint8, software Software) APIType { 760 if !t.doesNeedConversion(version, software) { 761 return t 762 } 763 apiMap := apiTypeMap(version, software) 764 for common, backward := range apiMap { 765 if backward == t { 766 return common // success to convert 767 } 768 } 769 return zebraError // fail to convert and error value 770 } 771 772 func (t APIType) addressFamily(version uint8) uint8 { 773 if version == 4 { 774 switch t { 775 case zapi4IPv4RouteAdd, zapi4IPv4RouteDelete, zapi4RedistributeIPv4Add, zapi4RedistributeIPv4Del, zapi6Frr7Ipv4NexthopLookupMRIB: 776 return syscall.AF_INET 777 case zapi4IPv6RouteAdd, zapi4IPv6RouteDelete, zapi4RedistributeIPv6Add, zapi4RedistributeIPv6Del: 778 return syscall.AF_INET6 779 } 780 } else if version < 4 { 781 switch t { 782 case zapi3IPv4RouteAdd, zapi3IPv4RouteDelete, zapi3IPv4NexthopLookup, zapi3IPv4ImportLookup, zapi3Ipv4NexthopLookupMRIB: 783 return syscall.AF_INET 784 case zapi3IPv6RouteAdd, zapi3IPv6RouteDelete, zapi3IPv6NexthopLookup: 785 return syscall.AF_INET6 786 } 787 } 788 return syscall.AF_UNSPEC 789 } 790 791 // RouteType is referred in zclient. 792 // 793 //go:generate stringer -type=RouteType 794 type RouteType uint8 795 796 // For FRRouting version 7 (ZAPI version 6). 797 const ( 798 routeSystem RouteType = iota //0 799 routeKernel 800 routeConnect 801 RouteStatic 802 routeRIP 803 routeRIPNG 804 routeOSPF 805 routeOSPF6 806 routeISIS 807 RouteBGP 808 routePIM // 10 809 routeEIGRP // FRRRouting version 4 (Zapi5) adds. 810 routeNHRP 811 routeHSLS 812 routeOLSR 813 routeTABLE 814 routeLDP 815 routeVNC 816 routeVNCDirect 817 routeVNCDirectRH 818 routeBGPDirect 819 routeBGPDirectEXT 820 routeBABEL 821 routeSHARP 822 routePBR // FRRRouting version 5 (Zapi5) adds. 823 routeBFD // FRRRouting version 6 (Zapi6) adds. 824 routeOpenfabric // FRRRouting version 7 (Zapi6) adds. 825 routeVRRP // FRRRouting version 7.2 (Zapi6) adds. 826 routeNHG // FRRRouting version 7.3 (Zapi6) adds. 827 routeSRTE // FRRRouting version 7.5 (Zapi6) adds. 828 routeAll 829 routeMax // max value for error 830 ) 831 const ( 832 zapi5Frr4RouteAll RouteType = 24 833 zapi5Frr5RouteAll RouteType = 25 834 zapi6Frr6RouteAll RouteType = 26 835 zapi6Frr7RouteAll RouteType = 27 836 zapi6Frr7dot2RouteAll RouteType = 28 837 zapi6Frr7dot3RouteAll RouteType = 29 838 ) 839 840 func getRouteAll(version uint8, software Software) RouteType { 841 if version == 5 { 842 if software.name == "frr" && software.version == 4 { 843 return zapi5Frr4RouteAll 844 } 845 return zapi5Frr5RouteAll 846 } else if version == 6 { 847 if software.name == "frr" && software.version == 6 { 848 return zapi6Frr6RouteAll 849 } else if software.name == "frr" && software.version >= 7 && software.version < 7.2 { 850 return zapi6Frr7RouteAll 851 } else if software.name == "frr" && software.version >= 7.2 && software.version < 7.3 { 852 return zapi6Frr7dot2RouteAll 853 } else if software.name == "frr" && software.version >= 7.3 && software.version < 7.5 { 854 return zapi6Frr7dot3RouteAll 855 } 856 } 857 return routeAll 858 } 859 860 // For FRRouting version 3.0 except common route type. 861 const ( 862 zapi4RouteNHRP RouteType = iota + routePIM + 1 863 zapi4RouteHSLS 864 zapi4RouteOLSR 865 zapi4RouteTABLE 866 zapi4RouteLDP 867 zapi4RouteVNC 868 zapi4RouteVNCDirect 869 zapi4RouteVNCDirectRH 870 zapi4RouteBGPDixrect 871 zapi4RouteBGPDirectEXT 872 zapi4RouteAll 873 ) 874 875 var routeTypeZapi4Map = map[RouteType]RouteType{ 876 routeNHRP: zapi4RouteNHRP, 877 routeHSLS: zapi4RouteHSLS, 878 routeOLSR: zapi4RouteOLSR, 879 routeTABLE: zapi4RouteTABLE, 880 routeLDP: zapi4RouteLDP, 881 routeVNC: zapi4RouteVNC, 882 routeVNCDirect: zapi4RouteVNCDirect, 883 routeVNCDirectRH: zapi4RouteVNCDirectRH, 884 routeBGPDirect: zapi4RouteBGPDixrect, 885 routeBGPDirectEXT: zapi4RouteBGPDirectEXT, 886 routeAll: zapi4RouteAll, 887 } 888 889 // For Quagga except common route type. 890 const ( 891 zapi3RouteHSLS RouteType = iota + routePIM + 1 892 zapi3RouteOLSR 893 zapi3RouteBABEL 894 zapi3RouteNHRP // quagga 1.2.4 895 ) 896 897 var routeTypeZapi3Map = map[RouteType]RouteType{ 898 routeHSLS: zapi3RouteHSLS, 899 routeOLSR: zapi3RouteOLSR, 900 routeBABEL: zapi3RouteBABEL, 901 routeNHRP: zapi3RouteNHRP, 902 } 903 904 func (t RouteType) toEach(version uint8) RouteType { 905 if t <= routePIM || version > 4 { // not need to convert 906 return t 907 } 908 routeTypeMap := routeTypeZapi4Map 909 if version < 4 { 910 routeTypeMap = routeTypeZapi3Map 911 } 912 backward, ok := routeTypeMap[t] 913 if ok { 914 return backward // success to convert 915 } 916 return routeMax // fail to convert and error value 917 } 918 919 var routeTypeValueMap = map[string]RouteType{ 920 "system": routeSystem, 921 "kernel": routeKernel, 922 "connect": routeConnect, // hack for backward compatibility 923 "directly-connected": routeConnect, 924 "static": RouteStatic, 925 "rip": routeRIP, 926 "ripng": routeRIPNG, 927 "ospf": routeOSPF, 928 "ospf3": routeOSPF6, 929 "isis": routeISIS, 930 "bgp": RouteBGP, 931 "pim": routePIM, 932 "eigrp": routeEIGRP, // added in frr4(zapi5) 933 "nhrp": routeNHRP, 934 "hsls": routeHSLS, 935 "olsr": routeOLSR, 936 "table": routeTABLE, 937 "ldp": routeLDP, 938 "vnc": routeVNC, 939 "vnc-direct": routeVNCDirect, 940 "vnc-rn": routeVNCDirectRH, 941 "bgp-direct": routeBGPDirect, 942 "bgp-direct-to-nve-groups": routeBGPDirectEXT, 943 "babel": routeBABEL, 944 "sharp": routeSHARP, 945 "pbr": routePBR, 946 "bfd": routeBFD, 947 "openfabric": routeOpenfabric, // added in frr7.0(zapi6) 948 "vrrp": routeVRRP, // added in frr7.2(zapi6) 949 "nhg": routeNHG, // added in frr7.3(zapi6) 950 "srte": routeSRTE, // added in frr7.5(zapi6) 951 "wildcard": routeAll, 952 } 953 954 // RouteTypeFromString converts from string to route type 955 func RouteTypeFromString(typ string, version uint8, software Software) (RouteType, error) { 956 t, ok := routeTypeValueMap[typ] 957 if !ok { // failed to lookup RouteType from string 958 return t, fmt.Errorf("unknown route type: %s in version: %d (%s)", typ, version, software.string()) 959 } 960 t = t.toEach(version) //when lookup failes return routeMax 961 if t > getRouteAll(version, software) { 962 return t, fmt.Errorf("unknown route type: %d in version: %d (%s)", t, version, software.string()) 963 } 964 return t, nil // Success 965 } 966 967 func addressByteLength(family uint8) (int, error) { 968 switch family { 969 case syscall.AF_INET: 970 return net.IPv4len, nil 971 case syscall.AF_INET6: 972 return net.IPv6len, nil 973 } 974 return 0, fmt.Errorf("unknown address family: %d", family) 975 } 976 977 func ipFromFamily(family uint8, buf []byte) net.IP { 978 switch family { 979 case syscall.AF_INET: 980 return net.IP(buf).To4() 981 case syscall.AF_INET6: 982 return net.IP(buf).To16() 983 } 984 return nil 985 } 986 987 // MESSAGE_FLAG is 32bit in frr7.5 and after frr7.5, 8bit in frr 7.4 and before frr7.4 988 // MessageFlag is the type of API Message Flags. 989 type MessageFlag uint32 990 991 const ( // For FRRouting version 4, 5 and 6 (ZAPI version 5 and 6). 992 // MessageNexthop is referred in zclient 993 MessageNexthop MessageFlag = 0x01 994 // MessageDistance is referred in zclient_test 995 MessageDistance MessageFlag = 0x02 996 // MessageMetric is referred in zclient 997 MessageMetric MessageFlag = 0x04 998 messageTag MessageFlag = 0x08 999 // MessageMTU is referred in zclient_test 1000 MessageMTU MessageFlag = 0x10 1001 messageSRCPFX MessageFlag = 0x20 1002 // MessageLabel is referred in zclient 1003 MessageLabel MessageFlag = 0x40 // deleted in frr7.3 1004 messageBackupNexthops MessageFlag = 0x40 // added in frr7.4 1005 messageNhg MessageFlag = 0x80 // added in frr8 1006 messageTableID MessageFlag = 0x100 // frr8: 0x100, frr5&6&7.x: 0x80 1007 messageSRTE MessageFlag = 0x200 // frr8: 0x200, frr7.5: 0x100 1008 messageOpaque MessageFlag = 0x400 // introduced in frr8 1009 ) 1010 1011 const ( // For FRRouting. 1012 messageIFIndex MessageFlag = 0x02 1013 zapi4MessageDistance MessageFlag = 0x04 1014 zapi4MessageMetric MessageFlag = 0x08 1015 zapi4MessageTag MessageFlag = 0x10 1016 zapi4MessageMTU MessageFlag = 0x20 1017 zapi4MessageSRCPFX MessageFlag = 0x40 1018 ) 1019 1020 const ( // For Quagga. 1021 zapi3MessageMTU MessageFlag = 0x10 1022 zapi3MessageTag MessageFlag = 0x20 1023 ) 1024 1025 // ToEach is referred in zclient 1026 func (f MessageFlag) ToEach(version uint8, software Software) MessageFlag { 1027 if version > 4 { //zapi version 5, 6 1028 if f > messageNhg && (version == 5 || 1029 (version == 6 && software.name == "frr" && software.version < 8)) { // except frr8 1030 return f >> 1 1031 } 1032 return f 1033 } 1034 if version < 4 { //zapi version 3, 2 1035 switch f { 1036 case MessageMTU: 1037 return zapi3MessageMTU 1038 case messageTag: 1039 return zapi3MessageTag 1040 } 1041 } 1042 switch f { //zapi version 4 1043 case MessageDistance, MessageMetric, messageTag, MessageMTU, messageSRCPFX: 1044 return f << 1 1045 } 1046 return f 1047 } 1048 func (f MessageFlag) string(version uint8, software Software) string { 1049 var ss []string 1050 if f&MessageNexthop > 0 { 1051 ss = append(ss, "NEXTHOP") 1052 } 1053 if version < 4 && f&messageIFIndex > 0 { 1054 ss = append(ss, "IFINDEX") 1055 } 1056 if f&MessageDistance.ToEach(version, software) > 0 { 1057 ss = append(ss, "DISTANCE") 1058 } 1059 if f&MessageMetric.ToEach(version, software) > 0 { 1060 ss = append(ss, "METRIC") 1061 } 1062 if f&MessageMTU.ToEach(version, software) > 0 { 1063 ss = append(ss, "MTU") 1064 } 1065 if f&messageTag.ToEach(version, software) > 0 { 1066 ss = append(ss, "TAG") 1067 } 1068 if version > 3 && f&messageSRCPFX.ToEach(version, software) > 0 { 1069 ss = append(ss, "SRCPFX") 1070 } 1071 if version == 6 && software.name == "frr" && software.version >= 7.4 && f&messageBackupNexthops > 0 { // added in frr7.4, frr7.5 1072 ss = append(ss, "BACKUP_NEXTHOPS") 1073 } else if version > 4 && f&MessageLabel > 0 { 1074 ss = append(ss, "LABEL") 1075 } 1076 if version > 6 && software.name == "frr" && software.version >= 8 && f&messageNhg > 0 { // added in frr8 1077 ss = append(ss, "NHG") 1078 } 1079 if version > 5 && f&messageTableID > 0 { 1080 ss = append(ss, "TABLEID") 1081 } 1082 if version == 6 && software.name == "frr" && software.version >= 7.5 && f&messageSRTE > 0 { // added in frr7.5 1083 ss = append(ss, "SRTE") 1084 } 1085 if version > 6 && software.name == "frr" && software.version >= 8 && f&messageOpaque > 0 { // added in frr8 1086 ss = append(ss, "OPAQUE") 1087 } 1088 return strings.Join(ss, "|") 1089 } 1090 1091 // Flag is Message Flag which is referred in zclient 1092 type Flag uint64 1093 1094 const ( // For FRRouting version 7 (zebra API version 6), these are defined in lib/zclient.h 1095 // FlagAllowRecursion is referred in zclient, and it is renamed from ZEBRA_FLAG_INTERNAL (https://github.com/FRRouting/frr/commit/4e8b02f4df5d6bcfde6390955b8feda2a17dc9bd) 1096 FlagAllowRecursion Flag = 0x01 // quagga, frr3, frr4, frr5, frr6, frr7 1097 flagSelfRoute Flag = 0x02 // quagga, frr3, frr4, frr5, frr6, frr7 1098 // FlagIBGP is referred in zclient 1099 FlagIBGP Flag = 0x04 1100 // FlagSelected referred in zclient_test 1101 FlagSelected Flag = 0x08 1102 flagFIBOverride Flag = 0x10 1103 flagEvpnRoute Flag = 0x20 1104 flagRRUseDistance Flag = 0x40 1105 flagOnlink Flag = 0x80 // frr7.0 only, this vale is deleted in frr7.1 1106 flagTrapped Flag = 0x80 // added in frr8 1107 flagOffloaded Flag = 0x100 // added in frr8 1108 flagOffloadFailed Flag = 0x200 // added in frr8 1109 ) 1110 1111 // For Quagga (ZAPI v2, v3), FRR v3 (ZAPI v4), FRR v4, v5 (ZAPI v5), FRR v6 (ZAPI v6) for backward compatibility 1112 const ( 1113 flagBlackhole Flag = 0x04 // quagga, frr3 1114 flagStatic Flag = 0x40 // quagga, frr3, frr4, frr5, frr6 1115 flagReject Flag = 0x80 // quagga, frr3 1116 flagScopeLink Flag = 0x100 // frr4, frr5, frr6 1117 ) 1118 1119 // ToEach is referred in zclient 1120 func (f Flag) ToEach(version uint8, software Software) Flag { 1121 if (version == 6 && software.name == "frr" && software.version >= 7) || (f < FlagIBGP) || f > flagRRUseDistance { 1122 return f 1123 } 1124 switch f { 1125 case FlagIBGP, FlagSelected: // 0x04->0x08,0x08->0x10(quagga, frr3,4,5,6) 1126 return f << 1 1127 case flagEvpnRoute, flagRRUseDistance: // 0x20->0x400,0x40->0x800(frr4,5,6) 1128 return f << 5 1129 case flagFIBOverride: 1130 if version < 4 { 1131 return f << 1 // 0x10->0x20(quagga) 1132 } 1133 return f << 5 // 0x10->0x200(frr3, frr4, frr5, frr6) 1134 } 1135 return f 1136 } 1137 1138 // String is referred in zclient 1139 func (f Flag) String(version uint8, software Software) string { 1140 var ss []string 1141 // common flag 1142 if f&FlagAllowRecursion > 0 { 1143 ss = append(ss, "FLAG_ALLOW_RECURSION") 1144 } 1145 if f&flagSelfRoute > 0 { 1146 ss = append(ss, "FLAG_SELFROUTE") 1147 } 1148 if f&FlagIBGP.ToEach(version, software) > 0 { 1149 ss = append(ss, "FLAG_IBGP") 1150 } 1151 if f&FlagSelected.ToEach(version, software) > 0 { 1152 ss = append(ss, "FLAG_SELECTED") 1153 } 1154 if f&flagEvpnRoute.ToEach(version, software) > 0 { 1155 ss = append(ss, "FLAG_EVPN_ROUTE") 1156 } 1157 if f&flagRRUseDistance.ToEach(version, software) > 0 { 1158 ss = append(ss, "FLAG_RR_USE_DISTANCE") 1159 } 1160 if f&flagFIBOverride.ToEach(version, software) > 0 { 1161 ss = append(ss, "FLAG_FIB_OVERRIDE") 1162 } 1163 if version == 6 && software.name == "frr" && software.version >= 7 && f&flagOnlink > 0 { // frr7.0 only 1164 ss = append(ss, "FLAG_ONLINK") 1165 } 1166 if version == 6 && software.name == "frr" && software.version >= 8 && f&flagTrapped > 0 { // added in frr8 1167 ss = append(ss, "FLAG_TRAPPED") 1168 } 1169 if f&flagOffloaded > 0 { // added in frr8 1170 ss = append(ss, "FLAG_OFFLOADED") 1171 } 1172 if f&flagOffloadFailed > 0 { // added in frr8 1173 ss = append(ss, "FLAG_OFFLOADFAILED") 1174 } 1175 if (version < 6 || (version == 6 && software.name == "frr" && software.version < 7)) && f&flagStatic > 0 { 1176 ss = append(ss, "FLAG_STATIC") // quagga, frr3, frr4, frr5, frr6 1177 } 1178 if version < 5 && f&flagBlackhole > 0 { // quagga, frr3 1179 ss = append(ss, "FLAG_BLACKHOLE") 1180 } 1181 if version < 5 && f&flagReject > 0 { // quagga, frr3 1182 ss = append(ss, "FLAG_REJECT") 1183 } 1184 if (version == 5 || (version == 6 && software.name == "frr" && software.version < 7)) && f&flagScopeLink > 0 { 1185 ss = append(ss, "FLAG_SCOPE_LINK") // frr4, frr5, frr6 1186 } 1187 return strings.Join(ss, "|") 1188 } 1189 1190 // Nexthop Types. 1191 // 1192 //go:generate stringer -type=nexthopType 1193 type nexthopType uint8 1194 1195 // For FRRouting. 1196 const ( 1197 _ nexthopType = iota 1198 nexthopTypeIFIndex // 1 1199 nexthopTypeIPv4 // 2 1200 nexthopTypeIPv4IFIndex // 3 1201 nexthopTypeIPv6 // 4 1202 nexthopTypeIPv6IFIndex // 5 1203 nexthopTypeBlackhole // 6 1204 ) 1205 1206 // For Quagga. 1207 const ( 1208 nexthopTypeIFName nexthopType = iota + 2 // 2 1209 backwardNexthopTypeIPv4 // 3 1210 backwardNexthopTypeIPv4IFIndex // 4 1211 nexthopTypeIPv4IFName // 5 1212 backwardNexthopTypeIPv6 // 6 1213 backwardNexthopTypeIPv6IFIndex // 7 1214 nexthopTypeIPv6IFName // 8 1215 backwardNexthopTypeBlackhole // 9 1216 ) 1217 1218 var nexthopTypeMap = map[nexthopType]nexthopType{ 1219 nexthopTypeIPv4: backwardNexthopTypeIPv4, // 2 -> 3 1220 nexthopTypeIPv4IFIndex: backwardNexthopTypeIPv4IFIndex, // 3 -> 4 1221 nexthopTypeIPv6: backwardNexthopTypeIPv6, // 4 -> 6 1222 nexthopTypeIPv6IFIndex: backwardNexthopTypeIPv6IFIndex, // 5 -> 7 1223 nexthopTypeBlackhole: backwardNexthopTypeBlackhole, // 6 -> 9 1224 } 1225 1226 func (t nexthopType) toEach(version uint8) nexthopType { 1227 if version > 3 { // frr 1228 return t 1229 } 1230 if t == nexthopTypeIFIndex || t > nexthopTypeBlackhole { // 1 (common), 7, 8, 9 (out of map range) 1231 return t 1232 } 1233 backward, ok := nexthopTypeMap[t] 1234 if ok { 1235 return backward // converted value 1236 } 1237 return nexthopType(0) // error for conversion 1238 } 1239 1240 func (t nexthopType) ipToIPIFIndex() nexthopType { 1241 // process of nexthopTypeIPv[4|6] is same as nexthopTypeIPv[4|6]IFIndex 1242 // in IPRouteBody of frr7.3 and NexthoUpdate of frr 1243 if t == nexthopTypeIPv4 { 1244 return nexthopTypeIPv4IFIndex 1245 } else if t == nexthopTypeIPv6 { 1246 return nexthopTypeIPv6IFIndex 1247 } 1248 return t 1249 } 1250 func (t nexthopType) ifNameToIFIndex() nexthopType { // quagga 1251 if t == nexthopTypeIFName { 1252 return nexthopTypeIFIndex 1253 } else if t == nexthopTypeIPv4IFName { 1254 return backwardNexthopTypeIPv4IFIndex 1255 } else if t == nexthopTypeIPv6IFName { 1256 return backwardNexthopTypeIPv6IFIndex 1257 } 1258 return t 1259 } 1260 1261 // Nexthop Flags. 1262 // 1263 //go:generate stringer -type=nexthopFlag 1264 type nexthopFlag uint8 1265 1266 const ( 1267 nexthopFlagActive nexthopFlag = 0x01 // This nexthop is alive. 1268 nexthopFlagFIB nexthopFlag = 0x02 // FIB nexthop. 1269 nexthopFlagRecursive nexthopFlag = 0x04 // Recursive nexthop. 1270 nexthopFlagOnlink nexthopFlag = 0x08 // Nexthop should be installed onlink. 1271 nexthopFlagDuplicate nexthopFlag = 0x10 // nexthop duplicates (frr8, 7.5, 7.4) 1272 nexthopFlagRnhFiltered nexthopFlag = 0x20 // nexthop duplicates (frr8, 7.5, 7.4) 1273 nexthopFlagHasBackup nexthopFlag = 0x40 // nexthop duplicates (frr8, 7.5, 7.4) 1274 nexthopFlagSRTE nexthopFlag = 0x80 // nexthop duplicates (frr8, 7.5) 1275 ) 1276 const ( 1277 // Already matched vs a nexthop (frr7.3, 7.2, 7.1, 7, 6, 5, 4, 3) (zapi version >= 4) 1278 zapi6Frr7dot3nexthopFlagMatched nexthopFlag = 0x10 1279 // nexthop duplicates (frr7.3, 7.2, 7.1) 1280 zapi6Frr7dot3nexthopFlagDuplicate nexthopFlag = 0x20 1281 // nexthop duplicates (frr7.3, 7.2, 7.1) 1282 zapi6Frr7dot3nexthopFlagRnhFiltered nexthopFlag = 0x40 1283 ) 1284 const ( 1285 // rmap filtered (frr7, 6, 5, 4, 3)(zapi version >= 4) 1286 zapi6Frr7nexthopFlagFiltered nexthopFlag = 0x20 1287 // nexthop duplicates (frr7, 6, 5, 4)(version >= 5) 1288 zapi6Frr7nexthopFlagDuplicate nexthopFlag = 0x40 1289 // Evpn remote vtep nexthop (frr7, 6, 5, 4)(version >= 5) 1290 zapi6Frr7nexthopFlagEvpnRvtep nexthopFlag = 0x80 1291 ) 1292 1293 // Interface PTM Enable Configuration. 1294 // 1295 //go:generate stringer -type=ptmEnable 1296 type ptmEnable uint8 1297 1298 const ( 1299 ptmEnableOff ptmEnable = 0 1300 ptmEnableOn ptmEnable = 1 1301 ptmEnableUnspec ptmEnable = 2 1302 ) 1303 1304 // PTM Status. 1305 // 1306 //go:generate stringer -type=ptmStatus 1307 type ptmStatus uint8 1308 1309 const ( 1310 ptmStatusDown ptmStatus = 0 1311 ptmStatusUp ptmStatus = 1 1312 ptmStatusUnknown ptmStatus = 2 1313 ) 1314 1315 const ( 1316 defaultZebraSoftwareName string = "frr" 1317 defaultZapi5SoftwareVersion float64 = 5 // FRR software version for Zapi5 1318 defaultZapi6SoftwareVersion float64 = 8.1 // FRR software version for Zapi6 1319 ) 1320 1321 // Software is zebra software (quagga, frr, cumulus) which is referred in zclient 1322 type Software struct { 1323 name string 1324 version float64 1325 } 1326 1327 // string returns combined string with name and version in Software structure 1328 func (software *Software) string() string { 1329 return fmt.Sprintf("%s%f", software.name, software.version) 1330 } 1331 1332 // NewSoftware is constructor of Software strucuture 1333 func NewSoftware(version uint8, softwareName string) Software { 1334 regex := regexp.MustCompile(`([a-z]*)(\d*\.?\d*)`) 1335 regexResult := regex.FindAllStringSubmatch(softwareName, -1) 1336 software := Software{regexResult[0][1], defaultZapi6SoftwareVersion} 1337 var err error 1338 software.version, err = strconv.ParseFloat(regexResult[0][2], 64) 1339 if err != nil || (software.name != "cumulus" && version >= 5) { 1340 software.name = defaultZebraSoftwareName 1341 if version == 5 && software.version < 4 && software.version >= 6 { 1342 software.version = defaultZapi5SoftwareVersion 1343 } else if version == 6 && software.version < 6 { 1344 software.version = defaultZapi6SoftwareVersion 1345 } 1346 } 1347 return software 1348 } 1349 1350 // Client is zebra client which is referred in zclient 1351 type Client struct { 1352 outgoing chan *Message 1353 incoming chan *Message 1354 redistDefault RouteType 1355 conn net.Conn 1356 Version uint8 1357 Software Software 1358 logger log.Logger 1359 } 1360 1361 func ReceiveSingleMsg(logger log.Logger, conn net.Conn, version uint8, software Software, topic string) (*Message, error) { 1362 headerBuf, err := readAll(conn, int(HeaderSize(version))) 1363 if err != nil { 1364 logger.Error("failed to read header", 1365 log.Fields{ 1366 "Topic": topic, 1367 "Error": err}) 1368 return nil, err 1369 } 1370 1371 hd := &Header{} 1372 err = hd.decodeFromBytes(headerBuf) 1373 if version != hd.Version { 1374 logger.Warn(fmt.Sprintf("ZAPI version mismatch. configured version: %d, version of received message:%d", version, hd.Version), 1375 log.Fields{ 1376 "Topic": topic}) 1377 return nil, errors.New("ZAPI version mismatch") 1378 } 1379 if err != nil { 1380 logger.Error("failed to decode header", 1381 log.Fields{ 1382 "Topic": topic, 1383 "Data": headerBuf, 1384 "Error": err}) 1385 return nil, err 1386 } 1387 1388 bodyBuf, err := readAll(conn, int(hd.Len-HeaderSize(version))) 1389 if err != nil { 1390 logger.Error("failed to read body", 1391 log.Fields{ 1392 "Topic": topic, 1393 "Header": hd, 1394 "Error": err}) 1395 return nil, err 1396 } 1397 1398 m, err := parseMessage(hd, bodyBuf, software) 1399 if err != nil { 1400 // Just outputting warnings (not error message) and ignore this 1401 // error considering the case that body parser is not implemented yet. 1402 logger.Warn("failed to decode body", 1403 log.Fields{ 1404 "Topic": topic, 1405 "Header": hd, 1406 "Data": bodyBuf, 1407 "Error": err}) 1408 return nil, nil 1409 } 1410 logger.Debug("read message from zebra", 1411 log.Fields{ 1412 "Topic": topic, 1413 "Message": m}) 1414 1415 return m, nil 1416 } 1417 1418 // NewClient returns a Client instance (Client constructor) 1419 func NewClient(logger log.Logger, network, address string, typ RouteType, version uint8, software Software, mplsLabelRangeSize uint32) (*Client, error) { 1420 conn, err := net.Dial(network, address) 1421 if err != nil { 1422 return nil, err 1423 } 1424 outgoing := make(chan *Message) 1425 incoming := make(chan *Message, 64) 1426 if version < MinZapiVer { 1427 version = MinZapiVer 1428 } else if version > MaxZapiVer { 1429 version = MaxZapiVer 1430 } 1431 c := &Client{ 1432 outgoing: outgoing, 1433 incoming: incoming, 1434 redistDefault: typ, 1435 conn: conn, 1436 Version: version, 1437 Software: software, 1438 logger: logger, 1439 } 1440 1441 go func() { 1442 for { 1443 m, more := <-outgoing 1444 if more { 1445 b, err := m.Serialize(software) 1446 if err != nil { 1447 logger.Warn(fmt.Sprintf("failed to serialize: %v", m), 1448 log.Fields{ 1449 "Topic": "Zebra"}) 1450 continue 1451 } 1452 1453 _, err = conn.Write(b) 1454 if err != nil { 1455 logger.Error("failed to write", 1456 log.Fields{ 1457 "Topic": "Zebra", 1458 "Error": err}) 1459 closeChannel(outgoing) 1460 return 1461 } 1462 } else { 1463 logger.Debug("finish outgoing loop", 1464 log.Fields{"Topic": "Zebra"}) 1465 return 1466 } 1467 } 1468 }() 1469 1470 // Send Hello/RouterIDAdd messages to negotiate the Zebra message version. 1471 c.SendHello() 1472 c.SendRouterIDAdd() 1473 1474 if mplsLabelRangeSize > 0 && c.SupportMpls() { 1475 c.sendLabelManagerConnect(true) 1476 } 1477 1478 // Try to receive the first message from Zebra. 1479 if m, err := ReceiveSingleMsg(logger, conn, version, software, "Zebra"); err != nil { 1480 c.close() 1481 // Return error explicitly in order to retry connection. 1482 return nil, err 1483 } else if m != nil { 1484 incoming <- m 1485 } 1486 1487 // Start receive loop only when the first message successfully received. 1488 go func() { 1489 defer close(incoming) 1490 for { 1491 if m, err := ReceiveSingleMsg(logger, conn, version, software, "Zebra"); err != nil { 1492 return 1493 } else if m != nil { 1494 incoming <- m 1495 } 1496 } 1497 }() 1498 1499 return c, nil 1500 } 1501 1502 func readAll(conn net.Conn, length int) ([]byte, error) { 1503 buf := make([]byte, length) 1504 _, err := io.ReadFull(conn, buf) 1505 return buf, err 1506 } 1507 1508 // Receive return incoming channel message 1509 func (c *Client) Receive() chan *Message { 1510 return c.incoming 1511 } 1512 1513 func (c *Client) send(m *Message) { 1514 defer func() { 1515 if err := recover(); err != nil { 1516 c.logger.Debug("recovered", 1517 log.Fields{ 1518 "Topic": "Zebra", 1519 "Error": err}) 1520 } 1521 }() 1522 c.logger.Debug("send command to zebra", 1523 log.Fields{ 1524 "Topic": "Zebra", 1525 "Header": m.Header, 1526 "Body": m.Body}) 1527 c.outgoing <- m 1528 } 1529 1530 func (c *Client) sendCommand(command APIType, vrfID uint32, body Body) error { 1531 m := &Message{ 1532 Header: Header{ 1533 Len: HeaderSize(c.Version), 1534 Marker: HeaderMarker(c.Version), 1535 Version: c.Version, 1536 VrfID: vrfID, 1537 Command: command.ToEach(c.Version, c.Software), 1538 }, 1539 Body: body, 1540 } 1541 c.send(m) 1542 return nil 1543 } 1544 1545 // SendHello sends HELLO message to zebra daemon. 1546 func (c *Client) SendHello() error { 1547 if c.redistDefault > 0 { 1548 body := &HelloBody{ 1549 redistDefault: c.redistDefault, 1550 instance: 0, 1551 } 1552 return c.sendCommand(Hello, DefaultVrf, body) 1553 } 1554 return nil 1555 } 1556 1557 // SendRouterIDAdd sends ROUTER_ID_ADD message to zebra daemon. 1558 func (c *Client) SendRouterIDAdd() error { 1559 bodies := make([]*routerIDUpdateBody, 0) 1560 for _, afi := range []afi{afiIP, afiIP6} { 1561 bodies = append(bodies, &routerIDUpdateBody{ 1562 afi: afi, 1563 }) 1564 } 1565 for _, body := range bodies { 1566 c.sendCommand(routerIDAdd, DefaultVrf, body) 1567 } 1568 return nil 1569 } 1570 1571 // SendInterfaceAdd sends INTERFACE_ADD message to zebra daemon. 1572 func (c *Client) SendInterfaceAdd() error { 1573 return c.sendCommand(interfaceAdd, DefaultVrf, nil) 1574 } 1575 1576 // SendRedistribute sends REDISTRIBUTE message to zebra daemon. 1577 func (c *Client) SendRedistribute(t RouteType, vrfID uint32) error { 1578 if c.redistDefault != t { 1579 bodies := make([]*redistributeBody, 0) 1580 if c.Version <= 3 { 1581 bodies = append(bodies, &redistributeBody{ 1582 redist: t, 1583 }) 1584 } else { // Version >= 4 1585 for _, afi := range []afi{afiIP, afiIP6} { 1586 bodies = append(bodies, &redistributeBody{ 1587 afi: afi, 1588 redist: t, 1589 instance: 0, 1590 }) 1591 } 1592 } 1593 1594 for _, body := range bodies { 1595 c.sendCommand(redistributeAdd, vrfID, body) 1596 } 1597 } 1598 return nil 1599 } 1600 1601 // SendIPRoute sends ROUTE message to zebra daemon. 1602 func (c *Client) SendIPRoute(vrfID uint32, body *IPRouteBody, isWithdraw bool) error { 1603 routeFamily := body.RouteFamily(c.logger, c.Version, c.Software) 1604 if vrfID == DefaultVrf && (routeFamily == bgp.RF_IPv4_VPN || routeFamily == bgp.RF_IPv6_VPN) { 1605 return fmt.Errorf("RF_IPv4_VPN or RF_IPv6_VPN are not suitable for Default VRF (default forwarding table)") 1606 } 1607 command := RouteAdd 1608 if isWithdraw { 1609 command = RouteDelete 1610 } 1611 if c.Version < 5 && familyFromPrefix(body.Prefix.Prefix) == syscall.AF_INET6 { 1612 command = BackwardIPv6RouteAdd 1613 if isWithdraw { 1614 command = BackwardIPv6RouteDelete 1615 } 1616 } 1617 return c.sendCommand(command, vrfID, body) 1618 } 1619 1620 // SendNexthopRegister sends NEXTHOP_REGISTER message to zebra daemon. 1621 func (c *Client) SendNexthopRegister(vrfID uint32, body *NexthopRegisterBody, isWithdraw bool) error { 1622 // Note: NexthopRegister and NexthopUnregister messages are not 1623 // supported in Zebra protocol version<3. 1624 if c.Version < 3 { 1625 return fmt.Errorf("NexthopRegister/NexthopUnregister are not supported in version: %d", c.Version) 1626 } 1627 command := nexthopRegister 1628 if isWithdraw { 1629 command = nexthopUnregister 1630 } 1631 return c.sendCommand(command, vrfID, body) 1632 } 1633 1634 // SupportMpls is referred in zclient. It returns bool value. 1635 func (c *Client) SupportMpls() bool { 1636 // Note: frr3&4 have LABEL_MANAGER_CONNECT& GET_LABEL_CHUNK. However 1637 // Routes will not be installed via zebra of frr3&4 after call these APIs. 1638 if c.Version < 5 || (c.Software.name == "frr" && c.Software.version == 4) { 1639 return false // if frr4 or earlier are used 1640 } 1641 return true // if frr5 or later are used 1642 } 1643 1644 // Ref: zread_label_manager_connect in zebra/zserv.c of FRR3 (ZAPI4) 1645 // Ref: zread_label_manager_connect in zebra/zapi_msg.c of FRR5&6 (ZAPI5&6) 1646 func (c *Client) sendLabelManagerConnect(async bool) error { 1647 if c.Version < 4 { 1648 return fmt.Errorf("LabelManagerConnect is not supported in zebra API version: %d", c.Version) 1649 } 1650 command := labelManagerConnectAsync 1651 // FRR version 4 (ZAPI version 5) and FRR version 3 (ZAPI version 4) 1652 if !async || c.Version == 4 || (c.Version == 5 && c.Software.name == "frr" && c.Software.version < 5) { 1653 command = labelManagerConnect 1654 } 1655 return c.sendCommand( 1656 command, 0, 1657 &labelManagerConnectBody{ 1658 redistDefault: RouteBGP, 1659 instance: 0, 1660 }) 1661 } 1662 1663 // SendGetLabelChunk sends GET_LABEL_CHUNK message to zebra daemon. 1664 func (c *Client) SendGetLabelChunk(body *GetLabelChunkBody) error { 1665 if c.Version < 4 { 1666 return fmt.Errorf("GetLabelChunk is not supported in version: %d", c.Version) 1667 } 1668 body.instance = 0 1669 body.proto = uint8(RouteBGP) 1670 return c.sendCommand(getLabelChunk, 0, body) 1671 } 1672 1673 // SendVrfLabel sends VRF_LABEL message to zebra daemon. 1674 func (c *Client) SendVrfLabel(label uint32, vrfID uint32) error { 1675 // ZAPIv5 has ZEBRA_VRF_LABEL, however frr4 (ZAPIv5) doesn't have it. 1676 if c.Version < 5 || (c.Version == 5 && c.Software.name == "frr" && c.Software.version < 5) { 1677 return fmt.Errorf("VrfLabel is not supported in zebra API version: %d software: %s", c.Version, c.Software.string()) 1678 } 1679 body := &vrfLabelBody{ 1680 label: label, 1681 afi: afiIP, 1682 labelType: lspBGP, 1683 } 1684 return c.sendCommand(vrfLabel, vrfID, body) 1685 } 1686 1687 // for avoiding double close 1688 func closeChannel(ch chan *Message) bool { 1689 select { 1690 case _, ok := <-ch: 1691 if ok { 1692 close(ch) 1693 return true 1694 } 1695 default: 1696 } 1697 return false 1698 } 1699 1700 func (c *Client) close() error { 1701 closeChannel(c.outgoing) 1702 return c.conn.Close() 1703 } 1704 1705 // SetLabelFlag is referred in zclient, this func sets label flag 1706 func (c Client) SetLabelFlag(msgFlags *MessageFlag, nexthop *Nexthop) { 1707 if c.Version == 6 && c.Software.name == "frr" { 1708 nexthop.flags |= zapiNexthopFlagLabel 1709 } else if c.Version > 4 { 1710 *msgFlags |= MessageLabel 1711 } 1712 } 1713 1714 // Header is header of zebra message. 1715 type Header struct { 1716 Len uint16 1717 Marker uint8 1718 Version uint8 1719 VrfID uint32 // ZAPI v4: 16bits, v5: 32bits 1720 Command APIType 1721 } 1722 1723 func (h *Header) serialize() ([]byte, error) { 1724 buf := make([]byte, HeaderSize(h.Version)) 1725 binary.BigEndian.PutUint16(buf[0:2], h.Len) 1726 buf[2] = h.Marker 1727 buf[3] = h.Version 1728 switch h.Version { 1729 case 2: 1730 binary.BigEndian.PutUint16(buf[4:6], uint16(h.Command)) 1731 case 3, 4: 1732 binary.BigEndian.PutUint16(buf[4:6], uint16(h.VrfID)) 1733 binary.BigEndian.PutUint16(buf[6:8], uint16(h.Command)) 1734 case 5, 6: 1735 binary.BigEndian.PutUint32(buf[4:8], uint32(h.VrfID)) 1736 binary.BigEndian.PutUint16(buf[8:10], uint16(h.Command)) 1737 default: 1738 return nil, fmt.Errorf("unsupported ZAPI version: %d", h.Version) 1739 } 1740 return buf, nil 1741 } 1742 1743 func (h *Header) decodeFromBytes(data []byte) error { 1744 if uint16(len(data)) < 4 { 1745 return fmt.Errorf("not all ZAPI message header") 1746 } 1747 h.Len = binary.BigEndian.Uint16(data[0:2]) 1748 h.Marker = data[2] 1749 h.Version = data[3] 1750 if uint16(len(data)) < HeaderSize(h.Version) { 1751 return fmt.Errorf("not all ZAPI message header") 1752 } 1753 switch h.Version { 1754 case 2: 1755 h.Command = APIType(binary.BigEndian.Uint16(data[4:6])) 1756 case 3, 4: 1757 h.VrfID = uint32(binary.BigEndian.Uint16(data[4:6])) 1758 h.Command = APIType(binary.BigEndian.Uint16(data[6:8])) 1759 case 5, 6: 1760 h.VrfID = binary.BigEndian.Uint32(data[4:8]) 1761 h.Command = APIType(binary.BigEndian.Uint16(data[8:10])) 1762 default: 1763 return fmt.Errorf("unsupported ZAPI version: %d", h.Version) 1764 } 1765 return nil 1766 } 1767 1768 // Body is an interface for zebra messages. 1769 type Body interface { 1770 decodeFromBytes([]byte, uint8, Software) error 1771 serialize(uint8, Software) ([]byte, error) 1772 string(uint8, Software) string 1773 } 1774 1775 type unknownBody struct { 1776 Data []byte 1777 } 1778 1779 func (b *unknownBody) decodeFromBytes(data []byte, version uint8, software Software) error { 1780 b.Data = data 1781 return nil 1782 } 1783 1784 func (b *unknownBody) serialize(version uint8, software Software) ([]byte, error) { 1785 return b.Data, nil 1786 } 1787 1788 func (b *unknownBody) string(version uint8, software Software) string { 1789 return fmt.Sprintf("data: %v", b.Data) 1790 } 1791 1792 type HelloBody struct { 1793 redistDefault RouteType 1794 instance uint16 1795 sessionID uint32 // frr7.4, 7.5, 8, 8.1, 8.2 1796 receiveNotify uint8 1797 synchronous uint8 // frr7.4, 7.5, 8, 8.1, 8.2 1798 } 1799 1800 // Ref: zread_hello in zebra/zserv.c of Quagga1.2&FRR3 (ZAPI3&4) 1801 // Ref: zread_hello in zebra/zapi_msg.c of FRR5&FRR6&FRR7&FRR7.1&FRR7.2&FRR7.3&FRR7.4&FRR7.5&FRR8 (ZAPI5&6) 1802 func (b *HelloBody) decodeFromBytes(data []byte, version uint8, software Software) error { 1803 b.redistDefault = RouteType(data[0]) 1804 if version > 3 { //frr 1805 b.instance = binary.BigEndian.Uint16(data[1:3]) 1806 if version == 6 && software.name == "frr" && software.version >= 7.4 { 1807 b.sessionID = binary.BigEndian.Uint32(data[3:7]) 1808 b.receiveNotify = data[7] 1809 b.synchronous = data[8] 1810 } else if version > 4 { 1811 b.receiveNotify = data[3] 1812 } 1813 } 1814 return nil 1815 } 1816 1817 // Ref: zebra_hello_send in lib/zclient.c of Quagga1.2&FRR3&FRR5&FRR6&FRR7&FRR7.1&FRR7.2&FRR7.3 (ZAPI3&4&5&6) 1818 // Ref: zclient_send_hello in lib/zclient.c of FRR7.4&FRR7.5&FRR8 (ZAPI6) 1819 func (b *HelloBody) serialize(version uint8, software Software) ([]byte, error) { 1820 if version < 4 { 1821 return []byte{uint8(b.redistDefault)}, nil 1822 } 1823 var buf []byte 1824 if version == 6 && software.name == "frr" && software.version >= 7.4 { 1825 buf = make([]byte, 9) 1826 } else if version > 4 { 1827 buf = make([]byte, 4) 1828 } else if version == 4 { 1829 buf = make([]byte, 3) 1830 } 1831 buf[0] = uint8(b.redistDefault) 1832 binary.BigEndian.PutUint16(buf[1:3], b.instance) 1833 if version == 6 && software.name == "frr" && software.version >= 7.4 { 1834 binary.BigEndian.PutUint32(buf[3:7], b.sessionID) 1835 buf[7] = b.receiveNotify 1836 buf[8] = b.synchronous 1837 } else if version > 4 { 1838 buf[3] = b.receiveNotify 1839 } 1840 return buf, nil 1841 } 1842 1843 func (b *HelloBody) string(version uint8, software Software) string { 1844 return fmt.Sprintf( 1845 "route_type: %s, instance :%d, sessionID: %d, receiveNotify: %d, synchronous: %d", 1846 b.redistDefault.String(), b.instance, b.sessionID, b.receiveNotify, b.synchronous) 1847 } 1848 1849 type redistributeBody struct { 1850 afi afi 1851 redist RouteType 1852 instance uint16 1853 } 1854 1855 // Ref: zebra_redistribute_add in zebra/redistribute.c of Quagga1.2&FRR3&FRR4&FRR5&FRR6&FRR7.x&FRR8 (ZAPI3&4&5&6) 1856 func (b *redistributeBody) decodeFromBytes(data []byte, version uint8, software Software) error { 1857 if version < 4 { 1858 b.redist = RouteType(data[0]) 1859 } else { // version >= 4 1860 b.afi = afi(data[0]) 1861 b.redist = RouteType(data[1]) 1862 b.instance = binary.BigEndian.Uint16(data[2:4]) 1863 } 1864 return nil 1865 } 1866 1867 // Ref: zebra_redistribute_send in lib/zclient.c of Quagga1.2&FRR3&FRR4&FRR5&FRR6&FRR7.x&FRR8 (ZAPI3&4&5&6) 1868 func (b *redistributeBody) serialize(version uint8, software Software) ([]byte, error) { 1869 if version < 4 { 1870 return []byte{uint8(b.redist)}, nil 1871 } 1872 buf := make([]byte, 4) 1873 buf[0] = uint8(b.afi) 1874 buf[1] = uint8(b.redist) 1875 binary.BigEndian.PutUint16(buf[2:4], b.instance) 1876 return buf, nil 1877 } 1878 1879 func (b *redistributeBody) string(version uint8, software Software) string { 1880 return fmt.Sprintf( 1881 "afi: %s, route_type: %s, instance :%d", 1882 b.afi.String(), b.redist.String(), b.instance) 1883 } 1884 1885 type linkParam struct { 1886 status uint32 1887 teMetric uint32 1888 maxBw float32 1889 maxRsvBw float32 1890 unrsvBw [8]float32 1891 bwClassNum uint32 1892 adminGroup uint32 1893 remoteAS uint32 1894 remoteIP net.IP 1895 aveDelay uint32 1896 minDelay uint32 1897 maxDelay uint32 1898 delayVar uint32 1899 pktLoss float32 1900 residualBw float32 1901 availableBw float32 1902 useBw float32 1903 } 1904 1905 type interfaceUpdateBody struct { 1906 name string 1907 index uint32 1908 status interfaceStatus 1909 flags uint64 1910 ptmEnable ptmEnable 1911 ptmStatus ptmStatus 1912 metric uint32 1913 speed uint32 1914 mtu uint32 1915 mtu6 uint32 1916 bandwidth uint32 1917 linkIfindex uint32 1918 linktype linkType 1919 hardwareAddr net.HardwareAddr 1920 linkParam linkParam 1921 } 1922 1923 // Ref: zebra_interface_if_set_value in lib/zclient.c of Quagga1.2&FRR3&FRR4&FRR5&FRR6&FRR7.x&FRR8 (ZAPI3&4&5&6) 1924 func (b *interfaceUpdateBody) decodeFromBytes(data []byte, version uint8, software Software) error { 1925 ifNameSize := interfaceNameSize 1926 if version == 6 && software.name == "frr" && software.version >= 8.3 { 1927 ifNameSize = osIfNameSize 1928 } 1929 // version 2: index(4)+status(1)+flags(8)+metric(4)+mtu(4)+mtu6(4)+bandwidth(4)+hw_addr_len(4) 1930 necessaryDataSize := ifNameSize + 33 1931 if version > 3 { 1932 necessaryDataSize += 6 // add ptmEnable(1)+ptmStatus(1)+speed(4) 1933 } 1934 if version > 2 { 1935 necessaryDataSize += 4 // add linktype(4) 1936 } 1937 if version == 6 && software.name == "frr" && software.version >= 7.2 { 1938 necessaryDataSize += 4 // add linkIfIndex(4) 1939 } 1940 if len(data) < necessaryDataSize { 1941 return fmt.Errorf("lack of bytes. need %d but %d", necessaryDataSize, len(data)) 1942 } 1943 1944 b.name = strings.Trim(string(data[:ifNameSize]), "\u0000") 1945 data = data[ifNameSize:] 1946 b.index = binary.BigEndian.Uint32(data[0:4]) 1947 b.status = interfaceStatus(data[4]) 1948 b.flags = binary.BigEndian.Uint64(data[5:13]) 1949 if version > 3 { 1950 b.ptmEnable = ptmEnable(data[13]) 1951 b.ptmStatus = ptmStatus(data[14]) 1952 b.metric = binary.BigEndian.Uint32(data[15:19]) 1953 b.speed = binary.BigEndian.Uint32(data[19:23]) 1954 data = data[23:] 1955 } else { 1956 b.metric = binary.BigEndian.Uint32(data[13:17]) 1957 data = data[17:] 1958 } 1959 b.mtu = binary.BigEndian.Uint32(data[0:4]) 1960 b.mtu6 = binary.BigEndian.Uint32(data[4:8]) 1961 b.bandwidth = binary.BigEndian.Uint32(data[8:12]) 1962 data = data[12:] 1963 1964 //frr 7.2 and later versions have link Ifindex 1965 if version == 6 && software.name == "frr" && software.version >= 7.2 { 1966 b.linkIfindex = binary.BigEndian.Uint32(data[:4]) 1967 data = data[4:] 1968 } 1969 if version > 2 { 1970 b.linktype = linkType(binary.BigEndian.Uint32(data[:4])) 1971 data = data[4:] 1972 } 1973 l := binary.BigEndian.Uint32(data[:4]) // STREAM_GETL(s, ifp->hw_addr_len) 1974 if l > 0 { 1975 if len(data) < 4+int(l) { 1976 return fmt.Errorf("lack of bytes in remain data. need %d but %d", 4+l, len(data)) 1977 } 1978 b.hardwareAddr = data[4 : 4+l] // STREAM_GET(ifp->hw_addr, s, MIN(ifp->hw_addr_len, INTERFACE_HWADDR_MAX)); 1979 } 1980 if version > 2 { 1981 linkParam := data[4+l] // stream_getc(s) 1982 if linkParam > 0 { // link_params_set_value 1983 data = data[5+l:] 1984 b.linkParam.status = binary.BigEndian.Uint32(data[0:4]) 1985 b.linkParam.teMetric = binary.BigEndian.Uint32(data[4:8]) 1986 b.linkParam.maxBw = math.Float32frombits(binary.BigEndian.Uint32(data[8:12])) 1987 b.linkParam.maxRsvBw = math.Float32frombits(binary.BigEndian.Uint32(data[12:16])) 1988 b.linkParam.bwClassNum = binary.BigEndian.Uint32(data[16:20]) 1989 for i := uint32(0); i < b.linkParam.bwClassNum; i++ { 1990 b.linkParam.unrsvBw[i] = math.Float32frombits(binary.BigEndian.Uint32(data[20+i*4 : 24+i*4])) 1991 } 1992 data = data[20+b.linkParam.bwClassNum*4:] 1993 b.linkParam.adminGroup = binary.BigEndian.Uint32(data[0:4]) 1994 b.linkParam.remoteAS = binary.BigEndian.Uint32(data[4:8]) 1995 b.linkParam.remoteIP = data[8:12] 1996 b.linkParam.aveDelay = binary.BigEndian.Uint32(data[12:16]) 1997 b.linkParam.minDelay = binary.BigEndian.Uint32(data[16:20]) 1998 b.linkParam.maxDelay = binary.BigEndian.Uint32(data[20:24]) 1999 b.linkParam.delayVar = binary.BigEndian.Uint32(data[24:28]) 2000 b.linkParam.pktLoss = math.Float32frombits(binary.BigEndian.Uint32(data[28:32])) 2001 b.linkParam.residualBw = math.Float32frombits(binary.BigEndian.Uint32(data[32:36])) 2002 b.linkParam.availableBw = math.Float32frombits(binary.BigEndian.Uint32(data[36:40])) 2003 b.linkParam.useBw = math.Float32frombits(binary.BigEndian.Uint32(data[40:44])) 2004 } 2005 } 2006 return nil 2007 } 2008 2009 func (b *interfaceUpdateBody) serialize(version uint8, software Software) ([]byte, error) { 2010 return []byte{}, nil 2011 } 2012 2013 func (b *interfaceUpdateBody) string(version uint8, software Software) string { 2014 s := fmt.Sprintf( 2015 "name: %s, idx: %d, status: %s, flags: %s, ptm_enable: %s, ptm_status: %s, metric: %d, speed: %d, mtu: %d, mtu6: %d, bandwidth: %d, linktype: %s", 2016 b.name, b.index, b.status.String(), intfflag2string(b.flags), b.ptmEnable.String(), b.ptmStatus.String(), b.metric, b.speed, b.mtu, b.mtu6, b.bandwidth, b.linktype.String()) 2017 if len(b.hardwareAddr) > 0 { 2018 return s + fmt.Sprintf(", mac: %s", b.hardwareAddr.String()) 2019 } 2020 return s 2021 } 2022 2023 type interfaceAddressUpdateBody struct { 2024 index uint32 2025 flags interfaceAddressFlag 2026 prefix net.IP 2027 length uint8 2028 destination net.IP 2029 } 2030 2031 // Ref: zebra_interface_address_read in lib/zclient.c of Quagga1.2&FRR3&FRR4&FRR5&FRR6&FRR7.x&FRR8 (ZAPI3&4&5&6) 2032 func (b *interfaceAddressUpdateBody) decodeFromBytes(data []byte, version uint8, software Software) error { 2033 b.index = binary.BigEndian.Uint32(data[:4]) //STREAM_GETL(s, ifindex) 2034 b.flags = interfaceAddressFlag(data[4]) //STREAM_GETC(s, ifc_flags) 2035 family := data[5] //STREAM_GETC(s, d.family) 2036 addrlen, err := addressByteLength(family) 2037 if err != nil { 2038 return err 2039 } 2040 b.prefix = data[6 : 6+addrlen] //zclient_stream_get_prefix //STREAM_GET(&p->u.prefix, s, plen); 2041 b.length = data[6+addrlen] //zclient_stream_get_prefix //STREAM_GETC(s, c); 2042 b.destination = data[7+addrlen : 7+addrlen*2] //STREAM_GET(&d.u.prefix, s, plen) 2043 return nil 2044 } 2045 2046 func (b *interfaceAddressUpdateBody) serialize(version uint8, software Software) ([]byte, error) { 2047 return []byte{}, nil 2048 } 2049 2050 func (b *interfaceAddressUpdateBody) string(version uint8, software Software) string { 2051 return fmt.Sprintf( 2052 "idx: %d, flags: %s, addr: %s/%d", 2053 b.index, b.flags.String(), b.prefix.String(), b.length) 2054 } 2055 2056 type routerIDUpdateBody struct { 2057 length uint8 2058 prefix net.IP 2059 afi afi 2060 } 2061 2062 // Ref: zebra_router_id_update_read in lib/zclient.c of Quagga1.2&FRR3&FRR5 (ZAPI3&4&5) 2063 func (b *routerIDUpdateBody) decodeFromBytes(data []byte, version uint8, software Software) error { 2064 family := data[0] 2065 2066 addrlen, err := addressByteLength(family) 2067 if err != nil { 2068 return err 2069 } 2070 b.prefix = data[1 : 1+addrlen] //zclient_stream_get_prefix 2071 b.length = data[1+addrlen] //zclient_stream_get_prefix 2072 return nil 2073 } 2074 2075 // Ref: zclient_send_router_id_update in lib/zclient.c of FRR7.5 2076 func (b *routerIDUpdateBody) serialize(version uint8, software Software) ([]byte, error) { 2077 if version == 6 && software.name == "frr" && software.version >= 7.5 { 2078 return []byte{0x00, uint8(b.afi)}, nil //stream_putw(s, afi); 2079 2080 } 2081 return []byte{}, nil 2082 } 2083 2084 func (b *routerIDUpdateBody) string(version uint8, software Software) string { 2085 return fmt.Sprintf("id: %s/%d", b.prefix.String(), b.length) 2086 } 2087 2088 // zapiNexthopFlag is defined in lib/zclient.h of FRR 2089 const ( 2090 zapiNexthopFlagOnlink uint8 = 0x01 // frr7.1, 7.2, 7.3, 7.4, 7.5, 8.0 2091 zapiNexthopFlagLabel uint8 = 0x02 // frr7.3, 7.4, 7.5, 8.0 2092 zapiNexthopFlagWeight uint8 = 0x04 // frr7.3, 7.4, 7.5, 8.0 2093 zapiNexthopFlagHasBackup uint8 = 0x08 // frr7.4, 7.5, 8.0 2094 zapiNexthopFlagSeg6 uint8 = 0x10 // frr8.1 2095 zapiNexthopFlagSeg6Local uint8 = 0x20 // frr8.1 2096 ) 2097 2098 // Flag for nexthop processing. It is gobgp's internal flag. 2099 type nexthopProcessFlag uint8 2100 2101 const ( 2102 nexthopHasType nexthopProcessFlag = 0x01 2103 nexthopHasVrfID nexthopProcessFlag = 0x02 2104 nexthopHasFlag nexthopProcessFlag = 0x04 2105 nexthopHasOnlink nexthopProcessFlag = 0x08 2106 nexthopProcessIPToIPIFindex nexthopProcessFlag = 0x10 2107 nexthopProcessIFnameToIFindex nexthopProcessFlag = 0x20 // for quagga 2108 ) 2109 2110 func nexthopProcessFlagForIPRouteBody(version uint8, software Software, isDecode bool) nexthopProcessFlag { 2111 if version < 5 { 2112 if isDecode { 2113 return nexthopProcessFlag(0) // frr3&quagga don't have type&vrfid 2114 } 2115 return nexthopHasType // frr3&quagga need type for encode(serialize) 2116 } 2117 processFlag := (nexthopHasVrfID | nexthopHasType) // frr4, 5, 6, 7 2118 if version == 6 && software.name == "frr" { 2119 if software.version >= 7.3 { 2120 processFlag |= (nexthopHasFlag | nexthopProcessIPToIPIFindex) 2121 } else if software.version >= 7.1 { 2122 processFlag |= nexthopHasOnlink 2123 } 2124 } 2125 return processFlag 2126 } 2127 2128 // Ref: struct seg6local_context in lib/srv6.h of FRR8.1 2129 type seg6localContext struct { 2130 nh4 net.IP //struct in_addr nh4 2131 nh6 net.IP //struct in_addr nh6 2132 table uint32 2133 } 2134 2135 func (s6lc seg6localContext) encode() []byte { 2136 var buf []byte 2137 buf = append(buf, s6lc.nh4.To4()...) 2138 buf = append(buf, s6lc.nh6.To16()...) 2139 tmpbuf := make([]byte, 4) 2140 binary.BigEndian.PutUint32(tmpbuf, s6lc.table) 2141 buf = append(buf, tmpbuf...) 2142 return buf 2143 } 2144 func (s6lc *seg6localContext) decode(data []byte) int { 2145 offset := 0 2146 s6lc.nh4 = net.IP(data[offset : offset+4]).To4() 2147 offset += 4 2148 s6lc.nh6 = net.IP(data[offset : offset+16]).To16() 2149 offset += 16 2150 s6lc.table = binary.BigEndian.Uint32(data[offset : offset+4]) 2151 offset += 4 2152 return offset 2153 } 2154 2155 // Ref: struct zapi_nexthop in lib/zclient.h of FRR5&FRR6&FRR7.x&FRR8, FRR8.1 (ZAPI5&6) 2156 // Nexthop is referred in zclient 2157 type Nexthop struct { 2158 Type nexthopType //FRR5, FRR6, FRR7.x, FRR8, FRR8.1 2159 VrfID uint32 //FRR5, FRR6, FRR7.x, FRR8, FRR8.1 2160 Ifindex uint32 // Ifindex is referred in zclient_test 2161 flags uint8 //FRR7.1, FRR7.2 FRR7.3, FRR7.4, FRR7.5, FRR8, FRR8.1 2162 Gate net.IP //union { union g_addr gate; 2163 blackholeType uint8 // enum blackhole_type bh_type;} 2164 LabelNum uint8 //FRR5, FRR6, FRR7.x, FRR8, FRR8.1 2165 MplsLabels []uint32 //FRR5, FRR6, FRR7.x, FRR8, FRR8.1 2166 rmac [6]byte //FRR6, FRR7.x, FRR8, FRR8.1 2167 Weight uint32 //FRR7.3, FRR7.4, FRR7.5, FRR8, FRR8.1 2168 backupNum uint8 //FRR7.4, FRR7.5, FRR8, FRR8.1 2169 backupIndex []uint8 //FRR7.5, FRR8, FRR8.1 2170 srteColor uint32 //FRR7.5, FRR8, FRR8.1 2171 seg6localAction uint32 //FRR8.1 2172 seg6localCtx seg6localContext // FRR8.1 2173 seg6Segs net.IP //strcut in6_addr // FRR8.1 2174 } 2175 2176 func (n Nexthop) string() string { 2177 s := make([]string, 0) 2178 s = append(s, fmt.Sprintf( 2179 "type: %s, vrf_id: %d, ifindex: %d, flags: %d, gate: %s, blackholeType: %d, label_num: %d, weight: %d, backupNum: %d, srteColor: %d", 2180 n.Type.String(), n.VrfID, n.Ifindex, n.flags, n.Gate.String(), 2181 n.blackholeType, n.LabelNum, n.Weight, n.backupNum, n.srteColor)) 2182 for i := uint8(0); i < n.LabelNum; i++ { 2183 s = append(s, fmt.Sprintf(" label[%d]: %d", i, n.MplsLabels[i])) 2184 } 2185 for i := uint8(0); i < n.backupNum; i++ { 2186 s = append(s, fmt.Sprintf(" backupIndex[%d]: %d", i, n.backupIndex[i])) 2187 } 2188 return strings.Join(s, ", ") 2189 } 2190 func (n Nexthop) gateToType(version uint8) nexthopType { 2191 if n.Gate.To4() != nil { 2192 if version > 4 && n.Ifindex > 0 { 2193 return nexthopTypeIPv4IFIndex 2194 } 2195 return nexthopTypeIPv4.toEach(version) 2196 } else if n.Gate.To16() != nil { 2197 if version > 4 && n.Ifindex > 0 { 2198 return nexthopTypeIPv6IFIndex 2199 } 2200 return nexthopTypeIPv6.toEach(version) 2201 } else if n.Ifindex > 0 { 2202 return nexthopTypeIFIndex.toEach(version) 2203 } else if version > 4 { 2204 return nexthopTypeBlackhole 2205 } 2206 return nexthopType(0) 2207 } 2208 2209 // Ref: zapi_nexthop_encode in lib/zclient.h of FRR7.3&FRR7.4&FRR7.5&FRR8 2210 func (n Nexthop) encode(version uint8, software Software, processFlag nexthopProcessFlag, message MessageFlag, apiFlag Flag) []byte { 2211 var buf []byte 2212 if processFlag&nexthopHasVrfID > 0 { 2213 tmpbuf := make([]byte, 4) 2214 binary.BigEndian.PutUint32(tmpbuf, n.VrfID) 2215 buf = append(buf, tmpbuf...) //frr: stream_putl(s, api_nh->vrf_id); 2216 } 2217 if processFlag&nexthopHasType > 0 { 2218 if n.Type == nexthopType(0) { 2219 n.Type = n.gateToType(version) 2220 } 2221 buf = append(buf, uint8(n.Type)) //frr: stream_putc(s, api_nh->type); 2222 } 2223 if processFlag&nexthopHasFlag > 0 { 2224 if n.LabelNum > 0 { 2225 n.flags |= zapiNexthopFlagLabel 2226 } 2227 if n.Weight > 0 { 2228 n.flags |= zapiNexthopFlagWeight 2229 } 2230 if n.backupNum > 0 { 2231 n.flags |= zapiNexthopFlagHasBackup 2232 } 2233 } 2234 if processFlag&nexthopHasFlag > 0 || processFlag&nexthopHasOnlink > 0 { 2235 // frr7.1, 7.2 has onlink, 7.3 has flag 2236 buf = append(buf, n.flags) //frr: stream_putc(s, nh_flags); 2237 } 2238 2239 nhType := n.Type 2240 if processFlag&nexthopProcessIPToIPIFindex > 0 { 2241 nhType = nhType.ipToIPIFIndex() 2242 } 2243 if processFlag&nexthopProcessIFnameToIFindex > 0 { 2244 nhType = nhType.ifNameToIFIndex() 2245 } 2246 if nhType == nexthopTypeIPv4.toEach(version) || 2247 nhType == nexthopTypeIPv4IFIndex.toEach(version) { 2248 //frr: stream_put_in_addr(s, &api_nh->gate.ipv4); 2249 buf = append(buf, n.Gate.To4()...) 2250 } else if nhType == nexthopTypeIPv6.toEach(version) || 2251 nhType == nexthopTypeIPv6IFIndex.toEach(version) { 2252 //frr: stream_write(s, (uint8_t *)&api_nh->gate.ipv6, 16); 2253 buf = append(buf, n.Gate.To16()...) 2254 } 2255 if nhType == nexthopTypeIFIndex || 2256 nhType == nexthopTypeIPv4IFIndex.toEach(version) || 2257 nhType == nexthopTypeIPv6IFIndex.toEach(version) { 2258 tmpbuf := make([]byte, 4) 2259 binary.BigEndian.PutUint32(tmpbuf, n.Ifindex) 2260 buf = append(buf, tmpbuf...) //frr: stream_putl(s, api_nh->ifindex); 2261 } 2262 if nhType == nexthopTypeBlackhole.toEach(version) { //case NEXTHOP_TYPE_BLACKHOLE: 2263 //frr: stream_putc(s, api_nh->bh_type); 2264 buf = append(buf, uint8(n.blackholeType)) 2265 } 2266 if n.flags&zapiNexthopFlagLabel > 0 || (message&MessageLabel > 0 && 2267 version == 5 || 2268 (version == 6 && software.name == "frr" && 2269 software.version >= 6 && software.version < 7.3)) { 2270 tmpbuf := make([]byte, 1+4*n.LabelNum) 2271 tmpbuf[0] = n.LabelNum //frr: stream_putc(s, api_nh->label_num); 2272 for i := uint8(0); i < n.LabelNum; i++ { 2273 // frr uses stream_put for mpls label array. 2274 // stream_put is unaware of byteorder coversion. 2275 // Therefore LittleEndian is used instead of BigEndian. 2276 binary.LittleEndian.PutUint32(tmpbuf[i*4+1:], n.MplsLabels[i]) 2277 } 2278 //frr: stream_put(s, &api_nh->labels[0], api_nh->label_num * sizeof(mpls_label_t)); 2279 buf = append(buf, tmpbuf...) 2280 } 2281 if n.flags&zapiNexthopFlagWeight > 0 && n.Weight > 0 { 2282 tmpbuf := make([]byte, 4) 2283 binary.BigEndian.PutUint32(tmpbuf, uint32(n.Weight)) 2284 buf = append(buf, tmpbuf...) //frr: stream_putl(s, api_nh->Weight); 2285 } 2286 if apiFlag&flagEvpnRoute.ToEach(version, software) > 0 { 2287 //frr: stream_put(s, &(api_nh->rmac), sizeof(struct ethaddr)); 2288 buf = append(buf, n.rmac[:]...) 2289 } 2290 // added in frr7.5 (Color for Segment Routing TE.) 2291 if message&messageSRTE > 0 && (version == 6 && software.name == "frr" && software.version >= 7.5) { 2292 tmpbuf := make([]byte, 4) 2293 binary.BigEndian.PutUint32(tmpbuf, uint32(n.srteColor)) 2294 buf = append(buf, tmpbuf...) //frr: stream_putl(s, api_nh->srte_color); 2295 } 2296 // added in frr7.4 (Index of backup nexthop) 2297 if n.flags&zapiNexthopFlagHasBackup > 0 { 2298 tmpbuf := make([]byte, 1+1*n.backupNum) 2299 tmpbuf[0] = n.backupNum //frr: stream_putc(s, api_nh->backup_num); 2300 for i := uint8(0); i < n.backupNum; i++ { 2301 tmpbuf[i+1] = n.backupIndex[i] 2302 } 2303 buf = append(buf, tmpbuf...) 2304 } 2305 // added in frr8.1 2306 if n.flags&zapiNexthopFlagSeg6 > 0 { 2307 tmpbuf := make([]byte, 4) 2308 binary.BigEndian.PutUint32(tmpbuf, uint32(n.seg6localAction)) 2309 buf = append(buf, tmpbuf...) // stream_putl(s, api_nh->seg6local_action); 2310 //frr: stream_write(s, &api_nh->seg6local_ctx, sizeof(struct seg6local_context)); 2311 buf = append(buf, n.seg6localCtx.encode()...) 2312 } 2313 // added in frr8.1 2314 if n.flags&zapiNexthopFlagSeg6Local > 0 { 2315 //frr: stream_write(s, &api_nh->seg6_segs, sizeof(struct in6_addr)); 2316 buf = append(buf, n.seg6Segs.To16()...) 2317 } 2318 return buf 2319 } 2320 2321 // Ref: zapi_nexthop_decode in lib/zclient.h of FRR7.3&FRR7.4&FRR7.5&FRR8 2322 func (n *Nexthop) decode(data []byte, version uint8, software Software, family uint8, processFlag nexthopProcessFlag, message MessageFlag, apiFlag Flag, nhType nexthopType) (int, error) { 2323 offset := 0 2324 if processFlag&nexthopHasVrfID > 0 { 2325 //frr: STREAM_GETL(s, api_nh->vrf_id); 2326 n.VrfID = binary.BigEndian.Uint32(data[offset : offset+4]) 2327 offset += 4 2328 } 2329 2330 n.Type = nhType // data does not have nexthop type 2331 if processFlag&nexthopHasType > 0 { 2332 n.Type = nexthopType(data[offset]) //frr: STREAM_GETC(s, api_nh->type); 2333 offset++ 2334 } 2335 2336 n.flags = uint8(0) 2337 if processFlag&nexthopHasFlag > 0 || processFlag&nexthopHasOnlink > 0 { 2338 n.flags = uint8(data[offset]) //frr: STREAM_GETC(s, api_nh->flags); 2339 offset++ 2340 } 2341 2342 nhType = n.Type 2343 if processFlag&nexthopProcessIPToIPIFindex > 0 { 2344 nhType = nhType.ipToIPIFIndex() 2345 } 2346 if processFlag&nexthopProcessIFnameToIFindex > 0 { 2347 nhType = nhType.ifNameToIFIndex() 2348 } 2349 if family == syscall.AF_INET { 2350 n.Gate = net.ParseIP("0.0.0.0") 2351 } else if family == syscall.AF_INET6 { 2352 n.Gate = net.ParseIP("::") 2353 } 2354 if nhType == nexthopTypeIPv4.toEach(version) || 2355 nhType == nexthopTypeIPv4IFIndex.toEach(version) { 2356 //frr: STREAM_GET(&api_nh->gate.ipv4.s_addr, s, IPV4_MAX_BYTELEN); 2357 n.Gate = net.IP(data[offset : offset+4]).To4() 2358 offset += 4 2359 } else if nhType == nexthopTypeIPv6.toEach(version) || 2360 nhType == nexthopTypeIPv6IFIndex.toEach(version) { 2361 //frr: STREAM_GET(&api_nh->gate.ipv6, s, 16); 2362 n.Gate = net.IP(data[offset : offset+16]).To16() 2363 offset += 16 2364 } 2365 if nhType == nexthopTypeIFIndex || 2366 nhType == nexthopTypeIPv4IFIndex.toEach(version) || 2367 nhType == nexthopTypeIPv6IFIndex.toEach(version) { 2368 //frr: STREAM_GETL(s, api_nh->ifindex); 2369 n.Ifindex = binary.BigEndian.Uint32(data[offset : offset+4]) 2370 offset += 4 2371 } 2372 if nhType == nexthopTypeBlackhole.toEach(version) { //case NEXTHOP_TYPE_BLACKHOLE: 2373 n.blackholeType = data[offset] //frr: STREAM_GETC(s, api_nh->bh_type); 2374 offset++ 2375 } 2376 if n.flags&zapiNexthopFlagLabel > 0 || (message&MessageLabel > 0 && 2377 (version == 5 || version == 6 && software.name == "frr" && 2378 software.version >= 6 && software.version < 7.3)) { 2379 n.LabelNum = uint8(data[offset]) //frr: STREAM_GETC(s, api_nh->label_num); 2380 offset++ 2381 if n.LabelNum > maxMplsLabel { 2382 n.LabelNum = maxMplsLabel 2383 } 2384 if n.LabelNum > 0 { 2385 n.MplsLabels = make([]uint32, n.LabelNum) 2386 for i := uint8(0); i < n.LabelNum; i++ { 2387 // frr uses stream_put which is unaware of byteorder for mpls label array. 2388 // Therefore LittleEndian is used instead of BigEndian. 2389 //frr: STREAM_GET(&api_nh->labels[0], s, api_nh->label_num * sizeof(mpls_label_t)); 2390 n.MplsLabels[i] = binary.LittleEndian.Uint32(data[offset : offset+4]) 2391 offset += 4 2392 } 2393 } 2394 } 2395 if n.flags&zapiNexthopFlagWeight > 0 { 2396 //frr: STREAM_GETL(s, api_nh->Weight); 2397 n.Weight = binary.BigEndian.Uint32(data[offset:]) 2398 offset += 4 2399 } 2400 if apiFlag&flagEvpnRoute.ToEach(version, software) > 0 { 2401 //frr: STREAM_GET(&(api_nh->rmac), s, sizeof(struct ethaddr)); 2402 copy(n.rmac[0:], data[offset:offset+6]) 2403 offset += 6 2404 } 2405 // added in frr7.5 (Color for Segment Routing TE.) 2406 if message&messageSRTE > 0 && 2407 (version == 6 && software.name == "frr" && software.version >= 7.5) { 2408 //frr: STREAM_GETL(s, api_nh->srte_color); 2409 n.srteColor = binary.BigEndian.Uint32(data[offset:]) 2410 offset += 4 2411 } 2412 // added in frr7.4 (Index of backup nexthop) 2413 if n.flags&zapiNexthopFlagHasBackup > 0 { 2414 n.backupNum = data[offset] //frr: STREAM_GETC(s, api_nh->backup_num); 2415 offset++ 2416 if n.backupNum > 0 { 2417 n.backupIndex = make([]uint8, n.backupNum) 2418 for i := uint8(0); i < n.backupNum; i++ { 2419 //frr STREAM_GETC(s, api_nh->backup_idx[i]); 2420 n.backupIndex[i] = data[offset] 2421 offset++ 2422 } 2423 } 2424 } 2425 // added in frr8.1 2426 if n.flags&zapiNexthopFlagSeg6 > 0 { 2427 n.seg6localAction = binary.BigEndian.Uint32(data[offset : offset+4]) 2428 offset += 4 2429 offset += n.seg6localCtx.decode(data[offset : offset+24]) 2430 } 2431 // added in frr8.1 2432 if n.flags&zapiNexthopFlagSeg6Local > 0 { 2433 n.seg6Segs = net.IP(data[offset : offset+16]).To16() 2434 offset += 16 2435 } 2436 return offset, nil 2437 } 2438 2439 // decodeNexthops is referred from decodeFromBytes of NexthopUpdateBody and IPRouteBody 2440 func decodeNexthops(nexthops *[]Nexthop, data []byte, version uint8, software Software, family uint8, numNexthop uint16, processFlag nexthopProcessFlag, message MessageFlag, apiFlag Flag, nhType nexthopType) (int, error) { 2441 offset := 0 2442 *nexthops = make([]Nexthop, numNexthop) 2443 for i := uint16(0); i < numNexthop; i++ { 2444 size, err := (&((*nexthops)[i])).decode(data[offset:], version, software, family, processFlag, message, apiFlag, nhType) 2445 if err != nil { 2446 return offset, err 2447 } 2448 offset += size 2449 } 2450 return offset, nil 2451 } 2452 2453 // Prefix referred in zclient is struct for network prefix and relate information 2454 type Prefix struct { 2455 Family uint8 2456 PrefixLen uint8 2457 Prefix net.IP 2458 } 2459 2460 func familyFromPrefix(prefix net.IP) uint8 { 2461 if prefix.To4() != nil { 2462 return syscall.AF_INET 2463 } else if prefix.To16() != nil { 2464 return syscall.AF_INET6 2465 } 2466 return syscall.AF_UNSPEC 2467 } 2468 2469 const messageOpaqueLenth uint16 = 1024 2470 2471 type opaque struct { 2472 length uint16 2473 data [messageOpaqueLenth]uint8 2474 } 2475 2476 // Ref: struct zapi_route in lib/zclient.h of FRR4&FRR5&FRR6&FRR7.x&RR8 (ZAPI5&6) 2477 // IPRouteBody is struct for IPRotue (zapi_route) 2478 type IPRouteBody struct { 2479 Type RouteType // FRR4&FRR5&FRR6&FRR7.x&FRR8 2480 instance uint16 // FRR4&FRR5&FRR6&FRR7.x&FRR8 2481 Flags Flag // FRR4&FRR5&FRR6&FRR7.x&FRR8 2482 Message MessageFlag // FRR4&FRR5&FRR6&FRR7.x&FRR8 2483 Safi Safi // FRR4&FRR5&FRR6&FRR7.x&FRR8 2484 Prefix Prefix // FRR4&FRR5&FRR6&FRR7.x&FRR8 2485 srcPrefix Prefix // FRR4&FRR5&FRR6&FRR7.x&FRR8 2486 Nexthops []Nexthop // FRR4&FRR5&FRR6&FRR7.x&FRR8 2487 backupNexthops []Nexthop // added in frr7.4, FRR7.4&FRR7.5&FRR8 2488 nhgid uint32 // added in frr8 2489 Distance uint8 // FRR4&FRR5&FRR6&FRR7.x&FRR8 2490 Metric uint32 // FRR4&FRR5&FRR6&FRR7.x&FRR8 2491 tag uint32 // FRR4&FRR5&FRR6&FRR7.x&FRR8 2492 Mtu uint32 // FRR4&FRR5&FRR6&FRR7.x&FRR8 2493 tableID uint32 // FRR5&FRR6&FRR7.x&FRR8 (nh_vrf_id in FRR4) 2494 srteColor uint32 // added in frr7.5, FRR7.5&FRR8 2495 opaque opaque // added in frr8 2496 API APIType // API is referred in zclient_test 2497 //vrfID uint32 // lib/zebra.h:typedef uint32_t vrf_id_t; 2498 } 2499 2500 func (b *IPRouteBody) safi(logger log.Logger, version uint8, software Software) Safi { 2501 // frr 7.2 and later versions have safiUnspec, older versions don't have safiUnspec 2502 if b.Safi == safiUnspec && (version < 6 || 2503 (version == 6 && software.name == "frr" && software.version < 7.2)) { 2504 return SafiUnicast //safiUnspec is regarded as safiUnicast in older versions 2505 } 2506 if b.Safi <= safiMulticast || version > 4 { // not need to convert 2507 return b.Safi 2508 } 2509 safiMap := zapi4SafiMap 2510 if version < 4 { 2511 safiMap = zapi3SafiMap 2512 } 2513 safi, ok := safiMap[b.Safi] 2514 if !ok { 2515 safi = safiUnspec // failed to convert 2516 } 2517 logger.Debug("zebra converts safi", 2518 log.Fields{ 2519 "Topic": "Zebra", 2520 "Body": b, 2521 "Old": b.Safi.String(), 2522 "New": safi.String()}) 2523 return safi // success to convert 2524 } 2525 2526 // RouteFamily is referred in zclient 2527 func (b *IPRouteBody) RouteFamily(logger log.Logger, version uint8, software Software) bgp.RouteFamily { 2528 if b == nil { 2529 return bgp.RF_OPAQUE // fail 2530 } 2531 safi := b.safi(logger, version, software) 2532 if safi == safiEvpn { 2533 return bgp.RF_EVPN // success 2534 } 2535 family := b.Prefix.Family 2536 if family == syscall.AF_UNSPEC { 2537 family = familyFromPrefix(b.Prefix.Prefix) 2538 } 2539 if family == syscall.AF_UNSPEC { // familyFromPrefix returs AF_UNSPEC 2540 return bgp.RF_OPAQUE // fail 2541 } 2542 safiRouteFamilyMap := safiRouteFamilyIPv4Map // syscall.AF_INET 2543 if family == syscall.AF_INET6 { 2544 safiRouteFamilyMap = safiRouteFamilyIPv6Map 2545 } 2546 rf, ok := safiRouteFamilyMap[safi] 2547 if !ok { 2548 return bgp.RF_OPAQUE // fail 2549 } 2550 logger.Debug("zebra converts safi", 2551 log.Fields{ 2552 "Topic": "Zebra", 2553 "Body": b, 2554 "Safi": safi.String(), 2555 "Rf": rf.String()}) 2556 2557 return rf // success 2558 } 2559 2560 // IsWithdraw is referred in zclient 2561 func (b *IPRouteBody) IsWithdraw(version uint8, software Software) bool { 2562 api := b.API.ToCommon(version, software) 2563 switch api { 2564 case RouteDelete, RedistributeRouteDel, BackwardIPv6RouteDelete: 2565 return true 2566 } 2567 if version == 4 && b.API == zapi4RedistributeIPv6Del { 2568 return true 2569 } 2570 return false 2571 } 2572 2573 // Ref: zapi_ipv4_route in lib/zclient.c of Quagga1.2.x&FRR3.x(ZAPI3&4) 2574 // Ref: zapi_route_encode in lib/zclient.c of FRR4&FRR5&FRR6&FRR7.x&FRR8 (ZAPI5&6) 2575 func (b *IPRouteBody) serialize(version uint8, software Software) ([]byte, error) { 2576 var buf []byte 2577 numNexthop := len(b.Nexthops) 2578 2579 bufInitSize := 12 //type(1)+instance(2)+flags(4)+message(4)+safi(1), frr7.4&newer 2580 switch version { 2581 case 2, 3: 2582 bufInitSize = 5 2583 case 4: 2584 bufInitSize = 10 2585 case 5: 2586 bufInitSize = 9 //type(1)+instance(2)+flags(4)+message(1)+safi(1) 2587 case 6: 2588 if software.name == "frr" && software.version < 7.4 { // frr6, 7, 7.2, 7.3 2589 bufInitSize = 9 //type(1)+instance(2)+flags(4)+message(1)+safi(1) 2590 } 2591 } 2592 buf = make([]byte, bufInitSize) 2593 2594 buf[0] = uint8(b.Type.toEach(version)) //frr: stream_putc(s, api->type); 2595 if version < 4 { 2596 buf[1] = uint8(b.Flags) 2597 buf[2] = uint8(b.Message) 2598 binary.BigEndian.PutUint16(buf[3:5], uint16(b.Safi)) 2599 } else { // version >= 4 2600 //frr: stream_putw(s, api->instance); 2601 binary.BigEndian.PutUint16(buf[1:3], uint16(b.instance)) 2602 //frr: stream_putl(s, api->flags); 2603 binary.BigEndian.PutUint32(buf[3:7], uint32(b.Flags)) 2604 if version == 6 && software.name == "frr" && software.version >= 7.5 { 2605 //frr7.5 and newer: stream_putl(s, api->message); 2606 binary.BigEndian.PutUint32(buf[7:11], uint32(b.Message)) 2607 buf[11] = uint8(b.Safi) //stream_putc(s, api->safi); 2608 } else { 2609 //frr 7.4 and older: stream_putc(s, api->message); 2610 buf[7] = uint8(b.Message) 2611 if version > 4 { 2612 buf[8] = uint8(b.Safi) //frr: stream_putc(s, api->safi); 2613 } else { // version 2,3 and 4 (quagga, frr3) 2614 binary.BigEndian.PutUint16(buf[8:10], uint16(b.Safi)) 2615 } 2616 } 2617 } 2618 // only zapi version 5 (frr4.0.x) have evpn routes 2619 if version == 5 && b.Flags&flagEvpnRoute.ToEach(version, software) > 0 { 2620 // size of struct ethaddr is 6 octets defined by ETH_ALEN 2621 buf = append(buf, b.Nexthops[numNexthop-1].rmac[:6]...) 2622 } 2623 if version > 4 { // version 5, 6 (after frr4) 2624 if b.Prefix.Family == syscall.AF_UNSPEC { 2625 b.Prefix.Family = familyFromPrefix(b.Prefix.Prefix) 2626 } 2627 //frr: stream_putc(s, api->prefix.family); 2628 buf = append(buf, b.Prefix.Family) 2629 } 2630 byteLen := (int(b.Prefix.PrefixLen) + 7) / 8 2631 buf = append(buf, b.Prefix.PrefixLen) //frr: stream_putc(s, api->prefix.prefixlen); 2632 //frr: stream_write(s, (uint8_t *)&api->prefix.u.prefix, psize); 2633 buf = append(buf, b.Prefix.Prefix[:byteLen]...) 2634 2635 if version > 3 && b.Message&messageSRCPFX.ToEach(version, software) > 0 { 2636 byteLen = (int(b.srcPrefix.PrefixLen) + 7) / 8 2637 //frr: stream_putc(s, api->src_prefix.prefixlen); 2638 buf = append(buf, b.srcPrefix.PrefixLen) 2639 //frr: stream_write(s, (uint8_t *)&api->prefix.u.prefix, psize); 2640 buf = append(buf, b.srcPrefix.Prefix[:byteLen]...) 2641 } 2642 2643 // NHG(Nexthop Group) is added in frr8 2644 //frr: if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NHG)) 2645 if version == 6 && software.name == "frr" && software.version >= 8 && 2646 b.Message&messageNhg.ToEach(version, software) > 0 { 2647 //frr: stream_putl(s, api->nhgid); 2648 tmpbuf := make([]byte, 4) 2649 binary.BigEndian.PutUint32(tmpbuf, b.nhgid) 2650 buf = append(buf, tmpbuf...) 2651 } 2652 2653 processFlag := nexthopProcessFlagForIPRouteBody(version, software, false) 2654 if b.Message&MessageNexthop > 0 { 2655 if version < 5 { 2656 if b.Flags&flagBlackhole > 0 { 2657 buf = append(buf, []byte{1, uint8(nexthopTypeBlackhole.toEach(version))}...) 2658 } else { 2659 buf = append(buf, uint8(numNexthop)) 2660 } 2661 } else { // version >= 5 2662 tmpbuf := make([]byte, 2) 2663 binary.BigEndian.PutUint16(tmpbuf, uint16(numNexthop)) 2664 buf = append(buf, tmpbuf...) //frr: stream_putw(s, api->nexthop_num); 2665 } 2666 for _, nexthop := range b.Nexthops { 2667 buf = append(buf, nexthop.encode(version, software, processFlag, b.Message, b.Flags)...) 2668 } 2669 } 2670 // MESSAGE_BACKUP_NEXTHOPS is added in frr7.4 2671 if version == 6 && software.name == "frr" && software.version >= 7.4 && 2672 b.Message&messageBackupNexthops > 0 { 2673 tmpbuf := make([]byte, 2) 2674 binary.BigEndian.PutUint16(tmpbuf, uint16(len(b.backupNexthops))) 2675 buf = append(buf, tmpbuf...) //frr: stream_putw(s, api->backup_nexthop_num); 2676 for _, nexthop := range b.backupNexthops { 2677 buf = append(buf, nexthop.encode(version, software, processFlag, b.Message, b.Flags)...) 2678 } 2679 } 2680 if b.Message&MessageDistance.ToEach(version, software) > 0 { 2681 buf = append(buf, b.Distance) 2682 } 2683 if b.Message&MessageMetric.ToEach(version, software) > 0 { 2684 tmpbuf := make([]byte, 4) 2685 binary.BigEndian.PutUint32(tmpbuf, b.Metric) 2686 buf = append(buf, tmpbuf...) 2687 } 2688 if b.Message&messageTag.ToEach(version, software) > 0 { 2689 tmpbuf := make([]byte, 4) 2690 binary.BigEndian.PutUint32(tmpbuf, b.tag) 2691 buf = append(buf, tmpbuf...) 2692 } 2693 if b.Message&MessageMTU.ToEach(version, software) > 0 { 2694 tmpbuf := make([]byte, 4) 2695 binary.BigEndian.PutUint32(tmpbuf, b.Mtu) 2696 buf = append(buf, tmpbuf...) 2697 } 2698 if b.Message&messageTableID.ToEach(version, software) > 0 { 2699 tmpbuf := make([]byte, 4) 2700 binary.BigEndian.PutUint32(tmpbuf, b.tableID) 2701 buf = append(buf, tmpbuf...) 2702 } 2703 if b.Message&messageOpaque.ToEach(version, software) > 0 { 2704 tmpbuf := make([]byte, 2) 2705 binary.BigEndian.PutUint16(tmpbuf, b.opaque.length) 2706 buf = append(buf, tmpbuf...) //frr: stream_putw(s, api->opaque.length); 2707 buf = append(buf, b.opaque.data[:]...) //frr: stream_write(s, api->opaque.data, api->opaque.length); 2708 } 2709 return buf, nil 2710 } 2711 2712 // decodeMessageNexthopFromBytes is referred in IPRouteBody's decodeFromBytes 2713 func (b *IPRouteBody) decodeMessageNexthopFromBytes(data []byte, version uint8, software Software, isBackup bool) (int, error) { 2714 pos := 0 2715 rest := len(data) 2716 message := MessageNexthop 2717 nexthops := &b.Nexthops 2718 messageString := "MessageNexthop" 2719 if isBackup { 2720 message = messageBackupNexthops 2721 nexthops = &b.backupNexthops 2722 messageString = "messageBackupNexthops" 2723 } 2724 if b.Message&message > 0 { 2725 numNexthop := uint16(0) 2726 numNexthopDataSize := 2 2727 processFlag := nexthopProcessFlagForIPRouteBody(version, software, true) 2728 nhType := nexthopType(0) 2729 if message == MessageNexthop && version < 5 { // frr3 and quagga 2730 numNexthopDataSize = 1 2731 nhType = nexthopTypeIPv4.toEach(version) 2732 if b.Prefix.Family == syscall.AF_INET6 { 2733 nhType = nexthopTypeIPv6.toEach(version) 2734 } 2735 } 2736 if pos+numNexthopDataSize > rest { 2737 return pos, fmt.Errorf("%s message length invalid pos:%d rest:%d", messageString, pos, rest) 2738 } 2739 if numNexthopDataSize == 2 { 2740 //frr: STREAM_GETW(s, api->nexthop_num); 2741 numNexthop = binary.BigEndian.Uint16(data[pos : pos+2]) 2742 } else if message == MessageNexthop && numNexthopDataSize == 1 { 2743 numNexthop = uint16(data[pos]) 2744 } 2745 pos += numNexthopDataSize 2746 2747 nexthopsByteLen, err := decodeNexthops(nexthops, data[pos:], version, software, b.Prefix.Family, numNexthop, processFlag, b.Message, b.Flags, nhType) 2748 if err != nil { 2749 return pos, err 2750 } 2751 pos += nexthopsByteLen 2752 } 2753 return pos, nil 2754 } 2755 2756 // Ref: zebra_read_ipv4 in bgpd/bgp_zebra.c of Quagga1.2.x&FRR3.x(ZAPI3&4) 2757 // Ref: zapi_route_decode in lib/zclient.c of FRR5&FRR6&FRR7.x&FRR8 (ZAPI5&6) 2758 func (b *IPRouteBody) decodeFromBytes(data []byte, version uint8, software Software) error { 2759 if b == nil { 2760 return fmt.Errorf("IPRouteBody is nil") 2761 } 2762 //frr: STREAM_GETC(s, api->type); 2763 b.Type = RouteType(data[0]) 2764 if b.Type > getRouteAll(version, software) { //ver5 and later work, fix for older 2765 return fmt.Errorf("unknown route type: %d in version: %d (%s)", b.Type, version, software.string()) 2766 } 2767 2768 if version <= 3 { 2769 b.Flags = Flag(data[1]) 2770 data = data[2:] 2771 } else { // version >= 4 2772 //frr: STREAM_GETW(s, api->instance); 2773 b.instance = binary.BigEndian.Uint16(data[1:3]) 2774 //frr: STREAM_GETL(s, api->flags); 2775 b.Flags = Flag(binary.BigEndian.Uint32(data[3:7])) 2776 data = data[7:] 2777 } 2778 if version == 6 && software.name == "frr" && software.version >= 7.5 { 2779 //frr7.5: STREAM_GETL(s, api->message); 2780 b.Message = MessageFlag(binary.BigEndian.Uint32(data[0:4])) 2781 data = data[4:] 2782 } else { 2783 b.Message = MessageFlag(data[0]) //frr: STREAM_GETC(s, api->message); 2784 data = data[1:] 2785 } 2786 b.Safi = Safi(SafiUnicast) 2787 b.Prefix.Family = b.API.addressFamily(version) // return AF_UNSPEC if version > 4 2788 var evpnNexthop Nexthop 2789 if version > 4 { 2790 b.Safi = Safi(data[0]) //frr: STREAM_GETC(s, api->safi); 2791 if b.Safi > safiMax { //frr5 and later work, ToDo: fix for older version 2792 return fmt.Errorf("unknown safi type: %d in version: %d (%s)", b.Type, version, software.string()) 2793 } 2794 data = data[1:] 2795 2796 // zapi version 5 only 2797 if version == 5 && b.Flags&flagEvpnRoute.ToEach(version, software) > 0 { 2798 // size of struct ethaddr is 6 octets defined by ETH_ALEN 2799 copy(evpnNexthop.rmac[0:6], data[0:6]) 2800 data = data[6:] 2801 } 2802 2803 b.Prefix.Family = data[0] //frr: STREAM_GETC(s, api->prefix.family); 2804 data = data[1:] 2805 } 2806 2807 addrByteLen, err := addressByteLength(b.Prefix.Family) 2808 if err != nil { 2809 return err 2810 } 2811 2812 addrBitLen := uint8(addrByteLen * 8) 2813 2814 b.Prefix.PrefixLen = data[0] //frr: STREAM_GETC(s, api->prefix.prefixlen); 2815 if b.Prefix.PrefixLen > addrBitLen { 2816 return fmt.Errorf("prefix length %d is greater than %d", b.Prefix.PrefixLen, addrBitLen) 2817 } 2818 data = data[1:] 2819 pos := 0 2820 rest := len(data) 2821 2822 buf := make([]byte, addrByteLen) 2823 byteLen := int((b.Prefix.PrefixLen + 7) / 8) 2824 if pos+byteLen > rest { 2825 return fmt.Errorf("message length invalid pos:%d rest:%d", pos, rest) 2826 } 2827 //frr: STREAM_GET(&api->prefix.u.prefix, s, PSIZE(api->prefix.prefixlen)); 2828 copy(buf, data[pos:pos+byteLen]) 2829 b.Prefix.Prefix = ipFromFamily(b.Prefix.Family, buf) 2830 pos += byteLen 2831 2832 if version > 3 && b.Message&messageSRCPFX.ToEach(version, software) > 0 { 2833 if pos+1 > rest { 2834 return fmt.Errorf("MessageSRCPFX message length invalid pos:%d rest:%d", pos, rest) 2835 } 2836 //frr: STREAM_GETC(s, api->src_prefix.prefixlen); 2837 b.srcPrefix.PrefixLen = data[pos] 2838 if b.srcPrefix.PrefixLen > addrBitLen { 2839 return fmt.Errorf("prefix length is greater than %d", addrByteLen*8) 2840 } 2841 pos++ 2842 buf = make([]byte, addrByteLen) 2843 byteLen = int((b.srcPrefix.PrefixLen + 7) / 8) 2844 if pos+byteLen > rest { 2845 return fmt.Errorf("MessageSRCPFX message length invalid pos:%d rest:%d", pos, rest) 2846 } 2847 //frr: STREAM_GET(&api->src_prefix.prefix, s, PSIZE(api->src_prefix.prefixlen)); 2848 copy(buf, data[pos:pos+byteLen]) 2849 b.srcPrefix.Prefix = ipFromFamily(b.Prefix.Family, buf) 2850 pos += byteLen 2851 } 2852 2853 // NHG(Nexthop Group) is added in frr8 2854 //frr: if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NHG)) 2855 if version == 6 && software.name == "frr" && software.version >= 8 { // added in frr8 2856 if b.Message&messageNhg.ToEach(version, software) > 0 { 2857 //frr: STREAM_GETL(s, api->nhgid); 2858 b.nhgid = binary.BigEndian.Uint32(data[pos : pos+4]) 2859 pos += 4 2860 } 2861 } 2862 2863 b.Nexthops = []Nexthop{} 2864 if b.Message&MessageNexthop.ToEach(version, software) > 0 { 2865 offset, err := b.decodeMessageNexthopFromBytes(data[pos:], version, software, false) 2866 if err != nil { 2867 return err 2868 } 2869 pos += offset 2870 } 2871 2872 b.backupNexthops = []Nexthop{} // backupNexthops is added in frr7.4 2873 if b.Message&messageBackupNexthops.ToEach(version, software) > 0 { 2874 offset, err := b.decodeMessageNexthopFromBytes(data[pos:], version, software, true) 2875 if err != nil { 2876 return err 2877 } 2878 pos += offset 2879 } 2880 2881 // version 5 only, In version 6, EvpnRoute is processed in MessageNexthop 2882 if version == 5 && b.Flags&flagEvpnRoute.ToEach(version, software) > 0 { 2883 b.Nexthops = append(b.Nexthops, evpnNexthop) 2884 } 2885 2886 if version < 5 && b.Message&messageIFIndex > 0 { // version 4, 3, 2 2887 if pos+1 > rest { 2888 return fmt.Errorf("MessageIFIndex message length invalid pos:%d rest:%d", pos, rest) 2889 } 2890 numIfIndex := uint8(data[pos]) 2891 pos++ 2892 for i := 0; i < int(numIfIndex); i++ { 2893 if pos+4 > rest { 2894 return fmt.Errorf("MessageIFIndex message length invalid pos:%d rest:%d", pos, rest) 2895 } 2896 var nexthop Nexthop 2897 nexthop.Ifindex = binary.BigEndian.Uint32(data[pos : pos+4]) 2898 nexthop.Type = nexthopTypeIFIndex 2899 b.Nexthops = append(b.Nexthops, nexthop) 2900 pos += 4 2901 } 2902 } 2903 2904 if b.Message&MessageDistance.ToEach(version, software) > 0 { 2905 if pos+1 > rest { 2906 return fmt.Errorf("MessageDistance message length invalid pos:%d rest:%d", pos, rest) 2907 } 2908 b.Distance = data[pos] //frr: STREAM_GETC(s, api->distance); 2909 pos++ 2910 } 2911 if b.Message&MessageMetric.ToEach(version, software) > 0 { 2912 if pos+4 > rest { 2913 return fmt.Errorf("MessageMetric message length invalid pos:%d rest:%d", pos, rest) 2914 } 2915 //frr: STREAM_GETL(s, api->metric); 2916 b.Metric = binary.BigEndian.Uint32(data[pos : pos+4]) 2917 pos += 4 2918 } 2919 if b.Message&messageTag.ToEach(version, software) > 0 { 2920 if pos+4 > rest { 2921 return fmt.Errorf("MessageTag message length invalid pos:%d rest:%d", pos, rest) 2922 } 2923 //frr: STREAM_GETL(s, api->tag); 2924 b.tag = binary.BigEndian.Uint32(data[pos : pos+4]) 2925 pos += 4 2926 } 2927 //frr3 and quagga does not have MESSAGE_MTU 2928 if b.Message&MessageMTU.ToEach(version, software) > 0 { 2929 if pos+4 > rest { 2930 return fmt.Errorf("MessageMTU message length invalid pos:%d rest:%d", pos, rest) 2931 } 2932 //frr: STREAM_GETL(s, api->mtu); 2933 b.Mtu = binary.BigEndian.Uint32(data[pos : pos+4]) 2934 pos += 4 2935 } 2936 //frr5 and later version have MESSAGE_TABLEID 2937 if b.Message&messageTableID.ToEach(version, software) > 0 { 2938 if pos+4 > rest { 2939 return fmt.Errorf("MessageTableID message length invalid pos:%d rest:%d", pos, rest) 2940 } 2941 //frr: STREAM_GETL(s, api->mtu); 2942 b.Mtu = binary.BigEndian.Uint32(data[pos : pos+4]) 2943 pos += 4 2944 } 2945 2946 if version == 6 && software.name == "frr" && software.version >= 8 { // added in frr8 2947 if b.Message&messageOpaque.ToEach(version, software) > 0 { 2948 b.opaque.length = binary.BigEndian.Uint16(data[pos : pos+2]) 2949 copy(b.opaque.data[0:b.opaque.length], data[pos+2:pos+2+int(b.opaque.length)]) 2950 pos += 2 + int(b.opaque.length) 2951 } 2952 } 2953 2954 if pos != rest { 2955 return fmt.Errorf("message length invalid (last) pos:%d rest:%d, message:%#x", pos, rest, b.Message) 2956 } 2957 return nil 2958 } 2959 2960 func (b *IPRouteBody) string(version uint8, software Software) string { 2961 s := fmt.Sprintf( 2962 "type: %s, instance: %d, flags: %s, message: %d(%s), safi: %s, prefix: %s/%d, src_prefix: %s/%d", 2963 b.Type.String(), b.instance, b.Flags.String(version, software), b.Message, 2964 b.Message.string(version, software), b.Safi.String(), b.Prefix.Prefix.String(), b.Prefix.PrefixLen, 2965 b.srcPrefix.Prefix.String(), b.srcPrefix.PrefixLen) 2966 for i, nh := range b.Nexthops { 2967 s += fmt.Sprintf(", nexthops[%d]: %s", i, nh.string()) 2968 } 2969 return s + fmt.Sprintf( 2970 ", nhgid:%d, distance: %d, metric: %d, mtu: %d, tag: %d", 2971 b.nhgid, b.Distance, b.Metric, b.Mtu, b.tag) 2972 } 2973 2974 // lookupBody is combination of nexthopLookupBody and imporetLookupBody 2975 type lookupBody struct { 2976 api APIType 2977 prefixLength uint8 // importLookup serialize only 2978 addr net.IP //it is same as prefix (it is deleted from importLookup) 2979 distance uint8 // nexthopIPv4LookupMRIB only 2980 metric uint32 2981 nexthops []Nexthop 2982 } 2983 2984 // Quagga only. Ref: zread_ipv4_(nexthop|import_lookup) in zebra/zserv.c 2985 func (b *lookupBody) serialize(version uint8, software Software) ([]byte, error) { 2986 buf := make([]byte, 0) 2987 if b.api == zapi3IPv4ImportLookup { 2988 buf = append(buf, b.prefixLength) 2989 } 2990 switch b.api { 2991 case ipv4NexthopLookupMRIB, zapi3IPv4NexthopLookup, zapi3IPv4ImportLookup: 2992 buf = append(buf, b.addr.To4()...) 2993 case zapi3IPv6NexthopLookup: 2994 buf = append(buf, b.addr.To16()...) 2995 } 2996 return buf, nil 2997 } 2998 2999 // Quagga only(except ipv4NexthopLookupMRIB). 3000 // Ref: zsend_ipv[4|6]_(nexthop|import)_lookup in zebra/zserv.c 3001 func (b *lookupBody) decodeFromBytes(data []byte, version uint8, software Software) error { 3002 family := uint8(syscall.AF_INET) 3003 if b.api == zapi3IPv6NexthopLookup { 3004 family = syscall.AF_INET6 3005 } 3006 addrByteLen, _ := addressByteLength(family) 3007 requiredLen := 5 //metric(4), numNexthop(1) 3008 hasDistance := false 3009 if b.api == ipv4NexthopLookupMRIB.ToEach(version, software) { 3010 requiredLen++ //distance 3011 hasDistance = true 3012 } 3013 if len(data) < addrByteLen+requiredLen { 3014 return fmt.Errorf("message length invalid") 3015 } 3016 buf := make([]byte, addrByteLen) 3017 copy(buf, data[0:addrByteLen]) 3018 pos := addrByteLen 3019 b.addr = ipFromFamily(family, buf) 3020 if hasDistance { 3021 b.distance = data[pos] 3022 pos++ 3023 } 3024 b.metric = binary.BigEndian.Uint32(data[pos : pos+4]) 3025 pos += 4 3026 numNexthop := uint16(data[pos]) 3027 pos++ 3028 b.nexthops = []Nexthop{} 3029 processFlag := nexthopHasType | nexthopProcessIFnameToIFindex 3030 nexthopsByteLen, err := decodeNexthops(&b.nexthops, data[pos:], version, software, family, numNexthop, processFlag, MessageFlag(0), Flag(0), nexthopType(0)) 3031 if err != nil { 3032 return err 3033 } 3034 pos += nexthopsByteLen 3035 return nil 3036 } 3037 func (b *lookupBody) string(version uint8, software Software) string { 3038 s := fmt.Sprintf( 3039 "addr/prefixLength: %s/%d, distance:%d, metric: %d", 3040 b.addr.String(), b.prefixLength, b.distance, b.metric) 3041 if len(b.nexthops) > 0 { 3042 for _, nh := range b.nexthops { 3043 s = s + fmt.Sprintf(", nexthop:{%s}", nh.string()) 3044 } 3045 } 3046 return s 3047 } 3048 3049 // RegisteredNexthop is referred in zclient 3050 type RegisteredNexthop struct { 3051 connected uint8 3052 resolveViaDef uint8 // added in frr8.2 3053 safi uint16 // added in frr8.2 3054 Family uint16 3055 // Note: Ignores PrefixLength (uint8), because this field should be always: 3056 // - 32 if Address Family is AF_INET 3057 // - 128 if Address Family is AF_INET6 3058 Prefix net.IP 3059 } 3060 3061 func (n *RegisteredNexthop) len() int { 3062 // Connected (1 byte) + Address Family (2 bytes) + Prefix Length (1 byte) + Prefix (variable) 3063 if n.Family == uint16(syscall.AF_INET) { 3064 return 4 + net.IPv4len 3065 } 3066 return 4 + net.IPv6len 3067 } 3068 3069 // Ref: sendmsg_nexthop in bgpd/bgp_nht.c of Quagga1.2.x (ZAPI3) 3070 // Ref: sendmsg_zebra_rnh in bgpd/bgp_nht.c of FRR3.x (ZAPI4) 3071 // Ref: zclient_send_rnh in lib/zclient.c of FRR5&FRR6&FRR7.x&FRR8 (ZAPI5&6) 3072 func (n *RegisteredNexthop) serialize(version uint8, software Software) ([]byte, error) { 3073 bufInitSize := 4 3074 if version == 6 && software.name == "frr" && software.version >= 8.2 { 3075 bufInitSize = 7 3076 } 3077 buf := make([]byte, bufInitSize) 3078 // Connected (1 byte) 3079 buf[0] = byte(n.connected) // stream_putc(s, (connected) ? 1 : 0); 3080 pos := 1 3081 if version == 6 && software.name == "frr" && software.version >= 8.2 { 3082 buf[1] = byte(n.resolveViaDef) 3083 binary.BigEndian.PutUint16(buf[1:3], uint16(SafiUnicast)) // stream_putw(s, PREFIX_FAMILY(p)); 3084 pos += 3 3085 } 3086 // Address Family (2 bytes) 3087 binary.BigEndian.PutUint16(buf[pos:pos+2], n.Family) // stream_putw(s, PREFIX_FAMILY(p)); 3088 pos += 2 3089 // Prefix Length (1 byte) 3090 addrByteLen, err := addressByteLength(uint8(n.Family)) 3091 if err != nil { 3092 return nil, err 3093 } 3094 3095 buf[3] = byte(addrByteLen * 8) // stream_putc(s, p->prefixlen); 3096 pos += 1 3097 // Prefix (variable) 3098 switch n.Family { 3099 case uint16(syscall.AF_INET): 3100 buf = append(buf, n.Prefix.To4()...) // stream_put_in_addr(s, &p->u.prefix4); 3101 case uint16(syscall.AF_INET6): 3102 buf = append(buf, n.Prefix.To16()...) // stream_put(s, &(p->u.prefix6), 16); 3103 default: 3104 return nil, fmt.Errorf("invalid address family: %d", n.Family) 3105 } 3106 3107 return buf, nil 3108 } 3109 3110 // Ref: zserv_nexthop_register in zebra/zserv.c of Quagga1.2.x (ZAPI3) 3111 // Ref: zserv_rnh_register in zebra/zserv.c of FRR3.x (ZAPI4) 3112 // Ref: zread_rnh_register in zebra/zapi_msg.c of FRR5&FRR6&FRR7.x&FRR8 (ZAPI5&6) 3113 func (n *RegisteredNexthop) decodeFromBytes(data []byte, version uint8, software Software) error { 3114 // Connected (1 byte) 3115 n.connected = uint8(data[0]) 3116 data = data[1:] 3117 if version == 6 && software.name == "frr" && software.version >= 8.2 { 3118 n.resolveViaDef = uint8(data[0]) //STREAM_GETC(s, resolve_via_default); 3119 n.safi = binary.BigEndian.Uint16(data[1:3]) //STREAM_GETW(s, safi); 3120 data = data[3:] 3121 } 3122 // Address Family (2 bytes) 3123 n.Family = binary.BigEndian.Uint16(data[0:2]) 3124 // Note: Ignores Prefix Length (1 byte) 3125 addrByteLen := (int(data[2]) + 7) / 8 3126 // Prefix (variable) 3127 n.Prefix = ipFromFamily(uint8(n.Family), data[3:3+addrByteLen]) 3128 3129 return nil 3130 } 3131 3132 func (n *RegisteredNexthop) string(version uint8, software Software) string { 3133 return fmt.Sprintf( 3134 "connected: %d, resolveViaDef:%d, safi: %d, family: %d, prefix: %s", 3135 n.connected, n.resolveViaDef, n.safi, n.Family, n.Prefix.String()) 3136 } 3137 3138 // NexthopRegisterBody us referred in zclient 3139 type NexthopRegisterBody struct { 3140 api APIType 3141 Nexthops []*RegisteredNexthop 3142 } 3143 3144 // Ref: sendmsg_nexthop in bgpd/bgp_nht.c of Quagga1.2.x (ZAPI3) 3145 // Ref: sendmsg_zebra_rnh in bgpd/bgp_nht.c of FRR3.x (ZAPI4) 3146 // Ref: zclient_send_rnh in lib/zclient.c of FRR5&FRR6&FRR7.x&FRR8 (ZAPI5&6) 3147 func (b *NexthopRegisterBody) serialize(version uint8, software Software) ([]byte, error) { 3148 buf := make([]byte, 0) 3149 3150 // List of Registered Nexthops 3151 for _, nh := range b.Nexthops { 3152 nhBuf, err := nh.serialize(version, software) 3153 if err != nil { 3154 return nil, err 3155 } 3156 buf = append(buf, nhBuf...) 3157 } 3158 3159 return buf, nil 3160 } 3161 3162 // Ref: zserv_nexthop_register in zebra/zserv.c of Quagga1.2.x (ZAPI3) 3163 // Ref: zserv_rnh_register in zebra/zserv.c of FRR3.x (ZAPI4) 3164 // Ref: zread_rnh_register in zebra/zapi_msg.c of FRR5.x (ZAPI5) 3165 func (b *NexthopRegisterBody) decodeFromBytes(data []byte, version uint8, software Software) error { 3166 offset := 0 3167 // List of Registered Nexthops 3168 b.Nexthops = []*RegisteredNexthop{} 3169 for len(data[offset:]) > 0 { 3170 nh := new(RegisteredNexthop) 3171 err := nh.decodeFromBytes(data[offset:], version, software) 3172 if err != nil { 3173 return err 3174 } 3175 b.Nexthops = append(b.Nexthops, nh) 3176 3177 offset += nh.len() 3178 if len(data) < offset { 3179 break 3180 } 3181 } 3182 return nil 3183 } 3184 3185 func (b *NexthopRegisterBody) string(version uint8, software Software) string { 3186 s := make([]string, 0) 3187 for _, nh := range b.Nexthops { 3188 s = append(s, fmt.Sprintf("nexthop:{%s}", nh.string(version, software))) 3189 } 3190 return strings.Join(s, ", ") 3191 } 3192 3193 // NexthopUpdateBody uses same data structure as IPRoute (zapi_route) after frr4 (Zapi5) 3194 type NexthopUpdateBody IPRouteBody 3195 3196 // Ref: send_client in zebra/zebra_rnh.c of Quagga1.2&FRR3&FRR5(ZAPI3&4$5) and until FRR7.4 3197 // Ref: zebra_send_rnh_update zebra/zebra_rnh.c of FRR7.5&FRR8 3198 func (b *NexthopUpdateBody) serialize(version uint8, software Software) ([]byte, error) { 3199 var buf []byte 3200 offset := 0 3201 // Message (4 bytes) // if (srte_color) stream_putl(s, message); 3202 if version == 6 && software.name == "frr" && software.version >= 7.5 { // since frr7.5 3203 buf = make([]byte, 7) 3204 binary.BigEndian.PutUint32(buf, uint32(b.Message)) 3205 offset += 4 3206 } else { // until frr7.4 3207 buf = make([]byte, 3) 3208 } 3209 3210 // Address Family (2 bytes) 3211 binary.BigEndian.PutUint16(buf[offset:], uint16(b.Prefix.Family)) 3212 addrByteLen, err := addressByteLength(b.Prefix.Family) 3213 if err != nil { 3214 return nil, err 3215 } 3216 3217 buf[offset+2] = byte(addrByteLen * 8) //stream_putc(s, rn->p.prefixlen); 3218 // Prefix Length (1 byte) + Prefix (variable) 3219 switch b.Prefix.Family { 3220 case syscall.AF_INET: 3221 buf = append(buf, b.Prefix.Prefix.To4()...) 3222 case syscall.AF_INET6: 3223 buf = append(buf, b.Prefix.Prefix.To16()...) 3224 default: 3225 return nil, fmt.Errorf("invalid address family: %d", b.Prefix.Family) 3226 } 3227 // SRTE color // if (srte_color) stream_putl(s, srte_color); 3228 if b.Message&messageSRTE > 0 { // since frr 7.5 3229 tmpbuf := make([]byte, 4) 3230 binary.BigEndian.PutUint32(tmpbuf, b.srteColor) 3231 buf = append(buf, tmpbuf...) 3232 } 3233 if version >= 5 { 3234 // Type (1 byte) (if version>=5) 3235 // instance (2 bytes) (if version>=5) 3236 buf = append(buf, byte(b.Type)) 3237 tmpbuf := make([]byte, 2) 3238 binary.BigEndian.PutUint16(tmpbuf, b.instance) 3239 buf = append(buf, tmpbuf...) 3240 } 3241 if version >= 4 { 3242 // Distance (1 byte) (if version>=4) 3243 buf = append(buf, b.Distance) 3244 } 3245 // Metric (4 bytes) 3246 tmpbuf := make([]byte, 4) 3247 binary.BigEndian.PutUint32(tmpbuf, b.Metric) 3248 buf = append(buf, tmpbuf...) 3249 // Number of Nexthops (1 byte) 3250 buf = append(buf, uint8(0)) // Temporary code 3251 // ToDo Processing Route Entry 3252 return buf, nil 3253 } 3254 3255 // Ref: bgp_parse_nexthop_update in bgpd/bgp_nht.c of Quagga1.2&FRR3 (ZAPI3&4) 3256 // Ref: zapi_nexthop_update_decode in lib/zclient.c of FRR5.x&FRR6&FRR7.x&FRR8 (ZAPI5&6) 3257 func (b *NexthopUpdateBody) decodeFromBytes(data []byte, version uint8, software Software) error { 3258 if version == 6 && software.name == "frr" && software.version >= 7.5 { // since frr7.5 3259 //Message //frr7.5: STREAM_GETL(s, nhr->message); 3260 b.Message = MessageFlag(binary.BigEndian.Uint32(data[0:4])) 3261 data = data[4:] 3262 if software.version >= 8.2 { //added in frr8.2 3263 b.Safi = Safi(binary.BigEndian.Uint16(data[0:2])) 3264 var match Prefix 3265 match.Family = uint8(binary.BigEndian.Uint16(data[2:4])) // STREAM_GETC(s, match->prefixlen); 3266 match.PrefixLen = data[4] // STREAM_GETC(s, match->prefixlen); 3267 addrByteLen, err := addressByteLength(match.Family) 3268 if err != nil { 3269 return err 3270 } 3271 match.Prefix = ipFromFamily(b.Prefix.Family, data[5:5+addrByteLen]) 3272 data = data[5+addrByteLen:] 3273 } 3274 } 3275 // Address Family (2 bytes) and Prefix Length (1 byte) 3276 prefixFamily := binary.BigEndian.Uint16(data[0:2]) 3277 b.Prefix.Family = uint8(prefixFamily) 3278 b.Prefix.PrefixLen = data[2] 3279 offset := 3 3280 3281 addrByteLen, err := addressByteLength(b.Prefix.Family) 3282 if err != nil { 3283 return err 3284 } 3285 3286 b.Prefix.Prefix = ipFromFamily(b.Prefix.Family, data[offset:offset+addrByteLen]) 3287 offset += addrByteLen 3288 3289 if b.Message&messageSRTE > 0 { // since frr 7.5 3290 b.srteColor = binary.BigEndian.Uint32(data[offset : offset+4]) 3291 offset += 4 3292 } 3293 3294 if version > 4 { 3295 // Route Type (1 byte) and insrance (2 bytes) 3296 b.Type = RouteType(data[offset]) 3297 b.instance = binary.BigEndian.Uint16(data[offset+1 : offset+3]) 3298 offset += 3 3299 } 3300 // Distance (1 byte) (if version>=4) 3301 if version > 3 { 3302 b.Distance = data[offset] 3303 offset++ 3304 } 3305 // Metric (4 bytes) & Number of Nexthops (1 byte) 3306 if len(data[offset:]) < 5 { 3307 return fmt.Errorf("invalid message length: missing metric(4 bytes) or nexthops(1 byte): %d<5", len(data[offset:])) 3308 } 3309 b.Metric = binary.BigEndian.Uint32(data[offset : offset+4]) 3310 offset += 4 3311 3312 numNexthop := uint16(data[offset]) 3313 offset++ 3314 // List of Nexthops 3315 b.Nexthops = []Nexthop{} 3316 3317 processFlag := nexthopProcessFlag(nexthopHasType) 3318 if version == 6 && software.name == "frr" { 3319 if software.version >= 7.3 { 3320 processFlag |= (nexthopHasVrfID | nexthopHasFlag | nexthopProcessIPToIPIFindex) 3321 } else if software.version >= 7 { 3322 processFlag |= (nexthopHasVrfID | nexthopProcessIPToIPIFindex) 3323 } else if software.version >= 6 { 3324 processFlag |= nexthopProcessIPToIPIFindex 3325 } 3326 } else if version == 5 && software.name == "frr" && software.version == 5 { 3327 processFlag |= nexthopProcessIPToIPIFindex 3328 } else if version < 4 { // quagga 3329 processFlag |= nexthopProcessIFnameToIFindex 3330 } 3331 3332 // since frr7.3, MessageLabel is deleted 3333 if (version == 6 && software.name == "frr" && software.version < 7.3) || 3334 (version == 5 && software.name == "frr" && software.version == 5) { 3335 b.Message |= MessageLabel 3336 } 3337 3338 nexthopsByteLen, err := decodeNexthops(&b.Nexthops, data[offset:], version, software, b.Prefix.Family, numNexthop, processFlag, b.Message, Flag(0), nexthopType(0)) 3339 if err != nil { 3340 return err 3341 } 3342 offset += nexthopsByteLen 3343 return nil 3344 } 3345 3346 func (b *NexthopUpdateBody) string(version uint8, software Software) string { 3347 s := fmt.Sprintf( 3348 "family: %d, prefix: %s, distance: %d, metric: %d", 3349 b.Prefix.Family, b.Prefix.Prefix.String(), b.Distance, b.Metric) 3350 for _, nh := range b.Nexthops { 3351 s = s + fmt.Sprintf(", nexthop:{%s}", nh.string()) 3352 } 3353 return s 3354 } 3355 3356 type labelManagerConnectBody struct { 3357 redistDefault RouteType 3358 instance uint16 3359 // The followings are used in response from Zebra 3360 result uint8 // 0 means success 3361 } 3362 3363 // Ref: lm_label_manager_connect in lib/zclient.c of FRR 3364 func (b *labelManagerConnectBody) serialize(version uint8, software Software) ([]byte, error) { 3365 buf := make([]byte, 3) 3366 buf[0] = uint8(b.redistDefault) 3367 binary.BigEndian.PutUint16(buf[1:3], b.instance) 3368 return buf, nil 3369 } 3370 3371 func (b *labelManagerConnectBody) decodeFromBytes(data []byte, version uint8, software Software) error { 3372 size := 1 3373 if version > 4 && !(software.name == "frr" && software.version == 4) { // FRR4 returns result only. 3374 size = 4 3375 } 3376 if len(data) < size { 3377 return fmt.Errorf("invalid message length for LabelManagerConnect response: %d<%d", 3378 len(data), size) 3379 } 3380 if version > 4 && !(software.name == "frr" && software.version == 4) { 3381 b.redistDefault = RouteType(data[0]) 3382 b.instance = binary.BigEndian.Uint16(data[1:3]) 3383 data = data[3:] 3384 } 3385 b.result = data[0] 3386 return nil 3387 } 3388 3389 func (b *labelManagerConnectBody) string(version uint8, software Software) string { 3390 return fmt.Sprintf( 3391 "route_type: %s, instance: %d, result: %d", 3392 b.redistDefault.String(), b.instance, b.result) 3393 } 3394 3395 // GetLabelChunkBody is referred in zclient (Ref: zsend_assign_label_chunk_response) 3396 type GetLabelChunkBody struct { 3397 proto uint8 // it is appeared in FRR5.x and 6.x 3398 instance uint16 // it is appeared in FRR5.x and 6.x 3399 keep uint8 3400 ChunkSize uint32 3401 Start uint32 // The followings are used in response from Zebra 3402 End uint32 3403 base uint32 // it is added in FRR7.2 3404 } 3405 3406 // Ref: zread_get_label_chunk in zebra/zserv.c of FRR3.x 3407 // Ref: zread_get_label_chunk in zebra/zapi_msg.c of FRR5.x, 6.x, 7,x, and 8 3408 func (b *GetLabelChunkBody) serialize(version uint8, software Software) ([]byte, error) { 3409 buf := make([]byte, 12) 3410 pos := 0 3411 b.base = 0 3412 if version > 4 && !(software.name == "frr" && software.version == 4) { 3413 buf[pos] = b.proto 3414 binary.BigEndian.PutUint16(buf[pos+1:pos+3], b.instance) 3415 pos += 3 3416 } 3417 buf[pos] = b.keep 3418 binary.BigEndian.PutUint32(buf[pos+1:pos+5], b.ChunkSize) 3419 pos += 5 3420 if version == 6 && software.name == "frr" && software.version >= 7.2 { 3421 binary.BigEndian.PutUint32(buf[pos:pos+4], b.base) 3422 pos += 4 3423 } 3424 return buf[0:pos], nil 3425 } 3426 3427 // Ref: zsend_assign_label_chunk_response in zebra/zserv.c of FRR3.x 3428 // Ref: zsend_assign_label_chunk_response in zebra/zapi_msg.c of FRR5.x, 6.x, 7,x, and 8 3429 func (b *GetLabelChunkBody) decodeFromBytes(data []byte, version uint8, software Software) error { 3430 size := 9 3431 if version > 4 && !(software.name == "frr" && software.version == 4) { 3432 size = 12 3433 } 3434 if len(data) < size { 3435 return fmt.Errorf("invalid message length for GetLabelChunk response: %d<%d", 3436 len(data), size) 3437 } 3438 if version > 4 && !(software.name == "frr" && software.version == 4) { 3439 b.proto = data[0] 3440 b.instance = binary.BigEndian.Uint16(data[1:3]) 3441 data = data[3:] 3442 } 3443 b.keep = data[0] 3444 b.Start = binary.BigEndian.Uint32(data[1:5]) 3445 b.End = binary.BigEndian.Uint32(data[5:9]) 3446 return nil 3447 } 3448 3449 func (b *GetLabelChunkBody) string(version uint8, software Software) string { 3450 return fmt.Sprintf( 3451 "keep: %d, chunk_size: %d, start: %d, end: %d", 3452 b.keep, b.ChunkSize, b.Start, b.End) 3453 } 3454 3455 type releaseLabelChunkBody struct { 3456 proto uint8 // it is added in FRR5.x 3457 instance uint16 // it is added in FRR5.x 3458 start uint32 3459 end uint32 3460 } 3461 3462 // Ref: zread_release_label_chunk in zebra/zapi_msg.c of FRR 3463 func (b *releaseLabelChunkBody) serialize(version uint8, software Software) ([]byte, error) { 3464 buf := make([]byte, 11) 3465 pos := 0 3466 if version > 4 && !(software.name == "frr" && software.version == 4) { 3467 buf[pos] = b.proto 3468 binary.BigEndian.PutUint16(buf[pos+1:pos+3], b.instance) 3469 pos += 3 3470 } 3471 binary.BigEndian.PutUint32(buf[pos:pos+4], b.start) 3472 binary.BigEndian.PutUint32(buf[pos+4:pos+8], b.end) 3473 pos += 8 3474 return buf[0:pos], nil 3475 } 3476 3477 func (b *releaseLabelChunkBody) decodeFromBytes(data []byte, version uint8, software Software) error { 3478 return nil // No response from Zebra 3479 } 3480 3481 func (b *releaseLabelChunkBody) string(version uint8, software Software) string { 3482 return fmt.Sprintf("start: %d, end: %d", b.start, b.end) 3483 } 3484 3485 //go:generate stringer -type=lspTYPE 3486 type lspTYPE uint8 3487 3488 const ( 3489 lspNone lspTYPE = iota //defined in FRR3 and over 3490 lspStatic //defined in FRR3 and over 3491 lspLDP //defined in FRR3 and over 3492 lspBGP //defined in FRR4 and over 3493 lspSR //defined in FRR4 and over 3494 lspSHARP //defined in FRR5 and over 3495 ) 3496 3497 type vrfLabelBody struct { 3498 label uint32 3499 afi afi 3500 labelType lspTYPE 3501 } 3502 3503 // Ref: zclient_send_vrf_label in lib/zclient.c of FRR 5.x, 6.x, 7.x, and 8 3504 func (b *vrfLabelBody) serialize(version uint8, software Software) ([]byte, error) { 3505 buf := make([]byte, 6) 3506 binary.BigEndian.PutUint32(buf[0:4], b.label) 3507 buf[4] = uint8(b.afi) 3508 buf[5] = uint8(b.labelType) 3509 return buf, nil 3510 } 3511 3512 // Ref: zread_vrf_label in zebra/zapi_msg.c of FRR 5.x, 6.x, 7.x, and 8 3513 func (b *vrfLabelBody) decodeFromBytes(data []byte, version uint8, software Software) error { 3514 if len(data) < 6 { 3515 return fmt.Errorf("invalid message length for VRFLabel message: %d<6", len(data)) 3516 } 3517 b.label = binary.BigEndian.Uint32(data[0:4]) 3518 b.afi = afi(data[4]) 3519 b.labelType = lspTYPE(data[5]) 3520 return nil 3521 } 3522 3523 func (b *vrfLabelBody) string(version uint8, software Software) string { 3524 return fmt.Sprintf( 3525 "label: %d, afi: %s LSP type: %s", 3526 b.label, b.afi, b.labelType) 3527 } 3528 3529 // Message is referred in zclient 3530 type Message struct { 3531 Header Header 3532 Body Body 3533 } 3534 3535 func (m *Message) Serialize(software Software) ([]byte, error) { 3536 var body []byte 3537 if m.Body != nil { 3538 var err error 3539 body, err = m.Body.serialize(m.Header.Version, software) 3540 if err != nil { 3541 return nil, err 3542 } 3543 } 3544 m.Header.Len = uint16(len(body)) + HeaderSize(m.Header.Version) 3545 hdr, err := m.Header.serialize() 3546 if err != nil { 3547 return nil, err 3548 } 3549 return append(hdr, body...), nil 3550 } 3551 3552 func parseMessage(hdr *Header, data []byte, software Software) (m *Message, err error) { 3553 m = &Message{Header: *hdr} 3554 /* TODO: 3555 InterfaceNBRAddressAdd, InterfaceNBRAddressDelete, 3556 InterfaceBFDDestUpdate, ImportCheckUpdate, BFDDestReplay, 3557 InterfaceVRFUpdate, InterfaceLinkParams, PWStatusUpdate 3558 */ 3559 command := m.Header.Command.ToCommon(m.Header.Version, software) 3560 switch command { 3561 case interfaceAdd, interfaceDelete, interfaceUp, interfaceDown: 3562 m.Body = &interfaceUpdateBody{} 3563 case interfaceAddressAdd, interfaceAddressDelete: 3564 m.Body = &interfaceAddressUpdateBody{} 3565 case routerIDUpdate: 3566 m.Body = &routerIDUpdateBody{} 3567 case nexthopUpdate: 3568 m.Body = &NexthopUpdateBody{} 3569 case RedistributeRouteAdd, RedistributeRouteDel: // for frr 3570 m.Body = &IPRouteBody{API: m.Header.Command} 3571 case labelManagerConnect: // Note: Synchronous message 3572 m.Body = &labelManagerConnectBody{} 3573 case getLabelChunk: // Note: Synchronous message 3574 m.Body = &GetLabelChunkBody{} 3575 case releaseLabelChunk: // Note: Synchronous message 3576 m.Body = &releaseLabelChunkBody{} 3577 case vrfLabel: 3578 m.Body = &vrfLabelBody{} 3579 case RouteAdd, RouteDelete, BackwardIPv6RouteAdd, BackwardIPv6RouteDelete: // for quagga 3580 m.Body = &IPRouteBody{API: m.Header.Command} 3581 case ipv4NexthopLookupMRIB: 3582 m.Body = &lookupBody{api: m.Header.Command} 3583 default: 3584 m.Body = &unknownBody{} 3585 if m.Header.Version == 4 { 3586 switch m.Header.Command { 3587 case zapi4RedistributeIPv6Add, zapi4RedistributeIPv6Del: // for frr3 3588 m.Body = &IPRouteBody{API: m.Header.Command} 3589 } 3590 } else if m.Header.Version < 4 { 3591 switch m.Header.Command { 3592 case zapi3IPv4NexthopLookup, zapi3IPv6NexthopLookup, zapi3IPv4ImportLookup: 3593 m.Body = &lookupBody{api: m.Header.Command} 3594 } 3595 } 3596 } 3597 return m, m.Body.decodeFromBytes(data, m.Header.Version, software) 3598 }