Skip to content

Commit bb8b173

Browse files
authored
BMP: Allow ignoring BGP sessions based on peer ASN (#379)
1 parent 634c76c commit bb8b173

File tree

5 files changed

+144
-13
lines changed

5 files changed

+144
-13
lines changed

cmd/ris/config/config.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import (
99

1010
// RISConfig is the config of RIS instance
1111
type RISConfig struct {
12-
BMPServers []BMPServer `yaml:"bmp_servers"`
12+
BMPServers []BMPServer `yaml:"bmp_servers"`
13+
IgnorePeerASNs []uint32 `yaml:"ignore_peer_asns"`
1314
}
1415

1516
// BMPServer represent a BMP enable Router

cmd/ris/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ func main() {
5252
b := server.NewServer(server.BMPServerConfig{
5353
KeepalivePeriod: time.Duration(*tcpKeepaliveInterval) * time.Second,
5454
AcceptAny: *allowAny,
55+
IgnorePeerASNs: cfg.IgnorePeerASNs,
5556
})
5657

5758
if *bmpListenAddr != "" {

protocols/bgp/server/bmp_router.go

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ type Router struct {
4848
ribClients map[afiClient]struct{}
4949
ribClientsMu sync.Mutex
5050
adjRIBInFactory adjRIBInFactoryI
51+
ignorePeerASNs []uint32
52+
ignoredPeers map[bnet.IP]struct{}
5153

5254
counters routerCounters
5355
}
@@ -72,7 +74,7 @@ type neighbor struct {
7274
opt *packet.DecodeOptions
7375
}
7476

75-
func newRouter(addr net.IP, port uint16, passive bool, arif adjRIBInFactoryI) *Router {
77+
func newRouter(addr net.IP, port uint16, passive bool, arif adjRIBInFactoryI, ignorePeerASNs []uint32) *Router {
7678
return &Router{
7779
address: addr,
7880
port: port,
@@ -86,6 +88,8 @@ func newRouter(addr net.IP, port uint16, passive bool, arif adjRIBInFactoryI) *R
8688
stop: make(chan struct{}),
8789
ribClients: make(map[afiClient]struct{}),
8890
adjRIBInFactory: arif,
91+
ignorePeerASNs: ignorePeerASNs,
92+
ignoredPeers: make(map[bnet.IP]struct{}),
8993
}
9094
}
9195

@@ -214,6 +218,10 @@ func (r *Router) processRouteMonitoringMsg(msg *bmppkt.RouteMonitoringMsg) {
214218
return
215219
}
216220

221+
if _, exists := r.ignoredPeers[peerAddrToBNetAddr(msg.PerPeerHeader.PeerAddress, msg.PerPeerHeader.GetIPVersion())]; exists {
222+
return
223+
}
224+
217225
n := r.neighborManager.getNeighbor(msg.PerPeerHeader.PeerDistinguisher, msg.PerPeerHeader.PeerAddress)
218226
if n == nil {
219227
log.Errorf("Received route monitoring message for non-existent neighbor %d/%v on %s", msg.PerPeerHeader.PeerDistinguisher, msg.PerPeerHeader.PeerAddress, r.address.String())
@@ -306,12 +314,39 @@ func (r *Router) processPeerDownNotification(msg *bmppkt.PeerDownNotification) {
306314
}).Infof("peer down notification received")
307315
atomic.AddUint64(&r.counters.peerDownNotificationMessages, 1)
308316

317+
peerAddr := peerAddrToBNetAddr(msg.PerPeerHeader.PeerAddress, msg.PerPeerHeader.GetIPVersion())
318+
if _, exists := r.ignoredPeers[peerAddr]; exists {
319+
delete(r.ignoredPeers, peerAddr)
320+
return
321+
}
322+
309323
err := r.neighborManager.neighborDown(msg.PerPeerHeader.PeerDistinguisher, msg.PerPeerHeader.PeerAddress)
310324
if err != nil {
311325
log.Errorf("Failed to process peer down notification: %v", err)
312326
}
313327
}
314328

329+
func peerAddrToBNetAddr(a [16]byte, ipVersion uint8) bnet.IP {
330+
addrLen := net.IPv4len
331+
if ipVersion == 6 {
332+
addrLen = net.IPv6len
333+
}
334+
335+
// bnet.IPFromBytes can only fail if length of argument is not 4 or 16. However, length is ensured here.
336+
ip, _ := bnet.IPFromBytes(a[16-addrLen:])
337+
return ip
338+
}
339+
340+
func (r *Router) isIgnoredPeerASN(asn uint32) bool {
341+
for _, x := range r.ignorePeerASNs {
342+
if x == asn {
343+
return true
344+
}
345+
}
346+
347+
return false
348+
}
349+
315350
func (r *Router) processPeerUpNotification(msg *bmppkt.PeerUpNotification) error {
316351
atomic.AddUint64(&r.counters.peerUpNotificationMessages, 1)
317352
log.WithFields(log.Fields{
@@ -321,6 +356,14 @@ func (r *Router) processPeerUpNotification(msg *bmppkt.PeerUpNotification) error
321356
"peer_address": addrToNetIP(msg.PerPeerHeader.PeerAddress).String(),
322357
}).Infof("peer up notification received")
323358

359+
peerAddress := peerAddrToBNetAddr(msg.PerPeerHeader.PeerAddress, msg.PerPeerHeader.GetIPVersion())
360+
localAddress := peerAddrToBNetAddr(msg.LocalAddress, msg.PerPeerHeader.GetIPVersion())
361+
362+
if r.isIgnoredPeerASN(msg.PerPeerHeader.PeerAS) {
363+
r.ignoredPeers[peerAddress] = struct{}{}
364+
return nil
365+
}
366+
324367
if len(msg.SentOpenMsg) < packet.MinOpenLen {
325368
return fmt.Errorf("received peer up notification for %v: Invalid sent open message: %v", msg.PerPeerHeader.PeerAddress, msg.SentOpenMsg)
326369
}
@@ -339,15 +382,6 @@ func (r *Router) processPeerUpNotification(msg *bmppkt.PeerUpNotification) error
339382
return fmt.Errorf("unable to decode received open message sent from %v to %v: %w", msg.PerPeerHeader.PeerAddress, r.address.String(), err)
340383
}
341384

342-
addrLen := net.IPv4len
343-
if msg.PerPeerHeader.GetIPVersion() == 6 {
344-
addrLen = net.IPv6len
345-
}
346-
347-
// bnet.IPFromBytes can only fail if length of argument is not 4 or 16. However, length is ensured here.
348-
peerAddress, _ := bnet.IPFromBytes(msg.PerPeerHeader.PeerAddress[16-addrLen:])
349-
localAddress, _ := bnet.IPFromBytes(msg.LocalAddress[16-addrLen:])
350-
351385
fsm := &FSM{
352386
isBMP: true,
353387
ribsInitialized: true,

protocols/bgp/server/bmp_server.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,13 @@ type BMPServer struct {
3434
listener net.Listener
3535
adjRIBInFactory adjRIBInFactoryI
3636
acceptAny bool
37+
ignorePeerASNs []uint32
3738
}
3839

3940
type BMPServerConfig struct {
4041
KeepalivePeriod time.Duration
4142
AcceptAny bool
43+
IgnorePeerASNs []uint32
4244
}
4345

4446
type afiClient struct {
@@ -54,6 +56,7 @@ func NewServer(cfg BMPServerConfig) *BMPServer {
5456
keepalivePeriod: cfg.KeepalivePeriod,
5557
adjRIBInFactory: adjRIBInFactory{},
5658
acceptAny: cfg.AcceptAny,
59+
ignorePeerASNs: cfg.IgnorePeerASNs,
5760
}
5861

5962
b.metrics = &bmpMetricsService{b}
@@ -226,7 +229,7 @@ func (b *BMPServer) AddRouter(addr net.IP, port uint16, passive bool, dynamic bo
226229
}
227230

228231
func (b *BMPServer) _addRouter(addr net.IP, port uint16, passive bool, dynamic bool) error {
229-
r := newRouter(addr, port, passive, b.adjRIBInFactory)
232+
r := newRouter(addr, port, passive, b.adjRIBInFactory, b.ignorePeerASNs)
230233
if _, exists := b.routers[r.address.String()]; exists {
231234
return fmt.Errorf("router %s already configured,", r.address.String())
232235
}

protocols/bgp/server/bmp_server_test.go

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ import (
66
"time"
77

88
bnet "github.com/bio-routing/bio-rd/net"
9+
"github.com/stretchr/testify/assert"
910
)
1011

1112
func TestBMPServer(t *testing.T) {
1213
srv := NewServer(BMPServerConfig{
1314
KeepalivePeriod: time.Second,
1415
})
1516

16-
rtr := newRouter(net.IP{10, 0, 255, 1}, 30119, false, &adjRIBInFactory{})
17+
rtr := newRouter(net.IP{10, 0, 255, 1}, 30119, false, &adjRIBInFactory{}, []uint32{13335})
1718
_, pipe := net.Pipe()
1819
rtr.con = pipe
1920
srv.routers[rtr.address.String()] = rtr
@@ -176,6 +177,97 @@ func TestBMPServer(t *testing.T) {
176177
}
177178
rtr.processMsg(peerUpC)
178179

180+
peerUpD := []byte{
181+
3, // Version
182+
0, 0, 0, 126, // Length
183+
3, // Msg Type (peer up)
184+
185+
0, // Peer Type (global instance peer)
186+
0, // Peer Flags
187+
0, 0, 0, 0, 0, 0, 0, 0, // Peer Distinguisher
188+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 1, 2, 100, // Peer Address (10.1.2.100)
189+
0, 0, 52, 23, // Peer AS = 13335
190+
0, 0, 0, 233, // Peer BGP ID = 240
191+
0, 0, 0, 0, // Timestamp seconds
192+
0, 0, 0, 0, // Timestamp microseconds
193+
194+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 1, 2, 200, // Local Address (10.1.2.200)
195+
0, 222, // Local Port
196+
0, 179, // Remote Port
197+
198+
// Sent OPEN
199+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // Marker
200+
0, 29, // Length
201+
1, // Type (OPEN)
202+
4, // BGP Version
203+
0, 100, // ASN
204+
0, 180, // Hold Time
205+
1, 0, 0, 100, // BGP ID
206+
0, // Ops Param Len
207+
208+
// Received OPEN
209+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // Marker
210+
0, 29, // Length
211+
1, // Type (OPEN)
212+
4, // BGP Version
213+
0, 233, // ASN
214+
0, 180, // Hold Time
215+
1, 0, 0, 222, // BGP ID
216+
0, // Ops Param Len
217+
}
218+
rtr.processMsg(peerUpD)
219+
220+
assert.Equal(t, rtr.ignoredPeers, map[bnet.IP]struct{}{
221+
bnet.IPv4FromOctets(10, 1, 2, 100): {},
222+
})
223+
224+
updateD1 := []byte{
225+
3, // Version
226+
0, 0, 0, 100, // Length
227+
0, // Msg Type (route monitoring)
228+
229+
0, // Peer Type (global instance peer)
230+
0b01100000, // Peer Flags
231+
0, 0, 0, 0, 0, 0, 0, 123, // Peer Distinguisher
232+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 1, 2, 100, // Peer Address (10.1.2.100)
233+
0, 0, 0, 200, // Peer AS = 200
234+
0, 0, 0, 200, // Peer BGP ID = 200
235+
0, 0, 0, 0, // Timestamp seconds
236+
0, 0, 0, 0, // Timestamp microseconds
237+
238+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // Marker
239+
0, 52, // Length
240+
2, // Type (UPDATE)
241+
242+
0, 0, // Withdraw length
243+
0, 27, // Total Path Attribute Length
244+
245+
0, // Attribute flags
246+
3, // Attribute Type code (Next Hop)
247+
4, // Length
248+
10, 0, 0, 0,
249+
250+
255, // Attribute flags
251+
1, // Attribute Type code (ORIGIN)
252+
0, 1, // Length
253+
2, // INCOMPLETE
254+
255+
0, // Attribute flags
256+
2, // Attribute Type code (AS Path)
257+
12, // Length
258+
2, // Type = AS_SEQUENCE
259+
2, // Path Segment Length
260+
59, 65, // AS15169
261+
12, 248, // AS3320
262+
1, // Type = AS_SET
263+
2, // Path Segment Length
264+
59, 65, // AS15169
265+
12, 248, // AS3320
266+
267+
8, 20, // 20.0.0.0/8
268+
}
269+
rtr.processMsg(updateD1)
270+
179271
aaaaVRFs = aaaa.GetVRFs()
180272
if len(aaaaVRFs) != 2 {
181273
t.Errorf("Unexpected VRF count for router AAAA: %d", len(aaaaVRFs))

0 commit comments

Comments
 (0)