Skip to content

Commit

Permalink
ISIS: Fix extended IP reachability TLV ser/des
Browse files Browse the repository at this point in the history
  • Loading branch information
taktv6 authored and BarbarossaTM committed Jul 29, 2024
1 parent 3440ac9 commit 53c49e3
Show file tree
Hide file tree
Showing 10 changed files with 105 additions and 68 deletions.
5 changes: 5 additions & 0 deletions net/ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
)
Expand Down
10 changes: 10 additions & 0 deletions net/prefix.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
44 changes: 44 additions & 0 deletions net/prefix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}
2 changes: 1 addition & 1 deletion protocols/bgp/packet/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
11 changes: 3 additions & 8 deletions protocols/bgp/packet/nlri.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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))
}
41 changes: 0 additions & 41 deletions protocols/bgp/packet/nlri_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion protocols/bgp/server/update_sender.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
48 changes: 36 additions & 12 deletions protocols/isis/packet/tlv_extended_ip_reachability.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand All @@ -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
Expand Down Expand Up @@ -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()
}
Expand Down Expand Up @@ -121,15 +122,19 @@ 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
}

// Serialize serializes an ExtendedIPReachability
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)
Expand All @@ -145,34 +150,53 @@ 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
for toRead > 0 {
// TODO: Read Sub TLVs
}

return e, nil
return e, bytesRead, nil
}
8 changes: 4 additions & 4 deletions protocols/isis/packet/tlv_extended_ip_reachability_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,17 @@ func TestReadExtendedIPReachabilityTLV(t *testing.T) {
input: []byte{
// First Extended IP Reach.
0, 0, 0, 100, // Metric
24, // UDSubBitPfxLen (no sub TLVs)
10, 20, 30, 40, // Address
24, // UDSubBitPfxLen (no sub TLVs)
10, 20, 30, // Address
},
expected: &ExtendedIPReachabilityTLV{
TLVType: 135,
TLVLength: 9,
TLVLength: 8,
ExtendedIPReachabilities: []*ExtendedIPReachability{
{
Metric: 100,
UDSubBitPfxLen: 24,
Address: 169090600,
Address: 169090560,
},
},
},
Expand Down
2 changes: 1 addition & 1 deletion protocols/isis/server/lsp.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (s *Server) extendedIPReachabilityTLV() *packet.ExtendedIPReachabilityTLV {
packet.NewExtendedIPReachability(
ifa.cfg.Level2.Metric,
addr.Len(),
addr.Addr().ToUint32()),
addr.BaseAddr().ToUint32()),
)
}
}
Expand Down

0 comments on commit 53c49e3

Please sign in to comment.