Skip to content
Snippets Groups Projects
fsm2.go 3.15 KiB
Newer Older
  • Learn to ignore specific revisions
  • Oliver Herms's avatar
    Oliver Herms committed
    package server
    
    import (
    	"fmt"
    	"net"
    	"time"
    
    	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
    	"github.com/bio-routing/bio-rd/routingtable"
    	"github.com/bio-routing/bio-rd/routingtable/adjRIBIn"
    	"github.com/bio-routing/bio-rd/routingtable/locRIB"
    )
    
    type state interface {
    	run() (state, string)
    }
    
    // FSM2 implements the BGP finite state machine (RFC4271)
    type FSM2 struct {
    	server  *BGPServer
    	peer    *Peer
    	eventCh chan int
    	con     net.Conn
    	conCh   chan net.Conn
    
    	delayOpen      bool
    	delayOpenTime  time.Duration
    	delayOpenTimer *time.Timer
    
    	connectRetryTime    time.Duration
    	connectRetryTimer   *time.Timer
    	connectRetryCounter int
    
    	holdTimeConfigured time.Duration
    	holdTime           time.Duration
    	holdTimer          *time.Timer
    
    	keepaliveTime  time.Duration
    	keepaliveTimer *time.Timer
    
    	msgRecvCh     chan msgRecvMsg
    	msgRecvFailCh chan msgRecvErr
    	stopMsgRecvCh chan struct{}
    
    	capAddPathSend bool
    	capAddPathRecv bool
    
    	local  net.IP
    	remote net.IP
    
    	ribsInitialized bool
    	adjRIBIn        *adjRIBIn.AdjRIBIn
    	adjRIBOut       routingtable.RouteTableClient
    	rib             *locRIB.LocRIB
    	updateSender    routingtable.RouteTableClient
    
    	neighborID uint32
    	state      state
    	reason     string
    	active     bool
    }
    
    // NewPassiveFSM2 initiates a new passive FSM
    func NewPassiveFSM2(peer *Peer, con *net.TCPConn) *FSM2 {
    	fsm := &FSM2{
    		peer:          peer,
    		eventCh:       make(chan int),
    		con:           con,
    		conCh:         make(chan net.Conn),
    		msgRecvCh:     make(chan msgRecvMsg),
    		msgRecvFailCh: make(chan msgRecvErr),
    		stopMsgRecvCh: make(chan struct{}),
    	}
    
    	return fsm
    }
    
    // NewActiveFSM2 initiates a new passive FSM
    func NewActiveFSM2(peer *Peer) *FSM2 {
    	return &FSM2{
    		peer:    peer,
    		eventCh: make(chan int),
    		active:  true,
    		conCh:   make(chan net.Conn),
    	}
    }
    
    func (fsm *FSM2) Cease() {
    
    }
    
    func (fsm *FSM2) startConnectRetryTimer() {
    	fsm.connectRetryTimer = time.NewTimer(time.Second * fsm.connectRetryTime)
    }
    
    func (fsm *FSM2) resetConnectRetryTimer() {
    	if !fsm.connectRetryTimer.Reset(time.Second * fsm.connectRetryTime) {
    		<-fsm.connectRetryTimer.C
    	}
    }
    
    func (fsm *FSM2) resetConnectRetryCounter() {
    	fsm.connectRetryCounter = 0
    }
    
    func (fsm *FSM2) tcpConnect() {
    
    }
    
    func (fsm *FSM2) sendOpen() error {
    	msg := packet.SerializeOpenMsg(&packet.BGPOpen{
    		Version:       BGPVersion,
    		AS:            uint16(fsm.peer.asn),
    		HoldTime:      uint16(fsm.holdTimeConfigured),
    		BGPIdentifier: fsm.server.routerID,
    		OptParams:     fsm.peer.optOpenParams,
    	})
    
    	_, err := fsm.con.Write(msg)
    	if err != nil {
    		return fmt.Errorf("Unable to send OPEN message: %v", err)
    	}
    
    	return nil
    }
    
    func (fsm *FSM2) sendNotification(errorCode uint8, errorSubCode uint8) error {
    	msg := packet.SerializeNotificationMsg(&packet.BGPNotification{})
    
    	_, err := fsm.con.Write(msg)
    	if err != nil {
    		return fmt.Errorf("Unable to send NOTIFICATION message: %v", err)
    	}
    
    	return nil
    }
    
    func (fsm *FSM2) sendKeepalive() error {
    	msg := packet.SerializeKeepaliveMsg()
    
    	_, err := fsm.con.Write(msg)
    	if err != nil {
    		return fmt.Errorf("Unable to send KEEPALIVE message: %v", err)
    	}
    
    	return nil
    }
    
    func stopTimer(t *time.Timer) {
    	if !t.Stop() {
    		select {
    		case <-t.C:
    		default:
    		}
    	}
    }