diff --git a/protocols/bgp/packet/decode_options.go b/protocols/bgp/packet/decode_options.go index 9cea580caaccdd2c2176bae4ab5081f281a6f729..fc50c946ed8027f74e6b0ada18eb54387eccd33e 100644 --- a/protocols/bgp/packet/decode_options.go +++ b/protocols/bgp/packet/decode_options.go @@ -1,5 +1,7 @@ package packet +// DecodeOptions represents options for the BGP message decoder type DecodeOptions struct { + AddPath bool Use32BitASN bool } diff --git a/protocols/bgp/packet/decoder.go b/protocols/bgp/packet/decoder.go index a6f226e49150210b4e3b781a30c571d18b191048..736137582bf1d73f5b474297cdaaf3c6cd8ba167 100644 --- a/protocols/bgp/packet/decoder.go +++ b/protocols/bgp/packet/decoder.go @@ -49,7 +49,7 @@ func decodeUpdateMsg(buf *bytes.Buffer, l uint16, opt *DecodeOptions) (*BGPUpdat return msg, err } - msg.WithdrawnRoutes, err = decodeNLRIs(buf, uint16(msg.WithdrawnRoutesLen), IPv4AFI) + msg.WithdrawnRoutes, err = decodeNLRIs(buf, uint16(msg.WithdrawnRoutesLen), IPv4AFI, opt.AddPath) if err != nil { return msg, err } @@ -66,7 +66,7 @@ func decodeUpdateMsg(buf *bytes.Buffer, l uint16, opt *DecodeOptions) (*BGPUpdat nlriLen := uint16(l) - 4 - uint16(msg.TotalPathAttrLen) - uint16(msg.WithdrawnRoutesLen) if nlriLen > 0 { - msg.NLRI, err = decodeNLRIs(buf, nlriLen, IPv4AFI) + msg.NLRI, err = decodeNLRIs(buf, nlriLen, IPv4AFI, opt.AddPath) if err != nil { return msg, err } diff --git a/protocols/bgp/packet/mp_reach_nlri.go b/protocols/bgp/packet/mp_reach_nlri.go index 513bf5d40265adcca1e00e4186752139eddcd126..e83482e5865dcf0b0084a0aa056c838ae075ed78 100644 --- a/protocols/bgp/packet/mp_reach_nlri.go +++ b/protocols/bgp/packet/mp_reach_nlri.go @@ -40,7 +40,7 @@ func (n *MultiProtocolReachNLRI) serialize(buf *bytes.Buffer, opt *EncodeOptions return uint16(tempBuf.Len()) } -func deserializeMultiProtocolReachNLRI(b []byte) (MultiProtocolReachNLRI, error) { +func deserializeMultiProtocolReachNLRI(b []byte, addPath bool) (MultiProtocolReachNLRI, error) { n := MultiProtocolReachNLRI{} nextHopLength := uint8(0) @@ -80,7 +80,7 @@ func deserializeMultiProtocolReachNLRI(b []byte) (MultiProtocolReachNLRI, error) variable = variable[1+nextHopLength:] // 1 <- RESERVED field buf := bytes.NewBuffer(variable) - nlri, err := decodeNLRIs(buf, uint16(buf.Len()), n.AFI) + nlri, err := decodeNLRIs(buf, uint16(buf.Len()), n.AFI, addPath) if err != nil { return MultiProtocolReachNLRI{}, err } diff --git a/protocols/bgp/packet/nlri.go b/protocols/bgp/packet/nlri.go index 9406c776d2dcadd66f96a4bd71220a6466d2ce31..b5878b56fbe94354811ef0b685d153af9b4b6c0c 100644 --- a/protocols/bgp/packet/nlri.go +++ b/protocols/bgp/packet/nlri.go @@ -6,16 +6,22 @@ import ( "math" bnet "github.com/bio-routing/bio-rd/net" + "github.com/bio-routing/bio-rd/util/decode" "github.com/taktv6/tflow2/convert" ) +const ( + pathIdentifierLen = 4 +) + +// NLRI represents a Network Layer Reachability Information type NLRI struct { PathIdentifier uint32 Prefix bnet.Prefix Next *NLRI } -func decodeNLRIs(buf *bytes.Buffer, length uint16, afi uint16) (*NLRI, error) { +func decodeNLRIs(buf *bytes.Buffer, length uint16, afi uint16, addPath bool) (*NLRI, error) { var ret *NLRI var eol *NLRI var nlri *NLRI @@ -24,7 +30,7 @@ func decodeNLRIs(buf *bytes.Buffer, length uint16, afi uint16) (*NLRI, error) { p := uint16(0) for p < length { - nlri, consumed, err = decodeNLRI(buf, afi) + nlri, consumed, err = decodeNLRI(buf, afi, addPath) if err != nil { return nil, fmt.Errorf("Unable to decode NLRI: %v", err) } @@ -43,10 +49,22 @@ func decodeNLRIs(buf *bytes.Buffer, length uint16, afi uint16) (*NLRI, error) { return ret, nil } -func decodeNLRI(buf *bytes.Buffer, afi uint16) (*NLRI, uint8, error) { +func decodeNLRI(buf *bytes.Buffer, afi uint16, addPath bool) (*NLRI, uint8, error) { nlri := &NLRI{} consumed := uint8(0) + + if addPath { + err := decode.Decode(buf, []interface{}{ + &nlri.PathIdentifier, + }) + if err != nil { + return nil, consumed, fmt.Errorf("Unable to decode path identifier: %v", err) + } + + consumed += pathIdentifierLen + } + pfxLen, err := buf.ReadByte() if err != nil { return nil, consumed, err diff --git a/protocols/bgp/packet/nlri_test.go b/protocols/bgp/packet/nlri_test.go index bd4f6653c5e18b905abdb67b0d4ac176b6677a16..ddbc8d85ae8a61d1a0c10c6243f98b22cea98443 100644 --- a/protocols/bgp/packet/nlri_test.go +++ b/protocols/bgp/packet/nlri_test.go @@ -46,7 +46,7 @@ func TestDecodeNLRIs(t *testing.T) { for _, test := range tests { buf := bytes.NewBuffer(test.input) - res, err := decodeNLRIs(buf, uint16(len(test.input)), IPv4AFI) + res, err := decodeNLRIs(buf, uint16(len(test.input)), IPv4AFI, false) if test.wantFail && err == nil { t.Errorf("Expected error did not happen for test %q", test.name) @@ -64,6 +64,7 @@ func TestDecodeNLRI(t *testing.T) { tests := []struct { name string input []byte + addPath bool wantFail bool expected *NLRI }{ @@ -101,6 +102,56 @@ func TestDecodeNLRI(t *testing.T) { }, wantFail: true, }, + + { + name: "Valid NRLI #1 add path", + input: []byte{ + 0, 0, 0, 10, 24, 192, 168, 0, + }, + addPath: true, + wantFail: false, + expected: &NLRI{ + PathIdentifier: 10, + Prefix: bnet.NewPfx(bnet.IPv4FromOctets(192, 168, 0, 0), 24), + }, + }, + { + name: "Valid NRLI #2 add path", + input: []byte{ + 0, 0, 1, 0, 25, 192, 168, 0, 128, + }, + addPath: true, + wantFail: false, + expected: &NLRI{ + PathIdentifier: 256, + Prefix: bnet.NewPfx(bnet.IPv4FromOctets(192, 168, 0, 128), 25), + }, + }, + { + name: "Incomplete path Identifier", + input: []byte{ + 0, 0, 0, + }, + addPath: true, + wantFail: true, + }, + { + name: "Incomplete NLRI #1 add path", + input: []byte{ + 0, 0, 1, 0, 25, 192, 168, 0, + }, + addPath: true, + wantFail: true, + }, + { + name: "Incomplete NLRI #2 add path", + input: []byte{ + 0, 0, 1, 0, 25, + }, + addPath: true, + wantFail: true, + }, + { name: "Empty input", input: []byte{}, @@ -110,7 +161,7 @@ func TestDecodeNLRI(t *testing.T) { for _, test := range tests { buf := bytes.NewBuffer(test.input) - res, _, err := decodeNLRI(buf, IPv4AFI) + res, _, err := decodeNLRI(buf, IPv4AFI, test.addPath) if test.wantFail && err == nil { t.Errorf("Expected error did not happen for test %q", test.name) diff --git a/protocols/bgp/packet/path_attributes.go b/protocols/bgp/packet/path_attributes.go index ae81d961753c15059925ef26711c5cc99234ff23..f162e277801410660406c187d9216400fe294fa3 100644 --- a/protocols/bgp/packet/path_attributes.go +++ b/protocols/bgp/packet/path_attributes.go @@ -110,7 +110,7 @@ func decodePathAttr(buf *bytes.Buffer, opt *DecodeOptions) (pa *PathAttribute, c return nil, consumed, fmt.Errorf("Failed to decode OriginatorID: %v", err) } case MultiProtocolReachNLRICode: - if err := pa.decodeMultiProtocolReachNLRI(buf); err != nil { + if err := pa.decodeMultiProtocolReachNLRI(buf, opt.AddPath); err != nil { return nil, consumed, fmt.Errorf("Failed to multi protocol reachable NLRI: %v", err) } case MultiProtocolUnreachNLRICode: @@ -134,7 +134,7 @@ func decodePathAttr(buf *bytes.Buffer, opt *DecodeOptions) (pa *PathAttribute, c return pa, consumed + pa.Length, nil } -func (pa *PathAttribute) decodeMultiProtocolReachNLRI(buf *bytes.Buffer) error { +func (pa *PathAttribute) decodeMultiProtocolReachNLRI(buf *bytes.Buffer, addPath bool) error { b := make([]byte, pa.Length) n, err := buf.Read(b) if err != nil { @@ -144,7 +144,7 @@ func (pa *PathAttribute) decodeMultiProtocolReachNLRI(buf *bytes.Buffer) error { return fmt.Errorf("Unable to read %d bytes from buffer, only got %d bytes", pa.Length, n) } - nlri, err := deserializeMultiProtocolReachNLRI(b) + nlri, err := deserializeMultiProtocolReachNLRI(b, addPath) if err != nil { return fmt.Errorf("Unable to decode MP_REACH_NLRI: %v", err) } diff --git a/protocols/bgp/packet/path_attributes_test.go b/protocols/bgp/packet/path_attributes_test.go index 2ddc92834c5592ab5ac30d5274712a389f543be4..1513fecf0352ad76f1bbafa6e29c75385d1bbf80 100644 --- a/protocols/bgp/packet/path_attributes_test.go +++ b/protocols/bgp/packet/path_attributes_test.go @@ -903,6 +903,7 @@ func TestDecodeMultiProtocolReachNLRI(t *testing.T) { tests := []struct { name string input []byte + addPath bool wantFail bool explicitLength uint16 expected *PathAttribute @@ -992,7 +993,7 @@ func TestDecodeMultiProtocolReachNLRI(t *testing.T) { pa := &PathAttribute{ Length: l, } - err := pa.decodeMultiProtocolReachNLRI(bytes.NewBuffer(test.input)) + err := pa.decodeMultiProtocolReachNLRI(bytes.NewBuffer(test.input), test.addPath) if test.wantFail { if err != nil {