Skip to content
Snippets Groups Projects
bgp_path.go 16.7 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
    
    
    	"github.com/bio-routing/tflow2/convert"
    
    	bnet "github.com/bio-routing/bio-rd/net"
    
    Oliver Herms's avatar
    Oliver Herms committed
    	"github.com/bio-routing/bio-rd/protocols/bgp/types"
    
    	"github.com/bio-routing/bio-rd/route/api"
    
    Oliver Herms's avatar
    Oliver Herms committed
    )
    
    
    // BGPPath represents a set of BGP path attributes
    type BGPPath struct {
    
    	BGPPathA          *BGPPathA
    	ASPath            *types.ASPath
    	ClusterList       *types.ClusterList
    	Communities       *types.Communities
    	LargeCommunities  *types.LargeCommunities
    	UnknownAttributes []types.UnknownPathAttribute
    
    	PathIdentifier    uint32
    	ASPathLen         uint16
    
    }
    
    // BGPPathA represents cachable BGP path attributes
    type BGPPathA struct {
    	NextHop         *bnet.IP
    	Source          *bnet.IP
    	LocalPref       uint32
    	MED             uint32
    	BGPIdentifier   uint32
    	OriginatorID    uint32
    	Aggregator      *types.Aggregator
    	EBGP            bool
    	AtomicAggregate bool
    	Origin          uint8
    }
    
    // NewBGPPathA creates a new BGPPathA
    func NewBGPPathA() *BGPPathA {
    
    takt's avatar
    takt committed
    	defaultAddr := bnet.IPv4(0)
    
    takt's avatar
    takt committed
    		NextHop: &defaultAddr,
    		Source:  &defaultAddr,
    
    	}
    }
    
    func (b *BGPPathA) Dedup() *BGPPathA {
    	return bgpC.get(b)
    }
    
    func (b *BGPPath) Dedup() *BGPPath {
    	b.BGPPathA = b.BGPPathA.Dedup()
    	return b
    
    // ToProto converts BGPPath to proto BGPPath
    func (b *BGPPath) ToProto() *api.BGPPath {
    	if b == nil {
    		return nil
    	}
    
    	a := &api.BGPPath{
    		PathIdentifier:    b.PathIdentifier,
    
    		NextHop:           b.BGPPathA.NextHop.ToProto(),
    		LocalPref:         b.BGPPathA.LocalPref,
    		Origin:            uint32(b.BGPPathA.Origin),
    		Med:               b.BGPPathA.MED,
    		Ebgp:              b.BGPPathA.EBGP,
    		BgpIdentifier:     b.BGPPathA.BGPIdentifier,
    		Source:            b.BGPPathA.Source.ToProto(),
    
    		UnknownAttributes: make([]*api.UnknownPathAttribute, len(b.UnknownAttributes)),
    
    		OriginatorId:      b.BGPPathA.OriginatorID,
    
    	if b.ASPath != nil {
    		a.AsPath = b.ASPath.ToProto()
    	}
    
    	if a.ClusterList != nil {
    		a.ClusterList = make([]uint32, len(*b.ClusterList))
    		for i := range *b.ClusterList {
    			a.ClusterList[i] = (*b.ClusterList)[i]
    		}
    	}
    
    	if b.Communities != nil {
    		a.Communities = make([]uint32, len(*b.Communities))
    		for i := range *b.Communities {
    			a.Communities[i] = (*b.Communities)[i]
    		}
    	}
    
    	if b.LargeCommunities != nil {
    		a.LargeCommunities = make([]*api.LargeCommunity, len(*b.LargeCommunities))
    		for i := range *b.LargeCommunities {
    			a.LargeCommunities[i] = (*b.LargeCommunities)[i].ToProto()
    		}
    
    	}
    
    	for i := range b.UnknownAttributes {
    		a.UnknownAttributes[i] = b.UnknownAttributes[i].ToProto()
    	}
    
    	return a
    }
    
    
    takt's avatar
    takt committed
    // BGPPathFromProtoBGPPath converts a proto BGPPath to BGPPath
    
    func BGPPathFromProtoBGPPath(pb *api.BGPPath, dedup bool) *BGPPath {
    
    takt's avatar
    takt committed
    	p := &BGPPath{
    
    		BGPPathA: &BGPPathA{
    			NextHop:       bnet.IPFromProtoIP(*pb.NextHop),
    			LocalPref:     pb.LocalPref,
    			OriginatorID:  pb.OriginatorId,
    			Origin:        uint8(pb.Origin),
    			MED:           pb.Med,
    			EBGP:          pb.Ebgp,
    			BGPIdentifier: pb.BgpIdentifier,
    			Source:        bnet.IPFromProtoIP(*pb.Source),
    		},
    		PathIdentifier: pb.PathIdentifier,
    		ASPath:         types.ASPathFromProtoASPath(pb.AsPath),
    
    takt's avatar
    takt committed
    	}
    
    
    
    	communities := make(types.Communities, len(pb.Communities))
    	p.Communities = &communities
    
    	largeCommunities := make(types.LargeCommunities, len(pb.LargeCommunities))
    	p.LargeCommunities = &largeCommunities
    
    	unknownAttr := make([]types.UnknownPathAttribute, len(pb.UnknownAttributes))
    	p.UnknownAttributes = unknownAttr
    
    	cl := make(types.ClusterList, len(pb.ClusterList))
    	p.ClusterList = &cl
    
    
    takt's avatar
    takt committed
    	for i := range pb.Communities {
    
    		(*p.Communities)[i] = pb.Communities[i]
    
    takt's avatar
    takt committed
    	}
    
    	for i := range pb.LargeCommunities {
    
    		(*p.LargeCommunities)[i] = types.LargeCommunityFromProtoCommunity(pb.LargeCommunities[i])
    
    takt's avatar
    takt committed
    	}
    
    	for i := range pb.UnknownAttributes {
    		p.UnknownAttributes[i] = types.UnknownPathAttributeFromProtoUnknownPathAttribute(pb.UnknownAttributes[i])
    	}
    
    	for i := range pb.ClusterList {
    
    		(*p.ClusterList)[i] = pb.ClusterList[i]
    
    takt's avatar
    takt committed
    	}
    
    	return p
    }
    
    
    // Length get's the length of serialized path
    func (b *BGPPath) Length() uint16 {
    
    Oliver Herms's avatar
    Oliver Herms committed
    	asPathLen := uint16(3)
    
    	for _, segment := range *b.ASPath {
    
    Oliver Herms's avatar
    Oliver Herms committed
    		asPathLen++
    		asPathLen += uint16(4 * len(segment.ASNs))
    	}
    
    
    Oliver Herms's avatar
    Oliver Herms committed
    	communitiesLen := uint16(0)
    
    	if b.Communities != nil && len(*b.Communities) != 0 {
    		communitiesLen += 3 + uint16(len(*b.Communities)*4)
    
    Oliver Herms's avatar
    Oliver Herms committed
    	}
    
    	largeCommunitiesLen := uint16(0)
    
    	if b.LargeCommunities != nil && len(*b.LargeCommunities) != 0 {
    		largeCommunitiesLen += 3 + uint16(len(*b.LargeCommunities)*12)
    
    	if b.ClusterList != nil && len(*b.ClusterList) != 0 {
    		clusterListLen += 3 + uint16(len(*b.ClusterList)*4)
    
    Oliver Herms's avatar
    Oliver Herms committed
    	unknownAttributesLen := uint16(0)
    
    	if b.UnknownAttributes != nil {
    		for _, unknownAttr := range b.UnknownAttributes {
    			unknownAttributesLen += unknownAttr.WireLength()
    		}
    
    	if b.BGPPathA.OriginatorID != 0 {
    
    		originatorID = 4
    	}
    
    	return communitiesLen + largeCommunitiesLen + 4*7 + 4 + originatorID + asPathLen + unknownAttributesLen
    
    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.BGPPathA.LocalPref == c.BGPPathA.LocalPref &&
    		b.ASPathLen == c.ASPathLen &&
    		b.BGPPathA.MED == c.BGPPathA.MED &&
    		b.BGPPathA.Origin == c.BGPPathA.Origin
    }
    
    // Compare checks if paths are the same
    func (b *BGPPath) Compare(c *BGPPath) bool {
    	if b.PathIdentifier != c.PathIdentifier {
    		return false
    	}
    
    	if !b.BGPPathA.compare(c.BGPPathA) {
    		return false
    	}
    
    	if !b.ASPath.Compare(c.ASPath) {
    		return false
    	}
    
    	if !b.compareClusterList(c) {
    		return false
    	}
    
    	if !b.compareCommunities(c) {
    		return false
    	}
    
    	if !b.compareLargeCommunities(c) {
    		return false
    	}
    
    	return true
    }
    
    func (b *BGPPath) compareCommunities(c *BGPPath) bool {
    	if b.Communities == nil && c.Communities == nil {
    		return true
    	}
    
    	if b.Communities != nil && c.Communities == nil {
    		return false
    	}
    
    	if b.Communities == nil && c.Communities != nil {
    		return false
    	}
    
    	if len(*b.Communities) != len(*c.Communities) {
    		return false
    	}
    
    	for i := range *b.Communities {
    		if (*b.Communities)[i] != (*c.Communities)[i] {
    			return false
    		}
    	}
    
    	if !b.compareUnknownAttributes(c) {
    		return false
    	}
    
    	return true
    }
    
    func (b *BGPPath) compareClusterList(c *BGPPath) bool {
    	if b.ClusterList == nil && c.ClusterList == nil {
    		return true
    	}
    
    	if b.ClusterList != nil && c.ClusterList == nil {
    		return false
    	}
    
    	if b.ClusterList == nil && c.ClusterList != nil {
    		return false
    	}
    
    	if len(*b.ClusterList) != len(*c.ClusterList) {
    		return false
    	}
    
    	for i := range *b.ClusterList {
    		if (*b.ClusterList)[i] != (*c.ClusterList)[i] {
    			return false
    		}
    	}
    
    	return true
    }
    
    func (b *BGPPath) compareLargeCommunities(c *BGPPath) bool {
    	if b.LargeCommunities == nil && c.LargeCommunities == nil {
    		return true
    	}
    
    	if b.LargeCommunities != nil && c.LargeCommunities == nil {
    		return false
    	}
    
    	if b.LargeCommunities == nil && c.LargeCommunities != nil {
    		return false
    	}
    
    	if len(*b.LargeCommunities) != len(*c.LargeCommunities) {
    		return false
    	}
    
    	for i := range *b.LargeCommunities {
    		if (*b.LargeCommunities)[i] != (*c.LargeCommunities)[i] {
    			return false
    		}
    	}
    
    	return true
    }
    
    func (b *BGPPath) compareUnknownAttributes(c *BGPPath) bool {
    	if len(b.UnknownAttributes) != len(c.UnknownAttributes) {
    		return false
    	}
    
    	for i := range b.UnknownAttributes {
    		if !b.UnknownAttributes[i].Compare(&c.UnknownAttributes[i]) {
    			return false
    		}
    	}
    
    	return true
    }
    
    func (b *BGPPathA) compare(c *BGPPathA) bool {
    	if b.NextHop.Compare(c.NextHop) != 0 {
    		return false
    	}
    
    	if b.Source.Compare(c.Source) != 0 {
    		return false
    	}
    
    	if b.LocalPref != c.LocalPref || b.MED != c.MED || b.BGPIdentifier != c.BGPIdentifier || b.OriginatorID != c.OriginatorID {
    		return false
    	}
    
    	if b.EBGP != c.EBGP || b.AtomicAggregate != c.AtomicAggregate || b.Origin != c.Origin {
    		return false
    	}
    
    	if b.Aggregator != nil || c.Aggregator != nil {
    		if b.Aggregator != nil && c.Aggregator != nil {
    			if *b.Aggregator != *c.Aggregator {
    				return false
    			}
    		} else {
    			return false
    		}
    	}
    
    	return true
    
    Oliver Herms's avatar
    Oliver Herms committed
    }
    
    // Equal checks if paths are equal
    func (b *BGPPath) Equal(c *BGPPath) bool {
    	if b.PathIdentifier != c.PathIdentifier {
    		return false
    	}
    
    	return b.Select(c) == 0
    }
    
    // Select returns negative if b < c, 0 if paths are equal, positive if b > c
    func (b *BGPPath) Select(c *BGPPath) int8 {
    
    	if c.BGPPathA.LocalPref < b.BGPPathA.LocalPref {
    
    Oliver Herms's avatar
    Oliver Herms committed
    		return 1
    	}
    
    	if c.BGPPathA.LocalPref > b.BGPPathA.LocalPref {
    
    Oliver Herms's avatar
    Oliver Herms committed
    		return -1
    	}
    
    	// 9.1.2.2.  Breaking Ties (Phase 2)
    
    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
    	}
    
    	if c.BGPPathA.Origin > b.BGPPathA.Origin {
    
    Oliver Herms's avatar
    Oliver Herms committed
    		return 1
    	}
    
    
    	if c.BGPPathA.Origin < b.BGPPathA.Origin {
    
    Oliver Herms's avatar
    Oliver Herms committed
    		return -1
    
    	if c.BGPPathA.MED > b.BGPPathA.MED {
    
    Oliver Herms's avatar
    Oliver Herms committed
    		return 1
    	}
    
    
    	if c.BGPPathA.MED < b.BGPPathA.MED {
    
    Oliver Herms's avatar
    Oliver Herms committed
    		return -1
    	}
    
    
    	if c.BGPPathA.EBGP && !b.BGPPathA.EBGP {
    
    	if !c.BGPPathA.EBGP && b.BGPPathA.EBGP {
    
    	// e) TODO: interior cost (hello IS-IS and OSPF)
    
    	bgpIdentifierC := c.BGPPathA.BGPIdentifier
    	bgpIdentifierB := b.BGPPathA.BGPIdentifier
    
    
    	// IF an OriginatorID (set by an RR) is present, use this instead of Originator
    
    	if c.BGPPathA.OriginatorID != 0 {
    		bgpIdentifierC = c.BGPPathA.OriginatorID
    
    	if b.BGPPathA.OriginatorID != 0 {
    		bgpIdentifierB = b.BGPPathA.OriginatorID
    
    Oliver Herms's avatar
    Oliver Herms committed
    		return 1
    	}
    
    
    	if c.ClusterList != nil && b.ClusterList != nil {
    		// Additionally check for the shorter ClusterList
    		if len(*c.ClusterList) < len(*b.ClusterList) {
    			return 1
    		}
    
    Oliver Herms's avatar
    Oliver Herms committed
    
    
    		if len(*c.ClusterList) > len(*b.ClusterList) {
    			return -1
    		}
    
    Oliver Herms's avatar
    Oliver Herms committed
    	}
    
    
    	if c.BGPPathA.Source.Compare(b.BGPPathA.Source) == -1 {
    
    Oliver Herms's avatar
    Oliver Herms committed
    		return 1
    	}
    
    
    	if c.BGPPathA.Source.Compare(b.BGPPathA.Source) == 1 {
    
    Oliver Herms's avatar
    Oliver Herms committed
    		return -1
    	}
    
    
    	if c.BGPPathA.NextHop.Compare(b.BGPPathA.NextHop) == -1 {
    
    	if c.BGPPathA.NextHop.Compare(b.BGPPathA.NextHop) == 1 {
    
    Oliver Herms's avatar
    Oliver Herms committed
    	return 0
    
    }
    
    func (b *BGPPath) betterECMP(c *BGPPath) bool {
    
    	if c.BGPPathA.LocalPref < b.BGPPathA.LocalPref {
    
    	if c.BGPPathA.LocalPref > b.BGPPathA.LocalPref {
    
    		return true
    	}
    
    	if c.ASPathLen > b.ASPathLen {
    		return false
    	}
    
    	if c.ASPathLen < b.ASPathLen {
    		return true
    	}
    
    
    	if c.BGPPathA.Origin > b.BGPPathA.Origin {
    
    	if c.BGPPathA.Origin < b.BGPPathA.Origin {
    
    	if c.BGPPathA.MED > b.BGPPathA.MED {
    
    	if c.BGPPathA.MED < b.BGPPathA.MED {
    
    		return true
    	}
    
    	return false
    }
    
    func (b *BGPPath) better(c *BGPPath) bool {
    	if b.betterECMP(c) {
    		return true
    	}
    
    
    	if c.BGPPathA.BGPIdentifier < b.BGPPathA.BGPIdentifier {
    
    	if c.BGPPathA.Source.Compare(b.BGPPathA.Source) == -1 {
    
    cedi's avatar
    cedi committed
    // Print all known information about a route in logfile friendly format
    
    cedi's avatar
    cedi committed
    func (b *BGPPath) String() string {
    
    cedi's avatar
    cedi committed
    	origin := ""
    
    	switch b.BGPPathA.Origin {
    
    cedi's avatar
    cedi committed
    	case 0:
    		origin = "Incomplete"
    	case 1:
    		origin = "EGP"
    	case 2:
    		origin = "IGP"
    	}
    
    	bgpType := "internal"
    
    cedi's avatar
    cedi committed
    		bgpType = "external"
    	}
    
    
    	fmt.Fprintf(buf, "Local Pref: %d, ", b.BGPPathA.LocalPref)
    
    	fmt.Fprintf(buf, "Origin: %s, ", origin)
    	fmt.Fprintf(buf, "AS Path: %v, ", b.ASPath)
    	fmt.Fprintf(buf, "BGP type: %s, ", bgpType)
    
    	fmt.Fprintf(buf, "NEXT HOP: %s, ", b.BGPPathA.NextHop)
    	fmt.Fprintf(buf, "MED: %d, ", b.BGPPathA.MED)
    
    	fmt.Fprintf(buf, "Path ID: %d, ", b.PathIdentifier)
    
    	fmt.Fprintf(buf, "Source: %s, ", b.BGPPathA.Source)
    	if b.Communities != nil {
    		fmt.Fprintf(buf, "Communities: %v, ", *b.Communities)
    	}
    	if b.LargeCommunities != nil {
    		fmt.Fprintf(buf, "LargeCommunities: %v", *b.LargeCommunities)
    	}
    
    cedi's avatar
    cedi committed
    
    
    	if b.BGPPathA.OriginatorID != 0 {
    		oid := convert.Uint32Byte(b.BGPPathA.OriginatorID)
    
    		fmt.Fprintf(buf, ", OriginatorID: %d.%d.%d.%d", oid[0], oid[1], oid[2], oid[3])
    
    cedi's avatar
    cedi committed
    	}
    	if b.ClusterList != nil {
    
    		fmt.Fprintf(buf, ", ClusterList %s", b.ClusterListString())
    
    cedi's avatar
    cedi committed
    	}
    
    
    cedi's avatar
    cedi committed
    }
    
    
    cedi's avatar
    cedi committed
    // Print all known information about a route in human readable form
    
    Oliver Herms's avatar
    Oliver Herms committed
    func (b *BGPPath) Print() string {
    
    Oliver Herms's avatar
    Oliver Herms committed
    	origin := ""
    
    	switch b.BGPPathA.Origin {
    
    Oliver Herms's avatar
    Oliver Herms committed
    	case 0:
    		origin = "Incomplete"
    	case 1:
    		origin = "EGP"
    	case 2:
    		origin = "IGP"
    	}
    
    	fmt.Fprintf(buf, "\t\tLocal Pref: %d\n", b.BGPPathA.LocalPref)
    
    	fmt.Fprintf(buf, "\t\tOrigin: %s\n", origin)
    	fmt.Fprintf(buf, "\t\tAS Path: %v\n", b.ASPath)
    	fmt.Fprintf(buf, "\t\tBGP type: %s\n", bgpType)
    
    	fmt.Fprintf(buf, "\t\tNEXT HOP: %s\n", b.BGPPathA.NextHop)
    	fmt.Fprintf(buf, "\t\tMED: %d\n", b.BGPPathA.MED)
    
    	fmt.Fprintf(buf, "\t\tPath ID: %d\n", b.PathIdentifier)
    
    	fmt.Fprintf(buf, "\t\tSource: %s\n", b.BGPPathA.Source)
    	if b.Communities != nil {
    		fmt.Fprintf(buf, "\t\tCommunities: %v\n", *b.Communities)
    	}
    	if b.LargeCommunities != nil {
    		fmt.Fprintf(buf, "\t\tLargeCommunities: %v\n", *b.LargeCommunities)
    	}
    
    Oliver Herms's avatar
    Oliver Herms committed
    
    
    	if b.BGPPathA.OriginatorID != 0 {
    		oid := convert.Uint32Byte(b.BGPPathA.OriginatorID)
    
    		fmt.Fprintf(buf, "\t\tOriginatorID: %d.%d.%d.%d\n", oid[0], oid[1], oid[2], oid[3])
    
    		fmt.Fprintf(buf, "\t\tClusterList %s\n", b.ClusterListString())
    
    Oliver Herms's avatar
    Oliver Herms committed
    }
    
    
    // Prepend the given BGPPath with the given ASN given times
    
    func (b *BGPPath) Prepend(asn uint32, times uint16) {
    
    	if len(*b.ASPath) == 0 {
    
    		b.insertNewASSequence()
    	}
    
    
    	first := (*b.ASPath)[0]
    
    Oliver Herms's avatar
    Oliver Herms committed
    	if first.Type == types.ASSet {
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    		b.insertNewASSequence()
    	}
    
    	for i := 0; i < int(times); i++ {
    
    		if len(*b.ASPath) == types.MaxASNsSegment {
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    			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()
    }
    
    func (b *BGPPath) insertNewASSequence() {
    
    	pa := make(types.ASPath, len(*b.ASPath)+1)
    	copy(pa[1:], (*b.ASPath))
    
    Oliver Herms's avatar
    Oliver Herms committed
    	pa[0] = types.ASPathSegment{
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    		ASNs: make([]uint32, 0),
    		Type: types.ASSequence,
    
    Oliver Herms's avatar
    Oliver Herms committed
    // Copy creates a deep copy of a BGPPath
    func (b *BGPPath) Copy() *BGPPath {
    	if b == nil {
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    		return nil
    	}
    
    
    Oliver Herms's avatar
    Oliver Herms committed
    	cp := *b
    
    
    	if cp.ASPath != nil {
    		asPath := make(types.ASPath, len(*cp.ASPath))
    		cp.ASPath = &asPath
    		copy(*cp.ASPath, *b.ASPath)
    	}
    
    Oliver Herms's avatar
    Oliver Herms committed
    
    
    	if cp.Communities != nil {
    		communities := make(types.Communities, len(*cp.Communities))
    		cp.Communities = &communities
    		copy(*cp.Communities, *b.Communities)
    	}
    
    Oliver Herms's avatar
    Oliver Herms committed
    
    
    	if cp.LargeCommunities != nil {
    		largeCommunities := make(types.LargeCommunities, len(*cp.LargeCommunities))
    		cp.LargeCommunities = &largeCommunities
    		copy(*cp.LargeCommunities, *b.LargeCommunities)
    	}
    
    Oliver Herms's avatar
    Oliver Herms committed
    
    
    		clusterList := make(types.ClusterList, len(*cp.ClusterList))
    		cp.ClusterList = &clusterList
    		copy(*cp.ClusterList, *b.ClusterList)
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    	return &cp
    }
    
    
    // ComputeHash computes an hash over all attributes of the path
    func (b *BGPPath) ComputeHash() string {
    
    	s := fmt.Sprintf("%s\t%d\t%s\t%d\t%d\t%v\t%d\t%s\t%s\t%s\t%d\t%s",
    		b.BGPPathA.NextHop.String(),
    		b.BGPPathA.LocalPref,
    		b.ASPath.String(),
    		b.BGPPathA.Origin,
    		b.BGPPathA.MED,
    		b.BGPPathA.EBGP,
    		b.BGPPathA.BGPIdentifier,
    		b.BGPPathA.Source.String(),
    		b.Communities.String(),
    		b.LargeCommunities.String(),
    		b.BGPPathA.OriginatorID,
    		b.ClusterList.String())
    
    	return fmt.Sprintf("%x", sha256.Sum256([]byte(s)))
    }
    
    // ComputeHash computes an hash over all attributes of the path
    func (b *BGPPath) ComputeHashWithPathID() string {
    	s := fmt.Sprintf("%s\t%d\t%s\t%d\t%d\t%v\t%d\t%s\t%s\t%s\t%d\t%d\t%s",
    		b.BGPPathA.NextHop.String(),
    		b.BGPPathA.LocalPref,
    		b.ASPath.String(),
    		b.BGPPathA.Origin,
    		b.BGPPathA.MED,
    		b.BGPPathA.EBGP,
    		b.BGPPathA.BGPIdentifier,
    		b.BGPPathA.Source.String(),
    		b.Communities.String(),
    		b.LargeCommunities.String(),
    
    		b.PathIdentifier,
    
    		b.BGPPathA.OriginatorID,
    		b.ClusterList.String())
    
    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 {
    
    	for i, com := range *b.Communities {
    
    		if i > 0 {
    			str.WriteByte(' ')
    		}
    		str.WriteString(types.CommunityStringForUint32(com))
    
    // ClusterListString returns the formated ClusterList
    func (b *BGPPath) ClusterListString() string {
    
    	for i, cid := range *b.ClusterList {
    
    		octes := convert.Uint32Byte(cid)
    
    
    		fmt.Fprintf(str, "%d.%d.%d.%d", octes[0], octes[1], octes[2], octes[3])
    
    // LargeCommunitiesString returns the formated communities
    func (b *BGPPath) LargeCommunitiesString() string {
    
    	for i, com := range *b.LargeCommunities {
    
    		if i > 0 {
    			str.WriteByte(' ')
    		}
    		str.WriteString(com.String())