summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorSerguei Bezverkhi <sbezverk@cisco.com>2020-05-06 15:44:17 -0400
committerSerguei Bezverkhi <sbezverk@cisco.com>2020-05-06 15:44:17 -0400
commit9251c7a7c0ce93c3365090a79146151c4294e393 (patch)
tree9128b2456f6dd2002d35de1bf6b7cff9df1fa04e
parentcd4b9c5b0abfbe73fc7ffc63725a758b7242d759 (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.mod1
-rw-r--r--go.sum4
-rw-r--r--pkg/packet/bgp/bgp.go6
-rw-r--r--pkg/packet/bgp/prefix_sid.go370
-rw-r--r--pkg/packet/bgp/prefix_sid_sstlv.go107
-rw-r--r--pkg/packet/bgp/prefix_sid_sstlv_test.go33
-rw-r--r--pkg/packet/bgp/prefix_sid_stlv_test.go33
-rw-r--r--pkg/packet/bgp/prefix_sid_test.go29
8 files changed, 376 insertions, 207 deletions
diff --git a/go.mod b/go.mod
index 8047015c..4752215a 100644
--- a/go.mod
+++ b/go.mod
@@ -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
diff --git a/go.sum b/go.sum
index dd8ec379..7ba85acd 100644
--- a/go.sum
+++ b/go.sum
@@ -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)
}
})
}