Skip to content
Snippets Groups Projects
Unverified Commit 5e140c48 authored by takt's avatar takt Committed by GitHub
Browse files

Merge pull request #125 from bio-routing/feature/refactor_mpunreach_nlri

MP_UNREACH also uses NLRI struct now
parents 381feef7 e2f9583b
No related branches found
No related tags found
No related merge requests found
......@@ -28,11 +28,7 @@ func (n *MultiProtocolReachNLRI) serialize(buf *bytes.Buffer, opt *EncodeOptions
tempBuf.WriteByte(0) // RESERVED
for cur := n.NLRI; cur != nil; cur = cur.Next {
if opt.UseAddPath {
n.NLRI.serializeAddPath(tempBuf)
} else {
n.NLRI.serialize(tempBuf)
}
cur.serialize(tempBuf, opt.UseAddPath)
}
buf.Write(tempBuf.Bytes())
......
......@@ -4,28 +4,24 @@ import (
"bytes"
"fmt"
bnet "github.com/bio-routing/bio-rd/net"
"github.com/bio-routing/bio-rd/util/decode"
"github.com/taktv6/tflow2/convert"
)
// MultiProtocolUnreachNLRI represents network layer withdraw information for one prefix of an IP address family (rfc4760)
type MultiProtocolUnreachNLRI struct {
AFI uint16
SAFI uint8
Prefixes []bnet.Prefix
PathID uint32
AFI uint16
SAFI uint8
NLRI *NLRI
}
func (n *MultiProtocolUnreachNLRI) serialize(buf *bytes.Buffer, opt *EncodeOptions) uint16 {
tempBuf := bytes.NewBuffer(nil)
tempBuf.Write(convert.Uint16Byte(n.AFI))
tempBuf.WriteByte(n.SAFI)
for _, pfx := range n.Prefixes {
if opt.UseAddPath {
tempBuf.Write(convert.Uint32Byte(n.PathID))
}
tempBuf.Write(serializePrefix(pfx))
for cur := n.NLRI; cur != nil; cur = cur.Next {
cur.serialize(tempBuf, opt.UseAddPath)
}
buf.Write(tempBuf.Bytes())
......@@ -33,7 +29,7 @@ func (n *MultiProtocolUnreachNLRI) serialize(buf *bytes.Buffer, opt *EncodeOptio
return uint16(tempBuf.Len())
}
func deserializeMultiProtocolUnreachNLRI(b []byte) (MultiProtocolUnreachNLRI, error) {
func deserializeMultiProtocolUnreachNLRI(b []byte, addPath bool) (MultiProtocolUnreachNLRI, error) {
n := MultiProtocolUnreachNLRI{}
prefixesLength := len(b) - 3 // 3 <- AFI + SAFI
......@@ -41,42 +37,27 @@ func deserializeMultiProtocolUnreachNLRI(b []byte) (MultiProtocolUnreachNLRI, er
return n, fmt.Errorf("Invalid length of MP_UNREACH_NLRI: expected more than 3 bytes but got %d", len(b))
}
prefixes := make([]byte, prefixesLength)
nlris := make([]byte, prefixesLength)
fields := []interface{}{
&n.AFI,
&n.SAFI,
&prefixes,
&nlris,
}
err := decode.Decode(bytes.NewBuffer(b), fields)
if err != nil {
return MultiProtocolUnreachNLRI{}, err
}
if len(prefixes) == 0 {
if len(nlris) == 0 {
return n, nil
}
idx := uint16(0)
for idx < uint16(len(prefixes)) {
pfxLen := prefixes[idx]
numBytes := uint16(BytesInAddr(pfxLen))
idx++
r := uint16(len(prefixes)) - idx
if r < numBytes {
return MultiProtocolUnreachNLRI{}, fmt.Errorf("expected %d bytes for NLRI, only %d remaining", numBytes, r)
}
start := idx
end := idx + numBytes
pfx, err := deserializePrefix(prefixes[start:end], pfxLen, n.AFI)
if err != nil {
return MultiProtocolUnreachNLRI{}, err
}
n.Prefixes = append(n.Prefixes, pfx)
idx = idx + numBytes
buf := bytes.NewBuffer(nlris)
nlri, err := decodeNLRIs(buf, uint16(buf.Len()), n.AFI, addPath)
if err != nil {
return MultiProtocolUnreachNLRI{}, err
}
n.NLRI = nlri
return n, nil
}
......@@ -20,8 +20,8 @@ func TestSerializeMultiProtocolUnreachNLRI(t *testing.T) {
nlri: MultiProtocolUnreachNLRI{
AFI: IPv6AFI,
SAFI: UnicastSAFI,
Prefixes: []bnet.Prefix{
bnet.NewPfx(bnet.IPv6FromBlocks(0x2620, 0x110, 0x9000, 0, 0, 0, 0, 0), 44),
NLRI: &NLRI{
Prefix: bnet.NewPfx(bnet.IPv6FromBlocks(0x2620, 0x110, 0x9000, 0, 0, 0, 0, 0), 44),
},
},
expected: []byte{
......@@ -35,10 +35,10 @@ func TestSerializeMultiProtocolUnreachNLRI(t *testing.T) {
nlri: MultiProtocolUnreachNLRI{
AFI: IPv6AFI,
SAFI: UnicastSAFI,
Prefixes: []bnet.Prefix{
bnet.NewPfx(bnet.IPv6FromBlocks(0x2620, 0x110, 0x9000, 0, 0, 0, 0, 0), 44),
NLRI: &NLRI{
PathIdentifier: 100,
Prefix: bnet.NewPfx(bnet.IPv6FromBlocks(0x2620, 0x110, 0x9000, 0, 0, 0, 0, 0), 44),
},
PathID: 100,
},
expected: []byte{
0x00, 0x02, // AFI
......
......@@ -89,20 +89,22 @@ func decodeNLRI(buf *bytes.Buffer, afi uint16, addPath bool) (*NLRI, uint8, erro
return nlri, consumed, nil
}
func (n *NLRI) serialize(buf *bytes.Buffer) uint8 {
buf.WriteByte(n.Prefix.Pfxlen())
b := n.Prefix.Addr().Bytes()
func (n *NLRI) serialize(buf *bytes.Buffer, addPath bool) uint8 {
numBytes := uint8(0)
nBytes := BytesInAddr(n.Prefix.Pfxlen())
buf.Write(b[:nBytes])
if addPath {
buf.Write(convert.Uint32Byte(n.PathIdentifier))
numBytes += 4
}
return nBytes + 1
}
buf.WriteByte(n.Prefix.Pfxlen())
numBytes++
func (n *NLRI) serializeAddPath(buf *bytes.Buffer) uint8 {
buf.Write(convert.Uint32Byte(n.PathIdentifier))
pfxNumBytes := BytesInAddr(n.Prefix.Pfxlen())
buf.Write(n.Prefix.Addr().Bytes()[:pfxNumBytes])
numBytes += pfxNumBytes
return uint8(n.serialize(buf) + 4)
return numBytes
}
// BytesInAddr gets the amount of bytes needed to encode an NLRI of prefix length pfxlen
......
......@@ -220,6 +220,7 @@ func TestNLRISerialize(t *testing.T) {
tests := []struct {
name string
nlri *NLRI
addPath bool
expected []byte
}{
{
......@@ -243,51 +244,38 @@ func TestNLRISerialize(t *testing.T) {
},
expected: []byte{17, 100, 200, 128},
},
}
for _, test := range tests {
buf := bytes.NewBuffer(nil)
test.nlri.serialize(buf)
res := buf.Bytes()
assert.Equal(t, test.expected, res)
}
}
func TestNLRIAddPathSerialize(t *testing.T) {
tests := []struct {
name string
nlri *NLRI
expected []byte
}{
{
name: "Test #1",
name: "with add-path #1",
nlri: &NLRI{
PathIdentifier: 100,
Prefix: bnet.NewPfx(bnet.IPv4FromOctets(1, 2, 3, 0), 25),
},
addPath: true,
expected: []byte{0, 0, 0, 100, 25, 1, 2, 3, 0},
},
{
name: "Test #2",
name: "with add-path #2",
nlri: &NLRI{
PathIdentifier: 100,
Prefix: bnet.NewPfx(bnet.IPv4FromOctets(1, 2, 3, 0), 24),
},
addPath: true,
expected: []byte{0, 0, 0, 100, 24, 1, 2, 3},
},
{
name: "Test #3",
name: "with add-path #3",
nlri: &NLRI{
PathIdentifier: 100,
Prefix: bnet.NewPfx(bnet.IPv4FromOctets(100, 200, 128, 0), 17),
},
addPath: true,
expected: []byte{0, 0, 0, 100, 17, 100, 200, 128},
},
}
for _, test := range tests {
buf := bytes.NewBuffer(nil)
test.nlri.serializeAddPath(buf)
test.nlri.serialize(buf, test.addPath)
res := buf.Bytes()
assert.Equal(t, test.expected, res)
}
......
......@@ -114,7 +114,7 @@ func decodePathAttr(buf *bytes.Buffer, opt *DecodeOptions) (pa *PathAttribute, c
return nil, consumed, fmt.Errorf("Failed to multi protocol reachable NLRI: %v", err)
}
case MultiProtocolUnreachNLRICode:
if err := pa.decodeMultiProtocolUnreachNLRI(buf); err != nil {
if err := pa.decodeMultiProtocolUnreachNLRI(buf, opt.AddPath); err != nil {
return nil, consumed, fmt.Errorf("Failed to multi protocol unreachable NLRI: %v", err)
}
case AS4AggregatorAttr:
......@@ -153,7 +153,7 @@ func (pa *PathAttribute) decodeMultiProtocolReachNLRI(buf *bytes.Buffer, addPath
return nil
}
func (pa *PathAttribute) decodeMultiProtocolUnreachNLRI(buf *bytes.Buffer) error {
func (pa *PathAttribute) decodeMultiProtocolUnreachNLRI(buf *bytes.Buffer, addPath bool) error {
b := make([]byte, pa.Length)
n, err := buf.Read(b)
if err != nil {
......@@ -163,7 +163,7 @@ func (pa *PathAttribute) decodeMultiProtocolUnreachNLRI(buf *bytes.Buffer) error
return fmt.Errorf("Unable to read %d bytes from buffer, only got %d bytes", pa.Length, n)
}
nlri, err := deserializeMultiProtocolUnreachNLRI(b)
nlri, err := deserializeMultiProtocolUnreachNLRI(b, addPath)
if err != nil {
return fmt.Errorf("Unable to decode MP_UNREACH_NLRI: %v", err)
}
......
......@@ -1037,8 +1037,8 @@ func TestDecodeMultiProtocolUnreachNLRI(t *testing.T) {
Value: MultiProtocolUnreachNLRI{
AFI: IPv6AFI,
SAFI: UnicastSAFI,
Prefixes: []bnet.Prefix{
bnet.NewPfx(bnet.IPv6FromBlocks(0x2620, 0x110, 0x9000, 0, 0, 0, 0, 0), 44),
NLRI: &NLRI{
Prefix: bnet.NewPfx(bnet.IPv6FromBlocks(0x2620, 0x110, 0x9000, 0, 0, 0, 0, 0), 44),
},
},
},
......@@ -1073,7 +1073,7 @@ func TestDecodeMultiProtocolUnreachNLRI(t *testing.T) {
pa := &PathAttribute{
Length: l,
}
err := pa.decodeMultiProtocolUnreachNLRI(bytes.NewBuffer(test.input))
err := pa.decodeMultiProtocolUnreachNLRI(bytes.NewBuffer(test.input), false)
if test.wantFail {
if err != nil {
......
......@@ -18,18 +18,11 @@ type BGPUpdate struct {
// SerializeUpdate serializes an BGPUpdate to wire format
func (b *BGPUpdate) SerializeUpdate(opt *EncodeOptions) ([]byte, error) {
budget := MaxLen - MinLen
nlriLen := 0
buf := bytes.NewBuffer(nil)
withdrawBuf := bytes.NewBuffer(nil)
for withdraw := b.WithdrawnRoutes; withdraw != nil; withdraw = withdraw.Next {
if opt.UseAddPath {
nlriLen = int(withdraw.serializeAddPath(withdrawBuf))
} else {
nlriLen = int(withdraw.serialize(withdrawBuf))
}
budget -= nlriLen
budget -= int(withdraw.serialize(withdrawBuf, opt.UseAddPath))
if budget < 0 {
return nil, fmt.Errorf("update too long")
}
......@@ -46,13 +39,7 @@ func (b *BGPUpdate) SerializeUpdate(opt *EncodeOptions) ([]byte, error) {
nlriBuf := bytes.NewBuffer(nil)
for nlri := b.NLRI; nlri != nil; nlri = nlri.Next {
if opt.UseAddPath {
nlriLen = int(nlri.serializeAddPath(nlriBuf))
} else {
nlriLen = int(nlri.serialize(nlriBuf))
}
budget -= nlriLen
budget -= int(nlri.serialize(nlriBuf, opt.UseAddPath))
if budget < 0 {
return nil, fmt.Errorf("update too long")
}
......@@ -92,8 +79,7 @@ func (b *BGPUpdate) SerializeUpdateAddPath(opt *EncodeOptions) ([]byte, error) {
withdrawBuf := bytes.NewBuffer(nil)
for withdraw := b.WithdrawnRoutes; withdraw != nil; withdraw = withdraw.Next {
nlriLen := int(withdraw.serialize(withdrawBuf))
budget -= nlriLen
budget -= int(withdraw.serialize(withdrawBuf, opt.UseAddPath))
if budget < 0 {
return nil, fmt.Errorf("update too long")
}
......@@ -110,8 +96,7 @@ func (b *BGPUpdate) SerializeUpdateAddPath(opt *EncodeOptions) ([]byte, error) {
nlriBuf := bytes.NewBuffer(nil)
for nlri := b.NLRI; nlri != nil; nlri = nlri.Next {
nlriLen := int(nlri.serialize(nlriBuf))
budget -= nlriLen
budget -= int(nlri.serialize(nlriBuf, opt.UseAddPath))
if budget < 0 {
return nil, fmt.Errorf("update too long")
}
......
......@@ -161,8 +161,8 @@ func (f *fsmAddressFamily) multiProtocolWithdraw(path *route.Path, nlri packet.M
return
}
for _, pfx := range nlri.Prefixes {
f.adjRIBIn.RemovePath(pfx, path)
for cur := nlri.NLRI; cur != nil; cur = cur.Next {
f.adjRIBIn.RemovePath(cur.Prefix, path)
}
}
......
......@@ -311,10 +311,12 @@ func (u *UpdateSender) withdrawPrefixMultiProtocol(out io.Writer, pfx bnet.Prefi
PathAttributes: &packet.PathAttribute{
TypeCode: packet.MultiProtocolUnreachNLRICode,
Value: packet.MultiProtocolUnreachNLRI{
AFI: u.addressFamily.afi,
SAFI: u.addressFamily.safi,
Prefixes: []bnet.Prefix{pfx},
PathID: pathID,
AFI: u.addressFamily.afi,
SAFI: u.addressFamily.safi,
NLRI: &packet.NLRI{
PathIdentifier: pathID,
Prefix: pfx,
},
},
},
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment