mirror of
https://github.com/osrg/gobgp.git
synced 2024-05-11 05:55:10 +00:00
Supporting BGP/MPLS L3VPNs with Frrouting Zebra API 6
- This commit aims to solve reported problem on issues #1611, #1648 and #1912
- Partial changes of this commit duplicate with changes on PR #1587 (not merged) and PR #1766 (not merged and already closed)
- This commit is tested with only FRRouting version 6.0.2 (which uses Zebra API 6)
- This commit fixes lack of LABEL_MANAGER_CONNECT_ASYNC for ZAPI6.
(This bug is introduced on commit 2bdb76f2dc "Supporting Zebra API version 6 which is used in FRRouting version 6")
This commit is contained in:
committed by
FUJITA Tomonori
parent
dc4d9c6d1b
commit
3a79ad3fdc
+500
-490
File diff suppressed because it is too large
Load Diff
@@ -414,6 +414,7 @@ message EnableZebraRequest {
|
||||
uint32 version = 3;
|
||||
bool nexthop_trigger_enable = 4;
|
||||
uint32 nexthop_trigger_delay = 5;
|
||||
uint32 mpls_label_range_size = 6;
|
||||
}
|
||||
|
||||
message EnableMrtRequest {
|
||||
|
||||
@@ -241,6 +241,7 @@ func main() {
|
||||
Version: uint32(c.Zebra.Config.Version),
|
||||
NexthopTriggerEnable: c.Zebra.Config.NexthopTriggerEnable,
|
||||
NexthopTriggerDelay: uint32(c.Zebra.Config.NexthopTriggerDelay),
|
||||
MplsLabelRangeSize: uint32(c.Zebra.Config.MplsLabelRangeSize),
|
||||
}); err != nil {
|
||||
log.Fatalf("failed to set zebra config: %s", err)
|
||||
}
|
||||
|
||||
@@ -1121,13 +1121,18 @@ type ZebraState struct {
|
||||
// original -> gobgp:redistribute-route-type
|
||||
RedistributeRouteTypeList []string `mapstructure:"redistribute-route-type-list" json:"redistribute-route-type-list,omitempty"`
|
||||
// original -> gobgp:version
|
||||
// Configure version of zebra protocol. Default is 2. Supported up to 3.
|
||||
// Configure version of zebra protocol. Default is 2.
|
||||
// Supported version are 2 or 3 for Quagga and 4, 5 or 6 for FRRouting.
|
||||
Version uint8 `mapstructure:"version" json:"version,omitempty"`
|
||||
// original -> gobgp:nexthop-trigger-enable
|
||||
// gobgp:nexthop-trigger-enable's original type is boolean.
|
||||
NexthopTriggerEnable bool `mapstructure:"nexthop-trigger-enable" json:"nexthop-trigger-enable,omitempty"`
|
||||
// original -> gobgp:nexthop-trigger-delay
|
||||
NexthopTriggerDelay uint8 `mapstructure:"nexthop-trigger-delay" json:"nexthop-trigger-delay,omitempty"`
|
||||
// original -> gobgp:mpls-label-range-size
|
||||
// Configure MPLS label range size which will be requested to
|
||||
// FRR/Zebra.
|
||||
MplsLabelRangeSize uint32 `mapstructure:"mpls-label-range-size" json:"mpls-label-range-size,omitempty"`
|
||||
}
|
||||
|
||||
// struct for container gobgp:config.
|
||||
@@ -1142,13 +1147,18 @@ type ZebraConfig struct {
|
||||
// original -> gobgp:redistribute-route-type
|
||||
RedistributeRouteTypeList []string `mapstructure:"redistribute-route-type-list" json:"redistribute-route-type-list,omitempty"`
|
||||
// original -> gobgp:version
|
||||
// Configure version of zebra protocol. Default is 2. Supported up to 3.
|
||||
// Configure version of zebra protocol. Default is 2.
|
||||
// Supported version are 2 or 3 for Quagga and 4, 5 or 6 for FRRouting.
|
||||
Version uint8 `mapstructure:"version" json:"version,omitempty"`
|
||||
// original -> gobgp:nexthop-trigger-enable
|
||||
// gobgp:nexthop-trigger-enable's original type is boolean.
|
||||
NexthopTriggerEnable bool `mapstructure:"nexthop-trigger-enable" json:"nexthop-trigger-enable,omitempty"`
|
||||
// original -> gobgp:nexthop-trigger-delay
|
||||
NexthopTriggerDelay uint8 `mapstructure:"nexthop-trigger-delay" json:"nexthop-trigger-delay,omitempty"`
|
||||
// original -> gobgp:mpls-label-range-size
|
||||
// Configure MPLS label range size which will be requested to
|
||||
// FRR/Zebra.
|
||||
MplsLabelRangeSize uint32 `mapstructure:"mpls-label-range-size" json:"mpls-label-range-size,omitempty"`
|
||||
}
|
||||
|
||||
func (lhs *ZebraConfig) Equal(rhs *ZebraConfig) bool {
|
||||
@@ -1178,6 +1188,9 @@ func (lhs *ZebraConfig) Equal(rhs *ZebraConfig) bool {
|
||||
if lhs.NexthopTriggerDelay != rhs.NexthopTriggerDelay {
|
||||
return false
|
||||
}
|
||||
if lhs.MplsLabelRangeSize != rhs.MplsLabelRangeSize {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
+25
-13
@@ -133,13 +133,14 @@ type Validation struct {
|
||||
}
|
||||
|
||||
type Path struct {
|
||||
info *originInfo
|
||||
parent *Path
|
||||
pathAttrs []bgp.PathAttributeInterface
|
||||
dels []bgp.BGPAttrType
|
||||
attrsHash uint32
|
||||
aslooped bool
|
||||
reason BestPathReason
|
||||
info *originInfo
|
||||
parent *Path
|
||||
pathAttrs []bgp.PathAttributeInterface
|
||||
dels []bgp.BGPAttrType
|
||||
attrsHash uint32
|
||||
aslooped bool
|
||||
reason BestPathReason
|
||||
receiveVrfId uint32 //VRF in which the path was received.
|
||||
|
||||
// For BGP Nexthop Tracking, this field shows if nexthop is invalidated by IGP.
|
||||
IsNexthopInvalid bool
|
||||
@@ -167,8 +168,9 @@ func NewPath(source *PeerInfo, nlri bgp.AddrPrefixInterface, isWithdraw bool, pa
|
||||
timestamp: timestamp.Unix(),
|
||||
noImplicitWithdraw: noImplicitWithdraw,
|
||||
},
|
||||
IsWithdraw: isWithdraw,
|
||||
pathAttrs: pattrs,
|
||||
IsWithdraw: isWithdraw,
|
||||
pathAttrs: pattrs,
|
||||
receiveVrfId: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,6 +334,13 @@ func (path *Path) IsIBGP() bool {
|
||||
return (as == path.GetSource().LocalAS) && as != 0
|
||||
}
|
||||
|
||||
func (path *Path) ReceiveVrfId() uint32 {
|
||||
return path.receiveVrfId
|
||||
}
|
||||
func (path *Path) SetReceiveVrfId(vrfId uint32) {
|
||||
path.receiveVrfId = vrfId
|
||||
}
|
||||
|
||||
// create new PathAttributes
|
||||
func (path *Path) Clone(isWithdraw bool) *Path {
|
||||
return &Path{
|
||||
@@ -339,6 +348,7 @@ func (path *Path) Clone(isWithdraw bool) *Path {
|
||||
IsWithdraw: isWithdraw,
|
||||
IsNexthopInvalid: path.IsNexthopInvalid,
|
||||
attrsHash: path.attrsHash,
|
||||
receiveVrfId: path.receiveVrfId,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -580,6 +590,7 @@ func (path *Path) String() string {
|
||||
if path.IsWithdraw {
|
||||
s.WriteString(", withdraw")
|
||||
}
|
||||
s.WriteString(fmt.Sprintf(", receiveVrfId: %d", path.receiveVrfId))
|
||||
s.WriteString(" }")
|
||||
return s.String()
|
||||
}
|
||||
@@ -1069,12 +1080,12 @@ func (v *Vrf) ToGlobalPath(path *Path) error {
|
||||
case bgp.RF_IPv4_UC:
|
||||
n := nlri.(*bgp.IPAddrPrefix)
|
||||
pathIdentifier := path.GetNlri().PathIdentifier()
|
||||
path.OriginInfo().nlri = bgp.NewLabeledVPNIPAddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(0), v.Rd)
|
||||
path.OriginInfo().nlri = bgp.NewLabeledVPNIPAddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(v.MplsLabel), v.Rd)
|
||||
path.GetNlri().SetPathIdentifier(pathIdentifier)
|
||||
case bgp.RF_IPv6_UC:
|
||||
n := nlri.(*bgp.IPv6AddrPrefix)
|
||||
pathIdentifier := path.GetNlri().PathIdentifier()
|
||||
path.OriginInfo().nlri = bgp.NewLabeledVPNIPv6AddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(0), v.Rd)
|
||||
path.OriginInfo().nlri = bgp.NewLabeledVPNIPv6AddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(v.MplsLabel), v.Rd)
|
||||
path.GetNlri().SetPathIdentifier(pathIdentifier)
|
||||
case bgp.RF_EVPN:
|
||||
n := nlri.(*bgp.EVPNNLRI)
|
||||
@@ -1098,11 +1109,11 @@ func (p *Path) ToGlobal(vrf *Vrf) *Path {
|
||||
switch rf := p.GetRouteFamily(); rf {
|
||||
case bgp.RF_IPv4_UC:
|
||||
n := nlri.(*bgp.IPAddrPrefix)
|
||||
nlri = bgp.NewLabeledVPNIPAddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(0), vrf.Rd)
|
||||
nlri = bgp.NewLabeledVPNIPAddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(vrf.MplsLabel), vrf.Rd)
|
||||
nlri.SetPathIdentifier(pathId)
|
||||
case bgp.RF_IPv6_UC:
|
||||
n := nlri.(*bgp.IPv6AddrPrefix)
|
||||
nlri = bgp.NewLabeledVPNIPv6AddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(0), vrf.Rd)
|
||||
nlri = bgp.NewLabeledVPNIPv6AddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(vrf.MplsLabel), vrf.Rd)
|
||||
nlri.SetPathIdentifier(pathId)
|
||||
case bgp.RF_EVPN:
|
||||
n := nlri.(*bgp.EVPNNLRI)
|
||||
@@ -1138,6 +1149,7 @@ func (p *Path) ToGlobal(vrf *Vrf) *Path {
|
||||
path.delPathAttr(bgp.BGP_ATTR_TYPE_NEXT_HOP)
|
||||
path.setPathAttr(bgp.NewPathAttributeMpReachNLRI(nh.String(), []bgp.AddrPrefixInterface{nlri}))
|
||||
path.IsNexthopInvalid = p.IsNexthopInvalid
|
||||
path.receiveVrfId = p.receiveVrfId
|
||||
return path
|
||||
}
|
||||
|
||||
|
||||
@@ -105,9 +105,10 @@ func ProcessMessage(m *bgp.BGPMessage, peerInfo *PeerInfo, timestamp time.Time)
|
||||
}
|
||||
|
||||
type TableManager struct {
|
||||
Tables map[bgp.RouteFamily]*Table
|
||||
Vrfs map[string]*Vrf
|
||||
rfList []bgp.RouteFamily
|
||||
Tables map[bgp.RouteFamily]*Table
|
||||
Vrfs map[string]*Vrf
|
||||
rfList []bgp.RouteFamily
|
||||
mplsLabelMaps map[uint64]*Bitmap
|
||||
}
|
||||
|
||||
func NewTableManager(rfList []bgp.RouteFamily) *TableManager {
|
||||
@@ -122,6 +123,63 @@ func NewTableManager(rfList []bgp.RouteFamily) *TableManager {
|
||||
return t
|
||||
}
|
||||
|
||||
func (manager *TableManager) EnableMplsLabelAllocation() error {
|
||||
if manager.mplsLabelMaps != nil {
|
||||
return fmt.Errorf("label allocation already enabled")
|
||||
}
|
||||
manager.mplsLabelMaps = make(map[uint64]*Bitmap)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (manager *TableManager) AllocateMplsLabelRange(start, end uint32) error {
|
||||
if manager.mplsLabelMaps == nil {
|
||||
return fmt.Errorf("label allocation not yet enabled")
|
||||
}
|
||||
log.WithFields(log.Fields{
|
||||
"Topic": "Vrf",
|
||||
"Start": start,
|
||||
"End": end,
|
||||
}).Debug("allocate new MPLS label range")
|
||||
startEnd := uint64(start)<<32 | uint64(end)
|
||||
manager.mplsLabelMaps[startEnd] = NewBitmap(int(end - start + 1))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (manager *TableManager) AssignMplsLabel() (uint32, error) {
|
||||
if manager.mplsLabelMaps == nil {
|
||||
return 0, nil
|
||||
}
|
||||
var label uint32
|
||||
for startEnd, bitmap := range manager.mplsLabelMaps {
|
||||
start := uint32(startEnd >> 32)
|
||||
end := uint32(startEnd & 0xffffffff)
|
||||
l, err := bitmap.FindandSetZeroBit()
|
||||
if err == nil && start+uint32(l) <= end {
|
||||
label = start + uint32(l)
|
||||
break
|
||||
}
|
||||
}
|
||||
if label == 0 {
|
||||
return 0, fmt.Errorf("could not assign new MPLS label; need to allocate new MPLS label range")
|
||||
}
|
||||
return label, nil
|
||||
}
|
||||
|
||||
func (manager *TableManager) releaseMplsLabel(label uint32) {
|
||||
if manager.mplsLabelMaps == nil {
|
||||
return
|
||||
}
|
||||
for startEnd, bitmap := range manager.mplsLabelMaps {
|
||||
start := uint32(startEnd >> 32)
|
||||
end := uint32(startEnd & 0xffffffff)
|
||||
if start <= label && label <= end {
|
||||
bitmap.Unflag(uint(label - start))
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (manager *TableManager) GetRFlist() []bgp.RouteFamily {
|
||||
return manager.rfList
|
||||
}
|
||||
@@ -166,12 +224,14 @@ func (manager *TableManager) DeleteVrf(name string) ([]*Path, error) {
|
||||
msgs = append(msgs, t.deletePathsByVrf(vrf)...)
|
||||
}
|
||||
log.WithFields(log.Fields{
|
||||
"Topic": "Vrf",
|
||||
"Key": vrf.Name,
|
||||
"Rd": vrf.Rd,
|
||||
"ImportRt": vrf.ImportRt,
|
||||
"ExportRt": vrf.ExportRt,
|
||||
"Topic": "Vrf",
|
||||
"Key": vrf.Name,
|
||||
"Rd": vrf.Rd,
|
||||
"ImportRt": vrf.ImportRt,
|
||||
"ExportRt": vrf.ExportRt,
|
||||
"MplsLabel": vrf.MplsLabel,
|
||||
}).Debugf("delete vrf")
|
||||
manager.releaseMplsLabel(vrf.MplsLabel)
|
||||
delete(manager.Vrfs, name)
|
||||
rtcTable := manager.Tables[bgp.RF_RTC_UC]
|
||||
msgs = append(msgs, rtcTable.deleteRTCPathsByVrf(vrf, manager.Vrfs)...)
|
||||
|
||||
+12
-10
@@ -20,11 +20,12 @@ import (
|
||||
)
|
||||
|
||||
type Vrf struct {
|
||||
Name string
|
||||
Id uint32
|
||||
Rd bgp.RouteDistinguisherInterface
|
||||
ImportRt []bgp.ExtendedCommunityInterface
|
||||
ExportRt []bgp.ExtendedCommunityInterface
|
||||
Name string
|
||||
Id uint32
|
||||
Rd bgp.RouteDistinguisherInterface
|
||||
ImportRt []bgp.ExtendedCommunityInterface
|
||||
ExportRt []bgp.ExtendedCommunityInterface
|
||||
MplsLabel uint32
|
||||
}
|
||||
|
||||
func (v *Vrf) Clone() *Vrf {
|
||||
@@ -33,11 +34,12 @@ func (v *Vrf) Clone() *Vrf {
|
||||
return append(l, rt...)
|
||||
}
|
||||
return &Vrf{
|
||||
Name: v.Name,
|
||||
Id: v.Id,
|
||||
Rd: v.Rd,
|
||||
ImportRt: f(v.ImportRt),
|
||||
ExportRt: f(v.ExportRt),
|
||||
Name: v.Name,
|
||||
Id: v.Id,
|
||||
Rd: v.Rd,
|
||||
ImportRt: f(v.ImportRt),
|
||||
ExportRt: f(v.ExportRt),
|
||||
MplsLabel: v.MplsLabel,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ package zebra
|
||||
|
||||
import "strconv"
|
||||
|
||||
const _API_TYPE_name = "FRR_ZAPI6_INTERFACE_ADDFRR_ZAPI6_INTERFACE_DELETEFRR_ZAPI6_INTERFACE_ADDRESS_ADDFRR_ZAPI6_INTERFACE_ADDRESS_DELETEFRR_ZAPI6_INTERFACE_UPFRR_ZAPI6_INTERFACE_DOWNFRR_ZAPI6_INTERFACE_SET_MASTERFRR_ZAPI6_ROUTE_ADDFRR_ZAPI6_ROUTE_DELETEFRR_ZAPI6_ROUTE_NOTIFY_OWNERFRR_ZAPI6_REDISTRIBUTE_ADDFRR_ZAPI6_REDISTRIBUTE_DELETEFRR_ZAPI6_REDISTRIBUTE_DEFAULT_ADDFRR_ZAPI6_REDISTRIBUTE_DEFAULT_DELETEFRR_ZAPI6_ROUTER_ID_ADDFRR_ZAPI6_ROUTER_ID_DELETEFRR_ZAPI6_ROUTER_ID_UPDATEFRR_ZAPI6_HELLOFRR_ZAPI6_CAPABILITIESFRR_ZAPI6_NEXTHOP_REGISTERFRR_ZAPI6_NEXTHOP_UNREGISTERFRR_ZAPI6_NEXTHOP_UPDATEFRR_ZAPI6_INTERFACE_NBR_ADDRESS_ADDFRR_ZAPI6_INTERFACE_NBR_ADDRESS_DELETEFRR_ZAPI6_INTERFACE_BFD_DEST_UPDATEFRR_ZAPI6_IMPORT_ROUTE_REGISTERFRR_ZAPI6_IMPORT_ROUTE_UNREGISTERFRR_ZAPI6_IMPORT_CHECK_UPDATEFRR_ZAPI6_IPV4_ROUTE_IPV6_NEXTHOP_ADDFRR_ZAPI6_BFD_DEST_REGISTERFRR_ZAPI6_BFD_DEST_DEREGISTERFRR_ZAPI6_BFD_DEST_UPDATEFRR_ZAPI6_BFD_DEST_REPLAYFRR_ZAPI6_REDISTRIBUTE_ROUTE_ADDFRR_ZAPI6_REDISTRIBUTE_ROUTE_DELFRR_ZAPI6_VRF_UNREGISTERFRR_ZAPI6_VRF_ADDFRR_ZAPI6_VRF_DELETEFRR_ZAPI6_VRF_LABELFRR_ZAPI6_INTERFACE_VRF_UPDATEFRR_ZAPI6_BFD_CLIENT_REGISTERFRR_ZAPI6_BFD_CLIENT_DEREGISTERFRR_ZAPI6_INTERFACE_ENABLE_RADVFRR_ZAPI6_INTERFACE_DISABLE_RADVFRR_ZAPI6_IPV4_NEXTHOP_LOOKUP_MRIBFRR_ZAPI6_INTERFACE_LINK_PARAMSFRR_ZAPI6_MPLS_LABELS_ADDFRR_ZAPI6_MPLS_LABELS_DELETEFRR_ZAPI6_IPMR_ROUTE_STATSFRR_ZAPI6_LABEL_MANAGER_CONNECTFRR_ZAPI6_GET_LABEL_CHUNKFRR_ZAPI6_RELEASE_LABEL_CHUNKFRR_ZAPI6_FEC_REGISTERFRR_ZAPI6_FEC_UNREGISTERFRR_ZAPI6_FEC_UPDATEFRR_ZAPI6_ADVERTISE_DEFAULT_GWFRR_ZAPI6_ADVERTISE_SUBNETFRR_ZAPI6_ADVERTISE_ALL_VNIFRR_ZAPI6_LOCAL_ES_ADDFRR_ZAPI6_LOCAL_ES_DELFRR_ZAPI6_VNI_ADDFRR_ZAPI6_VNI_DELFRR_ZAPI6_L3VNI_ADDFRR_ZAPI6_L3VNI_DELFRR_ZAPI6_REMOTE_VTEP_ADDFRR_ZAPI6_REMOTE_VTEP_DELFRR_ZAPI6_MACIP_ADDFRR_ZAPI6_MACIP_DELFRR_ZAPI6_IP_PREFIX_ROUTE_ADDFRR_ZAPI6_IP_PREFIX_ROUTE_DELFRR_ZAPI6_REMOTE_MACIP_ADDFRR_ZAPI6_REMOTE_MACIP_DELFRR_ZAPI6_PW_ADDFRR_ZAPI6_PW_DELETEFRR_ZAPI6_PW_SETFRR_ZAPI6_PW_UNSETFRR_ZAPI6_PW_STATUS_UPDATEFRR_ZAPI6_RULE_ADDFRR_ZAPI6_RULE_DELETEFRR_ZAPI6_RULE_NOTIFY_OWNERFRR_ZAPI6_TABLE_MANAGER_CONNECTFRR_ZAPI6_GET_TABLE_CHUNKFRR_ZAPI6_RELEASE_TABLE_CHUNKFRR_ZAPI6_IPSET_CREATEFRR_ZAPI6_IPSET_DESTROYFRR_ZAPI6_IPSET_ENTRY_ADDFRR_ZAPI6_IPSET_ENTRY_DELETEFRR_ZAPI6_IPSET_NOTIFY_OWNERFRR_ZAPI6_IPSET_ENTRY_NOTIFY_OWNERFRR_ZAPI6_IPTABLE_ADDFRR_ZAPI6_IPTABLE_DELETEFRR_ZAPI6_IPTABLE_NOTIFY_OWNERFRR_ZAPI5_IPTABLE_DELETEFRR_ZAPI5_IPTABLE_NOTIFY_OWNER"
|
||||
const _API_TYPE_name = "FRR_ZAPI6_INTERFACE_ADDFRR_ZAPI6_INTERFACE_DELETEFRR_ZAPI6_INTERFACE_ADDRESS_ADDFRR_ZAPI6_INTERFACE_ADDRESS_DELETEFRR_ZAPI6_INTERFACE_UPFRR_ZAPI6_INTERFACE_DOWNFRR_ZAPI6_INTERFACE_SET_MASTERFRR_ZAPI6_ROUTE_ADDFRR_ZAPI6_ROUTE_DELETEFRR_ZAPI6_ROUTE_NOTIFY_OWNERFRR_ZAPI6_REDISTRIBUTE_ADDFRR_ZAPI6_REDISTRIBUTE_DELETEFRR_ZAPI6_REDISTRIBUTE_DEFAULT_ADDFRR_ZAPI6_REDISTRIBUTE_DEFAULT_DELETEFRR_ZAPI6_ROUTER_ID_ADDFRR_ZAPI6_ROUTER_ID_DELETEFRR_ZAPI6_ROUTER_ID_UPDATEFRR_ZAPI6_HELLOFRR_ZAPI6_CAPABILITIESFRR_ZAPI6_NEXTHOP_REGISTERFRR_ZAPI6_NEXTHOP_UNREGISTERFRR_ZAPI6_NEXTHOP_UPDATEFRR_ZAPI6_INTERFACE_NBR_ADDRESS_ADDFRR_ZAPI6_INTERFACE_NBR_ADDRESS_DELETEFRR_ZAPI6_INTERFACE_BFD_DEST_UPDATEFRR_ZAPI6_IMPORT_ROUTE_REGISTERFRR_ZAPI6_IMPORT_ROUTE_UNREGISTERFRR_ZAPI6_IMPORT_CHECK_UPDATEFRR_ZAPI6_IPV4_ROUTE_IPV6_NEXTHOP_ADDFRR_ZAPI6_BFD_DEST_REGISTERFRR_ZAPI6_BFD_DEST_DEREGISTERFRR_ZAPI6_BFD_DEST_UPDATEFRR_ZAPI6_BFD_DEST_REPLAYFRR_ZAPI6_REDISTRIBUTE_ROUTE_ADDFRR_ZAPI6_REDISTRIBUTE_ROUTE_DELFRR_ZAPI6_VRF_UNREGISTERFRR_ZAPI6_VRF_ADDFRR_ZAPI6_VRF_DELETEFRR_ZAPI6_VRF_LABELFRR_ZAPI6_INTERFACE_VRF_UPDATEFRR_ZAPI6_BFD_CLIENT_REGISTERFRR_ZAPI6_BFD_CLIENT_DEREGISTERFRR_ZAPI6_INTERFACE_ENABLE_RADVFRR_ZAPI6_INTERFACE_DISABLE_RADVFRR_ZAPI6_IPV4_NEXTHOP_LOOKUP_MRIBFRR_ZAPI6_INTERFACE_LINK_PARAMSFRR_ZAPI6_MPLS_LABELS_ADDFRR_ZAPI6_MPLS_LABELS_DELETEFRR_ZAPI6_IPMR_ROUTE_STATSFRR_ZAPI6_LABEL_MANAGER_CONNECTFRR_ZAPI6_LABEL_MANAGER_CONNECT_ASYNCFRR_ZAPI6_GET_LABEL_CHUNKFRR_ZAPI6_RELEASE_LABEL_CHUNKFRR_ZAPI6_FEC_REGISTERFRR_ZAPI6_FEC_UNREGISTERFRR_ZAPI6_FEC_UPDATEFRR_ZAPI6_ADVERTISE_DEFAULT_GWFRR_ZAPI6_ADVERTISE_SUBNETFRR_ZAPI6_ADVERTISE_ALL_VNIFRR_ZAPI6_LOCAL_ES_ADDFRR_ZAPI6_LOCAL_ES_DELFRR_ZAPI6_VNI_ADDFRR_ZAPI6_VNI_DELFRR_ZAPI6_L3VNI_ADDFRR_ZAPI6_L3VNI_DELFRR_ZAPI6_REMOTE_VTEP_ADDFRR_ZAPI6_REMOTE_VTEP_DELFRR_ZAPI6_MACIP_ADDFRR_ZAPI6_MACIP_DELFRR_ZAPI6_IP_PREFIX_ROUTE_ADDFRR_ZAPI6_IP_PREFIX_ROUTE_DELFRR_ZAPI6_REMOTE_MACIP_ADDFRR_ZAPI6_REMOTE_MACIP_DELFRR_ZAPI6_PW_ADDFRR_ZAPI6_PW_DELETEFRR_ZAPI6_PW_SETFRR_ZAPI6_PW_UNSETFRR_ZAPI6_PW_STATUS_UPDATEFRR_ZAPI6_RULE_ADDFRR_ZAPI6_RULE_DELETEFRR_ZAPI6_RULE_NOTIFY_OWNERFRR_ZAPI6_TABLE_MANAGER_CONNECTFRR_ZAPI6_GET_TABLE_CHUNKFRR_ZAPI6_RELEASE_TABLE_CHUNKFRR_ZAPI6_IPSET_CREATEFRR_ZAPI6_IPSET_DESTROYFRR_ZAPI6_IPSET_ENTRY_ADDFRR_ZAPI6_IPSET_ENTRY_DELETEFRR_ZAPI6_IPSET_NOTIFY_OWNERFRR_ZAPI6_IPSET_ENTRY_NOTIFY_OWNERFRR_ZAPI6_IPTABLE_ADDFRR_ZAPI6_IPTABLE_DELETEFRR_ZAPI6_IPTABLE_NOTIFY_OWNERFRR_ZAPI5_IPTABLE_NOTIFY_OWNER"
|
||||
|
||||
var _API_TYPE_index = [...]uint16{0, 23, 49, 80, 114, 136, 160, 190, 209, 231, 259, 285, 314, 348, 385, 408, 434, 460, 475, 497, 523, 551, 575, 610, 648, 683, 714, 747, 776, 813, 840, 869, 894, 919, 951, 983, 1007, 1024, 1044, 1063, 1093, 1122, 1153, 1184, 1216, 1250, 1281, 1306, 1334, 1360, 1391, 1416, 1445, 1467, 1491, 1511, 1541, 1567, 1594, 1616, 1638, 1655, 1672, 1691, 1710, 1735, 1760, 1779, 1798, 1827, 1856, 1882, 1908, 1924, 1943, 1959, 1977, 2003, 2021, 2042, 2069, 2100, 2125, 2154, 2176, 2199, 2224, 2252, 2280, 2314, 2335, 2359, 2389, 2413, 2443}
|
||||
var _API_TYPE_index = [...]uint16{0, 23, 49, 80, 114, 136, 160, 190, 209, 231, 259, 285, 314, 348, 385, 408, 434, 460, 475, 497, 523, 551, 575, 610, 648, 683, 714, 747, 776, 813, 840, 869, 894, 919, 951, 983, 1007, 1024, 1044, 1063, 1093, 1122, 1153, 1184, 1216, 1250, 1281, 1306, 1334, 1360, 1391, 1428, 1453, 1482, 1504, 1528, 1548, 1578, 1604, 1631, 1653, 1675, 1692, 1709, 1728, 1747, 1772, 1797, 1816, 1835, 1864, 1893, 1919, 1945, 1961, 1980, 1996, 2014, 2040, 2058, 2079, 2106, 2137, 2162, 2191, 2213, 2236, 2261, 2289, 2317, 2351, 2372, 2396, 2426, 2456}
|
||||
|
||||
func (i API_TYPE) String() string {
|
||||
if i >= API_TYPE(len(_API_TYPE_index)-1) {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// Code generated by "stringer -type=LSP_TYPE"; DO NOT EDIT.
|
||||
|
||||
package zebra
|
||||
|
||||
import "strconv"
|
||||
|
||||
const _LSP_TYPE_name = "LSP_NONELSP_STATICLSP_LDPLSP_BGPLSP_SRLSP_SHARP"
|
||||
|
||||
var _LSP_TYPE_index = [...]uint8{0, 8, 18, 25, 32, 38, 47}
|
||||
|
||||
func (i LSP_TYPE) String() string {
|
||||
if i >= LSP_TYPE(len(_LSP_TYPE_index)-1) {
|
||||
return "LSP_TYPE(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _LSP_TYPE_name[_LSP_TYPE_index[i]:_LSP_TYPE_index[i+1]]
|
||||
}
|
||||
@@ -4,9 +4,9 @@ package zebra
|
||||
|
||||
import "strconv"
|
||||
|
||||
const _SAFI_name = "SAFI_UNICASTSAFI_MULTICASTSAFI_RESERVED_3SAFI_MPLS_VPNSAFI_MAX"
|
||||
const _SAFI_name = "FRR_ZAPI5_SAFI_UNICASTFRR_ZAPI5_SAFI_MULTICASTFRR_ZAPI5_SAFI_MPLS_VPNFRR_ZAPI5_SAFI_ENCAPFRR_ZAPI5_SAFI_EVPNFRR_ZAPI5_SAFI_LABELED_UNICASTFRR_ZAPI5_SAFI_FLOWSPECFRR_ZAPI5_SAFI_MAX"
|
||||
|
||||
var _SAFI_index = [...]uint8{0, 12, 26, 41, 54, 62}
|
||||
var _SAFI_index = [...]uint8{0, 22, 46, 69, 89, 108, 138, 161, 179}
|
||||
|
||||
func (i SAFI) String() string {
|
||||
i -= 1
|
||||
|
||||
+365
-11
@@ -178,12 +178,29 @@ const (
|
||||
//go:generate stringer -type=SAFI
|
||||
type SAFI uint8
|
||||
|
||||
// SAFI definition in Zebra of FRRouting 4.x, 5.x, 6.x
|
||||
const (
|
||||
_ SAFI = iota
|
||||
FRR_ZAPI5_SAFI_UNICAST
|
||||
FRR_ZAPI5_SAFI_MULTICAST
|
||||
FRR_ZAPI5_SAFI_MPLS_VPN
|
||||
FRR_ZAPI5_SAFI_ENCAP
|
||||
FRR_ZAPI5_SAFI_EVPN
|
||||
FRR_ZAPI5_SAFI_LABELED_UNICAST
|
||||
FRR_ZAPI5_SAFI_FLOWSPEC
|
||||
FRR_ZAPI5_SAFI_MAX
|
||||
)
|
||||
|
||||
// SAFI definition in Zebra of Quagga and FRRouting 3.x
|
||||
const (
|
||||
_ SAFI = iota
|
||||
SAFI_UNICAST
|
||||
SAFI_MULTICAST
|
||||
SAFI_RESERVED_3
|
||||
SAFI_MPLS_VPN
|
||||
FRR_SAFI_MPLS_VPN // SAFI_RESERVED_3 in quagga
|
||||
SAFI_MPLS_VPN // SAFI_RESERVED_4 in FRRouting 3.x
|
||||
FRR_SAFI_ENCAP
|
||||
FRR_SAFI_EVPN
|
||||
SAFI_ENCAP // SAFI_MAX in FRRouting 3.x
|
||||
SAFI_MAX
|
||||
)
|
||||
|
||||
@@ -243,6 +260,7 @@ const (
|
||||
FRR_ZAPI6_MPLS_LABELS_DELETE
|
||||
FRR_ZAPI6_IPMR_ROUTE_STATS
|
||||
FRR_ZAPI6_LABEL_MANAGER_CONNECT
|
||||
FRR_ZAPI6_LABEL_MANAGER_CONNECT_ASYNC
|
||||
FRR_ZAPI6_GET_LABEL_CHUNK
|
||||
FRR_ZAPI6_RELEASE_LABEL_CHUNK
|
||||
FRR_ZAPI6_FEC_REGISTER
|
||||
@@ -1020,6 +1038,9 @@ func NewClient(network, address string, typ ROUTE_TYPE, version uint8) (*Client,
|
||||
// Send HELLO/ROUTER_ID_ADD messages to negotiate the Zebra message version.
|
||||
c.SendHello()
|
||||
c.SendRouterIDAdd()
|
||||
if version >= 4 {
|
||||
c.SendLabelManagerConnect()
|
||||
}
|
||||
|
||||
receiveSingleMsg := func() (*Message, error) {
|
||||
headerBuf, err := readAll(conn, int(HeaderSize(version)))
|
||||
@@ -1241,6 +1262,10 @@ func (c *Client) SendRedistributeDelete(t ROUTE_TYPE) error {
|
||||
}
|
||||
|
||||
func (c *Client) SendIPRoute(vrfId uint32, body *IPRouteBody, isWithdraw bool) error {
|
||||
routeFamily := body.RouteFamily(c.Version)
|
||||
if vrfId == VRF_DEFAULT && (routeFamily == bgp.RF_IPv4_VPN || routeFamily == bgp.RF_IPv6_VPN) {
|
||||
return fmt.Errorf("RF_IPv4_VPN or RF_IPv6_VPN are not suitable for VPN_DEFAULT(default forwarding table).")
|
||||
}
|
||||
command := IPV4_ROUTE_ADD
|
||||
if c.Version <= 3 {
|
||||
if body.Prefix.Prefix.To4() != nil {
|
||||
@@ -1311,6 +1336,58 @@ func (c *Client) SendNexthopRegister(vrfId uint32, body *NexthopRegisterBody, is
|
||||
return c.SendCommand(command, vrfId, body)
|
||||
}
|
||||
|
||||
// Reference: zread_label_manager_connect function in zebra/zserv.c of FRR3.x (ZAPI)
|
||||
// Reference: zread_label_manager_connect function in zebra/zapi_msg.c of FRR5.x and 6.x (ZAPI5 and 6)
|
||||
|
||||
func (c *Client) SendLabelManagerConnect() error {
|
||||
if c.Version < 4 {
|
||||
return fmt.Errorf("LABEL_MANAGER_CONNECT is not supported in version: %d", c.Version)
|
||||
}
|
||||
command := FRR_LABEL_MANAGER_CONNECT
|
||||
proto := FRR_ROUTE_BGP
|
||||
if c.Version == 5 {
|
||||
command = FRR_ZAPI5_LABEL_MANAGER_CONNECT
|
||||
proto = FRR_ZAPI5_ROUTE_BGP
|
||||
} else if c.Version == 6 {
|
||||
command = FRR_ZAPI6_LABEL_MANAGER_CONNECT
|
||||
proto = FRR_ZAPI6_ROUTE_BGP
|
||||
}
|
||||
return c.SendCommand(
|
||||
command, 0,
|
||||
&LabelManagerConnectBody{
|
||||
RedistDefault: proto,
|
||||
Instance: 0,
|
||||
})
|
||||
}
|
||||
func (c *Client) SendGetLabelChunk(body *GetLabelChunkBody) error {
|
||||
if c.Version < 4 {
|
||||
return fmt.Errorf("GET_LABEL_CHUNK is not supported in version: %d", c.Version)
|
||||
}
|
||||
command := FRR_GET_LABEL_CHUNK
|
||||
body.Instance = 0
|
||||
if c.Version == 5 {
|
||||
body.Proto = uint8(FRR_ZAPI5_ROUTE_BGP)
|
||||
command = FRR_ZAPI5_GET_LABEL_CHUNK
|
||||
} else if c.Version == 6 {
|
||||
body.Proto = uint8(FRR_ZAPI6_ROUTE_BGP)
|
||||
command = FRR_ZAPI6_GET_LABEL_CHUNK
|
||||
}
|
||||
return c.SendCommand(command, 0, body)
|
||||
}
|
||||
|
||||
func (c *Client) SendVrfLabel(label uint32, vrfId uint32) error {
|
||||
body := &VrfLabelBody{
|
||||
Label: label,
|
||||
Afi: AFI_IP,
|
||||
LabelType: LSP_BGP,
|
||||
}
|
||||
command := FRR_ZAPI5_VRF_LABEL
|
||||
if c.Version == 6 {
|
||||
command = FRR_ZAPI6_VRF_LABEL
|
||||
}
|
||||
return c.SendCommand(command, vrfId, body)
|
||||
}
|
||||
|
||||
// for avoiding double close
|
||||
func ChannelClose(ch chan *Message) bool {
|
||||
select {
|
||||
@@ -1735,11 +1812,78 @@ func (b *IPRouteBody) RouteFamily(version uint8) bgp.RouteFamily {
|
||||
family = syscall.AF_INET6
|
||||
}
|
||||
}
|
||||
switch family {
|
||||
case syscall.AF_INET:
|
||||
return bgp.RF_IPv4_UC
|
||||
case syscall.AF_INET6:
|
||||
return bgp.RF_IPv6_UC
|
||||
if version < 5 {
|
||||
switch family {
|
||||
case syscall.AF_INET:
|
||||
switch b.SAFI {
|
||||
case SAFI_UNICAST:
|
||||
return bgp.RF_IPv4_UC
|
||||
case SAFI_MULTICAST:
|
||||
return bgp.RF_IPv4_MC
|
||||
case SAFI_MPLS_VPN, FRR_SAFI_MPLS_VPN:
|
||||
return bgp.RF_IPv4_VPN
|
||||
case FRR_SAFI_ENCAP, SAFI_ENCAP:
|
||||
return bgp.RF_IPv4_ENCAP
|
||||
}
|
||||
case syscall.AF_INET6:
|
||||
switch b.SAFI {
|
||||
case SAFI_UNICAST:
|
||||
return bgp.RF_IPv6_UC
|
||||
case SAFI_MULTICAST:
|
||||
return bgp.RF_IPv6_MC
|
||||
case SAFI_MPLS_VPN, FRR_SAFI_MPLS_VPN:
|
||||
return bgp.RF_IPv6_VPN
|
||||
case FRR_SAFI_ENCAP, SAFI_ENCAP:
|
||||
return bgp.RF_IPv6_ENCAP
|
||||
}
|
||||
default:
|
||||
switch b.SAFI {
|
||||
case FRR_SAFI_EVPN:
|
||||
return bgp.RF_EVPN
|
||||
default:
|
||||
return bgp.RF_OPAQUE
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch family {
|
||||
case syscall.AF_INET:
|
||||
switch b.SAFI {
|
||||
case FRR_ZAPI5_SAFI_UNICAST:
|
||||
return bgp.RF_IPv4_UC
|
||||
case FRR_ZAPI5_SAFI_MULTICAST:
|
||||
return bgp.RF_IPv4_MC
|
||||
case FRR_ZAPI5_SAFI_MPLS_VPN:
|
||||
return bgp.RF_IPv4_VPN
|
||||
case FRR_ZAPI5_SAFI_ENCAP:
|
||||
return bgp.RF_IPv4_ENCAP
|
||||
case FRR_ZAPI5_SAFI_LABELED_UNICAST:
|
||||
return bgp.RF_IPv4_MPLS
|
||||
case FRR_ZAPI5_SAFI_FLOWSPEC:
|
||||
return bgp.RF_FS_IPv4_UC
|
||||
}
|
||||
case syscall.AF_INET6:
|
||||
switch b.SAFI {
|
||||
case FRR_ZAPI5_SAFI_UNICAST:
|
||||
return bgp.RF_IPv6_UC
|
||||
case FRR_ZAPI5_SAFI_MULTICAST:
|
||||
return bgp.RF_IPv6_MC
|
||||
case FRR_ZAPI5_SAFI_MPLS_VPN:
|
||||
return bgp.RF_IPv6_VPN
|
||||
case FRR_ZAPI5_SAFI_ENCAP:
|
||||
return bgp.RF_IPv6_ENCAP
|
||||
case FRR_ZAPI5_SAFI_LABELED_UNICAST:
|
||||
return bgp.RF_IPv6_MPLS
|
||||
case FRR_ZAPI5_SAFI_FLOWSPEC:
|
||||
return bgp.RF_FS_IPv6_UC
|
||||
}
|
||||
default:
|
||||
switch b.SAFI {
|
||||
case FRR_ZAPI5_SAFI_EVPN:
|
||||
return bgp.RF_EVPN
|
||||
default:
|
||||
return bgp.RF_OPAQUE
|
||||
}
|
||||
}
|
||||
}
|
||||
return bgp.RF_OPAQUE
|
||||
}
|
||||
@@ -1897,9 +2041,15 @@ func (b *IPRouteBody) Serialize(version uint8) ([]byte, error) {
|
||||
}
|
||||
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...)
|
||||
for i := uint8(0); i < nexthop.LabelNum; i++ {
|
||||
bbuf := make([]byte, 4)
|
||||
/* Frr uses stream_put for mpls label array.
|
||||
stream_put is unaware of byteorder coversion.
|
||||
Therefore LittleEndian is used instead of BigEndian. */
|
||||
binary.LittleEndian.PutUint32(bbuf, nexthop.MplsLabels[i])
|
||||
buf = append(buf, bbuf...)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (version <= 3 && b.Message&MESSAGE_DISTANCE > 0) ||
|
||||
@@ -2240,7 +2390,10 @@ func decodeNexthopsFromBytes(nexthops *[]Nexthop, data []byte, family uint8, ver
|
||||
}
|
||||
nexthop.MplsLabels = make([]uint32, nexthop.LabelNum)
|
||||
for n := uint8(0); n < nexthop.LabelNum; n++ {
|
||||
nexthop.MplsLabels[n] = binary.BigEndian.Uint32(data[offset : offset+4])
|
||||
/* Frr uses stream_put for mpls label array.
|
||||
stream_put is unaware of byteorder coversion.
|
||||
Therefore LittleEndian is used instead of BigEndian. */
|
||||
nexthop.MplsLabels[n] = binary.LittleEndian.Uint32(data[offset : offset+4])
|
||||
offset += 4
|
||||
}
|
||||
}
|
||||
@@ -2612,6 +2765,177 @@ func (b *NexthopUpdateBody) String() string {
|
||||
return s
|
||||
}
|
||||
|
||||
type LabelManagerConnectBody struct {
|
||||
RedistDefault ROUTE_TYPE
|
||||
Instance uint16
|
||||
// The followings are used in response from Zebra
|
||||
Result uint8 // 0 means success
|
||||
}
|
||||
|
||||
// Reference: lm_label_manager_connect in lib/zclient.c of FRR
|
||||
func (b *LabelManagerConnectBody) Serialize(version uint8) ([]byte, error) {
|
||||
buf := make([]byte, 3)
|
||||
buf[0] = uint8(b.RedistDefault)
|
||||
binary.BigEndian.PutUint16(buf[1:3], b.Instance)
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func (b *LabelManagerConnectBody) DecodeFromBytes(data []byte, version uint8) error {
|
||||
size := 1
|
||||
// FRR v4 may work incorrectly. It returns result only although it uses ZAPI v5.
|
||||
if version >= 4 {
|
||||
size = 4
|
||||
}
|
||||
if len(data) < size {
|
||||
return fmt.Errorf("invalid message length for LABEL_MANAGER_CONNECT response: %d<%d",
|
||||
len(data), size)
|
||||
}
|
||||
if version > 4 {
|
||||
b.RedistDefault = ROUTE_TYPE(data[0])
|
||||
b.Instance = binary.BigEndian.Uint16(data[1:3])
|
||||
data = data[3:]
|
||||
}
|
||||
b.Result = data[0]
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *LabelManagerConnectBody) String() string {
|
||||
return fmt.Sprintf(
|
||||
"route_type: %s, instance: %d, result: %d",
|
||||
b.RedistDefault.String(), b.Instance, b.Result)
|
||||
}
|
||||
|
||||
// Reference: zsend_assign_label_chunk_response in zebra/zserv.c of FRR3.x
|
||||
// Reference: zsend_assign_label_chunk_response in zebra/zapi_msg.c of FRR5.x and 6.x
|
||||
type GetLabelChunkBody struct {
|
||||
Proto uint8 // it is appeared in FRR5.x and 6.x
|
||||
Instance uint16 // it is appeared in FRR5.x and 6.x
|
||||
Keep uint8
|
||||
ChunkSize uint32
|
||||
// The followings are used in response from Zebra
|
||||
Start uint32
|
||||
End uint32
|
||||
}
|
||||
|
||||
// Reference: zread_get_label_chunk in zebra/zserv.c of FRR3.x
|
||||
// Reference: zread_get_label_chunk in zebra/zapi_msg.c of FRR5.x and 6.x
|
||||
func (b *GetLabelChunkBody) Serialize(version uint8) ([]byte, error) {
|
||||
buf := make([]byte, 8)
|
||||
pos := 0
|
||||
if version > 4 {
|
||||
buf[pos] = b.Proto
|
||||
binary.BigEndian.PutUint16(buf[pos+1:pos+3], b.Instance)
|
||||
pos += 3
|
||||
}
|
||||
buf[pos] = b.Keep
|
||||
binary.BigEndian.PutUint32(buf[pos+1:pos+5], b.ChunkSize)
|
||||
pos += 5
|
||||
return buf[0:pos], nil
|
||||
}
|
||||
|
||||
// Reference: zsend_assign_label_chunk_response in zebra/zserv.c of FRR3.x
|
||||
// Reference: zsend_assign_label_chunk_response in zebra/zapi_msg.c of FRR5.x and 6.x
|
||||
func (b *GetLabelChunkBody) DecodeFromBytes(data []byte, version uint8) error {
|
||||
size := 9
|
||||
if version > 4 {
|
||||
size = 12
|
||||
}
|
||||
if len(data) < size {
|
||||
return fmt.Errorf("invalid message length for GET_LABEL_CHUNK response: %d<%d",
|
||||
len(data), size)
|
||||
}
|
||||
if version > 4 {
|
||||
b.Proto = data[0]
|
||||
b.Instance = binary.BigEndian.Uint16(data[1:3])
|
||||
data = data[3:]
|
||||
}
|
||||
b.Keep = data[0]
|
||||
b.Start = binary.BigEndian.Uint32(data[1:5])
|
||||
b.End = binary.BigEndian.Uint32(data[5:9])
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *GetLabelChunkBody) String() string {
|
||||
return fmt.Sprintf(
|
||||
"keep: %d, chunk_size: %d, start: %d, end: %d",
|
||||
b.Keep, b.ChunkSize, b.Start, b.End)
|
||||
}
|
||||
|
||||
type ReleaseLabelChunkBody struct {
|
||||
Proto uint8 // it is appeared in FRR5.x and 6.x
|
||||
Instance uint16 // it is appeared in FRR5.x and 6.x
|
||||
Start uint32
|
||||
End uint32
|
||||
}
|
||||
|
||||
func (b *ReleaseLabelChunkBody) Serialize(version uint8) ([]byte, error) {
|
||||
buf := make([]byte, 11)
|
||||
pos := 0
|
||||
if version > 4 {
|
||||
buf[pos] = b.Proto
|
||||
binary.BigEndian.PutUint16(buf[pos+1:pos+3], b.Instance)
|
||||
pos += 3
|
||||
}
|
||||
binary.BigEndian.PutUint32(buf[pos:pos+4], b.Start)
|
||||
binary.BigEndian.PutUint32(buf[pos+4:pos+8], b.End)
|
||||
pos += 8
|
||||
return buf[0:pos], nil
|
||||
}
|
||||
|
||||
func (b *ReleaseLabelChunkBody) DecodeFromBytes(data []byte, version uint8) error {
|
||||
// No response from Zebra
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *ReleaseLabelChunkBody) String() string {
|
||||
return fmt.Sprintf(
|
||||
"start: %d, end: %d",
|
||||
b.Start, b.End)
|
||||
}
|
||||
|
||||
//go:generate stringer -type=LSP_TYPE
|
||||
type LSP_TYPE uint8
|
||||
|
||||
const (
|
||||
LSP_NONE LSP_TYPE = iota //defined in FRR3 and over
|
||||
LSP_STATIC //defined in FRR3 and over
|
||||
LSP_LDP //defined in FRR3 and over
|
||||
LSP_BGP //defined in FRR4 and over
|
||||
LSP_SR //defined in FRR4 and over
|
||||
LSP_SHARP //defined in FRR5 and over
|
||||
)
|
||||
|
||||
type VrfLabelBody struct {
|
||||
Label uint32
|
||||
Afi AFI
|
||||
LabelType LSP_TYPE
|
||||
}
|
||||
|
||||
// Reference: zclient_send_vrf_label in lib/zclient.c of FRR 5.x and 6.x
|
||||
func (b *VrfLabelBody) Serialize(version uint8) ([]byte, error) {
|
||||
buf := make([]byte, 6)
|
||||
binary.BigEndian.PutUint32(buf[0:4], b.Label)
|
||||
buf[4] = uint8(b.Afi)
|
||||
buf[5] = uint8(b.LabelType)
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func (b *VrfLabelBody) DecodeFromBytes(data []byte, version uint8) error {
|
||||
if len(data) < 6 {
|
||||
return fmt.Errorf("invalid message length for VRF_LABEL message: %d<6", len(data))
|
||||
}
|
||||
b.Label = binary.BigEndian.Uint32(data[0:4])
|
||||
b.Afi = AFI(data[4])
|
||||
b.LabelType = LSP_TYPE(data[5])
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *VrfLabelBody) String() string {
|
||||
return fmt.Sprintf(
|
||||
"label: %d, AFI: %s LSP_type: %s",
|
||||
b.Label, b.Afi, b.LabelType)
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
Header Header
|
||||
Body Body
|
||||
@@ -2689,6 +3013,15 @@ func (m *Message) parseFrrMessage(data []byte) error {
|
||||
case FRR_PW_STATUS_UPDATE:
|
||||
// TODO
|
||||
m.Body = &UnknownBody{}
|
||||
case FRR_LABEL_MANAGER_CONNECT:
|
||||
// Note: Synchronous message
|
||||
m.Body = &LabelManagerConnectBody{}
|
||||
case FRR_GET_LABEL_CHUNK:
|
||||
// Note: Synchronous message
|
||||
m.Body = &GetLabelChunkBody{}
|
||||
case FRR_RELEASE_LABEL_CHUNK:
|
||||
// Note: Synchronous message
|
||||
m.Body = &ReleaseLabelChunkBody{}
|
||||
default:
|
||||
m.Body = &UnknownBody{}
|
||||
}
|
||||
@@ -2728,6 +3061,17 @@ func (m *Message) parseFrrZapi5Message(data []byte) error {
|
||||
case FRR_ZAPI5_PW_STATUS_UPDATE:
|
||||
// TODO
|
||||
m.Body = &UnknownBody{}
|
||||
case FRR_ZAPI5_LABEL_MANAGER_CONNECT:
|
||||
// Note: Synchronous message
|
||||
m.Body = &LabelManagerConnectBody{}
|
||||
case FRR_ZAPI5_GET_LABEL_CHUNK:
|
||||
// Note: Synchronous message
|
||||
m.Body = &GetLabelChunkBody{}
|
||||
case FRR_ZAPI5_RELEASE_LABEL_CHUNK:
|
||||
// Note: Synchronous message
|
||||
m.Body = &ReleaseLabelChunkBody{}
|
||||
case FRR_ZAPI5_VRF_LABEL:
|
||||
m.Body = &VrfLabelBody{}
|
||||
default:
|
||||
m.Body = &UnknownBody{}
|
||||
}
|
||||
@@ -2767,6 +3111,16 @@ func (m *Message) parseFrrZapi6Message(data []byte) error {
|
||||
case FRR_ZAPI6_PW_STATUS_UPDATE:
|
||||
// TODO
|
||||
m.Body = &UnknownBody{}
|
||||
case FRR_ZAPI6_LABEL_MANAGER_CONNECT:
|
||||
// Note: Synchronous message
|
||||
m.Body = &LabelManagerConnectBody{}
|
||||
case FRR_ZAPI6_GET_LABEL_CHUNK:
|
||||
// Note: Synchronous message
|
||||
m.Body = &GetLabelChunkBody{}
|
||||
case FRR_ZAPI6_RELEASE_LABEL_CHUNK:
|
||||
// Note: Synchronous message
|
||||
case FRR_ZAPI6_VRF_LABEL:
|
||||
m.Body = &VrfLabelBody{}
|
||||
default:
|
||||
m.Body = &UnknownBody{}
|
||||
}
|
||||
|
||||
+31
-1
@@ -958,6 +958,7 @@ func (s *BgpServer) propagateUpdate(peer *peer, pathList []*table.Path) {
|
||||
peer.fsm.lock.RLock()
|
||||
peerVrf := peer.fsm.pConf.Config.Vrf
|
||||
peer.fsm.lock.RUnlock()
|
||||
path.SetReceiveVrfId(rib.Vrfs[peerVrf].Id)
|
||||
path = path.ToGlobal(rib.Vrfs[peerVrf])
|
||||
}
|
||||
|
||||
@@ -1590,7 +1591,10 @@ func (s *BgpServer) EnableZebra(ctx context.Context, r *api.EnableZebraRequest)
|
||||
protos = append(protos, string(p))
|
||||
}
|
||||
var err error
|
||||
s.zclient, err = newZebraClient(s, r.Url, protos, uint8(r.Version), r.NexthopTriggerEnable, uint8(r.NexthopTriggerDelay))
|
||||
s.zclient, err = newZebraClient(s, r.Url, protos, uint8(r.Version), r.NexthopTriggerEnable, uint8(r.NexthopTriggerDelay), r.MplsLabelRangeSize)
|
||||
if err == nil && s.globalRib != nil && s.zclient.client.Version >= 4 && r.MplsLabelRangeSize > 0 {
|
||||
err = s.globalRib.EnableMplsLabelAllocation()
|
||||
}
|
||||
return err
|
||||
}, false)
|
||||
}
|
||||
@@ -2029,6 +2033,26 @@ func (s *BgpServer) ListVrf(ctx context.Context, _ *api.ListVrfRequest, fn func(
|
||||
return nil
|
||||
}
|
||||
|
||||
func assignMplsLabel(s *BgpServer, vrf *table.Vrf) error {
|
||||
var mplsLabel uint32
|
||||
var err error
|
||||
for mplsLabel, err = s.globalRib.AssignMplsLabel(); err != nil; mplsLabel, err = s.globalRib.AssignMplsLabel() {
|
||||
if err = s.zclient.client.SendGetLabelChunk(&zebra.GetLabelChunkBody{ChunkSize: s.zclient.mplsLabelRangeSize}); err != nil {
|
||||
return err
|
||||
}
|
||||
labels := <-s.zclient.mplsLabelRangeCh
|
||||
if err = s.globalRib.AllocateMplsLabelRange(labels[0], labels[1]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
vrf.MplsLabel = mplsLabel
|
||||
err = s.zclient.client.SendVrfLabel(vrf.MplsLabel, vrf.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *BgpServer) AddVrf(ctx context.Context, r *api.AddVrfRequest) error {
|
||||
return s.mgmtOperation(func() error {
|
||||
if r == nil || r.Vrf == nil {
|
||||
@@ -2055,11 +2079,17 @@ func (s *BgpServer) AddVrf(ctx context.Context, r *api.AddVrfRequest) error {
|
||||
AS: s.bgpConfig.Global.Config.As,
|
||||
LocalID: net.ParseIP(s.bgpConfig.Global.Config.RouterId).To4(),
|
||||
}
|
||||
|
||||
if pathList, err := s.globalRib.AddVrf(name, id, rd, im, ex, pi); err != nil {
|
||||
return err
|
||||
} else if len(pathList) > 0 {
|
||||
s.propagateUpdate(nil, pathList)
|
||||
}
|
||||
if vrf, ok := s.globalRib.Vrfs[name]; ok {
|
||||
if s.zclient.mplsLabelRangeSize > 0 {
|
||||
go assignMplsLabel(s, vrf)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}, true)
|
||||
}
|
||||
|
||||
+53
-16
@@ -116,18 +116,19 @@ func filterOutExternalPath(paths []*table.Path) []*table.Path {
|
||||
return filteredPaths
|
||||
}
|
||||
|
||||
func newIPRouteBody(dst []*table.Path) (body *zebra.IPRouteBody, isWithdraw bool) {
|
||||
func newIPRouteBody(dst []*table.Path, vrfId uint32, version uint8) (body *zebra.IPRouteBody, isWithdraw bool) {
|
||||
paths := filterOutExternalPath(dst)
|
||||
if len(paths) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
path := paths[0]
|
||||
receiveVrfId := path.ReceiveVrfId()
|
||||
|
||||
l := strings.SplitN(path.GetNlri().String(), "/", 2)
|
||||
var prefix net.IP
|
||||
//nexthops := make([]net.IP, 0, len(paths))
|
||||
var nexthop zebra.Nexthop
|
||||
nexthops := make([]zebra.Nexthop, 0, len(paths))
|
||||
msgFlags := zebra.MESSAGE_NEXTHOP
|
||||
switch path.GetRouteFamily() {
|
||||
case bgp.RF_IPv4_UC, bgp.RF_IPv4_VPN:
|
||||
if path.GetRouteFamily() == bgp.RF_IPv4_UC {
|
||||
@@ -137,6 +138,14 @@ func newIPRouteBody(dst []*table.Path) (body *zebra.IPRouteBody, isWithdraw bool
|
||||
}
|
||||
for _, p := range paths {
|
||||
nexthop.Gate = p.GetNexthop().To4()
|
||||
nexthop.VrfId = receiveVrfId
|
||||
if version > 4 && path.GetRouteFamily() == bgp.RF_IPv4_VPN && receiveVrfId != vrfId {
|
||||
msgFlags |= zebra.FRR_ZAPI5_MESSAGE_LABEL
|
||||
for _, label := range path.GetNlri().(*bgp.LabeledVPNIPAddrPrefix).Labels.Labels {
|
||||
nexthop.LabelNum++
|
||||
nexthop.MplsLabels = append(nexthop.MplsLabels, label)
|
||||
}
|
||||
}
|
||||
nexthops = append(nexthops, nexthop)
|
||||
}
|
||||
case bgp.RF_IPv6_UC, bgp.RF_IPv6_VPN:
|
||||
@@ -147,16 +156,27 @@ func newIPRouteBody(dst []*table.Path) (body *zebra.IPRouteBody, isWithdraw bool
|
||||
}
|
||||
for _, p := range paths {
|
||||
nexthop.Gate = p.GetNexthop().To16()
|
||||
nexthop.VrfId = receiveVrfId
|
||||
if version > 4 && path.GetRouteFamily() == bgp.RF_IPv6_VPN && receiveVrfId != vrfId {
|
||||
msgFlags |= zebra.FRR_ZAPI5_MESSAGE_LABEL
|
||||
for _, label := range path.GetNlri().(*bgp.LabeledVPNIPAddrPrefix).Labels.Labels {
|
||||
nexthop.LabelNum++
|
||||
nexthop.MplsLabels = append(nexthop.MplsLabels, label)
|
||||
}
|
||||
}
|
||||
nexthops = append(nexthops, nexthop)
|
||||
}
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
msgFlags := zebra.MESSAGE_NEXTHOP
|
||||
plen, _ := strconv.ParseUint(l[1], 10, 8)
|
||||
med, err := path.GetMed()
|
||||
if err == nil {
|
||||
msgFlags |= zebra.MESSAGE_METRIC
|
||||
if version < 5 {
|
||||
msgFlags |= zebra.MESSAGE_METRIC
|
||||
} else {
|
||||
msgFlags |= zebra.FRR_ZAPI5_MESSAGE_METRIC
|
||||
}
|
||||
}
|
||||
var flags zebra.FLAG
|
||||
if path.IsIBGP() {
|
||||
@@ -282,10 +302,12 @@ func newPathFromIPRouteMessage(m *zebra.Message, version uint8) *table.Path {
|
||||
}
|
||||
|
||||
type zebraClient struct {
|
||||
client *zebra.Client
|
||||
server *BgpServer
|
||||
nexthopCache nexthopStateCache
|
||||
dead chan struct{}
|
||||
client *zebra.Client
|
||||
server *BgpServer
|
||||
nexthopCache nexthopStateCache
|
||||
mplsLabelRangeCh chan [2]uint32 // {start, end}
|
||||
mplsLabelRangeSize uint32
|
||||
dead chan struct{}
|
||||
}
|
||||
|
||||
func (z *zebraClient) getPathListWithNexthopUpdate(body *zebra.NexthopUpdateBody) []*table.Path {
|
||||
@@ -336,6 +358,10 @@ func (z *zebraClient) loop() {
|
||||
}...)
|
||||
defer w.Stop()
|
||||
|
||||
if z.mplsLabelRangeSize > 0 {
|
||||
defer close(z.mplsLabelRangeCh)
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-z.dead:
|
||||
@@ -367,6 +393,8 @@ func (z *zebraClient) loop() {
|
||||
delete(z.nexthopCache, body.Prefix.Prefix.String())
|
||||
}
|
||||
z.updatePathByNexthopCache(paths)
|
||||
case *zebra.GetLabelChunkBody:
|
||||
z.mplsLabelRangeCh <- [2]uint32{body.Start, body.End}
|
||||
}
|
||||
case ev := <-w.Event():
|
||||
switch msg := ev.(type) {
|
||||
@@ -374,7 +402,7 @@ func (z *zebraClient) loop() {
|
||||
if table.UseMultiplePaths.Enabled {
|
||||
for _, paths := range msg.MultiPathList {
|
||||
z.updatePathByNexthopCache(paths)
|
||||
if body, isWithdraw := newIPRouteBody(paths); body != nil {
|
||||
if body, isWithdraw := newIPRouteBody(paths, 0, z.client.Version); body != nil {
|
||||
z.client.SendIPRoute(0, body, isWithdraw)
|
||||
}
|
||||
if body := newNexthopRegisterBody(paths, z.nexthopCache); body != nil {
|
||||
@@ -391,8 +419,15 @@ func (z *zebraClient) loop() {
|
||||
}
|
||||
}
|
||||
for _, i := range vrfs {
|
||||
if body, isWithdraw := newIPRouteBody([]*table.Path{path}); body != nil {
|
||||
z.client.SendIPRoute(i, body, isWithdraw)
|
||||
routeFamily := path.GetRouteFamily()
|
||||
if i == zebra.VRF_DEFAULT && (routeFamily == bgp.RF_IPv4_VPN || routeFamily == bgp.RF_IPv6_VPN) {
|
||||
continue
|
||||
}
|
||||
if body, isWithdraw := newIPRouteBody([]*table.Path{path}, i, z.client.Version); body != nil {
|
||||
err := z.client.SendIPRoute(i, body, isWithdraw)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if body := newNexthopRegisterBody([]*table.Path{path}, z.nexthopCache); body != nil {
|
||||
z.client.SendNexthopRegister(i, body, false)
|
||||
@@ -415,7 +450,7 @@ func (z *zebraClient) loop() {
|
||||
}
|
||||
}
|
||||
|
||||
func newZebraClient(s *BgpServer, url string, protos []string, version uint8, nhtEnable bool, nhtDelay uint8) (*zebraClient, error) {
|
||||
func newZebraClient(s *BgpServer, url string, protos []string, version uint8, nhtEnable bool, nhtDelay uint8, mplsLabelRangeSize uint32) (*zebraClient, error) {
|
||||
l := strings.SplitN(url, ":", 2)
|
||||
if len(l) != 2 {
|
||||
return nil, fmt.Errorf("unsupported url: %s", url)
|
||||
@@ -468,10 +503,12 @@ func newZebraClient(s *BgpServer, url string, protos []string, version uint8, nh
|
||||
cli.SendRedistribute(t, zebra.VRF_DEFAULT)
|
||||
}
|
||||
w := &zebraClient{
|
||||
client: cli,
|
||||
server: s,
|
||||
nexthopCache: make(nexthopStateCache),
|
||||
dead: make(chan struct{}),
|
||||
client: cli,
|
||||
server: s,
|
||||
nexthopCache: make(nexthopStateCache),
|
||||
mplsLabelRangeSize: mplsLabelRangeSize,
|
||||
dead: make(chan struct{}),
|
||||
mplsLabelRangeCh: make(chan [2]uint32),
|
||||
}
|
||||
go w.loop()
|
||||
return w, nil
|
||||
|
||||
@@ -1203,7 +1203,8 @@ module gobgp {
|
||||
leaf version {
|
||||
type uint8;
|
||||
description
|
||||
"Configure version of zebra protocol. Default is 2. Supported up to 3.";
|
||||
"Configure version of zebra protocol. Default is 2.
|
||||
Supported version are 2 or 3 for Quagga and 4, 5 or 6 for FRRouting.";
|
||||
}
|
||||
leaf nexthop-trigger-enable {
|
||||
type boolean;
|
||||
@@ -1211,6 +1212,12 @@ module gobgp {
|
||||
leaf nexthop-trigger-delay {
|
||||
type uint8;
|
||||
}
|
||||
leaf mpls-label-range-size {
|
||||
type uint32;
|
||||
description
|
||||
"Configure MPLS label range size which will be requested to
|
||||
FRR/Zebra.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping zebra-set {
|
||||
|
||||
Reference in New Issue
Block a user