From 1d37c1d73653c8dc8c9264904d4d543b5789c07f Mon Sep 17 00:00:00 2001 From: Oliver Geiselhardt-Herms Date: Sun, 28 Jul 2024 17:25:28 +0200 Subject: [PATCH] ISIS: Fix extended IP reachability TLV ser/des --- net/ip.go | 5 ++ net/prefix.go | 10 ++++ net/prefix_test.go | 44 ++++++++++++++++ protocols/bgp/packet/helper.go | 2 +- protocols/bgp/packet/nlri.go | 11 ++-- protocols/bgp/packet/nlri_test.go | 41 --------------- protocols/bgp/server/update_sender.go | 2 +- .../packet/tlv_extended_ip_reachability.go | 52 ++++++++++++++----- protocols/isis/server/lsp.go | 2 +- 9 files changed, 105 insertions(+), 64 deletions(-) diff --git a/net/ip.go b/net/ip.go index eb860212..cd68fa3e 100644 --- a/net/ip.go +++ b/net/ip.go @@ -9,6 +9,11 @@ import ( bmath "github.com/bio-routing/bio-rd/util/math" ) +const ( + IPv4AddrBytes = 4 + IPv6AddrBytes = 6 +) + var ( v4Loopback = NewPfx(IPv4FromOctets(127, 0, 0, 0), 8).Ptr() ) diff --git a/net/prefix.go b/net/prefix.go index bf865a58..4d8473b6 100644 --- a/net/prefix.go +++ b/net/prefix.go @@ -297,3 +297,13 @@ func (p *Prefix) baseAddr6() IP { return addr } + +// BytesInAddr gets the amount of bytes needed to encode an NLRI (BGP, ISIS) of prefix length pfxlen +func BytesInAddr(pfxlen uint8) uint8 { + return uint8(math.Ceil(float64(pfxlen) / 8)) +} + +// BytesInPrefix gets the amount of bytes needed to encode an NLRI (BGP, ISIS) +func (p *Prefix) BytesInPrefix() uint8 { + return BytesInAddr(p.len) +} diff --git a/net/prefix_test.go b/net/prefix_test.go index 42ae1399..0e38868b 100644 --- a/net/prefix_test.go +++ b/net/prefix_test.go @@ -729,3 +729,47 @@ func TestPrefixFromString(t *testing.T) { assert.Equal(t, test.wantFail, err != nil, test.name) } } + +func TestBytesInAddr(t *testing.T) { + tests := []struct { + name string + input uint8 + expected uint8 + }{ + { + name: "Test #1", + input: 24, + expected: 3, + }, + { + name: "Test #2", + input: 25, + expected: 4, + }, + { + name: "Test #3", + input: 32, + expected: 4, + }, + { + name: "Test #4", + input: 0, + expected: 0, + }, + { + name: "Test #5", + input: 9, + expected: 2, + }, + } + + for _, test := range tests { + p := &Prefix{ + len: test.input, + } + res := p.BytesInPrefix() + if res != test.expected { + t.Errorf("Unexpected result for test %q: %d", test.name, res) + } + } +} diff --git a/protocols/bgp/packet/helper.go b/protocols/bgp/packet/helper.go index cb9b852f..b6ba825f 100644 --- a/protocols/bgp/packet/helper.go +++ b/protocols/bgp/packet/helper.go @@ -7,7 +7,7 @@ import ( ) func deserializePrefix(b []byte, pfxLen uint8, afi uint16) (*bnet.Prefix, error) { - numBytes := BytesInAddr(pfxLen) + numBytes := bnet.BytesInAddr(pfxLen) if numBytes != uint8(len(b)) { return nil, fmt.Errorf("could not parse prefix of length %d. Expected %d bytes, got %d", pfxLen, numBytes, len(b)) diff --git a/protocols/bgp/packet/nlri.go b/protocols/bgp/packet/nlri.go index 6697609a..f60aa61b 100644 --- a/protocols/bgp/packet/nlri.go +++ b/protocols/bgp/packet/nlri.go @@ -3,8 +3,8 @@ package packet import ( "bytes" "fmt" - "math" + "github.com/bio-routing/bio-rd/net" bnet "github.com/bio-routing/bio-rd/net" "github.com/bio-routing/bio-rd/util/decode" "github.com/bio-routing/tflow2/convert" @@ -92,7 +92,7 @@ func decodeNLRI(buf *bytes.Buffer, afi uint16, safi uint8, addPath bool) (*NLRI, } } - numBytes := uint8(BytesInAddr(pfxLen)) + numBytes := uint8(net.BytesInAddr(pfxLen)) bytes := make([]byte, numBytes) r, err := buf.Read(bytes) @@ -137,14 +137,9 @@ func (n *NLRI) serialize(buf *bytes.Buffer, addPath bool, safi uint8) uint8 { } } - pfxNumBytes := BytesInAddr(n.Prefix.Len()) + pfxNumBytes := n.Prefix.BytesInPrefix() buf.Write(n.Prefix.Addr().Bytes()[:pfxNumBytes]) numBytes += pfxNumBytes return numBytes } - -// BytesInAddr gets the amount of bytes needed to encode an NLRI of prefix length pfxlen -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 be85dc6f..899e90ac 100644 --- a/protocols/bgp/packet/nlri_test.go +++ b/protocols/bgp/packet/nlri_test.go @@ -245,47 +245,6 @@ func TestDecodeNLRI(t *testing.T) { } } -func TestBytesInAddr(t *testing.T) { - tests := []struct { - name string - input uint8 - expected uint8 - }{ - { - name: "Test #1", - input: 24, - expected: 3, - }, - { - name: "Test #2", - input: 25, - expected: 4, - }, - { - name: "Test #3", - input: 32, - expected: 4, - }, - { - name: "Test #4", - input: 0, - expected: 0, - }, - { - name: "Test #5", - input: 9, - expected: 2, - }, - } - - for _, test := range tests { - res := BytesInAddr(test.input) - if res != test.expected { - t.Errorf("Unexpected result for test %q: %d", test.name, res) - } - } -} - func TestNLRISerialize(t *testing.T) { tests := []struct { name string diff --git a/protocols/bgp/server/update_sender.go b/protocols/bgp/server/update_sender.go index fd528ea3..0484728b 100644 --- a/protocols/bgp/server/update_sender.go +++ b/protocols/bgp/server/update_sender.go @@ -155,7 +155,7 @@ func (u *UpdateSender) _getUpdateInformation(pathNLRIs *pathPfxs) (*packet.PathA updatesPrefixes := make([][]*bnet.Prefix, 0, 1) prefixes := make([]*bnet.Prefix, 0, 1) for _, pfx := range pathNLRIs.pfxs { - budget -= int(packet.BytesInAddr(pfx.Len())) + 1 + budget -= int(pfx.BytesInPrefix()) + 1 if u.options.UseAddPath { budget -= packet.PathIdentifierLen diff --git a/protocols/isis/packet/tlv_extended_ip_reachability.go b/protocols/isis/packet/tlv_extended_ip_reachability.go index 86656f89..ff0df3a5 100644 --- a/protocols/isis/packet/tlv_extended_ip_reachability.go +++ b/protocols/isis/packet/tlv_extended_ip_reachability.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" + "github.com/bio-routing/bio-rd/net" "github.com/bio-routing/bio-rd/util/decode" "github.com/bio-routing/tflow2/convert" ) @@ -12,8 +13,8 @@ const ( // ExtendedIPReachabilityTLVType is the type value of an Extended IP Reachability TLV ExtendedIPReachabilityTLVType = 135 - // ExtendedIPReachabilityLength is the length of an Extended IP Reachability excluding Sub TLVs - ExtendedIPReachabilityLength = 9 + // ExtendedIPReachabilityMinLength is the minimum length of an Extended IP Reachability excluding Sub TLVs + ExtendedIPReachabilityMinLength = 5 ) // ExtendedIPReachabilityTLV is an Extended IP Reachability TLV @@ -74,12 +75,12 @@ func readExtendedIPReachabilityTLV(buf *bytes.Buffer, tlvType uint8, tlvLength u toRead := tlvLength for toRead > 0 { - extIPReach, err := readExtendedIPReachability(buf) + extIPReach, bytesRead, err := readExtendedIPReachability(buf) if err != nil { return nil, fmt.Errorf("unable to reach extended IP reachability: %w", err) } - toRead -= ExtendedIPReachabilityLength + toRead -= bytesRead for i := range extIPReach.SubTLVs { toRead -= extIPReach.SubTLVs[i].Length() } @@ -121,7 +122,8 @@ func (e *ExtendedIPReachability) Copy() *ExtendedIPReachability { // AddExtendedIPReachability adds an extended IP reachability func (e *ExtendedIPReachabilityTLV) AddExtendedIPReachability(eipr *ExtendedIPReachability) { e.ExtendedIPReachabilities = append(e.ExtendedIPReachabilities, eipr) - e.TLVLength += ExtendedIPReachabilityLength + e.TLVLength += ExtendedIPReachabilityMinLength + net.BytesInAddr(eipr.pfxLen()) + // TODO: Add length of sub TLVs. They will be added as soon as we support for TE } @@ -129,13 +131,20 @@ func (e *ExtendedIPReachabilityTLV) AddExtendedIPReachability(eipr *ExtendedIPRe func (e *ExtendedIPReachability) Serialize(buf *bytes.Buffer) { buf.Write(convert.Uint32Byte(e.Metric)) buf.WriteByte(e.UDSubBitPfxLen) - buf.Write(convert.Uint32Byte(e.Address)) + + n := net.BytesInAddr(e.pfxLen()) + addrBytes := convert.Uint32Byte(e.Address) + buf.Write(addrBytes[:n]) for i := range e.SubTLVs { e.SubTLVs[i].Serialize(buf) } } +func (e *ExtendedIPReachability) pfxLen() uint8 { + return e.UDSubBitPfxLen // FIXME! +} + func (e *ExtendedIPReachability) hasSubTLVs() bool { return e.UDSubBitPfxLen&(uint8(1)<<6) == 64 } @@ -145,28 +154,47 @@ func (e *ExtendedIPReachability) PfxLen() uint8 { return (e.UDSubBitPfxLen << 2) >> 2 } -func readExtendedIPReachability(buf *bytes.Buffer) (*ExtendedIPReachability, error) { +func readExtendedIPReachability(buf *bytes.Buffer) (*ExtendedIPReachability, uint8, error) { e := &ExtendedIPReachability{} fields := []interface{}{ &e.Metric, &e.UDSubBitPfxLen, - &e.Address, } err := decode.Decode(buf, fields) if err != nil { - return nil, fmt.Errorf("unable to decode fields: %v", err) + return nil, 0, fmt.Errorf("unable to decode fields: %v", err) + } + + nBytes := net.BytesInAddr(e.pfxLen()) + bytesRead := ExtendedIPReachabilityMinLength + nBytes + addr := make([]byte, nBytes) + for i := 0; i < int(nBytes); i++ { + buf.Read(addr) + } + + for i := len(addr); i < net.IPv4AddrBytes; i++ { + addr = append(addr, 0) + } + + fields = []interface{}{ + &e.Address, + } + + err = decode.Decode(bytes.NewBuffer(addr), fields) + if err != nil { + return nil, bytesRead, fmt.Errorf("unable to decode fields: %v", err) } if !e.hasSubTLVs() { - return e, nil + return e, bytesRead, nil } subTLVsLen := uint8(0) err = decode.Decode(buf, []interface{}{&subTLVsLen}) if err != nil { - return nil, fmt.Errorf("unable to decode fields: %v", err) + return nil, bytesRead, fmt.Errorf("unable to decode fields: %v", err) } toRead := subTLVsLen @@ -174,5 +202,5 @@ func readExtendedIPReachability(buf *bytes.Buffer) (*ExtendedIPReachability, err // TODO: Read Sub TLVs } - return e, nil + return e, bytesRead, nil } diff --git a/protocols/isis/server/lsp.go b/protocols/isis/server/lsp.go index cb044e2e..53132747 100644 --- a/protocols/isis/server/lsp.go +++ b/protocols/isis/server/lsp.go @@ -67,7 +67,7 @@ func (s *Server) extendedIPReachabilityTLV() *packet.ExtendedIPReachabilityTLV { packet.NewExtendedIPReachability( ifa.cfg.Level2.Metric, addr.Len(), - addr.Addr().ToUint32()), + addr.BaseAddr().ToUint32()), ) } }