Skip to content
Snippets Groups Projects
decoder_test.go 40 KiB
Newer Older
Oliver Herms's avatar
Oliver Herms committed
package packet

import (
	"bytes"
	"fmt"
Oliver Herms's avatar
Oliver Herms committed
	"testing"

Daniel Czerwonk's avatar
Daniel Czerwonk committed
	"github.com/bio-routing/bio-rd/net"
Oliver Herms's avatar
Oliver Herms committed
	"github.com/bio-routing/bio-rd/protocols/bgp/types"
Oliver Herms's avatar
Oliver Herms committed
	"github.com/stretchr/testify/assert"
	"github.com/taktv6/tflow2/convert"

	bnet "github.com/bio-routing/bio-rd/net"
Oliver Herms's avatar
Oliver Herms committed
)

type test struct {
	testNum  int
	input    []byte
	wantFail bool
	expected interface{}
}

type decodeFunc func(*bytes.Buffer) (interface{}, error)

func BenchmarkDecodeUpdateMsg(b *testing.B) {
	input := []byte{0, 5, 8, 10, 16, 192, 168,
		0, 53, // Total Path Attribute Length

		255,  // Attribute flags
		1,    // Attribute Type code (ORIGIN)
		0, 1, // Length
		2, // INCOMPLETE

		0,      // Attribute flags
		2,      // Attribute Type code (AS Path)
		12,     // Length
		2,      // Type = AS_SEQUENCE
		2,      // Path Segement Length
		59, 65, // AS15169
		12, 248, // AS3320
		1,      // Type = AS_SET
		2,      // Path Segement Length
		59, 65, // AS15169
		12, 248, // AS3320

		0,              // Attribute flags
		3,              // Attribute Type code (Next Hop)
		4,              // Length
		10, 11, 12, 13, // Next Hop

		0,          // Attribute flags
		4,          // Attribute Type code (MED)
		4,          // Length
		0, 0, 1, 0, // MED 256

		0,          // Attribute flags
		5,          // Attribute Type code (Local Pref)
		4,          // Length
		0, 0, 1, 0, // Local Pref 256

		0, // Attribute flags
		6, // Attribute Type code (Atomic Aggregate)
		0, // Length

		0,    // Attribute flags
		7,    // Attribute Type code (Atomic Aggregate)
		6,    // Length
		1, 2, // ASN
		10, 11, 12, 13, // Address

		8, 11, // 11.0.0.0/8
	}

	for i := 0; i < b.N; i++ {
		buf := bytes.NewBuffer(input)
		_, err := decodeUpdateMsg(buf, uint16(len(input)), &DecodeOptions{})
Oliver Herms's avatar
Oliver Herms committed
		if err != nil {
			fmt.Printf("decodeUpdateMsg failed: %v\n", err)
		}
		//buf.Next(1)
	}
}

func TestDecode(t *testing.T) {
	tests := []test{
		{
			// Proper packet
			testNum: 1,
			input: []byte{
				255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // Marker
				0, 19, // Length
				4, // Type = Keepalive

			},
			wantFail: false,
			expected: &BGPMessage{
				Header: &BGPHeader{
					Length: 19,
					Type:   4,
				},
			},
		},
		{
			// Invalid marker
			testNum: 2,
			input: []byte{
				1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, // Marker
				0, 19, // Length
				4, // Type = Keepalive

			},
			wantFail: true,
			expected: &BGPMessage{
				Header: &BGPHeader{
					Length: 19,
					Type:   4,
				},
			},
		},
		{
			// Proper NOTIFICATION packet
			testNum: 3,
			input: []byte{
				255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // Marker
				0, 21, // Length
				3,    // Type = Notification
				1, 1, // Message Header Error, Connection Not Synchronized.
			},
			wantFail: false,
			expected: &BGPMessage{
				Header: &BGPHeader{
					Length: 21,
					Type:   3,
				},
				Body: &BGPNotification{
					ErrorCode:    1,
					ErrorSubcode: 1,
				},
			},
		},
		{
			// Proper OPEN packet
			testNum: 4,
			input: []byte{
				255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // Marker
				0, 29, // Length
				1,      // Type = Open
				4,      // Version
				0, 200, //ASN,
				0, 15, // Holdtime
				10, 20, 30, 40, // BGP Identifier
				0, // Opt Parm Len
			},
			wantFail: false,
			expected: &BGPMessage{
				Header: &BGPHeader{
					Length: 29,
					Type:   1,
				},
				Body: &BGPOpen{
					Version:       4,
Oliver Herms's avatar
Oliver Herms committed
					HoldTime:      15,
					BGPIdentifier: uint32(169090600),
					OptParmLen:    0,
Oliver Herms's avatar
Oliver Herms committed
				},
			},
		},
		{
			// Incomplete OPEN packet
			testNum: 5,
			input: []byte{
				255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // Marker
				0, 28, // Length
				1,      // Type = Open
				4,      // Version
				0, 200, //ASN,
				0, 15, // Holdtime
				0, 0, 0, 100, // BGP Identifier
			},
			wantFail: true,
			expected: &BGPMessage{
				Header: &BGPHeader{
					Length: 28,
					Type:   1,
				},
				Body: &BGPOpen{
					Version:       4,
Oliver Herms's avatar
Oliver Herms committed
					HoldTime:      15,
					BGPIdentifier: uint32(100),
				},
			},
		},
		{
			testNum: 6,
			input: []byte{
				255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // Marker
				0, 28, // Length
				2,                               // Type = Update
				0, 5, 8, 10, 16, 192, 168, 0, 0, // 2 withdraws
			},
			wantFail: false,
			expected: &BGPMessage{
				Header: &BGPHeader{
					Length: 28,
					Type:   2,
				},
				Body: &BGPUpdate{
					WithdrawnRoutesLen: 5,
					WithdrawnRoutes: &NLRI{
Daniel Czerwonk's avatar
Daniel Czerwonk committed
						IP:     strAddr("10.0.0.0"),
Oliver Herms's avatar
Oliver Herms committed
						Pfxlen: 8,
						Next: &NLRI{
Daniel Czerwonk's avatar
Daniel Czerwonk committed
							IP:     strAddr("192.168.0.0"),
Oliver Herms's avatar
Oliver Herms committed
							Pfxlen: 16,
						},
					},
				},
			},
		},
		{
			testNum: 7,
			input: []byte{
				255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // Marker
				0, 28, // Length
				5,                               // Type = Invalid
				0, 5, 8, 10, 16, 192, 168, 0, 0, // Some more stuff
			},
			wantFail: true,
		},
Oliver Herms's avatar
Oliver Herms committed
		{
			testNum: 8,
			input: []byte{
				255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
				0, 21,
				3,
				6, 4,
			},
			wantFail: false,
			expected: &BGPMessage{
				Header: &BGPHeader{
					Length: 21,
					Type:   3,
				},
				Body: &BGPNotification{
					ErrorCode:    6,
					ErrorSubcode: 4,
				},
			},
		},
Oliver Herms's avatar
Oliver Herms committed
	}

	for _, test := range tests {
		buf := bytes.NewBuffer(test.input)
		msg, err := Decode(buf, &DecodeOptions{})
Oliver Herms's avatar
Oliver Herms committed

		if err != nil && !test.wantFail {
			t.Errorf("Unexpected error in test %d: %v", test.testNum, err)
			continue
		}

		if err == nil && test.wantFail {
			t.Errorf("Expected error did not happen in test %d", test.testNum)
			continue
		}

		if err != nil && test.wantFail {
			continue
		}

		if msg == nil {
			t.Errorf("Unexpected nil result in test %d. Expected: %v", test.testNum, test.expected)
			continue
		}

Oliver Herms's avatar
Oliver Herms committed
		assert.Equalf(t, test.expected, msg, "Test: %d", test.testNum)
Oliver Herms's avatar
Oliver Herms committed
	}
}

func TestDecodeNotificationMsg(t *testing.T) {
	tests := []struct {
		name     string
		input    []byte
		wantFail bool
		expected interface{}
	}{
		{
			name:     "Invalid error code",
			input:    []byte{0, 0},
			wantFail: true,
		},
		{
			name:     "Invalid error code #2",
			input:    []byte{7, 0},
			wantFail: true,
		},
		{
			name:     "Invalid ErrSubCode (Header)",
			input:    []byte{1, 0},
			wantFail: true,
		},
		{
			name:     "Invalid ErrSubCode (Header) #2",
			input:    []byte{1, 4},
			wantFail: true,
		},
		{
			name:     "Invalid ErrSubCode (Open)",
			input:    []byte{2, 0},
			wantFail: true,
		},
		{
			name:     "Invalid ErrSubCode (Open) #2",
			input:    []byte{2, 7},
			wantFail: true,
		},
		{
			name:     "Invalid ErrSubCode (Open) #3",
			input:    []byte{2, 5},
			wantFail: true,
		},
		{
			name:     "Invalid ErrSubCode (Update)",
			input:    []byte{3, 0},
			wantFail: true,
		},
		{
			name:     "Invalid ErrSubCode (Update) #2",
			input:    []byte{3, 12},
			wantFail: true,
		},
		{
			name:     "Invalid ErrSubCode (Update) #3",
			input:    []byte{3, 7},
			wantFail: true,
		},
		{
			name:     "Valid Notification",
			input:    []byte{2, 2},
			wantFail: false,
			expected: &BGPNotification{
				ErrorCode:    2,
				ErrorSubcode: 2,
			},
		},
		{
			name:     "Empty input",
			input:    []byte{},
			wantFail: true,
		},
		{
			name:     "Hold Timer Expired",
			input:    []byte{4, 0},
			wantFail: false,
			expected: &BGPNotification{
				ErrorCode:    4,
				ErrorSubcode: 0,
			},
		},
		{
			name:     "Hold Timer Expired (invalid subcode)",
			input:    []byte{4, 1},
			wantFail: true,
		},
		{
			name:     "FSM Error",
			input:    []byte{5, 0},
			wantFail: false,
			expected: &BGPNotification{
				ErrorCode:    5,
				ErrorSubcode: 0,
			},
		},
		{
			name:     "FSM Error (invalid subcode)",
			input:    []byte{5, 1},
			wantFail: true,
		},
		{
			name:     "Cease",
			input:    []byte{6, 0},
			wantFail: false,
			expected: &BGPNotification{
				ErrorCode:    6,
				ErrorSubcode: 0,
			},
		},
		{
			name:     "Cease (invalid subcode)",
			input:    []byte{6, 1},
			wantFail: true,
		},
	}

	for _, test := range tests {
		res, err := decodeNotificationMsg(bytes.NewBuffer(test.input))

		if test.wantFail {
			if err != nil {
				continue
			}
			t.Errorf("Expected error did not happen for test %q", test.name)
			continue
		}

		if err != nil {
			t.Errorf("Unexpected failure for test %q: %v", test.name, err)
			continue
		}

		assert.Equal(t, test.expected, res)
	}
}

func TestDecodeUpdateMsg(t *testing.T) {
	tests := []struct {
		testNum        int
		input          []byte
		explicitLength uint16
		wantFail       bool
		expected       interface{}
	}{
		{
			// 2 withdraws only, valid update
			testNum:  1,
			input:    []byte{0, 5, 8, 10, 16, 192, 168, 0, 0},
			wantFail: false,
			expected: &BGPUpdate{
				WithdrawnRoutesLen: 5,
				WithdrawnRoutes: &NLRI{
Daniel Czerwonk's avatar
Daniel Czerwonk committed
					IP:     strAddr("10.0.0.0"),
Oliver Herms's avatar
Oliver Herms committed
					Pfxlen: 8,
					Next: &NLRI{
Daniel Czerwonk's avatar
Daniel Czerwonk committed
						IP:     strAddr("192.168.0.0"),
Oliver Herms's avatar
Oliver Herms committed
						Pfxlen: 16,
					},
				},
			},
		},
		{
			// 2 withdraws with one path attribute (ORIGIN), valid update
			testNum: 2,
			input: []byte{
				0, 5, // Withdrawn Routes Length
				8, 10, // 10.0.0.0/8
				16, 192, 168, // 192.168.0.0/16
				0, 5, // Total Path Attribute Length
				255,  // Attribute flags
				1,    // Attribute Type code
				0, 1, // Length
				2, // INCOMPLETE
			},
			wantFail: false,
			expected: &BGPUpdate{
				WithdrawnRoutesLen: 5,
				WithdrawnRoutes: &NLRI{
Daniel Czerwonk's avatar
Daniel Czerwonk committed
					IP:     strAddr("10.0.0.0"),
Oliver Herms's avatar
Oliver Herms committed
					Pfxlen: 8,
					Next: &NLRI{
Daniel Czerwonk's avatar
Daniel Czerwonk committed
						IP:     strAddr("192.168.0.0"),
Oliver Herms's avatar
Oliver Herms committed
						Pfxlen: 16,
					},
				},
				TotalPathAttrLen: 5,
				PathAttributes: &PathAttribute{
					Optional:       true,
					Transitive:     true,
					Partial:        true,
					ExtendedLength: true,
					Length:         1,
					TypeCode:       1,
					Value:          uint8(2),
				},
			},
		},
		{
			// 2 withdraws with two path attributes (ORIGIN + ASPath), valid update
			testNum: 3,
			input: []byte{0, 5, 8, 10, 16, 192, 168,
				0, 14, // Total Path Attribute Length

				255,  // Attribute flags
				1,    // Attribute Type code (ORIGIN)
				0, 1, // Length
				2, // INCOMPLETE

				0,      // Attribute flags
				2,      // Attribute Type code (AS Path)
				6,      // Length
				2,      // Type = AS_SEQUENCE
				2,      // Path Segement Length
				59, 65, // AS15169
				12, 248, // AS3320
			},
			wantFail: false,
			expected: &BGPUpdate{
				WithdrawnRoutesLen: 5,
				WithdrawnRoutes: &NLRI{
Daniel Czerwonk's avatar
Daniel Czerwonk committed
					IP:     strAddr("10.0.0.0"),
Oliver Herms's avatar
Oliver Herms committed
					Pfxlen: 8,
					Next: &NLRI{
Daniel Czerwonk's avatar
Daniel Czerwonk committed
						IP:     strAddr("192.168.0.0"),
Oliver Herms's avatar
Oliver Herms committed
						Pfxlen: 16,
					},
				},
				TotalPathAttrLen: 14,
				PathAttributes: &PathAttribute{
					Optional:       true,
					Transitive:     true,
					Partial:        true,
					ExtendedLength: true,
					Length:         1,
					TypeCode:       1,
					Value:          uint8(2),
					Next: &PathAttribute{
						Optional:       false,
						Transitive:     false,
						Partial:        false,
						ExtendedLength: false,
						Length:         6,
						TypeCode:       2,
Oliver Herms's avatar
Oliver Herms committed
						Value: types.ASPath{
Oliver Herms's avatar
Oliver Herms committed
							{
Oliver Herms's avatar
Oliver Herms committed
								Type: 2,
Oliver Herms's avatar
Oliver Herms committed
								ASNs: []uint32{
									15169,
									3320,
								},
							},
						},
					},
				},
			},
		},
		{
			// 2 withdraws with two path attributes (ORIGIN + ASPath), invalid AS Path segment type
			testNum: 4,
			input: []byte{0, 5, 8, 10, 16, 192, 168,
				0, 13, // Total Path Attribute Length

				255,  // Attribute flags
				1,    // Attribute Type code (ORIGIN)
				0, 1, // Length
				2, // INCOMPLETE

				0, // Attribute flags
				2, // Attribute Type code (AS Path)
				6, // Length
				1, // Type = AS_SET
				0, // Path Segement Length
			},
			wantFail: true,
		},
		{
			// 2 withdraws with two path attributes (ORIGIN + ASPath), invalid AS Path segment member count
			testNum: 5,
			input: []byte{0, 5, 8, 10, 16, 192, 168,
				0, 13, // Total Path Attribute Length

				255,  // Attribute flags
				1,    // Attribute Type code (ORIGIN)
				0, 1, // Length
				2, // INCOMPLETE

				0,      // Attribute flags
				2,      // Attribute Type code (AS Path)
				6,      // Length
				3,      // Type = INVALID
				2,      // Path Segement Length
				59, 65, // AS15169
				12, 248, // AS3320
			},
			wantFail: true,
		},
		{
			// 2 withdraws with two path attributes (ORIGIN + ASPath), valid update
			testNum: 6,
			input: []byte{0, 5, 8, 10, 16, 192, 168,
				0, 20, // Total Path Attribute Length

				255,  // Attribute flags
				1,    // Attribute Type code (ORIGIN)
				0, 1, // Length
				2, // INCOMPLETE

				0,      // Attribute flags
				2,      // Attribute Type code (AS Path)
				12,     // Length
				2,      // Type = AS_SEQUENCE
				2,      // Path Segement Length
				59, 65, // AS15169
				12, 248, // AS3320
				1,      // Type = AS_SET
				2,      // Path Segement Length
				59, 65, // AS15169
				12, 248, // AS3320
			},
			wantFail: false,
			expected: &BGPUpdate{
				WithdrawnRoutesLen: 5,
				WithdrawnRoutes: &NLRI{
Daniel Czerwonk's avatar
Daniel Czerwonk committed
					IP:     strAddr("10.0.0.0"),
Oliver Herms's avatar
Oliver Herms committed
					Pfxlen: 8,
					Next: &NLRI{
Daniel Czerwonk's avatar
Daniel Czerwonk committed
						IP:     strAddr("192.168.0.0"),
Oliver Herms's avatar
Oliver Herms committed
						Pfxlen: 16,
					},
				},
				TotalPathAttrLen: 20,
				PathAttributes: &PathAttribute{
					Optional:       true,
					Transitive:     true,
					Partial:        true,
					ExtendedLength: true,
					Length:         1,
					TypeCode:       1,
					Value:          uint8(2),
					Next: &PathAttribute{
						Optional:       false,
						Transitive:     false,
						Partial:        false,
						ExtendedLength: false,
						Length:         12,
						TypeCode:       2,
Oliver Herms's avatar
Oliver Herms committed
						Value: types.ASPath{
Oliver Herms's avatar
Oliver Herms committed
							{
Oliver Herms's avatar
Oliver Herms committed
								Type: 2,
Oliver Herms's avatar
Oliver Herms committed
								ASNs: []uint32{
									15169,
									3320,
								},
							},
							{
Oliver Herms's avatar
Oliver Herms committed
								Type: 1,
Oliver Herms's avatar
Oliver Herms committed
								ASNs: []uint32{
									15169,
									3320,
								},
							},
						},
					},
				},
			},
		},
		{
			// 2 withdraws with 3 path attributes (ORIGIN + ASPath, NH), valid update
			testNum: 7,
			input: []byte{0, 5, 8, 10, 16, 192, 168,
				0, 27, // Total Path Attribute Length

				255,  // Attribute flags
				1,    // Attribute Type code (ORIGIN)
				0, 1, // Length
				2, // INCOMPLETE

				0,      // Attribute flags
				2,      // Attribute Type code (AS Path)
				12,     // Length
				2,      // Type = AS_SEQUENCE
				2,      // Path Segement Length
				59, 65, // AS15169
				12, 248, // AS3320
				1,      // Type = AS_SET
				2,      // Path Segement Length
				59, 65, // AS15169
				12, 248, // AS3320

				0,              // Attribute flags
				3,              // Attribute Type code (Next Hop)
				4,              // Length
				10, 11, 12, 13, // Next Hop
			},
			wantFail: false,
			expected: &BGPUpdate{
				WithdrawnRoutesLen: 5,
				WithdrawnRoutes: &NLRI{
Daniel Czerwonk's avatar
Daniel Czerwonk committed
					IP:     strAddr("10.0.0.0"),
Oliver Herms's avatar
Oliver Herms committed
					Pfxlen: 8,
					Next: &NLRI{
Daniel Czerwonk's avatar
Daniel Czerwonk committed
						IP:     strAddr("192.168.0.0"),
Oliver Herms's avatar
Oliver Herms committed
						Pfxlen: 16,
					},
				},
				TotalPathAttrLen: 27,
				PathAttributes: &PathAttribute{

					Optional:       true,
					Transitive:     true,
					Partial:        true,
					ExtendedLength: true,
					Length:         1,
					TypeCode:       1,
					Value:          uint8(2),
					Next: &PathAttribute{

						Optional:       false,
						Transitive:     false,
						Partial:        false,
						ExtendedLength: false,
						Length:         12,
						TypeCode:       2,
Oliver Herms's avatar
Oliver Herms committed
						Value: types.ASPath{
Oliver Herms's avatar
Oliver Herms committed
							{
Oliver Herms's avatar
Oliver Herms committed
								Type: 2,
Oliver Herms's avatar
Oliver Herms committed
								ASNs: []uint32{
									15169,
									3320,
								},
							},
							{
Oliver Herms's avatar
Oliver Herms committed
								Type: 1,
Oliver Herms's avatar
Oliver Herms committed
								ASNs: []uint32{
									15169,
									3320,
								},
							},
						},
						Next: &PathAttribute{
							Optional:       false,
							Transitive:     false,
							Partial:        false,
							ExtendedLength: false,
							Length:         4,
							TypeCode:       3,
							Value:          bnet.IPv4FromOctets(10, 11, 12, 13),
Oliver Herms's avatar
Oliver Herms committed
						},
					},
				},
			},
		},
		{
			// 2 withdraws with 4 path attributes (ORIGIN + ASPath, NH, MED), valid update
			testNum: 8,
			input: []byte{0, 5, 8, 10, 16, 192, 168,
				0, 34, // Total Path Attribute Length

				255,  // Attribute flags
				1,    // Attribute Type code (ORIGIN)
				0, 1, // Length
				2, // INCOMPLETE

				0,      // Attribute flags
				2,      // Attribute Type code (AS Path)
				12,     // Length
				2,      // Type = AS_SEQUENCE
				2,      // Path Segement Length
				59, 65, // AS15169
				12, 248, // AS3320
				1,      // Type = AS_SET
				2,      // Path Segement Length
				59, 65, // AS15169
				12, 248, // AS3320

				0,              // Attribute flags
				3,              // Attribute Type code (Next Hop)
				4,              // Length
				10, 11, 12, 13, // Next Hop

				0,          // Attribute flags
				4,          // Attribute Type code (Next Hop)
				4,          // Length
				0, 0, 1, 0, // MED 256
			},
			wantFail: false,
			expected: &BGPUpdate{
				WithdrawnRoutesLen: 5,
				WithdrawnRoutes: &NLRI{
Daniel Czerwonk's avatar
Daniel Czerwonk committed
					IP:     strAddr("10.0.0.0"),
Oliver Herms's avatar
Oliver Herms committed
					Pfxlen: 8,
					Next: &NLRI{
Daniel Czerwonk's avatar
Daniel Czerwonk committed
						IP:     strAddr("192.168.0.0"),
Oliver Herms's avatar
Oliver Herms committed
						Pfxlen: 16,
					},
				},
				TotalPathAttrLen: 34,
				PathAttributes: &PathAttribute{

					Optional:       true,
					Transitive:     true,
					Partial:        true,
					ExtendedLength: true,
					Length:         1,
					TypeCode:       1,
					Value:          uint8(2),
					Next: &PathAttribute{
						Optional:       false,
						Transitive:     false,
						Partial:        false,
						ExtendedLength: false,
						Length:         12,
						TypeCode:       2,
Oliver Herms's avatar
Oliver Herms committed
						Value: types.ASPath{
Oliver Herms's avatar
Oliver Herms committed
							{
Oliver Herms's avatar
Oliver Herms committed
								Type: 2,
Oliver Herms's avatar
Oliver Herms committed
								ASNs: []uint32{
									15169,
									3320,
								},
							},
							{
Oliver Herms's avatar
Oliver Herms committed
								Type: 1,
Oliver Herms's avatar
Oliver Herms committed
								ASNs: []uint32{
									15169,
									3320,
								},
							},
						},
						Next: &PathAttribute{
							Optional:       false,
							Transitive:     false,
							Partial:        false,
							ExtendedLength: false,
							Length:         4,
							TypeCode:       3,
							Value:          bnet.IPv4FromOctets(10, 11, 12, 13),
Oliver Herms's avatar
Oliver Herms committed
							Next: &PathAttribute{
								Optional:       false,
								Transitive:     false,
								Partial:        false,
								ExtendedLength: false,
								Length:         4,
								TypeCode:       4,
								Value:          uint32(256),
							},
						},
					},
				},
			},
		},
		{
			// 2 withdraws with 4 path attributes (ORIGIN + ASPath, NH, MED, Local Pref), valid update
			testNum: 9,
			input: []byte{0, 5, 8, 10, 16, 192, 168,
				0, 41, // Total Path Attribute Length

				255,  // Attribute flags
				1,    // Attribute Type code (ORIGIN)
				0, 1, // Length
				2, // INCOMPLETE

				0,      // Attribute flags
				2,      // Attribute Type code (AS Path)
				12,     // Length
				2,      // Type = AS_SEQUENCE
				2,      // Path Segement Length
				59, 65, // AS15169
				12, 248, // AS3320
				1,      // Type = AS_SET
				2,      // Path Segement Length
				59, 65, // AS15169
				12, 248, // AS3320

				0,              // Attribute flags
				3,              // Attribute Type code (Next Hop)
				4,              // Length
				10, 11, 12, 13, // Next Hop

				0,          // Attribute flags
				4,          // Attribute Type code (MED)
				4,          // Length
				0, 0, 1, 0, // MED 256

				0,          // Attribute flags
				5,          // Attribute Type code (Local Pref)
				4,          // Length
				0, 0, 1, 0, // Local Pref 256
			},
			wantFail: false,
			expected: &BGPUpdate{
				WithdrawnRoutesLen: 5,
				WithdrawnRoutes: &NLRI{
Daniel Czerwonk's avatar
Daniel Czerwonk committed
					IP:     strAddr("10.0.0.0"),
Oliver Herms's avatar
Oliver Herms committed
					Pfxlen: 8,
					Next: &NLRI{
Daniel Czerwonk's avatar
Daniel Czerwonk committed
						IP:     strAddr("192.168.0.0"),
Oliver Herms's avatar
Oliver Herms committed
						Pfxlen: 16,
					},
				},
				TotalPathAttrLen: 41,
				PathAttributes: &PathAttribute{
					Optional:       true,
					Transitive:     true,
					Partial:        true,
					ExtendedLength: true,
					Length:         1,
					TypeCode:       1,
					Value:          uint8(2),
					Next: &PathAttribute{
						Optional:       false,
						Transitive:     false,
						Partial:        false,
						ExtendedLength: false,
						Length:         12,
						TypeCode:       2,
Oliver Herms's avatar
Oliver Herms committed
						Value: types.ASPath{
Oliver Herms's avatar
Oliver Herms committed
							{
Oliver Herms's avatar
Oliver Herms committed
								Type: 2,
Oliver Herms's avatar
Oliver Herms committed
								ASNs: []uint32{
									15169,
									3320,
								},
							},
							{
Oliver Herms's avatar
Oliver Herms committed
								Type: 1,
Oliver Herms's avatar
Oliver Herms committed
								ASNs: []uint32{
									15169,
									3320,
								},
							},
						},
						Next: &PathAttribute{
							Optional:       false,
							Transitive:     false,
							Partial:        false,
							ExtendedLength: false,
							Length:         4,
							TypeCode:       3,
							Value:          bnet.IPv4FromOctets(10, 11, 12, 13),
Oliver Herms's avatar
Oliver Herms committed
							Next: &PathAttribute{
								Optional:       false,
								Transitive:     false,
								Partial:        false,
								ExtendedLength: false,
								Length:         4,
								TypeCode:       4,
								Value:          uint32(256),
								Next: &PathAttribute{
									Optional:       false,
									Transitive:     false,
									Partial:        false,
									ExtendedLength: false,
									Length:         4,
									TypeCode:       5,
									Value:          uint32(256),
								},
							},
						},
					},
				},
			},
		},
		{
			// 2 withdraws with 6 path attributes (ORIGIN, ASPath, NH, MED, Local Pref, Atomi Aggregate), valid update
			testNum: 9,
			input: []byte{0, 5, 8, 10, 16, 192, 168,
				0, 44, // Total Path Attribute Length

				255,  // Attribute flags
				1,    // Attribute Type code (ORIGIN)
				0, 1, // Length
				2, // INCOMPLETE

				0,      // Attribute flags
				2,      // Attribute Type code (AS Path)
				12,     // Length
				2,      // Type = AS_SEQUENCE
				2,      // Path Segement Length
				59, 65, // AS15169
				12, 248, // AS3320
				1,      // Type = AS_SET
				2,      // Path Segement Length
				59, 65, // AS15169
				12, 248, // AS3320

				0,              // Attribute flags
				3,              // Attribute Type code (Next Hop)
				4,              // Length
				10, 11, 12, 13, // Next Hop

				0,          // Attribute flags
				4,          // Attribute Type code (MED)
				4,          // Length
				0, 0, 1, 0, // MED 256

				0,          // Attribute flags
				5,          // Attribute Type code (Local Pref)
				4,          // Length
				0, 0, 1, 0, // Local Pref 256

				0, // Attribute flags
				6, // Attribute Type code (Atomic Aggregate)
				0, // Length
			},
			wantFail: false,
			expected: &BGPUpdate{
				WithdrawnRoutesLen: 5,
				WithdrawnRoutes: &NLRI{
Daniel Czerwonk's avatar
Daniel Czerwonk committed
					IP:     strAddr("10.0.0.0"),
Oliver Herms's avatar
Oliver Herms committed
					Pfxlen: 8,
					Next: &NLRI{
Daniel Czerwonk's avatar
Daniel Czerwonk committed
						IP:     strAddr("192.168.0.0"),
Oliver Herms's avatar
Oliver Herms committed
						Pfxlen: 16,
					},
				},
				TotalPathAttrLen: 44,
				PathAttributes: &PathAttribute{
					Optional:       true,