@@ -113,6 +113,14 @@ func (e *ContainerEdits) Apply(spec *oci.Spec) error {
113113 }
114114 }
115115
116+ if e .NetDevices != nil {
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 e .NetDevices != nil {
278+ return false
279+ }
247280 return true
248281}
249282
@@ -257,6 +290,46 @@ 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 other , ok := hostSeen [dev .HostIf ]; ok {
302+ return fmt .Errorf ("invalid linux net device, duplicate HostIf %q with names %q and %q" ,
303+ dev .HostIf , dev .Name , other )
304+ }
305+ hostSeen [dev .HostIf ] = dev .Name
306+
307+ if other , ok := nameSeen [dev .Name ]; ok {
308+ return fmt .Errorf ("invalid linux net device, duplicate Name %q with HostIf %q and %q" ,
309+ dev .Name , dev .HostIf , other )
310+ }
311+ nameSeen [dev .Name ] = dev .HostIf
312+ }
313+
314+ return nil
315+ }
316+
317+ // LinuxNetDevice is a CDI Spec LinuxNetDevice wrapper, used for OCI conversion and validating.
318+ type LinuxNetDevice struct {
319+ * cdi.LinuxNetDevice
320+ }
321+
322+ // Validate LinuxNetDevice.
323+ func (d * LinuxNetDevice ) Validate () error {
324+ if d .HostIf == "" {
325+ return errors .New ("invalid linux net device, empty HostIf" )
326+ }
327+ if d .Name == "" {
328+ return errors .New ("invalid linux net device, empty Name" )
329+ }
330+ return nil
331+ }
332+
260333// DeviceNode is a CDI Spec DeviceNode wrapper, used for validating DeviceNodes.
261334type DeviceNode struct {
262335 * cdi.DeviceNode
0 commit comments