@@ -113,6 +113,14 @@ func (e *ContainerEdits) Apply(spec *oci.Spec) error {
113113 }
114114 }
115115
116+ if len (e .NetDevices ) > 0 {
117+ // specgen is currently missing functionality to set Linux NetDevices,
118+ // so we use a locally rolled function for now.
119+ for _ , dev := range e .NetDevices {
120+ specgenAddLinuxNetDevice (& specgen , dev .HostIf , (& LinuxNetDevice {dev }).toOCI ())
121+ }
122+ }
123+
116124 if len (e .Mounts ) > 0 {
117125 for _ , m := range e .Mounts {
118126 specgen .RemoveMount (m .ContainerPath )
@@ -162,6 +170,24 @@ func (e *ContainerEdits) Apply(spec *oci.Spec) error {
162170 return nil
163171}
164172
173+ func specgenAddLinuxNetDevice (specgen * ocigen.Generator , hostIf string , netDev * oci.LinuxNetDevice ) {
174+ if specgen == nil || netDev == nil {
175+ return
176+ }
177+ ensureLinuxNetDevices (specgen .Config )
178+ specgen .Config .Linux .NetDevices [hostIf ] = * netDev
179+ }
180+
181+ // Ensure OCI Spec Linux NetDevices map is not nil.
182+ func ensureLinuxNetDevices (spec * oci.Spec ) {
183+ if spec .Linux == nil {
184+ spec .Linux = & oci.Linux {}
185+ }
186+ if spec .Linux .NetDevices == nil {
187+ spec .Linux .NetDevices = map [string ]oci.LinuxNetDevice {}
188+ }
189+ }
190+
165191// Validate container edits.
166192func (e * ContainerEdits ) Validate () error {
167193 if e == nil || e .ContainerEdits == nil {
@@ -191,6 +217,9 @@ func (e *ContainerEdits) Validate() error {
191217 return err
192218 }
193219 }
220+ if err := ValidateNetDevices (e .NetDevices ); err != nil {
221+ return err
222+ }
194223
195224 return nil
196225}
@@ -210,6 +239,7 @@ func (e *ContainerEdits) Append(o *ContainerEdits) *ContainerEdits {
210239
211240 e .Env = append (e .Env , o .Env ... )
212241 e .DeviceNodes = append (e .DeviceNodes , o .DeviceNodes ... )
242+ e .NetDevices = append (e .NetDevices , o .NetDevices ... )
213243 e .Hooks = append (e .Hooks , o .Hooks ... )
214244 e .Mounts = append (e .Mounts , o .Mounts ... )
215245 if o .IntelRdt != nil {
@@ -244,6 +274,9 @@ func (e *ContainerEdits) isEmpty() bool {
244274 if e .IntelRdt != nil {
245275 return false
246276 }
277+ if len (e .NetDevices ) > 0 {
278+ return false
279+ }
247280 return true
248281}
249282
@@ -257,6 +290,49 @@ func ValidateEnv(env []string) error {
257290 return nil
258291}
259292
293+ // ValidateNetDevices validates the given net devices.
294+ func ValidateNetDevices (devices []* cdi.LinuxNetDevice ) error {
295+ var (
296+ hostSeen = map [string ]string {}
297+ nameSeen = map [string ]string {}
298+ )
299+
300+ for _ , dev := range devices {
301+ if err := (& LinuxNetDevice {dev }).Validate (); err != nil {
302+ return err
303+ }
304+ if other , ok := hostSeen [dev .HostIf ]; ok {
305+ return fmt .Errorf ("invalid linux net device, duplicate HostIf %q with names %q and %q" ,
306+ dev .HostIf , dev .Name , other )
307+ }
308+ hostSeen [dev .HostIf ] = dev .Name
309+
310+ if other , ok := nameSeen [dev .Name ]; ok {
311+ return fmt .Errorf ("invalid linux net device, duplicate Name %q with HostIf %q and %q" ,
312+ dev .Name , dev .HostIf , other )
313+ }
314+ nameSeen [dev .Name ] = dev .HostIf
315+ }
316+
317+ return nil
318+ }
319+
320+ // LinuxNetDevice is a CDI Spec LinuxNetDevice wrapper, used for OCI conversion and validating.
321+ type LinuxNetDevice struct {
322+ * cdi.LinuxNetDevice
323+ }
324+
325+ // Validate LinuxNetDevice.
326+ func (d * LinuxNetDevice ) Validate () error {
327+ if d .HostIf == "" {
328+ return errors .New ("invalid linux net device, empty HostIf" )
329+ }
330+ if d .Name == "" {
331+ return errors .New ("invalid linux net device, empty Name" )
332+ }
333+ return nil
334+ }
335+
260336// DeviceNode is a CDI Spec DeviceNode wrapper, used for validating DeviceNodes.
261337type DeviceNode struct {
262338 * cdi.DeviceNode
0 commit comments