summaryrefslogtreecommitdiffhomepage
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/peer.go76
-rw-r--r--server/server.go78
-rw-r--r--server/server_test.go68
3 files changed, 182 insertions, 40 deletions
diff --git a/server/peer.go b/server/peer.go
index 4e5b7435..a1ec2404 100644
--- a/server/peer.go
+++ b/server/peer.go
@@ -32,14 +32,16 @@ const (
)
type PeerGroup struct {
- Conf *config.PeerGroup
- members map[string]config.Neighbor
+ Conf *config.PeerGroup
+ members map[string]config.Neighbor
+ dynamicNeighbors map[string]*config.DynamicNeighbor
}
func NewPeerGroup(c *config.PeerGroup) *PeerGroup {
return &PeerGroup{
- Conf: c,
- members: make(map[string]config.Neighbor, 0),
+ Conf: c,
+ members: make(map[string]config.Neighbor, 0),
+ dynamicNeighbors: make(map[string]*config.DynamicNeighbor, 0),
}
}
@@ -51,6 +53,29 @@ func (pg *PeerGroup) DeleteMember(c config.Neighbor) {
delete(pg.members, c.State.NeighborAddress)
}
+func (pg *PeerGroup) AddDynamicNeighbor(c *config.DynamicNeighbor) {
+ pg.dynamicNeighbors[c.Config.Prefix] = c
+}
+
+func newDynamicPeer(g *config.Global, neighborAddress string, pg *config.PeerGroup, loc *table.TableManager, policy *table.RoutingPolicy) *Peer {
+ conf := config.Neighbor{
+ Config: config.NeighborConfig{
+ PeerGroup: pg.Config.PeerGroupName,
+ },
+ Transport: config.Transport{
+ Config: config.TransportConfig{
+ PassiveMode: true,
+ },
+ },
+ }
+ config.OverwriteNeighborConfigWithPeerGroup(&conf, pg)
+ config.SetDefaultNeighborConfigValues(&conf, g.Config.As)
+ conf.State.NeighborAddress = neighborAddress
+ peer := NewPeer(g, &conf, loc, policy)
+ peer.fsm.state = bgp.BGP_FSM_ACTIVE
+ return peer
+}
+
type Peer struct {
tableId string
fsm *FSM
@@ -104,6 +129,10 @@ func (peer *Peer) isGracefulRestartEnabled() bool {
return peer.fsm.pConf.GracefulRestart.State.Enabled
}
+func (peer *Peer) isDynamicNeighbor() bool {
+ return peer.fsm.pConf.Config.NeighborAddress == "" && peer.fsm.pConf.Config.NeighborInterface == ""
+}
+
func (peer *Peer) recvedAllEOR() bool {
for _, a := range peer.fsm.pConf.AfiSafis {
if s := a.MpGracefulRestart.State; s.Enabled && !s.EndOfRibReceived {
@@ -585,3 +614,42 @@ func (peer *Peer) ToConfig(getAdvertised bool) *config.Neighbor {
func (peer *Peer) DropAll(rfList []bgp.RouteFamily) {
peer.adjRibIn.Drop(rfList)
}
+
+func (peer *Peer) stopFSM() error {
+ failed := false
+ addr := peer.fsm.pConf.State.NeighborAddress
+ t1 := time.AfterFunc(time.Minute*5, func() {
+ log.WithFields(log.Fields{
+ "Topic": "Peer",
+ }).Warnf("Failed to free the fsm.h.t for %s", addr)
+ failed = true
+ })
+ peer.fsm.h.t.Kill(nil)
+ peer.fsm.h.t.Wait()
+ t1.Stop()
+ if !failed {
+ log.WithFields(log.Fields{
+ "Topic": "Peer",
+ "Key": addr,
+ }).Debug("freed fsm.h.t")
+ cleanInfiniteChannel(peer.outgoing)
+ }
+ failed = false
+ t2 := time.AfterFunc(time.Minute*5, func() {
+ log.WithFields(log.Fields{
+ "Topic": "Peer",
+ }).Warnf("Failed to free the fsm.t for %s", addr)
+ failed = true
+ })
+ peer.fsm.t.Kill(nil)
+ peer.fsm.t.Wait()
+ t2.Stop()
+ if !failed {
+ log.WithFields(log.Fields{
+ "Topic": "Peer",
+ "Key": addr,
+ }).Debug("freed fsm.t")
+ return nil
+ }
+ return fmt.Errorf("Failed to free FSM for %s", addr)
+}
diff --git a/server/server.go b/server/server.go
index 7428d47e..d1b0b0ff 100644
--- a/server/server.go
+++ b/server/server.go
@@ -236,6 +236,16 @@ func (server *BgpServer) Serve() {
"Topic": "Peer",
}).Debugf("Accepted a new passive connection from:%s", remoteAddr)
peer.PassConn(conn)
+ } else if pg := server.matchLongestDynamicNeighborPrefix(remoteAddr); pg != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Peer",
+ }).Debugf("Accepted a new dynamic neighbor from:%s", remoteAddr)
+ peer := newDynamicPeer(&server.bgpConfig.Global, remoteAddr, pg.Conf, server.globalRib, server.policy)
+ server.policy.Reset(nil, map[string]config.ApplyPolicy{peer.ID(): peer.fsm.pConf.ApplyPolicy})
+ server.neighborMap[remoteAddr] = peer
+ peer.startFSMHandler(server.fsmincomingCh, server.fsmStateCh)
+ server.broadcastPeerState(peer, bgp.BGP_FSM_ACTIVE)
+ peer.PassConn(conn)
} else {
log.WithFields(log.Fields{
"Topic": "Peer",
@@ -280,6 +290,24 @@ func (server *BgpServer) Serve() {
}
}
+func (server *BgpServer) matchLongestDynamicNeighborPrefix(a string) *PeerGroup {
+ ipAddr := net.ParseIP(a)
+ longestMask := net.CIDRMask(0, 32).String()
+ var longestPG *PeerGroup
+ for _, pg := range server.peerGroupMap {
+ for _, d := range pg.dynamicNeighbors {
+ _, netAddr, _ := net.ParseCIDR(d.Config.Prefix)
+ if netAddr.Contains(ipAddr) {
+ if netAddr.Mask.String() > longestMask {
+ longestMask = netAddr.Mask.String()
+ longestPG = pg
+ }
+ }
+ }
+ }
+ return longestPG
+}
+
func sendFsmOutgoingMsg(peer *Peer, paths []*table.Path, notification *bgp.BGPMessage, stayIdle bool) {
peer.outgoing.In() <- &FsmOutgoingMsg{
Paths: paths,
@@ -721,6 +749,11 @@ func (server *BgpServer) handleFSMMessage(peer *Peer, e *FsmMsg) {
peer.fsm.pConf.State.PeerAs = 0
peer.fsm.peerInfo.AS = 0
}
+ if peer.isDynamicNeighbor() {
+ peer.stopPeerRestarting()
+ go peer.stopFSM()
+ delete(server.neighborMap, peer.fsm.pConf.State.NeighborAddress)
+ }
} else if peer.fsm.pConf.GracefulRestart.State.PeerRestarting && nextState == bgp.BGP_FSM_IDLE {
if peer.fsm.pConf.GracefulRestart.State.LongLivedEnabled {
llgr, no_llgr := peer.llgrFamilies()
@@ -1716,6 +1749,13 @@ func (s *BgpServer) AddNeighbor(c *config.Neighbor) error {
}, true)
}
+func (s *BgpServer) AddDynamicNeighbor(c *config.DynamicNeighbor) error {
+ return s.mgmtOperation(func() error {
+ s.peerGroupMap[c.Config.PeerGroup].AddDynamicNeighbor(c)
+ return nil
+ }, true)
+}
+
func (server *BgpServer) deletePeerGroup(pg *config.PeerGroup) error {
name := pg.Config.PeerGroupName
@@ -1766,41 +1806,7 @@ func (server *BgpServer) deleteNeighbor(c *config.Neighbor, code, subcode uint8)
n.fsm.sendNotification(code, subcode, nil, "")
n.stopPeerRestarting()
- go func(addr string) {
- failed := false
- t1 := time.AfterFunc(time.Minute*5, func() {
- log.WithFields(log.Fields{
- "Topic": "Peer",
- }).Warnf("Failed to free the fsm.h.t for %s", addr)
- failed = true
- })
- n.fsm.h.t.Kill(nil)
- n.fsm.h.t.Wait()
- t1.Stop()
- if !failed {
- log.WithFields(log.Fields{
- "Topic": "Peer",
- "Key": addr,
- }).Debug("freed fsm.h.t")
- cleanInfiniteChannel(n.outgoing)
- }
- failed = false
- t2 := time.AfterFunc(time.Minute*5, func() {
- log.WithFields(log.Fields{
- "Topic": "Peer",
- }).Warnf("Failed to free the fsm.t for %s", addr)
- failed = true
- })
- n.fsm.t.Kill(nil)
- n.fsm.t.Wait()
- t2.Stop()
- if !failed {
- log.WithFields(log.Fields{
- "Topic": "Peer",
- "Key": addr,
- }).Debug("freed fsm.t")
- }
- }(addr)
+ go n.stopFSM()
delete(server.neighborMap, addr)
server.dropPeerAllRoutes(n, n.configuredRFlist())
return nil
@@ -1861,7 +1867,7 @@ func (s *BgpServer) updateNeighbor(c *config.Neighbor) (needsSoftResetIn bool, e
addr, err := config.ExtractNeighborAddress(c)
if err != nil {
- return err
+ return needsSoftResetIn, err
}
peer, ok := s.neighborMap[addr]
diff --git a/server/server_test.go b/server/server_test.go
index 887f5ec4..e5deb975 100644
--- a/server/server_test.go
+++ b/server/server_test.go
@@ -441,6 +441,74 @@ func TestPeerGroup(test *testing.T) {
}
}
+func TestDynamicNeighbor(t *testing.T) {
+ assert := assert.New(t)
+ log.SetLevel(log.DebugLevel)
+ s1 := NewBgpServer()
+ go s1.Serve()
+ err := s1.Start(&config.Global{
+ Config: config.GlobalConfig{
+ As: 1,
+ RouterId: "1.1.1.1",
+ Port: 10179,
+ },
+ })
+ assert.Nil(err)
+ defer s1.Stop()
+
+ g := &config.PeerGroup{
+ Config: config.PeerGroupConfig{
+ PeerAs: 2,
+ PeerGroupName: "g",
+ },
+ }
+ err = s1.AddPeerGroup(g)
+ assert.Nil(err)
+
+ d := &config.DynamicNeighbor{
+ Config: config.DynamicNeighborConfig{
+ Prefix: "127.0.0.0/24",
+ PeerGroup: "g",
+ },
+ }
+ err = s1.AddDynamicNeighbor(d)
+ assert.Nil(err)
+
+ s2 := NewBgpServer()
+ go s2.Serve()
+ err = s2.Start(&config.Global{
+ Config: config.GlobalConfig{
+ As: 2,
+ RouterId: "2.2.2.2",
+ Port: -1,
+ },
+ })
+ assert.Nil(err)
+ defer s2.Stop()
+
+ m := &config.Neighbor{
+ Config: config.NeighborConfig{
+ NeighborAddress: "127.0.0.1",
+ PeerAs: 1,
+ },
+ Transport: config.Transport{
+ Config: config.TransportConfig{
+ RemotePort: 10179,
+ },
+ },
+ }
+ err = s2.AddNeighbor(m)
+
+ assert.Nil(err)
+
+ for {
+ time.Sleep(time.Second)
+ if s2.GetNeighbor("", false)[0].State.SessionState == config.SESSION_STATE_ESTABLISHED {
+ break
+ }
+ }
+}
+
func TestGracefulRestartTimerExpired(t *testing.T) {
assert := assert.New(t)
s1 := NewBgpServer()