diff options
Diffstat (limited to 'pkg/packet/bgp/prefix_sid.go')
-rw-r--r-- | pkg/packet/bgp/prefix_sid.go | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/pkg/packet/bgp/prefix_sid.go b/pkg/packet/bgp/prefix_sid.go new file mode 100644 index 00000000..4ae727f5 --- /dev/null +++ b/pkg/packet/bgp/prefix_sid.go @@ -0,0 +1,303 @@ +package bgp + +import ( + "bytes" + "encoding/binary" + "encoding/json" + "fmt" +) + +type PrefixSIDTLVType uint16 + +type PrefixSIDTLV struct { + Type PrefixSIDTLVType + Length uint16 +} + +type PrefixSIDTLVInterface interface { + Len() int + DecodeFromBytes([]byte) error + Serialize() ([]byte, error) + String() string + MarshalJSON() ([]byte, error) +} + +type PathAttributePrefixSID struct { + PathAttribute + TLVs []PrefixSIDTLVInterface +} + +func (s *PrefixSIDTLV) Len() int { + return int(s.Length) + tlvHdrLen +} + +func (s *PrefixSIDTLV) Serialize(value []byte) ([]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 +} + +func (s *PrefixSIDTLV) DecodeFromBytes(data []byte) ([]byte, error) { + if len(data) < tlvHdrLen { + return nil, malformedAttrListErr("decoding failed: Prefix SID TLV malformed") + } + // l.Type = PrefixSIDTLVType(binary.BigEndian.Uint16(data[:2])) + // l.Length = binary.BigEndian.Uint16(data[2:4]) + + // if len(data) < l.Len() { + // return nil, malformedAttrListErr("decoding failed: Prefix SID TLV malformed") + // } + + return data[tlvHdrLen:s.Len()], nil +} + +//type LsAttributePrefix struct { +// IGPFlags *LsIGPFlags `json:"igp_flags,omitempty"` +// Opaque *[]byte `json:"opaque,omitempty"` +// +// SrPrefixSID *uint32 `json:"sr_prefix_sid,omitempty"` +//} + +type PrefixSIDAttribute struct { + // Node LsAttributeNode `json:"node"` + // Link LsAttributeLink `json:"link"` + // Prefix LsAttributePrefix `json:"prefix"` +} + +func (p *PathAttributePrefixSID) Extract() *PrefixSIDAttribute { + s := &PrefixSIDAttribute{} + + // for _, tlv := range p.TLVs { + // switch v := tlv.(type) { + // case *LsTLVNodeFlagBits: + // l.Node.Flags = v.Extract() + + // case *LsTLVOpaqueNodeAttr: + // l.Node.Opaque = &v.Attr + + // case *LsTLVNodeName: + // l.Node.Name = &v.Name + + // case *LsTLVIsisArea: + // l.Node.IsisArea = &v.Area + + // case *LsTLVLocalIPv4RouterID: + // l.Node.LocalRouterID = &v.IP + // l.Link.LocalRouterID = &v.IP + + // case *LsTLVLocalIPv6RouterID: + // l.Node.LocalRouterIDv6 = &v.IP + // l.Link.LocalRouterIDv6 = &v.IP + + // case *LsTLVSrCapabilities: + // l.Node.SrCapabilties = v.Extract() + + // case *LsTLVSrAlgorithm: + // l.Node.SrAlgorithms = &v.Algorithm + + // case *LsTLVSrLocalBlock: + // l.Node.SrLocalBlock = v.Extract() + + // case *LsTLVRemoteIPv4RouterID: + // l.Link.RemoteRouterID = &v.IP + + // case *LsTLVRemoteIPv6RouterID: + // l.Link.RemoteRouterIDv6 = &v.IP + + // case *LsTLVAdminGroup: + // l.Link.AdminGroup = &v.AdminGroup + + // case *LsTLVMaxLinkBw: + // l.Link.Bandwidth = &v.Bandwidth + + // case *LsTLVMaxReservableLinkBw: + // l.Link.ReservableBandwidth = &v.Bandwidth + + // case *LsTLVUnreservedBw: + // l.Link.UnreservedBandwidth = &v.Bandwidth + + // case *LsTLVSrlg: + // l.Link.Srlgs = &v.Srlgs + + // case *LsTLVTEDefaultMetric: + // l.Link.DefaultTEMetric = &v.Metric + + // case *LsTLVIGPMetric: + // l.Link.IGPMetric = &v.Metric + + // case *LsTLVOpaqueLinkAttr: + // l.Link.Opaque = &v.Attr + + // case *LsTLVLinkName: + // l.Link.Name = &v.Name + + // case *LsTLVAdjacencySID: + // l.Link.SrAdjacencySID = &v.SID + + // case *LsTLVIGPFlags: + // l.Prefix.IGPFlags = v.Extract() + + // case *LsTLVOpaquePrefixAttr: + // l.Prefix.Opaque = &v.Attr + + // case *LsTLVPrefixSID: + // l.Prefix.SrPrefixSID = &v.SID + // } + // } + + return s +} + +func (p *PathAttributePrefixSID) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + tlvs, err := p.PathAttribute.DecodeFromBytes(data) + if err != nil { + return err + } + + for len(tlvs) >= tlvHdrLen { + t := &PrefixSIDTLV{} + _, err := t.DecodeFromBytes(tlvs) + if err != nil { + return err + } + + var tlv PrefixSIDTLVInterface + // switch t.Type { + // // Node NLRI-related TLVs (https://tools.ietf.org/html/rfc7752#section-3.3.1) + // case LS_TLV_NODE_FLAG_BITS: + // tlv = &LsTLVNodeFlagBits{} + + // case LS_TLV_OPAQUE_NODE_ATTR: + // tlv = &LsTLVOpaqueNodeAttr{} + + // case LS_TLV_NODE_NAME: + // tlv = &LsTLVNodeName{} + + // case LS_TLV_ISIS_AREA: + // tlv = &LsTLVIsisArea{} + + // // Used by Link NLRI as well. + // case LS_TLV_IPV4_LOCAL_ROUTER_ID: + // tlv = &LsTLVLocalIPv4RouterID{} + + // // Used by Link NLRI as well. + // case LS_TLV_IPV6_LOCAL_ROUTER_ID: + // tlv = &LsTLVLocalIPv6RouterID{} + + // // SR-related TLVs (draft-ietf-idr-bgp-ls-segment-routing-ext-08) for Node NLRI + // case LS_TLV_SR_CAPABILITIES: + // tlv = &LsTLVSrCapabilities{} + + // case LS_TLV_SR_ALGORITHM: + // tlv = &LsTLVSrAlgorithm{} + + // case LS_TLV_SR_LOCAL_BLOCK: + // tlv = &LsTLVSrLocalBlock{} + + // // Link NLRI-related TLVs (https://tools.ietf.org/html/rfc7752#section-3.3.2) + // case LS_TLV_IPV4_REMOTE_ROUTER_ID: + // tlv = &LsTLVRemoteIPv4RouterID{} + + // case LS_TLV_IPV6_REMOTE_ROUTER_ID: + // tlv = &LsTLVRemoteIPv6RouterID{} + + // case LS_TLV_ADMIN_GROUP: + // tlv = &LsTLVAdminGroup{} + + // case LS_TLV_MAX_LINK_BANDWIDTH: + // tlv = &LsTLVMaxLinkBw{} + + // case LS_TLV_MAX_RESERVABLE_BANDWIDTH: + // tlv = &LsTLVMaxReservableLinkBw{} + + // case LS_TLV_UNRESERVED_BANDWIDTH: + // tlv = &LsTLVUnreservedBw{} + + // case LS_TLV_SRLG: + // tlv = &LsTLVSrlg{} + + // case LS_TLV_TE_DEFAULT_METRIC: + // tlv = &LsTLVTEDefaultMetric{} + + // case LS_TLV_IGP_METRIC: + // tlv = &LsTLVIGPMetric{} + + // case LS_TLV_OPAQUE_LINK_ATTR: + // tlv = &LsTLVOpaqueLinkAttr{} + + // case LS_TLV_LINK_NAME: + // tlv = &LsTLVLinkName{} + + // // SR-related TLVs (draft-ietf-idr-bgp-ls-segment-routing-ext-08) for Link NLRI + // case LS_TLV_ADJACENCY_SID: + // tlv = &LsTLVAdjacencySID{} + + // // Prefix NLRI-related TLVs (https://tools.ietf.org/html/rfc7752#section-3.3.3) + // case LS_TLV_IGP_FLAGS: + // tlv = &LsTLVIGPFlags{} + + // case LS_TLV_OPAQUE_PREFIX_ATTR: + // tlv = &LsTLVOpaquePrefixAttr{} + + // // SR-related TLVs (draft-ietf-idr-bgp-ls-segment-routing-ext-08) for Prefix NLRI + // case LS_TLV_PREFIX_SID: + // tlv = &LsTLVPrefixSID{} + + // default: + // tlvs = tlvs[t.Len():] + // continue + // } + + if err := tlv.DecodeFromBytes(tlvs); err != nil { + return err + } + tlvs = tlvs[t.Len():] + + p.TLVs = append(p.TLVs, tlv) + } + + return nil +} + +func (p *PathAttributePrefixSID) Serialize(options ...*MarshallingOption) ([]byte, error) { + buf := []byte{} + + for _, tlv := range p.TLVs { + s, err := tlv.Serialize() + if err != nil { + return nil, err + } + buf = append(buf, s...) + } + + return p.PathAttribute.Serialize(buf, options...) +} + +func (p *PathAttributePrefixSID) String() string { + var buf bytes.Buffer + + for _, tlv := range p.TLVs { + buf.WriteString(fmt.Sprintf("%s ", tlv.String())) + } + + return fmt.Sprintf("{LsAttributes: %s}", buf.String()) +} + +func (p *PathAttributePrefixSID) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type BGPAttrType `json:"type"` + Flags BGPAttrFlag `json:"flags"` + PrefixSIDAttribute + }{ + p.GetType(), + p.GetFlags(), + *p.Extract(), + }) +} |