Skip to content

Commit

Permalink
pkg/packet/bgp: refactor Prefix-SID
Browse files Browse the repository at this point in the history
- Add TLVType contant values.
- Add NewPathAttributePrefixSID().
- Add SRv6ServiceTLV to support SRv6 L2 Service TLV.
- Move reserved field handling to each type of TLV,
  because header and reserved field size are different for each type.
  For more details, see https://www.rfc-editor.org/rfc/rfc8669.html
  and https://www.rfc-editor.org/rfc/rfc9252.html.
  • Loading branch information
higebu committed Oct 14, 2022
1 parent ddfc02e commit 0869c83
Show file tree
Hide file tree
Showing 6 changed files with 462 additions and 170 deletions.
358 changes: 217 additions & 141 deletions api/attribute.pb.go

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions api/attribute.proto
Original file line number Diff line number Diff line change
Expand Up @@ -868,19 +868,26 @@ message SRv6InformationSubTLV {
map<uint32, SRv6TLV> sub_sub_tlvs = 4;
}

// https://tools.ietf.org/html/draft-dawra-bess-srv6-services-02#section-2
// https://www.rfc-editor.org/rfc/rfc9252.html#section-2
message SRv6L3ServiceTLV {
// SRv6TLV is one of:
// - SRv6InformationSubTLV
map<uint32, SRv6TLV> sub_tlvs = 1;
}

// https://www.rfc-editor.org/rfc/rfc9252.html#section-2
message SRv6L2ServiceTLV {
// SRv6TLV is one of:
// - SRv6InformationSubTLV
map<uint32, SRv6TLV> sub_tlvs = 1;
}

// https://tools.ietf.org/html/rfc8669
message PrefixSID {
// tlv is one of:
// - IndexLabelTLV Type 1 (not yet implemented)
// - OriginatorSRGBTLV Type 3 (not yet implemented)
// - SRv6L3ServiceTLV Type 5
// - SRv6L2ServiceTLV Type 6 (not yet implemented)
// - SRv6L2ServiceTLV Type 6
repeated google.protobuf.Any tlvs = 1;
}
17 changes: 17 additions & 0 deletions pkg/apiutil/attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,23 @@ func MarshalSRv6TLVs(tlvs []bgp.PrefixSIDTLVInterface) ([]*apb.Any, error) {
return nil, err
}
r = o
case *bgp.SRv6ServiceTLV:
switch t.TLV.Type {
case bgp.TLVTypeSRv6L3Service:
o := &api.SRv6L3ServiceTLV{}
o.SubTlvs, err = MarshalSRv6SubTLVs(t.SubTLVs)
if err != nil {
return nil, err
}
r = o
case bgp.TLVTypeSRv6L2Service:
o := &api.SRv6L2ServiceTLV{}
o.SubTlvs, err = MarshalSRv6SubTLVs(t.SubTLVs)
if err != nil {
return nil, err
}
r = o
}
default:
return nil, fmt.Errorf("invalid prefix sid tlv type to marshal %v", t)
}
Expand Down
5 changes: 4 additions & 1 deletion pkg/apiutil/attribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1790,7 +1790,10 @@ func TestFullCyclePrefixSID(t *testing.T) {
t.Fatalf("test failed with error: %+v", err)
}
// Converting from Native to API
apiPrefixSID, _ := NewPrefixSIDAttributeFromNative(&attribute)
apiPrefixSID, err := NewPrefixSIDAttributeFromNative(&attribute)
if err != nil {
t.Fatalf("test failed with error: %+v", err)
}
// Converting back from API to Native
recoveredPrefixSID, err := UnmarshalPrefixSID(apiPrefixSID)
if err != nil {
Expand Down
204 changes: 178 additions & 26 deletions pkg/packet/bgp/prefix_sid.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,54 +6,61 @@ import (
"encoding/json"
"fmt"
"net"
"net/netip"
)

const (
prefixSIDtlvHdrLen = 4
)

// BGP Prefix-SID TLV Types
// https://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#bgp-prefix-sid-tlv-types
type TLVType uint8

const (
_ TLVType = iota // Reserved
TLVTypeLavelIndex
_ // Deprecated
TLVTypeOriginatorSRGB
_ // Deprecated
TLVTypeSRv6L3Service
TLVTypeSRv6L2Service
)

type TLV struct {
Type TLVType
Length uint16
}

func (s *TLV) Len() int {
return int(s.Length) + tlvHdrLen - 1 // Extra reserved byte in the header
func (t *TLV) Len() int {
return int(t.Length) + 3 // Type(1) + Length(2)
}

func (s *TLV) Serialize(value []byte) ([]byte, error) {
if len(value) != int(s.Length)-1 {
func (t *TLV) Serialize(value []byte) ([]byte, error) {
if len(value) != int(t.Len()) {
return nil, malformedAttrListErr("serialization failed: Prefix SID TLV malformed")
}
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
value[p] = byte(t.Type)
p++
copy(buf[p:], value)

return buf, nil
binary.BigEndian.PutUint16(value[p:p+2], uint16(t.Length))
return value, nil
}

func (s *TLV) DecodeFromBytes(data []byte) ([]byte, error) {
if len(data) < prefixSIDtlvHdrLen {
func (t *TLV) DecodeFromBytes(data []byte) ([]byte, error) {
if len(data) < 3 {
return nil, malformedAttrListErr("decoding failed: Prefix SID TLV malformed")
}
p := 0
s.Type = TLVType(data[p])
t.Type = TLVType(data[p])
p++
s.Length = binary.BigEndian.Uint16(data[p : p+2])
t.Length = binary.BigEndian.Uint16(data[p : p+2])
p += 2

if s.Len() < prefixSIDtlvHdrLen || len(data) < s.Len() {
if len(data[p:]) < int(t.Length) {
return nil, malformedAttrListErr("decoding failed: Prefix SID TLV malformed")
}

return data[prefixSIDtlvHdrLen:s.Len()], nil
return data[p : p+int(t.Length)], nil
}

// PrefixSIDTLVInterface defines standard set of methods to handle Prefix SID attribute's TLVs
Expand All @@ -74,6 +81,21 @@ type PathAttributePrefixSID struct {
TLVs []PrefixSIDTLVInterface
}

func NewPathAttributePrefixSID(values ...PrefixSIDTLVInterface) *PathAttributePrefixSID {
var l int
for _, v := range values {
l += v.Len()
}
return &PathAttributePrefixSID{
PathAttribute: PathAttribute{
Flags: getPathAttrFlags(BGP_ATTR_TYPE_PREFIX_SID, l),
Type: BGP_ATTR_TYPE_PREFIX_SID,
Length: uint16(l),
},
TLVs: values,
}
}

func (p *PathAttributePrefixSID) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
tlvs, err := p.PathAttribute.DecodeFromBytes(data)
if err != nil {
Expand All @@ -89,8 +111,8 @@ func (p *PathAttributePrefixSID) DecodeFromBytes(data []byte, options ...*Marsha

var tlv PrefixSIDTLVInterface
switch t.Type {
case 5:
tlv = &SRv6L3ServiceAttribute{
case TLVTypeSRv6L3Service, TLVTypeSRv6L2Service:
tlv = &SRv6ServiceTLV{
SubTLVs: make([]PrefixSIDTLVInterface, 0),
}
default:
Expand Down Expand Up @@ -158,6 +180,7 @@ type SRv6L3Service struct {
}

// SRv6L3ServiceAttribute defines the structure of SRv6 L3 Service attribute
// Deprecated: Use SRv6ServiceTLV instead.
type SRv6L3ServiceAttribute struct {
TLV
SubTLVs []PrefixSIDTLVInterface
Expand All @@ -168,13 +191,15 @@ func (s *SRv6L3ServiceAttribute) Len() int {
}

func (s *SRv6L3ServiceAttribute) Serialize() ([]byte, error) {
buf := make([]byte, 0)
buf := make([]byte, s.Length+3)
p := 4
for _, tlv := range s.SubTLVs {
s, err := tlv.Serialize()
if err != nil {
return nil, err
}
buf = append(buf, s...)
copy(buf[p:p+len(s)], s)
p += len(s)
}
return s.TLV.Serialize(buf)
}
Expand All @@ -184,6 +209,7 @@ func (s *SRv6L3ServiceAttribute) DecodeFromBytes(data []byte) error {
if err != nil {
return err
}
stlvs = stlvs[1:] // RESERVED(1)

for len(stlvs) >= subTLVHdrLen {
t := &SubTLV{}
Expand Down Expand Up @@ -274,13 +300,13 @@ func (s *SubTLV) Serialize(value []byte) ([]byte, error) {

func (s *SubTLV) DecodeFromBytes(data []byte) ([]byte, error) {
if len(data) < subTLVHdrLen {
return nil, malformedAttrListErr("decoding failed: Prefix SID TLV malformed")
return nil, malformedAttrListErr("decoding failed: Prefix SID Sub TLV malformed")
}
s.Type = SubTLVType(data[0])
s.Length = binary.BigEndian.Uint16(data[1:3])

if len(data) < s.Len() {
return nil, malformedAttrListErr("decoding failed: Prefix SID TLV malformed")
return nil, malformedAttrListErr("decoding failed: Prefix SID Sub TLV malformed")
}

return data[subTLVHdrLen:s.Len()], nil
Expand All @@ -303,6 +329,23 @@ type SRv6InformationSubTLV struct {
SubSubTLVs []PrefixSIDTLVInterface
}

func NewSRv6InformationSubTLV(sid netip.Addr, behavior SRBehavior, values ...PrefixSIDTLVInterface) *SRv6InformationSubTLV {
l := 21 // RESERVED1(1) + SID(16) + Flags(1) + Endpoint Behavior(2) + RESERVED2(1)
for _, v := range values {
l += v.Len()
}
return &SRv6InformationSubTLV{
SubTLV: SubTLV{
Type: 1,
Length: uint16(l),
},
SID: sid.AsSlice(),
Flags: 0,
EndpointBehavior: uint16(behavior),
SubSubTLVs: values,
}
}

func (s *SRv6InformationSubTLV) Len() int {
return int(s.Length) + subTLVHdrLen
}
Expand Down Expand Up @@ -471,6 +514,21 @@ type SRv6SIDStructureSubSubTLV struct {
TranspositionOffset uint8
}

func NewSRv6SIDStructureSubSubTLV(lbl, lnl, fl, al, tl, to uint8) *SRv6SIDStructureSubSubTLV {
return &SRv6SIDStructureSubSubTLV{
SubSubTLV: SubSubTLV{
Type: 1,
Length: 6,
},
LocatorBlockLength: lbl,
LocatorNodeLength: lnl,
FunctionLength: fl,
ArgumentLength: al,
TranspositionLength: tl,
TranspositionOffset: to,
}
}

func (s *SRv6SIDStructureSubSubTLV) Len() int {
return int(s.Length) + subSubTLVHdrLen
}
Expand Down Expand Up @@ -540,3 +598,97 @@ func (s *SRv6SIDStructureSubSubTLV) String() string {
s.TranspositionOffset,
)
}

// SRv6ServiceTLV represents SRv6 Service TLV.
// https://www.rfc-editor.org/rfc/rfc9252.html#section-2
type SRv6ServiceTLV struct {
TLV
SubTLVs []PrefixSIDTLVInterface
}

func NewSRv6ServiceTLV(t TLVType, values ...PrefixSIDTLVInterface) *SRv6ServiceTLV {
l := 1 // RESERVED(1)
for _, v := range values {
l += v.Len()
}
return &SRv6ServiceTLV{
TLV: TLV{
Type: t,
Length: uint16(l),
},
SubTLVs: values,
}
}

func (s *SRv6ServiceTLV) Len() int {
return int(s.Length) + 3 // Type(1) + Length(2)
}

func (t *SRv6ServiceTLV) Serialize() ([]byte, error) {
buf := make([]byte, t.Len())
p := 4
for _, tlv := range t.SubTLVs {
b, err := tlv.Serialize()
if err != nil {
return nil, err
}
copy(buf[p:p+len(b)], b)
p += len(b)
}
return t.TLV.Serialize(buf)
}

func (s *SRv6ServiceTLV) DecodeFromBytes(data []byte) error {
stlvs, err := s.TLV.DecodeFromBytes(data)
if err != nil {
return err
}
stlvs = stlvs[1:] // RESERVED(1)

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.SubTLVs = append(s.SubTLVs, stlv)
}

return nil
}

func (t *SRv6ServiceTLV) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Type TLVType `json:"type"`
SubTLVs []PrefixSIDTLVInterface
}{
t.Type,
t.SubTLVs,
})
}

func (t *SRv6ServiceTLV) String() string {
var buf bytes.Buffer

for _, tlv := range t.SubTLVs {
buf.WriteString(fmt.Sprintf("%s ", tlv.String()))
}

return fmt.Sprintf("{SRv6 Service TLV: %s}", buf.String())
}
Loading

0 comments on commit 0869c83

Please sign in to comment.