diff --git a/.travis.yml b/.travis.yml index 8b3da873949238d178b63a41de0c020068d6618e..ebeb4b25556a1350a221f804040b1d63c3125b82 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,10 @@ language: go go: - - "1.10" +- "1.9.2" +- master +before_install: +- mkdir -p $GOPATH/src/github.com/bio-routing +- ln -s $TRAVIS_BUILD_DIR $HOME/gopath/src/github.com/bio-routing/ || true +- go get github.com/mattn/goveralls +script: +- goveralls -v diff --git a/README.md b/README.md index dda57a6bb1510dc391b35056865daa93632d5886..8d1dc734f69d0e083e2147bb37d790a81fd21435 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # bio-rd [](https://travis-ci.org/bio-routing/bio-rd) -[](http://goreportcard.com/report/bio-routing/bio-rd) \ No newline at end of file +[](https://coveralls.io/github/bio-routing/bio-rd?branch=master) +[](http://goreportcard.com/report/bio-routing/bio-rd) diff --git a/config/peer.go b/config/peer.go index 8f7692b085e39fae5b1ec998233bf2d174a84581..9e057b9da60f6a33632a55bf7a3181c4a850ba70 100644 --- a/config/peer.go +++ b/config/peer.go @@ -2,6 +2,8 @@ package config import ( "net" + + "github.com/bio-routing/bio-rd/routingtable" ) type Peer struct { @@ -14,4 +16,6 @@ type Peer struct { PeerAS uint32 Passive bool RouterID uint32 + AddPathSend routingtable.ClientOptions + AddPathRecv bool } diff --git a/main.go b/main.go index 78171d7c20df8a77c4cdb95553591b4b19381c92..7e19a5aa8d1e0d982435fe12dd8229eecfbb1a35 100644 --- a/main.go +++ b/main.go @@ -10,6 +10,7 @@ import ( "github.com/bio-routing/bio-rd/config" "github.com/bio-routing/bio-rd/protocols/bgp/server" + "github.com/bio-routing/bio-rd/routingtable" "github.com/bio-routing/bio-rd/routingtable/locRIB" ) @@ -36,9 +37,12 @@ func main() { KeepAlive: 30, Passive: true, RouterID: b.RouterID(), + AddPathSend: routingtable.ClientOptions{ + MaxPaths: 10, + }, }, rib) - time.Sleep(time.Second * 30) + time.Sleep(time.Second * 15) b.AddPeer(config.Peer{ AdminEnabled: true, @@ -50,6 +54,10 @@ func main() { KeepAlive: 30, Passive: true, RouterID: b.RouterID(), + AddPathSend: routingtable.ClientOptions{ + MaxPaths: 10, + }, + AddPathRecv: true, }, rib) go func() { diff --git a/net/helper.go b/net/helper.go index efb6759637fab4d13a08b43908057226e723d511..4f7319cddfd92ef975819b143e4c03488ec22fb8 100644 --- a/net/helper.go +++ b/net/helper.go @@ -4,5 +4,5 @@ import "net" // IPv4ToUint32 converts an `net.IP` to an uint32 interpretation func IPv4ToUint32(ip net.IP) uint32 { - return uint32(ip[0]) + uint32(ip[1])<<8 + uint32(ip[2])<<16 + uint32(ip[3])<<24 + return uint32(ip[3]) + uint32(ip[2])<<8 + uint32(ip[1])<<16 + uint32(ip[0])<<24 } diff --git a/net/helper_test.go b/net/helper_test.go index 7503a6854d951e6a97bb0674945416b5bc52bc94..7a267c3c9e26715bd9b14e3579265e2057aac8db 100644 --- a/net/helper_test.go +++ b/net/helper_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" ) -func IPv4ToUint32Test(t *testing.T) { +func TestIPv4ToUint32(t *testing.T) { tests := []struct { input []byte expected uint32 diff --git a/protocols/bgp/packet/bgp.go b/protocols/bgp/packet/bgp.go index ba1d3d32206fe90680798ec1bf7338a9ee6fee22..41a2113f8e6cb85cb0250d0333908071dc03fd79 100644 --- a/protocols/bgp/packet/bgp.go +++ b/protocols/bgp/packet/bgp.go @@ -4,6 +4,7 @@ const ( OctetLen = 8 MaxASNsSegment = 255 BGP4Version = 4 + MinOpenLen = 29 MarkerLen = 16 HeaderLen = 19 @@ -76,6 +77,14 @@ const ( OtherConfigChange = 8 ConnectionCollisionResolution = 7 OutOfResoutces = 8 + + IPv4AFI = 1 + UnicastSAFI = 1 + CapabilitiesParamType = 2 + AddPathCapabilityCode = 69 + AddPathReceive = 1 + AddPathSend = 2 + AddPathSendReceive = 3 ) type BGPError struct { @@ -104,6 +113,7 @@ type BGPOpen struct { HoldTime uint16 BGPIdentifier uint32 OptParmLen uint8 + OptParams []OptParam } type BGPNotification struct { @@ -119,6 +129,14 @@ type BGPUpdate struct { NLRI *NLRI } +type BGPUpdateAddPath struct { + WithdrawnRoutesLen uint16 + WithdrawnRoutes *NLRIAddPath + TotalPathAttrLen uint16 + PathAttributes *PathAttribute + NLRI *NLRIAddPath +} + type PathAttribute struct { Length uint16 Optional bool @@ -136,6 +154,13 @@ type NLRI struct { Next *NLRI } +type NLRIAddPath struct { + PathIdentifier uint32 + IP uint32 + Pfxlen uint8 + Next *NLRIAddPath +} + type ASPath []ASPathSegment type ASPathSegment struct { Type uint8 @@ -144,6 +169,6 @@ type ASPathSegment struct { } type Aggretator struct { - Addr [4]byte + Addr uint32 ASN uint16 } diff --git a/protocols/bgp/packet/decoder.go b/protocols/bgp/packet/decoder.go index 8ba824ec9fd0620a32416bc0c66c8fd3b8d4c0ef..961789b3cfdd43b0aae606e2a693ceef88a315b9 100644 --- a/protocols/bgp/packet/decoder.go +++ b/protocols/bgp/packet/decoder.go @@ -130,6 +130,9 @@ func invalidErrCode(n *BGPNotification) (*BGPNotification, error) { func decodeOpenMsg(buf *bytes.Buffer) (*BGPOpen, error) { msg, err := _decodeOpenMsg(buf) + if err != nil { + return nil, fmt.Errorf("Unable to decode OPEN message: %v", err) + } return msg.(*BGPOpen), err } @@ -154,9 +157,115 @@ func _decodeOpenMsg(buf *bytes.Buffer) (interface{}, error) { return nil, err } + msg.OptParams, err = decodeOptParams(buf, msg.OptParmLen) + if err != nil { + return nil, fmt.Errorf("Unable to decode optional parameters: %v", err) + } + return msg, nil } +func decodeOptParams(buf *bytes.Buffer, optParmLen uint8) ([]OptParam, error) { + optParams := make([]OptParam, 0) + read := uint8(0) + for read < optParmLen { + o := OptParam{} + fields := []interface{}{ + &o.Type, + &o.Length, + } + + err := decode(buf, fields) + if err != nil { + return nil, err + } + + read += 2 + + switch o.Type { + case CapabilitiesParamType: + caps, err := decodeCapabilities(buf, o.Length) + if err != nil { + return nil, fmt.Errorf("Unable to decode capabilites: %v", err) + } + + o.Value = caps + optParams = append(optParams, o) + for _, cap := range caps { + read += cap.Length + 2 + } + default: + return nil, fmt.Errorf("Unrecognized option: %d", o.Type) + } + + } + + return optParams, nil +} + +func decodeCapabilities(buf *bytes.Buffer, length uint8) (Capabilities, error) { + ret := make(Capabilities, 0) + read := uint8(0) + for read < length { + cap, err := decodeCapability(buf) + if err != nil { + return nil, fmt.Errorf("Unable to decode capability: %v", err) + } + + ret = append(ret, cap) + read += cap.Length + 2 + } + + return ret, nil +} + +func decodeCapability(buf *bytes.Buffer) (Capability, error) { + cap := Capability{} + fields := []interface{}{ + &cap.Code, + &cap.Length, + } + + err := decode(buf, fields) + if err != nil { + return cap, err + } + + switch cap.Code { + case AddPathCapabilityCode: + addPathCap, err := decodeAddPathCapability(buf) + if err != nil { + return cap, fmt.Errorf("Unable to decode add path capability") + } + cap.Value = addPathCap + default: + for i := uint8(0); i < cap.Length; i++ { + _, err := buf.ReadByte() + if err != nil { + return cap, fmt.Errorf("Read failed: %v", err) + } + } + } + + return cap, nil +} + +func decodeAddPathCapability(buf *bytes.Buffer) (AddPathCapability, error) { + addPathCap := AddPathCapability{} + fields := []interface{}{ + &addPathCap.AFI, + &addPathCap.SAFI, + &addPathCap.SendReceive, + } + + err := decode(buf, fields) + if err != nil { + return addPathCap, err + } + + return addPathCap, nil +} + func validateOpen(msg *BGPOpen) error { if msg.Version != BGP4Version { return BGPError{ diff --git a/protocols/bgp/packet/decoder_test.go b/protocols/bgp/packet/decoder_test.go index 63b5631d7c0a4e165a2fea093edc9083a2ffdc06..01d4e01596040cdab68d7cd5abdfb30b846fe3fa 100644 --- a/protocols/bgp/packet/decoder_test.go +++ b/protocols/bgp/packet/decoder_test.go @@ -160,6 +160,7 @@ func TestDecode(t *testing.T) { HoldTime: 15, BGPIdentifier: uint32(169090600), OptParmLen: 0, + OptParams: []OptParam{}, }, }, }, @@ -706,7 +707,7 @@ func TestDecodeUpdateMsg(t *testing.T) { ExtendedLength: false, Length: 4, TypeCode: 3, - Value: [4]byte{10, 11, 12, 13}, + Value: strAddr("10.11.12.13"), }, }, }, @@ -799,7 +800,7 @@ func TestDecodeUpdateMsg(t *testing.T) { ExtendedLength: false, Length: 4, TypeCode: 3, - Value: [4]byte{10, 11, 12, 13}, + Value: strAddr("10.11.12.13"), Next: &PathAttribute{ Optional: false, Transitive: false, @@ -905,7 +906,7 @@ func TestDecodeUpdateMsg(t *testing.T) { ExtendedLength: false, Length: 4, TypeCode: 3, - Value: [4]byte{10, 11, 12, 13}, + Value: strAddr("10.11.12.13"), Next: &PathAttribute{ Optional: false, Transitive: false, @@ -1023,7 +1024,7 @@ func TestDecodeUpdateMsg(t *testing.T) { ExtendedLength: false, Length: 4, TypeCode: 3, - Value: [4]byte{10, 11, 12, 13}, + Value: strAddr("10.11.12.13"), Next: &PathAttribute{ Optional: false, Transitive: false, @@ -1157,7 +1158,7 @@ func TestDecodeUpdateMsg(t *testing.T) { ExtendedLength: false, Length: 4, TypeCode: 3, - Value: [4]byte{10, 11, 12, 13}, + Value: strAddr("10.11.12.13"), Next: &PathAttribute{ Optional: false, Transitive: false, @@ -1190,7 +1191,7 @@ func TestDecodeUpdateMsg(t *testing.T) { TypeCode: 7, Value: Aggretator{ ASN: uint16(258), - Addr: [4]byte{10, 11, 12, 13}, + Addr: strAddr("10.11.12.13"), }, }, }, @@ -1201,7 +1202,7 @@ func TestDecodeUpdateMsg(t *testing.T) { }, NLRI: &NLRI{ Pfxlen: 8, - IP: strAddr("1.0.0.0"), + IP: strAddr("11.0.0.0"), }, }, }, @@ -1266,7 +1267,7 @@ func TestDecodeUpdateMsg(t *testing.T) { continue } - assert.Equal(t, test.expected, msg) + assert.Equalf(t, test.expected, msg, "%d", test.testNum) } } @@ -1313,6 +1314,7 @@ func TestDecodeOpenMsg(t *testing.T) { HoldTime: 15, BGPIdentifier: 169090600, OptParmLen: 0, + OptParams: make([]OptParam, 0), }, }, { @@ -1452,7 +1454,7 @@ func genericTest(f decodeFunc, tests []test, t *testing.T) { continue } - assert.Equal(t, test.expected, msg) + assert.Equalf(t, test.expected, msg, "%d", test.testNum) } } @@ -1536,6 +1538,159 @@ func TestValidateOpenMessage(t *testing.T) { } } +func TestDecodeOptParams(t *testing.T) { + tests := []struct { + name string + input []byte + wantFail bool + expected []OptParam + }{ + { + name: "Add path capability", + input: []byte{ + 2, // Type + 6, // Length + 69, // Code + 4, // Length + 0, 1, // AFI + 1, // SAFI + 3, // Send/Receive + }, + wantFail: false, + expected: []OptParam{ + { + Type: 2, + Length: 6, + Value: Capabilities{ + { + Code: 69, + Length: 4, + Value: AddPathCapability{ + AFI: 1, + SAFI: 1, + SendReceive: 3, + }, + }, + }, + }, + }, + }, + } + + for _, test := range tests { + buf := bytes.NewBuffer(test.input) + res, err := decodeOptParams(buf, uint8(len(test.input))) + if err != nil { + if test.wantFail { + continue + } + + t.Errorf("Unexpected failure for test %q: %v", test.name, err) + continue + } + + if test.wantFail { + t.Errorf("Unexpected success for test %q", test.name) + continue + } + + assert.Equal(t, test.expected, res) + } +} + +func TestDecodeCapability(t *testing.T) { + tests := []struct { + name string + input []byte + expected Capability + wantFail bool + }{ + { + name: "Add Path", + input: []byte{69, 4, 0, 1, 1, 3}, + expected: Capability{ + Code: 69, + Length: 4, + Value: AddPathCapability{ + AFI: 1, + SAFI: 1, + SendReceive: 3, + }, + }, + wantFail: false, + }, + { + name: "Fail", + input: []byte{69, 4, 0, 1}, + wantFail: true, + }, + } + + for _, test := range tests { + cap, err := decodeCapability(bytes.NewBuffer(test.input)) + if err != nil { + if test.wantFail { + continue + } + + t.Errorf("Unexpected failure for test %q: %v", test.name, err) + continue + } + + if test.wantFail { + t.Errorf("Unexpected success for test %q", err) + continue + } + + assert.Equal(t, test.expected, cap) + } +} + +func TestDecodeAddPathCapability(t *testing.T) { + tests := []struct { + name string + input []byte + expected AddPathCapability + wantFail bool + }{ + { + name: "ok", + input: []byte{0, 1, 1, 3}, + wantFail: false, + expected: AddPathCapability{ + AFI: 1, + SAFI: 1, + SendReceive: 3, + }, + }, + { + name: "Incomplete", + input: []byte{0, 1, 1}, + wantFail: true, + }, + } + + for _, test := range tests { + buf := bytes.NewBuffer(test.input) + cap, err := decodeAddPathCapability(buf) + if err != nil { + if test.wantFail { + continue + } + + t.Errorf("Unexpected failure for test %q: %v", test.name, err) + continue + } + + if test.wantFail { + t.Errorf("Unexpected success for test %q", test.name) + continue + } + + assert.Equal(t, test.expected, cap) + } +} + func strAddr(s string) uint32 { ret, _ := net.StrToAddr(s) return ret diff --git a/protocols/bgp/packet/encoder.go b/protocols/bgp/packet/encoder.go index 3cfe702d14ffb66605919fe60839d98a8308b761..ea87d1ff64cfc946688e738ae9f7ffa372cf10c7 100644 --- a/protocols/bgp/packet/encoder.go +++ b/protocols/bgp/packet/encoder.go @@ -26,7 +26,11 @@ func SerializeNotificationMsg(msg *BGPNotification) []byte { } func SerializeOpenMsg(msg *BGPOpen) []byte { - openLen := uint16(29) + optParmsBuf := bytes.NewBuffer(make([]byte, 0)) + serializeOptParams(optParmsBuf, msg.OptParams) + optParms := optParmsBuf.Bytes() + openLen := uint16(len(optParms) + MinOpenLen) + buf := bytes.NewBuffer(make([]byte, 0, openLen)) serializeHeader(buf, openLen, OpenMsg) @@ -34,17 +38,90 @@ func SerializeOpenMsg(msg *BGPOpen) []byte { buf.Write(convert.Uint16Byte(msg.AS)) buf.Write(convert.Uint16Byte(msg.HoldTime)) buf.Write(convert.Uint32Byte(msg.BGPIdentifier)) - buf.WriteByte(uint8(0)) + + buf.WriteByte(uint8(len(optParms))) + buf.Write(optParms) return buf.Bytes() } +func serializeOptParams(buf *bytes.Buffer, params []OptParam) { + for _, param := range params { + tmpBuf := bytes.NewBuffer(make([]byte, 0)) + param.Value.serialize(tmpBuf) + payload := tmpBuf.Bytes() + + buf.WriteByte(param.Type) + buf.WriteByte(uint8(len(payload))) + buf.Write(payload) + } +} + func serializeHeader(buf *bytes.Buffer, length uint16, typ uint8) { buf.Write([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}) buf.Write(convert.Uint16Byte(length)) buf.WriteByte(typ) } +func (b *BGPUpdateAddPath) SerializeUpdate() ([]byte, error) { + budget := MaxLen - MinLen + buf := bytes.NewBuffer(nil) + + withdrawBuf := bytes.NewBuffer(nil) + for withdraw := b.WithdrawnRoutes; withdraw != nil; withdraw = withdraw.Next { + nlriLen := int(withdraw.serialize(withdrawBuf)) + budget -= nlriLen + if budget < 0 { + return nil, fmt.Errorf("update too long") + } + } + + pathAttributesBuf := bytes.NewBuffer(nil) + for pa := b.PathAttributes; pa != nil; pa = pa.Next { + paLen := int(pa.serialize(pathAttributesBuf)) + budget -= paLen + if budget < 0 { + return nil, fmt.Errorf("update too long") + } + } + + nlriBuf := bytes.NewBuffer(nil) + for nlri := b.NLRI; nlri != nil; nlri = nlri.Next { + nlriLen := int(nlri.serialize(nlriBuf)) + budget -= nlriLen + if budget < 0 { + return nil, fmt.Errorf("update too long") + } + } + + withdrawnRoutesLen := withdrawBuf.Len() + if withdrawnRoutesLen > 65535 { + return nil, fmt.Errorf("Invalid Withdrawn Routes Length: %d", withdrawnRoutesLen) + } + + totalPathAttributesLen := pathAttributesBuf.Len() + if totalPathAttributesLen > 65535 { + return nil, fmt.Errorf("Invalid Total Path Attribute Length: %d", totalPathAttributesLen) + } + + totalLength := 2 + withdrawnRoutesLen + totalPathAttributesLen + 2 + nlriBuf.Len() + 19 + if totalLength > 4096 { + return nil, fmt.Errorf("Update too long: %d bytes", totalLength) + } + + serializeHeader(buf, uint16(totalLength), UpdateMsg) + + buf.Write(convert.Uint16Byte(uint16(withdrawnRoutesLen))) + buf.Write(withdrawBuf.Bytes()) + + buf.Write(convert.Uint16Byte(uint16(totalPathAttributesLen))) + buf.Write(pathAttributesBuf.Bytes()) + + buf.Write(nlriBuf.Bytes()) + + return buf.Bytes(), nil +} + func (b *BGPUpdate) SerializeUpdate() ([]byte, error) { budget := MaxLen - MinLen buf := bytes.NewBuffer(nil) diff --git a/protocols/bgp/packet/encoder_test.go b/protocols/bgp/packet/encoder_test.go index eccfdfdcace6be4eeac998bdbcaa29749d0a2581..0d4f70a3483dabd8f7332dd148c72b09df626dee 100644 --- a/protocols/bgp/packet/encoder_test.go +++ b/protocols/bgp/packet/encoder_test.go @@ -94,6 +94,45 @@ func TestSerializeOpenMsg(t *testing.T) { } } +func TestSerializeOptParams(t *testing.T) { + tests := []struct { + name string + optParams []OptParam + expected []byte + }{ + { + name: "empty", + optParams: []OptParam{}, + expected: []byte{}, + }, + { + name: "1 Option", + optParams: []OptParam{ + { + Type: 2, + Length: 6, + Value: Capability{ + Code: 69, + Length: 4, + Value: AddPathCapability{ + AFI: 1, + SAFI: 1, + SendReceive: 3, + }, + }, + }, + }, + expected: []byte{2, 6, 69, 4, 0, 1, 1, 3}, + }, + } + + for _, test := range tests { + buf := bytes.NewBuffer(make([]byte, 0)) + serializeOptParams(buf, test.optParams) + assert.Equal(t, test.expected, buf.Bytes()) + } +} + func TestSerializeHeader(t *testing.T) { tests := []struct { name string diff --git a/protocols/bgp/packet/nlri.go b/protocols/bgp/packet/nlri.go index 05fecbff1a4ccf8441306ae340d88ed170cdb409..6de92a6cd59ff167d87efbaf5d197fb46c00aaca 100644 --- a/protocols/bgp/packet/nlri.go +++ b/protocols/bgp/packet/nlri.go @@ -73,6 +73,19 @@ func (n *NLRI) serialize(buf *bytes.Buffer) uint8 { return nBytes + 1 } +func (n *NLRIAddPath) serialize(buf *bytes.Buffer) uint8 { + a := convert.Uint32Byte(n.IP) + + addr := [4]byte{a[0], a[1], a[2], a[3]} + nBytes := bytesInAddr(n.Pfxlen) + + buf.Write(convert.Uint32Byte(n.PathIdentifier)) + buf.WriteByte(n.Pfxlen) + buf.Write(addr[:nBytes]) + + return nBytes + 1 +} + func bytesInAddr(pfxlen uint8) uint8 { return uint8(math.Ceil(float64(pfxlen) / 8)) } diff --git a/protocols/bgp/packet/nlri_test.go b/protocols/bgp/packet/nlri_test.go index b97509b87325ccfe13c04fbb9caacaf76b080491..17a17dd3bf5ae997fa4676de27a5db5a4376907b 100644 --- a/protocols/bgp/packet/nlri_test.go +++ b/protocols/bgp/packet/nlri_test.go @@ -208,3 +208,46 @@ func TestNLRISerialize(t *testing.T) { assert.Equal(t, test.expected, res) } } + +func TestNLRIAddPathSerialize(t *testing.T) { + tests := []struct { + name string + nlri *NLRIAddPath + expected []byte + }{ + { + name: "Test #1", + nlri: &NLRIAddPath{ + PathIdentifier: 100, + IP: strAddr("1.2.3.0"), + Pfxlen: 25, + }, + expected: []byte{0, 0, 0, 100, 25, 1, 2, 3, 0}, + }, + { + name: "Test #2", + nlri: &NLRIAddPath{ + PathIdentifier: 100, + IP: strAddr("1.2.3.0"), + Pfxlen: 24, + }, + expected: []byte{0, 0, 0, 100, 24, 1, 2, 3}, + }, + { + name: "Test #3", + nlri: &NLRIAddPath{ + PathIdentifier: 100, + IP: strAddr("100.200.128.0"), + Pfxlen: 17, + }, + expected: []byte{0, 0, 0, 100, 17, 100, 200, 128}, + }, + } + + for _, test := range tests { + buf := bytes.NewBuffer(nil) + test.nlri.serialize(buf) + res := buf.Bytes() + assert.Equal(t, test.expected, res) + } +} diff --git a/protocols/bgp/packet/parameters.go b/protocols/bgp/packet/parameters.go new file mode 100644 index 0000000000000000000000000000000000000000..8edf42fc58e05bb3b73cacd4272012844bedcd45 --- /dev/null +++ b/protocols/bgp/packet/parameters.go @@ -0,0 +1,54 @@ +package packet + +import ( + "bytes" + + "github.com/taktv6/tflow2/convert" +) + +type Serializable interface { + serialize(*bytes.Buffer) +} + +type OptParam struct { + Type uint8 + Length uint8 + Value Serializable +} + +type Capabilities []Capability + +type Capability struct { + Code uint8 + Length uint8 + Value Serializable +} + +func (c Capabilities) serialize(buf *bytes.Buffer) { + tmpBuf := bytes.NewBuffer(make([]byte, 0)) + for _, cap := range c { + cap.serialize(tmpBuf) + } +} + +func (c Capability) serialize(buf *bytes.Buffer) { + tmpBuf := bytes.NewBuffer(make([]byte, 0)) + c.Value.serialize(tmpBuf) + payload := tmpBuf.Bytes() + + buf.WriteByte(c.Code) + buf.WriteByte(uint8(len(payload))) + buf.Write(payload) +} + +type AddPathCapability struct { + AFI uint16 + SAFI uint8 + SendReceive uint8 +} + +func (a AddPathCapability) serialize(buf *bytes.Buffer) { + buf.Write(convert.Uint16Byte(a.AFI)) + buf.WriteByte(a.SAFI) + buf.WriteByte(a.SendReceive) +} diff --git a/protocols/bgp/packet/path_attributes.go b/protocols/bgp/packet/path_attributes.go index c305ec27a45b899cad0b9aeeba44a23d690d412f..0390b6617944b5ea1933b542b97c29ac069c52c6 100644 --- a/protocols/bgp/packet/path_attributes.go +++ b/protocols/bgp/packet/path_attributes.go @@ -186,24 +186,27 @@ func (pa *PathAttribute) decodeLocalPref(buf *bytes.Buffer) error { func (pa *PathAttribute) decodeAggregator(buf *bytes.Buffer) error { aggr := Aggretator{} - p := uint16(0) + err := decode(buf, []interface{}{&aggr.ASN}) if err != nil { return err } p += 2 - n, err := buf.Read(aggr.Addr[:]) + addr := [4]byte{} + n, err := buf.Read(addr[:]) if err != nil { return err } if n != 4 { - return fmt.Errorf("Unable to read aggregator IP: buf.Read read %d bytes", n) + return fmt.Errorf("Unable to read next hop: buf.Read read %d bytes", n) } - p += 4 + aggr.Addr = fourBytesToUint32(addr) pa.Value = aggr + p += 4 + return dumpNBytes(buf, pa.Length-p) } diff --git a/protocols/bgp/packet/path_attributes_test.go b/protocols/bgp/packet/path_attributes_test.go index e413d4f88f93a66dccca5b1d1444dbf3f64dff7d..15f78fe39a763b86eb31281cbee5e30e54a84585 100644 --- a/protocols/bgp/packet/path_attributes_test.go +++ b/protocols/bgp/packet/path_attributes_test.go @@ -34,7 +34,7 @@ func TestDecodePathAttrs(t *testing.T) { Next: &PathAttribute{ TypeCode: 3, Length: 4, - Value: [4]byte{10, 20, 30, 40}, + Value: strAddr("10.20.30.40"), }, }, }, @@ -62,7 +62,7 @@ func TestDecodePathAttrs(t *testing.T) { continue } - assert.Equal(t, test.expected, res) + assert.Equalf(t, test.expected, res, "%s", test.name) } } @@ -367,9 +367,7 @@ func TestDecodeNextHop(t *testing.T) { wantFail: false, expected: &PathAttribute{ Length: 4, - Value: [4]byte{ - 10, 20, 30, 40, - }, + Value: strAddr("10.20.30.40"), }, }, { @@ -538,7 +536,7 @@ func TestDecodeAggregator(t *testing.T) { Length: 6, Value: Aggretator{ ASN: 222, - Addr: [4]byte{10, 20, 30, 40}, + Addr: strAddr("10.20.30.40"), }, }, }, @@ -892,9 +890,9 @@ func TestSerializeNextHop(t *testing.T) { name: "Test #1", input: &PathAttribute{ TypeCode: NextHopAttr, - Value: [4]byte{100, 110, 120, 130}, + Value: strAddr("100.110.120.130"), }, - expected: []byte{0, 3, 4, 100, 110, 120, 130}, + expected: []byte{64, 3, 4, 100, 110, 120, 130}, expectedLen: 7, }, } @@ -1186,7 +1184,7 @@ func TestSerialize(t *testing.T) { }, Next: &PathAttribute{ TypeCode: NextHopAttr, - Value: [4]byte{10, 20, 30, 40}, + Value: strAddr("10.20.30.40"), Next: &PathAttribute{ TypeCode: MEDAttr, Value: uint32(100), @@ -1216,7 +1214,7 @@ func TestSerialize(t *testing.T) { }, expected: []byte{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0, 85, // Length + 0, 86, // Length 2, // Msg Type // Withdraws @@ -1224,7 +1222,7 @@ func TestSerialize(t *testing.T) { 8, 10, // Withdraw 10/8 16, 192, 168, // Withdraw 192.168/16 - 0, 49, // Total Path Attribute Length + 0, 50, // Total Path Attribute Length // ORIGIN 64, // Attr. Flags @@ -1234,6 +1232,7 @@ func TestSerialize(t *testing.T) { // ASPath 64, // Attr. Flags 2, // Attr. Type Code + 14, // Attr. Length 2, // Path Segment Type = AS_SEQUENCE 3, // Path Segment Length 0, 100, 0, 155, 0, 200, // ASNs @@ -1288,7 +1287,7 @@ func TestSerialize(t *testing.T) { continue } - assert.Equal(t, test.expected, res) + assert.Equalf(t, test.expected, res, "%s", test.name) } } diff --git a/protocols/bgp/server/fsm.go b/protocols/bgp/server/fsm.go index 051eaf03cd24f5d6c176935c7c288a1fe1e7c0f0..c53696fb5e6895c165e56f75d38a3e441fd9449e 100644 --- a/protocols/bgp/server/fsm.go +++ b/protocols/bgp/server/fsm.go @@ -15,6 +15,7 @@ import ( "github.com/bio-routing/bio-rd/route" "github.com/bio-routing/bio-rd/routingtable/adjRIBIn" "github.com/bio-routing/bio-rd/routingtable/adjRIBOut" + "github.com/bio-routing/bio-rd/routingtable/adjRIBOutAddPath" "github.com/bio-routing/bio-rd/routingtable/locRIB" log "github.com/sirupsen/logrus" tomb "gopkg.in/tomb.v2" @@ -46,6 +47,8 @@ const ( ) type FSM struct { + peer *Peer + t tomb.Tomb stateReason string state int @@ -88,9 +91,12 @@ type FSM struct { stopMsgRecvCh chan struct{} adjRIBIn *adjRIBIn.AdjRIBIn - adjRIBOut *adjRIBOut.AdjRIBOut + adjRIBOut routingtable.RouteTableClient rib *locRIB.LocRIB - updateSender *UpdateSender + updateSender routingtable.RouteTableClient + + capAddPathSend bool + capAddPathRecv bool } type msgRecvMsg struct { @@ -103,8 +109,9 @@ type msgRecvErr struct { con *net.TCPConn } -func NewFSM(c config.Peer, rib *locRIB.LocRIB) *FSM { +func NewFSM(peer *Peer, c config.Peer, rib *locRIB.LocRIB) *FSM { fsm := &FSM{ + peer: peer, state: Idle, passive: true, connectRetryTime: 5, @@ -131,7 +138,6 @@ func NewFSM(c config.Peer, rib *locRIB.LocRIB) *FSM { rib: rib, } - fsm.updateSender = newUpdateSender(fsm) return fsm } @@ -454,6 +460,9 @@ func (fsm *FSM) openSent() int { fsm.keepaliveTime = fsm.holdTime / 3 fsm.keepaliveTimer.Reset(time.Second * fsm.keepaliveTime) } + + fsm.processOpenOptions(openMsg.OptParams) + return fsm.changeState(OpenConfirm, "Received OPEN message") default: sendNotification(fsm.con, packet.FiniteStateMachineError, 0) @@ -480,6 +489,56 @@ func (fsm *FSM) openSent() int { } } +func (fsm *FSM) processOpenOptions(optParams []packet.OptParam) { + for _, optParam := range optParams { + if optParam.Type != packet.CapabilitiesParamType { + continue + } + + fsm.processCapabilities(optParam.Value.(packet.Capabilities)) + } +} + +func (fsm *FSM) processCapabilities(caps packet.Capabilities) { + for _, cap := range caps { + fsm.processCapability(cap) + } +} + +func (fsm *FSM) processCapability(cap packet.Capability) { + switch cap.Code { + case packet.AddPathCapabilityCode: + fsm.processAddPathCapability(cap.Value.(packet.AddPathCapability)) + + } +} + +func (fsm *FSM) processAddPathCapability(addPathCap packet.AddPathCapability) { + if addPathCap.AFI != 1 { + return + } + if addPathCap.SAFI != 1 { + return + } + switch addPathCap.SendReceive { + case packet.AddPathReceive: + if !fsm.peer.addPathSend.BestOnly { + fsm.capAddPathSend = true + } + case packet.AddPathSend: + if fsm.peer.addPathRecv { + fsm.capAddPathRecv = true + } + case packet.AddPathSendReceive: + if !fsm.peer.addPathSend.BestOnly { + fsm.capAddPathSend = true + } + if fsm.peer.addPathRecv { + fsm.capAddPathRecv = true + } + } +} + func (fsm *FSM) openSentTCPFail(err error) int { fsm.con.Close() fsm.resetConnectRetryTimer() @@ -602,7 +661,7 @@ func (fsm *FSM) openConfirm() int { switch msg.Header.Type { case packet.NotificationMsg: - nMsg := msg.Body.(packet.BGPNotification) + nMsg := msg.Body.(*packet.BGPNotification) if nMsg.ErrorCode == packet.UnsupportedVersionNumber { stopTimer(fsm.connectRetryTimer) fsm.con.Close() @@ -664,18 +723,30 @@ func (fsm *FSM) established() int { Type: route.BGPPathType, Address: tnet.IPv4ToUint32(fsm.remote), } - fsm.adjRIBOut = adjRIBOut.New(n) - fsm.adjRIBOut.Register(fsm.updateSender) - fsm.rib.RegisterWithOptions(fsm.adjRIBOut, routingtable.ClientOptions{BestOnly: true}) + clientOptions := routingtable.ClientOptions{} + if fsm.capAddPathSend { + fsm.updateSender = newUpdateSenderAddPath(fsm) + fsm.adjRIBOut = adjRIBOutAddPath.New(n) + clientOptions = fsm.peer.addPathSend + } else { + fsm.updateSender = newUpdateSender(fsm) + fsm.adjRIBOut = adjRIBOut.New(n) + } + + fsm.adjRIBOut.Register(fsm.updateSender) + fsm.rib.RegisterWithOptions(fsm.adjRIBOut, clientOptions) - go func() { + /*go func() { for { + if fsm.adjRIBOut == nil { + return + } fmt.Printf("ADJ-RIB-OUT: %s\n", fsm.remote.String()) fmt.Print(fsm.adjRIBOut.Print()) time.Sleep(time.Second * 11) } - }() + }()*/ for { select { @@ -751,8 +822,10 @@ func (fsm *FSM) established() int { fmt.Printf("LPM: Adding prefix %s\n", pfx.String()) path := &route.Path{ - Type: route.BGPPathType, - BGPPath: &route.BGPPath{}, + Type: route.BGPPathType, + BGPPath: &route.BGPPath{ + Source: tnet.IPv4ToUint32(fsm.remote), + }, } for pa := u.PathAttributes; pa != nil; pa = pa.Next { @@ -860,7 +933,7 @@ func (fsm *FSM) sendOpen(c *net.TCPConn) error { AS: fsm.localASN, HoldTime: uint16(fsm.holdTimeConfigured), BGPIdentifier: fsm.routerID, - OptParmLen: 0, + OptParams: fsm.peer.optOpenParams, }) _, err := c.Write(msg) diff --git a/protocols/bgp/server/peer.go b/protocols/bgp/server/peer.go index 5c65732b6a3247ecf88b833c1626a2cba96b2f43..7bfcbc560181663fec221f76ada98d00ef29e517 100644 --- a/protocols/bgp/server/peer.go +++ b/protocols/bgp/server/peer.go @@ -3,26 +3,63 @@ package server import ( "net" + "github.com/bio-routing/bio-rd/protocols/bgp/packet" + "github.com/bio-routing/bio-rd/routingtable" "github.com/bio-routing/bio-rd/routingtable/locRIB" "github.com/bio-routing/bio-rd/config" ) type Peer struct { - addr net.IP - asn uint32 - fsm *FSM - rib *locRIB.LocRIB - routerID uint32 + addr net.IP + asn uint32 + fsm *FSM + rib *locRIB.LocRIB + routerID uint32 + addPathSend routingtable.ClientOptions + addPathRecv bool + optOpenParams []packet.OptParam } func NewPeer(c config.Peer, rib *locRIB.LocRIB) (*Peer, error) { p := &Peer{ - addr: c.PeerAddress, - asn: c.PeerAS, - fsm: NewFSM(c, rib), - rib: rib, + addr: c.PeerAddress, + asn: c.PeerAS, + rib: rib, + addPathSend: c.AddPathSend, + addPathRecv: c.AddPathRecv, + optOpenParams: make([]packet.OptParam, 0), } + p.fsm = NewFSM(p, c, rib) + + caps := make([]packet.Capability, 0) + + addPath := uint8(0) + if c.AddPathRecv { + addPath += packet.AddPathReceive + } + if !c.AddPathSend.BestOnly { + addPath += packet.AddPathSend + } + + if addPath > 0 { + caps = append(caps, packet.Capability{ + Code: packet.AddPathCapabilityCode, + Value: packet.AddPathCapability{ + AFI: packet.IPv4AFI, + SAFI: packet.UnicastSAFI, + SendReceive: addPath, + }, + }) + } + + for _, cap := range caps { + p.optOpenParams = append(p.optOpenParams, packet.OptParam{ + Type: packet.CapabilitiesParamType, + Value: cap, + }) + } + return p, nil } diff --git a/protocols/bgp/server/update_sender.go b/protocols/bgp/server/update_sender.go index 329e97138f449f1859c5b691f9add50392880dc1..95dded6f74ce1c095301026a7b00c2b48f99beb9 100644 --- a/protocols/bgp/server/update_sender.go +++ b/protocols/bgp/server/update_sender.go @@ -11,7 +11,9 @@ import ( "github.com/bio-routing/bio-rd/routingtable" ) +// UpdateSender converts table changes into BGP update messages type UpdateSender struct { + routingtable.ClientManager fsm *FSM } @@ -21,8 +23,8 @@ func newUpdateSender(fsm *FSM) *UpdateSender { } } +// AddPath serializes a new path and sends out a BGP update message func (u *UpdateSender) AddPath(pfx net.Prefix, p *route.Path) error { - fmt.Printf("SENDING AN BGP UPDATE\n") asPathPA, err := packet.ParseASPathStr(fmt.Sprintf("%d %s", u.fsm.localASN, p.BGPPath.ASPath)) if err != nil { return fmt.Errorf("Unable to parse AS path: %v", err) @@ -52,7 +54,7 @@ func (u *UpdateSender) AddPath(pfx net.Prefix, p *route.Path) error { log.Errorf("Unable to serialize BGP Update: %v", err) return nil } - fmt.Printf("Sending Update: %v\n", updateBytes) + _, err = u.fsm.con.Write(updateBytes) if err != nil { return fmt.Errorf("Failed sending Update: %v", err) @@ -60,12 +62,14 @@ func (u *UpdateSender) AddPath(pfx net.Prefix, p *route.Path) error { return nil } +// RemovePath withdraws prefix `pfx` from a peer func (u *UpdateSender) RemovePath(pfx net.Prefix, p *route.Path) bool { log.Warningf("BGP Update Sender: RemovePath not implemented") return false } +// UpdateNewClient does nothing func (u *UpdateSender) UpdateNewClient(client routingtable.RouteTableClient) error { - log.Warningf("BGP Update Sender: RemovePath not implemented") + log.Warningf("BGP Update Sender: UpdateNewClient() not supported") return nil } diff --git a/protocols/bgp/server/update_sender_add_path.go b/protocols/bgp/server/update_sender_add_path.go new file mode 100644 index 0000000000000000000000000000000000000000..c4fe7de5f145a256eedab2c980e3ee82418b1898 --- /dev/null +++ b/protocols/bgp/server/update_sender_add_path.go @@ -0,0 +1,76 @@ +package server + +import ( + "fmt" + + log "github.com/sirupsen/logrus" + + "github.com/bio-routing/bio-rd/net" + "github.com/bio-routing/bio-rd/protocols/bgp/packet" + "github.com/bio-routing/bio-rd/route" + "github.com/bio-routing/bio-rd/routingtable" +) + +// UpdateSenderAddPath converts table changes into BGP update messages with add path +type UpdateSenderAddPath struct { + routingtable.ClientManager + fsm *FSM +} + +func newUpdateSenderAddPath(fsm *FSM) *UpdateSenderAddPath { + return &UpdateSenderAddPath{ + fsm: fsm, + } +} + +// AddPath serializes a new path and sends out a BGP update message +func (u *UpdateSenderAddPath) AddPath(pfx net.Prefix, p *route.Path) error { + asPathPA, err := packet.ParseASPathStr(fmt.Sprintf("%d %s", u.fsm.localASN, p.BGPPath.ASPath)) + if err != nil { + return fmt.Errorf("Unable to parse AS path: %v", err) + } + + update := &packet.BGPUpdateAddPath{ + PathAttributes: &packet.PathAttribute{ + TypeCode: packet.OriginAttr, + Value: p.BGPPath.Origin, + Next: &packet.PathAttribute{ + TypeCode: packet.ASPathAttr, + Value: asPathPA.Value, + Next: &packet.PathAttribute{ + TypeCode: packet.NextHopAttr, + Value: p.BGPPath.NextHop, + }, + }, + }, + NLRI: &packet.NLRIAddPath{ + PathIdentifier: p.BGPPath.PathIdentifier, + IP: pfx.Addr(), + Pfxlen: pfx.Pfxlen(), + }, + } + + updateBytes, err := update.SerializeUpdate() + if err != nil { + log.Errorf("Unable to serialize BGP Update: %v", err) + return nil + } + + _, err = u.fsm.con.Write(updateBytes) + if err != nil { + return fmt.Errorf("Failed sending Update: %v", err) + } + return nil +} + +// RemovePath withdraws prefix `pfx` from a peer +func (u *UpdateSenderAddPath) RemovePath(pfx net.Prefix, p *route.Path) bool { + log.Warningf("BGP Update Sender: RemovePath not implemented") + return false +} + +// UpdateNewClient does nothing +func (u *UpdateSenderAddPath) UpdateNewClient(client routingtable.RouteTableClient) error { + log.Warningf("BGP Update Sender: RemovePath not implemented") + return nil +} diff --git a/routingtable/adjRIBIn/adj_rib_in_test.go b/routingtable/adjRIBIn/adj_rib_in_test.go index a458dc780c9320e2c5d57676ec272489b1dcddd5..5659ab805f73b3bf888a08fa8ff6a7dbe8185bdf 100644 --- a/routingtable/adjRIBIn/adj_rib_in_test.go +++ b/routingtable/adjRIBIn/adj_rib_in_test.go @@ -30,6 +30,14 @@ func (m *RTMockClient) UpdateNewClient(client routingtable.RouteTableClient) err return fmt.Errorf("Not implemented") } +func (m *RTMockClient) Register(routingtable.RouteTableClient) { + return +} + +func (m *RTMockClient) Unregister(routingtable.RouteTableClient) { + return +} + // RemovePath removes the path for prefix `pfx` func (m *RTMockClient) RemovePath(pfx net.Prefix, p *route.Path) bool { m.removePathParams.pfx = pfx diff --git a/routingtable/adjRIBOut/adj_rib_out.go b/routingtable/adjRIBOut/adj_rib_out.go index 8691c5ac87f473946225a35a5fce4823a482c6a0..1ddd93c6e05b835c9952b6e86ba5fe57545ed5e4 100644 --- a/routingtable/adjRIBOut/adj_rib_out.go +++ b/routingtable/adjRIBOut/adj_rib_out.go @@ -29,7 +29,7 @@ func New(neighbor *routingtable.Neighbor) *AdjRIBOut { // UpdateNewClient sends current state to a new client func (a *AdjRIBOut) UpdateNewClient(client routingtable.RouteTableClient) error { - return fmt.Errorf("Not supported") + return nil } // AddPath replaces the path for prefix `pfx`. If the prefix doesn't exist it is added. diff --git a/routingtable/adjRIBOutAddPath/adj_rib_out_add_path.go b/routingtable/adjRIBOutAddPath/adj_rib_out_add_path.go new file mode 100644 index 0000000000000000000000000000000000000000..07b702db3360040de4c4d190a16fc4cabfdb2a38 --- /dev/null +++ b/routingtable/adjRIBOutAddPath/adj_rib_out_add_path.go @@ -0,0 +1,104 @@ +package adjRIBOutAddPath + +import ( + "fmt" + "sync" + + "github.com/bio-routing/bio-rd/net" + "github.com/bio-routing/bio-rd/route" + "github.com/bio-routing/bio-rd/routingtable" +) + +// AdjRIBOutAddPath represents an Adjacency RIB Out with BGP add path +type AdjRIBOutAddPath struct { + routingtable.ClientManager + rt *routingtable.RoutingTable + neighbor *routingtable.Neighbor + mu sync.RWMutex +} + +// New creates a new Adjacency RIB Out with BGP add path +func New(neighbor *routingtable.Neighbor) *AdjRIBOutAddPath { + a := &AdjRIBOutAddPath{ + rt: routingtable.NewRoutingTable(), + neighbor: neighbor, + } + a.ClientManager = routingtable.NewClientManager(a) + return a +} + +// UpdateNewClient sends current state to a new client +func (a *AdjRIBOutAddPath) UpdateNewClient(client routingtable.RouteTableClient) error { + return nil +} + +// AddPath adds path p to prefix `pfx` +func (a *AdjRIBOutAddPath) AddPath(pfx net.Prefix, p *route.Path) error { + if a.isOwnPath(p) { + return nil + } + + a.mu.Lock() + defer a.mu.Unlock() + + p.BGPPath.PathIdentifier = 7 + + a.rt.AddPath(pfx, p) + + for _, client := range a.ClientManager.Clients() { + client.AddPath(pfx, p) + } + return nil +} + +// RemovePath removes the path for prefix `pfx` +func (a *AdjRIBOutAddPath) RemovePath(pfx net.Prefix, p *route.Path) bool { + if a.isOwnPath(p) { + return false + } + + a.mu.Lock() + defer a.mu.Unlock() + + r := a.rt.Get(pfx) + if r == nil { + return false + } + + a.rt.RemovePath(pfx, p) + a.removePathFromClients(pfx, p) + return true +} + +func (a *AdjRIBOutAddPath) isOwnPath(p *route.Path) bool { + if p.Type != a.neighbor.Type { + return false + } + + switch p.Type { + case route.BGPPathType: + return p.BGPPath.Source == a.neighbor.Address + } + + return false +} + +func (a *AdjRIBOutAddPath) removePathFromClients(pfx net.Prefix, path *route.Path) { + for _, client := range a.ClientManager.Clients() { + client.RemovePath(pfx, path) + } +} + +// Print dumps all prefixes in the Adj-RIB +func (a *AdjRIBOutAddPath) Print() string { + a.mu.RLock() + defer a.mu.RUnlock() + + ret := fmt.Sprintf("DUMPING ADJ-RIB-OUT:\n") + routes := a.rt.Dump() + for _, r := range routes { + ret += fmt.Sprintf("%s\n", r.Prefix().String()) + } + + return ret +} diff --git a/routingtable/client_interface.go b/routingtable/client_interface.go index 63ba81e8d5afa4fb73b0989b2ae519000e56a6b5..0800ceec8db1cb3b758b74b3a1d3c8b7aef62acb 100644 --- a/routingtable/client_interface.go +++ b/routingtable/client_interface.go @@ -10,4 +10,6 @@ type RouteTableClient interface { AddPath(net.Prefix, *route.Path) error RemovePath(net.Prefix, *route.Path) bool UpdateNewClient(RouteTableClient) error + Register(RouteTableClient) + Unregister(RouteTableClient) } diff --git a/routingtable/client_manager_test.go b/routingtable/client_manager_test.go index 674a9a4ebd8ed8b0a691db6613eb4a931a606838..af2507855bfac8a5d09551b105d7bfc4ae93dd79 100644 --- a/routingtable/client_manager_test.go +++ b/routingtable/client_manager_test.go @@ -22,6 +22,12 @@ func (m MockClient) RemovePath(net.Prefix, *route.Path) bool { func (m MockClient) UpdateNewClient(RouteTableClient) error { return nil } +func (m MockClient) Register(RouteTableClient) { + return +} +func (m MockClient) Unregister(RouteTableClient) { + return +} func TestClients(t *testing.T) { tests := []struct { @@ -61,7 +67,19 @@ func TestClients(t *testing.T) { cm.Register(client) } ret := cm.Clients() - assert.Equal(t, test.expected, ret) + + for _, exp := range test.expected { + found := false + for _, client := range ret { + if exp == client { + found = true + continue + } + } + if !found { + t.Errorf("Test %q failed: Client %v not found in result: %v", test.name, exp, ret) + } + } } } diff --git a/routingtable/locRIB/loc_rib.go b/routingtable/locRIB/loc_rib.go index 6e030de30ac6cdb3fc51b942b8b2fb68997862c7..dd06e10069108809feb7da2118188a0fbe1bb4a9 100644 --- a/routingtable/locRIB/loc_rib.go +++ b/routingtable/locRIB/loc_rib.go @@ -51,7 +51,7 @@ func (a *LocRIB) AddPath(pfx net.Prefix, p *route.Path) error { oldRoute = r.Copy() routeExisted = true } - + // FIXME: in AddPath() we assume that the same reference of route (r) is modified (not responsibility of locRIB). If this implementation changes in the future this code will break. a.rt.AddPath(pfx, p) if !routeExisted { @@ -59,12 +59,8 @@ func (a *LocRIB) AddPath(pfx net.Prefix, p *route.Path) error { } r.PathSelection() - newRoute := r.Copy() - fmt.Printf("NEW: %v\n", newRoute.Paths()) - fmt.Printf("OLD: %v\n", oldRoute.Paths()) - a.propagateChanges(oldRoute, newRoute) return nil } @@ -86,9 +82,6 @@ func (a *LocRIB) RemovePath(pfx net.Prefix, p *route.Path) bool { r = a.rt.Get(pfx) newRoute := r.Copy() - fmt.Printf("NEW: %v\n", newRoute.Paths()) - fmt.Printf("OLD: %v\n", oldRoute.Paths()) - a.propagateChanges(oldRoute, newRoute) return true } @@ -108,7 +101,6 @@ func (a *LocRIB) addPathsToClients(oldRoute *route.Route, newRoute *route.Route) newPathsLimit := int(math.Min(float64(newMaxPaths), float64(len(newRoute.Paths())))) advertise := route.PathsDiff(newRoute.Paths()[0:newPathsLimit], oldRoute.Paths()[0:oldPathsLimit]) - fmt.Printf("ADVERTISING PATHS %v TO CLIENTS\n", advertise) for _, p := range advertise { client.AddPath(newRoute.Prefix(), p)