// 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 gobgpapi import ( "fmt" "net" "github.com/golang/protobuf/proto" "github.com/golang/protobuf/ptypes" "github.com/golang/protobuf/ptypes/any" log "github.com/sirupsen/logrus" "github.com/osrg/gobgp/packet/bgp" ) func NewOriginAttributeFromNative(a *bgp.PathAttributeOrigin) *OriginAttribute { return &OriginAttribute{ Origin: uint32(a.Value), } } func (a *OriginAttribute) ToNative() (*bgp.PathAttributeOrigin, error) { return bgp.NewPathAttributeOrigin(uint8(a.Origin)), nil } func NewAsPathAttributeFromNative(a *bgp.PathAttributeAsPath) *AsPathAttribute { segments := make([]*AsSegment, 0, len(a.Value)) for _, param := range a.Value { segments = append(segments, &AsSegment{ Type: uint32(param.GetType()), Numbers: param.GetAS(), }) } return &AsPathAttribute{ Segments: segments, } } func (a *AsPathAttribute) ToNative() (*bgp.PathAttributeAsPath, error) { 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 } func NewNextHopAttributeFromNative(a *bgp.PathAttributeNextHop) *NextHopAttribute { return &NextHopAttribute{ NextHop: a.Value.String(), } } func (a *NextHopAttribute) ToNative() (*bgp.PathAttributeNextHop, error) { 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 } func NewMultiExitDiscAttributeFromNative(a *bgp.PathAttributeMultiExitDisc) *MultiExitDiscAttribute { return &MultiExitDiscAttribute{ Med: a.Value, } } func (a *MultiExitDiscAttribute) ToNative() (*bgp.PathAttributeMultiExitDisc, error) { return bgp.NewPathAttributeMultiExitDisc(a.Med), nil } func NewLocalPrefAttributeFromNative(a *bgp.PathAttributeLocalPref) *LocalPrefAttribute { return &LocalPrefAttribute{ LocalPref: a.Value, } } func (a *LocalPrefAttribute) ToNative() (*bgp.PathAttributeLocalPref, error) { return bgp.NewPathAttributeLocalPref(a.LocalPref), nil } func NewAtomicAggregateAttributeFromNative(a *bgp.PathAttributeAtomicAggregate) *AtomicAggregateAttribute { return &AtomicAggregateAttribute{} } func (a *AtomicAggregateAttribute) ToNative() (*bgp.PathAttributeAtomicAggregate, error) { return bgp.NewPathAttributeAtomicAggregate(), nil } func NewAggregatorAttributeFromNative(a *bgp.PathAttributeAggregator) *AggregatorAttribute { return &AggregatorAttribute{ As: a.Value.AS, Address: a.Value.Address.String(), } } func (a *AggregatorAttribute) ToNative() (*bgp.PathAttributeAggregator, error) { 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 } func NewCommunitiesAttributeFromNative(a *bgp.PathAttributeCommunities) *CommunitiesAttribute { return &CommunitiesAttribute{ Communities: a.Value, } } func (a *CommunitiesAttribute) ToNative() (*bgp.PathAttributeCommunities, error) { return bgp.NewPathAttributeCommunities(a.Communities), nil } func NewOriginatorIdAttributeFromNative(a *bgp.PathAttributeOriginatorId) *OriginatorIdAttribute { return &OriginatorIdAttribute{ Id: a.Value.String(), } } func (a *OriginatorIdAttribute) ToNative() (*bgp.PathAttributeOriginatorId, error) { if net.ParseIP(a.Id).To4() == nil { return nil, fmt.Errorf("invalid originator id: %s", a.Id) } return bgp.NewPathAttributeOriginatorId(a.Id), nil } func NewClusterListAttributeFromNative(a *bgp.PathAttributeClusterList) *ClusterListAttribute { ids := make([]string, 0, len(a.Value)) for _, id := range a.Value { ids = append(ids, id.String()) } return &ClusterListAttribute{ Ids: ids, } } func (a *ClusterListAttribute) ToNative() (*bgp.PathAttributeClusterList, error) { 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 } func MarshalRD(rd bgp.RouteDistinguisherInterface) *any.Any { var r proto.Message switch v := rd.(type) { case *bgp.RouteDistinguisherTwoOctetAS: r = &RouteDistinguisherTwoOctetAS{ Admin: uint32(v.Admin), Assigned: v.Assigned, } case *bgp.RouteDistinguisherIPAddressAS: r = &RouteDistinguisherIPAddress{ Admin: v.Admin.String(), Assigned: uint32(v.Assigned), } case *bgp.RouteDistinguisherFourOctetAS: r = &RouteDistinguisherFourOctetAS{ Admin: v.Admin, Assigned: uint32(v.Assigned), } default: 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 *RouteDistinguisherTwoOctetAS: return bgp.NewRouteDistinguisherTwoOctetAS(uint16(v.Admin), v.Assigned), nil case *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 *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) *EthernetSegmentIdentifier { return &EthernetSegmentIdentifier{ Type: uint32(a.Type), Value: a.Value, } } func (a *EthernetSegmentIdentifier) ToNative() (*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 = &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 = &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 = &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 = &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 = &FlowSpecMAC{ Type: uint32(bgp.FLOW_SPEC_TYPE_SRC_MAC), Address: v.Mac.String(), } case *bgp.FlowSpecDestinationMac: rule = &FlowSpecMAC{ Type: uint32(bgp.FLOW_SPEC_TYPE_DST_MAC), Address: v.Mac.String(), } case *bgp.FlowSpecComponent: items := make([]*FlowSpecComponentItem, 0, len(v.Items)) for _, i := range v.Items { items = append(items, &FlowSpecComponentItem{ Op: uint32(i.Op), Value: i.Value, }) } rule = &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 *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 *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 *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 = &IPAddressPrefix{ PrefixLen: uint32(v.Length), Prefix: v.Prefix.String(), } case *bgp.IPv6AddrPrefix: nlri = &IPAddressPrefix{ PrefixLen: uint32(v.Length), Prefix: v.Prefix.String(), } case *bgp.LabeledIPAddrPrefix: nlri = &LabeledIPAddressPrefix{ Labels: v.Labels.Labels, PrefixLen: uint32(v.IPPrefixLen()), Prefix: v.Prefix.String(), } case *bgp.LabeledIPv6AddrPrefix: nlri = &LabeledIPAddressPrefix{ Labels: v.Labels.Labels, PrefixLen: uint32(v.IPPrefixLen()), Prefix: v.Prefix.String(), } case *bgp.EncapNLRI: nlri = &EncapsulationNLRI{ Address: v.String(), } case *bgp.Encapv6NLRI: nlri = &EncapsulationNLRI{ Address: v.String(), } case *bgp.EVPNNLRI: switch r := v.RouteTypeData.(type) { case *bgp.EVPNEthernetAutoDiscoveryRoute: nlri = &EVPNEthernetAutoDiscoveryRoute{ Rd: MarshalRD(r.RD), Esi: NewEthernetSegmentIdentifierFromNative(&r.ESI), EthernetTag: r.ETag, Label: r.Label, } case *bgp.EVPNMacIPAdvertisementRoute: nlri = &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 = &EVPNInclusiveMulticastEthernetTagRoute{ Rd: MarshalRD(r.RD), EthernetTag: r.ETag, IpAddress: r.IPAddress.String(), } case *bgp.EVPNEthernetSegmentRoute: nlri = &EVPNEthernetSegmentRoute{ Rd: MarshalRD(r.RD), Esi: NewEthernetSegmentIdentifierFromNative(&r.ESI), IpAddress: r.IPAddress.String(), } case *bgp.EVPNIPPrefixRoute: nlri = &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 = &LabeledVPNIPAddressPrefix{ Labels: v.Labels.Labels, Rd: MarshalRD(v.RD), PrefixLen: uint32(v.IPPrefixLen()), Prefix: v.Prefix.String(), } case *bgp.LabeledVPNIPv6AddrPrefix: nlri = &LabeledVPNIPAddressPrefix{ Labels: v.Labels.Labels, Rd: MarshalRD(v.RD), PrefixLen: uint32(v.IPPrefixLen()), Prefix: v.Prefix.String(), } case *bgp.RouteTargetMembershipNLRI: nlri = &RouteTargetMembershipNLRI{ As: v.AS, Rt: MarshalRT(v.RouteTarget), } case *bgp.FlowSpecIPv4Unicast: nlri = &FlowSpecNLRI{ Rules: MarshalFlowSpecRules(v.Value), } case *bgp.FlowSpecIPv6Unicast: nlri = &FlowSpecNLRI{ Rules: MarshalFlowSpecRules(v.Value), } case *bgp.FlowSpecIPv4VPN: nlri = &VPNFlowSpecNLRI{ Rd: MarshalRD(v.RD()), Rules: MarshalFlowSpecRules(v.Value), } case *bgp.FlowSpecIPv6VPN: nlri = &VPNFlowSpecNLRI{ Rd: MarshalRD(v.RD()), Rules: MarshalFlowSpecRules(v.Value), } case *bgp.FlowSpecL2VPN: nlri = &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 *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 *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 *EncapsulationNLRI: switch rf { case bgp.RF_IPv4_ENCAP: nlri = bgp.NewEncapNLRI(v.Address) case bgp.RF_IPv6_ENCAP: nlri = bgp.NewEncapv6NLRI(v.Address) } case *EVPNEthernetAutoDiscoveryRoute: if rf == bgp.RF_EVPN { rd, err := UnmarshalRD(v.Rd) if err != nil { return nil, err } esi, err := v.Esi.ToNative() if err != nil { return nil, err } nlri = bgp.NewEVPNEthernetAutoDiscoveryRoute(rd, *esi, v.EthernetTag, v.Label) } case *EVPNMACIPAdvertisementRoute: if rf == bgp.RF_EVPN { rd, err := UnmarshalRD(v.Rd) if err != nil { return nil, err } esi, err := v.Esi.ToNative() if err != nil { return nil, err } nlri = bgp.NewEVPNMacIPAdvertisementRoute(rd, *esi, v.EthernetTag, v.MacAddress, v.IpAddress, v.Labels) } case *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 *EVPNEthernetSegmentRoute: if rf == bgp.RF_EVPN { rd, err := UnmarshalRD(v.Rd) if err != nil { return nil, err } esi, err := v.Esi.ToNative() if err != nil { return nil, err } nlri = bgp.NewEVPNEthernetSegmentRoute(rd, *esi, v.IpAddress) } case *EVPNIPPrefixRoute: if rf == bgp.RF_EVPN { rd, err := UnmarshalRD(v.Rd) if err != nil { return nil, err } esi, err := v.Esi.ToNative() if err != nil { return nil, err } nlri = bgp.NewEVPNIPPrefixRoute(rd, *esi, v.EthernetTag, uint8(v.IpPrefixLen), v.IpPrefix, v.GwAddress, v.Label) } case *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 *RouteTargetMembershipNLRI: rt, err := UnmarshalRT(v.Rt) if err != nil { return nil, err } nlri = bgp.NewRouteTargetMembershipNLRI(v.As, rt) case *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 *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) *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 &MpReachNLRIAttribute{ Family: uint32(bgp.AfiSafiToRouteFamily(a.AFI, a.SAFI)), NextHops: nexthops, Nlris: MarshalNLRIs(a.Value), } } func (a *MpReachNLRIAttribute) ToNative() (*bgp.PathAttributeMpReachNLRI, error) { 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 } func NewMpUnreachNLRIAttributeFromNative(a *bgp.PathAttributeMpUnreachNLRI) *MpUnreachNLRIAttribute { return &MpUnreachNLRIAttribute{ Family: uint32(bgp.AfiSafiToRouteFamily(a.AFI, a.SAFI)), Nlris: MarshalNLRIs(a.Value), } } func (a *MpUnreachNLRIAttribute) ToNative() (*bgp.PathAttributeMpUnreachNLRI, error) { rf := bgp.RouteFamily(a.Family) nlris, err := UnmarshalNLRIs(rf, a.Nlris) if err != nil { return nil, err } return bgp.NewPathAttributeMpUnreachNLRI(nlris), nil } func MarshalRT(rt bgp.ExtendedCommunityInterface) *any.Any { var r proto.Message switch v := rt.(type) { case *bgp.TwoOctetAsSpecificExtended: r = &TwoOctetAsSpecificExtended{ IsTransitive: true, SubType: uint32(bgp.EC_SUBTYPE_ROUTE_TARGET), As: uint32(v.AS), LocalAdmin: uint32(v.LocalAdmin), } case *bgp.IPv4AddressSpecificExtended: r = &IPv4AddressSpecificExtended{ IsTransitive: true, SubType: uint32(bgp.EC_SUBTYPE_ROUTE_TARGET), Address: v.IPv4.String(), LocalAdmin: uint32(v.LocalAdmin), } case *bgp.FourOctetAsSpecificExtended: r = &FourOctetAsSpecificExtended{ IsTransitive: true, SubType: uint32(bgp.EC_SUBTYPE_ROUTE_TARGET), As: uint32(v.AS), LocalAdmin: uint32(v.LocalAdmin), } default: return nil } a, _ := ptypes.MarshalAny(r) return a } 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 *TwoOctetAsSpecificExtended: return bgp.NewTwoOctetAsSpecificExtended(bgp.ExtendedCommunityAttrSubType(v.SubType), uint16(v.As), v.LocalAdmin, v.IsTransitive), nil case *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 *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 NewExtendedCommunitiesAttributeFromNative(a *bgp.PathAttributeExtendedCommunities) *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 = &TwoOctetAsSpecificExtended{ IsTransitive: v.IsTransitive, SubType: uint32(v.SubType), As: uint32(v.AS), LocalAdmin: uint32(v.LocalAdmin), } case *bgp.IPv4AddressSpecificExtended: community = &IPv4AddressSpecificExtended{ IsTransitive: v.IsTransitive, SubType: uint32(v.SubType), Address: v.IPv4.String(), LocalAdmin: uint32(v.LocalAdmin), } case *bgp.FourOctetAsSpecificExtended: community = &FourOctetAsSpecificExtended{ IsTransitive: v.IsTransitive, SubType: uint32(v.SubType), As: uint32(v.AS), LocalAdmin: uint32(v.LocalAdmin), } case *bgp.ValidationExtended: community = &ValidationExtended{ State: uint32(v.State), } case *bgp.ColorExtended: community = &ColorExtended{ Color: v.Color, } case *bgp.EncapExtended: community = &EncapExtended{ TunnelType: uint32(v.TunnelType), } case *bgp.DefaultGatewayExtended: community = &DefaultGatewayExtended{} case *bgp.OpaqueExtended: community = &OpaqueExtended{ IsTransitive: v.IsTransitive, Value: v.Value, } case *bgp.ESILabelExtended: community = &ESILabelExtended{ IsSingleActive: v.IsSingleActive, Label: v.Label, } case *bgp.ESImportRouteTarget: community = &ESImportRouteTarget{ EsImport: v.ESImport.String(), } case *bgp.MacMobilityExtended: community = &MacMobilityExtended{ IsSticky: v.IsSticky, SequenceNum: v.Sequence, } case *bgp.RouterMacExtended: community = &RouterMacExtended{ Mac: v.Mac.String(), } case *bgp.TrafficRateExtended: community = &TrafficRateExtended{ As: uint32(v.AS), Rate: v.Rate, } case *bgp.TrafficActionExtended: community = &TrafficActionExtended{ Terminal: v.Terminal, Sample: v.Sample, } case *bgp.RedirectTwoOctetAsSpecificExtended: community = &RedirectTwoOctetAsSpecificExtended{ As: uint32(v.AS), LocalAdmin: v.LocalAdmin, } case *bgp.RedirectIPv4AddressSpecificExtended: community = &RedirectIPv4AddressSpecificExtended{ Address: v.IPv4.String(), LocalAdmin: uint32(v.LocalAdmin), } case *bgp.RedirectFourOctetAsSpecificExtended: community = &RedirectFourOctetAsSpecificExtended{ As: v.AS, LocalAdmin: uint32(v.LocalAdmin), } case *bgp.TrafficRemarkExtended: community = &TrafficRemarkExtended{ Dscp: uint32(v.DSCP), } case *bgp.UnknownExtended: community = &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 &ExtendedCommunitiesAttribute{ Communities: communities, } } func (a *ExtendedCommunitiesAttribute) ToNative() (*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 *TwoOctetAsSpecificExtended: community = bgp.NewTwoOctetAsSpecificExtended(bgp.ExtendedCommunityAttrSubType(v.SubType), uint16(v.As), v.LocalAdmin, v.IsTransitive) case *IPv4AddressSpecificExtended: community = bgp.NewIPv4AddressSpecificExtended(bgp.ExtendedCommunityAttrSubType(v.SubType), v.Address, uint16(v.LocalAdmin), v.IsTransitive) case *FourOctetAsSpecificExtended: community = bgp.NewFourOctetAsSpecificExtended(bgp.ExtendedCommunityAttrSubType(v.SubType), v.As, uint16(v.LocalAdmin), v.IsTransitive) case *ValidationExtended: community = bgp.NewValidationExtended(bgp.ValidationState(v.State)) case *ColorExtended: community = bgp.NewColorExtended(v.Color) case *EncapExtended: community = bgp.NewEncapExtended(bgp.TunnelType(v.TunnelType)) case *DefaultGatewayExtended: community = bgp.NewDefaultGatewayExtended() case *OpaqueExtended: community = bgp.NewOpaqueExtended(v.IsTransitive, v.Value) case *ESILabelExtended: community = bgp.NewESILabelExtended(v.Label, v.IsSingleActive) case *ESImportRouteTarget: community = bgp.NewESImportRouteTarget(v.EsImport) case *MacMobilityExtended: community = bgp.NewMacMobilityExtended(v.SequenceNum, v.IsSticky) case *RouterMacExtended: community = bgp.NewRoutersMacExtended(v.Mac) case *TrafficRateExtended: community = bgp.NewTrafficRateExtended(uint16(v.As), v.Rate) case *TrafficActionExtended: community = bgp.NewTrafficActionExtended(v.Terminal, v.Sample) case *RedirectTwoOctetAsSpecificExtended: community = bgp.NewRedirectTwoOctetAsSpecificExtended(uint16(v.As), v.LocalAdmin) case *RedirectIPv4AddressSpecificExtended: community = bgp.NewRedirectIPv4AddressSpecificExtended(v.Address, uint16(v.LocalAdmin)) case *RedirectFourOctetAsSpecificExtended: community = bgp.NewRedirectFourOctetAsSpecificExtended(v.As, uint16(v.LocalAdmin)) case *TrafficRemarkExtended: community = bgp.NewTrafficRemarkExtended(uint8(v.Dscp)) case *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) *As4PathAttribute { segments := make([]*AsSegment, 0, len(a.Value)) for _, param := range a.Value { segments = append(segments, &AsSegment{ Type: uint32(param.Type), Numbers: param.AS, }) } return &As4PathAttribute{ Segments: segments, } } func (a *As4PathAttribute) ToNative() (*bgp.PathAttributeAs4Path, error) { 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 } func NewAs4AggregatorAttributeFromNative(a *bgp.PathAttributeAs4Aggregator) *As4AggregatorAttribute { return &As4AggregatorAttribute{ As: a.Value.AS, Address: a.Value.Address.String(), } } func (a *As4AggregatorAttribute) ToNative() (*bgp.PathAttributeAs4Aggregator, error) { 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 } func NewPmsiTunnelAttributeFromNative(a *bgp.PathAttributePmsiTunnel) *PmsiTunnelAttribute { var flags uint32 if a.IsLeafInfoRequired { flags |= 0x01 } id, _ := a.TunnelID.Serialize() return &PmsiTunnelAttribute{ Flags: flags, Type: uint32(a.TunnelType), Label: a.Label, Id: id, } } func (a *PmsiTunnelAttribute) ToNative() (*bgp.PathAttributePmsiTunnel, error) { 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 } func NewTunnelEncapAttributeFromNative(a *bgp.PathAttributeTunnelEncap) *TunnelEncapAttribute { tlvs := make([]*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 = &TunnelEncapSubTLVEncapsulation{ Key: sv.Key, Cookie: sv.Cookie, } case *bgp.TunnelEncapSubTLVProtocol: subTlv = &TunnelEncapSubTLVProtocol{ Protocol: uint32(sv.Protocol), } case *bgp.TunnelEncapSubTLVColor: subTlv = &TunnelEncapSubTLVColor{ Color: sv.Color, } case *bgp.TunnelEncapSubTLVUnknown: subTlv = &TunnelEncapSubTLVUnknown{ Type: uint32(sv.Type), Value: sv.Value, } } an, _ := ptypes.MarshalAny(subTlv) subTlvs = append(subTlvs, an) } tlvs = append(tlvs, &TunnelEncapTLV{ Type: uint32(v.Type), Tlvs: subTlvs, }) } return &TunnelEncapAttribute{ Tlvs: tlvs, } } func (a *TunnelEncapAttribute) ToNative() (*bgp.PathAttributeTunnelEncap, error) { 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 *TunnelEncapSubTLVEncapsulation: subTlv = bgp.NewTunnelEncapSubTLVEncapsulation(sv.Key, sv.Cookie) case *TunnelEncapSubTLVProtocol: subTlv = bgp.NewTunnelEncapSubTLVProtocol(uint16(sv.Protocol)) case *TunnelEncapSubTLVColor: subTlv = bgp.NewTunnelEncapSubTLVColor(sv.Color) case *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 } func NewIP6ExtendedCommunitiesAttributeFromNative(a *bgp.PathAttributeIP6ExtendedCommunities) *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 = &IPv6AddressSpecificExtended{ IsTransitive: v.IsTransitive, SubType: uint32(v.SubType), Address: v.IPv6.String(), LocalAdmin: uint32(v.LocalAdmin), } case *bgp.RedirectIPv6AddressSpecificExtended: community = &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 &IP6ExtendedCommunitiesAttribute{ Communities: communities, } } func (a *IP6ExtendedCommunitiesAttribute) ToNative() (*bgp.PathAttributeIP6ExtendedCommunities, 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 ipv6 extended community: %s", err) } switch v := value.Message.(type) { case *IPv6AddressSpecificExtended: community = bgp.NewIPv6AddressSpecificExtended(bgp.ExtendedCommunityAttrSubType(v.SubType), v.Address, uint16(v.LocalAdmin), v.IsTransitive) case *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 } func NewAigpAttributeFromNative(a *bgp.PathAttributeAigp) *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 = &AigpTLVIGPMetric{ Metric: v.Metric, } case *bgp.AigpTLVDefault: tlv = &AigpTLVUnknown{ Type: uint32(v.Type()), Value: v.Value, } } an, _ := ptypes.MarshalAny(tlv) tlvs = append(tlvs, an) } return &AigpAttribute{ Tlvs: tlvs, } } func (a *AigpAttribute) ToNative() (*bgp.PathAttributeAigp, error) { 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 *AigpTLVIGPMetric: tlv = bgp.NewAigpTLVIgpMetric(v.Metric) case *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 } func NewLargeCommunitiesAttributeFromNative(a *bgp.PathAttributeLargeCommunities) *LargeCommunitiesAttribute { communities := make([]*LargeCommunity, 0, len(a.Values)) for _, v := range a.Values { communities = append(communities, &LargeCommunity{ GlobalAdmin: v.ASN, LocalData1: v.LocalData1, LocalData2: v.LocalData2, }) } return &LargeCommunitiesAttribute{ Communities: communities, } } func (a *LargeCommunitiesAttribute) ToNative() (*bgp.PathAttributeLargeCommunities, error) { 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 } func NewUnknownAttributeFromNative(a *bgp.PathAttributeUnknown) *UnknownAttribute { return &UnknownAttribute{ Flags: uint32(a.Flags), Type: uint32(a.Type), Value: a.Value, } } func (a *UnknownAttribute) ToNative() (*bgp.PathAttributeUnknown, error) { return bgp.NewPathAttributeUnknown(bgp.BGPAttrFlag(a.Flags), bgp.BGPAttrType(a.Type), a.Value), nil } 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 { var attr bgp.PathAttributeInterface var value ptypes.DynamicAny err := ptypes.UnmarshalAny(an, &value) if err != nil { return nil, fmt.Errorf("failed to unmarshal path attribute: %s", err) } switch v := value.Message.(type) { case *OriginAttribute: attr, err = v.ToNative() case *AsPathAttribute: attr, err = v.ToNative() case *NextHopAttribute: attr, err = v.ToNative() case *MultiExitDiscAttribute: attr, err = v.ToNative() case *LocalPrefAttribute: attr, err = v.ToNative() case *AtomicAggregateAttribute: attr, err = v.ToNative() case *AggregatorAttribute: attr, err = v.ToNative() case *CommunitiesAttribute: attr, err = v.ToNative() case *OriginatorIdAttribute: attr, err = v.ToNative() case *ClusterListAttribute: attr, err = v.ToNative() case *MpReachNLRIAttribute: var nlri *bgp.PathAttributeMpReachNLRI nlri, err = v.ToNative() if len(nlri.Value) > 1 { return nil, fmt.Errorf("multiple nlri in a single mp_reach_nlri are not supported") } attr = nlri case *MpUnreachNLRIAttribute: attr, err = v.ToNative() case *ExtendedCommunitiesAttribute: attr, err = v.ToNative() case *As4PathAttribute: attr, err = v.ToNative() case *As4AggregatorAttribute: attr, err = v.ToNative() case *PmsiTunnelAttribute: attr, err = v.ToNative() case *TunnelEncapAttribute: attr, err = v.ToNative() case *IP6ExtendedCommunitiesAttribute: attr, err = v.ToNative() case *AigpAttribute: attr, err = v.ToNative() case *LargeCommunitiesAttribute: attr, err = v.ToNative() case *UnknownAttribute: attr, err = v.ToNative() } if err != nil { return nil, err } if attr == nil { return nil, fmt.Errorf("invalid value type for path attribute: %s", value.Message) } 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 }