summaryrefslogtreecommitdiffhomepage
path: root/internal/pkg/apiutil
diff options
context:
space:
mode:
authorFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2018-07-08 00:00:47 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2018-07-08 21:32:32 +0900
commit07f47b7d370e4a2197cf34e3847b2f867b97a40a (patch)
treeae89ab07ea53d9bc34c443efcb5a980d7f3ac625 /internal/pkg/apiutil
parent26aed14b48dc8afce6a3d2faa20f5a8ce95494b6 (diff)
remove package dependency except for grpc in api/
Nothing except for protobuf IDL files and files generated by protobuf in api/. Try to make the APIs portable to any languages. Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Diffstat (limited to 'internal/pkg/apiutil')
-rw-r--r--internal/pkg/apiutil/attribute.go1302
-rw-r--r--internal/pkg/apiutil/attribute_test.go1493
-rw-r--r--internal/pkg/apiutil/capability.go244
-rw-r--r--internal/pkg/apiutil/capability_test.go251
-rw-r--r--internal/pkg/apiutil/util.go114
5 files changed, 3404 insertions, 0 deletions
diff --git a/internal/pkg/apiutil/attribute.go b/internal/pkg/apiutil/attribute.go
new file mode 100644
index 00000000..e149edbb
--- /dev/null
+++ b/internal/pkg/apiutil/attribute.go
@@ -0,0 +1,1302 @@
+// Copyright (C) 2018 Nippon Telegraph and Telephone Corporation.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+// implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package apiutil
+
+import (
+ "errors"
+ "fmt"
+ "net"
+
+ "github.com/golang/protobuf/proto"
+ "github.com/golang/protobuf/ptypes"
+ "github.com/golang/protobuf/ptypes/any"
+ api "github.com/osrg/gobgp/api"
+ "github.com/osrg/gobgp/pkg/packet/bgp"
+ log "github.com/sirupsen/logrus"
+)
+
+func UnmarshalAttribute(an *any.Any) (bgp.PathAttributeInterface, error) {
+ var value ptypes.DynamicAny
+ if err := ptypes.UnmarshalAny(an, &value); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal route distinguisher: %s", err)
+ }
+ switch a := value.Message.(type) {
+ case *api.OriginAttribute:
+ return bgp.NewPathAttributeOrigin(uint8(a.Origin)), nil
+ case *api.AsPathAttribute:
+ params := make([]bgp.AsPathParamInterface, 0, len(a.Segments))
+ for _, segment := range a.Segments {
+ params = append(params, bgp.NewAs4PathParam(uint8(segment.Type), segment.Numbers))
+ }
+ return bgp.NewPathAttributeAsPath(params), nil
+ case *api.NextHopAttribute:
+ nexthop := net.ParseIP(a.NextHop).To4()
+ if nexthop == nil {
+ return nil, fmt.Errorf("invalid nexthop address: %s", a.NextHop)
+ }
+ return bgp.NewPathAttributeNextHop(a.NextHop), nil
+ case *api.MultiExitDiscAttribute:
+ return bgp.NewPathAttributeMultiExitDisc(a.Med), nil
+ case *api.LocalPrefAttribute:
+ return bgp.NewPathAttributeLocalPref(a.LocalPref), nil
+ case *api.AtomicAggregateAttribute:
+ return bgp.NewPathAttributeAtomicAggregate(), nil
+ case *api.AggregatorAttribute:
+ if net.ParseIP(a.Address).To4() == nil {
+ return nil, fmt.Errorf("invalid aggregator address: %s", a.Address)
+ }
+ return bgp.NewPathAttributeAggregator(a.As, a.Address), nil
+ case *api.CommunitiesAttribute:
+ return bgp.NewPathAttributeCommunities(a.Communities), nil
+ case *api.OriginatorIdAttribute:
+ if net.ParseIP(a.Id).To4() == nil {
+ return nil, fmt.Errorf("invalid originator id: %s", a.Id)
+ }
+ return bgp.NewPathAttributeOriginatorId(a.Id), nil
+ case *api.ClusterListAttribute:
+ for _, id := range a.Ids {
+ if net.ParseIP(id).To4() == nil {
+ return nil, fmt.Errorf("invalid cluster list: %s", a.Ids)
+ }
+ }
+ return bgp.NewPathAttributeClusterList(a.Ids), nil
+ }
+ return nil, errors.New("unexpected object")
+}
+
+func NewOriginAttributeFromNative(a *bgp.PathAttributeOrigin) *api.OriginAttribute {
+ return &api.OriginAttribute{
+ Origin: uint32(a.Value),
+ }
+}
+
+func NewAsPathAttributeFromNative(a *bgp.PathAttributeAsPath) *api.AsPathAttribute {
+ segments := make([]*api.AsSegment, 0, len(a.Value))
+ for _, param := range a.Value {
+ segments = append(segments, &api.AsSegment{
+ Type: uint32(param.GetType()),
+ Numbers: param.GetAS(),
+ })
+ }
+ return &api.AsPathAttribute{
+ Segments: segments,
+ }
+}
+
+func NewNextHopAttributeFromNative(a *bgp.PathAttributeNextHop) *api.NextHopAttribute {
+ return &api.NextHopAttribute{
+ NextHop: a.Value.String(),
+ }
+}
+
+func NewMultiExitDiscAttributeFromNative(a *bgp.PathAttributeMultiExitDisc) *api.MultiExitDiscAttribute {
+ return &api.MultiExitDiscAttribute{
+ Med: a.Value,
+ }
+}
+
+func NewLocalPrefAttributeFromNative(a *bgp.PathAttributeLocalPref) *api.LocalPrefAttribute {
+ return &api.LocalPrefAttribute{
+ LocalPref: a.Value,
+ }
+}
+
+func NewAtomicAggregateAttributeFromNative(a *bgp.PathAttributeAtomicAggregate) *api.AtomicAggregateAttribute {
+ return &api.AtomicAggregateAttribute{}
+}
+
+func NewAggregatorAttributeFromNative(a *bgp.PathAttributeAggregator) *api.AggregatorAttribute {
+ return &api.AggregatorAttribute{
+ As: a.Value.AS,
+ Address: a.Value.Address.String(),
+ }
+}
+
+func NewCommunitiesAttributeFromNative(a *bgp.PathAttributeCommunities) *api.CommunitiesAttribute {
+ return &api.CommunitiesAttribute{
+ Communities: a.Value,
+ }
+}
+
+func NewOriginatorIdAttributeFromNative(a *bgp.PathAttributeOriginatorId) *api.OriginatorIdAttribute {
+ return &api.OriginatorIdAttribute{
+ Id: a.Value.String(),
+ }
+}
+
+func NewClusterListAttributeFromNative(a *bgp.PathAttributeClusterList) *api.ClusterListAttribute {
+ ids := make([]string, 0, len(a.Value))
+ for _, id := range a.Value {
+ ids = append(ids, id.String())
+ }
+ return &api.ClusterListAttribute{
+ Ids: ids,
+ }
+}
+
+func MarshalRD(rd bgp.RouteDistinguisherInterface) *any.Any {
+ var r proto.Message
+ switch v := rd.(type) {
+ case *bgp.RouteDistinguisherTwoOctetAS:
+ r = &api.RouteDistinguisherTwoOctetAS{
+ Admin: uint32(v.Admin),
+ Assigned: v.Assigned,
+ }
+ case *bgp.RouteDistinguisherIPAddressAS:
+ r = &api.RouteDistinguisherIPAddress{
+ Admin: v.Admin.String(),
+ Assigned: uint32(v.Assigned),
+ }
+ case *bgp.RouteDistinguisherFourOctetAS:
+ r = &api.RouteDistinguisherFourOctetAS{
+ Admin: v.Admin,
+ Assigned: uint32(v.Assigned),
+ }
+ default:
+ log.WithFields(log.Fields{
+ "Topic": "protobuf",
+ "RD": rd,
+ }).Warn("invalid rd type to marshal")
+ return nil
+ }
+ a, _ := ptypes.MarshalAny(r)
+ return a
+}
+
+func UnmarshalRD(a *any.Any) (bgp.RouteDistinguisherInterface, error) {
+ var value ptypes.DynamicAny
+ if err := ptypes.UnmarshalAny(a, &value); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal route distinguisher: %s", err)
+ }
+ switch v := value.Message.(type) {
+ case *api.RouteDistinguisherTwoOctetAS:
+ return bgp.NewRouteDistinguisherTwoOctetAS(uint16(v.Admin), v.Assigned), nil
+ case *api.RouteDistinguisherIPAddress:
+ rd := bgp.NewRouteDistinguisherIPAddressAS(v.Admin, uint16(v.Assigned))
+ if rd == nil {
+ return nil, fmt.Errorf("invalid address for route distinguisher: %s", v.Admin)
+ }
+ return rd, nil
+ case *api.RouteDistinguisherFourOctetAS:
+ return bgp.NewRouteDistinguisherFourOctetAS(v.Admin, uint16(v.Assigned)), nil
+ }
+ return nil, fmt.Errorf("invalid route distinguisher type: %s", a.TypeUrl)
+}
+
+func NewEthernetSegmentIdentifierFromNative(a *bgp.EthernetSegmentIdentifier) *api.EthernetSegmentIdentifier {
+ return &api.EthernetSegmentIdentifier{
+ Type: uint32(a.Type),
+ Value: a.Value,
+ }
+}
+
+func unmarshalESI(a *api.EthernetSegmentIdentifier) (*bgp.EthernetSegmentIdentifier, error) {
+ return &bgp.EthernetSegmentIdentifier{
+ Type: bgp.ESIType(a.Type),
+ Value: a.Value,
+ }, nil
+}
+
+func MarshalFlowSpecRules(values []bgp.FlowSpecComponentInterface) []*any.Any {
+ rules := make([]*any.Any, 0, len(values))
+ for _, value := range values {
+ var rule proto.Message
+ switch v := value.(type) {
+ case *bgp.FlowSpecDestinationPrefix:
+ rule = &api.FlowSpecIPPrefix{
+ Type: uint32(bgp.FLOW_SPEC_TYPE_DST_PREFIX),
+ PrefixLen: uint32(v.Prefix.(*bgp.IPAddrPrefix).Length),
+ Prefix: v.Prefix.(*bgp.IPAddrPrefix).Prefix.String(),
+ }
+ case *bgp.FlowSpecSourcePrefix:
+ rule = &api.FlowSpecIPPrefix{
+ Type: uint32(bgp.FLOW_SPEC_TYPE_SRC_PREFIX),
+ PrefixLen: uint32(v.Prefix.(*bgp.IPAddrPrefix).Length),
+ Prefix: v.Prefix.(*bgp.IPAddrPrefix).Prefix.String(),
+ }
+ case *bgp.FlowSpecDestinationPrefix6:
+ rule = &api.FlowSpecIPPrefix{
+ Type: uint32(bgp.FLOW_SPEC_TYPE_DST_PREFIX),
+ PrefixLen: uint32(v.Prefix.(*bgp.IPv6AddrPrefix).Length),
+ Prefix: v.Prefix.(*bgp.IPv6AddrPrefix).Prefix.String(),
+ Offset: uint32(v.Offset),
+ }
+ case *bgp.FlowSpecSourcePrefix6:
+ rule = &api.FlowSpecIPPrefix{
+ Type: uint32(bgp.FLOW_SPEC_TYPE_SRC_PREFIX),
+ PrefixLen: uint32(v.Prefix.(*bgp.IPv6AddrPrefix).Length),
+ Prefix: v.Prefix.(*bgp.IPv6AddrPrefix).Prefix.String(),
+ Offset: uint32(v.Offset),
+ }
+ case *bgp.FlowSpecSourceMac:
+ rule = &api.FlowSpecMAC{
+ Type: uint32(bgp.FLOW_SPEC_TYPE_SRC_MAC),
+ Address: v.Mac.String(),
+ }
+ case *bgp.FlowSpecDestinationMac:
+ rule = &api.FlowSpecMAC{
+ Type: uint32(bgp.FLOW_SPEC_TYPE_DST_MAC),
+ Address: v.Mac.String(),
+ }
+ case *bgp.FlowSpecComponent:
+ items := make([]*api.FlowSpecComponentItem, 0, len(v.Items))
+ for _, i := range v.Items {
+ items = append(items, &api.FlowSpecComponentItem{
+ Op: uint32(i.Op),
+ Value: i.Value,
+ })
+ }
+ rule = &api.FlowSpecComponent{
+ Type: uint32(v.Type()),
+ Items: items,
+ }
+ }
+ a, _ := ptypes.MarshalAny(rule)
+ rules = append(rules, a)
+ }
+ return rules
+}
+
+func UnmarshalFlowSpecRules(values []*any.Any) ([]bgp.FlowSpecComponentInterface, error) {
+ rules := make([]bgp.FlowSpecComponentInterface, 0, len(values))
+ for _, an := range values {
+ var rule bgp.FlowSpecComponentInterface
+ var value ptypes.DynamicAny
+ if err := ptypes.UnmarshalAny(an, &value); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal flow spec component: %s", err)
+ }
+ switch v := value.Message.(type) {
+ case *api.FlowSpecIPPrefix:
+ typ := bgp.BGPFlowSpecType(v.Type)
+ isIPv4 := net.ParseIP(v.Prefix).To4() != nil
+ switch {
+ case typ == bgp.FLOW_SPEC_TYPE_DST_PREFIX && isIPv4:
+ rule = bgp.NewFlowSpecDestinationPrefix(bgp.NewIPAddrPrefix(uint8(v.PrefixLen), v.Prefix))
+ case typ == bgp.FLOW_SPEC_TYPE_SRC_PREFIX && isIPv4:
+ rule = bgp.NewFlowSpecSourcePrefix(bgp.NewIPAddrPrefix(uint8(v.PrefixLen), v.Prefix))
+ case typ == bgp.FLOW_SPEC_TYPE_DST_PREFIX && !isIPv4:
+ rule = bgp.NewFlowSpecDestinationPrefix6(bgp.NewIPv6AddrPrefix(uint8(v.PrefixLen), v.Prefix), uint8(v.Offset))
+ case typ == bgp.FLOW_SPEC_TYPE_SRC_PREFIX && !isIPv4:
+ rule = bgp.NewFlowSpecSourcePrefix6(bgp.NewIPv6AddrPrefix(uint8(v.PrefixLen), v.Prefix), uint8(v.Offset))
+ }
+ case *api.FlowSpecMAC:
+ typ := bgp.BGPFlowSpecType(v.Type)
+ mac, err := net.ParseMAC(v.Address)
+ if err != nil {
+ return nil, fmt.Errorf("invalid mac address for %s flow spec component: %s", typ.String(), v.Address)
+ }
+ switch typ {
+ case bgp.FLOW_SPEC_TYPE_SRC_MAC:
+ rule = bgp.NewFlowSpecSourceMac(mac)
+ case bgp.FLOW_SPEC_TYPE_DST_MAC:
+ rule = bgp.NewFlowSpecDestinationMac(mac)
+ }
+ case *api.FlowSpecComponent:
+ items := make([]*bgp.FlowSpecComponentItem, 0, len(v.Items))
+ for _, item := range v.Items {
+ items = append(items, bgp.NewFlowSpecComponentItem(uint8(item.Op), item.Value))
+ }
+ rule = bgp.NewFlowSpecComponent(bgp.BGPFlowSpecType(v.Type), items)
+ }
+ if rule == nil {
+ return nil, fmt.Errorf("invalid flow spec component: %v", value.Message)
+ }
+ rules = append(rules, rule)
+ }
+ return rules, nil
+}
+
+func MarshalNLRI(value bgp.AddrPrefixInterface) *any.Any {
+ var nlri proto.Message
+
+ switch v := value.(type) {
+ case *bgp.IPAddrPrefix:
+ nlri = &api.IPAddressPrefix{
+ PrefixLen: uint32(v.Length),
+ Prefix: v.Prefix.String(),
+ }
+ case *bgp.IPv6AddrPrefix:
+ nlri = &api.IPAddressPrefix{
+ PrefixLen: uint32(v.Length),
+ Prefix: v.Prefix.String(),
+ }
+ case *bgp.LabeledIPAddrPrefix:
+ nlri = &api.LabeledIPAddressPrefix{
+ Labels: v.Labels.Labels,
+ PrefixLen: uint32(v.IPPrefixLen()),
+ Prefix: v.Prefix.String(),
+ }
+ case *bgp.LabeledIPv6AddrPrefix:
+ nlri = &api.LabeledIPAddressPrefix{
+ Labels: v.Labels.Labels,
+ PrefixLen: uint32(v.IPPrefixLen()),
+ Prefix: v.Prefix.String(),
+ }
+ case *bgp.EncapNLRI:
+ nlri = &api.EncapsulationNLRI{
+ Address: v.String(),
+ }
+ case *bgp.Encapv6NLRI:
+ nlri = &api.EncapsulationNLRI{
+ Address: v.String(),
+ }
+ case *bgp.EVPNNLRI:
+ switch r := v.RouteTypeData.(type) {
+ case *bgp.EVPNEthernetAutoDiscoveryRoute:
+ nlri = &api.EVPNEthernetAutoDiscoveryRoute{
+ Rd: MarshalRD(r.RD),
+ Esi: NewEthernetSegmentIdentifierFromNative(&r.ESI),
+ EthernetTag: r.ETag,
+ Label: r.Label,
+ }
+ case *bgp.EVPNMacIPAdvertisementRoute:
+ nlri = &api.EVPNMACIPAdvertisementRoute{
+ Rd: MarshalRD(r.RD),
+ Esi: NewEthernetSegmentIdentifierFromNative(&r.ESI),
+ EthernetTag: r.ETag,
+ MacAddress: r.MacAddress.String(),
+ IpAddress: r.IPAddress.String(),
+ Labels: r.Labels,
+ }
+ case *bgp.EVPNMulticastEthernetTagRoute:
+ nlri = &api.EVPNInclusiveMulticastEthernetTagRoute{
+ Rd: MarshalRD(r.RD),
+ EthernetTag: r.ETag,
+ IpAddress: r.IPAddress.String(),
+ }
+ case *bgp.EVPNEthernetSegmentRoute:
+ nlri = &api.EVPNEthernetSegmentRoute{
+ Rd: MarshalRD(r.RD),
+ Esi: NewEthernetSegmentIdentifierFromNative(&r.ESI),
+ IpAddress: r.IPAddress.String(),
+ }
+ case *bgp.EVPNIPPrefixRoute:
+ nlri = &api.EVPNIPPrefixRoute{
+ Rd: MarshalRD(r.RD),
+ Esi: NewEthernetSegmentIdentifierFromNative(&r.ESI),
+ EthernetTag: r.ETag,
+ IpPrefix: r.IPPrefix.String(),
+ IpPrefixLen: uint32(r.IPPrefixLength),
+ Label: r.Label,
+ }
+ }
+ case *bgp.LabeledVPNIPAddrPrefix:
+ nlri = &api.LabeledVPNIPAddressPrefix{
+ Labels: v.Labels.Labels,
+ Rd: MarshalRD(v.RD),
+ PrefixLen: uint32(v.IPPrefixLen()),
+ Prefix: v.Prefix.String(),
+ }
+ case *bgp.LabeledVPNIPv6AddrPrefix:
+ nlri = &api.LabeledVPNIPAddressPrefix{
+ Labels: v.Labels.Labels,
+ Rd: MarshalRD(v.RD),
+ PrefixLen: uint32(v.IPPrefixLen()),
+ Prefix: v.Prefix.String(),
+ }
+ case *bgp.RouteTargetMembershipNLRI:
+ nlri = &api.RouteTargetMembershipNLRI{
+ As: v.AS,
+ Rt: MarshalRT(v.RouteTarget),
+ }
+ case *bgp.FlowSpecIPv4Unicast:
+ nlri = &api.FlowSpecNLRI{
+ Rules: MarshalFlowSpecRules(v.Value),
+ }
+ case *bgp.FlowSpecIPv6Unicast:
+ nlri = &api.FlowSpecNLRI{
+ Rules: MarshalFlowSpecRules(v.Value),
+ }
+ case *bgp.FlowSpecIPv4VPN:
+ nlri = &api.VPNFlowSpecNLRI{
+ Rd: MarshalRD(v.RD()),
+ Rules: MarshalFlowSpecRules(v.Value),
+ }
+ case *bgp.FlowSpecIPv6VPN:
+ nlri = &api.VPNFlowSpecNLRI{
+ Rd: MarshalRD(v.RD()),
+ Rules: MarshalFlowSpecRules(v.Value),
+ }
+ case *bgp.FlowSpecL2VPN:
+ nlri = &api.VPNFlowSpecNLRI{
+ Rd: MarshalRD(v.RD()),
+ Rules: MarshalFlowSpecRules(v.Value),
+ }
+ }
+
+ an, _ := ptypes.MarshalAny(nlri)
+ return an
+}
+
+func MarshalNLRIs(values []bgp.AddrPrefixInterface) []*any.Any {
+ nlris := make([]*any.Any, 0, len(values))
+ for _, value := range values {
+ nlris = append(nlris, MarshalNLRI(value))
+ }
+ return nlris
+}
+
+func UnmarshalNLRI(rf bgp.RouteFamily, an *any.Any) (bgp.AddrPrefixInterface, error) {
+ var nlri bgp.AddrPrefixInterface
+
+ var value ptypes.DynamicAny
+ if err := ptypes.UnmarshalAny(an, &value); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal nlri: %s", err)
+ }
+
+ switch v := value.Message.(type) {
+ case *api.IPAddressPrefix:
+ switch rf {
+ case bgp.RF_IPv4_UC:
+ nlri = bgp.NewIPAddrPrefix(uint8(v.PrefixLen), v.Prefix)
+ case bgp.RF_IPv6_UC:
+ nlri = bgp.NewIPv6AddrPrefix(uint8(v.PrefixLen), v.Prefix)
+ }
+ case *api.LabeledIPAddressPrefix:
+ switch rf {
+ case bgp.RF_IPv4_MPLS:
+ nlri = bgp.NewLabeledIPAddrPrefix(uint8(v.PrefixLen), v.Prefix, *bgp.NewMPLSLabelStack(v.Labels...))
+ case bgp.RF_IPv6_MPLS:
+ nlri = bgp.NewLabeledIPv6AddrPrefix(uint8(v.PrefixLen), v.Prefix, *bgp.NewMPLSLabelStack(v.Labels...))
+ }
+ case *api.EncapsulationNLRI:
+ switch rf {
+ case bgp.RF_IPv4_ENCAP:
+ nlri = bgp.NewEncapNLRI(v.Address)
+ case bgp.RF_IPv6_ENCAP:
+ nlri = bgp.NewEncapv6NLRI(v.Address)
+ }
+ case *api.EVPNEthernetAutoDiscoveryRoute:
+ if rf == bgp.RF_EVPN {
+ rd, err := UnmarshalRD(v.Rd)
+ if err != nil {
+ return nil, err
+ }
+ esi, err := unmarshalESI(v.Esi)
+ if err != nil {
+ return nil, err
+ }
+ nlri = bgp.NewEVPNEthernetAutoDiscoveryRoute(rd, *esi, v.EthernetTag, v.Label)
+ }
+ case *api.EVPNMACIPAdvertisementRoute:
+ if rf == bgp.RF_EVPN {
+ rd, err := UnmarshalRD(v.Rd)
+ if err != nil {
+ return nil, err
+ }
+ esi, err := unmarshalESI(v.Esi)
+ if err != nil {
+ return nil, err
+ }
+ nlri = bgp.NewEVPNMacIPAdvertisementRoute(rd, *esi, v.EthernetTag, v.MacAddress, v.IpAddress, v.Labels)
+ }
+ case *api.EVPNInclusiveMulticastEthernetTagRoute:
+ if rf == bgp.RF_EVPN {
+ rd, err := UnmarshalRD(v.Rd)
+ if err != nil {
+ return nil, err
+ }
+ nlri = bgp.NewEVPNMulticastEthernetTagRoute(rd, v.EthernetTag, v.IpAddress)
+ }
+ case *api.EVPNEthernetSegmentRoute:
+ if rf == bgp.RF_EVPN {
+ rd, err := UnmarshalRD(v.Rd)
+ if err != nil {
+ return nil, err
+ }
+ esi, err := unmarshalESI(v.Esi)
+ if err != nil {
+ return nil, err
+ }
+ nlri = bgp.NewEVPNEthernetSegmentRoute(rd, *esi, v.IpAddress)
+ }
+ case *api.EVPNIPPrefixRoute:
+ if rf == bgp.RF_EVPN {
+ rd, err := UnmarshalRD(v.Rd)
+ if err != nil {
+ return nil, err
+ }
+ esi, err := unmarshalESI(v.Esi)
+ if err != nil {
+ return nil, err
+ }
+ nlri = bgp.NewEVPNIPPrefixRoute(rd, *esi, v.EthernetTag, uint8(v.IpPrefixLen), v.IpPrefix, v.GwAddress, v.Label)
+ }
+ case *api.LabeledVPNIPAddressPrefix:
+ rd, err := UnmarshalRD(v.Rd)
+ if err != nil {
+ return nil, err
+ }
+ switch rf {
+ case bgp.RF_IPv4_VPN:
+ nlri = bgp.NewLabeledVPNIPAddrPrefix(uint8(v.PrefixLen), v.Prefix, *bgp.NewMPLSLabelStack(v.Labels...), rd)
+ case bgp.RF_IPv6_VPN:
+ nlri = bgp.NewLabeledVPNIPv6AddrPrefix(uint8(v.PrefixLen), v.Prefix, *bgp.NewMPLSLabelStack(v.Labels...), rd)
+ }
+ case *api.RouteTargetMembershipNLRI:
+ rt, err := UnmarshalRT(v.Rt)
+ if err != nil {
+ return nil, err
+ }
+ nlri = bgp.NewRouteTargetMembershipNLRI(v.As, rt)
+ case *api.FlowSpecNLRI:
+ rules, err := UnmarshalFlowSpecRules(v.Rules)
+ if err != nil {
+ return nil, err
+ }
+ switch rf {
+ case bgp.RF_FS_IPv4_UC:
+ nlri = bgp.NewFlowSpecIPv4Unicast(rules)
+ case bgp.RF_FS_IPv6_UC:
+ nlri = bgp.NewFlowSpecIPv6Unicast(rules)
+ }
+ case *api.VPNFlowSpecNLRI:
+ rd, err := UnmarshalRD(v.Rd)
+ if err != nil {
+ return nil, err
+ }
+ rules, err := UnmarshalFlowSpecRules(v.Rules)
+ if err != nil {
+ return nil, err
+ }
+ switch rf {
+ case bgp.RF_FS_IPv4_VPN:
+ nlri = bgp.NewFlowSpecIPv4VPN(rd, rules)
+ case bgp.RF_FS_IPv6_VPN:
+ nlri = bgp.NewFlowSpecIPv6VPN(rd, rules)
+ case bgp.RF_FS_L2_VPN:
+ nlri = bgp.NewFlowSpecL2VPN(rd, rules)
+ }
+ }
+
+ if nlri == nil {
+ return nil, fmt.Errorf("invalid nlri for %s family: %s", rf.String(), value.Message)
+ }
+
+ return nlri, nil
+}
+
+func UnmarshalNLRIs(rf bgp.RouteFamily, values []*any.Any) ([]bgp.AddrPrefixInterface, error) {
+ nlris := make([]bgp.AddrPrefixInterface, 0, len(values))
+ for _, an := range values {
+ nlri, err := UnmarshalNLRI(rf, an)
+ if err != nil {
+ return nil, err
+ }
+ nlris = append(nlris, nlri)
+ }
+ return nlris, nil
+}
+
+func NewMpReachNLRIAttributeFromNative(a *bgp.PathAttributeMpReachNLRI) *api.MpReachNLRIAttribute {
+ var nexthops []string
+ if a.SAFI == bgp.SAFI_FLOW_SPEC_UNICAST || a.SAFI == bgp.SAFI_FLOW_SPEC_VPN {
+ nexthops = nil
+ } else {
+ nexthops = []string{a.Nexthop.String()}
+ if a.LinkLocalNexthop != nil {
+ nexthops = append(nexthops, a.LinkLocalNexthop.String())
+ }
+ }
+ return &api.MpReachNLRIAttribute{
+ Family: uint32(bgp.AfiSafiToRouteFamily(a.AFI, a.SAFI)),
+ NextHops: nexthops,
+ Nlris: MarshalNLRIs(a.Value),
+ }
+}
+
+func NewMpUnreachNLRIAttributeFromNative(a *bgp.PathAttributeMpUnreachNLRI) *api.MpUnreachNLRIAttribute {
+ return &api.MpUnreachNLRIAttribute{
+ Family: uint32(bgp.AfiSafiToRouteFamily(a.AFI, a.SAFI)),
+ Nlris: MarshalNLRIs(a.Value),
+ }
+}
+
+func MarshalRT(rt bgp.ExtendedCommunityInterface) *any.Any {
+ var r proto.Message
+ switch v := rt.(type) {
+ case *bgp.TwoOctetAsSpecificExtended:
+ r = &api.TwoOctetAsSpecificExtended{
+ IsTransitive: true,
+ SubType: uint32(bgp.EC_SUBTYPE_ROUTE_TARGET),
+ As: uint32(v.AS),
+ LocalAdmin: uint32(v.LocalAdmin),
+ }
+ case *bgp.IPv4AddressSpecificExtended:
+ r = &api.IPv4AddressSpecificExtended{
+ IsTransitive: true,
+ SubType: uint32(bgp.EC_SUBTYPE_ROUTE_TARGET),
+ Address: v.IPv4.String(),
+ LocalAdmin: uint32(v.LocalAdmin),
+ }
+ case *bgp.FourOctetAsSpecificExtended:
+ r = &api.FourOctetAsSpecificExtended{
+ IsTransitive: true,
+ SubType: uint32(bgp.EC_SUBTYPE_ROUTE_TARGET),
+ As: uint32(v.AS),
+ LocalAdmin: uint32(v.LocalAdmin),
+ }
+ default:
+ log.WithFields(log.Fields{
+ "Topic": "protobuf",
+ "RT": rt,
+ }).Warn("invalid rt type to marshal")
+ return nil
+ }
+ a, _ := ptypes.MarshalAny(r)
+ return a
+}
+
+func MarshalRTs(values []bgp.ExtendedCommunityInterface) []*any.Any {
+ rts := make([]*any.Any, 0, len(values))
+ for _, rt := range values {
+ rts = append(rts, MarshalRT(rt))
+ }
+ return rts
+}
+
+func UnmarshalRT(a *any.Any) (bgp.ExtendedCommunityInterface, error) {
+ var value ptypes.DynamicAny
+ if err := ptypes.UnmarshalAny(a, &value); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal route target: %s", err)
+ }
+ switch v := value.Message.(type) {
+ case *api.TwoOctetAsSpecificExtended:
+ return bgp.NewTwoOctetAsSpecificExtended(bgp.ExtendedCommunityAttrSubType(v.SubType), uint16(v.As), v.LocalAdmin, v.IsTransitive), nil
+ case *api.IPv4AddressSpecificExtended:
+ rt := bgp.NewIPv4AddressSpecificExtended(bgp.ExtendedCommunityAttrSubType(v.SubType), v.Address, uint16(v.LocalAdmin), v.IsTransitive)
+ if rt == nil {
+ return nil, fmt.Errorf("invalid address for ipv4 address specific route target: %s", v.Address)
+ }
+ return rt, nil
+ case *api.FourOctetAsSpecificExtended:
+ return bgp.NewFourOctetAsSpecificExtended(bgp.ExtendedCommunityAttrSubType(v.SubType), v.As, uint16(v.LocalAdmin), v.IsTransitive), nil
+ }
+ return nil, fmt.Errorf("invalid route target type: %s", a.TypeUrl)
+}
+
+func UnmarshalRTs(values []*any.Any) ([]bgp.ExtendedCommunityInterface, error) {
+ rts := make([]bgp.ExtendedCommunityInterface, 0, len(values))
+ for _, an := range values {
+ rt, err := UnmarshalRT(an)
+ if err != nil {
+ return nil, err
+ }
+ rts = append(rts, rt)
+ }
+ return rts, nil
+}
+
+func NewExtendedCommunitiesAttributeFromNative(a *bgp.PathAttributeExtendedCommunities) *api.ExtendedCommunitiesAttribute {
+ communities := make([]*any.Any, 0, len(a.Value))
+ for _, value := range a.Value {
+ var community proto.Message
+ switch v := value.(type) {
+ case *bgp.TwoOctetAsSpecificExtended:
+ community = &api.TwoOctetAsSpecificExtended{
+ IsTransitive: v.IsTransitive,
+ SubType: uint32(v.SubType),
+ As: uint32(v.AS),
+ LocalAdmin: uint32(v.LocalAdmin),
+ }
+ case *bgp.IPv4AddressSpecificExtended:
+ community = &api.IPv4AddressSpecificExtended{
+ IsTransitive: v.IsTransitive,
+ SubType: uint32(v.SubType),
+ Address: v.IPv4.String(),
+ LocalAdmin: uint32(v.LocalAdmin),
+ }
+ case *bgp.FourOctetAsSpecificExtended:
+ community = &api.FourOctetAsSpecificExtended{
+ IsTransitive: v.IsTransitive,
+ SubType: uint32(v.SubType),
+ As: uint32(v.AS),
+ LocalAdmin: uint32(v.LocalAdmin),
+ }
+ case *bgp.ValidationExtended:
+ community = &api.ValidationExtended{
+ State: uint32(v.State),
+ }
+ case *bgp.ColorExtended:
+ community = &api.ColorExtended{
+ Color: v.Color,
+ }
+ case *bgp.EncapExtended:
+ community = &api.EncapExtended{
+ TunnelType: uint32(v.TunnelType),
+ }
+ case *bgp.DefaultGatewayExtended:
+ community = &api.DefaultGatewayExtended{}
+ case *bgp.OpaqueExtended:
+ community = &api.OpaqueExtended{
+ IsTransitive: v.IsTransitive,
+ Value: v.Value,
+ }
+ case *bgp.ESILabelExtended:
+ community = &api.ESILabelExtended{
+ IsSingleActive: v.IsSingleActive,
+ Label: v.Label,
+ }
+ case *bgp.ESImportRouteTarget:
+ community = &api.ESImportRouteTarget{
+ EsImport: v.ESImport.String(),
+ }
+ case *bgp.MacMobilityExtended:
+ community = &api.MacMobilityExtended{
+ IsSticky: v.IsSticky,
+ SequenceNum: v.Sequence,
+ }
+ case *bgp.RouterMacExtended:
+ community = &api.RouterMacExtended{
+ Mac: v.Mac.String(),
+ }
+ case *bgp.TrafficRateExtended:
+ community = &api.TrafficRateExtended{
+ As: uint32(v.AS),
+ Rate: v.Rate,
+ }
+ case *bgp.TrafficActionExtended:
+ community = &api.TrafficActionExtended{
+ Terminal: v.Terminal,
+ Sample: v.Sample,
+ }
+ case *bgp.RedirectTwoOctetAsSpecificExtended:
+ community = &api.RedirectTwoOctetAsSpecificExtended{
+ As: uint32(v.AS),
+ LocalAdmin: v.LocalAdmin,
+ }
+ case *bgp.RedirectIPv4AddressSpecificExtended:
+ community = &api.RedirectIPv4AddressSpecificExtended{
+ Address: v.IPv4.String(),
+ LocalAdmin: uint32(v.LocalAdmin),
+ }
+ case *bgp.RedirectFourOctetAsSpecificExtended:
+ community = &api.RedirectFourOctetAsSpecificExtended{
+ As: v.AS,
+ LocalAdmin: uint32(v.LocalAdmin),
+ }
+ case *bgp.TrafficRemarkExtended:
+ community = &api.TrafficRemarkExtended{
+ Dscp: uint32(v.DSCP),
+ }
+ case *bgp.UnknownExtended:
+ community = &api.UnknownExtended{
+ Type: uint32(v.Type),
+ Value: v.Value,
+ }
+ default:
+ log.WithFields(log.Fields{
+ "Topic": "protobuf",
+ "Community": value,
+ }).Warn("unsupported extended community")
+ return nil
+ }
+ an, _ := ptypes.MarshalAny(community)
+ communities = append(communities, an)
+ }
+ return &api.ExtendedCommunitiesAttribute{
+ Communities: communities,
+ }
+}
+
+func unmarshalExComm(a *api.ExtendedCommunitiesAttribute) (*bgp.PathAttributeExtendedCommunities, error) {
+ communities := make([]bgp.ExtendedCommunityInterface, 0, len(a.Communities))
+ for _, an := range a.Communities {
+ var community bgp.ExtendedCommunityInterface
+ var value ptypes.DynamicAny
+ if err := ptypes.UnmarshalAny(an, &value); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal extended community: %s", err)
+ }
+ switch v := value.Message.(type) {
+ case *api.TwoOctetAsSpecificExtended:
+ community = bgp.NewTwoOctetAsSpecificExtended(bgp.ExtendedCommunityAttrSubType(v.SubType), uint16(v.As), v.LocalAdmin, v.IsTransitive)
+ case *api.IPv4AddressSpecificExtended:
+ community = bgp.NewIPv4AddressSpecificExtended(bgp.ExtendedCommunityAttrSubType(v.SubType), v.Address, uint16(v.LocalAdmin), v.IsTransitive)
+ case *api.FourOctetAsSpecificExtended:
+ community = bgp.NewFourOctetAsSpecificExtended(bgp.ExtendedCommunityAttrSubType(v.SubType), v.As, uint16(v.LocalAdmin), v.IsTransitive)
+ case *api.ValidationExtended:
+ community = bgp.NewValidationExtended(bgp.ValidationState(v.State))
+ case *api.ColorExtended:
+ community = bgp.NewColorExtended(v.Color)
+ case *api.EncapExtended:
+ community = bgp.NewEncapExtended(bgp.TunnelType(v.TunnelType))
+ case *api.DefaultGatewayExtended:
+ community = bgp.NewDefaultGatewayExtended()
+ case *api.OpaqueExtended:
+ community = bgp.NewOpaqueExtended(v.IsTransitive, v.Value)
+ case *api.ESILabelExtended:
+ community = bgp.NewESILabelExtended(v.Label, v.IsSingleActive)
+ case *api.ESImportRouteTarget:
+ community = bgp.NewESImportRouteTarget(v.EsImport)
+ case *api.MacMobilityExtended:
+ community = bgp.NewMacMobilityExtended(v.SequenceNum, v.IsSticky)
+ case *api.RouterMacExtended:
+ community = bgp.NewRoutersMacExtended(v.Mac)
+ case *api.TrafficRateExtended:
+ community = bgp.NewTrafficRateExtended(uint16(v.As), v.Rate)
+ case *api.TrafficActionExtended:
+ community = bgp.NewTrafficActionExtended(v.Terminal, v.Sample)
+ case *api.RedirectTwoOctetAsSpecificExtended:
+ community = bgp.NewRedirectTwoOctetAsSpecificExtended(uint16(v.As), v.LocalAdmin)
+ case *api.RedirectIPv4AddressSpecificExtended:
+ community = bgp.NewRedirectIPv4AddressSpecificExtended(v.Address, uint16(v.LocalAdmin))
+ case *api.RedirectFourOctetAsSpecificExtended:
+ community = bgp.NewRedirectFourOctetAsSpecificExtended(v.As, uint16(v.LocalAdmin))
+ case *api.TrafficRemarkExtended:
+ community = bgp.NewTrafficRemarkExtended(uint8(v.Dscp))
+ case *api.UnknownExtended:
+ community = bgp.NewUnknownExtended(bgp.ExtendedCommunityAttrType(v.Type), v.Value)
+ }
+ if community == nil {
+ return nil, fmt.Errorf("invalid extended community: %v", value.Message)
+ }
+ communities = append(communities, community)
+ }
+ return bgp.NewPathAttributeExtendedCommunities(communities), nil
+}
+
+func NewAs4PathAttributeFromNative(a *bgp.PathAttributeAs4Path) *api.As4PathAttribute {
+ segments := make([]*api.AsSegment, 0, len(a.Value))
+ for _, param := range a.Value {
+ segments = append(segments, &api.AsSegment{
+ Type: uint32(param.Type),
+ Numbers: param.AS,
+ })
+ }
+ return &api.As4PathAttribute{
+ Segments: segments,
+ }
+}
+
+func NewAs4AggregatorAttributeFromNative(a *bgp.PathAttributeAs4Aggregator) *api.As4AggregatorAttribute {
+ return &api.As4AggregatorAttribute{
+ As: a.Value.AS,
+ Address: a.Value.Address.String(),
+ }
+}
+
+func NewPmsiTunnelAttributeFromNative(a *bgp.PathAttributePmsiTunnel) *api.PmsiTunnelAttribute {
+ var flags uint32
+ if a.IsLeafInfoRequired {
+ flags |= 0x01
+ }
+ id, _ := a.TunnelID.Serialize()
+ return &api.PmsiTunnelAttribute{
+ Flags: flags,
+ Type: uint32(a.TunnelType),
+ Label: a.Label,
+ Id: id,
+ }
+}
+
+func NewTunnelEncapAttributeFromNative(a *bgp.PathAttributeTunnelEncap) *api.TunnelEncapAttribute {
+ tlvs := make([]*api.TunnelEncapTLV, 0, len(a.Value))
+ for _, v := range a.Value {
+ subTlvs := make([]*any.Any, 0, len(v.Value))
+ for _, s := range v.Value {
+ var subTlv proto.Message
+ switch sv := s.(type) {
+ case *bgp.TunnelEncapSubTLVEncapsulation:
+ subTlv = &api.TunnelEncapSubTLVEncapsulation{
+ Key: sv.Key,
+ Cookie: sv.Cookie,
+ }
+ case *bgp.TunnelEncapSubTLVProtocol:
+ subTlv = &api.TunnelEncapSubTLVProtocol{
+ Protocol: uint32(sv.Protocol),
+ }
+ case *bgp.TunnelEncapSubTLVColor:
+ subTlv = &api.TunnelEncapSubTLVColor{
+ Color: sv.Color,
+ }
+ case *bgp.TunnelEncapSubTLVUnknown:
+ subTlv = &api.TunnelEncapSubTLVUnknown{
+ Type: uint32(sv.Type),
+ Value: sv.Value,
+ }
+ }
+ an, _ := ptypes.MarshalAny(subTlv)
+ subTlvs = append(subTlvs, an)
+ }
+ tlvs = append(tlvs, &api.TunnelEncapTLV{
+ Type: uint32(v.Type),
+ Tlvs: subTlvs,
+ })
+ }
+ return &api.TunnelEncapAttribute{
+ Tlvs: tlvs,
+ }
+}
+
+func NewIP6ExtendedCommunitiesAttributeFromNative(a *bgp.PathAttributeIP6ExtendedCommunities) *api.IP6ExtendedCommunitiesAttribute {
+ communities := make([]*any.Any, 0, len(a.Value))
+ for _, value := range a.Value {
+ var community proto.Message
+ switch v := value.(type) {
+ case *bgp.IPv6AddressSpecificExtended:
+ community = &api.IPv6AddressSpecificExtended{
+ IsTransitive: v.IsTransitive,
+ SubType: uint32(v.SubType),
+ Address: v.IPv6.String(),
+ LocalAdmin: uint32(v.LocalAdmin),
+ }
+ case *bgp.RedirectIPv6AddressSpecificExtended:
+ community = &api.RedirectIPv6AddressSpecificExtended{
+ Address: v.IPv6.String(),
+ LocalAdmin: uint32(v.LocalAdmin),
+ }
+ default:
+ log.WithFields(log.Fields{
+ "Topic": "protobuf",
+ "Attribute": value,
+ }).Warn("invalid ipv6 extended community")
+ return nil
+ }
+ an, _ := ptypes.MarshalAny(community)
+ communities = append(communities, an)
+ }
+ return &api.IP6ExtendedCommunitiesAttribute{
+ Communities: communities,
+ }
+}
+
+func NewAigpAttributeFromNative(a *bgp.PathAttributeAigp) *api.AigpAttribute {
+ tlvs := make([]*any.Any, 0, len(a.Values))
+ for _, value := range a.Values {
+ var tlv proto.Message
+ switch v := value.(type) {
+ case *bgp.AigpTLVIgpMetric:
+ tlv = &api.AigpTLVIGPMetric{
+ Metric: v.Metric,
+ }
+ case *bgp.AigpTLVDefault:
+ tlv = &api.AigpTLVUnknown{
+ Type: uint32(v.Type()),
+ Value: v.Value,
+ }
+ }
+ an, _ := ptypes.MarshalAny(tlv)
+ tlvs = append(tlvs, an)
+ }
+ return &api.AigpAttribute{
+ Tlvs: tlvs,
+ }
+}
+
+func NewLargeCommunitiesAttributeFromNative(a *bgp.PathAttributeLargeCommunities) *api.LargeCommunitiesAttribute {
+ communities := make([]*api.LargeCommunity, 0, len(a.Values))
+ for _, v := range a.Values {
+ communities = append(communities, &api.LargeCommunity{
+ GlobalAdmin: v.ASN,
+ LocalData1: v.LocalData1,
+ LocalData2: v.LocalData2,
+ })
+ }
+ return &api.LargeCommunitiesAttribute{
+ Communities: communities,
+ }
+}
+
+func NewUnknownAttributeFromNative(a *bgp.PathAttributeUnknown) *api.UnknownAttribute {
+ return &api.UnknownAttribute{
+ Flags: uint32(a.Flags),
+ Type: uint32(a.Type),
+ Value: a.Value,
+ }
+}
+
+func MarshalPathAttributes(attrList []bgp.PathAttributeInterface) []*any.Any {
+ anyList := make([]*any.Any, 0, len(attrList))
+ for _, attr := range attrList {
+ switch a := attr.(type) {
+ case *bgp.PathAttributeOrigin:
+ n, _ := ptypes.MarshalAny(NewOriginAttributeFromNative(a))
+ anyList = append(anyList, n)
+ case *bgp.PathAttributeAsPath:
+ n, _ := ptypes.MarshalAny(NewAsPathAttributeFromNative(a))
+ anyList = append(anyList, n)
+ case *bgp.PathAttributeNextHop:
+ n, _ := ptypes.MarshalAny(NewNextHopAttributeFromNative(a))
+ anyList = append(anyList, n)
+ case *bgp.PathAttributeMultiExitDisc:
+ n, _ := ptypes.MarshalAny(NewMultiExitDiscAttributeFromNative(a))
+ anyList = append(anyList, n)
+ case *bgp.PathAttributeLocalPref:
+ n, _ := ptypes.MarshalAny(NewLocalPrefAttributeFromNative(a))
+ anyList = append(anyList, n)
+ case *bgp.PathAttributeAtomicAggregate:
+ n, _ := ptypes.MarshalAny(NewAtomicAggregateAttributeFromNative(a))
+ anyList = append(anyList, n)
+ case *bgp.PathAttributeAggregator:
+ n, _ := ptypes.MarshalAny(NewAggregatorAttributeFromNative(a))
+ anyList = append(anyList, n)
+ case *bgp.PathAttributeCommunities:
+ n, _ := ptypes.MarshalAny(NewCommunitiesAttributeFromNative(a))
+ anyList = append(anyList, n)
+ case *bgp.PathAttributeOriginatorId:
+ n, _ := ptypes.MarshalAny(NewOriginatorIdAttributeFromNative(a))
+ anyList = append(anyList, n)
+ case *bgp.PathAttributeClusterList:
+ n, _ := ptypes.MarshalAny(NewClusterListAttributeFromNative(a))
+ anyList = append(anyList, n)
+ case *bgp.PathAttributeMpReachNLRI:
+ n, _ := ptypes.MarshalAny(NewMpReachNLRIAttributeFromNative(a))
+ anyList = append(anyList, n)
+ case *bgp.PathAttributeMpUnreachNLRI:
+ n, _ := ptypes.MarshalAny(NewMpUnreachNLRIAttributeFromNative(a))
+ anyList = append(anyList, n)
+ case *bgp.PathAttributeExtendedCommunities:
+ n, _ := ptypes.MarshalAny(NewExtendedCommunitiesAttributeFromNative(a))
+ anyList = append(anyList, n)
+ case *bgp.PathAttributeAs4Path:
+ n, _ := ptypes.MarshalAny(NewAs4PathAttributeFromNative(a))
+ anyList = append(anyList, n)
+ case *bgp.PathAttributeAs4Aggregator:
+ n, _ := ptypes.MarshalAny(NewAs4AggregatorAttributeFromNative(a))
+ anyList = append(anyList, n)
+ case *bgp.PathAttributePmsiTunnel:
+ n, _ := ptypes.MarshalAny(NewPmsiTunnelAttributeFromNative(a))
+ anyList = append(anyList, n)
+ case *bgp.PathAttributeTunnelEncap:
+ n, _ := ptypes.MarshalAny(NewTunnelEncapAttributeFromNative(a))
+ anyList = append(anyList, n)
+ case *bgp.PathAttributeIP6ExtendedCommunities:
+ n, _ := ptypes.MarshalAny(NewIP6ExtendedCommunitiesAttributeFromNative(a))
+ anyList = append(anyList, n)
+ case *bgp.PathAttributeAigp:
+ n, _ := ptypes.MarshalAny(NewAigpAttributeFromNative(a))
+ anyList = append(anyList, n)
+ case *bgp.PathAttributeLargeCommunities:
+ n, _ := ptypes.MarshalAny(NewLargeCommunitiesAttributeFromNative(a))
+ anyList = append(anyList, n)
+ case *bgp.PathAttributeUnknown:
+ n, _ := ptypes.MarshalAny(NewUnknownAttributeFromNative(a))
+ anyList = append(anyList, n)
+ }
+ }
+ return anyList
+}
+
+func UnmarshalPathAttributes(values []*any.Any) ([]bgp.PathAttributeInterface, error) {
+ attrList := make([]bgp.PathAttributeInterface, 0, len(values))
+ typeMap := make(map[bgp.BGPAttrType]struct{})
+ for _, an := range values {
+ attr, err := unmarshalAttribute(an)
+ if err != nil {
+ return nil, err
+ }
+ if _, ok := typeMap[attr.GetType()]; ok {
+ return nil, fmt.Errorf("duplicated path attribute type: %d", attr.GetType())
+ }
+ typeMap[attr.GetType()] = struct{}{}
+ attrList = append(attrList, attr)
+ }
+ return attrList, nil
+}
+
+func unmarshalAttribute(an *any.Any) (bgp.PathAttributeInterface, error) {
+ var value ptypes.DynamicAny
+ if err := ptypes.UnmarshalAny(an, &value); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal route distinguisher: %s", err)
+ }
+ switch a := value.Message.(type) {
+ case *api.OriginAttribute:
+ return bgp.NewPathAttributeOrigin(uint8(a.Origin)), nil
+ case *api.AsPathAttribute:
+ params := make([]bgp.AsPathParamInterface, 0, len(a.Segments))
+ for _, segment := range a.Segments {
+ params = append(params, bgp.NewAs4PathParam(uint8(segment.Type), segment.Numbers))
+ }
+ return bgp.NewPathAttributeAsPath(params), nil
+ case *api.NextHopAttribute:
+ nexthop := net.ParseIP(a.NextHop).To4()
+ if nexthop == nil {
+ return nil, fmt.Errorf("invalid nexthop address: %s", a.NextHop)
+ }
+ return bgp.NewPathAttributeNextHop(a.NextHop), nil
+ case *api.MultiExitDiscAttribute:
+ return bgp.NewPathAttributeMultiExitDisc(a.Med), nil
+ case *api.LocalPrefAttribute:
+ return bgp.NewPathAttributeLocalPref(a.LocalPref), nil
+ case *api.AtomicAggregateAttribute:
+ return bgp.NewPathAttributeAtomicAggregate(), nil
+ case *api.AggregatorAttribute:
+ if net.ParseIP(a.Address).To4() == nil {
+ return nil, fmt.Errorf("invalid aggregator address: %s", a.Address)
+ }
+ return bgp.NewPathAttributeAggregator(a.As, a.Address), nil
+ case *api.CommunitiesAttribute:
+ return bgp.NewPathAttributeCommunities(a.Communities), nil
+ case *api.OriginatorIdAttribute:
+ if net.ParseIP(a.Id).To4() == nil {
+ return nil, fmt.Errorf("invalid originator id: %s", a.Id)
+ }
+ return bgp.NewPathAttributeOriginatorId(a.Id), nil
+ case *api.ClusterListAttribute:
+ for _, id := range a.Ids {
+ if net.ParseIP(id).To4() == nil {
+ return nil, fmt.Errorf("invalid cluster list: %s", a.Ids)
+ }
+ }
+ return bgp.NewPathAttributeClusterList(a.Ids), nil
+ case *api.MpReachNLRIAttribute:
+ rf := bgp.RouteFamily(a.Family)
+ nlris, err := UnmarshalNLRIs(rf, a.Nlris)
+ if err != nil {
+ return nil, err
+ }
+ afi, safi := bgp.RouteFamilyToAfiSafi(rf)
+ nexthop := "0.0.0.0"
+ var linkLocalNexthop net.IP
+ if afi == bgp.AFI_IP6 {
+ nexthop = "::"
+ if len(a.NextHops) > 1 {
+ linkLocalNexthop = net.ParseIP(a.NextHops[1]).To16()
+ if linkLocalNexthop == nil {
+ return nil, fmt.Errorf("invalid nexthop: %s", a.NextHops[1])
+ }
+ }
+ }
+ if safi == bgp.SAFI_FLOW_SPEC_UNICAST || safi == bgp.SAFI_FLOW_SPEC_VPN {
+ nexthop = ""
+ } else if len(a.NextHops) > 0 {
+ nexthop = a.NextHops[0]
+ if net.ParseIP(nexthop) == nil {
+ return nil, fmt.Errorf("invalid nexthop: %s", nexthop)
+ }
+ }
+ attr := bgp.NewPathAttributeMpReachNLRI(nexthop, nlris)
+ attr.LinkLocalNexthop = linkLocalNexthop
+ return attr, nil
+ case *api.MpUnreachNLRIAttribute:
+ rf := bgp.RouteFamily(a.Family)
+ nlris, err := UnmarshalNLRIs(rf, a.Nlris)
+ if err != nil {
+ return nil, err
+ }
+ return bgp.NewPathAttributeMpUnreachNLRI(nlris), nil
+ case *api.ExtendedCommunitiesAttribute:
+ return unmarshalExComm(a)
+ case *api.As4PathAttribute:
+ params := make([]*bgp.As4PathParam, 0, len(a.Segments))
+ for _, segment := range a.Segments {
+ params = append(params, bgp.NewAs4PathParam(uint8(segment.Type), segment.Numbers))
+ }
+ return bgp.NewPathAttributeAs4Path(params), nil
+ case *api.As4AggregatorAttribute:
+ if net.ParseIP(a.Address).To4() == nil {
+ return nil, fmt.Errorf("invalid as4 aggregator address: %s", a.Address)
+ }
+ return bgp.NewPathAttributeAs4Aggregator(a.As, a.Address), nil
+ case *api.PmsiTunnelAttribute:
+ typ := bgp.PmsiTunnelType(a.Type)
+ var isLeafInfoRequired bool
+ if a.Flags&0x01 > 0 {
+ isLeafInfoRequired = true
+ }
+ var id bgp.PmsiTunnelIDInterface
+ switch typ {
+ case bgp.PMSI_TUNNEL_TYPE_INGRESS_REPL:
+ ip := net.IP(a.Id)
+ if ip.To4() == nil && ip.To16() == nil {
+ return nil, fmt.Errorf("invalid pmsi tunnel identifier: %s", a.Id)
+ }
+ id = bgp.NewIngressReplTunnelID(ip.String())
+ default:
+ id = bgp.NewDefaultPmsiTunnelID(a.Id)
+ }
+ return bgp.NewPathAttributePmsiTunnel(typ, isLeafInfoRequired, a.Label, id), nil
+ case *api.TunnelEncapAttribute:
+ tlvs := make([]*bgp.TunnelEncapTLV, 0, len(a.Tlvs))
+ for _, tlv := range a.Tlvs {
+ subTlvs := make([]bgp.TunnelEncapSubTLVInterface, 0, len(tlv.Tlvs))
+ for _, an := range tlv.Tlvs {
+ var subTlv bgp.TunnelEncapSubTLVInterface
+ var subValue ptypes.DynamicAny
+ if err := ptypes.UnmarshalAny(an, &subValue); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal tunnel encapsulation attribute sub tlv: %s", err)
+ }
+ switch sv := subValue.Message.(type) {
+ case *api.TunnelEncapSubTLVEncapsulation:
+ subTlv = bgp.NewTunnelEncapSubTLVEncapsulation(sv.Key, sv.Cookie)
+ case *api.TunnelEncapSubTLVProtocol:
+ subTlv = bgp.NewTunnelEncapSubTLVProtocol(uint16(sv.Protocol))
+ case *api.TunnelEncapSubTLVColor:
+ subTlv = bgp.NewTunnelEncapSubTLVColor(sv.Color)
+ case *api.TunnelEncapSubTLVUnknown:
+ subTlv = bgp.NewTunnelEncapSubTLVUnknown(bgp.EncapSubTLVType(sv.Type), sv.Value)
+ default:
+ return nil, fmt.Errorf("invalid tunnel encapsulation attribute sub tlv: %v", subValue.Message)
+ }
+ subTlvs = append(subTlvs, subTlv)
+ }
+ tlvs = append(tlvs, bgp.NewTunnelEncapTLV(bgp.TunnelType(tlv.Type), subTlvs))
+ }
+ return bgp.NewPathAttributeTunnelEncap(tlvs), nil
+ case *api.IP6ExtendedCommunitiesAttribute:
+ communities := make([]bgp.ExtendedCommunityInterface, 0, len(a.Communities))
+ for _, an := range a.Communities {
+ var community bgp.ExtendedCommunityInterface
+ var value ptypes.DynamicAny
+ if err := ptypes.UnmarshalAny(an, &value); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal ipv6 extended community: %s", err)
+ }
+ switch v := value.Message.(type) {
+ case *api.IPv6AddressSpecificExtended:
+ community = bgp.NewIPv6AddressSpecificExtended(bgp.ExtendedCommunityAttrSubType(v.SubType), v.Address, uint16(v.LocalAdmin), v.IsTransitive)
+ case *api.RedirectIPv6AddressSpecificExtended:
+ community = bgp.NewRedirectIPv6AddressSpecificExtended(v.Address, uint16(v.LocalAdmin))
+ }
+ if community == nil {
+ return nil, fmt.Errorf("invalid ipv6 extended community: %v", value.Message)
+ }
+ communities = append(communities, community)
+ }
+ return bgp.NewPathAttributeIP6ExtendedCommunities(communities), nil
+
+ case *api.AigpAttribute:
+ tlvs := make([]bgp.AigpTLVInterface, 0, len(a.Tlvs))
+ for _, an := range a.Tlvs {
+ var tlv bgp.AigpTLVInterface
+ var value ptypes.DynamicAny
+ if err := ptypes.UnmarshalAny(an, &value); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal aigp attribute tlv: %s", err)
+ }
+ switch v := value.Message.(type) {
+ case *api.AigpTLVIGPMetric:
+ tlv = bgp.NewAigpTLVIgpMetric(v.Metric)
+ case *api.AigpTLVUnknown:
+ tlv = bgp.NewAigpTLVDefault(bgp.AigpTLVType(v.Type), v.Value)
+ }
+ if tlv == nil {
+ return nil, fmt.Errorf("invalid aigp attribute tlv: %v", value.Message)
+ }
+ tlvs = append(tlvs, tlv)
+ }
+ return bgp.NewPathAttributeAigp(tlvs), nil
+
+ case *api.LargeCommunitiesAttribute:
+ communities := make([]*bgp.LargeCommunity, 0, len(a.Communities))
+ for _, c := range a.Communities {
+ communities = append(communities, bgp.NewLargeCommunity(c.GlobalAdmin, c.LocalData1, c.LocalData2))
+ }
+ return bgp.NewPathAttributeLargeCommunities(communities), nil
+
+ case *api.UnknownAttribute:
+ return bgp.NewPathAttributeUnknown(bgp.BGPAttrFlag(a.Flags), bgp.BGPAttrType(a.Type), a.Value), nil
+ }
+ return nil, errors.New("unknown path attribute")
+}
diff --git a/internal/pkg/apiutil/attribute_test.go b/internal/pkg/apiutil/attribute_test.go
new file mode 100644
index 00000000..df86427f
--- /dev/null
+++ b/internal/pkg/apiutil/attribute_test.go
@@ -0,0 +1,1493 @@
+// Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+// implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package apiutil
+
+import (
+ "net"
+ "testing"
+
+ "github.com/golang/protobuf/ptypes"
+ "github.com/golang/protobuf/ptypes/any"
+ api "github.com/osrg/gobgp/api"
+ "github.com/osrg/gobgp/pkg/packet/bgp"
+ "github.com/stretchr/testify/assert"
+)
+
+func Test_OriginAttribute(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.OriginAttribute{
+ Origin: 0, // IGP
+ }
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewOriginAttributeFromNative(n.(*bgp.PathAttributeOrigin))
+ assert.Equal(input.Origin, output.Origin)
+}
+
+func Test_AsPathAttribute(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.AsPathAttribute{
+ Segments: []*api.AsSegment{
+ {
+ Type: 1, // SET
+ Numbers: []uint32{100, 200},
+ },
+ {
+ Type: 2, // SEQ
+ Numbers: []uint32{300, 400},
+ },
+ },
+ }
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewAsPathAttributeFromNative(n.(*bgp.PathAttributeAsPath))
+ assert.Equal(2, len(output.Segments))
+ assert.Equal(input.Segments, output.Segments)
+}
+
+func Test_NextHopAttribute(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.NextHopAttribute{
+ NextHop: "192.168.0.1",
+ }
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewNextHopAttributeFromNative(n.(*bgp.PathAttributeNextHop))
+ assert.Equal(input.NextHop, output.NextHop)
+}
+
+func Test_MultiExitDiscAttribute(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.MultiExitDiscAttribute{
+ Med: 100,
+ }
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMultiExitDiscAttributeFromNative(n.(*bgp.PathAttributeMultiExitDisc))
+ assert.Equal(input.Med, output.Med)
+}
+
+func Test_LocalPrefAttribute(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.LocalPrefAttribute{
+ LocalPref: 100,
+ }
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewLocalPrefAttributeFromNative(n.(*bgp.PathAttributeLocalPref))
+ assert.Equal(input.LocalPref, output.LocalPref)
+}
+
+func Test_AtomicAggregateAttribute(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.AtomicAggregateAttribute{}
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewAtomicAggregateAttributeFromNative(n.(*bgp.PathAttributeAtomicAggregate))
+ // AtomicAggregateAttribute has no value
+ assert.NotNil(output)
+}
+
+func Test_AggregatorAttribute(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.AggregatorAttribute{
+ As: 65000,
+ Address: "1.1.1.1",
+ }
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewAggregatorAttributeFromNative(n.(*bgp.PathAttributeAggregator))
+ assert.Equal(input.As, output.As)
+ assert.Equal(input.Address, output.Address)
+}
+
+func Test_CommunitiesAttribute(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.CommunitiesAttribute{
+ Communities: []uint32{100, 200},
+ }
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewCommunitiesAttributeFromNative(n.(*bgp.PathAttributeCommunities))
+ assert.Equal(input.Communities, output.Communities)
+}
+
+func Test_OriginatorIdAttribute(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.OriginatorIdAttribute{
+ Id: "1.1.1.1",
+ }
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewOriginatorIdAttributeFromNative(n.(*bgp.PathAttributeOriginatorId))
+ assert.Equal(input.Id, output.Id)
+}
+
+func Test_ClusterListAttribute(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.ClusterListAttribute{
+ Ids: []string{"1.1.1.1", "2.2.2.2"},
+ }
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewClusterListAttributeFromNative(n.(*bgp.PathAttributeClusterList))
+ assert.Equal(input.Ids, output.Ids)
+}
+
+func Test_MpReachNLRIAttribute_IPv4_UC(t *testing.T) {
+ assert := assert.New(t)
+
+ nlris := make([]*any.Any, 0, 2)
+ a, err := ptypes.MarshalAny(&api.IPAddressPrefix{
+ PrefixLen: 24,
+ Prefix: "192.168.101.0",
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+ a, err = ptypes.MarshalAny(&api.IPAddressPrefix{
+ PrefixLen: 24,
+ Prefix: "192.168.201.0",
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+
+ input := &api.MpReachNLRIAttribute{
+ Family: uint32(bgp.RF_IPv4_UC),
+ NextHops: []string{"192.168.1.1"},
+ Nlris: nlris,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
+ assert.Equal(input.Family, output.Family)
+ assert.Equal(input.NextHops, output.NextHops)
+ assert.Equal(2, len(output.Nlris))
+ for idx, inputNLRI := range input.Nlris {
+ outputNLRI := output.Nlris[idx]
+ assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
+ assert.Equal(inputNLRI.Value, outputNLRI.Value)
+ }
+}
+
+func Test_MpReachNLRIAttribute_IPv6_UC(t *testing.T) {
+ assert := assert.New(t)
+
+ nlris := make([]*any.Any, 0, 2)
+ a, err := ptypes.MarshalAny(&api.IPAddressPrefix{
+ PrefixLen: 64,
+ Prefix: "2001:db8:1::",
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+ a, err = ptypes.MarshalAny(&api.IPAddressPrefix{
+ PrefixLen: 64,
+ Prefix: "2001:db8:2::",
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+
+ input := &api.MpReachNLRIAttribute{
+ Family: uint32(bgp.RF_IPv6_UC),
+ NextHops: []string{"2001:db8::1", "2001:db8::2"},
+ Nlris: nlris,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
+ assert.Equal(input.Family, output.Family)
+ assert.Equal(input.NextHops, output.NextHops)
+ assert.Equal(2, len(output.Nlris))
+ for idx, inputNLRI := range input.Nlris {
+ outputNLRI := output.Nlris[idx]
+ assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
+ assert.Equal(inputNLRI.Value, outputNLRI.Value)
+ }
+}
+
+func Test_MpReachNLRIAttribute_IPv4_MPLS(t *testing.T) {
+ assert := assert.New(t)
+
+ nlris := make([]*any.Any, 0, 2)
+ a, err := ptypes.MarshalAny(&api.LabeledIPAddressPrefix{
+ Labels: []uint32{100},
+ PrefixLen: 24,
+ Prefix: "192.168.101.0",
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+ a, err = ptypes.MarshalAny(&api.LabeledIPAddressPrefix{
+ Labels: []uint32{200},
+ PrefixLen: 24,
+ Prefix: "192.168.201.0",
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+
+ input := &api.MpReachNLRIAttribute{
+ Family: uint32(bgp.RF_IPv4_MPLS),
+ NextHops: []string{"192.168.1.1"},
+ Nlris: nlris,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
+ assert.Equal(input.Family, output.Family)
+ assert.Equal(input.NextHops, output.NextHops)
+ assert.Equal(2, len(output.Nlris))
+ for idx, inputNLRI := range input.Nlris {
+ outputNLRI := output.Nlris[idx]
+ assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
+ assert.Equal(inputNLRI.Value, outputNLRI.Value)
+ }
+}
+
+func Test_MpReachNLRIAttribute_IPv6_MPLS(t *testing.T) {
+ assert := assert.New(t)
+
+ nlris := make([]*any.Any, 0, 2)
+ a, err := ptypes.MarshalAny(&api.LabeledIPAddressPrefix{
+ Labels: []uint32{100},
+ PrefixLen: 64,
+ Prefix: "2001:db8:1::",
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+ a, err = ptypes.MarshalAny(&api.LabeledIPAddressPrefix{
+ Labels: []uint32{200},
+ PrefixLen: 64,
+ Prefix: "2001:db8:2::",
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+
+ input := &api.MpReachNLRIAttribute{
+ Family: uint32(bgp.RF_IPv6_MPLS),
+ NextHops: []string{"2001:db8::1"},
+ Nlris: nlris,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
+ assert.Equal(input.Family, output.Family)
+ assert.Equal(input.NextHops, output.NextHops)
+ assert.Equal(2, len(output.Nlris))
+ for idx, inputNLRI := range input.Nlris {
+ outputNLRI := output.Nlris[idx]
+ assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
+ assert.Equal(inputNLRI.Value, outputNLRI.Value)
+ }
+}
+
+func Test_MpReachNLRIAttribute_IPv4_ENCAP(t *testing.T) {
+ assert := assert.New(t)
+
+ nlris := make([]*any.Any, 0, 2)
+ a, err := ptypes.MarshalAny(&api.EncapsulationNLRI{
+ Address: "192.168.101.1",
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+ a, err = ptypes.MarshalAny(&api.EncapsulationNLRI{
+ Address: "192.168.201.1",
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+
+ input := &api.MpReachNLRIAttribute{
+ Family: uint32(bgp.RF_IPv4_ENCAP),
+ NextHops: []string{"192.168.1.1"},
+ Nlris: nlris,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
+ assert.Equal(input.Family, output.Family)
+ assert.Equal(input.NextHops, output.NextHops)
+ assert.Equal(2, len(output.Nlris))
+ for idx, inputNLRI := range input.Nlris {
+ outputNLRI := output.Nlris[idx]
+ assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
+ assert.Equal(inputNLRI.Value, outputNLRI.Value)
+ }
+}
+
+func Test_MpReachNLRIAttribute_IPv6_ENCAP(t *testing.T) {
+ assert := assert.New(t)
+
+ nlris := make([]*any.Any, 0, 2)
+ a, err := ptypes.MarshalAny(&api.EncapsulationNLRI{
+ Address: "2001:db8:1::1",
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+ a, err = ptypes.MarshalAny(&api.EncapsulationNLRI{
+ Address: "2001:db8:2::1",
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+
+ input := &api.MpReachNLRIAttribute{
+ Family: uint32(bgp.RF_IPv6_ENCAP),
+ NextHops: []string{"2001:db8::1"},
+ Nlris: nlris,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
+ assert.Equal(input.Family, output.Family)
+ assert.Equal(input.NextHops, output.NextHops)
+ assert.Equal(2, len(output.Nlris))
+ for idx, inputNLRI := range input.Nlris {
+ outputNLRI := output.Nlris[idx]
+ assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
+ assert.Equal(inputNLRI.Value, outputNLRI.Value)
+ }
+}
+
+func Test_MpReachNLRIAttribute_EVPN_AD_Route(t *testing.T) {
+ assert := assert.New(t)
+
+ nlris := make([]*any.Any, 0, 1)
+ rd, err := ptypes.MarshalAny(&api.RouteDistinguisherTwoOctetAS{
+ Admin: 65000,
+ Assigned: 100,
+ })
+ assert.Nil(err)
+ esi := &api.EthernetSegmentIdentifier{
+ Type: 0,
+ Value: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
+ }
+ a, err := ptypes.MarshalAny(&api.EVPNEthernetAutoDiscoveryRoute{
+ Rd: rd,
+ Esi: esi,
+ EthernetTag: 100,
+ Label: 200,
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+
+ input := &api.MpReachNLRIAttribute{
+ Family: uint32(bgp.RF_EVPN),
+ NextHops: []string{"192.168.1.1"},
+ Nlris: nlris,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
+ assert.Equal(input.Family, output.Family)
+ assert.Equal(input.NextHops, output.NextHops)
+ assert.Equal(1, len(output.Nlris))
+ for idx, inputNLRI := range input.Nlris {
+ outputNLRI := output.Nlris[idx]
+ assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
+ assert.Equal(inputNLRI.Value, outputNLRI.Value)
+ }
+}
+
+func Test_MpReachNLRIAttribute_EVPN_MAC_IP_Route(t *testing.T) {
+ assert := assert.New(t)
+
+ nlris := make([]*any.Any, 0, 1)
+ rd, err := ptypes.MarshalAny(&api.RouteDistinguisherIPAddress{
+ Admin: "1.1.1.1",
+ Assigned: 100,
+ })
+ assert.Nil(err)
+ esi := &api.EthernetSegmentIdentifier{
+ Type: 0,
+ Value: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
+ }
+ a, err := ptypes.MarshalAny(&api.EVPNMACIPAdvertisementRoute{
+ Rd: rd,
+ Esi: esi,
+ EthernetTag: 100,
+ MacAddress: "aa:bb:cc:dd:ee:ff",
+ IpAddress: "192.168.101.1",
+ Labels: []uint32{200},
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+
+ input := &api.MpReachNLRIAttribute{
+ Family: uint32(bgp.RF_EVPN),
+ NextHops: []string{"192.168.1.1"},
+ Nlris: nlris,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
+ assert.Equal(input.Family, output.Family)
+ assert.Equal(input.NextHops, output.NextHops)
+ assert.Equal(1, len(output.Nlris))
+ for idx, inputNLRI := range input.Nlris {
+ outputNLRI := output.Nlris[idx]
+ assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
+ assert.Equal(inputNLRI.Value, outputNLRI.Value)
+ }
+}
+
+func Test_MpReachNLRIAttribute_EVPN_MC_Route(t *testing.T) {
+ assert := assert.New(t)
+
+ nlris := make([]*any.Any, 0, 1)
+ rd, err := ptypes.MarshalAny(&api.RouteDistinguisherFourOctetAS{
+ Admin: 65000,
+ Assigned: 100,
+ })
+ assert.Nil(err)
+ a, err := ptypes.MarshalAny(&api.EVPNInclusiveMulticastEthernetTagRoute{
+ Rd: rd,
+ EthernetTag: 100,
+ IpAddress: "192.168.101.1",
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+
+ input := &api.MpReachNLRIAttribute{
+ Family: uint32(bgp.RF_EVPN),
+ NextHops: []string{"192.168.1.1"},
+ Nlris: nlris,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
+ assert.Equal(input.Family, output.Family)
+ assert.Equal(input.NextHops, output.NextHops)
+ assert.Equal(1, len(output.Nlris))
+ for idx, inputNLRI := range input.Nlris {
+ outputNLRI := output.Nlris[idx]
+ assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
+ assert.Equal(inputNLRI.Value, outputNLRI.Value)
+ }
+}
+
+func Test_MpReachNLRIAttribute_EVPN_ES_Route(t *testing.T) {
+ assert := assert.New(t)
+
+ nlris := make([]*any.Any, 0, 1)
+ rd, err := ptypes.MarshalAny(&api.RouteDistinguisherIPAddress{
+ Admin: "1.1.1.1",
+ Assigned: 100,
+ })
+ assert.Nil(err)
+ esi := &api.EthernetSegmentIdentifier{
+ Type: 0,
+ Value: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
+ }
+ a, err := ptypes.MarshalAny(&api.EVPNEthernetSegmentRoute{
+ Rd: rd,
+ Esi: esi,
+ IpAddress: "192.168.101.1",
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+
+ input := &api.MpReachNLRIAttribute{
+ Family: uint32(bgp.RF_EVPN),
+ NextHops: []string{"192.168.1.1"},
+ Nlris: nlris,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
+ assert.Equal(input.Family, output.Family)
+ assert.Equal(input.NextHops, output.NextHops)
+ assert.Equal(1, len(output.Nlris))
+ for idx, inputNLRI := range input.Nlris {
+ outputNLRI := output.Nlris[idx]
+ assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
+ assert.Equal(inputNLRI.Value, outputNLRI.Value)
+ }
+}
+
+func Test_MpReachNLRIAttribute_EVPN_Prefix_Route(t *testing.T) {
+ assert := assert.New(t)
+
+ nlris := make([]*any.Any, 0, 1)
+ rd, err := ptypes.MarshalAny(&api.RouteDistinguisherIPAddress{
+ Admin: "1.1.1.1",
+ Assigned: 100,
+ })
+ assert.Nil(err)
+ esi := &api.EthernetSegmentIdentifier{
+ Type: 0,
+ Value: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
+ }
+ a, err := ptypes.MarshalAny(&api.EVPNIPPrefixRoute{
+ Rd: rd,
+ Esi: esi,
+ EthernetTag: 100,
+ IpPrefixLen: 24,
+ IpPrefix: "192.168.101.0",
+ Label: 200,
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+
+ input := &api.MpReachNLRIAttribute{
+ Family: uint32(bgp.RF_EVPN),
+ NextHops: []string{"192.168.1.1"},
+ Nlris: nlris,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
+ assert.Equal(input.Family, output.Family)
+ assert.Equal(input.NextHops, output.NextHops)
+ assert.Equal(1, len(output.Nlris))
+ for idx, inputNLRI := range input.Nlris {
+ outputNLRI := output.Nlris[idx]
+ assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
+ assert.Equal(inputNLRI.Value, outputNLRI.Value)
+ }
+}
+
+func Test_MpReachNLRIAttribute_IPv4_VPN(t *testing.T) {
+ assert := assert.New(t)
+
+ nlris := make([]*any.Any, 0, 1)
+ rd, err := ptypes.MarshalAny(&api.RouteDistinguisherIPAddress{
+ Admin: "1.1.1.1",
+ Assigned: 100,
+ })
+ assert.Nil(err)
+ a, err := ptypes.MarshalAny(&api.LabeledVPNIPAddressPrefix{
+ Labels: []uint32{100, 200},
+ Rd: rd,
+ PrefixLen: 24,
+ Prefix: "192.168.101.0",
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+
+ input := &api.MpReachNLRIAttribute{
+ Family: uint32(bgp.RF_IPv4_VPN),
+ NextHops: []string{"192.168.1.1"},
+ Nlris: nlris,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
+ assert.Equal(input.Family, output.Family)
+ assert.Equal(input.NextHops, output.NextHops)
+ assert.Equal(1, len(output.Nlris))
+ for idx, inputNLRI := range input.Nlris {
+ outputNLRI := output.Nlris[idx]
+ assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
+ assert.Equal(inputNLRI.Value, outputNLRI.Value)
+ }
+}
+
+func Test_MpReachNLRIAttribute_IPv6_VPN(t *testing.T) {
+ assert := assert.New(t)
+
+ nlris := make([]*any.Any, 0, 1)
+ rd, err := ptypes.MarshalAny(&api.RouteDistinguisherIPAddress{
+ Admin: "1.1.1.1",
+ Assigned: 100,
+ })
+ assert.Nil(err)
+ a, err := ptypes.MarshalAny(&api.LabeledVPNIPAddressPrefix{
+ Labels: []uint32{100, 200},
+ Rd: rd,
+ PrefixLen: 64,
+ Prefix: "2001:db8:1::",
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+
+ input := &api.MpReachNLRIAttribute{
+ Family: uint32(bgp.RF_IPv6_VPN),
+ NextHops: []string{"2001:db8::1"},
+ Nlris: nlris,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
+ assert.Equal(input.Family, output.Family)
+ assert.Equal(input.NextHops, output.NextHops)
+ assert.Equal(1, len(output.Nlris))
+ for idx, inputNLRI := range input.Nlris {
+ outputNLRI := output.Nlris[idx]
+ assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
+ assert.Equal(inputNLRI.Value, outputNLRI.Value)
+ }
+}
+
+func Test_MpReachNLRIAttribute_RTC_UC(t *testing.T) {
+ assert := assert.New(t)
+
+ nlris := make([]*any.Any, 0, 1)
+ rt, err := ptypes.MarshalAny(&api.IPv4AddressSpecificExtended{
+ IsTransitive: true,
+ SubType: 0x02, // Route Target
+ Address: "1.1.1.1",
+ LocalAdmin: 100,
+ })
+ assert.Nil(err)
+ a, err := ptypes.MarshalAny(&api.RouteTargetMembershipNLRI{
+ As: 65000,
+ Rt: rt,
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+
+ input := &api.MpReachNLRIAttribute{
+ Family: uint32(bgp.RF_RTC_UC),
+ NextHops: []string{"192.168.1.1"},
+ Nlris: nlris,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
+ assert.Equal(input.Family, output.Family)
+ assert.Equal(input.NextHops, output.NextHops)
+ assert.Equal(1, len(output.Nlris))
+ for idx, inputNLRI := range input.Nlris {
+ outputNLRI := output.Nlris[idx]
+ assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
+ assert.Equal(inputNLRI.Value, outputNLRI.Value)
+ }
+}
+
+func Test_MpReachNLRIAttribute_FS_IPv4_UC(t *testing.T) {
+ assert := assert.New(t)
+
+ rules := make([]*any.Any, 0, 3)
+ rule, err := ptypes.MarshalAny(&api.FlowSpecIPPrefix{
+ Type: 1, // Destination Prefix
+ PrefixLen: 24,
+ Prefix: "192.168.101.0",
+ })
+ assert.Nil(err)
+ rules = append(rules, rule)
+ rule, err = ptypes.MarshalAny(&api.FlowSpecIPPrefix{
+ Type: 2, // Source Prefix
+ PrefixLen: 24,
+ Prefix: "192.168.201.0",
+ })
+ assert.Nil(err)
+ rules = append(rules, rule)
+ rule, err = ptypes.MarshalAny(&api.FlowSpecComponent{
+ Type: 3, // IP Protocol
+ Items: []*api.FlowSpecComponentItem{
+ {
+ Op: 0x80 | 0x01, // End, EQ
+ Value: 6, // TCP
+ },
+ },
+ })
+ assert.Nil(err)
+ rules = append(rules, rule)
+
+ nlris := make([]*any.Any, 0, 1)
+ a, err := ptypes.MarshalAny(&api.FlowSpecNLRI{
+ Rules: rules,
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+
+ input := &api.MpReachNLRIAttribute{
+ Family: uint32(bgp.RF_FS_IPv4_UC),
+ // NextHops: // No nexthop required
+ Nlris: nlris,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
+ assert.Equal(input.Family, output.Family)
+ assert.Equal(input.NextHops, output.NextHops)
+ assert.Equal(1, len(output.Nlris))
+ for idx, inputNLRI := range input.Nlris {
+ outputNLRI := output.Nlris[idx]
+ assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
+ assert.Equal(inputNLRI.Value, outputNLRI.Value)
+ }
+}
+
+func Test_MpReachNLRIAttribute_FS_IPv4_VPN(t *testing.T) {
+ assert := assert.New(t)
+
+ rd, err := ptypes.MarshalAny(&api.RouteDistinguisherIPAddress{
+ Admin: "1.1.1.1",
+ Assigned: 100,
+ })
+ assert.Nil(err)
+
+ rules := make([]*any.Any, 0, 3)
+ rule, err := ptypes.MarshalAny(&api.FlowSpecIPPrefix{
+ Type: 1, // Destination Prefix
+ PrefixLen: 24,
+ Prefix: "192.168.101.0",
+ })
+ assert.Nil(err)
+ rules = append(rules, rule)
+ rule, err = ptypes.MarshalAny(&api.FlowSpecIPPrefix{
+ Type: 2, // Source Prefix
+ PrefixLen: 24,
+ Prefix: "192.168.201.0",
+ })
+ assert.Nil(err)
+ rules = append(rules, rule)
+ rule, err = ptypes.MarshalAny(&api.FlowSpecComponent{
+ Type: 3, // IP Protocol
+ Items: []*api.FlowSpecComponentItem{
+ {
+ Op: 0x80 | 0x01, // End, EQ
+ Value: 6, // TCP
+ },
+ },
+ })
+ assert.Nil(err)
+ rules = append(rules, rule)
+
+ nlris := make([]*any.Any, 0, 1)
+ a, err := ptypes.MarshalAny(&api.VPNFlowSpecNLRI{
+ Rd: rd,
+ Rules: rules,
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+
+ input := &api.MpReachNLRIAttribute{
+ Family: uint32(bgp.RF_FS_IPv4_VPN),
+ // NextHops: // No nexthop required
+ Nlris: nlris,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
+ assert.Equal(input.Family, output.Family)
+ assert.Equal(input.NextHops, output.NextHops)
+ assert.Equal(1, len(output.Nlris))
+ for idx, inputNLRI := range input.Nlris {
+ outputNLRI := output.Nlris[idx]
+ assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
+ assert.Equal(inputNLRI.Value, outputNLRI.Value)
+ }
+}
+
+func Test_MpReachNLRIAttribute_FS_IPv6_UC(t *testing.T) {
+ assert := assert.New(t)
+
+ rules := make([]*any.Any, 0, 3)
+ rule, err := ptypes.MarshalAny(&api.FlowSpecIPPrefix{
+ Type: 1, // Destination Prefix
+ PrefixLen: 64,
+ Prefix: "2001:db8:1::",
+ })
+ assert.Nil(err)
+ rules = append(rules, rule)
+ rule, err = ptypes.MarshalAny(&api.FlowSpecIPPrefix{
+ Type: 2, // Source Prefix
+ PrefixLen: 64,
+ Prefix: "2001:db8:2::",
+ })
+ assert.Nil(err)
+ rules = append(rules, rule)
+ rule, err = ptypes.MarshalAny(&api.FlowSpecComponent{
+ Type: 3, // Next Header
+ Items: []*api.FlowSpecComponentItem{
+ {
+ Op: 0x80 | 0x01, // End, EQ
+ Value: 6, // TCP
+ },
+ },
+ })
+ assert.Nil(err)
+ rules = append(rules, rule)
+
+ nlris := make([]*any.Any, 0, 1)
+ a, err := ptypes.MarshalAny(&api.FlowSpecNLRI{
+ Rules: rules,
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+
+ input := &api.MpReachNLRIAttribute{
+ Family: uint32(bgp.RF_FS_IPv6_UC),
+ // NextHops: // No nexthop required
+ Nlris: nlris,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
+ assert.Equal(input.Family, output.Family)
+ assert.Equal(input.NextHops, output.NextHops)
+ assert.Equal(1, len(output.Nlris))
+ for idx, inputNLRI := range input.Nlris {
+ outputNLRI := output.Nlris[idx]
+ assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
+ assert.Equal(inputNLRI.Value, outputNLRI.Value)
+ }
+}
+
+func Test_MpReachNLRIAttribute_FS_IPv6_VPN(t *testing.T) {
+ assert := assert.New(t)
+
+ rd, err := ptypes.MarshalAny(&api.RouteDistinguisherIPAddress{
+ Admin: "1.1.1.1",
+ Assigned: 100,
+ })
+ assert.Nil(err)
+
+ rules := make([]*any.Any, 0, 3)
+ rule, err := ptypes.MarshalAny(&api.FlowSpecIPPrefix{
+ Type: 1, // Destination Prefix
+ PrefixLen: 64,
+ Prefix: "2001:db8:1::",
+ })
+ assert.Nil(err)
+ rules = append(rules, rule)
+ rule, err = ptypes.MarshalAny(&api.FlowSpecIPPrefix{
+ Type: 2, // Source Prefix
+ PrefixLen: 64,
+ Prefix: "2001:db8:2::",
+ })
+ assert.Nil(err)
+ rules = append(rules, rule)
+ rule, err = ptypes.MarshalAny(&api.FlowSpecComponent{
+ Type: 3, // Next Header
+ Items: []*api.FlowSpecComponentItem{
+ {
+ Op: 0x80 | 0x01, // End, EQ
+ Value: 6, // TCP
+ },
+ },
+ })
+ assert.Nil(err)
+ rules = append(rules, rule)
+
+ nlris := make([]*any.Any, 0, 1)
+ a, err := ptypes.MarshalAny(&api.VPNFlowSpecNLRI{
+ Rd: rd,
+ Rules: rules,
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+
+ input := &api.MpReachNLRIAttribute{
+ Family: uint32(bgp.RF_FS_IPv6_VPN),
+ // NextHops: // No nexthop required
+ Nlris: nlris,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
+ assert.Equal(input.Family, output.Family)
+ assert.Equal(input.NextHops, output.NextHops)
+ assert.Equal(1, len(output.Nlris))
+ for idx, inputNLRI := range input.Nlris {
+ outputNLRI := output.Nlris[idx]
+ assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
+ assert.Equal(inputNLRI.Value, outputNLRI.Value)
+ }
+}
+
+func Test_MpReachNLRIAttribute_FS_L2_VPN(t *testing.T) {
+ assert := assert.New(t)
+
+ rd, err := ptypes.MarshalAny(&api.RouteDistinguisherIPAddress{
+ Admin: "1.1.1.1",
+ Assigned: 100,
+ })
+ assert.Nil(err)
+
+ rules := make([]*any.Any, 0, 3)
+ rule, err := ptypes.MarshalAny(&api.FlowSpecMAC{
+ Type: 15, // Source MAC
+ Address: "aa:bb:cc:11:22:33",
+ })
+ assert.Nil(err)
+ rules = append(rules, rule)
+ rule, err = ptypes.MarshalAny(&api.FlowSpecMAC{
+ Type: 16, // Destination MAC
+ Address: "dd:ee:ff:11:22:33",
+ })
+ assert.Nil(err)
+ rules = append(rules, rule)
+ rule, err = ptypes.MarshalAny(&api.FlowSpecComponent{
+ Type: 21, // VLAN ID
+ Items: []*api.FlowSpecComponentItem{
+ {
+ Op: 0x80 | 0x01, // End, EQ
+ Value: 100,
+ },
+ },
+ })
+ assert.Nil(err)
+ rules = append(rules, rule)
+
+ nlris := make([]*any.Any, 0, 1)
+ a, err := ptypes.MarshalAny(&api.VPNFlowSpecNLRI{
+ Rd: rd,
+ Rules: rules,
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+
+ input := &api.MpReachNLRIAttribute{
+ Family: uint32(bgp.RF_FS_L2_VPN),
+ // NextHops: // No nexthop required
+ Nlris: nlris,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
+ assert.Equal(input.Family, output.Family)
+ assert.Equal(input.NextHops, output.NextHops)
+ assert.Equal(1, len(output.Nlris))
+ for idx, inputNLRI := range input.Nlris {
+ outputNLRI := output.Nlris[idx]
+ assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
+ assert.Equal(inputNLRI.Value, outputNLRI.Value)
+ }
+}
+
+func Test_MpUnreachNLRIAttribute_IPv4_UC(t *testing.T) {
+ assert := assert.New(t)
+
+ nlris := make([]*any.Any, 0, 2)
+ a, err := ptypes.MarshalAny(&api.IPAddressPrefix{
+ PrefixLen: 24,
+ Prefix: "192.168.101.0",
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+ a, err = ptypes.MarshalAny(&api.IPAddressPrefix{
+ PrefixLen: 24,
+ Prefix: "192.168.201.0",
+ })
+ assert.Nil(err)
+ nlris = append(nlris, a)
+
+ input := &api.MpUnreachNLRIAttribute{
+ Family: uint32(bgp.RF_IPv4_UC),
+ Nlris: nlris,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewMpUnreachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpUnreachNLRI))
+ assert.Equal(input.Family, output.Family)
+ assert.Equal(2, len(output.Nlris))
+ for idx, inputNLRI := range input.Nlris {
+ outputNLRI := output.Nlris[idx]
+ assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
+ assert.Equal(inputNLRI.Value, outputNLRI.Value)
+ }
+}
+
+func Test_ExtendedCommunitiesAttribute(t *testing.T) {
+ assert := assert.New(t)
+
+ communities := make([]*any.Any, 0, 19)
+ a, err := ptypes.MarshalAny(&api.TwoOctetAsSpecificExtended{
+ IsTransitive: true,
+ SubType: 0x02, // ROUTE_TARGET
+ As: 65001,
+ LocalAdmin: 100,
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+ a, err = ptypes.MarshalAny(&api.IPv4AddressSpecificExtended{
+ IsTransitive: true,
+ SubType: 0x02, // ROUTE_TARGET
+ Address: "2.2.2.2",
+ LocalAdmin: 200,
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+ a, err = ptypes.MarshalAny(&api.FourOctetAsSpecificExtended{
+ IsTransitive: true,
+ SubType: 0x02, // ROUTE_TARGET
+ As: 65003,
+ LocalAdmin: 300,
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+ a, err = ptypes.MarshalAny(&api.ValidationExtended{
+ State: 0, // VALID
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+ a, err = ptypes.MarshalAny(&api.ColorExtended{
+ Color: 400,
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+ a, err = ptypes.MarshalAny(&api.EncapExtended{
+ TunnelType: 8, // VXLAN
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+ a, err = ptypes.MarshalAny(&api.DefaultGatewayExtended{
+ // No value
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+ a, err = ptypes.MarshalAny(&api.OpaqueExtended{
+ IsTransitive: true,
+ Value: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77},
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+ a, err = ptypes.MarshalAny(&api.ESILabelExtended{
+ IsSingleActive: true,
+ Label: 500,
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+ a, err = ptypes.MarshalAny(&api.ESImportRouteTarget{
+ EsImport: "aa:bb:cc:dd:ee:ff",
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+ a, err = ptypes.MarshalAny(&api.MacMobilityExtended{
+ IsSticky: true,
+ SequenceNum: 1,
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+ a, err = ptypes.MarshalAny(&api.RouterMacExtended{
+ Mac: "ff:ee:dd:cc:bb:aa",
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+ a, err = ptypes.MarshalAny(&api.TrafficRateExtended{
+ As: 65004,
+ Rate: 100.0,
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+ a, err = ptypes.MarshalAny(&api.TrafficActionExtended{
+ Terminal: true,
+ Sample: false,
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+ a, err = ptypes.MarshalAny(&api.RedirectTwoOctetAsSpecificExtended{
+ As: 65005,
+ LocalAdmin: 500,
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+ a, err = ptypes.MarshalAny(&api.RedirectIPv4AddressSpecificExtended{
+ Address: "6.6.6.6",
+ LocalAdmin: 600,
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+ a, err = ptypes.MarshalAny(&api.RedirectFourOctetAsSpecificExtended{
+ As: 65007,
+ LocalAdmin: 700,
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+ a, err = ptypes.MarshalAny(&api.TrafficRemarkExtended{
+ Dscp: 0x0a, // AF11
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+ a, err = ptypes.MarshalAny(&api.UnknownExtended{
+ Type: 0xff, // Max of uint8
+ Value: []byte{1, 2, 3, 4, 5, 6, 7},
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+
+ input := &api.ExtendedCommunitiesAttribute{
+ Communities: communities,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewExtendedCommunitiesAttributeFromNative(n.(*bgp.PathAttributeExtendedCommunities))
+ assert.Equal(19, len(output.Communities))
+ for idx, inputCommunity := range input.Communities {
+ outputCommunity := output.Communities[idx]
+ assert.Equal(inputCommunity.TypeUrl, outputCommunity.TypeUrl)
+ assert.Equal(inputCommunity.Value, outputCommunity.Value)
+ }
+}
+
+func Test_As4PathAttribute(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.As4PathAttribute{
+ Segments: []*api.AsSegment{
+ {
+ Type: 1, // SET
+ Numbers: []uint32{100, 200},
+ },
+ {
+ Type: 2, // SEQ
+ Numbers: []uint32{300, 400},
+ },
+ },
+ }
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewAs4PathAttributeFromNative(n.(*bgp.PathAttributeAs4Path))
+ assert.Equal(2, len(output.Segments))
+ assert.Equal(input.Segments, output.Segments)
+}
+
+func Test_As4AggregatorAttribute(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.As4AggregatorAttribute{
+ As: 65000,
+ Address: "1.1.1.1",
+ }
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewAs4AggregatorAttributeFromNative(n.(*bgp.PathAttributeAs4Aggregator))
+ assert.Equal(input.As, output.As)
+ assert.Equal(input.Address, output.Address)
+}
+
+func Test_PmsiTunnelAttribute(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.PmsiTunnelAttribute{
+ Flags: 0x01, // IsLeafInfoRequired = true
+ Type: 6, // INGRESS_REPL
+ Label: 100,
+ Id: net.ParseIP("1.1.1.1").To4(), // IngressReplTunnelID with IPv4
+ }
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewPmsiTunnelAttributeFromNative(n.(*bgp.PathAttributePmsiTunnel))
+ assert.Equal(input.Flags, output.Flags)
+ assert.Equal(input.Type, output.Type)
+ assert.Equal(input.Label, output.Label)
+ assert.Equal(input.Id, output.Id)
+}
+
+func Test_TunnelEncapAttribute(t *testing.T) {
+ assert := assert.New(t)
+
+ subTlvs := make([]*any.Any, 0, 4)
+ a, err := ptypes.MarshalAny(&api.TunnelEncapSubTLVEncapsulation{
+ Key: 100,
+ Cookie: []byte{0x11, 0x22, 0x33, 0x44},
+ })
+ assert.Nil(err)
+ subTlvs = append(subTlvs, a)
+ a, err = ptypes.MarshalAny(&api.TunnelEncapSubTLVProtocol{
+ Protocol: 200,
+ })
+ assert.Nil(err)
+ subTlvs = append(subTlvs, a)
+ a, err = ptypes.MarshalAny(&api.TunnelEncapSubTLVColor{
+ Color: 300,
+ })
+ assert.Nil(err)
+ subTlvs = append(subTlvs, a)
+ a, err = ptypes.MarshalAny(&api.TunnelEncapSubTLVUnknown{
+ Type: 0xff, // Max of uint8
+ Value: []byte{0x55, 0x66, 0x77, 0x88},
+ })
+ assert.Nil(err)
+ subTlvs = append(subTlvs, a)
+
+ input := &api.TunnelEncapAttribute{
+ Tlvs: []*api.TunnelEncapTLV{
+ {
+ Type: 8, // VXLAN
+ Tlvs: subTlvs,
+ },
+ },
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewTunnelEncapAttributeFromNative(n.(*bgp.PathAttributeTunnelEncap))
+ assert.Equal(1, len(output.Tlvs))
+ assert.Equal(input.Tlvs[0].Type, output.Tlvs[0].Type)
+ assert.Equal(len(output.Tlvs[0].Tlvs), len(output.Tlvs[0].Tlvs))
+ for idx, inputSubTlv := range input.Tlvs[0].Tlvs {
+ outputSubTlv := output.Tlvs[0].Tlvs[idx]
+ assert.Equal(inputSubTlv.TypeUrl, outputSubTlv.TypeUrl)
+ assert.Equal(inputSubTlv.Value, outputSubTlv.Value)
+ }
+}
+
+func Test_IP6ExtendedCommunitiesAttribute(t *testing.T) {
+ assert := assert.New(t)
+
+ communities := make([]*any.Any, 0, 2)
+ a, err := ptypes.MarshalAny(&api.IPv6AddressSpecificExtended{
+ IsTransitive: true,
+ SubType: 0xff, // Max of uint8
+ Address: "2001:db8:1::1",
+ LocalAdmin: 100,
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+ a, err = ptypes.MarshalAny(&api.RedirectIPv6AddressSpecificExtended{
+ Address: "2001:db8:2::1",
+ LocalAdmin: 200,
+ })
+ assert.Nil(err)
+ communities = append(communities, a)
+
+ input := &api.IP6ExtendedCommunitiesAttribute{
+ Communities: communities,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewIP6ExtendedCommunitiesAttributeFromNative(n.(*bgp.PathAttributeIP6ExtendedCommunities))
+ assert.Equal(2, len(output.Communities))
+ for idx, inputCommunity := range input.Communities {
+ outputCommunity := output.Communities[idx]
+ assert.Equal(inputCommunity.TypeUrl, outputCommunity.TypeUrl)
+ assert.Equal(inputCommunity.Value, outputCommunity.Value)
+ }
+}
+
+func Test_AigpAttribute(t *testing.T) {
+ assert := assert.New(t)
+
+ tlvs := make([]*any.Any, 0, 2)
+ a, err := ptypes.MarshalAny(&api.AigpTLVIGPMetric{
+ Metric: 50,
+ })
+ assert.Nil(err)
+ tlvs = append(tlvs, a)
+ a, err = ptypes.MarshalAny(&api.AigpTLVUnknown{
+ Type: 0xff, // Max of uint8
+ Value: []byte{0x11, 0x22, 0x33, 0x44},
+ })
+ assert.Nil(err)
+ tlvs = append(tlvs, a)
+
+ input := &api.AigpAttribute{
+ Tlvs: tlvs,
+ }
+
+ a, err = ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewAigpAttributeFromNative(n.(*bgp.PathAttributeAigp))
+ assert.Equal(2, len(output.Tlvs))
+ for idx, inputTlv := range input.Tlvs {
+ outputTlv := output.Tlvs[idx]
+ assert.Equal(inputTlv.TypeUrl, outputTlv.TypeUrl)
+ assert.Equal(inputTlv.Value, outputTlv.Value)
+ }
+}
+
+func Test_LargeCommunitiesAttribute(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.LargeCommunitiesAttribute{
+ Communities: []*api.LargeCommunity{
+ {
+ GlobalAdmin: 65001,
+ LocalData1: 100,
+ LocalData2: 200,
+ },
+ {
+ GlobalAdmin: 65002,
+ LocalData1: 300,
+ LocalData2: 400,
+ },
+ },
+ }
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewLargeCommunitiesAttributeFromNative(n.(*bgp.PathAttributeLargeCommunities))
+ assert.Equal(2, len(output.Communities))
+ assert.Equal(input.Communities, output.Communities)
+}
+
+func Test_UnknownAttribute(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.UnknownAttribute{
+ Flags: (1 << 6) | (1 << 7), // OPTIONAL and TRANSITIVE
+ Type: 0xff,
+ Value: []byte{0x11, 0x22, 0x33, 0x44},
+ }
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalAttribute(a)
+ assert.Nil(err)
+
+ output := NewUnknownAttributeFromNative(n.(*bgp.PathAttributeUnknown))
+ assert.Equal(input.Flags, output.Flags)
+ assert.Equal(input.Type, output.Type)
+ assert.Equal(input.Value, output.Value)
+}
diff --git a/internal/pkg/apiutil/capability.go b/internal/pkg/apiutil/capability.go
new file mode 100644
index 00000000..0e3b4c0b
--- /dev/null
+++ b/internal/pkg/apiutil/capability.go
@@ -0,0 +1,244 @@
+// Copyright (C) 2018 Nippon Telegraph and Telephone Corporation.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+// implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package apiutil
+
+import (
+ "fmt"
+
+ proto "github.com/golang/protobuf/proto"
+ "github.com/golang/protobuf/ptypes"
+ "github.com/golang/protobuf/ptypes/any"
+ api "github.com/osrg/gobgp/api"
+ "github.com/osrg/gobgp/pkg/packet/bgp"
+)
+
+func NewMultiProtocolCapability(a *bgp.CapMultiProtocol) *api.MultiProtocolCapability {
+ return &api.MultiProtocolCapability{
+ Family: api.Family(a.CapValue),
+ }
+}
+
+func NewRouteRefreshCapability(a *bgp.CapRouteRefresh) *api.RouteRefreshCapability {
+ return &api.RouteRefreshCapability{}
+}
+
+func NewCarryingLabelInfoCapability(a *bgp.CapCarryingLabelInfo) *api.CarryingLabelInfoCapability {
+ return &api.CarryingLabelInfoCapability{}
+}
+
+func NewExtendedNexthopCapability(a *bgp.CapExtendedNexthop) *api.ExtendedNexthopCapability {
+ tuples := make([]*api.ExtendedNexthopCapabilityTuple, 0, len(a.Tuples))
+ for _, t := range a.Tuples {
+ tuples = append(tuples, &api.ExtendedNexthopCapabilityTuple{
+ NlriFamily: api.Family(bgp.AfiSafiToRouteFamily(t.NLRIAFI, uint8(t.NLRISAFI))),
+ NexthopFamily: api.Family(bgp.AfiSafiToRouteFamily(t.NexthopAFI, bgp.SAFI_UNICAST)),
+ })
+ }
+ return &api.ExtendedNexthopCapability{
+ Tuples: tuples,
+ }
+}
+
+func NewGracefulRestartCapability(a *bgp.CapGracefulRestart) *api.GracefulRestartCapability {
+ tuples := make([]*api.GracefulRestartCapabilityTuple, 0, len(a.Tuples))
+ for _, t := range a.Tuples {
+ tuples = append(tuples, &api.GracefulRestartCapabilityTuple{
+ Family: api.Family(bgp.AfiSafiToRouteFamily(t.AFI, uint8(t.SAFI))),
+ Flags: uint32(t.Flags),
+ })
+ }
+ return &api.GracefulRestartCapability{
+ Flags: uint32(a.Flags),
+ Time: uint32(a.Time),
+ Tuples: tuples,
+ }
+}
+
+func NewFourOctetASNumberCapability(a *bgp.CapFourOctetASNumber) *api.FourOctetASNumberCapability {
+ return &api.FourOctetASNumberCapability{
+ As: a.CapValue,
+ }
+}
+
+func NewAddPathCapability(a *bgp.CapAddPath) *api.AddPathCapability {
+ tuples := make([]*api.AddPathCapabilityTuple, 0, len(a.Tuples))
+ for _, t := range a.Tuples {
+ tuples = append(tuples, &api.AddPathCapabilityTuple{
+ Family: api.Family(t.RouteFamily),
+ Mode: api.AddPathMode(t.Mode),
+ })
+ }
+ return &api.AddPathCapability{
+ Tuples: tuples,
+ }
+}
+
+func NewEnhancedRouteRefreshCapability(a *bgp.CapEnhancedRouteRefresh) *api.EnhancedRouteRefreshCapability {
+ return &api.EnhancedRouteRefreshCapability{}
+}
+
+func NewLongLivedGracefulRestartCapability(a *bgp.CapLongLivedGracefulRestart) *api.LongLivedGracefulRestartCapability {
+ tuples := make([]*api.LongLivedGracefulRestartCapabilityTuple, 0, len(a.Tuples))
+ for _, t := range a.Tuples {
+ tuples = append(tuples, &api.LongLivedGracefulRestartCapabilityTuple{
+ Family: api.Family(bgp.AfiSafiToRouteFamily(t.AFI, uint8(t.SAFI))),
+ Flags: uint32(t.Flags),
+ Time: t.RestartTime,
+ })
+ }
+ return &api.LongLivedGracefulRestartCapability{
+ Tuples: tuples,
+ }
+}
+
+func NewRouteRefreshCiscoCapability(a *bgp.CapRouteRefreshCisco) *api.RouteRefreshCiscoCapability {
+ return &api.RouteRefreshCiscoCapability{}
+}
+
+func NewUnknownCapability(a *bgp.CapUnknown) *api.UnknownCapability {
+ return &api.UnknownCapability{
+ Code: uint32(a.CapCode),
+ Value: a.CapValue,
+ }
+}
+
+func MarshalCapability(value bgp.ParameterCapabilityInterface) (*any.Any, error) {
+ var m proto.Message
+ switch n := value.(type) {
+ case *bgp.CapMultiProtocol:
+ m = NewMultiProtocolCapability(n)
+ case *bgp.CapRouteRefresh:
+ m = NewRouteRefreshCapability(n)
+ case *bgp.CapCarryingLabelInfo:
+ m = NewCarryingLabelInfoCapability(n)
+ case *bgp.CapExtendedNexthop:
+ m = NewExtendedNexthopCapability(n)
+ case *bgp.CapGracefulRestart:
+ m = NewGracefulRestartCapability(n)
+ case *bgp.CapFourOctetASNumber:
+ m = NewFourOctetASNumberCapability(n)
+ case *bgp.CapAddPath:
+ m = NewAddPathCapability(n)
+ case *bgp.CapEnhancedRouteRefresh:
+ m = NewEnhancedRouteRefreshCapability(n)
+ case *bgp.CapLongLivedGracefulRestart:
+ m = NewLongLivedGracefulRestartCapability(n)
+ case *bgp.CapRouteRefreshCisco:
+ m = NewRouteRefreshCiscoCapability(n)
+ case *bgp.CapUnknown:
+ m = NewUnknownCapability(n)
+ default:
+ return nil, fmt.Errorf("invalid capability type to marshal: %+v", value)
+ }
+ return ptypes.MarshalAny(m)
+}
+
+func MarshalCapabilities(values []bgp.ParameterCapabilityInterface) ([]*any.Any, error) {
+ caps := make([]*any.Any, 0, len(values))
+ for _, value := range values {
+ a, err := MarshalCapability(value)
+ if err != nil {
+ return nil, err
+ }
+ caps = append(caps, a)
+ }
+ return caps, nil
+}
+
+func unmarshalCapability(a *any.Any) (bgp.ParameterCapabilityInterface, error) {
+ var value ptypes.DynamicAny
+ if err := ptypes.UnmarshalAny(a, &value); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal capability: %s", err)
+ }
+ switch a := value.Message.(type) {
+ case *api.MultiProtocolCapability:
+ return bgp.NewCapMultiProtocol(bgp.RouteFamily(a.Family)), nil
+ case *api.RouteRefreshCapability:
+ return bgp.NewCapRouteRefresh(), nil
+ case *api.CarryingLabelInfoCapability:
+ return bgp.NewCapCarryingLabelInfo(), nil
+ case *api.ExtendedNexthopCapability:
+ tuples := make([]*bgp.CapExtendedNexthopTuple, 0, len(a.Tuples))
+ for _, t := range a.Tuples {
+ var nhAfi uint16
+ switch t.NexthopFamily {
+ case api.Family_IPv4:
+ nhAfi = bgp.AFI_IP
+ case api.Family_IPv6:
+ nhAfi = bgp.AFI_IP6
+ default:
+ return nil, fmt.Errorf("invalid address family for nexthop afi in extended nexthop capability: %s", t.NexthopFamily)
+ }
+ tuples = append(tuples, bgp.NewCapExtendedNexthopTuple(bgp.RouteFamily(t.NlriFamily), nhAfi))
+ }
+ return bgp.NewCapExtendedNexthop(tuples), nil
+ case *api.GracefulRestartCapability:
+ tuples := make([]*bgp.CapGracefulRestartTuple, 0, len(a.Tuples))
+ for _, t := range a.Tuples {
+ var forward bool
+ if t.Flags&0x80 > 0 {
+ forward = true
+ }
+ tuples = append(tuples, bgp.NewCapGracefulRestartTuple(bgp.RouteFamily(t.Family), forward))
+ }
+ var restarting bool
+ if a.Flags&0x08 > 0 {
+ restarting = true
+ }
+ var notification bool
+ if a.Flags&0x04 > 0 {
+ notification = true
+ }
+ return bgp.NewCapGracefulRestart(restarting, notification, uint16(a.Time), tuples), nil
+ case *api.FourOctetASNumberCapability:
+ return bgp.NewCapFourOctetASNumber(a.As), nil
+ case *api.AddPathCapability:
+ tuples := make([]*bgp.CapAddPathTuple, 0, len(a.Tuples))
+ for _, t := range a.Tuples {
+ tuples = append(tuples, bgp.NewCapAddPathTuple(bgp.RouteFamily(t.Family), bgp.BGPAddPathMode(t.Mode)))
+ }
+ return bgp.NewCapAddPath(tuples), nil
+ case *api.EnhancedRouteRefreshCapability:
+ return bgp.NewCapEnhancedRouteRefresh(), nil
+ case *api.LongLivedGracefulRestartCapability:
+ tuples := make([]*bgp.CapLongLivedGracefulRestartTuple, 0, len(a.Tuples))
+ for _, t := range a.Tuples {
+ var forward bool
+ if t.Flags&0x80 > 0 {
+ forward = true
+ }
+ tuples = append(tuples, bgp.NewCapLongLivedGracefulRestartTuple(bgp.RouteFamily(t.Family), forward, t.Time))
+ }
+ return bgp.NewCapLongLivedGracefulRestart(tuples), nil
+ case *api.RouteRefreshCiscoCapability:
+ return bgp.NewCapRouteRefreshCisco(), nil
+ case *api.UnknownCapability:
+ return bgp.NewCapUnknown(bgp.BGPCapabilityCode(a.Code), a.Value), nil
+ }
+ return nil, fmt.Errorf("invalid capability type to unmarshal: %s", a.TypeUrl)
+}
+
+func UnmarshalCapabilities(values []*any.Any) ([]bgp.ParameterCapabilityInterface, error) {
+ caps := make([]bgp.ParameterCapabilityInterface, 0, len(values))
+ for _, value := range values {
+ c, err := unmarshalCapability(value)
+ if err != nil {
+ return nil, err
+ }
+ caps = append(caps, c)
+ }
+ return caps, nil
+}
diff --git a/internal/pkg/apiutil/capability_test.go b/internal/pkg/apiutil/capability_test.go
new file mode 100644
index 00000000..0872ed58
--- /dev/null
+++ b/internal/pkg/apiutil/capability_test.go
@@ -0,0 +1,251 @@
+// Copyright (C) 2018 Nippon Telegraph and Telephone Corporation.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+// implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package apiutil
+
+import (
+ "testing"
+
+ "github.com/golang/protobuf/ptypes"
+ api "github.com/osrg/gobgp/api"
+ "github.com/osrg/gobgp/pkg/packet/bgp"
+ "github.com/stretchr/testify/assert"
+)
+
+func Test_MultiProtocolCapability(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.MultiProtocolCapability{
+ Family: api.Family_IPv4,
+ }
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalCapability(a)
+ assert.Nil(err)
+ c := n.(*bgp.CapMultiProtocol)
+ assert.Equal(bgp.RF_IPv4_UC, c.CapValue)
+
+ output := NewMultiProtocolCapability(c)
+ assert.Equal(input, output)
+}
+
+func Test_RouteRefreshCapability(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.RouteRefreshCapability{}
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalCapability(a)
+ assert.Nil(err)
+
+ output := NewRouteRefreshCapability(n.(*bgp.CapRouteRefresh))
+ assert.Equal(input, output)
+}
+
+func Test_CarryingLabelInfoCapability(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.CarryingLabelInfoCapability{}
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalCapability(a)
+ assert.Nil(err)
+
+ output := NewCarryingLabelInfoCapability(n.(*bgp.CapCarryingLabelInfo))
+ assert.Equal(input, output)
+}
+
+func Test_ExtendedNexthopCapability(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.ExtendedNexthopCapability{
+ Tuples: []*api.ExtendedNexthopCapabilityTuple{
+ {
+ NlriFamily: api.Family_IPv4,
+ NexthopFamily: api.Family_IPv6,
+ },
+ },
+ }
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalCapability(a)
+ assert.Nil(err)
+ c := n.(*bgp.CapExtendedNexthop)
+ assert.Equal(1, len(c.Tuples))
+ assert.Equal(uint16(bgp.AFI_IP), c.Tuples[0].NLRIAFI)
+ assert.Equal(uint16(bgp.SAFI_UNICAST), c.Tuples[0].NLRISAFI)
+ assert.Equal(uint16(bgp.AFI_IP6), c.Tuples[0].NexthopAFI)
+
+ output := NewExtendedNexthopCapability(c)
+ assert.Equal(input, output)
+}
+
+func Test_GracefulRestartCapability(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.GracefulRestartCapability{
+ Flags: 0x08 | 0x04, // restarting|notification
+ Time: 90,
+ Tuples: []*api.GracefulRestartCapabilityTuple{
+ {
+ Family: api.Family_IPv4,
+ Flags: 0x80, // forward
+ },
+ },
+ }
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalCapability(a)
+ assert.Nil(err)
+
+ c := n.(*bgp.CapGracefulRestart)
+ assert.Equal(1, len(c.Tuples))
+ assert.Equal(uint8(0x08|0x04), c.Flags)
+ assert.Equal(uint16(90), c.Time)
+ assert.Equal(uint16(bgp.AFI_IP), c.Tuples[0].AFI)
+ assert.Equal(uint8(bgp.SAFI_UNICAST), c.Tuples[0].SAFI)
+ assert.Equal(uint8(0x80), c.Tuples[0].Flags)
+
+ output := NewGracefulRestartCapability(c)
+ assert.Equal(input, output)
+}
+
+func Test_FourOctetASNumberCapability(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.FourOctetASNumberCapability{
+ As: 100,
+ }
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalCapability(a)
+ assert.Nil(err)
+
+ c := n.(*bgp.CapFourOctetASNumber)
+ assert.Equal(uint32(100), c.CapValue)
+
+ output := NewFourOctetASNumberCapability(c)
+ assert.Equal(input, output)
+}
+
+func Test_AddPathCapability(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.AddPathCapability{
+ Tuples: []*api.AddPathCapabilityTuple{
+ {
+ Family: api.Family_IPv4,
+ Mode: api.AddPathMode_MODE_BOTH,
+ },
+ },
+ }
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalCapability(a)
+ assert.Nil(err)
+
+ c := n.(*bgp.CapAddPath)
+ assert.Equal(1, len(c.Tuples))
+ assert.Equal(bgp.RF_IPv4_UC, c.Tuples[0].RouteFamily)
+ assert.Equal(bgp.BGP_ADD_PATH_BOTH, c.Tuples[0].Mode)
+
+ output := NewAddPathCapability(c)
+ assert.Equal(input, output)
+}
+
+func Test_EnhancedRouteRefreshCapability(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.EnhancedRouteRefreshCapability{}
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalCapability(a)
+ assert.Nil(err)
+
+ output := NewEnhancedRouteRefreshCapability(n.(*bgp.CapEnhancedRouteRefresh))
+ assert.Equal(input, output)
+}
+
+func Test_LongLivedGracefulRestartCapability(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.LongLivedGracefulRestartCapability{
+ Tuples: []*api.LongLivedGracefulRestartCapabilityTuple{
+ {
+ Family: api.Family_IPv4,
+ Flags: 0x80, // forward
+ Time: 90,
+ },
+ },
+ }
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalCapability(a)
+ assert.Nil(err)
+
+ c := n.(*bgp.CapLongLivedGracefulRestart)
+ assert.Equal(1, len(c.Tuples))
+ assert.Equal(uint16(bgp.AFI_IP), c.Tuples[0].AFI)
+ assert.Equal(uint8(bgp.SAFI_UNICAST), c.Tuples[0].SAFI)
+ assert.Equal(uint8(0x80), c.Tuples[0].Flags)
+ assert.Equal(uint32(90), c.Tuples[0].RestartTime)
+
+ output := NewLongLivedGracefulRestartCapability(c)
+ assert.Equal(input, output)
+}
+
+func Test_RouteRefreshCiscoCapability(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.RouteRefreshCiscoCapability{}
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalCapability(a)
+ assert.Nil(err)
+
+ output := NewRouteRefreshCiscoCapability(n.(*bgp.CapRouteRefreshCisco))
+ assert.Equal(input, output)
+}
+
+func Test_UnknownCapability(t *testing.T) {
+ assert := assert.New(t)
+
+ input := &api.UnknownCapability{
+ Code: 0xff,
+ Value: []byte{0x11, 0x22, 0x33, 0x44},
+ }
+
+ a, err := ptypes.MarshalAny(input)
+ assert.Nil(err)
+ n, err := unmarshalCapability(a)
+ assert.Nil(err)
+
+ c := n.(*bgp.CapUnknown)
+ assert.Equal(bgp.BGPCapabilityCode(0xff), c.CapCode)
+ assert.Equal([]byte{0x11, 0x22, 0x33, 0x44}, c.CapValue)
+
+ output := NewUnknownCapability(c)
+ assert.Equal(input, output)
+}
diff --git a/internal/pkg/apiutil/util.go b/internal/pkg/apiutil/util.go
new file mode 100644
index 00000000..45cf1a04
--- /dev/null
+++ b/internal/pkg/apiutil/util.go
@@ -0,0 +1,114 @@
+// Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+// implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package apiutil
+
+import (
+ "encoding/json"
+ "net"
+ "time"
+
+ api "github.com/osrg/gobgp/api"
+ "github.com/osrg/gobgp/pkg/packet/bgp"
+)
+
+// workaround. This for the json format compatibility. Once we update senario tests, we can remove this.
+type Path struct {
+ Nlri bgp.AddrPrefixInterface `json:"nlri"`
+ Age int64 `json:"age"`
+ Best bool `json:"best"`
+ Attrs []bgp.PathAttributeInterface `json:"attrs"`
+ Stale bool `json:"stale"`
+ Withdrawal bool `json:"withdrawal,omitempty"`
+ SourceID net.IP `json:"source-id,omitempty"`
+ NeighborIP net.IP `json:"neighbor-ip,omitempty"`
+}
+
+type Destination struct {
+ Paths []*Path
+}
+
+func (d *Destination) MarshalJSON() ([]byte, error) {
+ return json.Marshal(d.Paths)
+}
+
+func NewDestination(dst *api.Destination) *Destination {
+ l := make([]*Path, 0, len(dst.Paths))
+ for _, p := range dst.Paths {
+ nlri, _ := GetNativeNlri(p)
+ attrs, _ := GetNativePathAttributes(p)
+ l = append(l, &Path{
+ Nlri: nlri,
+ Age: p.Age,
+ Best: p.Best,
+ Attrs: attrs,
+ Stale: p.Stale,
+ Withdrawal: p.IsWithdraw,
+ SourceID: net.ParseIP(p.SourceId),
+ NeighborIP: net.ParseIP(p.NeighborIp),
+ })
+ }
+ return &Destination{Paths: l}
+}
+
+func NewPath(nlri bgp.AddrPrefixInterface, isWithdraw bool, attrs []bgp.PathAttributeInterface, age time.Time) *api.Path {
+ return &api.Path{
+ AnyNlri: MarshalNLRI(nlri),
+ AnyPattrs: MarshalPathAttributes(attrs),
+ Age: age.Unix(),
+ IsWithdraw: isWithdraw,
+ Family: uint32(bgp.AfiSafiToRouteFamily(nlri.AFI(), nlri.SAFI())),
+ Identifier: nlri.PathIdentifier(),
+ }
+}
+
+func getNLRI(family bgp.RouteFamily, buf []byte) (bgp.AddrPrefixInterface, error) {
+ afi, safi := bgp.RouteFamilyToAfiSafi(family)
+ nlri, err := bgp.NewPrefixFromRouteFamily(afi, safi)
+ if err != nil {
+ return nil, err
+ }
+ if err := nlri.DecodeFromBytes(buf); err != nil {
+ return nil, err
+ }
+ return nlri, nil
+}
+
+func GetNativeNlri(p *api.Path) (bgp.AddrPrefixInterface, error) {
+ if len(p.Nlri) > 0 {
+ return getNLRI(bgp.RouteFamily(p.Family), p.Nlri)
+ }
+ return UnmarshalNLRI(bgp.RouteFamily(p.Family), p.AnyNlri)
+}
+
+func GetNativePathAttributes(p *api.Path) ([]bgp.PathAttributeInterface, error) {
+ pattrsLen := len(p.Pattrs)
+ if pattrsLen > 0 {
+ pattrs := make([]bgp.PathAttributeInterface, 0, pattrsLen)
+ for _, attr := range p.Pattrs {
+ a, err := bgp.GetPathAttribute(attr)
+ if err != nil {
+ return nil, err
+ }
+ err = a.DecodeFromBytes(attr)
+ if err != nil {
+ return nil, err
+ }
+ pattrs = append(pattrs, a)
+ }
+ return pattrs, nil
+ }
+ return UnmarshalPathAttributes(p.AnyPattrs)
+}