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 package packet
import (
"fmt"
)
const ( const (
OctetLen = 8 OctetLen = 8
MaxASNsSegment = 255 MaxASNsSegment = 255
BGP4Version = 4 BGP4Version = 4
MinOpenLen = 29 MinOpenLen = 29
MarkerLen = 16 MarkerLen = 16
HeaderLen = 19 HeaderLen = 19
MinLen = 19 MinLen = 19
MaxLen = 4096 MaxLen = 4096
NLRIMaxLen = 5 NLRIMaxLen = 5
LargeCommunityLen = 12
OpenMsg = 1 OpenMsg = 1
UpdateMsg = 2 UpdateMsg = 2
...@@ -177,13 +174,3 @@ type Aggretator struct { ...@@ -177,13 +174,3 @@ type Aggretator struct {
Addr uint32 Addr uint32
ASN uint16 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 { ...@@ -171,7 +171,7 @@ func (pa *PathAttribute) decodeNextHop(buf *bytes.Buffer) error {
func (pa *PathAttribute) decodeMED(buf *bytes.Buffer) error { func (pa *PathAttribute) decodeMED(buf *bytes.Buffer) error {
med, err := pa.decodeUint32(buf) med, err := pa.decodeUint32(buf)
if err != nil { 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) pa.Value = uint32(med)
...@@ -181,7 +181,7 @@ func (pa *PathAttribute) decodeMED(buf *bytes.Buffer) error { ...@@ -181,7 +181,7 @@ func (pa *PathAttribute) decodeMED(buf *bytes.Buffer) error {
func (pa *PathAttribute) decodeLocalPref(buf *bytes.Buffer) error { func (pa *PathAttribute) decodeLocalPref(buf *bytes.Buffer) error {
lpref, err := pa.decodeUint32(buf) lpref, err := pa.decodeUint32(buf)
if err != nil { 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) pa.Value = uint32(lpref)
...@@ -216,8 +216,7 @@ func (pa *PathAttribute) decodeAggregator(buf *bytes.Buffer) error { ...@@ -216,8 +216,7 @@ func (pa *PathAttribute) decodeAggregator(buf *bytes.Buffer) error {
func (pa *PathAttribute) decodeLargeCommunities(buf *bytes.Buffer) error { func (pa *PathAttribute) decodeLargeCommunities(buf *bytes.Buffer) error {
length := pa.Length length := pa.Length
recordLen := uint16(12) count := length / LargeCommunityLen
count := length / recordLen
coms := make([]LargeCommunity, count) coms := make([]LargeCommunity, count)
...@@ -247,7 +246,7 @@ func (pa *PathAttribute) decodeLargeCommunities(buf *bytes.Buffer) error { ...@@ -247,7 +246,7 @@ func (pa *PathAttribute) decodeLargeCommunities(buf *bytes.Buffer) error {
pa.Value = coms pa.Value = coms
dump := pa.Length - (count * recordLen) dump := pa.Length - (count * LargeCommunityLen)
return dumpNBytes(buf, dump) return dumpNBytes(buf, dump)
} }
...@@ -363,6 +362,8 @@ func (pa *PathAttribute) serialize(buf *bytes.Buffer) uint8 { ...@@ -363,6 +362,8 @@ func (pa *PathAttribute) serialize(buf *bytes.Buffer) uint8 {
pathAttrLen = pa.serializeAtomicAggregate(buf) pathAttrLen = pa.serializeAtomicAggregate(buf)
case AggregatorAttr: case AggregatorAttr:
pathAttrLen = pa.serializeAggregator(buf) pathAttrLen = pa.serializeAggregator(buf)
case LargeCommunityAttr:
pathAttrLen = pa.serializeLargeCommunities(buf)
} }
return pathAttrLen return pathAttrLen
...@@ -458,6 +459,32 @@ func (pa *PathAttribute) serializeAggregator(buf *bytes.Buffer) uint8 { ...@@ -458,6 +459,32 @@ func (pa *PathAttribute) serializeAggregator(buf *bytes.Buffer) uint8 {
return 5 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) { /*func (pa *PathAttribute) PrependASPath(prepend []uint32) {
if pa.TypeCode != ASPathAttr { if pa.TypeCode != ASPathAttr {
return return
...@@ -539,6 +566,24 @@ func ParseASPathStr(asPathString string) (*PathAttribute, error) { ...@@ -539,6 +566,24 @@ func ParseASPathStr(asPathString string) (*PathAttribute, error) {
}, nil }, 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 { func isBeginOfASSet(asPathPart string) bool {
return strings.Contains(asPathPart, "(") return strings.Contains(asPathPart, "(")
} }
......
...@@ -1195,6 +1195,62 @@ func TestSerializeASPath(t *testing.T) { ...@@ -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) { func TestSerialize(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment