diff --git a/dataplane/forwarding/fwdconfig/action.go b/dataplane/forwarding/fwdconfig/action.go index fdb00442..4caa0033 100644 --- a/dataplane/forwarding/fwdconfig/action.go +++ b/dataplane/forwarding/fwdconfig/action.go @@ -65,10 +65,12 @@ func (ab *ActionBuilder) Build() *fwdpb.ActionDesc { // UpdateActionBuilder is a builder for an update action. type UpdateActionBuilder struct { - fieldIDNum fwdpb.PacketFieldNum - updateType fwdpb.UpdateType - fieldSrc fwdpb.PacketFieldNum - value []byte + fieldIDNum fwdpb.PacketFieldNum + updateType fwdpb.UpdateType + fieldSrc fwdpb.PacketFieldNum + instance uint32 + srcInstance uint32 + value []byte } // UpdateAction returns a new update action builder. @@ -91,6 +93,18 @@ func (u *UpdateActionBuilder) WithUpdateType(t fwdpb.UpdateType) *UpdateActionBu return u } +// WithFieldIDInstance sets the instance of the id num. +func (u *UpdateActionBuilder) WithFieldIDInstance(i uint32) *UpdateActionBuilder { + u.instance = i + return u +} + +// WithFieldSrcInstance sets the instance of the src id num. +func (u *UpdateActionBuilder) WithFieldSrcInstance(i uint32) *UpdateActionBuilder { + u.srcInstance = i + return u +} + // WithUpdateType sets the update source field id. func (u *UpdateActionBuilder) WithFieldSrc(num fwdpb.PacketFieldNum) *UpdateActionBuilder { u.fieldSrc = num @@ -115,6 +129,7 @@ func (u *UpdateActionBuilder) set(ad *fwdpb.ActionDesc) { FieldId: &fwdpb.PacketFieldId{ Field: &fwdpb.PacketField{ FieldNum: u.fieldIDNum, + Instance: u.instance, }, }, Type: u.updateType, @@ -122,6 +137,7 @@ func (u *UpdateActionBuilder) set(ad *fwdpb.ActionDesc) { Field: &fwdpb.PacketFieldId{ Field: &fwdpb.PacketField{ FieldNum: u.fieldSrc, + Instance: u.srcInstance, }, }, }, diff --git a/dataplane/forwarding/fwdconfig/table.go b/dataplane/forwarding/fwdconfig/table.go index d0018958..4808bd44 100644 --- a/dataplane/forwarding/fwdconfig/table.go +++ b/dataplane/forwarding/fwdconfig/table.go @@ -55,14 +55,16 @@ func (b TableEntryAddRequestBuilder) Build() *fwdpb.TableEntryAddRequest { Entries: []*fwdpb.TableEntryAddRequest_Entry{}, } for i, entry := range b.entries { - var acts []*fwdpb.ActionDesc + entry := &fwdpb.TableEntryAddRequest_Entry{ + EntryDesc: entry.Build(), + } + req.Entries = append(req.Entries, entry) + if i >= len(b.actions) { + break + } for _, act := range b.actions[i] { - acts = append(acts, act.Build()) + entry.Actions = append(entry.Actions, act.Build()) } - req.Entries = append(req.Entries, &fwdpb.TableEntryAddRequest_Entry{ - EntryDesc: entry.Build(), - Actions: acts, - }) } return req } diff --git a/dataplane/forwarding/protocol/attr.go b/dataplane/forwarding/protocol/attr.go index 0f2509b0..eec77385 100644 --- a/dataplane/forwarding/protocol/attr.go +++ b/dataplane/forwarding/protocol/attr.go @@ -185,6 +185,9 @@ var FieldAttr = map[fwdpb.PacketFieldNum]struct { fwdpb.PacketFieldNum_PACKET_FIELD_NUM_OUTPUT_IFACE: { Sizes: []int{SizeUint64}, }, + fwdpb.PacketFieldNum_PACKET_FIELD_NUM_TUNNEL_ID: { + Sizes: []int{SizeUint64}, + }, } // GroupAttr contains attributes for each packet header group. @@ -221,6 +224,7 @@ var GroupAttr = map[fwdpb.PacketHeaderGroup]struct { fwdpb.PacketFieldNum_PACKET_FIELD_NUM_TRAP_ID, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_INPUT_IFACE, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_OUTPUT_IFACE, + fwdpb.PacketFieldNum_PACKET_FIELD_NUM_TUNNEL_ID, }, }, fwdpb.PacketHeaderGroup_PACKET_HEADER_GROUP_L2: { diff --git a/dataplane/forwarding/protocol/metadata/metadata.go b/dataplane/forwarding/protocol/metadata/metadata.go index 730fb95e..fbbd0016 100644 --- a/dataplane/forwarding/protocol/metadata/metadata.go +++ b/dataplane/forwarding/protocol/metadata/metadata.go @@ -44,6 +44,7 @@ type Metadata struct { trapID []byte // ID of the trap rule that was applies to this packet. inputIface []byte // L3 input interface id. outputIface []byte // L3 output interface id. + tunnelID []byte // Tunnel ID desc *protocol.Desc // Protocol descriptor. } @@ -120,6 +121,8 @@ func (m *Metadata) Field(id fwdpacket.FieldID) ([]byte, error) { return m.outputIface, nil case fwdpb.PacketFieldNum_PACKET_FIELD_NUM_TRAP_ID: return m.trapID, nil + case fwdpb.PacketFieldNum_PACKET_FIELD_NUM_TUNNEL_ID: + return m.tunnelID, nil default: return nil, fmt.Errorf("metadata: Field %v failed, unsupported field", id) @@ -220,6 +223,9 @@ func (m *Metadata) updateSet(id fwdpacket.FieldID, arg []byte) (bool, error) { case fwdpb.PacketFieldNum_PACKET_FIELD_NUM_OUTPUT_IFACE: m.outputIface = arg return true, nil + case fwdpb.PacketFieldNum_PACKET_FIELD_NUM_TUNNEL_ID: + m.tunnelID = arg + return true, nil default: return false, fmt.Errorf("metadata: UpdateField failed, set unsupported for field %v", id) } diff --git a/dataplane/saiserver/BUILD b/dataplane/saiserver/BUILD index 5f7595a4..43e10958 100644 --- a/dataplane/saiserver/BUILD +++ b/dataplane/saiserver/BUILD @@ -9,6 +9,7 @@ go_library( "routing.go", "saiserver.go", "switch.go", + "tunnel.go", ], importpath = "github.com/openconfig/lemming/dataplane/saiserver", visibility = ["//visibility:public"], @@ -39,6 +40,7 @@ go_test( "ports_test.go", "routing_test.go", "switch_test.go", + "tunnel_test.go", ], embed = [":saiserver"], deps = [ diff --git a/dataplane/saiserver/routing.go b/dataplane/saiserver/routing.go index 1f6432cd..da344df7 100644 --- a/dataplane/saiserver/routing.go +++ b/dataplane/saiserver/routing.go @@ -230,37 +230,41 @@ func newNextHop(mgr *attrmgr.AttrMgr, dataplane switchDataplaneAPI, s *grpc.Serv func (nh *nextHop) CreateNextHop(ctx context.Context, req *saipb.CreateNextHopRequest) (*saipb.CreateNextHopResponse, error) { id := nh.mgr.NextID() - if req.GetType() != saipb.NextHopType_NEXT_HOP_TYPE_IP { - return nil, status.Errorf(codes.InvalidArgument, "unsupported req type: %v", req.GetType()) - } + var actions []*fwdpb.ActionDesc + switch req.GetType() { + case saipb.NextHopType_NEXT_HOP_TYPE_IP: + actions = []*fwdpb.ActionDesc{ + fwdconfig.Action(fwdconfig.UpdateAction(fwdpb.UpdateType_UPDATE_TYPE_SET, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_OUTPUT_IFACE).WithUint64Value(req.GetRouterInterfaceId())).Build(), + fwdconfig.Action(fwdconfig.UpdateAction(fwdpb.UpdateType_UPDATE_TYPE_SET, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_NEXT_HOP_IP).WithValue(req.GetIp())).Build(), + fwdconfig.Action(fwdconfig.LookupAction(NHActionTable)).Build(), + } case saipb.NextHopType_NEXT_HOP_TYPE_TUNNEL_ENCAP: - ip := req.GetIp() - tunnel := req.GetTunnelId() - mac := req.GetTunnelMac() - } - - actions := []*fwdpb.ActionDesc{ - { - ActionType: fwdpb.ActionType_ACTION_TYPE_ENCAP, - Action: &fwdpb.ActionDesc_Encap{ - Encap: &fwdpb.EncapActionDesc{ - HeaderId: fwdpb.PacketHeaderId_PACKET_HEADER_ID_IP, + actions = []*fwdpb.ActionDesc{ + { + ActionType: fwdpb.ActionType_ACTION_TYPE_ENCAP, + Action: &fwdpb.ActionDesc_Encap{ + Encap: &fwdpb.EncapActionDesc{ + HeaderId: fwdpb.PacketHeaderId_PACKET_HEADER_ID_IP, + }, }, }, - }, - fwdconfig.Action(fwdconfig.UpdateAction(fwdpb.UpdateType_UPDATE_TYPE_SET, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_IP_ADDR_DST).WithValue(req.GetIp())).Build(), + fwdconfig.Action(fwdconfig.UpdateAction(fwdpb.UpdateType_UPDATE_TYPE_SET, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_IP_ADDR_DST).WithValue(req.GetIp())).Build(), + fwdconfig.Action(fwdconfig.UpdateAction(fwdpb.UpdateType_UPDATE_TYPE_SET, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_NEXT_HOP_IP).WithValue(req.GetIp())).Build(), + fwdconfig.Action(fwdconfig.UpdateAction(fwdpb.UpdateType_UPDATE_TYPE_SET, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_TUNNEL_ID).WithUint64Value(req.GetTunnelId())).Build(), + fwdconfig.Action(fwdconfig.LookupAction(NHActionTable)).Build(), + fwdconfig.Action(fwdconfig.LookupAction(TunnelEncap)).Build(), + } + default: + return nil, status.Errorf(codes.InvalidArgument, "unsupported req type: %v", req.GetType()) } - // SRC IP == encap tunnel IP or tunnel interface ip??? nhReq := fwdconfig.TableEntryAddRequest(nh.dataplane.ID(), NHTable).AppendEntry( fwdconfig.EntryDesc(fwdconfig.ExactEntry(fwdconfig.PacketFieldBytes(fwdpb.PacketFieldNum_PACKET_FIELD_NUM_NEXT_HOP_ID).WithUint64(id))), - fwdconfig.Action(fwdconfig.UpdateAction(fwdpb.UpdateType_UPDATE_TYPE_SET, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_OUTPUT_IFACE).WithUint64Value(req.GetRouterInterfaceId())), - fwdconfig.Action(fwdconfig.UpdateAction(fwdpb.UpdateType_UPDATE_TYPE_SET, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_NEXT_HOP_IP).WithValue(req.GetIp())), - fwdconfig.Action(fwdconfig.LookupAction(NHActionTable)), - ) + ).Build() + nhReq.Entries[0].Actions = actions - if _, err := nh.dataplane.TableEntryAdd(ctx, nhReq.Build()); err != nil { + if _, err := nh.dataplane.TableEntryAdd(ctx, nhReq); err != nil { return nil, err } return &saipb.CreateNextHopResponse{ diff --git a/dataplane/saiserver/routing_test.go b/dataplane/saiserver/routing_test.go index c43291d5..2d30deb2 100644 --- a/dataplane/saiserver/routing_test.go +++ b/dataplane/saiserver/routing_test.go @@ -229,7 +229,7 @@ func TestCreateNextHop(t *testing.T) { req: &saipb.CreateNextHopRequest{}, wantErr: "InvalidArgument", }, { - desc: "success", + desc: "success ip next hop", req: &saipb.CreateNextHopRequest{ Type: saipb.NextHopType_NEXT_HOP_TYPE_IP.Enum(), RouterInterfaceId: proto.Uint64(10), @@ -296,6 +296,102 @@ func TestCreateNextHop(t *testing.T) { }, }}, }, + }, { + desc: "success tunnel next hop", + req: &saipb.CreateNextHopRequest{ + Type: saipb.NextHopType_NEXT_HOP_TYPE_TUNNEL_ENCAP.Enum(), + TunnelId: proto.Uint64(10), + Ip: []byte{127, 0, 0, 1}, + }, + wantAttr: &saipb.NextHopAttribute{ + Type: saipb.NextHopType_NEXT_HOP_TYPE_TUNNEL_ENCAP.Enum(), + TunnelId: proto.Uint64(10), + Ip: []byte{127, 0, 0, 1}, + }, + wantReq: &fwdpb.TableEntryAddRequest{ + ContextId: &fwdpb.ContextId{Id: "foo"}, + TableId: &fwdpb.TableId{ObjectId: &fwdpb.ObjectId{Id: NHTable}}, + Entries: []*fwdpb.TableEntryAddRequest_Entry{{ + Actions: []*fwdpb.ActionDesc{{ + ActionType: fwdpb.ActionType_ACTION_TYPE_ENCAP, + Action: &fwdpb.ActionDesc_Encap{ + Encap: &fwdpb.EncapActionDesc{ + HeaderId: fwdpb.PacketHeaderId_PACKET_HEADER_ID_IP, + }, + }, + }, { + ActionType: fwdpb.ActionType_ACTION_TYPE_UPDATE, + Action: &fwdpb.ActionDesc_Update{ + Update: &fwdpb.UpdateActionDesc{ + Type: fwdpb.UpdateType_UPDATE_TYPE_SET, + FieldId: &fwdpb.PacketFieldId{ + Field: &fwdpb.PacketField{ + FieldNum: fwdpb.PacketFieldNum_PACKET_FIELD_NUM_IP_ADDR_DST, + }, + }, + Field: &fwdpb.PacketFieldId{Field: &fwdpb.PacketField{}}, + Value: []byte{0x7f, 0x00, 0x00, 0x01}, + }, + }, + }, { + ActionType: fwdpb.ActionType_ACTION_TYPE_UPDATE, + Action: &fwdpb.ActionDesc_Update{ + Update: &fwdpb.UpdateActionDesc{ + Type: fwdpb.UpdateType_UPDATE_TYPE_SET, + FieldId: &fwdpb.PacketFieldId{ + Field: &fwdpb.PacketField{ + FieldNum: fwdpb.PacketFieldNum_PACKET_FIELD_NUM_NEXT_HOP_IP, + }, + }, + Field: &fwdpb.PacketFieldId{Field: &fwdpb.PacketField{}}, + Value: []byte{0x7f, 0x00, 0x00, 0x01}, + }, + }, + }, { + ActionType: fwdpb.ActionType_ACTION_TYPE_UPDATE, + Action: &fwdpb.ActionDesc_Update{ + Update: &fwdpb.UpdateActionDesc{ + Type: fwdpb.UpdateType_UPDATE_TYPE_SET, + FieldId: &fwdpb.PacketFieldId{ + Field: &fwdpb.PacketField{ + FieldNum: fwdpb.PacketFieldNum_PACKET_FIELD_NUM_TUNNEL_ID, + }, + }, + Field: &fwdpb.PacketFieldId{Field: &fwdpb.PacketField{}}, + Value: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a}, + }, + }, + }, { + ActionType: fwdpb.ActionType_ACTION_TYPE_LOOKUP, + Action: &fwdpb.ActionDesc_Lookup{ + Lookup: &fwdpb.LookupActionDesc{ + TableId: &fwdpb.TableId{ObjectId: &fwdpb.ObjectId{Id: NHActionTable}}, + }, + }, + }, { + ActionType: fwdpb.ActionType_ACTION_TYPE_LOOKUP, + Action: &fwdpb.ActionDesc_Lookup{ + Lookup: &fwdpb.LookupActionDesc{ + TableId: &fwdpb.TableId{ObjectId: &fwdpb.ObjectId{Id: TunnelEncap}}, + }, + }, + }}, + EntryDesc: &fwdpb.EntryDesc{ + Entry: &fwdpb.EntryDesc_Exact{ + Exact: &fwdpb.ExactEntryDesc{ + Fields: []*fwdpb.PacketFieldBytes{{ + Bytes: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + FieldId: &fwdpb.PacketFieldId{ + Field: &fwdpb.PacketField{ + FieldNum: fwdpb.PacketFieldNum_PACKET_FIELD_NUM_NEXT_HOP_ID, + }, + }, + }}, + }, + }, + }, + }}, + }, }} for _, tt := range tests { t.Run(tt.desc, func(t *testing.T) { diff --git a/dataplane/saiserver/switch.go b/dataplane/saiserver/switch.go index 266623aa..1ce6b283 100644 --- a/dataplane/saiserver/switch.go +++ b/dataplane/saiserver/switch.go @@ -84,6 +84,7 @@ const ( IngressActionTable = "ingress-table" EgressActionTable = "egress-action-table" NHActionTable = "nh-action" + TunnelEncap = "tunnel-encap" ) func newSwitch(mgr *attrmgr.AttrMgr, engine switchDataplaneAPI, s *grpc.Server, opts *dplaneopts.Options) (*saiSwitch, error) { diff --git a/dataplane/saiserver/tunnel.go b/dataplane/saiserver/tunnel.go index 36b4e7da..e60c3f0e 100644 --- a/dataplane/saiserver/tunnel.go +++ b/dataplane/saiserver/tunnel.go @@ -18,9 +18,14 @@ import ( "context" "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" - saipb "github.com/openconfig/lemming/dataplane/proto/sai" + "github.com/openconfig/lemming/dataplane/forwarding/fwdconfig" "github.com/openconfig/lemming/dataplane/saiserver/attrmgr" + + saipb "github.com/openconfig/lemming/dataplane/proto/sai" + fwdpb "github.com/openconfig/lemming/proto/forwarding" ) type tunnel struct { @@ -39,28 +44,56 @@ func newTunnel(mgr *attrmgr.AttrMgr, dataplane switchDataplaneAPI, s *grpc.Serve } func (t *tunnel) CreateTunnel(ctx context.Context, req *saipb.CreateTunnelRequest) (*saipb.CreateTunnelResponse, error) { - over := req.GetOverlayInterface() - under := req.GetUnderlayInterface() + id := t.mgr.NextID() + tunType := req.GetType() - ecnMode := req.GetDecapEcnMode() - ttlMode := req.GetDecapTtlMode() - dscpMode := req.GetDecapDscpMode() + switch tunType { + case saipb.TunnelType_TUNNEL_TYPE_IPINIP: + default: + return nil, status.Errorf(codes.InvalidArgument, "unsupported tunnel type: %v", tunType) + } + + actions := []*fwdpb.ActionDesc{} + + // TODO: Support parsing QOS into ECN and DSCP bits seperately. + ecnMode := req.GetEncapEcnMode() + dscpMode := req.GetEncapDscpMode() + if ecnMode == saipb.TunnelEncapEcnMode_TUNNEL_ENCAP_ECN_MODE_STANDARD && dscpMode == saipb.TunnelDscpMode_TUNNEL_DSCP_MODE_UNIFORM_MODEL { // Copy the QOS bits from the inner IP header. + actions = append(actions, fwdconfig.Action(fwdconfig.UpdateAction(fwdpb.UpdateType_UPDATE_TYPE_COPY, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_IP_QOS). + WithFieldSrc(fwdpb.PacketFieldNum_PACKET_FIELD_NUM_IP_QOS).WithFieldSrcInstance(1)).Build()) + } else { + return nil, status.Errorf(codes.InvalidArgument, "unsupported encap ecn mode %v and dscp mode: %v", ecnMode, dscpMode) + } + + ttlMode := req.GetEncapTtlMode() + switch ttlMode { + case saipb.TunnelTtlMode_TUNNEL_TTL_MODE_UNIFORM_MODEL: // Copy the TTL from the inner IP header. + actions = append(actions, fwdconfig.Action(fwdconfig.UpdateAction(fwdpb.UpdateType_UPDATE_TYPE_COPY, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_IP_HOP). + WithFieldSrc(fwdpb.PacketFieldNum_PACKET_FIELD_NUM_IP_HOP).WithFieldSrcInstance(1)).Build()) + default: + return nil, status.Errorf(codes.InvalidArgument, "unsupported ttl mode: %v", ttlMode) + } + + if req.GetEncapSrcIp() != nil { + actions = append(actions, fwdconfig.Action(fwdconfig.UpdateAction( + fwdpb.UpdateType_UPDATE_TYPE_SET, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_IP_ADDR_SRC).WithValue(req.EncapSrcIp)).Build()) + } + if req.GetEncapDstIp() != nil { + actions = append(actions, fwdconfig.Action(fwdconfig.UpdateAction( + fwdpb.UpdateType_UPDATE_TYPE_SET, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_IP_ADDR_DST).WithValue(req.EncapDstIp)).Build()) + } + + under := req.GetUnderlayInterface() + entry := fwdconfig.TableEntryAddRequest(t.dataplane.ID(), TunnelEncap).AppendEntry( + fwdconfig.EntryDesc(fwdconfig.ExactEntry(fwdconfig.PacketFieldBytes(fwdpb.PacketFieldNum_PACKET_FIELD_NUM_TUNNEL_ID).WithUint64(id))), + fwdconfig.Action(fwdconfig.UpdateAction(fwdpb.UpdateType_UPDATE_TYPE_SET, fwdpb.PacketFieldNum_PACKET_FIELD_NUM_OUTPUT_IFACE).WithUint64Value(under)), + ).Build() + entry.Entries[0].Actions = append(entry.Entries[0].Actions, actions...) + if _, err := t.dataplane.TableEntryAdd(ctx, entry); err != nil { + return nil, err + } - id := t.mgr.NextID() return &saipb.CreateTunnelResponse{ Oid: id, }, nil } - -// func (t *tunnel) CreateTunnelTermTableEntry(ctx context.Context, req *saipb.CreateTunnelTermTableEntryRequest) (*saipb.CreateTunnelTermTableEntryResponse, error) { -// vr := req.GetVrId() -// entryType := req.GetType() -// tunnelType := req.GetTunnelType() -// tunnel := req.GetActionTunnelId() -// dstIP := req.GetDstIp() - -// id := t.mgr.NextID() -// return &saipb.CreateTunnelTermTableEntryResponse{ -// Oid: id, -// }, nil -// } diff --git a/dataplane/saiserver/tunnel_test.go b/dataplane/saiserver/tunnel_test.go new file mode 100644 index 00000000..33a43c25 --- /dev/null +++ b/dataplane/saiserver/tunnel_test.go @@ -0,0 +1,136 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package saiserver + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/openconfig/gnmi/errdiff" + "google.golang.org/grpc" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/testing/protocmp" + + saipb "github.com/openconfig/lemming/dataplane/proto/sai" + "github.com/openconfig/lemming/dataplane/saiserver/attrmgr" + fwdpb "github.com/openconfig/lemming/proto/forwarding" +) + +func TestCreateTunnel(t *testing.T) { + tests := []struct { + desc string + req *saipb.CreateTunnelRequest + wantReq *fwdpb.TableEntryAddRequest + types map[string]saipb.ObjectType + wantErr string + }{{ + desc: "invalid request", + req: &saipb.CreateTunnelRequest{}, + wantErr: "InvalidArgument", + }, { + desc: "ipinip tunnel", + req: &saipb.CreateTunnelRequest{ + Type: saipb.TunnelType_TUNNEL_TYPE_IPINIP.Enum(), + EncapEcnMode: saipb.TunnelEncapEcnMode_TUNNEL_ENCAP_ECN_MODE_STANDARD.Enum(), + EncapDscpMode: saipb.TunnelDscpMode_TUNNEL_DSCP_MODE_UNIFORM_MODEL.Enum(), + EncapTtlMode: saipb.TunnelTtlMode_TUNNEL_TTL_MODE_UNIFORM_MODEL.Enum(), + UnderlayInterface: proto.Uint64(10), + }, + wantReq: &fwdpb.TableEntryAddRequest{ + ContextId: &fwdpb.ContextId{Id: "foo"}, + TableId: &fwdpb.TableId{ObjectId: &fwdpb.ObjectId{Id: TunnelEncap}}, + Entries: []*fwdpb.TableEntryAddRequest_Entry{{ + EntryDesc: &fwdpb.EntryDesc{ + Entry: &fwdpb.EntryDesc_Exact{ + Exact: &fwdpb.ExactEntryDesc{ + Fields: []*fwdpb.PacketFieldBytes{{ + FieldId: &fwdpb.PacketFieldId{ + Field: &fwdpb.PacketField{FieldNum: fwdpb.PacketFieldNum_PACKET_FIELD_NUM_TUNNEL_ID}, + }, + Bytes: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + }}, + }, + }, + }, + Actions: []*fwdpb.ActionDesc{{ + ActionType: fwdpb.ActionType_ACTION_TYPE_UPDATE, + Action: &fwdpb.ActionDesc_Update{ + Update: &fwdpb.UpdateActionDesc{ + Type: fwdpb.UpdateType_UPDATE_TYPE_SET, + Field: &fwdpb.PacketFieldId{Field: &fwdpb.PacketField{}}, + FieldId: &fwdpb.PacketFieldId{Field: &fwdpb.PacketField{FieldNum: fwdpb.PacketFieldNum_PACKET_FIELD_NUM_OUTPUT_IFACE}}, + Value: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a}, + }, + }, + }, { + ActionType: fwdpb.ActionType_ACTION_TYPE_UPDATE, + Action: &fwdpb.ActionDesc_Update{ + Update: &fwdpb.UpdateActionDesc{ + Type: fwdpb.UpdateType_UPDATE_TYPE_COPY, + Field: &fwdpb.PacketFieldId{Field: &fwdpb.PacketField{ + FieldNum: fwdpb.PacketFieldNum_PACKET_FIELD_NUM_IP_QOS, + Instance: 1, + }}, + FieldId: &fwdpb.PacketFieldId{Field: &fwdpb.PacketField{FieldNum: fwdpb.PacketFieldNum_PACKET_FIELD_NUM_IP_QOS}}, + }, + }, + }, { + ActionType: fwdpb.ActionType_ACTION_TYPE_UPDATE, + Action: &fwdpb.ActionDesc_Update{ + Update: &fwdpb.UpdateActionDesc{ + Type: fwdpb.UpdateType_UPDATE_TYPE_COPY, + Field: &fwdpb.PacketFieldId{Field: &fwdpb.PacketField{ + FieldNum: fwdpb.PacketFieldNum_PACKET_FIELD_NUM_IP_HOP, + Instance: 1, + }}, + FieldId: &fwdpb.PacketFieldId{Field: &fwdpb.PacketField{FieldNum: fwdpb.PacketFieldNum_PACKET_FIELD_NUM_IP_HOP}}, + }, + }, + }}, + }}, + }, + }} + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + dplane := &fakeSwitchDataplane{} + c, mgr, stopFn := newTestTunnel(t, dplane) + defer stopFn() + for k, v := range tt.types { + mgr.SetType(k, v) + } + mgr.StoreAttributes(1, &saipb.SwitchAttribute{ + CpuPort: proto.Uint64(10), + }) + _, gotErr := c.CreateTunnel(context.TODO(), tt.req) + if diff := errdiff.Check(gotErr, tt.wantErr); diff != "" { + t.Fatalf("CreateTunnel() unexpected err: %s", diff) + } + if gotErr != nil { + return + } + if d := cmp.Diff(dplane.gotEntryAddReqs[0], tt.wantReq, protocmp.Transform()); d != "" { + t.Errorf("CreateTunnel() failed: diff(-got,+want)\n:%s", d) + } + }) + } +} + +func newTestTunnel(t testing.TB, api switchDataplaneAPI) (saipb.TunnelClient, *attrmgr.AttrMgr, func()) { + conn, mgr, stopFn := newTestServer(t, func(mgr *attrmgr.AttrMgr, srv *grpc.Server) { + newTunnel(mgr, api, srv) + }) + return saipb.NewTunnelClient(conn), mgr, stopFn +} diff --git a/proto/forwarding/forwarding_common.pb.go b/proto/forwarding/forwarding_common.pb.go index 13496ffd..baf8629e 100644 --- a/proto/forwarding/forwarding_common.pb.go +++ b/proto/forwarding/forwarding_common.pb.go @@ -278,6 +278,7 @@ const ( PacketFieldNum_PACKET_FIELD_NUM_TRAP_ID PacketFieldNum = 59 PacketFieldNum_PACKET_FIELD_NUM_INPUT_IFACE PacketFieldNum = 60 PacketFieldNum_PACKET_FIELD_NUM_OUTPUT_IFACE PacketFieldNum = 61 + PacketFieldNum_PACKET_FIELD_NUM_TUNNEL_ID PacketFieldNum = 62 PacketFieldNum_PACKET_FIELD_NUM_COUNT PacketFieldNum = 1000 ) @@ -326,6 +327,7 @@ var ( 59: "PACKET_FIELD_NUM_TRAP_ID", 60: "PACKET_FIELD_NUM_INPUT_IFACE", 61: "PACKET_FIELD_NUM_OUTPUT_IFACE", + 62: "PACKET_FIELD_NUM_TUNNEL_ID", 1000: "PACKET_FIELD_NUM_COUNT", } PacketFieldNum_value = map[string]int32{ @@ -371,6 +373,7 @@ var ( "PACKET_FIELD_NUM_TRAP_ID": 59, "PACKET_FIELD_NUM_INPUT_IFACE": 60, "PACKET_FIELD_NUM_OUTPUT_IFACE": 61, + "PACKET_FIELD_NUM_TUNNEL_ID": 62, "PACKET_FIELD_NUM_COUNT": 1000, } ) @@ -2711,7 +2714,7 @@ var file_proto_forwarding_forwarding_common_proto_rawDesc = []byte{ 0x0a, 0x13, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x5f, 0x49, 0x44, 0x5f, 0x49, 0x50, 0x10, 0x13, 0x12, 0x1b, 0x0a, 0x16, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x5f, 0x49, 0x44, 0x5f, 0x43, 0x4f, 0x55, 0x4e, - 0x54, 0x10, 0xe8, 0x07, 0x2a, 0xca, 0x0b, 0x0a, 0x0e, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x46, + 0x54, 0x10, 0xe8, 0x07, 0x2a, 0xea, 0x0b, 0x0a, 0x0e, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4e, 0x75, 0x6d, 0x12, 0x20, 0x0a, 0x1c, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x4e, 0x55, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x50, 0x41, 0x43, @@ -2802,7 +2805,9 @@ var file_proto_forwarding_forwarding_common_proto_rawDesc = []byte{ 0x4e, 0x55, 0x4d, 0x5f, 0x49, 0x4e, 0x50, 0x55, 0x54, 0x5f, 0x49, 0x46, 0x41, 0x43, 0x45, 0x10, 0x3c, 0x12, 0x21, 0x0a, 0x1d, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x4e, 0x55, 0x4d, 0x5f, 0x4f, 0x55, 0x54, 0x50, 0x55, 0x54, 0x5f, 0x49, 0x46, 0x41, - 0x43, 0x45, 0x10, 0x3d, 0x12, 0x1b, 0x0a, 0x16, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x46, + 0x43, 0x45, 0x10, 0x3d, 0x12, 0x1e, 0x0a, 0x1a, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x46, + 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x4e, 0x55, 0x4d, 0x5f, 0x54, 0x55, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, + 0x49, 0x44, 0x10, 0x3e, 0x12, 0x1b, 0x0a, 0x16, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x4e, 0x55, 0x4d, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0xe8, 0x07, 0x2a, 0xda, 0x0a, 0x0a, 0x09, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x45, 0x52, 0x5f, 0x49, 0x44, 0x5f, 0x55, 0x4e, diff --git a/proto/forwarding/forwarding_common.proto b/proto/forwarding/forwarding_common.proto index e8fada61..8c2de29c 100644 --- a/proto/forwarding/forwarding_common.proto +++ b/proto/forwarding/forwarding_common.proto @@ -174,6 +174,7 @@ enum PacketFieldNum { PACKET_FIELD_NUM_TRAP_ID = 59; // Trap id (metadata). PACKET_FIELD_NUM_INPUT_IFACE = 60; // Input L3 interface (metadata). PACKET_FIELD_NUM_OUTPUT_IFACE = 61; // Output L3 interface (metadata). + PACKET_FIELD_NUM_TUNNEL_ID = 62; // Tunnel ID (metadata). PACKET_FIELD_NUM_COUNT = 1000; }