Skip to content
Snippets Groups Projects
peer.go 3.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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
    }
    
    
    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
    		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),
    
    Oliver Herms's avatar
    Oliver Herms committed
    	}
    
    Oliver Herms's avatar
    Oliver Herms committed
    	p.fsms = append(p.fsms, NewActiveFSM2(p))
    
    	addPathEnabled, addPathCap := handleAddPathCapability(c)
    	if addPathEnabled {
    		caps = append(caps, addPathCap)
    
    	caps = append(caps, asn4Capability(c))
    
    
    	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
    }
    
    
    func asn4Capability(c config.Peer) packet.Capability {
    	return packet.Capability{
    		Code: packet.ASN4CapabilityCode,
    		Value: packet.ASN4Capability{
    			ASN4: c.LocalAS,
    		},
    	}
    }
    
    func handleAddPathCapability(c config.Peer) (bool, packet.Capability) {
    	addPath := uint8(0)
    	if c.AddPathRecv {
    		addPath += packet.AddPathReceive
    	}
    	if !c.AddPathSend.BestOnly {
    		addPath += packet.AddPathSend
    	}
    
    	if addPath == 0 {
    		return false, packet.Capability{}
    	}
    
    	return true, packet.Capability{
    		Code: packet.AddPathCapabilityCode,
    		Value: packet.AddPathCapability{
    			AFI:         packet.IPv4AFI,
    			SAFI:        packet.UnicastSAFI,
    			SendReceive: addPath,
    		},
    	}
    }
    
    
    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
    }