diff --git a/pkg/packet/pcep/capability.go b/pkg/packet/pcep/capability.go new file mode 100644 index 0000000..90cd6b0 --- /dev/null +++ b/pkg/packet/pcep/capability.go @@ -0,0 +1,42 @@ +// Copyright (c) 2022 NTT Communications Corporation +// +// This software is released under the MIT License. +// see https://github.com/nttcom/pola/blob/main/LICENSE + +package pcep + +type CapabilityInterface interface { + TlvInterface +} + +func PolaCapability() []CapabilityInterface { + return []CapabilityInterface{ + &StatefulPceCapability{ + LspUpdateCapability: true, + IncludeDBVersion: false, + LspInstantiationCapability: true, + TriggeredResync: false, + DeltaLspSyncCapability: false, + TriggeredInitialSync: false, + }, + &PathSetupTypeCapability{ + Length: uint16(10), + PathSetupTypes: Psts{PST_RSVP_TE, PST_SR_TE}, + SubTlvs: []TlvInterface{ + &SrPceCapability{ + UnlimitedMSD: false, + SupportNAI: false, + MaximumSidDepth: uint8(16), + }, + }, + }, + &SrPceCapability{ + UnlimitedMSD: false, + SupportNAI: false, + MaximumSidDepth: uint8(16), + }, + &AssocTypeList{ + AssocTypes: []AssocType{AT_PATH_PROTECTION_ASSOCIATION, AT_SR_POLICY_ASSOCIATION}, + }, + } +} diff --git a/pkg/packet/pcep/message.go b/pkg/packet/pcep/message.go index ee457c6..6ace0a6 100644 --- a/pkg/packet/pcep/message.go +++ b/pkg/packet/pcep/message.go @@ -107,8 +107,8 @@ func (m *OpenMessage) Serialize() []uint8 { return byteOpenMessage } -func NewOpenMessage(sessionID uint8, keepalive uint8) (*OpenMessage, error) { - oo, err := NewOpenObject(sessionID, keepalive) +func NewOpenMessage(sessionID uint8, keepalive uint8, capabilities []CapabilityInterface) (*OpenMessage, error) { + oo, err := NewOpenObject(sessionID, keepalive, capabilities) if err != nil { return nil, err } diff --git a/pkg/packet/pcep/object.go b/pkg/packet/pcep/object.go index 1cced5a..733ff96 100644 --- a/pkg/packet/pcep/object.go +++ b/pkg/packet/pcep/object.go @@ -8,7 +8,6 @@ package pcep import ( "encoding/binary" "errors" - "math" "net/netip" "github.com/nttcom/pola/internal/pkg/table" @@ -22,6 +21,24 @@ const ( RFC_COMPLIANT ) +// Determine PCC type from capability +func DeterminePccType(caps []CapabilityInterface) (pccType PccType) { + pccType = RFC_COMPLIANT + for _, cap := range caps { + if t, ok := cap.(*AssocTypeList); ok { + for _, v := range t.AssocTypes { + if v == AssocType(20) { // Cisco specific Assoc-Type + pccType = CISCO_LEGACY + } else if v == AssocType(65505) { // Juniper specific Assoc-Type + pccType = JUNIPER_LEGACY + break + } + } + } + } + return +} + const COMMON_OBJECT_HEADER_LENGTH uint16 = 4 const ( // PCEP Object-Class (1 byte) @@ -120,139 +137,6 @@ func NewCommonObjectHeader(objectClass uint8, objectType uint8, messageLength ui return oh } -type Tlv struct { - Type uint16 - Length uint16 - Value []uint8 -} - -func (tlv *Tlv) SetLength() { - tlv.Length = uint16(len(tlv.Value)) -} - -func (tlv Tlv) getByteLength() uint16 { - // Type(2byte) + Length(2byte) + Value(valiable) + padding(valiable) - return uint16(4) + uint16(math.Ceil(float64(len(tlv.Value))/4)*4) -} - -const ( // PCEP TLV - TLV_RESERVED = 0x00 // RFC5440 - TLV_NO_PATH_VECTOR = 0x01 // RFC5440 - TLV_OVERLOAD_DURATION = 0x02 // RFC5440 - TLV_REQ_MISSING = 0x03 // RFC5440 - TLV_OF_LIST = 0x04 // RFC5541 - TLV_ORDER = 0x05 // RFC5557 - TLV_P2MP_CAPABLE = 0x06 // RFC8306 - TLV_VENDOR_INFORMATION = 0x07 // RFC7470 - TLV_WAVELENGTH_SELECTION = 0x08 // RFC8780 - TLV_WAVELENGTH_RESTRICTION = 0x09 // RFC8780 - TLV_WAVELENGTH_ALLOCATION = 0x0a // RFC8780 - TLV_OPTICAL_INTERFACE_CLASS_LIST = 0x0b // RFC8780 - TLV_CLIENT_SIGNAL_INFORMATION = 0x0c // RFC8780 - TLV_H_PCE_CAPABILITY = 0x0d // RFC8685 - TLV_DOMAIN_ID = 0x0e // RFC8685 - TLV_H_PCE_FLAG = 0x0f // RFC8685 - TLV_STATEFUL_PCE_CAPABILITY = 0x10 // RFC8231 - TLV_SYMBOLIC_PATH_NAME = 0x11 // RFC8231 - TLV_IPV4_LSP_IDENTIFIERS = 0x12 // RFC8231 - TLV_IPV6_LSP_IDENTIFIERS = 0x13 // RFC8231 - TLV_LSP_ERROR_CODE = 0x14 // RFC8231 - TLV_RSVP_ERROR_SPEC = 0x15 // RFC8231 - // 0x16 is Unassigned - TLV_LSP_DB_VERSION = 0x17 // RFC8232 - TLV_SPEAKER_ENTITY_ID = 0x18 // RFC8232 - // 0x19 is Unassigned - TLV_SR_PCE_CAPABILITY = 0x1a // RFC8664, Deprecated - // 0x1b is Unassigned - TLV_PATH_SETUP_TYPE = 0x1c // RFC8408 - TLV_OPERATOR_CONFIGURED_ASSOCIATION_RANGE = 0x1d // RFC8697 - TLV_GLOBAL_ASSOCIATION_SOURCE = 0x1e // RFC8697 - TLV_EXTENDED_ASSOCIATION_ID = 0x1f // RFC8697 - TLV_P2MP_IPV4_LSP_IDENTIFIERS = 0x20 // RFC8623 - TLV_P2MP_IPV6_LSP_IDENTIFIERS = 0x21 // RFC8623 - TLV_PATH_SETUP_TYPE_CAPABILITY = 0x22 // RFC8409 - TLV_ASSOC_TYPE_LIST = 0x23 // RFC8697 - TLV_AUTO_BANDWIDTH_CAPABILITY = 0x24 // RFC8733 - TLV_AUTO_BANDWIDTH_ATTRIBUTES = 0x25 // RFC8733 - TLV_PATH_PROTECTION_ASSOCIATION_GROUP_TLV = 0x26 // RFC8745 - TLV_IPV4_ADDRESS = 0x27 // RFC8779 - TLV_IPV6_ADDRESS = 0x28 // RFC8779 - TLV_UNNUMBERED_ENDPOINT = 0x29 // RFC8779 - TLV_LABEL_REQUEST = 0x2a // RFC8779 - TLV_LABEL_SET = 0x2b // RFC8779 - TLV_PROTECTION_ATTRIBUTE = 0x2c // RFC8779 - TLV_GMPLS_CAPABILITY = 0x2d // RFC8779 - TLV_DISJOINTNESS_CONFIGURATION = 0x2e // RFC8800 - TLV_DISJOINTNESS_STATUS = 0x2f // RFC8800 - TLV_POLICY_PARAMETERSjTLV = 0x30 // RFC9005 - TLV_SCHED_LSP_ATTRIBUTE = 0x31 // RFC8934 - TLV_SCHED_PD_LSP_ATTRIBUTE = 0x32 // RFC8934 - TLV_PCE_FLOWSPEC_CAPABILITY = 0x33 // ietf-pce-pcep-flowspec-12 - TLV_FLOW_FILTER = 0x34 // ietf-pce-pcep-flowspec-12 - TLV_L2_FLOW_FILTER = 0x35 // ietf-pce-pcep-flowspec-12 - TLV_BIDIRECTIONAL_LSP_ASSOCIATION_GROUP = 0x36 // RFC9059 - TLV_SRPOLICY_POL_NAME uint16 = 0x38 // ietf-pce-segment-routing-policy-cp-07 - TLV_SRPOLICY_CPATH_ID uint16 = 0x39 // ietf-pce-segment-routing-policy-cp-07 - TLV_SRPOLICY_CPATH_NAME uint16 = 0x3a // ietf-pce-segment-routing-policy-cp-07 - TLV_SRPOLICY_CPATH_PREFERENCE uint16 = 0x3b // ietf-pce-segment-routing-policy-cp-07 -) - -const ( - TLV_STATEFUL_PCE_CAPABILITY_LENGTH uint16 = 4 - TLV_SR_PCE_CAPABILITY_LENGTH uint16 = 4 - TLV_PATH_SETUP_TYPE_LENGTH uint16 = 4 - TLV_EXTENDED_ASSOCIATION_ID_LENGTH uint16 = 8 - TLV_SRPOLICY_CPATH_ID_LENGTH uint16 = 28 - TLV_SRPOLICY_CPATH_PREFERENCE_LENGTH uint16 = 4 -) - -const TL_LENGTH = 4 - -func (tlv *Tlv) DecodeFromBytes(data []uint8) error { - tlv.Type = binary.BigEndian.Uint16(data[0:2]) - tlv.Length = binary.BigEndian.Uint16(data[2:4]) - tlv.Value = data[4 : 4+tlv.Length] - return nil -} - -func (tlv *Tlv) Serialize() []uint8 { - bytePcepTLV := []uint8{} - - byteTlvType := make([]uint8, 2) - binary.BigEndian.PutUint16(byteTlvType, tlv.Type) - bytePcepTLV = append(bytePcepTLV, byteTlvType...) // Type (2byte) - - byteTlvLength := make([]uint8, 2) - binary.BigEndian.PutUint16(byteTlvLength, tlv.Length) - bytePcepTLV = append(bytePcepTLV, byteTlvLength...) // Length (2byte) - - bytePcepTLV = append(bytePcepTLV, tlv.Value...) // Value (Length byte) - if padding := tlv.Length % 4; padding != 0 { - bytePadding := make([]uint8, 4-padding) - bytePcepTLV = append(bytePcepTLV, bytePadding...) - } - return bytePcepTLV -} - -func DecodeTLVsFromBytes(data []uint8) ([]Tlv, error) { - tlvs := []Tlv{} - for { - var tlv Tlv - if err := tlv.DecodeFromBytes(data); err != nil { - return nil, err - } - tlvs = append(tlvs, tlv) - if int(tlv.getByteLength()) < len(data) { - data = data[tlv.getByteLength():] - } else if int(tlv.getByteLength()) == len(data) { - break - } else { - return nil, errors.New("tlvs decode error") - } - } - return tlvs, nil -} - type optParams struct { pccType PccType } @@ -276,7 +160,7 @@ type OpenObject struct { Keepalive uint8 Deadtime uint8 Sid uint8 - Tlvs []Tlv + Caps []CapabilityInterface } func (o *OpenObject) DecodeFromBytes(objectBody []uint8) error { @@ -285,11 +169,16 @@ func (o *OpenObject) DecodeFromBytes(objectBody []uint8) error { o.Keepalive = uint8(objectBody[1]) o.Deadtime = uint8(objectBody[2]) o.Sid = uint8(objectBody[3]) - tlvs, err := DecodeTLVsFromBytes(objectBody[4:]) + + tlvs, err := DecodeTLVs(objectBody[4:]) if err != nil { return err } - o.Tlvs = append(o.Tlvs, tlvs...) + for _, t := range tlvs { + if c, ok := t.(CapabilityInterface); ok { + o.Caps = append(o.Caps, c) + } + } return nil } @@ -303,8 +192,8 @@ func (o *OpenObject) Serialize() []uint8 { buf[3] = o.Sid byteTlvs := []uint8{} - for _, tlv := range o.Tlvs { - byteTlvs = append(byteTlvs, tlv.Serialize()...) + for _, cap := range o.Caps { + byteTlvs = append(byteTlvs, cap.Serialize()...) } byteOpenObject := AppendByteSlices(byteOpenObjectHeader, buf, byteTlvs) @@ -313,36 +202,23 @@ func (o *OpenObject) Serialize() []uint8 { func (o *OpenObject) getByteLength() uint16 { tlvsByteLength := uint16(0) - for _, tlv := range o.Tlvs { - tlvsByteLength += tlv.getByteLength() + for _, cap := range o.Caps { + tlvsByteLength += cap.GetByteLength() } // TODO: Calculate TLV length and record in open_object_length // CommonObjectHeader(4byte) + openObject(4byte) + tlvslength(valiable) return COMMON_OBJECT_HEADER_LENGTH + 4 + tlvsByteLength } -func NewOpenObject(sessionID uint8, keepalive uint8) (*OpenObject, error) { +func NewOpenObject(sessionID uint8, keepalive uint8, capabilities []CapabilityInterface) (*OpenObject, error) { o := &OpenObject{ Version: uint8(1), // PCEP version. Current version is 1 Flag: uint8(0), Keepalive: keepalive, Deadtime: keepalive * 4, Sid: sessionID, - Tlvs: []Tlv{}, - } - openObjectTLVs := []Tlv{ // TODO: Functionalize - { - Type: TLV_STATEFUL_PCE_CAPABILITY, - Length: TLV_STATEFUL_PCE_CAPABILITY_LENGTH, - Value: []uint8{0x00, 0x00, 0x00, 0x05}, - }, - { - Type: TLV_SR_PCE_CAPABILITY, - Length: TLV_SR_PCE_CAPABILITY_LENGTH, - Value: []uint8{0x00, 0x00, 0x00, 0x0a}, - }, + Caps: capabilities, } - o.Tlvs = append(o.Tlvs, openObjectTLVs...) return o, nil } @@ -426,7 +302,7 @@ const ( type SrpObject struct { RFlag bool SrpId uint32 // 0x00000000 and 0xFFFFFFFF are reserved. - Tlvs []Tlv + Tlvs []TlvInterface } func (o *SrpObject) DecodeFromBytes(objectBody []uint8) error { @@ -457,7 +333,7 @@ func (o *SrpObject) Serialize() []uint8 { func (o *SrpObject) getByteLength() uint16 { tlvsByteLength := uint16(0) for _, tlv := range o.Tlvs { - tlvsByteLength += tlv.getByteLength() + tlvsByteLength += tlv.GetByteLength() } // CommonObjectHeader(4byte) + Flags, SRP-ID(8byte) return COMMON_OBJECT_HEADER_LENGTH + 8 + tlvsByteLength @@ -467,11 +343,9 @@ func NewSrpObject(srpId uint32, isRemove bool) (*SrpObject, error) { o := &SrpObject{ RFlag: isRemove, // RFC8281 5.2 SrpId: srpId, - Tlvs: []Tlv{ - { - Type: TLV_PATH_SETUP_TYPE, - Length: TLV_PATH_SETUP_TYPE_LENGTH, - Value: []uint8{0x00, 0x00, 0x00, 0x01}, + Tlvs: []TlvInterface{ + &PathSetupType{ + PathSetupType: PST_SR_TE, // SR-MPLS TE }, }, } @@ -494,7 +368,7 @@ type LspObject struct { RFlag bool SFlag bool DFlag bool - Tlvs []Tlv + Tlvs []TlvInterface } func (o *LspObject) DecodeFromBytes(objectBody []uint8) error { @@ -506,33 +380,20 @@ func (o *LspObject) DecodeFromBytes(objectBody []uint8) error { o.DFlag = (objectBody[3] & 0x01) != 0 if len(objectBody) > 4 { byteTlvs := objectBody[4:] - for { - var tlv Tlv - if err := tlv.DecodeFromBytes(byteTlvs); err != nil { - return err - } - if tlv.Type == uint16(TLV_SYMBOLIC_PATH_NAME) { - o.Name = string(removePadding(tlv.Value)) + var err error + if o.Tlvs, err = DecodeTLVs(byteTlvs); err != nil { + return err + } + for _, tlv := range o.Tlvs { + + if t, ok := tlv.(*SymbolicPathName); ok { + o.Name = t.Name } - if tlv.Type == uint16(TLV_IPV4_LSP_IDENTIFIERS) { + if t, ok := tlv.(*IPv4LspIdentifiers); ok { // TODO: Obtain true srcAddr - var ok bool - if o.SrcAddr, ok = netip.AddrFromSlice(tlv.Value[0:4]); !ok { - return errors.New("lsp tlv decode error") - } - if o.DstAddr, ok = netip.AddrFromSlice(tlv.Value[12:16]); !ok { - return errors.New("lsp tlv decode error") - } - } - o.Tlvs = append(o.Tlvs, tlv) - - if int(tlv.getByteLength()) < len(byteTlvs) { - byteTlvs = byteTlvs[tlv.getByteLength():] - } else if int(tlv.getByteLength()) == len(byteTlvs) { - break - } else { - return errors.New("lsp tlv decode error") + o.SrcAddr = t.IPv4TunnelSenderAddress + o.DstAddr = t.IPv4TunnelEndpointAddress } } } @@ -559,17 +420,17 @@ func (o *LspObject) Serialize() []uint8 { } byteTlvs := []uint8{} for _, tlv := range o.Tlvs { - byteTlvs = append(byteTlvs, tlv.Serialize()...) + byteTlvs = tlv.Serialize() } byteLspObject := AppendByteSlices(byteLspObjectHeader, buf, byteTlvs) return byteLspObject } -func (o LspObject) getByteLength() uint16 { +func (o *LspObject) getByteLength() uint16 { tlvsByteLength := uint16(0) for _, tlv := range o.Tlvs { - tlvsByteLength += tlv.getByteLength() + tlvsByteLength += tlv.GetByteLength() } // Flags, SRP-ID (4byte) lspObjectBodyLength := uint16(4) + tlvsByteLength @@ -586,15 +447,12 @@ func NewLspObject(lspName string, plspId uint32) (*LspObject, error) { RFlag: false, // TODO: Allow setting from function arguments SFlag: false, DFlag: true, - Tlvs: []Tlv{}, + Tlvs: []TlvInterface{}, } - symbolicPathNameTlv := Tlv{ - Type: TLV_SYMBOLIC_PATH_NAME, - Length: 0x0000, //valiable, set next line - Value: []uint8(lspName), + symbolicPathNameTlv := &SymbolicPathName{ + Name: lspName, } - symbolicPathNameTlv.SetLength() - o.Tlvs = append(o.Tlvs, symbolicPathNameTlv) + o.Tlvs = append(o.Tlvs, TlvInterface(symbolicPathNameTlv)) return o, nil } @@ -883,7 +741,7 @@ type AssociationObject struct { AssocType uint16 AssocId uint16 AssocSrc netip.Addr - Tlvs []Tlv + Tlvs []TlvInterface } func (o *AssociationObject) DecodeFromBytes(objectBody []uint8) error { @@ -893,21 +751,9 @@ func (o *AssociationObject) DecodeFromBytes(objectBody []uint8) error { o.AssocSrc, _ = netip.AddrFromSlice(objectBody[8:12]) if len(objectBody) > 12 { byteTlvs := objectBody[12:] - for { - var tlv Tlv - if err := tlv.DecodeFromBytes(byteTlvs); err != nil { - return err - } - - o.Tlvs = append(o.Tlvs, tlv) - - if int(tlv.getByteLength()) < len(byteTlvs) { - byteTlvs = byteTlvs[tlv.getByteLength():] - } else if int(tlv.getByteLength()) == len(byteTlvs) { - break - } else { - return errors.New("lsp tlv decode error") - } + var err error + if o.Tlvs, err = DecodeTLVs(byteTlvs); err != nil { + return err } } return nil @@ -940,7 +786,7 @@ func (o AssociationObject) Serialize() []uint8 { func (o AssociationObject) getByteLength() uint16 { tlvsByteLength := uint16(0) for _, tlv := range o.Tlvs { - tlvsByteLength += tlv.getByteLength() + tlvsByteLength += tlv.GetByteLength() } // Reserved(2byte) + Flags(2byte) + Assoc Type(2byte) + Assoc ID(2byte) + IPv4 Assoc Src(4byte) associationObjectBodyLength := uint16(12) + tlvsByteLength @@ -959,22 +805,22 @@ func NewAssociationObject(srcAddr netip.Addr, dstAddr netip.Addr, color uint32, // TODO: Expantion for IPv6 Endpoint o := &AssociationObject{ RFlag: false, - Tlvs: []Tlv{}, + Tlvs: []TlvInterface{}, AssocSrc: srcAddr, } if opts.pccType == JUNIPER_LEGACY { o.AssocId = 0 o.AssocType = JUNIPER_SPEC_ASSOC_TYPE_SR_POLICY_ASSOCIATION - associationObjectTLVs := []Tlv{ - { - Type: JUNIPER_SPEC_TLV_EXTENDED_ASSOCIATION_ID, + associationObjectTLVs := []TlvInterface{ + &UndefinedTlv{ + Typ: JUNIPER_SPEC_TLV_EXTENDED_ASSOCIATION_ID, Length: TLV_EXTENDED_ASSOCIATION_ID_LENGTH, // TODO: 20 if ipv6 endpoint Value: AppendByteSlices( uint32ToListUint8(color), dstAddr.AsSlice(), ), }, - { - Type: JUNIPER_SPEC_TLV_SRPOLICY_CPATH_ID, + &UndefinedTlv{ + Typ: JUNIPER_SPEC_TLV_SRPOLICY_CPATH_ID, Length: TLV_SRPOLICY_CPATH_ID_LENGTH, Value: []uint8{ 0x00, // protocol origin @@ -984,8 +830,8 @@ func NewAssociationObject(srcAddr netip.Addr, dstAddr netip.Addr, color uint32, 0x00, 0x00, 0x00, 0x00, //discriminator }, }, - { - Type: JUNIPER_SPEC_TLV_SRPOLICY_CPATH_PREFERENCE, + &UndefinedTlv{ + Typ: JUNIPER_SPEC_TLV_SRPOLICY_CPATH_PREFERENCE, Length: TLV_SRPOLICY_CPATH_PREFERENCE_LENGTH, Value: uint32ToListUint8(preference), }, @@ -994,16 +840,16 @@ func NewAssociationObject(srcAddr netip.Addr, dstAddr netip.Addr, color uint32, } else { o.AssocId = 1 // (I.D. pce-segment-routing-policy-cp-07 5.1) o.AssocType = ASSOC_TYPE_SR_POLICY_ASSOCIATION // (I.D. pce-segment-routing-policy-cp-07 5.1) - associationObjectTLVs := []Tlv{ - { - Type: TLV_EXTENDED_ASSOCIATION_ID, + associationObjectTLVs := []TlvInterface{ + &UndefinedTlv{ + Typ: TLV_EXTENDED_ASSOCIATION_ID, Length: TLV_EXTENDED_ASSOCIATION_ID_LENGTH, // TODO: 20 if ipv6 endpoint Value: AppendByteSlices( uint32ToListUint8(color), dstAddr.AsSlice(), ), }, - { - Type: TLV_SRPOLICY_CPATH_ID, + &UndefinedTlv{ + Typ: TLV_SRPOLICY_CPATH_ID, Length: TLV_SRPOLICY_CPATH_ID_LENGTH, Value: []uint8{ 0x00, // protocol origin @@ -1013,8 +859,8 @@ func NewAssociationObject(srcAddr netip.Addr, dstAddr netip.Addr, color uint32, 0x00, 0x00, 0x00, 0x00, //discriminator }, }, - { - Type: TLV_SRPOLICY_CPATH_PREFERENCE, + &UndefinedTlv{ + Typ: TLV_SRPOLICY_CPATH_PREFERENCE, Length: TLV_SRPOLICY_CPATH_PREFERENCE_LENGTH, Value: uint32ToListUint8(preference), }, @@ -1028,10 +874,12 @@ func NewAssociationObject(srcAddr netip.Addr, dstAddr netip.Addr, color uint32, // (I.D. pce-segment-routing-policy-cp-08 5.1) func (o *AssociationObject) Color() uint32 { for _, tlv := range o.Tlvs { - if tlv.Type == TLV_EXTENDED_ASSOCIATION_ID { - return uint32(binary.BigEndian.Uint32(tlv.Value[:4])) - } else if tlv.Type == JUNIPER_SPEC_TLV_EXTENDED_ASSOCIATION_ID { - return uint32(binary.BigEndian.Uint32(tlv.Value[:4])) + if t, ok := tlv.(*UndefinedTlv); ok { + if t.Type() == TLV_EXTENDED_ASSOCIATION_ID { + return uint32(binary.BigEndian.Uint32(t.Value[:4])) + } else if t.Type() == JUNIPER_SPEC_TLV_EXTENDED_ASSOCIATION_ID { + return uint32(binary.BigEndian.Uint32(t.Value[:4])) + } } } return 0 @@ -1040,10 +888,12 @@ func (o *AssociationObject) Color() uint32 { // (I.D. pce-segment-routing-policy-cp-08 5.1) func (o *AssociationObject) Preference() uint32 { for _, tlv := range o.Tlvs { - if tlv.Type == TLV_SRPOLICY_CPATH_PREFERENCE { - return uint32(binary.BigEndian.Uint32(tlv.Value)) - } else if tlv.Type == JUNIPER_SPEC_TLV_SRPOLICY_CPATH_PREFERENCE { - return uint32(binary.BigEndian.Uint32(tlv.Value)) + if t, ok := tlv.(*UndefinedTlv); ok { + if t.Type() == TLV_SRPOLICY_CPATH_PREFERENCE { + return uint32(binary.BigEndian.Uint32(t.Value)) + } else if t.Type() == JUNIPER_SPEC_TLV_SRPOLICY_CPATH_PREFERENCE { + return uint32(binary.BigEndian.Uint32(t.Value)) + } } } return 0 @@ -1063,29 +913,18 @@ const ( type VendorInformationObject struct { ObjectType uint8 // vendor specific constraints: 1 EnterpriseNumber uint32 - Tlvs []Tlv + Tlvs []TlvInterface } func (o *VendorInformationObject) DecodeFromBytes(objectBody []uint8) error { o.EnterpriseNumber = binary.BigEndian.Uint32(objectBody[0:4]) if len(objectBody) > 4 { byteTlvs := objectBody[4:] - for { - var tlv Tlv - if err := tlv.DecodeFromBytes(byteTlvs); err != nil { - return err - } - - o.Tlvs = append(o.Tlvs, tlv) - - if int(tlv.getByteLength()) < len(byteTlvs) { - byteTlvs = byteTlvs[tlv.getByteLength():] - } else if int(tlv.getByteLength()) == len(byteTlvs) { - break - } else { - return errors.New("lsp tlv decode error") - } + var err error + if o.Tlvs, err = DecodeTLVs(byteTlvs); err != nil { + return err } + } return nil } @@ -1119,18 +958,18 @@ func NewVendorInformationObject(vendor PccType, color uint32, preference uint32) o = &VendorInformationObject{ // for Cisco PCC ObjectType: uint8(1), // (RFC7470 4) EnterpriseNumber: EN_CISCO, - Tlvs: []Tlv{}, + Tlvs: []TlvInterface{}, } - vendorInformationObjectTLVs := []Tlv{ - { - Type: CISCO_SPEC_TLV_COLOR, + vendorInformationObjectTLVs := []TlvInterface{ + &UndefinedTlv{ + Typ: CISCO_SPEC_TLV_COLOR, Length: CISCO_SPEC_TLV_COLOR_LENGTH, // TODO: 20 if ipv6 endpoint Value: AppendByteSlices( uint32ToListUint8(color), ), }, - { - Type: CISCO_SPEC_TLV_PREFERENCE, + &UndefinedTlv{ + Typ: CISCO_SPEC_TLV_PREFERENCE, Length: CISCO_SPEC_TLV_PREFERENCE_LENGTH, Value: uint32ToListUint8(preference), }, @@ -1144,17 +983,21 @@ func NewVendorInformationObject(vendor PccType, color uint32, preference uint32) func (o *VendorInformationObject) Color() uint32 { for _, tlv := range o.Tlvs { - if tlv.Type == CISCO_SPEC_TLV_COLOR { - return uint32(binary.BigEndian.Uint32(tlv.Value)) - } + if t, ok := tlv.(*UndefinedTlv); ok { + if t.Type() == CISCO_SPEC_TLV_COLOR { + return uint32(binary.BigEndian.Uint32(t.Value)) + } } - return 0 } + return 0 +} func (o *VendorInformationObject) Preference() uint32 { for _, tlv := range o.Tlvs { - if tlv.Type == CISCO_SPEC_TLV_PREFERENCE { - return uint32(binary.BigEndian.Uint32(tlv.Value)) + if t, ok := tlv.(*UndefinedTlv); ok { + if t.Type() == CISCO_SPEC_TLV_PREFERENCE { + return uint32(binary.BigEndian.Uint32(t.Value)) + } } } return 0 diff --git a/pkg/packet/pcep/pcep_util.go b/pkg/packet/pcep/pcep_util.go index f388550..af74267 100644 --- a/pkg/packet/pcep/pcep_util.go +++ b/pkg/packet/pcep/pcep_util.go @@ -20,16 +20,6 @@ func AppendByteSlices(byteSlices ...[]uint8) []uint8 { return joinedSlice } -func removePadding(data []uint8) []uint8 { - for { - if data[len(data)-1] == 0x00 { - data = data[:len(data)-1] - } else { - return data - } - } -} - func uint16ToListUint8(input uint16) []uint8 { uint8Fmt := make([]uint8, 2) binary.BigEndian.PutUint16(uint8Fmt, input) diff --git a/pkg/packet/pcep/tlv.go b/pkg/packet/pcep/tlv.go new file mode 100644 index 0000000..4eaec3b --- /dev/null +++ b/pkg/packet/pcep/tlv.go @@ -0,0 +1,625 @@ +// Copyright (c) 2022 NTT Communications Corporation +// +// This software is released under the MIT License. +// see https://github.com/nttcom/pola/blob/main/LICENSE + +package pcep + +import ( + "encoding/binary" + "errors" + "fmt" + "net/netip" + "strings" + + "go.uber.org/zap/zapcore" +) + +const ( // PCEP TLV + TLV_RESERVED uint16 = 0x00 // RFC5440 + TLV_NO_PATH_VECTOR uint16 = 0x01 // RFC5440 + TLV_OVERLOAD_DURATION uint16 = 0x02 // RFC5440 + TLV_REQ_MISSING uint16 = 0x03 // RFC5440 + TLV_OF_LIST uint16 = 0x04 // RFC5541 + TLV_ORDER uint16 = 0x05 // RFC5557 + TLV_P2MP_CAPABLE uint16 = 0x06 // RFC8306 + TLV_VENDOR_INFORMATION uint16 = 0x07 // RFC7470 + TLV_WAVELENGTH_SELECTION uint16 = 0x08 // RFC8780 + TLV_WAVELENGTH_RESTRICTION uint16 = 0x09 // RFC8780 + TLV_WAVELENGTH_ALLOCATION uint16 = 0x0a // RFC8780 + TLV_OPTICAL_INTERFACE_CLASS_LIST uint16 = 0x0b // RFC8780 + TLV_CLIENT_SIGNAL_INFORMATION uint16 = 0x0c // RFC8780 + TLV_H_PCE_CAPABILITY uint16 = 0x0d // RFC8685 + TLV_DOMAIN_ID uint16 = 0x0e // RFC8685 + TLV_H_PCE_FLAG uint16 = 0x0f // RFC8685 + TLV_STATEFUL_PCE_CAPABILITY uint16 = 0x10 // RFC8231 + TLV_SYMBOLIC_PATH_NAME uint16 = 0x11 // RFC8231 + TLV_IPV4_LSP_IDENTIFIERS uint16 = 0x12 // RFC8231 + TLV_IPV6_LSP_IDENTIFIERS uint16 = 0x13 // RFC8231 + TLV_LSP_ERROR_CODE uint16 = 0x14 // RFC8231 + TLV_RSVP_ERROR_SPEC uint16 = 0x15 // RFC8231 + TLV_LSP_DB_VERSION uint16 = 0x17 // RFC8232 + TLV_SPEAKER_ENTITY_ID uint16 = 0x18 // RFC8232 + TLV_SR_PCE_CAPABILITY uint16 = 0x1a // RFC8664 + TLV_PATH_SETUP_TYPE uint16 = 0x1c // RFC8408 + TLV_OPERATOR_CONFIGURED_ASSOCIATION_RANGE uint16 = 0x1d // RFC8697 + TLV_GLOBAL_ASSOCIATION_SOURCE uint16 = 0x1e // RFC8697 + TLV_EXTENDED_ASSOCIATION_ID uint16 = 0x1f // RFC8697 + TLV_P2MP_IPV4_LSP_IDENTIFIERS uint16 = 0x20 // RFC8623 + TLV_P2MP_IPV6_LSP_IDENTIFIERS uint16 = 0x21 // RFC8623 + TLV_PATH_SETUP_TYPE_CAPABILITY uint16 = 0x22 // RFC8409 + TLV_ASSOC_TYPE_LIST uint16 = 0x23 // RFC8697 + TLV_AUTO_BANDWIDTH_CAPABILITY uint16 = 0x24 // RFC8733 + TLV_AUTO_BANDWIDTH_ATTRIBUTES uint16 = 0x25 // RFC8733 + TLV_PATH_PROTECTION_ASSOCIATION_GROUP_TLV uint16 = 0x26 // RFC8745 + TLV_IPV4_ADDRESS uint16 = 0x27 // RFC8779 + TLV_IPV6_ADDRESS uint16 = 0x28 // RFC8779 + TLV_UNNUMBERED_ENDPOINT uint16 = 0x29 // RFC8779 + TLV_LABEL_REQUEST uint16 = 0x2a // RFC8779 + TLV_LABEL_SET uint16 = 0x2b // RFC8779 + TLV_PROTECTION_ATTRIBUTE uint16 = 0x2c // RFC8779 + TLV_GMPLS_CAPABILITY uint16 = 0x2d // RFC8779 + TLV_DISJOINTNESS_CONFIGURATION uint16 = 0x2e // RFC8800 + TLV_DISJOINTNESS_STATUS uint16 = 0x2f // RFC8800 + TLV_POLICY_PARAMETERSjTLV uint16 = 0x30 // RFC9005 + TLV_SCHED_LSP_ATTRIBUTE uint16 = 0x31 // RFC8934 + TLV_SCHED_PD_LSP_ATTRIBUTE uint16 = 0x32 // RFC8934 + TLV_PCE_FLOWSPEC_CAPABILITY uint16 = 0x33 // ietf-pce-pcep-flowspec-12 + TLV_FLOW_FILTER uint16 = 0x34 // ietf-pce-pcep-flowspec-12 + TLV_L2_FLOW_FILTER uint16 = 0x35 // ietf-pce-pcep-flowspec-12 + TLV_BIDIRECTIONAL_LSP_ASSOCIATION_GROUP uint16 = 0x36 // RFC9059 + TLV_SRPOLICY_POL_NAME uint16 = 0x38 // ietf-pce-segment-routing-policy-cp-07 + TLV_SRPOLICY_CPATH_ID uint16 = 0x39 // ietf-pce-segment-routing-policy-cp-07 + TLV_SRPOLICY_CPATH_NAME uint16 = 0x3a // ietf-pce-segment-routing-policy-cp-07 + TLV_SRPOLICY_CPATH_PREFERENCE uint16 = 0x3b // ietf-pce-segment-routing-policy-cp-07 +) + +const ( + TLV_STATEFUL_PCE_CAPABILITY_LENGTH uint16 = 4 + TLV_SR_PCE_CAPABILITY_LENGTH uint16 = 4 + TLV_PATH_SETUP_TYPE_LENGTH uint16 = 4 + TLV_EXTENDED_ASSOCIATION_ID_LENGTH uint16 = 8 + TLV_IPV4_LSP_IDENTIFIERS_LENGTH uint16 = 16 + TLV_SRPOLICY_CPATH_ID_LENGTH uint16 = 28 + TLV_SRPOLICY_CPATH_PREFERENCE_LENGTH uint16 = 4 +) + +const TL_LENGTH = 4 + +type TlvInterface interface { + DecodeFromBytes(data []uint8) error + Serialize() []uint8 + MarshalLogObject(enc zapcore.ObjectEncoder) error + Type() uint16 + Len() uint16 + GetByteLength() uint16 +} + +type StatefulPceCapability struct { + LspUpdateCapability bool + IncludeDBVersion bool + LspInstantiationCapability bool + TriggeredResync bool + DeltaLspSyncCapability bool + TriggeredInitialSync bool +} + +func (tlv *StatefulPceCapability) DecodeFromBytes(data []uint8) error { + tlv.LspUpdateCapability = (data[7] & 0x01) != 0 + tlv.IncludeDBVersion = (data[7] & 0x02) != 0 + tlv.LspInstantiationCapability = (data[7] & 0x04) != 0 + tlv.TriggeredResync = (data[7] & 0x08) != 0 + tlv.DeltaLspSyncCapability = (data[7] & 0x10) != 0 + tlv.TriggeredInitialSync = (data[7] & 0x20) != 0 + + return nil +} + +func (tlv *StatefulPceCapability) Serialize() []uint8 { + buf := []uint8{} + + typ := make([]uint8, 2) + binary.BigEndian.PutUint16(typ, tlv.Type()) + buf = append(buf, typ...) + + length := make([]uint8, 2) + binary.BigEndian.PutUint16(length, tlv.Len()) + buf = append(buf, length...) + + val := make([]uint8, tlv.Len()) + if tlv.LspUpdateCapability { + val[3] = val[3] | 0x01 + } + if tlv.IncludeDBVersion { + val[3] = val[3] | 0x02 + } + if tlv.LspInstantiationCapability { + val[3] = val[3] | 0x04 + } + if tlv.TriggeredResync { + val[3] = val[3] | 0x08 + } + if tlv.DeltaLspSyncCapability { + val[3] = val[3] | 0x10 + } + if tlv.TriggeredInitialSync { + val[3] = val[3] | 0x20 + } + buf = append(buf, val...) + + return buf +} + +func (tlv *StatefulPceCapability) MarshalLogObject(enc zapcore.ObjectEncoder) error { + return nil +} + +func (tlv *StatefulPceCapability) Type() uint16 { + return TLV_STATEFUL_PCE_CAPABILITY +} + +func (tlv *StatefulPceCapability) Len() uint16 { + return TLV_STATEFUL_PCE_CAPABILITY_LENGTH +} + +func (tlv *StatefulPceCapability) GetByteLength() uint16 { + return TL_LENGTH + TLV_STATEFUL_PCE_CAPABILITY_LENGTH +} + +type SymbolicPathName struct { + Name string +} + +func (tlv *SymbolicPathName) DecodeFromBytes(data []uint8) error { + length := binary.BigEndian.Uint16(data[2:4]) + tlv.Name = string(data[4 : 4+length]) + return nil +} + +func (tlv *SymbolicPathName) Serialize() []uint8 { + buf := []uint8{} + + typ := make([]uint8, 2) + binary.BigEndian.PutUint16(typ, tlv.Type()) + buf = append(buf, typ...) + + length := make([]uint8, 2) + binary.BigEndian.PutUint16(length, tlv.Len()) + buf = append(buf, length...) + + buf = append(buf, []uint8(tlv.Name)...) + + if tlv.Len()%4 != 0 { + pad := make([]uint8, 4-tlv.Len()%4) + buf = append(buf, pad...) + } + return buf +} + +func (tlv *SymbolicPathName) MarshalLogObject(enc zapcore.ObjectEncoder) error { + return nil +} + +func (tlv *SymbolicPathName) Type() uint16 { + return TLV_SYMBOLIC_PATH_NAME +} + +func (tlv *SymbolicPathName) Len() uint16 { + return uint16(len(tlv.Name)) +} + +func (tlv *SymbolicPathName) GetByteLength() uint16 { + if tlv.Len()%4 == 0 { + return TL_LENGTH + tlv.Len() + } else { + return TL_LENGTH + tlv.Len() + (4 - tlv.Len()%4) // padding + } +} + +type IPv4LspIdentifiers struct { + IPv4TunnelSenderAddress netip.Addr + IPv4TunnelEndpointAddress netip.Addr +} + +func (tlv *IPv4LspIdentifiers) DecodeFromBytes(data []uint8) error { + var ok bool + if tlv.IPv4TunnelSenderAddress, ok = netip.AddrFromSlice(data[12:16]); !ok { + tlv.IPv4TunnelSenderAddress, _ = netip.AddrFromSlice(data[4:8]) + } + tlv.IPv4TunnelEndpointAddress, _ = netip.AddrFromSlice(data[16:20]) + return nil +} + +func (tlv *IPv4LspIdentifiers) Serialize() []uint8 { + return nil +} + +func (tlv *IPv4LspIdentifiers) MarshalLogObject(enc zapcore.ObjectEncoder) error { + return nil +} + +func (tlv *IPv4LspIdentifiers) Type() uint16 { + return TLV_IPV4_LSP_IDENTIFIERS +} + +func (tlv *IPv4LspIdentifiers) Len() uint16 { + return TLV_IPV4_LSP_IDENTIFIERS_LENGTH +} + +func (tlv *IPv4LspIdentifiers) GetByteLength() uint16 { + return TL_LENGTH + TLV_IPV4_LSP_IDENTIFIERS_LENGTH +} + +type SrPceCapability struct { + UnlimitedMSD bool + SupportNAI bool + MaximumSidDepth uint8 +} + +func (tlv *SrPceCapability) DecodeFromBytes(data []uint8) error { + tlv.UnlimitedMSD = (data[6] & 0x01) != 0 + tlv.SupportNAI = (data[6] & 0x02) != 0 + tlv.MaximumSidDepth = data[7] + return nil +} + +func (tlv *SrPceCapability) Serialize() []uint8 { + buf := []uint8{} + + typ := make([]uint8, 2) + binary.BigEndian.PutUint16(typ, tlv.Type()) + buf = append(buf, typ...) + + length := make([]uint8, 2) + binary.BigEndian.PutUint16(length, tlv.Len()) + buf = append(buf, length...) + + val := make([]uint8, tlv.Len()) + if tlv.UnlimitedMSD { + val[2] = val[2] | 0x01 + } + if tlv.SupportNAI { + val[2] = val[2] | 0x02 + } + val[3] = tlv.MaximumSidDepth + + buf = append(buf, val...) + return buf +} + +func (tlv *SrPceCapability) MarshalLogObject(enc zapcore.ObjectEncoder) error { + return nil +} + +func (tlv *SrPceCapability) Type() uint16 { + return TLV_SR_PCE_CAPABILITY +} + +func (tlv *SrPceCapability) Len() uint16 { + return TLV_SR_PCE_CAPABILITY_LENGTH +} + +func (tlv *SrPceCapability) GetByteLength() uint16 { + return TL_LENGTH + TLV_SR_PCE_CAPABILITY_LENGTH +} + +type Pst uint8 + +const ( + PST_RSVP_TE Pst = 0x0 + PST_SR_TE Pst = 0x1 + PST_PCECC_TE Pst = 0x2 + PST_SRV6_TE Pst = 0x3 +) + +type Psts []Pst + +func (ts Psts) MarshalJSON() ([]byte, error) { + var result string + if ts == nil { + result = "null" + } else { + result = strings.Join(strings.Fields(fmt.Sprintf("%d", ts)), ",") + } + return []byte(result), nil +} + +type PathSetupType struct { + PathSetupType Pst +} + +func (tlv *PathSetupType) DecodeFromBytes(data []uint8) error { + tlv.PathSetupType = Pst(data[7]) + return nil +} + +func (tlv *PathSetupType) Serialize() []uint8 { + buf := []uint8{} + + typ := make([]uint8, 2) + binary.BigEndian.PutUint16(typ, tlv.Type()) + buf = append(buf, typ...) + + length := make([]uint8, 2) + binary.BigEndian.PutUint16(length, tlv.Len()) + buf = append(buf, length...) + + val := make([]uint8, tlv.Len()) + val[3] = uint8(tlv.PathSetupType) + + buf = append(buf, val...) + return buf +} + +func (tlv *PathSetupType) MarshalLogObject(enc zapcore.ObjectEncoder) error { + return nil +} + +func (tlv *PathSetupType) Type() uint16 { + return TLV_PATH_SETUP_TYPE +} + +func (tlv *PathSetupType) Len() uint16 { + return TLV_PATH_SETUP_TYPE_LENGTH +} + +func (tlv *PathSetupType) GetByteLength() uint16 { + return TL_LENGTH + TLV_PATH_SETUP_TYPE_LENGTH +} + +type PathSetupTypeCapability struct { + Length uint16 + PathSetupTypes Psts + SubTlvs []TlvInterface +} + +func (tlv *PathSetupTypeCapability) DecodeFromBytes(data []uint8) error { + tlv.Length = binary.BigEndian.Uint16(data[2:4]) + + pstNum := int(data[7]) + for i := 0; i < pstNum; i++ { + tlv.PathSetupTypes = append(tlv.PathSetupTypes, Pst(data[8+i])) + } + + if pstNum%4 != 0 { + pstNum += 4 - (pstNum % 4) // padding byte + } + var err error + tlv.SubTlvs, err = DecodeTLVs(data[8+pstNum : TL_LENGTH+tlv.Length]) // 8 byte: Type&Length (4 byte) + Reserve&pstNum (4 byte) + if err != nil { + return err + } + return nil +} + +func (tlv *PathSetupTypeCapability) Serialize() []uint8 { + buf := []uint8{} + + typ := make([]uint8, 2) + binary.BigEndian.PutUint16(typ, tlv.Type()) + buf = append(buf, typ...) + + length := make([]uint8, 2) + binary.BigEndian.PutUint16(length, tlv.Len()) + buf = append(buf, length...) + + pstNum := uint8(len(tlv.PathSetupTypes)) + + var val []uint8 + if pstNum%4 == 0 { + val = make([]uint8, 4+pstNum) // 4 byte: Reserve & Num of PST + + } else { + val = make([]uint8, 4+pstNum+(4-(pstNum%4))) // 4 byte: Reserve & Num of PST + } + + val[3] = pstNum + for i, pst := range tlv.PathSetupTypes { + val[4+i] = uint8(pst) + } + + for _, subTlv := range tlv.SubTlvs { + val = append(val, subTlv.Serialize()...) + } + buf = append(buf, val...) + return buf +} + +func (tlv *PathSetupTypeCapability) MarshalLogObject(enc zapcore.ObjectEncoder) error { + return nil +} + +func (tlv *PathSetupTypeCapability) Type() uint16 { + return TLV_PATH_SETUP_TYPE_CAPABILITY +} + +func (tlv *PathSetupTypeCapability) Len() uint16 { + return tlv.Length +} + +func (tlv *PathSetupTypeCapability) GetByteLength() uint16 { + return TL_LENGTH + tlv.Length +} + +type AssocType uint16 + +const ( + AT_RESERVED AssocType = 0x00 + AT_PATH_PROTECTION_ASSOCIATION AssocType = 0x01 + AT_DISCOINT_ASSOCIATION AssocType = 0x02 + AT_POLICY_ASSOCIATION AssocType = 0x03 + AT_SINGLE_SIDED_BIDIRECTIONAL_LSP_ASSOCIATION AssocType = 0x04 + AT_DOUBLE_SIDED_BIDIRECTIONAL_LSP_ASSOCIATION AssocType = 0x05 + AT_SR_POLICY_ASSOCIATION AssocType = 0x06 + AT_VN_ASSOCIATION_TYPE AssocType = 0x07 +) + +type AssocTypeList struct { + AssocTypes []AssocType +} + +func (tlv *AssocTypeList) DecodeFromBytes(data []uint8) error { + AssocTypeNum := binary.BigEndian.Uint16(data[2:4]) / 2 + fmt.Printf("ASOC NUM: %d\n", AssocTypeNum) + for i := 0; i < int(AssocTypeNum); i++ { + fmt.Printf("aaa\n") + at := binary.BigEndian.Uint16(data[4+2*i : 6+2*i]) + tlv.AssocTypes = append(tlv.AssocTypes, AssocType(at)) + } + return nil +} + +func (tlv *AssocTypeList) Serialize() []uint8 { + buf := []uint8{} + + typ := make([]uint8, 2) + binary.BigEndian.PutUint16(typ, tlv.Type()) + buf = append(buf, typ...) + + length := make([]uint8, 2) + binary.BigEndian.PutUint16(length, tlv.Len()) + buf = append(buf, length...) + + for _, at := range tlv.AssocTypes { + binAt := make([]uint8, 2) + binary.BigEndian.PutUint16(binAt, uint16(at)) + buf = append(buf, binAt...) + } + fmt.Printf("len: %d\n", tlv.Len()) + if tlv.Len()%4 != 0 { + + fmt.Printf("len: %d\n", tlv.Len()%4) + pad := make([]uint8, 4-(tlv.Len()%4)) + buf = append(buf, pad...) + } + return buf +} + +func (tlv *AssocTypeList) MarshalLogObject(enc zapcore.ObjectEncoder) error { + return nil +} + +func (tlv *AssocTypeList) Type() uint16 { + return TLV_ASSOC_TYPE_LIST +} + +func (tlv *AssocTypeList) Len() uint16 { + return uint16(len(tlv.AssocTypes)) * 2 +} +func (tlv *AssocTypeList) GetByteLength() uint16 { + if tlv.Len()%4 == 0 { + return TL_LENGTH + tlv.Len() + } else { + return TL_LENGTH + tlv.Len() + 2 // padding + } +} + +type UndefinedTlv struct { + Typ uint16 + Length uint16 + Value []uint8 +} + +func (tlv *UndefinedTlv) DecodeFromBytes(data []uint8) error { + tlv.Typ = binary.BigEndian.Uint16(data[0:2]) + tlv.Length = binary.BigEndian.Uint16(data[2:4]) + + tlv.Value = data[4 : 4+tlv.Length] + return nil +} + +func (tlv *UndefinedTlv) Serialize() []uint8 { + bytePcepTLV := []uint8{} + + byteTlvType := make([]uint8, 2) + binary.BigEndian.PutUint16(byteTlvType, tlv.Typ) + bytePcepTLV = append(bytePcepTLV, byteTlvType...) // Type (2byte) + + byteTlvLength := make([]uint8, 2) + binary.BigEndian.PutUint16(byteTlvLength, tlv.Length) + bytePcepTLV = append(bytePcepTLV, byteTlvLength...) // Length (2byte) + + bytePcepTLV = append(bytePcepTLV, tlv.Value...) // Value (Length byte) + if padding := tlv.Length % 4; padding != 0 { + bytePadding := make([]uint8, 4-padding) + bytePcepTLV = append(bytePcepTLV, bytePadding...) + } + return bytePcepTLV +} + +func (c *UndefinedTlv) MarshalLogObject(enc zapcore.ObjectEncoder) error { + return nil +} + +func (tlv *UndefinedTlv) Type() uint16 { + return tlv.Typ +} + +func (tlv *UndefinedTlv) Len() uint16 { + return tlv.Length +} + +func (tlv *UndefinedTlv) GetByteLength() uint16 { + if tlv.Len()%4 == 0 { + return TL_LENGTH + tlv.Len() + } else { + return TL_LENGTH + tlv.Len() + (4 - tlv.Len()%4) // padding + } +} + +func (tlv *UndefinedTlv) SetLength() { + tlv.Length = uint16(len(tlv.Value)) +} + +func DecodeTLV(data []uint8) (TlvInterface, error) { + var tlv TlvInterface + switch binary.BigEndian.Uint16(data[0:2]) { + case TLV_STATEFUL_PCE_CAPABILITY: + tlv = &StatefulPceCapability{} + + case TLV_SYMBOLIC_PATH_NAME: + tlv = &SymbolicPathName{} + + case TLV_IPV4_LSP_IDENTIFIERS: + tlv = &IPv4LspIdentifiers{} + + case TLV_SR_PCE_CAPABILITY: + tlv = &SrPceCapability{} + case TLV_PATH_SETUP_TYPE: + tlv = &PathSetupType{} + + case TLV_PATH_SETUP_TYPE_CAPABILITY: + tlv = &PathSetupTypeCapability{} + + case TLV_ASSOC_TYPE_LIST: + tlv = &AssocTypeList{} + + default: + tlv = &UndefinedTlv{} + } + if err := tlv.DecodeFromBytes(data); err != nil { + return nil, err + } + return tlv, nil +} + +func DecodeTLVs(data []uint8) ([]TlvInterface, error) { + tlvs := []TlvInterface{} + var tlv TlvInterface + var err error + + for { + if tlv, err = DecodeTLV(data); err != nil { + return nil, err + } + tlvs = append(tlvs, tlv) + if int(tlv.GetByteLength()) < len(data) { + data = data[tlv.GetByteLength():] + } else if int(tlv.GetByteLength()) == len(data) { + break + } else { + return nil, errors.New("tlvs decode error") + } + } + return tlvs, nil +} diff --git a/pkg/server/session.go b/pkg/server/session.go index a4762f6..5a9c420 100644 --- a/pkg/server/session.go +++ b/pkg/server/session.go @@ -6,7 +6,6 @@ package server import ( - "encoding/binary" "fmt" "net" "net/netip" @@ -18,17 +17,17 @@ import ( "go.uber.org/zap" ) -const KEEPALIVE uint8 = 30 - type Session struct { - sessionId uint8 - peerAddr netip.Addr - tcpConn *net.TCPConn - isSynced bool - srpIdHead uint32 // 0x00000000 and 0xFFFFFFFF are reserved. - srPolicies []table.SRPolicy - logger *zap.Logger - pccType pcep.PccType + sessionId uint8 + peerAddr netip.Addr + tcpConn *net.TCPConn + isSynced bool + srpIdHead uint32 // 0x00000000 and 0xFFFFFFFF are reserved. + srPolicies []table.SRPolicy + logger *zap.Logger + keepAlive uint8 + pccType pcep.PccType + pccCapabilities []pcep.CapabilityInterface } func NewSession(sessionId uint8, logger *zap.Logger) *Session { @@ -58,12 +57,12 @@ func (ss *Session) Established() { defer close(closeChan) go func() { if err := ss.ReceivePcepMessage(); err != nil { - ss.logger.Info("Receive PCEP error", zap.String("session", ss.peerAddr.String())) + ss.logger.Info("Receive PCEP Message error", zap.String("session", ss.peerAddr.String()), zap.Error(err)) } closeChan <- true }() - ticker := time.NewTicker(time.Duration(KEEPALIVE) * time.Second) + ticker := time.NewTicker(time.Duration(ss.keepAlive) * time.Second) defer ticker.Stop() for { select { @@ -114,36 +113,21 @@ func (ss *Session) ReceiveOpen() error { if _, err := ss.tcpConn.Read(byteOpenObject); err != nil { return err } - var openMessage pcep.OpenMessage if err := openMessage.DecodeFromBytes(byteOpenObject); err != nil { return err } - - // TODO: Parse OPEN Object + ss.pccCapabilities = append(ss.pccCapabilities, openMessage.OpenObject.Caps...) // pccType detection // * FRRouting cannot be detected from the open message, so it is treated as an RFC compliant - for _, openObjTlv := range openMessage.OpenObject.Tlvs { - if openObjTlv.Type != pcep.TLV_ASSOC_TYPE_LIST { - continue - } - for i, v := 0, openObjTlv.Value; i < int(openObjTlv.Length)/2; i++ { // - if binary.BigEndian.Uint16(v) == uint16(20) { // Cisco specific Assoc-Type - ss.pccType = pcep.CISCO_LEGACY - break - } else if binary.BigEndian.Uint16(v) == uint16(65505) { // Juniper specific Assoc-Type - ss.pccType = pcep.JUNIPER_LEGACY - break - } - v = v[2:] - } - } + ss.pccType = pcep.DeterminePccType(ss.pccCapabilities) + ss.keepAlive = openMessage.OpenObject.Keepalive return nil } func (ss *Session) SendOpen() error { - openMessage, err := pcep.NewOpenMessage(ss.sessionId, KEEPALIVE) + openMessage, err := pcep.NewOpenMessage(ss.sessionId, ss.keepAlive, ss.pccCapabilities) if err != nil { return err }