Skip to content
Snippets Groups Projects
update_sender.go 3.98 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
    
    	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
    
    Oliver Herms's avatar
    Oliver Herms committed
    	"github.com/bio-routing/bio-rd/route"
    	"github.com/bio-routing/bio-rd/routingtable"
    
    Oliver Herms's avatar
    Oliver Herms committed
    
    	bnet "github.com/bio-routing/bio-rd/net"
    	log "github.com/sirupsen/logrus"
    
    Oliver Herms's avatar
    Oliver Herms committed
    // UpdateSender converts table changes into BGP update messages
    
    Oliver Herms's avatar
    Oliver Herms committed
    type UpdateSender struct {
    
    Oliver Herms's avatar
    Oliver Herms committed
    	routingtable.ClientManager
    
    	fsm       *FSM
    	iBGP      bool
    	toSendMu  sync.Mutex
    	toSend    map[string]*pathPfxs
    	destroyCh chan struct{}
    }
    
    type pathPfxs struct {
    	path *route.Path
    	pfxs []bnet.Prefix
    }
    
    
    Oliver Herms's avatar
    Oliver Herms committed
    func newUpdateSender(fsm *FSM) *UpdateSender {
    
    Oliver Herms's avatar
    Oliver Herms committed
    	return &UpdateSender{
    
    		fsm:       fsm,
    		iBGP:      fsm.peer.localASN == fsm.peer.peerASN,
    		destroyCh: make(chan struct{}),
    
    		toSend:    make(map[string]*pathPfxs),
    
    Oliver Herms's avatar
    Oliver Herms committed
    func (u *UpdateSender) Start(aggrTime time.Duration) {
    	go u.sender(aggrTime)
    
    }
    
    // Destroy destroys everything (with greetings to Hatebreed)
    func (u *UpdateSender) Destroy() {
    	u.destroyCh <- struct{}{}
    }
    
    // AddPath adds path p for pfx to toSend queue
    func (u *UpdateSender) AddPath(pfx bnet.Prefix, p *route.Path) error {
    	u.toSendMu.Lock()
    
    	hash := p.BGPPath.ComputeHash()
    	if _, exists := u.toSend[hash]; exists {
    		u.toSend[hash].pfxs = append(u.toSend[hash].pfxs, pfx)
    		u.toSendMu.Unlock()
    
    		return nil
    
    	u.toSend[p.BGPPath.ComputeHash()] = &pathPfxs{
    		path: p,
    		pfxs: []bnet.Prefix{
    			pfx,
    
    	u.toSendMu.Unlock()
    	return nil
    }
    
    // sender serializes BGP update messages
    
    Oliver Herms's avatar
    Oliver Herms committed
    func (u *UpdateSender) sender(aggrTime time.Duration) {
    	ticker := time.NewTicker(aggrTime)
    
    	var err error
    	var pathAttrs *packet.PathAttribute
    	var budget int
    
    	for {
    		select {
    		case <-u.destroyCh:
    			return
    		case <-ticker.C:
    		}
    
    		u.toSendMu.Lock()
    
    		for key, pathNLRIs := range u.toSend {
    
    Oliver Herms's avatar
    Oliver Herms committed
    			budget = packet.MaxLen - packet.HeaderLen - packet.MinUpdateLen - int(pathNLRIs.path.BGPPath.Length())
    
    			pathAttrs, err = packet.PathAttributes(pathNLRIs.path, u.iBGP)
    
    			if err != nil {
    				log.Errorf("Unable to get path attributes: %v", err)
    				continue
    			}
    
    
    Oliver Herms's avatar
    Oliver Herms committed
    			updatesPrefixes := make([][]bnet.Prefix, 0, 1)
    			prefixes := make([]bnet.Prefix, 0, 1)
    
    			for _, pfx := range pathNLRIs.pfxs {
    
    Oliver Herms's avatar
    Oliver Herms committed
    				budget -= int(packet.BytesInAddr(pfx.Pfxlen())) + 1
    
    				if budget < 0 {
    					updatesPrefixes = append(updatesPrefixes, prefixes)
    
    Oliver Herms's avatar
    Oliver Herms committed
    					prefixes = make([]bnet.Prefix, 0, 1)
    					budget = packet.MaxLen - int(pathNLRIs.path.BGPPath.Length())
    
    Oliver Herms's avatar
    Oliver Herms committed
    			if len(prefixes) > 0 {
    				updatesPrefixes = append(updatesPrefixes, prefixes)
    			}
    
    
    			delete(u.toSend, key)
    			u.toSendMu.Unlock()
    
    			u.sendUpdates(pathAttrs, updatesPrefixes, pathNLRIs.path.BGPPath.PathIdentifier)
    			u.toSendMu.Lock()
    		}
    
    Oliver Herms's avatar
    Oliver Herms committed
    		u.toSendMu.Unlock()
    
    	}
    }
    
    func (u *UpdateSender) sendUpdates(pathAttrs *packet.PathAttribute, updatePrefixes [][]bnet.Prefix, pathID uint32) {
    	var nlri *packet.NLRI
    	var err error
    
    	for _, updatePrefix := range updatePrefixes {
    		update := &packet.BGPUpdate{
    			PathAttributes: pathAttrs,
    		}
    
    		for _, pfx := range updatePrefix {
    			nlri = &packet.NLRI{
    				PathIdentifier: pathID,
    
    				IP:             pfx.Addr().ToUint32(),
    
    				Pfxlen:         pfx.Pfxlen(),
    				Next:           update.NLRI,
    			}
    			update.NLRI = nlri
    		}
    
    		err = serializeAndSendUpdate(u.fsm.con, update, u.fsm.options)
    		if err != nil {
    			log.Errorf("Failed to serialize and send: %v", err)
    		}
    	}
    
    Oliver Herms's avatar
    Oliver Herms committed
    // RemovePath withdraws prefix `pfx` from a peer
    
    func (u *UpdateSender) RemovePath(pfx bnet.Prefix, p *route.Path) bool {
    	err := withDrawPrefixesAddPath(u.fsm.con, u.fsm.options, pfx, p)
    
    Oliver Herms's avatar
    Oliver Herms committed
    	if err != nil {
    		log.Errorf("Unable to withdraw prefix: %v", err)
    		return false
    	}
    	return true
    
    Oliver Herms's avatar
    Oliver Herms committed
    // UpdateNewClient does nothing
    
    Oliver Herms's avatar
    Oliver Herms committed
    func (u *UpdateSender) UpdateNewClient(client routingtable.RouteTableClient) error {
    
    	log.Warningf("BGP Update Sender: UpdateNewClient not implemented")
    
    Oliver Herms's avatar
    Oliver Herms committed
    	return nil
    
    // RouteCount returns the number of stored routes
    
    func (u *UpdateSender) RouteCount() int64 {
    
    	log.Warningf("BGP Update Sender: RouteCount not implemented")