diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/peer.go | 76 | ||||
-rw-r--r-- | server/server.go | 78 | ||||
-rw-r--r-- | server/server_test.go | 68 |
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() |