diff --git a/protocols/bgp/packet/BUILD.bazel b/protocols/bgp/packet/BUILD.bazel index bc081c1e463c24e67b103de106d686462fd340f5..3a9b5fd463ba33831be932734b27a8c845e8069d 100644 --- a/protocols/bgp/packet/BUILD.bazel +++ b/protocols/bgp/packet/BUILD.bazel @@ -7,7 +7,6 @@ go_library( "decoder.go", "encoder.go", "nlri.go", - "options.go", "parameters.go", "path_attribute_flags.go", "path_attributes.go", @@ -33,6 +32,7 @@ go_test( embed = [":go_default_library"], deps = [ "//net:go_default_library", + "//protocols/bgp/types:go_default_library", "//vendor/github.com/stretchr/testify/assert:go_default_library", "//vendor/github.com/taktv6/tflow2/convert:go_default_library", ], diff --git a/protocols/bgp/packet/decoder.go b/protocols/bgp/packet/decoder.go index c4d583f2138edfbbfb5b9be33b2a1c11764ee0bd..ca717c781194adf20d2d5c08f332c03f060be849 100644 --- a/protocols/bgp/packet/decoder.go +++ b/protocols/bgp/packet/decoder.go @@ -6,11 +6,12 @@ import ( "fmt" "net" + "github.com/bio-routing/bio-rd/protocols/bgp/types" "github.com/taktv6/tflow2/convert" ) // Decode decodes a BGP message -func Decode(buf *bytes.Buffer, opt *Options) (*BGPMessage, error) { +func Decode(buf *bytes.Buffer, opt *types.Options) (*BGPMessage, error) { hdr, err := decodeHeader(buf) if err != nil { return nil, fmt.Errorf("Failed to decode header: %v", err) @@ -27,7 +28,7 @@ func Decode(buf *bytes.Buffer, opt *Options) (*BGPMessage, error) { }, nil } -func decodeMsgBody(buf *bytes.Buffer, msgType uint8, l uint16, opt *Options) (interface{}, error) { +func decodeMsgBody(buf *bytes.Buffer, msgType uint8, l uint16, opt *types.Options) (interface{}, error) { switch msgType { case OpenMsg: return decodeOpenMsg(buf) @@ -41,7 +42,7 @@ func decodeMsgBody(buf *bytes.Buffer, msgType uint8, l uint16, opt *Options) (in return nil, fmt.Errorf("Unknown message type: %d", msgType) } -func decodeUpdateMsg(buf *bytes.Buffer, l uint16, opt *Options) (*BGPUpdate, error) { +func decodeUpdateMsg(buf *bytes.Buffer, l uint16, opt *types.Options) (*BGPUpdate, error) { msg := &BGPUpdate{} err := decode(buf, []interface{}{&msg.WithdrawnRoutesLen}) diff --git a/protocols/bgp/packet/decoder_test.go b/protocols/bgp/packet/decoder_test.go index 56416186ba1d714a13fb4f248281d3d5f48451dd..64c5cf0426596a04ce463fdfc38b7fb4d8511b87 100644 --- a/protocols/bgp/packet/decoder_test.go +++ b/protocols/bgp/packet/decoder_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/bio-routing/bio-rd/net" + "github.com/bio-routing/bio-rd/protocols/bgp/types" "github.com/stretchr/testify/assert" "github.com/taktv6/tflow2/convert" ) @@ -71,7 +72,7 @@ func BenchmarkDecodeUpdateMsg(b *testing.B) { for i := 0; i < b.N; i++ { buf := bytes.NewBuffer(input) - _, err := decodeUpdateMsg(buf, uint16(len(input)), &Options{}) + _, err := decodeUpdateMsg(buf, uint16(len(input)), &types.Options{}) if err != nil { fmt.Printf("decodeUpdateMsg failed: %v\n", err) } @@ -252,7 +253,7 @@ func TestDecode(t *testing.T) { for _, test := range tests { buf := bytes.NewBuffer(test.input) - msg, err := Decode(buf, &Options{}) + msg, err := Decode(buf, &types.Options{}) if err != nil && !test.wantFail { t.Errorf("Unexpected error in test %d: %v", test.testNum, err) @@ -519,10 +520,9 @@ func TestDecodeUpdateMsg(t *testing.T) { ExtendedLength: false, Length: 6, TypeCode: 2, - Value: ASPath{ + Value: types.ASPath{ { - Type: 2, - Count: 2, + Type: 2, ASNs: []uint32{ 15169, 3320, @@ -623,18 +623,16 @@ func TestDecodeUpdateMsg(t *testing.T) { ExtendedLength: false, Length: 12, TypeCode: 2, - Value: ASPath{ + Value: types.ASPath{ { - Type: 2, - Count: 2, + Type: 2, ASNs: []uint32{ 15169, 3320, }, }, { - Type: 1, - Count: 2, + Type: 1, ASNs: []uint32{ 15169, 3320, @@ -702,18 +700,16 @@ func TestDecodeUpdateMsg(t *testing.T) { ExtendedLength: false, Length: 12, TypeCode: 2, - Value: ASPath{ + Value: types.ASPath{ { - Type: 2, - Count: 2, + Type: 2, ASNs: []uint32{ 15169, 3320, }, }, { - Type: 1, - Count: 2, + Type: 1, ASNs: []uint32{ 15169, 3320, @@ -794,18 +790,16 @@ func TestDecodeUpdateMsg(t *testing.T) { ExtendedLength: false, Length: 12, TypeCode: 2, - Value: ASPath{ + Value: types.ASPath{ { - Type: 2, - Count: 2, + Type: 2, ASNs: []uint32{ 15169, 3320, }, }, { - Type: 1, - Count: 2, + Type: 1, ASNs: []uint32{ 15169, 3320, @@ -899,18 +893,16 @@ func TestDecodeUpdateMsg(t *testing.T) { ExtendedLength: false, Length: 12, TypeCode: 2, - Value: ASPath{ + Value: types.ASPath{ { - Type: 2, - Count: 2, + Type: 2, ASNs: []uint32{ 15169, 3320, }, }, { - Type: 1, - Count: 2, + Type: 1, ASNs: []uint32{ 15169, 3320, @@ -1017,18 +1009,16 @@ func TestDecodeUpdateMsg(t *testing.T) { ExtendedLength: false, Length: 12, TypeCode: 2, - Value: ASPath{ + Value: types.ASPath{ { - Type: 2, - Count: 2, + Type: 2, ASNs: []uint32{ 15169, 3320, }, }, { - Type: 1, - Count: 2, + Type: 1, ASNs: []uint32{ 15169, 3320, @@ -1151,18 +1141,16 @@ func TestDecodeUpdateMsg(t *testing.T) { ExtendedLength: false, Length: 12, TypeCode: 2, - Value: ASPath{ + Value: types.ASPath{ { - Type: 2, - Count: 2, + Type: 2, ASNs: []uint32{ 15169, 3320, }, }, { - Type: 1, - Count: 2, + Type: 1, ASNs: []uint32{ 15169, 3320, @@ -1425,11 +1413,10 @@ func TestDecodeUpdateMsg(t *testing.T) { ExtendedLength: false, Length: 6, TypeCode: 17, - Value: ASPath{ - ASPathSegment{ - Type: 2, - Count: 1, - ASNs: []uint32{202739}, + Value: types.ASPath{ + types.ASPathSegment{ + Type: 2, + ASNs: []uint32{202739}, }, }, Next: &PathAttribute{ @@ -1465,7 +1452,7 @@ func TestDecodeUpdateMsg(t *testing.T) { if l == 0 { l = uint16(len(test.input)) } - msg, err := decodeUpdateMsg(buf, l, &Options{}) + msg, err := decodeUpdateMsg(buf, l, &types.Options{}) if err != nil && !test.wantFail { t.Fatalf("Unexpected error in test %d: %v", test.testNum, err) @@ -1501,7 +1488,7 @@ func TestDecodeMsgBody(t *testing.T) { } for _, test := range tests { - res, err := decodeMsgBody(test.buffer, test.msgType, test.length, &Options{}) + res, err := decodeMsgBody(test.buffer, test.msgType, test.length, &types.Options{}) if test.wantFail && err == nil { t.Errorf("Expected error dit not happen in test %q", test.name) } diff --git a/protocols/bgp/packet/nlri.go b/protocols/bgp/packet/nlri.go index a9ed83b94946ea6415672970668e58fd5c99aa71..e4bd4cea7a7cf65a8ac5ad75ff17218a294cbfe5 100644 --- a/protocols/bgp/packet/nlri.go +++ b/protocols/bgp/packet/nlri.go @@ -90,7 +90,7 @@ func (n *NLRI) serializeAddPath(buf *bytes.Buffer) uint8 { buf.WriteByte(n.Pfxlen) buf.Write(addr[:nBytes]) - return nBytes + 1 + return nBytes + 4 } // BytesInAddr gets the amount of bytes needed to encode an NLRI of prefix length pfxlen diff --git a/protocols/bgp/packet/nlri_test.go b/protocols/bgp/packet/nlri_test.go index 17a17dd3bf5ae997fa4676de27a5db5a4376907b..4cefc5adb3a664564ac201a81afc5efaebe015a8 100644 --- a/protocols/bgp/packet/nlri_test.go +++ b/protocols/bgp/packet/nlri_test.go @@ -162,7 +162,7 @@ func TestBytesInAddr(t *testing.T) { } for _, test := range tests { - res := bytesInAddr(test.input) + res := BytesInAddr(test.input) if res != test.expected { t.Errorf("Unexpected result for test %q: %d", test.name, res) } @@ -212,12 +212,12 @@ func TestNLRISerialize(t *testing.T) { func TestNLRIAddPathSerialize(t *testing.T) { tests := []struct { name string - nlri *NLRIAddPath + nlri *NLRI expected []byte }{ { name: "Test #1", - nlri: &NLRIAddPath{ + nlri: &NLRI{ PathIdentifier: 100, IP: strAddr("1.2.3.0"), Pfxlen: 25, @@ -226,7 +226,7 @@ func TestNLRIAddPathSerialize(t *testing.T) { }, { name: "Test #2", - nlri: &NLRIAddPath{ + nlri: &NLRI{ PathIdentifier: 100, IP: strAddr("1.2.3.0"), Pfxlen: 24, @@ -235,7 +235,7 @@ func TestNLRIAddPathSerialize(t *testing.T) { }, { name: "Test #3", - nlri: &NLRIAddPath{ + nlri: &NLRI{ PathIdentifier: 100, IP: strAddr("100.200.128.0"), Pfxlen: 17, @@ -246,7 +246,7 @@ func TestNLRIAddPathSerialize(t *testing.T) { for _, test := range tests { buf := bytes.NewBuffer(nil) - test.nlri.serialize(buf) + test.nlri.serializeAddPath(buf) res := buf.Bytes() assert.Equal(t, test.expected, res) } diff --git a/protocols/bgp/packet/path_attributes.go b/protocols/bgp/packet/path_attributes.go index 2e47c5e6a7d17ab0a6d4882f712f50a9ae1f047c..efb3e1ec581630abb166f62ac21608d3ef5be9dc 100644 --- a/protocols/bgp/packet/path_attributes.go +++ b/protocols/bgp/packet/path_attributes.go @@ -9,7 +9,7 @@ import ( "github.com/taktv6/tflow2/convert" ) -func decodePathAttrs(buf *bytes.Buffer, tpal uint16, opt *Options) (*PathAttribute, error) { +func decodePathAttrs(buf *bytes.Buffer, tpal uint16, opt *types.Options) (*PathAttribute, error) { var ret *PathAttribute var eol *PathAttribute var pa *PathAttribute @@ -36,7 +36,7 @@ func decodePathAttrs(buf *bytes.Buffer, tpal uint16, opt *Options) (*PathAttribu return ret, nil } -func decodePathAttr(buf *bytes.Buffer, opt *Options) (pa *PathAttribute, consumed uint16, err error) { +func decodePathAttr(buf *bytes.Buffer, opt *types.Options) (pa *PathAttribute, consumed uint16, err error) { pa = &PathAttribute{} err = decodePathAttrFlags(buf, pa) @@ -373,7 +373,7 @@ func dumpNBytes(buf *bytes.Buffer, n uint16) error { } // Serialize serializes a path attribute -func (pa *PathAttribute) Serialize(buf *bytes.Buffer, opt *Options) uint8 { +func (pa *PathAttribute) Serialize(buf *bytes.Buffer, opt *types.Options) uint8 { pathAttrLen := uint8(0) switch pa.TypeCode { @@ -413,7 +413,7 @@ func (pa *PathAttribute) serializeOrigin(buf *bytes.Buffer) uint8 { return 4 } -func (pa *PathAttribute) serializeASPath(buf *bytes.Buffer, opt *Options) uint8 { +func (pa *PathAttribute) serializeASPath(buf *bytes.Buffer, opt *types.Options) uint8 { attrFlags := uint8(0) attrFlags = setTransitive(attrFlags) buf.WriteByte(attrFlags) @@ -437,7 +437,6 @@ func (pa *PathAttribute) serializeASPath(buf *bytes.Buffer, opt *Options) uint8 segmentsBuf.Write(convert.Uint32Byte(asn)) } } - fmt.Println(segment.ASNs) length += 2 + uint8(len(segment.ASNs))*asnLength } diff --git a/protocols/bgp/packet/path_attributes_test.go b/protocols/bgp/packet/path_attributes_test.go index fbf1d4806e127b1b2e4b15255a11e018bd00bbaf..1077e1668ced9b339b452c3c6320d8ec2ce635e1 100644 --- a/protocols/bgp/packet/path_attributes_test.go +++ b/protocols/bgp/packet/path_attributes_test.go @@ -4,6 +4,7 @@ import ( "bytes" "testing" + "github.com/bio-routing/bio-rd/protocols/bgp/types" "github.com/stretchr/testify/assert" ) @@ -50,7 +51,7 @@ func TestDecodePathAttrs(t *testing.T) { } for _, test := range tests { - res, err := decodePathAttrs(bytes.NewBuffer(test.input), uint16(len(test.input)), &Options{}) + res, err := decodePathAttrs(bytes.NewBuffer(test.input), uint16(len(test.input)), &types.Options{}) if test.wantFail && err == nil { t.Errorf("Expected error did not happen for test %q", test.name) @@ -173,7 +174,7 @@ func TestDecodePathAttr(t *testing.T) { } for _, test := range tests { - res, _, err := decodePathAttr(bytes.NewBuffer(test.input), &Options{}) + res, _, err := decodePathAttr(bytes.NewBuffer(test.input), &types.Options{}) if test.wantFail && err == nil { t.Errorf("Expected error did not happen for test %q", test.name) @@ -277,10 +278,9 @@ func TestDecodeASPath(t *testing.T) { wantFail: false, expected: &PathAttribute{ Length: 10, - Value: ASPath{ - ASPathSegment{ - Type: 2, - Count: 4, + Value: types.ASPath{ + types.ASPathSegment{ + Type: 2, ASNs: []uint32{ 100, 200, 222, 240, }, @@ -298,10 +298,9 @@ func TestDecodeASPath(t *testing.T) { wantFail: false, expected: &PathAttribute{ Length: 8, - Value: ASPath{ - ASPathSegment{ - Type: 1, - Count: 3, + Value: types.ASPath{ + types.ASPathSegment{ + Type: 1, ASNs: []uint32{ 100, 222, 240, }, @@ -320,10 +319,9 @@ func TestDecodeASPath(t *testing.T) { use4OctetASNs: true, expected: &PathAttribute{ Length: 14, - Value: ASPath{ - ASPathSegment{ - Type: 1, - Count: 3, + Value: types.ASPath{ + types.ASPathSegment{ + Type: 1, ASNs: []uint32{ 100, 222, 240, }, @@ -636,7 +634,7 @@ func TestDecodeLargeCommunity(t *testing.T) { wantFail: false, expected: &PathAttribute{ Length: 24, - Value: []LargeCommunity{ + Value: []types.LargeCommunity{ { GlobalAdministrator: 1, DataPart1: 2, @@ -656,7 +654,7 @@ func TestDecodeLargeCommunity(t *testing.T) { wantFail: false, expected: &PathAttribute{ Length: 0, - Value: []LargeCommunity{}, + Value: []types.LargeCommunity{}, }, }, } @@ -1175,7 +1173,7 @@ func TestSerializeASPath(t *testing.T) { name: "Test #1", input: &PathAttribute{ TypeCode: ASPathAttr, - Value: ASPath{ + Value: types.ASPath{ { Type: 2, // Sequence ASNs: []uint32{ @@ -1200,7 +1198,7 @@ func TestSerializeASPath(t *testing.T) { name: "32bit ASN", input: &PathAttribute{ TypeCode: ASPathAttr, - Value: ASPath{ + Value: types.ASPath{ { Type: 2, // Sequence ASNs: []uint32{ @@ -1229,7 +1227,7 @@ func TestSerializeASPath(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { buf := bytes.NewBuffer(nil) - opt := &Options{ + opt := &types.Options{ Supports4OctetASN: test.use32BitASN, } n := test.input.serializeASPath(buf, opt) @@ -1253,7 +1251,7 @@ func TestSerializeLargeCommunities(t *testing.T) { name: "2 large communities", input: &PathAttribute{ TypeCode: LargeCommunitiesAttr, - Value: []LargeCommunity{ + Value: []types.LargeCommunity{ { GlobalAdministrator: 1, DataPart1: 2, @@ -1278,7 +1276,7 @@ func TestSerializeLargeCommunities(t *testing.T) { name: "empty list of communities", input: &PathAttribute{ TypeCode: LargeCommunitiesAttr, - Value: []LargeCommunity{}, + Value: []types.LargeCommunity{}, }, expected: []byte{}, expectedLen: 0, @@ -1459,7 +1457,7 @@ func TestSerialize(t *testing.T) { Value: uint8(0), Next: &PathAttribute{ TypeCode: ASPathAttr, - Value: ASPath{ + Value: types.ASPath{ { Type: 2, ASNs: []uint32{100, 155, 200}, @@ -1559,7 +1557,9 @@ func TestSerialize(t *testing.T) { } for _, test := range tests { - opt := &Options{} + opt := &types.Options{ + AddPathRX: false, + } res, err := test.msg.SerializeUpdate(opt) if err != nil { if test.wantFail { @@ -1582,14 +1582,14 @@ func TestSerialize(t *testing.T) { func TestSerializeAddPath(t *testing.T) { tests := []struct { name string - msg *BGPUpdateAddPath + msg *BGPUpdate expected []byte wantFail bool }{ - { + /*{ name: "Withdraw only", - msg: &BGPUpdateAddPath{ - WithdrawnRoutes: &NLRIAddPath{ + msg: &BGPUpdate{ + WithdrawnRoutes: &NLRI{ PathIdentifier: 257, IP: strAddr("100.110.120.0"), Pfxlen: 24, @@ -1607,8 +1607,8 @@ func TestSerializeAddPath(t *testing.T) { }, { name: "NLRI only", - msg: &BGPUpdateAddPath{ - NLRI: &NLRIAddPath{ + msg: &BGPUpdate{ + NLRI: &NLRI{ PathIdentifier: 257, IP: strAddr("100.110.128.0"), Pfxlen: 17, @@ -1626,7 +1626,7 @@ func TestSerializeAddPath(t *testing.T) { }, { name: "Path Attributes only", - msg: &BGPUpdateAddPath{ + msg: &BGPUpdate{ PathAttributes: &PathAttribute{ Optional: true, Transitive: true, @@ -1645,14 +1645,14 @@ func TestSerializeAddPath(t *testing.T) { 1, // Length 0, // Value }, - }, + },*/ { name: "Full test", - msg: &BGPUpdateAddPath{ - WithdrawnRoutes: &NLRIAddPath{ + msg: &BGPUpdate{ + WithdrawnRoutes: &NLRI{ IP: strAddr("10.0.0.0"), Pfxlen: 8, - Next: &NLRIAddPath{ + Next: &NLRI{ IP: strAddr("192.168.0.0"), Pfxlen: 16, }, @@ -1662,7 +1662,7 @@ func TestSerializeAddPath(t *testing.T) { Value: uint8(0), Next: &PathAttribute{ TypeCode: ASPathAttr, - Value: ASPath{ + Value: types.ASPath{ { Type: 2, ASNs: []uint32{100, 155, 200}, @@ -1693,10 +1693,10 @@ func TestSerializeAddPath(t *testing.T) { }, }, }, - NLRI: &NLRIAddPath{ + NLRI: &NLRI{ IP: strAddr("8.8.8.0"), Pfxlen: 24, - Next: &NLRIAddPath{ + Next: &NLRI{ IP: strAddr("185.65.240.0"), Pfxlen: 22, }, @@ -1766,7 +1766,9 @@ func TestSerializeAddPath(t *testing.T) { } for _, test := range tests { - opt := &Options{} + opt := &types.Options{ + AddPathRX: true, + } res, err := test.msg.SerializeUpdate(opt) if err != nil { if test.wantFail { diff --git a/protocols/bgp/packet/update.go b/protocols/bgp/packet/update.go index 38e1d7196be15fba04554f6845a8265b330a39e2..55b0cc0b9099076edbaef35fcfab1cfc83443330 100644 --- a/protocols/bgp/packet/update.go +++ b/protocols/bgp/packet/update.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" + "github.com/bio-routing/bio-rd/protocols/bgp/types" "github.com/taktv6/tflow2/convert" ) @@ -15,7 +16,8 @@ type BGPUpdate struct { NLRI *NLRI } -func (b *BGPUpdate) SerializeUpdate(opt *Options) ([]byte, error) { +// SerializeUpdate serializes an BGPUpdate to wire format +func (b *BGPUpdate) SerializeUpdate(opt *types.Options) ([]byte, error) { budget := MaxLen - MinLen nlriLen := 0 buf := bytes.NewBuffer(nil) @@ -46,9 +48,9 @@ func (b *BGPUpdate) SerializeUpdate(opt *Options) ([]byte, error) { nlriBuf := bytes.NewBuffer(nil) for nlri := b.NLRI; nlri != nil; nlri = nlri.Next { if opt.AddPathRX { - nlriLen = int(nlri.serializeAddPath(withdrawBuf)) + nlriLen = int(nlri.serializeAddPath(nlriBuf)) } else { - nlriLen = int(nlri.serialize(withdrawBuf)) + nlriLen = int(nlri.serialize(nlriBuf)) } budget -= nlriLen @@ -85,7 +87,7 @@ func (b *BGPUpdate) SerializeUpdate(opt *Options) ([]byte, error) { return buf.Bytes(), nil } -func (b *BGPUpdate) SerializeUpdateAddPath(opt *Options) ([]byte, error) { +func (b *BGPUpdate) SerializeUpdateAddPath(opt *types.Options) ([]byte, error) { budget := MaxLen - MinLen buf := bytes.NewBuffer(nil) diff --git a/protocols/bgp/server/fsm.go b/protocols/bgp/server/fsm.go index 94612c231adca5737f1c28537c428e8152808b0b..e85bda8cc21d6c47ac2c300639177aab8623859f 100644 --- a/protocols/bgp/server/fsm.go +++ b/protocols/bgp/server/fsm.go @@ -7,6 +7,7 @@ import ( "time" "github.com/bio-routing/bio-rd/protocols/bgp/packet" + "github.com/bio-routing/bio-rd/protocols/bgp/types" "github.com/bio-routing/bio-rd/routingtable" "github.com/bio-routing/bio-rd/routingtable/locRIB" log "github.com/sirupsen/logrus" @@ -54,7 +55,7 @@ type FSM struct { msgRecvFailCh chan error stopMsgRecvCh chan struct{} - options *packet.Options + options *types.Options local net.IP @@ -99,7 +100,7 @@ func newFSM2(peer *peer) *FSM { msgRecvFailCh: make(chan error), stopMsgRecvCh: make(chan struct{}), rib: peer.rib, - options: &packet.Options{}, + options: &types.Options{}, } } diff --git a/protocols/bgp/server/fsm_established.go b/protocols/bgp/server/fsm_established.go index e184404c2ee95ab684250e4a96a04f34a9a8a9e8..20ae668232984fead709cbfae9cceeecfec97217 100644 --- a/protocols/bgp/server/fsm_established.go +++ b/protocols/bgp/server/fsm_established.go @@ -251,7 +251,7 @@ func (s *establishedState) processAttributes(attrs *packet.PathAttribute, path * default: unknownAttr := s.processUnknownAttribute(pa) if unknownAttr != nil { - path.BGPPath.UnknownAttributes = append(path.BGPPath.UnknownAttributes) + path.BGPPath.UnknownAttributes = append(path.BGPPath.UnknownAttributes, *unknownAttr) } } } diff --git a/protocols/bgp/server/fsm_established_test.go b/protocols/bgp/server/fsm_established_test.go index 4e92e4eede30ed4b0dfedeb1217e5d11962c6252..61103d99c133e01e47ab923e81d121f5acc48018 100644 --- a/protocols/bgp/server/fsm_established_test.go +++ b/protocols/bgp/server/fsm_established_test.go @@ -4,11 +4,12 @@ import ( "testing" "github.com/bio-routing/bio-rd/protocols/bgp/packet" + "github.com/bio-routing/bio-rd/protocols/bgp/types" "github.com/bio-routing/bio-rd/route" "github.com/stretchr/testify/assert" ) -func TestProcessAttribues(t *testing.T) { +func TestProcessAttributes(t *testing.T) { unknown3 := &packet.PathAttribute{ Transitive: true, TypeCode: 100, @@ -33,11 +34,10 @@ func TestProcessAttribues(t *testing.T) { asPath := &packet.PathAttribute{ Transitive: true, TypeCode: packet.ASPathAttr, - Value: packet.ASPath{ - packet.ASPathSegment{ - Count: 0, - Type: packet.ASSequence, - ASNs: []uint32{}, + Value: types.ASPath{ + types.ASPathSegment{ + Type: types.ASSequence, + ASNs: []uint32{}, }, }, Next: unknown1, @@ -54,12 +54,12 @@ func TestProcessAttribues(t *testing.T) { expectedValues := [][]byte{[]byte{5, 6}, []byte{1, 2, 3, 4}} i := 0 - for attr := p.BGPPath.UnknownAttributes; attr != nil; attr = attr.Next { + for _, attr := range p.BGPPath.UnknownAttributes { assert.Equal(t, true, attr.Transitive, "Transitive") assert.Equal(t, expectedCodes[i], attr.TypeCode, "Code") assert.Equal(t, expectedValues[i], attr.Value, "Value") i++ } - assert.Equal(t, i, 2, "Count") + assert.Equal(t, 2, i, "Count") } diff --git a/protocols/bgp/server/fsm_test.go b/protocols/bgp/server/fsm_test.go index a6f6bd7a19e2c571c374df2daa59914d02640a66..9cff29b3706dc30d11a1017a7d963d30bafcb1f2 100644 --- a/protocols/bgp/server/fsm_test.go +++ b/protocols/bgp/server/fsm_test.go @@ -88,6 +88,7 @@ func TestFSM100Updates(t *testing.T) { } fsmA.msgRecvCh <- update + } time.Sleep(time.Second) diff --git a/protocols/bgp/server/update_helper.go b/protocols/bgp/server/update_helper.go index 2c36aa2fdf7880d6f1e2c6b2ff76d8a7bade61f8..2cb82934a0a12d2f25243db2bc82cd60fca10e02 100644 --- a/protocols/bgp/server/update_helper.go +++ b/protocols/bgp/server/update_helper.go @@ -4,11 +4,11 @@ import ( "fmt" "io" - "github.com/bio-routing/bio-rd/protocols/bgp/packet" + "github.com/bio-routing/bio-rd/protocols/bgp/types" log "github.com/sirupsen/logrus" ) -func serializeAndSendUpdate(out io.Writer, update *packet.BGPUpdate, opt *packet.Options) error { +func serializeAndSendUpdate(out io.Writer, update serializeAbleUpdate, opt *types.Options) error { updateBytes, err := update.SerializeUpdate(opt) if err != nil { log.Errorf("Unable to serialize BGP Update: %v", err) @@ -21,3 +21,7 @@ func serializeAndSendUpdate(out io.Writer, update *packet.BGPUpdate, opt *packet } return nil } + +type serializeAbleUpdate interface { + SerializeUpdate(opt *types.Options) ([]byte, error) +} diff --git a/protocols/bgp/server/update_helper_test.go b/protocols/bgp/server/update_helper_test.go index d2d0a7fcf424276b6a351176cebc9a3959f9ec69..6c599f18c965d55a9a611509ea10e2c5d5ffa35e 100644 --- a/protocols/bgp/server/update_helper_test.go +++ b/protocols/bgp/server/update_helper_test.go @@ -1,14 +1,13 @@ package server import ( + "bytes" + "errors" "io" "testing" - "bytes" - "github.com/bio-routing/bio-rd/protocols/bgp/packet" - - "errors" + "github.com/bio-routing/bio-rd/protocols/bgp/types" "github.com/bio-routing/bio-rd/net" "github.com/stretchr/testify/assert" @@ -16,7 +15,7 @@ import ( type failingUpdate struct{} -func (f *failingUpdate) SerializeUpdate(opt *packet.Options) ([]byte, error) { +func (f *failingUpdate) SerializeUpdate(opt *types.Options) ([]byte, error) { return nil, errors.New("general error") } @@ -94,7 +93,7 @@ func TestSerializeAndSendUpdate(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - opt := &packet.Options{} + opt := &types.Options{} err := serializeAndSendUpdate(test.buf, test.testUpdate, opt) assert.Equal(t, test.err, err) diff --git a/protocols/bgp/server/update_sender.go b/protocols/bgp/server/update_sender.go index ccb1d869316724c23933cbf00ee1f0008282e35e..078faebfde101b8d774a8785ad0a71c9dce3b159 100644 --- a/protocols/bgp/server/update_sender.go +++ b/protocols/bgp/server/update_sender.go @@ -117,6 +117,7 @@ func (u *UpdateSender) sender() { u.sendUpdates(pathAttrs, updatesPrefixes, pathNLRIs.path.BGPPath.PathIdentifier) u.toSendMu.Lock() } + u.toSendMu.Unlock() } } diff --git a/protocols/bgp/server/withdraw.go b/protocols/bgp/server/withdraw.go index a66fade667558a45b4a2f92d4a569516c57c7dd1..e3f1137e1e96469dfa69f3bd825a3a644a582fc2 100644 --- a/protocols/bgp/server/withdraw.go +++ b/protocols/bgp/server/withdraw.go @@ -6,12 +6,13 @@ import ( "github.com/bio-routing/bio-rd/net" "github.com/bio-routing/bio-rd/protocols/bgp/packet" + "github.com/bio-routing/bio-rd/protocols/bgp/types" "github.com/bio-routing/bio-rd/route" ) // withDrawPrefixes generates a BGPUpdate message and write it to the given // io.Writer. -func withDrawPrefixes(out io.Writer, opt *packet.Options, prefixes ...net.Prefix) error { +func withDrawPrefixes(out io.Writer, opt *types.Options, prefixes ...net.Prefix) error { if len(prefixes) < 1 { return nil } @@ -41,7 +42,7 @@ func withDrawPrefixes(out io.Writer, opt *packet.Options, prefixes ...net.Prefix // withDrawPrefixesAddPath generates a BGPUpdateAddPath message and write it to the given // io.Writer. -func withDrawPrefixesAddPath(out io.Writer, opt *packet.Options, pfx net.Prefix, p *route.Path) error { +func withDrawPrefixesAddPath(out io.Writer, opt *types.Options, pfx net.Prefix, p *route.Path) error { if p.Type != route.BGPPathType { return errors.New("wrong path type, expected BGPPathType") } diff --git a/protocols/bgp/server/withdraw_test.go b/protocols/bgp/server/withdraw_test.go index d8831c3eb526d3afdaceb0a3506bf5dca39c2c41..c21b6ada956e4c694a8408e962a67efe611574c2 100644 --- a/protocols/bgp/server/withdraw_test.go +++ b/protocols/bgp/server/withdraw_test.go @@ -3,7 +3,7 @@ package server import ( "testing" - "github.com/bio-routing/bio-rd/protocols/bgp/packet" + "github.com/bio-routing/bio-rd/protocols/bgp/types" "errors" @@ -54,7 +54,7 @@ func TestWithDrawPrefixes(t *testing.T) { } for _, tc := range testcases { buf := bytes.NewBuffer([]byte{}) - opt := &packet.Options{} + opt := &types.Options{} err := withDrawPrefixes(buf, opt, tc.Prefix...) assert.Equal(t, tc.ExpectedError, err, "error mismatch in testcase %v", tc.Name) assert.Equal(t, tc.Expected, buf.Bytes(), "expected different bytes in testcase %v", tc.Name) @@ -111,7 +111,9 @@ func TestWithDrawPrefixesAddPath(t *testing.T) { } for _, tc := range testcases { buf := bytes.NewBuffer([]byte{}) - opt := &packet.Options{} + opt := &types.Options{ + AddPathRX: true, + } err := withDrawPrefixesAddPath(buf, opt, tc.Prefix, tc.Path) assert.Equal(t, tc.ExpectedError, err, "error mismatch in testcase %v", tc.Name) assert.Equal(t, tc.Expected, buf.Bytes(), "expected different bytes in testcase %v", tc.Name) diff --git a/protocols/bgp/types/BUILD.bazel b/protocols/bgp/types/BUILD.bazel index 175cedfcb63e894221efe75d1e850acab65c7f2e..cd582779e7275027d66fadef922165706b2c5003 100644 --- a/protocols/bgp/types/BUILD.bazel +++ b/protocols/bgp/types/BUILD.bazel @@ -6,6 +6,7 @@ go_library( "as_path.go", "community.go", "large_community.go", + "options.go", "unknown_attribute.go", ], importpath = "github.com/bio-routing/bio-rd/protocols/bgp/types", diff --git a/protocols/bgp/packet/options.go b/protocols/bgp/types/options.go similarity index 52% rename from protocols/bgp/packet/options.go rename to protocols/bgp/types/options.go index 612e68935c59108d84915dcd78d505bf5e42efb5..cfe15266a557a91c4a3948d953048d7cf8495051 100644 --- a/protocols/bgp/packet/options.go +++ b/protocols/bgp/types/options.go @@ -1,5 +1,6 @@ -package packet +package types +// Options represents options to the update sender type Options struct { Supports4OctetASN bool AddPathRX bool diff --git a/route/BUILD.bazel b/route/BUILD.bazel index b9634f7e7b152e52e9074b507643466c71ef77a6..3673d29995e0ef11a14bbd7043135457f7ea1d7e 100644 --- a/route/BUILD.bazel +++ b/route/BUILD.bazel @@ -29,7 +29,7 @@ go_test( embed = [":go_default_library"], deps = [ "//net:go_default_library", - "//protocols/bgp/packet:go_default_library", + "//protocols/bgp/types:go_default_library", "//vendor/github.com/stretchr/testify/assert:go_default_library", ], ) diff --git a/route/bgp_path.go b/route/bgp_path.go index 6b31dd85a361f37d137e43a6daf28ac6702a4158..6b3c7100d66391e9163a175a0a39c8bceb94da6d 100644 --- a/route/bgp_path.go +++ b/route/bgp_path.go @@ -34,12 +34,22 @@ func (b *BGPPath) Length() uint16 { asPathLen += uint16(4 * len(segment.ASNs)) } + communitiesLen := uint16(0) + if len(b.Communities) != 0 { + communitiesLen += 3 + uint16(len(b.Communities)*4) + } + + largeCommunitiesLen := uint16(0) + if len(b.LargeCommunities) != 0 { + largeCommunitiesLen += 3 + uint16(len(b.LargeCommunities)*12) + } + unknownAttributesLen := uint16(0) for _, unknownAttr := range b.UnknownAttributes { unknownAttributesLen += unknownAttr.WireLength() } - return uint16(len(b.Communities))*7 + uint16(len(b.LargeCommunities))*15 + 4*7 + 4 + asPathLen + unknownAttributesLen + return communitiesLen + largeCommunitiesLen + 4*7 + 4 + asPathLen + unknownAttributesLen } // ECMP determines if routes b and c are euqal in terms of ECMP diff --git a/route/bgp_path_test.go b/route/bgp_path_test.go index d1ea111a091ca1ce9c263c672b5f2a1a2e9ca73e..9ea931153ea5778061e852e34af7666204e97b0b 100644 --- a/route/bgp_path_test.go +++ b/route/bgp_path_test.go @@ -1,10 +1,9 @@ package route import ( - "bytes" "testing" - "github.com/bio-routing/bio-rd/protocols/bgp/packet" + "github.com/bio-routing/bio-rd/protocols/bgp/types" "github.com/stretchr/testify/assert" ) @@ -35,12 +34,12 @@ func TestCommunitiesString(t *testing.T) { func TestLargeCommunitiesString(t *testing.T) { tests := []struct { name string - comms []packet.LargeCommunity + comms []types.LargeCommunity expected string }{ { name: "two attributes", - comms: []packet.LargeCommunity{ + comms: []types.LargeCommunity{ { GlobalAdministrator: 1, DataPart1: 2, @@ -70,37 +69,67 @@ func TestLength(t *testing.T) { tests := []struct { name string path *BGPPath - options packet.Options - wantFail bool + expected uint16 }{ { - name: "Test 1", - path: &BGPPath{}, + name: "No communities", + path: &BGPPath{ + ASPath: []types.ASPathSegment{ + { + Type: types.ASSequence, + ASNs: []uint32{15169, 199714}, + }, + }, + LargeCommunities: []types.LargeCommunity{}, + Communities: []uint32{}, + }, + expected: 44, + }, + { + name: "communities", + path: &BGPPath{ + ASPath: []types.ASPathSegment{ + { + Type: types.ASSequence, + ASNs: []uint32{15169, 199714}, + }, + }, + LargeCommunities: []types.LargeCommunity{}, + Communities: []uint32{10, 20, 30}, + }, + expected: 59, + }, + { + name: "large communities", + path: &BGPPath{ + ASPath: []types.ASPathSegment{ + { + Type: types.ASSequence, + ASNs: []uint32{15169, 199714}, + }, + }, + LargeCommunities: []types.LargeCommunity{ + { + GlobalAdministrator: 199714, + DataPart1: 100, + DataPart2: 200, + }, + { + GlobalAdministrator: 199714, + DataPart1: 100, + DataPart2: 201, + }, + }, + }, + expected: 71, }, } for _, test := range tests { calcLen := test.path.Length() - pa, err := test.path.PathAttributes() - 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 - } - buf := bytes.Buffer(nil) - pa.Serialize(buf, test.options) - realLen := len(buf.Bytes()) - if realLen != calcLen { - t.Errorf("Unexpected result for test %q: Expected: %d Got: %d", test.name, realLen, calcLen) + if calcLen != test.expected { + t.Errorf("Unexpected result for test %q: Expected: %d Got: %d", test.name, test.expected, calcLen) } } } diff --git a/route/bgp_test.go b/route/bgp_test.go index 2eb017c2a6b33e5174b94cb9d43e4325750e968d..46ceb9af2364746aba48711400e9091cc882457f 100644 --- a/route/bgp_test.go +++ b/route/bgp_test.go @@ -3,18 +3,16 @@ package route import ( "testing" - "github.com/bio-routing/bio-rd/protocols/bgp/packet" - + "github.com/bio-routing/bio-rd/protocols/bgp/types" "github.com/stretchr/testify/assert" ) func TestComputeHash(t *testing.T) { p := &BGPPath{ - ASPath: packet.ASPath{ - packet.ASPathSegment{ - ASNs: []uint32{123, 456}, - Count: 2, - Type: packet.ASSequence, + ASPath: types.ASPath{ + types.ASPathSegment{ + ASNs: []uint32{123, 456}, + Type: types.ASSequence, }, }, BGPIdentifier: 1, @@ -22,8 +20,8 @@ func TestComputeHash(t *testing.T) { 123, 456, }, EBGP: false, - LargeCommunities: []packet.LargeCommunity{ - packet.LargeCommunity{ + LargeCommunities: []types.LargeCommunity{ + types.LargeCommunity{ DataPart1: 1, DataPart2: 2, GlobalAdministrator: 3, diff --git a/routingtable/filter/actions/add_large_community_action_test.go b/routingtable/filter/actions/add_large_community_action_test.go index f7af91396fdd7d697cf667d7712e18c9784d68e3..6b569d2ebd79e7225791b0172c2ad32fab764d88 100644 --- a/routingtable/filter/actions/add_large_community_action_test.go +++ b/routingtable/filter/actions/add_large_community_action_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/bio-routing/bio-rd/net" - "github.com/bio-routing/bio-rd/protocols/bgp/packet" + "github.com/bio-routing/bio-rd/protocols/bgp/types" "github.com/bio-routing/bio-rd/route" "github.com/stretchr/testify/assert" ) @@ -12,14 +12,14 @@ import ( func TestAddingLargeCommunities(t *testing.T) { tests := []struct { name string - current []packet.LargeCommunity - communities []packet.LargeCommunity + current []types.LargeCommunity + communities []types.LargeCommunity expected string }{ { name: "add one to empty", - communities: []packet.LargeCommunity{ - packet.LargeCommunity{ + communities: []types.LargeCommunity{ + types.LargeCommunity{ GlobalAdministrator: 1, DataPart1: 2, DataPart2: 3, @@ -29,15 +29,15 @@ func TestAddingLargeCommunities(t *testing.T) { }, { name: "add one to existing", - current: []packet.LargeCommunity{ - packet.LargeCommunity{ + current: []types.LargeCommunity{ + types.LargeCommunity{ GlobalAdministrator: 5, DataPart1: 6, DataPart2: 7, }, }, - communities: []packet.LargeCommunity{ - packet.LargeCommunity{ + communities: []types.LargeCommunity{ + types.LargeCommunity{ GlobalAdministrator: 1, DataPart1: 2, DataPart2: 3, @@ -47,20 +47,20 @@ func TestAddingLargeCommunities(t *testing.T) { }, { name: "add two to existing", - current: []packet.LargeCommunity{ - packet.LargeCommunity{ + current: []types.LargeCommunity{ + types.LargeCommunity{ GlobalAdministrator: 5, DataPart1: 6, DataPart2: 7, }, }, - communities: []packet.LargeCommunity{ - packet.LargeCommunity{ + communities: []types.LargeCommunity{ + types.LargeCommunity{ GlobalAdministrator: 1, DataPart1: 2, DataPart2: 3, }, - packet.LargeCommunity{ + types.LargeCommunity{ GlobalAdministrator: 7, DataPart1: 8, DataPart2: 9, diff --git a/routingtable/filter/actions/as_path_prepend_action_test.go b/routingtable/filter/actions/as_path_prepend_action_test.go index 253c119ffc91d702e0f4d4cf31e1f88c35d2008c..702a9497cc767cb6b240805a7b4af6f20e17277b 100644 --- a/routingtable/filter/actions/as_path_prepend_action_test.go +++ b/routingtable/filter/actions/as_path_prepend_action_test.go @@ -3,7 +3,7 @@ package actions import ( "testing" - "github.com/bio-routing/bio-rd/protocols/bgp/packet" + "github.com/bio-routing/bio-rd/protocols/bgp/types" "github.com/bio-routing/bio-rd/net" "github.com/bio-routing/bio-rd/route" @@ -25,11 +25,10 @@ func TestAppendPath(t *testing.T) { name: "append 0", times: 0, bgpPath: &route.BGPPath{ - ASPath: packet.ASPath{ - packet.ASPathSegment{ - Count: 2, - Type: packet.ASSequence, - ASNs: []uint32{12345, 12345}, + ASPath: types.ASPath{ + types.ASPathSegment{ + Type: types.ASSequence, + ASNs: []uint32{12345, 12345}, }, }, ASPathLen: 2, @@ -41,11 +40,10 @@ func TestAppendPath(t *testing.T) { name: "append 3", times: 3, bgpPath: &route.BGPPath{ - ASPath: packet.ASPath{ - packet.ASPathSegment{ - Count: 2, - Type: packet.ASSequence, - ASNs: []uint32{12345, 15169}, + ASPath: types.ASPath{ + types.ASPathSegment{ + Type: types.ASSequence, + ASNs: []uint32{12345, 15169}, }, }, ASPathLen: 2, diff --git a/routingtable/filter/term_condition_test.go b/routingtable/filter/term_condition_test.go index e1b3d4bd6173b196ddaca029e768274a08364883..5217feaaacc67a57539a90369664a81663f4e642 100644 --- a/routingtable/filter/term_condition_test.go +++ b/routingtable/filter/term_condition_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/bio-routing/bio-rd/net" - "github.com/bio-routing/bio-rd/protocols/bgp/packet" + "github.com/bio-routing/bio-rd/protocols/bgp/types" "github.com/bio-routing/bio-rd/route" "github.com/stretchr/testify/assert" ) @@ -137,13 +137,13 @@ func TestMatches(t *testing.T) { name: "large community matches", prefix: net.NewPfx(strAddr("10.0.0.0"), 24), bgpPath: &route.BGPPath{ - LargeCommunities: []packet.LargeCommunity{ - packet.LargeCommunity{ + LargeCommunities: []types.LargeCommunity{ + types.LargeCommunity{ GlobalAdministrator: 1, DataPart1: 2, DataPart2: 3, }, - packet.LargeCommunity{ + types.LargeCommunity{ GlobalAdministrator: 1, DataPart1: 2, DataPart2: 0, @@ -152,7 +152,7 @@ func TestMatches(t *testing.T) { }, largeCommunityFilters: []*LargeCommunityFilter{ { - packet.LargeCommunity{ + types.LargeCommunity{ GlobalAdministrator: 1, DataPart1: 2, DataPart2: 3, @@ -167,7 +167,7 @@ func TestMatches(t *testing.T) { bgpPath: &route.BGPPath{}, largeCommunityFilters: []*LargeCommunityFilter{ { - packet.LargeCommunity{ + types.LargeCommunity{ GlobalAdministrator: 1, DataPart1: 2, DataPart2: 3, @@ -181,7 +181,7 @@ func TestMatches(t *testing.T) { prefix: net.NewPfx(strAddr("10.0.0.0"), 24), largeCommunityFilters: []*LargeCommunityFilter{ { - packet.LargeCommunity{ + types.LargeCommunity{ GlobalAdministrator: 1, DataPart1: 2, DataPart2: 3, diff --git a/routingtable/update_helper_test.go b/routingtable/update_helper_test.go index 452a7e4af04152e21c13631c38190b8d4795649d..451b983beae4df2ce289b60be0be8d1b7bd7f67a 100644 --- a/routingtable/update_helper_test.go +++ b/routingtable/update_helper_test.go @@ -6,7 +6,7 @@ import ( "testing" bnet "github.com/bio-routing/bio-rd/net" - "github.com/bio-routing/bio-rd/protocols/bgp/packet" + "github.com/bio-routing/bio-rd/protocols/bgp/types" "github.com/bio-routing/bio-rd/route" "github.com/stretchr/testify/assert" ) @@ -67,7 +67,7 @@ func TestShouldPropagateUpdate(t *testing.T) { continue } - com, err := packet.ParseCommunityString(s) + com, err := types.ParseCommunityString(s) if err != nil { t.Fatalf("test failed: %s", err) }