diff options
-rw-r--r-- | internal/pkg/apiutil/attribute.go | 128 | ||||
-rw-r--r-- | pkg/packet/bgp/bgp.go | 23 | ||||
-rw-r--r-- | pkg/packet/bgp/sr_policy.go | 301 | ||||
-rw-r--r-- | pkg/server/grpc_server.go | 5 |
4 files changed, 353 insertions, 104 deletions
diff --git a/internal/pkg/apiutil/attribute.go b/internal/pkg/apiutil/attribute.go index 112df6ff..a85ec06b 100644 --- a/internal/pkg/apiutil/attribute.go +++ b/internal/pkg/apiutil/attribute.go @@ -1167,6 +1167,9 @@ func NewTunnelEncapAttributeFromNative(a *bgp.PathAttributeTunnelEncap) *api.Tun Type: uint32(sv.Type), Value: sv.Value, } + + // TODO (sbezverk) Add processing new tunneling sub tlvs + } an, _ := ptypes.MarshalAny(subTlv) subTlvs = append(subTlvs, an) @@ -1611,15 +1614,58 @@ func unmarshalAttribute(an *any.Any) (bgp.PathAttributeInterface, error) { subTlv = bgp.NewTunnelEncapSubTLVProtocol(uint16(sv.Protocol)) case *api.TunnelEncapSubTLVColor: subTlv = bgp.NewTunnelEncapSubTLVColor(sv.Color) - - // TODO (sbezverk) Add processing SR Policy Tunnel sub tlv 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", subValue.Message) + return nil, fmt.Errorf("invalid tunnel encapsulation attribute sub tlv: %v type: %T", subValue.Message, sv) } subTlvs = append(subTlvs, subTlv) } @@ -1681,3 +1727,77 @@ func unmarshalAttribute(an *any.Any) (bgp.PathAttributeInterface, error) { } return nil, errors.New("unknown path attribute") } + +// 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: + return nil, fmt.Errorf("srv6 binding sid is not yet supported") + default: + return nil, fmt.Errorf("unknown binding sid type %+v", v) + } +} + +// 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: + return nil, fmt.Errorf("segment of type B is not yet supported") + } + } + return segments, nil +} diff --git a/pkg/packet/bgp/bgp.go b/pkg/packet/bgp/bgp.go index 0976935e..63082af1 100644 --- a/pkg/packet/bgp/bgp.go +++ b/pkg/packet/bgp/bgp.go @@ -254,16 +254,15 @@ func (p PmsiTunnelType) String() string { type EncapSubTLVType uint8 const ( - ENCAP_SUBTLV_TYPE_ENCAPSULATION EncapSubTLVType = 1 - ENCAP_SUBTLV_TYPE_PROTOCOL EncapSubTLVType = 2 - ENCAP_SUBTLV_TYPE_COLOR EncapSubTLVType = 4 - ENCAP_SUBTLV_TYPE_SRPREFIX_SID EncapSubTLVType = 11 - ENCAP_SUBTLV_TYPE_SRPREFERENCE EncapSubTLVType = 12 - ENCAP_SUBTLV_TYPE_SRBINDING_SID EncapSubTLVType = 13 - ENCAP_SUBTLV_TYPE_SRENLP EncapSubTLVType = 14 - ENCAP_SUBTLV_TYPE_SRPRIORITY EncapSubTLVType = 15 - ENCAP_SUBTLV_TYPE_SRSEGMENT_LIST EncapSubTLVType = 128 - ENCAP_SUBTLV_TYPE_SRPOLICY_NAME EncapSubTLVType = 129 + ENCAP_SUBTLV_TYPE_ENCAPSULATION EncapSubTLVType = 1 + ENCAP_SUBTLV_TYPE_PROTOCOL EncapSubTLVType = 2 + ENCAP_SUBTLV_TYPE_COLOR EncapSubTLVType = 4 + ENCAP_SUBTLV_TYPE_SRPREFERENCE EncapSubTLVType = 12 + ENCAP_SUBTLV_TYPE_SRBINDING_SID EncapSubTLVType = 13 + ENCAP_SUBTLV_TYPE_SRENLP EncapSubTLVType = 14 + ENCAP_SUBTLV_TYPE_SRPRIORITY EncapSubTLVType = 15 + ENCAP_SUBTLV_TYPE_SRSEGMENT_LIST EncapSubTLVType = 128 + ENCAP_SUBTLV_TYPE_SRCANDIDATE_PATH_NAME EncapSubTLVType = 129 ) const ( @@ -11645,8 +11644,8 @@ func (t *TunnelEncapTLV) DecodeFromBytes(data []byte) error { subTlv = &TunnelEncapSubTLVSRENLP{} case ENCAP_SUBTLV_TYPE_SRPRIORITY: subTlv = &TunnelEncapSubTLVSRPriority{} - case ENCAP_SUBTLV_TYPE_SRPOLICY_NAME: - subTlv = &TunnelEncapSubTLVSRPolicyName{} + case ENCAP_SUBTLV_TYPE_SRCANDIDATE_PATH_NAME: + subTlv = &TunnelEncapSubTLVSRCandidatePathName{} default: subTlv = &TunnelEncapSubTLVUnknown{ TunnelEncapSubTLV: TunnelEncapSubTLV{ diff --git a/pkg/packet/bgp/sr_policy.go b/pkg/packet/bgp/sr_policy.go index 007612c4..e7baa069 100644 --- a/pkg/packet/bgp/sr_policy.go +++ b/pkg/packet/bgp/sr_policy.go @@ -6,6 +6,8 @@ import ( "fmt" "net" "strconv" + + api "github.com/osrg/gobgp/api" ) type SRPolicyNLRI struct { @@ -60,11 +62,11 @@ func (s *SRPolicyNLRI) decodeFromBytes(rf RouteFamily, data []byte, options ...* func (s *SRPolicyNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, 1+s.Length) p := 0 - buf[0] = s.Length + buf[0] = s.Length * 8 p++ - binary.BigEndian.PutUint32(buf[:4], s.Distinguisher) + binary.BigEndian.PutUint32(buf[p:p+4], s.Distinguisher) p += 4 - binary.BigEndian.PutUint32(buf[:4], s.Color) + binary.BigEndian.PutUint32(buf[p:p+4], s.Color) p += 4 copy(buf[p:], s.Endpoint) if IsAddPathEnabled(false, s.rf, options) { @@ -129,11 +131,10 @@ func (s *SRPolicyIPv4) DecodeFromBytes(data []byte, options ...*MarshallingOptio } 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), + Length: uint8(l / 8), Distinguisher: d, Color: c, Endpoint: ep, @@ -150,11 +151,10 @@ func (s *SRPolicyIPv6) DecodeFromBytes(data []byte, options ...*MarshallingOptio } 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), + Length: uint8(l / 8), Distinguisher: d, Color: c, Endpoint: ep, @@ -184,7 +184,7 @@ func (t *TunnelEncapSubTLVSRPreference) DecodeFromBytes(data []byte) error { } func (t *TunnelEncapSubTLVSRPreference) Serialize() ([]byte, error) { - buf := make([]byte, t.Length) + buf := make([]byte, 6) buf[0] = t.Flags binary.BigEndian.PutUint32(buf[2:6], t.Preference) return t.TunnelEncapSubTLV.Serialize(buf[:]) @@ -209,7 +209,8 @@ func (t *TunnelEncapSubTLVSRPreference) MarshalJSON() ([]byte, error) { func NewTunnelEncapSubTLVSRPreference(flags uint32, preference uint32) *TunnelEncapSubTLVSRPreference { return &TunnelEncapSubTLVSRPreference{ TunnelEncapSubTLV: TunnelEncapSubTLV{ - Type: ENCAP_SUBTLV_TYPE_SRPREFERENCE, + Type: ENCAP_SUBTLV_TYPE_SRPREFERENCE, + Length: 6, }, Flags: uint8(flags), Preference: preference, @@ -236,7 +237,7 @@ func (t *TunnelEncapSubTLVSRPriority) DecodeFromBytes(data []byte) error { } func (t *TunnelEncapSubTLVSRPriority) Serialize() ([]byte, error) { - buf := make([]byte, t.Length) + buf := make([]byte, 1+1) buf[0] = t.Priority return t.TunnelEncapSubTLV.Serialize(buf[:]) } @@ -258,53 +259,55 @@ func (t *TunnelEncapSubTLVSRPriority) MarshalJSON() ([]byte, error) { func NewTunnelEncapSubTLVSRPriority(priority uint8) *TunnelEncapSubTLVSRPriority { return &TunnelEncapSubTLVSRPriority{ TunnelEncapSubTLV: TunnelEncapSubTLV{ - Type: ENCAP_SUBTLV_TYPE_SRPRIORITY, + Type: ENCAP_SUBTLV_TYPE_SRPRIORITY, + Length: 2, }, Priority: priority, } } -type TunnelEncapSubTLVSRPolicyName struct { +type TunnelEncapSubTLVSRCandidatePathName struct { TunnelEncapSubTLV - PolicyName string + CandidatePathName string } -func (t *TunnelEncapSubTLVSRPolicyName) DecodeFromBytes(data []byte) error { +func (t *TunnelEncapSubTLVSRCandidatePathName) 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()]) + t.CandidatePathName = string(value[1:t.TunnelEncapSubTLV.Len()]) return nil } -func (t *TunnelEncapSubTLVSRPolicyName) Serialize() ([]byte, error) { - buf := make([]byte, t.Length) - copy(buf[1:], t.PolicyName) +func (t *TunnelEncapSubTLVSRCandidatePathName) Serialize() ([]byte, error) { + buf := make([]byte, 1+len(t.CandidatePathName)) + copy(buf[1:], t.CandidatePathName) return t.TunnelEncapSubTLV.Serialize(buf[:]) } -func (t *TunnelEncapSubTLVSRPolicyName) String() string { - return fmt.Sprintf("{Policy Name: %s}", t.PolicyName) +func (t *TunnelEncapSubTLVSRCandidatePathName) String() string { + return fmt.Sprintf("{Candidate Path Name: %s}", t.CandidatePathName) } -func (t *TunnelEncapSubTLVSRPolicyName) MarshalJSON() ([]byte, error) { +func (t *TunnelEncapSubTLVSRCandidatePathName) MarshalJSON() ([]byte, error) { return json.Marshal(struct { - Type EncapSubTLVType `json:"type"` - PolicyName string `json:"policy_name"` + Type EncapSubTLVType `json:"type"` + CandidatePathName string `json:"candidate_path_name"` }{ - Type: t.Type, - PolicyName: t.PolicyName, + Type: t.Type, + CandidatePathName: t.CandidatePathName, }) } -func NewTunnelEncapSubTLVSRPolicyName(pn string) *TunnelEncapSubTLVSRPolicyName { - return &TunnelEncapSubTLVSRPolicyName{ +func NewTunnelEncapSubTLVSRCandidatePathName(cpn string) *TunnelEncapSubTLVSRCandidatePathName { + return &TunnelEncapSubTLVSRCandidatePathName{ TunnelEncapSubTLV: TunnelEncapSubTLV{ - Type: ENCAP_SUBTLV_TYPE_SRPOLICY_NAME, + Type: ENCAP_SUBTLV_TYPE_SRCANDIDATE_PATH_NAME, + Length: uint16(len(cpn) + 1), // length of Candidate Path name string + 1 Reserved byte }, - PolicyName: pn, + CandidatePathName: cpn, } } @@ -380,10 +383,11 @@ func (t *TunnelEncapSubTLVSRENLP) MarshalJSON() ([]byte, error) { }) } -func NewTTunnelEncapSubTLVSRENLP(flags uint32, enlp SRENLPValue) *TunnelEncapSubTLVSRENLP { +func NewTunnelEncapSubTLVSRENLP(flags uint32, enlp SRENLPValue) *TunnelEncapSubTLVSRENLP { return &TunnelEncapSubTLVSRENLP{ TunnelEncapSubTLV: TunnelEncapSubTLV{ - Type: ENCAP_SUBTLV_TYPE_SRENLP, + Type: ENCAP_SUBTLV_TYPE_SRENLP, + Length: 3, }, Flags: uint8(flags), ENLP: enlp, @@ -391,12 +395,11 @@ func NewTTunnelEncapSubTLVSRENLP(flags uint32, enlp SRENLPValue) *TunnelEncapSub } type BSID struct { - Length int - Value []byte + Value []byte } func (b *BSID) String() string { - switch b.Length { + switch len(b.Value) { case 0: return "n/a" case 4: @@ -411,24 +414,31 @@ func (b *BSID) String() string { } func (b *BSID) Serialize() []byte { - return []byte{} + return b.Value +} +func (b *BSID) Len() int { + return len(b.Value) } -func NewBSID(v []byte, l int) (*BSID, error) { - switch l { + +func NewBSID(v []byte) (*BSID, error) { + var bsid *BSID + switch len(v) { case 0: case 4: + t := binary.BigEndian.Uint32(v) + t <<= 12 + bsid = &BSID{ + Value: make([]byte, len(v)), + } + binary.BigEndian.PutUint32(bsid.Value, t) case 16: + bsid = &BSID{ + Value: make([]byte, len(v)), + } + copy(bsid.Value, v) 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") + return nil, fmt.Errorf("invalid length %d", len(v)) } - bsid := &BSID{ - Length: l, - Value: make([]byte, l), - } - copy(bsid.Value, v) return bsid, nil } @@ -446,25 +456,33 @@ func (t *TunnelEncapSubTLVSRBSID) DecodeFromBytes(data []byte) error { } // Check Sub TLV length, only 3 possible length are allowed switch t.Length { - case 2: + case 2: // No BSID, do not initializing BSID struct case 6: + fallthrough case 18: + t.BSID = &BSID{ + Value: make([]byte, t.Length-2), + } + copy(t.BSID.Value, value[2:t.Length]) 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) + l := 2 + if t.BSID != nil { + l += t.BSID.Len() + } + buf := make([]byte, l) // 1st byte Flags, 2nd byte Reserved, 3rd+ BSID buf[0] = t.Flags - copy(buf[2:t.BSID.Length], t.BSID.Serialize()) + if t.BSID != nil { + bsid := t.BSID.Serialize() + copy(buf[2:], bsid) + } return t.TunnelEncapSubTLV.Serialize(buf[:]) } @@ -484,14 +502,47 @@ func (t *TunnelEncapSubTLVSRBSID) MarshalJSON() ([]byte, error) { }) } -// 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), +type TunnelEncapSubTLVSRv6BSID struct { + TunnelEncapSubTLV + Flags uint8 + BSID *BSID + EPBAS *SRv6EndpointBehaviorStructure +} + +func (t *TunnelEncapSubTLVSRv6BSID) 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()) } + t.Flags = value[0] + t.BSID, err = NewBSID(value[2:t.Length]) + if err != nil { + return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, err.Error()) + } + return nil +} + +func (t *TunnelEncapSubTLVSRv6BSID) Serialize() ([]byte, error) { + buf := make([]byte, t.Length) + buf[0] = t.Flags + copy(buf[2:t.BSID.Len()], t.BSID.Serialize()) + return t.TunnelEncapSubTLV.Serialize(buf[:]) +} + +func (t *TunnelEncapSubTLVSRv6BSID) String() string { + return fmt.Sprintf("{S-Flag: %t, I-Flag: %t, B-Flag: %t, BSID: %s}", t.Flags&0x80 == 0x80, t.Flags&0x40 == 0x40, t.Flags&0x20 == 0x20, t.BSID.String()) +} + +func (t *TunnelEncapSubTLVSRv6BSID) 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(), + }) } // SegmentType defines a type of Segment in Segment List @@ -500,6 +551,8 @@ type SegmentType int const ( // TypeA Segment Sub-TLV encodes a single SR-MPLS SID TypeA SegmentType = 1 + // TypeB Segment Sub-TLV encodes a single SRv6 SID. + TypeB SegmentType = 13 // TypeC Segment Sub-TLV encodes an IPv4 node address, SR Algorithm // and an optional SR-MPLS SID TypeC SegmentType = 3 @@ -521,10 +574,19 @@ const ( // TypeH Segment Sub-TLV encodes an adjacency local address, an // adjacency remote address and an optional SR-MPLS SID. TypeH SegmentType = 8 + // TypeI Segment Sub-TLV encodes an IPv6 node address, SR Algorithm + // and an optional SRv6 SID. + TypeI SegmentType = 14 + // TypeJ Segment Sub-TLV encodes an IPv6 Link Local adjacency with + // local node address, a local interface identifier (Local Interface + // ID), remote IPv6 node address, a remote interface identifier (Remote + // Interface ID) and an optional SRv6 SID. + TypeJ SegmentType = 15 + // TypeK Segment Sub-TLV encodes an adjacency local address, an + // adjacency remote address and an optional SRv6 SID. + TypeK SegmentType = 16 ) -const SegmentListWeightType = 9 - // Weight sub-TLV specifies the weight associated to a given segment list. type SegmentListWeight struct { TunnelEncapSubTLV @@ -585,7 +647,6 @@ func (s *SegmentTypeA) Serialize() ([]byte, error) { 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) @@ -615,6 +676,61 @@ func (s *SegmentTypeA) MarshalJSON() ([]byte, error) { }) } +type SRv6EndpointBehaviorStructure struct { + Behavior api.SRv6Behavior + BlockLen uint8 + NodeLen uint8 + FuncLen uint8 + ArgLen uint8 +} + +type SegmentTypeB struct { + TunnelEncapSubTLV + Flags uint8 + SID []byte + EP *SRv6EndpointBehaviorStructure +} + +func (s *SegmentTypeB) 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] + return nil +} +func (s *SegmentTypeB) Serialize() ([]byte, error) { + buf := make([]byte, 6) + buf[0] = s.Flags + return s.TunnelEncapSubTLV.Serialize(buf) +} +func (s *SegmentTypeB) String() string { + + return fmt.Sprintf("{V-flag: %t, A-flag:, %t S-flag: %t, B-flag: %t}", + s.Flags&0x80 == 0x80, s.Flags&0x40 == 0x40, s.Flags&0x20 == 0x20, s.Flags&0x10 == 0x10) +} + +func (s *SegmentTypeB) 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"` + }{ + Type: s.Type, + VFlag: s.Flags&0x80 == 0x80, + AFlag: s.Flags&0x40 == 0x40, + SFlag: s.Flags&0x20 == 0x20, + BFlag: s.Flags&0x10 == 0x10, + }) +} + +const ( + // SegmentListSubTLVWeight defines code for Segment List's Weight sub-TLV + SegmentListSubTLVWeight = 9 +) + type TunnelEncapSubTLVSRSegmentList struct { TunnelEncapSubTLV Weight *SegmentListWeight @@ -628,12 +744,12 @@ func (t *TunnelEncapSubTLVSRSegmentList) DecodeFromBytes(data []byte) error { } // Skip reserved byte to access inner SubTLV type value = value[1:] - t.Segments = make([]TunnelEncapSubTLVInterface, 0) + segments := make([]TunnelEncapSubTLVInterface, 0) p := 0 for p < t.TunnelEncapSubTLV.Len()-4 { var segment TunnelEncapSubTLVInterface switch SegmentType(value[0]) { - case SegmentListWeightType: + case SegmentListSubTLVWeight: 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()) @@ -646,6 +762,8 @@ func (t *TunnelEncapSubTLVSRSegmentList) DecodeFromBytes(data []byte) error { if err := segment.DecodeFromBytes(value); err != nil { return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, err.Error()) } + case TypeB: + fallthrough case TypeC: fallthrough case TypeD: @@ -657,47 +775,62 @@ func (t *TunnelEncapSubTLVSRSegmentList) DecodeFromBytes(data []byte) error { case TypeG: fallthrough case TypeH: + fallthrough + case TypeI: + fallthrough + case TypeJ: + fallthrough + case TypeK: 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) + segments = append(segments, segment) p += segment.Len() value = value[segment.Len():] } + if len(segments) == 0 { + t.Segments = nil + } else { + t.Segments = segments + } 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 + buf := make([]byte, 0) // Add reserved byte - p++ - copy(buf[p:], wbuf) - p += len(wbuf) + buf = append(buf, 0x0) + if t.Weight != nil { + wbuf, err := t.Weight.Serialize() + if err != nil { + return nil, err + } + buf = append(buf, wbuf...) + } for _, s := range t.Segments { sbuf, err := s.Serialize() if err != nil { return nil, err } - copy(buf[p:], sbuf) - p += len(sbuf) + buf = append(buf, sbuf...) } return t.TunnelEncapSubTLV.Serialize(buf[:]) } func (t *TunnelEncapSubTLVSRSegmentList) String() string { - var segments string + msg := "{" + if t.Weight != nil { + msg += "Weight: " + t.Weight.String() + "," + } + msg += "Segment List: [ " for _, s := range t.Segments { - segments += s.String() + msg += s.String() + "," } - return fmt.Sprintf("{Weight: %s Segment List: %s}", t.Weight.String(), segments) + msg += " ] }" + return msg } func (t *TunnelEncapSubTLVSRSegmentList) MarshalJSON() ([]byte, error) { @@ -711,11 +844,3 @@ func (t *TunnelEncapSubTLVSRSegmentList) MarshalJSON() ([]byte, error) { Segments: t.Segments, }) } - -func NewTunnelEncapSubTLVSRSegmentList() *TunnelEncapSubTLVSRSegmentList { - return &TunnelEncapSubTLVSRSegmentList{ - TunnelEncapSubTLV: TunnelEncapSubTLV{ - Type: ENCAP_SUBTLV_TYPE_SRSEGMENT_LIST, - }, - } -} diff --git a/pkg/server/grpc_server.go b/pkg/server/grpc_server.go index 06425dfa..a057d6ae 100644 --- a/pkg/server/grpc_server.go +++ b/pkg/server/grpc_server.go @@ -296,6 +296,11 @@ func api2Path(resource api.TableType, path *api.Path, isWithdraw bool) (*table.P return nil, err } + // TODO (sbezverk) At this poinnt nlri and path attributes are converted to native mode + // need to check if update with SR Policy nlri comes with mandatory route distinguisher + // extended community or NO_ADVERTISE community, with Tunnel Encapsulation Attribute 23 + // and tunnel type 15. If it is not the case ignore update and log an error. + pattrs := make([]bgp.PathAttributeInterface, 0) seen := make(map[bgp.BGPAttrType]struct{}) for _, attr := range attrList { |