Skip to content
Snippets Groups Projects
fsm2.go 3.15 KiB
Newer Older
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:
		}
	}
}