summaryrefslogtreecommitdiffhomepage
path: root/server/fsm.go
diff options
context:
space:
mode:
authorHiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp>2015-01-21 20:14:49 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2015-01-26 20:41:08 +0900
commitdafa0a31d73f49b6cd68e658f000da904565f36c (patch)
tree75bb21a4920f78ec7f5a4fdc70a79d13ee30f1ad /server/fsm.go
parent3491d5214352586708444bcf41eca16f7ff1d3e6 (diff)
fsm: check hold timer expiration and add test case for holdtimer expiration at Established state
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Diffstat (limited to 'server/fsm.go')
-rw-r--r--server/fsm.go102
1 files changed, 82 insertions, 20 deletions
diff --git a/server/fsm.go b/server/fsm.go
index 2f8ea52e..8c3882cf 100644
--- a/server/fsm.go
+++ b/server/fsm.go
@@ -37,14 +37,20 @@ type fsmMsg struct {
MsgData interface{}
}
+const (
+ HOLDTIME_OPENSENT = 240
+)
+
type FSM struct {
- globalConfig *config.GlobalType
- peerConfig *config.NeighborType
- keepaliveTicker *time.Ticker
- state bgp.FSMState
- passiveConn *net.TCPConn
- passiveConnCh chan *net.TCPConn
- idleHoldTime float64
+ globalConfig *config.GlobalType
+ peerConfig *config.NeighborType
+ keepaliveTicker *time.Ticker
+ state bgp.FSMState
+ passiveConn net.Conn
+ passiveConnCh chan net.Conn
+ idleHoldTime float64
+ opensentHoldTime float64
+ negotiatedHoldTime float64
}
func (fsm *FSM) bgpMessageStateUpdate(MessageType uint8, isIn bool) {
@@ -89,12 +95,13 @@ func (fsm *FSM) bgpMessageStateUpdate(MessageType uint8, isIn bool) {
}
}
-func NewFSM(gConfig *config.GlobalType, pConfig *config.NeighborType, connCh chan *net.TCPConn) *FSM {
+func NewFSM(gConfig *config.GlobalType, pConfig *config.NeighborType, connCh chan net.Conn) *FSM {
return &FSM{
- globalConfig: gConfig,
- peerConfig: pConfig,
- state: bgp.BGP_FSM_IDLE,
- passiveConnCh: connCh,
+ globalConfig: gConfig,
+ peerConfig: pConfig,
+ state: bgp.BGP_FSM_IDLE,
+ passiveConnCh: connCh,
+ opensentHoldTime: float64(HOLDTIME_OPENSENT),
}
}
@@ -109,13 +116,14 @@ func (fsm *FSM) StateChange(nextState bgp.FSMState) {
}
type FSMHandler struct {
- t tomb.Tomb
- fsm *FSM
- conn *net.TCPConn
- msgCh chan *fsmMsg
- errorCh chan bool
- incoming chan *fsmMsg
- outgoing chan *bgp.BGPMessage
+ t tomb.Tomb
+ fsm *FSM
+ conn net.Conn
+ msgCh chan *fsmMsg
+ errorCh chan bool
+ incoming chan *fsmMsg
+ outgoing chan *bgp.BGPMessage
+ holdTimer *time.Timer
}
func NewFSMHandler(fsm *FSM, incoming chan *fsmMsg, outgoing chan *bgp.BGPMessage) *FSMHandler {
@@ -204,7 +212,7 @@ func buildopen(global *config.GlobalType, peerConf *config.NeighborType) *bgp.BG
[]bgp.OptionParameterInterface{p1, p2, p3})
}
-func readAll(conn *net.TCPConn, length int) ([]byte, error) {
+func readAll(conn net.Conn, length int) ([]byte, error) {
buf := make([]byte, length)
for cur := 0; cur < length; {
if num, err := conn.Read(buf); err != nil {
@@ -265,6 +273,12 @@ func (h *FSMHandler) recvMessageWithError() error {
MsgData: m,
}
h.fsm.bgpMessageStateUpdate(m.Header.Type, true)
+
+ if h.fsm.state == bgp.BGP_FSM_ESTABLISHED {
+ if m.Header.Type == bgp.BGP_MSG_KEEPALIVE || m.Header.Type == bgp.BGP_MSG_UPDATE {
+ h.holdTimer.Reset(time.Second * time.Duration(h.fsm.negotiatedHoldTime))
+ }
+ }
}
h.msgCh <- fmsg
return err
@@ -287,6 +301,12 @@ func (h *FSMHandler) opensent() bgp.FSMState {
h.t.Go(h.recvMessage)
+ // RFC 4271 P.60
+ // sets its HoldTimer to a large value
+ // A HoldTimer value of 4 minutes is suggested as a "large value"
+ // for the HoldTimer
+ h.holdTimer = time.NewTimer(time.Second * time.Duration(fsm.opensentHoldTime))
+
for {
select {
case <-h.t.Dying():
@@ -336,6 +356,19 @@ func (h *FSMHandler) opensent() bgp.FSMState {
case <-h.errorCh:
h.conn.Close()
return bgp.BGP_FSM_IDLE
+ case <-h.holdTimer.C:
+ log.WithFields(log.Fields{
+ "Topic": "Peer",
+ "Key": fsm.peerConfig.NeighborAddress,
+ "data": bgp.BGP_FSM_OPENSENT,
+ }).Warn("hold timer expired")
+ m := bgp.NewBGPNotificationMessage(bgp.BGP_ERROR_HOLD_TIMER_EXPIRED, 0, nil)
+ b, _ := m.Serialize()
+ fsm.passiveConn.Write(b)
+ fsm.bgpMessageStateUpdate(m.Header.Type, false)
+ h.conn.Close()
+ h.t.Kill(nil)
+ return bgp.BGP_FSM_IDLE
}
}
}
@@ -350,6 +383,10 @@ func (h *FSMHandler) openconfirm() bgp.FSMState {
h.t.Go(h.recvMessage)
+ // RFC 4271 P.65
+ // sets the HoldTimer according to the negotiated value
+ h.holdTimer = time.NewTimer(time.Second * time.Duration(fsm.negotiatedHoldTime))
+
for {
select {
case <-h.t.Dying():
@@ -397,6 +434,19 @@ func (h *FSMHandler) openconfirm() bgp.FSMState {
case <-h.errorCh:
h.conn.Close()
return bgp.BGP_FSM_IDLE
+ case <-h.holdTimer.C:
+ log.WithFields(log.Fields{
+ "Topic": "Peer",
+ "Key": fsm.peerConfig.NeighborAddress,
+ "data": bgp.BGP_FSM_OPENCONFIRM,
+ }).Warn("hold timer expired")
+ m := bgp.NewBGPNotificationMessage(bgp.BGP_ERROR_HOLD_TIMER_EXPIRED, 0, nil)
+ b, _ := m.Serialize()
+ fsm.passiveConn.Write(b)
+ fsm.bgpMessageStateUpdate(m.Header.Type, false)
+ h.conn.Close()
+ h.t.Kill(nil)
+ return bgp.BGP_FSM_IDLE
}
}
log.WithFields(log.Fields{
@@ -462,6 +512,9 @@ func (h *FSMHandler) established() bgp.FSMState {
h.msgCh = h.incoming
h.t.Go(h.recvMessageloop)
+ // restart HoldTimer
+ h.holdTimer = time.NewTimer(time.Second * time.Duration(fsm.negotiatedHoldTime))
+
for {
select {
case <-h.t.Dying():
@@ -476,6 +529,15 @@ func (h *FSMHandler) established() bgp.FSMState {
h.conn.Close()
h.t.Kill(nil)
return bgp.BGP_FSM_IDLE
+ case <-h.holdTimer.C:
+ log.WithFields(log.Fields{
+ "Topic": "Peer",
+ "Key": fsm.peerConfig.NeighborAddress,
+ "data": bgp.BGP_FSM_ESTABLISHED,
+ }).Warn("hold timer expired")
+ m := bgp.NewBGPNotificationMessage(bgp.BGP_ERROR_HOLD_TIMER_EXPIRED, 0, nil)
+ h.outgoing <- m
+ return bgp.BGP_FSM_IDLE
}
}
return 0