// 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 { if nexthop = net.ParseIP(a.NextHop).To16(); 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.PrefixSID: return bgp.NewPathAttributePrefixSID(a) } 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 NewPrefixSIDAttributeFromNative(a *bgp.PathAttributePrefixSID) *api.PrefixSID { psid := &api.PrefixSID{} psid.Tlvs = MarshalSRv6TLVs(a.TLVs) return psid } func MarshalSRv6TLVs(tlvs []bgp.PrefixSIDTLVInterface) []*any.Any { mtlvs := make([]*any.Any, len(tlvs)) for i, tlv := range tlvs { var r proto.Message switch t := tlv.(type) { case *bgp.SRv6L3ServiceAttribute: o := &api.SRv6L3ServiceTLV{} o.SubTlvs = MarshalSRv6SubTLVs(t.SubTLVs) r = o default: log.WithFields(log.Fields{ "Topic": "protobuf", "SRv6": t, }).Warn("invalid prefix sid tlv type to marshal") return nil } a, _ := ptypes.MarshalAny(r) mtlvs[i] = a } return mtlvs } func MarshalSRv6SubTLVs(tlvs []bgp.PrefixSIDTLVInterface) map[uint32]*api.SRv6TLV { mtlvs := make(map[uint32]*api.SRv6TLV) var key uint32 for _, tlv := range tlvs { var r proto.Message switch t := tlv.(type) { case *bgp.SRv6InformationSubTLV: o := &api.SRv6InformationSubTLV{ EndpointBehavior: uint32(t.EndpointBehavior), // TODO Once flags are used in RFC, add processing. Flags: &api.SRv6SIDFlags{}, } o.Sid = make([]byte, len(t.SID)) copy(o.Sid, t.SID) o.SubSubTlvs = MarshalSRv6SubSubTLVs(t.SubSubTLVs) // SRv6 Information Sub TLV is type 1 Sub TLV key = 1 r = o default: log.WithFields(log.Fields{ "Topic": "protobuf", "SRv6": t, }).Warn("invalid prefix sid sub tlv type to marshal") return nil } a, _ := ptypes.MarshalAny(r) tlvs, ok := mtlvs[key] if !ok { tlvs = &api.SRv6TLV{ Tlv: make([]*any.Any, 0), } mtlvs[key] = tlvs } tlvs.Tlv = append(tlvs.Tlv, a) } return mtlvs } func MarshalSRv6SubSubTLVs(tlvs []bgp.PrefixSIDTLVInterface) map[uint32]*api.SRv6TLV { mtlvs := make(map[uint32]*api.SRv6TLV) var key uint32 for _, tlv := range tlvs { var r proto.Message switch t := tlv.(type) { case *bgp.SRv6SIDStructureSubSubTLV: o := &api.SRv6StructureSubSubTLV{ LocalBlockLength: uint32(t.LocalBlockLength), LocalNodeLength: uint32(t.LocatorNodeLength), FunctionLength: uint32(t.FunctionLength), ArgumentLength: uint32(t.ArgumentLength), TranspositionLength: uint32(t.TranspositionLength), TranspositionOffset: uint32(t.TranspositionOffset), } // SRv6 SID Structure Sub Sub TLV is type 1 Sub Sub TLV key = 1 r = o default: log.WithFields(log.Fields{ "Topic": "protobuf", "SRv6": t, }).Warn("invalid prefix sid sub sub tlv type to marshal") return nil } a, _ := ptypes.MarshalAny(r) tlvs, ok := mtlvs[key] if !ok { tlvs = &api.SRv6TLV{ Tlv: make([]*any.Any, 0), } mtlvs[key] = tlvs } tlvs.Tlv = append(tlvs.Tlv, a) } return mtlvs } 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 MarshalLsNodeDescriptor(d *bgp.LsNodeDescriptor) *api.LsNodeDescriptor { return &api.LsNodeDescriptor{ Asn: d.Asn, BgpLsId: d.BGPLsID, OspfAreaId: d.OspfAreaID, Pseudonode: d.PseudoNode, IgpRouterId: d.IGPRouterID, } } func MarshalLsLinkDescriptor(n *bgp.LsLinkDescriptor) *api.LsLinkDescriptor { return &api.LsLinkDescriptor{ LinkLocalId: uint32OrDefault(n.LinkLocalID), LinkRemoteId: uint32OrDefault(n.LinkRemoteID), InterfaceAddrIpv4: ipOrDefault(n.InterfaceAddrIPv4), NeighborAddrIpv4: ipOrDefault(n.NeighborAddrIPv4), InterfaceAddrIpv6: ipOrDefault(n.InterfaceAddrIPv6), NeighborAddrIpv6: ipOrDefault(n.NeighborAddrIPv6), } } func MarshalLsPrefixDescriptor(d *bgp.LsPrefixDescriptor) *api.LsPrefixDescriptor { p := &api.LsPrefixDescriptor{ OspfRouteType: d.OSPFRouteType.String(), } for _, ip := range d.IPReachability { p.IpReachability = append(p.IpReachability, ip.String()) } return p } func MarshalLsNodeNLRI(n *bgp.LsNodeNLRI) *any.Any { node := &api.LsNodeNLRI{ LocalNode: MarshalLsNodeDescriptor(n.LocalNodeDesc.(*bgp.LsTLVNodeDescriptor).Extract()), } a, _ := ptypes.MarshalAny(node) return a } func MarshalLsLinkNLRI(n *bgp.LsLinkNLRI) *any.Any { desc := &bgp.LsLinkDescriptor{} desc.ParseTLVs(n.LinkDesc) link := &api.LsLinkNLRI{ LocalNode: MarshalLsNodeDescriptor(n.LocalNodeDesc.(*bgp.LsTLVNodeDescriptor).Extract()), RemoteNode: MarshalLsNodeDescriptor(n.RemoteNodeDesc.(*bgp.LsTLVNodeDescriptor).Extract()), LinkDescriptor: MarshalLsLinkDescriptor(desc), } a, _ := ptypes.MarshalAny(link) return a } func MarshalLsPrefixV4NLRI(n *bgp.LsPrefixV4NLRI) *any.Any { desc := &bgp.LsPrefixDescriptor{} desc.ParseTLVs(n.PrefixDesc, false) prefix := &api.LsPrefixV4NLRI{ LocalNode: MarshalLsNodeDescriptor(n.LocalNodeDesc.(*bgp.LsTLVNodeDescriptor).Extract()), PrefixDescriptor: MarshalLsPrefixDescriptor(desc), } a, _ := ptypes.MarshalAny(prefix) return a } func MarshalLsPrefixV6NLRI(n *bgp.LsPrefixV6NLRI) *any.Any { desc := &bgp.LsPrefixDescriptor{} desc.ParseTLVs(n.PrefixDesc, true) prefix := &api.LsPrefixV6NLRI{ LocalNode: MarshalLsNodeDescriptor(n.LocalNodeDesc.(*bgp.LsTLVNodeDescriptor).Extract()), PrefixDescriptor: MarshalLsPrefixDescriptor(desc), } a, _ := ptypes.MarshalAny(prefix) return a } 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, GwAddress: r.GWIPAddress.String(), } } 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), } case *bgp.LsAddrPrefix: switch n := v.NLRI.(type) { case *bgp.LsNodeNLRI: nlri = &api.LsAddrPrefix{ Type: api.LsNLRIType_LS_NLRI_NODE, Nlri: MarshalLsNodeNLRI(n), Length: uint32(n.Length), ProtocolId: api.LsProtocolID(n.ProtocolID), Identifier: n.Identifier, } case *bgp.LsLinkNLRI: nlri = &api.LsAddrPrefix{ Type: api.LsNLRIType_LS_NLRI_LINK, Nlri: MarshalLsLinkNLRI(n), Length: uint32(n.Length), ProtocolId: api.LsProtocolID(n.ProtocolID), Identifier: n.Identifier, } case *bgp.LsPrefixV4NLRI: nlri = &api.LsAddrPrefix{ Type: api.LsNLRIType_LS_NLRI_PREFIX_V4, Nlri: MarshalLsPrefixV4NLRI(n), Length: uint32(n.Length), ProtocolId: api.LsProtocolID(n.ProtocolID), Identifier: n.Identifier, } case *bgp.LsPrefixV6NLRI: nlri = &api.LsAddrPrefix{ Type: api.LsNLRIType_LS_NLRI_PREFIX_V6, Nlri: MarshalLsPrefixV6NLRI(n), Length: uint32(n.Length), ProtocolId: api.LsProtocolID(n.ProtocolID), Identifier: n.Identifier, } } case *bgp.SRPolicyIPv4: nlri = &api.SRPolicyNLRI{ Length: uint32(v.Length), Distinguisher: v.Distinguisher, Color: v.Color, Endpoint: v.Endpoint, } case *bgp.SRPolicyIPv6: nlri = &api.SRPolicyNLRI{ Length: uint32(v.Length), Distinguisher: v.Distinguisher, Color: v.Color, Endpoint: v.Endpoint, } } 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.SRPolicyNLRI: switch rf { case bgp.RF_SR_POLICY_IPv4: nlri = bgp.NewSRPolicyIPv4(v.Length, v.Distinguisher, v.Color, v.Endpoint) case bgp.RF_SR_POLICY_IPv6: nlri = bgp.NewSRPolicyIPv6(v.Length, v.Distinguisher, v.Color, v.Endpoint) } 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: ToApiFamily(a.AFI, a.SAFI), NextHops: nexthops, Nlris: MarshalNLRIs(a.Value), } } func NewMpUnreachNLRIAttributeFromNative(a *bgp.PathAttributeMpUnreachNLRI) *api.MpUnreachNLRIAttribute { return &api.MpUnreachNLRIAttribute{ Family: ToApiFamily(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.TunnelEncapSubTLVWireguard: subTlv = &api.TunnelEncapSubTLVWireguard{ Peer: sv.Peer, } case *bgp.TunnelEncapSubTLVProtocol: subTlv = &api.TunnelEncapSubTLVProtocol{ Protocol: uint32(sv.Protocol), } case *bgp.TunnelEncapSubTLVColor: subTlv = &api.TunnelEncapSubTLVColor{ Color: sv.Color, } case *bgp.TunnelEncapSubTLVEgressEndpoint: subTlv = &api.TunnelEncapSubTLVEgressEndpoint{ Address: sv.Address.String(), } case *bgp.TunnelEncapSubTLVUDPDestPort: subTlv = &api.TunnelEncapSubTLVUDPDestPort{ Port: uint32(sv.UDPDestPort), } case *bgp.TunnelEncapSubTLVUnknown: subTlv = &api.TunnelEncapSubTLVUnknown{ Type: uint32(sv.Type), Value: sv.Value, } case *bgp.TunnelEncapSubTLVSRBSID: subTlv = MarshalSRBSID(sv) // TODO (sbezverk) Add processing of SRv6 Binding SID when it gets assigned ID case *bgp.TunnelEncapSubTLVSRCandidatePathName: subTlv = &api.TunnelEncapSubTLVSRCandidatePathName{ CandidatePathName: sv.CandidatePathName, } // TODO (sbezverk) Add processing of SR Policy name when it gets assigned ID case *bgp.TunnelEncapSubTLVSRENLP: subTlv = &api.TunnelEncapSubTLVSRENLP{ Flags: uint32(sv.Flags), Enlp: api.ENLPType(sv.ENLP), } case *bgp.TunnelEncapSubTLVSRPreference: subTlv = &api.TunnelEncapSubTLVSRPreference{ Flags: uint32(sv.Flags), Preference: sv.Preference, } case *bgp.TunnelEncapSubTLVSRPriority: subTlv = &api.TunnelEncapSubTLVSRPriority{ Priority: uint32(sv.Priority), } case *bgp.TunnelEncapSubTLVSRSegmentList: subTlv = &api.TunnelEncapSubTLVSRSegmentList{ Weight: &api.SRWeight{ Flags: uint32(sv.Weight.Flags), Weight: uint32(sv.Weight.Weight), }, Segments: MarshalSRSegments(sv.Segments), } } 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 stringOrDefault(s *string) string { if s == nil { return "" } return *s } func bytesOrDefault(b *[]byte) []byte { if b == nil { return []byte{} } return *b } func ipOrDefault(ip *net.IP) string { if ip == nil { return "" } return ip.String() } func uint32OrDefault(i *uint32) uint32 { if i == nil { return 0 } return *i } func float32OrDefault(f *float32) float32 { if f == nil { return 0.0 } return *f } func NewLsAttributeFromNative(a *bgp.PathAttributeLs) *api.LsAttribute { attr := a.Extract() apiAttr := &api.LsAttribute{ Node: &api.LsAttributeNode{ Name: stringOrDefault(attr.Node.Name), Opaque: bytesOrDefault(attr.Node.Opaque), IsisArea: bytesOrDefault(attr.Node.IsisArea), LocalRouterId: ipOrDefault(attr.Node.LocalRouterID), LocalRouterIdV6: ipOrDefault(attr.Node.LocalRouterIDv6), SrAlgorithms: bytesOrDefault(attr.Node.SrAlgorithms), }, Link: &api.LsAttributeLink{ Name: stringOrDefault(attr.Link.Name), Opaque: bytesOrDefault(attr.Link.Opaque), LocalRouterId: ipOrDefault(attr.Link.LocalRouterID), LocalRouterIdV6: ipOrDefault(attr.Link.LocalRouterIDv6), RemoteRouterId: ipOrDefault(attr.Link.RemoteRouterID), RemoteRouterIdV6: ipOrDefault(attr.Link.RemoteRouterIDv6), AdminGroup: uint32OrDefault(attr.Link.AdminGroup), DefaultTeMetric: uint32OrDefault(attr.Link.DefaultTEMetric), IgpMetric: uint32OrDefault(attr.Link.IGPMetric), Bandwidth: float32OrDefault(attr.Link.Bandwidth), ReservableBandwidth: float32OrDefault(attr.Link.ReservableBandwidth), SrAdjacencySid: uint32OrDefault(attr.Link.SrAdjacencySID), }, Prefix: &api.LsAttributePrefix{ Opaque: bytesOrDefault(attr.Prefix.Opaque), SrPrefixSid: uint32OrDefault(attr.Prefix.SrPrefixSID), }, } if attr.Node.Flags != nil { apiAttr.Node.Flags = &api.LsNodeFlags{ Overload: attr.Node.Flags.Overload, Attached: attr.Node.Flags.Attached, External: attr.Node.Flags.External, Abr: attr.Node.Flags.ABR, Router: attr.Node.Flags.Router, V6: attr.Node.Flags.V6, } } if attr.Node.SrCapabilties != nil { apiAttr.Node.SrCapabilities = &api.LsSrCapabilities{ Ipv4Supported: attr.Node.SrCapabilties.IPv4Supported, Ipv6Supported: attr.Node.SrCapabilties.IPv6Supported, } for _, r := range attr.Node.SrCapabilties.Ranges { apiAttr.Node.SrCapabilities.Ranges = append(apiAttr.Node.SrCapabilities.Ranges, &api.LsSrRange{ Begin: r.Begin, End: r.End, }) } } if attr.Node.SrLocalBlock != nil { apiAttr.Node.SrLocalBlock = &api.LsSrLocalBlock{} for _, r := range attr.Node.SrLocalBlock.Ranges { apiAttr.Node.SrLocalBlock.Ranges = append(apiAttr.Node.SrLocalBlock.Ranges, &api.LsSrRange{ Begin: r.Begin, End: r.End, }) } } if attr.Link.UnreservedBandwidth != nil { for _, f := range attr.Link.UnreservedBandwidth { apiAttr.Link.UnreservedBandwidth = append(apiAttr.Link.UnreservedBandwidth, f) } } if attr.Link.Srlgs != nil { apiAttr.Link.Srlgs = append(apiAttr.Link.Srlgs, *attr.Link.Srlgs...) } if attr.Prefix.IGPFlags != nil { apiAttr.Prefix.IgpFlags = &api.LsIGPFlags{ Down: attr.Prefix.IGPFlags.Down, NoUnicast: attr.Prefix.IGPFlags.NoUnicast, LocalAddress: attr.Prefix.IGPFlags.LocalAddress, PropagateNssa: attr.Prefix.IGPFlags.PropagateNSSA, } } return apiAttr } 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.PathAttributeLs: n, _ := ptypes.MarshalAny(NewLsAttributeFromNative(a)) anyList = append(anyList, n) case *bgp.PathAttributePrefixSID: n, _ := ptypes.MarshalAny(NewPrefixSIDAttributeFromNative(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 { if nexthop = net.ParseIP(a.NextHop).To16(); 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: if a.Family == nil { return nil, fmt.Errorf("empty family") } rf := ToRouteFamily(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 := ToRouteFamily(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.TunnelEncapSubTLVWireguard: subTlv = bgp.NewTunnelEncapSubTLVWireguard(sv.Peer) case *api.TunnelEncapSubTLVProtocol: subTlv = bgp.NewTunnelEncapSubTLVProtocol(uint16(sv.Protocol)) case *api.TunnelEncapSubTLVColor: subTlv = bgp.NewTunnelEncapSubTLVColor(sv.Color) case *api.TunnelEncapSubTLVEgressEndpoint: subTlv = bgp.NewTunnelEncapSubTLVEgressEndpoint(sv.Address) case *api.TunnelEncapSubTLVUDPDestPort: subTlv = bgp.NewTunnelEncapSubTLVUDPDestPort(uint16(sv.Port)) case *api.TunnelEncapSubTLVSRPreference: subTlv = bgp.NewTunnelEncapSubTLVSRPreference(sv.Flags, sv.Preference) case *api.TunnelEncapSubTLVSRPriority: subTlv = bgp.NewTunnelEncapSubTLVSRPriority(uint8(sv.Priority)) case *api.TunnelEncapSubTLVSRCandidatePathName: subTlv = bgp.NewTunnelEncapSubTLVSRCandidatePathName(sv.CandidatePathName) case *api.TunnelEncapSubTLVSRENLP: subTlv = bgp.NewTunnelEncapSubTLVSRENLP(sv.Flags, bgp.SRENLPValue(sv.Enlp)) case *api.TunnelEncapSubTLVSRBindingSID: var err error subTlv, err = UnmarshalSRBSID(sv.Bsid) if err != nil { return nil, fmt.Errorf("failed to unmarshal tunnel encapsulation attribute sub tlv: %s", err) } case *api.TunnelEncapSubTLVSRSegmentList: var err error weight := uint32(0) flags := uint8(0) if sv.Weight != nil { weight = sv.Weight.Weight flags = uint8(sv.Weight.Flags) } s := &bgp.TunnelEncapSubTLVSRSegmentList{ TunnelEncapSubTLV: bgp.TunnelEncapSubTLV{ Type: bgp.ENCAP_SUBTLV_TYPE_SRSEGMENT_LIST, Length: uint16(6), // Weight (6 bytes) + length of segment (added later, after all segments are discovered) }, Weight: &bgp.SegmentListWeight{ TunnelEncapSubTLV: bgp.TunnelEncapSubTLV{ Type: bgp.SegmentListSubTLVWeight, Length: uint16(6), }, Flags: flags, Weight: weight, }, Segments: make([]bgp.TunnelEncapSubTLVInterface, 0), } if len(sv.Segments) != 0 { s.Segments, err = UnmarshalSRSegments(sv.Segments) if err != nil { return nil, fmt.Errorf("failed to unmarshal tunnel encapsulation attribute sub tlv: %s", err) } } // Get total length of Segment List Sub TLV for _, seg := range s.Segments { s.TunnelEncapSubTLV.Length += uint16(seg.Len() + 2) // Adding 1 byte of type and 1 byte of length for each Segment object } subTlv = s case *api.TunnelEncapSubTLVUnknown: subTlv = bgp.NewTunnelEncapSubTLVUnknown(bgp.EncapSubTLVType(sv.Type), sv.Value) default: return nil, fmt.Errorf("invalid tunnel encapsulation attribute sub tlv: %v type: %T", subValue.Message, sv) } 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.PrefixSID: return bgp.NewPathAttributePrefixSID(a) case *api.UnknownAttribute: return bgp.NewPathAttributeUnknown(bgp.BGPAttrFlag(a.Flags), bgp.BGPAttrType(a.Type), a.Value), nil } return nil, errors.New("unknown path attribute") } // MarshalSRBSID marshals SR Policy Binding SID Sub TLV structure func MarshalSRBSID(bsid *bgp.TunnelEncapSubTLVSRBSID) *any.Any { var r proto.Message s := &api.SRBindingSID{ Sid: make([]byte, len(bsid.BSID.Value)), } copy(s.Sid, bsid.BSID.Value) s.SFlag = bsid.Flags&0x80 == 0x80 s.IFlag = bsid.Flags&0x40 == 0x40 r = s a, _ := ptypes.MarshalAny(r) return a } // UnmarshalSRBSID unmarshals SR Policy Binding SID Sub TLV and returns native TunnelEncapSubTLVInterface interface func UnmarshalSRBSID(bsid *any.Any) (bgp.TunnelEncapSubTLVInterface, error) { var value ptypes.DynamicAny if err := ptypes.UnmarshalAny(bsid, &value); err != nil { return nil, fmt.Errorf("failed to unmarshal tunnel encap sub tlv: %s", err) } switch v := value.Message.(type) { case *api.SRBindingSID: b, err := bgp.NewBSID(v.Sid) if err != nil { return nil, err } flags := uint8(0x0) if v.SFlag { flags += 0x80 } if v.IFlag { flags += 0x40 } return &bgp.TunnelEncapSubTLVSRBSID{ TunnelEncapSubTLV: bgp.TunnelEncapSubTLV{ Type: bgp.ENCAP_SUBTLV_TYPE_SRBINDING_SID, Length: uint16(2 + b.Len()), }, BSID: b, Flags: flags, }, nil case *api.SRv6BindingSID: b, err := bgp.NewBSID(v.Sid) if err != nil { return nil, err } result := &bgp.TunnelEncapSubTLVSRv6BSID{ TunnelEncapSubTLV: bgp.TunnelEncapSubTLV{ Type: bgp.ENCAP_SUBTLV_TYPE_SRBINDING_SID, Length: uint16(2 + b.Len()), }, Flags: 0, BSID: b, } if v.EndpointBehaviorStructure != nil { result.EPBAS = &bgp.SRv6EndpointBehaviorStructure{ Behavior: bgp.SRBehavior(v.EndpointBehaviorStructure.Behavior), BlockLen: uint8(v.EndpointBehaviorStructure.BlockLen), NodeLen: uint8(v.EndpointBehaviorStructure.NodeLen), FuncLen: uint8(v.EndpointBehaviorStructure.FuncLen), ArgLen: uint8(v.EndpointBehaviorStructure.ArgLen), } } return result, nil default: return nil, fmt.Errorf("unknown binding sid type %+v", v) } } // MarshalSRSegments marshals a slice of SR Policy Segment List func MarshalSRSegments(segs []bgp.TunnelEncapSubTLVInterface) []*any.Any { anyList := make([]*any.Any, 0, len(segs)) for _, seg := range segs { var r proto.Message switch s := seg.(type) { case *bgp.SegmentTypeA: r = &api.SegmentTypeA{ Label: s.Label, Flags: &api.SegmentFlags{ VFlag: s.Flags&0x80 == 0x80, AFlag: s.Flags&0x40 == 0x40, SFlag: s.Flags&0x20 == 0x20, BFlag: s.Flags&0x10 == 0x10, }, } case *bgp.SegmentTypeB: flags := &api.SegmentFlags{ VFlag: s.Flags&0x80 == 0x80, AFlag: s.Flags&0x40 == 0x40, SFlag: s.Flags&0x20 == 0x20, BFlag: s.Flags&0x10 == 0x10, } segment := &api.SegmentTypeB{ Flags: flags, Sid: s.SID, } if s.SRv6EBS != nil { segment.EndpointBehaviorStructure = &api.SRv6EndPointBehavior{ Behavior: api.SRv6Behavior(s.SRv6EBS.Behavior), BlockLen: uint32(s.SRv6EBS.BlockLen), NodeLen: uint32(s.SRv6EBS.NodeLen), FuncLen: uint32(s.SRv6EBS.FuncLen), ArgLen: uint32(s.SRv6EBS.ArgLen), } } r = segment default: // Unrecognize Segment type, skip it continue } a, _ := ptypes.MarshalAny(r) anyList = append(anyList, a) } return anyList } // UnmarshalSRSegments unmarshals SR Policy Segments slice of structs func UnmarshalSRSegments(s []*any.Any) ([]bgp.TunnelEncapSubTLVInterface, error) { if len(s) == 0 { return nil, nil } segments := make([]bgp.TunnelEncapSubTLVInterface, len(s)) for i := 0; i < len(s); i++ { var value ptypes.DynamicAny if err := ptypes.UnmarshalAny(s[i], &value); err != nil { return nil, fmt.Errorf("failed to unmarshal SR Policy Segment: %s", err) } switch v := value.Message.(type) { case *api.SegmentTypeA: seg := &bgp.SegmentTypeA{ TunnelEncapSubTLV: bgp.TunnelEncapSubTLV{ Type: bgp.EncapSubTLVType(bgp.TypeA), Length: 6, }, Label: v.Label << 12, } if v.Flags.VFlag { seg.Flags += 0x80 } if v.Flags.AFlag { seg.Flags += 0x40 } if v.Flags.SFlag { seg.Flags += 0x20 } if v.Flags.BFlag { seg.Flags += 0x10 } segments[i] = seg case *api.SegmentTypeB: seg := &bgp.SegmentTypeB{ TunnelEncapSubTLV: bgp.TunnelEncapSubTLV{ Type: bgp.EncapSubTLVType(bgp.TypeB), Length: 18, }, SID: v.GetSid(), } if v.Flags.VFlag { seg.Flags += 0x80 } if v.Flags.AFlag { seg.Flags += 0x40 } if v.Flags.SFlag { seg.Flags += 0x20 } if v.Flags.BFlag { seg.Flags += 0x10 } if v.EndpointBehaviorStructure != nil { ebs := v.GetEndpointBehaviorStructure() seg.SRv6EBS = &bgp.SRv6EndpointBehaviorStructure{ Behavior: bgp.SRBehavior(ebs.Behavior), BlockLen: uint8(ebs.BlockLen), NodeLen: uint8(ebs.NodeLen), FuncLen: uint8(ebs.FuncLen), ArgLen: uint8(ebs.ArgLen), } } segments[i] = seg } } return segments, nil }