Skip to content
Snippets Groups Projects
bgp.go 3.76 KiB
Newer Older
Oliver Herms's avatar
Oliver Herms committed
import (
	"crypto/sha256"
Oliver Herms's avatar
Oliver Herms committed
	"fmt"
	"strconv"
	"strings"
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
	ASPath           string
	ASPathLen        uint16
	Origin           uint8
	MED              uint32
	EBGP             bool
	BGPIdentifier    uint32
	Source           uint32
	Communities      []uint32
Daniel Czerwonk's avatar
Daniel Czerwonk committed
	LargeCommunities string
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
	}

	if c.BGPIdentifier < b.BGPIdentifier {
		return 1
	}

	if c.BGPIdentifier > b.BGPIdentifier {
		return -1
	}

	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: %s\n", b.ASPath)
	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: %s\n", b.Communities)
	ret += fmt.Sprintf("\t\tLargeCommunities: %s\n", b.LargeCommunities)
Oliver Herms's avatar
Oliver Herms committed

	return ret
}

func (b *BGPPath) Prepend(asn uint32, times uint16) {
	if times == 0 {
		return
	}

	asnStr := strconv.FormatUint(uint64(asn), 10)

	path := make([]string, times+1)
	for i := 0; uint16(i) < times; i++ {
		path[i] = asnStr
	path[times] = b.ASPath
	b.ASPath = strings.TrimSuffix(strings.Join(path, " "), " ")
	b.ASPathLen = b.ASPathLen + times
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%s\t%d\t%d\t%v\t%d\t%d\t%s\t%s\t%d",
		b.NextHop,
		b.LocalPref,
		b.ASPath,
		b.Origin,
		b.MED,
		b.EBGP,
		b.BGPIdentifier,
		b.Source,
		b.Communities,
		b.LargeCommunities,
		b.PathIdentifier)

	r := strings.NewReader(s)
	h := sha256.New()
	r.WriteTo(h)

	return fmt.Sprintf("%x", h.Sum(nil))
}

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
}