From 7f14b479d3c47dba39530e193941d8b871a2fe4f Mon Sep 17 00:00:00 2001 From: Sree Iyer Date: Wed, 23 Sep 2026 10:37:52 +0000 Subject: [PATCH] Prevent unconnected ports from reporting oper status up Signed-off-by: Sree Iyer --- dataplane/saiserver/ports.go | 33 ++++++++++++++++++++++++++--- dataplane/saiserver/ports_test.go | 35 +++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/dataplane/saiserver/ports.go b/dataplane/saiserver/ports.go index 9ab6f834e..ceccb29be 100644 --- a/dataplane/saiserver/ports.go +++ b/dataplane/saiserver/ports.go @@ -244,7 +244,7 @@ func (port *port) CreatePort(ctx context.Context, req *saipb.CreatePortRequest) attrs.OperStatus = saipb.PortOperStatus_PORT_OPER_STATUS_NOT_PRESENT.Enum() port.mgr.StoreAttributes(id, attrs) // TODO: This should be a real error, improve once we a correct config solution. - // For now, create dummy port with no actions so we don't get a bunch error for a nonexistant port. + // For now, create dummy port with no actions so we don't get a bunch error for a nonexistent port. fwdPort := &fwdpb.PortCreateRequest{ ContextId: &fwdpb.ContextId{Id: port.dataplane.ID()}, Port: &fwdpb.PortDesc{ @@ -527,7 +527,7 @@ func (port *port) createCPUPort(ctx context.Context) (uint64, error) { // SetPortAttributes sets the attributes in the request. func (port *port) SetPortAttribute(ctx context.Context, req *saipb.SetPortAttributeRequest) (*saipb.SetPortAttributeResponse, error) { if req.AdminState != nil { - // Skip ports that don't exsit. + // Skip ports that don't exist. attrReq := &saipb.GetPortAttributeRequest{Oid: req.GetOid(), AttrType: []saipb.PortAttr{saipb.PortAttr_PORT_ATTR_OPER_STATUS}} p := &saipb.GetPortAttributeResponse{} if err := port.mgr.PopulateAttributes(attrReq, p); err != nil { @@ -537,6 +537,33 @@ func (port *port) SetPortAttribute(ctx context.Context, req *saipb.SetPortAttrib return nil, nil } + // Do not apply admin-state changes to the fallback TAP created for a + // kernel-backed port whose real lane interface is absent. + if port.opts.PortType == fwdpb.PortType_PORT_TYPE_KERNEL && req.GetAdminState() { + attrReq := &saipb.GetPortAttributeRequest{ + Oid: req.GetOid(), + AttrType: []saipb.PortAttr{saipb.PortAttr_PORT_ATTR_HW_LANE_LIST}, + } + p := &saipb.GetPortAttributeResponse{} + if err := port.mgr.PopulateAttributes(attrReq, p); err != nil { + return nil, err + } + attr := p.GetAttr() + if attr == nil { + return nil, fmt.Errorf("failed to get attributes for port %d", req.GetOid()) + } + lanes := attr.GetHwLaneList() + if len(lanes) == 0 { + return nil, fmt.Errorf("port %d has no hardware lanes", req.GetOid()) + } + dev := fmt.Sprintf("eth%d", lanes[0]) + if _, err := getInterface(dev); err != nil { + slog.InfoContext(ctx, "ignoring admin-state update for port without backing interface", + "oid", req.GetOid(), "device", dev, "admin_state", req.GetAdminState()) + return &saipb.SetPortAttributeResponse{}, nil + } + } + stateReq := &fwdpb.PortStateRequest{ ContextId: &fwdpb.ContextId{Id: port.dataplane.ID()}, PortId: &fwdpb.PortId{ObjectId: &fwdpb.ObjectId{Id: fmt.Sprint(req.GetOid())}}, @@ -709,7 +736,7 @@ func (port *port) RemovePort(ctx context.Context, req *saipb.RemovePortRequest) } func (port *port) Reset() { - slog.Info("reseting port") + slog.Info("resetting port") } type lagMember struct { diff --git a/dataplane/saiserver/ports_test.go b/dataplane/saiserver/ports_test.go index 6b853a41b..0458c523c 100644 --- a/dataplane/saiserver/ports_test.go +++ b/dataplane/saiserver/ports_test.go @@ -362,6 +362,41 @@ func TestSetPortAttribute(t *testing.T) { } }) } + + t.Run("admin status ignored without backing interface", func(t *testing.T) { + oldGetInterface := getInterface + defer func() { getInterface = oldGetInterface }() + + getInterface = func(name string) (*net.Interface, error) { + if name != "eth125" { + t.Errorf("getInterface() got %q, want eth125", name) + } + return nil, fmt.Errorf("link not found") + } + + dplane := &fakeSwitchDataplane{} + c, mgr, stopFn := newTestPort(t, dplane, &dplaneopts.Options{ + PortType: fwdpb.PortType_PORT_TYPE_KERNEL, + }) + defer stopFn() + + mgr.StoreAttributes(3, &saipb.PortAttribute{ + OperStatus: saipb.PortOperStatus_PORT_OPER_STATUS_DOWN.Enum(), + HwLaneList: []uint32{125, 126, 127, 128}, + }) + + _, err := c.SetPortAttribute(context.Background(), &saipb.SetPortAttributeRequest{ + Oid: 3, + AdminState: proto.Bool(true), + }) + if err != nil { + t.Fatalf("SetPortAttribute() unexpected error: %v", err) + } + if got := len(dplane.gotPortStateReq); got != 0 { + t.Fatalf("SetPortAttribute() sent %d PortState requests, want 0", got) + } + }) + fecTests := []struct { desc string req *saipb.SetPortAttributeRequest