Skip to content

Commit ca09e85

Browse files
committed
Add support for CNI-configured VM network interfaces.
Signed-off-by: Erik Sipsma <[email protected]>
1 parent 498dbf0 commit ca09e85

27 files changed

+1365
-239
lines changed

Makefile

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,34 @@ firecracker-containerd-naive-integ-test-image: $(RUNC_BIN) $(FIRECRACKER_BIN) $(
123123

124124
.PHONY: all $(SUBDIRS) clean proto deps lint install test-images firecracker-container-test-image firecracker-containerd-naive-integ-test-image test test-in-docker $(TEST_SUBDIRS) integ-test $(INTEG_TEST_SUBDIRS)
125125

126+
##########################
127+
# CNI Network
128+
##########################
129+
130+
CNI_BIN_ROOT?=/opt/cni/bin
131+
$(CNI_BIN_ROOT):
132+
mkdir -p $(CNI_BIN_ROOT)
133+
134+
PTP_BIN?=$(CNI_BIN_ROOT)/ptp
135+
$(PTP_BIN): $(CNI_BIN_ROOT)
136+
GOBIN=$(CNI_BIN_ROOT) GO111MODULE=off go get -u github.com/containernetworking/plugins/plugins/main/ptp
137+
138+
HOSTLOCAL_BIN?=$(CNI_BIN_ROOT)/host-local
139+
$(HOSTLOCAL_BIN): $(CNI_BIN_ROOT)
140+
GOBIN=$(CNI_BIN_ROOT) GO111MODULE=off go get -u github.com/containernetworking/plugins/plugins/ipam/host-local
141+
142+
TC_REDIRECT_TAP_BIN?=$(CNI_BIN_ROOT)/tc-redirect-tap
143+
$(TC_REDIRECT_TAP_BIN): $(CNI_BIN_ROOT)
144+
GOBIN=$(CNI_BIN_ROOT) go install github.com/firecracker-microvm/firecracker-go-sdk/cni/cmd/tc-redirect-tap
145+
146+
FCNET_CONFIG?=/etc/cni/conf.d/fcnet.conflist
147+
$(FCNET_CONFIG):
148+
mkdir -p $(dir $(FCNET_CONFIG))
149+
cp tools/demo/fcnet.conflist $(FCNET_CONFIG)
150+
151+
.PHONY: demo-network
152+
demo-network: $(PTP_BIN) $(HOSTLOCAL_BIN) $(TC_REDIRECT_TAP_BIN) $(FCNET_CONFIG)
153+
126154
##########################
127155
# Firecracker submodule
128156
##########################

docs/getting-started.md

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,10 @@ configuration file has the following fields:
192192
delivered.
193193
* `ht_enabled` (unused) - Reserved for future use.
194194
* `debug` (optional) - Enable debug-level logging from the runtime.
195+
* `default_network_interfaces` (optional) - a list of network interfaces to configure
196+
a VM with if no list of network interfaces is provided with a CreateVM call. Defaults
197+
to an empty list. The structure of the items in the list is the same as the Go API
198+
FirecrackerNetworkInterface defined [in protobuf here](../proto/types.proto).
195199

196200
<details>
197201
<summary>A reasonable example configuration</summary>
@@ -205,8 +209,7 @@ configuration file has the following fields:
205209
"cpu_template": "T2",
206210
"log_fifo": "fc-logs.fifo",
207211
"log_level": "Debug",
208-
"metrics_fifo": "fc-metrics.fifo",
209-
212+
"metrics_fifo": "fc-metrics.fifo"
210213
}
211214
```
212215
</details>
@@ -240,11 +243,13 @@ And start a container!
240243

241244
```bash
242245
$ sudo firecracker-ctr --address /run/firecracker-containerd/containerd.sock \
243-
run --snapshotter firecracker-naive --runtime aws.firecracker --tty \
246+
run --snapshotter firecracker-naive --runtime aws.firecracker \
247+
--rm --tty --net-host \
244248
docker.io/library/busybox:latest busybox-test
245249
```
246250

247-
Alternatively you can specify `--runtime` and `--snapshotter` just once when creating a new namespace using containerd's default labels:
251+
Alternatively you can specify `--runtime` and `--snapshotter` just once when
252+
creating a new namespace using containerd's default labels:
248253

249254
```bash
250255
$ sudo firecracker-ctr --address /run/firecracker-containerd/containerd.sock \
@@ -257,6 +262,62 @@ $ sudo firecracker-ctr --address /run/firecracker-containerd/containerd.sock \
257262

258263
$ sudo firecracker-ctr --address /run/firecracker-containerd/containerd.sock \
259264
-n fc \
260-
run --tty \
265+
run --rm --tty --net-host \
261266
docker.io/library/busybox:latest busybox-test
262267
```
268+
269+
## Networking support
270+
Firecracker-containerd supports the same networking options as provided by the
271+
Firecracker Go SDK, [documented here](https://github.com/firecracker-microvm/firecracker-go-sdk#network-configuration).
272+
This includes support for configuring VM network interfaces both with
273+
pre-created tap devices and with tap devices created automatically by
274+
[CNI](https://github.com/containernetworking/cni) plugins.
275+
276+
### CNI Setup
277+
CNI-configured networks offer the quickest way to get VMs up and running with
278+
connectivity to external networks. Setting one up requires a few extra steps in
279+
addition to the above Setup steps.
280+
281+
To install the required CNI dependencies, run the following make target from the
282+
previously cloned firecracker-containerd repository:
283+
```bash
284+
$ sudo make demo-network
285+
```
286+
287+
You can check the Makefile to see exactly what is installed and where, but for a
288+
quick summary:
289+
* [`ptp` CNI plugin](https://github.com/containernetworking/plugins/tree/master/plugins/main/ptp)
290+
- Creates a [veth](http://man7.org/linux/man-pages/man4/veth.4.html) pair with
291+
one end in a private network namespace and the other end in the host's network namespace.
292+
* [`host-local` CNI
293+
plugin](https://github.com/containernetworking/plugins/tree/master/plugins/ipam/host-local)
294+
- Manages IP allocations of network devices present on the local machine by
295+
vending them from a statically defined subnet.
296+
* [`tc-redirect-tap` CNI
297+
plugin](https://github.com/firecracker-microvm/firecracker-go-sdk/tree/master/cni)
298+
- A CNI plugin that adapts other CNI plugins to be usable by Firecracker VMs.
299+
[See this doc for more details](networking.md). It is used here to adapt veth
300+
devices created by the `ptp` plugin to tap devices provided to VMs.
301+
* [`fcnet.conflist`](../tools/demo/fcnet.conflist) - A sample CNI configuration
302+
file that defines a `fcnet` network created via the `ptp`, `host-local` and
303+
`tc-redirect-tap` plugins
304+
305+
After those dependencies are installed, an update to the firecracker-containerd
306+
configuration file is required for VMs to use the `fcnet` CNI-configuration as
307+
their default way of generating network interfaces. Just include the following `
308+
default_network_interfaces` key in your runtime configuration file (by default
309+
at `/etc/containerd/firecracker-runtime.json`):
310+
```json
311+
"default_network_interfaces": [
312+
{
313+
"CNIConfig": {
314+
"NetworkName": "fcnet",
315+
"InterfaceName": "veth0"
316+
}
317+
}
318+
]
319+
```
320+
321+
After that, start up a container (as described in the above Usage section) and
322+
try pinging an IP or making an HTTP request to an endpoint available on your
323+
host's network.

docs/networking.md

Lines changed: 34 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ The Linux Kernel’s [Traffic Control (TC)](http://tldp.org/HOWTO/Traffic-Contro
7070
Most relevant to our interests, the [U32 filter](http://man7.org/linux/man-pages/man8/tc-u32.8.html) provided as part of TC allows you to create a rule that essentially says “take all the packets entering the ingress queue of this device and move them to the egress queue of this other device”. For example, if you have DeviceA and DeviceB you can setup that rule on each of them such that the end effect is every packet sent into DeviceA goes out of DeviceB and every packet sent to DeviceB goes out of DeviceA. The host kernel just moves the ethernet packets from one device’s queue to the other’s, so the redirection is entirely transparent to any userspace application or VM guest kernel all the way down to and including the link layer.
7171

7272
* We first learned about this approach from [Kata Containers](https://github.com/kata-containers/runtime), who are using it for similar purposes in their framework. They have [some more background information documented here](https://gist.github.com/mcastelino/7d85f4164ffdaf48242f9281bb1d0f9b).
73+
* Another use of TC redirect filters in the context of CNI plugins can be found in the [bandwidth CNI plugin](https://github.com/containernetworking/plugins/tree/master/plugins/meta/bandwidth).
7374

7475
This technique can be used to redirect between a Firecracker VM’s tap device and another device in the network namespace Firecracker is running in. If, for example, the VM tap is redirecting with a veth device in a network namespace, the VM guest internally gets a network device with the same mac address as the veth and needs to assign to it the same IP and routes the veth uses. After that, the VM guest essentially operates as though its nic is the same as the veth device outside on the host.
7576

@@ -117,51 +118,45 @@ VMs will execute in.
117118
In this option, Firecracker-containerd just asks for CNI configuration during a CreateVM call, which it will use to configure a network namespace for the Firecracker VM to execute in. The API updates may look something like:
118119

119120
```
120-
message FirecrackerNetworkConfiguration {
121-
// CNI Configuration to use to create the network namespace in which the
122-
// VM will execute. It's an error to specify both this and any NetworkInterfaces
123-
// below.
124-
FirecrackerCNIConfiguration CNIConfiguration;
121+
message FirecrackerNetworkInterface {
122+
// <existing fields...>
123+
124+
// CNI Configuration that will be used to configure the network interface
125+
CNIConfiguration CNIConfig;
125126
126-
// The existing FirecrackerNetworkInterface configuration
127-
// which specifies the name of the tap device on the host and rate limiters
128-
repeated FirecrackerNetworkInterface NetworkInterfaces;
127+
// Static configuration that will be used to configure the network interface
128+
StaticNetworkConfiguration StaticConfig;
129129
}
130130
131131
message FirecrackerCNIConfiguration {
132132
// Name of the CNI network that will be used to configure the VM
133133
string NetworkName;
134134
135-
// Path to CNI bin directory and CNI conf directory, respectively, that will
136-
// be used to configure the VM.
137-
string BinDirectory;
135+
// IF_NAME CNI parameter provided to plugins for the name of devices to create
136+
string InterfaceName;
137+
138+
// Paths to CNI bin directories, CNI conf directory and CNI cache directory,
139+
// respectively, that will be used to configure the VM.
140+
repeated string BinPath;
138141
string ConfDirectory;
142+
string CacheDirectory;
143+
144+
// CNI Args passed to plugins
145+
repeated CNIArg Args;
139146
}
140147
141-
message FirecrackerNetworkInterface {
142-
// <existing fields...>
143-
144-
// (Optional) Static configuration that will be applied internally in the
145-
// Guest VM. At first, it will be an error to specify this for multiple
146-
// NetworkInterfacesin the same CreateVM call (due to the limitations of
147-
// using "ip=..."). In time, we may be able to lift that restriction with
148-
// updates to the implementation.
149-
StaticIPConfiguration StaticIP;
148+
message StaticNetworkConfiguration {
149+
string MacAddress;
150+
string HostDevName;
151+
IPConfiguration IPConfig;
150152
}
151153
152-
message StaticIPConfiguration {
154+
message IPConfiguration {
153155
// Network configuration that will be applied to a network interface in a
154156
// Guest VM on boot.
155-
string IP;
156-
string SubnetMask;
157-
string DefaultGateway;
157+
string PrimaryAddr;
158+
string GatewayAddr;
158159
repeated string Nameservers;
159-
string Hostname;
160-
}
161-
162-
message CreateVMRequest {
163-
// <same existing fields except FirecrackerNetworkInterface which is replaced with the following...>
164-
FirecrackerNetworkConfiguration NetworkConfiguration;
165160
}
166161
```
167162

@@ -258,7 +253,7 @@ In order for networking to work as expected inside the VM, it needs to have IP a
258253

259254
The IP configuration is just pre-configured in the kernel when the system starts (the same end effect of having run the corresponding netlink commands to configure IP and routes). The DNS configuration is applied by writing the nameserver and search domain configuration to /proc/net/pnp in a format that is compatible with /etc/resolv.conf. The typical approach is to then have /etc/resolv.conf be a symlink to /proc/net/pnp.
260255

261-
Users of Firecracker-containerd are also free to provide their own kernel boot options, which could include their own static IP/DNS configuration. In those cases, if they have enabled CNI configuration, Firecracker-containerd will return an error.
256+
Users of Firecracker-containerd are also free to provide their own kernel boot options, which could include their own static IP/DNS configuration. In those cases, if they have enabled CNI configuration, Firecracker-containerd will return an error.
262257

263258
**Pros**
264259

@@ -335,21 +330,15 @@ The biggest immediate downside of Option A is the requirement that /etc/resolv.c
335330

336331
Firecracker-containerd will build the current binaries it does today plus a new CNI-plugin compatible binary, `tc-redirect-tap`, that takes an existing network namespace and creates within it a tap device that is redirected via a TC filter to an already networked device in the netns. This CNI plugin is only useful when chained with other CNI-plugins (which will setup the device that the tap will redirect with).
337332

338-
When setting up Firecracker-containerd, users can optionally include CNI configuration in Firecracker-containerd’s runtime config file. If CNI configuration is not passed during CreateVM (such as the single-container VM use case), the runtime will fall back to configuration in the runtime config. If there’s no CNI configuration present in either the CreateVM call or the runtime config, the behavior will remain the same as it is today.
333+
When setting up Firecracker-containerd, users can optionally include a set of default network interfaces to provide to a VM if none are specified by the user. This allows users to optionally set their VMs to use CNI-configured network interfaces by default. The user is free to provide an explicit NetworkInterfaces list during the CreateVM call (including an empty list), in which case that will be used instead of any defaults present in the runtime config file.
339334

340-
On a high-level, the implementation of CreateVM relevant to the new networking configuration will look something like this:
341-
342-
1. Parse what, if any, CNI configuration is provided via either the CreateVM call or the defaults in the runtime config file.
343-
2. If CNI Configuration is not present, just continue the VM creation process as it is today
344-
3. If CNI Configuration is present, check to see if the Jailer configuration specifies a network namespace
345-
1. If it does, that will be the network namespace provided to the CNI plugins
346-
2. If it does not, a new empty network namespace will be created by the runtime and provided to the CNI plugins
347-
4. Use the provided CNI configuration to configure the network namespace
348-
5. Start the Firecracker VM in the network namespace via the Jailer and with the corresponding `ip=...` kernel boot parameters
335+
The Firecracker Go SDK will take care of checking whether any Jailer config specifies a pre-existing network namespace to use and, if not, creating a new network namespace for the VM on behalf of the user. The Go SDK will also take care of invoking CNI on that network namespace, starting the VMM inside of it, and handling CNI network deletion after the VM stops.
349336

350337
If CreateVM succeeds, any containers running inside the VM with a “host” network namespace will have access to the network configured via CNI outside the VM.
351338

352-
The CNI configuration Firecracker-containerd asks for are just references to a CNI network name, a CNI bin directory (i.e. `/opt/cni/bin`) and a CNI configuration directory (i.e. `/etc/cni/net.d`). A hypothetical example CNI configuration file that uses the standard [ptp CNI plugin](https://github.com/containernetworking/plugins/tree/master/plugins/main/ptp) to create a veth device whose traffic is redirected with a tap device:
339+
The CNI configuration Firecracker-containerd requires from users are a CNI network name and an IfName parameter to provide to CNI plugins. Other values such as the a CNI bin directories and CNI configuration directories can be provided but will have sensible defaults if not provided.
340+
341+
A hypothetical example CNI configuration file that uses the standard [ptp CNI plugin](https://github.com/containernetworking/plugins/tree/master/plugins/main/ptp) to create a veth device whose traffic is redirected with a tap device:
353342

354343
```
355344
{
@@ -361,10 +350,8 @@ The CNI configuration Firecracker-containerd asks for are just references to a C
361350
"ipMasq": true,
362351
"ipam": {
363352
"type": "host-local",
364-
"subnet": "192.168.1.0/24"
365-
},
366-
"dns": {
367-
"nameservers": [ "1.1.1.1" ]
353+
"subnet": "192.168.1.0/24",
354+
"resolvConf": "/etc/resolv.conf"
368355
}
369356
},
370357
{
@@ -376,7 +363,7 @@ The CNI configuration Firecracker-containerd asks for are just references to a C
376363

377364
Given the above configuration, the containers inside the VM will have access to the 192.168.1.0/24 network. Thanks to setting `ipMasq: true`, the containers should also have internet access (assuming the host itself has internet access).
378365

379-
Firecracker-containerd will also provide an example CNI configuration that, if used, will result in Firecracker VMs being spun up with the same access to the network the host has on its default interface (something comparable to Docker’s default networking configuration). This can be setup via a Makefile target (i.e. `install-default-network`), which allows users trying out Firecracker-containerd to get networking, including outbound internet access, working in their Firecracker VMs by default if they so choose.
366+
Firecracker-containerd will also provide an example CNI configuration that, if used, will result in Firecracker VMs being spun up with the same access to the network the host has on its default interface (something comparable to Docker’s default networking configuration). This can be setup via a Makefile target (i.e. `demo-network`), which allows users trying out Firecracker-containerd to get networking, including outbound internet access, working in their Firecracker VMs by default if they so choose.
380367

381368
## Hypothetical CRI interactions
382369

docs/quickstart.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,14 @@ cd ~
8080
# overlay
8181
# * firecracker-containerd, an alternative containerd binary that includes the
8282
# firecracker VM lifecycle plugin and API
83+
# * tc-redirect-tap and other CNI dependencies that enable VMs to start with
84+
# access to networks available on the host
8385
git clone https://github.com/firecracker-microvm/firecracker-containerd.git
8486
cd firecracker-containerd
8587
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y dmsetup
8688
make all image
8789
sudo make install
90+
sudo make demo-network
8891

8992
cd ~
9093

@@ -128,7 +131,13 @@ sudo tee /etc/containerd/firecracker-runtime.json <<EOF
128131
"log_fifo": "fc-logs.fifo",
129132
"log_level": "Debug",
130133
"metrics_fifo": "fc-metrics.fifo",
131-
"kernel_args": "console=ttyS0 noapic reboot=k panic=1 pci=off nomodules ro systemd.journald.forward_to_console systemd.unit=firecracker.target init=/sbin/overlay-init"
134+
"kernel_args": "console=ttyS0 noapic reboot=k panic=1 pci=off nomodules ro systemd.journald.forward_to_console systemd.unit=firecracker.target init=/sbin/overlay-init",
135+
"default_network_interfaces": [{
136+
"CNIConfig": {
137+
"NetworkName": "fcnet",
138+
"InterfaceName": "veth0"
139+
}
140+
}]
132141
}
133142
EOF
134143

@@ -164,7 +173,7 @@ sudo firecracker-ctr --address /run/firecracker-containerd/containerd.sock \
164173
run \
165174
--snapshotter firecracker-naive \
166175
--runtime aws.firecracker \
167-
--tty \
176+
--rm --tty --net-host \
168177
docker.io/library/debian:latest \
169178
test
170179
```

examples/Makefile

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,27 @@ integ-test:
3535
--privileged \
3636
--ipc=host \
3737
--volume /dev:/dev \
38-
--volume /sys:/sys \
3938
--volume /run/udev/control:/run/udev/control \
4039
--volume $(CURDIR)/logs:/var/log/firecracker-containerd-test \
4140
--env EXTRAGOARGS="${EXTRAGOARGS}" \
4241
--workdir="/firecracker-containerd/examples" \
4342
localhost/firecracker-containerd-naive-integ-test:${DOCKER_IMAGE_TAG} \
44-
"make examples && ./taskworkflow"
43+
"make examples && make testtap && ./taskworkflow -ip $(TEST_IP)$(TEST_SUBNET) -gw $(TEST_GATEWAY)"
44+
45+
TEST_GATEWAY?=172.16.0.1
46+
TEST_IP?=172.16.0.2
47+
TEST_SUBNET?=/24
48+
testtap:
49+
ip link add br0 type bridge
50+
ip tuntap add tap0 mode tap
51+
ip link set tap0 master br0
52+
ip link set dev tap0 up
53+
ip link set dev br0 up
54+
ip addr add dev br0 $(TEST_GATEWAY)$(TEST_SUBNET)
4555

4656
clean:
4757
- rm -f taskworkflow
4858

4959
install:
5060

51-
.PHONY: all examples clean install test integ-test
61+
.PHONY: all examples clean install test integ-test testtap

0 commit comments

Comments
 (0)