Skip to content
Snippets Groups Projects
peer.go 3.94 KiB
Newer Older
  • Learn to ignore specific revisions
  • Oliver Herms's avatar
    Oliver Herms committed
    package server
    
    import (
    
    Oliver Herms's avatar
    Oliver Herms committed
    	"sync"
    	"time"
    
    Oliver Herms's avatar
    Oliver Herms committed
    
    
    	"github.com/bio-routing/bio-rd/config"
    
    	bnet "github.com/bio-routing/bio-rd/net"
    
    	"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"
    
    	"github.com/bio-routing/bio-rd/routingtable/locRIB"
    
    Oliver Herms's avatar
    Oliver Herms committed
    )
    
    
    	PeerASN  uint32
    	LocalASN uint32
    }
    
    type peer struct {
    	server   *bgpServer
    
    	peerASN  uint32
    	localASN uint32
    
    	// guarded by fsmsMu
    	fsms   []*FSM
    	fsmsMu sync.Mutex
    
    
    	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
    }
    
    
    func (p *peer) snapshot() PeerInfo {
    	return PeerInfo{
    		PeerAddr: p.addr,
    		PeerASN:  p.peerASN,
    		LocalASN: p.localASN,
    	}
    }
    
    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.
    
    func newPeer(c config.Peer, rib *locRIB.LocRIB, server *bgpServer) (*peer, error) {
    
    	if c.LocalAS == 0 {
    		c.LocalAS = server.localASN
    	}
    	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.Capabilities, 0)
    
    	addPathEnabled, addPathCap := handleAddPathCapability(c)
    	if addPathEnabled {
    		caps = append(caps, addPathCap)
    
    	caps = append(caps, asn4Capability(c))
    
    	p.optOpenParams = append(p.optOpenParams, packet.OptParam{
    		Type:  packet.CapabilitiesParamType,
    		Value: caps,
    	})
    
    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
    
    func (p *peer) GetAddr() bnet.IP {
    
    Oliver Herms's avatar
    Oliver Herms committed
    	return p.addr
    }
    
    
    Oliver Herms's avatar
    Oliver Herms committed
    	p.fsms[0].start()
    
    Oliver Herms's avatar
    Oliver Herms committed
    }