diff options
author | Serguei Bezverkhi <sbezverk@cisco.com> | 2020-05-06 15:44:17 -0400 |
---|---|---|
committer | Serguei Bezverkhi <sbezverk@cisco.com> | 2020-05-06 15:44:17 -0400 |
commit | 9251c7a7c0ce93c3365090a79146151c4294e393 (patch) | |
tree | 9128b2456f6dd2002d35de1bf6b7cff9df1fa04e /pkg/packet/bgp/prefix_sid.go | |
parent | cd4b9c5b0abfbe73fc7ffc63725a758b7242d759 (diff) |
code Decode and Serialize for Prefix SID types and add unit tests
Signed-off-by: Serguei Bezverkhi <sbezverk@cisco.com>
Diffstat (limited to 'pkg/packet/bgp/prefix_sid.go')
-rw-r--r-- | pkg/packet/bgp/prefix_sid.go | 370 |
1 files changed, 173 insertions, 197 deletions
diff --git a/pkg/packet/bgp/prefix_sid.go b/pkg/packet/bgp/prefix_sid.go index f096a8de..1642b87f 100644 --- a/pkg/packet/bgp/prefix_sid.go +++ b/pkg/packet/bgp/prefix_sid.go @@ -5,8 +5,10 @@ import ( "encoding/binary" "encoding/json" "fmt" +) - "github.com/golang/glog" +const ( + prefixSIDtlvHdrLen = 4 ) // PrefixSIDTLVInterface defines standard set of methods to handle Prefix SID attribute's TLVs @@ -23,46 +25,53 @@ type PathAttributePrefixSID struct { TLVs []PrefixSIDTLVInterface } -type PrefixSIDTLVType uint8 +type TLVType uint8 -type PrefixSIDTLV struct { - Type PrefixSIDTLVType - Length uint16 +type TLV struct { + Type TLVType + Length uint16 + Reserved uint8 } -func (s *PrefixSIDTLV) Len() int { - return int(s.Length) + tlvHdrLen +func (s *TLV) Len() int { + return int(s.Length) + tlvHdrLen - 1 } -func (s *PrefixSIDTLV) Serialize(value []byte) ([]byte, error) { - if len(value) != int(s.Length) { +func (s *TLV) Serialize(value []byte) ([]byte, error) { + if len(value) != int(s.Length)-1 { return nil, malformedAttrListErr("serialization failed: Prefix SID TLV malformed") } - - buf := make([]byte, tlvHdrLen+len(value)) - binary.BigEndian.PutUint16(buf[:2], uint16(s.Type)) - binary.BigEndian.PutUint16(buf[2:4], uint16(s.Length)) - copy(buf[4:], value) + buf := make([]byte, prefixSIDtlvHdrLen+len(value)) + p := 0 + buf[p] = byte(s.Type) + p++ + binary.BigEndian.PutUint16(buf[p:p+2], uint16(s.Length)) + p += 2 + // Reserved byte + p++ + copy(buf[p:], value) return buf, nil } -func (s *PrefixSIDTLV) DecodeFromBytes(data []byte) ([]byte, error) { - if len(data) < tlvHdrLen { +func (s *TLV) DecodeFromBytes(data []byte) ([]byte, error) { + if len(data) < prefixSIDtlvHdrLen { return nil, malformedAttrListErr("decoding failed: Prefix SID TLV malformed") } - s.Type = PrefixSIDTLVType(binary.BigEndian.Uint16(data[:2])) - s.Length = binary.BigEndian.Uint16(data[2:4]) + p := 0 + s.Type = TLVType(data[p]) + p++ + s.Length = binary.BigEndian.Uint16(data[p : p+2]) if len(data) < s.Len() { return nil, malformedAttrListErr("decoding failed: Prefix SID TLV malformed") } - return data[tlvHdrLen:s.Len()], nil + return data[prefixSIDtlvHdrLen:s.Len()], nil } type PrefixSIDAttribute struct { - PrefixSIDTLV + TLV TLVs []PrefixSIDTLVInterface } @@ -72,9 +81,8 @@ func (p *PathAttributePrefixSID) DecodeFromBytes(data []byte, options ...*Marsha return err } - glog.Infof("><SB> tlvs: %+v", tlvs) - for len(tlvs) >= tlvHdrLen { - t := &PrefixSIDTLV{} + for len(tlvs) >= prefixSIDtlvHdrLen { + t := &TLV{} _, err := t.DecodeFromBytes(tlvs) if err != nil { return err @@ -83,7 +91,9 @@ func (p *PathAttributePrefixSID) DecodeFromBytes(data []byte, options ...*Marsha var tlv PrefixSIDTLVInterface switch t.Type { case 5: - tlv = &PrefixSIDType5{} + tlv = &PrefixSIDType5{ + ServiceTLVs: make([]PrefixSIDTLVInterface, 0), + } default: tlvs = tlvs[t.Len():] continue @@ -100,8 +110,7 @@ func (p *PathAttributePrefixSID) DecodeFromBytes(data []byte, options ...*Marsha } func (p *PathAttributePrefixSID) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := []byte{} - + buf := make([]byte, 0) for _, tlv := range p.TLVs { s, err := tlv.Serialize() if err != nil { @@ -120,7 +129,7 @@ func (p *PathAttributePrefixSID) String() string { buf.WriteString(fmt.Sprintf("%s ", tlv.String())) } - return fmt.Sprintf("{LsAttributes: %s}", buf.String()) + return fmt.Sprintf("{Prefix SID attributes: %s}", buf.String()) } func (p *PathAttributePrefixSID) MarshalJSON() ([]byte, error) { @@ -131,45 +140,63 @@ func (p *PathAttributePrefixSID) MarshalJSON() ([]byte, error) { }{ p.GetType(), p.GetFlags(), + // TODO sbezverk PrefixSIDAttribute{}, }) } // PrefixSIDType5 defines the structure of type PrefixSIDType5 struct { - PrefixSIDTLV + TLV ServiceTLVs []PrefixSIDTLVInterface } func (s *PrefixSIDType5) Len() int { - return int(s.Length) + tlvHdrLen + return int(s.Length) + prefixSIDtlvHdrLen } func (s *PrefixSIDType5) Serialize() ([]byte, error) { - // if len(value) != int(s.Length) { - // return nil, malformedAttrListErr("serialization failed: Prefix SID TLV malformed") - // } - - // buf := make([]byte, tlvHdrLen+len(value)) - // binary.BigEndian.PutUint16(buf[:2], uint16(s.Type)) - // binary.BigEndian.PutUint16(buf[2:4], uint16(s.Length)) - // copy(buf[4:], value) - - // return buf, nil - return nil, nil + buf := make([]byte, 0) + for _, tlv := range s.ServiceTLVs { + s, err := tlv.Serialize() + if err != nil { + return nil, err + } + buf = append(buf, s...) + } + return s.TLV.Serialize(buf) } func (s *PrefixSIDType5) DecodeFromBytes(data []byte) error { - if len(data) < tlvHdrLen { - return malformedAttrListErr("decoding failed: Prefix SID TLV malformed") + stlvs, err := s.TLV.DecodeFromBytes(data) + if err != nil { + return err } - s.Type = PrefixSIDTLVType(binary.BigEndian.Uint16(data[:2])) - s.Length = binary.BigEndian.Uint16(data[2:4]) - if len(data) < s.Len() { - return malformedAttrListErr("decoding failed: Prefix SID TLV malformed") + for len(stlvs) >= subTLVHdrLen { + t := &SubTLV{} + _, err := t.DecodeFromBytes(stlvs) + if err != nil { + return err + } + + var stlv PrefixSIDTLVInterface + switch t.Type { + case 1: + stlv = &SRv6InformationSubTLV{ + SubSubTLVs: make([]PrefixSIDTLVInterface, 0), + } + default: + data = data[t.Len():] + continue + } + + if err := stlv.DecodeFromBytes(stlvs); err != nil { + return err + } + stlvs = stlvs[t.Len():] + s.ServiceTLVs = append(s.ServiceTLVs, stlv) } - glog.Infof("><SB> PrefixSIDType5 %+v", data) return nil } @@ -186,190 +213,139 @@ func (s *PrefixSIDType5) Extract() string { return "" } -type SRv6ServiceSubTLV struct { - PrefixSIDTLV - TLV []PrefixSIDTLVInterface -} +const ( + subTLVHdrLen = 3 +) + +type SubTLVType uint8 -func (s *SRv6ServiceSubTLV) Len() int { - return int(s.Length) + tlvHdrLen +type SubTLV struct { + Type SubTLVType + Length uint16 } -func (s *SRv6ServiceSubTLV) Serialize() ([]byte, error) { - // if len(value) != int(s.Length) { - // return nil, malformedAttrListErr("serialization failed: Prefix SID TLV malformed") - // } +func (s *SubTLV) Len() int { + return int(s.Length) + subTLVHdrLen +} - // buf := make([]byte, tlvHdrLen+len(value)) - // binary.BigEndian.PutUint16(buf[:2], uint16(s.Type)) - // binary.BigEndian.PutUint16(buf[2:4], uint16(s.Length)) - // copy(buf[4:], value) +func (s *SubTLV) Serialize(value []byte) ([]byte, error) { + if len(value) != int(s.Length) { + return nil, malformedAttrListErr("serialization failed: Prefix SID TLV malformed") + } + // Extra byte is reserved + buf := make([]byte, subTLVHdrLen+len(value)) + buf[0] = byte(s.Type) + binary.BigEndian.PutUint16(buf[1:4], uint16(s.Length)) + // 4th reserved byte + copy(buf[4:], value) - // return buf, nil - return nil, nil + return buf, nil } -func (s *SRv6ServiceSubTLV) DecodeFromBytes(data []byte) error { - if len(data) < tlvHdrLen { - return malformedAttrListErr("decoding failed: Prefix SID TLV malformed") +func (s *SubTLV) DecodeFromBytes(data []byte) ([]byte, error) { + if len(data) < subTLVHdrLen { + return nil, malformedAttrListErr("decoding failed: Prefix SID TLV malformed") } - s.Type = PrefixSIDTLVType(binary.BigEndian.Uint16(data[:2])) - s.Length = binary.BigEndian.Uint16(data[2:4]) + s.Type = SubTLVType(data[0]) + s.Length = binary.BigEndian.Uint16(data[1:3]) if len(data) < s.Len() { - return malformedAttrListErr("decoding failed: Prefix SID TLV malformed") + return nil, malformedAttrListErr("decoding failed: Prefix SID TLV malformed") } - return nil -} - -func (s *SRv6ServiceSubTLV) MarshalJSON() ([]byte, error) { - return nil, nil -} - -func (s *SRv6ServiceSubTLV) String() string { - return "" + return data[subTLVHdrLen:s.Len()], nil } // SRv6InformationSubTLV defines a structure of SRv6 Information Sub TLV (type 1) object // https://tools.ietf.org/html/draft-dawra-bess-srv6-services-02#section-2.1.1 type SRv6InformationSubTLV struct { - PrefixSIDTLV + SubTLV SID []byte Flags uint8 EndpointBehavior uint16 - SubSubTLV []PrefixSIDTLVInterface -} - -type SRv6SubSubTLV struct { - PrefixSIDTLV - TLV []PrefixSIDTLVInterface -} - -func (s *SRv6SubSubTLV) Len() int { - return int(s.Length) + tlvHdrLen -} - -func (s *SRv6SubSubTLV) Serialize() ([]byte, error) { - s. - if len(value) != int(s.Length) { - return nil, malformedAttrListErr("serialization failed: Prefix SID TLV malformed") + SubSubTLVs []PrefixSIDTLVInterface +} + +func (s *SRv6InformationSubTLV) Len() int { + return int(s.Length) + subTLVHdrLen +} + +func (s *SRv6InformationSubTLV) Serialize() ([]byte, error) { + buf := make([]byte, s.Length) + p := 0 + copy(buf[p:], s.SID) + p += len(s.SID) + buf[p] = byte(s.Flags) + p++ + binary.BigEndian.PutUint16(buf[p:p+2], uint16(s.EndpointBehavior)) + p += 2 + // Reserved byte + buf[p] = 0x0 + p++ + for _, sstlv := range s.SubSubTLVs { + sbuf, err := sstlv.Serialize() + if err != nil { + return nil, err } + copy(buf[p:], sbuf) + p += len(sbuf) + } - buf := make([]byte, tlvHdrLen+len(value)) - binary.BigEndian.PutUint16(buf[:2], uint16(s.Type)) - binary.BigEndian.PutUint16(buf[2:4], uint16(s.Length)) - copy(buf[4:], value) - - return buf, nil - return nil, nil + return s.SubTLV.Serialize(buf) } -func (s *SRv6SubSubTLV) DecodeFromBytes(data []byte) error { - if len(data) < tlvHdrLen { +func (s *SRv6InformationSubTLV) DecodeFromBytes(data []byte) error { + if len(data) < subTLVHdrLen { return malformedAttrListErr("decoding failed: Prefix SID TLV malformed") } - s.Type = PrefixSIDTLVType(binary.BigEndian.Uint16(data[:2])) - s.Length = binary.BigEndian.Uint16(data[2:4]) + s.Type = SubTLVType(data[0]) + s.Length = binary.BigEndian.Uint16(data[1:3]) + // 4th reserved byte + p := 4 + s.SID = make([]byte, 16) + copy(s.SID, data[p:p+16]) + p += 16 + s.Flags = uint8(data[p]) + p++ + s.EndpointBehavior = binary.BigEndian.Uint16(data[p : p+2]) + p += 2 + // reserved byte + p++ + if p+3 > len(data) { + // There is no Sub Sub TLVs detected, returning + return nil + } + stlvs := data[p:] + for len(stlvs) >= prefixSIDtlvHdrLen { + t := &SubSubTLV{} + _, err := t.DecodeFromBytes(stlvs) + if err != nil { + return err + } - if len(data) < s.Len() { - return malformedAttrListErr("decoding failed: Prefix SID TLV malformed") + var sstlv PrefixSIDTLVInterface + switch t.Type { + case 1: + sstlv = &SRv6SIDStructureSubSubTLV{} + default: + stlvs = stlvs[t.Len():] + continue + } + + if err := sstlv.DecodeFromBytes(stlvs); err != nil { + return err + } + stlvs = stlvs[t.Len():] + s.SubSubTLVs = append(s.SubSubTLVs, sstlv) } return nil } -func (s *SRv6SubSubTLV) MarshalJSON() ([]byte, error) { +func (s *SRv6InformationSubTLV) MarshalJSON() ([]byte, error) { return nil, nil } -func (s *SRv6SubSubTLV) String() string { +func (s *SRv6InformationSubTLV) String() string { return "" } - -// SRv6SIDStructureSubSubTLV defines a structure of SRv6 SID Structure Sub Sub TLV (type 1) object -// https://tools.ietf.org/html/draft-dawra-bess-srv6-services-02#section-2.1.2.1 -type SRv6SIDStructureSubSubTLV struct { - PrefixSIDTLV - LocalBlockLength uint8 `json:"local_block_length,omitempty"` - LocatorNodeLength uint8 `json:"locator_node_length,omitempty"` - FunctionLength uint8 `json:"function_length,omitempty"` - ArgumentLength uint8 `json:"argument_length,omitempty"` - TranspositionLength uint8 `json:"transposition_length,omitempty"` - TranspositionOffset uint8 `json:"transposition_offset,omitempty"` -} - - - -///////////////////////////// -// type LsTLVAdjacencySID struct { -// LsTLV -// Flags uint8 -// Weight uint8 -// SID uint32 -// } - -// func (l *LsTLVAdjacencySID) DecodeFromBytes(data []byte) error { -// value, err := l.LsTLV.DecodeFromBytes(data) -// if err != nil { -// return err -// } - -// if l.Type != LS_TLV_ADJACENCY_SID { -// return malformedAttrListErr("Unexpected TLV type") -// } - -// // https://tools.ietf.org/html/draft-ietf-idr-bgp-ls-segment-routing-ext-08#section-2.2.1 -// if len(value) != 7 && len(value) != 8 { -// return malformedAttrListErr("Incorrect Adjacency SID length") -// } - -// l.Flags = value[0] -// l.Weight = value[1] - -// v := value[4:] -// if len(v) == 4 { -// l.SID = binary.BigEndian.Uint32(v) -// } else { -// buf := []byte{0, 0, 0, 0} -// for i := 1; i < len(buf); i++ { -// buf[i] = v[i-1] -// } -// // Label is represented by 20 rightmost bits. -// l.SID = binary.BigEndian.Uint32(buf) & 0xfffff -// } - -// return nil -// } - -// func (l *LsTLVAdjacencySID) Serialize() ([]byte, error) { -// buf := make([]byte, 0) -// buf = append(buf, l.Flags) -// buf = append(buf, l.Weight) -// // Reserved -// buf = append(buf, []byte{0, 0}...) - -// var b [4]byte -// binary.BigEndian.PutUint32(b[:4], l.SID) - -// if l.Length == 7 { -// return l.LsTLV.Serialize(append(buf, b[1:]...)) -// } - -// return l.LsTLV.Serialize(append(buf, b[:]...)) -// } - -// func (l *LsTLVAdjacencySID) String() string { -// return fmt.Sprintf("{Adjacency SID: %v}", l.SID) -// } - -// func (l *LsTLVAdjacencySID) MarshalJSON() ([]byte, error) { -// return json.Marshal(struct { -// Type LsTLVType `json:"type"` -// SID uint32 `json:"adjacency_sid"` -// }{ -// Type: l.Type, -// SID: l.SID, -// }) -// } -//////////////////////////////////////
\ No newline at end of file |