From d041577e2f05612c054c3d7207a8d74b734d97a6 Mon Sep 17 00:00:00 2001 From: gavinz-ship-it Date: Fri, 6 Nov 2026 18:31:41 -0800 Subject: [PATCH 1/3] Update ports.go Avoid calling updatePortList repeatly for each port. --- dataplane/saiserver/ports.go | 67 +++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/dataplane/saiserver/ports.go b/dataplane/saiserver/ports.go index d712d45d..c12c2271 100644 --- a/dataplane/saiserver/ports.go +++ b/dataplane/saiserver/ports.go @@ -135,7 +135,7 @@ func (port *port) createQueue(ctx context.Context, id uint64, count int) ([]uint return queues, nil } -func (port *port) createSchedulerGroups(ctx context.Context, id uint64, queues []uint64) ([]uint64, error) { +func (port *port) createSchedulerGroup(ctx context.Context, id uint64, queues []uint64) ([]uint64, error) { var sgs []uint64 for i := 0; i < len(queues); i++ { sgResp, err := attrmgr.InvokeAndSave(ctx, port.mgr, port.sg.CreateSchedulerGroup, &saipb.CreateSchedulerGroupRequest{ @@ -155,21 +155,23 @@ func (port *port) createSchedulerGroups(ctx context.Context, id uint64, queues [ return sgs, nil } -func (port *port) updatePortList(id uint64) error { +func (port *port) updatePortList(ids ...uint64) error { switchID, ok := port.mgr.GetSwitchID() if !ok { return fmt.Errorf("failed to get switch ID") } - switchAttrs := &saipb.SwitchAttribute{} - if err := port.mgr.PopulateAllAttributes(switchID, switchAttrs); err != nil { - return fmt.Errorf("failed to get switch attributes: %v", err) - } uSwitchID, err := strconv.ParseUint(switchID, 10, 64) if err != nil { return err } - portList := switchAttrs.GetPortList() - portList = append(portList, id) + resp := &saipb.GetSwitchAttributeResponse{} + if err := port.mgr.PopulateAttributes(&saipb.GetSwitchAttributeRequest{ + Oid: uSwitchID, + AttrType: []saipb.SwitchAttr{saipb.SwitchAttr_SWITCH_ATTR_PORT_LIST}, + }, resp); err != nil { + return fmt.Errorf("failed to get switch port list: %v", err) + } + portList := append(resp.GetAttr().GetPortList(), ids...) port.mgr.StoreAttributes(uSwitchID, &saipb.SwitchAttribute{ PortList: portList, NumberOfActivePorts: proto.Uint32(uint32(len(portList))), @@ -182,7 +184,7 @@ func (port *port) storeAttributes(ctx context.Context, req *saipb.CreatePortRequ if err != nil { return err } - sgs, err := port.createSchedulerGroups(ctx, id, queues) + sgs, err := port.createSchedulerGroup(ctx, id, queues) if err != nil { return err } @@ -245,14 +247,22 @@ func (port *port) storeAttributes(ctx context.Context, req *saipb.CreatePortRequ OperStatus: operStatus, } port.mgr.StoreAttributes(id, attrs) - if err := port.updatePortList(id); err != nil { - return err - } return nil } // CreatePort creates a new port, mapping the port to ethX, where X is assigned sequentially from 1 to n. func (port *port) CreatePort(ctx context.Context, req *saipb.CreatePortRequest) (*saipb.CreatePortResponse, error) { + resp, err := port.createPort(ctx, req) + if err != nil { + return nil, err + } + if err := port.updatePortList(resp.GetOid()); err != nil { + return nil, err + } + return resp, nil +} + +func (port *port) createPort(ctx context.Context, req *saipb.CreatePortRequest) (*saipb.CreatePortResponse, error) { id := port.mgr.NextID() // Set the type early, otherwise the initial port notifs won't send. port.mgr.SetType(fmt.Sprint(id), saipb.ObjectType_OBJECT_TYPE_PORT) @@ -351,13 +361,20 @@ func (port *port) CreatePort(ctx context.Context, req *saipb.CreatePortRequest) // CreatePorts creates multiple ports. func (port *port) CreatePorts(ctx context.Context, re *saipb.CreatePortsRequest) (*saipb.CreatePortsResponse, error) { - resp := &saipb.CreatePortsResponse{} + resp := &saipb.CreatePortsResponse{ + Resps: make([]*saipb.CreatePortResponse, 0, len(re.GetReqs())), + } + oids := make([]uint64, 0, len(re.GetReqs())) for _, req := range re.GetReqs() { - res, err := attrmgr.InvokeAndSave(ctx, port.mgr, port.CreatePort, req) + res, err := attrmgr.InvokeAndSave(ctx, port.mgr, port.createPort, req) if err != nil { return nil, err } resp.Resps = append(resp.Resps, res) + oids = append(oids, res.GetOid()) + } + if err := port.updatePortList(oids...); err != nil { + return nil, err } return resp, nil } @@ -405,7 +422,7 @@ func (port *port) createCPUPort(ctx context.Context) (uint64, error) { if err != nil { return 0, err } - sgs, err := port.createSchedulerGroups(ctx, id, queues) + sgs, err := port.createSchedulerGroup(ctx, id, queues) if err != nil { return 0, err } @@ -629,19 +646,21 @@ func (port *port) RemovePort(ctx context.Context, req *saipb.RemovePortRequest) if !ok { return nil, fmt.Errorf("failed to get switch ID") } - switchAttrs := &saipb.SwitchAttribute{} - if err := port.mgr.PopulateAllAttributes(switchID, switchAttrs); err != nil { - return nil, fmt.Errorf("failed to get switch attributes: %v", err) - } uSwitchID, err := strconv.ParseUint(switchID, 10, 64) if err != nil { return nil, err } - portList := switchAttrs.GetPortList() - portOid := req.GetOid() - - if i := slices.Index(portList, portOid); i != -1 { - portList = slices.Delete(portList, i, i+1) + resp := &saipb.GetSwitchAttributeResponse{} + if err := port.mgr.PopulateAttributes(&saipb.GetSwitchAttributeRequest{ + Oid: uSwitchID, + AttrType: []saipb.SwitchAttr{saipb.SwitchAttr_SWITCH_ATTR_PORT_LIST}, + }, resp); err != nil { + return nil, fmt.Errorf("failed to get switch port list: %v", err) + } + portList := resp.GetAttr().GetPortList() + if i := slices.Index(portList, req.GetOid()); i != -1 { + portList[i] = portList[len(portList)-1] + portList = portList[:len(portList)-1] } port.mgr.StoreAttributes(uSwitchID, &saipb.SwitchAttribute{ PortList: portList, From 363bf7fcb9a0ad8505090e913cee23480b673d6c Mon Sep 17 00:00:00 2001 From: gavinz-ship-it Date: Fri, 6 Nov 2026 18:32:00 -0800 Subject: [PATCH 2/3] Update ports_test.go --- dataplane/saiserver/ports_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/dataplane/saiserver/ports_test.go b/dataplane/saiserver/ports_test.go index 9f1a7399..3c93e8a5 100644 --- a/dataplane/saiserver/ports_test.go +++ b/dataplane/saiserver/ports_test.go @@ -558,6 +558,7 @@ func newTestPort(t testing.TB, api switchDataplaneAPI, opts *dplaneopts.Options) swID := mgr.NextID() mgr.StoreAttributes(swID, &saipb.SwitchAttribute{ DefaultStpInstId: proto.Uint64(101), + PortList: []uint64{}, }) mgr.SetType(fmt.Sprint(swID), saipb.ObjectType_OBJECT_TYPE_SWITCH) resp, err := vlan.CreateVlan(context.Background(), &saipb.CreateVlanRequest{ From 583990a1b566dc3d060a5ab41eab3b1687c7f39a Mon Sep 17 00:00:00 2001 From: gavinz-ship-it Date: Fri, 6 Nov 2026 18:32:45 -0800 Subject: [PATCH 3/3] Update interface.go Update to call CreatePorts instead of CreatePort --- dataplane/dplanerc/interface.go | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/dataplane/dplanerc/interface.go b/dataplane/dplanerc/interface.go index 3263f47f..86900642 100644 --- a/dataplane/dplanerc/interface.go +++ b/dataplane/dplanerc/interface.go @@ -1197,12 +1197,30 @@ func (ni *Reconciler) setupPorts(ctx context.Context) error { return err } + var portLinks []netlink.Link + var portReqs []*saipb.CreatePortRequest for idx, i := range ifs { // Skip loopback, k8s pod interface, and tap interfaces. if i.Attrs().Name == "lo" || i.Attrs().Name == "eth0" || isHostifName(i.Attrs().Name) { log.V(1).Infof("skipping interface %q", i.Attrs().Name) continue } + portLinks = append(portLinks, i) + portReqs = append(portReqs, &saipb.CreatePortRequest{ + Switch: ni.switchID, + HwLaneList: []uint32{portLane(i.Attrs().Name, idx)}, + AdminState: proto.Bool(true), + }) + } + portsResp, err := ni.portClient.CreatePorts(ctx, &saipb.CreatePortsRequest{ + Reqs: portReqs, + }) + if err != nil { + return fmt.Errorf("failed to create ports: %w", err) + } + + for idx, i := range portLinks { + portResp := portsResp.GetResps()[idx] log.Infof("creating interfaces for %v", i.Attrs().Name) ocIntf := ocInterface{ name: i.Attrs().Name, @@ -1210,17 +1228,8 @@ func (ni *Reconciler) setupPorts(ctx context.Context) error { } data := &interfaceData{ networkInstance: fakedevice.DefaultNetworkInstance, + portID: portResp.Oid, } - - portResp, err := ni.portClient.CreatePort(ctx, &saipb.CreatePortRequest{ - Switch: ni.switchID, - HwLaneList: []uint32{portLane(i.Attrs().Name, idx)}, - AdminState: proto.Bool(true), - }) - if err != nil { - return fmt.Errorf("failed to create port %q: %w", i.Attrs().Name, err) - } - data.portID = portResp.Oid nid, err := ni.fwdClient.ObjectNID(ctx, &fwdpb.ObjectNIDRequest{ ContextId: &fwdpb.ContextId{Id: ni.contextID}, ObjectId: &fwdpb.ObjectId{Id: fmt.Sprint(portResp.Oid)},