summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--docs/sources/cli-command-syntax.md2
-rw-r--r--gobgp/cmd/global.go24
-rw-r--r--packet/bgp/bgp.go125
3 files changed, 148 insertions, 3 deletions
diff --git a/docs/sources/cli-command-syntax.md b/docs/sources/cli-command-syntax.md
index c7e359a2..22ed2f38 100644
--- a/docs/sources/cli-command-syntax.md
+++ b/docs/sources/cli-command-syntax.md
@@ -64,6 +64,8 @@ If you want to remove routes with the address of the ipv6 from global rib:
% gobgp global rib add -a ipv4 10.0.0.0/24 community 100:100,200:200
% gobgp global rib add -a ipv4 10.0.0.0/24 community no-export
% gobgp global rib add -a ipv4 10.0.0.0/24 aigp metric 200
+% gobgp global rib add -a ipv4 10.0.0.0/24 large-community 100:100:100
+% gobgp global rib add -a ipv4 10.0.0.0/24 large-community 100:100:100,200:200:200
% gobgp global rib add -a ipv4-mpls 10.0.0.0/24 100
% gobgp global rib add -a ipv4-mpls 10.0.0.0/24 100/200
% gobgp global rib add -a ipv4-mpls 10.0.0.0/24 100 nexthop 20.20.20.20
diff --git a/gobgp/cmd/global.go b/gobgp/cmd/global.go
index 5c720c4a..5b1e60ef 100644
--- a/gobgp/cmd/global.go
+++ b/gobgp/cmd/global.go
@@ -519,6 +519,25 @@ func extractCommunity(args []string) ([]string, bgp.PathAttributeInterface, erro
return args, nil, nil
}
+func extractLargeCommunity(args []string) ([]string, bgp.PathAttributeInterface, error) {
+ for idx, arg := range args {
+ if arg == "large-community" && len(args) > (idx+1) {
+ elems := strings.Split(args[idx+1], ",")
+ comms := make([]*bgp.LargeCommunity, 0, 1)
+ for _, elem := range elems {
+ c, err := bgp.ParseLargeCommunity(elem)
+ if err != nil {
+ return nil, nil, err
+ }
+ comms = append(comms, c)
+ }
+ args = append(args[:idx], args[idx+2:]...)
+ return args, bgp.NewPathAttributeLargeCommunities(comms), nil
+ }
+ }
+ return args, nil, nil
+}
+
func extractAigp(args []string) ([]string, bgp.PathAttributeInterface, error) {
for idx, arg := range args {
if arg == "aigp" {
@@ -597,6 +616,7 @@ func ParsePath(rf bgp.RouteFamily, args []string) (*api.Path, error) {
extractCommunity,
extractAigp,
extractAggregator,
+ extractLargeCommunity,
}
for _, fn := range fns {
@@ -783,8 +803,8 @@ func modPath(resource api.Resource, name, modtype string, args []string) error {
}
etherTypes := strings.Join(ss, ", ")
helpErrMap := map[bgp.RouteFamily]error{}
- helpErrMap[bgp.RF_IPv4_UC] = fmt.Errorf("usage: %s rib %s <PREFIX> [origin { igp | egp | incomplete }] [nexthop <ADDRESS>] [med <VALUE>] [local-pref <VALUE>] [community <VALUE>] [aigp metric <METRIC>] -a ipv4", cmdstr, modtype)
- helpErrMap[bgp.RF_IPv6_UC] = fmt.Errorf("usage: %s rib %s <PREFIX> [origin { igp | egp | incomplete }] [nexthop <ADDRESS>] [med <VALUE>] [local-pref <VALUE>] [community <VALUE>] [aigp metric <METRIC>] -a ipv6", cmdstr, modtype)
+ helpErrMap[bgp.RF_IPv4_UC] = fmt.Errorf("usage: %s rib %s <PREFIX> [origin { igp | egp | incomplete }] [nexthop <ADDRESS>] [med <VALUE>] [local-pref <VALUE>] [community <VALUE>] [aigp metric <METRIC>] [large-community <VALUE> ] -a ipv4", cmdstr, modtype)
+ helpErrMap[bgp.RF_IPv6_UC] = fmt.Errorf("usage: %s rib %s <PREFIX> [origin { igp | egp | incomplete }] [nexthop <ADDRESS>] [med <VALUE>] [local-pref <VALUE>] [community <VALUE>] [aigp metric <METRIC>] [large-community <VALUE> ] -a ipv6", cmdstr, modtype)
fsHelpMsgFmt := fmt.Sprintf(`err: %s
usage: %s rib %s%%smatch <MATCH_EXPR> then <THEN_EXPR> -a %%s
%%s
diff --git a/packet/bgp/bgp.go b/packet/bgp/bgp.go
index 798644ec..a29a6962 100644
--- a/packet/bgp/bgp.go
+++ b/packet/bgp/bgp.go
@@ -3606,7 +3606,8 @@ const (
BGP_ATTR_TYPE_TUNNEL_ENCAP
_
_
- BGP_ATTR_TYPE_AIGP // = 26
+ BGP_ATTR_TYPE_AIGP // = 26
+ BGP_ATTR_TYPE_LARGE_COMMUNITY BGPAttrType = 41
)
// NOTIFICATION Error Code RFC 4271 4.5.
@@ -3792,6 +3793,7 @@ var PathAttrFlags map[BGPAttrType]BGPAttrFlag = map[BGPAttrType]BGPAttrFlag{
BGP_ATTR_TYPE_PMSI_TUNNEL: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL,
BGP_ATTR_TYPE_TUNNEL_ENCAP: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL,
BGP_ATTR_TYPE_AIGP: BGP_ATTR_FLAG_OPTIONAL,
+ BGP_ATTR_TYPE_LARGE_COMMUNITY: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL,
}
type PathAttributeInterface interface {
@@ -6651,6 +6653,125 @@ func NewPathAttributeAigp(values []AigpTLV) *PathAttributeAigp {
}
}
+type LargeCommunity struct {
+ ASN uint32
+ LocalData1 uint32
+ LocalData2 uint32
+}
+
+func (c *LargeCommunity) Serialize() ([]byte, error) {
+ buf := make([]byte, 12)
+ binary.BigEndian.PutUint32(buf, c.ASN)
+ binary.BigEndian.PutUint32(buf[4:], c.LocalData1)
+ binary.BigEndian.PutUint32(buf[8:], c.LocalData2)
+ return buf, nil
+}
+
+func (c *LargeCommunity) String() string {
+ return fmt.Sprintf("%d:%d:%d", c.ASN, c.LocalData1, c.LocalData2)
+}
+
+func NewLargeCommunity(asn, data1, data2 uint32) *LargeCommunity {
+ return &LargeCommunity{
+ ASN: asn,
+ LocalData1: data1,
+ LocalData2: data2,
+ }
+}
+
+func ParseLargeCommunity(value string) (*LargeCommunity, error) {
+ elems := strings.Split(value, ":")
+ if len(elems) != 3 {
+ return nil, fmt.Errorf("invalid large community format")
+ }
+ v := make([]uint32, 0, 3)
+ for _, elem := range elems {
+ e, err := strconv.ParseUint(elem, 10, 32)
+ if err != nil {
+ return nil, fmt.Errorf("invalid large community format")
+ }
+ v = append(v, uint32(e))
+ }
+ return NewLargeCommunity(v[0], v[1], v[2]), nil
+}
+
+type PathAttributeLargeCommunities struct {
+ PathAttribute
+ Values []*LargeCommunity
+}
+
+func (p *PathAttributeLargeCommunities) DecodeFromBytes(data []byte) error {
+ err := p.PathAttribute.DecodeFromBytes(data)
+ if err != nil {
+ return err
+ }
+
+ rest := p.PathAttribute.Value
+
+ if len(rest)%12 != 0 {
+ eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
+ eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR)
+ return NewMessageError(eCode, eSubCode, nil, "large communities length isn't correct")
+ }
+
+ p.Values = make([]*LargeCommunity, 0, len(rest)/12)
+
+ for len(rest) >= 12 {
+ asn := binary.BigEndian.Uint32(rest[:4])
+ data1 := binary.BigEndian.Uint32(rest[4:8])
+ data2 := binary.BigEndian.Uint32(rest[8:12])
+ p.Values = append(p.Values, NewLargeCommunity(asn, data1, data2))
+ rest = rest[12:]
+ }
+ return nil
+}
+
+func (p *PathAttributeLargeCommunities) Serialize() ([]byte, error) {
+ buf := make([]byte, 0)
+ for _, t := range p.Values {
+ bbuf, err := t.Serialize()
+ if err != nil {
+ return nil, err
+ }
+ buf = append(buf, bbuf...)
+ }
+ p.PathAttribute.Value = buf
+ return p.PathAttribute.Serialize()
+}
+
+func (p *PathAttributeLargeCommunities) String() string {
+ buf := bytes.NewBuffer(make([]byte, 0, 32))
+ buf.WriteString("{LargeCommunity: [ ")
+ ss := []string{}
+ for _, v := range p.Values {
+ ss = append(ss, v.String())
+ }
+ buf.WriteString(strings.Join(ss, ", "))
+ buf.WriteString("]}")
+ return buf.String()
+}
+
+func (p *PathAttributeLargeCommunities) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type BGPAttrType `json:"type"`
+ Value []*LargeCommunity `json:"value"`
+ }{
+ Type: p.GetType(),
+ Value: p.Values,
+ })
+}
+
+func NewPathAttributeLargeCommunities(values []*LargeCommunity) *PathAttributeLargeCommunities {
+ t := BGP_ATTR_TYPE_LARGE_COMMUNITY
+ return &PathAttributeLargeCommunities{
+ PathAttribute: PathAttribute{
+ Flags: PathAttrFlags[t],
+ Type: t,
+ },
+ Values: values,
+ }
+}
+
type PathAttributeUnknown struct {
PathAttribute
}
@@ -6698,6 +6819,8 @@ func GetPathAttribute(data []byte) (PathAttributeInterface, error) {
return &PathAttributePmsiTunnel{}, nil
case BGP_ATTR_TYPE_AIGP:
return &PathAttributeAigp{}, nil
+ case BGP_ATTR_TYPE_LARGE_COMMUNITY:
+ return &PathAttributeLargeCommunities{}, nil
}
return &PathAttributeUnknown{}, nil
}