From 244e7957a5fd87b688b8e00449999ce09e2725af Mon Sep 17 00:00:00 2001 From: Guo-shiuan Wang Date: Wed, 20 Mar 2024 20:54:30 +0000 Subject: [PATCH 1/6] MyMac integration test. --- dataplane/BUILD | 1 + dataplane/saiserver/acl.go | 9 +++ dataplane/saiserver/attrmgr/attrmgr.go | 1 + dataplane/server.go | 4 +- .../dataplane/basictraffic/BUILD | 1 + .../basictraffic/basic_traffic_test.go | 77 +++++++++++++------ 6 files changed, 69 insertions(+), 24 deletions(-) diff --git a/dataplane/BUILD b/dataplane/BUILD index b1f95896..6768a5b8 100644 --- a/dataplane/BUILD +++ b/dataplane/BUILD @@ -18,6 +18,7 @@ go_library( "//gnmi/oc", "//gnmi/reconciler", "//proto/forwarding", + "@com_github_golang_glog//:glog", "@com_github_openconfig_gnmi//proto/gnmi", "@com_github_openconfig_ygnmi//ygnmi", "@org_golang_google_grpc//:go_default_library", diff --git a/dataplane/saiserver/acl.go b/dataplane/saiserver/acl.go index 0ba5e724..1f46ece9 100644 --- a/dataplane/saiserver/acl.go +++ b/dataplane/saiserver/acl.go @@ -391,6 +391,15 @@ func (m *myMac) CreateMyMac(ctx context.Context, req *saipb.CreateMyMacRequest) if _, err := m.dataplane.TableEntryAdd(ctx, mReq); err != nil { return nil, err } + m.myMacTable[id] = mi + myMacEntry := &saipb.MyMacAttribute{ + Priority: req.Priority, + PortId: req.PortId, + VlanId: req.VlanId, + MacAddress: req.MacAddress, + MacAddressMask: req.MacAddressMask, + } + m.mgr.StoreAttributes(id, myMacEntry) return &saipb.CreateMyMacResponse{Oid: id}, nil } diff --git a/dataplane/saiserver/attrmgr/attrmgr.go b/dataplane/saiserver/attrmgr/attrmgr.go index 3e0600d1..3e579de8 100644 --- a/dataplane/saiserver/attrmgr/attrmgr.go +++ b/dataplane/saiserver/attrmgr/attrmgr.go @@ -267,6 +267,7 @@ func (mgr *AttrMgr) storeAttributes(id string, msg proto.Message) { mgr.mu.Lock() defer mgr.mu.Unlock() + log.Infof("Set %s to %+v", id, msg) ty := proto.GetExtension(msg.ProtoReflect().Descriptor().Options(), saipb.E_SaiType).(saipb.ObjectType) if ty != saipb.ObjectType_OBJECT_TYPE_UNSPECIFIED { mgr.SetType(id, ty) diff --git a/dataplane/server.go b/dataplane/server.go index 15719ac5..55d4c4b9 100644 --- a/dataplane/server.go +++ b/dataplane/server.go @@ -20,6 +20,7 @@ import ( "fmt" "net" + log "github.com/golang/glog" "github.com/openconfig/ygnmi/ygnmi" "google.golang.org/grpc" "google.golang.org/grpc/credentials/local" @@ -107,7 +108,7 @@ func (d *Dataplane) Start(ctx context.Context, c gpb.GNMIClient, target string) // Allow all traffic to L3 processing. mmc := saipb.NewMyMacClient(conn) - _, err = mmc.CreateMyMac(context.Background(), &saipb.CreateMyMacRequest{ + resp, err := mmc.CreateMyMac(context.Background(), &saipb.CreateMyMacRequest{ Switch: swResp.Oid, Priority: proto.Uint32(1), MacAddress: []byte{0, 0, 0, 0, 0, 0}, @@ -116,6 +117,7 @@ func (d *Dataplane) Start(ctx context.Context, c gpb.GNMIClient, target string) if err != nil { return err } + log.Infof("Craig MyMac OID: %+v", resp.Oid) _, err = hostif.CreateHostifTrap(ctx, &saipb.CreateHostifTrapRequest{ Switch: swResp.Oid, diff --git a/integration_tests/dataplane/basictraffic/BUILD b/integration_tests/dataplane/basictraffic/BUILD index 26a2e955..874a732a 100644 --- a/integration_tests/dataplane/basictraffic/BUILD +++ b/integration_tests/dataplane/basictraffic/BUILD @@ -11,6 +11,7 @@ go_test( "@com_github_open_traffic_generator_snappi_gosnappi//:gosnappi", "@com_github_openconfig_ondatra//:ondatra", "@com_github_openconfig_ondatra//binding", + "@com_github_golang_glog//:glog", "@com_github_openconfig_ondatra//gnmi", "@org_golang_google_grpc//:go_default_library", "@org_golang_google_protobuf//proto", diff --git a/integration_tests/dataplane/basictraffic/basic_traffic_test.go b/integration_tests/dataplane/basictraffic/basic_traffic_test.go index d0575bff..4f13b059 100644 --- a/integration_tests/dataplane/basictraffic/basic_traffic_test.go +++ b/integration_tests/dataplane/basictraffic/basic_traffic_test.go @@ -17,6 +17,7 @@ package basictraffic import ( "context" + "fmt" "net" "strconv" "testing" @@ -111,14 +112,6 @@ func configureDUT(t testing.TB, dut *ondatra.DUTDevice) { if err != nil { t.Fatal(err) } - // Allow all traffic to L3 processing. - mmc := saipb.NewMyMacClient(conn) - _, err = mmc.CreateMyMac(context.Background(), &saipb.CreateMyMacRequest{ - Switch: 1, - Priority: proto.Uint32(1), - MacAddress: []byte{0, 0, 0, 0, 0, 0}, - MacAddressMask: []byte{0, 0, 0, 0, 0, 0}, - }) mac1, err := net.ParseMAC(dutPort1.MAC) if err != nil { @@ -179,17 +172,56 @@ func configureDUT(t testing.TB, dut *ondatra.DUTDevice) { } func TestTraffic(t *testing.T) { - ate := ondatra.ATE(t, "ate") - ateTop := configureATE(t, ate) - ate.OTG().PushConfig(t, ateTop) - ate.OTG().StartProtocols(t) - - dut := ondatra.DUT(t, "dut") - configureDUT(t, dut) - - loss := testTraffic(t, ate, ateTop, atePort1, dutPort1, atePort2, 10*time.Second) - if loss > 1 { - t.Errorf("loss %f, greater than 1", loss) + tests := []struct { + desc string + myMacFunc func(*ondatra.DUTDevice) error + passed bool + }{{ + desc: "Passed", + passed: true, + }, { + desc: "Failed", + myMacFunc: func(dut *ondatra.DUTDevice) error { + conn := dataplaneConn(t, dut) + mmc := saipb.NewMyMacClient(conn) + if _, err := mmc.RemoveMyMac(context.Background(), &saipb.RemoveMyMacRequest{ + Oid: 9, + }); err != nil { + return fmt.Errorf("Failed to remove MyMac: %+v", err) + } + return nil + }, + }} + + for _, tt := range tests { + ate := ondatra.ATE(t, "ate") + ateTop := configureATE(t, ate) + ate.OTG().PushConfig(t, ateTop) + ate.OTG().StartProtocols(t) + + dut := ondatra.DUT(t, "dut") + configureDUT(t, dut) + + conn := dataplaneConn(t, dut) + mmc := saipb.NewSwitchClient(conn) + _, err := mmc.GetSwitchAttribute(context.Background(), &saipb.GetSwitchAttributeRequest{Oid: 1}) + if err != nil { + t.Fatalf("Failed to MyMac Get attrs: %+v", err) + } + // t.Infof("Craig: %+v", rsp.GetAttr()) + + if tt.myMacFunc != nil { + if err := tt.myMacFunc(dut); err != nil { + t.Fatal(err) + } + } + tx, rx := testTraffic(t, ate, ateTop, atePort1, dutPort1, atePort2, 10*time.Second) + switch { + case tt.passed && rx != tx: + t.Errorf("got %d, expect 0", rx-tx) + case !tt.passed && rx != 0: + t.Errorf("got %fd, expect %d", rx, tx) + } } } @@ -207,8 +239,8 @@ func configureATE(t *testing.T, ate *ondatra.ATEDevice) gosnappi.Config { // testTraffic generates traffic flow from source network to // destination network via srcEndPoint to dstEndPoint and checks for -// packet loss and returns loss percentage as float. -func testTraffic(t *testing.T, ate *ondatra.ATEDevice, top gosnappi.Config, srcEndPoint, srcPeerEndpoint, dstEndPoint attrs.Attributes, dur time.Duration) float32 { +// packet loss and returns the number of tx and rx packets. +func testTraffic(t *testing.T, ate *ondatra.ATEDevice, top gosnappi.Config, srcEndPoint, srcPeerEndpoint, dstEndPoint attrs.Attributes, dur time.Duration) (uint64, uint64) { otg := ate.OTG() top.Flows().Clear().Items() @@ -243,6 +275,5 @@ func testTraffic(t *testing.T, ate *ondatra.ATEDevice, top gosnappi.Config, srcE txPkts := gnmi.Get(t, otg, gnmi.OTG().Flow("Flow").Counters().OutPkts().State()) rxPkts := gnmi.Get(t, otg, gnmi.OTG().Flow("Flow").Counters().InPkts().State()) - lossPct := (txPkts - rxPkts) * 100 / txPkts - return float32(lossPct) + return txPkts, rxPkts } From ecb3210c7999ad514e01a8e752af10dcc2c5ba82 Mon Sep 17 00:00:00 2001 From: Guo-shiuan Wang Date: Thu, 21 Mar 2024 20:23:08 +0000 Subject: [PATCH 2/6] Revert the basic traffic test. --- .../dataplane/basictraffic/BUILD | 1 - .../basictraffic/basic_traffic_test.go | 77 ++++++------------- 2 files changed, 23 insertions(+), 55 deletions(-) diff --git a/integration_tests/dataplane/basictraffic/BUILD b/integration_tests/dataplane/basictraffic/BUILD index 874a732a..26a2e955 100644 --- a/integration_tests/dataplane/basictraffic/BUILD +++ b/integration_tests/dataplane/basictraffic/BUILD @@ -11,7 +11,6 @@ go_test( "@com_github_open_traffic_generator_snappi_gosnappi//:gosnappi", "@com_github_openconfig_ondatra//:ondatra", "@com_github_openconfig_ondatra//binding", - "@com_github_golang_glog//:glog", "@com_github_openconfig_ondatra//gnmi", "@org_golang_google_grpc//:go_default_library", "@org_golang_google_protobuf//proto", diff --git a/integration_tests/dataplane/basictraffic/basic_traffic_test.go b/integration_tests/dataplane/basictraffic/basic_traffic_test.go index 4f13b059..d0575bff 100644 --- a/integration_tests/dataplane/basictraffic/basic_traffic_test.go +++ b/integration_tests/dataplane/basictraffic/basic_traffic_test.go @@ -17,7 +17,6 @@ package basictraffic import ( "context" - "fmt" "net" "strconv" "testing" @@ -112,6 +111,14 @@ func configureDUT(t testing.TB, dut *ondatra.DUTDevice) { if err != nil { t.Fatal(err) } + // Allow all traffic to L3 processing. + mmc := saipb.NewMyMacClient(conn) + _, err = mmc.CreateMyMac(context.Background(), &saipb.CreateMyMacRequest{ + Switch: 1, + Priority: proto.Uint32(1), + MacAddress: []byte{0, 0, 0, 0, 0, 0}, + MacAddressMask: []byte{0, 0, 0, 0, 0, 0}, + }) mac1, err := net.ParseMAC(dutPort1.MAC) if err != nil { @@ -172,56 +179,17 @@ func configureDUT(t testing.TB, dut *ondatra.DUTDevice) { } func TestTraffic(t *testing.T) { - tests := []struct { - desc string - myMacFunc func(*ondatra.DUTDevice) error - passed bool - }{{ - desc: "Passed", - passed: true, - }, { - desc: "Failed", - myMacFunc: func(dut *ondatra.DUTDevice) error { - conn := dataplaneConn(t, dut) - mmc := saipb.NewMyMacClient(conn) - if _, err := mmc.RemoveMyMac(context.Background(), &saipb.RemoveMyMacRequest{ - Oid: 9, - }); err != nil { - return fmt.Errorf("Failed to remove MyMac: %+v", err) - } - return nil - }, - }} - - for _, tt := range tests { - ate := ondatra.ATE(t, "ate") - ateTop := configureATE(t, ate) - ate.OTG().PushConfig(t, ateTop) - ate.OTG().StartProtocols(t) - - dut := ondatra.DUT(t, "dut") - configureDUT(t, dut) - - conn := dataplaneConn(t, dut) - mmc := saipb.NewSwitchClient(conn) - _, err := mmc.GetSwitchAttribute(context.Background(), &saipb.GetSwitchAttributeRequest{Oid: 1}) - if err != nil { - t.Fatalf("Failed to MyMac Get attrs: %+v", err) - } - // t.Infof("Craig: %+v", rsp.GetAttr()) - - if tt.myMacFunc != nil { - if err := tt.myMacFunc(dut); err != nil { - t.Fatal(err) - } - } - tx, rx := testTraffic(t, ate, ateTop, atePort1, dutPort1, atePort2, 10*time.Second) - switch { - case tt.passed && rx != tx: - t.Errorf("got %d, expect 0", rx-tx) - case !tt.passed && rx != 0: - t.Errorf("got %fd, expect %d", rx, tx) - } + ate := ondatra.ATE(t, "ate") + ateTop := configureATE(t, ate) + ate.OTG().PushConfig(t, ateTop) + ate.OTG().StartProtocols(t) + + dut := ondatra.DUT(t, "dut") + configureDUT(t, dut) + + loss := testTraffic(t, ate, ateTop, atePort1, dutPort1, atePort2, 10*time.Second) + if loss > 1 { + t.Errorf("loss %f, greater than 1", loss) } } @@ -239,8 +207,8 @@ func configureATE(t *testing.T, ate *ondatra.ATEDevice) gosnappi.Config { // testTraffic generates traffic flow from source network to // destination network via srcEndPoint to dstEndPoint and checks for -// packet loss and returns the number of tx and rx packets. -func testTraffic(t *testing.T, ate *ondatra.ATEDevice, top gosnappi.Config, srcEndPoint, srcPeerEndpoint, dstEndPoint attrs.Attributes, dur time.Duration) (uint64, uint64) { +// packet loss and returns loss percentage as float. +func testTraffic(t *testing.T, ate *ondatra.ATEDevice, top gosnappi.Config, srcEndPoint, srcPeerEndpoint, dstEndPoint attrs.Attributes, dur time.Duration) float32 { otg := ate.OTG() top.Flows().Clear().Items() @@ -275,5 +243,6 @@ func testTraffic(t *testing.T, ate *ondatra.ATEDevice, top gosnappi.Config, srcE txPkts := gnmi.Get(t, otg, gnmi.OTG().Flow("Flow").Counters().OutPkts().State()) rxPkts := gnmi.Get(t, otg, gnmi.OTG().Flow("Flow").Counters().InPkts().State()) - return txPkts, rxPkts + lossPct := (txPkts - rxPkts) * 100 / txPkts + return float32(lossPct) } From e935d5b92bd276a6aa4841bf0f2e712847cfcc81 Mon Sep 17 00:00:00 2001 From: Guo-shiuan Wang Date: Thu, 21 Mar 2024 20:27:15 +0000 Subject: [PATCH 3/6] Update switch MyMacList attriute. --- dataplane/saiserver/acl.go | 24 +++++++++++++++--------- dataplane/saiserver/attrmgr/attrmgr.go | 2 +- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/dataplane/saiserver/acl.go b/dataplane/saiserver/acl.go index 1f46ece9..3a78d5aa 100644 --- a/dataplane/saiserver/acl.go +++ b/dataplane/saiserver/acl.go @@ -387,19 +387,25 @@ func (m *myMac) CreateMyMac(ctx context.Context, req *saipb.CreateMyMacRequest) EntryDesc: ed, Actions: []*fwdpb.ActionDesc{{ActionType: fwdpb.ActionType_ACTION_TYPE_CONTINUE}}, } - if _, err := m.dataplane.TableEntryAdd(ctx, mReq); err != nil { return nil, err } m.myMacTable[id] = mi - myMacEntry := &saipb.MyMacAttribute{ - Priority: req.Priority, - PortId: req.PortId, - VlanId: req.VlanId, - MacAddress: req.MacAddress, - MacAddressMask: req.MacAddressMask, - } - m.mgr.StoreAttributes(id, myMacEntry) + // Populate the switch attribute. + saReq := &saipb.GetSwitchAttributeRequest{ + Oid: switchID, + AttrType: []saipb.SwitchAttr{ + saipb.SwitchAttr_SWITCH_ATTR_MY_MAC_LIST, + }, + } + saResp := &saipb.GetSwitchAttributeResponse{} + if err := m.mgr.PopulateAttributes(saReq, saResp); err != nil { + return nil, fmt.Errorf("Failed to populate switch attributes: %v", err) + } + mml := append(saResp.GetAttr().MyMacList, id) + m.mgr.StoreAttributes(switchID, &saipb.SwitchAttribute{ + MyMacList: mml, + }) return &saipb.CreateMyMacResponse{Oid: id}, nil } diff --git a/dataplane/saiserver/attrmgr/attrmgr.go b/dataplane/saiserver/attrmgr/attrmgr.go index 3e579de8..4f90b2f3 100644 --- a/dataplane/saiserver/attrmgr/attrmgr.go +++ b/dataplane/saiserver/attrmgr/attrmgr.go @@ -267,7 +267,7 @@ func (mgr *AttrMgr) storeAttributes(id string, msg proto.Message) { mgr.mu.Lock() defer mgr.mu.Unlock() - log.Infof("Set %s to %+v", id, msg) + // log.Infof("Set %s to %+v", id, msg) ty := proto.GetExtension(msg.ProtoReflect().Descriptor().Options(), saipb.E_SaiType).(saipb.ObjectType) if ty != saipb.ObjectType_OBJECT_TYPE_UNSPECIFIED { mgr.SetType(id, ty) From 498e871ff01b7c9499805a3c8c732335d0b7d747 Mon Sep 17 00:00:00 2001 From: Guo-shiuan Wang Date: Thu, 21 Mar 2024 21:45:36 +0000 Subject: [PATCH 4/6] Add MyMac test. --- integration_tests/dataplane/mymac/BUILD | 18 + .../dataplane/mymac/mymac_test.go | 310 ++++++++++++++++++ .../dataplane/mymac/testbed.pb.txt | 36 ++ 3 files changed, 364 insertions(+) create mode 100644 integration_tests/dataplane/mymac/BUILD create mode 100644 integration_tests/dataplane/mymac/mymac_test.go create mode 100644 integration_tests/dataplane/mymac/testbed.pb.txt diff --git a/integration_tests/dataplane/mymac/BUILD b/integration_tests/dataplane/mymac/BUILD new file mode 100644 index 00000000..4569b6ce --- /dev/null +++ b/integration_tests/dataplane/mymac/BUILD @@ -0,0 +1,18 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_test") + +go_test( + name = "mymac_test", + srcs = ["mymac_test.go"], + data = [":testbed.pb.txt"], + deps = [ + "//dataplane/proto/sai", + "//internal/attrs", + "//internal/binding", + "@com_github_open_traffic_generator_snappi_gosnappi//:gosnappi", + "@com_github_openconfig_ondatra//:ondatra", + "@com_github_openconfig_ondatra//binding", + "@com_github_openconfig_ondatra//gnmi", + "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_protobuf//proto", + ], +) diff --git a/integration_tests/dataplane/mymac/mymac_test.go b/integration_tests/dataplane/mymac/mymac_test.go new file mode 100644 index 00000000..a9d7e31a --- /dev/null +++ b/integration_tests/dataplane/mymac/mymac_test.go @@ -0,0 +1,310 @@ +// 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 +// +// https://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. + +// TODO: Fill this in with a real test +package basictraffic + +import ( + "context" + "fmt" + "net" + "strconv" + "testing" + "time" + + "github.com/open-traffic-generator/snappi/gosnappi" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "google.golang.org/grpc" + "google.golang.org/protobuf/proto" + + "github.com/openconfig/lemming/internal/attrs" + "github.com/openconfig/lemming/internal/binding" + + obind "github.com/openconfig/ondatra/binding" + + saipb "github.com/openconfig/lemming/dataplane/proto/sai" +) + +const ( + ipv4PrefixLen = 30 + ateDstNetCIDR = "198.51.100.0/24" + ateIndirectNH = "203.0.113.1" + ateIndirectNHCIDR = ateIndirectNH + "/32" + nhIndex = 1 + nhgIndex = 42 + nhIndex2 = 2 + nhgIndex2 = 52 + nhIndex3 = 3 + nhgIndex3 = 62 + defaultNetworkInstance = "DEFAULT" +) + +var ( + dutPort1 = attrs.Attributes{ + Desc: "dutPort1", + MAC: "10:10:10:10:10:10", + IPv4: "192.0.2.1", + IPv4Len: ipv4PrefixLen, + } + + atePort1 = attrs.Attributes{ + Name: "port1", + MAC: "02:00:01:01:01:01", + IPv4: "192.0.2.2", + IPv4Len: ipv4PrefixLen, + } + + dutPort2 = attrs.Attributes{ + Desc: "dutPort2", + MAC: "10:10:10:10:10:11", + IPv4: "192.0.2.5", + IPv4Len: ipv4PrefixLen, + } + + atePort2 = attrs.Attributes{ + Name: "port2", + MAC: "02:00:02:01:01:01", + IPv4: "192.0.2.6", + IPv4Len: ipv4PrefixLen, + } +) + +func TestMain(m *testing.M) { + ondatra.RunTests(m, binding.Local(".")) +} + +func dataplaneConn(t testing.TB, dut *ondatra.DUTDevice) *grpc.ClientConn { + t.Helper() + var lemming interface { + DataplaneConn(ctx context.Context, opts ...grpc.DialOption) (*grpc.ClientConn, error) + } + if err := obind.DUTAs(dut.RawAPIs().BindingDUT(), &lemming); err != nil { + t.Fatalf("failed to get lemming dut: %v", err) + } + conn, err := lemming.DataplaneConn(context.Background()) + if err != nil { + t.Fatal(err) + } + return conn +} + +func configureDUT(t testing.TB, dut *ondatra.DUTDevice) { + t.Helper() + conn := dataplaneConn(t, dut) + ric := saipb.NewRouterInterfaceClient(conn) + port1ID, err := strconv.ParseUint(dut.Port(t, "port1").Name(), 10, 64) + if err != nil { + t.Fatal(err) + } + port2ID, err := strconv.ParseUint(dut.Port(t, "port2").Name(), 10, 64) + if err != nil { + t.Fatal(err) + } + + mac1, err := net.ParseMAC(dutPort1.MAC) + if err != nil { + t.Fatal(err) + } + _, err = ric.CreateRouterInterface(context.Background(), &saipb.CreateRouterInterfaceRequest{ + Switch: 1, + PortId: proto.Uint64(port1ID), + Type: saipb.RouterInterfaceType_ROUTER_INTERFACE_TYPE_PORT.Enum(), + SrcMacAddress: mac1, + }) + if err != nil { + t.Fatal(err) + } + mac2, err := net.ParseMAC(dutPort2.MAC) + if err != nil { + t.Fatal(err) + } + rif2Resp, err := ric.CreateRouterInterface(context.Background(), &saipb.CreateRouterInterfaceRequest{ + Switch: 1, + PortId: proto.Uint64(port2ID), + Type: saipb.RouterInterfaceType_ROUTER_INTERFACE_TYPE_PORT.Enum(), + SrcMacAddress: mac2, + }) + if err != nil { + t.Fatal(err) + } + + rc := saipb.NewRouteClient(conn) + _, err = rc.CreateRouteEntry(context.Background(), &saipb.CreateRouteEntryRequest{ + Entry: &saipb.RouteEntry{ + SwitchId: 1, + VrId: 0, + Destination: &saipb.IpPrefix{ + Addr: []byte{192, 0, 2, 6}, + Mask: []byte{255, 255, 255, 255}, + }, + }, + PacketAction: saipb.PacketAction_PACKET_ACTION_FORWARD.Enum(), + NextHopId: &rif2Resp.Oid, + }) + if err != nil { + t.Fatal(err) + } + + nc := saipb.NewNeighborClient(conn) + _, err = nc.CreateNeighborEntry(context.Background(), &saipb.CreateNeighborEntryRequest{ + Entry: &saipb.NeighborEntry{ + SwitchId: 1, + RifId: rif2Resp.Oid, + IpAddress: []byte{192, 0, 2, 6}, + }, + DstMacAddress: []byte{0o2, 0o0, 0o2, 0o1, 0o1, 0o1}, + }) + if err != nil { + t.Fatal(err) + } +} + +// clearMyMac removes all entities in MyMac table. +func clearMyMac(t *testing.T, dut *ondatra.DUTDevice) error { + // Try to get the MyMac list, and there should be only one entry. + conn := dataplaneConn(t, dut) + mmc := saipb.NewSwitchClient(conn) + var err error + req := &saipb.GetSwitchAttributeRequest{ + Oid: 1, + AttrType: []saipb.SwitchAttr{saipb.SwitchAttr_SWITCH_ATTR_MY_MAC_LIST}, + } + resp, err := mmc.GetSwitchAttribute(context.Background(), req) + if err != nil { + return err + } + oids := resp.GetAttr().MyMacList + if oids == nil { + return nil + } + for _, oid := range oids { + mmc := saipb.NewMyMacClient(conn) + if _, err := mmc.RemoveMyMac(context.Background(), &saipb.RemoveMyMacRequest{ + Oid: oid, + }); err != nil { + return fmt.Errorf("Failed to remove MyMac: %+v", err) + } + } + t.Logf("MyMac table cleared.") + return nil +} + +// restoreMyMac restores the rule to allow all traffic to send to L3. +func restoreMyMac(t *testing.T, dut *ondatra.DUTDevice) error { + // Allow all traffic to L3 processing. + conn := dataplaneConn(t, dut) + mmc := saipb.NewMyMacClient(conn) + _, err := mmc.CreateMyMac(context.Background(), &saipb.CreateMyMacRequest{ + Switch: 1, + Priority: proto.Uint32(1), + MacAddress: []byte{0, 0, 0, 0, 0, 0}, + MacAddressMask: []byte{0, 0, 0, 0, 0, 0}, + }) + if err != nil { + return err + } + t.Logf("MyMac table restored.") + return nil +} + +func TestMyMac(t *testing.T) { + tests := []struct { + desc string + clearMyMac bool + macAddr []byte + macAddrMask []byte + passed bool + }{{ + desc: "Traffic dropped", // Remove the default entry that allows all traffic to L3. + clearMyMac: true, + passed: false, + }} + ate := ondatra.ATE(t, "ate") + ateTop := configureATE(t, ate) + ate.OTG().PushConfig(t, ateTop) + ate.OTG().StartProtocols(t) + + dut := ondatra.DUT(t, "dut") + configureDUT(t, dut) + + for _, tt := range tests { + tx, rx := testTraffic(t, ate, ateTop, atePort1, dutPort1, atePort2, 10*time.Second, dut, tt.clearMyMac) + t.Logf("[%s] Got TX: %d, RX: %d", tt.desc, tx, rx) + if tx == 0 { + t.Fatalf("No packet sent") + } + switch { + case tt.passed && rx != tx, !tt.passed && rx != 0: + t.Errorf("got %d, expect %d", rx, tx) + } + } +} + +// configureATE configures port1 and port2 on the ATE. +func configureATE(t *testing.T, ate *ondatra.ATEDevice) gosnappi.Config { + top := gosnappi.NewConfig() + + p1 := ate.Port(t, "port1") + p2 := ate.Port(t, "port2") + + atePort1.AddToOTG(top, p1, &dutPort1) + atePort2.AddToOTG(top, p2, &dutPort2) + return top +} + +// testTraffic generates traffic flow from source network to +// destination network via srcEndPoint to dstEndPoint and checks for +// packet loss and returns the number of tx and rx packets. +func testTraffic(t *testing.T, ate *ondatra.ATEDevice, top gosnappi.Config, srcEndPoint, srcPeerEndpoint, dstEndPoint attrs.Attributes, dur time.Duration, dut *ondatra.DUTDevice, clearMyMacTable bool) (uint64, uint64) { + if clearMyMacTable { + clearMyMac(t, dut) + defer restoreMyMac(t, dut) + } + otg := ate.OTG() + top.Flows().Clear().Items() + + ipFLow := top.Flows().Add().SetName("Flow") + ipFLow.Metrics().SetEnable(true) + ipFLow.TxRx().Port().SetTxName(srcEndPoint.Name).SetRxNames([]string{dstEndPoint.Name}) + + ipFLow.Rate().SetPps(10) + + // OTG specifies that the order of the .Packet().Add() calls determines + // the stack of headers that are to be used, starting at the outer-most and + // ending with the inner-most. + + // Set up ethernet layer. + eth := ipFLow.Packet().Add().Ethernet() + eth.Src().SetValue(srcEndPoint.MAC) + eth.Dst().SetValue(srcPeerEndpoint.MAC) + + ip4 := ipFLow.Packet().Add().Ipv4() + ip4.Src().SetValue(srcEndPoint.IPv4) + ip4.Dst().SetValue(dstEndPoint.IPv4) + ip4.Version().SetValue(4) + + otg.PushConfig(t, top) + + otg.StartTraffic(t) + time.Sleep(dur) + t.Logf("Stop traffic") + otg.StopTraffic(t) + + time.Sleep(5 * time.Second) + + txPkts := gnmi.Get(t, otg, gnmi.OTG().Flow("Flow").Counters().OutPkts().State()) + rxPkts := gnmi.Get(t, otg, gnmi.OTG().Flow("Flow").Counters().InPkts().State()) + return txPkts, rxPkts +} diff --git a/integration_tests/dataplane/mymac/testbed.pb.txt b/integration_tests/dataplane/mymac/testbed.pb.txt new file mode 100644 index 00000000..b67a0943 --- /dev/null +++ b/integration_tests/dataplane/mymac/testbed.pb.txt @@ -0,0 +1,36 @@ + +# proto-file: github.com/openconfig/ondatra/blob/main/proto/testbed.proto +# proto-message: ondatra.Testbed + +# This testbed provides 2 links between a DUT and an ATE connected +# pairwise. + +duts { + id: "dut" + ports { + id: "port1" + } + ports { + id: "port2" + } +} + +ates { + id: "ate" + ports { + id: "port1" + } + ports { + id: "port2" + } +} + +links { + a: "dut:port1" + b: "ate:port1" +} + +links { + a: "dut:port2" + b: "ate:port2" +} From 0c1b212784b8f4c6e16e5274fa99527fb4a95b09 Mon Sep 17 00:00:00 2001 From: Guo-shiuan Wang Date: Thu, 21 Mar 2024 21:51:28 +0000 Subject: [PATCH 5/6] Remove unused code. --- dataplane/saiserver/attrmgr/attrmgr.go | 1 - dataplane/server.go | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/dataplane/saiserver/attrmgr/attrmgr.go b/dataplane/saiserver/attrmgr/attrmgr.go index 4f90b2f3..3e0600d1 100644 --- a/dataplane/saiserver/attrmgr/attrmgr.go +++ b/dataplane/saiserver/attrmgr/attrmgr.go @@ -267,7 +267,6 @@ func (mgr *AttrMgr) storeAttributes(id string, msg proto.Message) { mgr.mu.Lock() defer mgr.mu.Unlock() - // log.Infof("Set %s to %+v", id, msg) ty := proto.GetExtension(msg.ProtoReflect().Descriptor().Options(), saipb.E_SaiType).(saipb.ObjectType) if ty != saipb.ObjectType_OBJECT_TYPE_UNSPECIFIED { mgr.SetType(id, ty) diff --git a/dataplane/server.go b/dataplane/server.go index 55d4c4b9..15719ac5 100644 --- a/dataplane/server.go +++ b/dataplane/server.go @@ -20,7 +20,6 @@ import ( "fmt" "net" - log "github.com/golang/glog" "github.com/openconfig/ygnmi/ygnmi" "google.golang.org/grpc" "google.golang.org/grpc/credentials/local" @@ -108,7 +107,7 @@ func (d *Dataplane) Start(ctx context.Context, c gpb.GNMIClient, target string) // Allow all traffic to L3 processing. mmc := saipb.NewMyMacClient(conn) - resp, err := mmc.CreateMyMac(context.Background(), &saipb.CreateMyMacRequest{ + _, err = mmc.CreateMyMac(context.Background(), &saipb.CreateMyMacRequest{ Switch: swResp.Oid, Priority: proto.Uint32(1), MacAddress: []byte{0, 0, 0, 0, 0, 0}, @@ -117,7 +116,6 @@ func (d *Dataplane) Start(ctx context.Context, c gpb.GNMIClient, target string) if err != nil { return err } - log.Infof("Craig MyMac OID: %+v", resp.Oid) _, err = hostif.CreateHostifTrap(ctx, &saipb.CreateHostifTrapRequest{ Switch: swResp.Oid, From 589d9e3613573f4b20c6e36c7a7576cefbd9b5c7 Mon Sep 17 00:00:00 2001 From: Guo-shiuan Wang Date: Thu, 21 Mar 2024 23:23:53 +0000 Subject: [PATCH 6/6] Revised based on feedback. --- integration_tests/dataplane/mymac/mymac_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration_tests/dataplane/mymac/mymac_test.go b/integration_tests/dataplane/mymac/mymac_test.go index a9d7e31a..f5bd85c5 100644 --- a/integration_tests/dataplane/mymac/mymac_test.go +++ b/integration_tests/dataplane/mymac/mymac_test.go @@ -12,8 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// TODO: Fill this in with a real test -package basictraffic +package mymac import ( "context" @@ -220,6 +219,7 @@ func restoreMyMac(t *testing.T, dut *ondatra.DUTDevice) error { } func TestMyMac(t *testing.T) { + // TODO: add more sub-tests when the Magna issue is resolved. tests := []struct { desc string clearMyMac bool