Skip to content
Snippets Groups Projects
bgp_path.go 4.85 KiB
Newer Older
  • Learn to ignore specific revisions
  • Oliver Herms's avatar
    Oliver Herms committed
    import (
    
    	"crypto/sha256"
    
    Oliver Herms's avatar
    Oliver Herms committed
    	"fmt"
    
    Oliver Herms's avatar
    Oliver Herms committed
    
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
    
    Oliver Herms's avatar
    Oliver Herms committed
    	"github.com/taktv6/tflow2/convert"
    )
    
    
    // BGPPath represents a set of BGP path attributes
    type BGPPath struct {
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    	PathIdentifier   uint32
    	NextHop          uint32
    	LocalPref        uint32
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    	ASPath           packet.ASPath
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    	ASPathLen        uint16
    	Origin           uint8
    	MED              uint32
    	EBGP             bool
    	BGPIdentifier    uint32
    	Source           uint32
    
    	Communities      []uint32
    
    	LargeCommunities []packet.LargeCommunity
    
    Oliver Herms's avatar
    Oliver Herms committed
    // ECMP determines if routes b and c are euqal in terms of ECMP
    func (b *BGPPath) ECMP(c *BGPPath) bool {
    	return b.LocalPref == c.LocalPref && b.ASPathLen == c.ASPathLen && b.MED == c.MED && b.Origin == c.Origin
    }
    
    Oliver Herms's avatar
    Oliver Herms committed
    // Compare returns negative if b < c, 0 if paths are equal, positive if b > c
    func (b *BGPPath) Compare(c *BGPPath) int8 {
    	if c.LocalPref < b.LocalPref {
    		return 1
    	}
    
    Oliver Herms's avatar
    Oliver Herms committed
    	if c.LocalPref > b.LocalPref {
    		return -1
    	}
    
    Oliver Herms's avatar
    Oliver Herms committed
    	if c.ASPathLen > b.ASPathLen {
    		return 1
    	}
    
    Oliver Herms's avatar
    Oliver Herms committed
    	if c.ASPathLen < b.ASPathLen {
    		return -1
    	}
    
    Oliver Herms's avatar
    Oliver Herms committed
    	if c.Origin > b.Origin {
    		return 1
    	}
    
    	if c.Origin < b.Origin {
    		return -1
    
    Oliver Herms's avatar
    Oliver Herms committed
    	if c.MED > b.MED {
    		return 1
    	}
    
    	if c.MED < b.MED {
    		return -1
    	}
    
    
    	// d)
    	if c.EBGP && !b.EBGP {
    		return -1
    	}
    
    	if !c.EBGP && b.EBGP {
    		return 1
    	}
    
    	// e) TODO: interiour cost (hello IS-IS and OSPF)
    
    	// f)
    
    Oliver Herms's avatar
    Oliver Herms committed
    	if c.BGPIdentifier < b.BGPIdentifier {
    		return 1
    	}
    
    	if c.BGPIdentifier > b.BGPIdentifier {
    		return -1
    	}
    
    
    Oliver Herms's avatar
    Oliver Herms committed
    	if c.Source < b.Source {
    		return 1
    	}
    
    	if c.Source > b.Source {
    		return -1
    	}
    
    
    	if c.NextHop < b.NextHop {
    		return 1
    	}
    
    	if c.NextHop > b.NextHop {
    		return -1
    	}
    
    
    Oliver Herms's avatar
    Oliver Herms committed
    	return 0
    
    }
    
    func (b *BGPPath) betterECMP(c *BGPPath) bool {
    	if c.LocalPref < b.LocalPref {
    		return false
    	}
    
    	if c.LocalPref > b.LocalPref {
    		return true
    	}
    
    	if c.ASPathLen > b.ASPathLen {
    		return false
    	}
    
    	if c.ASPathLen < b.ASPathLen {
    		return true
    	}
    
    	if c.Origin > b.Origin {
    		return false
    	}
    
    	if c.Origin < b.Origin {
    		return true
    	}
    
    	if c.MED > b.MED {
    		return false
    	}
    
    	if c.MED < b.MED {
    		return true
    	}
    
    	return false
    }
    
    func (b *BGPPath) better(c *BGPPath) bool {
    	if b.betterECMP(c) {
    		return true
    	}
    
    	if c.BGPIdentifier < b.BGPIdentifier {
    		return true
    	}
    
    	if c.Source < b.Source {
    		return true
    	}
    
    	return false
    }
    
    
    Oliver Herms's avatar
    Oliver Herms committed
    func (b *BGPPath) Print() string {
    	origin := ""
    	switch b.Origin {
    	case 0:
    		origin = "Incomplete"
    	case 1:
    		origin = "EGP"
    	case 2:
    		origin = "IGP"
    	}
    	ret := fmt.Sprintf("\t\tLocal Pref: %d\n", b.LocalPref)
    	ret += fmt.Sprintf("\t\tOrigin: %s\n", origin)
    
    	ret += fmt.Sprintf("\t\tAS Path: %v\n", b.ASPath)
    
    Oliver Herms's avatar
    Oliver Herms committed
    	nh := uint32To4Byte(b.NextHop)
    	ret += fmt.Sprintf("\t\tNEXT HOP: %d.%d.%d.%d\n", nh[0], nh[1], nh[2], nh[3])
    	ret += fmt.Sprintf("\t\tMED: %d\n", b.MED)
    
    Oliver Herms's avatar
    Oliver Herms committed
    	ret += fmt.Sprintf("\t\tPath ID: %d\n", b.PathIdentifier)
    	ret += fmt.Sprintf("\t\tSource: %d\n", b.Source)
    
    	ret += fmt.Sprintf("\t\tCommunities: %v\n", b.Communities)
    	ret += fmt.Sprintf("\t\tLargeCommunities: %v\n", b.LargeCommunities)
    
    Oliver Herms's avatar
    Oliver Herms committed
    
    	return ret
    }
    
    
    func (b *BGPPath) Prepend(asn uint32, times uint16) {
    
    	if len(b.ASPath) == 0 {
    		b.insertNewASSequence()
    	}
    
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    	first := b.ASPath[0]
    
    	if first.Type == packet.ASSet {
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    		b.insertNewASSequence()
    	}
    
    	for i := 0; i < int(times); i++ {
    		if len(b.ASPath) == packet.MaxASNsSegment {
    			b.insertNewASSequence()
    		}
    
    
    		old := b.ASPath[0].ASNs
    		asns := make([]uint32, len(old)+1)
    		copy(asns[1:], old)
    		asns[0] = asn
    		b.ASPath[0].ASNs = asns
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    	}
    
    	b.ASPathLen = b.ASPath.Length()
    }
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    func (b *BGPPath) insertNewASSequence() packet.ASPath {
    	pa := make(packet.ASPath, len(b.ASPath)+1)
    	copy(pa[1:], b.ASPath)
    	pa[0] = packet.ASPathSegment{
    		ASNs:  make([]uint32, 0),
    		Count: 0,
    		Type:  packet.ASSequence,
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    	return pa
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    func (p *BGPPath) Copy() *BGPPath {
    	if p == nil {
    		return nil
    	}
    
    	cp := *p
    	return &cp
    }
    
    
    // ComputeHash computes an hash over all attributes of the path
    func (b *BGPPath) ComputeHash() string {
    
    	s := fmt.Sprintf("%d\t%d\t%v\t%d\t%d\t%v\t%d\t%d\t%v\t%v\t%d",
    
    		b.NextHop,
    		b.LocalPref,
    		b.ASPath,
    		b.Origin,
    		b.MED,
    		b.EBGP,
    		b.BGPIdentifier,
    		b.Source,
    		b.Communities,
    		b.LargeCommunities,
    		b.PathIdentifier)
    
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    	return fmt.Sprintf("%x", sha256.Sum256([]byte(s)))
    
    // CommunitiesString returns the formated communities
    func (b *BGPPath) CommunitiesString() string {
    	str := ""
    	for _, com := range b.Communities {
    		str += packet.CommunityStringForUint32(com) + " "
    	}
    
    	return strings.TrimRight(str, " ")
    }
    
    // LargeCommunitiesString returns the formated communities
    func (b *BGPPath) LargeCommunitiesString() string {
    	str := ""
    	for _, com := range b.LargeCommunities {
    		str += com.String() + " "
    	}
    
    	return strings.TrimRight(str, " ")
    }
    
    
    Oliver Herms's avatar
    Oliver Herms committed
    func uint32To4Byte(addr uint32) [4]byte {
    	slice := convert.Uint32Byte(addr)
    	ret := [4]byte{
    		slice[0],
    		slice[1],
    		slice[2],
    		slice[3],
    	}
    	return ret
    }