diff options
Diffstat (limited to 'pkg/packet/bgp/sr_policy.go')
-rw-r--r-- | pkg/packet/bgp/sr_policy.go | 721 |
1 files changed, 721 insertions, 0 deletions
diff --git a/pkg/packet/bgp/sr_policy.go b/pkg/packet/bgp/sr_policy.go new file mode 100644 index 00000000..007612c4 --- /dev/null +++ b/pkg/packet/bgp/sr_policy.go @@ -0,0 +1,721 @@ +package bgp + +import ( + "encoding/binary" + "encoding/json" + "fmt" + "net" + "strconv" +) + +type SRPolicyNLRI struct { + PrefixDefault + rf RouteFamily + Length uint8 + Distinguisher uint32 + Color uint32 + Endpoint []byte +} + +const ( + // SRPolicyIPv4NLRILen defines IPv4 SR Policy NLRI portion length in bits + SRPolicyIPv4NLRILen = 96 + // SRPolicyIPv6NLRILen defines IPv6 SR Policy NLRI portion length in bits + SRPolicyIPv6NLRILen = 192 +) + +func (s *SRPolicyNLRI) Flat() map[string]string { + return map[string]string{} +} + +func (s *SRPolicyNLRI) decodeFromBytes(rf RouteFamily, data []byte, options ...*MarshallingOption) error { + if IsAddPathEnabled(true, rf, options) { + var err error + data, err = s.decodePathIdentifier(data) + if err != nil { + return err + } + } + switch data[0] { + case SRPolicyIPv4NLRILen: + s.rf = RF_SR_POLICY_IPv4 + case SRPolicyIPv6NLRILen: + s.rf = RF_SR_POLICY_IPv6 + default: + msg := fmt.Sprintf("Invalid length %d for SR Policy NLRI", len(data)) + return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, msg) + } + p := 0 + s.Length = data[p] / 8 + p++ + s.Distinguisher = binary.BigEndian.Uint32(data[p : p+4]) + p += 4 + s.Color = binary.BigEndian.Uint32(data[p : p+4]) + p += 4 + s.Endpoint = data[p:] + + return nil +} + +func (s *SRPolicyNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { + buf := make([]byte, 1+s.Length) + p := 0 + buf[0] = s.Length + p++ + binary.BigEndian.PutUint32(buf[:4], s.Distinguisher) + p += 4 + binary.BigEndian.PutUint32(buf[:4], s.Color) + p += 4 + copy(buf[p:], s.Endpoint) + if IsAddPathEnabled(false, s.rf, options) { + id, err := s.serializeIdentifier() + if err != nil { + return nil, err + } + return append(id, buf...), nil + } + return buf, nil +} + +func (s *SRPolicyNLRI) AFI() uint16 { + afi, _ := RouteFamilyToAfiSafi(s.rf) + return afi +} + +func (s *SRPolicyNLRI) SAFI() uint8 { + _, safi := RouteFamilyToAfiSafi(s.rf) + return safi +} + +func (s *SRPolicyNLRI) Len(options ...*MarshallingOption) int { + buf, _ := s.Serialize(options...) + return len(buf) +} + +func (s *SRPolicyNLRI) String() string { + afi, _ := RouteFamilyToAfiSafi(s.rf) + var endp string + switch afi { + case AFI_IP: + endp = net.IP(s.Endpoint).To4().String() + case AFI_IP6: + endp = net.IP(s.Endpoint).To16().String() + default: + endp = "[" + string(s.Endpoint) + "]" + } + return fmt.Sprintf("{ Length: %d (bytes), Distinguisher: %d, Color %d, Endpoint: %s }", s.Length, s.Distinguisher, s.Color, endp) +} + +func (s *SRPolicyNLRI) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Length uint8 `json:"length"` + Distinguisher uint32 `json:"distinguisher"` + Color uint32 `json:"color"` + Endpoint string `json:"endpoint"` + }{ + Length: s.Length, + Distinguisher: s.Distinguisher, + Color: s.Color, + Endpoint: string(s.Endpoint), + }) +} + +type SRPolicyIPv4 struct { + SRPolicyNLRI +} + +func (s *SRPolicyIPv4) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + return s.decodeFromBytes(s.rf, data) +} + +func NewSRPolicyIPv4(l uint32, d uint32, c uint32, ep []byte) *SRPolicyIPv4 { + fmt.Printf("><SB> NewSRPolicyIPv4: length: %d distinguisher: %d color: %d endpoint: %+v\n", l, d, c, ep) + return &SRPolicyIPv4{ + SRPolicyNLRI: SRPolicyNLRI{ + rf: RF_SR_POLICY_IPv4, + Length: uint8(l), + Distinguisher: d, + Color: c, + Endpoint: ep, + }, + } +} + +type SRPolicyIPv6 struct { + SRPolicyNLRI +} + +func (s *SRPolicyIPv6) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + return s.decodeFromBytes(s.rf, data) +} + +func NewSRPolicyIPv6(l uint32, d uint32, c uint32, ep []byte) *SRPolicyIPv6 { + fmt.Printf("><SB> NewSRPolicyIPv6: length: %d distinguisher: %d color: %d endpoint: %+v\n", l, d, c, ep) + return &SRPolicyIPv6{ + SRPolicyNLRI: SRPolicyNLRI{ + rf: RF_SR_POLICY_IPv6, + Length: uint8(l), + Distinguisher: d, + Color: c, + Endpoint: ep, + }, + } +} + +type TunnelEncapSubTLVSRPreference struct { + TunnelEncapSubTLV + Flags uint8 + Preference uint32 +} + +func (t *TunnelEncapSubTLVSRPreference) DecodeFromBytes(data []byte) error { + value, err := t.TunnelEncapSubTLV.DecodeFromBytes(data) + if err != nil { + return err + } + // Second byte carries the length of SR Preference SubTLV + if t.Length != 6 { + msg := fmt.Sprintf("Invalid TunnelEncapSubTLVSRPreference length: %d", t.Length) + return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, msg) + } + t.Flags = value[0] + t.Preference = binary.BigEndian.Uint32(value[2:6]) + return nil +} + +func (t *TunnelEncapSubTLVSRPreference) Serialize() ([]byte, error) { + buf := make([]byte, t.Length) + buf[0] = t.Flags + binary.BigEndian.PutUint32(buf[2:6], t.Preference) + return t.TunnelEncapSubTLV.Serialize(buf[:]) +} + +func (t *TunnelEncapSubTLVSRPreference) String() string { + return fmt.Sprintf("{Flags: 0x%02x, Preference: %d}", t.Flags, t.Preference) +} + +func (t *TunnelEncapSubTLVSRPreference) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type EncapSubTLVType `json:"type"` + Flags uint8 `json:"flags"` + Preference uint32 `json:"preference"` + }{ + Type: t.Type, + Flags: t.Flags, + Preference: t.Preference, + }) +} + +func NewTunnelEncapSubTLVSRPreference(flags uint32, preference uint32) *TunnelEncapSubTLVSRPreference { + return &TunnelEncapSubTLVSRPreference{ + TunnelEncapSubTLV: TunnelEncapSubTLV{ + Type: ENCAP_SUBTLV_TYPE_SRPREFERENCE, + }, + Flags: uint8(flags), + Preference: preference, + } +} + +type TunnelEncapSubTLVSRPriority struct { + TunnelEncapSubTLV + Priority uint8 +} + +func (t *TunnelEncapSubTLVSRPriority) DecodeFromBytes(data []byte) error { + value, err := t.TunnelEncapSubTLV.DecodeFromBytes(data) + if err != nil { + return err + } + // Second byte carries the length of SR Preference SubTLV + if t.Length != 2 { + msg := fmt.Sprintf("Invalid TunnelEncapSubTLVSRPriority length: %d", t.Length) + return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, msg) + } + t.Priority = value[0] + return nil +} + +func (t *TunnelEncapSubTLVSRPriority) Serialize() ([]byte, error) { + buf := make([]byte, t.Length) + buf[0] = t.Priority + return t.TunnelEncapSubTLV.Serialize(buf[:]) +} + +func (t *TunnelEncapSubTLVSRPriority) String() string { + return fmt.Sprintf("{Priority: %d}", t.Priority) +} + +func (t *TunnelEncapSubTLVSRPriority) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type EncapSubTLVType `json:"type"` + Priority uint8 `json:"priority"` + }{ + Type: t.Type, + Priority: t.Priority, + }) +} + +func NewTunnelEncapSubTLVSRPriority(priority uint8) *TunnelEncapSubTLVSRPriority { + return &TunnelEncapSubTLVSRPriority{ + TunnelEncapSubTLV: TunnelEncapSubTLV{ + Type: ENCAP_SUBTLV_TYPE_SRPRIORITY, + }, + Priority: priority, + } +} + +type TunnelEncapSubTLVSRPolicyName struct { + TunnelEncapSubTLV + PolicyName string +} + +func (t *TunnelEncapSubTLVSRPolicyName) DecodeFromBytes(data []byte) error { + value, err := t.TunnelEncapSubTLV.DecodeFromBytes(data) + if err != nil { + return err + } + // Skip Reserved byte + t.PolicyName = string(value[1:t.TunnelEncapSubTLV.Len()]) + return nil +} + +func (t *TunnelEncapSubTLVSRPolicyName) Serialize() ([]byte, error) { + buf := make([]byte, t.Length) + copy(buf[1:], t.PolicyName) + return t.TunnelEncapSubTLV.Serialize(buf[:]) +} + +func (t *TunnelEncapSubTLVSRPolicyName) String() string { + return fmt.Sprintf("{Policy Name: %s}", t.PolicyName) +} + +func (t *TunnelEncapSubTLVSRPolicyName) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type EncapSubTLVType `json:"type"` + PolicyName string `json:"policy_name"` + }{ + Type: t.Type, + PolicyName: t.PolicyName, + }) +} + +func NewTunnelEncapSubTLVSRPolicyName(pn string) *TunnelEncapSubTLVSRPolicyName { + return &TunnelEncapSubTLVSRPolicyName{ + TunnelEncapSubTLV: TunnelEncapSubTLV{ + Type: ENCAP_SUBTLV_TYPE_SRPOLICY_NAME, + }, + PolicyName: pn, + } +} + +type SRENLPValue uint8 + +const ( + // ENLPType1 Indicates to push an IPv4 Explicit NULL label on an unlabeled IPv4 + // packet, but do not push an IPv6 Explicit NULL label on an + // unlabeled IPv6 packet. + ENLPType1 SRENLPValue = 1 + // ENLPType2 Indicates to push an IPv6 Explicit NULL label on an unlabeled IPv6 + // packet, but do not push an IPv4 Explicit NULL label on an + // unlabeled IPv4 packet. + ENLPType2 SRENLPValue = 2 + // ENLPType3 Indicates to push an IPv4 Explicit NULL label on an unlabeled IPv4 + // packet, and push an IPv6 Explicit NULL label on an unlabeled + // IPv6 packet. + ENLPType3 SRENLPValue = 3 + // ENLPType4 Indicates to not push an Explicit NULL label. + ENLPType4 SRENLPValue = 4 +) + +type TunnelEncapSubTLVSRENLP struct { + TunnelEncapSubTLV + Flags uint8 + ENLP SRENLPValue +} + +func (t *TunnelEncapSubTLVSRENLP) DecodeFromBytes(data []byte) error { + value, err := t.TunnelEncapSubTLV.DecodeFromBytes(data) + if err != nil { + return err + } + // Second byte carries the length of SR Preference SubTLV + if t.Length != 3 { + msg := fmt.Sprintf("Invalid TunnelEncapSubTLVSRENLP length: %d", t.Length) + return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, msg) + } + t.Flags = value[0] + switch SRENLPValue(value[2]) { + case ENLPType1: + case ENLPType2: + case ENLPType3: + case ENLPType4: + default: + msg := fmt.Sprintf("Invalid ENLP Type: %d", value[2]) + return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, msg) + } + t.ENLP = SRENLPValue(value[2]) + return nil +} + +func (t *TunnelEncapSubTLVSRENLP) Serialize() ([]byte, error) { + buf := make([]byte, t.Length) + buf[0] = t.Flags + buf[2] = byte(t.ENLP) + return t.TunnelEncapSubTLV.Serialize(buf[:]) +} + +func (t *TunnelEncapSubTLVSRENLP) String() string { + return fmt.Sprintf("{Flags: 0x%02x, ENLP Type: %d}", t.Flags, t.ENLP) +} + +func (t *TunnelEncapSubTLVSRENLP) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type EncapSubTLVType `json:"type"` + Flags uint8 `json:"flags"` + ENLP uint8 `json:"enlp"` + }{ + Type: t.Type, + Flags: t.Flags, + ENLP: uint8(t.ENLP), + }) +} + +func NewTTunnelEncapSubTLVSRENLP(flags uint32, enlp SRENLPValue) *TunnelEncapSubTLVSRENLP { + return &TunnelEncapSubTLVSRENLP{ + TunnelEncapSubTLV: TunnelEncapSubTLV{ + Type: ENCAP_SUBTLV_TYPE_SRENLP, + }, + Flags: uint8(flags), + ENLP: enlp, + } +} + +type BSID struct { + Length int + Value []byte +} + +func (b *BSID) String() string { + switch b.Length { + case 0: + return "n/a" + case 4: + bsid := binary.BigEndian.Uint32(b.Value) + bsid >>= 12 + return strconv.Itoa(int(bsid)) + case 16: + return net.IP(b.Value).To16().String() + default: + return "invalid" + } +} + +func (b *BSID) Serialize() []byte { + return []byte{} +} +func NewBSID(v []byte, l int) (*BSID, error) { + switch l { + case 0: + case 4: + case 16: + default: + return nil, fmt.Errorf("invalid length %d", l) + } + if l < len(v) { + return nil, fmt.Errorf("parameter length does not match the length of data bytes") + } + bsid := &BSID{ + Length: l, + Value: make([]byte, l), + } + copy(bsid.Value, v) + + return bsid, nil +} + +type TunnelEncapSubTLVSRBSID struct { + TunnelEncapSubTLV + Flags uint8 + BSID *BSID +} + +func (t *TunnelEncapSubTLVSRBSID) DecodeFromBytes(data []byte) error { + value, err := t.TunnelEncapSubTLV.DecodeFromBytes(data) + if err != nil { + return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, err.Error()) + } + // Check Sub TLV length, only 3 possible length are allowed + switch t.Length { + case 2: + case 6: + case 18: + default: + msg := fmt.Sprintf("Invalid TunnelEncapSubTLVSRBSID length: %d", t.Length) + return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, msg) + } + t.Flags = value[0] + t.BSID, err = NewBSID(value[2:t.Length], int(t.Length-2)) + if err != nil { + return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, err.Error()) + } + return nil +} + +func (t *TunnelEncapSubTLVSRBSID) Serialize() ([]byte, error) { + buf := make([]byte, t.Length) + buf[0] = t.Flags + copy(buf[2:t.BSID.Length], t.BSID.Serialize()) + return t.TunnelEncapSubTLV.Serialize(buf[:]) +} + +func (t *TunnelEncapSubTLVSRBSID) String() string { + return fmt.Sprintf("{S-Flag: %t, I-Flag: %t, BSID: %s}", t.Flags&0x80 == 0x80, t.Flags&0x40 == 0x40, t.BSID.String()) +} + +func (t *TunnelEncapSubTLVSRBSID) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type EncapSubTLVType `json:"type"` + Flags uint8 `json:"flags"` + BSID string `json:"binding_sid,omitempty"` + }{ + Type: t.Type, + Flags: t.Flags, + BSID: t.BSID.String(), + }) +} + +// TODO sbezverk Figure out parameters to pass to NewTunnelEncapSubTLVSRBSID +func NewTunnelEncapSubTLVSRBSID(flags uint32) *TunnelEncapSubTLVSRBSID { + return &TunnelEncapSubTLVSRBSID{ + TunnelEncapSubTLV: TunnelEncapSubTLV{ + Type: ENCAP_SUBTLV_TYPE_SRBINDING_SID, + }, + Flags: uint8(flags), + } +} + +// SegmentType defines a type of Segment in Segment List +type SegmentType int + +const ( + // TypeA Segment Sub-TLV encodes a single SR-MPLS SID + TypeA SegmentType = 1 + // TypeC Segment Sub-TLV encodes an IPv4 node address, SR Algorithm + // and an optional SR-MPLS SID + TypeC SegmentType = 3 + // TypeD Segment Sub-TLV encodes an IPv6 node address, SR Algorithm + // and an optional SR-MPLS SID. + TypeD SegmentType = 4 + // TypeE Segment Sub-TLV encodes an IPv4 node address, a local + // interface Identifier (Local Interface ID) and an optional SR-MPLS + // SID. + TypeE SegmentType = 5 + // TypeF Segment Sub-TLV encodes an adjacency local address, an + // adjacency remote address and an optional SR-MPLS SID. + TypeF SegmentType = 6 + // TypeG Segment Sub-TLV encodes an IPv6 Link Local adjacency with + // IPv6 local node address, a local interface identifier (Local + // Interface ID), IPv6 remote node address , a remote interface + // identifier (Remote Interface ID) and an optional SR-MPLS SID. + TypeG SegmentType = 7 + // TypeH Segment Sub-TLV encodes an adjacency local address, an + // adjacency remote address and an optional SR-MPLS SID. + TypeH SegmentType = 8 +) + +const SegmentListWeightType = 9 + +// Weight sub-TLV specifies the weight associated to a given segment list. +type SegmentListWeight struct { + TunnelEncapSubTLV + Flags uint8 + Weight uint32 +} + +func (s *SegmentListWeight) DecodeFromBytes(data []byte) error { + value, err := s.TunnelEncapSubTLV.DecodeFromBytes(data) + if err != nil { + return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, err.Error()) + } + s.Flags = value[0] + s.Weight = binary.BigEndian.Uint32(value[2:6]) + return nil +} +func (s *SegmentListWeight) Serialize() ([]byte, error) { + buf := make([]byte, 6) + buf[0] = s.Flags + binary.BigEndian.PutUint32(buf[2:6], s.Weight) + return s.TunnelEncapSubTLV.Serialize(buf) +} +func (s *SegmentListWeight) String() string { + return fmt.Sprintf("{Flags: 0x%02x, Weight: %d}", s.Flags, s.Weight) +} + +func (s *SegmentListWeight) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type EncapSubTLVType `json:"type"` + Flags uint8 `json:"flags"` + Weight uint32 `json:"weight,omitempty"` + }{ + Type: s.Type, + Flags: s.Flags, + Weight: s.Weight, + }) +} + +type SegmentTypeA struct { + TunnelEncapSubTLV + Flags uint8 + Label uint32 +} + +func (s *SegmentTypeA) DecodeFromBytes(data []byte) error { + value, err := s.TunnelEncapSubTLV.DecodeFromBytes(data) + if err != nil { + return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, err.Error()) + } + s.Flags = value[0] + s.Label = binary.BigEndian.Uint32(value[2:6]) + return nil +} +func (s *SegmentTypeA) Serialize() ([]byte, error) { + buf := make([]byte, 6) + buf[0] = s.Flags + binary.BigEndian.PutUint32(buf[2:6], s.Label) + return s.TunnelEncapSubTLV.Serialize(buf) +} +func (s *SegmentTypeA) String() string { + + return fmt.Sprintf("{V-flag: %t, A-flag:, %t S-flag: %t, B-flag: %t, Label: %d TC: %d S: %t TTL: %d}", + s.Flags&0x80 == 0x80, s.Flags&0x40 == 0x40, s.Flags&0x20 == 0x20, s.Flags&0x10 == 0x10, + s.Label>>12, s.Label&0x00000e00>>9, s.Label&0x00000100 == 0x00000100, s.Label&0x000000ff) +} + +func (s *SegmentTypeA) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type EncapSubTLVType `json:"type"` + VFlag bool `json:"v_flag"` + AFlag bool `json:"a_flag"` + SFlag bool `json:"s_flag"` + BFlag bool `json:"b_flag"` + Label uint32 `json:"label"` + TC uint8 `json:"tc"` + S bool `json:"s"` + TTL uint8 `json:"ttl"` + }{ + Type: s.Type, + VFlag: s.Flags&0x80 == 0x80, + AFlag: s.Flags&0x40 == 0x40, + SFlag: s.Flags&0x20 == 0x20, + BFlag: s.Flags&0x10 == 0x10, + Label: s.Label >> 12, + TC: uint8(s.Label & 0x00000e00 >> 9), + S: s.Label&0x00000100 == 0x00000100, + TTL: uint8(s.Label & 0x000000ff), + }) +} + +type TunnelEncapSubTLVSRSegmentList struct { + TunnelEncapSubTLV + Weight *SegmentListWeight + Segments []TunnelEncapSubTLVInterface +} + +func (t *TunnelEncapSubTLVSRSegmentList) DecodeFromBytes(data []byte) error { + value, err := t.TunnelEncapSubTLV.DecodeFromBytes(data) + if err != nil { + return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, err.Error()) + } + // Skip reserved byte to access inner SubTLV type + value = value[1:] + t.Segments = make([]TunnelEncapSubTLVInterface, 0) + p := 0 + for p < t.TunnelEncapSubTLV.Len()-4 { + var segment TunnelEncapSubTLVInterface + switch SegmentType(value[0]) { + case SegmentListWeightType: + t.Weight = &SegmentListWeight{} + if err := t.Weight.DecodeFromBytes(value); err != nil { + return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, err.Error()) + } + p += t.Weight.TunnelEncapSubTLV.Len() + value = value[t.Weight.TunnelEncapSubTLV.Len():] + continue + case TypeA: + segment = &SegmentTypeA{} + if err := segment.DecodeFromBytes(value); err != nil { + return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, err.Error()) + } + case TypeC: + fallthrough + case TypeD: + fallthrough + case TypeE: + fallthrough + case TypeF: + fallthrough + case TypeG: + fallthrough + case TypeH: + msg := fmt.Sprintf("Invalid SR Policy Segment SubTLV %d is not yet supported", value[0]) + return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, msg) + default: + msg := fmt.Sprintf("Invalid SR Policy Segment List SubTLV %d", value[0]) + return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, msg) + } + t.Segments = append(t.Segments, segment) + p += segment.Len() + value = value[segment.Len():] + } + return nil +} + +func (t *TunnelEncapSubTLVSRSegmentList) Serialize() ([]byte, error) { + buf := make([]byte, t.Length) + wbuf, err := t.Weight.Serialize() + if err != nil { + return nil, err + } + p := 0 + // Add reserved byte + p++ + copy(buf[p:], wbuf) + p += len(wbuf) + for _, s := range t.Segments { + sbuf, err := s.Serialize() + if err != nil { + return nil, err + } + copy(buf[p:], sbuf) + p += len(sbuf) + } + return t.TunnelEncapSubTLV.Serialize(buf[:]) +} + +func (t *TunnelEncapSubTLVSRSegmentList) String() string { + var segments string + for _, s := range t.Segments { + segments += s.String() + } + return fmt.Sprintf("{Weight: %s Segment List: %s}", t.Weight.String(), segments) +} + +func (t *TunnelEncapSubTLVSRSegmentList) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type EncapSubTLVType `json:"type"` + Weight *SegmentListWeight + Segments []TunnelEncapSubTLVInterface + }{ + Type: t.Type, + Weight: t.Weight, + Segments: t.Segments, + }) +} + +func NewTunnelEncapSubTLVSRSegmentList() *TunnelEncapSubTLVSRSegmentList { + return &TunnelEncapSubTLVSRSegmentList{ + TunnelEncapSubTLV: TunnelEncapSubTLV{ + Type: ENCAP_SUBTLV_TYPE_SRSEGMENT_LIST, + }, + } +} |