Skip to content

Commit d83c103

Browse files
authored
fix: tap interface attach to bridge (#479)
When requesting that a tap device is added to a microvm then we should attach (i.e. set the master) to a bridge. The bridge will be supplied via a new bridge-name flag. And the attach should not be done for the mmds network interface. The grpc api has been updated to allow the consumer to specify a bridge-name that is different as part of the create microvm call. Signed-off-by: Richard Case <richard.case@outlook.com>
1 parent 16f8675 commit d83c103

File tree

20 files changed

+357
-165
lines changed

20 files changed

+357
-165
lines changed

api/services/microvm/v1alpha1/microvms.swagger.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,10 @@
404404
"address": {
405405
"$ref": "#/definitions/typesStaticAddress",
406406
"description": "Address is an optional static IP address to manually assign to this interface. \nIf not supplied then DHCP will be used."
407+
},
408+
"overrides": {
409+
"$ref": "#/definitions/typesNetworkOverrides",
410+
"description": "Overrides is optional overrides applicable for network configuration."
407411
}
408412
}
409413
},
@@ -425,6 +429,16 @@
425429
}
426430
}
427431
},
432+
"typesNetworkOverrides": {
433+
"type": "object",
434+
"properties": {
435+
"bridgeName": {
436+
"type": "string",
437+
"description": "BridgeName is the name of the Linux bridge to attach TAP devices to. This overrides\nany value set at the overall flintlock level."
438+
}
439+
},
440+
"description": "NetworkOverrides represents override values for a network interface."
441+
},
428442
"typesStaticAddress": {
429443
"type": "object",
430444
"properties": {

api/types/microvm.pb.go

Lines changed: 214 additions & 130 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/types/microvm.proto

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ message NetworkInterface {
110110
// Address is an optional static IP address to manually assign to this interface.
111111
// If not supplied then DHCP will be used.
112112
optional StaticAddress address = 5;
113+
// Overrides is optional overrides applicable for network configuration.
114+
optional NetworkOverrides overrides = 6;
115+
113116
}
114117

115118
// StaticAddress represents a static IPv4 or IPv6 address.
@@ -201,3 +204,10 @@ message NetworkInterfaceStatus {
201204
// MACAddress is the MAC address of the host interface.
202205
string mac_address = 3;
203206
}
207+
208+
// NetworkOverrides represents override values for a network interface.
209+
message NetworkOverrides {
210+
// BridgeName is the name of the Linux bridge to attach TAP devices to. This overrides
211+
// any value set at the overall flintlock level.
212+
optional string bridge_name = 1;
213+
}

buf.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ deps:
44
- remote: buf.build
55
owner: googleapis
66
repository: googleapis
7-
commit: 86d30bdfc34044fb9339e1bd9673839b
7+
commit: 2646de1347094058879360e68cb2ccc6
88
- remote: buf.build
99
owner: grpc-ecosystem
1010
repository: grpc-gateway

core/errors/errors.go

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,23 @@ import (
66
)
77

88
var (
9-
ErrSpecRequired = errors.New("microvm spec is required")
10-
ErrVMIDRequired = errors.New("id for microvm is required")
11-
ErrNameRequired = errors.New("name is required")
12-
ErrUIDRequired = errors.New("uid is required")
13-
ErrNamespaceRequired = errors.New("namespace is required")
14-
ErrKernelImageRequired = errors.New("kernel image is required")
15-
ErrVolumeRequired = errors.New("no volumes specified, at least 1 volume is required")
16-
ErrRootVolumeRequired = errors.New("a root volume is required")
17-
ErrNoMount = errors.New("no image mount point")
18-
ErrNoVolumeMount = errors.New("no volume mount point")
19-
ErrParentIfaceRequired = errors.New("a parent network device name is required")
20-
ErrGuestDeviceNameRequired = errors.New("a guest device name is required")
21-
ErrUnsupportedIfaceType = errors.New("unsupported network interface type")
22-
ErrIfaceNotFound = errors.New("network interface not found")
23-
ErrMissingStatusInfo = errors.New("status is not defined")
24-
ErrUnableToBoot = errors.New("microvm is unable to boot")
9+
ErrSpecRequired = errors.New("microvm spec is required")
10+
ErrVMIDRequired = errors.New("id for microvm is required")
11+
ErrNameRequired = errors.New("name is required")
12+
ErrUIDRequired = errors.New("uid is required")
13+
ErrNamespaceRequired = errors.New("namespace is required")
14+
ErrKernelImageRequired = errors.New("kernel image is required")
15+
ErrVolumeRequired = errors.New("no volumes specified, at least 1 volume is required")
16+
ErrRootVolumeRequired = errors.New("a root volume is required")
17+
ErrNoMount = errors.New("no image mount point")
18+
ErrNoVolumeMount = errors.New("no volume mount point")
19+
ErrParentIfaceRequiredForMacvtap = errors.New("a parent network device name is required for macvtap interfaces")
20+
ErrParentIfaceRequiredForAttachingTap = errors.New("a parent network device name is required for attaching a TAP interface")
21+
ErrGuestDeviceNameRequired = errors.New("a guest device name is required")
22+
ErrUnsupportedIfaceType = errors.New("unsupported network interface type")
23+
ErrIfaceNotFound = errors.New("network interface not found")
24+
ErrMissingStatusInfo = errors.New("status is not defined")
25+
ErrUnableToBoot = errors.New("microvm is unable to boot")
2526
)
2627

2728
// TopicNotFoundError is an error created when a topic with a specific name isn't found.

core/models/network.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ type NetworkInterface struct {
2323
Type IfaceType `json:"type" validate:"oneof=tap macvtap unsupported"`
2424
// StaticAddress is an optional static IP address to assign to this interface.
2525
// If not supplied then DHCP will be used.
26-
StaticAddress *StaticAddress `json:"staticAddress,omitempty"`
26+
StaticAddress *StaticAddress `json:"staticAddrss,omitempty"`
27+
// BridgeName is the name of the Linux bridge to attach the TAP device to.
28+
BridgeName string `json:"branch_name,omitempty"`
2729
}
2830

2931
// StaticAddress specifies a static IP address configuration.

core/ports/services.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ type IfaceCreateInput struct {
124124
// MAC allows the specifying of a specific MAC address to use for the interface. If
125125
// not supplied a autogenerated MAC address will be used.
126126
MAC string
127+
// Attach indicates if this device should be attached to the parent bridge. Only applicable to TAP devices.
128+
Attach bool
129+
// BridgeName is the name of the bridge to attach to. Only if this is a tap device and attach is true.
130+
BridgeName string
127131
}
128132

129133
type IfaceDetails struct {

core/steps/network/interface_create.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ func (s *createInterface) Do(ctx context.Context) ([]planner.Procedure, error) {
109109
DeviceName: deviceName,
110110
Type: s.iface.Type,
111111
MAC: s.iface.GuestMAC,
112+
Attach: true,
113+
BridgeName: s.iface.BridgeName,
114+
}
115+
116+
if s.iface.Type == models.IfaceTypeTap && s.iface.AllowMetadataRequests {
117+
input.Attach = false
112118
}
113119

114120
output, err := s.svc.IfaceCreate(ctx, *input)

core/steps/network/interface_create_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ func TestNewNetworkInterface_missingInterface(t *testing.T) {
211211
IfaceCreate(gomock.Eq(ctx), gomock.Eq(ports.IfaceCreateInput{
212212
DeviceName: expectedTapDeviceName,
213213
MAC: defaultMACAddress,
214+
Attach: true,
214215
})).
215216
Return(&ports.IfaceDetails{
216217
DeviceName: expectedTapDeviceName,
@@ -239,7 +240,7 @@ func TestNewNetworkInterface_svcError(t *testing.T) {
239240

240241
svc.EXPECT().
241242
IfaceExists(gomock.Eq(ctx), gomock.Eq(expectedTapDeviceName)).
242-
Return(false, errors.ErrParentIfaceRequired).
243+
Return(false, errors.ErrParentIfaceRequiredForAttachingTap).
243244
Times(2)
244245

245246
step := network.NewNetworkInterface(vmid, iface, status, svc)
@@ -249,7 +250,7 @@ func TestNewNetworkInterface_svcError(t *testing.T) {
249250
g.Expect(shouldDo).To(g.BeFalse())
250251

251252
_, err = step.Do(ctx)
252-
g.Expect(err).To(g.MatchError(errors.ErrParentIfaceRequired))
253+
g.Expect(err).To(g.MatchError(errors.ErrParentIfaceRequiredForAttachingTap))
253254

254255
verifyErr := step.Verify(ctx)
255256
g.Expect(verifyErr).To(g.BeNil())
@@ -322,11 +323,11 @@ func TestNewNetworkInterface_createError(t *testing.T) {
322323

323324
svc.EXPECT().
324325
IfaceCreate(gomock.Eq(ctx), &ifaceCreateInputMatcher{}).
325-
Return(nil, errors.ErrParentIfaceRequired).
326+
Return(nil, errors.ErrParentIfaceRequiredForAttachingTap).
326327
Times(1)
327328

328329
_, err = step.Do(ctx)
329-
g.Expect(err).To(g.MatchError(errors.ErrParentIfaceRequired))
330+
g.Expect(err).To(g.MatchError(errors.ErrParentIfaceRequiredForAttachingTap))
330331

331332
verifyErr := step.Verify(ctx)
332333
g.Expect(verifyErr).To(g.BeNil())

core/steps/network/interface_delete_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ func TestDeleteNetworkInterface_IfaceExistsError(t *testing.T) {
169169

170170
svc.EXPECT().
171171
IfaceExists(gomock.Eq(ctx), gomock.Eq(expectedTapDeviceName)).
172-
Return(false, errors.ErrParentIfaceRequired).
172+
Return(false, errors.ErrParentIfaceRequiredForAttachingTap).
173173
Times(2)
174174

175175
step := network.DeleteNetworkInterface(vmid, iface, svc)
@@ -179,7 +179,7 @@ func TestDeleteNetworkInterface_IfaceExistsError(t *testing.T) {
179179
g.Expect(shouldDo).To(g.BeFalse())
180180

181181
_, err = step.Do(ctx)
182-
g.Expect(err).To(g.MatchError(errors.ErrParentIfaceRequired))
182+
g.Expect(err).To(g.MatchError(errors.ErrParentIfaceRequiredForAttachingTap))
183183

184184
verifyErr := step.Verify(ctx)
185185
g.Expect(verifyErr).To(g.BeNil())

0 commit comments

Comments
 (0)