github.com/osrg/gobgp/v3@v3.30.0/pkg/zebra/zapi.go (about)

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