diff options
author | Hiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp> | 2015-02-15 17:46:31 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2015-02-16 10:13:40 +0900 |
commit | 560fa6cbd5c6ddb8fcd5c262b720459c064a9b23 (patch) | |
tree | 94b407108e89687ef010504938edd14d104c29f3 /server/fsm.go | |
parent | 161ea3b25709820991b1b1e17e621eb9a2082865 (diff) |
peer: support enable/disable
Diffstat (limited to 'server/fsm.go')
-rw-r--r-- | server/fsm.go | 174 |
1 files changed, 159 insertions, 15 deletions
diff --git a/server/fsm.go b/server/fsm.go index a8c41e9c..4649ef85 100644 --- a/server/fsm.go +++ b/server/fsm.go @@ -16,6 +16,7 @@ package server import ( + "fmt" log "github.com/Sirupsen/logrus" "github.com/osrg/gobgp/config" "github.com/osrg/gobgp/packet" @@ -41,6 +42,24 @@ const ( HOLDTIME_OPENSENT = 240 ) +type AdminState int + +const ( + ADMIN_STATE_UP AdminState = iota + ADMIN_STATE_DOWN +) + +func (s AdminState) String() string { + switch s { + case ADMIN_STATE_UP: + return "ADMIN_STATE_UP" + case ADMIN_STATE_DOWN: + return "ADMIN_STATE_DOWN" + default: + return "Unknown" + } +} + type FSM struct { globalConfig *config.GlobalType peerConfig *config.NeighborType @@ -51,6 +70,8 @@ type FSM struct { idleHoldTime float64 opensentHoldTime float64 negotiatedHoldTime float64 + adminState AdminState + adminStateCh chan AdminState } func (fsm *FSM) bgpMessageStateUpdate(MessageType uint8, isIn bool) { @@ -108,6 +129,8 @@ func NewFSM(gConfig *config.GlobalType, pConfig *config.NeighborType, connCh cha state: bgp.BGP_FSM_IDLE, passiveConnCh: connCh, opensentHoldTime: float64(HOLDTIME_OPENSENT), + adminState: ADMIN_STATE_UP, + adminStateCh: make(chan AdminState, 1), } } @@ -193,28 +216,67 @@ func (h *FSMHandler) idle() bgp.FSMState { "Key": fsm.peerConfig.NeighborAddress, }).Warn("Closed an accepted connection") case <-idleHoldTimer.C: - log.WithFields(log.Fields{ - "Topic": "Peer", - "Key": fsm.peerConfig.NeighborAddress, - "Duration": fsm.idleHoldTime, - }).Debug("IdleHoldTimer expired") - fsm.idleHoldTime = 0 - return bgp.BGP_FSM_ACTIVE + + if fsm.adminState == ADMIN_STATE_UP { + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": fsm.peerConfig.NeighborAddress, + "Duration": fsm.idleHoldTime, + }).Debug("IdleHoldTimer expired") + fsm.idleHoldTime = 0 + return bgp.BGP_FSM_ACTIVE + + } else { + log.Debug("IdleHoldTimer expired, but stay at idle because the admin state is DOWN") + } + + case s := <-fsm.adminStateCh: + err := h.changeAdminState(s) + if err == nil { + switch s { + case ADMIN_STATE_DOWN: + // stop idle hold timer + idleHoldTimer.Stop() + + case ADMIN_STATE_UP: + // restart idle hold timer + idleHoldTimer.Reset(time.Second * time.Duration(fsm.idleHoldTime)) + } + } } } } func (h *FSMHandler) active() bgp.FSMState { fsm := h.fsm - select { - case <-h.t.Dying(): - return 0 - case conn := <-fsm.passiveConnCh: - fsm.passiveConn = conn + for { + select { + case <-h.t.Dying(): + return 0 + case conn := <-fsm.passiveConnCh: + fsm.passiveConn = conn + // we don't implement delayed open timer so move to opensent right + // away. + return bgp.BGP_FSM_OPENSENT + case <-h.errorCh: + return bgp.BGP_FSM_IDLE + case s := <-fsm.adminStateCh: + err := h.changeAdminState(s) + if err == nil { + switch s { + case ADMIN_STATE_DOWN: + return bgp.BGP_FSM_IDLE + case ADMIN_STATE_UP: + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": fsm.peerConfig.NeighborAddress, + "State": fsm.state, + "AdminState": s.String(), + }).Panic("code logic bug") + } + } + } } - // we don't implement delayed open timer so move to opensent right - // away. - return bgp.BGP_FSM_OPENSENT } func buildopen(global *config.GlobalType, peerConf *config.NeighborType) *bgp.BGPMessage { @@ -391,6 +453,22 @@ func (h *FSMHandler) opensent() bgp.FSMState { fsm.sendNotification(h.conn, bgp.BGP_ERROR_HOLD_TIMER_EXPIRED, 0, nil, "hold timer expired") h.t.Kill(nil) return bgp.BGP_FSM_IDLE + case s := <-fsm.adminStateCh: + err := h.changeAdminState(s) + if err == nil { + switch s { + case ADMIN_STATE_DOWN: + h.conn.Close() + return bgp.BGP_FSM_IDLE + case ADMIN_STATE_UP: + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": fsm.peerConfig.NeighborAddress, + "State": fsm.state, + "AdminState": s.String(), + }).Panic("code logic bug") + } + } } } } @@ -455,6 +533,22 @@ func (h *FSMHandler) openconfirm() bgp.FSMState { fsm.sendNotification(h.conn, bgp.BGP_ERROR_HOLD_TIMER_EXPIRED, 0, nil, "hold timer expired") h.t.Kill(nil) return bgp.BGP_FSM_IDLE + case s := <-fsm.adminStateCh: + err := h.changeAdminState(s) + if err == nil { + switch s { + case ADMIN_STATE_DOWN: + h.conn.Close() + return bgp.BGP_FSM_IDLE + case ADMIN_STATE_UP: + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": fsm.peerConfig.NeighborAddress, + "State": fsm.state, + "AdminState": s.String(), + }).Panic("code logic bug") + } + } } } log.WithFields(log.Fields{ @@ -546,6 +640,16 @@ func (h *FSMHandler) established() bgp.FSMState { m := bgp.NewBGPNotificationMessage(bgp.BGP_ERROR_HOLD_TIMER_EXPIRED, 0, nil) h.outgoing <- m return bgp.BGP_FSM_IDLE + case s := <-fsm.adminStateCh: + err := h.changeAdminState(s) + if err == nil { + switch s { + case ADMIN_STATE_DOWN: + m := bgp.NewBGPNotificationMessage( + bgp.BGP_ERROR_CEASE, bgp.BGP_ERROR_SUB_ADMINISTRATIVE_SHUTDOWN, nil) + h.outgoing <- m + } + } } } return 0 @@ -579,3 +683,43 @@ func (h *FSMHandler) loop() error { } return nil } + +func (h *FSMHandler) changeAdminState(s AdminState) error { + fsm := h.fsm + if fsm.adminState != s { + + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": fsm.peerConfig.NeighborAddress, + "AdminState": s.String(), + }).Debug("admin state changed") + + fsm.adminState = s + + switch s { + case ADMIN_STATE_UP: + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": h.fsm.peerConfig.NeighborAddress, + "FSMState": fsm.state.String(), + }).Info("Administrative start") + + case ADMIN_STATE_DOWN: + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": h.fsm.peerConfig.NeighborAddress, + "FSMState": fsm.state.String(), + }).Info("Administrative shutdown") + } + + } else { + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": fsm.peerConfig.NeighborAddress, + "FSMState": fsm.state.String(), + }).Warn("cannot change to the same state") + + return fmt.Errorf("cannot change to the same state.") + } + return nil +} |