From ef9400a00149855505de10ec218c07e1fb46203b Mon Sep 17 00:00:00 2001 From: Daniel Czerwonk <daniel@dan-nrw.de> Date: Mon, 25 Jun 2018 21:21:15 +0200 Subject: [PATCH] as path refactoring --- protocols/bgp/packet/as_path.go | 44 ++++++++++++ protocols/bgp/packet/bgp.go | 7 -- protocols/bgp/packet/path_attributes.go | 93 ------------------------- protocols/bgp/server/fsm_established.go | 4 +- protocols/bgp/server/update_helper.go | 11 ++- route/{bgp.go => bgp_path.go} | 35 +++++++--- routingtable/adjRIBIn/adj_rib_in.go | 6 +- routingtable/adjRIBOut/adj_rib_out.go | 2 +- 8 files changed, 78 insertions(+), 124 deletions(-) create mode 100644 protocols/bgp/packet/as_path.go rename route/{bgp.go => bgp_path.go} (84%) diff --git a/protocols/bgp/packet/as_path.go b/protocols/bgp/packet/as_path.go new file mode 100644 index 00000000..0cdfc96a --- /dev/null +++ b/protocols/bgp/packet/as_path.go @@ -0,0 +1,44 @@ +package packet + +import "fmt" + +type ASPath []ASPathSegment + +type ASPathSegment struct { + Type uint8 + Count uint8 + ASNs []uint32 +} + +func (pa ASPath) String() (ret string) { + for _, p := range pa { + if p.Type == ASSet { + ret += " (" + } + n := len(p.ASNs) + for i, asn := range p.ASNs { + if i < n-1 { + ret += fmt.Sprintf("%d ", asn) + continue + } + ret += fmt.Sprintf("%d", asn) + } + if p.Type == ASSet { + ret += ")" + } + } + + return +} + +func (pa ASPath) Length() (ret uint16) { + for _, p := range pa { + if p.Type == ASSet { + ret++ + continue + } + ret += uint16(len(p.ASNs)) + } + + return +} diff --git a/protocols/bgp/packet/bgp.go b/protocols/bgp/packet/bgp.go index 8082f5dd..8aabec7f 100644 --- a/protocols/bgp/packet/bgp.go +++ b/protocols/bgp/packet/bgp.go @@ -173,13 +173,6 @@ type NLRIAddPath struct { Next *NLRIAddPath } -type ASPath []ASPathSegment -type ASPathSegment struct { - Type uint8 - Count uint8 - ASNs []uint32 -} - type Aggretator struct { Addr uint32 ASN uint16 diff --git a/protocols/bgp/packet/path_attributes.go b/protocols/bgp/packet/path_attributes.go index a859f4a0..fa5e9f0e 100644 --- a/protocols/bgp/packet/path_attributes.go +++ b/protocols/bgp/packet/path_attributes.go @@ -3,7 +3,6 @@ package packet import ( "bytes" "fmt" - "strconv" "strings" "github.com/taktv6/tflow2/convert" @@ -344,39 +343,6 @@ func (pa *PathAttribute) setLength(buf *bytes.Buffer) (int, error) { return bytesRead, nil } -func (pa *PathAttribute) ASPathString() (ret string) { - for _, p := range pa.Value.(ASPath) { - if p.Type == ASSet { - ret += " (" - } - n := len(p.ASNs) - for i, asn := range p.ASNs { - if i < n-1 { - ret += fmt.Sprintf("%d ", asn) - continue - } - ret += fmt.Sprintf("%d", asn) - } - if p.Type == ASSet { - ret += ")" - } - } - - return -} - -func (pa *PathAttribute) ASPathLen() (ret uint16) { - for _, p := range pa.Value.(ASPath) { - if p.Type == ASSet { - ret++ - continue - } - ret += uint16(len(p.ASNs)) - } - - return -} - func (a *PathAttribute) CommunityString() string { s := "" for _, com := range a.Value.([]uint32) { @@ -587,57 +553,6 @@ func (pa *PathAttribute) serializeLargeCommunities(buf *bytes.Buffer) uint8 { return length } -// ParseASPathStr converts an AS path from string representation info an PathAttribute object -func ParseASPathStr(asPathString string) (*PathAttribute, error) { - asPath := ASPath{} - - currentType := ASSequence - newSegmentNeeded := true - currentSegment := -1 - for _, asn := range strings.Split(asPathString, " ") { - if asn == "" { - continue - } - - if isBeginOfASSet(asn) { - currentType = ASSet - newSegmentNeeded = true - asn = strings.Replace(asn, "(", "", 1) - } - - if newSegmentNeeded { - seg := ASPathSegment{ - Type: uint8(currentType), - ASNs: make([]uint32, 0), - } - asPath = append(asPath, seg) - currentSegment++ - newSegmentNeeded = false - } - - if isEndOfASSset(asn) { - currentType = ASSequence - newSegmentNeeded = true - asn = strings.Replace(asn, ")", "", 1) - } - - numericASN, err := strconv.Atoi(asn) - if err != nil { - return nil, fmt.Errorf("Unable to convert ASN: %v", err) - } - asPath[currentSegment].ASNs = append(asPath[currentSegment].ASNs, uint32(numericASN)) - - if len(asPath[currentSegment].ASNs) == MaxASNsSegment { - newSegmentNeeded = true - } - } - - return &PathAttribute{ - TypeCode: ASPathAttr, - Value: asPath, - }, nil -} - func LargeCommunityAttributeForString(s string) (*PathAttribute, error) { strs := strings.Split(s, " ") coms := make([]LargeCommunity, len(strs)) @@ -656,14 +571,6 @@ func LargeCommunityAttributeForString(s string) (*PathAttribute, error) { }, nil } -func isBeginOfASSet(asPathPart string) bool { - return strings.Contains(asPathPart, "(") -} - -func isEndOfASSset(asPathPart string) bool { - return strings.Contains(asPathPart, ")") -} - func fourBytesToUint32(address [4]byte) uint32 { return uint32(address[0])<<24 + uint32(address[1])<<16 + uint32(address[2])<<8 + uint32(address[3]) } diff --git a/protocols/bgp/server/fsm_established.go b/protocols/bgp/server/fsm_established.go index c1507eb5..9ce739ec 100644 --- a/protocols/bgp/server/fsm_established.go +++ b/protocols/bgp/server/fsm_established.go @@ -230,8 +230,8 @@ func (s *establishedState) updates(u *packet.BGPUpdate) { case packet.NextHopAttr: path.BGPPath.NextHop = pa.Value.(uint32) case packet.ASPathAttr: - path.BGPPath.ASPath = pa.ASPathString() - path.BGPPath.ASPathLen = pa.ASPathLen() + path.BGPPath.ASPath = pa.Value.(packet.ASPath) + path.BGPPath.ASPathLen = path.BGPPath.ASPath.Length() case packet.CommunitiesAttr: path.BGPPath.Communities = pa.Value.([]uint32) case packet.LargeCommunitiesAttr: diff --git a/protocols/bgp/server/update_helper.go b/protocols/bgp/server/update_helper.go index 393df4e9..2f46e811 100644 --- a/protocols/bgp/server/update_helper.go +++ b/protocols/bgp/server/update_helper.go @@ -3,7 +3,6 @@ package server import ( "fmt" "io" - "strings" "github.com/bio-routing/bio-rd/protocols/bgp/packet" "github.com/bio-routing/bio-rd/route" @@ -11,22 +10,22 @@ import ( ) func pathAttribues(p *route.Path) (*packet.PathAttribute, error) { - asPathPA, err := packet.ParseASPathStr(strings.TrimRight(p.BGPPath.ASPath, " ")) - if err != nil { - return nil, fmt.Errorf("Unable to parse AS path: %v", err) + asPath := &packet.PathAttribute{ + TypeCode: packet.ASPathAttr, + Value: p.BGPPath.ASPath, } origin := &packet.PathAttribute{ TypeCode: packet.OriginAttr, Value: p.BGPPath.Origin, - Next: asPathPA, } + asPath.Next = origin nextHop := &packet.PathAttribute{ TypeCode: packet.NextHopAttr, Value: p.BGPPath.NextHop, } - asPathPA.Next = nextHop + origin.Next = nextHop localPref := &packet.PathAttribute{ TypeCode: packet.LocalPrefAttr, diff --git a/route/bgp.go b/route/bgp_path.go similarity index 84% rename from route/bgp.go rename to route/bgp_path.go index 3beb6b56..1222487b 100644 --- a/route/bgp.go +++ b/route/bgp_path.go @@ -3,9 +3,9 @@ package route import ( "crypto/sha256" "fmt" - "strconv" "strings" + "github.com/bio-routing/bio-rd/protocols/bgp/packet" "github.com/taktv6/tflow2/convert" ) @@ -14,7 +14,7 @@ type BGPPath struct { PathIdentifier uint32 NextHop uint32 LocalPref uint32 - ASPath string + ASPath packet.ASPath ASPathLen uint16 Origin uint8 MED uint32 @@ -155,7 +155,7 @@ func (b *BGPPath) Print() string { } 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) + ret += fmt.Sprintf("\t\tAS Path: %s\n") 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) @@ -172,16 +172,31 @@ func (b *BGPPath) Prepend(asn uint32, times uint16) { return } - asnStr := strconv.FormatUint(uint64(asn), 10) + first := b.ASPath[0] + if len(b.ASPath) == 0 || first.Type == packet.ASSet { + b.insertNewASSequence() + } + + for i := 0; i < int(times); i++ { + if len(b.ASPath) == packet.MaxASNsSegment { + b.insertNewASSequence() + } + + } + + b.ASPathLen = b.ASPath.Length() +} - path := make([]string, times+1) - for i := 0; uint16(i) < times; i++ { - path[i] = asnStr +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, } - path[times] = b.ASPath - b.ASPath = strings.TrimSuffix(strings.Join(path, " "), " ") - b.ASPathLen = b.ASPathLen + times + return pa } func (p *BGPPath) Copy() *BGPPath { diff --git a/routingtable/adjRIBIn/adj_rib_in.go b/routingtable/adjRIBIn/adj_rib_in.go index 2d850024..2cf454be 100644 --- a/routingtable/adjRIBIn/adj_rib_in.go +++ b/routingtable/adjRIBIn/adj_rib_in.go @@ -3,7 +3,6 @@ package adjRIBIn import ( "sync" - "github.com/bio-routing/bio-rd/protocols/bgp/packet" "github.com/bio-routing/bio-rd/routingtable/filter" "github.com/bio-routing/bio-rd/net" @@ -80,10 +79,7 @@ func (a *AdjRIBIn) AddPath(pfx net.Prefix, p *route.Path) error { } func (a *AdjRIBIn) ourASNsInPath(p *route.Path) bool { - // Don't accept path via iBGP which contain our ASN - ASPathAttr, _ := packet.ParseASPathStr(p.BGPPath.ASPath) - - for _, pathSegment := range ASPathAttr.Value.(packet.ASPath) { + for _, pathSegment := range p.BGPPath.ASPath { for _, asn := range pathSegment.ASNs { if a.contributingASNs.IsContributingASN(asn) { return true diff --git a/routingtable/adjRIBOut/adj_rib_out.go b/routingtable/adjRIBOut/adj_rib_out.go index 19b44b8b..088756dc 100644 --- a/routingtable/adjRIBOut/adj_rib_out.go +++ b/routingtable/adjRIBOut/adj_rib_out.go @@ -52,7 +52,7 @@ func (a *AdjRIBOut) AddPath(pfx bnet.Prefix, p *route.Path) error { p = p.Copy() if !a.neighbor.IBGP && !a.neighbor.RouteServerClient { - p.BGPPath.ASPath = fmt.Sprintf("%d %s", a.neighbor.LocalASN, p.BGPPath.ASPath) + p.BGPPath.Prepend(a.neighbor.LocalASN, 1) } if !a.neighbor.IBGP && !a.neighbor.RouteServerClient { -- GitLab