Skip to content

Commit

Permalink
demoexporter/bmp: add support for large communities
Browse files Browse the repository at this point in the history
  • Loading branch information
vincentbernat committed Sep 27, 2022
1 parent 9b82141 commit ebf3645
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 3 deletions.
7 changes: 7 additions & 0 deletions demoexporter/bmp/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@ func (c *Component) startBMPClient(ctx context.Context) {
}
attrs = append(attrs, bgp.NewPathAttributeCommunities(comms))
}
if route.LargeCommunities != nil {
comms := make([]*bgp.LargeCommunity, len(route.LargeCommunities))
for idx, comm := range route.LargeCommunities {
comms[idx] = (*bgp.LargeCommunity)(&comm)
}
attrs = append(attrs, bgp.NewPathAttributeLargeCommunities(comms))
}
pkt, err = bmp.NewBMPRouteMonitoring(*peerHeader,
bgp.NewBGPUpdateMessage(nil, attrs, nil)).Serialize()
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions demoexporter/bmp/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ func TestClient(t *testing.T) {
netip.MustParsePrefix("2001:db8::/64"),
},
ASPath: []uint32{65001, 65002},
LargeCommunities: []bmp.LargeCommunity{
{ASN: 65000, LocalData1: 100, LocalData2: 200},
{ASN: 65000, LocalData1: 300, LocalData2: 2000},
},
},
}
r := reporter.NewMock(t)
Expand Down
46 changes: 43 additions & 3 deletions demoexporter/bmp/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"strconv"
"strings"
"time"

"github.com/osrg/gobgp/v3/pkg/packet/bgp"
)

// Configuration describes the configuration for the BMP component. Only one peer is emulated.
Expand All @@ -34,12 +36,14 @@ type Configuration struct {

// RouteConfiguration describes a route to be generated with BMP.
type RouteConfiguration struct {
// Prefix is the prefix to announce.
// Prefix is the set of prefixes to announce.
Prefixes []netip.Prefix `validate:"min=1"`
// ASPath is the AS path to associate with the prefix.
// ASPath is the AS path to associate with the prefixes.
ASPath []uint32 `validate:"min=1"`
// Communities are the set of standard communities to associate with the prefix
// Communities are the set of standard communities to associate with the prefixes.
Communities []Community
// LargeCommunities are the set of large communities to associate with the prefixes.
LargeCommunities []LargeCommunity
}

// DefaultConfiguration represents the default configuration for the BMP component.
Expand Down Expand Up @@ -80,3 +84,39 @@ func (comm *Community) UnmarshalText(input []byte) error {
func (comm Community) String() string {
return fmt.Sprintf("%d:%d", comm>>16, comm&0xffff)
}

// LargeCommunity represents a large community.
type LargeCommunity bgp.LargeCommunity

// UnmarshalText parses a large community
func (comm *LargeCommunity) UnmarshalText(input []byte) error {
text := string(input)
elems := strings.Split(text, ":")
if len(elems) != 3 {
return errors.New("community should be ASN:XX:YY")
}
asn, err := strconv.ParseUint(elems[0], 10, 32)
if err != nil {
return errors.New("community should be ASN4:XX:YY")
}
local1, err := strconv.ParseUint(elems[1], 10, 32)
if err != nil {
return errors.New("community should be ASN:XX4:YY")
}
local2, err := strconv.ParseUint(elems[2], 10, 32)
if err != nil {
return errors.New("community should be ASN:XX:YY4")
}
*comm = LargeCommunity{
ASN: uint32(asn),
LocalData1: uint32(local1),
LocalData2: uint32(local2),
}
return nil
}

// String turns a large community to a string.
func (comm LargeCommunity) String() string {
b := bgp.LargeCommunity(comm)
return b.String()
}
29 changes: 29 additions & 0 deletions demoexporter/bmp/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,35 @@ func TestCommunity(t *testing.T) {
}
}

func TestLargeCommunity(t *testing.T) {
cases := []struct {
Input string
Expected LargeCommunity
Error bool
}{
{"12322:20:10", LargeCommunity{12322, 20, 10}, false},
{"65000:10:100", LargeCommunity{65000, 10, 100}, false},
{"65536:10:100", LargeCommunity{65536, 10, 100}, false},
{"65536:1", LargeCommunity{}, true},
{"5000000000:65536:10", LargeCommunity{}, true},
{"kfjgkf", LargeCommunity{}, true},
{"fdgj:gffg:jdfkgjfk", LargeCommunity{}, true},
}
for _, tc := range cases {
var got LargeCommunity
err := got.UnmarshalText([]byte(tc.Input))
if err == nil && tc.Error {
t.Errorf("UnmarshalText(%q) did not error", tc.Input)
} else if err != nil && !tc.Error {
t.Errorf("UnmarshalText(%q) error:\n%+v", tc.Input, err)
} else if err == nil && got != tc.Expected {
t.Errorf("UnmarshalText(%q) == %d, expected %d", tc.Input, got, tc.Expected)
} else if err == nil && got.String() != tc.Input {
t.Errorf("%q.String() == %s", tc.Input, got.String())
}
}
}

func TestDefaultConfiguration(t *testing.T) {
config := DefaultConfiguration()
if err := helpers.Validate.Struct(config); err != nil {
Expand Down

0 comments on commit ebf3645

Please sign in to comment.