@@ -21,11 +21,13 @@ import (
2121 "github.com/openshift/dpu-operator/pkgs/vars"
2222 pb "github.com/opiproject/opi-api/network/evpn-gw/v1alpha1/gen/go"
2323 lifecycleapi "github.com/opiproject/opi-api/v1/gen/go/lifecycle/v1alpha1"
24+ "github.com/vishvananda/netlink"
2425 "google.golang.org/grpc"
2526 emptypb "google.golang.org/protobuf/types/known/emptypb"
2627 "k8s.io/client-go/rest"
2728 ctrl "sigs.k8s.io/controller-runtime"
2829 "sigs.k8s.io/controller-runtime/pkg/cache"
30+ "sigs.k8s.io/controller-runtime/pkg/client"
2931 "sigs.k8s.io/controller-runtime/pkg/metrics/filters"
3032 "sigs.k8s.io/controller-runtime/pkg/metrics/server"
3133)
@@ -113,7 +115,12 @@ func NewDpuSideManager(vsp plugin.VendorPlugin, config *rest.Config, opts ...fun
113115 opt (d )
114116 }
115117
116- d .dp = deviceplugin .NewDevicePlugin (vsp , true , d .pathManager )
118+ if k8sClient , err := client .New (d .config , client.Options {Scheme : scheme .Scheme }); err != nil {
119+ d .log .Error (err , "Failed to create Kubernetes client for device plugin; falling back to default-only registration" )
120+ d .dp = deviceplugin .NewDevicePluginManager (vsp , true , d .pathManager , nil )
121+ } else {
122+ d .dp = deviceplugin .NewDevicePluginManager (vsp , true , d .pathManager , k8sClient )
123+ }
117124
118125 return d , nil
119126}
@@ -149,12 +156,21 @@ func (d *DpuSideManager) cniCmdNfAddHandler(req *cnitypes.PodRequest) (*cni100.R
149156 return nil , fmt .Errorf ("SRIOV manager failed in add handler: %v" , err )
150157 }
151158
152- d .macStore [req .Netns ] = append (d .macStore [req .Netns ], req .CNIConf .MAC )
153- if len (d .macStore [req .Netns ]) == 2 {
154- d .log .Info ("cniCmdNfAddHandler" , "req.Netns" , req .Netns )
155- macs := d .macStore [req .Netns ]
156- d .vsp .CreateNetworkFunction (macs [0 ], macs [1 ])
159+ bridgeID := req .CNIConf .BridgeID
160+
161+ if req .CNIConf .IsAccelerated {
162+ d .log .Info ("cniCmdNfAddHandler accelerated mode: calling CNF per VF" , "mac" , req .CNIConf .MAC , "bridgeID" , bridgeID )
163+ d .macStore [req .Netns ] = append (d .macStore [req .Netns ], req .CNIConf .MAC )
164+ d .vsp .CreateNetworkFunction (req .CNIConf .MAC , "" , bridgeID )
165+ } else {
166+ d .macStore [req .Netns ] = append (d .macStore [req .Netns ], req .CNIConf .MAC )
167+ if len (d .macStore [req .Netns ]) == 2 {
168+ d .log .Info ("cniCmdNfAddHandler" , "req.Netns" , req .Netns , "bridgeID" , bridgeID )
169+ macs := d .macStore [req .Netns ]
170+ d .vsp .CreateNetworkFunction (macs [0 ], macs [1 ], bridgeID )
171+ }
157172 }
173+
158174 d .log .Info ("cniCmdNfAddHandler CmdAdd succeeded" )
159175 return res , nil
160176}
@@ -166,19 +182,71 @@ func (d *DpuSideManager) cniCmdNfDelHandler(req *cnitypes.PodRequest) (*cni100.R
166182 return nil , errors .New ("SRIOV manager failed in del handler" )
167183 }
168184
169- macs := d . macStore [ req .Netns ]
185+ bridgeID := req .CNIConf . BridgeID
170186
171- if len (macs ) == 2 {
172- d .log .Info ("cniCmdNfDelHandler" , "req.Netns" , req .Netns )
173- d .vsp .DeleteNetworkFunction (macs [0 ], macs [1 ])
187+ if req .CNIConf .IsAccelerated {
188+ macs := d .macStore [req .Netns ]
189+ mac := ""
190+ if len (macs ) > 0 {
191+ mac = macs [len (macs )- 1 ]
192+ d .macStore [req .Netns ] = macs [:len (macs )- 1 ]
193+ }
194+ d .log .Info ("cniCmdNfDelHandler accelerated mode: calling DNF per VF" , "mac" , mac , "bridgeID" , bridgeID )
195+ d .vsp .DeleteNetworkFunction (mac , "" , bridgeID )
196+ } else {
197+ macs := d .macStore [req .Netns ]
198+ if len (macs ) == 2 {
199+ d .log .Info ("cniCmdNfDelHandler" , "req.Netns" , req .Netns , "bridgeID" , bridgeID )
200+ d .vsp .DeleteNetworkFunction (macs [0 ], macs [1 ], bridgeID )
201+ }
202+ if len (macs ) > 0 {
203+ d .macStore [req .Netns ] = macs [:len (macs )- 1 ]
204+ }
174205 }
175206
176- d .macStore [req .Netns ] = macs [:len (macs )- 1 ]
177-
178207 d .log .Info ("cniCmdNfDelHandler CmdDel succeeded" )
179208 return nil , nil
180209}
181210
211+ // releaseNfDevices recovers any devices (VF representors or veths) that are
212+ // still inside NF pod namespaces during graceful shutdown. This must run
213+ // before the CNI server and VSP are stopped so the host can safely reset
214+ // sriov_numvfs without hitting a kernel D-state hang.
215+ func (d * DpuSideManager ) releaseNfDevices () {
216+ d .log .Info ("releaseNfDevices: checking for devices still in pod namespaces" )
217+
218+ devices , err := d .vsp .GetDevices ()
219+ if err != nil {
220+ d .log .Error (err , "releaseNfDevices: failed to get device list from VSP" )
221+ return
222+ }
223+
224+ for _ , dev := range devices .Devices {
225+ devName := dev .ID
226+ if _ , err := netlink .LinkByName (devName ); err == nil {
227+ continue
228+ }
229+
230+ links , listErr := netlink .LinkList ()
231+ if listErr != nil {
232+ d .log .Error (listErr , "releaseNfDevices: failed to list links" )
233+ return
234+ }
235+ for _ , link := range links {
236+ if link .Attrs ().Alias == devName {
237+ d .log .Info ("releaseNfDevices: found device under temp name, restoring" ,
238+ "tempName" , link .Attrs ().Name , "originalName" , devName )
239+ if err := netlink .LinkSetName (link , devName ); err != nil {
240+ d .log .Error (err , "releaseNfDevices: failed to rename" , "device" , devName )
241+ } else if err := netlink .LinkSetUp (link ); err != nil {
242+ d .log .Error (err , "releaseNfDevices: failed to bring up" , "device" , devName )
243+ }
244+ break
245+ }
246+ }
247+ }
248+ }
249+
182250func (d * DpuSideManager ) Listen () (net.Listener , error ) {
183251 d .startedWg .Add (1 )
184252 d .log .Info ("Starting DpuDaemon" )
@@ -225,6 +293,7 @@ func (d *DpuSideManager) Serve(ctx context.Context, listener net.Listener) error
225293 go func () {
226294 <- ctx .Done ()
227295 d .log .Info ("Context cancelled, shutting down servers" )
296+ d .releaseNfDevices ()
228297 d .server .Stop ()
229298 d .dp .Stop ()
230299 d .vsp .Close ()
0 commit comments