Skip to content
Snippets Groups Projects
peer.go 2.99 KiB
Newer Older
Oliver Herms's avatar
Oliver Herms committed
package server

import (
	"net"
Oliver Herms's avatar
Oliver Herms committed
	"sync"
	"time"
Oliver Herms's avatar
Oliver Herms committed

	"github.com/bio-routing/bio-rd/config"
	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
	"github.com/bio-routing/bio-rd/routingtable"
Oliver Herms's avatar
Oliver Herms committed
	"github.com/bio-routing/bio-rd/routingtable/filter"
Oliver Herms's avatar
Oliver Herms committed
)

type Peer struct {
Oliver Herms's avatar
Oliver Herms committed
	server            *BGPServer
Oliver Herms's avatar
Oliver Herms committed
	peerASN           uint32
Oliver Herms's avatar
Oliver Herms committed
	localASN          uint32
Oliver Herms's avatar
Oliver Herms committed
	fsms              []*FSM2
	fsmsMu            sync.Mutex
Oliver Herms's avatar
Oliver Herms committed
	rib               routingtable.RouteTableClient
	routerID          uint32
	addPathSend       routingtable.ClientOptions
	addPathRecv       bool
	reconnectInterval time.Duration
Oliver Herms's avatar
Oliver Herms committed
	keepaliveTime     time.Duration
	holdTime          time.Duration
	optOpenParams     []packet.OptParam
	importFilter      *filter.Filter
	exportFilter      *filter.Filter
}

func (p *Peer) collisionHandling(callingFSM *FSM2) bool {
	p.fsmsMu.Lock()
	defer p.fsmsMu.Unlock()

	for _, fsm := range p.fsms {
		if callingFSM == fsm {
			continue
		}

		fsm.stateMu.RLock()
		isEstablished := isEstablishedState(fsm.state)
		isOpenConfirm := isOpenConfirmState(fsm.state)
		fsm.stateMu.RUnlock()

		if isEstablished {
			return true
		}

		if !isOpenConfirm {
			continue
		}

		if p.routerID < callingFSM.neighborID {
			fsm.cease()
		} else {
			return true
		}
	}

	return false
}

func isOpenConfirmState(s state) bool {
	switch s.(type) {
	case openConfirmState:
		return true
	}

	return false
}

func isEstablishedState(s state) bool {
	switch s.(type) {
	case establishedState:
		return true
	}

	return false
Oliver Herms's avatar
Oliver Herms committed
}

// NewPeer creates a new peer with the given config. If an connection is established, the adjRIBIN of the peer is connected
// to the given rib. To actually connect the peer, call Start() on the returned peer.
Oliver Herms's avatar
Oliver Herms committed
func NewPeer(c config.Peer, rib routingtable.RouteTableClient, server *BGPServer) (*Peer, error) {
Oliver Herms's avatar
Oliver Herms committed
	p := &Peer{
Oliver Herms's avatar
Oliver Herms committed
		server:            server,
Oliver Herms's avatar
Oliver Herms committed
		peerASN:           c.PeerAS,
Oliver Herms's avatar
Oliver Herms committed
		localASN:          c.LocalAS,
Oliver Herms's avatar
Oliver Herms committed
		fsms:              make([]*FSM2, 0),
		rib:               rib,
		addPathSend:       c.AddPathSend,
		addPathRecv:       c.AddPathRecv,
		reconnectInterval: c.ReconnectInterval,
Oliver Herms's avatar
Oliver Herms committed
		keepaliveTime:     c.KeepAlive,
		holdTime:          c.HoldTimer,
		optOpenParams:     make([]packet.OptParam, 0),
Oliver Herms's avatar
Oliver Herms committed
	}
Oliver Herms's avatar
Oliver Herms committed
	p.fsms = append(p.fsms, NewActiveFSM2(p))

	caps := make([]packet.Capability, 0)

	addPath := uint8(0)
Oliver Herms's avatar
Oliver Herms committed
	if c.AddPathRecv {
		addPath += packet.AddPathReceive
	}
	if !c.AddPathSend.BestOnly {
		addPath += packet.AddPathSend
	}

	if addPath > 0 {
		caps = append(caps, packet.Capability{
			Code: packet.AddPathCapabilityCode,
			Value: packet.AddPathCapability{
				AFI:         packet.IPv4AFI,
				SAFI:        packet.UnicastSAFI,
				SendReceive: addPath,
			},
		})
	}

	for _, cap := range caps {
		p.optOpenParams = append(p.optOpenParams, packet.OptParam{
			Type:  packet.CapabilitiesParamType,
			Value: cap,
		})
	}

Oliver Herms's avatar
Oliver Herms committed
	return p, nil
}

// GetAddr returns the IP address of the peer
Oliver Herms's avatar
Oliver Herms committed
func (p *Peer) GetAddr() net.IP {
	return p.addr
}

func (p *Peer) Start() {
Oliver Herms's avatar
Oliver Herms committed
	p.fsms[0].start()
Oliver Herms's avatar
Oliver Herms committed
}