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

large community encoding

parent 0cc9da01
No related branches found
No related tags found
No related merge requests found
package packet
import (
"fmt"
)
const (
OctetLen = 8
MaxASNsSegment = 255
BGP4Version = 4
MinOpenLen = 29
MarkerLen = 16
HeaderLen = 19
MinLen = 19
MaxLen = 4096
NLRIMaxLen = 5
MarkerLen = 16
HeaderLen = 19
MinLen = 19
MaxLen = 4096
NLRIMaxLen = 5
LargeCommunityLen = 12
OpenMsg = 1
UpdateMsg = 2
......@@ -177,13 +174,3 @@ type Aggretator struct {
Addr uint32
ASN uint16
}
type LargeCommunity struct {
GlobalAdministrator uint32
DataPart1 uint32
DataPart2 uint32
}
func (c LargeCommunity) String() string {
return fmt.Sprintf("(%d,%d,%d)", c.GlobalAdministrator, c.DataPart1, c.DataPart2)
}
package packet
import (
"fmt"
"strconv"
"strings"
)
type LargeCommunity struct {
GlobalAdministrator uint32
DataPart1 uint32
DataPart2 uint32
}
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) {
s = strings.Trim(s, "()")
t := strings.Split(s, ",")
if len(t) != 3 {
return com, fmt.Errorf("can not parse large community %s", s)
}
v, err := strconv.ParseUint(t[0], 10, 32)
if err != nil {
return com, err
}
com.GlobalAdministrator = uint32(v)
v, err = strconv.ParseUint(t[1], 10, 32)
if err != nil {
return com, err
}
com.DataPart1 = uint32(v)
v, err = strconv.ParseUint(t[2], 10, 32)
if err != nil {
return com, err
}
com.DataPart2 = uint32(v)
return com, err
}
......@@ -171,7 +171,7 @@ func (pa *PathAttribute) decodeNextHop(buf *bytes.Buffer) error {
func (pa *PathAttribute) decodeMED(buf *bytes.Buffer) error {
med, err := pa.decodeUint32(buf)
if err != nil {
return fmt.Errorf("Unable to recode local pref: %v", err)
return fmt.Errorf("Unable to decode local pref: %v", err)
}
pa.Value = uint32(med)
......@@ -181,7 +181,7 @@ func (pa *PathAttribute) decodeMED(buf *bytes.Buffer) error {
func (pa *PathAttribute) decodeLocalPref(buf *bytes.Buffer) error {
lpref, err := pa.decodeUint32(buf)
if err != nil {
return fmt.Errorf("Unable to recode local pref: %v", err)
return fmt.Errorf("Unable to decode local pref: %v", err)
}
pa.Value = uint32(lpref)
......@@ -216,8 +216,7 @@ func (pa *PathAttribute) decodeAggregator(buf *bytes.Buffer) error {
func (pa *PathAttribute) decodeLargeCommunities(buf *bytes.Buffer) error {
length := pa.Length
recordLen := uint16(12)
count := length / recordLen
count := length / LargeCommunityLen
coms := make([]LargeCommunity, count)
......@@ -247,7 +246,7 @@ func (pa *PathAttribute) decodeLargeCommunities(buf *bytes.Buffer) error {
pa.Value = coms
dump := pa.Length - (count * recordLen)
dump := pa.Length - (count * LargeCommunityLen)
return dumpNBytes(buf, dump)
}
......@@ -363,6 +362,8 @@ func (pa *PathAttribute) serialize(buf *bytes.Buffer) uint8 {
pathAttrLen = pa.serializeAtomicAggregate(buf)
case AggregatorAttr:
pathAttrLen = pa.serializeAggregator(buf)
case LargeCommunityAttr:
pathAttrLen = pa.serializeLargeCommunities(buf)
}
return pathAttrLen
......@@ -458,6 +459,32 @@ func (pa *PathAttribute) serializeAggregator(buf *bytes.Buffer) uint8 {
return 5
}
func (pa *PathAttribute) serializeLargeCommunities(buf *bytes.Buffer) uint8 {
coms := pa.Value.([]LargeCommunity)
if len(coms) == 0 {
return 0
}
attrFlags := uint8(0)
attrFlags = setOptional(attrFlags)
attrFlags = setTransitive(attrFlags)
attrFlags = setPartial(attrFlags)
buf.WriteByte(attrFlags)
buf.WriteByte(LargeCommunityAttr)
length := uint8(LargeCommunityLen * len(coms))
buf.WriteByte(length)
for _, com := range coms {
buf.Write(convert.Uint32Byte(com.GlobalAdministrator))
buf.Write(convert.Uint32Byte(com.DataPart1))
buf.Write(convert.Uint32Byte(com.DataPart2))
}
return length
}
/*func (pa *PathAttribute) PrependASPath(prepend []uint32) {
if pa.TypeCode != ASPathAttr {
return
......@@ -539,6 +566,24 @@ func ParseASPathStr(asPathString string) (*PathAttribute, error) {
}, nil
}
func largeCommunityAttributeForString(s string) (*PathAttribute, error) {
strs := strings.Split(s, " ")
coms := make([]LargeCommunity, len(strs))
var err error
for i, str := range strs {
coms[i], err = ParseCommunityString(str)
if err != nil {
return nil, err
}
}
return &PathAttribute{
TypeCode: LargeCommunityAttr,
Value: coms,
}, nil
}
func isBeginOfASSet(asPathPart string) bool {
return strings.Contains(asPathPart, "(")
}
......
......@@ -1195,6 +1195,62 @@ func TestSerializeASPath(t *testing.T) {
}
}
func TestSerializeLargeCommunities(t *testing.T) {
tests := []struct {
name string
input *PathAttribute
expected []byte
expectedLen uint8
}{
{
name: "2 large communities",
input: &PathAttribute{
TypeCode: LargeCommunityAttr,
Value: []LargeCommunity{
{
GlobalAdministrator: 1,
DataPart1: 2,
DataPart2: 3,
},
{
GlobalAdministrator: 4,
DataPart1: 5,
DataPart2: 6,
},
},
},
expected: []byte{
0xe0, // Attribute flags
32, // Type
24, // Length
0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6, // Communities (1, 2, 3), (4, 5, 6)
},
expectedLen: 24,
},
{
name: "empty list of communities",
input: &PathAttribute{
TypeCode: LargeCommunityAttr,
Value: []LargeCommunity{},
},
expected: []byte{},
expectedLen: 0,
},
}
for _, test := range tests {
t.Run(test.name, func(te *testing.T) {
buf := bytes.NewBuffer([]byte{})
n := test.input.serializeLargeCommunities(buf)
if n != test.expectedLen {
t.Fatalf("Unexpected length for test %q: %d", test.name, n)
}
assert.Equal(t, test.expected, buf.Bytes())
})
}
}
func TestSerialize(t *testing.T) {
tests := []struct {
name string
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment