diff options
Diffstat (limited to 'internal/pkg/zebra/zapi.go')
-rw-r--r-- | internal/pkg/zebra/zapi.go | 4175 |
1 files changed, 1915 insertions, 2260 deletions
diff --git a/internal/pkg/zebra/zapi.go b/internal/pkg/zebra/zapi.go index cbae40f0..eb4d243a 100644 --- a/internal/pkg/zebra/zapi.go +++ b/internal/pkg/zebra/zapi.go @@ -19,761 +19,856 @@ import ( "encoding/binary" "errors" "fmt" + "github.com/osrg/gobgp/pkg/packet/bgp" + log "github.com/sirupsen/logrus" "io" "math" "net" "strings" "syscall" - - log "github.com/sirupsen/logrus" - - "github.com/osrg/gobgp/pkg/packet/bgp" ) const ( - HEADER_MARKER uint8 = 255 - FRR_HEADER_MARKER uint8 = 254 - INTERFACE_NAMSIZ = 20 + // MinZapiVer is minimum zebra api version which is referred in zclient + MinZapiVer uint8 = 2 + // MaxZapiVer is maximum zebra api version which is referredd in zclient + MaxZapiVer uint8 = 6 + // DefaultVrf is default vrf id is referredd in zclient and server + DefaultVrf = 0 ) const ( - MinZapiVer uint8 = 2 - MaxZapiVer uint8 = 6 + headerMarker uint8 = 255 + frrHeaderMarker uint8 = 254 + interfaceNameSize = 20 + maxPathNum = 64 + maxMplsLabel = 16 ) // Internal Interface Status. -type INTERFACE_STATUS uint8 +type interfaceStatus uint8 const ( - INTERFACE_ACTIVE INTERFACE_STATUS = 0x01 - INTERFACE_SUB INTERFACE_STATUS = 0x02 - INTERFACE_LINKDETECTION INTERFACE_STATUS = 0x04 - INTERFACE_VRF_LOOPBACK INTERFACE_STATUS = 0x08 + interfaceActive interfaceStatus = 0x01 + interfaceSub interfaceStatus = 0x02 + interfaceLinkDetection interfaceStatus = 0x04 + interfaceVrfLoopback interfaceStatus = 0x08 ) // Interface Link Layer Types. -//go:generate stringer -type=LINK_TYPE -type LINK_TYPE uint32 +//go:generate stringer -type=linkType +type linkType uint32 const ( - LINK_TYPE_UNKNOWN LINK_TYPE = iota - LINK_TYPE_ETHER - LINK_TYPE_EETHER - LINK_TYPE_AX25 - LINK_TYPE_PRONET - LINK_TYPE_IEEE802 - LINK_TYPE_ARCNET - LINK_TYPE_APPLETLK - LINK_TYPE_DLCI - LINK_TYPE_ATM - LINK_TYPE_METRICOM - LINK_TYPE_IEEE1394 - LINK_TYPE_EUI64 - LINK_TYPE_INFINIBAND - LINK_TYPE_SLIP - LINK_TYPE_CSLIP - LINK_TYPE_SLIP6 - LINK_TYPE_CSLIP6 - LINK_TYPE_RSRVD - LINK_TYPE_ADAPT - LINK_TYPE_ROSE - LINK_TYPE_X25 - LINK_TYPE_PPP - LINK_TYPE_CHDLC - LINK_TYPE_LAPB - LINK_TYPE_RAWHDLC - LINK_TYPE_IPIP - LINK_TYPE_IPIP6 - LINK_TYPE_FRAD - LINK_TYPE_SKIP - LINK_TYPE_LOOPBACK - LINK_TYPE_LOCALTLK - LINK_TYPE_FDDI - LINK_TYPE_SIT - LINK_TYPE_IPDDP - LINK_TYPE_IPGRE - LINK_TYPE_IP6GRE - LINK_TYPE_PIMREG - LINK_TYPE_HIPPI - LINK_TYPE_ECONET - LINK_TYPE_IRDA - LINK_TYPE_FCPP - LINK_TYPE_FCAL - LINK_TYPE_FCPL - LINK_TYPE_FCFABRIC - LINK_TYPE_IEEE802_TR - LINK_TYPE_IEEE80211 - LINK_TYPE_IEEE80211_RADIOTAP - LINK_TYPE_IEEE802154 - LINK_TYPE_IEEE802154_PHY + linkTypeUnknown linkType = iota + linkTypeEther + linkTypeEEther + linkTypeAX25 + linkTypePRONET + linkTypeIeee802 + linkTypeARCNET + linkTypeAPPLETLK + linkTypeDLCI + linkTypeATM + linkTypeMetricOM + linkTypeIeee1394 + linkTypeEUI64 + linkTypeINFINIBAND + linkTypeSLIP + linkTypeCSLIP + linkTypeSLIP6 + linkTypeCSLIP6 + linkTypeRSRVD + linkTypeADAPT + linkTypeROSE + linkTypeX25 + linkTypePPP + linkTypeCHDLC + linkTypeLAPB + linkTypeRAWHDLC + linkTypeIPIP + linkTypeIPIP6 + linkTypeFRAD + linkTypeSKIP + linkTypeLOOPBACK + linkTypeLOCALTLK + linkTypeFDDI + linkTypeSIT + linkTypeIPDDP + linkTypeIPGRE + linkTypeIP6GRE + linkTypePIMREG + linkTypeHIPPI + linkTypeECONET + linkTypeIRDA + linkTypeFCPP + linkTypeFCAL + linkTypeFCPL + linkTypeFCFABRIC + linkTypeIeee802Tr + linkTypeIeee80211 + linkTypeIeee80211RadioTap + linkTypeIeee802154 + linkTypeIeee802154Phy ) -const VRF_DEFAULT = 0 -const MAXPATH_NUM = 64 -const MPLS_MAX_LABEL = 16 - +// HeaderSize returns suitable header size from version func HeaderSize(version uint8) uint16 { switch version { case 3, 4: return 8 case 5, 6: return 10 - default: - return 6 } + return 6 // version == 2 } -func (t INTERFACE_STATUS) String() string { +// HeaderMarker returns suitable header marker from version +func HeaderMarker(version uint8) uint8 { + if version > 3 { + return frrHeaderMarker + } + return headerMarker +} + +func (t interfaceStatus) String() string { ss := make([]string, 0, 3) - if t&INTERFACE_ACTIVE > 0 { - ss = append(ss, "ACTIVE") + if t&interfaceActive > 0 { + ss = append(ss, "Active") } - if t&INTERFACE_SUB > 0 { - ss = append(ss, "SUB") + if t&interfaceSub > 0 { + ss = append(ss, "Sub") } - if t&INTERFACE_LINKDETECTION > 0 { - ss = append(ss, "LINKDETECTION") + if t&interfaceLinkDetection > 0 { + ss = append(ss, "LinkDetection") } - if t&INTERFACE_VRF_LOOPBACK > 0 { - ss = append(ss, "VRF_LOOPBACK") + if t&interfaceVrfLoopback > 0 { + ss = append(ss, "VrfLoopback") } return strings.Join(ss, "|") } // Interface Connected Address Flags -type INTERFACE_ADDRESS_FLAG uint8 +type interfaceAddressFlag uint8 const ( - INTERFACE_ADDRESS_SECONDARY INTERFACE_ADDRESS_FLAG = 0x01 - INTERFACE_ADDRESS_PEER INTERFACE_ADDRESS_FLAG = 0x02 - INTERFACE_ADDRESS_UNNUMBERED INTERFACE_ADDRESS_FLAG = 0x04 + interfaceAddressSecondary interfaceAddressFlag = 0x01 + interfaceAddressPeer interfaceAddressFlag = 0x02 + interfaceAddressUnnumbered interfaceAddressFlag = 0x04 ) -func (t INTERFACE_ADDRESS_FLAG) String() string { +func (t interfaceAddressFlag) String() string { ss := make([]string, 0, 3) - if t&INTERFACE_ADDRESS_SECONDARY > 0 { + if t&interfaceAddressSecondary > 0 { ss = append(ss, "SECONDARY") } - if t&INTERFACE_ADDRESS_PEER > 0 { + if t&interfaceAddressPeer > 0 { ss = append(ss, "PEER") } - if t&INTERFACE_ADDRESS_UNNUMBERED > 0 { + if t&interfaceAddressUnnumbered > 0 { ss = append(ss, "UNNUMBERED") } return strings.Join(ss, "|") } -// Address Family Identifier. -//go:generate stringer -type=AFI -type AFI uint8 +// Address Family IDentifier. +//go:generate stringer -type=afi +type afi uint8 const ( - AFI_IP AFI = 1 - AFI_IP6 AFI = 2 - AFI_ETHER AFI = 3 - AFI_MAX AFI = 4 + afiIP afi = 1 + afiIP6 afi = 2 + afiEther afi = 3 + afiMax afi = 4 ) -// Subsequent Address Family Identifier. -//go:generate stringer -type=SAFI -type SAFI uint8 +// Safi is Subsequent Address Family IDentifier. +//go:generate stringer -type=Safi +type Safi uint8 -// SAFI definition in Zebra of FRRouting 4.x, 5.x, 6.x +// Safi definition in Zebra of FRRouting 4.x, 5.x, 6.x, and 7.x const ( - _ SAFI = iota - FRR_ZAPI5_SAFI_UNICAST - FRR_ZAPI5_SAFI_MULTICAST - FRR_ZAPI5_SAFI_MPLS_VPN - FRR_ZAPI5_SAFI_ENCAP - FRR_ZAPI5_SAFI_EVPN - FRR_ZAPI5_SAFI_LABELED_UNICAST - FRR_ZAPI5_SAFI_FLOWSPEC - FRR_ZAPI5_SAFI_MAX + safiUnspec Safi = iota // add in FRRouting version 7.2 (Zapi 6) + SafiUnicast + safiMulticast + safiMplsVpn + safiEncap + safiEvpn + safiLabeledUnicast + safiFlowspec // add in FRRouting version 5 (Zapi 5) + safiMax ) -// SAFI definition in Zebra of Quagga and FRRouting 3.x +// Safi definition in Zebra of Quagga and FRRouting 3.x const ( - _ SAFI = iota - SAFI_UNICAST - SAFI_MULTICAST - FRR_SAFI_MPLS_VPN // SAFI_RESERVED_3 in quagga - SAFI_MPLS_VPN // SAFI_RESERVED_4 in FRRouting 3.x - FRR_SAFI_ENCAP - FRR_SAFI_EVPN - SAFI_ENCAP // SAFI_MAX in FRRouting 3.x - SAFI_MAX + zapi4SafiMplsVpn Safi = iota + safiMulticast + 1 // SafiRESERVED_3 in quagga + zapi3SafiMplsVpn // SafiRESERVED_4 in FRRouting 3.x + zapi4SafiEncap + zapi4SafiEvpn + zapi3SafiEncap // SafiMax in FRRouting 3.x ) -// API Types. -//go:generate stringer -type=API_TYPE -type API_TYPE uint16 - -// For FRRouting version 7. (ZAPI version 6) +var zapi3SafiMap = map[Safi]Safi{ + zapi3SafiMplsVpn: safiMplsVpn, + zapi3SafiEncap: safiEncap, +} +var zapi4SafiMap = map[Safi]Safi{ + zapi4SafiMplsVpn: safiMplsVpn, + zapi4SafiEncap: safiEncap, + zapi4SafiEvpn: safiEvpn, +} +var safiRouteFamilyIPv4Map = map[Safi]bgp.RouteFamily{ + safiUnspec: bgp.RF_OPAQUE, + SafiUnicast: bgp.RF_IPv4_UC, + safiMulticast: bgp.RF_IPv4_MC, + safiMplsVpn: bgp.RF_IPv4_VPN, + safiEncap: bgp.RF_IPv4_ENCAP, + safiLabeledUnicast: bgp.RF_IPv4_MPLS, + safiFlowspec: bgp.RF_FS_IPv4_UC, +} +var safiRouteFamilyIPv6Map = map[Safi]bgp.RouteFamily{ + safiUnspec: bgp.RF_OPAQUE, + SafiUnicast: bgp.RF_IPv6_UC, + safiMulticast: bgp.RF_IPv6_MC, + safiMplsVpn: bgp.RF_IPv6_VPN, + safiEncap: bgp.RF_IPv6_ENCAP, + safiLabeledUnicast: bgp.RF_IPv6_MPLS, + safiFlowspec: bgp.RF_FS_IPv6_UC, +} + +// APIType is referred in zclient_test. +//go:generate stringer -type=APIType +type APIType uint16 + +// For FRRouting version 7.3 (ZAPI version 6) const ( - FRR_ZAPI6_INTERFACE_ADD API_TYPE = iota - FRR_ZAPI6_INTERFACE_DELETE - FRR_ZAPI6_INTERFACE_ADDRESS_ADD - FRR_ZAPI6_INTERFACE_ADDRESS_DELETE - FRR_ZAPI6_INTERFACE_UP - FRR_ZAPI6_INTERFACE_DOWN - FRR_ZAPI6_INTERFACE_SET_MASTER - //FRR_ZAPI6_INTERFACE_SET_PROTODOWN // Add Frr 7.2 - FRR_ZAPI6_ROUTE_ADD - FRR_ZAPI6_ROUTE_DELETE - FRR_ZAPI6_ROUTE_NOTIFY_OWNER - FRR_ZAPI6_REDISTRIBUTE_ADD - FRR_ZAPI6_REDISTRIBUTE_DELETE - FRR_ZAPI6_REDISTRIBUTE_DEFAULT_ADD - FRR_ZAPI6_REDISTRIBUTE_DEFAULT_DELETE - FRR_ZAPI6_ROUTER_ID_ADD - FRR_ZAPI6_ROUTER_ID_DELETE - FRR_ZAPI6_ROUTER_ID_UPDATE - FRR_ZAPI6_HELLO - FRR_ZAPI6_CAPABILITIES - FRR_ZAPI6_NEXTHOP_REGISTER - FRR_ZAPI6_NEXTHOP_UNREGISTER - FRR_ZAPI6_NEXTHOP_UPDATE - FRR_ZAPI6_INTERFACE_NBR_ADDRESS_ADD - FRR_ZAPI6_INTERFACE_NBR_ADDRESS_DELETE - FRR_ZAPI6_INTERFACE_BFD_DEST_UPDATE - FRR_ZAPI6_IMPORT_ROUTE_REGISTER - FRR_ZAPI6_IMPORT_ROUTE_UNREGISTER - FRR_ZAPI6_IMPORT_CHECK_UPDATE - FRR_ZAPI6_BFD_DEST_REGISTER - FRR_ZAPI6_BFD_DEST_DEREGISTER - FRR_ZAPI6_BFD_DEST_UPDATE - FRR_ZAPI6_BFD_DEST_REPLAY - FRR_ZAPI6_REDISTRIBUTE_ROUTE_ADD - FRR_ZAPI6_REDISTRIBUTE_ROUTE_DEL - FRR_ZAPI6_VRF_UNREGISTER - FRR_ZAPI6_VRF_ADD - FRR_ZAPI6_VRF_DELETE - FRR_ZAPI6_VRF_LABEL - FRR_ZAPI6_INTERFACE_VRF_UPDATE - FRR_ZAPI6_BFD_CLIENT_REGISTER - FRR_ZAPI6_BFD_CLIENT_DEREGISTER - FRR_ZAPI6_INTERFACE_ENABLE_RADV - FRR_ZAPI6_INTERFACE_DISABLE_RADV - FRR_ZAPI6_IPV4_NEXTHOP_LOOKUP_MRIB - FRR_ZAPI6_INTERFACE_LINK_PARAMS - FRR_ZAPI6_MPLS_LABELS_ADD - FRR_ZAPI6_MPLS_LABELS_DELETE - FRR_ZAPI6_IPMR_ROUTE_STATS - FRR_ZAPI6_LABEL_MANAGER_CONNECT - FRR_ZAPI6_LABEL_MANAGER_CONNECT_ASYNC - FRR_ZAPI6_GET_LABEL_CHUNK - FRR_ZAPI6_RELEASE_LABEL_CHUNK - FRR_ZAPI6_FEC_REGISTER - FRR_ZAPI6_FEC_UNREGISTER - FRR_ZAPI6_FEC_UPDATE - FRR_ZAPI6_ADVERTISE_DEFAULT_GW - FRR_ZAPI6_ADVERTISE_SUBNET - FRR_ZAPI6_ADVERTISE_ALL_VNI - FRR_ZAPI6_LOCAL_ES_ADD - FRR_ZAPI6_LOCAL_ES_DEL - FRR_ZAPI6_VNI_ADD - FRR_ZAPI6_VNI_DEL - FRR_ZAPI6_L3VNI_ADD - FRR_ZAPI6_L3VNI_DEL - FRR_ZAPI6_REMOTE_VTEP_ADD - FRR_ZAPI6_REMOTE_VTEP_DEL - FRR_ZAPI6_MACIP_ADD - FRR_ZAPI6_MACIP_DEL - FRR_ZAPI6_IP_PREFIX_ROUTE_ADD - FRR_ZAPI6_IP_PREFIX_ROUTE_DEL - FRR_ZAPI6_REMOTE_MACIP_ADD - FRR_ZAPI6_REMOTE_MACIP_DEL - FRR_ZAPI6_DUPLICATE_ADDR_DETECTION - FRR_ZAPI6_PW_ADD - FRR_ZAPI6_PW_DELETE - FRR_ZAPI6_PW_SET - FRR_ZAPI6_PW_UNSET - FRR_ZAPI6_PW_STATUS_UPDATE - FRR_ZAPI6_RULE_ADD - FRR_ZAPI6_RULE_DELETE - FRR_ZAPI6_RULE_NOTIFY_OWNER - FRR_ZAPI6_TABLE_MANAGER_CONNECT - FRR_ZAPI6_GET_TABLE_CHUNK - FRR_ZAPI6_RELEASE_TABLE_CHUNK - FRR_ZAPI6_IPSET_CREATE - FRR_ZAPI6_IPSET_DESTROY - FRR_ZAPI6_IPSET_ENTRY_ADD - FRR_ZAPI6_IPSET_ENTRY_DELETE - FRR_ZAPI6_IPSET_NOTIFY_OWNER - FRR_ZAPI6_IPSET_ENTRY_NOTIFY_OWNER - FRR_ZAPI6_IPTABLE_ADD - FRR_ZAPI6_IPTABLE_DELETE - FRR_ZAPI6_IPTABLE_NOTIFY_OWNER - FRR_ZAPI6_VXLAN_FLOOD_CONTROL + interfaceAdd APIType = iota // 0 // same ID in frr3, 4, 5, 6, 7.0, 7.1. 7.2. 7.3 + interfaceDelete // same ID in frr3, 4, 5, 6, 7.0, 7.1. 7.2. 7.3 + interfaceAddressAdd // same ID in frr3, 4, 5, 6, 7.0, 7.1. 7.2. 7.3 + interfaceAddressDelete // same ID in frr3, 4, 5, 6, 7.0, 7.1. 7.2. 7.3 + interfaceUp // same ID in frr3, 4, 5, 6, 7.0, 7.1. 7.2. 7.3 + interfaceDown // same ID in frr3, 4, 5, 6, 7.0, 7.1. 7.2. 7.3 + _interfaceSetMaster + _interfaceSetProtoDown // Add in frr 7.2 + RouteAdd // RouteAdd is referred in zclient_test + RouteDelete // RouteDelete is referred in zclient_test + _routeNotifyOwner // 10 + redistributeAdd + _redistributeDelete + _redistributeDefaultAdd + _redistributeDefaultDelete + routerIDAdd + _routerIDDelete + routerIDUpdate + hello + _capabilities // add in frr5 + nexthopRegister // 20 + nexthopUnregister + nexthopUpdate + _interfaceNBRAddressAdd + _interfaceNBRAddressDelete + _interfaceBFDDestUpdate + _importRouteRegister + _importRouteUnregister + _importCheckUpdate + _bfdDestRegister + _bfdDestDeregister // 30 + _bfdDestUpdate + _bfdDestReplay + redistributeRouteAdd + redistributeRouteDel + _vrfUnregister + _vrfAdd + _vrfDelete + vrfLabel // add in frr5 + _interfaceVRFUpdate + _bfdClientRegister // 40 + _bfdClientDeregister + _interfaceEnableRADV + _interfaceDisableRADV + ipv4NexthopLookupMRIB + _interfaceLinkParams + _mplsLabelsAdd + _mplsLabelsDelete + _mplsLabelsReplace // add in frr7.3 + _ipmrRouteStats + labelManagerConnect // 50 + labelManagerConnectAsync // add in frr5 + getLabelChunk + releaseLabelChunk + _fecRegister + _fecUnregister + _fecUpdate + _advertiseDefaultGW + _advertiseSviMACIP // add in frr7.1 + _advertiseSubnet + _advertiseAllVNI // 60 + _localESAdd + _localESDel + _vniAdd + _vniDel + _l3VNIAdd + _l3VNIDel + _remoteVTEPAdd + _remoteVTEPDel + _macIPAdd + _macIPDel // 70 + _ipPrefixRouteAdd + _ipPrefixRouteDel + _remoteMACIPAdd + _remoteMACIPDel + _duplicateAddrDetection + _pwAdd + _pwDelete + _pwSet + _pwUnset + _pwStatusUpdate // 80 + _ruleAdd + _ruleDelete + _ruleNotifyOwner + _tableManagerConnect + _getTableChunk + _releaseTableChunk + _ipSetCreate + _ipSetDestroy + _ipSetEntryAdd + _ipSetEntryDelete // 90 + _ipSetNotifyOwner + _ipSetEntryNotifyOwner + _ipTableAdd + _ipTableDelete + _ipTableNotifyOwner + _vxlanFloodControl + _vxlanSgAdd + _vxlanSgDel + _vxlanSgReplay + _mlagProcessUp // 100 // add in frr7.3 + _mlagProcessDown // add in frr7.3 + _mlagClientRegister // add in frr7.3 + _mlagClientUnregister // add in frr7.3 + _mlagClientForwardMsg // add in frr7.3 + zebraError // add in frr7.3 + // BackwardIPv6RouteAdd is referred in zclient_test + BackwardIPv6RouteAdd // quagga, frr3, frr4, frr5 + // BackwardIPv6RouteDelete is referred in zclient_test + BackwardIPv6RouteDelete // quagga, frr3, frr4, frr5 ) - -// For FRRouting 5. (ZAPI version 5) const ( - FRR_ZAPI5_INTERFACE_ADD API_TYPE = iota - FRR_ZAPI5_INTERFACE_DELETE - FRR_ZAPI5_INTERFACE_ADDRESS_ADD - FRR_ZAPI5_INTERFACE_ADDRESS_DELETE - FRR_ZAPI5_INTERFACE_UP - FRR_ZAPI5_INTERFACE_DOWN - FRR_ZAPI5_INTERFACE_SET_MASTER - FRR_ZAPI5_ROUTE_ADD - FRR_ZAPI5_ROUTE_DELETE - FRR_ZAPI5_ROUTE_NOTIFY_OWNER - FRR_ZAPI5_IPV4_ROUTE_ADD - FRR_ZAPI5_IPV4_ROUTE_DELETE - FRR_ZAPI5_IPV6_ROUTE_ADD - FRR_ZAPI5_IPV6_ROUTE_DELETE - FRR_ZAPI5_REDISTRIBUTE_ADD - FRR_ZAPI5_REDISTRIBUTE_DELETE - FRR_ZAPI5_REDISTRIBUTE_DEFAULT_ADD - FRR_ZAPI5_REDISTRIBUTE_DEFAULT_DELETE - FRR_ZAPI5_ROUTER_ID_ADD - FRR_ZAPI5_ROUTER_ID_DELETE - FRR_ZAPI5_ROUTER_ID_UPDATE - FRR_ZAPI5_HELLO - FRR_ZAPI5_CAPABILITIES - FRR_ZAPI5_NEXTHOP_REGISTER - FRR_ZAPI5_NEXTHOP_UNREGISTER - FRR_ZAPI5_NEXTHOP_UPDATE - FRR_ZAPI5_INTERFACE_NBR_ADDRESS_ADD - FRR_ZAPI5_INTERFACE_NBR_ADDRESS_DELETE - FRR_ZAPI5_INTERFACE_BFD_DEST_UPDATE - FRR_ZAPI5_IMPORT_ROUTE_REGISTER - FRR_ZAPI5_IMPORT_ROUTE_UNREGISTER - FRR_ZAPI5_IMPORT_CHECK_UPDATE - FRR_ZAPI5_IPV4_ROUTE_IPV6_NEXTHOP_ADD - FRR_ZAPI5_BFD_DEST_REGISTER - FRR_ZAPI5_BFD_DEST_DEREGISTER - FRR_ZAPI5_BFD_DEST_UPDATE - FRR_ZAPI5_BFD_DEST_REPLAY - FRR_ZAPI5_REDISTRIBUTE_ROUTE_ADD - FRR_ZAPI5_REDISTRIBUTE_ROUTE_DEL - FRR_ZAPI5_VRF_UNREGISTER - FRR_ZAPI5_VRF_ADD - FRR_ZAPI5_VRF_DELETE - FRR_ZAPI5_VRF_LABEL - FRR_ZAPI5_INTERFACE_VRF_UPDATE - FRR_ZAPI5_BFD_CLIENT_REGISTER - FRR_ZAPI5_INTERFACE_ENABLE_RADV - FRR_ZAPI5_INTERFACE_DISABLE_RADV - FRR_ZAPI5_IPV4_NEXTHOP_LOOKUP_MRIB - FRR_ZAPI5_INTERFACE_LINK_PARAMS - FRR_ZAPI5_MPLS_LABELS_ADD - FRR_ZAPI5_MPLS_LABELS_DELETE - FRR_ZAPI5_IPMR_ROUTE_STATS - FRR_ZAPI5_LABEL_MANAGER_CONNECT - FRR_ZAPI5_LABEL_MANAGER_CONNECT_ASYNC - FRR_ZAPI5_GET_LABEL_CHUNK - FRR_ZAPI5_RELEASE_LABEL_CHUNK - FRR_ZAPI5_FEC_REGISTER - FRR_ZAPI5_FEC_UNREGISTER - FRR_ZAPI5_FEC_UPDATE - FRR_ZAPI5_ADVERTISE_DEFAULT_GW - FRR_ZAPI5_ADVERTISE_SUBNET - FRR_ZAPI5_ADVERTISE_ALL_VNI - FRR_ZAPI5_VNI_ADD - FRR_ZAPI5_VNI_DEL - FRR_ZAPI5_L3VNI_ADD - FRR_ZAPI5_L3VNI_DEL - FRR_ZAPI5_REMOTE_VTEP_ADD - FRR_ZAPI5_REMOTE_VTEP_DEL - FRR_ZAPI5_MACIP_ADD - FRR_ZAPI5_MACIP_DEL - FRR_ZAPI5_IP_PREFIX_ROUTE_ADD - FRR_ZAPI5_IP_PREFIX_ROUTE_DEL - FRR_ZAPI5_REMOTE_MACIP_ADD - FRR_ZAPI5_REMOTE_MACIP_DEL - FRR_ZAPI5_PW_ADD - FRR_ZAPI5_PW_DELETE - FRR_ZAPI5_PW_SET - FRR_ZAPI5_PW_UNSET - FRR_ZAPI5_PW_STATUS_UPDATE - FRR_ZAPI5_RULE_ADD - FRR_ZAPI5_RULE_DELETE - FRR_ZAPI5_RULE_NOTIFY_OWNER - FRR_ZAPI5_TABLE_MANAGER_CONNECT - FRR_ZAPI5_GET_TABLE_CHUNK - FRR_ZAPI5_RELEASE_TABLE_CHUNK - FRR_ZAPI5_IPSET_CREATE - FRR_ZAPI5_IPSET_DESTROY - FRR_ZAPI5_IPSET_ENTRY_ADD - FRR_ZAPI5_IPSET_ENTRY_DELETE - FRR_ZAPI5_IPSET_NOTIFY_OWNER - FRR_ZAPI5_IPSET_ENTRY_NOTIFY_OWNER - FRR_ZAPI5_IPTABLE_ADD - FRR_ZAPI5_IPTABLE_DELETE - FRR_ZAPI5_IPTABLE_NOTIFY_OWNER + zapi6Frr7dot2MinDifferentAPIType APIType = 48 //frr7.2(zapi6) + zapi5ClMinDifferentAPIType APIType = 19 //cumuluslinux3.7.7, zebra4.0+cl3u13(zapi5) + zapi5MinDifferentAPIType APIType = 7 //frr4&5(zapi5), frr6&7.0&7.1(zapi6) + zapi4MinDifferentAPIType APIType = 6 + zapi3MinDifferentAPIType APIType = 0 ) -// For FRRouting version 3. (ZAPI version 4) +func minDifferentAPIType(version uint8, softwareName string) APIType { + if version < 4 { + return zapi3MinDifferentAPIType + } else if version == 4 { + return zapi4MinDifferentAPIType + } else if version == 5 && softwareName == "cumulus" { + return zapi5ClMinDifferentAPIType + } else if version == 5 || + (version == 6 && (softwareName == "frr6" || softwareName == "frr7" || softwareName == "frr7.1")) { + return zapi5MinDifferentAPIType + } + return zapi6Frr7dot2MinDifferentAPIType +} + const ( - FRR_INTERFACE_ADD API_TYPE = iota - FRR_INTERFACE_DELETE - FRR_INTERFACE_ADDRESS_ADD - FRR_INTERFACE_ADDRESS_DELETE - FRR_INTERFACE_UP - FRR_INTERFACE_DOWN - FRR_IPV4_ROUTE_ADD - FRR_IPV4_ROUTE_DELETE - FRR_IPV6_ROUTE_ADD - FRR_IPV6_ROUTE_DELETE - FRR_REDISTRIBUTE_ADD - FRR_REDISTRIBUTE_DELETE - FRR_REDISTRIBUTE_DEFAULT_ADD - FRR_REDISTRIBUTE_DEFAULT_DELETE - FRR_ROUTER_ID_ADD - FRR_ROUTER_ID_DELETE - FRR_ROUTER_ID_UPDATE - FRR_HELLO - FRR_NEXTHOP_REGISTER - FRR_NEXTHOP_UNREGISTER - FRR_NEXTHOP_UPDATE - FRR_INTERFACE_NBR_ADDRESS_ADD - FRR_INTERFACE_NBR_ADDRESS_DELETE - FRR_INTERFACE_BFD_DEST_UPDATE - FRR_IMPORT_ROUTE_REGISTER - FRR_IMPORT_ROUTE_UNREGISTER - FRR_IMPORT_CHECK_UPDATE - FRR_IPV4_ROUTE_IPV6_NEXTHOP_ADD - FRR_BFD_DEST_REGISTER - FRR_BFD_DEST_DEREGISTER - FRR_BFD_DEST_UPDATE - FRR_BFD_DEST_REPLAY - FRR_REDISTRIBUTE_IPV4_ADD - FRR_REDISTRIBUTE_IPV4_DEL - FRR_REDISTRIBUTE_IPV6_ADD - FRR_REDISTRIBUTE_IPV6_DEL - FRR_VRF_UNREGISTER - FRR_VRF_ADD - FRR_VRF_DELETE - FRR_INTERFACE_VRF_UPDATE - FRR_BFD_CLIENT_REGISTER - FRR_INTERFACE_ENABLE_RADV - FRR_INTERFACE_DISABLE_RADV - FRR_IPV4_NEXTHOP_LOOKUP_MRIB - FRR_INTERFACE_LINK_PARAMS - FRR_MPLS_LABELS_ADD - FRR_MPLS_LABELS_DELETE - FRR_IPV4_NEXTHOP_ADD - FRR_IPV4_NEXTHOP_DELETE - FRR_IPV6_NEXTHOP_ADD - FRR_IPV6_NEXTHOP_DELETE - FRR_IPMR_ROUTE_STATS - FRR_LABEL_MANAGER_CONNECT - FRR_GET_LABEL_CHUNK - FRR_RELEASE_LABEL_CHUNK - FRR_PW_ADD - FRR_PW_DELETE - FRR_PW_SET - FRR_PW_UNSET - FRR_PW_STATUS_UPDATE + zapi6Frr7dot2LabelManagerConnect APIType = 49 // difference from frr7.3 + zapi6Frr7dot2LabelManagerConnectAsync APIType = 50 // difference from frr7.3 + zapi6Frr7dot2GetLabelChunk APIType = 51 // difference from frr7.3 + zapi6Frr7dot2ReleaseLabelChunk APIType = 52 // difference from frr7.3 ) -// For Quagga. -const ( - _ API_TYPE = iota - INTERFACE_ADD - INTERFACE_DELETE - INTERFACE_ADDRESS_ADD - INTERFACE_ADDRESS_DELETE - INTERFACE_UP - INTERFACE_DOWN - IPV4_ROUTE_ADD - IPV4_ROUTE_DELETE - IPV6_ROUTE_ADD - IPV6_ROUTE_DELETE - REDISTRIBUTE_ADD - REDISTRIBUTE_DELETE - REDISTRIBUTE_DEFAULT_ADD - REDISTRIBUTE_DEFAULT_DELETE - IPV4_NEXTHOP_LOOKUP - IPV6_NEXTHOP_LOOKUP - IPV4_IMPORT_LOOKUP - IPV6_IMPORT_LOOKUP - INTERFACE_RENAME - ROUTER_ID_ADD - ROUTER_ID_DELETE - ROUTER_ID_UPDATE - HELLO - IPV4_NEXTHOP_LOOKUP_MRIB - VRF_UNREGISTER - INTERFACE_LINK_PARAMS - NEXTHOP_REGISTER - NEXTHOP_UNREGISTER - NEXTHOP_UPDATE - MESSAGE_MAX +var apiTypeZapi6Frr7dot2Map = map[APIType]APIType{ + labelManagerConnect: zapi6Frr7dot2LabelManagerConnect, + labelManagerConnectAsync: zapi6Frr7dot2LabelManagerConnectAsync, + getLabelChunk: zapi6Frr7dot2GetLabelChunk, + releaseLabelChunk: zapi6Frr7dot2ReleaseLabelChunk, +} + +const ( // frr7.0, 7.1 + zapi6Frr7RouteAdd APIType = 7 + zapi6Frr7RouteDelete APIType = 8 + zapi6Frr7RedistributAdd APIType = 10 + zapi6Frr7RouterIDAdd APIType = 14 + zapi6Frr7RouterIDUpdate APIType = 16 + zapi6Frr7Hello APIType = 17 + zapi6Frr7NexthopRegister APIType = 19 + zapi6Frr7NexthopUnregister APIType = 20 + zapi6Frr7NexthopUpdate APIType = 21 + zapi6Frr7RedistributeRouteAdd APIType = 32 + zapi6Frr7RedistributeRouteDel APIType = 33 + zapi6Frr7VrfLabel APIType = 37 + zapi6Frr7Ipv4NexthopLookupMRIB APIType = 43 + zapi6Frr7LabelManagerConnect APIType = 48 + zapi6Frr7LabelManagerConnectAsync APIType = 49 + zapi6Frr7GetLabelChunk APIType = 50 + zapi6Frr7ReleaseLabelChunk APIType = 51 +) + +var apiTypeZapi6Frr7Map = map[APIType]APIType{ // frr7.0, 7.1 + RouteAdd: zapi6Frr7RouteAdd, + RouteDelete: zapi6Frr7RouteDelete, + redistributeAdd: zapi6Frr7RedistributAdd, + routerIDAdd: zapi6Frr7RouterIDAdd, + routerIDUpdate: zapi6Frr7RouterIDUpdate, + hello: zapi6Frr7Hello, + nexthopRegister: zapi6Frr7NexthopRegister, + nexthopUnregister: zapi6Frr7NexthopUnregister, + nexthopUpdate: zapi6Frr7NexthopUpdate, + redistributeRouteAdd: zapi6Frr7RedistributeRouteAdd, + redistributeRouteDel: zapi6Frr7RedistributeRouteDel, + vrfLabel: zapi6Frr7VrfLabel, + ipv4NexthopLookupMRIB: zapi6Frr7Ipv4NexthopLookupMRIB, + labelManagerConnect: zapi6Frr7LabelManagerConnect, + labelManagerConnectAsync: zapi6Frr7LabelManagerConnectAsync, + getLabelChunk: zapi6Frr7GetLabelChunk, + releaseLabelChunk: zapi6Frr7ReleaseLabelChunk, +} + +var apiTypeZapi6Frr6Map = map[APIType]APIType{ + RouteAdd: zapi6Frr7RouteAdd, // same as frr7.0&7.1 + RouteDelete: zapi6Frr7RouteDelete, // same as frr7.0&7.1 + redistributeAdd: zapi6Frr7RedistributAdd, // same as frr7.0&7.1 + routerIDAdd: zapi6Frr7RouterIDAdd, // same as frr7.0&7.1 + routerIDUpdate: zapi6Frr7RouterIDUpdate, // same as frr7.0&7.1 + hello: zapi6Frr7Hello, // same as frr7.0&7.1 + nexthopRegister: zapi6Frr7NexthopRegister, // same as frr7.0&7.1 + nexthopUnregister: zapi6Frr7NexthopUnregister, // same as frr7.0&7.1 + nexthopUpdate: zapi6Frr7NexthopUpdate, // same as frr7.0&7.1 + redistributeRouteAdd: redistributeRouteAdd, // same as frr7.2&7.3 + redistributeRouteDel: redistributeRouteDel, // same as frr7.2&7.3 + vrfLabel: vrfLabel, // same as frr7.2&7.3 + ipv4NexthopLookupMRIB: ipv4NexthopLookupMRIB, // same as frr7.2&7.3 + labelManagerConnect: zapi6Frr7dot2LabelManagerConnect, // same as frr7.2 + labelManagerConnectAsync: zapi6Frr7dot2LabelManagerConnectAsync, // same as frr7.2 + getLabelChunk: zapi6Frr7dot2GetLabelChunk, // same as frr7.2 + releaseLabelChunk: zapi6Frr7dot2ReleaseLabelChunk, // same as frr7.2 +} + +const ( // For Cumulus Linux 3.7.7, zebra 4.0+cl3u13 (ZAPI version 5) + zapi5ClIpv4NexthopLookupMRIB APIType = 42 + zapi5ClLabelManagerConnect APIType = 47 + zapi5ClGetLabelChunk APIType = 48 + zapi5ClReleaseLabelChunk APIType = 49 ) -// Route Types. -//go:generate stringer -type=ROUTE_TYPE -type ROUTE_TYPE uint8 +var apiTypeZapi5ClMap = map[APIType]APIType{ + nexthopRegister: zapi6Frr7NexthopRegister, // same as frr7.0&7.1 + nexthopUnregister: zapi6Frr7NexthopUnregister, // same as frr7.0&7.1 + nexthopUpdate: zapi6Frr7NexthopUpdate, // same as frr7.0&7.1 + redistributeRouteAdd: zapi6Frr7RedistributeRouteAdd, // same as frr7.0&7.1 + redistributeRouteDel: zapi6Frr7RedistributeRouteDel, // same as frr7.0&7.1 + vrfLabel: zapi6Frr7VrfLabel, // same as frr7.0&7.1 + labelManagerConnect: zapi5ClLabelManagerConnect, + getLabelChunk: zapi5ClGetLabelChunk, + releaseLabelChunk: zapi5ClReleaseLabelChunk, +} -// For FRRouting version 7 (ZAPI version 6). const ( - FRR_ZAPI6_ROUTE_SYSTEM ROUTE_TYPE = iota - FRR_ZAPI6_ROUTE_KERNEL - FRR_ZAPI6_ROUTE_CONNECT - FRR_ZAPI6_ROUTE_STATIC - FRR_ZAPI6_ROUTE_RIP - FRR_ZAPI6_ROUTE_RIPNG - FRR_ZAPI6_ROUTE_OSPF - FRR_ZAPI6_ROUTE_OSPF6 - FRR_ZAPI6_ROUTE_ISIS - FRR_ZAPI6_ROUTE_BGP - FRR_ZAPI6_ROUTE_PIM - FRR_ZAPI6_ROUTE_EIGRP - FRR_ZAPI6_ROUTE_NHRP - FRR_ZAPI6_ROUTE_HSLS - FRR_ZAPI6_ROUTE_OLSR - FRR_ZAPI6_ROUTE_TABLE - FRR_ZAPI6_ROUTE_LDP - FRR_ZAPI6_ROUTE_VNC - FRR_ZAPI6_ROUTE_VNC_DIRECT - FRR_ZAPI6_ROUTE_VNC_DIRECT_RH - FRR_ZAPI6_ROUTE_BGP_DIRECT - FRR_ZAPI6_ROUTE_BGP_DIRECT_EXT - FRR_ZAPI6_ROUTE_BABEL - FRR_ZAPI6_ROUTE_SHARP - FRR_ZAPI6_ROUTE_PBR - FRR_ZAPI6_ROUTE_BFD - FRR_ZAPI6_ROUTE_OPENFABRIC // FRRRouting version 7 adds. - FRR_ZAPI6_ROUTE_VRRP // FRRRouting version 7.2 adds. - FRR_ZAPI6_ROUTE_ALL - FRR_ZAPI6_ROUTE_MAX + zapi5RedistributAdd APIType = 14 + zapi5RouterIDAdd APIType = 18 + zapi5RouterIDUpdate APIType = 20 + zapi5Hello APIType = 21 + zapi5Frr5NexthopRegister APIType = 23 + zapi5Frr5NexthopUnregister APIType = 24 + zapi5Frr5NexthopUpdate APIType = 25 + zapi5Frr5RedistributeRouteAdd APIType = 37 + zapi5Frr5RedistributeRouteDel APIType = 38 + zapi5Frr5VrfLabel APIType = 42 + zapi5Frr5Ipv4NexthopLookupMRIB APIType = 47 + zapi5Frr5LabelManagerConnect APIType = 52 + zapi5Frr5LabelManagerConnectAsync APIType = 53 + zapi5Frr5GetLabelChunk APIType = 54 + zapi5Frr5ReleaseLabelChunk APIType = 55 ) -// For FRRouting version 5 (ZAPI version 5). +var apiTypeZapi5Frr5Map = map[APIType]APIType{ + RouteAdd: zapi6Frr7RouteAdd, // same as frr7.0&7.1 + RouteDelete: zapi6Frr7RouteDelete, // same as frr7.0&7.1 + redistributeAdd: zapi5RedistributAdd, + routerIDAdd: zapi5RouterIDAdd, + routerIDUpdate: zapi5RouterIDUpdate, + hello: zapi5Hello, + nexthopRegister: zapi5Frr5NexthopRegister, + nexthopUnregister: zapi5Frr5NexthopUnregister, + nexthopUpdate: zapi5Frr5NexthopUpdate, + redistributeRouteAdd: zapi5Frr5RedistributeRouteAdd, + redistributeRouteDel: zapi5Frr5RedistributeRouteDel, + vrfLabel: zapi5Frr5VrfLabel, + ipv4NexthopLookupMRIB: zapi5Frr5Ipv4NexthopLookupMRIB, + labelManagerConnect: zapi5Frr5LabelManagerConnect, + labelManagerConnectAsync: zapi5Frr5LabelManagerConnectAsync, + getLabelChunk: zapi5Frr5GetLabelChunk, + releaseLabelChunk: zapi5Frr5ReleaseLabelChunk, +} + const ( - FRR_ZAPI5_ROUTE_SYSTEM ROUTE_TYPE = iota - FRR_ZAPI5_ROUTE_KERNEL - FRR_ZAPI5_ROUTE_CONNECT - FRR_ZAPI5_ROUTE_STATIC - FRR_ZAPI5_ROUTE_RIP - FRR_ZAPI5_ROUTE_RIPNG - FRR_ZAPI5_ROUTE_OSPF - FRR_ZAPI5_ROUTE_OSPF6 - FRR_ZAPI5_ROUTE_ISIS - FRR_ZAPI5_ROUTE_BGP - FRR_ZAPI5_ROUTE_PIM - FRR_ZAPI5_ROUTE_EIGRP - FRR_ZAPI5_ROUTE_NHRP - FRR_ZAPI5_ROUTE_HSLS - FRR_ZAPI5_ROUTE_OLSR - FRR_ZAPI5_ROUTE_TABLE - FRR_ZAPI5_ROUTE_LDP - FRR_ZAPI5_ROUTE_VNC - FRR_ZAPI5_ROUTE_VNC_DIRECT - FRR_ZAPI5_ROUTE_VNC_DIRECT_RH - FRR_ZAPI5_ROUTE_BGP_DIRECT - FRR_ZAPI5_ROUTE_BGP_DIRECT_EXT - FRR_ZAPI5_ROUTE_BABEL - FRR_ZAPI5_ROUTE_SHARP - FRR_ZAPI5_ROUTE_PBR // FRRRouting version 5 adds. - FRR_ZAPI5_ROUTE_ALL - FRR_ZAPI5_ROUTE_MAX + zapi5Frr4NexthopRegister APIType = 22 + zapi5Frr4NexthopUnregister APIType = 23 + zapi5Frr4NexthopUpdate APIType = 24 + zapi5Frr4RedistributeRouteAdd APIType = 36 + zapi5Frr4RedistributeRouteDel APIType = 37 + zapi5Frr4Ipv4NexthopLookupMRIB APIType = 45 + zapi5Frr4LabelManagerConnect APIType = 50 + zapi5Frr4GetLabelChunk APIType = 51 + zapi5Frr4ReleaseLabelChunk APIType = 52 ) -// For FRRouting. +var apiTypeZapi5Frr4Map = map[APIType]APIType{ + RouteAdd: zapi6Frr7RouteAdd, // same as frr7.0&7.1 + RouteDelete: zapi6Frr7RouteDelete, // same as frr7.0&7.1 + redistributeAdd: zapi5RedistributAdd, + routerIDAdd: zapi5RouterIDAdd, + routerIDUpdate: zapi5RouterIDUpdate, + hello: zapi5Hello, + nexthopRegister: zapi5Frr4NexthopRegister, + nexthopUnregister: zapi5Frr4NexthopUnregister, + nexthopUpdate: zapi5Frr4NexthopUpdate, + redistributeRouteAdd: zapi5Frr4RedistributeRouteAdd, + redistributeRouteDel: zapi5Frr4RedistributeRouteDel, + ipv4NexthopLookupMRIB: zapi5Frr4Ipv4NexthopLookupMRIB, + labelManagerConnect: zapi5Frr4LabelManagerConnect, + getLabelChunk: zapi5Frr4GetLabelChunk, + releaseLabelChunk: zapi5Frr4ReleaseLabelChunk, +} + const ( - FRR_ROUTE_SYSTEM ROUTE_TYPE = iota - FRR_ROUTE_KERNEL - FRR_ROUTE_CONNECT - FRR_ROUTE_STATIC - FRR_ROUTE_RIP - FRR_ROUTE_RIPNG - FRR_ROUTE_OSPF - FRR_ROUTE_OSPF6 - FRR_ROUTE_ISIS - FRR_ROUTE_BGP - FRR_ROUTE_PIM - FRR_ROUTE_HSLS - FRR_ROUTE_OLSR - FRR_ROUTE_TABLE - FRR_ROUTE_LDP - FRR_ROUTE_VNC - FRR_ROUTE_VNC_DIRECT - FRR_ROUTE_VNC_DIRECT_RH - FRR_ROUTE_BGP_DIRECT - FRR_ROUTE_BGP_DIRECT_EXT - FRR_ROUTE_ALL - FRR_ROUTE_MAX + zapi4IPv4RouteAdd APIType = 6 // deleted in zapi6 + zapi4IPv4RouteDelete APIType = 7 // deleted in zapi6 + zapi4IPv6RouteAdd APIType = 8 // deleted in zapi6 + zapi4IPv6RouteDelete APIType = 9 // deleted in zapi6 + zapi4RedistributAdd APIType = 10 + zapi4RouterIDAdd APIType = 14 + zapi4RouterIDUpdate APIType = 16 + zapi4Hello APIType = 17 + zapi4NexthopRegister APIType = 18 + zapi4NexthopUnregister APIType = 19 + zapi4NexthopUpdate APIType = 20 + zapi4RedistributeIPv4Add APIType = 32 // deleted in zapi6 + zapi4RedistributeIPv4Del APIType = 33 // deleted in zapi6 + zapi4RedistributeIPv6Add APIType = 34 // deleted in zapi6 + zapi4RedistributeIPv6Del APIType = 35 // deleted in zapi6 + zapi4LabelManagerConnect APIType = 52 + zapi4GetLabelChunk APIType = 53 + zapi4ReleaseLabelChunk APIType = 54 ) -// For Quagga. +var apiTypeZapi4Map = map[APIType]APIType{ + RouteAdd: zapi4IPv4RouteAdd, // deleted in zapi5 + RouteDelete: zapi4IPv4RouteDelete, // deleted in zapi5 + redistributeAdd: zapi4RedistributAdd, + routerIDAdd: zapi4RouterIDAdd, + routerIDUpdate: zapi4RouterIDUpdate, + hello: zapi4Hello, + nexthopRegister: zapi4NexthopRegister, + nexthopUnregister: zapi4NexthopUnregister, + nexthopUpdate: zapi4NexthopUpdate, + redistributeRouteAdd: zapi4RedistributeIPv4Add, // deleted in zapi5 + redistributeRouteDel: zapi4RedistributeIPv4Del, // deleted in zapi5 + ipv4NexthopLookupMRIB: zapi6Frr7Ipv4NexthopLookupMRIB, // same as frr7.0&7.1 + labelManagerConnect: zapi4LabelManagerConnect, + getLabelChunk: zapi4GetLabelChunk, + releaseLabelChunk: zapi4ReleaseLabelChunk, + BackwardIPv6RouteAdd: zapi4IPv6RouteAdd, + BackwardIPv6RouteDelete: zapi4IPv6RouteDelete, +} + const ( - ROUTE_SYSTEM ROUTE_TYPE = iota - ROUTE_KERNEL - ROUTE_CONNECT - ROUTE_STATIC - ROUTE_RIP - ROUTE_RIPNG - ROUTE_OSPF - ROUTE_OSPF6 - ROUTE_ISIS - ROUTE_BGP - ROUTE_PIM - ROUTE_HSLS - ROUTE_OLSR - ROUTE_BABEL - ROUTE_NHRP // quagga 1.2.4 - ROUTE_MAX + zapi3InterfaceAdd APIType = 1 + zapi3InterfaceDelete APIType = 2 + zapi3InterfaceAddressAdd APIType = 3 + zapi3InterfaceAddressDelete APIType = 4 + zapi3InterfaceUp APIType = 5 + zapi3InterfaceDown APIType = 6 + zapi3IPv4RouteAdd APIType = 7 // deleted in zapi5 + zapi3IPv4RouteDelete APIType = 8 // deleted in zapi5 + zapi3IPv6RouteAdd APIType = 9 // deleted in zapi5 + zapi3IPv6RouteDelete APIType = 10 // deleted in zapi5 + zapi3RedistributeAdd APIType = 11 + zapi3IPv4NexthopLookup APIType = 15 // zapi3(quagga) only + zapi3IPv6NexthopLookup APIType = 16 // zapi3(quagga) only + zapi3IPv4ImportLookup APIType = 17 // zapi3(quagga) only + zapi3RouterIDAdd APIType = 20 + zapi3RouterIDUpdate APIType = 22 + zapi3Hello APIType = 23 + zapi3Ipv4NexthopLookupMRIB APIType = 24 + zapi3NexthopRegister APIType = 27 + zapi3NexthopUnregister APIType = 28 + zapi3NexthopUpdate APIType = 29 ) -var routeTypeValueMapFrrZapi6 = map[string]ROUTE_TYPE{ - "system": FRR_ZAPI6_ROUTE_SYSTEM, - "kernel": FRR_ZAPI6_ROUTE_KERNEL, - "connect": FRR_ZAPI6_ROUTE_CONNECT, // hack for backward compatibility - "directly-connected": FRR_ZAPI6_ROUTE_CONNECT, - "static": FRR_ZAPI6_ROUTE_STATIC, - "rip": FRR_ZAPI6_ROUTE_RIP, - "ripng": FRR_ZAPI6_ROUTE_RIPNG, - "ospf": FRR_ZAPI6_ROUTE_OSPF, - "ospf3": FRR_ZAPI6_ROUTE_OSPF6, - "isis": FRR_ZAPI6_ROUTE_ISIS, - "bgp": FRR_ZAPI6_ROUTE_BGP, - "pim": FRR_ZAPI6_ROUTE_PIM, - "eigrp": FRR_ZAPI6_ROUTE_EIGRP, - "nhrp": FRR_ZAPI6_ROUTE_EIGRP, - "hsls": FRR_ZAPI6_ROUTE_HSLS, - "olsr": FRR_ZAPI6_ROUTE_OLSR, - "table": FRR_ZAPI6_ROUTE_TABLE, - "ldp": FRR_ZAPI6_ROUTE_LDP, - "vnc": FRR_ZAPI6_ROUTE_VNC, - "vnc-direct": FRR_ZAPI6_ROUTE_VNC_DIRECT, - "vnc-direct-rh": FRR_ZAPI6_ROUTE_VNC_DIRECT_RH, - "bgp-direct": FRR_ZAPI6_ROUTE_BGP_DIRECT, - "bgp-direct-ext": FRR_ZAPI6_ROUTE_BGP_DIRECT_EXT, - "babel": FRR_ZAPI6_ROUTE_BABEL, - "sharp": FRR_ZAPI6_ROUTE_SHARP, - "pbr": FRR_ZAPI6_ROUTE_PBR, - "bfd": FRR_ZAPI6_ROUTE_BFD, - "openfabric": FRR_ZAPI6_ROUTE_OPENFABRIC, - "vrrp": FRR_ZAPI6_ROUTE_VRRP, - "all": FRR_ZAPI6_ROUTE_ALL, -} - -var routeTypeValueMapFrrZapi5 = map[string]ROUTE_TYPE{ - "system": FRR_ZAPI5_ROUTE_SYSTEM, - "kernel": FRR_ZAPI5_ROUTE_KERNEL, - "connect": FRR_ZAPI5_ROUTE_CONNECT, // hack for backward compatibility - "directly-connected": FRR_ZAPI5_ROUTE_CONNECT, - "static": FRR_ZAPI5_ROUTE_STATIC, - "rip": FRR_ZAPI5_ROUTE_RIP, - "ripng": FRR_ZAPI5_ROUTE_RIPNG, - "ospf": FRR_ZAPI5_ROUTE_OSPF, - "ospf3": FRR_ZAPI5_ROUTE_OSPF6, - "isis": FRR_ZAPI5_ROUTE_ISIS, - "bgp": FRR_ZAPI5_ROUTE_BGP, - "pim": FRR_ZAPI5_ROUTE_PIM, - "eigrp": FRR_ZAPI5_ROUTE_EIGRP, - "nhrp": FRR_ZAPI5_ROUTE_EIGRP, - "hsls": FRR_ZAPI5_ROUTE_HSLS, - "olsr": FRR_ZAPI5_ROUTE_OLSR, - "table": FRR_ZAPI5_ROUTE_TABLE, - "ldp": FRR_ZAPI5_ROUTE_LDP, - "vnc": FRR_ZAPI5_ROUTE_VNC, - "vnc-direct": FRR_ZAPI5_ROUTE_VNC_DIRECT, - "vnc-direct-rh": FRR_ZAPI5_ROUTE_VNC_DIRECT_RH, - "bgp-direct": FRR_ZAPI5_ROUTE_BGP_DIRECT, - "bgp-direct-ext": FRR_ZAPI5_ROUTE_BGP_DIRECT_EXT, - "babel": FRR_ZAPI5_ROUTE_BABEL, - "sharp": FRR_ZAPI5_ROUTE_SHARP, - "pbr": FRR_ZAPI5_ROUTE_PBR, - "all": FRR_ZAPI5_ROUTE_ALL, -} - -var routeTypeValueMapFrr = map[string]ROUTE_TYPE{ - "system": FRR_ROUTE_SYSTEM, - "kernel": FRR_ROUTE_KERNEL, - "connect": FRR_ROUTE_CONNECT, // hack for backward compatibility - "directly-connected": FRR_ROUTE_CONNECT, - "static": FRR_ROUTE_STATIC, - "rip": FRR_ROUTE_RIP, - "ripng": FRR_ROUTE_RIPNG, - "ospf": FRR_ROUTE_OSPF, - "ospf3": FRR_ROUTE_OSPF6, - "isis": FRR_ROUTE_ISIS, - "bgp": FRR_ROUTE_BGP, - "pim": FRR_ROUTE_PIM, - "hsls": FRR_ROUTE_HSLS, - "olsr": FRR_ROUTE_OLSR, - "table": FRR_ROUTE_TABLE, - "ldp": FRR_ROUTE_LDP, - "vnc": FRR_ROUTE_VNC, - "vnc-direct": FRR_ROUTE_VNC_DIRECT, - "vnc-direct-rh": FRR_ROUTE_VNC_DIRECT_RH, - "bgp-direct": FRR_ROUTE_BGP_DIRECT, - "bgp-direct-ext": FRR_ROUTE_BGP_DIRECT_EXT, - "all": FRR_ROUTE_ALL, -} - -var routeTypeValueMap = map[string]ROUTE_TYPE{ - "system": ROUTE_SYSTEM, - "kernel": ROUTE_KERNEL, - "connect": ROUTE_CONNECT, // hack for backward compatibility - "directly-connected": ROUTE_CONNECT, - "static": ROUTE_STATIC, - "rip": ROUTE_RIP, - "ripng": ROUTE_RIPNG, - "ospf": ROUTE_OSPF, - "ospf3": ROUTE_OSPF6, - "isis": ROUTE_ISIS, - "bgp": ROUTE_BGP, - "pim": ROUTE_PIM, - "hsls": ROUTE_HSLS, - "olsr": ROUTE_OLSR, - "babel": ROUTE_BABEL, - "nhrp": ROUTE_NHRP, -} - -func RouteTypeFromString(typ string, version uint8, softwareName string) (ROUTE_TYPE, error) { - delegateRouteTypeValueMap := routeTypeValueMap - if version == 4 { - delegateRouteTypeValueMap = routeTypeValueMapFrr +var apiTypeZapi3Map = map[APIType]APIType{ + interfaceAdd: zapi3InterfaceAdd, + interfaceDelete: zapi3InterfaceDelete, + interfaceAddressAdd: zapi3InterfaceAddressAdd, + interfaceAddressDelete: zapi3InterfaceAddressDelete, + interfaceUp: zapi3InterfaceUp, + interfaceDown: zapi3InterfaceDown, + RouteAdd: zapi3IPv4RouteAdd, // deleted in zapi5 + RouteDelete: zapi3IPv4RouteDelete, // deleted in zapi5 + redistributeAdd: zapi3RedistributeAdd, + routerIDAdd: zapi3RouterIDAdd, + routerIDUpdate: zapi3RouterIDUpdate, + hello: zapi3Hello, + nexthopRegister: zapi3NexthopRegister, + nexthopUnregister: zapi3NexthopUnregister, + nexthopUpdate: zapi3NexthopUpdate, + BackwardIPv6RouteAdd: zapi3IPv6RouteAdd, + BackwardIPv6RouteDelete: zapi3IPv6RouteDelete, +} + +func (t APIType) doesNeedConversion(version uint8, softwareName string) bool { + if (version == 6 && (softwareName == "frr7.3" || softwareName == "")) || t < minDifferentAPIType(version, softwareName) { + return false + } + return true +} +func apiTypeMap(version uint8, softwareName string) map[APIType]APIType { + if version == 6 && (softwareName == "frr7" || softwareName == "frr7.1") { + return apiTypeZapi6Frr7Map + } else if version == 6 && softwareName == "frr6" { + return apiTypeZapi6Frr6Map } else if version == 5 { - delegateRouteTypeValueMap = routeTypeValueMapFrrZapi5 - } else if version >= 6 { - delegateRouteTypeValueMap = routeTypeValueMapFrrZapi6 + if softwareName == "frr4" { + return apiTypeZapi5Frr4Map + } else if softwareName == "cumulus" { + return apiTypeZapi5ClMap + } + return apiTypeZapi5Frr5Map + } else if version == 4 { + return apiTypeZapi4Map + } else if version < 4 { + return apiTypeZapi3Map + } + return apiTypeZapi6Frr7dot2Map +} + +// ToEach is referred in zclient_test +func (t APIType) ToEach(version uint8, softwareName string) APIType { + if !t.doesNeedConversion(version, softwareName) { + return t } - t, ok := delegateRouteTypeValueMap[typ] - if (version == 5 && softwareName == "frr4" && t == FRR_ZAPI5_ROUTE_PBR) || - (version == 6 && softwareName == "frr6" && t == FRR_ZAPI6_ROUTE_OPENFABRIC) || - (version == 6 && softwareName != "frr7.2" && t == FRR_ZAPI6_ROUTE_VRRP) { - ok = false + apiMap := apiTypeMap(version, softwareName) + backward, ok := apiMap[t] + if !ok { + backward = zebraError // fail to convert and error value } - if ok { - return t, nil + log.WithFields(log.Fields{ + "Topic": "Zebra", + }).Debugf("zebra ToEach converts APIType: %d(%s) -> %d (version: %d, software: %s)", + t, t.String(), backward, version, softwareName) + return backward // success to convert +} +func (t APIType) toCommon(version uint8, softwareName string) APIType { + if !t.doesNeedConversion(version, softwareName) { + return t + } + apiMap := apiTypeMap(version, softwareName) + for common, backward := range apiMap { + if backward == t { + log.WithFields(log.Fields{ + "Topic": "Zebra", + }).Debugf("zebra toCommon converts APIType: %d -> %d(%s) (version: %d, software: %s)", + t, common, common.String(), version, softwareName) + return common // success to convert + } } - return t, fmt.Errorf("unknown route type: %s in version: %d (%s)", typ, version, softwareName) + return zebraError // fail to convert and error value } -func addressFamilyFromApi(Api API_TYPE, version uint8) uint8 { - //ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB is not implemented. - if version <= 3 { - switch Api { - case IPV4_ROUTE_ADD, IPV4_ROUTE_DELETE, IPV4_NEXTHOP_LOOKUP, IPV4_IMPORT_LOOKUP: - return syscall.AF_INET - case IPV6_ROUTE_ADD, IPV6_ROUTE_DELETE, IPV6_NEXTHOP_LOOKUP, IPV6_IMPORT_LOOKUP: - return syscall.AF_INET6 - } - } else if version == 4 { - switch Api { - case FRR_REDISTRIBUTE_IPV4_ADD, FRR_REDISTRIBUTE_IPV4_DEL, FRR_IPV4_ROUTE_ADD, FRR_IPV4_ROUTE_DELETE, FRR_IPV4_NEXTHOP_LOOKUP_MRIB: +func (t APIType) addressFamily(version uint8) uint8 { + if version == 4 { + switch t { + case zapi4IPv4RouteAdd, zapi4IPv4RouteDelete, zapi4RedistributeIPv4Add, zapi4RedistributeIPv4Del, zapi6Frr7Ipv4NexthopLookupMRIB: return syscall.AF_INET - case FRR_REDISTRIBUTE_IPV6_ADD, FRR_REDISTRIBUTE_IPV6_DEL, FRR_IPV6_ROUTE_ADD, FRR_IPV6_ROUTE_DELETE: + case zapi4IPv6RouteAdd, zapi4IPv6RouteDelete, zapi4RedistributeIPv6Add, zapi4RedistributeIPv6Del: return syscall.AF_INET6 } - } else if version == 5 { - switch Api { - case FRR_ZAPI5_IPV4_ROUTE_ADD, FRR_ZAPI5_IPV4_ROUTE_DELETE: + } else if version < 4 { + switch t { + case zapi3IPv4RouteAdd, zapi3IPv4RouteDelete, zapi3IPv4NexthopLookup, zapi3IPv4ImportLookup, zapi3Ipv4NexthopLookupMRIB: return syscall.AF_INET - case FRR_ZAPI5_IPV6_ROUTE_ADD, FRR_ZAPI5_IPV6_ROUTE_DELETE: + case zapi3IPv6RouteAdd, zapi3IPv6RouteDelete, zapi3IPv6NexthopLookup: return syscall.AF_INET6 } } return syscall.AF_UNSPEC } +// RouteType is referred in zclient. +//go:generate stringer -type=RouteType +type RouteType uint8 + +// For FRRouting version 7 (ZAPI version 6). +const ( + routeSystem RouteType = iota //0 + routeKernel + routeConnect + RouteStatic + routeRIP + routeRIPNG + routeOSPF + routeOSPF6 + routeISIS + RouteBGP + routePIM // 10 + routeEIGRP // FRRRouting version 4 (Zapi5) adds. + routeNHRP + routeHSLS + routeOLSR + routeTABLE + routeLDP + routeVNC + routeVNCDirect + routeVNCDirectRH + routeBGPDirect + routeBGPDirectEXT + routeBABEL + routeSHARP + routePBR // FRRRouting version 5 (Zapi5) adds. + routeBFD // FRRRouting version 6 (Zapi6) adds. + routeOpenfabric // FRRRouting version 7 (Zapi6) adds. + routeVRRP // FRRRouting version 7.2 (Zapi6) adds. + routeNHG // FRRRouting version 7.3 (Zapi6) adds. + routeAll + routeMax // max value for error +) +const ( + zapi5Frr4RouteAll RouteType = 24 + zapi5Frr5RouteAll RouteType = 25 + zapi6Frr6RouteAll RouteType = 26 + zapi6Frr7RouteAll RouteType = 27 + zapi6Frr7dot2RouteAll RouteType = 28 +) + +func getRouteAll(version uint8, softwareName string) RouteType { + if version == 5 { + if softwareName == "frr4" { + return zapi5Frr4RouteAll + } + return zapi5Frr5RouteAll + } else if version == 6 { + if softwareName == "frr6" { + return zapi6Frr6RouteAll + } else if softwareName == "frr7" || softwareName == "frr7.1" { + return zapi6Frr7RouteAll + } else if softwareName == "frr7.2" { + return zapi6Frr7dot2RouteAll + } + } + return routeAll +} + +// For FRRouting version 3.0 except common route type. +const ( + zapi4RouteNHRP RouteType = iota + routePIM + 1 + zapi4RouteHSLS + zapi4RouteOLSR + zapi4RouteTABLE + zapi4RouteLDP + zapi4RouteVNC + zapi4RouteVNCDirect + zapi4RouteVNCDirectRH + zapi4RouteBGPDixrect + zapi4RouteBGPDirectEXT + zapi4RouteAll +) + +var routeTypeZapi4Map = map[RouteType]RouteType{ + routeNHRP: zapi4RouteNHRP, + routeHSLS: zapi4RouteHSLS, + routeOLSR: zapi4RouteOLSR, + routeTABLE: zapi4RouteTABLE, + routeLDP: zapi4RouteLDP, + routeVNC: zapi4RouteVNC, + routeVNCDirect: zapi4RouteVNCDirect, + routeVNCDirectRH: zapi4RouteVNCDirectRH, + routeBGPDirect: zapi4RouteBGPDixrect, + routeBGPDirectEXT: zapi4RouteBGPDirectEXT, + routeAll: zapi4RouteAll, +} + +// For Quagga except common route type. +const ( + zapi3RouteHSLS RouteType = iota + routePIM + 1 + zapi3RouteOLSR + zapi3RouteBABEL + zapi3RouteNHRP // quagga 1.2.4 +) + +var routeTypeZapi3Map = map[RouteType]RouteType{ + routeHSLS: zapi3RouteHSLS, + routeOLSR: zapi3RouteOLSR, + routeBABEL: zapi3RouteBABEL, + routeNHRP: zapi3RouteNHRP, +} + +func (t RouteType) toEach(version uint8, softwareName string) RouteType { + if t <= routePIM || version > 4 { // not need to convert + return t + } + routeTypeMap := routeTypeZapi4Map + if version < 4 { + routeTypeMap = routeTypeZapi3Map + } + backward, ok := routeTypeMap[t] + if ok { + return backward // success to convert + } + return routeMax // fail to convert and error value +} + +var routeTypeValueMap = map[string]RouteType{ + "system": routeSystem, + "kernel": routeKernel, + "connect": routeConnect, // hack for backward compatibility + "directly-connected": routeConnect, + "static": RouteStatic, + "rip": routeRIP, + "ripng": routeRIPNG, + "ospf": routeOSPF, + "ospf3": routeOSPF6, + "isis": routeISIS, + "bgp": RouteBGP, + "pim": routePIM, + "eigrp": routeEIGRP, // add in frr4(zapi5) + "nhrp": routeNHRP, + "hsls": routeHSLS, + "olsr": routeOLSR, + "table": routeTABLE, + "ldp": routeLDP, + "vnc": routeVNC, + "vnc-direct": routeVNCDirect, + "vnc-rn": routeVNCDirectRH, + "bgp-direct": routeBGPDirect, + "bgp-direct-to-nve-groups": routeBGPDirectEXT, + "babel": routeBABEL, + "sharp": routeSHARP, + "pbr": routePBR, + "bfd": routeBFD, + "openfabric": routeOpenfabric, // add in frr7.0(zapi6) + "vrrp": routeVRRP, // add in frr7.2(zapi6) + "nhg": routeNHG, // add in frr7.3(zapi6) + "wildcard": routeAll, +} + +// RouteTypeFromString converts from string to route type +func RouteTypeFromString(typ string, version uint8, softwareName string) (RouteType, error) { + t, ok := routeTypeValueMap[typ] + if !ok { // failed to lookup RouteType from string + return t, fmt.Errorf("unknown route type: %s in version: %d (%s)", typ, version, softwareName) + } + t = t.toEach(version, softwareName) //when lookup failes return routeMax + if t > getRouteAll(version, softwareName) { + return t, fmt.Errorf("unknown route type: %d in version: %d (%s)", t, version, softwareName) + } + return t, nil // Success +} + func addressByteLength(family uint8) (int, error) { switch family { case syscall.AF_INET: @@ -794,265 +889,294 @@ func ipFromFamily(family uint8, buf []byte) net.IP { return nil } -// API Message Flags. -type MESSAGE_FLAG uint8 - -// For FRRouting version 4, 5 and 6 (ZAPI version 5 and 6). -const ( - FRR_ZAPI5_MESSAGE_NEXTHOP MESSAGE_FLAG = 0x01 - FRR_ZAPI5_MESSAGE_DISTANCE MESSAGE_FLAG = 0x02 - FRR_ZAPI5_MESSAGE_METRIC MESSAGE_FLAG = 0x04 - FRR_ZAPI5_MESSAGE_TAG MESSAGE_FLAG = 0x08 - FRR_ZAPI5_MESSAGE_MTU MESSAGE_FLAG = 0x10 - FRR_ZAPI5_MESSAGE_SRCPFX MESSAGE_FLAG = 0x20 - FRR_ZAPI5_MESSAGE_LABEL MESSAGE_FLAG = 0x40 - FRR_ZAPI5_MESSAGE_TABLEID MESSAGE_FLAG = 0x80 +// MessageFlag is the type of API Message Flags. +type MessageFlag uint8 + +const ( // For FRRouting version 4, 5 and 6 (ZAPI version 5 and 6). + // MessageNexthop is referred in zclient + MessageNexthop MessageFlag = 0x01 + // MessageDistance is referred in zclient_test + MessageDistance MessageFlag = 0x02 + // MessageMetric is referred in zclient + MessageMetric MessageFlag = 0x04 + messageTag MessageFlag = 0x08 + // MessageMTU is referred in zclient_test + MessageMTU MessageFlag = 0x10 + messageSRCPFX MessageFlag = 0x20 + // MessageLabel is referred in zclient + MessageLabel MessageFlag = 0x40 // deleted in frr7.3 + messageTableID MessageFlag = 0x80 // introduced in frr5 ) -// For FRRouting. -const ( - FRR_MESSAGE_NEXTHOP MESSAGE_FLAG = 0x01 - FRR_MESSAGE_IFINDEX MESSAGE_FLAG = 0x02 - FRR_MESSAGE_DISTANCE MESSAGE_FLAG = 0x04 - FRR_MESSAGE_METRIC MESSAGE_FLAG = 0x08 - FRR_MESSAGE_TAG MESSAGE_FLAG = 0x10 - FRR_MESSAGE_MTU MESSAGE_FLAG = 0x20 - FRR_MESSAGE_SRCPFX MESSAGE_FLAG = 0x40 +const ( // For FRRouting. + messageIFIndex MessageFlag = 0x02 + zapi4MessageDistance MessageFlag = 0x04 + zapi4MessageMetric MessageFlag = 0x08 + zapi4MessageTag MessageFlag = 0x10 + zapi4MessageMTU MessageFlag = 0x20 + zapi4MessageSRCPFX MessageFlag = 0x40 ) -// For Quagga. -const ( - MESSAGE_NEXTHOP MESSAGE_FLAG = 0x01 - MESSAGE_IFINDEX MESSAGE_FLAG = 0x02 - MESSAGE_DISTANCE MESSAGE_FLAG = 0x04 - MESSAGE_METRIC MESSAGE_FLAG = 0x08 - MESSAGE_MTU MESSAGE_FLAG = 0x10 - MESSAGE_TAG MESSAGE_FLAG = 0x20 +const ( // For Quagga. + zapi3MessageMTU MessageFlag = 0x10 + zapi3MessageTag MessageFlag = 0x20 ) -func (t MESSAGE_FLAG) String(version uint8) string { +// ToEach is referred in zclient +func (f MessageFlag) ToEach(version uint8) MessageFlag { + if version > 4 { //zapi version 5, 6 + return f + } + if version < 4 { //zapi version 3, 2 + switch f { + case MessageMTU: + return zapi3MessageMTU + case messageTag: + return zapi3MessageTag + } + } + switch f { //zapi version 4 + case MessageDistance, MessageMetric, messageTag, MessageMTU, messageSRCPFX: + return f << 1 + } + return f +} +func (f MessageFlag) string(version uint8) string { var ss []string - if (version <= 3 && t&MESSAGE_NEXTHOP > 0) || - (version == 4 && t&FRR_MESSAGE_NEXTHOP > 0) || - (version >= 5 && t&FRR_ZAPI5_MESSAGE_NEXTHOP > 0) { + if f&MessageNexthop > 0 { ss = append(ss, "NEXTHOP") } - if (version <= 3 && t&MESSAGE_IFINDEX > 0) || (version == 4 && t&FRR_MESSAGE_IFINDEX > 0) { + if version < 4 && f&messageIFIndex > 0 { ss = append(ss, "IFINDEX") } - if (version <= 3 && t&MESSAGE_DISTANCE > 0) || - (version == 4 && t&FRR_MESSAGE_DISTANCE > 0) || - (version >= 5 && t&FRR_ZAPI5_MESSAGE_DISTANCE > 0) { + if f&MessageDistance.ToEach(version) > 0 { ss = append(ss, "DISTANCE") } - if (version <= 3 && t&MESSAGE_METRIC > 0) || - (version == 4 && t&FRR_MESSAGE_METRIC > 0) || - (version >= 5 && t&FRR_ZAPI5_MESSAGE_METRIC > 0) { + if f&MessageMetric.ToEach(version) > 0 { ss = append(ss, "METRIC") } - if (version <= 3 && t&MESSAGE_MTU > 0) || (version == 4 && t&FRR_MESSAGE_MTU > 0) || - (version >= 5 && t&FRR_ZAPI5_MESSAGE_MTU > 0) { + if f&MessageMTU.ToEach(version) > 0 { ss = append(ss, "MTU") } - if (version <= 3 && t&MESSAGE_TAG > 0) || (version == 4 && t&FRR_MESSAGE_TAG > 0) || - (version >= 5 && t&FRR_ZAPI5_MESSAGE_TAG > 0) { + if f&messageTag.ToEach(version) > 0 { ss = append(ss, "TAG") } - if (version == 4 && t&FRR_MESSAGE_SRCPFX > 0) || - (version >= 5 && t&FRR_ZAPI5_MESSAGE_SRCPFX > 0) { + if version > 3 && f&messageSRCPFX.ToEach(version) > 0 { ss = append(ss, "SRCPFX") } - if version >= 5 && t&FRR_ZAPI5_MESSAGE_LABEL > 0 { + if version > 4 && f&MessageLabel > 0 { ss = append(ss, "LABEL") } - + if version > 5 && f&messageTableID > 0 { + ss = append(ss, "TABLEID") + } return strings.Join(ss, "|") } -// Message Flags -type FLAG uint64 - -// For FRRouting version 7 (zebra API version 6) -const ( - FRR_ZAPI6_FLAG_ALLOW_RECURSION FLAG = 0x01 - FRR_ZAPI6_FLAG_SELFROUTE FLAG = 0x02 - FRR_ZAPI6_FLAG_IBGP FLAG = 0x04 - FRR_ZAPI6_FLAG_SELECTED FLAG = 0x08 - FRR_ZAPI6_FLAG_FIB_OVERRIDE FLAG = 0x10 - FRR_ZAPI6_FLAG_EVPN_ROUTE FLAG = 0x20 - FRR_ZAPI6_FLAG_RR_USE_DISTANCE FLAG = 0x40 - FRR_ZAPI6_FLAG_ONLINk FLAG = 0x40 +// Flag is Message Flag which is referred in zclient +type Flag uint64 + +const ( // For FRRouting version 7 (zebra API version 6) + // FlagAllowRecursion is referred in zclient, and it is renamed from ZEBRA_FLAG_INTERNAL (https://github.com/FRRouting/frr/commit/4e8b02f4df5d6bcfde6390955b8feda2a17dc9bd) + FlagAllowRecursion Flag = 0x01 // quagga, frr3, frr4, frr5, frr6, frr7 + flagSelfRoute Flag = 0x02 // quagga, frr3, frr4, frr5, frr6, frr7 + // FlagIBGP is referred in zclient + FlagIBGP Flag = 0x04 + // FlagSelected referred in zclient_test + FlagSelected Flag = 0x08 + flagFIBOverride Flag = 0x10 + flagEvpnRoute Flag = 0x20 + flagRRUseDistance Flag = 0x40 + flagOnlink Flag = 0x80 // frr7.0 only, this vale is deleted in frr7.1 ) -// For Quagga (ZAPI v2, v3), FRR v3 (ZAPI v4), FRR v4, v5 (ZAPI v5), FRR v6 (ZAPI v6) +// For Quagga (ZAPI v2, v3), FRR v3 (ZAPI v4), FRR v4, v5 (ZAPI v5), FRR v6 (ZAPI v6) for backward compatibility const ( - // Rename ZEBRA_FLAG_INTERNAL -> ZEBRA_FLAG_ALLOW_RECURSION - // https://github.com/FRRouting/frr/commit/4e8b02f4df5d6bcfde6390955b8feda2a17dc9bd - FLAG_ALLOW_RECURSION FLAG = 0x01 - FLAG_SELFROUTE FLAG = 0x02 - FLAG_BLACKHOLE FLAG = 0x04 // quagga, frr3 - FLAG_IBGP FLAG = 0x08 - FLAG_SELECTED FLAG = 0x10 - FLAG_CHANGED FLAG = 0x20 - FLAG_STATIC FLAG = 0x40 - FLAG_REJECT FLAG = 0x80 // quagga, frr3 - FLAG_SCOPE_LINK FLAG = 0x100 - FLAG_FIB_OVERRIDE FLAG = 0x200 - FLAG_EVPN_ROUTE FLAG = 0x400 - FLAG_RR_USE_DISTANCE FLAG = 0x800 + flagBlackhole Flag = 0x04 // quagga, frr3 + flagStatic Flag = 0x40 // quagga, frr3, frr4, frr5, frr6 + flagReject Flag = 0x80 // quagga, frr3 + flagScopeLink Flag = 0x100 // frr4, frr5, frr6 ) -func (t FLAG) String(version uint8, softwareName string) string { - if version == 6 && softwareName != "frr6" { - return t.stringFrrZapi6() +// ToEach is referred in zclient +func (f Flag) ToEach(version uint8, softwareName string) Flag { + if (version == 6 && softwareName != "frr6") || (f < FlagIBGP) || f > flagRRUseDistance { + return f + } + switch f { + case FlagIBGP, FlagSelected: // 0x04->0x08,0x08->0x10(quagga, frr3,4,5,6) + return f << 1 + case flagEvpnRoute, flagRRUseDistance: // 0x20->0x400,0x40->0x800(frr4,5,6) + return f << 5 + case flagFIBOverride: + if version < 4 { + return f << 1 // 0x10->0x20(quagga) + } + return f << 5 // 0x10->0x200(frr3, frr4, frr5, frr6) } - return t.string() + return f } -func (t FLAG) string() string { +// String is referred in zclient +func (f Flag) String(version uint8, softwareName string) string { var ss []string - if t&FLAG_ALLOW_RECURSION > 0 { + // common flag + if f&FlagAllowRecursion > 0 { ss = append(ss, "FLAG_ALLOW_RECURSION") } - if t&FLAG_SELFROUTE > 0 { + if f&flagSelfRoute > 0 { ss = append(ss, "FLAG_SELFROUTE") } - if t&FLAG_BLACKHOLE > 0 { - ss = append(ss, "FLAG_BLACKHOLE") - } - if t&FLAG_IBGP > 0 { + if f&FlagIBGP.ToEach(version, softwareName) > 0 { ss = append(ss, "FLAG_IBGP") } - if t&FLAG_SELECTED > 0 { + if f&FlagSelected.ToEach(version, softwareName) > 0 { ss = append(ss, "FLAG_SELECTED") } - if t&FLAG_CHANGED > 0 { - ss = append(ss, "FLAG_CHANGED") - } - if t&FLAG_STATIC > 0 { - ss = append(ss, "FLAG_STATIC") - } - if t&FLAG_REJECT > 0 { - ss = append(ss, "FLAG_REJECT") - } - if t&FLAG_SCOPE_LINK > 0 { - ss = append(ss, "FLAG_SCOPE_LINK") - } - if t&FLAG_FIB_OVERRIDE > 0 { - ss = append(ss, "FLAG_FIB_OVERRIDE") - } - if t&FLAG_EVPN_ROUTE > 0 { + if f&flagEvpnRoute.ToEach(version, softwareName) > 0 { ss = append(ss, "FLAG_EVPN_ROUTE") } - if t&FLAG_RR_USE_DISTANCE > 0 { + if f&flagRRUseDistance.ToEach(version, softwareName) > 0 { ss = append(ss, "FLAG_RR_USE_DISTANCE") } - - return strings.Join(ss, "|") -} -func (t FLAG) stringFrrZapi6() string { - var ss []string - if t&FRR_ZAPI6_FLAG_ALLOW_RECURSION > 0 { - ss = append(ss, "FLAG_ALLOW_RECURSION") - } - if t&FRR_ZAPI6_FLAG_SELFROUTE > 0 { - ss = append(ss, "FLAG_SELFROUTE") - } - if t&FRR_ZAPI6_FLAG_IBGP > 0 { - ss = append(ss, "FLAG_IBGP") + if f&flagFIBOverride.ToEach(version, softwareName) > 0 { + ss = append(ss, "FLAG_FIB_OVERRIDE") } - if t&FRR_ZAPI6_FLAG_SELECTED > 0 { - ss = append(ss, "FLAG_SELECTED") + if version == 6 && softwareName == "frr7" && f&flagOnlink > 0 { // frr7.0 only + ss = append(ss, "FLAG_ONLINK") } - if t&FRR_ZAPI6_FLAG_FIB_OVERRIDE > 0 { - ss = append(ss, "FLAG_FIB_OVERRIDE") + if (version < 6 || (version == 6 && softwareName == "frr6")) && f&flagStatic > 0 { + ss = append(ss, "FLAG_STATIC") // quagga, frr3, frr4, frr5, frr6 } - if t&FRR_ZAPI6_FLAG_EVPN_ROUTE > 0 { - ss = append(ss, "FLAG_EVPN_ROUTE") + if version < 5 && f&flagBlackhole > 0 { // quagga, frr3 + ss = append(ss, "FLAG_BLACKHOLE") } - if t&FRR_ZAPI6_FLAG_RR_USE_DISTANCE > 0 { - ss = append(ss, "FLAG_RR_USE_DISTANCE") + if version < 5 && f&flagReject > 0 { // quagga, frr3 + ss = append(ss, "FLAG_REJECT") } - if t&FRR_ZAPI6_FLAG_ONLINk > 0 { - ss = append(ss, "FLAG_ONLINK") + if (version == 5 || (version == 6 && softwareName == "frr6")) && f&flagScopeLink > 0 { + ss = append(ss, "FLAG_SCOPE_LINK") // frr4, frr5, frr6 } return strings.Join(ss, "|") } // Nexthop Types. -//go:generate stringer -type=NEXTHOP_TYPE -type NEXTHOP_TYPE uint8 +//go:generate stringer -type=nexthopType +type nexthopType uint8 // For FRRouting. const ( - _ NEXTHOP_TYPE = iota - FRR_NEXTHOP_TYPE_IFINDEX - FRR_NEXTHOP_TYPE_IPV4 - FRR_NEXTHOP_TYPE_IPV4_IFINDEX - FRR_NEXTHOP_TYPE_IPV6 - FRR_NEXTHOP_TYPE_IPV6_IFINDEX - FRR_NEXTHOP_TYPE_BLACKHOLE + _ nexthopType = iota + nexthopTypeIFIndex // 1 + nexthopTypeIPv4 // 2 + nexthopTypeIPv4IFIndex // 3 + nexthopTypeIPv6 // 4 + nexthopTypeIPv6IFIndex // 5 + nexthopTypeBlackhole // 6 ) // For Quagga. const ( - _ NEXTHOP_TYPE = iota - NEXTHOP_TYPE_IFINDEX - NEXTHOP_TYPE_IFNAME - NEXTHOP_TYPE_IPV4 - NEXTHOP_TYPE_IPV4_IFINDEX - NEXTHOP_TYPE_IPV4_IFNAME - NEXTHOP_TYPE_IPV6 - NEXTHOP_TYPE_IPV6_IFINDEX - NEXTHOP_TYPE_IPV6_IFNAME - NEXTHOP_TYPE_BLACKHOLE + nexthopTypeIFName nexthopType = iota + 2 // 2 + backwardNexthopTypeIPv4 // 3 + backwardNexthopTypeIPv4IFIndex // 4 + nexthopTypeIPv4IFName // 5 + backwardNexthopTypeIPv6 // 6 + backwardNexthopTypeIPv6IFIndex // 7 + nexthopTypeIPv6IFName // 8 + backwardNexthopTypeBlackhole // 9 ) +var nexthopTypeMap = map[nexthopType]nexthopType{ + nexthopTypeIPv4: backwardNexthopTypeIPv4, // 2 -> 3 + nexthopTypeIPv4IFIndex: backwardNexthopTypeIPv4IFIndex, // 3 -> 4 + nexthopTypeIPv6: backwardNexthopTypeIPv6, // 4 -> 6 + nexthopTypeIPv6IFIndex: backwardNexthopTypeIPv6IFIndex, // 5 -> 7 + nexthopTypeBlackhole: backwardNexthopTypeBlackhole, // 6 -> 9 +} + +func (t nexthopType) toEach(version uint8) nexthopType { + if version > 3 { // frr + return t + } + if t == nexthopTypeIFIndex || t > nexthopTypeBlackhole { // 1 (common), 7, 8, 9 (out of map range) + return t + } + backward, ok := nexthopTypeMap[t] + if ok { + return backward // converted value + } + return nexthopType(0) // error for conversion +} + +func (t nexthopType) ipToIPIFIndex() nexthopType { + // process of nexthopTypeIPv[4|6] is same as nexthopTypeIPv[4|6]IFIndex + // in IPRouteBode of frr7.3 and NexthoUpdate of frr + if t == nexthopTypeIPv4 { + return nexthopTypeIPv4IFIndex + } else if t == nexthopTypeIPv6 { + return nexthopTypeIPv6IFIndex + } + return t +} +func (t nexthopType) ifNameToIFIndex() nexthopType { // quagga + if t == nexthopTypeIFName { + return nexthopTypeIFIndex + } else if t == nexthopTypeIPv4IFName { + return backwardNexthopTypeIPv4IFIndex + } else if t == nexthopTypeIPv6IFName { + return backwardNexthopTypeIPv6IFIndex + } + return t +} + // Nexthop Flags. -//go:generate stringer -type=NEXTHOP_FLAG -type NEXTHOP_FLAG uint8 +//go:generate stringer -type=nexthopFlag +type nexthopFlag uint8 const ( - NEXTHOP_FLAG_ACTIVE NEXTHOP_FLAG = 0x01 // This nexthop is alive. - NEXTHOP_FLAG_FIB NEXTHOP_FLAG = 0x02 // FIB nexthop. - NEXTHOP_FLAG_RECURSIVE NEXTHOP_FLAG = 0x04 // Recursive nexthop. - NEXTHOP_FLAG_ONLINK NEXTHOP_FLAG = 0x08 // Nexthop should be installed onlink. - NEXTHOP_FLAG_MATCHED NEXTHOP_FLAG = 0x10 // Already matched vs a nexthop - NEXTHOP_FLAG_FILTERED NEXTHOP_FLAG = 0x20 // rmap filtered (version >= 4) - NEXTHOP_FLAG_DUPLICATE NEXTHOP_FLAG = 0x40 // nexthop duplicates (version >= 5) - NEXTHOP_FLAG_EVPN_RVTEP NEXTHOP_FLAG = 0x80 // EVPN remote vtep nexthop (version >= 5) + nexthopFlagActive nexthopFlag = 0x01 // This nexthop is alive. + nexthopFlagFIB nexthopFlag = 0x02 // FIB nexthop. + nexthopFlagRecursive nexthopFlag = 0x04 // Recursive nexthop. + nexthopFlagOnlink nexthopFlag = 0x08 // Nexthop should be installed onlink. + nexthopFlagMatched nexthopFlag = 0x10 // Already matched vs a nexthop + nexthopFlagFiltered nexthopFlag = 0x20 // rmap filtered (version >= 4) + nexthopFlagDuplicate nexthopFlag = 0x40 // nexthop duplicates (version >= 5) + nexthopFlagEvpnRvtep nexthopFlag = 0x80 // Evpn remote vtep nexthop (version >= 5) ) // Interface PTM Enable Configuration. -//go:generate stringer -type=PTM_ENABLE -type PTM_ENABLE uint8 +//go:generate stringer -type=ptmEnable +type ptmEnable uint8 const ( - PTM_ENABLE_OFF PTM_ENABLE = 0 - PTM_ENABLE_ON PTM_ENABLE = 1 - PTM_ENABLE_UNSPEC PTM_ENABLE = 2 + ptmEnableOff ptmEnable = 0 + ptmEnableOn ptmEnable = 1 + ptmEnableUnspec ptmEnable = 2 ) // PTM Status. -//go:generate stringer -type=PTM_STATUS -type PTM_STATUS uint8 +//go:generate stringer -type=ptmStatus +type ptmStatus uint8 const ( - PTM_STATUS_DOWN PTM_STATUS = 0 - PTM_STATUS_UP PTM_STATUS = 1 - PTM_STATUS_UNKNOWN PTM_STATUS = 2 + ptmStatusDown ptmStatus = 0 + ptmStatusUp ptmStatus = 1 + ptmStatusUnknown ptmStatus = 2 ) +// Client is zebra client which is referred in zclient type Client struct { outgoing chan *Message incoming chan *Message - redistDefault ROUTE_TYPE + redistDefault RouteType conn net.Conn Version uint8 SoftwareName string } -func NewClient(network, address string, typ ROUTE_TYPE, version uint8, software string) (*Client, error) { +// NewClient returns a Client instance (Client constructor) +func NewClient(network, address string, typ RouteType, version uint8, software string, mplsLabelRangeSize uint32) (*Client, error) { conn, err := net.Dial(network, address) if err != nil { return nil, err @@ -1069,7 +1193,7 @@ func NewClient(network, address string, typ ROUTE_TYPE, version uint8, software if ((version == 2 || version == 3) && software != "" && software != "quagga") || (version == 4 && software != "" && software != "frr3") || (version == 5 && software != "" && software != "frr4" && software != "frr5" && software != "cumulus") || - (version == 6 && software != "" && software != "frr6" && software != "frr7" && software != "frr7.1" && software != "frr7.2") { + (version == 6 && software != "" && software != "frr6" && software != "frr7" && software != "frr7.1" && software != "frr7.2" && software != "frr7.3") { isAllowableSoftware = false } if !isAllowableSoftware { @@ -1092,7 +1216,7 @@ func NewClient(network, address string, typ ROUTE_TYPE, version uint8, software for { m, more := <-outgoing if more { - b, err := m.Serialize(software) + b, err := m.serialize(software) if err != nil { log.WithFields(log.Fields{ "Topic": "Zebra", @@ -1115,13 +1239,12 @@ func NewClient(network, address string, typ ROUTE_TYPE, version uint8, software } }() - // Send HELLO/ROUTER_ID_ADD messages to negotiate the Zebra message version. + // Send Hello/RouterIDAdd messages to negotiate the Zebra message version. c.SendHello() c.SendRouterIDAdd() - // ZAPIv5 has ZEBRA_LABEL_MANAGER_CONNECT_ASYNC, however frr4 (ZAPIv5) doesn't have it. - if version > 4 && software != "frr4" { - c.SendLabelManagerConnectAsync() + if mplsLabelRangeSize > 0 && c.SupportMpls() { + c.sendLabelManagerConnect(true) } receiveSingleMsg := func() (*Message, error) { @@ -1135,7 +1258,7 @@ func NewClient(network, address string, typ ROUTE_TYPE, version uint8, software } hd := &Header{} - err = hd.DecodeFromBytes(headerBuf) + err = hd.decodeFromBytes(headerBuf) if c.Version != hd.Version { log.WithFields(log.Fields{ "Topic": "Zebra", @@ -1161,11 +1284,10 @@ func NewClient(network, address string, typ ROUTE_TYPE, version uint8, software return nil, err } - m, err := ParseMessage(hd, bodyBuf, software) + m, err := parseMessage(hd, bodyBuf, software) if err != nil { // Just outputting warnings (not error message) and ignore this - // error considering the case that body parser is not implemented - // yet. + // error considering the case that body parser is not implemented yet. log.WithFields(log.Fields{ "Topic": "Zebra", "Header": hd, @@ -1184,7 +1306,7 @@ func NewClient(network, address string, typ ROUTE_TYPE, version uint8, software // Try to receive the first message from Zebra. if m, err := receiveSingleMsg(); err != nil { - c.Close() + c.close() // Return error explicitly in order to retry connection. return nil, err } else if m != nil { @@ -1212,11 +1334,12 @@ func readAll(conn net.Conn, length int) ([]byte, error) { return buf, err } +// Receive return incoming channel message func (c *Client) Receive() chan *Message { return c.incoming } -func (c *Client) Send(m *Message) { +func (c *Client) send(m *Message) { defer func() { if err := recover(); err != nil { log.WithFields(log.Fields{ @@ -1232,292 +1355,152 @@ func (c *Client) Send(m *Message) { c.outgoing <- m } -func (c *Client) SendCommand(command API_TYPE, vrfId uint32, body Body) error { - marker := HEADER_MARKER - if c.Version >= 4 { - marker = FRR_HEADER_MARKER - } - if c.Version == 6 && c.SoftwareName == "frr6" { - if frr6Command, err := frr6Zapi6Command(command, c.SoftwareName, false); err == nil { - command = frr6Command - } else { - return err - } - } else if c.Version == 6 && c.SoftwareName == "frr7.2" { - // frr7.2 adds INTERFACE_SET_PROTODOWN between INTERFACE_SET_MASTER(6) and ROUTE_ADD - if command >= FRR_ZAPI6_ROUTE_ADD { - command++ - } - } else if c.Version == 5 && c.SoftwareName == "frr4" { - if frr4Command, err := frr4Zapi5Command(command, c.SoftwareName, false); err == nil { - command = frr4Command - } else { - return err - } - } else if c.Version == 5 && c.SoftwareName == "cumulus" { - if cumulusCommand, err := cumulusZapi5Command(command, c.SoftwareName, false); err == nil { - command = cumulusCommand - } else { - return err - } - } +func (c *Client) sendCommand(command APIType, vrfID uint32, body Body) error { m := &Message{ Header: Header{ Len: HeaderSize(c.Version), - Marker: marker, + Marker: HeaderMarker(c.Version), Version: c.Version, - VrfId: vrfId, - Command: command, + VrfID: vrfID, + Command: command.ToEach(c.Version, c.SoftwareName), }, Body: body, } - c.Send(m) + c.send(m) return nil } +// SendHello sends HELLO message to zebra daemon. func (c *Client) SendHello() error { if c.redistDefault > 0 { - command := HELLO - if c.Version == 4 { - command = FRR_HELLO - } else if c.Version == 5 { - command = FRR_ZAPI5_HELLO - } else if c.Version >= 6 { - command = FRR_ZAPI6_HELLO + body := &helloBody{ + redistDefault: c.redistDefault, + instance: 0, } - body := &HelloBody{ - RedistDefault: c.redistDefault, - Instance: 0, - } - return c.SendCommand(command, VRF_DEFAULT, body) + return c.sendCommand(hello, DefaultVrf, body) } return nil } +// SendRouterIDAdd sends ROUTER_ID_ADD message to zebra daemon. func (c *Client) SendRouterIDAdd() error { - command := ROUTER_ID_ADD - if c.Version == 4 { - command = FRR_ROUTER_ID_ADD - } else if c.Version == 5 { - command = FRR_ZAPI5_ROUTER_ID_ADD - } else if c.Version >= 6 { - command = FRR_ZAPI6_ROUTER_ID_ADD - } - return c.SendCommand(command, VRF_DEFAULT, nil) + return c.sendCommand(routerIDAdd, DefaultVrf, nil) } +// SendInterfaceAdd sends INTERFACE_ADD message to zebra daemon. func (c *Client) SendInterfaceAdd() error { - command := INTERFACE_ADD - if c.Version == 4 { - command = FRR_INTERFACE_ADD - } else if c.Version >= 5 { - command = FRR_ZAPI5_INTERFACE_ADD - } - return c.SendCommand(command, VRF_DEFAULT, nil) + return c.sendCommand(interfaceAdd, DefaultVrf, nil) } -func (c *Client) SendRedistribute(t ROUTE_TYPE, vrfId uint32) error { - command := REDISTRIBUTE_ADD +// SendRedistribute sends REDISTRIBUTE message to zebra daemon. +func (c *Client) SendRedistribute(t RouteType, vrfID uint32) error { + if c.redistDefault != t { - bodies := make([]*RedistributeBody, 0) + bodies := make([]*redistributeBody, 0) if c.Version <= 3 { - bodies = append(bodies, &RedistributeBody{ - Redist: t, + bodies = append(bodies, &redistributeBody{ + redist: t, }) - } else { // version >= 4 - command = FRR_REDISTRIBUTE_ADD - if c.Version == 5 { - command = FRR_ZAPI5_REDISTRIBUTE_ADD - } else if c.Version >= 6 { - command = FRR_ZAPI6_REDISTRIBUTE_ADD - } - for _, afi := range []AFI{AFI_IP, AFI_IP6} { - bodies = append(bodies, &RedistributeBody{ - Afi: afi, - Redist: t, - Instance: 0, + } else { // Version >= 4 + for _, afi := range []afi{afiIP, afiIP6} { + bodies = append(bodies, &redistributeBody{ + afi: afi, + redist: t, + instance: 0, }) } } for _, body := range bodies { - return c.SendCommand(command, vrfId, body) + return c.sendCommand(redistributeAdd, vrfID, body) } } - return nil } -func (c *Client) SendRedistributeDelete(t ROUTE_TYPE) error { - if t < ROUTE_MAX { - command := REDISTRIBUTE_DELETE - if c.Version == 4 { - command = FRR_REDISTRIBUTE_DELETE - } else if c.Version == 5 { - command = FRR_ZAPI5_REDISTRIBUTE_DELETE - } else if c.Version >= 6 { - command = FRR_ZAPI6_REDISTRIBUTE_DELETE - } - body := &RedistributeBody{ - Redist: t, - } - return c.SendCommand(command, VRF_DEFAULT, body) - } else { - return fmt.Errorf("unknown route type: %d", t) +// SendIPRoute sends ROUTE message to zebra daemon. +func (c *Client) SendIPRoute(vrfID uint32, body *IPRouteBody, isWithdraw bool) error { + routeFamily := body.RouteFamily(c.Version, c.SoftwareName) + if vrfID == DefaultVrf && (routeFamily == bgp.RF_IPv4_VPN || routeFamily == bgp.RF_IPv6_VPN) { + return fmt.Errorf("RF_IPv4_VPN or RF_IPv6_VPN are not suitable for Default VRF (default forwarding table)") } -} - -func (c *Client) SendIPRoute(vrfId uint32, body *IPRouteBody, isWithdraw bool) error { - routeFamily := body.RouteFamily(c.Version) - if vrfId == VRF_DEFAULT && (routeFamily == bgp.RF_IPv4_VPN || routeFamily == bgp.RF_IPv6_VPN) { - return fmt.Errorf("RF_IPv4_VPN or RF_IPv6_VPN are not suitable for VPN_DEFAULT(default forwarding table)") + command := RouteAdd + if isWithdraw { + command = RouteDelete } - command := IPV4_ROUTE_ADD - if c.Version <= 3 { - if body.Prefix.Prefix.To4() != nil { - if isWithdraw { - command = IPV4_ROUTE_DELETE - } - } else { - if isWithdraw { - command = IPV6_ROUTE_DELETE - } else { - command = IPV6_ROUTE_ADD - } - } - } else if c.Version == 4 { // version >= 4 - if body.Prefix.Prefix.To4() != nil { - if isWithdraw { - command = FRR_IPV4_ROUTE_DELETE - } else { - command = FRR_IPV4_ROUTE_ADD - } - } else { - if isWithdraw { - command = FRR_IPV6_ROUTE_DELETE - } else { - command = FRR_IPV6_ROUTE_ADD - } - } - } else { // version >= 5 (version 6 uses the same value as version 5) + if c.Version < 5 && familyFromPrefix(body.Prefix.Prefix) == syscall.AF_INET6 { + command = BackwardIPv6RouteAdd if isWithdraw { - command = FRR_ZAPI5_ROUTE_DELETE - } else { - command = FRR_ZAPI5_ROUTE_ADD + command = BackwardIPv6RouteDelete } } - return c.SendCommand(command, vrfId, body) + return c.sendCommand(command, vrfID, body) } -func (c *Client) SendNexthopRegister(vrfId uint32, body *NexthopRegisterBody, isWithdraw bool) error { - // Note: NEXTHOP_REGISTER and NEXTHOP_UNREGISTER messages are not +// SendNexthopRegister sends NEXTHOP_REGISTER message to zebra daemon. +func (c *Client) SendNexthopRegister(vrfID uint32, body *NexthopRegisterBody, isWithdraw bool) error { + // Note: NexthopRegister and NexthopUnregister messages are not // supported in Zebra protocol version<3. if c.Version < 3 { - return fmt.Errorf("NEXTHOP_REGISTER/NEXTHOP_UNREGISTER are not supported in version: %d", c.Version) + return fmt.Errorf("NexthopRegister/NexthopUnregister are not supported in version: %d", c.Version) } - command := NEXTHOP_REGISTER - if c.Version == 3 { - if isWithdraw { - command = NEXTHOP_UNREGISTER - } - } else if c.Version == 4 { // version == 4 - if isWithdraw { - command = FRR_NEXTHOP_UNREGISTER - } else { - command = FRR_NEXTHOP_REGISTER - } - } else if c.Version == 5 { // version == 5 - if isWithdraw { - command = FRR_ZAPI5_NEXTHOP_UNREGISTER - } else { - command = FRR_ZAPI5_NEXTHOP_REGISTER - } - } else { // version >= 6 - if isWithdraw { - command = FRR_ZAPI6_NEXTHOP_UNREGISTER - } else { - command = FRR_ZAPI6_NEXTHOP_REGISTER - } + command := nexthopRegister + if isWithdraw { + command = nexthopUnregister } - return c.SendCommand(command, vrfId, body) + return c.sendCommand(command, vrfID, body) } -// Reference: zread_label_manager_connect function in zebra/zserv.c of FRR3.x (ZAPI) -// Reference: zread_label_manager_connect function in zebra/zapi_msg.c of FRR5.x and 6.x (ZAPI5 and 6) - -func (c *Client) SendLabelManagerConnect() error { - if c.Version < 4 { - return fmt.Errorf("LABEL_MANAGER_CONNECT is not supported in zebra API version: %d", c.Version) - } - command := FRR_LABEL_MANAGER_CONNECT - proto := FRR_ROUTE_BGP - if c.Version == 5 { - command = FRR_ZAPI5_LABEL_MANAGER_CONNECT - proto = FRR_ZAPI5_ROUTE_BGP - } else if c.Version == 6 { - command = FRR_ZAPI6_LABEL_MANAGER_CONNECT - proto = FRR_ZAPI6_ROUTE_BGP - } - return c.SendCommand( - command, 0, - &LabelManagerConnectBody{ - RedistDefault: proto, - Instance: 0, - }) +// SupportMpls is referred in zclient. It returns bool value. +func (c *Client) SupportMpls() bool { + // Note: frr3&4 have LABEL_MANAGER_CONNECT& GET_LABEL_CHUNK. However + // Routes will not be installed via zebra of frr3&4 after call these APIs. + if c.Version < 5 || c.SoftwareName == "frr4" { + return false // if frr4 or ealier are used + } + return true // if frr5 or later are used } -// Reference: zread_label_manager_connect function in zebra/zserv.c of FRR3.x (ZAPI) -// Reference: zread_label_manager_connect function in zebra/zapi_msg.c of FRR5.x and 6.x (ZAPI5 and 6) - -func (c *Client) SendLabelManagerConnectAsync() error { - if c.Version < 5 { - return fmt.Errorf("LABEL_MANAGER_CONNECT_ASYNC is not supported in zebra API version: %d", c.Version) - } - // ZAPIv5 has ZEBRA_LABEL_MANAGER_CONNECT_ASYNC, however frr4 (ZAPIv5) doesn't have it. - if c.SoftwareName == "frr4" { - return fmt.Errorf("LABEL_MANAGER_CONNECT_ASYNC is not supported in software: %s", c.SoftwareName) +// Ref: zread_label_manager_connect in zebra/zserv.c of FRR3 (ZAPI4) +// Ref: zread_label_manager_connect in zebra/zapi_msg.c of FRR5&6 (ZAPI5&6) +func (c *Client) sendLabelManagerConnect(async bool) error { + if c.Version < 4 { + return fmt.Errorf("LabelManagerConnect is not supported in zebra API version: %d", c.Version) } - command := FRR_ZAPI5_LABEL_MANAGER_CONNECT_ASYNC - proto := FRR_ZAPI5_ROUTE_BGP - if c.Version == 6 { - command = FRR_ZAPI6_LABEL_MANAGER_CONNECT_ASYNC - proto = FRR_ZAPI6_ROUTE_BGP + command := labelManagerConnectAsync + if !async || c.Version == 4 || (c.Version == 5 && c.SoftwareName == "frr4") { + command = labelManagerConnect } - return c.SendCommand( + return c.sendCommand( command, 0, - &LabelManagerConnectBody{ - RedistDefault: proto, - Instance: 0, + &labelManagerConnectBody{ + redistDefault: RouteBGP, + instance: 0, }) } +// SendGetLabelChunk sends GET_LABEL_CHUNK message to zebra daemon. func (c *Client) SendGetLabelChunk(body *GetLabelChunkBody) error { if c.Version < 4 { - return fmt.Errorf("GET_LABEL_CHUNK is not supported in version: %d", c.Version) + return fmt.Errorf("GetLabelChunk is not supported in version: %d", c.Version) } - command := FRR_GET_LABEL_CHUNK - body.Instance = 0 - if c.Version == 5 { - body.Proto = uint8(FRR_ZAPI5_ROUTE_BGP) - command = FRR_ZAPI5_GET_LABEL_CHUNK - } else if c.Version == 6 { - body.Proto = uint8(FRR_ZAPI6_ROUTE_BGP) - command = FRR_ZAPI6_GET_LABEL_CHUNK - } - return c.SendCommand(command, 0, body) + body.instance = 0 + body.proto = uint8(RouteBGP) + return c.sendCommand(getLabelChunk, 0, body) } -func (c *Client) SendVrfLabel(label uint32, vrfId uint32) error { - body := &VrfLabelBody{ - Label: label, - Afi: AFI_IP, - LabelType: LSP_BGP, +// SendVrfLabel sends VRF_LABEL message to zebra daemon. +func (c *Client) SendVrfLabel(label uint32, vrfID uint32) error { + // ZAPIv5 has ZEBRA_VRF_LABEL, however frr4 (ZAPIv5) doesn't have it. + if c.Version < 5 || (c.Version == 5 && c.SoftwareName == "frr4") { + return fmt.Errorf("VrfLabel is not supported in zebra API version: %d software: %s", c.Version, c.SoftwareName) } - command := FRR_ZAPI5_VRF_LABEL - if c.Version == 6 { - command = FRR_ZAPI6_VRF_LABEL + body := &vrfLabelBody{ + label: label, + afi: afiIP, + labelType: lspBGP, } - return c.SendCommand(command, vrfId, body) + return c.sendCommand(vrfLabel, vrfID, body) } // for avoiding double close @@ -1533,20 +1516,30 @@ func closeChannel(ch chan *Message) bool { return false } -func (c *Client) Close() error { +func (c *Client) close() error { closeChannel(c.outgoing) return c.conn.Close() } +// SetLabelFlag is referred in zclient, this func sets label flag +func (c Client) SetLabelFlag(msgFlags *MessageFlag, nexthop *Nexthop) { + if c.Version == 6 && (c.SoftwareName == "frr7.3" || c.SoftwareName == "") { + nexthop.flags |= zapiNexthopFlagLabel + } else if c.Version > 4 { + *msgFlags |= MessageLabel + } +} + +// Header is header of zebra message. type Header struct { Len uint16 Marker uint8 Version uint8 - VrfId uint32 // ZAPI v4: 16bits, v5: 32bits - Command API_TYPE + VrfID uint32 // ZAPI v4: 16bits, v5: 32bits + Command APIType } -func (h *Header) Serialize() ([]byte, error) { +func (h *Header) serialize() ([]byte, error) { buf := make([]byte, HeaderSize(h.Version)) binary.BigEndian.PutUint16(buf[0:2], h.Len) buf[2] = h.Marker @@ -1555,10 +1548,10 @@ func (h *Header) Serialize() ([]byte, error) { case 2: binary.BigEndian.PutUint16(buf[4:6], uint16(h.Command)) case 3, 4: - binary.BigEndian.PutUint16(buf[4:6], uint16(h.VrfId)) + binary.BigEndian.PutUint16(buf[4:6], uint16(h.VrfID)) binary.BigEndian.PutUint16(buf[6:8], uint16(h.Command)) case 5, 6: - binary.BigEndian.PutUint32(buf[4:8], uint32(h.VrfId)) + binary.BigEndian.PutUint32(buf[4:8], uint32(h.VrfID)) binary.BigEndian.PutUint16(buf[8:10], uint16(h.Command)) default: return nil, fmt.Errorf("unsupported ZAPI version: %d", h.Version) @@ -1566,7 +1559,7 @@ func (h *Header) Serialize() ([]byte, error) { return buf, nil } -func (h *Header) DecodeFromBytes(data []byte) error { +func (h *Header) decodeFromBytes(data []byte) error { if uint16(len(data)) < 4 { return fmt.Errorf("not all ZAPI message header") } @@ -1578,202 +1571,193 @@ func (h *Header) DecodeFromBytes(data []byte) error { } switch h.Version { case 2: - h.Command = API_TYPE(binary.BigEndian.Uint16(data[4:6])) + h.Command = APIType(binary.BigEndian.Uint16(data[4:6])) case 3, 4: - h.VrfId = uint32(binary.BigEndian.Uint16(data[4:6])) - h.Command = API_TYPE(binary.BigEndian.Uint16(data[6:8])) + h.VrfID = uint32(binary.BigEndian.Uint16(data[4:6])) + h.Command = APIType(binary.BigEndian.Uint16(data[6:8])) case 5, 6: - h.VrfId = binary.BigEndian.Uint32(data[4:8]) - h.Command = API_TYPE(binary.BigEndian.Uint16(data[8:10])) + h.VrfID = binary.BigEndian.Uint32(data[4:8]) + h.Command = APIType(binary.BigEndian.Uint16(data[8:10])) default: return fmt.Errorf("unsupported ZAPI version: %d", h.Version) } return nil } +// Body is an interface for zebra messages. type Body interface { - DecodeFromBytes([]byte, uint8, string) error - Serialize(uint8, string) ([]byte, error) - String(uint8, string) string + decodeFromBytes([]byte, uint8, string) error + serialize(uint8, string) ([]byte, error) + string(uint8, string) string } -type UnknownBody struct { +type unknownBody struct { Data []byte } -func (b *UnknownBody) DecodeFromBytes(data []byte, version uint8, softwareName string) error { +func (b *unknownBody) decodeFromBytes(data []byte, version uint8, softwareName string) error { b.Data = data return nil } -func (b *UnknownBody) Serialize(version uint8, softwareName string) ([]byte, error) { +func (b *unknownBody) serialize(version uint8, softwareName string) ([]byte, error) { return b.Data, nil } -func (b *UnknownBody) String(version uint8, softwareName string) string { +func (b *unknownBody) string(version uint8, softwareName string) string { return fmt.Sprintf("data: %v", b.Data) } -type HelloBody struct { - RedistDefault ROUTE_TYPE - Instance uint16 - ReceiveNotify uint8 +type helloBody struct { + redistDefault RouteType + instance uint16 + receiveNotify uint8 } -// Reference: zread_hello function in zebra/zserv.c of Quagga1.2.x (ZAPI3) -// Reference: zread_hello function in zebra/zserv.c of FRR3.x (ZAPI4) -// Reference: zread_hello function in zebra/zapi_msg.c of FRR5.x (ZAPI5) -func (b *HelloBody) DecodeFromBytes(data []byte, version uint8, softwareName string) error { - b.RedistDefault = ROUTE_TYPE(data[0]) +// Ref: zread_hello in zebra/zserv.c of Quagga1.2&FRR3 (ZAPI3&4) +// Ref: zread_hello in zebra/zapi_msg.c of FRR5 (ZAPI5) +func (b *helloBody) decodeFromBytes(data []byte, version uint8, softwareName string) error { + b.redistDefault = RouteType(data[0]) if version >= 4 { - b.Instance = binary.BigEndian.Uint16(data[1:3]) + b.instance = binary.BigEndian.Uint16(data[1:3]) if version >= 5 { - b.ReceiveNotify = data[3] + b.receiveNotify = data[3] } } return nil } -// Reference: zebra_hello_send function in lib/zclient.c of Quagga1.2.x (ZAPI3) -// Reference: zebra_hello_send function in lib/zclient.c of FRR3.x (ZAPI4) -// Reference: zebra_hello_send function in lib/zclient.c of FRR5.x (ZAPI5) -func (b *HelloBody) Serialize(version uint8, softwareName string) ([]byte, error) { - if version <= 3 { - return []byte{uint8(b.RedistDefault)}, nil - } else { // version >= 4 - var buf []byte - if version == 4 { - buf = make([]byte, 3) - } else if version >= 5 { - buf = make([]byte, 4) - } - buf[0] = uint8(b.RedistDefault) - binary.BigEndian.PutUint16(buf[1:3], b.Instance) - if version >= 5 { - buf[3] = b.ReceiveNotify - } - return buf, nil +// Ref: zebra_hello_send in lib/zclient.c of Quagga1.2&FRR3&FRR5 (ZAPI3&4&5) +func (b *helloBody) serialize(version uint8, softwareName string) ([]byte, error) { + if version < 4 { + return []byte{uint8(b.redistDefault)}, nil + } + var buf []byte + if version == 4 { + buf = make([]byte, 3) + } else if version > 4 { + buf = make([]byte, 4) } + buf[0] = uint8(b.redistDefault) + binary.BigEndian.PutUint16(buf[1:3], b.instance) + if version > 4 { + buf[3] = b.receiveNotify + } + return buf, nil } -func (b *HelloBody) String(version uint8, softwareName string) string { +func (b *helloBody) string(version uint8, softwareName string) string { return fmt.Sprintf( "route_type: %s, instance :%d", - b.RedistDefault.String(), b.Instance) + b.redistDefault.String(), b.instance) } -type RedistributeBody struct { - Afi AFI - Redist ROUTE_TYPE - Instance uint16 +type redistributeBody struct { + afi afi + redist RouteType + instance uint16 } -// Reference: zebra_redistribute_add function in zebra/redistribute.c of Quagga1.2.x (ZAPI3) -// Reference: zebra_redistribute_add function in zebra/redistribute.c of FRR3.x (ZAPI4) -// Reference: zebra_redistribute_add function in zebra/redistribute.c of FRR5.x (ZAPI5) -func (b *RedistributeBody) DecodeFromBytes(data []byte, version uint8, softwareName string) error { +// Ref: zebra_redistribute_add in zebra/redistribute.c of Quagga1.2&FRR3&FRR5 (ZAPI3&4&5) +func (b *redistributeBody) decodeFromBytes(data []byte, version uint8, softwareName string) error { if version <= 3 { - b.Redist = ROUTE_TYPE(data[0]) + b.redist = RouteType(data[0]) } else { // version >= 4 - b.Afi = AFI(data[0]) - b.Redist = ROUTE_TYPE(data[1]) - b.Instance = binary.BigEndian.Uint16(data[2:4]) + b.afi = afi(data[0]) + b.redist = RouteType(data[1]) + b.instance = binary.BigEndian.Uint16(data[2:4]) } return nil } -// Reference: zebra_redistribute_send function in lib/zclient.c of Quagga1.2.x (ZAPI3) -// Reference: zebra_redistribute_send function in lib/zclient.c of FRR3.x (ZAPI4) -// Reference: zebra_redistribute_send function in lib/zclient.c of FRR5.x (ZAPI5) -func (b *RedistributeBody) Serialize(version uint8, softwareName string) ([]byte, error) { - if version <= 3 { - return []byte{uint8(b.Redist)}, nil - } else { // version >= 4 - buf := make([]byte, 4) - buf[0] = uint8(b.Afi) - buf[1] = uint8(b.Redist) - binary.BigEndian.PutUint16(buf[2:4], b.Instance) - return buf, nil +// Ref: zebra_redistribute_send in lib/zclient.c of Quagga1.2&FRR3&FRR5 (ZAPI3&4&5) +func (b *redistributeBody) serialize(version uint8, softwareName string) ([]byte, error) { + if version < 4 { + return []byte{uint8(b.redist)}, nil } + buf := make([]byte, 4) + buf[0] = uint8(b.afi) + buf[1] = uint8(b.redist) + binary.BigEndian.PutUint16(buf[2:4], b.instance) + return buf, nil } -func (b *RedistributeBody) String(version uint8, softwareName string) string { +func (b *redistributeBody) string(version uint8, softwareName string) string { return fmt.Sprintf( "afi: %s, route_type: %s, instance :%d", - b.Afi.String(), b.Redist.String(), b.Instance) -} - -type LinkParam struct { - Status uint32 - TeMetric uint32 - MaxBw float32 - MaxRsvBw float32 - UnrsvBw [8]float32 - BwClassNum uint32 - AdminGroup uint32 - RemoteAS uint32 - RemoteIP net.IP - AveDelay uint32 - MinDelay uint32 - MaxDelay uint32 - DelayVar uint32 - PktLoss float32 - ResidualBw float32 - AvailableBw float32 - UseBw float32 -} - -type InterfaceUpdateBody struct { - Name string - Index uint32 - Status INTERFACE_STATUS - Flags uint64 - PTMEnable PTM_ENABLE - PTMStatus PTM_STATUS - Metric uint32 - Speed uint32 - MTU uint32 - MTU6 uint32 - Bandwidth uint32 - LinkIfindex uint32 - Linktype LINK_TYPE - HardwareAddr net.HardwareAddr - LinkParam LinkParam -} - -// Reference: zebra_interface_if_set_value function in lib/zclient.c of Quagga1.2.x (ZAPI4) -// Reference: zebra_interface_if_set_value function in lib/zclient.c of FRR3.x (ZAPI4) -// Reference: zebra_interface_if_set_value function in lib/zclient.c of FRR5.x (ZAPI5) -func (b *InterfaceUpdateBody) DecodeFromBytes(data []byte, version uint8, softwareName string) error { - if len(data) < INTERFACE_NAMSIZ+33 { - return fmt.Errorf("lack of bytes. need %d but %d", INTERFACE_NAMSIZ+29, len(data)) - } - - b.Name = strings.Trim(string(data[:INTERFACE_NAMSIZ]), "\u0000") - data = data[INTERFACE_NAMSIZ:] - b.Index = binary.BigEndian.Uint32(data[0:4]) - b.Status = INTERFACE_STATUS(data[4]) - b.Flags = binary.BigEndian.Uint64(data[5:13]) - if version >= 4 { - b.PTMEnable = PTM_ENABLE(data[13]) - b.PTMStatus = PTM_STATUS(data[14]) - b.Metric = binary.BigEndian.Uint32(data[15:19]) - b.Speed = binary.BigEndian.Uint32(data[19:23]) + b.afi.String(), b.redist.String(), b.instance) +} + +type linkParam struct { + status uint32 + teMetric uint32 + maxBw float32 + maxRsvBw float32 + unrsvBw [8]float32 + bwClassNum uint32 + adminGroup uint32 + remoteAS uint32 + remoteIP net.IP + aveDelay uint32 + minDelay uint32 + maxDelay uint32 + delayVar uint32 + pktLoss float32 + residualBw float32 + availableBw float32 + useBw float32 +} + +type interfaceUpdateBody struct { + name string + index uint32 + status interfaceStatus + flags uint64 + ptmEnable ptmEnable + ptmStatus ptmStatus + metric uint32 + speed uint32 + mtu uint32 + mtu6 uint32 + bandwidth uint32 + linkIfindex uint32 + linktype linkType + hardwareAddr net.HardwareAddr + linkParam linkParam +} + +// Ref: zebra_interface_if_set_value in lib/zclient.c of Quagga1.2&FRR3&FRR5 (ZAPI3&4&5) +func (b *interfaceUpdateBody) decodeFromBytes(data []byte, version uint8, softwareName string) error { + if len(data) < interfaceNameSize+33 { + return fmt.Errorf("lack of bytes. need %d but %d", interfaceNameSize+29, len(data)) + } + + b.name = strings.Trim(string(data[:interfaceNameSize]), "\u0000") + data = data[interfaceNameSize:] + b.index = binary.BigEndian.Uint32(data[0:4]) + b.status = interfaceStatus(data[4]) + b.flags = binary.BigEndian.Uint64(data[5:13]) + if version > 3 { + b.ptmEnable = ptmEnable(data[13]) + b.ptmStatus = ptmStatus(data[14]) + b.metric = binary.BigEndian.Uint32(data[15:19]) + b.speed = binary.BigEndian.Uint32(data[19:23]) data = data[23:] } else { - b.Metric = binary.BigEndian.Uint32(data[13:17]) + b.metric = binary.BigEndian.Uint32(data[13:17]) data = data[17:] } - b.MTU = binary.BigEndian.Uint32(data[0:4]) - b.MTU6 = binary.BigEndian.Uint32(data[4:8]) - b.Bandwidth = binary.BigEndian.Uint32(data[8:12]) + b.mtu = binary.BigEndian.Uint32(data[0:4]) + b.mtu6 = binary.BigEndian.Uint32(data[4:8]) + b.bandwidth = binary.BigEndian.Uint32(data[8:12]) data = data[12:] - if version == 6 && softwareName == "frr7.2" { - b.LinkIfindex = binary.BigEndian.Uint32(data[:4]) + if version == 6 && + (softwareName == "frr7.2" || softwareName == "frr7.3" || softwareName == "") { //link Ifindex + b.linkIfindex = binary.BigEndian.Uint32(data[:4]) data = data[4:] } - if version >= 3 { - b.Linktype = LINK_TYPE(binary.BigEndian.Uint32(data[:4])) + if version > 2 { + b.linktype = linkType(binary.BigEndian.Uint32(data[:4])) data = data[4:] } l := binary.BigEndian.Uint32(data[:4]) @@ -1781,287 +1765,457 @@ func (b *InterfaceUpdateBody) DecodeFromBytes(data []byte, version uint8, softwa if len(data) < 4+int(l) { return fmt.Errorf("lack of bytes in remain data. need %d but %d", 4+l, len(data)) } - b.HardwareAddr = data[4 : 4+l] + b.hardwareAddr = data[4 : 4+l] } - if version >= 3 { - LinkParam := data[4+l] - if LinkParam > 0 { + if version > 2 { + linkParam := data[4+l] + if linkParam > 0 { data = data[5+l:] - b.LinkParam.Status = binary.BigEndian.Uint32(data[0:4]) - b.LinkParam.TeMetric = binary.BigEndian.Uint32(data[4:8]) - b.LinkParam.MaxBw = math.Float32frombits(binary.BigEndian.Uint32(data[8:12])) - b.LinkParam.MaxRsvBw = math.Float32frombits(binary.BigEndian.Uint32(data[12:16])) - b.LinkParam.BwClassNum = binary.BigEndian.Uint32(data[16:20]) - for i := uint32(0); i < b.LinkParam.BwClassNum; i++ { - b.LinkParam.UnrsvBw[i] = math.Float32frombits(binary.BigEndian.Uint32(data[20+i*4 : 24+i*4])) + b.linkParam.status = binary.BigEndian.Uint32(data[0:4]) + b.linkParam.teMetric = binary.BigEndian.Uint32(data[4:8]) + b.linkParam.maxBw = math.Float32frombits(binary.BigEndian.Uint32(data[8:12])) + b.linkParam.maxRsvBw = math.Float32frombits(binary.BigEndian.Uint32(data[12:16])) + b.linkParam.bwClassNum = binary.BigEndian.Uint32(data[16:20]) + for i := uint32(0); i < b.linkParam.bwClassNum; i++ { + b.linkParam.unrsvBw[i] = math.Float32frombits(binary.BigEndian.Uint32(data[20+i*4 : 24+i*4])) } - data = data[20+b.LinkParam.BwClassNum*4:] - b.LinkParam.AdminGroup = binary.BigEndian.Uint32(data[0:4]) - b.LinkParam.RemoteAS = binary.BigEndian.Uint32(data[4:8]) - b.LinkParam.RemoteIP = data[8:12] - b.LinkParam.AveDelay = binary.BigEndian.Uint32(data[12:16]) - b.LinkParam.MinDelay = binary.BigEndian.Uint32(data[16:20]) - b.LinkParam.MaxDelay = binary.BigEndian.Uint32(data[20:24]) - b.LinkParam.DelayVar = binary.BigEndian.Uint32(data[24:28]) - b.LinkParam.PktLoss = math.Float32frombits(binary.BigEndian.Uint32(data[28:32])) - b.LinkParam.ResidualBw = math.Float32frombits(binary.BigEndian.Uint32(data[32:36])) - b.LinkParam.AvailableBw = math.Float32frombits(binary.BigEndian.Uint32(data[36:40])) - b.LinkParam.UseBw = math.Float32frombits(binary.BigEndian.Uint32(data[40:44])) + data = data[20+b.linkParam.bwClassNum*4:] + b.linkParam.adminGroup = binary.BigEndian.Uint32(data[0:4]) + b.linkParam.remoteAS = binary.BigEndian.Uint32(data[4:8]) + b.linkParam.remoteIP = data[8:12] + b.linkParam.aveDelay = binary.BigEndian.Uint32(data[12:16]) + b.linkParam.minDelay = binary.BigEndian.Uint32(data[16:20]) + b.linkParam.maxDelay = binary.BigEndian.Uint32(data[20:24]) + b.linkParam.delayVar = binary.BigEndian.Uint32(data[24:28]) + b.linkParam.pktLoss = math.Float32frombits(binary.BigEndian.Uint32(data[28:32])) + b.linkParam.residualBw = math.Float32frombits(binary.BigEndian.Uint32(data[32:36])) + b.linkParam.availableBw = math.Float32frombits(binary.BigEndian.Uint32(data[36:40])) + b.linkParam.useBw = math.Float32frombits(binary.BigEndian.Uint32(data[40:44])) } } return nil } -func (b *InterfaceUpdateBody) Serialize(version uint8, softwareName string) ([]byte, error) { +func (b *interfaceUpdateBody) serialize(version uint8, softwareName string) ([]byte, error) { return []byte{}, nil } -func (b *InterfaceUpdateBody) String(version uint8, softwareName string) string { +func (b *interfaceUpdateBody) string(version uint8, softwareName string) string { s := fmt.Sprintf( "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", - 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()) - if len(b.HardwareAddr) > 0 { - return s + fmt.Sprintf(", mac: %s", b.HardwareAddr.String()) + 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()) + if len(b.hardwareAddr) > 0 { + return s + fmt.Sprintf(", mac: %s", b.hardwareAddr.String()) } return s } -type InterfaceAddressUpdateBody struct { - Index uint32 - Flags INTERFACE_ADDRESS_FLAG - Prefix net.IP - Length uint8 - Destination net.IP +type interfaceAddressUpdateBody struct { + index uint32 + flags interfaceAddressFlag + prefix net.IP + length uint8 + destination net.IP } -// Reference: zebra_interface_address_read function in lib/zclient.c of Quagga1.2.x (ZAPI4) -// Reference: zebra_interface_address_read function in lib/zclient.c of FRR3.x (ZAPI4) -// Reference: zebra_interface_address_read function in lib/zclient.c of FRR5.x (ZAPI5) -func (b *InterfaceAddressUpdateBody) DecodeFromBytes(data []byte, version uint8, softwareName string) error { - b.Index = binary.BigEndian.Uint32(data[:4]) - b.Flags = INTERFACE_ADDRESS_FLAG(data[4]) +// Ref: zebra_interface_address_read in lib/zclient.c of Quagga1.2&FRR3&FRR5 (ZAPI3&4&5) +func (b *interfaceAddressUpdateBody) decodeFromBytes(data []byte, version uint8, softwareName string) error { + b.index = binary.BigEndian.Uint32(data[:4]) + b.flags = interfaceAddressFlag(data[4]) family := data[5] addrlen, err := addressByteLength(family) if err != nil { return err } - b.Prefix = data[6 : 6+addrlen] - b.Length = data[6+addrlen] - b.Destination = data[7+addrlen : 7+addrlen*2] + b.prefix = data[6 : 6+addrlen] + b.length = data[6+addrlen] + b.destination = data[7+addrlen : 7+addrlen*2] return nil } -func (b *InterfaceAddressUpdateBody) Serialize(version uint8, softwareName string) ([]byte, error) { +func (b *interfaceAddressUpdateBody) serialize(version uint8, softwareName string) ([]byte, error) { return []byte{}, nil } -func (b *InterfaceAddressUpdateBody) String(version uint8, softwareName string) string { +func (b *interfaceAddressUpdateBody) string(version uint8, softwareName string) string { return fmt.Sprintf( "idx: %d, flags: %s, addr: %s/%d", - b.Index, b.Flags.String(), b.Prefix.String(), b.Length) + b.index, b.flags.String(), b.prefix.String(), b.length) } -type RouterIDUpdateBody struct { - Length uint8 - Prefix net.IP +type routerIDUpdateBody struct { + length uint8 + prefix net.IP } -// Reference: zebra_router_id_update_read function in lib/zclient.c of Quagga1.2.x (ZAPI4) -// Reference: zebra_router_id_update_read function in lib/zclient.c of FRR3.x (ZAPI4) -// Reference: zebra_router_id_update_read function in lib/zclient.c of FRR5.x (ZAPI5) -func (b *RouterIDUpdateBody) DecodeFromBytes(data []byte, version uint8, softwareName string) error { +// Ref: zebra_router_id_update_read in lib/zclient.c of Quagga1.2&FRR3&FRR5 (ZAPI3&4&5) +func (b *routerIDUpdateBody) decodeFromBytes(data []byte, version uint8, softwareName string) error { family := data[0] addrlen, err := addressByteLength(family) if err != nil { return err } - b.Prefix = data[1 : 1+addrlen] - b.Length = data[1+addrlen] + b.prefix = data[1 : 1+addrlen] + b.length = data[1+addrlen] return nil } -func (b *RouterIDUpdateBody) Serialize(version uint8, softwareName string) ([]byte, error) { +func (b *routerIDUpdateBody) serialize(version uint8, softwareName string) ([]byte, error) { return []byte{}, nil } -func (b *RouterIDUpdateBody) String(version uint8, softwareName string) string { - return fmt.Sprintf("id: %s/%d", b.Prefix.String(), b.Length) +func (b *routerIDUpdateBody) string(version uint8, softwareName string) string { + return fmt.Sprintf("id: %s/%d", b.prefix.String(), b.length) } -/* - Reference: struct zapi_nexthop in lib/zclient.h of FRR5.x (ZAPI5) -*/ +const ( + zapiNexthopFlagOnlink uint8 = 0x01 // frr7.1, 7.2, 7.3 + zapiNexthopFlagLabel uint8 = 0x02 // frr7.3 + zapiNexthopFlagWeight uint8 = 0x04 // frr7.3 +) + +// Flag for nexthop processing. It is gobgp's internal flag. +type nexthopProcessFlag uint8 + +const ( + nexthopHasType nexthopProcessFlag = 0x01 + nexthopHasVrfID nexthopProcessFlag = 0x02 + nexthopHasFlag nexthopProcessFlag = 0x04 + nexthopHasOnlink nexthopProcessFlag = 0x08 + nexthopProcessIPToIPIFindex nexthopProcessFlag = 0x10 + nexthopProcessIFnameToIFindex nexthopProcessFlag = 0x20 // for quagga +) + +func nexthopProcessFlagForIPRouteBody(version uint8, softwareName string, isDecode bool) nexthopProcessFlag { + if version < 5 { + if isDecode { + return nexthopProcessFlag(0) // frr3&quagga don't have type&vrfid + } + return nexthopHasType // frr3&quagga need type for encode(serialize) + } + processFlag := (nexthopHasVrfID | nexthopHasType) // frr4, 5, 6, 7 + if version == 6 { + switch softwareName { + case "frr7.3", "": + processFlag |= (nexthopHasFlag | nexthopProcessIPToIPIFindex) + case "frr7.2", "frr7.1", "frr7.0": + processFlag |= nexthopHasOnlink + } + } + return processFlag +} + +// Nexthop is referred in zclient (Ref: struct zapi_nexthop in lib/zclient.h of FRR5.x (ZAPI5)) type Nexthop struct { - Type NEXTHOP_TYPE - VrfId uint32 - Ifindex uint32 + Type nexthopType + VrfID uint32 + Ifindex uint32 // Ifindex is referred in zclient_test Gate net.IP - BlackholeType uint8 + flags uint8 + blackholeType uint8 LabelNum uint8 MplsLabels []uint32 - Onlink uint8 + weight uint32 + rmac [6]byte } -func (n *Nexthop) String() string { +func (n Nexthop) string() string { s := make([]string, 0) s = append(s, fmt.Sprintf( "type: %s, gate: %s, ifindex: %d, vrf_id: %d, label_num: %d", - n.Type.String(), n.Gate.String(), n.Ifindex, n.VrfId, n.LabelNum)) + n.Type.String(), n.Gate.String(), n.Ifindex, n.VrfID, n.LabelNum)) for i := uint8(0); i < n.LabelNum; i++ { s = append(s, fmt.Sprintf("label: %d", n.MplsLabels[i])) } return strings.Join(s, ", ") } +func (n Nexthop) gateToType(version uint8) nexthopType { + if n.Gate.To4() != nil { + if version > 4 && n.Ifindex > 0 { + return nexthopTypeIPv4IFIndex + } + return nexthopTypeIPv4.toEach(version) + } else if n.Gate.To16() != nil { + if version > 4 && n.Ifindex > 0 { + return nexthopTypeIPv6IFIndex + } + return nexthopTypeIPv6.toEach(version) + } else if n.Ifindex > 0 { + return nexthopTypeIFIndex.toEach(version) + } else if version > 4 { + return nexthopTypeBlackhole + } + return nexthopType(0) +} +// Ref: zapi_nexthop_encode in lib/zclient.h of FRR7.3 +func (n Nexthop) encode(version uint8, softwareName string, processFlag nexthopProcessFlag, message MessageFlag, apiFlag Flag) []byte { + var buf []byte + if processFlag&nexthopHasVrfID > 0 { + tmpbuf := make([]byte, 4) + binary.BigEndian.PutUint32(tmpbuf, n.VrfID) + buf = append(buf, tmpbuf...) + } + if processFlag&nexthopHasType > 0 { + if n.Type == nexthopType(0) { + n.Type = n.gateToType(version) + } + buf = append(buf, uint8(n.Type)) + } + if processFlag&nexthopHasFlag > 0 { + if n.LabelNum > 0 { + n.flags |= zapiNexthopFlagLabel + } + if n.weight > 0 { + n.flags |= zapiNexthopFlagWeight + } + } + if processFlag&nexthopHasFlag > 0 || processFlag&nexthopHasOnlink > 0 { + buf = append(buf, n.flags) // frr7.1, 7.2 has onlink, 7.3 has flag + } + + nhType := n.Type + if processFlag&nexthopProcessIPToIPIFindex > 0 { + nhType = nhType.ipToIPIFIndex() + } + if processFlag&nexthopProcessIFnameToIFindex > 0 { + nhType = nhType.ifNameToIFIndex() + } + if nhType == nexthopTypeIPv4.toEach(version) || + nhType == nexthopTypeIPv4IFIndex.toEach(version) { + buf = append(buf, n.Gate.To4()...) + } else if nhType == nexthopTypeIPv6.toEach(version) || + nhType == nexthopTypeIPv6IFIndex.toEach(version) { + buf = append(buf, n.Gate.To16()...) + } + if nhType == nexthopTypeIFIndex || + nhType == nexthopTypeIPv4IFIndex.toEach(version) || + nhType == nexthopTypeIPv6IFIndex.toEach(version) { + tmpbuf := make([]byte, 4) + binary.BigEndian.PutUint32(tmpbuf, n.Ifindex) + buf = append(buf, tmpbuf...) + } + if nhType == nexthopTypeBlackhole.toEach(version) { + buf = append(buf, uint8(n.blackholeType)) + } + if n.flags&zapiNexthopFlagLabel > 0 || message&MessageLabel > 0 { + tmpbuf := make([]byte, 1+4*n.LabelNum) + tmpbuf[0] = n.LabelNum + for i := uint8(0); i < n.LabelNum; i++ { + // frr uses stream_put for mpls label array. + // stream_put is unaware of byteorder coversion. + // Therefore LittleEndian is used instead of BigEndian. + binary.LittleEndian.PutUint32(tmpbuf[i*4+1:], n.MplsLabels[i]) + } + buf = append(buf, tmpbuf...) + } + if n.flags&zapiNexthopFlagWeight > 0 && n.weight > 0 { + tmpbuf := make([]byte, 4) + binary.BigEndian.PutUint32(tmpbuf, uint32(n.weight)) + buf = append(buf, tmpbuf...) + } + if apiFlag&flagEvpnRoute.ToEach(version, softwareName) > 0 { + buf = append(buf, n.rmac[:]...) + } + return buf +} + +// Ref: zapi_nexthop_decode in lib/zclient.h of FRR7.3 +func (n *Nexthop) decode(data []byte, version uint8, softwareName string, family uint8, processFlag nexthopProcessFlag, message MessageFlag, apiFlag Flag, nhType nexthopType) (int, error) { + offset := 0 + if processFlag&nexthopHasVrfID > 0 { + n.VrfID = binary.BigEndian.Uint32(data[offset : offset+4]) + offset += 4 + } + + n.Type = nhType // data does not have nexthop type + if processFlag&nexthopHasType > 0 { + n.Type = nexthopType(data[offset]) + offset++ + } + + n.flags = uint8(0) + if processFlag&nexthopHasFlag > 0 || processFlag&nexthopHasOnlink > 0 { + n.flags = uint8(data[offset]) + offset++ + } + + nhType = n.Type + if processFlag&nexthopProcessIPToIPIFindex > 0 { + nhType = nhType.ipToIPIFIndex() + } + if processFlag&nexthopProcessIFnameToIFindex > 0 { + nhType = nhType.ifNameToIFIndex() + } + if family == syscall.AF_INET { + n.Gate = net.ParseIP("0.0.0.0") + } else if family == syscall.AF_INET6 { + n.Gate = net.ParseIP("::") + } + if nhType == nexthopTypeIPv4.toEach(version) || + nhType == nexthopTypeIPv4IFIndex.toEach(version) { + n.Gate = net.IP(data[offset : offset+4]).To4() + offset += 4 + } else if nhType == nexthopTypeIPv6.toEach(version) || + nhType == nexthopTypeIPv6IFIndex.toEach(version) { + n.Gate = net.IP(data[offset : offset+16]).To16() + offset += 16 + } + if nhType == nexthopTypeIFIndex || + nhType == nexthopTypeIPv4IFIndex.toEach(version) || + nhType == nexthopTypeIPv6IFIndex.toEach(version) { + n.Ifindex = binary.BigEndian.Uint32(data[offset : offset+4]) + offset += 4 + } + if nhType == nexthopTypeBlackhole.toEach(version) { + n.blackholeType = data[offset] + offset++ + } + if n.flags&zapiNexthopFlagLabel > 0 || message&MessageLabel > 0 { + n.LabelNum = uint8(data[offset]) + offset++ + if n.LabelNum > maxMplsLabel { + n.LabelNum = maxMplsLabel + } + if n.LabelNum > 0 { + n.MplsLabels = make([]uint32, n.LabelNum) + for i := uint8(0); i < n.LabelNum; i++ { + // frr uses stream_put which is unaware of byteorder for mpls label array. + // Therefore LittleEndian is used instead of BigEndian. + n.MplsLabels[i] = binary.LittleEndian.Uint32(data[offset : offset+4]) + offset += 4 + } + } + } + if n.flags&zapiNexthopFlagWeight > 0 { + n.weight = binary.BigEndian.Uint32(data[offset:]) + } + if apiFlag&flagEvpnRoute.ToEach(version, softwareName) > 0 { + copy(n.rmac[0:], data[offset:offset+6]) + } + return offset, nil +} + +// Ref: zapi_nexthop_update_decode in lib/zclient.h +// decodeNexthops is referred from decodeFromBytes of NexthopUpdateBody and IPRouteBody +func decodeNexthops(nexthops *[]Nexthop, data []byte, version uint8, softwareName string, family uint8, numNexthop uint16, processFlag nexthopProcessFlag, message MessageFlag, apiFlag Flag, nhType nexthopType) (int, error) { + offset := 0 + *nexthops = make([]Nexthop, numNexthop) + for i := uint16(0); i < numNexthop; i++ { + size, err := (&((*nexthops)[i])).decode(data[offset:], version, softwareName, family, processFlag, message, apiFlag, nhType) + if err != nil { + return offset, err + } + offset += size + } + return offset, nil +} + +// Prefix referred in zclient is struct for network prefix and relate information type Prefix struct { Family uint8 PrefixLen uint8 Prefix net.IP } +func familyFromPrefix(prefix net.IP) uint8 { + if prefix.To4() != nil { + return syscall.AF_INET + } else if prefix.To16() != nil { + return syscall.AF_INET6 + } + return syscall.AF_UNSPEC +} + +// IPRouteBody is struct for IPRotue (zapi_route) type IPRouteBody struct { - Type ROUTE_TYPE - Instance uint16 - Flags FLAG - Message MESSAGE_FLAG - SAFI SAFI + Type RouteType + instance uint16 + Flags Flag + Message MessageFlag + Safi Safi Prefix Prefix - SrcPrefix Prefix + srcPrefix Prefix Nexthops []Nexthop Distance uint8 Metric uint32 Mtu uint32 - Tag uint32 - Rmac [6]byte - Api API_TYPE + tag uint32 + API APIType // API is referred in zclient_test +} + +func (b *IPRouteBody) safi(version uint8, sw string) Safi { + if b.Safi == safiUnspec && (version < 6 || sw == "frr6" || sw == "frr7" || sw == "frr7.1") { + return SafiUnicast // older versions don't have safiUnspec + } + if b.Safi <= safiMulticast || version > 4 { // not need to convert + return b.Safi + } + safiMap := zapi4SafiMap + if version < 4 { + safiMap = zapi3SafiMap + } + safi, ok := safiMap[b.Safi] + if !ok { + safi = safiUnspec // failed to convert + } + log.WithFields(log.Fields{ + "Topic": "Zebra", + "Body": b, + }).Debugf("zebra converts safi: %s -> %s", b.Safi.String(), safi.String()) + return safi // success to convert } -func (b *IPRouteBody) RouteFamily(version uint8) bgp.RouteFamily { +// RouteFamily is referred in zclient +func (b *IPRouteBody) RouteFamily(version uint8, softwareName string) bgp.RouteFamily { if b == nil { - return bgp.RF_OPAQUE + return bgp.RF_OPAQUE // fail } - family := addressFamilyFromApi(b.Api, version) + safi := b.safi(version, softwareName) + if safi == safiEvpn { + return bgp.RF_EVPN // sucess + } + family := b.Prefix.Family if family == syscall.AF_UNSPEC { - if b.Prefix.Prefix.To4() != nil { - family = syscall.AF_INET - } else if b.Prefix.Prefix.To16() != nil { - family = syscall.AF_INET6 - } + family = familyFromPrefix(b.Prefix.Prefix) } - if version < 5 { - switch family { - case syscall.AF_INET: - switch b.SAFI { - case SAFI_UNICAST: - return bgp.RF_IPv4_UC - case SAFI_MULTICAST: - return bgp.RF_IPv4_MC - case SAFI_MPLS_VPN, FRR_SAFI_MPLS_VPN: - return bgp.RF_IPv4_VPN - case FRR_SAFI_ENCAP, SAFI_ENCAP: - return bgp.RF_IPv4_ENCAP - default: - return bgp.RF_IPv4_UC - } - case syscall.AF_INET6: - switch b.SAFI { - case SAFI_UNICAST: - return bgp.RF_IPv6_UC - case SAFI_MULTICAST: - return bgp.RF_IPv6_MC - case SAFI_MPLS_VPN, FRR_SAFI_MPLS_VPN: - return bgp.RF_IPv6_VPN - case FRR_SAFI_ENCAP, SAFI_ENCAP: - return bgp.RF_IPv6_ENCAP - default: - return bgp.RF_IPv6_UC - } - default: - switch b.SAFI { - case FRR_SAFI_EVPN: - return bgp.RF_EVPN - default: - return bgp.RF_OPAQUE - } - } - } else { - switch family { - case syscall.AF_INET: - switch b.SAFI { - case FRR_ZAPI5_SAFI_UNICAST: - return bgp.RF_IPv4_UC - case FRR_ZAPI5_SAFI_MULTICAST: - return bgp.RF_IPv4_MC - case FRR_ZAPI5_SAFI_MPLS_VPN: - return bgp.RF_IPv4_VPN - case FRR_ZAPI5_SAFI_ENCAP: - return bgp.RF_IPv4_ENCAP - case FRR_ZAPI5_SAFI_LABELED_UNICAST: - return bgp.RF_IPv4_MPLS - case FRR_ZAPI5_SAFI_FLOWSPEC: - return bgp.RF_FS_IPv4_UC - default: - return bgp.RF_IPv4_UC - } - case syscall.AF_INET6: - switch b.SAFI { - case FRR_ZAPI5_SAFI_UNICAST: - return bgp.RF_IPv6_UC - case FRR_ZAPI5_SAFI_MULTICAST: - return bgp.RF_IPv6_MC - case FRR_ZAPI5_SAFI_MPLS_VPN: - return bgp.RF_IPv6_VPN - case FRR_ZAPI5_SAFI_ENCAP: - return bgp.RF_IPv6_ENCAP - case FRR_ZAPI5_SAFI_LABELED_UNICAST: - return bgp.RF_IPv6_MPLS - case FRR_ZAPI5_SAFI_FLOWSPEC: - return bgp.RF_FS_IPv6_UC - default: - return bgp.RF_IPv6_UC - } - default: - switch b.SAFI { - case FRR_ZAPI5_SAFI_EVPN: - return bgp.RF_EVPN - default: - return bgp.RF_OPAQUE - } - } + if family == syscall.AF_UNSPEC { // familyFromPrefix returs AF_UNSPEC + return bgp.RF_OPAQUE // fail + } + safiRouteFamilyMap := safiRouteFamilyIPv4Map // syscall.AF_INET + if family == syscall.AF_INET6 { + safiRouteFamilyMap = safiRouteFamilyIPv6Map + } + rf, ok := safiRouteFamilyMap[safi] + if !ok { + return bgp.RF_OPAQUE // fail } + log.WithFields(log.Fields{ + "Topic": "Zebra", + "Body": b, + }).Debugf("zebra converts safi:%s -> rf: %s", safi.String(), rf.String()) + return rf // sucess } -func (b *IPRouteBody) IsWithdraw(version uint8) bool { - if version <= 3 { - switch b.Api { - case IPV4_ROUTE_DELETE, IPV6_ROUTE_DELETE: - return true - } - } else if version == 4 { - switch b.Api { - case FRR_IPV4_ROUTE_DELETE, FRR_IPV6_ROUTE_DELETE, FRR_REDISTRIBUTE_IPV4_DEL, FRR_REDISTRIBUTE_IPV6_DEL: - return true - } - } else if version == 5 { - switch b.Api { - case FRR_ZAPI5_ROUTE_DELETE, FRR_ZAPI5_IPV4_ROUTE_DELETE, FRR_ZAPI5_IPV6_ROUTE_DELETE, FRR_ZAPI5_REDISTRIBUTE_ROUTE_DEL: - return true - } - } else if version >= 6 { - switch b.Api { - case FRR_ZAPI6_ROUTE_DELETE, FRR_ZAPI6_REDISTRIBUTE_ROUTE_DEL: - return true - } +// IsWithdraw is referred in zclient +func (b *IPRouteBody) IsWithdraw(version uint8, softwareName string) bool { + api := b.API.toCommon(version, softwareName) + switch api { + case RouteDelete, redistributeRouteDel, BackwardIPv6RouteDelete: + return true + } + if version == 4 && b.API == zapi4RedistributeIPv6Del { + return true } return false } -// Reference: zapi_ipv4_route function in lib/zclient.c of Quagga1.2.x (ZAPI3) -// Reference: zapi_ipv4_route function in lib/zclient.c of FRR3.x (ZAPI4) -// Reference: zapi_route_encode function in lib/zclient.c of FRR5.x (ZAPI5) -func (b *IPRouteBody) Serialize(version uint8, softwareName string) ([]byte, error) { +// Ref: zapi_ipv4_route in lib/zclient.c of Quagga1.2.x&FRR3.x(ZAPI3&4) +// Ref: zapi_route_encode in lib/zclient.c of FRR5.x (ZAPI5) +func (b *IPRouteBody) serialize(version uint8, softwareName string) ([]byte, error) { var buf []byte + numNexthop := len(b.Nexthops) if version <= 3 { buf = make([]byte, 5) } else if version == 4 { @@ -2070,28 +2224,24 @@ func (b *IPRouteBody) Serialize(version uint8, softwareName string) ([]byte, err buf = make([]byte, 9) } buf[0] = uint8(b.Type) - if version <= 3 { + if version < 4 { buf[1] = uint8(b.Flags) buf[2] = uint8(b.Message) - binary.BigEndian.PutUint16(buf[3:5], uint16(b.SAFI)) + binary.BigEndian.PutUint16(buf[3:5], uint16(b.Safi)) } else { // version >= 4 - binary.BigEndian.PutUint16(buf[1:3], uint16(b.Instance)) + binary.BigEndian.PutUint16(buf[1:3], uint16(b.instance)) binary.BigEndian.PutUint32(buf[3:7], uint32(b.Flags)) buf[7] = uint8(b.Message) if version == 4 { - binary.BigEndian.PutUint16(buf[8:10], uint16(b.SAFI)) + binary.BigEndian.PutUint16(buf[8:10], uint16(b.Safi)) } else { // version >= 5 - buf[8] = uint8(b.SAFI) - if b.Flags&FLAG_EVPN_ROUTE > 0 { + buf[8] = uint8(b.Safi) + if version == 5 && b.Flags&flagEvpnRoute.ToEach(version, softwareName) > 0 { // size of struct ethaddr is 6 octets defined by ETH_ALEN - buf = append(buf, b.Rmac[:6]...) + buf = append(buf, b.Nexthops[numNexthop-1].rmac[:6]...) } if b.Prefix.Family == syscall.AF_UNSPEC { - if b.Prefix.Prefix.To4() != nil { - b.Prefix.Family = syscall.AF_INET - } else if b.Prefix.Prefix.To16() != nil { - b.Prefix.Family = syscall.AF_INET6 - } + b.Prefix.Family = familyFromPrefix(b.Prefix.Prefix) } buf = append(buf, b.Prefix.Family) } @@ -2100,165 +2250,75 @@ func (b *IPRouteBody) Serialize(version uint8, softwareName string) ([]byte, err buf = append(buf, b.Prefix.PrefixLen) buf = append(buf, b.Prefix.Prefix[:byteLen]...) - if (version == 4 && b.Message&FRR_MESSAGE_SRCPFX > 0) || - (version >= 5 && b.Message&FRR_ZAPI5_MESSAGE_SRCPFX > 0) { - byteLen = (int(b.SrcPrefix.PrefixLen) + 7) / 8 - buf = append(buf, b.SrcPrefix.PrefixLen) - buf = append(buf, b.SrcPrefix.Prefix[:byteLen]...) + if version > 3 && b.Message&messageSRCPFX.ToEach(version) > 0 { + byteLen = (int(b.srcPrefix.PrefixLen) + 7) / 8 + buf = append(buf, b.srcPrefix.PrefixLen) + buf = append(buf, b.srcPrefix.Prefix[:byteLen]...) } - if (version <= 3 && b.Message&MESSAGE_NEXTHOP > 0) || - (version == 4 && b.Message&FRR_MESSAGE_NEXTHOP > 0) || - (version >= 5 && b.Message&FRR_ZAPI5_MESSAGE_NEXTHOP > 0) { + if b.Message&MessageNexthop > 0 { + processFlag := nexthopProcessFlagForIPRouteBody(version, softwareName, false) if version < 5 { - if b.Flags&FLAG_BLACKHOLE > 0 { - buf = append(buf, []byte{1, uint8(NEXTHOP_TYPE_BLACKHOLE)}...) + if b.Flags&flagBlackhole > 0 { + buf = append(buf, []byte{1, uint8(nexthopTypeBlackhole.toEach(version))}...) } else { - buf = append(buf, uint8(len(b.Nexthops))) + buf = append(buf, uint8(numNexthop)) } } else { // version >= 5 - bbuf := make([]byte, 2) - binary.BigEndian.PutUint16(bbuf, uint16(len(b.Nexthops))) - buf = append(buf, bbuf...) + tmpbuf := make([]byte, 2) + binary.BigEndian.PutUint16(tmpbuf, uint16(numNexthop)) + buf = append(buf, tmpbuf...) } for _, nexthop := range b.Nexthops { - if version >= 5 { - bbuf := make([]byte, 4) - binary.BigEndian.PutUint32(bbuf, nexthop.VrfId) - buf = append(buf, bbuf...) - } - - if nexthop.Type == NEXTHOP_TYPE(0) { - if nexthop.Gate.To4() != nil { - if version <= 3 { - nexthop.Type = NEXTHOP_TYPE_IPV4 - } else { - nexthop.Type = FRR_NEXTHOP_TYPE_IPV4 - } - if version >= 5 && nexthop.Ifindex > 0 { - nexthop.Type = FRR_NEXTHOP_TYPE_IPV4_IFINDEX - } - } else if nexthop.Gate.To16() != nil { - if version <= 3 { - nexthop.Type = NEXTHOP_TYPE_IPV6 - } else { - nexthop.Type = FRR_NEXTHOP_TYPE_IPV6 - } - if version >= 5 && nexthop.Ifindex > 0 { - nexthop.Type = FRR_NEXTHOP_TYPE_IPV6_IFINDEX - } - } else if nexthop.Ifindex > 0 { - if version <= 3 { - nexthop.Type = NEXTHOP_TYPE_IFINDEX - } else { - nexthop.Type = FRR_NEXTHOP_TYPE_IFINDEX - } - } else if version >= 5 { - nexthop.Type = FRR_NEXTHOP_TYPE_BLACKHOLE - } - } - - buf = append(buf, uint8(nexthop.Type)) - - if version == 6 && (softwareName == "frr7.1" || softwareName == "frr7.2") { - buf = append(buf, nexthop.Onlink) - } - if (version <= 3 && nexthop.Type == NEXTHOP_TYPE_IPV4) || - (version >= 4 && nexthop.Type == FRR_NEXTHOP_TYPE_IPV4) { - buf = append(buf, nexthop.Gate.To4()...) - } else if (version <= 3 && nexthop.Type == NEXTHOP_TYPE_IPV6) || - (version >= 4 && nexthop.Type == FRR_NEXTHOP_TYPE_IPV6) { - buf = append(buf, nexthop.Gate.To16()...) - } else if (version <= 3 && nexthop.Type == NEXTHOP_TYPE_IFINDEX) || - (version >= 4 && nexthop.Type == FRR_NEXTHOP_TYPE_IFINDEX) { - bbuf := make([]byte, 4) - binary.BigEndian.PutUint32(bbuf, nexthop.Ifindex) - buf = append(buf, bbuf...) - } else if version >= 5 && nexthop.Type == FRR_NEXTHOP_TYPE_IPV4_IFINDEX { - buf = append(buf, nexthop.Gate.To4()...) - bbuf := make([]byte, 4) - binary.BigEndian.PutUint32(bbuf, nexthop.Ifindex) - buf = append(buf, bbuf...) - } else if version >= 5 && nexthop.Type == FRR_NEXTHOP_TYPE_IPV6_IFINDEX { - buf = append(buf, nexthop.Gate.To16()...) - bbuf := make([]byte, 4) - binary.BigEndian.PutUint32(bbuf, nexthop.Ifindex) - buf = append(buf, bbuf...) - } else if version >= 5 && nexthop.Type == FRR_NEXTHOP_TYPE_BLACKHOLE { - buf = append(buf, uint8(nexthop.BlackholeType)) - } - if version >= 5 && b.Message&FRR_ZAPI5_MESSAGE_LABEL > 0 { - buf = append(buf, nexthop.LabelNum) - for i := uint8(0); i < nexthop.LabelNum; i++ { - bbuf := make([]byte, 4) - /* Frr uses stream_put for mpls label array. - stream_put is unaware of byteorder coversion. - Therefore LittleEndian is used instead of BigEndian. */ - binary.LittleEndian.PutUint32(bbuf, nexthop.MplsLabels[i]) - buf = append(buf, bbuf...) - - } - } - } - if (version <= 3 && b.Message&MESSAGE_DISTANCE > 0) || - (version == 4 && b.Message&FRR_MESSAGE_DISTANCE > 0) || - (version >= 5 && b.Message&FRR_ZAPI5_MESSAGE_DISTANCE > 0) { - buf = append(buf, b.Distance) - } - if (version <= 3 && b.Message&MESSAGE_METRIC > 0) || - (version == 4 && b.Message&FRR_MESSAGE_METRIC > 0) || - (version >= 5 && b.Message&FRR_ZAPI5_MESSAGE_METRIC > 0) { - bbuf := make([]byte, 4) - binary.BigEndian.PutUint32(bbuf, b.Metric) - buf = append(buf, bbuf...) - } - if (version <= 3 && b.Message&MESSAGE_MTU > 0) || - (version == 4 && b.Message&FRR_MESSAGE_MTU > 0) || - (version >= 5 && b.Message&FRR_ZAPI5_MESSAGE_MTU > 0) { - bbuf := make([]byte, 4) - binary.BigEndian.PutUint32(bbuf, b.Mtu) - buf = append(buf, bbuf...) - } - if (version <= 3 && b.Message&MESSAGE_TAG > 0) || - (version == 4 && b.Message&FRR_MESSAGE_TAG > 0) || - (version >= 5 && b.Message&FRR_ZAPI5_MESSAGE_TAG > 0) { - bbuf := make([]byte, 4) - binary.BigEndian.PutUint32(bbuf, b.Tag) - buf = append(buf, bbuf...) + buf = append(buf, nexthop.encode(version, softwareName, processFlag, b.Message, b.Flags)...) } } + if b.Message&MessageDistance.ToEach(version) > 0 { + buf = append(buf, b.Distance) + } + if b.Message&MessageMetric.ToEach(version) > 0 { + tmpbuf := make([]byte, 4) + binary.BigEndian.PutUint32(tmpbuf, b.Metric) + buf = append(buf, tmpbuf...) + } + if b.Message&MessageMTU.ToEach(version) > 0 { + tmpbuf := make([]byte, 4) + binary.BigEndian.PutUint32(tmpbuf, b.Mtu) + buf = append(buf, tmpbuf...) + } + if b.Message&messageTag.ToEach(version) > 0 { + tmpbuf := make([]byte, 4) + binary.BigEndian.PutUint32(tmpbuf, b.tag) + buf = append(buf, tmpbuf...) + } return buf, nil } -// Reference: zebra_read_ipv4 function in bgpd/bgp_zebra.c of Quagga1.2.x (ZAPI3) -// Reference: zebra_read_ipv4 function in bgpd/bgp_zebra.c of FRR4.x (ZAPI4) -// Reference: zapi_route_decode function in lib/zclient.c of FRR5.x (ZAPI5) -func (b *IPRouteBody) DecodeFromBytes(data []byte, version uint8, softwareName string) error { +// Ref: zebra_read_ipv4 in bgpd/bgp_zebra.c of Quagga1.2.x&FRR3.x(ZAPI3&4) +// Ref: zapi_route_decode in lib/zclient.c of FRR5.x (ZAPI5) +func (b *IPRouteBody) decodeFromBytes(data []byte, version uint8, softwareName string) error { if b == nil { return fmt.Errorf("IPRouteBody is nil") } - b.Prefix.Family = addressFamilyFromApi(b.Api, version) - /* REDSTRIBUTE_IPV4_ADD|DEL and REDSITRBUTE_IPV6_ADD|DEL have merged to - REDISTRIBUTE_ROUTE_ADD|DEL in ZAPI version 5. - Therefore it can not judge the protocol famiiy from API. */ - - b.Type = ROUTE_TYPE(data[0]) + b.Type = RouteType(data[0]) if version <= 3 { - b.Flags = FLAG(data[1]) + b.Flags = Flag(data[1]) data = data[2:] } else { // version >= 4 - b.Instance = binary.BigEndian.Uint16(data[1:3]) - b.Flags = FLAG(binary.BigEndian.Uint32(data[3:7])) + b.instance = binary.BigEndian.Uint16(data[1:3]) + b.Flags = Flag(binary.BigEndian.Uint32(data[3:7])) data = data[7:] } - b.Message = MESSAGE_FLAG(data[0]) - b.SAFI = SAFI(SAFI_UNICAST) - if version >= 5 { - b.SAFI = SAFI(data[1]) + b.Message = MessageFlag(data[0]) + b.Safi = Safi(SafiUnicast) + b.Prefix.Family = b.API.addressFamily(version) // return AF_UNSPEC if version > 4 + var evpnNexthop Nexthop + if version > 4 { + b.Safi = Safi(data[1]) data = data[2:] - if b.Flags&FLAG_EVPN_ROUTE > 0 { + if version == 5 && b.Flags&flagEvpnRoute.ToEach(version, softwareName) > 0 { // size of struct ethaddr is 6 octets defined by ETH_ALEN - copy(b.Rmac[0:6], data[0:6]) + copy(evpnNexthop.rmac[0:6], data[0:6]) data = data[6:] } b.Prefix.Family = data[0] @@ -2287,426 +2347,222 @@ func (b *IPRouteBody) DecodeFromBytes(data []byte, version uint8, softwareName s copy(buf, data[pos:pos+byteLen]) b.Prefix.Prefix = ipFromFamily(b.Prefix.Family, buf) pos += byteLen - if (version == 4 && b.Message&FRR_MESSAGE_SRCPFX > 0) || - (version >= 5 && b.Message&FRR_ZAPI5_MESSAGE_SRCPFX > 0) { + if version > 3 && b.Message&messageSRCPFX.ToEach(version) > 0 { if pos+1 > rest { - return fmt.Errorf("MESSAGE_SRCPFX message length invalid pos:%d rest:%d", pos, rest) + return fmt.Errorf("MessageSRCPFX message length invalid pos:%d rest:%d", pos, rest) } - b.SrcPrefix.PrefixLen = data[pos] - if b.SrcPrefix.PrefixLen > addrBitLen { + b.srcPrefix.PrefixLen = data[pos] + if b.srcPrefix.PrefixLen > addrBitLen { return fmt.Errorf("prefix length is greater than %d", addrByteLen*8) } - pos += 1 + pos++ buf = make([]byte, addrByteLen) - byteLen = int((b.SrcPrefix.PrefixLen + 7) / 8) + byteLen = int((b.srcPrefix.PrefixLen + 7) / 8) if pos+byteLen > rest { - return fmt.Errorf("MESSAGE_SRCPFX message length invalid pos:%d rest:%d", pos, rest) + return fmt.Errorf("MessageSRCPFX message length invalid pos:%d rest:%d", pos, rest) } copy(buf, data[pos:pos+byteLen]) - b.SrcPrefix.Prefix = ipFromFamily(b.Prefix.Family, buf) + b.srcPrefix.Prefix = ipFromFamily(b.Prefix.Family, buf) pos += byteLen } b.Nexthops = []Nexthop{} - if (version <= 3 && b.Message&MESSAGE_NEXTHOP > 0) || - (version == 4 && b.Message&FRR_MESSAGE_NEXTHOP > 0) || - (version >= 5 && b.Message&FRR_ZAPI5_MESSAGE_NEXTHOP > 0) { - var numNexthop uint16 - if version <= 4 { - if pos+1 > rest { - return fmt.Errorf("MESSAGE_NEXTHOP message length invalid pos:%d rest:%d", pos, rest) - } - numNexthop = uint16(data[pos]) - pos += 1 - } else { // version >= 5 - if pos+2 > rest { - return fmt.Errorf("MESSAGE_NEXTHOP message length invalid pos:%d rest:%d", pos, rest) + if b.Message&MessageNexthop > 0 { + numNexthop := uint16(0) + numNexthopDataSize := 2 + processFlag := nexthopProcessFlagForIPRouteBody(version, softwareName, true) + nhType := nexthopType(0) + if version < 5 { // frr3 and quagga + numNexthopDataSize = 1 + nhType = nexthopTypeIPv4.toEach(version) + if b.Prefix.Family == syscall.AF_INET6 { + nhType = nexthopTypeIPv6.toEach(version) } + } + if pos+numNexthopDataSize > rest { + return fmt.Errorf("MessageNexthop message length invalid pos:%d rest:%d", pos, rest) + } + if numNexthopDataSize == 2 { numNexthop = binary.BigEndian.Uint16(data[pos : pos+2]) - pos += 2 + } else if numNexthopDataSize == 1 { + numNexthop = uint16(data[pos]) } - for i := 0; i < int(numNexthop); i++ { - var nexthop Nexthop - if version <= 3 { - if b.Prefix.Family == syscall.AF_INET { - nexthop.Type = NEXTHOP_TYPE_IPV4 - } else if b.Prefix.Family == syscall.AF_INET6 { - nexthop.Type = NEXTHOP_TYPE_IPV6 - } - } else if version == 4 { - if b.Prefix.Family == syscall.AF_INET { - nexthop.Type = FRR_NEXTHOP_TYPE_IPV4 - } else if b.Prefix.Family == syscall.AF_INET6 { - nexthop.Type = FRR_NEXTHOP_TYPE_IPV6 - } - } else { // version >= 5 - if pos+5 > rest { - return fmt.Errorf("MESSAGE_NEXTHOP message length invalid pos:%d rest:%d", pos, rest) - } - nexthop.VrfId = binary.BigEndian.Uint32(data[pos : pos+4]) - nexthop.Type = NEXTHOP_TYPE(data[pos+4]) - pos += 5 - if softwareName == "frr7.1" || softwareName == "frr7.2" { - nexthop.Onlink = uint8(data[pos]) - pos += 1 - } - } + pos += numNexthopDataSize - if (version <= 3 && nexthop.Type == NEXTHOP_TYPE_IPV4) || - (version >= 4 && nexthop.Type == FRR_NEXTHOP_TYPE_IPV4) { - if pos+4 > rest { - return fmt.Errorf("MESSAGE_NEXTHOP NEXTHOP_TYPE_IPV4 message length invalid pos:%d rest:%d", pos, rest) - } - addr := data[pos : pos+4] - nexthop.Gate = net.IP(addr).To4() - pos += 4 - } else if (version <= 3 && nexthop.Type == NEXTHOP_TYPE_IPV6) || - (version >= 4 && nexthop.Type == FRR_NEXTHOP_TYPE_IPV6) { - if pos+16 > rest { - return fmt.Errorf("MESSAGE_NEXTHOP NEXTHOP_TYPE_IPV6 message length invalid pos:%d rest:%d", pos, rest) - } - addr := data[pos : pos+16] - nexthop.Gate = net.IP(addr).To16() - pos += 16 - } else if version >= 5 && nexthop.Type == FRR_NEXTHOP_TYPE_IFINDEX { - if pos+4 > rest { - return fmt.Errorf("MESSAGE_NEXTHOP NEXTHOP_TYPE_IFINDEX message length invalid pos:%d rest:%d", pos, rest) - } - nexthop.Ifindex = binary.BigEndian.Uint32(data[pos : pos+4]) - pos += 4 - // barkward compatibility - if b.Prefix.Family == syscall.AF_INET { - nexthop.Gate = net.ParseIP("0.0.0.0") - } else if b.Prefix.Family == syscall.AF_INET6 { - nexthop.Gate = net.ParseIP("::") - } - } else if version >= 5 && nexthop.Type == FRR_NEXTHOP_TYPE_IPV4_IFINDEX { - if pos+8 > rest { - return fmt.Errorf("MESSAGE_NEXTHOP NEXTHOP_TYPE_IPV4_IFINDEX message length invalid pos:%d rest:%d", pos, rest) - } - addr := data[pos : pos+4] - nexthop.Gate = net.IP(addr).To4() - nexthop.Ifindex = binary.BigEndian.Uint32(data[pos+4 : pos+8]) - pos += 8 - } else if version >= 5 && nexthop.Type == FRR_NEXTHOP_TYPE_IPV6_IFINDEX { - if pos+20 > rest { - return fmt.Errorf("MESSAGE_NEXTHOP NEXTHOP_TYPE_IPV6_IFINDEX message length invalid pos:%d rest:%d", pos, rest) - } - addr := data[pos : pos+16] - nexthop.Gate = net.IP(addr).To16() - nexthop.Ifindex = binary.BigEndian.Uint32(data[pos+16 : pos+20]) - pos += 20 - } else if version >= 5 && nexthop.Type == FRR_NEXTHOP_TYPE_BLACKHOLE { - if pos+1 > rest { - return fmt.Errorf("MESSAGE_NEXTHOP NEXTHOP_TYPE_BLACKHOLE message length invalid pos:%d rest:%d", pos, rest) - } - nexthop.BlackholeType = data[pos] - pos += 1 - } - b.Nexthops = append(b.Nexthops, nexthop) + nexthopsByteLen, err := decodeNexthops(&b.Nexthops, data[pos:], version, softwareName, b.Prefix.Family, numNexthop, processFlag, b.Message, b.Flags, nhType) + if err != nil { + return err } + pos += nexthopsByteLen + } + if version == 5 && b.Flags&flagEvpnRoute.ToEach(version, softwareName) > 0 { + b.Nexthops = append(b.Nexthops, evpnNexthop) } - if (version <= 3 && b.Message&MESSAGE_IFINDEX > 0) || - (version == 4 && b.Message&FRR_MESSAGE_IFINDEX > 0) { + if version < 5 && b.Message&messageIFIndex > 0 { if pos+1 > rest { - return fmt.Errorf("MESSAGE_IFINDEX message length invalid pos:%d rest:%d", pos, rest) + return fmt.Errorf("MessageIFIndex message length invalid pos:%d rest:%d", pos, rest) } numIfIndex := uint8(data[pos]) - pos += 1 + pos++ for i := 0; i < int(numIfIndex); i++ { if pos+4 > rest { - return fmt.Errorf("MESSAGE_IFINDEX message length invalid pos:%d rest:%d", pos, rest) + return fmt.Errorf("MessageIFIndex message length invalid pos:%d rest:%d", pos, rest) } var nexthop Nexthop nexthop.Ifindex = binary.BigEndian.Uint32(data[pos : pos+4]) - if version <= 3 { - nexthop.Type = NEXTHOP_TYPE_IFINDEX - } else if version == 4 { - nexthop.Type = FRR_NEXTHOP_TYPE_IFINDEX - } + nexthop.Type = nexthopTypeIFIndex b.Nexthops = append(b.Nexthops, nexthop) pos += 4 } } - if (version <= 3 && b.Message&MESSAGE_DISTANCE > 0) || - (version == 4 && b.Message&FRR_MESSAGE_DISTANCE > 0) || - (version >= 5 && b.Message&FRR_ZAPI5_MESSAGE_DISTANCE > 0) { + if b.Message&MessageDistance.ToEach(version) > 0 { if pos+1 > rest { - return fmt.Errorf("MESSAGE_DISTANCE message length invalid pos:%d rest:%d", pos, rest) + return fmt.Errorf("MessageDistance message length invalid pos:%d rest:%d", pos, rest) } b.Distance = data[pos] - pos += 1 + pos++ } - if (version <= 3 && b.Message&MESSAGE_METRIC > 0) || - (version == 4 && b.Message&FRR_MESSAGE_METRIC > 0) || - (version >= 5 && b.Message&FRR_ZAPI5_MESSAGE_METRIC > 0) { + if b.Message&MessageMetric.ToEach(version) > 0 { if pos+4 > rest { - return fmt.Errorf("MESSAGE_METRIC message length invalid pos:%d rest:%d", pos, rest) + return fmt.Errorf("MessageMetric message length invalid pos:%d rest:%d", pos, rest) } b.Metric = binary.BigEndian.Uint32(data[pos : pos+4]) pos += 4 } - if (version <= 3 && b.Message&MESSAGE_MTU > 0) || - (version == 4 && b.Message&FRR_MESSAGE_MTU > 0) || - (version >= 5 && b.Message&FRR_ZAPI5_MESSAGE_MTU > 0) { + if b.Message&MessageMTU.ToEach(version) > 0 { if pos+4 > rest { - return fmt.Errorf("MESSAGE_MTU message length invalid pos:%d rest:%d", pos, rest) + return fmt.Errorf("MessageMTU message length invalid pos:%d rest:%d", pos, rest) } b.Mtu = binary.BigEndian.Uint32(data[pos : pos+4]) pos += 4 } - if (version <= 3 && b.Message&MESSAGE_TAG > 0) || - (version == 4 && b.Message&FRR_MESSAGE_TAG > 0) || - (version >= 5 && b.Message&FRR_ZAPI5_MESSAGE_TAG > 0) { + if b.Message&messageTag.ToEach(version) > 0 { if pos+4 > rest { - return fmt.Errorf("MESSAGE_TAG message length invalid pos:%d rest:%d", pos, rest) + return fmt.Errorf("MessageTag message length invalid pos:%d rest:%d", pos, rest) } - b.Tag = binary.BigEndian.Uint32(data[pos : pos+4]) + b.tag = binary.BigEndian.Uint32(data[pos : pos+4]) pos += 4 } if pos != rest { - return fmt.Errorf("message length invalid pos:%d rest:%d", pos, rest) + return fmt.Errorf("message length invalid (last) pos:%d rest:%d, message:%#x", pos, rest, b.Message) } return nil } -func (b *IPRouteBody) String(version uint8, softwareName string) string { +func (b *IPRouteBody) string(version uint8, softwareName string) string { s := fmt.Sprintf( - "type: %s, instance: %d, flags: %s, message: %d, safi: %s, prefix: %s/%d, src_prefix: %s/%d", - b.Type.String(), b.Instance, b.Flags.String(version, softwareName), b.Message, b.SAFI.String(), b.Prefix.Prefix.String(), b.Prefix.PrefixLen, b.SrcPrefix.Prefix.String(), b.SrcPrefix.PrefixLen) + "type: %s, instance: %d, flags: %s, message: %d(%s), safi: %s, prefix: %s/%d, src_prefix: %s/%d", + b.Type.String(), b.instance, b.Flags.String(version, softwareName), b.Message, b.Message.string(version), b.Safi.String(), b.Prefix.Prefix.String(), b.Prefix.PrefixLen, b.srcPrefix.Prefix.String(), b.srcPrefix.PrefixLen) for i, nh := range b.Nexthops { - s += fmt.Sprintf(", nexthops[%d]: %s", i, nh.String()) + s += fmt.Sprintf(", nexthops[%d]: %s", i, nh.string()) } return s + fmt.Sprintf( ", distance: %d, metric: %d, mtu: %d, tag: %d", - b.Distance, b.Metric, b.Mtu, b.Tag) + b.Distance, b.Metric, b.Mtu, b.tag) } -func decodeNexthopsFromBytes(nexthops *[]Nexthop, data []byte, family uint8, version uint8) (int, error) { - addrByteLen, err := addressByteLength(family) - if err != nil { - return 0, err - } - - numNexthop := int(data[0]) - offset := 1 - - for i := 0; i < numNexthop; i++ { - nexthop := Nexthop{} - nexthop.Type = NEXTHOP_TYPE(data[offset]) - offset += 1 - - // On Quagga, NEXTHOP_TYPE_IFNAME is same as NEXTHOP_TYPE_IFINDEX, - // NEXTHOP_TYPE_IPV4_IFNAME is same as NEXTHOP_TYPE_IPV4_IFINDEX, - // NEXTHOP_TYPE_IPV6_IFNAME is same as NEXTHOP_TYPE_IPV6_IFINDEX - - // On FRRouting version 3.0 or later, NEXTHOP_TYPE_IPV4 and NEXTHOP_TYPE_IPV6 have - // the same structure with NEXTHOP_TYPE_IPV4_IFINDEX and NEXTHOP_TYPE_IPV6_IFINDEX. - - if (version <= 3 && (nexthop.Type == NEXTHOP_TYPE_IFINDEX || nexthop.Type == NEXTHOP_TYPE_IFNAME)) || - (version >= 4 && nexthop.Type == FRR_NEXTHOP_TYPE_IFINDEX) { - nexthop.Ifindex = binary.BigEndian.Uint32(data[offset : offset+4]) - offset += 4 - } else if version <= 3 && nexthop.Type == NEXTHOP_TYPE_IPV4 { - nexthop.Gate = net.IP(data[offset : offset+addrByteLen]).To4() - offset += addrByteLen - } else if version <= 3 && nexthop.Type == NEXTHOP_TYPE_IPV6 { - nexthop.Gate = net.IP(data[offset : offset+addrByteLen]).To16() - offset += addrByteLen - } else if (version <= 3 && (nexthop.Type == NEXTHOP_TYPE_IPV4_IFINDEX || nexthop.Type == NEXTHOP_TYPE_IPV4_IFNAME)) || - (version >= 4 && (nexthop.Type == FRR_NEXTHOP_TYPE_IPV4 || nexthop.Type == FRR_NEXTHOP_TYPE_IPV4_IFINDEX)) { - nexthop.Gate = net.IP(data[offset : offset+addrByteLen]).To4() - offset += addrByteLen - nexthop.Ifindex = binary.BigEndian.Uint32(data[offset : offset+4]) - offset += 4 - } else if (version <= 3 && (nexthop.Type == NEXTHOP_TYPE_IPV6_IFINDEX || nexthop.Type == NEXTHOP_TYPE_IPV6_IFNAME)) || - (version >= 4 && (nexthop.Type == FRR_NEXTHOP_TYPE_IPV6 || nexthop.Type == FRR_NEXTHOP_TYPE_IPV6_IFINDEX)) { - nexthop.Gate = net.IP(data[offset : offset+addrByteLen]).To16() - offset += addrByteLen - nexthop.Ifindex = binary.BigEndian.Uint32(data[offset : offset+4]) - offset += 4 - } - if version >= 5 { - nexthop.LabelNum = uint8(data[offset]) - offset += 1 - if nexthop.LabelNum > MPLS_MAX_LABEL { - nexthop.LabelNum = MPLS_MAX_LABEL - } - if nexthop.LabelNum > 0 { - nexthop.MplsLabels = make([]uint32, nexthop.LabelNum) - for n := uint8(0); n < nexthop.LabelNum; n++ { - /* Frr uses stream_put for mpls label array. - stream_put is unaware of byteorder coversion. - Therefore LittleEndian is used instead of BigEndian. */ - nexthop.MplsLabels[n] = binary.LittleEndian.Uint32(data[offset : offset+4]) - offset += 4 - } - } - } - *nexthops = append(*nexthops, nexthop) - } - - return offset, nil +// lookupBody is combination of nexthopLookupBody and imporetLookupBody +type lookupBody struct { + api APIType + prefixLength uint8 // importLookup serialize only + addr net.IP //it is same as prefix (it is deleted from importLookup) + distance uint8 // nexthopIPv4LookupMRIB only + metric uint32 + nexthops []Nexthop } -type NexthopLookupBody struct { - Api API_TYPE - Addr net.IP - Distance uint8 - Metric uint32 - Nexthops []Nexthop -} - -// Quagga only. Reference: zread_ipv[4|6]_nexthop_lookup in zebra/zserv.c of Quagga1.2.x (ZAPI3) -func (b *NexthopLookupBody) Serialize(version uint8, softwareName string) ([]byte, error) { - family := addressFamilyFromApi(b.Api, version) +// Quagga only. Ref: zread_ipv4_(nexthop|import_lookup) in zebra/zserv.c +func (b *lookupBody) serialize(version uint8, softwareName string) ([]byte, error) { buf := make([]byte, 0) - - if family == syscall.AF_INET { - buf = append(buf, b.Addr.To4()...) - } else if family == syscall.AF_INET6 { - buf = append(buf, b.Addr.To16()...) + if b.api == zapi3IPv4ImportLookup { + buf = append(buf, b.prefixLength) + } + switch b.api { + case ipv4NexthopLookupMRIB, zapi3IPv4NexthopLookup, zapi3IPv4ImportLookup: + buf = append(buf, b.addr.To4()...) + case zapi3IPv6NexthopLookup: + buf = append(buf, b.addr.To16()...) } return buf, nil } -// Quagga only. Reference: zsend_ipv[4|6]_nexthop_lookup in zebra/zserv.c of Quagga1.2.x (ZAPI3) -func (b *NexthopLookupBody) DecodeFromBytes(data []byte, version uint8, softwareName string) error { - family := addressFamilyFromApi(b.Api, version) - addrByteLen, err := addressByteLength(family) - if err != nil { - return err +// Quagga only(except ipv4NexthopLookupMRIB). +// Ref: zsend_ipv[4|6]_(nexthop|import)_lookup in zebra/zserv.c +func (b *lookupBody) decodeFromBytes(data []byte, version uint8, softwareName string) error { + family := uint8(syscall.AF_INET) + if b.api == zapi3IPv6NexthopLookup { + family = syscall.AF_INET6 } - - if len(data) < addrByteLen { + addrByteLen, _ := addressByteLength(family) + requiredLen := 5 //metric(4), numNexthop(1) + hasDistance := false + if b.api == ipv4NexthopLookupMRIB.ToEach(version, softwareName) { + requiredLen++ //distance + hasDistance = true + } + if len(data) < addrByteLen+requiredLen { return fmt.Errorf("message length invalid") } - buf := make([]byte, addrByteLen) copy(buf, data[0:addrByteLen]) pos := addrByteLen - b.Addr = ipFromFamily(family, buf) - - if version >= 4 { - b.Distance = data[pos] + b.addr = ipFromFamily(family, buf) + if hasDistance { + b.distance = data[pos] pos++ } - - if len(data[pos:]) > int(1+addrByteLen) { - b.Metric = binary.BigEndian.Uint32(data[pos : pos+4]) - pos += 4 - b.Nexthops = []Nexthop{} - if nexthopsByteLen, err := decodeNexthopsFromBytes(&b.Nexthops, data[pos:], family, version); err != nil { - return err - } else { - pos += nexthopsByteLen - } - } - - return nil -} - -func (b *NexthopLookupBody) String(version uint8, softwareName string) string { - s := fmt.Sprintf( - "addr: %s, distance:%d, metric: %d", - b.Addr.String(), b.Distance, b.Metric) - if len(b.Nexthops) > 0 { - for _, nh := range b.Nexthops { - s = s + fmt.Sprintf(", nexthop:{%s}", nh.String()) - } - } - return s -} - -type ImportLookupBody struct { - Api API_TYPE - PrefixLength uint8 - Prefix net.IP - Addr net.IP - Metric uint32 - Nexthops []Nexthop -} - -// Quagga only. Reference: zread_ipv4_import_lookup in zebra/zserv.c of Quagga1.2.x (ZAPI3) -func (b *ImportLookupBody) Serialize(version uint8, softwareName string) ([]byte, error) { - buf := make([]byte, 1) - buf[0] = b.PrefixLength - buf = append(buf, b.Addr.To4()...) - return buf, nil -} - -// Quagga only. Reference: zsend_ipv4_import_lookup in zebra/zserv.c of Quagga1.2.x (ZAPI3) -func (b *ImportLookupBody) DecodeFromBytes(data []byte, version uint8, softwareName string) error { - family := addressFamilyFromApi(b.Api, version) - addrByteLen, err := addressByteLength(family) + b.metric = binary.BigEndian.Uint32(data[pos : pos+4]) + pos += 4 + numNexthop := uint16(data[pos]) + pos++ + b.nexthops = []Nexthop{} + processFlag := nexthopHasType | nexthopProcessIFnameToIFindex + nexthopsByteLen, err := decodeNexthops(&b.nexthops, data[pos:], version, softwareName, family, numNexthop, processFlag, MessageFlag(0), Flag(0), nexthopType(0)) if err != nil { return err } - - if len(data) < addrByteLen { - return fmt.Errorf("message length invalid") - } - - buf := make([]byte, addrByteLen) - copy(buf, data[0:addrByteLen]) - pos := addrByteLen - - b.Addr = net.IP(buf).To4() - - if len(data[pos:]) > int(1+addrByteLen) { - b.Metric = binary.BigEndian.Uint32(data[pos : pos+4]) - pos += 4 - b.Nexthops = []Nexthop{} - if nexthopsByteLen, err := decodeNexthopsFromBytes(&b.Nexthops, data[pos:], family, version); err != nil { - return err - } else { - pos += nexthopsByteLen - } - } - + pos += nexthopsByteLen return nil } - -func (b *ImportLookupBody) String(version uint8, softwareName string) string { +func (b *lookupBody) string(version uint8, softwareName string) string { s := fmt.Sprintf( - "prefix: %s/%d, addr: %s, metric: %d", - b.Prefix.String(), b.PrefixLength, b.Addr.String(), b.Metric) - if len(b.Nexthops) > 0 { - for _, nh := range b.Nexthops { - s = s + fmt.Sprintf(", nexthop:{%s}", nh.String()) + "addr/prefixLength: %s/%d, distance:%d, metric: %d", + b.addr.String(), b.prefixLength, b.distance, b.metric) + if len(b.nexthops) > 0 { + for _, nh := range b.nexthops { + s = s + fmt.Sprintf(", nexthop:{%s}", nh.string()) } } return s } +// RegisteredNexthop is referred in zclient type RegisteredNexthop struct { - Connected uint8 + connected uint8 Family uint16 - // Note: Ignores PrefixLength (uint8), - // because this field should be always: + // Note: Ignores PrefixLength (uint8), because this field should be always: // - 32 if Address Family is AF_INET // - 128 if Address Family is AF_INET6 Prefix net.IP } -func (n *RegisteredNexthop) Len() int { +func (n *RegisteredNexthop) len() int { // Connected (1 byte) + Address Family (2 bytes) + Prefix Length (1 byte) + Prefix (variable) if n.Family == uint16(syscall.AF_INET) { return 4 + net.IPv4len - } else { - return 4 + net.IPv6len } + return 4 + net.IPv6len } -// Reference: sendmsg_nexthop in bgpd/bgp_nht.c of Quagga1.2.x (ZAPI3) -// Reference: sendmsg_zebra_rnh in bgpd/bgp_nht.c of FRR3.x (ZAPI4) -// Reference: zclient_send_rnh function in lib/zclient.c of FRR5.x (ZAPI5) -func (n *RegisteredNexthop) Serialize() ([]byte, error) { +// Ref: sendmsg_nexthop in bgpd/bgp_nht.c of Quagga1.2.x (ZAPI3) +// Ref: sendmsg_zebra_rnh in bgpd/bgp_nht.c of FRR3.x (ZAPI4) +// Ref: zclient_send_rnh in lib/zclient.c of FRR5.x (ZAPI5) +func (n *RegisteredNexthop) serialize() ([]byte, error) { // Connected (1 byte) buf := make([]byte, 4) - buf[0] = byte(n.Connected) + buf[0] = byte(n.connected) // Address Family (2 bytes) binary.BigEndian.PutUint16(buf[1:3], n.Family) @@ -2730,12 +2586,12 @@ func (n *RegisteredNexthop) Serialize() ([]byte, error) { return buf, nil } -// Reference: zserv_nexthop_register in zebra/zserv.c of Quagga1.2.x (ZAPI3) -// Reference: zserv_rnh_register in zebra/zserv.c of FRR3.x (ZAPI4) -// Reference: zread_rnh_register in zebra/zapi_msg.c of FRR5.x (ZAPI5) -func (n *RegisteredNexthop) DecodeFromBytes(data []byte, softwareName string) error { +// Ref: zserv_nexthop_register in zebra/zserv.c of Quagga1.2.x (ZAPI3) +// Ref: zserv_rnh_register in zebra/zserv.c of FRR3.x (ZAPI4) +// Ref: zread_rnh_register in zebra/zapi_msg.c of FRR5.x (ZAPI5) +func (n *RegisteredNexthop) decodeFromBytes(data []byte, softwareName string) error { // Connected (1 byte) - n.Connected = uint8(data[0]) + n.connected = uint8(data[0]) // Address Family (2 bytes) n.Family = binary.BigEndian.Uint16(data[1:3]) // Note: Ignores Prefix Length (1 byte) @@ -2746,26 +2602,27 @@ func (n *RegisteredNexthop) DecodeFromBytes(data []byte, softwareName string) er return nil } -func (n *RegisteredNexthop) String(version uint8, softwareName string) string { +func (n *RegisteredNexthop) string(version uint8, softwareName string) string { return fmt.Sprintf( "connected: %d, family: %d, prefix: %s", - n.Connected, n.Family, n.Prefix.String()) + n.connected, n.Family, n.Prefix.String()) } +// NexthopRegisterBody us referred in zclient type NexthopRegisterBody struct { - Api API_TYPE + api APIType Nexthops []*RegisteredNexthop } -// Reference: sendmsg_nexthop in bgpd/bgp_nht.c of Quagga1.2.x (ZAPI3) -// Reference: sendmsg_zebra_rnh in bgpd/bgp_nht.c of FRR3.x (ZAPI4) -// Reference: zclient_send_rnh function in lib/zclient.c of FRR5.x (ZAPI5) -func (b *NexthopRegisterBody) Serialize(version uint8, softwareName string) ([]byte, error) { +// Ref: sendmsg_nexthop in bgpd/bgp_nht.c of Quagga1.2.x (ZAPI3) +// Ref: sendmsg_zebra_rnh in bgpd/bgp_nht.c of FRR3.x (ZAPI4) +// Ref: zclient_send_rnh in lib/zclient.c of FRR5.x (ZAPI5) +func (b *NexthopRegisterBody) serialize(version uint8, softwareName string) ([]byte, error) { buf := make([]byte, 0) // List of Registered Nexthops for _, nh := range b.Nexthops { - nhBuf, err := nh.Serialize() + nhBuf, err := nh.serialize() if err != nil { return nil, err } @@ -2775,47 +2632,42 @@ func (b *NexthopRegisterBody) Serialize(version uint8, softwareName string) ([]b return buf, nil } -// Reference: zserv_nexthop_register in zebra/zserv.c of Quagga1.2.x (ZAPI3) -// Reference: zserv_rnh_register in zebra/zserv.c of FRR3.x (ZAPI4) -// Reference: zread_rnh_register in zebra/zapi_msg.c of FRR5.x (ZAPI5) -func (b *NexthopRegisterBody) DecodeFromBytes(data []byte, version uint8, softwareName string) error { +// Ref: zserv_nexthop_register in zebra/zserv.c of Quagga1.2.x (ZAPI3) +// Ref: zserv_rnh_register in zebra/zserv.c of FRR3.x (ZAPI4) +// Ref: zread_rnh_register in zebra/zapi_msg.c of FRR5.x (ZAPI5) +func (b *NexthopRegisterBody) decodeFromBytes(data []byte, version uint8, softwareName string) error { offset := 0 - // List of Registered Nexthops b.Nexthops = []*RegisteredNexthop{} for len(data[offset:]) > 0 { nh := new(RegisteredNexthop) - err := nh.DecodeFromBytes(data[offset:], softwareName) + err := nh.decodeFromBytes(data[offset:], softwareName) if err != nil { return err } b.Nexthops = append(b.Nexthops, nh) - offset += nh.Len() + offset += nh.len() if len(data) < offset { break } } - return nil } -func (b *NexthopRegisterBody) String(version uint8, softwareName string) string { +func (b *NexthopRegisterBody) string(version uint8, softwareName string) string { s := make([]string, 0) for _, nh := range b.Nexthops { - s = append(s, fmt.Sprintf("nexthop:{%s}", nh.String(version, softwareName))) + s = append(s, fmt.Sprintf("nexthop:{%s}", nh.string(version, softwareName))) } return strings.Join(s, ", ") } -/* NEXTHOP_UPDATE message uses same data structure as IPRoute (zapi_route) - in FRR version 4, 5 (ZApi version 5) */ +// NexthopUpdateBody uses same data structure as IPRoute (zapi_route) after frr4 (Zapi5) type NexthopUpdateBody IPRouteBody -// Reference: send_client function in zebra/zebra_rnh.c of Quagga1.2.x (ZAPI3) -// Reference: send_client function in zebra/zebra_rnh.c of FRR3.x (ZAPI4) -// Reference: send_client function in zebra/zebra_rnh.c of FRR5.x (ZAPI5) -func (b *NexthopUpdateBody) Serialize(version uint8, softwareName string) ([]byte, error) { +// Ref: send_client in zebra/zebra_rnh.c of Quagga1.2&FRR3&FRR5(ZAPI3&4$5) +func (b *NexthopUpdateBody) serialize(version uint8, softwareName string) ([]byte, error) { // Address Family (2 bytes) buf := make([]byte, 3) binary.BigEndian.PutUint16(buf, uint16(b.Prefix.Family)) @@ -2836,31 +2688,29 @@ func (b *NexthopUpdateBody) Serialize(version uint8, softwareName string) ([]byt } if version >= 5 { // Type (1 byte) (if version>=5) - // Instance (2 bytes) (if version>=5) + // instance (2 bytes) (if version>=5) buf = append(buf, byte(b.Type)) - bbuf := make([]byte, 2) - binary.BigEndian.PutUint16(bbuf, b.Instance) - buf = append(buf, bbuf...) + tmpbuf := make([]byte, 2) + binary.BigEndian.PutUint16(tmpbuf, b.instance) + buf = append(buf, tmpbuf...) } if version >= 4 { // Distance (1 byte) (if version>=4) buf = append(buf, b.Distance) } // Metric (4 bytes) - bbuf := make([]byte, 4) - binary.BigEndian.PutUint32(bbuf, b.Metric) - buf = append(buf, bbuf...) + tmpbuf := make([]byte, 4) + binary.BigEndian.PutUint32(tmpbuf, b.Metric) + buf = append(buf, tmpbuf...) // Number of Nexthops (1 byte) buf = append(buf, uint8(0)) // Temporary code // ToDo Processing Route Entry - return buf, nil } -// Reference: bgp_parse_nexthop_update function in bgpd/bgp_nht.c of Quagga1.2.x (ZAPI3) -// Reference: bgp_parse_nexthop_update function in bgpd/bgp_nht.c of FRR3.x (ZAPI4) -// Reference: zapi_nexthop_update_decode function in lib/zclient.c of FRR5.x (ZAPI5) -func (b *NexthopUpdateBody) DecodeFromBytes(data []byte, version uint8, softwareName string) error { +// Ref: bgp_parse_nexthop_update in bgpd/bgp_nht.c of Quagga1.2&FRR3 (ZAPI3&4) +// Ref: zapi_nexthop_update_decode in lib/zclient.c of FRR5.x (ZAPI5) +func (b *NexthopUpdateBody) decodeFromBytes(data []byte, version uint8, softwareName string) error { // Address Family (2 bytes) prefixFamily := binary.BigEndian.Uint16(data[0:2]) b.Prefix.Family = uint8(prefixFamily) @@ -2875,505 +2725,310 @@ func (b *NexthopUpdateBody) DecodeFromBytes(data []byte, version uint8, software b.Prefix.Prefix = ipFromFamily(b.Prefix.Family, data[offset:offset+addrByteLen]) offset += addrByteLen - if version >= 5 { - b.Type = ROUTE_TYPE(data[offset]) - b.Instance = binary.BigEndian.Uint16(data[offset+1 : offset+3]) + if version > 4 { + b.Type = RouteType(data[offset]) + b.instance = binary.BigEndian.Uint16(data[offset+1 : offset+3]) offset += 3 } // Distance (1 byte) (if version>=4) - if version >= 4 { + if version > 3 { b.Distance = data[offset] - offset += 1 + offset++ } - // Metric (4 bytes) - // Number of Nexthops (1 byte) + // Metric (4 bytes) & Number of Nexthops (1 byte) if len(data[offset:]) < 5 { return fmt.Errorf("invalid message length: missing metric(4 bytes) or nexthops(1 byte): %d<5", len(data[offset:])) } b.Metric = binary.BigEndian.Uint32(data[offset : offset+4]) offset += 4 + numNexthop := uint16(data[offset]) + offset++ // List of Nexthops b.Nexthops = []Nexthop{} - if nexthopsByteLen, err := decodeNexthopsFromBytes(&b.Nexthops, data[offset:], b.Prefix.Family, version); err != nil { + + processFlag := nexthopProcessFlag(nexthopHasType) + if version == 6 { + switch softwareName { + case "frr7.3", "": + processFlag |= (nexthopHasVrfID | nexthopHasFlag | nexthopProcessIPToIPIFindex) + case "frr7.0", "frr7.1", "frr7.2": + processFlag |= (nexthopHasVrfID | nexthopProcessIPToIPIFindex) + case "frr6": + processFlag |= nexthopProcessIPToIPIFindex + } + } else if version == 5 { + switch softwareName { + case "frr5", "": + processFlag |= nexthopProcessIPToIPIFindex + } + } else if version < 4 { // quagga + processFlag |= nexthopProcessIFnameToIFindex + } + + message := MessageFlag(0) + if (version == 6 && !(softwareName == "frr7.3" || softwareName == "")) || + (version == 5 && (softwareName == "frr5" || softwareName == "")) { + message |= MessageLabel + } + + nexthopsByteLen, err := decodeNexthops(&b.Nexthops, data[offset:], version, softwareName, b.Prefix.Family, numNexthop, processFlag, message, Flag(0), nexthopType(0)) + if err != nil { return err - } else { - offset += nexthopsByteLen } + offset += nexthopsByteLen return nil } -func (b *NexthopUpdateBody) String(version uint8, softwareName string) string { +func (b *NexthopUpdateBody) string(version uint8, softwareName string) string { s := fmt.Sprintf( "family: %d, prefix: %s, distance: %d, metric: %d", b.Prefix.Family, b.Prefix.Prefix.String(), b.Distance, b.Metric) for _, nh := range b.Nexthops { - s = s + fmt.Sprintf(", nexthop:{%s}", nh.String()) + s = s + fmt.Sprintf(", nexthop:{%s}", nh.string()) } return s } -type LabelManagerConnectBody struct { - RedistDefault ROUTE_TYPE - Instance uint16 +type labelManagerConnectBody struct { + redistDefault RouteType + instance uint16 // The followings are used in response from Zebra - Result uint8 // 0 means success + result uint8 // 0 means success } -// Reference: lm_label_manager_connect in lib/zclient.c of FRR -func (b *LabelManagerConnectBody) Serialize(version uint8, softwareName string) ([]byte, error) { +// Ref: lm_label_manager_connect in lib/zclient.c of FRR +func (b *labelManagerConnectBody) serialize(version uint8, softwareName string) ([]byte, error) { buf := make([]byte, 3) - buf[0] = uint8(b.RedistDefault) - binary.BigEndian.PutUint16(buf[1:3], b.Instance) + buf[0] = uint8(b.redistDefault) + binary.BigEndian.PutUint16(buf[1:3], b.instance) return buf, nil } -func (b *LabelManagerConnectBody) DecodeFromBytes(data []byte, version uint8, softwareName string) error { +func (b *labelManagerConnectBody) decodeFromBytes(data []byte, version uint8, softwareName string) error { size := 1 - // FRR v4 may work incorrectly. It returns result only although it uses ZAPI v5. - if version >= 4 { + if version > 4 && softwareName != "frr4" { // FRR4 returns result only. size = 4 } if len(data) < size { - return fmt.Errorf("invalid message length for LABEL_MANAGER_CONNECT response: %d<%d", + return fmt.Errorf("invalid message length for LabelManagerConnect response: %d<%d", len(data), size) } - if version > 4 { - b.RedistDefault = ROUTE_TYPE(data[0]) - b.Instance = binary.BigEndian.Uint16(data[1:3]) + if version > 4 && softwareName != "frr4" { + b.redistDefault = RouteType(data[0]) + b.instance = binary.BigEndian.Uint16(data[1:3]) data = data[3:] } - b.Result = data[0] + b.result = data[0] return nil } -func (b *LabelManagerConnectBody) String(version uint8, softwareName string) string { +func (b *labelManagerConnectBody) string(version uint8, softwareName string) string { return fmt.Sprintf( "route_type: %s, instance: %d, result: %d", - b.RedistDefault.String(), b.Instance, b.Result) + b.redistDefault.String(), b.instance, b.result) } -// Reference: zsend_assign_label_chunk_response in zebra/zserv.c of FRR3.x -// Reference: zsend_assign_label_chunk_response in zebra/zapi_msg.c of FRR5.x and 6.x +// GetLabelChunkBody is referred in zclient (Ref: zsend_assign_label_chunk_response) type GetLabelChunkBody struct { - Proto uint8 // it is appeared in FRR5.x and 6.x - Instance uint16 // it is appeared in FRR5.x and 6.x - Keep uint8 + proto uint8 // it is appeared in FRR5.x and 6.x + instance uint16 // it is appeared in FRR5.x and 6.x + keep uint8 ChunkSize uint32 - // The followings are used in response from Zebra - Start uint32 - End uint32 + Start uint32 // The followings are used in response from Zebra + End uint32 + base uint32 // it is added in FRR7.2 } -// Reference: zread_get_label_chunk in zebra/zserv.c of FRR3.x -// Reference: zread_get_label_chunk in zebra/zapi_msg.c of FRR5.x and 6.x -func (b *GetLabelChunkBody) Serialize(version uint8, softwareName string) ([]byte, error) { - buf := make([]byte, 8) +// Ref: zread_get_label_chunk in zebra/zserv.c of FRR3.x +// Ref: zread_get_label_chunk in zebra/zapi_msg.c of FRR5.x and 6.x +func (b *GetLabelChunkBody) serialize(version uint8, softwareName string) ([]byte, error) { + buf := make([]byte, 12) pos := 0 - if version > 4 { - buf[pos] = b.Proto - binary.BigEndian.PutUint16(buf[pos+1:pos+3], b.Instance) + b.base = 0 + if version > 4 && softwareName != "frr4" { + buf[pos] = b.proto + binary.BigEndian.PutUint16(buf[pos+1:pos+3], b.instance) pos += 3 } - buf[pos] = b.Keep + buf[pos] = b.keep binary.BigEndian.PutUint32(buf[pos+1:pos+5], b.ChunkSize) pos += 5 + if version == 6 && (softwareName == "frr7.2" || softwareName == "frr7.3" || softwareName == "") { + binary.BigEndian.PutUint32(buf[pos:pos+4], b.base) + pos += 4 + } return buf[0:pos], nil } -// Reference: zsend_assign_label_chunk_response in zebra/zserv.c of FRR3.x -// Reference: zsend_assign_label_chunk_response in zebra/zapi_msg.c of FRR5.x and 6.x -func (b *GetLabelChunkBody) DecodeFromBytes(data []byte, version uint8, softwareName string) error { +// Ref: zsend_assign_label_chunk_response in zebra/zserv.c of FRR3.x +// Ref: zsend_assign_label_chunk_response in zebra/zapi_msg.c of FRR5.x and 6.x +func (b *GetLabelChunkBody) decodeFromBytes(data []byte, version uint8, softwareName string) error { size := 9 - if version > 4 { + if version > 4 && softwareName != "frr4" { size = 12 } if len(data) < size { - return fmt.Errorf("invalid message length for GET_LABEL_CHUNK response: %d<%d", + return fmt.Errorf("invalid message length for GetLabelChunk response: %d<%d", len(data), size) } - if version > 4 { - b.Proto = data[0] - b.Instance = binary.BigEndian.Uint16(data[1:3]) + if version > 4 && softwareName != "frr4" { + b.proto = data[0] + b.instance = binary.BigEndian.Uint16(data[1:3]) data = data[3:] } - b.Keep = data[0] + b.keep = data[0] b.Start = binary.BigEndian.Uint32(data[1:5]) b.End = binary.BigEndian.Uint32(data[5:9]) return nil } -func (b *GetLabelChunkBody) String(version uint8, softwareName string) string { +func (b *GetLabelChunkBody) string(version uint8, softwareName string) string { return fmt.Sprintf( "keep: %d, chunk_size: %d, start: %d, end: %d", - b.Keep, b.ChunkSize, b.Start, b.End) + b.keep, b.ChunkSize, b.Start, b.End) } -type ReleaseLabelChunkBody struct { - Proto uint8 // it is appeared in FRR5.x and 6.x - Instance uint16 // it is appeared in FRR5.x and 6.x - Start uint32 - End uint32 +type releaseLabelChunkBody struct { + proto uint8 // it is appeared in FRR5.x and 6.x + instance uint16 // it is appeared in FRR5.x and 6.x + start uint32 + end uint32 } -func (b *ReleaseLabelChunkBody) Serialize(version uint8, softwareName string) ([]byte, error) { +func (b *releaseLabelChunkBody) serialize(version uint8, softwareName string) ([]byte, error) { buf := make([]byte, 11) pos := 0 - if version > 4 { - buf[pos] = b.Proto - binary.BigEndian.PutUint16(buf[pos+1:pos+3], b.Instance) + if version > 4 && softwareName != "frr4" { + buf[pos] = b.proto + binary.BigEndian.PutUint16(buf[pos+1:pos+3], b.instance) pos += 3 } - binary.BigEndian.PutUint32(buf[pos:pos+4], b.Start) - binary.BigEndian.PutUint32(buf[pos+4:pos+8], b.End) + binary.BigEndian.PutUint32(buf[pos:pos+4], b.start) + binary.BigEndian.PutUint32(buf[pos+4:pos+8], b.end) pos += 8 return buf[0:pos], nil } -func (b *ReleaseLabelChunkBody) DecodeFromBytes(data []byte, version uint8, softwareName string) error { - // No response from Zebra - return nil +func (b *releaseLabelChunkBody) decodeFromBytes(data []byte, version uint8, softwareName string) error { + return nil // No response from Zebra } -func (b *ReleaseLabelChunkBody) String(version uint8, softwareName string) string { - return fmt.Sprintf( - "start: %d, end: %d", - b.Start, b.End) +func (b *releaseLabelChunkBody) string(version uint8, softwareName string) string { + return fmt.Sprintf("start: %d, end: %d", b.start, b.end) } -//go:generate stringer -type=LSP_TYPE -type LSP_TYPE uint8 +//go:generate stringer -type=lspTYPE +type lspTYPE uint8 const ( - LSP_NONE LSP_TYPE = iota //defined in FRR3 and over - LSP_STATIC //defined in FRR3 and over - LSP_LDP //defined in FRR3 and over - LSP_BGP //defined in FRR4 and over - LSP_SR //defined in FRR4 and over - LSP_SHARP //defined in FRR5 and over + lspNone lspTYPE = iota //defined in FRR3 and over + lspStatic //defined in FRR3 and over + lspLDP //defined in FRR3 and over + lspBGP //defined in FRR4 and over + lspSR //defined in FRR4 and over + lspSHARP //defined in FRR5 and over ) -type VrfLabelBody struct { - Label uint32 - Afi AFI - LabelType LSP_TYPE +type vrfLabelBody struct { + label uint32 + afi afi + labelType lspTYPE } -// Reference: zclient_send_vrf_label in lib/zclient.c of FRR 5.x and 6.x -func (b *VrfLabelBody) Serialize(version uint8, softwareName string) ([]byte, error) { +// Ref: zclient_send_vrf_label in lib/zclient.c of FRR 5.x and 6.x +func (b *vrfLabelBody) serialize(version uint8, softwareName string) ([]byte, error) { buf := make([]byte, 6) - binary.BigEndian.PutUint32(buf[0:4], b.Label) - buf[4] = uint8(b.Afi) - buf[5] = uint8(b.LabelType) + binary.BigEndian.PutUint32(buf[0:4], b.label) + buf[4] = uint8(b.afi) + buf[5] = uint8(b.labelType) return buf, nil } -func (b *VrfLabelBody) DecodeFromBytes(data []byte, version uint8, softwareName string) error { +// Ref: zread_vrf_label in zebra/zapi_msg.c of FRR 5.x and 6.x +func (b *vrfLabelBody) decodeFromBytes(data []byte, version uint8, softwareName string) error { if len(data) < 6 { - return fmt.Errorf("invalid message length for VRF_LABEL message: %d<6", len(data)) + return fmt.Errorf("invalid message length for VRFLabel message: %d<6", len(data)) } - b.Label = binary.BigEndian.Uint32(data[0:4]) - b.Afi = AFI(data[4]) - b.LabelType = LSP_TYPE(data[5]) + b.label = binary.BigEndian.Uint32(data[0:4]) + b.afi = afi(data[4]) + b.labelType = lspTYPE(data[5]) return nil } -func (b *VrfLabelBody) String(version uint8, softwareName string) string { +func (b *vrfLabelBody) string(version uint8, softwareName string) string { return fmt.Sprintf( - "label: %d, AFI: %s LSP_type: %s", - b.Label, b.Afi, b.LabelType) + "label: %d, afi: %s LSP type: %s", + b.label, b.afi, b.labelType) } +// Message is referred in zclient type Message struct { Header Header Body Body } -func (m *Message) Serialize(software string) ([]byte, error) { +func (m *Message) serialize(software string) ([]byte, error) { var body []byte if m.Body != nil { var err error - body, err = m.Body.Serialize(m.Header.Version, software) + body, err = m.Body.serialize(m.Header.Version, software) if err != nil { return nil, err } } m.Header.Len = uint16(len(body)) + HeaderSize(m.Header.Version) - hdr, err := m.Header.Serialize() + hdr, err := m.Header.serialize() if err != nil { return nil, err } return append(hdr, body...), nil } -func (m *Message) parseMessage(data []byte, software string) error { - switch m.Header.Command { - case INTERFACE_ADD, INTERFACE_DELETE, INTERFACE_UP, INTERFACE_DOWN: - m.Body = &InterfaceUpdateBody{} - case INTERFACE_ADDRESS_ADD, INTERFACE_ADDRESS_DELETE: - m.Body = &InterfaceAddressUpdateBody{} - case ROUTER_ID_UPDATE: - m.Body = &RouterIDUpdateBody{} - case IPV4_ROUTE_ADD, IPV6_ROUTE_ADD, IPV4_ROUTE_DELETE, IPV6_ROUTE_DELETE: - m.Body = &IPRouteBody{Api: m.Header.Command} - case IPV4_NEXTHOP_LOOKUP, IPV6_NEXTHOP_LOOKUP: - m.Body = &NexthopLookupBody{Api: m.Header.Command} - case IPV4_IMPORT_LOOKUP: - m.Body = &ImportLookupBody{Api: m.Header.Command} - case NEXTHOP_UPDATE: - m.Body = &NexthopUpdateBody{Api: m.Header.Command} - default: - m.Body = &UnknownBody{} - } - return m.Body.DecodeFromBytes(data, m.Header.Version, software) -} - -func (m *Message) parseFrrMessage(data []byte, software string) error { - switch m.Header.Command { - case FRR_INTERFACE_ADD, FRR_INTERFACE_DELETE, FRR_INTERFACE_UP, FRR_INTERFACE_DOWN: - m.Body = &InterfaceUpdateBody{} - case FRR_INTERFACE_ADDRESS_ADD, FRR_INTERFACE_ADDRESS_DELETE: - m.Body = &InterfaceAddressUpdateBody{} - case FRR_ROUTER_ID_UPDATE: - m.Body = &RouterIDUpdateBody{} - case FRR_NEXTHOP_UPDATE: - m.Body = &NexthopUpdateBody{} - case FRR_INTERFACE_NBR_ADDRESS_ADD, FRR_INTERFACE_NBR_ADDRESS_DELETE: - // TODO - m.Body = &UnknownBody{} - case FRR_INTERFACE_BFD_DEST_UPDATE: - // TODO - m.Body = &UnknownBody{} - case FRR_IMPORT_CHECK_UPDATE: - // TODO - m.Body = &UnknownBody{} - case FRR_BFD_DEST_REPLAY: - // TODO - m.Body = &UnknownBody{} - case FRR_REDISTRIBUTE_IPV4_ADD, FRR_REDISTRIBUTE_IPV4_DEL, FRR_REDISTRIBUTE_IPV6_ADD, FRR_REDISTRIBUTE_IPV6_DEL: - m.Body = &IPRouteBody{Api: m.Header.Command} - case FRR_INTERFACE_VRF_UPDATE: - // TODO - m.Body = &UnknownBody{} - case FRR_INTERFACE_LINK_PARAMS: - // TODO - m.Body = &UnknownBody{} - case FRR_PW_STATUS_UPDATE: - // TODO - m.Body = &UnknownBody{} - case FRR_LABEL_MANAGER_CONNECT: - // Note: Synchronous message - m.Body = &LabelManagerConnectBody{} - case FRR_GET_LABEL_CHUNK: - // Note: Synchronous message - m.Body = &GetLabelChunkBody{} - case FRR_RELEASE_LABEL_CHUNK: - // Note: Synchronous message - m.Body = &ReleaseLabelChunkBody{} - default: - m.Body = &UnknownBody{} - } - return m.Body.DecodeFromBytes(data, m.Header.Version, software) -} - -func (m *Message) parseFrrZapi5Message(data []byte, software string) error { - command := m.Header.Command - if software == "frr4" { - if c, err := frr4Zapi5Command(command, software, true); err == nil { - command = c - } else { - return err - } - } else if software == "cumulus" { - if c, err := cumulusZapi5Command(command, software, true); err == nil { - command = c - } else { - return err - } - } +func parseMessage(hdr *Header, data []byte, software string) (m *Message, err error) { + m = &Message{Header: *hdr} + /* TODO: + InterfaceNBRAddressAdd, InterfaceNBRAddressDelete, + InterfaceBFDDestUpdate, ImportCheckUpdate, BFDDestReplay, + InterfaceVRFUpdate, InterfaceLinkParams, PWStatusUpdate + */ + command := m.Header.Command.toCommon(m.Header.Version, software) switch command { - case FRR_ZAPI5_INTERFACE_ADD, FRR_ZAPI5_INTERFACE_DELETE, FRR_ZAPI5_INTERFACE_UP, FRR_ZAPI5_INTERFACE_DOWN: - m.Body = &InterfaceUpdateBody{} - case FRR_ZAPI5_INTERFACE_ADDRESS_ADD, FRR_ZAPI5_INTERFACE_ADDRESS_DELETE: - m.Body = &InterfaceAddressUpdateBody{} - case FRR_ZAPI5_ROUTER_ID_UPDATE: - m.Body = &RouterIDUpdateBody{} - case FRR_ZAPI5_NEXTHOP_UPDATE: + case interfaceAdd, interfaceDelete, interfaceUp, interfaceDown: + m.Body = &interfaceUpdateBody{} + case interfaceAddressAdd, interfaceAddressDelete: + m.Body = &interfaceAddressUpdateBody{} + case routerIDUpdate: + m.Body = &routerIDUpdateBody{} + case nexthopUpdate: m.Body = &NexthopUpdateBody{} - case FRR_ZAPI5_INTERFACE_NBR_ADDRESS_ADD, FRR_ZAPI5_INTERFACE_NBR_ADDRESS_DELETE: - // TODO - m.Body = &UnknownBody{} - case FRR_ZAPI5_INTERFACE_BFD_DEST_UPDATE: - // TODO - m.Body = &UnknownBody{} - case FRR_ZAPI5_IMPORT_CHECK_UPDATE: - // TODO - m.Body = &UnknownBody{} - case FRR_ZAPI5_BFD_DEST_REPLAY: - // TODO - m.Body = &UnknownBody{} - case FRR_ZAPI5_REDISTRIBUTE_ROUTE_ADD, FRR_ZAPI5_REDISTRIBUTE_ROUTE_DEL: - m.Body = &IPRouteBody{Api: m.Header.Command} - case FRR_ZAPI5_INTERFACE_VRF_UPDATE: - // TODO - m.Body = &UnknownBody{} - case FRR_ZAPI5_INTERFACE_LINK_PARAMS: - // TODO - m.Body = &UnknownBody{} - case FRR_ZAPI5_PW_STATUS_UPDATE: - // TODO - m.Body = &UnknownBody{} - case FRR_ZAPI5_LABEL_MANAGER_CONNECT: - // Note: Synchronous message - m.Body = &LabelManagerConnectBody{} - case FRR_ZAPI5_GET_LABEL_CHUNK: - // Note: Synchronous message + case redistributeRouteAdd, redistributeRouteDel: // for frr + m.Body = &IPRouteBody{API: m.Header.Command} + case labelManagerConnect: // Note: Synchronous message + m.Body = &labelManagerConnectBody{} + case getLabelChunk: // Note: Synchronous message m.Body = &GetLabelChunkBody{} - case FRR_ZAPI5_RELEASE_LABEL_CHUNK: - // Note: Synchronous message - m.Body = &ReleaseLabelChunkBody{} - case FRR_ZAPI5_VRF_LABEL: - m.Body = &VrfLabelBody{} + case releaseLabelChunk: // Note: Synchronous message + m.Body = &releaseLabelChunkBody{} + case vrfLabel: + m.Body = &vrfLabelBody{} + case RouteAdd, RouteDelete, BackwardIPv6RouteAdd, BackwardIPv6RouteDelete: // for quagga + m.Body = &IPRouteBody{API: m.Header.Command} + case ipv4NexthopLookupMRIB: + m.Body = &lookupBody{api: m.Header.Command} default: - m.Body = &UnknownBody{} - } - return m.Body.DecodeFromBytes(data, m.Header.Version, software) -} - -func (m *Message) parseFrrZapi6Message(data []byte, software string) error { - command := m.Header.Command - if software == "frr6" { - if c, err := frr6Zapi6Command(command, software, true); err == nil { - command = c - } else { - return err - } - } else if software == "frr7.2" { - // frr7.2 adds INTERFACE_SET_PROTODOWN between INTERFACE_SET_MASTER(6) and ROUTE_ADD - if command >= FRR_ZAPI6_ROUTE_ADD { - command-- + m.Body = &unknownBody{} + if m.Header.Version == 4 { + switch m.Header.Command { + case zapi4RedistributeIPv6Add, zapi4RedistributeIPv6Del: // for frr3 + m.Body = &IPRouteBody{API: m.Header.Command} + } + } else if m.Header.Version < 4 { + switch m.Header.Command { + case zapi3IPv4NexthopLookup, zapi3IPv6NexthopLookup, zapi3IPv4ImportLookup: + m.Body = &lookupBody{api: m.Header.Command} + } } } - switch command { - case FRR_ZAPI6_INTERFACE_ADD, FRR_ZAPI6_INTERFACE_DELETE, FRR_ZAPI6_INTERFACE_UP, FRR_ZAPI6_INTERFACE_DOWN: - m.Body = &InterfaceUpdateBody{} - case FRR_ZAPI6_INTERFACE_ADDRESS_ADD, FRR_ZAPI6_INTERFACE_ADDRESS_DELETE: - m.Body = &InterfaceAddressUpdateBody{} - case FRR_ZAPI6_ROUTER_ID_UPDATE: - m.Body = &RouterIDUpdateBody{} - case FRR_ZAPI6_NEXTHOP_UPDATE: - m.Body = &NexthopUpdateBody{} - case FRR_ZAPI6_INTERFACE_NBR_ADDRESS_ADD, FRR_ZAPI6_INTERFACE_NBR_ADDRESS_DELETE: - // TODO - m.Body = &UnknownBody{} - case FRR_ZAPI6_INTERFACE_BFD_DEST_UPDATE: - // TODO - m.Body = &UnknownBody{} - case FRR_ZAPI6_IMPORT_CHECK_UPDATE: - // TODO - m.Body = &UnknownBody{} - case FRR_ZAPI6_BFD_DEST_REPLAY: - // TODO - m.Body = &UnknownBody{} - case FRR_ZAPI6_REDISTRIBUTE_ROUTE_ADD, FRR_ZAPI6_REDISTRIBUTE_ROUTE_DEL: - m.Body = &IPRouteBody{Api: command} - case FRR_ZAPI6_INTERFACE_VRF_UPDATE: - // TODO - m.Body = &UnknownBody{} - case FRR_ZAPI6_INTERFACE_LINK_PARAMS: - // TODO - m.Body = &UnknownBody{} - case FRR_ZAPI6_PW_STATUS_UPDATE: - // TODO - m.Body = &UnknownBody{} - case FRR_ZAPI6_LABEL_MANAGER_CONNECT: - // Note: Synchronous message - m.Body = &LabelManagerConnectBody{} - case FRR_ZAPI6_GET_LABEL_CHUNK: - // Note: Synchronous message - m.Body = &GetLabelChunkBody{} - case FRR_ZAPI6_RELEASE_LABEL_CHUNK: - // Note: Synchronous message - case FRR_ZAPI6_VRF_LABEL: - m.Body = &VrfLabelBody{} - default: - m.Body = &UnknownBody{} - } - return m.Body.DecodeFromBytes(data, m.Header.Version, software) -} - -func ParseMessage(hdr *Header, data []byte, software string) (m *Message, err error) { - m = &Message{Header: *hdr} - if m.Header.Version == 4 { - err = m.parseFrrMessage(data, software) - } else if m.Header.Version == 5 { - err = m.parseFrrZapi5Message(data, software) - } else if m.Header.Version == 6 { - err = m.parseFrrZapi6Message(data, software) - } else { - err = m.parseMessage(data, software) - } - if err != nil { - return nil, err - } - return m, nil -} - -// frr6Zapi6Command adjust command (API_TYPE) between Frr6 Zebra and frr7 Zapi6 -func frr6Zapi6Command(command API_TYPE, softwareName string, from bool) (API_TYPE, error) { - if softwareName != "frr6" { - return command, fmt.Errorf("softwareName %s is not supported", softwareName) - } - // frr6 has ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD (ID:28), frr7 removes it. - // frr7 adds ZEBRA_DUPLICATE_ADDR_DETECTION (ID:72). - if from && FRR_ZAPI6_BFD_DEST_REGISTER < command && command < FRR_ZAPI6_PW_ADD { - // if true, command will be converted from Frr6 Zebra to Frr7 Zapi6 (for parsing) - return command - 1, nil - } else if !from && FRR_ZAPI6_IMPORT_CHECK_UPDATE < command && command < FRR_ZAPI6_DUPLICATE_ADDR_DETECTION { - // if false, command will be converted from Frr7 Zapi6 to Frr6 Zebra (for send) - return command + 1, nil - } - return command, nil -} - -// frr4Zapi5Command adjust command (API_TYPE) between Frr4 Zebra and latest Zapi5 -func frr4Zapi5Command(command API_TYPE, softwareName string, from bool) (API_TYPE, error) { - if softwareName != "frr4" { - return command, fmt.Errorf("softwareName %s is not supported", softwareName) - } - // if from is true, command will be converted from Frr4 Zebra to latest Zapi5 (for parsing) - // if from is false, command will be converted from latest Zapi5 to Frr4 Zebra (for send) - sign := 1 - if !from { - sign = -1 - } - /* - frr5 adds ZEBRA_CAPABILITIES (ID:22), ZEBRA_VRF_LABEL (ID:42), - ZEBRA_LABEL_MANAGER_CONNECT_ASYNC (ID:53), ZEBRA_ADVERTISE_SUBNET (ID:60), - ZEBRA_IP_PREFIX_ROUTE_ADD (ID:70), ZEBRA_IP_PREFIX_ROUTE_DEL (ID:71) and - from ZEBRA_RULE_ADD (ID:79) and ZEBRA_IPTABLE_NOTIFY_OWNER (ID:93) - */ - if FRR_ZAPI5_HELLO < command { // ZEBRA_HELLO: ID:21 in frr4, ID:21 in frr5 - command = API_TYPE(int(command) + sign) - } - if FRR_ZAPI5_VRF_DELETE < command { // ZEBRA_VRF_DELETE: ID:40 in frr4, ID:41 in frr5 - command = API_TYPE(int(command) + sign) - } - // ZEBRA_LABEL_MANAGER_CONNECT : ID:50 in frr4, ID:52 in frr5 - if FRR_ZAPI5_LABEL_MANAGER_CONNECT < command { - command = API_TYPE(int(command) + sign) - } - // ZEBRA_ADVERTISE_DEFAULT_GW : ID:56 in frr4, ID:59 in frr5 - if FRR_ZAPI5_ADVERTISE_DEFAULT_GW < command { - command = API_TYPE(int(command) + sign) - } - // ZEBRA_MACIP_DEL : ID:64 in frr4, ID:69 in frr5 - if FRR_ZAPI5_MACIP_DEL < command { - command = API_TYPE(int(command) + (2 * sign)) - } - // ZBRA_PW_SATUS_UPDATE: ID:72 in frr4, ID:78 in frr5 - if FRR_ZAPI5_PW_STATUS_UPDATE < command { - return command, fmt.Errorf("unsupported command") - } - return command, nil + return m, m.Body.decodeFromBytes(data, m.Header.Version, software) } |