From 493d41ba2d648869382b61fc2408f78c3c75eb0e Mon Sep 17 00:00:00 2001 From: gavinz-ship-it Date: Fri, 16 Oct 2026 16:30:26 -0700 Subject: [PATCH 01/13] Update forwarding_port.proto Add admin_state to KernelPortDesc --- proto/forwarding/forwarding_port.proto | 1 + 1 file changed, 1 insertion(+) diff --git a/proto/forwarding/forwarding_port.proto b/proto/forwarding/forwarding_port.proto index 74cbcf0f8..bac2997bc 100644 --- a/proto/forwarding/forwarding_port.proto +++ b/proto/forwarding/forwarding_port.proto @@ -62,6 +62,7 @@ message CPUPortDesc { message KernelPortDesc { string device_name = 1; + bool admin_state = 2; } message TAPPortDesc { From 0bed2f8df0cb9a9a3a32e2bca994713878fa8d74 Mon Sep 17 00:00:00 2001 From: gavinz-ship-it Date: Fri, 16 Oct 2026 17:35:31 -0700 Subject: [PATCH 02/13] Update forwarding_port.proto Add admin_state to TAPPortDesc --- proto/forwarding/forwarding_port.proto | 1 + 1 file changed, 1 insertion(+) diff --git a/proto/forwarding/forwarding_port.proto b/proto/forwarding/forwarding_port.proto index bac2997bc..609835248 100644 --- a/proto/forwarding/forwarding_port.proto +++ b/proto/forwarding/forwarding_port.proto @@ -67,6 +67,7 @@ message KernelPortDesc { message TAPPortDesc { string device_name = 1; + bool admin_state = 2; } message FakePortDesc { From 3747ad90d3016bde9414ab318fbf95242ef680f9 Mon Sep 17 00:00:00 2001 From: gavinz-ship-it Date: Fri, 16 Oct 2026 17:38:17 -0700 Subject: [PATCH 03/13] Update tap.go Add code to set the admin status. --- dataplane/forwarding/fwdport/ports/tap.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dataplane/forwarding/fwdport/ports/tap.go b/dataplane/forwarding/fwdport/ports/tap.go index 90876c59f..1308cbd9c 100644 --- a/dataplane/forwarding/fwdport/ports/tap.go +++ b/dataplane/forwarding/fwdport/ports/tap.go @@ -280,6 +280,16 @@ func (tp tapBuilder) Build(portDesc *fwdpb.PortDesc, ctx *fwdcontext.Context) (f if err := unix.SetNonblock(fd, true); err != nil { return nil, fmt.Errorf("failed to set tap in non-blocking mode: %v", err) } + l, err := tp.ifaceMgr.LinkByName(kp.Tap.GetDeviceName()) + if err != nil { + return nil, fmt.Errorf("failed to get tap interface %q: %w", kp.Tap.GetDeviceName(), err) + } + isUp := l.Attrs().Flags&net.FlagUp != 0 + if kp.Tap.GetAdminState() && !isUp { + tp.ifaceMgr.LinkSetUp(l) + } else if !kp.Tap.GetAdminState() && isUp { + tp.ifaceMgr.LinkSetDown(l) + } file := os.NewFile(uintptr(fd), "/dev/tun") p := &tapPort{ ctx: ctx, From ec3192ca1250a189d597918e98d623828395ed4a Mon Sep 17 00:00:00 2001 From: gavinz-ship-it Date: Fri, 16 Oct 2026 17:39:47 -0700 Subject: [PATCH 04/13] Update kernel.go Update to set the admin status --- dataplane/forwarding/fwdport/ports/kernel.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dataplane/forwarding/fwdport/ports/kernel.go b/dataplane/forwarding/fwdport/ports/kernel.go index f18fa9275..7cbcee2fd 100644 --- a/dataplane/forwarding/fwdport/ports/kernel.go +++ b/dataplane/forwarding/fwdport/ports/kernel.go @@ -190,7 +190,12 @@ func (kernelBuilder) Build(portDesc *fwdpb.PortDesc, ctx *fwdcontext.Context) (f return nil, fmt.Errorf("failed to set arp_ignore to 2: %v", err) } - netlink.LinkSetUp(l) + isUp := l.Attrs().Flags&net.FlagUp != 0 + if kp.Kernel.GetAdminState() && !isUp { + netlink.LinkSetUp(l) + } else if !kp.Kernel.GetAdminState() && isUp { + netlink.LinkSetDown(l) + } // Set snaplen to 64KB to capture max size IP packets handle, err := pcap.OpenLive(kp.Kernel.GetDeviceName(), 65536, true, pcap.BlockForever) From 1daad1da44dbd29469c36f9e962747e26a756184 Mon Sep 17 00:00:00 2001 From: gavinz-ship-it Date: Fri, 16 Oct 2026 17:42:24 -0700 Subject: [PATCH 05/13] Update ports.go Set admin status when creating the ports. --- dataplane/saiserver/ports.go | 40 +++++++++++------------------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/dataplane/saiserver/ports.go b/dataplane/saiserver/ports.go index 7e8b344b4..a63b35fab 100644 --- a/dataplane/saiserver/ports.go +++ b/dataplane/saiserver/ports.go @@ -216,7 +216,7 @@ func (port *port) CreatePort(ctx context.Context, req *saipb.CreatePortRequest) SupportedFecMode: []saipb.PortFecMode{saipb.PortFecMode_PORT_FEC_MODE_NONE}, NumberOfIngressPriorityGroups: proto.Uint32(0), QosMaximumHeadroomSize: proto.Uint32(0), - AdminState: proto.Bool(true), + AdminState: proto.Bool(req.GetAdminState()), AutoNegMode: proto.Bool(req.GetAutoNegMode()), Mtu: proto.Uint32(1514), HwLaneList: req.HwLaneList, @@ -237,6 +237,7 @@ func (port *port) CreatePort(ctx context.Context, req *saipb.CreatePortRequest) fwdPort.Port.Port = &fwdpb.PortDesc_Kernel{ Kernel: &fwdpb.KernelPortDesc{ DeviceName: dev, + AdminState: req.GetAdminState(), }, } // For ports that don't exist, do not create dataplane ports. @@ -255,25 +256,20 @@ func (port *port) CreatePort(ctx context.Context, req *saipb.CreatePortRequest) Port: &fwdpb.PortDesc_Tap{ Tap: &fwdpb.TAPPortDesc{ DeviceName: fmt.Sprintf("port%d", id), + AdminState: req.GetAdminState(), }, }, }, } - _, err := port.dataplane.PortCreate(ctx, fwdPort) - if err != nil { + if _, err := port.dataplane.PortCreate(ctx, fwdPort); err != nil { return nil, err } - stateReq := &fwdpb.PortStateRequest{ - ContextId: &fwdpb.ContextId{Id: port.dataplane.ID()}, - PortId: &fwdpb.PortId{ObjectId: &fwdpb.ObjectId{Id: fmt.Sprint(id)}}, - Operation: &fwdpb.PortInfo{ - AdminStatus: fwdpb.PortState_PORT_STATE_DISABLED_DOWN, - }, - } - if _, err := port.dataplane.PortState(ctx, stateReq); err != nil { - return nil, err + if req.GetAdminState() { + attrs.OperStatus = saipb.PortOperStatus_PORT_OPER_STATUS_UP.Enum() + } else { + attrs.OperStatus = saipb.PortOperStatus_PORT_OPER_STATUS_DOWN.Enum() } - + port.mgr.StoreAttributes(id, attrs) return &saipb.CreatePortResponse{ Oid: id, }, nil @@ -310,23 +306,11 @@ func (port *port) CreatePort(ctx context.Context, req *saipb.CreatePortRequest) if _, err := port.dataplane.PortUpdate(ctx, update); err != nil { return nil, err } - attrs.OperStatus = saipb.PortOperStatus_PORT_OPER_STATUS_UP.Enum() - if req.AdminState == nil || req.GetAdminState() == false { - stateReq := &fwdpb.PortStateRequest{ - ContextId: &fwdpb.ContextId{Id: port.dataplane.ID()}, - PortId: &fwdpb.PortId{ObjectId: &fwdpb.ObjectId{Id: fmt.Sprint(id)}}, - Operation: &fwdpb.PortInfo{ - AdminStatus: fwdpb.PortState_PORT_STATE_DISABLED_DOWN, - }, - } - _, err := port.dataplane.PortState(ctx, stateReq) - if err != nil { - return nil, err - } - attrs.AdminState = proto.Bool(false) + if req.GetAdminState() { + attrs.OperStatus = saipb.PortOperStatus_PORT_OPER_STATUS_UP.Enum() + } else { attrs.OperStatus = saipb.PortOperStatus_PORT_OPER_STATUS_DOWN.Enum() } - port.mgr.StoreAttributes(id, attrs) // Update the switch's port list. From 98e949055e5e0259a8048d02bf33666ae952ba95 Mon Sep 17 00:00:00 2001 From: gavinz-ship-it Date: Fri, 16 Oct 2026 17:42:49 -0700 Subject: [PATCH 06/13] Update kernel.go Add imports --- dataplane/forwarding/fwdport/ports/kernel.go | 1 + 1 file changed, 1 insertion(+) diff --git a/dataplane/forwarding/fwdport/ports/kernel.go b/dataplane/forwarding/fwdport/ports/kernel.go index 7cbcee2fd..a961f1d49 100644 --- a/dataplane/forwarding/fwdport/ports/kernel.go +++ b/dataplane/forwarding/fwdport/ports/kernel.go @@ -18,6 +18,7 @@ package ports import ( "fmt" + "net" "os" "time" From 40cf385e713bfa534825b289312e73fb45b2e94f Mon Sep 17 00:00:00 2001 From: gavinz-ship-it Date: Fri, 16 Oct 2026 17:50:39 -0700 Subject: [PATCH 07/13] Update ports.go Remove redundant code --- dataplane/saiserver/ports.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/dataplane/saiserver/ports.go b/dataplane/saiserver/ports.go index a63b35fab..3073181cb 100644 --- a/dataplane/saiserver/ports.go +++ b/dataplane/saiserver/ports.go @@ -242,8 +242,6 @@ func (port *port) CreatePort(ctx context.Context, req *saipb.CreatePortRequest) } // For ports that don't exist, do not create dataplane ports. if _, err := getInterface(dev); err != nil { - attrs.OperStatus = saipb.PortOperStatus_PORT_OPER_STATUS_DOWN.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 nonexistent port. fwdPort := &fwdpb.PortCreateRequest{ From 3c6aaf189940fae5b871817aac357d3278817b9f Mon Sep 17 00:00:00 2001 From: gavinz-ship-it Date: Fri, 16 Oct 2026 17:54:24 -0700 Subject: [PATCH 08/13] Update forwarding_port.pb.go --- proto/forwarding/forwarding_port.pb.go | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/proto/forwarding/forwarding_port.pb.go b/proto/forwarding/forwarding_port.pb.go index 72cc42f47..690514f0b 100644 --- a/proto/forwarding/forwarding_port.pb.go +++ b/proto/forwarding/forwarding_port.pb.go @@ -450,6 +450,7 @@ func (x *CPUPortDesc) GetRemotePort() bool { type KernelPortDesc struct { state protoimpl.MessageState `protogen:"open.v1"` DeviceName string `protobuf:"bytes,1,opt,name=device_name,json=deviceName,proto3" json:"device_name,omitempty"` + AdminState bool `protobuf:"varint,2,opt,name=admin_state,json=adminState,proto3" json:"admin_state,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -491,9 +492,17 @@ func (x *KernelPortDesc) GetDeviceName() string { return "" } +func (x *KernelPortDesc) GetAdminState() bool { + if x != nil { + return x.AdminState + } + return false +} + type TAPPortDesc struct { state protoimpl.MessageState `protogen:"open.v1"` DeviceName string `protobuf:"bytes,1,opt,name=device_name,json=deviceName,proto3" json:"device_name,omitempty"` + AdminState bool `protobuf:"varint,2,opt,name=admin_state,json=adminState,proto3" json:"admin_state,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -535,6 +544,13 @@ func (x *TAPPortDesc) GetDeviceName() string { return "" } +func (x *TAPPortDesc) GetAdminState() bool { + if x != nil { + return x.AdminState + } + return false +} + type FakePortDesc struct { state protoimpl.MessageState `protogen:"open.v1"` InFile string `protobuf:"bytes,1,opt,name=in_file,json=inFile,proto3" json:"in_file,omitempty"` @@ -1669,13 +1685,17 @@ const file_proto_forwarding_forwarding_port_proto_rawDesc = "" + "\fqueue_length\x18\x02 \x01(\x05R\vqueueLength\x12C\n" + "\x10export_field_ids\x18\x03 \x03(\v2\x19.forwarding.PacketFieldIdR\x0eexportFieldIds\x12\x1f\n" + "\vremote_port\x18\x04 \x01(\bR\n" + - "remotePort\"1\n" + + "remotePort\"R\n" + "\x0eKernelPortDesc\x12\x1f\n" + "\vdevice_name\x18\x01 \x01(\tR\n" + - "deviceName\".\n" + + "deviceName\x12\x1f\n" + + "\vadmin_state\x18\x02 \x01(\bR\n" + + "adminState\"O\n" + "\vTAPPortDesc\x12\x1f\n" + "\vdevice_name\x18\x01 \x01(\tR\n" + - "deviceName\"[\n" + + "deviceName\x12\x1f\n" + + "\vadmin_state\x18\x02 \x01(\bR\n" + + "adminState\"[\n" + "\fFakePortDesc\x12\x17\n" + "\ain_file\x18\x01 \x01(\tR\x06inFile\x12\x19\n" + "\bout_file\x18\x02 \x01(\tR\aoutFile\x12\x17\n" + From 9c892e20ba5ec472f5f5f8176e641d92f6561b10 Mon Sep 17 00:00:00 2001 From: gavinz-ship-it Date: Fri, 16 Oct 2026 19:01:14 -0700 Subject: [PATCH 09/13] Update kernel.go Revert previously changed logic to set the admin status since pcap requires the status to be up. --- dataplane/forwarding/fwdport/ports/kernel.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/dataplane/forwarding/fwdport/ports/kernel.go b/dataplane/forwarding/fwdport/ports/kernel.go index a961f1d49..08cb3e749 100644 --- a/dataplane/forwarding/fwdport/ports/kernel.go +++ b/dataplane/forwarding/fwdport/ports/kernel.go @@ -18,7 +18,6 @@ package ports import ( "fmt" - "net" "os" "time" @@ -191,18 +190,16 @@ func (kernelBuilder) Build(portDesc *fwdpb.PortDesc, ctx *fwdcontext.Context) (f return nil, fmt.Errorf("failed to set arp_ignore to 2: %v", err) } - isUp := l.Attrs().Flags&net.FlagUp != 0 - if kp.Kernel.GetAdminState() && !isUp { - netlink.LinkSetUp(l) - } else if !kp.Kernel.GetAdminState() && isUp { - netlink.LinkSetDown(l) - } + netlink.LinkSetUp(l) // Set snaplen to 64KB to capture max size IP packets handle, err := pcap.OpenLive(kp.Kernel.GetDeviceName(), 65536, true, pcap.BlockForever) if err != nil { return nil, fmt.Errorf("failed to create afpacket: %v", err) } + if !kp.Kernel.GetAdminState() { + netlink.LinkSetDown(l) + } p := &kernelPort{ ctx: ctx, handle: handle, From 09c9f31078fefcb4c05abd55bed6292693508e7d Mon Sep 17 00:00:00 2001 From: gavinz-ship-it Date: Sun, 18 Oct 2026 15:05:58 -0700 Subject: [PATCH 10/13] Update kernel.go Added error handling for LinkSet --- dataplane/forwarding/fwdport/ports/kernel.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dataplane/forwarding/fwdport/ports/kernel.go b/dataplane/forwarding/fwdport/ports/kernel.go index 08cb3e749..ecc42c63a 100644 --- a/dataplane/forwarding/fwdport/ports/kernel.go +++ b/dataplane/forwarding/fwdport/ports/kernel.go @@ -190,7 +190,9 @@ func (kernelBuilder) Build(portDesc *fwdpb.PortDesc, ctx *fwdcontext.Context) (f return nil, fmt.Errorf("failed to set arp_ignore to 2: %v", err) } - netlink.LinkSetUp(l) + if err := netlink.LinkSetUp(l); err != nil { + return nil, fmt.Errorf("failed to set link up: %v", err) + } // Set snaplen to 64KB to capture max size IP packets handle, err := pcap.OpenLive(kp.Kernel.GetDeviceName(), 65536, true, pcap.BlockForever) @@ -198,7 +200,9 @@ func (kernelBuilder) Build(portDesc *fwdpb.PortDesc, ctx *fwdcontext.Context) (f return nil, fmt.Errorf("failed to create afpacket: %v", err) } if !kp.Kernel.GetAdminState() { - netlink.LinkSetDown(l) + if err := netlink.LinkSetDown(l); err != nil { + return nil, fmt.Errorf("failed to set link down: %v", err) + } } p := &kernelPort{ ctx: ctx, From 39c332e519709ada8b5cafe28d9dbe69fb9e7a11 Mon Sep 17 00:00:00 2001 From: gavinz-ship-it Date: Sun, 18 Oct 2026 15:06:59 -0700 Subject: [PATCH 11/13] Update tap.go --- dataplane/forwarding/fwdport/ports/tap.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dataplane/forwarding/fwdport/ports/tap.go b/dataplane/forwarding/fwdport/ports/tap.go index 1308cbd9c..f39fb2113 100644 --- a/dataplane/forwarding/fwdport/ports/tap.go +++ b/dataplane/forwarding/fwdport/ports/tap.go @@ -286,9 +286,13 @@ func (tp tapBuilder) Build(portDesc *fwdpb.PortDesc, ctx *fwdcontext.Context) (f } isUp := l.Attrs().Flags&net.FlagUp != 0 if kp.Tap.GetAdminState() && !isUp { - tp.ifaceMgr.LinkSetUp(l) + if err := tp.ifaceMgr.LinkSetUp(l); err != nil { + return nil, fmt.Errorf("failed to set tap interface %q up: %w", kp.Tap.GetDeviceName(), err) + } } else if !kp.Tap.GetAdminState() && isUp { - tp.ifaceMgr.LinkSetDown(l) + if err := tp.ifaceMgr.LinkSetDown(l); err != nil { + return nil, fmt.Errorf("failed to set tap interface %q down: %w", kp.Tap.GetDeviceName(), err) + } } file := os.NewFile(uintptr(fd), "/dev/tun") p := &tapPort{ From 6048f492dcc053584c616cec4cd78808f8c2dea0 Mon Sep 17 00:00:00 2001 From: gavinz-ship-it Date: Sun, 18 Oct 2026 15:17:12 -0700 Subject: [PATCH 12/13] Update ports_test.go Fix unit test. --- dataplane/saiserver/ports_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dataplane/saiserver/ports_test.go b/dataplane/saiserver/ports_test.go index 8f1ca2fa1..9f1a73995 100644 --- a/dataplane/saiserver/ports_test.go +++ b/dataplane/saiserver/ports_test.go @@ -102,7 +102,7 @@ func TestCreatePort(t *testing.T) { SupportedFecMode: []saipb.PortFecMode{saipb.PortFecMode_PORT_FEC_MODE_NONE}, NumberOfIngressPriorityGroups: proto.Uint32(0), QosMaximumHeadroomSize: proto.Uint32(0), - AdminState: proto.Bool(true), + AdminState: proto.Bool(false), AutoNegMode: proto.Bool(false), Mtu: proto.Uint32(1514), PortVlanId: proto.Uint32(DefaultVlanId), From 8ea9e41920bcbe175b57aac1ece9cd7c7374379b Mon Sep 17 00:00:00 2001 From: gavinz-ship-it Date: Mon, 19 Oct 2026 13:03:46 -0700 Subject: [PATCH 13/13] Update ports.go Fix the previously changed oper status for tap ports. --- dataplane/saiserver/ports.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/dataplane/saiserver/ports.go b/dataplane/saiserver/ports.go index 3073181cb..72406d1e1 100644 --- a/dataplane/saiserver/ports.go +++ b/dataplane/saiserver/ports.go @@ -262,11 +262,7 @@ func (port *port) CreatePort(ctx context.Context, req *saipb.CreatePortRequest) if _, err := port.dataplane.PortCreate(ctx, fwdPort); err != nil { return nil, err } - if req.GetAdminState() { - attrs.OperStatus = saipb.PortOperStatus_PORT_OPER_STATUS_UP.Enum() - } else { - attrs.OperStatus = saipb.PortOperStatus_PORT_OPER_STATUS_DOWN.Enum() - } + attrs.OperStatus = saipb.PortOperStatus_PORT_OPER_STATUS_DOWN.Enum() port.mgr.StoreAttributes(id, attrs) return &saipb.CreatePortResponse{ Oid: id,