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 | |
parent | cd4b9c5b0abfbe73fc7ffc63725a758b7242d759 (diff) |
code Decode and Serialize for Prefix SID types and add unit tests
Signed-off-by: Serguei Bezverkhi <sbezverk@cisco.com>
-rw-r--r-- | go.mod | 1 | ||||
-rw-r--r-- | go.sum | 4 | ||||
-rw-r--r-- | pkg/packet/bgp/bgp.go | 6 | ||||
-rw-r--r-- | pkg/packet/bgp/prefix_sid.go | 370 | ||||
-rw-r--r-- | pkg/packet/bgp/prefix_sid_sstlv.go | 107 | ||||
-rw-r--r-- | pkg/packet/bgp/prefix_sid_sstlv_test.go | 33 | ||||
-rw-r--r-- | pkg/packet/bgp/prefix_sid_stlv_test.go | 33 | ||||
-rw-r--r-- | pkg/packet/bgp/prefix_sid_test.go | 29 |
8 files changed, 376 insertions, 207 deletions
@@ -21,6 +21,7 @@ require ( github.com/pelletier/go-buffruneio v0.2.0 // indirect github.com/pelletier/go-toml v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/sbezverk/gobmp/pkg/tools v0.0.0-20200506032342-04944823ac3f github.com/sirupsen/logrus v0.0.0-20170713114250-a3f95b5c4235 github.com/spf13/afero v0.0.0-20170217164146-9be650865eab // indirect github.com/spf13/cast v1.1.0 // indirect @@ -12,6 +12,7 @@ github.com/eapache/queue v1.0.2 h1:jRJXCx6uciOfN69MfZCC9EZlGRqqHhwlyb6GBeNow+c= github.com/eapache/queue v1.0.2/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/fsnotify/fsnotify v1.4.2 h1:v5tKwtf2hNhBV24eNYfQ5UmvFOGlOCmRqk7/P1olxtk= github.com/fsnotify/fsnotify v1.4.2/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-test/deep v1.0.5/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/protobuf v1.0.0 h1:lsek0oXi8iFE9L+EXARyHIjU5rlWIhhTkjDz3vHhWWQ= @@ -44,6 +45,9 @@ github.com/pelletier/go-toml v1.0.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sbezverk/gobmp v0.0.0-20200506032342-04944823ac3f h1:nfQdt9K+bxggu50Lsd/7SozAY8Y6OPqvZdinycjI6S4= +github.com/sbezverk/gobmp/pkg/tools v0.0.0-20200506032342-04944823ac3f h1:li6T1EkByRuwm5oCyFHpdu1uZkQCRZKljIEiCVUMEz0= +github.com/sbezverk/gobmp/pkg/tools v0.0.0-20200506032342-04944823ac3f/go.mod h1:XY3q43hOXcF64qjFKhFahQbrYSHm8jGK8gubrsumfE4= github.com/sirupsen/logrus v0.0.0-20170713114250-a3f95b5c4235 h1:a2XWU6egUZQhD52o2GEKr79zE+OuZmwLybyOQpoqhHQ= github.com/sirupsen/logrus v0.0.0-20170713114250-a3f95b5c4235/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/spf13/afero v0.0.0-20170217164146-9be650865eab h1:IVAbBHQR8rXL2Fc8Zba/lMF7KOnTi70lqdx91UTuAwQ= diff --git a/pkg/packet/bgp/bgp.go b/pkg/packet/bgp/bgp.go index b35981c4..d60f3d36 100644 --- a/pkg/packet/bgp/bgp.go +++ b/pkg/packet/bgp/bgp.go @@ -28,6 +28,9 @@ import ( "sort" "strconv" "strings" + + "github.com/golang/glog" + "github.com/sbezverk/gobmp/pkg/tools" ) type MarshallingOption struct { @@ -8285,7 +8288,7 @@ const ( _ BGP_ATTR_TYPE_LS // = 29 BGP_ATTR_TYPE_LARGE_COMMUNITY BGPAttrType = 32 - BGP_ATTR_TYPE_PREFIX_SID = 40 + BGP_ATTR_TYPE_PREFIX_SID BGPAttrType = 40 ) // NOTIFICATION Error Code RFC 4271 4.5. @@ -12375,6 +12378,7 @@ func GetPathAttribute(data []byte) (PathAttributeInterface, error) { case BGP_ATTR_TYPE_LS: return &PathAttributeLs{}, nil case BGP_ATTR_TYPE_PREFIX_SID: + glog.Infof("Prefix SID RAW: %s", tools.MessageHex(data)) return &PathAttributePrefixSID{}, nil } return &PathAttributeUnknown{}, nil 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 diff --git a/pkg/packet/bgp/prefix_sid_sstlv.go b/pkg/packet/bgp/prefix_sid_sstlv.go new file mode 100644 index 00000000..14ff621a --- /dev/null +++ b/pkg/packet/bgp/prefix_sid_sstlv.go @@ -0,0 +1,107 @@ +package bgp + +import "encoding/binary" + +const ( + subSubTLVHdrLen = 3 +) + +type SubSubTLVType uint8 + +type SubSubTLV struct { + Type SubSubTLVType + Length uint16 +} + +func (s *SubSubTLV) Len() int { + return int(s.Length) + subSubTLVHdrLen +} + +func (s *SubSubTLV) 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, subSubTLVHdrLen+len(value)) + p := 0 + buf[p] = byte(s.Type) + p++ + binary.BigEndian.PutUint16(buf[p:p+2], uint16(s.Length)) + p += 2 + copy(buf[p:], value) + + return buf, nil +} + +func (s *SubSubTLV) DecodeFromBytes(data []byte) ([]byte, error) { + if len(data) < prefixSIDtlvHdrLen { + return nil, malformedAttrListErr("decoding failed: Prefix SID Sub Sub TLV malformed") + } + s.Type = SubSubTLVType(data[0]) + s.Length = binary.BigEndian.Uint16(data[1:3]) + + if len(data) < s.Len() { + return nil, malformedAttrListErr("decoding failed: Prefix SID Sub Sub TLV malformed") + } + + return data[prefixSIDtlvHdrLen:s.Len()], nil +} + +// 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 { + SubSubTLV + 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"` +} + +func (s *SRv6SIDStructureSubSubTLV) Len() int { + return int(s.Length) + subSubTLVHdrLen +} + +func (s *SRv6SIDStructureSubSubTLV) Serialize() ([]byte, error) { + buf := make([]byte, s.Length) + p := 0 + buf[p] = s.LocalBlockLength + p++ + buf[p] = s.LocatorNodeLength + p++ + buf[p] = s.FunctionLength + p++ + buf[p] = s.ArgumentLength + p++ + buf[p] = s.TranspositionLength + p++ + buf[p] = s.TranspositionOffset + + return s.SubSubTLV.Serialize(buf) +} + +func (s *SRv6SIDStructureSubSubTLV) DecodeFromBytes(data []byte) error { + if len(data) < subSubTLVHdrLen { + return malformedAttrListErr("decoding failed: Prefix SID Sub Sub TLV malformed") + } + s.Type = SubSubTLVType(data[0]) + s.Length = binary.BigEndian.Uint16(data[1:3]) + + s.LocalBlockLength = data[3] + s.LocatorNodeLength = data[4] + s.FunctionLength = data[5] + s.ArgumentLength = data[6] + s.TranspositionLength = data[7] + s.TranspositionOffset = data[8] + + return nil +} + +func (s *SRv6SIDStructureSubSubTLV) MarshalJSON() ([]byte, error) { + return nil, nil +} + +func (s *SRv6SIDStructureSubSubTLV) String() string { + return "" +} diff --git a/pkg/packet/bgp/prefix_sid_sstlv_test.go b/pkg/packet/bgp/prefix_sid_sstlv_test.go new file mode 100644 index 00000000..478ee431 --- /dev/null +++ b/pkg/packet/bgp/prefix_sid_sstlv_test.go @@ -0,0 +1,33 @@ +package bgp + +import ( + "bytes" + "testing" +) + +func TestRoundTripSubSubTLV(t *testing.T) { + tests := []struct { + name string + input []byte + }{ + { + name: "SRv6SIDStructureSubSubTLV", + input: []byte{0x01, 0x00, 0x06, 0x28, 0x18, 0x10, 0x00, 0x10, 0x40}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + sstlv := &SRv6SIDStructureSubSubTLV{} + if err := sstlv.DecodeFromBytes(tt.input); err != nil { + t.Fatalf("test failed with error: %+v", err) + } + recovered, err := sstlv.Serialize() + if err != nil { + t.Fatalf("test failed with error: %+v", err) + } + if bytes.Compare(tt.input, recovered) != 0 { + t.Fatalf("round trip conversion test failed as expected prefix sid attribute %+v does not match actual: %+v", tt.input, recovered) + } + }) + } +} diff --git a/pkg/packet/bgp/prefix_sid_stlv_test.go b/pkg/packet/bgp/prefix_sid_stlv_test.go new file mode 100644 index 00000000..b4f19d5b --- /dev/null +++ b/pkg/packet/bgp/prefix_sid_stlv_test.go @@ -0,0 +1,33 @@ +package bgp + +import ( + "bytes" + "testing" +) + +func TestRoundTripSubTLV(t *testing.T) { + tests := []struct { + name string + input []byte + }{ + { + name: "SRv6InformationSubTLV", + input: []byte{0x01, 0x00, 0x1e, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x01, 0x00, 0x06, 0x28, 0x18, 0x10, 0x00, 0x10, 0x40}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + stlv := &SRv6InformationSubTLV{} + if err := stlv.DecodeFromBytes(tt.input); err != nil { + t.Fatalf("test failed with error: %+v", err) + } + recovered, err := stlv.Serialize() + if err != nil { + t.Fatalf("test failed with error: %+v", err) + } + if bytes.Compare(tt.input, recovered) != 0 { + t.Fatalf("round trip conversion test failed as expected prefix sid attribute %+v does not match actual: %+v", tt.input, recovered) + } + }) + } +} diff --git a/pkg/packet/bgp/prefix_sid_test.go b/pkg/packet/bgp/prefix_sid_test.go index 84f1312f..6457c8df 100644 --- a/pkg/packet/bgp/prefix_sid_test.go +++ b/pkg/packet/bgp/prefix_sid_test.go @@ -1,24 +1,35 @@ package bgp import ( - "reflect" + "bytes" "testing" ) -func TestUnmarshalUnicastNLRI(t *testing.T) { +func TestRoundTripPrefixSID(t *testing.T) { tests := []struct { - name string - input []byte - expect *PathAttributePrefixSID - }{} + name string + input []byte + }{ + { + name: "srv6 prefix sid", + input: []byte{0xc0, 0x28, 0x25, 0x05, 0x00, 0x22, 0x00, 0x01, 0x00, 0x1e, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x01, 0x00, 0x06, 0x28, 0x18, 0x10, 0x00, 0x10, 0x40}, + }, + } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := GetPathAttribute(tt.input) + attribute, err := GetPathAttribute(tt.input) + if err != nil { + t.Fatalf("test failed with error: %+v", err) + } + if err := attribute.DecodeFromBytes(tt.input); err != nil { + t.Fatalf("test failed with error: %+v", err) + } + recovered, err := attribute.Serialize() if err != nil { t.Fatalf("test failed with error: %+v", err) } - if !reflect.DeepEqual(tt.expect, got) { - t.Fatalf("test failed as expected nlri %+v does not match actual nlri %+v", tt.expect, got) + if bytes.Compare(tt.input, recovered) != 0 { + t.Fatalf("round trip conversion test failed as expected prefix sid attribute %+v does not match actual: %+v", tt.input, recovered) } }) } |