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 /internal | |
parent | 95745b6cf9a5ed229c5494bb0b531215dec38dbe (diff) |
extend attributes proto for Prefix SID support
Signed-off-by: Serguei Bezverkhi <sbezverk@cisco.com>
Diffstat (limited to 'internal')
-rw-r--r-- | internal/pkg/apiutil/attribute.go | 113 | ||||
-rw-r--r-- | internal/pkg/apiutil/attribute_test.go | 103 |
2 files changed, 215 insertions, 1 deletions
diff --git a/internal/pkg/apiutil/attribute.go b/internal/pkg/apiutil/attribute.go index 1610a181..8422f3f3 100644 --- a/internal/pkg/apiutil/attribute.go +++ b/internal/pkg/apiutil/attribute.go @@ -75,6 +75,8 @@ func UnmarshalAttribute(an *any.Any) (bgp.PathAttributeInterface, error) { } } return bgp.NewPathAttributeClusterList(a.Ids), nil + case *api.PrefixSID: + return bgp.NewPathAttributePrefixSID(a) } return nil, errors.New("unexpected object") } @@ -149,6 +151,114 @@ func NewClusterListAttributeFromNative(a *bgp.PathAttributeClusterList) *api.Clu } } +func NewPrefixSIDAttributeFromNative(a *bgp.PathAttributePrefixSID) *api.PrefixSID { + psid := &api.PrefixSID{} + psid.Tlvs = MarshalSRv6TLVs(a.TLVs) + + return psid +} + +func MarshalSRv6TLVs(tlvs []bgp.PrefixSIDTLVInterface) []*any.Any { + mtlvs := make([]*any.Any, len(tlvs)) + for i, tlv := range tlvs { + var r proto.Message + switch t := tlv.(type) { + case *bgp.SRv6L3ServiceAttribute: + o := &api.SRv6L3ServiceTLV{} + o.SubTlvs = MarshalSRv6SubTLVs(t.SubTLVs) + r = o + default: + log.WithFields(log.Fields{ + "Topic": "protobuf", + "SRv6": t, + }).Warn("invalid prefix sid tlv type to marshal") + return nil + } + a, _ := ptypes.MarshalAny(r) + mtlvs[i] = a + } + + return mtlvs +} + +func MarshalSRv6SubTLVs(tlvs []bgp.PrefixSIDTLVInterface) map[uint32]*api.SRv6TLV { + mtlvs := make(map[uint32]*api.SRv6TLV) + var key uint32 + for _, tlv := range tlvs { + var r proto.Message + switch t := tlv.(type) { + case *bgp.SRv6InformationSubTLV: + o := &api.SRv6InformationSubTLV{ + EndpointBehavior: uint32(t.EndpointBehavior), + // TODO Once flags are used in RFC, add processing. + Flags: &api.SRv6SIDFlags{}, + } + o.Sid = make([]byte, len(t.SID)) + copy(o.Sid, t.SID) + o.SubSubTlvs = MarshalSRv6SubSubTLVs(t.SubSubTLVs) + // SRv6 Information Sub TLV is type 1 Sub TLV + key = 1 + r = o + default: + log.WithFields(log.Fields{ + "Topic": "protobuf", + "SRv6": t, + }).Warn("invalid prefix sid sub tlv type to marshal") + return nil + } + a, _ := ptypes.MarshalAny(r) + tlvs, ok := mtlvs[key] + if !ok { + tlvs = &api.SRv6TLV{ + Tlv: make([]*any.Any, 0), + } + mtlvs[key] = tlvs + } + tlvs.Tlv = append(tlvs.Tlv, a) + } + + return mtlvs +} + +func MarshalSRv6SubSubTLVs(tlvs []bgp.PrefixSIDTLVInterface) map[uint32]*api.SRv6TLV { + mtlvs := make(map[uint32]*api.SRv6TLV) + var key uint32 + for _, tlv := range tlvs { + var r proto.Message + switch t := tlv.(type) { + case *bgp.SRv6SIDStructureSubSubTLV: + o := &api.SRv6StructureSubSubTLV{ + LocalBlockLength: uint32(t.LocalBlockLength), + LocalNodeLength: uint32(t.LocatorNodeLength), + FunctionLength: uint32(t.FunctionLength), + ArgumentLength: uint32(t.ArgumentLength), + TranspositionLength: uint32(t.TranspositionLength), + TranspositionOffset: uint32(t.TranspositionOffset), + } + // SRv6 SID Structure Sub Sub TLV is type 1 Sub Sub TLV + key = 1 + r = o + default: + log.WithFields(log.Fields{ + "Topic": "protobuf", + "SRv6": t, + }).Warn("invalid prefix sid sub sub tlv type to marshal") + return nil + } + a, _ := ptypes.MarshalAny(r) + tlvs, ok := mtlvs[key] + if !ok { + tlvs = &api.SRv6TLV{ + Tlv: make([]*any.Any, 0), + } + mtlvs[key] = tlvs + } + tlvs.Tlv = append(tlvs.Tlv, a) + } + + return mtlvs +} + func MarshalRD(rd bgp.RouteDistinguisherInterface) *any.Any { var r proto.Message switch v := rd.(type) { @@ -1537,7 +1647,8 @@ func unmarshalAttribute(an *any.Any) (bgp.PathAttributeInterface, error) { communities = append(communities, bgp.NewLargeCommunity(c.GlobalAdmin, c.LocalData1, c.LocalData2)) } return bgp.NewPathAttributeLargeCommunities(communities), nil - + case *api.PrefixSID: + return bgp.NewPathAttributePrefixSID(a) case *api.UnknownAttribute: return bgp.NewPathAttributeUnknown(bgp.BGPAttrFlag(a.Flags), bgp.BGPAttrType(a.Type), a.Value), nil } diff --git a/internal/pkg/apiutil/attribute_test.go b/internal/pkg/apiutil/attribute_test.go index 8b3cd1c2..a3eff1a7 100644 --- a/internal/pkg/apiutil/attribute_test.go +++ b/internal/pkg/apiutil/attribute_test.go @@ -16,6 +16,7 @@ package apiutil import ( + "bytes" "net" "testing" @@ -1579,3 +1580,105 @@ func Test_UnknownAttribute(t *testing.T) { assert.Equal(input.Type, output.Type) assert.Equal(input.Value, output.Value) } + +func TestFullCyclePrefixSID(t *testing.T) { + tests := []struct { + 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) { + attribute := bgp.PathAttributePrefixSID{} + if err := attribute.DecodeFromBytes(tt.input); err != nil { + t.Fatalf("test failed with error: %+v", err) + } + // Converting from Native to API + apiPrefixSID := NewPrefixSIDAttributeFromNative(&attribute) + // Converting back from API to Native + recoveredPrefixSID, err := bgp.NewPathAttributePrefixSID(apiPrefixSID) + if err != nil { + t.Fatalf("test failed with error: %+v", err) + } + recovered, err := recoveredPrefixSID.Serialize() + if err != nil { + t.Fatalf("test failed with error: %+v", err) + } + if !bytes.Equal(tt.input, recovered) { + t.Fatalf("round trip conversion test failed as expected prefix sid attribute %+v does not match actual: %+v", tt.input, recovered) + } + }) + } +} + +func TestFullCycleSRv6SIDStructureSubSubTLV(t *testing.T) { + tests := []struct { + name string + input []byte + }{ + { + name: "srv6 prefix sid", + input: []byte{0x01, 0x00, 0x06, 0x28, 0x18, 0x10, 0x00, 0x10, 0x40}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + sstlv := bgp.SRv6SIDStructureSubSubTLV{} + if err := sstlv.DecodeFromBytes(tt.input); err != nil { + t.Fatalf("test failed with error: %+v", err) + } + // Converting from Native to API + apiPrefixSID := MarshalSRv6SubSubTLVs([]bgp.PrefixSIDTLVInterface{&sstlv}) + // Converting back from API to Native + _, recoveredPrefixSID, err := bgp.UnmarshalSubSubTLVs(apiPrefixSID) + if err != nil { + t.Fatalf("test failed with error: %+v", err) + } + recovered, err := recoveredPrefixSID[0].Serialize() + if err != nil { + t.Fatalf("test failed with error: %+v", err) + } + if !bytes.Equal(tt.input, recovered) { + t.Fatalf("round trip conversion test failed as expected prefix sid attribute %+v does not match actual: %+v", tt.input, recovered) + } + }) + } +} + +func TestFullCycleSRv6InformationSubTLV(t *testing.T) { + tests := []struct { + name string + input []byte + }{ + { + name: "srv6 prefix sid informationw sub tlv", + 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 := bgp.SRv6InformationSubTLV{} + if err := stlv.DecodeFromBytes(tt.input); err != nil { + t.Fatalf("test failed with error: %+v", err) + } + // Converting from Native to API + apiPrefixSID := MarshalSRv6SubTLVs([]bgp.PrefixSIDTLVInterface{&stlv}) + // Converting back from API to Native + _, recoveredPrefixSID, err := bgp.UnmarshalSubTLVs(apiPrefixSID) + if err != nil { + t.Fatalf("test failed with error: %+v", err) + } + recovered, err := recoveredPrefixSID[0].Serialize() + if err != nil { + t.Fatalf("test failed with error: %+v", err) + } + if !bytes.Equal(tt.input, recovered) { + t.Fatalf("round trip conversion test failed as expected prefix sid attribute %+v does not match actual: %+v", tt.input, recovered) + } + }) + } +} |