Skip to content

Commit c8dd0e7

Browse files
committed
add tests using inmemory listener
1 parent b554c27 commit c8dd0e7

File tree

2 files changed

+187
-66
lines changed

2 files changed

+187
-66
lines changed

protocols/bgp/server/server.go

Lines changed: 49 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ const (
2020
)
2121

2222
type bgpServer struct {
23-
listeners []listener
24-
acceptCh chan net.Conn
25-
peers *peerManager
26-
routerID uint32
27-
metrics *metricsService
28-
logger log.LoggerInterface
23+
addListeners chan listener
24+
acceptedListeners []listener
25+
acceptCh chan net.Conn
26+
peers *peerManager
27+
routerID uint32
28+
metrics *metricsService
29+
logger log.LoggerInterface
2930
}
3031

3132
type BGPServer interface {
@@ -37,6 +38,7 @@ type BGPServer interface {
3738
GetPeerConfig(*bnet.IP) *PeerConfig
3839
DisposePeer(*bnet.IP)
3940
GetPeers() []*bnet.IP
41+
GetPeerStatus(*bnet.IP) string
4042
Metrics() (*metrics.BGPMetrics, error)
4143
GetRIBIn(peerIP *bnet.IP, afi uint16, safi uint8) *adjRIBIn.AdjRIBIn
4244
GetRIBOut(peerIP *bnet.IP, afi uint16, safi uint8) *adjRIBOut.AdjRIBOut
@@ -52,9 +54,10 @@ func NewBGPServer(routerID uint32) BGPServer {
5254

5355
func newBGPServer(routerID uint32) *bgpServer {
5456
server := &bgpServer{
55-
peers: newPeerManager(),
56-
routerID: routerID,
57-
listeners: make([]listener, 0),
57+
peers: newPeerManager(),
58+
routerID: routerID,
59+
addListeners: make(chan listener, 256),
60+
acceptedListeners: make([]listener, 0),
5861
logger: log.GetLogger().WithFields(log.Fields{
5962
"router_id": bnet.IPv4(routerID).String(),
6063
}),
@@ -99,12 +102,12 @@ func (d *dummyListener) setTCPMD5(net.IP, string) error {
99102
func (b *bgpServer) AddListener(l ...net.Listener) error {
100103
for _, l := range l {
101104
if ll, ok := l.(listener); ok {
102-
b.listeners = append(b.listeners, ll)
105+
b.addListeners <- ll
103106
} else {
104107
d := &dummyListener{
105108
Listener: l,
106109
logger: b.logger}
107-
b.listeners = append(b.listeners, d)
110+
b.addListeners <- d
108111
}
109112
}
110113

@@ -126,28 +129,30 @@ func (b *bgpServer) AddListenerFromAddrString(addrs ...string) error {
126129
return nil
127130
}
128131

129-
func (b *bgpServer) Start() error {
130-
if len(b.listeners) > 0 {
131-
acceptCh := make(chan net.Conn, 4096)
132-
133-
for _, addr := range b.listeners {
134-
go func(addr listener) {
135-
for {
136-
conn, err := addr.Accept()
137-
138-
if err != nil {
139-
b.logger.Errorf("failed to accept connection: %v", err)
140-
continue
141-
}
142-
143-
acceptCh <- conn
144-
}
145-
}(addr)
132+
func (b *bgpServer) accept(addr listener, acceptCh chan net.Conn) {
133+
for {
134+
conn, err := addr.Accept()
135+
136+
if err != nil {
137+
b.logger.Errorf("failed to accept connection: %v", err)
138+
continue
146139
}
147-
b.acceptCh = acceptCh
148140

149-
go b.incomingConnectionWorker()
141+
acceptCh <- conn
150142
}
143+
}
144+
145+
func (b *bgpServer) Start() error {
146+
b.acceptCh = make(chan net.Conn, 4096)
147+
148+
go b.incomingConnectionWorker()
149+
150+
go func() {
151+
for addr := range b.addListeners {
152+
go b.accept(addr, b.acceptCh)
153+
b.acceptedListeners = append(b.acceptedListeners, addr)
154+
}
155+
}()
151156

152157
return nil
153158
}
@@ -264,7 +269,7 @@ func (b *bgpServer) AddPeer(c PeerConfig) error {
264269
}
265270

266271
if c.AuthenticationKey != "" {
267-
for _, l := range b.listeners {
272+
for _, l := range b.acceptedListeners {
268273
err = l.setTCPMD5(c.PeerAddress.ToNetIP(), c.AuthenticationKey)
269274
if err != nil {
270275
return fmt.Errorf("unable to set TCP MD5 secret: %w", err)
@@ -298,6 +303,19 @@ func (b *bgpServer) GetPeerConfig(addr *bnet.IP) *PeerConfig {
298303
return nil
299304
}
300305

306+
// GetPeerStatus gets the status of a BGP peer by its address
307+
func (b *bgpServer) GetPeerStatus(addr *bnet.IP) string {
308+
p := b.peers.get(addr)
309+
if p != nil {
310+
p.fsms[0].stateMu.RLock()
311+
defer p.fsms[0].stateMu.RUnlock()
312+
313+
return stateName(p.fsms[0].state)
314+
}
315+
316+
return ""
317+
}
318+
301319
func (b *bgpServer) DisposePeer(addr *bnet.IP) {
302320
p := b.peers.get(addr)
303321
if p == nil {

protocols/bgp/server/server_test.go

Lines changed: 138 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,32 @@ import (
1111
"github.com/valyala/fasthttp/fasthttputil"
1212

1313
bnet "github.com/bio-routing/bio-rd/net"
14+
"github.com/bio-routing/bio-rd/protocols/bgp/packet"
1415
bgpserver "github.com/bio-routing/bio-rd/protocols/bgp/server"
1516
"github.com/bio-routing/bio-rd/protocols/bgp/types"
1617
"github.com/bio-routing/bio-rd/route"
17-
"github.com/bio-routing/bio-rd/routingtable"
1818
"github.com/bio-routing/bio-rd/routingtable/filter"
1919
"github.com/bio-routing/bio-rd/routingtable/vrf"
2020
)
2121

22-
func TestServerInMemory(t *testing.T) {
23-
ip1 := bnet.IPv4FromOctets(172, 17, 0, 3)
24-
ip2 := bnet.IPv4FromOctets(169, 254, 200, 0)
22+
func TestInMemoryServerMinimalConnection(t *testing.T) {
23+
ip1 := bnet.IPv4FromOctets(172, 16, 0, 1)
24+
as1 := uint32(65101)
25+
ip2 := bnet.IPv4FromOctets(172, 16, 0, 2)
26+
as2 := uint32(65102)
2527

26-
s1, ml1, vrfs1, err := startServer(ip1)
28+
s1, vrfs1, err := startServer(ip1)
2729
if err != nil {
28-
t.Fatalf("Unable to start server 1: %v", err)
30+
t.Fatalf("Unable to start server: %v", err)
2931
}
30-
s2, ml2, vrfs2, err := startServer(ip2)
32+
33+
s2, vrfs2, err := startServer(ip2)
3134
if err != nil {
32-
t.Fatalf("Unable to start server 2: %v", err)
35+
t.Fatalf("Unable to start server: %v", err)
3336
}
3437

35-
as1 := uint32(65100)
36-
as2 := uint32(65101)
38+
ml1 := addListener(s1, ip1)
39+
ml2 := addListener(s2, ip2)
3740

3841
if err := s1.AddPeer(
3942
bgpPeerConfig(s1, ip1.Ptr(), ip2.Ptr(), as1, as2,
@@ -54,49 +57,155 @@ func TestServerInMemory(t *testing.T) {
5457
t.Fatalf("Unable to add peer: %v", err)
5558
}
5659

57-
master := vrfs1.GetVRFByName("master")
58-
locRIB := master.IPv4UnicastRIB()
60+
// Wait for connection to be established
61+
assert.Eventually(t, func() bool {
62+
return s1.GetPeerStatus(ip2.Ptr()) == "established" && s2.GetPeerStatus(ip1.Ptr()) == "established"
63+
}, time.Second*10, time.Millisecond*100, "Peer not established")
64+
65+
assert.Zero(t, s1.GetRIBIn(ip2.Ptr(), packet.AFIIPv4, packet.SAFIUnicast).RouteCount())
66+
assert.Zero(t, s2.GetRIBIn(ip1.Ptr(), packet.AFIIPv4, packet.SAFIUnicast).RouteCount())
67+
}
68+
69+
func TestInMemoryServerMinimalPaths(t *testing.T) {
70+
ip1 := bnet.IPv4FromOctets(172, 16, 0, 1)
71+
as1 := uint32(65101)
72+
ip2 := bnet.IPv4FromOctets(172, 16, 0, 2)
73+
as2 := uint32(65102)
74+
ip3 := bnet.IPv4FromOctets(172, 16, 0, 3)
75+
as3 := uint32(65103)
76+
77+
s1, vrfs1, err := startServer(ip1)
78+
if err != nil {
79+
t.Fatalf("Unable to start server: %v", err)
80+
}
81+
82+
s2, vrfs2, err := startServer(ip2)
83+
if err != nil {
84+
t.Fatalf("Unable to start server: %v", err)
85+
}
86+
87+
s3, vrfs3, err := startServer(ip3)
88+
if err != nil {
89+
t.Fatalf("Unable to start server: %v", err)
90+
}
91+
92+
ml1 := addListener(s1, ip1)
93+
ml2 := addListener(s2, ip2)
94+
ml3 := addListener(s3, ip3)
95+
96+
if err := connect(s1, s2, ip1, ip2, vrfs1, vrfs2, as1, as2, ml1, ml2); err != nil {
97+
t.Fatalf("Unable to connect s1 and s2: %v", err)
98+
}
99+
100+
if err := connect(s2, s3, ip2, ip3, vrfs2, vrfs3, as2, as3, ml2, ml3); err != nil {
101+
t.Fatalf("Unable to connect s2 and s3: %v", err)
102+
}
59103

60104
pfx := bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8)
61105

62-
if err := locRIB.AddPath(pfx.Ptr(), generatePath(ip1.Ptr(), ip1.Ptr())); err != nil {
106+
if err := vrfs1.GetVRFByName("master").IPv4UnicastRIB().AddPath(pfx.Ptr(), generatePath(ip1.Ptr(), ip1.Ptr())); err != nil {
63107
t.Fatalf("Unable to add path: %v", err)
64108
}
65109

110+
// Wait for connection to be established
111+
assert.Eventually(t, func() bool {
112+
return s1.GetPeerStatus(ip2.Ptr()) == "established" &&
113+
s2.GetPeerStatus(ip1.Ptr()) == "established" &&
114+
s2.GetPeerStatus(ip3.Ptr()) == "established" &&
115+
s3.GetPeerStatus(ip2.Ptr()) == "established"
116+
}, time.Second*10, time.Millisecond*100, "Peer not established")
117+
66118
assert.Eventually(t, func() bool {
67119
routes := vrfs2.GetVRFByName("master").IPv4UnicastRIB().LPM(pfx.Ptr())
68120

69121
if len(routes) != 1 {
122+
t.Logf("Expected 1 route, got %d", len(routes))
123+
70124
return false
71125
}
72126

73127
if len(routes[0].Paths()) != 1 {
128+
t.Logf("Expected 1 path, got %d", len(routes[0].Paths()))
129+
74130
return false
75131
}
76132

77133
path := routes[0].Paths()[0]
78134

79-
return path.NextHop().Equal(ip1) &&
80-
path.BGPPath.BGPPathA.LocalPref == 0 &&
81-
path.BGPPath.BGPPathA.MED == 200
82-
}, time.Second*15, time.Millisecond*100, "Route not received")
135+
return path.NextHop().Equal(ip1)
136+
}, time.Second*3, time.Millisecond*500, "Route not received")
137+
138+
assert.Eventually(t, func() bool {
139+
routes := vrfs3.GetVRFByName("master").IPv4UnicastRIB().LPM(pfx.Ptr())
140+
141+
if len(routes) != 1 {
142+
t.Logf("Expected 1 route, got %d", len(routes))
143+
144+
return false
145+
}
146+
147+
if len(routes[0].Paths()) != 1 {
148+
t.Logf("Expected 1 path, got %d", len(routes[0].Paths()))
149+
150+
return false
151+
}
152+
153+
path := routes[0].Paths()[0]
154+
155+
return path.NextHop().Equal(ip2)
156+
}, time.Second*3, time.Millisecond*500, "Route not received")
157+
}
158+
159+
func startServer(routerID bnet.IP) (bgpserver.BGPServer, *vrf.VRFRegistry, error) {
160+
s := bgpserver.NewBGPServer(uint32(routerID.Lower()))
161+
162+
if err := s.Start(); err != nil {
163+
return nil, nil, fmt.Errorf("Unable to start BGP server: %v", err)
164+
}
165+
166+
vrfs := vrf.NewVRFRegistry()
167+
168+
return s, vrfs, nil
83169
}
84170

85-
func startServer(routerID bnet.IP) (bgpserver.BGPServer, *fasthttputil.InmemoryListener, *vrf.VRFRegistry, error) {
171+
func addListener(s bgpserver.BGPServer, routerID bnet.IP) *fasthttputil.InmemoryListener {
86172
ml := fasthttputil.NewInmemoryListener()
87173
ml.SetLocalAddr(&net.TCPAddr{IP: routerID.ToNetIP()})
88174

89-
s := bgpserver.NewBGPServer(uint32(routerID.Lower()))
90-
91175
s.AddListener(ml)
92176

93-
if err := s.Start(); err != nil {
94-
return nil, nil, nil, fmt.Errorf("Unable to start BGP server: %v", err)
177+
return ml
178+
}
179+
180+
func connect(r1, r2 bgpserver.BGPServer, ip1, ip2 bnet.IP, vrfs1, vrfs2 *vrf.VRFRegistry, as1, as2 uint32, ml1, ml2 *fasthttputil.InmemoryListener) error {
181+
if err := r1.AddPeer(
182+
bgpPeerConfig(r1,
183+
bnet.IPv4FromBytes(ml1.Addr().(*net.TCPAddr).IP.To4()).Ptr(),
184+
bnet.IPv4FromBytes(ml2.Addr().(*net.TCPAddr).IP.To4()).Ptr(),
185+
as1,
186+
as2,
187+
vrfs1.CreateVRFIfNotExists("master", 0),
188+
ml2,
189+
),
190+
); err != nil {
191+
return fmt.Errorf("Unable to add peer: %v", err)
95192
}
96193

97-
vrfs := vrf.NewVRFRegistry()
194+
pc := bgpPeerConfig(r2,
195+
bnet.IPv4FromBytes(ml2.Addr().(*net.TCPAddr).IP.To4()).Ptr(),
196+
bnet.IPv4FromBytes(ml1.Addr().(*net.TCPAddr).IP.To4()).Ptr(),
197+
as2,
198+
as1,
199+
vrfs2.CreateVRFIfNotExists("master", 0),
200+
ml1,
201+
)
202+
// pc.Passive = true
98203

99-
return s, ml, vrfs, nil
204+
if err := r2.AddPeer(pc); err != nil {
205+
return fmt.Errorf("Unable to add peer: %v", err)
206+
}
207+
208+
return nil
100209
}
101210

102211
func bgpPeerConfig(s bgpserver.BGPServer, localAddr, peerAddr *bnet.IP, localAS, peerAS uint32, vrf *vrf.VRF, ml *fasthttputil.InmemoryListener) bgpserver.PeerConfig {
@@ -112,13 +221,9 @@ func bgpPeerConfig(s bgpserver.BGPServer, localAddr, peerAddr *bnet.IP, localAS,
112221
IPv4: &bgpserver.AddressFamilyConfig{
113222
ImportFilterChain: filter.NewAcceptAllFilterChain(),
114223
ExportFilterChain: filter.NewAcceptAllFilterChain(),
115-
AddPathSend: routingtable.ClientOptions{
116-
MaxPaths: 10,
117-
},
118224
},
119-
VRF: vrf,
120-
TCPDialer: ml,
121-
AuthenticationKey: "test",
225+
VRF: vrf,
226+
TCPDialer: ml,
122227
}
123228
}
124229

@@ -127,11 +232,9 @@ func generatePath(source, nh *bnet.IP) *route.Path {
127232
Type: route.BGPPathType,
128233
BGPPath: &route.BGPPath{
129234
BGPPathA: &route.BGPPathA{
130-
Source: source,
131-
NextHop: nh,
132-
LocalPref: 100,
133-
MED: 200,
134-
EBGP: true,
235+
Source: source,
236+
NextHop: nh,
237+
EBGP: true,
135238
},
136239
ASPath: &types.ASPath{
137240
types.ASPathSegment{

0 commit comments

Comments
 (0)