diff options
author | Serguei Bezverkhi <sbezverk@cisco.com> | 2020-05-12 22:05:44 -0400 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@gmail.com> | 2020-05-13 12:58:51 +0900 |
commit | 833188f52610dcf47c57250788b36625b10a8925 (patch) | |
tree | 2c4f80208c1d40bc0e52a2f379421039fe577f56 /pkg/packet/bgp/prefix_sid.go | |
parent | 95745b6cf9a5ed229c5494bb0b531215dec38dbe (diff) |
extend attributes proto for Prefix SID support
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 | 143 |
1 files changed, 139 insertions, 4 deletions
diff --git a/pkg/packet/bgp/prefix_sid.go b/pkg/packet/bgp/prefix_sid.go index 7dd90082..a7983bcd 100644 --- a/pkg/packet/bgp/prefix_sid.go +++ b/pkg/packet/bgp/prefix_sid.go @@ -5,6 +5,10 @@ import ( "encoding/binary" "encoding/json" "fmt" + "net" + + "github.com/golang/protobuf/ptypes" + api "github.com/osrg/gobgp/api" ) const ( @@ -14,9 +18,8 @@ const ( type TLVType uint8 type TLV struct { - Type TLVType - Length uint16 - Reserved uint8 + Type TLVType + Length uint16 } func (s *TLV) Len() int { @@ -391,7 +394,7 @@ func (s *SRv6InformationSubTLV) MarshalJSON() ([]byte, error) { func (s *SRv6InformationSubTLV) String() string { var buf bytes.Buffer - buf.WriteString(fmt.Sprintf("SID: %s ", string(s.SID))) + buf.WriteString(fmt.Sprintf("SID: %s ", net.IP(s.SID).To16().String())) buf.WriteString(fmt.Sprintf("Flag: %d ", s.Flags)) buf.WriteString(fmt.Sprintf("Endpoint Behavior: %d ", s.EndpointBehavior)) for _, tlv := range s.SubSubTLVs { @@ -540,3 +543,135 @@ func (s *SRv6SIDStructureSubSubTLV) String() string { s.TranspositionOffset, ) } + +func NewPathAttributePrefixSID(psid *api.PrefixSID) (*PathAttributePrefixSID, error) { + t := BGP_ATTR_TYPE_PREFIX_SID + s := &PathAttributePrefixSID{ + PathAttribute: PathAttribute{ + Flags: PathAttrFlags[t], + Type: t, + }, + TLVs: make([]PrefixSIDTLVInterface, 0), + } + for _, raw := range psid.Tlvs { + var tlv ptypes.DynamicAny + if err := ptypes.UnmarshalAny(raw, &tlv); err != nil { + return nil, err + } + switch v := tlv.Message.(type) { + case *api.SRv6L3ServiceTLV: + tlvLength, tlvs, err := UnmarshalSubTLVs(v.SubTlvs) + if err != nil { + return nil, err + } + o := &SRv6L3ServiceAttribute{ + TLV: TLV{ + Type: TLVType(5), + Length: tlvLength, + }, + } + s.PathAttribute.Length += tlvLength + // Storing Sub TLVs in a Service TLV + o.SubTLVs = append(o.SubTLVs, tlvs...) + // Adding Service TLV to Path Attribute TLV slice. + s.TLVs = append(s.TLVs, o) + default: + return nil, fmt.Errorf("unknown or not implemented Prefix SID type: %+v", v) + } + } + // Final Path Attribute Length is 3 bytes of the header and 1 byte Reserved1 + s.PathAttribute.Length += (3 + 1) + return s, nil +} + +func UnmarshalSubTLVs(stlvs map[uint32]*api.SRv6TLV) (uint16, []PrefixSIDTLVInterface, error) { + p := make([]PrefixSIDTLVInterface, 0, len(stlvs)) + l := uint16(0) + // v.SubTlvs is a map by sub tlv type and the value is a slice of sub tlvs of the specific type + for t, tlv := range stlvs { + switch t { + case 1: + // Sub TLV Type 1 is SRv6 Informational Sub TLV + for _, stlvRaw := range tlv.Tlv { + // Instantiating Information Sub TLV + info := &SRv6InformationSubTLV{ + SubTLV: SubTLV{ + Type: SubTLVType(1), + }, + SubSubTLVs: make([]PrefixSIDTLVInterface, 0), + } + var raw ptypes.DynamicAny + if err := ptypes.UnmarshalAny(stlvRaw, &raw); err != nil { + return 0, nil, err + } + infoProto := raw.Message.(*api.SRv6InformationSubTLV) + info.SID = make([]byte, len(infoProto.Sid)) + copy(info.SID, infoProto.Sid) + // TODO Once RFC is published add processing of flags + info.Flags = 0 + info.EndpointBehavior = uint16(infoProto.EndpointBehavior) + var sstlvslength uint16 + var sstlvs []PrefixSIDTLVInterface + if len(infoProto.SubSubTlvs) != 0 { + // Processing Sub Sub TLVs + var err error + sstlvslength, sstlvs, err = UnmarshalSubSubTLVs(infoProto.SubSubTlvs) + if err != nil { + return 0, nil, err + } + info.SubSubTLVs = append(info.SubSubTLVs, sstlvs...) + } + // SRv6 Information Sub TLV length consists 1 byte Resrved2, 16 bytes SID, 1 byte flags, 2 bytes Endpoint Behavior + // 1 byte Reserved3 and length of Sub Sub TLVs + info.SubTLV.Length = 1 + 16 + 1 + 2 + 1 + sstlvslength + // For total Srv6 Information Sub TLV length, adding 3 bytes of the Sub TLV header + l += info.SubTLV.Length + 4 + p = append(p, info) + } + default: + return 0, nil, fmt.Errorf("unknown or not implemented Prefix SID Sub TLV type: %d", t) + } + } + + return l, p, nil +} + +func UnmarshalSubSubTLVs(stlvs map[uint32]*api.SRv6TLV) (uint16, []PrefixSIDTLVInterface, error) { + p := make([]PrefixSIDTLVInterface, 0) + l := uint16(0) + // v.SubTlvs is a map by sub tlv type and the value is a slice of sub tlvs of the specific type + for t, tlv := range stlvs { + switch t { + case 1: + // Sub Sub TLV Type 1 is SRv6 Structure Sub Sub TLV + for _, stlvRaw := range tlv.Tlv { + // Instantiating Information Sub TLV + structure := &SRv6SIDStructureSubSubTLV{ + SubSubTLV: SubSubTLV{ + Type: SubSubTLVType(1), + Length: 6, + }, + } + var raw ptypes.DynamicAny + if err := ptypes.UnmarshalAny(stlvRaw, &raw); err != nil { + return 0, nil, err + } + structureProto := raw.Message.(*api.SRv6StructureSubSubTLV) + structure.LocalBlockLength = uint8(structureProto.LocalBlockLength) + structure.LocatorNodeLength = uint8(structureProto.LocalNodeLength) + structure.FunctionLength = uint8(structureProto.FunctionLength) + structure.ArgumentLength = uint8(structureProto.ArgumentLength) + structure.TranspositionLength = uint8(structureProto.TranspositionLength) + structure.TranspositionOffset = uint8(structureProto.TranspositionOffset) + + // SRv6 Structure Sub Sub TLV length consists of header 3 bytes, 6 bytes of value + l += (3 + 6) + p = append(p, structure) + } + default: + return 0, nil, fmt.Errorf("unknown or not implemented Prefix SID Sub TLV type: %d", t) + } + } + + return l, p, nil +} |