Skip to content

Commit 718efe2

Browse files
committed
rtc: implement default route target and cli support
* add support for cli add/del operations * add support for default route target via api/cli * fix panic while deduplication of default route target * fix rt membership validation, partial prefixes are still not supported, just 0/32/96-bit for consistency * add tests
1 parent 4e5f609 commit 718efe2

File tree

5 files changed

+130
-17
lines changed

5 files changed

+130
-17
lines changed

cmd/gobgp/global.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1651,6 +1651,41 @@ func parseLsArgs(args []string) (bgp.AddrPrefixInterface, *bgp.PathAttributeLs,
16511651
return nil, nil, fmt.Errorf("invalid nlriType. expect [link] but %s", nlriType)
16521652
}
16531653

1654+
func parseRtcArgs(args []string) (bgp.AddrPrefixInterface, error) {
1655+
// Format:
1656+
// asn <asn> rt <rt> | default
1657+
m, err := extractReserved(args, map[string]int{
1658+
"asn": paramSingle,
1659+
"rt": paramSingle,
1660+
"default": paramFlag,
1661+
})
1662+
if err != nil {
1663+
return nil, err
1664+
}
1665+
1666+
if _, ok := m["default"]; ok {
1667+
return bgp.NewRouteTargetMembershipNLRI(0, nil), nil
1668+
}
1669+
1670+
for _, f := range []string{"asn", "rt"} {
1671+
if len(m[f]) == 0 {
1672+
return nil, fmt.Errorf("specify %s", f)
1673+
}
1674+
}
1675+
1676+
asn, err := toAs4Value(m["asn"][0])
1677+
if err != nil {
1678+
return nil, err
1679+
}
1680+
1681+
rt, err := bgp.ParseRouteTarget(m["rt"][0])
1682+
if err != nil {
1683+
return nil, err
1684+
}
1685+
1686+
return bgp.NewRouteTargetMembershipNLRI(asn, rt), nil
1687+
}
1688+
16541689
func extractOrigin(args []string) ([]string, bgp.PathAttributeInterface, error) {
16551690
typ := bgp.BGP_ORIGIN_ATTR_TYPE_INCOMPLETE
16561691
for idx, arg := range args {
@@ -2056,6 +2091,8 @@ func parsePath(rf bgp.RouteFamily, args []string) (*api.Path, error) {
20562091
nlri, psid, extcomms, err = parseMUPArgs(args, bgp.AFI_IP6, nexthop)
20572092
case bgp.RF_LS:
20582093
nlri, ls, err = parseLsArgs(args)
2094+
case bgp.RF_RTC_UC:
2095+
nlri, err = parseRtcArgs(args)
20592096
default:
20602097
return nil, fmt.Errorf("unsupported route family: %s", rf)
20612098
}
@@ -2298,6 +2335,19 @@ usage: %s rib %s key <KEY> [value <VALUE>]`,
22982335
cmdstr,
22992336
modtype,
23002337
)
2338+
2339+
rtcHelpMsgFmt := fmt.Sprintf(`error: %s
2340+
usage: %s rib -a %%s %s %%s [origin { igp | egp | incomplete }] [aspath <ASPATH>] [nexthop <ADDRESS>] [med <NUM>] [local-pref <NUM>] [community <COMMUNITY>] [aigp metric <NUM>] [large-community <LARGE_COMMUNITY>] [aggregator <AGGREGATOR>]
2341+
<ASPATH>: <AS>[,<AS>],
2342+
<COMMUNITY>: xxx:xxx|internet|planned-shut|accept-own|route-filter-translated-v4|route-filter-v4|route-filter-translated-v6|route-filter-v6|llgr-stale|no-llgr|blackhole|no-export|no-advertise|no-export-subconfed|no-peer,
2343+
<LARGE_COMMUNITY>: xxx:xxx:xxx[,<LARGE_COMMUNITY>],
2344+
<AGGREGATOR>: <AS>:<ADDRESS>`,
2345+
err,
2346+
cmdstr,
2347+
modtype,
2348+
)
2349+
helpErrMap[bgp.RF_RTC_UC] = fmt.Errorf(rtcHelpMsgFmt, "rtc", "{ asn <ASN> rt <RT> | default }")
2350+
23012351
if err, ok := helpErrMap[rf]; ok {
23022352
return err
23032353
}

pkg/apiutil/attribute.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1282,7 +1282,12 @@ func MarshalNLRI(value bgp.AddrPrefixInterface) (*apb.Any, error) {
12821282
Prefix: v.Prefix.String(),
12831283
}
12841284
case *bgp.RouteTargetMembershipNLRI:
1285-
rt, err := MarshalRT(v.RouteTarget)
1285+
rt, err := func() (*apb.Any, error) {
1286+
if v.RouteTarget == nil {
1287+
return nil, nil
1288+
}
1289+
return MarshalRT(v.RouteTarget)
1290+
}()
12861291
if err != nil {
12871292
return nil, err
12881293
}
@@ -1620,7 +1625,12 @@ func UnmarshalNLRI(rf bgp.RouteFamily, an *apb.Any) (bgp.AddrPrefixInterface, er
16201625
nlri = bgp.NewLabeledVPNIPv6AddrPrefix(uint8(v.PrefixLen), v.Prefix, *bgp.NewMPLSLabelStack(v.Labels...), rd)
16211626
}
16221627
case *api.RouteTargetMembershipNLRI:
1623-
rt, err := UnmarshalRT(v.Rt)
1628+
rt, err := func() (bgp.ExtendedCommunityInterface, error) {
1629+
if v.Rt == nil {
1630+
return nil, nil
1631+
}
1632+
return UnmarshalRT(v.Rt)
1633+
}()
16241634
if err != nil {
16251635
return nil, err
16261636
}

pkg/packet/bgp/bgp.go

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2296,21 +2296,29 @@ func (n *RouteTargetMembershipNLRI) DecodeFromBytes(data []byte, options ...*Mar
22962296
}
22972297
}
22982298
if len(data) < 1 {
2299-
return NewMessageError(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST), nil, "prefix misses length field")
2299+
eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
2300+
eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
2301+
return NewMessageError(eCode, eSubCode, nil, "prefix misses length field")
23002302
}
23012303
n.Length = data[0]
2302-
data = data[1 : n.Length/8+1]
2303-
if len(data) == 0 {
2304+
if n.Length == 0 {
23042305
return nil
2305-
} else if len(data) != 12 {
2306-
return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all RouteTargetMembershipNLRI bytes available")
2306+
}
2307+
data = data[1:]
2308+
if n.Length < 32 || len(data)*8 < int(n.Length) {
2309+
eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
2310+
eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
2311+
return NewMessageError(eCode, eSubCode, nil, "bad RouteTargetMembershipNLRI length")
23072312
}
23082313
n.AS = binary.BigEndian.Uint32(data[0:4])
2314+
if n.Length < 96 {
2315+
return nil
2316+
}
23092317
rt, err := ParseExtended(data[4:])
2310-
n.RouteTarget = rt
23112318
if err != nil {
23122319
return err
23132320
}
2321+
n.RouteTarget = rt
23142322
return nil
23152323
}
23162324

@@ -2323,13 +2331,16 @@ func (n *RouteTargetMembershipNLRI) Serialize(options ...*MarshallingOption) ([]
23232331
return nil, err
23242332
}
23252333
}
2326-
if n.RouteTarget == nil {
2334+
if n.Length == 0 {
23272335
return append(buf, 0), nil
23282336
}
23292337
offset := len(buf)
23302338
buf = append(buf, make([]byte, 5)...)
2331-
buf[offset] = 96
2339+
buf[offset] = n.Length
23322340
binary.BigEndian.PutUint32(buf[offset+1:], n.AS)
2341+
if n.RouteTarget == nil {
2342+
return buf, nil
2343+
}
23332344
ebuf, err := n.RouteTarget.Serialize()
23342345
if err != nil {
23352346
return nil, err
@@ -2346,14 +2357,14 @@ func (n *RouteTargetMembershipNLRI) SAFI() uint8 {
23462357
}
23472358

23482359
func (n *RouteTargetMembershipNLRI) Len(options ...*MarshallingOption) int {
2349-
if n.AS == 0 && n.RouteTarget == nil {
2350-
return 1
2351-
}
2352-
return 13
2360+
return 1 + (int(n.Length)+7)/8
23532361
}
23542362

23552363
func (n *RouteTargetMembershipNLRI) String() string {
2356-
target := "default"
2364+
if n.Length == 0 {
2365+
return "default"
2366+
}
2367+
target := "0:0"
23572368
if n.RouteTarget != nil {
23582369
target = n.RouteTarget.String()
23592370
}
@@ -2371,7 +2382,9 @@ func (n *RouteTargetMembershipNLRI) MarshalJSON() ([]byte, error) {
23712382
func NewRouteTargetMembershipNLRI(as uint32, target ExtendedCommunityInterface) *RouteTargetMembershipNLRI {
23722383
l := 12 * 8
23732384
if as == 0 && target == nil {
2374-
l = 1
2385+
l = 0
2386+
} else if target == nil {
2387+
l = 32
23752388
}
23762389
return &RouteTargetMembershipNLRI{
23772390
Length: uint8(l),

pkg/packet/bgp/bgp_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,39 @@ func Test_RouteTargetMembershipNLRIString(t *testing.T) {
209209
assert.Equal(nil, err)
210210
assert.Equal("65546:1000000", r.String())
211211

212+
// Default
213+
buf = make([]byte, 1)
214+
buf[0] = 0 // in bit length
215+
r = &RouteTargetMembershipNLRI{}
216+
err = r.DecodeFromBytes(buf)
217+
assert.Equal(nil, err)
218+
assert.Equal("default", r.String())
219+
buf, err = r.Serialize()
220+
assert.Equal(nil, err)
221+
err = r.DecodeFromBytes(buf)
222+
assert.Equal(nil, err)
223+
assert.Equal("default", r.String())
224+
r = NewRouteTargetMembershipNLRI(0, nil)
225+
buf, err = r.Serialize()
226+
assert.Equal(nil, err)
227+
err = r.DecodeFromBytes(buf)
228+
assert.Equal(nil, err)
229+
assert.Equal("default", r.String())
230+
231+
// AS only
232+
buf = make([]byte, 5)
233+
buf[0] = 32 // in bit length
234+
binary.BigEndian.PutUint32(buf[1:5], 65546)
235+
r = &RouteTargetMembershipNLRI{}
236+
err = r.DecodeFromBytes(buf)
237+
assert.Equal(nil, err)
238+
assert.Equal("65546:0:0", r.String())
239+
r = NewRouteTargetMembershipNLRI(65546, nil)
240+
buf, err = r.Serialize()
241+
assert.Equal(nil, err)
242+
err = r.DecodeFromBytes(buf)
243+
assert.Equal(nil, err)
244+
assert.Equal("65546:0:0", r.String())
212245
}
213246

214247
func Test_MalformedUpdateMsg(t *testing.T) {

pkg/server/server.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1322,8 +1322,15 @@ func (s *BgpServer) propagateUpdate(peer *peer, pathList []*table.Path) {
13221322
// Ignore duplicate Membership announcements
13231323
membershipsForSource := s.globalRib.GetPathListWithSource(table.GLOBAL_RIB_NAME, []bgp.RouteFamily{bgp.RF_RTC_UC}, path.GetSource())
13241324
found := false
1325+
equalRT := func(a, b bgp.ExtendedCommunityInterface) bool {
1326+
if a == nil && b == nil {
1327+
return true
1328+
}
1329+
return a != nil && b != nil && a.String() == b.String()
1330+
}
13251331
for _, membership := range membershipsForSource {
1326-
if membership.GetNlri().(*bgp.RouteTargetMembershipNLRI).RouteTarget.String() == rt.String() {
1332+
mrt := membership.GetNlri().(*bgp.RouteTargetMembershipNLRI).RouteTarget
1333+
if equalRT(mrt, rt) {
13271334
found = true
13281335
break
13291336
}

0 commit comments

Comments
 (0)