@@ -130,6 +130,12 @@ func (d *nicPhysical) validateConfig(instConf instance.ConfigReader) error {
130
130
// Get actual parent device from network's parent setting.
131
131
d .config ["parent" ] = netConfig ["parent" ]
132
132
133
+ // If parent is a bridge, ensure it's managed.
134
+ isParentBridge := d .config ["parent" ] != "" && util .PathExists (fmt .Sprintf ("/sys/class/net/%s/bridge" , d .config ["parent" ]))
135
+ if isParentBridge && d .network == nil {
136
+ return fmt .Errorf ("Parent device is a bridge, use nictype=bridged instead" )
137
+ }
138
+
133
139
// Copy certain keys verbatim from the network's settings.
134
140
for _ , field := range optionalFields {
135
141
_ , found := netConfig [field ]
@@ -174,6 +180,25 @@ func (d *nicPhysical) Start() (*deviceConfig.RunConfig, error) {
174
180
return nil , err
175
181
}
176
182
183
+ // Handle the case where the parent is a bridge.
184
+ isParentBridge := util .PathExists (fmt .Sprintf ("/sys/class/net/%s/bridge" , d .config ["parent" ]))
185
+ if isParentBridge {
186
+ // Convert the device to a nictype=bridged internally.
187
+ bridgedConfig := d .config .Clone ()
188
+ bridgedConfig ["type" ] = "nic"
189
+ bridgedConfig ["nictype" ] = "bridged"
190
+ bridgedConfig ["network" ] = ""
191
+
192
+ // Instantiate the new device.
193
+ bridged , err := load (d .inst , d .state , d .inst .Project ().Name , d .inst .Name (), bridgedConfig , d .volatileGet , d .volatileSet )
194
+ if err != nil {
195
+ return nil , fmt .Errorf ("Failed to initialize bridged device: %w" , err )
196
+ }
197
+
198
+ // Forward the start call.
199
+ return bridged .Start ()
200
+ }
201
+
177
202
// Lock to avoid issues with containers starting in parallel.
178
203
networkCreateSharedDeviceLock .Lock ()
179
204
defer networkCreateSharedDeviceLock .Unlock ()
@@ -374,6 +399,25 @@ func (d *nicPhysical) startVMUSB(name string) (*deviceConfig.RunConfig, error) {
374
399
375
400
// Stop is run when the device is removed from the instance.
376
401
func (d * nicPhysical ) Stop () (* deviceConfig.RunConfig , error ) {
402
+ // Handle the case where the parent is a bridge.
403
+ isParentBridge := util .PathExists (fmt .Sprintf ("/sys/class/net/%s/bridge" , d .config ["parent" ]))
404
+ if isParentBridge {
405
+ // Convert the device to a nictype=bridged internally.
406
+ bridgedConfig := d .config .Clone ()
407
+ bridgedConfig ["type" ] = "nic"
408
+ bridgedConfig ["nictype" ] = "bridged"
409
+ bridgedConfig ["network" ] = ""
410
+
411
+ // Instantiate the new device.
412
+ bridged , err := load (d .inst , d .state , d .inst .Project ().Name , d .inst .Name (), bridgedConfig , d .volatileGet , d .volatileSet )
413
+ if err != nil {
414
+ return nil , fmt .Errorf ("Failed to initialize bridged device: %w" , err )
415
+ }
416
+
417
+ // Forward the stop call.
418
+ return bridged .Stop ()
419
+ }
420
+
377
421
v := d .volatileGet ()
378
422
379
423
runConf := deviceConfig.RunConfig {
0 commit comments