Skip to content

Commit f44d87f

Browse files
stgrabernmezhenskyi
authored andcommitted
lxd/bgp: Rework start/stop logic
This simplifies the BGP package a bit and improves on the ability to reconfigure it. The go-bgp ability to start/stop the daemon doesn't work reliably, so we need to spawn a completely new listener instead. This moves Start/Stop interactions to the main Reconfigure option and makes sure to always feed all peers and prefixes on startup. Signed-off-by: Stéphane Graber <[email protected]> (cherry picked from commit 6a0d0137735c260b5872e27c7d94720e8d989228) Signed-off-by: Nikita Mezhenskyi <[email protected]> License: Apache-2.0
1 parent 4efe496 commit f44d87f

File tree

3 files changed

+53
-59
lines changed

3 files changed

+53
-59
lines changed

lxd/api_1.0.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -996,7 +996,7 @@ func doAPI10UpdateTriggers(d *Daemon, nodeChanged, clusterChanged map[string]str
996996
return fmt.Errorf("Cannot convert BGP ASN to uint32: Upper bound exceeded")
997997
}
998998

999-
err := s.BGP.Reconfigure(address, uint32(asn), net.ParseIP(routerid))
999+
err := s.BGP.Configure(address, uint32(asn), net.ParseIP(routerid))
10001000
if err != nil {
10011001
return fmt.Errorf("Failed reconfiguring BGP: %w", err)
10021002
}

lxd/bgp/server.go

+51-57
Original file line numberDiff line numberDiff line change
@@ -56,45 +56,21 @@ func NewServer() *Server {
5656
return s
5757
}
5858

59-
func (s *Server) setup() {
60-
if s.bgp != nil {
61-
return
62-
}
63-
64-
// Spawn the BGP goroutines.
65-
s.bgp = bgpServer.NewBgpServer()
66-
go s.bgp.Serve()
67-
68-
// Insert any path that's already defined.
69-
if len(s.paths) > 0 {
70-
// Reset the path list.
71-
paths := s.paths
72-
s.paths = map[string]path{}
73-
74-
for _, path := range paths {
75-
err := s.addPrefix(path.prefix, path.nexthop, path.owner)
76-
logger.Warn("Unable to add prefix to BGP server", logger.Ctx{"prefix": path.prefix.String(), "err": err})
77-
}
78-
}
79-
}
80-
8159
// Start sets up the BGP listener.
82-
func (s *Server) Start(address string, asn uint32, routerID net.IP) error {
83-
// Locking.
84-
s.mu.Lock()
85-
defer s.mu.Unlock()
86-
87-
return s.start(address, asn, routerID)
88-
}
89-
9060
func (s *Server) start(address string, asn uint32, routerID net.IP) error {
9161
// If routerID is nil, fill with our best guess.
9262
if routerID == nil || routerID.To4() == nil {
9363
return ErrBadRouterID
9464
}
9565

96-
// Make sure we have a BGP instance.
97-
s.setup()
66+
// Check if already running
67+
if s.bgp != nil {
68+
return fmt.Errorf("BGP listener is already running")
69+
}
70+
71+
// Spawn the BGP goroutines.
72+
s.bgp = bgpServer.NewBgpServer()
73+
go s.bgp.Serve()
9874

9975
// Get the address and port.
10076
addrHost, addrPort, err := net.SplitHostPort(address)
@@ -131,8 +107,30 @@ func (s *Server) start(address string, asn uint32, routerID net.IP) error {
131107
return err
132108
}
133109

134-
// Add any existing peers.
135-
for _, peer := range s.peers {
110+
// Copy the path list
111+
oldPaths := map[string]path{}
112+
for pathUUID, path := range s.paths {
113+
oldPaths[pathUUID] = path
114+
}
115+
116+
// Add existing paths.
117+
s.paths = map[string]path{}
118+
for _, path := range oldPaths {
119+
err := s.addPrefix(path.prefix, path.nexthop, path.owner)
120+
if err != nil {
121+
logger.Warn("Unable to add prefix to BGP server", logger.Ctx{"prefix": path.prefix.String(), "err": err})
122+
}
123+
}
124+
125+
// Copy the peer list.
126+
oldPeers := map[string]peer{}
127+
for peerUUID, peer := range s.peers {
128+
oldPeers[peerUUID] = peer
129+
}
130+
131+
// Add existing peers.
132+
s.peers = map[string]peer{}
133+
for _, peer := range oldPeers {
136134
err := s.addPeer(peer.address, peer.asn, peer.password, peer.holdtime)
137135
if err != nil {
138136
return err
@@ -148,20 +146,18 @@ func (s *Server) start(address string, asn uint32, routerID net.IP) error {
148146
}
149147

150148
// Stop tears down the BGP listener.
151-
func (s *Server) Stop() error {
152-
// Locking.
153-
s.mu.Lock()
154-
defer s.mu.Unlock()
155-
156-
return s.stop()
157-
}
158-
159149
func (s *Server) stop() error {
160150
// Skip if no instance.
161151
if s.bgp == nil {
162152
return nil
163153
}
164154

155+
// Save the peer list.
156+
oldPeers := map[string]peer{}
157+
for peerUUID, peer := range s.peers {
158+
oldPeers[peerUUID] = peer
159+
}
160+
165161
// Remove all the peers (ignore failures).
166162
for _, peer := range s.peers {
167163
err := s.removePeer(peer.address)
@@ -170,37 +166,38 @@ func (s *Server) stop() error {
170166
}
171167
}
172168

169+
// Restore peer list.
170+
s.peers = oldPeers
171+
173172
// Stop the listener.
174173
err := s.bgp.StopBgp(context.Background(), &bgpAPI.StopBgpRequest{})
175174
if err != nil {
176175
return err
177176
}
178177

179-
// Unset the address
178+
// Mark the daemon as down.
180179
s.address = ""
181180
s.asn = 0
182181
s.routerID = nil
182+
s.bgp = nil
183+
183184
return nil
184185
}
185186

186-
// Reconfigure updates the listener with a new configuration..
187-
func (s *Server) Reconfigure(address string, asn uint32, routerID net.IP) error {
187+
// Configure updates the listener with a new configuration..
188+
func (s *Server) Configure(address string, asn uint32, routerID net.IP) error {
188189
// Locking.
189190
s.mu.Lock()
190191
defer s.mu.Unlock()
191192

192-
return s.reconfigure(address, asn, routerID)
193+
return s.configure(address, asn, routerID)
193194
}
194195

195-
func (s *Server) reconfigure(address string, asn uint32, routerID net.IP) error {
196-
// Get the old address.
196+
func (s *Server) configure(address string, asn uint32, routerID net.IP) error {
197+
// Store current configuration for reverting.
197198
oldAddress := s.address
198199
oldASN := s.asn
199200
oldRouterID := s.routerID
200-
oldPeers := map[string]peer{}
201-
for peerUUID, peer := range s.peers {
202-
oldPeers[peerUUID] = peer
203-
}
204201

205202
// Setup reverter.
206203
revert := revert.New()
@@ -209,12 +206,9 @@ func (s *Server) reconfigure(address string, asn uint32, routerID net.IP) error
209206
// Stop the listener.
210207
err := s.stop()
211208
if err != nil {
212-
return err
209+
return fmt.Errorf("Failed to stop current listener: %w", err)
213210
}
214211

215-
// Restore peer list.
216-
s.peers = oldPeers
217-
218212
// Check if we should start.
219213
if address != "" && asn > 0 && routerID != nil {
220214
// Restore old address on failure.
@@ -223,7 +217,7 @@ func (s *Server) reconfigure(address string, asn uint32, routerID net.IP) error
223217
// Start the listener with the new address.
224218
err = s.start(address, asn, routerID)
225219
if err != nil {
226-
return err
220+
return fmt.Errorf("Failed to start new listener: %w", err)
227221
}
228222
}
229223

lxd/daemon.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1762,7 +1762,7 @@ func (d *Daemon) init() error {
17621762
return fmt.Errorf("Cannot convert BGP ASN to uint32: Upper bound exceeded")
17631763
}
17641764

1765-
err := d.bgp.Start(bgpAddress, uint32(bgpASN), net.ParseIP(bgpRouterID))
1765+
err := d.bgp.Configure(bgpAddress, uint32(bgpASN), net.ParseIP(bgpRouterID))
17661766
if err != nil {
17671767
return err
17681768
}

0 commit comments

Comments
 (0)