diff options
Diffstat (limited to 'pkg/server')
-rw-r--r-- | pkg/server/server.go | 33 | ||||
-rw-r--r-- | pkg/server/zclient.go | 108 |
2 files changed, 89 insertions, 52 deletions
diff --git a/pkg/server/server.go b/pkg/server/server.go index 92a0ca33..7e7c370f 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -960,7 +960,7 @@ func (s *BgpServer) propagateUpdate(peer *peer, pathList []*table.Path) { peer.fsm.lock.RUnlock() path = path.ToGlobal(rib.Vrfs[peerVrf]) if s.zclient != nil { - s.zclient.pathVrf[path] = rib.Vrfs[peerVrf].Id + s.zclient.pathVrfMap[path] = rib.Vrfs[peerVrf].Id } } @@ -1594,9 +1594,6 @@ func (s *BgpServer) EnableZebra(ctx context.Context, r *api.EnableZebraRequest) } var err error 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) } @@ -2035,26 +2032,6 @@ 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 { @@ -2088,8 +2065,8 @@ func (s *BgpServer) AddVrf(ctx context.Context, r *api.AddVrfRequest) error { s.propagateUpdate(nil, pathList) } if vrf, ok := s.globalRib.Vrfs[name]; ok { - if s.zclient != nil && s.zclient.mplsLabelRangeSize > 0 { - go assignMplsLabel(s, vrf) + if s.zclient != nil && s.zclient.mplsLabel.rangeSize > 0 { + s.zclient.assignAndSendVrfMplsLabel(vrf) } } return nil @@ -2110,6 +2087,10 @@ func (s *BgpServer) DeleteVrf(ctx context.Context, r *api.DeleteVrfRequest) erro return fmt.Errorf("failed to delete VRF %s: neighbor %s is in use", name, n.ID()) } } + vrfMplsLabel := s.globalRib.Vrfs[name].MplsLabel + if vrfMplsLabel > 0 { + s.zclient.releaseMplsLabel(vrfMplsLabel) + } pathList, err := s.globalRib.DeleteVrf(name) if err != nil { return err diff --git a/pkg/server/zclient.go b/pkg/server/zclient.go index 3a650cfe..e16edd93 100644 --- a/pkg/server/zclient.go +++ b/pkg/server/zclient.go @@ -35,9 +35,6 @@ import ( // the metric value of math.MaxUint32 means the nexthop is unreachable. type nexthopStateCache map[string]uint32 -// pathVrfMap stores nexthop vpn id of VPN paths in global rib -type pathVrfMap map[*table.Path]uint32 - func (m nexthopStateCache) applyToPathList(paths []*table.Path) []*table.Path { updated := make([]*table.Path, 0, len(paths)) for _, path := range paths { @@ -121,7 +118,7 @@ func filterOutExternalPath(paths []*table.Path) []*table.Path { func addMessageLabelToIPRouteBody(path *table.Path, vrfId uint32, z *zebraClient, msgFlags *zebra.MESSAGE_FLAG, nexthop *zebra.Nexthop) { v := z.client.Version - nhVrfId := z.pathVrf[path] + nhVrfId := z.pathVrfMap[path] rf := path.GetRouteFamily() if v > 4 && (rf == bgp.RF_IPv4_VPN || rf == bgp.RF_IPv6_VPN) && nhVrfId != vrfId { *msgFlags |= zebra.FRR_ZAPI5_MESSAGE_LABEL @@ -162,11 +159,11 @@ func newIPRouteBody(dst []*table.Path, vrfId uint32, z *zebraClient) (body *zebr return nil, false } var nhVrfId uint32 - if nhvrfid, ok := z.pathVrf[path]; ok { - // if the path is withdraw, delete path from Map pathVrf after refer the path + if nhvrfid, ok := z.pathVrfMap[path]; ok { + // if the path is withdraw, delete path from pathVrfMap after refer the path nhVrfId = nhvrfid if isWithdraw { - delete(z.pathVrf, path) + delete(z.pathVrfMap, path) } } else { nhVrfId = zebra.VRF_DEFAULT @@ -309,14 +306,19 @@ func newPathFromIPRouteMessage(m *zebra.Message, version uint8) *table.Path { return path } +type mplsLabelParameter struct { + rangeSize uint32 + maps map[uint64]*table.Bitmap + unassinedVrf []*table.Vrf //Vrfs which are not assigned MPLS label +} + type zebraClient struct { - client *zebra.Client - server *BgpServer - nexthopCache nexthopStateCache - pathVrf pathVrfMap - mplsLabelRangeCh chan [2]uint32 // {start, end} - mplsLabelRangeSize uint32 - dead chan struct{} + client *zebra.Client + server *BgpServer + nexthopCache nexthopStateCache + pathVrfMap map[*table.Path]uint32 //vpn paths and nexthop vpn id + mplsLabel mplsLabelParameter + dead chan struct{} } func (z *zebraClient) getPathListWithNexthopUpdate(body *zebra.NexthopUpdateBody) []*table.Path { @@ -367,10 +369,6 @@ func (z *zebraClient) loop() { }...) defer w.Stop() - if z.mplsLabelRangeSize > 0 { - defer close(z.mplsLabelRangeCh) - } - for { select { case <-z.dead: @@ -403,7 +401,12 @@ func (z *zebraClient) loop() { } z.updatePathByNexthopCache(paths) case *zebra.GetLabelChunkBody: - z.mplsLabelRangeCh <- [2]uint32{body.Start, body.End} + startEnd := uint64(body.Start)<<32 | uint64(body.End) + z.mplsLabel.maps[startEnd] = table.NewBitmap(int(body.End - body.Start + 1)) + for _, vrf := range z.mplsLabel.unassinedVrf { + z.assignAndSendVrfMplsLabel(vrf) + } + z.mplsLabel.unassinedVrf = nil } case ev := <-w.Event(): switch msg := ev.(type) { @@ -512,14 +515,67 @@ 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), - pathVrf: make(pathVrfMap), - mplsLabelRangeSize: mplsLabelRangeSize, - dead: make(chan struct{}), - mplsLabelRangeCh: make(chan [2]uint32), + client: cli, + server: s, + nexthopCache: make(nexthopStateCache), + pathVrfMap: make(map[*table.Path]uint32), + mplsLabel: mplsLabelParameter{ + rangeSize: mplsLabelRangeSize, + maps: make(map[uint64]*table.Bitmap), + }, + dead: make(chan struct{}), } go w.loop() + if mplsLabelRangeSize > 0 { + if err = cli.SendGetLabelChunk(&zebra.GetLabelChunkBody{ChunkSize: mplsLabelRangeSize}); err != nil { + return nil, err + } + } return w, nil } + +func (z *zebraClient) assignMplsLabel() (uint32, error) { + if z.mplsLabel.maps == nil { + return 0, nil + } + var label uint32 + for startEnd, bitmap := range z.mplsLabel.maps { + 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("failed to assign new MPLS label") + } + return label, nil +} + +func (z *zebraClient) assignAndSendVrfMplsLabel(vrf *table.Vrf) error { + var err error + if vrf.MplsLabel, err = z.assignMplsLabel(); vrf.MplsLabel > 0 { // success + if err = z.client.SendVrfLabel(vrf.MplsLabel, vrf.Id); err != nil { + return err + } + } else if vrf.MplsLabel == 0 { // GetLabelChunk is not performed + z.mplsLabel.unassinedVrf = append(z.mplsLabel.unassinedVrf, vrf) + } + return err +} + +func (z *zebraClient) releaseMplsLabel(label uint32) { + if z.mplsLabel.maps == nil { + return + } + for startEnd, bitmap := range z.mplsLabel.maps { + start := uint32(startEnd >> 32) + end := uint32(startEnd & 0xffffffff) + if start <= label && label <= end { + bitmap.Unflag(uint(label - start)) + return + } + } +} |