diff options
author | Hitoshi Irino <irino@sfc.wide.ad.jp> | 2018-08-17 19:41:32 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2018-08-18 10:41:20 +0900 |
commit | edbedebf7b048034eeed4bc7f442432d15d549d8 (patch) | |
tree | 9ace882d6b57e1b458fe208cd7e7ef200853adce /internal | |
parent | 75254037d47ca8a6cf86604d8371d5db5db8464d (diff) |
ZAPI5 (FRRouting version 5) support
Diffstat (limited to 'internal')
-rw-r--r-- | internal/pkg/config/default.go | 4 | ||||
-rw-r--r-- | internal/pkg/zebra/afi_string.go | 4 | ||||
-rw-r--r-- | internal/pkg/zebra/api_type_string.go | 8 | ||||
-rw-r--r-- | internal/pkg/zebra/link_type_string.go | 4 | ||||
-rw-r--r-- | internal/pkg/zebra/nexthop_flag_string.go | 38 | ||||
-rw-r--r-- | internal/pkg/zebra/nexthop_type_string.go | 17 | ||||
-rw-r--r-- | internal/pkg/zebra/ptm_enable_string.go | 4 | ||||
-rw-r--r-- | internal/pkg/zebra/ptm_status_string.go | 4 | ||||
-rw-r--r-- | internal/pkg/zebra/route_type_string.go | 8 | ||||
-rw-r--r-- | internal/pkg/zebra/safi_string.go | 4 | ||||
-rw-r--r-- | internal/pkg/zebra/zapi.go | 1623 | ||||
-rw-r--r-- | internal/pkg/zebra/zapi_test.go | 67 |
12 files changed, 1222 insertions, 563 deletions
diff --git a/internal/pkg/config/default.go b/internal/pkg/config/default.go index 6ab1eddc..1f4105c7 100644 --- a/internal/pkg/config/default.go +++ b/internal/pkg/config/default.go @@ -398,8 +398,8 @@ func setDefaultConfigValuesWithViper(v *viper.Viper, b *BgpConfigSet) error { } if b.Zebra.Config.Version < 2 { b.Zebra.Config.Version = 2 - } else if b.Zebra.Config.Version > 4 { - b.Zebra.Config.Version = 4 + } else if b.Zebra.Config.Version > 5 { + b.Zebra.Config.Version = 5 } if !v.IsSet("zebra.config.nexthop-trigger-enable") && !b.Zebra.Config.NexthopTriggerEnable && b.Zebra.Config.Version > 2 { b.Zebra.Config.NexthopTriggerEnable = true diff --git a/internal/pkg/zebra/afi_string.go b/internal/pkg/zebra/afi_string.go index 6c07a09d..6a4278a3 100644 --- a/internal/pkg/zebra/afi_string.go +++ b/internal/pkg/zebra/afi_string.go @@ -2,7 +2,7 @@ package zebra -import "fmt" +import "strconv" const _AFI_name = "AFI_IPAFI_IP6AFI_ETHERAFI_MAX" @@ -11,7 +11,7 @@ var _AFI_index = [...]uint8{0, 6, 13, 22, 29} func (i AFI) String() string { i -= 1 if i >= AFI(len(_AFI_index)-1) { - return fmt.Sprintf("AFI(%d)", i+1) + return "AFI(" + strconv.FormatInt(int64(i+1), 10) + ")" } return _AFI_name[_AFI_index[i]:_AFI_index[i+1]] } diff --git a/internal/pkg/zebra/api_type_string.go b/internal/pkg/zebra/api_type_string.go index e97059b1..3d780850 100644 --- a/internal/pkg/zebra/api_type_string.go +++ b/internal/pkg/zebra/api_type_string.go @@ -2,15 +2,15 @@ package zebra -import "fmt" +import "strconv" -const _API_TYPE_name = "FRR_INTERFACE_ADDINTERFACE_ADDINTERFACE_DELETEINTERFACE_ADDRESS_ADDINTERFACE_ADDRESS_DELETEINTERFACE_UPINTERFACE_DOWNIPV4_ROUTE_ADDIPV4_ROUTE_DELETEIPV6_ROUTE_ADDIPV6_ROUTE_DELETEREDISTRIBUTE_ADDREDISTRIBUTE_DELETEREDISTRIBUTE_DEFAULT_ADDREDISTRIBUTE_DEFAULT_DELETEIPV4_NEXTHOP_LOOKUPIPV6_NEXTHOP_LOOKUPIPV4_IMPORT_LOOKUPIPV6_IMPORT_LOOKUPINTERFACE_RENAMEROUTER_ID_ADDROUTER_ID_DELETEROUTER_ID_UPDATEHELLOIPV4_NEXTHOP_LOOKUP_MRIBVRF_UNREGISTERINTERFACE_LINK_PARAMSNEXTHOP_REGISTERNEXTHOP_UNREGISTERNEXTHOP_UPDATEMESSAGE_MAXFRR_BFD_DEST_REPLAYFRR_REDISTRIBUTE_IPV4_ADDFRR_REDISTRIBUTE_IPV4_DELFRR_REDISTRIBUTE_IPV6_ADDFRR_REDISTRIBUTE_IPV6_DELFRR_VRF_UNREGISTERFRR_VRF_ADDFRR_VRF_DELETEFRR_INTERFACE_VRF_UPDATEFRR_BFD_CLIENT_REGISTERFRR_INTERFACE_ENABLE_RADVFRR_INTERFACE_DISABLE_RADVFRR_IPV4_NEXTHOP_LOOKUP_MRIBFRR_INTERFACE_LINK_PARAMSFRR_MPLS_LABELS_ADDFRR_MPLS_LABELS_DELETEFRR_IPV4_NEXTHOP_ADDFRR_IPV4_NEXTHOP_DELETEFRR_IPV6_NEXTHOP_ADDFRR_IPV6_NEXTHOP_DELETEFRR_IPMR_ROUTE_STATSFRR_LABEL_MANAGER_CONNECTFRR_GET_LABEL_CHUNKFRR_RELEASE_LABEL_CHUNKFRR_PW_ADDFRR_PW_DELETEFRR_PW_SETFRR_PW_UNSETFRR_PW_STATUS_UPDATE" +const _API_TYPE_name = "FRR_ZAPI5_INTERFACE_ADDFRR_ZAPI5_INTERFACE_DELETEFRR_ZAPI5_INTERFACE_ADDRESS_ADDFRR_ZAPI5_INTERFACE_ADDRESS_DELETEFRR_ZAPI5_INTERFACE_UPFRR_ZAPI5_INTERFACE_DOWNFRR_ZAPI5_INTERFACE_SET_MASTERFRR_ZAPI5_ROUTE_ADDFRR_ZAPI5_ROUTE_DELETEFRR_ZAPI5_ROUTE_NOTIFY_OWNERFRR_ZAPI5_IPV4_ROUTE_ADDFRR_ZAPI5_IPV4_ROUTE_DELETEFRR_ZAPI5_IPV6_ROUTE_ADDFRR_ZAPI5_IPV6_ROUTE_DELETEFRR_ZAPI5_REDISTRIBUTE_ADDFRR_ZAPI5_REDISTRIBUTE_DELETEFRR_ZAPI5_REDISTRIBUTE_DEFAULT_ADDFRR_ZAPI5_REDISTRIBUTE_DEFAULT_DELETEFRR_ZAPI5_ROUTER_ID_ADDFRR_ZAPI5_ROUTER_ID_DELETEFRR_ZAPI5_ROUTER_ID_UPDATEFRR_ZAPI5_HELLOFRR_ZAPI5_CAPABILITIESFRR_ZAPI5_NEXTHOP_REGISTERFRR_ZAPI5_NEXTHOP_UNREGISTERFRR_ZAPI5_NEXTHOP_UPDATEFRR_ZAPI5_INTERFACE_NBR_ADDRESS_ADDFRR_ZAPI5_INTERFACE_NBR_ADDRESS_DELETEFRR_ZAPI5_INTERFACE_BFD_DEST_UPDATEFRR_ZAPI5_IMPORT_ROUTE_REGISTERFRR_ZAPI5_IMPORT_ROUTE_UNREGISTERFRR_ZAPI5_IMPORT_CHECK_UPDATEFRR_ZAPI5_IPV4_ROUTE_IPV6_NEXTHOP_ADDFRR_ZAPI5_BFD_DEST_REGISTERFRR_ZAPI5_BFD_DEST_DEREGISTERFRR_ZAPI5_BFD_DEST_UPDATEFRR_ZAPI5_BFD_DEST_REPLAYFRR_ZAPI5_REDISTRIBUTE_ROUTE_ADDFRR_ZAPI5_REDISTRIBUTE_ROUTE_DELFRR_ZAPI5_VRF_UNREGISTERFRR_ZAPI5_VRF_ADDFRR_ZAPI5_VRF_DELETEFRR_ZAPI5_VRF_LABELFRR_ZAPI5_INTERFACE_VRF_UPDATEFRR_ZAPI5_BFD_CLIENT_REGISTERFRR_ZAPI5_INTERFACE_ENABLE_RADVFRR_ZAPI5_INTERFACE_DISABLE_RADVFRR_ZAPI5_IPV4_NEXTHOP_LOOKUP_MRIBFRR_ZAPI5_INTERFACE_LINK_PARAMSFRR_ZAPI5_MPLS_LABELS_ADDFRR_ZAPI5_MPLS_LABELS_DELETEFRR_ZAPI5_IPMR_ROUTE_STATSFRR_ZAPI5_LABEL_MANAGER_CONNECTFRR_ZAPI5_GET_LABEL_CHUNKFRR_ZAPI5_RELEASE_LABEL_CHUNKFRR_ZAPI5_FEC_REGISTERFRR_ZAPI5_FEC_UNREGISTERFRR_ZAPI5_FEC_UPDATEFRR_ZAPI5_ADVERTISE_DEFAULT_GWFRR_ZAPI5_ADVERTISE_SUBNETFRR_ZAPI5_ADVERTISE_ALL_VNIFRR_ZAPI5_VNI_ADDFRR_ZAPI5_VNI_DELFRR_ZAPI5_L3VNI_ADDFRR_ZAPI5_L3VNI_DELFRR_ZAPI5_REMOTE_VTEP_ADDFRR_ZAPI5_REMOTE_VTEP_DELFRR_ZAPI5_MACIP_ADDFRR_ZAPI5_MACIP_DELFRR_ZAPI5_IP_PREFIX_ROUTE_ADDFRR_ZAPI5_IP_PREFIX_ROUTE_DELFRR_ZAPI5_REMOTE_MACIP_ADDFRR_ZAPI5_REMOTE_MACIP_DELFRR_ZAPI5_PW_ADDFRR_ZAPI5_PW_DELETEFRR_ZAPI5_PW_SETFRR_ZAPI5_PW_UNSETFRR_ZAPI5_PW_STATUS_UPDATEFRR_ZAPI5_RULE_ADDFRR_ZAPI5_RULE_DELETEFRR_ZAPI5_RULE_NOTIFY_OWNERFRR_ZAPI5_TABLE_MANAGER_CONNECTFRR_ZAPI5_GET_TABLE_CHUNKFRR_ZAPI5_RELEASE_TABLE_CHUNKFRR_ZAPI5_IPSET_CREATEFRR_ZAPI5_IPSET_DESTROYFRR_ZAPI5_IPSET_ENTRY_ADDFRR_ZAPI5_IPSET_ENTRY_DELETEFRR_ZAPI5_IPSET_NOTIFY_OWNERFRR_ZAPI5_IPSET_ENTRY_NOTIFY_OWNERFRR_ZAPI5_IPTABLE_ADDFRR_ZAPI5_IPTABLE_DELETEFRR_ZAPI5_IPTABLE_NOTIFY_OWNER" -var _API_TYPE_index = [...]uint16{0, 17, 30, 46, 67, 91, 103, 117, 131, 148, 162, 179, 195, 214, 238, 265, 284, 303, 321, 339, 355, 368, 384, 400, 405, 429, 443, 464, 480, 498, 512, 523, 542, 567, 592, 617, 642, 660, 671, 685, 709, 732, 757, 783, 811, 836, 855, 877, 897, 920, 940, 963, 983, 1008, 1027, 1050, 1060, 1073, 1083, 1095, 1115} +var _API_TYPE_index = [...]uint16{0, 23, 49, 80, 114, 136, 160, 190, 209, 231, 259, 283, 310, 334, 361, 387, 416, 450, 487, 510, 536, 562, 577, 599, 625, 653, 677, 712, 750, 785, 816, 849, 878, 915, 942, 971, 996, 1021, 1053, 1085, 1109, 1126, 1146, 1165, 1195, 1224, 1255, 1287, 1321, 1352, 1377, 1405, 1431, 1462, 1487, 1516, 1538, 1562, 1582, 1612, 1638, 1665, 1682, 1699, 1718, 1737, 1762, 1787, 1806, 1825, 1854, 1883, 1909, 1935, 1951, 1970, 1986, 2004, 2030, 2048, 2069, 2096, 2127, 2152, 2181, 2203, 2226, 2251, 2279, 2307, 2341, 2362, 2386, 2416} func (i API_TYPE) String() string { if i >= API_TYPE(len(_API_TYPE_index)-1) { - return fmt.Sprintf("API_TYPE(%d)", i) + return "API_TYPE(" + strconv.FormatInt(int64(i), 10) + ")" } return _API_TYPE_name[_API_TYPE_index[i]:_API_TYPE_index[i+1]] } diff --git a/internal/pkg/zebra/link_type_string.go b/internal/pkg/zebra/link_type_string.go index 9db8544b..f04a24ce 100644 --- a/internal/pkg/zebra/link_type_string.go +++ b/internal/pkg/zebra/link_type_string.go @@ -2,7 +2,7 @@ package zebra -import "fmt" +import "strconv" const _LINK_TYPE_name = "LINK_TYPE_UNKNOWNLINK_TYPE_ETHERLINK_TYPE_EETHERLINK_TYPE_AX25LINK_TYPE_PRONETLINK_TYPE_IEEE802LINK_TYPE_ARCNETLINK_TYPE_APPLETLKLINK_TYPE_DLCILINK_TYPE_ATMLINK_TYPE_METRICOMLINK_TYPE_IEEE1394LINK_TYPE_EUI64LINK_TYPE_INFINIBANDLINK_TYPE_SLIPLINK_TYPE_CSLIPLINK_TYPE_SLIP6LINK_TYPE_CSLIP6LINK_TYPE_RSRVDLINK_TYPE_ADAPTLINK_TYPE_ROSELINK_TYPE_X25LINK_TYPE_PPPLINK_TYPE_CHDLCLINK_TYPE_LAPBLINK_TYPE_RAWHDLCLINK_TYPE_IPIPLINK_TYPE_IPIP6LINK_TYPE_FRADLINK_TYPE_SKIPLINK_TYPE_LOOPBACKLINK_TYPE_LOCALTLKLINK_TYPE_FDDILINK_TYPE_SITLINK_TYPE_IPDDPLINK_TYPE_IPGRELINK_TYPE_IP6GRELINK_TYPE_PIMREGLINK_TYPE_HIPPILINK_TYPE_ECONETLINK_TYPE_IRDALINK_TYPE_FCPPLINK_TYPE_FCALLINK_TYPE_FCPLLINK_TYPE_FCFABRICLINK_TYPE_IEEE802_TRLINK_TYPE_IEEE80211LINK_TYPE_IEEE80211_RADIOTAPLINK_TYPE_IEEE802154LINK_TYPE_IEEE802154_PHY" @@ -10,7 +10,7 @@ var _LINK_TYPE_index = [...]uint16{0, 17, 32, 48, 62, 78, 95, 111, 129, 143, 156 func (i LINK_TYPE) String() string { if i >= LINK_TYPE(len(_LINK_TYPE_index)-1) { - return fmt.Sprintf("LINK_TYPE(%d)", i) + return "LINK_TYPE(" + strconv.FormatInt(int64(i), 10) + ")" } return _LINK_TYPE_name[_LINK_TYPE_index[i]:_LINK_TYPE_index[i+1]] } diff --git a/internal/pkg/zebra/nexthop_flag_string.go b/internal/pkg/zebra/nexthop_flag_string.go index 38f08b8a..1ec9d6ac 100644 --- a/internal/pkg/zebra/nexthop_flag_string.go +++ b/internal/pkg/zebra/nexthop_flag_string.go @@ -2,16 +2,40 @@ package zebra -import "fmt" +import "strconv" -const _NEXTHOP_FLAG_name = "NEXTHOP_IFINDEXNEXTHOP_IFNAMENEXTHOP_IPV4NEXTHOP_IPV4_IFINDEXNEXTHOP_IPV4_IFNAMENEXTHOP_IPV6NEXTHOP_IPV6_IFINDEXNEXTHOP_IPV6_IFNAMENEXTHOP_BLACKHOLE" +const ( + _NEXTHOP_FLAG_name_0 = "NEXTHOP_FLAG_ACTIVENEXTHOP_FLAG_FIB" + _NEXTHOP_FLAG_name_1 = "NEXTHOP_FLAG_RECURSIVE" + _NEXTHOP_FLAG_name_2 = "NEXTHOP_FLAG_ONLINK" + _NEXTHOP_FLAG_name_3 = "NEXTHOP_FLAG_MATCHED" + _NEXTHOP_FLAG_name_4 = "NEXTHOP_FLAG_FILTERED" + _NEXTHOP_FLAG_name_5 = "NEXTHOP_FLAG_DUPLICATE" + _NEXTHOP_FLAG_name_6 = "NEXTHOP_FLAG_EVPN_RVTEP" +) -var _NEXTHOP_FLAG_index = [...]uint8{0, 15, 29, 41, 61, 80, 92, 112, 131, 148} +var ( + _NEXTHOP_FLAG_index_0 = [...]uint8{0, 19, 35} +) func (i NEXTHOP_FLAG) String() string { - i -= 1 - if i >= NEXTHOP_FLAG(len(_NEXTHOP_FLAG_index)-1) { - return fmt.Sprintf("NEXTHOP_FLAG(%d)", i+1) + switch { + case 1 <= i && i <= 2: + i -= 1 + return _NEXTHOP_FLAG_name_0[_NEXTHOP_FLAG_index_0[i]:_NEXTHOP_FLAG_index_0[i+1]] + case i == 4: + return _NEXTHOP_FLAG_name_1 + case i == 8: + return _NEXTHOP_FLAG_name_2 + case i == 16: + return _NEXTHOP_FLAG_name_3 + case i == 32: + return _NEXTHOP_FLAG_name_4 + case i == 64: + return _NEXTHOP_FLAG_name_5 + case i == 128: + return _NEXTHOP_FLAG_name_6 + default: + return "NEXTHOP_FLAG(" + strconv.FormatInt(int64(i), 10) + ")" } - return _NEXTHOP_FLAG_name[_NEXTHOP_FLAG_index[i]:_NEXTHOP_FLAG_index[i+1]] } diff --git a/internal/pkg/zebra/nexthop_type_string.go b/internal/pkg/zebra/nexthop_type_string.go new file mode 100644 index 00000000..adfc73f8 --- /dev/null +++ b/internal/pkg/zebra/nexthop_type_string.go @@ -0,0 +1,17 @@ +// Code generated by "stringer -type=NEXTHOP_TYPE"; DO NOT EDIT. + +package zebra + +import "strconv" + +const _NEXTHOP_TYPE_name = "FRR_NEXTHOP_TYPE_IFINDEXFRR_NEXTHOP_TYPE_IPV4FRR_NEXTHOP_TYPE_IPV4_IFINDEXFRR_NEXTHOP_TYPE_IPV6FRR_NEXTHOP_TYPE_IPV6_IFINDEXFRR_NEXTHOP_TYPE_BLACKHOLENEXTHOP_TYPE_IPV6_IFINDEXNEXTHOP_TYPE_IPV6_IFNAMENEXTHOP_TYPE_BLACKHOLE" + +var _NEXTHOP_TYPE_index = [...]uint8{0, 24, 45, 74, 95, 124, 150, 175, 199, 221} + +func (i NEXTHOP_TYPE) String() string { + i -= 1 + if i >= NEXTHOP_TYPE(len(_NEXTHOP_TYPE_index)-1) { + return "NEXTHOP_TYPE(" + strconv.FormatInt(int64(i+1), 10) + ")" + } + return _NEXTHOP_TYPE_name[_NEXTHOP_TYPE_index[i]:_NEXTHOP_TYPE_index[i+1]] +} diff --git a/internal/pkg/zebra/ptm_enable_string.go b/internal/pkg/zebra/ptm_enable_string.go index d750542e..e9d829fa 100644 --- a/internal/pkg/zebra/ptm_enable_string.go +++ b/internal/pkg/zebra/ptm_enable_string.go @@ -2,7 +2,7 @@ package zebra -import "fmt" +import "strconv" const _PTM_ENABLE_name = "PTM_ENABLE_OFFPTM_ENABLE_ONPTM_ENABLE_UNSPEC" @@ -10,7 +10,7 @@ var _PTM_ENABLE_index = [...]uint8{0, 14, 27, 44} func (i PTM_ENABLE) String() string { if i >= PTM_ENABLE(len(_PTM_ENABLE_index)-1) { - return fmt.Sprintf("PTM_ENABLE(%d)", i) + return "PTM_ENABLE(" + strconv.FormatInt(int64(i), 10) + ")" } return _PTM_ENABLE_name[_PTM_ENABLE_index[i]:_PTM_ENABLE_index[i+1]] } diff --git a/internal/pkg/zebra/ptm_status_string.go b/internal/pkg/zebra/ptm_status_string.go index 464233b7..031e7c01 100644 --- a/internal/pkg/zebra/ptm_status_string.go +++ b/internal/pkg/zebra/ptm_status_string.go @@ -2,7 +2,7 @@ package zebra -import "fmt" +import "strconv" const _PTM_STATUS_name = "PTM_STATUS_DOWNPTM_STATUS_UPPTM_STATUS_UNKNOWN" @@ -10,7 +10,7 @@ var _PTM_STATUS_index = [...]uint8{0, 15, 28, 46} func (i PTM_STATUS) String() string { if i >= PTM_STATUS(len(_PTM_STATUS_index)-1) { - return fmt.Sprintf("PTM_STATUS(%d)", i) + return "PTM_STATUS(" + strconv.FormatInt(int64(i), 10) + ")" } return _PTM_STATUS_name[_PTM_STATUS_index[i]:_PTM_STATUS_index[i+1]] } diff --git a/internal/pkg/zebra/route_type_string.go b/internal/pkg/zebra/route_type_string.go index e2ad6c97..47d6f27d 100644 --- a/internal/pkg/zebra/route_type_string.go +++ b/internal/pkg/zebra/route_type_string.go @@ -2,15 +2,15 @@ package zebra -import "fmt" +import "strconv" -const _ROUTE_TYPE_name = "ROUTE_SYSTEMROUTE_KERNELROUTE_CONNECTROUTE_STATICROUTE_RIPROUTE_RIPNGROUTE_OSPFROUTE_OSPF6ROUTE_ISISROUTE_BGPROUTE_PIMROUTE_HSLSROUTE_OLSRROUTE_BABELROUTE_MAXFRR_ROUTE_VNCFRR_ROUTE_VNC_DIRECTFRR_ROUTE_VNC_DIRECT_RHFRR_ROUTE_BGP_DIRECTFRR_ROUTE_BGP_DIRECT_EXTFRR_ROUTE_ALLFRR_ROUTE_MAX" +const _ROUTE_TYPE_name = "FRR_ZAPI5_ROUTE_SYSTEMFRR_ZAPI5_ROUTE_KERNELFRR_ZAPI5_ROUTE_CONNECTFRR_ZAPI5_ROUTE_STATICFRR_ZAPI5_ROUTE_RIPFRR_ZAPI5_ROUTE_RIPNGFRR_ZAPI5_ROUTE_OSPFFRR_ZAPI5_ROUTE_OSPF6FRR_ZAPI5_ROUTE_ISISFRR_ZAPI5_ROUTE_BGPFRR_ZAPI5_ROUTE_PIMFRR_ZAPI5_ROUTE_EIGRPFRR_ZAPI5_ROUTE_NHRPFRR_ZAPI5_ROUTE_HSLSFRR_ZAPI5_ROUTE_OLSRFRR_ZAPI5_ROUTE_TABLEFRR_ZAPI5_ROUTE_LDPFRR_ZAPI5_ROUTE_VNCFRR_ZAPI5_ROUTE_VNC_DIRECTFRR_ZAPI5_ROUTE_VNC_DIRECT_RHFRR_ZAPI5_ROUTE_BGP_DIRECTFRR_ZAPI5_ROUTE_BGP_DIRECT_EXTFRR_ZAPI5_ROUTE_BABELFRR_ZAPI5_ROUTE_SHARPFRR_ZAPI5_ROUTE_PBRFRR_ZAPI5_ROUTE_ALLFRR_ZAPI5_ROUTE_MAX" -var _ROUTE_TYPE_index = [...]uint16{0, 12, 24, 37, 49, 58, 69, 79, 90, 100, 109, 118, 128, 138, 149, 158, 171, 191, 214, 234, 258, 271, 284} +var _ROUTE_TYPE_index = [...]uint16{0, 22, 44, 67, 89, 108, 129, 149, 170, 190, 209, 228, 249, 269, 289, 309, 330, 349, 368, 394, 423, 449, 479, 500, 521, 540, 559, 578} func (i ROUTE_TYPE) String() string { if i >= ROUTE_TYPE(len(_ROUTE_TYPE_index)-1) { - return fmt.Sprintf("ROUTE_TYPE(%d)", i) + return "ROUTE_TYPE(" + strconv.FormatInt(int64(i), 10) + ")" } return _ROUTE_TYPE_name[_ROUTE_TYPE_index[i]:_ROUTE_TYPE_index[i+1]] } diff --git a/internal/pkg/zebra/safi_string.go b/internal/pkg/zebra/safi_string.go index ab491cb6..8199a0e3 100644 --- a/internal/pkg/zebra/safi_string.go +++ b/internal/pkg/zebra/safi_string.go @@ -2,7 +2,7 @@ package zebra -import "fmt" +import "strconv" const _SAFI_name = "SAFI_UNICASTSAFI_MULTICASTSAFI_RESERVED_3SAFI_MPLS_VPNSAFI_MAX" @@ -11,7 +11,7 @@ var _SAFI_index = [...]uint8{0, 12, 26, 41, 54, 62} func (i SAFI) String() string { i -= 1 if i >= SAFI(len(_SAFI_index)-1) { - return fmt.Sprintf("SAFI(%d)", i+1) + return "SAFI(" + strconv.FormatInt(int64(i+1), 10) + ")" } return _SAFI_name[_SAFI_index[i]:_SAFI_index[i+1]] } diff --git a/internal/pkg/zebra/zapi.go b/internal/pkg/zebra/zapi.go index eb443d05..9d658f1a 100644 --- a/internal/pkg/zebra/zapi.go +++ b/internal/pkg/zebra/zapi.go @@ -19,6 +19,7 @@ import ( "encoding/binary" "fmt" "io" + "math" "net" "strings" "syscall" @@ -102,11 +103,15 @@ const ( ) const VRF_DEFAULT = 0 +const MAXPATH_NUM = 64 +const MPLS_MAX_LABLE = 16 func HeaderSize(version uint8) uint16 { switch version { case 3, 4: return 8 + case 5: + return 10 default: return 6 } @@ -180,39 +185,101 @@ const ( //go:generate stringer -type=API_TYPE type API_TYPE uint16 -// For Quagga. +// For FRRouting version 4 and 5. (ZAPI version 5) const ( - _ API_TYPE = iota - INTERFACE_ADD - INTERFACE_DELETE - INTERFACE_ADDRESS_ADD - INTERFACE_ADDRESS_DELETE - INTERFACE_UP - INTERFACE_DOWN - IPV4_ROUTE_ADD - IPV4_ROUTE_DELETE - IPV6_ROUTE_ADD - IPV6_ROUTE_DELETE - REDISTRIBUTE_ADD - REDISTRIBUTE_DELETE - REDISTRIBUTE_DEFAULT_ADD - REDISTRIBUTE_DEFAULT_DELETE - IPV4_NEXTHOP_LOOKUP - IPV6_NEXTHOP_LOOKUP - IPV4_IMPORT_LOOKUP - IPV6_IMPORT_LOOKUP - INTERFACE_RENAME - ROUTER_ID_ADD - ROUTER_ID_DELETE - ROUTER_ID_UPDATE - HELLO - IPV4_NEXTHOP_LOOKUP_MRIB - VRF_UNREGISTER - INTERFACE_LINK_PARAMS - NEXTHOP_REGISTER - NEXTHOP_UNREGISTER - NEXTHOP_UPDATE - MESSAGE_MAX + FRR_ZAPI5_INTERFACE_ADD API_TYPE = iota + FRR_ZAPI5_INTERFACE_DELETE + FRR_ZAPI5_INTERFACE_ADDRESS_ADD + FRR_ZAPI5_INTERFACE_ADDRESS_DELETE + FRR_ZAPI5_INTERFACE_UP + FRR_ZAPI5_INTERFACE_DOWN + FRR_ZAPI5_INTERFACE_SET_MASTER + FRR_ZAPI5_ROUTE_ADD + FRR_ZAPI5_ROUTE_DELETE + FRR_ZAPI5_ROUTE_NOTIFY_OWNER + FRR_ZAPI5_IPV4_ROUTE_ADD + FRR_ZAPI5_IPV4_ROUTE_DELETE + FRR_ZAPI5_IPV6_ROUTE_ADD + FRR_ZAPI5_IPV6_ROUTE_DELETE + FRR_ZAPI5_REDISTRIBUTE_ADD + FRR_ZAPI5_REDISTRIBUTE_DELETE + FRR_ZAPI5_REDISTRIBUTE_DEFAULT_ADD + FRR_ZAPI5_REDISTRIBUTE_DEFAULT_DELETE + FRR_ZAPI5_ROUTER_ID_ADD + FRR_ZAPI5_ROUTER_ID_DELETE + FRR_ZAPI5_ROUTER_ID_UPDATE + FRR_ZAPI5_HELLO + FRR_ZAPI5_CAPABILITIES + FRR_ZAPI5_NEXTHOP_REGISTER + FRR_ZAPI5_NEXTHOP_UNREGISTER + FRR_ZAPI5_NEXTHOP_UPDATE + FRR_ZAPI5_INTERFACE_NBR_ADDRESS_ADD + FRR_ZAPI5_INTERFACE_NBR_ADDRESS_DELETE + FRR_ZAPI5_INTERFACE_BFD_DEST_UPDATE + FRR_ZAPI5_IMPORT_ROUTE_REGISTER + FRR_ZAPI5_IMPORT_ROUTE_UNREGISTER + FRR_ZAPI5_IMPORT_CHECK_UPDATE + FRR_ZAPI5_IPV4_ROUTE_IPV6_NEXTHOP_ADD + FRR_ZAPI5_BFD_DEST_REGISTER + FRR_ZAPI5_BFD_DEST_DEREGISTER + FRR_ZAPI5_BFD_DEST_UPDATE + FRR_ZAPI5_BFD_DEST_REPLAY + FRR_ZAPI5_REDISTRIBUTE_ROUTE_ADD + FRR_ZAPI5_REDISTRIBUTE_ROUTE_DEL + FRR_ZAPI5_VRF_UNREGISTER + FRR_ZAPI5_VRF_ADD + FRR_ZAPI5_VRF_DELETE + FRR_ZAPI5_VRF_LABEL + FRR_ZAPI5_INTERFACE_VRF_UPDATE + FRR_ZAPI5_BFD_CLIENT_REGISTER + FRR_ZAPI5_INTERFACE_ENABLE_RADV + FRR_ZAPI5_INTERFACE_DISABLE_RADV + FRR_ZAPI5_IPV4_NEXTHOP_LOOKUP_MRIB + FRR_ZAPI5_INTERFACE_LINK_PARAMS + FRR_ZAPI5_MPLS_LABELS_ADD + FRR_ZAPI5_MPLS_LABELS_DELETE + FRR_ZAPI5_IPMR_ROUTE_STATS + FRR_ZAPI5_LABEL_MANAGER_CONNECT + FRR_ZAPI5_GET_LABEL_CHUNK + FRR_ZAPI5_RELEASE_LABEL_CHUNK + FRR_ZAPI5_FEC_REGISTER + FRR_ZAPI5_FEC_UNREGISTER + FRR_ZAPI5_FEC_UPDATE + FRR_ZAPI5_ADVERTISE_DEFAULT_GW + FRR_ZAPI5_ADVERTISE_SUBNET + FRR_ZAPI5_ADVERTISE_ALL_VNI + FRR_ZAPI5_VNI_ADD + FRR_ZAPI5_VNI_DEL + FRR_ZAPI5_L3VNI_ADD + FRR_ZAPI5_L3VNI_DEL + FRR_ZAPI5_REMOTE_VTEP_ADD + FRR_ZAPI5_REMOTE_VTEP_DEL + FRR_ZAPI5_MACIP_ADD + FRR_ZAPI5_MACIP_DEL + FRR_ZAPI5_IP_PREFIX_ROUTE_ADD + FRR_ZAPI5_IP_PREFIX_ROUTE_DEL + FRR_ZAPI5_REMOTE_MACIP_ADD + FRR_ZAPI5_REMOTE_MACIP_DEL + FRR_ZAPI5_PW_ADD + FRR_ZAPI5_PW_DELETE + FRR_ZAPI5_PW_SET + FRR_ZAPI5_PW_UNSET + FRR_ZAPI5_PW_STATUS_UPDATE + FRR_ZAPI5_RULE_ADD + FRR_ZAPI5_RULE_DELETE + FRR_ZAPI5_RULE_NOTIFY_OWNER + FRR_ZAPI5_TABLE_MANAGER_CONNECT + FRR_ZAPI5_GET_TABLE_CHUNK + FRR_ZAPI5_RELEASE_TABLE_CHUNK + FRR_ZAPI5_IPSET_CREATE + FRR_ZAPI5_IPSET_DESTROY + FRR_ZAPI5_IPSET_ENTRY_ADD + FRR_ZAPI5_IPSET_ENTRY_DELETE + FRR_ZAPI5_IPSET_NOTIFY_OWNER + FRR_ZAPI5_IPSET_ENTRY_NOTIFY_OWNER + FRR_ZAPI5_IPTABLE_ADD + FRR_ZAPI5_IPTABLE_DELETE + FRR_ZAPI5_IPTABLE_NOTIFY_OWNER ) // For FRRouting. @@ -279,27 +346,74 @@ const ( FRR_PW_STATUS_UPDATE ) +// For Quagga. +const ( + _ API_TYPE = iota + INTERFACE_ADD + INTERFACE_DELETE + INTERFACE_ADDRESS_ADD + INTERFACE_ADDRESS_DELETE + INTERFACE_UP + INTERFACE_DOWN + IPV4_ROUTE_ADD + IPV4_ROUTE_DELETE + IPV6_ROUTE_ADD + IPV6_ROUTE_DELETE + REDISTRIBUTE_ADD + REDISTRIBUTE_DELETE + REDISTRIBUTE_DEFAULT_ADD + REDISTRIBUTE_DEFAULT_DELETE + IPV4_NEXTHOP_LOOKUP + IPV6_NEXTHOP_LOOKUP + IPV4_IMPORT_LOOKUP + IPV6_IMPORT_LOOKUP + INTERFACE_RENAME + ROUTER_ID_ADD + ROUTER_ID_DELETE + ROUTER_ID_UPDATE + HELLO + IPV4_NEXTHOP_LOOKUP_MRIB + VRF_UNREGISTER + INTERFACE_LINK_PARAMS + NEXTHOP_REGISTER + NEXTHOP_UNREGISTER + NEXTHOP_UPDATE + MESSAGE_MAX +) + // Route Types. //go:generate stringer -type=ROUTE_TYPE type ROUTE_TYPE uint8 -// For Quagga. +// For FRRouting version 4 and 5 (ZAPI version 5). const ( - ROUTE_SYSTEM ROUTE_TYPE = iota - ROUTE_KERNEL - ROUTE_CONNECT - ROUTE_STATIC - ROUTE_RIP - ROUTE_RIPNG - ROUTE_OSPF - ROUTE_OSPF6 - ROUTE_ISIS - ROUTE_BGP - ROUTE_PIM - ROUTE_HSLS - ROUTE_OLSR - ROUTE_BABEL - ROUTE_MAX + FRR_ZAPI5_ROUTE_SYSTEM ROUTE_TYPE = iota + FRR_ZAPI5_ROUTE_KERNEL + FRR_ZAPI5_ROUTE_CONNECT + FRR_ZAPI5_ROUTE_STATIC + FRR_ZAPI5_ROUTE_RIP + FRR_ZAPI5_ROUTE_RIPNG + FRR_ZAPI5_ROUTE_OSPF + FRR_ZAPI5_ROUTE_OSPF6 + FRR_ZAPI5_ROUTE_ISIS + FRR_ZAPI5_ROUTE_BGP + FRR_ZAPI5_ROUTE_PIM + FRR_ZAPI5_ROUTE_EIGRP + FRR_ZAPI5_ROUTE_NHRP + FRR_ZAPI5_ROUTE_HSLS + FRR_ZAPI5_ROUTE_OLSR + FRR_ZAPI5_ROUTE_TABLE + FRR_ZAPI5_ROUTE_LDP + FRR_ZAPI5_ROUTE_VNC + FRR_ZAPI5_ROUTE_VNC_DIRECT + FRR_ZAPI5_ROUTE_VNC_DIRECT_RH + FRR_ZAPI5_ROUTE_BGP_DIRECT + FRR_ZAPI5_ROUTE_BGP_DIRECT_EXT + FRR_ZAPI5_ROUTE_BABEL + FRR_ZAPI5_ROUTE_SHARP + FRR_ZAPI5_ROUTE_PBR + FRR_ZAPI5_ROUTE_ALL + FRR_ZAPI5_ROUTE_MAX ) // For FRRouting. @@ -328,10 +442,84 @@ const ( FRR_ROUTE_MAX ) +// For Quagga. +const ( + ROUTE_SYSTEM ROUTE_TYPE = iota + ROUTE_KERNEL + ROUTE_CONNECT + ROUTE_STATIC + ROUTE_RIP + ROUTE_RIPNG + ROUTE_OSPF + ROUTE_OSPF6 + ROUTE_ISIS + ROUTE_BGP + ROUTE_PIM + ROUTE_HSLS + ROUTE_OLSR + ROUTE_BABEL + ROUTE_MAX +) + +var routeTypeValueMapFrrZapi5 = map[string]ROUTE_TYPE{ + "system": FRR_ZAPI5_ROUTE_SYSTEM, + "kernel": FRR_ZAPI5_ROUTE_KERNEL, + "connect": FRR_ZAPI5_ROUTE_CONNECT, // hack for backward compatibility + "directly-connected": FRR_ZAPI5_ROUTE_CONNECT, + "static": FRR_ZAPI5_ROUTE_STATIC, + "rip": FRR_ZAPI5_ROUTE_RIP, + "ripng": FRR_ZAPI5_ROUTE_RIPNG, + "ospf": FRR_ZAPI5_ROUTE_OSPF, + "ospf3": FRR_ZAPI5_ROUTE_OSPF6, + "isis": FRR_ZAPI5_ROUTE_ISIS, + "bgp": FRR_ZAPI5_ROUTE_BGP, + "pim": FRR_ZAPI5_ROUTE_PIM, + "eigrp": FRR_ZAPI5_ROUTE_EIGRP, + "nhrp": FRR_ZAPI5_ROUTE_EIGRP, + "hsls": FRR_ZAPI5_ROUTE_HSLS, + "olsr": FRR_ZAPI5_ROUTE_OLSR, + "table": FRR_ZAPI5_ROUTE_TABLE, + "ldp": FRR_ZAPI5_ROUTE_LDP, + "vnc": FRR_ZAPI5_ROUTE_VNC, + "vnc-direct": FRR_ZAPI5_ROUTE_VNC_DIRECT, + "vnc-direct-rh": FRR_ZAPI5_ROUTE_VNC_DIRECT_RH, + "bgp-direct": FRR_ZAPI5_ROUTE_BGP_DIRECT, + "bgp-direct-ext": FRR_ZAPI5_ROUTE_BGP_DIRECT_EXT, + "babel": FRR_ZAPI5_ROUTE_BABEL, + "sharp": FRR_ZAPI5_ROUTE_SHARP, + "pbr": FRR_ZAPI5_ROUTE_PBR, + "all": FRR_ZAPI5_ROUTE_ALL, +} + +var routeTypeValueMapFrr = map[string]ROUTE_TYPE{ + "system": FRR_ROUTE_SYSTEM, + "kernel": FRR_ROUTE_KERNEL, + "connect": FRR_ROUTE_CONNECT, // hack for backward compatibility + "directly-connected": FRR_ROUTE_CONNECT, + "static": FRR_ROUTE_STATIC, + "rip": FRR_ROUTE_RIP, + "ripng": FRR_ROUTE_RIPNG, + "ospf": FRR_ROUTE_OSPF, + "ospf3": FRR_ROUTE_OSPF6, + "isis": FRR_ROUTE_ISIS, + "bgp": FRR_ROUTE_BGP, + "pim": FRR_ROUTE_PIM, + "hsls": FRR_ROUTE_HSLS, + "olsr": FRR_ROUTE_OLSR, + "table": FRR_ROUTE_TABLE, + "ldp": FRR_ROUTE_LDP, + "vnc": FRR_ROUTE_VNC, + "vnc-direct": FRR_ROUTE_VNC_DIRECT, + "vnc-direct-rh": FRR_ROUTE_VNC_DIRECT_RH, + "bgp-direct": FRR_ROUTE_BGP_DIRECT, + "bgp-direct-ext": FRR_ROUTE_BGP_DIRECT_EXT, + "all": FRR_ROUTE_ALL, +} + var routeTypeValueMap = map[string]ROUTE_TYPE{ "system": ROUTE_SYSTEM, "kernel": ROUTE_KERNEL, - "connect": ROUTE_CONNECT, // hack for backyard compatibility + "connect": ROUTE_CONNECT, // hack for backward compatibility "directly-connected": ROUTE_CONNECT, "static": ROUTE_STATIC, "rip": ROUTE_RIP, @@ -344,27 +532,93 @@ var routeTypeValueMap = map[string]ROUTE_TYPE{ "hsls": ROUTE_HSLS, "olsr": ROUTE_OLSR, "babel": ROUTE_BABEL, - "table": FRR_ROUTE_TABLE, - "ldp": FRR_ROUTE_LDP, - "vnc": FRR_ROUTE_VNC, - "vnc-direct": FRR_ROUTE_VNC_DIRECT, - "vnc-direct-rh": FRR_ROUTE_VNC_DIRECT_RH, - "bgp-direct": FRR_ROUTE_BGP_DIRECT, - "bgp-direct-ext": FRR_ROUTE_BGP_DIRECT_EXT, - "all": FRR_ROUTE_ALL, } -func RouteTypeFromString(typ string) (ROUTE_TYPE, error) { - t, ok := routeTypeValueMap[typ] +func RouteTypeFromString(typ string, version uint8) (ROUTE_TYPE, error) { + delegateRouteTypeValueMap := routeTypeValueMap + if version == 4 { + delegateRouteTypeValueMap = routeTypeValueMapFrr + } else if version >= 5 { + delegateRouteTypeValueMap = routeTypeValueMapFrrZapi5 + } + t, ok := delegateRouteTypeValueMap[typ] if ok { return t, nil } return t, fmt.Errorf("unknown route type: %s", typ) } +func addressFamilyFromApi(Api API_TYPE, version uint8) uint8 { + if version <= 3 { + switch Api { + case IPV4_ROUTE_ADD, IPV4_ROUTE_DELETE, IPV4_NEXTHOP_LOOKUP, IPV4_IMPORT_LOOKUP: + return syscall.AF_INET + case IPV6_ROUTE_ADD, IPV6_ROUTE_DELETE, IPV6_NEXTHOP_LOOKUP, IPV6_IMPORT_LOOKUP: + return syscall.AF_INET6 + } + } else if version == 4 { + switch Api { + case FRR_REDISTRIBUTE_IPV4_ADD, FRR_REDISTRIBUTE_IPV4_DEL, FRR_IPV4_ROUTE_ADD, FRR_IPV4_ROUTE_DELETE, FRR_IPV4_NEXTHOP_LOOKUP_MRIB: + return syscall.AF_INET + case FRR_REDISTRIBUTE_IPV6_ADD, FRR_REDISTRIBUTE_IPV6_DEL, FRR_IPV6_ROUTE_ADD, FRR_IPV6_ROUTE_DELETE: + return syscall.AF_INET6 + } + } else if version == 5 { + switch Api { + case FRR_ZAPI5_IPV4_ROUTE_ADD, FRR_ZAPI5_IPV4_ROUTE_DELETE, FRR_ZAPI5_IPV4_NEXTHOP_LOOKUP_MRIB: + return syscall.AF_INET + case FRR_ZAPI5_IPV6_ROUTE_ADD, FRR_ZAPI5_IPV6_ROUTE_DELETE: + return syscall.AF_INET6 + } + } + return syscall.AF_UNSPEC +} + +func addressByteLength(family uint8) (int, error) { + switch family { + case syscall.AF_INET: + return net.IPv4len, nil + case syscall.AF_INET6: + return net.IPv6len, nil + } + return 0, fmt.Errorf("unknown address family: %d", family) +} + +func ipFromFamily(family uint8, buf []byte) net.IP { + switch family { + case syscall.AF_INET: + return net.IP(buf).To4() + case syscall.AF_INET6: + return net.IP(buf).To16() + } + return nil +} + // API Message Flags. type MESSAGE_FLAG uint8 +// For FRRouting version 4 and 5 (ZAPI version 5). +const ( + FRR_ZAPI5_MESSAGE_NEXTHOP MESSAGE_FLAG = 0x01 + FRR_ZAPI5_MESSAGE_DISTANCE MESSAGE_FLAG = 0x02 + FRR_ZAPI5_MESSAGE_METRIC MESSAGE_FLAG = 0x04 + FRR_ZAPI5_MESSAGE_TAG MESSAGE_FLAG = 0x08 + FRR_ZAPI5_MESSAGE_MTU MESSAGE_FLAG = 0x10 + FRR_ZAPI5_MESSAGE_SRCPFX MESSAGE_FLAG = 0x20 + FRR_ZAPI5_MESSAGE_LABEL MESSAGE_FLAG = 0x40 +) + +// For FRRouting. +const ( + FRR_MESSAGE_NEXTHOP MESSAGE_FLAG = 0x01 + FRR_MESSAGE_IFINDEX MESSAGE_FLAG = 0x02 + FRR_MESSAGE_DISTANCE MESSAGE_FLAG = 0x04 + FRR_MESSAGE_METRIC MESSAGE_FLAG = 0x08 + FRR_MESSAGE_TAG MESSAGE_FLAG = 0x10 + FRR_MESSAGE_MTU MESSAGE_FLAG = 0x20 + FRR_MESSAGE_SRCPFX MESSAGE_FLAG = 0x40 +) + // For Quagga. const ( MESSAGE_NEXTHOP MESSAGE_FLAG = 0x01 @@ -375,40 +629,45 @@ const ( MESSAGE_TAG MESSAGE_FLAG = 0x20 ) -func (t MESSAGE_FLAG) String() string { +func (t MESSAGE_FLAG) String(version uint8) string { var ss []string - if t&MESSAGE_NEXTHOP > 0 { + if (version <= 3 && t&MESSAGE_NEXTHOP > 0) || + (version == 4 && t&FRR_MESSAGE_NEXTHOP > 0) || + (version == 5 && t&FRR_ZAPI5_MESSAGE_NEXTHOP > 0) { ss = append(ss, "NEXTHOP") } - if t&MESSAGE_IFINDEX > 0 { + if (version <= 3 && t&MESSAGE_IFINDEX > 0) || (version == 4 && t&FRR_MESSAGE_IFINDEX > 0) { ss = append(ss, "IFINDEX") } - if t&MESSAGE_DISTANCE > 0 { + if (version <= 3 && t&MESSAGE_DISTANCE > 0) || + (version == 4 && t&FRR_MESSAGE_DISTANCE > 0) || + (version == 5 && t&FRR_ZAPI5_MESSAGE_DISTANCE > 0) { ss = append(ss, "DISTANCE") } - if t&MESSAGE_METRIC > 0 { + if (version <= 3 && t&MESSAGE_METRIC > 0) || + (version == 4 && t&FRR_MESSAGE_METRIC > 0) || + (version == 5 && t&FRR_ZAPI5_MESSAGE_METRIC > 0) { ss = append(ss, "METRIC") } - if t&MESSAGE_MTU > 0 { + if (version <= 3 && t&MESSAGE_MTU > 0) || (version == 4 && t&FRR_MESSAGE_MTU > 0) || + (version == 5 && t&FRR_ZAPI5_MESSAGE_MTU > 0) { ss = append(ss, "MTU") } - if t&MESSAGE_TAG > 0 { + if (version <= 3 && t&MESSAGE_TAG > 0) || (version == 4 && t&FRR_MESSAGE_TAG > 0) || + (version == 5 && t&FRR_ZAPI5_MESSAGE_TAG > 0) { ss = append(ss, "TAG") } + if (version == 4 && t&FRR_MESSAGE_SRCPFX > 0) || + (version == 5 && t&FRR_ZAPI5_MESSAGE_SRCPFX > 0) { + ss = append(ss, "SRCPFX") + } + if version == 5 && t&FRR_ZAPI5_MESSAGE_LABEL > 0 { + ss = append(ss, "LABLE") + } + return strings.Join(ss, "|") } -// For FRRouting. -const ( - FRR_MESSAGE_NEXTHOP MESSAGE_FLAG = 0x01 - FRR_MESSAGE_IFINDEX MESSAGE_FLAG = 0x02 - FRR_MESSAGE_DISTANCE MESSAGE_FLAG = 0x04 - FRR_MESSAGE_METRIC MESSAGE_FLAG = 0x08 - FRR_MESSAGE_TAG MESSAGE_FLAG = 0x10 - FRR_MESSAGE_MTU MESSAGE_FLAG = 0x20 - FRR_MESSAGE_SRCPFX MESSAGE_FLAG = 0x40 -) - // Message Flags type FLAG uint64 @@ -423,6 +682,7 @@ const ( FLAG_REJECT FLAG = 0x80 FLAG_SCOPE_LINK FLAG = 0x100 FLAG_FIB_OVERRIDE FLAG = 0x200 + FLAG_EVPN_ROUTE FLAG = 0x400 ) func (t FLAG) String() string { @@ -457,36 +717,55 @@ func (t FLAG) String() string { if t&FLAG_FIB_OVERRIDE > 0 { ss = append(ss, "FLAG_FIB_OVERRIDE") } + if t&FLAG_EVPN_ROUTE > 0 { + ss = append(ss, "FLAG_EVPN_ROUTE") + } + return strings.Join(ss, "|") } -// Nexthop Flags. -//go:generate stringer -type=NEXTHOP_FLAG -type NEXTHOP_FLAG uint8 +// Nexthop Types. +//go:generate stringer -type=NEXTHOP_TYPE +type NEXTHOP_TYPE uint8 + +// For FRRouting. +const ( + _ NEXTHOP_TYPE = iota + FRR_NEXTHOP_TYPE_IFINDEX + FRR_NEXTHOP_TYPE_IPV4 + FRR_NEXTHOP_TYPE_IPV4_IFINDEX + FRR_NEXTHOP_TYPE_IPV6 + FRR_NEXTHOP_TYPE_IPV6_IFINDEX + FRR_NEXTHOP_TYPE_BLACKHOLE +) // For Quagga. const ( - _ NEXTHOP_FLAG = iota - NEXTHOP_IFINDEX - NEXTHOP_IFNAME - NEXTHOP_IPV4 - NEXTHOP_IPV4_IFINDEX - NEXTHOP_IPV4_IFNAME - NEXTHOP_IPV6 - NEXTHOP_IPV6_IFINDEX - NEXTHOP_IPV6_IFNAME - NEXTHOP_BLACKHOLE + _ NEXTHOP_TYPE = iota + NEXTHOP_TYPE_IFINDEX + NEXTHOP_TYPE_IFNAME + NEXTHOP_TYPE_IPV4 + NEXTHOP_TYPE_IPV4_IFINDEX + NEXTHOP_TYPE_IPV4_IFNAME + NEXTHOP_TYPE_IPV6 + NEXTHOP_TYPE_IPV6_IFINDEX + NEXTHOP_TYPE_IPV6_IFNAME + NEXTHOP_TYPE_BLACKHOLE ) -// For FRRouting. +// Nexthop Flags. +//go:generate stringer -type=NEXTHOP_FLAG +type NEXTHOP_FLAG uint8 + const ( - _ NEXTHOP_FLAG = iota - FRR_NEXTHOP_IFINDEX - FRR_NEXTHOP_IPV4 - FRR_NEXTHOP_IPV4_IFINDEX - FRR_NEXTHOP_IPV6 - FRR_NEXTHOP_IPV6_IFINDEX - FRR_NEXTHOP_BLACKHOLE + NEXTHOP_FLAG_ACTIVE NEXTHOP_FLAG = 0x01 // This nexthop is alive. + NEXTHOP_FLAG_FIB NEXTHOP_FLAG = 0x02 // FIB nexthop. + NEXTHOP_FLAG_RECURSIVE NEXTHOP_FLAG = 0x04 // Recursive nexthop. + NEXTHOP_FLAG_ONLINK NEXTHOP_FLAG = 0x08 // Nexthop should be installed onlink. + NEXTHOP_FLAG_MATCHED NEXTHOP_FLAG = 0x10 // Already matched vs a nexthop + NEXTHOP_FLAG_FILTERED NEXTHOP_FLAG = 0x20 // rmap filtered (version >= 4) + NEXTHOP_FLAG_DUPLICATE NEXTHOP_FLAG = 0x40 // nexthop duplicates (version >= 5) + NEXTHOP_FLAG_EVPN_RVTEP NEXTHOP_FLAG = 0x80 // EVPN remote vtep nexthop (version >= 5) ) // Interface PTM Enable Configuration. @@ -526,8 +805,8 @@ func NewClient(network, address string, typ ROUTE_TYPE, version uint8) (*Client, incoming := make(chan *Message, 64) if version < 2 { version = 2 - } else if version > 4 { - version = 4 + } else if version > 5 { + version = 5 } c := &Client{ @@ -670,7 +949,7 @@ func (c *Client) Send(m *Message) { c.outgoing <- m } -func (c *Client) SendCommand(command API_TYPE, vrfId uint16, body Body) error { +func (c *Client) SendCommand(command API_TYPE, vrfId uint32, body Body) error { var marker uint8 = HEADER_MARKER if c.Version >= 4 { marker = FRR_HEADER_MARKER @@ -692,13 +971,15 @@ func (c *Client) SendCommand(command API_TYPE, vrfId uint16, body Body) error { func (c *Client) SendHello() error { if c.redistDefault > 0 { command := HELLO + if c.Version == 4 { + command = FRR_HELLO + } else if c.Version >= 5 { + command = FRR_ZAPI5_HELLO + } body := &HelloBody{ RedistDefault: c.redistDefault, Instance: 0, } - if c.Version >= 4 { - command = FRR_HELLO - } return c.SendCommand(command, VRF_DEFAULT, body) } return nil @@ -706,21 +987,25 @@ func (c *Client) SendHello() error { func (c *Client) SendRouterIDAdd() error { command := ROUTER_ID_ADD - if c.Version >= 4 { + if c.Version == 4 { command = FRR_ROUTER_ID_ADD + } else if c.Version >= 5 { + command = FRR_ZAPI5_ROUTER_ID_ADD } return c.SendCommand(command, VRF_DEFAULT, nil) } func (c *Client) SendInterfaceAdd() error { command := INTERFACE_ADD - if c.Version >= 4 { + if c.Version == 4 { command = FRR_INTERFACE_ADD + } else if c.Version >= 5 { + command = FRR_ZAPI5_INTERFACE_ADD } return c.SendCommand(command, VRF_DEFAULT, nil) } -func (c *Client) SendRedistribute(t ROUTE_TYPE, vrfId uint16) error { +func (c *Client) SendRedistribute(t ROUTE_TYPE, vrfId uint32) error { command := REDISTRIBUTE_ADD if c.redistDefault != t { bodies := make([]*RedistributeBody, 0) @@ -730,6 +1015,9 @@ func (c *Client) SendRedistribute(t ROUTE_TYPE, vrfId uint16) error { }) } else { // version >= 4 command = FRR_REDISTRIBUTE_ADD + if c.Version >= 5 { + command = FRR_ZAPI5_REDISTRIBUTE_ADD + } for _, afi := range []AFI{AFI_IP, AFI_IP6} { bodies = append(bodies, &RedistributeBody{ Afi: afi, @@ -750,8 +1038,10 @@ func (c *Client) SendRedistribute(t ROUTE_TYPE, vrfId uint16) error { func (c *Client) SendRedistributeDelete(t ROUTE_TYPE) error { if t < ROUTE_MAX { command := REDISTRIBUTE_DELETE - if c.Version >= 4 { + if c.Version == 4 { command = FRR_REDISTRIBUTE_DELETE + } else if c.Version >= 5 { + command = FRR_ZAPI5_REDISTRIBUTE_DELETE } body := &RedistributeBody{ Redist: t, @@ -762,10 +1052,10 @@ func (c *Client) SendRedistributeDelete(t ROUTE_TYPE) error { } } -func (c *Client) SendIPRoute(vrfId uint16, body *IPRouteBody, isWithdraw bool) error { +func (c *Client) SendIPRoute(vrfId uint32, body *IPRouteBody, isWithdraw bool) error { command := IPV4_ROUTE_ADD if c.Version <= 3 { - if body.Prefix.To4() != nil { + if body.Prefix.Prefix.To4() != nil { if isWithdraw { command = IPV4_ROUTE_DELETE } @@ -776,8 +1066,8 @@ func (c *Client) SendIPRoute(vrfId uint16, body *IPRouteBody, isWithdraw bool) e command = IPV6_ROUTE_ADD } } - } else { // version >= 4 - if body.Prefix.To4() != nil { + } else if c.Version == 4 { // version >= 4 + if body.Prefix.Prefix.To4() != nil { if isWithdraw { command = FRR_IPV4_ROUTE_DELETE } else { @@ -790,11 +1080,17 @@ func (c *Client) SendIPRoute(vrfId uint16, body *IPRouteBody, isWithdraw bool) e command = FRR_IPV6_ROUTE_ADD } } + } else { // version >= 5 + if isWithdraw { + command = FRR_ZAPI5_ROUTE_DELETE + } else { + command = FRR_ZAPI5_ROUTE_ADD + } } return c.SendCommand(command, vrfId, body) } -func (c *Client) SendNexthopRegister(vrfId uint16, body *NexthopRegisterBody, isWithdraw bool) error { +func (c *Client) SendNexthopRegister(vrfId uint32, body *NexthopRegisterBody, isWithdraw bool) error { // Note: NEXTHOP_REGISTER and NEXTHOP_UNREGISTER messages are not // supported in Zebra protocol version<3. if c.Version < 3 { @@ -805,12 +1101,18 @@ func (c *Client) SendNexthopRegister(vrfId uint16, body *NexthopRegisterBody, is if isWithdraw { command = NEXTHOP_UNREGISTER } - } else { // version >= 4 + } else if c.Version == 4 { // version >= 4 if isWithdraw { command = FRR_NEXTHOP_UNREGISTER } else { command = FRR_NEXTHOP_REGISTER } + } else { // version >= 5 + if isWithdraw { + command = FRR_ZAPI5_NEXTHOP_UNREGISTER + } else { + command = FRR_ZAPI5_NEXTHOP_REGISTER + } } return c.SendCommand(command, vrfId, body) } @@ -824,7 +1126,7 @@ type Header struct { Len uint16 Marker uint8 Version uint8 - VrfId uint16 + VrfId uint32 // ZAPI v4: 16bits, v5: 32bits Command API_TYPE } @@ -839,6 +1141,9 @@ func (h *Header) Serialize() ([]byte, error) { case 3, 4: binary.BigEndian.PutUint16(buf[4:6], uint16(h.VrfId)) binary.BigEndian.PutUint16(buf[6:8], uint16(h.Command)) + case 5: + binary.BigEndian.PutUint32(buf[4:8], uint32(h.VrfId)) + binary.BigEndian.PutUint16(buf[8:10], uint16(h.Command)) default: return nil, fmt.Errorf("Unsupported ZAPI version: %d", h.Version) } @@ -859,8 +1164,11 @@ func (h *Header) DecodeFromBytes(data []byte) error { case 2: h.Command = API_TYPE(binary.BigEndian.Uint16(data[4:6])) case 3, 4: - h.VrfId = binary.BigEndian.Uint16(data[4:6]) + h.VrfId = uint32(binary.BigEndian.Uint16(data[4:6])) h.Command = API_TYPE(binary.BigEndian.Uint16(data[6:8])) + case 5: + h.VrfId = binary.BigEndian.Uint32(data[4:8]) + h.Command = API_TYPE(binary.BigEndian.Uint16(data[8:10])) default: return fmt.Errorf("Unsupported ZAPI version: %d", h.Version) } @@ -893,25 +1201,42 @@ func (b *UnknownBody) String() string { type HelloBody struct { RedistDefault ROUTE_TYPE Instance uint16 + ReceiveNotify uint8 } +// Reference: zread_hello function in zebra/zserv.c of Quagga1.2.x (ZAPI3) +// Reference: zread_hello function in zebra/zserv.c of FRR3.x (ZAPI4) +// Reference: zread_hello function in zebra/zapi_msg.c of FRR5.x (ZAPI5) func (b *HelloBody) DecodeFromBytes(data []byte, version uint8) error { b.RedistDefault = ROUTE_TYPE(data[0]) if version >= 4 { b.Instance = binary.BigEndian.Uint16(data[1:3]) + if version >= 5 { + b.ReceiveNotify = data[3] + } } return nil } +// Reference: zebra_hello_send function in lib/zclient.c of Quagga1.2.x (ZAPI3) +// Reference: zebra_hello_send function in lib/zclient.c of FRR3.x (ZAPI4) +// Reference: zebra_hello_send function in lib/zclient.c of FRR5.x (ZAPI5) func (b *HelloBody) Serialize(version uint8) ([]byte, error) { if version <= 3 { return []byte{uint8(b.RedistDefault)}, nil } else { // version >= 4 - buf := make([]byte, 3) + var buf []byte + if version == 4 { + buf = make([]byte, 3) + } else if version >= 5 { + buf = make([]byte, 4) + } buf[0] = uint8(b.RedistDefault) binary.BigEndian.PutUint16(buf[1:3], b.Instance) + if version >= 5 { + buf[3] = b.ReceiveNotify + } return buf, nil - } } @@ -927,6 +1252,9 @@ type RedistributeBody struct { Instance uint16 } +// Reference: zebra_redistribute_add function in zebra/redistribute.c of Quagga1.2.x (ZAPI3) +// Reference: zebra_redistribute_add function in zebra/redistribute.c of FRR3.x (ZAPI4) +// Reference: zebra_redistribute_add function in zebra/redistribute.c of FRR5.x (ZAPI5) func (b *RedistributeBody) DecodeFromBytes(data []byte, version uint8) error { if version <= 3 { b.Redist = ROUTE_TYPE(data[0]) @@ -938,6 +1266,9 @@ func (b *RedistributeBody) DecodeFromBytes(data []byte, version uint8) error { return nil } +// Reference: zebra_redistribute_send function in lib/zclient.c of Quagga1.2.x (ZAPI4) +// Reference: zebra_redistribute_send function in lib/zclient.c of FRR3.x (ZAPI4) +// Reference: zebra_redistribute_send function in lib/zclient.c of FRR5.x (ZAPI5) func (b *RedistributeBody) Serialize(version uint8) ([]byte, error) { if version <= 3 { return []byte{uint8(b.Redist)}, nil @@ -956,6 +1287,26 @@ func (b *RedistributeBody) String() string { b.Afi.String(), b.Redist.String(), b.Instance) } +type LinkParam struct { + Status uint32 + TeMetric uint32 + MaxBw float32 + MaxRsvBw float32 + UnrsvBw [8]float32 + BwClassNum uint32 + AdminGroup uint32 + RemoteAS uint32 + RemoteIP net.IP + AveDelay uint32 + MinDelay uint32 + MaxDelay uint32 + DelayVar uint32 + PktLoss float32 + ResidualBw float32 + AvailableBw float32 + UseBw float32 +} + type InterfaceUpdateBody struct { Name string Index uint32 @@ -970,8 +1321,12 @@ type InterfaceUpdateBody struct { Bandwidth uint32 Linktype LINK_TYPE HardwareAddr net.HardwareAddr + LinkParam LinkParam } +// Reference: zebra_interface_if_set_value function in lib/zclient.c of Quagga1.2.x (ZAPI4) +// Reference: zebra_interface_if_set_value function in lib/zclient.c of FRR3.x (ZAPI4) +// Reference: zebra_interface_if_set_value function in lib/zclient.c of FRR5.x (ZAPI5) func (b *InterfaceUpdateBody) DecodeFromBytes(data []byte, version uint8) error { if len(data) < INTERFACE_NAMSIZ+29 { return fmt.Errorf("lack of bytes. need %d but %d", INTERFACE_NAMSIZ+29, len(data)) @@ -1008,6 +1363,32 @@ func (b *InterfaceUpdateBody) DecodeFromBytes(data []byte, version uint8) error } b.HardwareAddr = data[4 : 4+l] } + if version >= 5 { + LinkParam := data[4+l] + if LinkParam > 0 { + data = data[5+l:] + b.LinkParam.Status = binary.BigEndian.Uint32(data[0:4]) + b.LinkParam.TeMetric = binary.BigEndian.Uint32(data[4:8]) + b.LinkParam.MaxBw = math.Float32frombits(binary.BigEndian.Uint32(data[8:12])) + b.LinkParam.MaxRsvBw = math.Float32frombits(binary.BigEndian.Uint32(data[12:16])) + b.LinkParam.BwClassNum = binary.BigEndian.Uint32(data[16:20]) + for i := uint32(0); i < b.LinkParam.BwClassNum; i++ { + b.LinkParam.UnrsvBw[i] = math.Float32frombits(binary.BigEndian.Uint32(data[20+i*4 : 24+i*4])) + } + data = data[20+b.LinkParam.BwClassNum*4:] + b.LinkParam.AdminGroup = binary.BigEndian.Uint32(data[0:4]) + b.LinkParam.RemoteAS = binary.BigEndian.Uint32(data[4:8]) + b.LinkParam.RemoteIP = data[8:12] + b.LinkParam.AveDelay = binary.BigEndian.Uint32(data[12:16]) + b.LinkParam.MinDelay = binary.BigEndian.Uint32(data[16:20]) + b.LinkParam.MaxDelay = binary.BigEndian.Uint32(data[20:24]) + b.LinkParam.DelayVar = binary.BigEndian.Uint32(data[24:28]) + b.LinkParam.PktLoss = math.Float32frombits(binary.BigEndian.Uint32(data[28:32])) + b.LinkParam.ResidualBw = math.Float32frombits(binary.BigEndian.Uint32(data[32:36])) + b.LinkParam.AvailableBw = math.Float32frombits(binary.BigEndian.Uint32(data[36:40])) + b.LinkParam.UseBw = math.Float32frombits(binary.BigEndian.Uint32(data[40:44])) + } + } return nil } @@ -1033,18 +1414,16 @@ type InterfaceAddressUpdateBody struct { Destination net.IP } +// Reference: zebra_interface_address_read function in lib/zclient.c of Quagga1.2.x (ZAPI4) +// Reference: zebra_interface_address_read function in lib/zclient.c of FRR3.x (ZAPI4) +// Reference: zebra_interface_address_read function in lib/zclient.c of FRR5.x (ZAPI5) func (b *InterfaceAddressUpdateBody) DecodeFromBytes(data []byte, version uint8) error { b.Index = binary.BigEndian.Uint32(data[:4]) b.Flags = INTERFACE_ADDRESS_FLAG(data[4]) family := data[5] - var addrlen int8 - switch family { - case syscall.AF_INET: - addrlen = net.IPv4len - case syscall.AF_INET6: - addrlen = net.IPv6len - default: - return fmt.Errorf("unknown address family: %d", family) + addrlen, err := addressByteLength(family) + if err != nil { + return err } b.Prefix = data[6 : 6+addrlen] b.Length = data[6+addrlen] @@ -1067,16 +1446,15 @@ type RouterIDUpdateBody struct { Prefix net.IP } +// Reference: zebra_router_id_update_read function in lib/zclient.c of Quagga1.2.x (ZAPI4) +// Reference: zebra_router_id_update_read function in lib/zclient.c of FRR3.x (ZAPI4) +// Reference: zebra_router_id_update_read function in lib/zclient.c of FRR5.x (ZAPI5) func (b *RouterIDUpdateBody) DecodeFromBytes(data []byte, version uint8) error { family := data[0] - var addrlen int8 - switch family { - case syscall.AF_INET: - addrlen = net.IPv4len - case syscall.AF_INET6: - addrlen = net.IPv6len - default: - return fmt.Errorf("unknown address family: %d", family) + + addrlen, err := addressByteLength(family) + if err != nil { + return err } b.Prefix = data[1 : 1+addrlen] b.Length = data[1+addrlen] @@ -1091,149 +1469,264 @@ func (b *RouterIDUpdateBody) String() string { return fmt.Sprintf("id: %s/%d", b.Prefix.String(), b.Length) } +/* + Reference: struct zapi_nexthop in lib/zclient.h of FRR5.x (ZAPI5) +*/ +type Nexthop struct { + Type NEXTHOP_TYPE + VrfId uint32 + Ifindex uint32 + Gate net.IP + BlackholeType uint8 + LabelNum uint8 + MplsLabels []uint32 +} + +func (n *Nexthop) String() string { + s := fmt.Sprintf( + "type: %s, gate: %s, ifindex: %d", + n.Type.String(), n.Gate.String(), n.Ifindex) + return s +} + +type Prefix struct { + Family uint8 + PrefixLen uint8 + Prefix net.IP +} + type IPRouteBody struct { - Type ROUTE_TYPE - Instance uint16 - Flags FLAG - Message MESSAGE_FLAG - SAFI SAFI - Prefix net.IP - PrefixLength uint8 - SrcPrefix net.IP - SrcPrefixLength uint8 - Nexthops []net.IP - Ifindexs []uint32 - Distance uint8 - Metric uint32 - Mtu uint32 - Tag uint32 - Api API_TYPE -} - -func (b *IPRouteBody) RouteFamily() bgp.RouteFamily { - switch b.Api { - case IPV4_ROUTE_ADD, IPV4_ROUTE_DELETE, FRR_REDISTRIBUTE_IPV4_ADD, FRR_REDISTRIBUTE_IPV4_DEL: + Type ROUTE_TYPE + Instance uint16 + Flags FLAG + Message MESSAGE_FLAG + SAFI SAFI + Prefix Prefix + SrcPrefix Prefix + Nexthops []Nexthop + Distance uint8 + Metric uint32 + Mtu uint32 + Tag uint32 + Rmac [6]byte + Api API_TYPE +} + +func (b *IPRouteBody) RouteFamily(version uint8) bgp.RouteFamily { + if b == nil { + return bgp.RF_OPAQUE + } + family := addressFamilyFromApi(b.Api, version) + if family == syscall.AF_UNSPEC { + if b.Prefix.Prefix.To4() != nil { + family = syscall.AF_INET + } else if b.Prefix.Prefix.To16() != nil { + family = syscall.AF_INET6 + } + } + switch family { + case syscall.AF_INET: return bgp.RF_IPv4_UC - case IPV6_ROUTE_ADD, IPV6_ROUTE_DELETE, FRR_REDISTRIBUTE_IPV6_ADD, FRR_REDISTRIBUTE_IPV6_DEL: + case syscall.AF_INET6: return bgp.RF_IPv6_UC - default: - return bgp.RF_OPAQUE } + return bgp.RF_OPAQUE } -func (b *IPRouteBody) IsWithdraw() bool { - switch b.Api { - case IPV4_ROUTE_DELETE, FRR_REDISTRIBUTE_IPV4_DEL, IPV6_ROUTE_DELETE, FRR_REDISTRIBUTE_IPV6_DEL: - return true - default: - return false +func (b *IPRouteBody) IsWithdraw(version uint8) bool { + if version <= 3 { + switch b.Api { + case IPV4_ROUTE_DELETE, IPV6_ROUTE_DELETE: + return true + } + } else if version == 4 { + switch b.Api { + case FRR_IPV4_ROUTE_DELETE, FRR_IPV6_ROUTE_DELETE, FRR_REDISTRIBUTE_IPV4_DEL, FRR_REDISTRIBUTE_IPV6_DEL: + return true + } + } else if version >= 5 { + switch b.Api { + case FRR_ZAPI5_ROUTE_DELETE, FRR_ZAPI5_REDISTRIBUTE_ROUTE_DEL: + return true + } } + return false } +// Reference: zapi_ipv4_route function in lib/zclient.c of Quagga1.2.x (ZAPI3) +// Reference: zapi_ipv4_route function in lib/zclient.c of FRR3.x (ZAPI4) +// Reference: zapi_route_encode function in lib/zclient.c of FRR5.x (ZAPI5) func (b *IPRouteBody) Serialize(version uint8) ([]byte, error) { - var buf []byte - nhfIPv4 := uint8(NEXTHOP_IPV4) - nhfIPv6 := uint8(NEXTHOP_IPV6) - nhfIndx := uint8(NEXTHOP_IFINDEX) - nhfBlkH := uint8(NEXTHOP_BLACKHOLE) if version <= 3 { buf = make([]byte, 5) - buf[0] = uint8(b.Type) + } else if version == 4 { + buf = make([]byte, 10) + } else { // version >= 5 + buf = make([]byte, 9) + } + buf[0] = uint8(b.Type) + if version <= 3 { buf[1] = uint8(b.Flags) buf[2] = uint8(b.Message) binary.BigEndian.PutUint16(buf[3:5], uint16(b.SAFI)) } else { // version >= 4 - buf = make([]byte, 10) - buf[0] = uint8(b.Type) binary.BigEndian.PutUint16(buf[1:3], uint16(b.Instance)) binary.BigEndian.PutUint32(buf[3:7], uint32(b.Flags)) buf[7] = uint8(b.Message) - binary.BigEndian.PutUint16(buf[8:10], uint16(b.SAFI)) - nhfIPv4 = uint8(FRR_NEXTHOP_IPV4) - nhfIPv6 = uint8(FRR_NEXTHOP_IPV6) - nhfIndx = uint8(FRR_NEXTHOP_IFINDEX) - nhfBlkH = uint8(FRR_NEXTHOP_BLACKHOLE) - } - byteLen := (int(b.PrefixLength) + 7) / 8 - buf = append(buf, b.PrefixLength) - buf = append(buf, b.Prefix[:byteLen]...) - if b.Message&FRR_MESSAGE_SRCPFX > 0 { - byteLen = (int(b.SrcPrefixLength) + 7) / 8 - buf = append(buf, b.SrcPrefixLength) - buf = append(buf, b.SrcPrefix[:byteLen]...) - } - - if b.Message&MESSAGE_NEXTHOP > 0 { - if b.Flags&FLAG_BLACKHOLE > 0 { - buf = append(buf, []byte{1, nhfBlkH}...) - } else { - buf = append(buf, uint8(len(b.Nexthops)+len(b.Ifindexs))) + if version == 4 { + binary.BigEndian.PutUint16(buf[8:10], uint16(b.SAFI)) + } else { // version >= 5 + buf[8] = uint8(b.SAFI) + if b.Flags&FLAG_EVPN_ROUTE > 0 { + // size of struct ethaddr is 6 octets defined by ETH_ALEN + buf = append(buf, b.Rmac[:6]...) + } + if b.Prefix.Family == syscall.AF_UNSPEC { + if b.Prefix.Prefix.To4() != nil { + b.Prefix.Family = syscall.AF_INET + } else if b.Prefix.Prefix.To16() != nil { + b.Prefix.Family = syscall.AF_INET6 + } + } + buf = append(buf, b.Prefix.Family) } - - for _, v := range b.Nexthops { - if v.To4() != nil { - buf = append(buf, nhfIPv4) - buf = append(buf, v.To4()...) + } + byteLen := (int(b.Prefix.PrefixLen) + 7) / 8 + buf = append(buf, b.Prefix.PrefixLen) + buf = append(buf, b.Prefix.Prefix[:byteLen]...) + + if (version == 4 && b.Message&FRR_MESSAGE_SRCPFX > 0) || + (version == 5 && b.Message&FRR_ZAPI5_MESSAGE_SRCPFX > 0) { + byteLen = (int(b.SrcPrefix.PrefixLen) + 7) / 8 + buf = append(buf, b.SrcPrefix.PrefixLen) + buf = append(buf, b.SrcPrefix.Prefix[:byteLen]...) + } + if (version <= 3 && b.Message&MESSAGE_NEXTHOP > 0) || + (version == 4 && b.Message&FRR_MESSAGE_NEXTHOP > 0) || + (version == 5 && b.Message&FRR_ZAPI5_MESSAGE_NEXTHOP > 0) { + if version < 5 { + if b.Flags&FLAG_BLACKHOLE > 0 { + buf = append(buf, []byte{1, uint8(NEXTHOP_TYPE_BLACKHOLE)}...) } else { - buf = append(buf, nhfIPv6) - buf = append(buf, v.To16()...) + buf = append(buf, uint8(len(b.Nexthops))) } - } - - for _, v := range b.Ifindexs { - buf = append(buf, nhfIndx) - bbuf := make([]byte, 4) - binary.BigEndian.PutUint32(bbuf, v) + } else { // version == 5 + bbuf := make([]byte, 2) + binary.BigEndian.PutUint16(bbuf, uint16(len(b.Nexthops))) buf = append(buf, bbuf...) } - } + for _, nexthop := range b.Nexthops { + if version == 5 { + bbuf := make([]byte, 4) + binary.BigEndian.PutUint32(bbuf, nexthop.VrfId) + buf = append(buf, bbuf...) + } - if b.Message&MESSAGE_DISTANCE > 0 { - buf = append(buf, b.Distance) - } - if b.Message&MESSAGE_METRIC > 0 { - bbuf := make([]byte, 4) - binary.BigEndian.PutUint32(bbuf, b.Metric) - buf = append(buf, bbuf...) - } - if version <= 3 { - if b.Message&MESSAGE_MTU > 0 { - bbuf := make([]byte, 4) - binary.BigEndian.PutUint32(bbuf, b.Mtu) - buf = append(buf, bbuf...) + if nexthop.Type == NEXTHOP_TYPE(0) { + if nexthop.Gate.To4() != nil { + if version <= 3 { + nexthop.Type = NEXTHOP_TYPE_IPV4 + } else { + nexthop.Type = FRR_NEXTHOP_TYPE_IPV4 + } + if version == 5 && nexthop.Ifindex > 0 { + nexthop.Type = FRR_NEXTHOP_TYPE_IPV4_IFINDEX + } + } else if nexthop.Gate.To16() != nil { + if version <= 3 { + nexthop.Type = NEXTHOP_TYPE_IPV6 + } else { + nexthop.Type = FRR_NEXTHOP_TYPE_IPV6 + } + if version == 5 && nexthop.Ifindex > 0 { + nexthop.Type = FRR_NEXTHOP_TYPE_IPV6_IFINDEX + } + } else if nexthop.Ifindex > 0 { + if version <= 3 { + nexthop.Type = NEXTHOP_TYPE_IFINDEX + } else { + nexthop.Type = FRR_NEXTHOP_TYPE_IFINDEX + } + } else if version >= 5 { + nexthop.Type = FRR_NEXTHOP_TYPE_BLACKHOLE + } + } + + buf = append(buf, uint8(nexthop.Type)) + + if (version <= 3 && nexthop.Type == NEXTHOP_TYPE_IPV4) || + (version >= 4 && nexthop.Type == FRR_NEXTHOP_TYPE_IPV4) { + buf = append(buf, nexthop.Gate.To4()...) + } else if (version <= 3 && nexthop.Type == NEXTHOP_TYPE_IPV6) || + (version >= 4 && nexthop.Type == FRR_NEXTHOP_TYPE_IPV6) { + buf = append(buf, nexthop.Gate.To16()...) + } else if (version <= 3 && nexthop.Type == NEXTHOP_TYPE_IFINDEX) || + (version >= 4 && nexthop.Type == FRR_NEXTHOP_TYPE_IFINDEX) { + bbuf := make([]byte, 4) + binary.BigEndian.PutUint32(bbuf, nexthop.Ifindex) + buf = append(buf, bbuf...) + } else if version >= 5 && nexthop.Type == FRR_NEXTHOP_TYPE_IPV4_IFINDEX { + buf = append(buf, nexthop.Gate.To4()...) + bbuf := make([]byte, 4) + binary.BigEndian.PutUint32(bbuf, nexthop.Ifindex) + buf = append(buf, bbuf...) + } else if version >= 5 && nexthop.Type == FRR_NEXTHOP_TYPE_IPV6_IFINDEX { + buf = append(buf, nexthop.Gate.To16()...) + bbuf := make([]byte, 4) + binary.BigEndian.PutUint32(bbuf, nexthop.Ifindex) + buf = append(buf, bbuf...) + } else if version >= 5 && nexthop.Type == FRR_NEXTHOP_TYPE_BLACKHOLE { + buf = append(buf, uint8(nexthop.BlackholeType)) + } + if version == 5 && b.Message&FRR_ZAPI5_MESSAGE_LABEL > 0 { + buf = append(buf, nexthop.LabelNum) + bbuf := make([]byte, 4) + binary.BigEndian.PutUint32(bbuf, nexthop.MplsLabels[0]) + buf = append(buf, bbuf...) + } + } + if (version <= 3 && b.Message&MESSAGE_DISTANCE > 0) || + (version == 4 && b.Message&FRR_MESSAGE_DISTANCE > 0) || + (version == 5 && b.Message&FRR_ZAPI5_MESSAGE_DISTANCE > 0) { + buf = append(buf, b.Distance) } - if b.Message&MESSAGE_TAG > 0 { + if (version <= 3 && b.Message&MESSAGE_METRIC > 0) || + (version == 4 && b.Message&FRR_MESSAGE_METRIC > 0) || + (version == 5 && b.Message&FRR_ZAPI5_MESSAGE_METRIC > 0) { bbuf := make([]byte, 4) - binary.BigEndian.PutUint32(bbuf, b.Tag) + binary.BigEndian.PutUint32(bbuf, b.Metric) buf = append(buf, bbuf...) } - } else { // version >= 4 - if b.Message&FRR_MESSAGE_TAG > 0 { + if (version <= 3 && b.Message&MESSAGE_MTU > 0) || + (version == 4 && b.Message&FRR_MESSAGE_MTU > 0) || + (version == 5 && b.Message&FRR_ZAPI5_MESSAGE_MTU > 0) { bbuf := make([]byte, 4) - binary.BigEndian.PutUint32(bbuf, b.Tag) + binary.BigEndian.PutUint32(bbuf, b.Mtu) buf = append(buf, bbuf...) } - if b.Message&FRR_MESSAGE_MTU > 0 { + if (version <= 3 && b.Message&MESSAGE_TAG > 0) || + (version == 4 && b.Message&FRR_MESSAGE_TAG > 0) || + (version == 5 && b.Message&FRR_ZAPI5_MESSAGE_TAG > 0) { bbuf := make([]byte, 4) - binary.BigEndian.PutUint32(bbuf, b.Mtu) + binary.BigEndian.PutUint32(bbuf, b.Tag) buf = append(buf, bbuf...) } } return buf, nil } +// Reference: zebra_read_ipv4 function in bgpd/bgp_zebra.c of Quagga1.2.x (ZAPI3) +// Reference: zebra_read_ipv4 function in bgpd/bgp_zebra.c of FRR4.x (ZAPI4) +// Reference: zapi_route_decode function in lib/zclient.c of FRR5.x (ZAPI5) func (b *IPRouteBody) DecodeFromBytes(data []byte, version uint8) error { - isV4 := true - if version <= 3 { - isV4 = b.Api == IPV4_ROUTE_ADD || b.Api == IPV4_ROUTE_DELETE - } else { - isV4 = b.Api == FRR_REDISTRIBUTE_IPV4_ADD || b.Api == FRR_REDISTRIBUTE_IPV4_DEL - } - var addrLen uint8 = net.IPv4len - if !isV4 { - addrLen = net.IPv6len + if b == nil { + return fmt.Errorf("[IPRouteBody DecodeFromBytes] IPRouteBody is nil") } + b.Prefix.Family = addressFamilyFromApi(b.Api, version) + /* REDSTRIBUTE_IPV4_ADD|DEL and REDSITRBUTE_IPV6_ADD|DEL have merged to + REDISTRIBUTE_ROUTE_ADD|DEL in ZAPI version 5. + Therefore it can not judge the protocol famiiy from API. */ b.Type = ROUTE_TYPE(data[0]) if version <= 3 { @@ -1247,124 +1740,217 @@ func (b *IPRouteBody) DecodeFromBytes(data []byte, version uint8) error { b.Message = MESSAGE_FLAG(data[0]) b.SAFI = SAFI(SAFI_UNICAST) + if version >= 5 { + b.SAFI = SAFI(data[1]) + data = data[2:] + if b.Flags&FLAG_EVPN_ROUTE > 0 { + // size of struct ethaddr is 6 octets defined by ETH_ALEN + copy(b.Rmac[0:6], data[0:6]) + data = data[6:] + } + b.Prefix.Family = data[0] + } - b.PrefixLength = data[1] - if b.PrefixLength > addrLen*8 { - return fmt.Errorf("prefix length is greater than %d", addrLen*8) + addrByteLen, err := addressByteLength(b.Prefix.Family) + if err != nil { + return err + } + + addrBitLen := uint8(addrByteLen * 8) + + b.Prefix.PrefixLen = data[1] + if b.Prefix.PrefixLen > addrBitLen { + return fmt.Errorf("prefix length is greater than %d", addrByteLen*8) } pos := 2 - buf := make([]byte, addrLen) - byteLen := int((b.PrefixLength + 7) / 8) - copy(buf, data[pos:pos+byteLen]) - if isV4 { - b.Prefix = net.IP(buf).To4() - } else { - b.Prefix = net.IP(buf).To16() + rest := len(data[pos:]) + 2 + + buf := make([]byte, addrByteLen) + byteLen := int((b.Prefix.PrefixLen + 7) / 8) + if pos+byteLen > rest { + return fmt.Errorf("message length invalid pos:%d rest:%d", pos, rest) } + copy(buf, data[pos:pos+byteLen]) + b.Prefix.Prefix = ipFromFamily(b.Prefix.Family, buf) pos += byteLen - if b.Message&FRR_MESSAGE_SRCPFX > 0 { - b.SrcPrefixLength = data[pos] + if (version == 4 && b.Message&FRR_MESSAGE_SRCPFX > 0) || + (version == 5 && b.Message&FRR_ZAPI5_MESSAGE_SRCPFX > 0) { + if pos+1 > rest { + return fmt.Errorf("MESSAGE_SRCPFX message length invalid pos:%d rest:%d", pos, rest) + } + b.SrcPrefix.PrefixLen = data[pos] + if b.SrcPrefix.PrefixLen > addrBitLen { + return fmt.Errorf("prefix length is greater than %d", addrByteLen*8) + } pos += 1 - buf = make([]byte, addrLen) - byteLen = int((b.SrcPrefixLength + 7) / 8) + buf = make([]byte, addrByteLen) + byteLen = int((b.SrcPrefix.PrefixLen + 7) / 8) copy(buf, data[pos:pos+byteLen]) - if isV4 { - b.SrcPrefix = net.IP(buf).To4() - } else { - b.SrcPrefix = net.IP(buf).To16() + if pos+byteLen > rest { + return fmt.Errorf("MESSAGE_SRCPFX message length invalid pos:%d rest:%d", pos, rest) } + b.SrcPrefix.Prefix = ipFromFamily(b.Prefix.Family, buf) pos += byteLen } - rest := 0 - var numNexthop int - if b.Message&MESSAGE_NEXTHOP > 0 { - numNexthop = int(data[pos]) - // rest = numNexthop(1) + (nexthop(4 or 16) + placeholder(1) + ifindex(4)) * numNexthop - rest += 1 + numNexthop*(int(addrLen)+5) - } - if b.Message&MESSAGE_DISTANCE > 0 { - // distance(1) - rest += 1 - } - if b.Message&MESSAGE_METRIC > 0 { - // metric(4) - rest += 4 - } - if version <= 3 { - if b.Message&MESSAGE_MTU > 0 { - // mtu(4) - rest += 4 - } - if b.Message&MESSAGE_TAG > 0 { - // tag(4) - rest += 4 - } - } else { // version >= 4 - if b.Message&FRR_MESSAGE_TAG > 0 { - // tag(4) - rest += 4 - } - if b.Message&FRR_MESSAGE_MTU > 0 { - // mtu(4) - rest += 4 + b.Nexthops = []Nexthop{} + if (version <= 3 && b.Message&MESSAGE_NEXTHOP > 0) || + (version == 4 && b.Message&FRR_MESSAGE_NEXTHOP > 0) || + (version == 5 && b.Message&FRR_ZAPI5_MESSAGE_NEXTHOP > 0) { + var numNexthop uint16 + if version <= 4 { + if pos+1 > rest { + return fmt.Errorf("MESSAGE_NEXTHOP message length invalid pos:%d rest:%d", pos, rest) + } + numNexthop = uint16(data[pos]) + pos += 1 + } else { // version >= 5 + if pos+2 > rest { + return fmt.Errorf("MESSAGE_NEXTHOP message length invalid pos:%d rest:%d", pos, rest) + } + numNexthop = binary.BigEndian.Uint16(data[pos : pos+2]) + pos += 2 } - } + for i := 0; i < int(numNexthop); i++ { + var nexthop Nexthop + if version <= 3 { + if b.Prefix.Family == syscall.AF_INET { + nexthop.Type = NEXTHOP_TYPE_IPV4 + } else if b.Prefix.Family == syscall.AF_INET6 { + nexthop.Type = NEXTHOP_TYPE_IPV6 + } + } else if version == 4 { + if b.Prefix.Family == syscall.AF_INET { + nexthop.Type = FRR_NEXTHOP_TYPE_IPV4 + } else if b.Prefix.Family == syscall.AF_INET6 { + nexthop.Type = FRR_NEXTHOP_TYPE_IPV6 + } + } else { // version >= 5 + if pos+5 > rest { + return fmt.Errorf("MESSAGE_NEXTHOP message length invalid pos:%d rest:%d", pos, rest) + } + nexthop.VrfId = binary.BigEndian.Uint32(data[pos : pos+4]) + nexthop.Type = NEXTHOP_TYPE(data[pos+4]) + pos += 5 + } - if len(data[pos:]) != rest { - return fmt.Errorf("message length invalid") + if (version <= 3 && nexthop.Type == NEXTHOP_TYPE_IPV4) || + (version >= 4 && nexthop.Type == FRR_NEXTHOP_TYPE_IPV4) { + if pos+4 > rest { + return fmt.Errorf("MESSAGE_NEXTHOP NEXTHOP_TYPE_IPV4 message length invalid pos:%d rest:%d", pos, rest) + } + addr := data[pos : pos+4] + nexthop.Gate = net.IP(addr).To4() + pos += 4 + } else if (version <= 3 && nexthop.Type == NEXTHOP_TYPE_IPV6) || + (version >= 4 && nexthop.Type == FRR_NEXTHOP_TYPE_IPV6) { + if pos+16 > rest { + return fmt.Errorf("MESSAGE_NEXTHOP NEXTHOP_TYPE_IPV6 message length invalid pos:%d rest:%d", pos, rest) + } + addr := data[pos : pos+16] + nexthop.Gate = net.IP(addr).To16() + pos += 16 + } else if version >= 5 && nexthop.Type == FRR_NEXTHOP_TYPE_IFINDEX { + if pos+4 > rest { + return fmt.Errorf("MESSAGE_NEXTHOP NEXTHOP_TYPE_IFINDEX message length invalid pos:%d rest:%d", pos, rest) + } + nexthop.Ifindex = binary.BigEndian.Uint32(data[pos : pos+4]) + pos += 4 + // barkward compatibility + if b.Prefix.Family == syscall.AF_INET { + nexthop.Gate = net.ParseIP("0.0.0.0") + } else if b.Prefix.Family == syscall.AF_INET6 { + nexthop.Gate = net.ParseIP("::") + } + } else if version >= 5 && nexthop.Type == FRR_NEXTHOP_TYPE_IPV4_IFINDEX { + if pos+8 > rest { + return fmt.Errorf("MESSAGE_NEXTHOP NEXTHOP_TYPE_IPV4_IFINDEX message length invalid pos:%d rest:%d", pos, rest) + } + addr := data[pos : pos+4] + nexthop.Gate = net.IP(addr).To4() + nexthop.Ifindex = binary.BigEndian.Uint32(data[pos+4 : pos+8]) + pos += 8 + } else if version >= 5 && nexthop.Type == FRR_NEXTHOP_TYPE_IPV6_IFINDEX { + if pos+20 > rest { + return fmt.Errorf("MESSAGE_NEXTHOP NEXTHOP_TYPE_IPV6_IFINDEX message length invalid pos:%d rest:%d", pos, rest) + } + addr := data[pos : pos+16] + nexthop.Gate = net.IP(addr).To16() + nexthop.Ifindex = binary.BigEndian.Uint32(data[pos+16 : pos+20]) + pos += 20 + } else if version >= 5 && nexthop.Type == FRR_NEXTHOP_TYPE_BLACKHOLE { + if pos+1 > rest { + return fmt.Errorf("MESSAGE_NEXTHOP NEXTHOP_TYPE_BLACKHOLE message length invalid pos:%d rest:%d", pos, rest) + } + nexthop.BlackholeType = data[pos] + pos += 1 + } + b.Nexthops = append(b.Nexthops, nexthop) + } } - b.Nexthops = []net.IP{} - b.Ifindexs = []uint32{} - - if b.Message&MESSAGE_NEXTHOP > 0 { + if (version <= 3 && b.Message&MESSAGE_IFINDEX > 0) || + (version == 4 && b.Message&FRR_MESSAGE_IFINDEX > 0) { + if pos+1 > rest { + return fmt.Errorf("MESSAGE_IFINDEX message length invalid pos:%d rest:%d", pos, rest) + } + numIfIndex := uint8(data[pos]) pos += 1 - for i := 0; i < numNexthop; i++ { - addr := data[pos : pos+int(addrLen)] - var nexthop net.IP - if isV4 { - nexthop = net.IP(addr).To4() - } else { - nexthop = net.IP(addr).To16() + for i := 0; i < int(numIfIndex); i++ { + if pos+4 > rest { + return fmt.Errorf("MESSAGE_IFINDEX message length invalid pos:%d rest:%d", pos, rest) + } + var nexthop Nexthop + nexthop.Ifindex = binary.BigEndian.Uint32(data[pos : pos+4]) + if version <= 3 { + nexthop.Type = NEXTHOP_TYPE_IFINDEX + } else if version == 4 { + nexthop.Type = FRR_NEXTHOP_TYPE_IFINDEX } b.Nexthops = append(b.Nexthops, nexthop) - - // skip nexthop and 1byte place holder - pos += int(addrLen + 1) - ifidx := binary.BigEndian.Uint32(data[pos : pos+4]) - b.Ifindexs = append(b.Ifindexs, ifidx) pos += 4 } } - if b.Message&MESSAGE_DISTANCE > 0 { + if (version <= 3 && b.Message&MESSAGE_DISTANCE > 0) || + (version == 4 && b.Message&FRR_MESSAGE_DISTANCE > 0) || + (version == 5 && b.Message&FRR_ZAPI5_MESSAGE_DISTANCE > 0) { + if pos+1 > rest { + return fmt.Errorf("MESSAGE_DISTANCE message length invalid pos:%d rest:%d", pos, rest) + } b.Distance = data[pos] pos += 1 } - if b.Message&MESSAGE_METRIC > 0 { + if (version <= 3 && b.Message&MESSAGE_METRIC > 0) || + (version == 4 && b.Message&FRR_MESSAGE_METRIC > 0) || + (version == 5 && b.Message&FRR_ZAPI5_MESSAGE_METRIC > 0) { + if pos+4 > rest { + return fmt.Errorf("MESSAGE_METRIC message length invalid pos:%d rest:%d", pos, rest) + } b.Metric = binary.BigEndian.Uint32(data[pos : pos+4]) pos += 4 } - if version <= 3 { - if b.Message&MESSAGE_MTU > 0 { - b.Mtu = binary.BigEndian.Uint32(data[pos : pos+4]) - pos += 4 + if (version <= 3 && b.Message&MESSAGE_MTU > 0) || + (version == 4 && b.Message&FRR_MESSAGE_MTU > 0) || + (version == 5 && b.Message&FRR_ZAPI5_MESSAGE_MTU > 0) { + if pos+4 > rest { + return fmt.Errorf("MESSAGE_MTU message length invalid pos:%d rest:%d", pos, rest) } - if b.Message&MESSAGE_TAG > 0 { - b.Tag = binary.BigEndian.Uint32(data[pos : pos+4]) - pos += 4 - } - } else { - if b.Message&FRR_MESSAGE_TAG > 0 { - b.Tag = binary.BigEndian.Uint32(data[pos : pos+4]) - pos += 4 - } - if b.Message&FRR_MESSAGE_MTU > 0 { - b.Mtu = binary.BigEndian.Uint32(data[pos : pos+4]) - pos += 4 + b.Mtu = binary.BigEndian.Uint32(data[pos : pos+4]) + pos += 4 + } + if (version <= 3 && b.Message&MESSAGE_TAG > 0) || + (version == 4 && b.Message&FRR_MESSAGE_TAG > 0) || + (version == 5 && b.Message&FRR_ZAPI5_MESSAGE_TAG > 0) { + if pos+4 > rest { + return fmt.Errorf("MESSAGE_TAG message length invalid pos:%d rest:%d", pos, rest) } + b.Tag = binary.BigEndian.Uint32(data[pos : pos+4]) + pos += 4 + } + if pos != rest { + return fmt.Errorf("message length invalid") } return nil @@ -1373,162 +1959,129 @@ func (b *IPRouteBody) DecodeFromBytes(data []byte, version uint8) error { func (b *IPRouteBody) String() string { s := fmt.Sprintf( "type: %s, instance: %d, flags: %s, message: %d, safi: %s, prefix: %s/%d, src_prefix: %s/%d", - b.Type.String(), b.Instance, b.Flags.String(), b.Message, b.SAFI.String(), b.Prefix.String(), b.PrefixLength, b.SrcPrefix.String(), b.SrcPrefixLength) + b.Type.String(), b.Instance, b.Flags.String(), b.Message, b.SAFI.String(), b.Prefix.Prefix.String(), b.Prefix.PrefixLen, b.SrcPrefix.Prefix.String(), b.SrcPrefix.PrefixLen) for i, nh := range b.Nexthops { s += fmt.Sprintf(", nexthops[%d]: %s", i, nh.String()) - } - for i, idx := range b.Ifindexs { - s += fmt.Sprintf(", ifindex[%d]: %d", i, idx) + /* + s += fmt.Sprintf(", nexthops[%d]: %s", i, nh.Gate.String()) + s += fmt.Sprintf(", ifindex[%d]: %d", i, nh.Ifindex) + */ } return s + fmt.Sprintf( ", distance: %d, metric: %d, mtu: %d, tag: %d", b.Distance, b.Metric, b.Mtu, b.Tag) } -type NexthopLookupBody struct { - Api API_TYPE - Addr net.IP - Distance uint8 - Metric uint32 - Nexthops []*Nexthop -} - -type Nexthop struct { - Ifname string - Ifindex uint32 - Type NEXTHOP_FLAG - Addr net.IP -} - -func (n *Nexthop) String() string { - s := fmt.Sprintf( - "type: %s, addr: %s, ifindex: %d, ifname: %s", - n.Type.String(), n.Addr.String(), n.Ifindex, n.Ifname) - return s -} - -func decodeNexthopsFromBytes(nexthops *[]*Nexthop, data []byte, isV4 bool, version uint8) (int, error) { - addrLen := net.IPv4len - if !isV4 { - addrLen = net.IPv6len - } - nhIfindex := NEXTHOP_IFINDEX - nhIfname := NEXTHOP_IFNAME - nhIPv4 := NEXTHOP_IPV4 - nhIPv4Ifindex := NEXTHOP_IPV4_IFINDEX - nhIPv4Ifname := NEXTHOP_IPV4_IFNAME - nhIPv6 := NEXTHOP_IPV6 - nhIPv6Ifindex := NEXTHOP_IPV6_IFINDEX - nhIPv6Ifname := NEXTHOP_IPV6_IFNAME - if version >= 4 { - nhIfindex = FRR_NEXTHOP_IFINDEX - nhIfname = NEXTHOP_FLAG(0) - nhIPv4 = FRR_NEXTHOP_IPV4 - nhIPv4Ifindex = FRR_NEXTHOP_IPV4_IFINDEX - nhIPv4Ifname = NEXTHOP_FLAG(0) - nhIPv6 = FRR_NEXTHOP_IPV6 - nhIPv6Ifindex = FRR_NEXTHOP_IPV6_IFINDEX - nhIPv6Ifname = NEXTHOP_FLAG(0) +func decodeNexthopsFromBytes(nexthops *[]Nexthop, data []byte, family uint8, version uint8) (int, error) { + addrByteLen, err := addressByteLength(family) + if err != nil { + return 0, err } numNexthop := int(data[0]) offset := 1 for i := 0; i < numNexthop; i++ { - nh := &Nexthop{} - nh.Type = NEXTHOP_FLAG(data[offset]) + nexthop := Nexthop{} + nexthop.Type = NEXTHOP_TYPE(data[offset]) offset += 1 - switch nh.Type { - case nhIfindex, nhIfname: - nh.Ifindex = binary.BigEndian.Uint32(data[offset : offset+4]) - offset += 4 + // On Quagga, NEXTHOP_TYPE_IFNAME is same as NEXTHOP_TYPE_IFINDEX, + // NEXTHOP_TYPE_IPV4_IFNAME is same as NEXTHOP_TYPE_IPV4_IFINDEX, + // NEXTHOP_TYPE_IPV6_IFNAME is same as NEXTHOP_TYPE_IPV6_IFINDEX - case nhIPv4, nhIPv6: - if isV4 { - nh.Addr = net.IP(data[offset : offset+addrLen]).To4() - } else { - nh.Addr = net.IP(data[offset : offset+addrLen]).To16() + // On FRRouting version 3.0 or later, NEXTHOP_TYPE_IPV4 and NEXTHOP_TYPE_IPV6 have + // the same structure with NEXTHOP_TYPE_IPV4_IFINDEX and NEXTHOP_TYPE_IPV6_IFINDEX. + + if (version <= 3 && (nexthop.Type == NEXTHOP_TYPE_IFINDEX || nexthop.Type == NEXTHOP_TYPE_IFNAME)) || + (version >= 4 && nexthop.Type == FRR_NEXTHOP_TYPE_IFINDEX) { + nexthop.Ifindex = binary.BigEndian.Uint32(data[offset : offset+4]) + offset += 4 + } else if version <= 3 && nexthop.Type == NEXTHOP_TYPE_IPV4 { + nexthop.Gate = net.IP(data[offset : offset+addrByteLen]).To4() + offset += addrByteLen + } else if version <= 3 && nexthop.Type == NEXTHOP_TYPE_IPV6 { + nexthop.Gate = net.IP(data[offset : offset+addrByteLen]).To16() + offset += addrByteLen + } else if (version <= 3 && (nexthop.Type == NEXTHOP_TYPE_IPV4_IFINDEX || nexthop.Type == NEXTHOP_TYPE_IPV4_IFNAME)) || + (version >= 4 && (nexthop.Type == FRR_NEXTHOP_TYPE_IPV4 || nexthop.Type == FRR_NEXTHOP_TYPE_IPV4_IFINDEX)) { + nexthop.Gate = net.IP(data[offset : offset+addrByteLen]).To4() + offset += addrByteLen + nexthop.Ifindex = binary.BigEndian.Uint32(data[offset : offset+4]) + offset += 4 + } else if (version <= 3 && (nexthop.Type == NEXTHOP_TYPE_IPV6_IFINDEX || nexthop.Type == NEXTHOP_TYPE_IPV6_IFNAME)) || + (version >= 4 && (nexthop.Type == FRR_NEXTHOP_TYPE_IPV6 || nexthop.Type == FRR_NEXTHOP_TYPE_IPV6_IFINDEX)) { + nexthop.Gate = net.IP(data[offset : offset+addrByteLen]).To16() + offset += addrByteLen + nexthop.Ifindex = binary.BigEndian.Uint32(data[offset : offset+4]) + offset += 4 + } + if version >= 5 { + nexthop.LabelNum = data[offset] + offset += 1 + if nexthop.LabelNum > MPLS_MAX_LABLE { + nexthop.LabelNum = MPLS_MAX_LABLE } - offset += addrLen - if version >= 4 { - // On FRRouting version 3.0 or later, NEXTHOP_IPV4 and - // NEXTHOP_IPV6 have the same structure with - // NEXTHOP_TYPE_IPV4_IFINDEX and NEXTHOP_TYPE_IPV6_IFINDEX. - nh.Ifindex = binary.BigEndian.Uint32(data[offset : offset+4]) + var n uint8 + for ; n < nexthop.LabelNum; n++ { + nexthop.MplsLabels[n] = binary.BigEndian.Uint32(data[offset : offset+4]) offset += 4 } - - case nhIPv4Ifindex, nhIPv4Ifname, nhIPv6Ifindex, nhIPv6Ifname: - if isV4 { - nh.Addr = net.IP(data[offset : offset+addrLen]).To4() - } else { - nh.Addr = net.IP(data[offset : offset+addrLen]).To16() - } - offset += addrLen - nh.Ifindex = binary.BigEndian.Uint32(data[offset : offset+4]) - offset += 4 } - *nexthops = append(*nexthops, nh) + *nexthops = append(*nexthops, nexthop) } return offset, nil } -func (b *NexthopLookupBody) Serialize(version uint8) ([]byte, error) { - isV4 := false - if version <= 3 { - isV4 = b.Api == IPV4_NEXTHOP_LOOKUP - } else { // version >= 4 - isV4 = b.Api == FRR_IPV4_NEXTHOP_LOOKUP_MRIB - } +type NexthopLookupBody struct { + Api API_TYPE + Addr net.IP + Distance uint8 + Metric uint32 + Nexthops []Nexthop +} +// Quagga only. Reference: zread_ipv[4|6]_nexthop_lookup in zebra/zserv.c of Quagga1.2.x (ZAPI3) +func (b *NexthopLookupBody) Serialize(version uint8) ([]byte, error) { + family := addressFamilyFromApi(b.Api, version) buf := make([]byte, 0) - if isV4 { + if family == syscall.AF_INET { buf = append(buf, b.Addr.To4()...) - } else { + } else if family == syscall.AF_INET6 { buf = append(buf, b.Addr.To16()...) } return buf, nil } +// Quagga only. Reference: zsend_ipv[4|6]_nexthop_lookup in zebra/zserv.c of Quagga1.2.x (ZAPI3) func (b *NexthopLookupBody) DecodeFromBytes(data []byte, version uint8) error { - isV4 := false - if version <= 3 { - isV4 = b.Api == IPV4_NEXTHOP_LOOKUP - } else { // version >= 4 - isV4 = b.Api == FRR_IPV4_NEXTHOP_LOOKUP_MRIB - } - addrLen := net.IPv4len - if !isV4 { - addrLen = net.IPv6len + family := addressFamilyFromApi(b.Api, version) + addrByteLen, err := addressByteLength(family) + if err != nil { + return err } - if len(data) < addrLen { + if len(data) < addrByteLen { return fmt.Errorf("message length invalid") } - buf := make([]byte, addrLen) - copy(buf, data[0:addrLen]) - pos := addrLen - - if isV4 { - b.Addr = net.IP(buf).To4() - } else { - b.Addr = net.IP(buf).To16() - } + buf := make([]byte, addrByteLen) + copy(buf, data[0:addrByteLen]) + pos := addrByteLen + b.Addr = ipFromFamily(family, buf) if version >= 4 { b.Distance = data[pos] pos++ } - if len(data[pos:]) > int(1+addrLen) { + if len(data[pos:]) > int(1+addrByteLen) { b.Metric = binary.BigEndian.Uint32(data[pos : pos+4]) pos += 4 - b.Nexthops = []*Nexthop{} - if nexthopsByteLen, err := decodeNexthopsFromBytes(&b.Nexthops, data[pos:], isV4, version); err != nil { + b.Nexthops = []Nexthop{} + if nexthopsByteLen, err := decodeNexthopsFromBytes(&b.Nexthops, data[pos:], family, version); err != nil { return err } else { pos += nexthopsByteLen @@ -1556,9 +2109,10 @@ type ImportLookupBody struct { Prefix net.IP Addr net.IP Metric uint32 - Nexthops []*Nexthop + Nexthops []Nexthop } +// Quagga only. Reference: zread_ipv4_import_lookup in zebra/zserv.c of Quagga1.2.x (ZAPI3) func (b *ImportLookupBody) Serialize(version uint8) ([]byte, error) { buf := make([]byte, 1) buf[0] = b.PrefixLength @@ -1566,28 +2120,29 @@ func (b *ImportLookupBody) Serialize(version uint8) ([]byte, error) { return buf, nil } +// Quagga only. Reference: zsend_ipv4_import_lookup in zebra/zserv.c of Quagga1.2.x (ZAPI3) func (b *ImportLookupBody) DecodeFromBytes(data []byte, version uint8) error { - isV4 := b.Api == IPV4_IMPORT_LOOKUP - addrLen := net.IPv4len - if !isV4 { - addrLen = net.IPv6len + family := addressFamilyFromApi(b.Api, version) + addrByteLen, err := addressByteLength(family) + if err != nil { + return err } - if len(data) < addrLen { + if len(data) < addrByteLen { return fmt.Errorf("message length invalid") } - buf := make([]byte, addrLen) - copy(buf, data[0:addrLen]) - pos := addrLen + buf := make([]byte, addrByteLen) + copy(buf, data[0:addrByteLen]) + pos := addrByteLen b.Addr = net.IP(buf).To4() - if len(data[pos:]) > int(1+addrLen) { + if len(data[pos:]) > int(1+addrByteLen) { b.Metric = binary.BigEndian.Uint32(data[pos : pos+4]) pos += 4 - b.Nexthops = []*Nexthop{} - if nexthopsByteLen, err := decodeNexthopsFromBytes(&b.Nexthops, data[pos:], isV4, version); err != nil { + b.Nexthops = []Nexthop{} + if nexthopsByteLen, err := decodeNexthopsFromBytes(&b.Nexthops, data[pos:], family, version); err != nil { return err } else { pos += nexthopsByteLen @@ -1628,6 +2183,9 @@ func (n *RegisteredNexthop) Len() int { } } +// Reference: sendmsg_nexthop in bgpd/bgp_nht.c of Quagga1.2.x (ZAPI3) +// Reference: sendmsg_zebra_rnh in bgpd/bgp_nht.c of FRR3.x (ZAPI4) +// Reference: zclient_send_rnh function in lib/zclient.c of FRR5.x (ZAPI5) func (n *RegisteredNexthop) Serialize() ([]byte, error) { // Connected (1 byte) buf := make([]byte, 4) @@ -1635,14 +2193,18 @@ func (n *RegisteredNexthop) Serialize() ([]byte, error) { // Address Family (2 bytes) binary.BigEndian.PutUint16(buf[1:3], n.Family) + // Prefix Length (1 byte) + addrByteLen, err := addressByteLength(uint8(n.Family)) + if err != nil { + return nil, err + } - // Prefix Length (1 byte) + Prefix (variable) + buf[3] = byte(addrByteLen * 8) + // Prefix (variable) switch n.Family { case uint16(syscall.AF_INET): - buf[3] = byte(net.IPv4len * 8) buf = append(buf, n.Prefix.To4()...) case uint16(syscall.AF_INET6): - buf[3] = byte(net.IPv6len * 8) buf = append(buf, n.Prefix.To16()...) default: return nil, fmt.Errorf("invalid address family: %d", n.Family) @@ -1651,27 +2213,18 @@ func (n *RegisteredNexthop) Serialize() ([]byte, error) { return buf, nil } +// Reference: zserv_nexthop_register in zebra/zserv.c of Quagga1.2.x (ZAPI3) +// Reference: zserv_rnh_register in zebra/zserv.c of FRR3.x (ZAPI4) +// Reference: zread_rnh_register in zebra/zapi_msg.c of FRR5.x (ZAPI5) func (n *RegisteredNexthop) DecodeFromBytes(data []byte) error { // Connected (1 byte) n.Connected = uint8(data[0]) - offset := 1 - // Address Family (2 bytes) - n.Family = binary.BigEndian.Uint16(data[offset : offset+2]) - isV4 := n.Family == uint16(syscall.AF_INET) - addrLen := int(net.IPv4len) - if !isV4 { - addrLen = net.IPv6len - } + n.Family = binary.BigEndian.Uint16(data[1:3]) // Note: Ignores Prefix Length (1 byte) - offset += 3 - + addrByteLen := (int(data[3]) + 7) / 8 // Prefix (variable) - if isV4 { - n.Prefix = net.IP(data[offset : offset+addrLen]).To4() - } else { - n.Prefix = net.IP(data[offset : offset+addrLen]).To16() - } + n.Prefix = ipFromFamily(uint8(n.Family), data[4:4+addrByteLen]) return nil } @@ -1687,6 +2240,9 @@ type NexthopRegisterBody struct { Nexthops []*RegisteredNexthop } +// Reference: sendmsg_nexthop in bgpd/bgp_nht.c of Quagga1.2.x (ZAPI3) +// Reference: sendmsg_zebra_rnh in bgpd/bgp_nht.c of FRR3.x (ZAPI4) +// Reference: zclient_send_rnh function in lib/zclient.c of FRR5.x (ZAPI5) func (b *NexthopRegisterBody) Serialize(version uint8) ([]byte, error) { buf := make([]byte, 0) @@ -1702,6 +2258,9 @@ func (b *NexthopRegisterBody) Serialize(version uint8) ([]byte, error) { return buf, nil } +// Reference: zserv_nexthop_register in zebra/zserv.c of Quagga1.2.x (ZAPI3) +// Reference: zserv_rnh_register in zebra/zserv.c of FRR3.x (ZAPI4) +// Reference: zread_rnh_register in zebra/zapi_msg.c of FRR5.x (ZAPI5) func (b *NexthopRegisterBody) DecodeFromBytes(data []byte, version uint8) error { offset := 0 @@ -1732,88 +2291,105 @@ func (b *NexthopRegisterBody) String() string { return strings.Join(s, ", ") } -type NexthopUpdateBody struct { - Api API_TYPE - Family uint16 - // Note: Ignores PrefixLength (uint8), - // because this field should be always: - // - 32 if Address Family is AF_INET - // - 128 if Address Family is AF_INET6 - Prefix net.IP - Distance uint8 - Metric uint32 - Nexthops []*Nexthop -} +/* NEXTHOP_UPDATE message uses same data structure as IPRoute (zapi_route) + in FRR version 4, 5 (ZApi version 5) */ +type NexthopUpdateBody IPRouteBody +// Reference: send_client function in zebra/zebra_rnh.c of Quagga1.2.x (ZAPI3) +// Reference: send_client function in zebra/zebra_rnh.c of FRR3.x (ZAPI4) +// Reference: send_client function in zebra/zebra_rnh.c of FRR5.x (ZAPI5) func (b *NexthopUpdateBody) Serialize(version uint8) ([]byte, error) { // Address Family (2 bytes) buf := make([]byte, 3) - binary.BigEndian.PutUint16(buf, b.Family) + binary.BigEndian.PutUint16(buf, uint16(b.Prefix.Family)) + addrByteLen, err := addressByteLength(b.Prefix.Family) + if err != nil { + return nil, err + } + buf[2] = byte(addrByteLen * 8) // Prefix Length (1 byte) + Prefix (variable) - switch b.Family { - case uint16(syscall.AF_INET): - buf[2] = byte(net.IPv4len * 8) - buf = append(buf, b.Prefix.To4()...) - case uint16(syscall.AF_INET6): - buf[2] = byte(net.IPv6len * 8) - buf = append(buf, b.Prefix.To16()...) + switch b.Prefix.Family { + case syscall.AF_INET: + buf = append(buf, b.Prefix.Prefix.To4()...) + case syscall.AF_INET6: + buf = append(buf, b.Prefix.Prefix.To16()...) default: - return nil, fmt.Errorf("invalid address family: %d", b.Family) + return nil, fmt.Errorf("invalid address family: %d", b.Prefix.Family) + } + if version >= 5 { + // Type (1 byte) (if version>=5) + // Instance (2 bytes) (if version>=5) + buf = append(buf, byte(b.Type)) + bbuf := make([]byte, 2) + binary.BigEndian.PutUint16(bbuf, b.Instance) + buf = append(buf, bbuf...) + } + if version >= 4 { + // Distance (1 byte) (if version>=4) + buf = append(buf, b.Distance) } + // Metric (4 bytes) + bbuf := make([]byte, 4) + binary.BigEndian.PutUint32(bbuf, b.Metric) + buf = append(buf, bbuf...) + // Number of Nexthops (1 byte) + buf = append(buf, uint8(0)) // Temporary code + // ToDo Processing Route Entry return buf, nil } +// Reference: bgp_parse_nexthop_update function in bgpd/bgp_nht.c of Quagga1.2.x (ZAPI3) +// Reference: bgp_parse_nexthop_update function in bgpd/bgp_nht.c of FRR3.x (ZAPI4) +// Reference: zapi_nexthop_update_decode function in lib/zclient.c of FRR5.x (ZAPI5) func (b *NexthopUpdateBody) DecodeFromBytes(data []byte, version uint8) error { // Address Family (2 bytes) - b.Family = binary.BigEndian.Uint16(data[0:2]) - isV4 := b.Family == uint16(syscall.AF_INET) - addrLen := int(net.IPv4len) - if !isV4 { - addrLen = net.IPv6len - } - // Note: Ignores Prefix Length (1 byte) + prefixFamily := binary.BigEndian.Uint16(data[0:2]) + b.Prefix.Family = uint8(prefixFamily) + b.Prefix.PrefixLen = data[2] offset := 3 - // Prefix (variable) - if isV4 { - b.Prefix = net.IP(data[offset : offset+addrLen]).To4() - } else { - b.Prefix = net.IP(data[offset : offset+addrLen]).To16() + addrByteLen, err := addressByteLength(b.Prefix.Family) + if err != nil { + return err } - offset += addrLen + b.Prefix.Prefix = ipFromFamily(b.Prefix.Family, data[offset:offset+addrByteLen]) + offset += addrByteLen + + if version >= 5 { + b.Type = ROUTE_TYPE(data[offset]) + b.Instance = binary.BigEndian.Uint16(data[offset+1 : offset+3]) + offset += 3 + } // Distance (1 byte) (if version>=4) - // Metric (4 bytes) - // Number of Nexthops (1 byte) if version >= 4 { - if len(data[offset:]) < 6 { - return fmt.Errorf("invalid message length: missing distance(1 byte), metric(4 bytes) or nexthops(1 byte): %d<6", len(data[offset:])) - } b.Distance = data[offset] offset += 1 - } else if len(data[offset:]) < 5 { + } + // Metric (4 bytes) + // Number of Nexthops (1 byte) + if len(data[offset:]) < 5 { return fmt.Errorf("invalid message length: missing metric(4 bytes) or nexthops(1 byte): %d<5", len(data[offset:])) } b.Metric = binary.BigEndian.Uint32(data[offset : offset+4]) offset += 4 // List of Nexthops - b.Nexthops = []*Nexthop{} - if nexthopsByteLen, err := decodeNexthopsFromBytes(&b.Nexthops, data[offset:], isV4, version); err != nil { + b.Nexthops = []Nexthop{} + if nexthopsByteLen, err := decodeNexthopsFromBytes(&b.Nexthops, data[offset:], b.Prefix.Family, version); err != nil { return err } else { offset += nexthopsByteLen } - return nil } func (b *NexthopUpdateBody) String() string { s := fmt.Sprintf( "family: %d, prefix: %s, distance: %d, metric: %d", - b.Family, b.Prefix.String(), b.Distance, b.Metric) + b.Prefix.Family, b.Prefix.Prefix.String(), b.Distance, b.Metric) for _, nh := range b.Nexthops { s = s + fmt.Sprintf(", nexthop:{%s}", nh.String()) } @@ -1903,10 +2479,51 @@ func (m *Message) parseFrrMessage(data []byte) error { return m.Body.DecodeFromBytes(data, m.Header.Version) } +func (m *Message) parseFrrZapi5Message(data []byte) error { + switch m.Header.Command { + case FRR_ZAPI5_INTERFACE_ADD, FRR_ZAPI5_INTERFACE_DELETE, FRR_ZAPI5_INTERFACE_UP, FRR_ZAPI5_INTERFACE_DOWN: + m.Body = &InterfaceUpdateBody{} + case FRR_ZAPI5_INTERFACE_ADDRESS_ADD, FRR_ZAPI5_INTERFACE_ADDRESS_DELETE: + m.Body = &InterfaceAddressUpdateBody{} + case FRR_ZAPI5_ROUTER_ID_UPDATE: + m.Body = &RouterIDUpdateBody{} + case FRR_ZAPI5_NEXTHOP_UPDATE: + m.Body = &NexthopUpdateBody{} + case FRR_ZAPI5_INTERFACE_NBR_ADDRESS_ADD, FRR_ZAPI5_INTERFACE_NBR_ADDRESS_DELETE: + // TODO + m.Body = &UnknownBody{} + case FRR_ZAPI5_INTERFACE_BFD_DEST_UPDATE: + // TODO + m.Body = &UnknownBody{} + case FRR_ZAPI5_IMPORT_CHECK_UPDATE: + // TODO + m.Body = &UnknownBody{} + case FRR_ZAPI5_BFD_DEST_REPLAY: + // TODO + m.Body = &UnknownBody{} + case FRR_ZAPI5_REDISTRIBUTE_ROUTE_ADD, FRR_ZAPI5_REDISTRIBUTE_ROUTE_DEL: + m.Body = &IPRouteBody{Api: m.Header.Command} + case FRR_ZAPI5_INTERFACE_VRF_UPDATE: + // TODO + m.Body = &UnknownBody{} + case FRR_ZAPI5_INTERFACE_LINK_PARAMS: + // TODO + m.Body = &UnknownBody{} + case FRR_ZAPI5_PW_STATUS_UPDATE: + // TODO + m.Body = &UnknownBody{} + default: + m.Body = &UnknownBody{} + } + return m.Body.DecodeFromBytes(data, m.Header.Version) +} + func ParseMessage(hdr *Header, data []byte) (m *Message, err error) { m = &Message{Header: *hdr} if m.Header.Version == 4 { err = m.parseFrrMessage(data) + } else if m.Header.Version == 5 { + err = m.parseFrrZapi5Message(data) } else { err = m.parseMessage(data) } diff --git a/internal/pkg/zebra/zapi_test.go b/internal/pkg/zebra/zapi_test.go index 9fda5416..12cb5f93 100644 --- a/internal/pkg/zebra/zapi_test.go +++ b/internal/pkg/zebra/zapi_test.go @@ -165,7 +165,7 @@ func Test_IPRouteBody_IPv4(t *testing.T) { buf := make([]byte, 26) buf[0] = byte(ROUTE_CONNECT) buf[1] = byte(FLAG_SELECTED) - buf[2] = byte(MESSAGE_NEXTHOP | MESSAGE_DISTANCE | MESSAGE_METRIC | MESSAGE_MTU) + buf[2] = byte(MESSAGE_NEXTHOP | MESSAGE_IFINDEX | MESSAGE_DISTANCE | MESSAGE_METRIC | MESSAGE_MTU) buf[3] = 24 ip := net.ParseIP("192.168.100.0").To4() copy(buf[4:7], []byte(ip)) @@ -183,11 +183,11 @@ func Test_IPRouteBody_IPv4(t *testing.T) { err := r.DecodeFromBytes(buf, 2) assert.Equal(nil, err) - assert.Equal("192.168.100.0", r.Prefix.String()) - assert.Equal(uint8(0x18), r.PrefixLength) - assert.Equal(MESSAGE_NEXTHOP|MESSAGE_DISTANCE|MESSAGE_METRIC|MESSAGE_MTU, r.Message) - assert.Equal("0.0.0.0", r.Nexthops[0].String()) - assert.Equal(uint32(1), r.Ifindexs[0]) + assert.Equal("192.168.100.0", r.Prefix.Prefix.String()) + assert.Equal(uint8(0x18), r.Prefix.PrefixLen) + assert.Equal(MESSAGE_NEXTHOP|MESSAGE_IFINDEX|MESSAGE_DISTANCE|MESSAGE_METRIC|MESSAGE_MTU, r.Message) + assert.Equal("0.0.0.0", r.Nexthops[0].Gate.String()) + assert.Equal(uint32(1), r.Nexthops[1].Ifindex) assert.Equal(uint8(0), r.Distance) assert.Equal(uint32(1), r.Metric) assert.Equal(uint32(1), r.Mtu) @@ -195,13 +195,14 @@ func Test_IPRouteBody_IPv4(t *testing.T) { //Serialize buf, err = r.Serialize(2) assert.Equal(nil, err) - assert.Equal([]byte{0x2, 0x10, 0x1d}, buf[0:3]) + assert.Equal([]byte{0x2, 0x10, 0x1f}, buf[0:3]) assert.Equal([]byte{0x0, 0x1}, buf[3:5]) assert.Equal(byte(24), buf[5]) ip = net.ParseIP("192.168.100.0").To4() assert.Equal([]byte(ip)[0:3], buf[6:9]) - assert.Equal(byte(NEXTHOP_IPV4), buf[10]) - assert.Equal(byte(NEXTHOP_IFINDEX), buf[15]) + assert.Equal(byte(2), buf[9]) + assert.Equal(byte(NEXTHOP_TYPE_IPV4), buf[10]) + assert.Equal(byte(NEXTHOP_TYPE_IFINDEX), buf[15]) assert.Equal(byte(0x0), buf[20]) bi := make([]byte, 4) @@ -213,7 +214,7 @@ func Test_IPRouteBody_IPv4(t *testing.T) { buf = make([]byte, 18) buf[0] = byte(ROUTE_CONNECT) buf[1] = byte(FLAG_SELECTED) - buf[2] = byte(MESSAGE_NEXTHOP | MESSAGE_DISTANCE | MESSAGE_METRIC) + buf[2] = byte(MESSAGE_NEXTHOP | MESSAGE_IFINDEX | MESSAGE_DISTANCE | MESSAGE_METRIC) buf[3] = 24 ip = net.ParseIP("192.168.100.0").To4() copy(buf[4:7], []byte(ip)) @@ -225,7 +226,7 @@ func Test_IPRouteBody_IPv4(t *testing.T) { r = &IPRouteBody{Api: IPV4_ROUTE_ADD} err = r.DecodeFromBytes(buf, 2) - assert.Equal("message length invalid", err.Error()) + assert.Equal("MESSAGE_METRIC message length invalid pos:16 rest:16", err.Error()) // no nexthop buf = make([]byte, 12) @@ -250,7 +251,7 @@ func Test_IPRouteBody_IPv6(t *testing.T) { buf := make([]byte, 43) buf[0] = byte(ROUTE_CONNECT) buf[1] = byte(FLAG_SELECTED) - buf[2] = byte(MESSAGE_NEXTHOP | MESSAGE_DISTANCE | MESSAGE_METRIC | MESSAGE_MTU) + buf[2] = byte(MESSAGE_NEXTHOP | MESSAGE_IFINDEX | MESSAGE_DISTANCE | MESSAGE_METRIC | MESSAGE_MTU) buf[3] = 64 ip := net.ParseIP("2001:db8:0:f101::").To16() copy(buf[4:12], []byte(ip)) @@ -269,11 +270,11 @@ func Test_IPRouteBody_IPv6(t *testing.T) { err := r.DecodeFromBytes(buf, 2) assert.Equal(nil, err) - assert.Equal("2001:db8:0:f101::", r.Prefix.String()) - assert.Equal(uint8(64), r.PrefixLength) - assert.Equal(MESSAGE_NEXTHOP|MESSAGE_DISTANCE|MESSAGE_METRIC|MESSAGE_MTU, r.Message) - assert.Equal("::", r.Nexthops[0].String()) - assert.Equal(uint32(1), r.Ifindexs[0]) + assert.Equal("2001:db8:0:f101::", r.Prefix.Prefix.String()) + assert.Equal(uint8(64), r.Prefix.PrefixLen) + assert.Equal(MESSAGE_NEXTHOP|MESSAGE_IFINDEX|MESSAGE_DISTANCE|MESSAGE_METRIC|MESSAGE_MTU, r.Message) + assert.Equal("::", r.Nexthops[0].Gate.String()) + assert.Equal(uint32(1), r.Nexthops[1].Ifindex) assert.Equal(uint8(0), r.Distance) assert.Equal(uint32(1), r.Metric) assert.Equal(uint32(1), r.Mtu) @@ -281,16 +282,16 @@ func Test_IPRouteBody_IPv6(t *testing.T) { //Serialize buf, err = r.Serialize(2) assert.Equal(nil, err) - assert.Equal([]byte{0x2, 0x10, 0x1d}, buf[0:3]) + assert.Equal([]byte{0x2, 0x10, 0x1f}, buf[0:3]) assert.Equal([]byte{0x0, 0x1}, buf[3:5]) assert.Equal(byte(64), buf[5]) ip = net.ParseIP("2001:db8:0:f101::").To16() assert.Equal([]byte(ip)[0:8], buf[6:14]) assert.Equal(byte(2), buf[14]) - assert.Equal(byte(NEXTHOP_IPV6), buf[15]) + assert.Equal(byte(NEXTHOP_TYPE_IPV6), buf[15]) ip = net.ParseIP("::").To16() assert.Equal([]byte(ip), buf[16:32]) - assert.Equal(byte(NEXTHOP_IFINDEX), buf[32]) + assert.Equal(byte(NEXTHOP_TYPE_IFINDEX), buf[32]) bi := make([]byte, 4) binary.BigEndian.PutUint32(bi, 1) assert.Equal(bi, buf[33:37]) @@ -306,7 +307,7 @@ func Test_IPRouteBody_IPv6(t *testing.T) { buf = make([]byte, 50) buf[0] = byte(ROUTE_CONNECT) buf[1] = byte(FLAG_SELECTED) - buf[2] = byte(MESSAGE_NEXTHOP | MESSAGE_DISTANCE | MESSAGE_METRIC) + buf[2] = byte(MESSAGE_NEXTHOP | MESSAGE_IFINDEX | MESSAGE_DISTANCE | MESSAGE_METRIC) buf[3] = 24 ip = net.ParseIP("2001:db8:0:f101::").To4() copy(buf[4:12], []byte(ip)) @@ -362,8 +363,8 @@ func Test_NexthopLookupBody(t *testing.T) { assert.Equal("192.168.50.0", b.Addr.String()) assert.Equal(uint32(10), b.Metric) assert.Equal(uint32(3), b.Nexthops[0].Ifindex) - assert.Equal(NEXTHOP_FLAG(4), b.Nexthops[0].Type) - assert.Equal("172.16.1.101", b.Nexthops[0].Addr.String()) + assert.Equal(NEXTHOP_TYPE(4), b.Nexthops[0].Type) + assert.Equal("172.16.1.101", b.Nexthops[0].Gate.String()) //Serialize buf, err = b.Serialize(2) @@ -388,7 +389,7 @@ func Test_NexthopLookupBody(t *testing.T) { pos += 4 buf[pos] = byte(1) pos += 1 - buf[pos] = byte(4) + buf[pos] = byte(7) pos += 1 ip = net.ParseIP("2001:db8:0:1111::1").To16() copy(buf[pos:pos+16], []byte(ip)) @@ -401,8 +402,8 @@ func Test_NexthopLookupBody(t *testing.T) { assert.Equal("2001:db8:0:f101::", b.Addr.String()) assert.Equal(uint32(10), b.Metric) assert.Equal(uint32(3), b.Nexthops[0].Ifindex) - assert.Equal(NEXTHOP_FLAG(4), b.Nexthops[0].Type) - assert.Equal("2001:db8:0:1111::1", b.Nexthops[0].Addr.String()) + assert.Equal(NEXTHOP_TYPE(7), b.Nexthops[0].Type) + assert.Equal("2001:db8:0:1111::1", b.Nexthops[0].Gate.String()) //Serialize buf, err = b.Serialize(2) @@ -443,8 +444,8 @@ func Test_ImportLookupBody(t *testing.T) { assert.Equal("192.168.50.0", b.Addr.String()) assert.Equal(uint32(10), b.Metric) assert.Equal(uint32(3), b.Nexthops[0].Ifindex) - assert.Equal(NEXTHOP_FLAG(4), b.Nexthops[0].Type) - assert.Equal("172.16.1.101", b.Nexthops[0].Addr.String()) + assert.Equal(NEXTHOP_TYPE(4), b.Nexthops[0].Type) + assert.Equal("172.16.1.101", b.Nexthops[0].Gate.String()) //Serialize b.PrefixLength = uint8(24) @@ -518,12 +519,12 @@ func Test_NexthopUpdateBody(t *testing.T) { assert.Nil(err) // Test decoded values - assert.Equal(uint16(syscall.AF_INET), b.Family) - assert.Equal(net.ParseIP("192.168.1.1").To4(), b.Prefix) + assert.Equal(uint8(syscall.AF_INET), b.Prefix.Family) + assert.Equal(net.ParseIP("192.168.1.1").To4(), b.Prefix.Prefix) assert.Equal(uint32(1), b.Metric) - nexthop := &Nexthop{ - Type: NEXTHOP_FLAG(NEXTHOP_IPV4_IFINDEX), - Addr: net.ParseIP("192.168.1.1").To4(), + nexthop := Nexthop{ + Type: NEXTHOP_TYPE(NEXTHOP_TYPE_IPV4_IFINDEX), + Gate: net.ParseIP("192.168.1.1").To4(), Ifindex: uint32(2), } assert.Equal(1, len(b.Nexthops)) |