Skip to content
Snippets Groups Projects
Commit 5bf9d69a authored by Daniel Czerwonk's avatar Daniel Czerwonk
Browse files

community convert methods, decoding

parent 29a9e629
No related branches found
No related tags found
No related merge requests found
......@@ -11,6 +11,7 @@ const (
MinLen = 19
MaxLen = 4096
NLRIMaxLen = 5
CommunityLen = 4
LargeCommunityLen = 12
OpenMsg = 1
......
package packet
import (
"fmt"
"strconv"
"strings"
)
func CommunityString(v uint32) string {
e1 := v >> 16
e2 := v - e1<<16
return fmt.Sprintf("(%d,%d)", e1, e2)
}
func ParseCommunityString(s string) (uint32, error) {
s = strings.Trim(s, "()")
t := strings.Split(s, ",")
if len(t) != 2 {
return 0, fmt.Errorf("can not parse community %s", s)
}
v, err := strconv.ParseUint(t[0], 10, 16)
if err != nil {
return 0, err
}
e1 := uint32(v)
v, err = strconv.ParseUint(t[1], 10, 16)
if err != nil {
return 0, err
}
e2 := uint16(v)
return e1<<16 + uint32(e2), nil
}
package packet
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCommunityString(t *testing.T) {
tests := []struct {
name string
value uint32
expected string
}{
{
name: "both elements",
value: 131080,
expected: "(2,8)",
},
{
name: "right element only",
value: 250,
expected: "(0,250)",
},
{
name: "left element only",
value: 131072,
expected: "(2,0)",
},
}
for _, test := range tests {
t.Run(test.name, func(te *testing.T) {
assert.Equal(te, test.expected, CommunityString(test.value))
})
}
}
func TestParseCommunityString(t *testing.T) {
tests := []struct {
name string
value string
expected uint32
wantFail bool
}{
{
name: "both elements",
expected: 131080,
value: "(2,8)",
},
{
name: "right element only",
expected: 250,
value: "(0,250)",
},
{
name: "left element only",
expected: 131072,
value: "(2,0)",
},
{
name: "too big",
value: "(131072,256)",
wantFail: true,
},
{
name: "empty string",
value: "",
wantFail: true,
},
{
name: "random string",
value: "foo-bar",
wantFail: true,
},
}
for _, test := range tests {
t.Run(test.name, func(te *testing.T) {
c, err := ParseCommunityString(test.value)
if test.wantFail {
if err == nil {
te.Fatal("test was expected to fail, but did not")
}
return
}
assert.Equal(te, test.expected, c)
})
}
}
......@@ -16,7 +16,7 @@ func (c LargeCommunity) String() string {
return fmt.Sprintf("(%d,%d,%d)", c.GlobalAdministrator, c.DataPart1, c.DataPart2)
}
func ParseCommunityString(s string) (com LargeCommunity, err error) {
func ParseLargeCommunityString(s string) (com LargeCommunity, err error) {
s = strings.Trim(s, "()")
t := strings.Split(s, ",")
......
......@@ -244,13 +244,15 @@ func (pa *PathAttribute) decodeAggregator(buf *bytes.Buffer) error {
}
func (pa *PathAttribute) decodeCommunities(buf *bytes.Buffer) error {
if pa.Length%4 != 0 {
if pa.Length%CommunityLen != 0 {
return fmt.Errorf("Unable to read community path attribute length %d is not divisible by 4", pa.Length)
}
comNumber := pa.Length / 4
var com = make([]uint32, comNumber)
for i := uint16(0); i < comNumber; i++ {
c := [4]byte{}
count := pa.Length / CommunityLen
coms := make([]uint32, count)
for i := uint16(0); i < count; i++ {
c := [CommunityLen]byte{}
n, err := buf.Read(c[:])
if err != nil {
return err
......@@ -258,16 +260,21 @@ func (pa *PathAttribute) decodeCommunities(buf *bytes.Buffer) error {
if n != 4 {
return fmt.Errorf("Unable to read next hop: buf.Read read %d bytes", n)
}
com[i] = fourBytesToUint32(c)
v := fourBytesToUint32(c)
coms[i] = v
}
pa.Value = com
pa.Value = coms
return nil
}
func (pa *PathAttribute) decodeLargeCommunities(buf *bytes.Buffer) error {
length := pa.Length
count := length / LargeCommunityLen
if pa.Length%LargeCommunityLen != 0 {
return fmt.Errorf("Unable to read large community path attribute. Length %d is not divisible by 12", pa.Length)
}
count := pa.Length / LargeCommunityLen
coms := make([]LargeCommunity, count)
for i := uint16(0); i < count; i++ {
......@@ -295,9 +302,7 @@ func (pa *PathAttribute) decodeLargeCommunities(buf *bytes.Buffer) error {
}
pa.Value = coms
dump := pa.Length - (count * LargeCommunityLen)
return dumpNBytes(buf, dump)
return nil
}
func (pa *PathAttribute) decodeAS4Path(buf *bytes.Buffer) error {
......@@ -646,7 +651,7 @@ func LargeCommunityAttributeForString(s string) (*PathAttribute, error) {
var err error
for i, str := range strs {
coms[i], err = ParseCommunityString(str)
coms[i], err = ParseLargeCommunityString(str)
if err != nil {
return nil, err
}
......
......@@ -657,6 +657,65 @@ func TestDecodeLargeCommunity(t *testing.T) {
}
}
func TestDecodeCommunity(t *testing.T) {
tests := []struct {
name string
input []byte
wantFail bool
explicitLength uint16
expected *PathAttribute
}{
{
name: "two valid communities",
input: []byte{
0, 2, 0, 8, 1, 0, 4, 1, // (2,8), (256,1025)
},
wantFail: false,
expected: &PathAttribute{
Length: 8,
Value: []uint32{
131080, 16777216 + 1025,
},
},
},
{
name: "Empty input",
input: []byte{},
wantFail: false,
expected: &PathAttribute{
Length: 0,
Value: []uint32{},
},
},
}
for _, test := range tests {
l := uint16(len(test.input))
if test.explicitLength != 0 {
l = test.explicitLength
}
pa := &PathAttribute{
Length: l,
}
err := pa.decodeCommunities(bytes.NewBuffer(test.input))
if test.wantFail {
if err != nil {
continue
}
t.Errorf("Expected error did not happen for test %q", test.name)
continue
}
if err != nil {
t.Errorf("Unexpected failure for test %q: %v", test.name, err)
continue
}
assert.Equal(t, test.expected, pa)
}
}
func TestSetLength(t *testing.T) {
tests := []struct {
name string
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment