Skip to content
Snippets Groups Projects
peer.go 3.27 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              []*FSM
Oliver Herms's avatar
Oliver Herms committed
	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
	routeServerClient bool
Oliver Herms's avatar
Oliver Herms committed
}

Oliver Herms's avatar
Oliver Herms committed
func (p *Peer) collisionHandling(callingFSM *FSM) bool {
Oliver Herms's avatar
Oliver Herms committed
	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([]*FSM, 0),
		rib:               rib,
		addPathSend:       c.AddPathSend,
		addPathRecv:       c.AddPathRecv,
		reconnectInterval: c.ReconnectInterval,
Oliver Herms's avatar
Oliver Herms committed
		keepaliveTime:     c.KeepAlive,
		holdTime:          c.HoldTime,
Oliver Herms's avatar
Oliver Herms committed
		optOpenParams:     make([]packet.OptParam, 0),
Oliver Herms's avatar
Oliver Herms committed
		importFilter:      filterOrDefault(c.ImportFilter),
		exportFilter:      filterOrDefault(c.ExportFilter),
		routeServerClient: c.RouteServerClient,
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
}

Oliver Herms's avatar
Oliver Herms committed
func filterOrDefault(f *filter.Filter) *filter.Filter {
	if f != nil {
		return f
	}

	return filter.NewDrainFilter()
}

// 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
}