Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ISIS: Fix extended IP reachability TLV ser/des #476

Merged
merged 1 commit into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading