Skip to content

Commit 568af71

Browse files
taktv6Oliver Geiselhardt-Herms
andauthored
RIS: Do not send withdraws when BMP session is lost (#372)
* RIS: Do not send withdraws when BMP session is lost Co-authored-by: Oliver Geiselhardt-Herms <ogeiselhardt-herms@cloudflare.com>
1 parent c862182 commit 568af71

File tree

7 files changed

+95
-7
lines changed

7 files changed

+95
-7
lines changed

cmd/ris-mirror/rismirror/router.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ func (r *Router) Address() net.IP {
3838
return r.address
3939
}
4040

41+
func (r *Router) Ready(vrf uint64, afi uint16) bool {
42+
return true
43+
}
44+
4145
// GetVRF gets a VRF by its ID
4246
func (r *Router) GetVRF(vrfID uint64) *vrf.VRF {
4347
return r.vrfRegistry.GetVRFByRD(vrfID)

cmd/ris/risserver/server.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,21 @@ func wrapGetRIBErr(err error, rtr string, vrfID uint64, version api.IP_Version)
5757
return fmt.Errorf("unable to get RIB (%s/%s/v%d): %w", rtr, vrf.RouteDistinguisherHumanReadable(vrfID), version, err)
5858
}
5959

60+
func wrapRIBNotReadyErr(err error, rtr string, vrfID uint64, version api.IP_Version) error {
61+
return fmt.Errorf("RIB not ready yet (%s/%s/v%d): %w", rtr, vrf.RouteDistinguisherHumanReadable(vrfID), version, err)
62+
}
63+
64+
func ipVersionFromProto(v netapi.IP_Version) uint16 {
65+
switch v {
66+
case netapi.IP_IPv4:
67+
return 4
68+
case netapi.IP_IPv6:
69+
return 6
70+
}
71+
72+
return 0
73+
}
74+
6075
func (s Server) getRIB(rtr string, vrfID uint64, ipVersion netapi.IP_Version) (*locRIB.LocRIB, error) {
6176
r := s.bmp.GetRouter(rtr)
6277
if r == nil {
@@ -179,6 +194,10 @@ func (s *Server) ObserveRIB(req *pb.ObserveRIBRequest, stream pb.RoutingInformat
179194
return status.New(codes.Unavailable, wrapGetRIBErr(err, req.Router, vrfID, ipVersion).Error()).Err()
180195
}
181196

197+
if !s.bmp.GetRouter(req.Router).Ready(vrfID, ipVersionFromProto(ipVersion)) {
198+
return status.New(codes.Unavailable, wrapRIBNotReadyErr(err, req.Router, vrfID, ipVersion).Error()).Err()
199+
}
200+
182201
risObserveFIBClients.WithLabelValues(req.Router, fmt.Sprintf("%d", req.VrfId), fmt.Sprintf("%d", req.Afisafi)).Inc()
183202
defer risObserveFIBClients.WithLabelValues(req.Router, fmt.Sprintf("%d", req.VrfId), fmt.Sprintf("%d", req.Afisafi)).Dec()
184203

protocols/bgp/server/bmp_router.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type RouterInterface interface {
2323
Address() net.IP
2424
GetVRF(vrfID uint64) *vrf.VRF
2525
GetVRFs() []*vrf.VRF
26+
Ready(vrf uint64, afi uint16) bool
2627
}
2728

2829
// Router represents a BMP enabled route in BMP context
@@ -88,6 +89,46 @@ func newRouter(addr net.IP, port uint16, passive bool, arif adjRIBInFactoryI) *R
8889
}
8990
}
9091

92+
func (r *Router) Ready(vrf uint64, afi uint16) bool {
93+
neighbors := r.neighborManager.list()
94+
if len(neighbors) == 0 {
95+
return false
96+
}
97+
98+
if !neighborsIncludeVRF(neighbors, vrf) {
99+
return false
100+
}
101+
102+
for _, n := range neighbors {
103+
if n.vrfID != vrf {
104+
continue
105+
}
106+
107+
var fsmAfi *fsmAddressFamily
108+
if afi == 4 {
109+
fsmAfi = n.fsm.ipv4Unicast
110+
} else {
111+
fsmAfi = n.fsm.ipv6Unicast
112+
}
113+
114+
if !fsmAfi.endOfRIBMarkerReceived.Load() {
115+
return false
116+
}
117+
}
118+
119+
return true
120+
}
121+
122+
func neighborsIncludeVRF(neighbors []*neighbor, vrfID uint64) bool {
123+
for _, n := range neighbors {
124+
if n.vrfID == vrfID {
125+
return true
126+
}
127+
}
128+
129+
return false
130+
}
131+
91132
// GetVRF get's a VRF
92133
func (r *Router) GetVRF(rd uint64) *vrf.VRF {
93134
return r.vrfRegistry.GetVRFByRD(rd)

protocols/bgp/server/fsm_address_family.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package server
22

33
import (
4+
"sync/atomic"
45
"time"
56

67
bnet "github.com/bio-routing/bio-rd/net"
@@ -35,7 +36,7 @@ type fsmAddressFamily struct {
3536
multiProtocol bool
3637

3738
initialized bool
38-
endOfRIBMarkerReceived bool
39+
endOfRIBMarkerReceived atomic.Bool
3940
}
4041

4142
func newFSMAddressFamily(afi uint16, safi uint8, family *peerAddressFamily, fsm *FSM) *fsmAddressFamily {
@@ -181,7 +182,7 @@ func (f *fsmAddressFamily) processUpdate(u *packet.BGPUpdate, bmpPostPolicy bool
181182
f.multiProtocolUpdates(u, bmpPostPolicy, timestamp)
182183
if f.afi == packet.AFIIPv4 {
183184
if u.IsEndOfRIBMarker() {
184-
f.endOfRIBMarkerReceived = true
185+
f.endOfRIBMarkerReceived.Store(true)
185186
}
186187

187188
f.withdraws(u, bmpPostPolicy)
@@ -226,7 +227,7 @@ func (f *fsmAddressFamily) multiProtocolUpdates(u *packet.BGPUpdate, bmpPostPoli
226227

227228
if mpReachNLRI != nil && mpUnreachNLRI != nil {
228229
if mpReachNLRI.NLRI == nil && mpUnreachNLRI.NLRI == nil {
229-
f.endOfRIBMarkerReceived = true
230+
f.endOfRIBMarkerReceived.Store(true)
230231
}
231232
}
232233
}

protocols/bgp/server/metrics_service.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func metricsForFamily(family *fsmAddressFamily) *metrics.BGPAddressFamilyMetrics
7171
AFI: family.afi,
7272
SAFI: family.safi,
7373
RoutesReceived: uint64(family.adjRIBIn.RouteCount()),
74-
EndOfRIBMarkerReceived: family.endOfRIBMarkerReceived,
74+
EndOfRIBMarkerReceived: family.endOfRIBMarkerReceived.Load(),
7575
}
7676

7777
if family.adjRIBOut != nil {

routingtable/client_manager.go

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@ func (c *ClientOptions) GetMaxPaths(ecmpPaths uint) uint {
3030

3131
// ClientManager manages clients of routing tables (observer pattern)
3232
type ClientManager struct {
33-
clients map[RouteTableClient]ClientOptions
34-
master ClientManagerMaster
35-
mu sync.RWMutex
33+
clients map[RouteTableClient]ClientOptions
34+
master ClientManagerMaster
35+
mu sync.RWMutex
36+
endOfLife bool // do not accept new clients when EOL
3637
}
3738

3839
// NewClientManager creates and initializes a new client manager
@@ -62,6 +63,11 @@ func (c *ClientManager) GetOptions(client RouteTableClient) ClientOptions {
6263
// RegisterWithOptions registers a client with options for updates
6364
func (c *ClientManager) RegisterWithOptions(client RouteTableClient, opt ClientOptions) {
6465
c.mu.Lock()
66+
67+
if c.endOfLife {
68+
return
69+
}
70+
6571
c.clients[client] = opt
6672
c.mu.Unlock()
6773

@@ -72,6 +78,11 @@ func (c *ClientManager) RegisterWithOptions(client RouteTableClient, opt ClientO
7278
func (c *ClientManager) Unregister(client RouteTableClient) bool {
7379
c.mu.Lock()
7480
defer c.mu.Unlock()
81+
82+
return c._unregister(client)
83+
}
84+
85+
func (c *ClientManager) _unregister(client RouteTableClient) bool {
7586
if _, ok := c.clients[client]; !ok {
7687
return false
7788
}
@@ -90,3 +101,14 @@ func (c *ClientManager) Clients() []RouteTableClient {
90101

91102
return ret
92103
}
104+
105+
func (c *ClientManager) Dispose() {
106+
c.mu.Lock()
107+
defer c.mu.Unlock()
108+
109+
c.endOfLife = true
110+
111+
for cli := range c.clients {
112+
c._unregister(cli)
113+
}
114+
}

routingtable/locRIB/loc_rib.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,5 +352,6 @@ func (a *LocRIB) RefreshRoute(*net.Prefix, []*route.Path) {
352352
func (a *LocRIB) Dispose() {
353353
for _, c := range a.clientManager.Clients() {
354354
c.Dispose()
355+
a.clientManager.Unregister(c)
355356
}
356357
}

0 commit comments

Comments
 (0)