diff --git a/doc/ChangeLog.md b/doc/ChangeLog.md
index 4dc2d098..52015513 100644
--- a/doc/ChangeLog.md
+++ b/doc/ChangeLog.md
@@ -13,6 +13,13 @@ addresses for interfaces! For details, see below issue #680.
- Update CONTRIBUTING.md for scaling core team and helping external
contributors understand the development process, issue #672
- OSPF: Add limitation to only allow one interface per area
+- Add support for "dummy" interfaces, mostly useful for testing
+- Add support for container hostname format specifiers, just like it
+ already works for the host's hostname setting
+- Updated container documentation, improved images, detail how to set
+ interface name inside the container, and some syntax fixes
+- Greatly reduced size of bundled curiOS httpd OCI container image,
+ reduced from 1.8 MiB to 281 KiB
- The default builds now include the curiOS nftables container image,
which can be used for advanced firewall setups. For an introduction
see
@@ -37,6 +44,8 @@ addresses for interfaces! For details, see below issue #680.
this includes all operational data in ietf-routing:/routing/ribs.
- Fix #697: password is not always set for new users, bug introduced
in v24.06.0 when replacing Augeas with native user handling
+- Fix #708: allow all container networks to set interface name inside
+ container, not just auto-generated veth-pair ends for `docker0` bridge
- Fix BFD in OSPF, previously you could not enable BFD on a single
interface without it was enabled on all interfaces
diff --git a/doc/container.md b/doc/container.md
index d7cd6437..95f5ef49 100644
--- a/doc/container.md
+++ b/doc/container.md
@@ -1,5 +1,6 @@
Containers in Infix
===================
+
* [Introduction](#introduction)
* [Caution](#caution)
@@ -78,16 +79,17 @@ In the CLI, containers can be run in one of two ways:
1. `container run IMAGE [COMMAND]`, and
2. enter `configure` context, then `edit container NAME`
-The first is useful mostly for testing, or running single commands in an
-image. It is a wrapper for `podman run -it --rm ...`, while the latter
-is a wrapper and adaptation of `podman create ...`.
+The former is useful mostly for testing, or running single commands in
+an image. It is a wrapper for `podman run -it --rm ...`, while the
+latter is a wrapper and adaptation of `podman create ...`.
The second create a container with a semi-persistent writable layer that
survives container restarts and host system restarts. However, if you
change the container configuration or upgrade the image (see below), the
container will be recreated and the writable layer is lost. This is why
it is recommended to set up a named volume for directories, or use file
-[Content Mounts][], in your container you want truly persistent content.
+[Content Mounts](#content-mounts), in your container if you want truly
+persistent content.
In fact, in many cases the best way is to create a `read-only` container
and use file mounts and volumes only for the critical parts. Podman
@@ -299,14 +301,19 @@ Currently two types of of container networks are supported:
> For more information on VETH pairs, see the [Networking Guide][0].
+
### Container Bridge
A container bridge is what most container setups use and users want.
+
+
+
The difference from a regular bridge is that the container runtime fully
-manages them -- connecting containers automatically with VETH pairs and
-setting up firewall rules between the host and other containers, as well
-as managing port forwarding. This transparent background management is
-what makes container use seem to be so simple.
+manages them -- connecting containers with automatically created VETH
+pairs (look at the bridge port names) and setting up firewall rules
+between the host and other containers, as well as managing port
+forwarding. This transparent background management is what makes
+container use seem to be so simple.
All interface configuration is done in configure context.
@@ -394,20 +401,21 @@ namespace of a container[^3]. This of course works with plain Ethernet
interfaces as well, but here we will use one end of a VETH pair as an
example.
+The network `option` setting is available also for this case, but only
+the `interface_name=foo0` option works. Which is still very useful. To
+change the MAC address, you need to use the `custom-phys-adderss` in the
+general network settings.
+
[^3]: Something which the container bridge network type does behind the
scenes with one end of an automatically created VETH pair.
+
#### Routed Setup
In this routed setup we reserve 192.168.0.0/24 for the network between
the host and the `ntpd` container.
- _____________
- | |
- veth0 .1 | .2 eth0 |
- \ 192.168.0.0/24 | / |
- '--------------------' [ntpd] |
- |_____________|
+
Configuration is a straight-forward VETH pair setup where we name the
container-end of pair `ntpd`. This is just a convenience for us when
@@ -429,9 +437,12 @@ Adding the interface to the container is the same as before, but since
everything for host interfaces is set up in the interfaces context, we
can take a bit of a shortcut.
- admin@example:/config/container/ntpd/> set network ntpd
+ admin@example:/config/container/ntpd/> set network interface ntpd
admin@example:/config/container/ntpd/> leave
+> Use the `set network inteface ntpd option interface_name=foo0` to set
+> the name of the interface inside the container to `foo0`.
+
The point of the routed case is that port forwarding from the container
in this case is limited to a single interface, not *all interfaces* as
is the default in the masquerading container bridge setup.
@@ -443,21 +454,15 @@ A perhaps more common case is to bridge the other end of the VETH pair
with other physical ports. In this section we show how to add a new
pair to give our container two interfaces:
- _______________
- | | .1 br0
- veth0 .1 | .2 eth0 | / \
- \ 192.168.0.0/24 | / eth1 .2 | veth1b e1
- '------------------' \ | 192.168.1.0/24 /
- | [ntpd] '------------------'
- |_______________|
+
We start by adding the second VETH pair:
admin@example:/config/> edit interface veth1a
- admin@example:/config/interface/veth1a/> set veth peer veth1b
+ admin@example:/config/interface/veth1a/> set veth peer veth1
admin@example:/config/interface/veth1a/> set ipv4 address 192.168.1.2 prefix-length 24
-> The LAN bridge (br0) in this example has IP address 192.168.1.1.
+> The LAN bridge (br1) in this example has IP address 192.168.1.1.
When a container has multiple host interfaces it can often be useful to
have a default route installed. This can be added from the host with a
@@ -473,15 +478,16 @@ have a default route installed. This can be added from the host with a
}
}
veth {
- peer veth1b;
+ peer veth1;
}
admin@example:/config/interface/veth1a/> end
- admin@example:/config/> set interface veth1b bridge-port bridge br0
+ admin@example:/config/> set interface veth1 bridge-port bridge br1
Please note, container network routes require the base interface also
have a static IP address set. Setting only the route, but no address,
means the route is skipped.
+
### Host Networking
The third use-case is host networking, this is where a container share
@@ -491,7 +497,7 @@ the host operating system.
The host networking setup cannot be combined with any other network.
-For an example, see below.
+For an example, [see below](#application-container-nftables).
Mounts and Volumes
@@ -599,6 +605,17 @@ container ID (hash) is used, but this can be easily changed:
admin@example:/> container shell system
root@sys101:/#
+In fact, the container `hostname` setting supports the same format
+specifiers as the host's `hostname` setting:
+
+ - `%i`: OS ID, from `/etc/os-release`, from Menuconfig branding
+ - `%h`: Default hostname, from `/etc/os-release`, from branding
+ - `%m`: NIC specific part of base MAC, e.g., to `c0-ff-ee`
+ - `%%`: Literal %
+
+The most useful combination is probably `"container-name-%m"`, which in
+this example give the container hostname `container-name-c0-ff-ee`.
+
[^1]: this does not apply to the admin-exec command `container run`.
This command is intended to be used for testing and evaluating
container images. Such containers are given a private network
@@ -626,6 +643,7 @@ Notice how we `set network host`, so the container can see and act on
all the host's interfaces, and that we also have to run the container
in *privileged* mode.
+
### Application Container: ntpd
The default NTP server/client in Infix is Chrony, a fully working and
diff --git a/doc/img/cni-bridge-firewall.svg b/doc/img/cni-bridge-firewall.svg
new file mode 100644
index 00000000..04fb8861
--- /dev/null
+++ b/doc/img/cni-bridge-firewall.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/doc/img/cni-ntpd-bridged.svg b/doc/img/cni-ntpd-bridged.svg
new file mode 100644
index 00000000..28b33ffc
--- /dev/null
+++ b/doc/img/cni-ntpd-bridged.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/doc/img/cni-ntpd-routed.svg b/doc/img/cni-ntpd-routed.svg
new file mode 100644
index 00000000..033e08f4
--- /dev/null
+++ b/doc/img/cni-ntpd-routed.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/doc/img/docker.webp b/doc/img/docker.webp
new file mode 100644
index 00000000..b29b95ec
Binary files /dev/null and b/doc/img/docker.webp differ
diff --git a/src/confd/src/ietf-system.c b/src/confd/src/ietf-system.c
index 39ef7dfd..c95b8b7b 100644
--- a/src/confd/src/ietf-system.c
+++ b/src/confd/src/ietf-system.c
@@ -1625,7 +1625,7 @@ static char *get_mac(struct confd *confd, char *mac, size_t len)
*
* XXX: PLEASE REFACTOR THIS INTO A PYTHON HELPER FOR FUTURE EXTENSIONS, OR BUGS!
*/
-static int hostnamefmt(struct confd *confd, char **fmt)
+int hostnamefmt(struct confd *confd, char **fmt)
{
size_t hostlen, fmt_len;
char *hostname;
diff --git a/src/confd/src/infix-containers.c b/src/confd/src/infix-containers.c
index 320070ef..ef576c8f 100644
--- a/src/confd/src/infix-containers.c
+++ b/src/confd/src/infix-containers.c
@@ -21,6 +21,9 @@
#define ACTIVE_QUEUE "/var/lib/containers/active"
#define LOGGER "logger -t container -p local1.notice"
+int hostnamefmt(struct confd *confd, char **fmt);
+
+
static int add(const char *name, struct lyd_node *cif)
{
const char *image = lydx_get_cattr(cif, "image");
@@ -46,8 +49,16 @@ static int add(const char *name, struct lyd_node *cif)
LYX_LIST_FOR_EACH(lyd_child(cif), node, "search")
fprintf(fp, " --dns-search %s", lyd_get_value(node));
- if ((string = lydx_get_cattr(cif, "hostname")))
- fprintf(fp, " --hostname %s", string);
+ if ((string = lydx_get_cattr(cif, "hostname"))) {
+ char *fmt = (char *)string;
+
+ if (hostnamefmt(&confd, &fmt)) {
+ ERRNO("%s: failed setting custom hostname", name);
+ } else {
+ fprintf(fp, " --hostname %s", fmt);
+ free(fmt);
+ }
+ }
if (lydx_is_enabled(cif, "read-only"))
fprintf(fp, " --read-only");
diff --git a/src/confd/yang/containers.inc b/src/confd/yang/containers.inc
index 7e63b0f2..5e6a45af 100644
--- a/src/confd/yang/containers.inc
+++ b/src/confd/yang/containers.inc
@@ -2,5 +2,5 @@
# REMEMBER TO UPDATE infix-interfaces ALSO IN confd.inc
MODULES=(
"infix-interfaces@2024-09-23.yang -e vlan-filtering -e containers"
- "infix-containers@2024-03-27.yang"
+ "infix-containers@2024-10-14.yang"
)
diff --git a/src/confd/yang/infix-containers.yang b/src/confd/yang/infix-containers.yang
index c9dfc9d6..beb86601 100644
--- a/src/confd/yang/infix-containers.yang
+++ b/src/confd/yang/infix-containers.yang
@@ -22,6 +22,17 @@ module infix-containers {
prefix infix-if;
}
+ import infix-system {
+ prefix infix-sys;
+ }
+
+ revision 2024-10-14 {
+ description "Two major changes:
+ - Allow changing name of host interfaces inside container
+ - Support hostname format specifiers, like ietf-system";
+ reference "internal";
+ }
+
revision 2024-03-27 {
description "Add support for capabilities.";
reference "internal";
@@ -160,8 +171,11 @@ module infix-containers {
}
leaf hostname {
- description "Sets the container host name that is available inside the container.";
- type inet:domain-name;
+ description "Sets the container host name, available inside the container.
+
+ Format specifiers are for, default hostname, ID, and the
+ last three octets in base MAC, e.g., c0-ff-ee";
+ type infix-sys:hostname;
}
leaf privileged {
@@ -201,12 +215,16 @@ module infix-containers {
}
leaf-list option {
- when "deref(../name)/../infix-if:container-network/infix-if:type = 'infix-if:bridge'";
- description "Options for masquerading container bridges.
+ description "Options for interface inside container, e.g., interface_name=foo0
- Example: ip=1.2.3.4 -- request a specific IP (IPv4 or IPv6)
- mac=00:01:02:c0:ff:ee -- set fixed MAC address in container
- interface_name=foo0 -- set interface name inside container";
+ Options: ip=1.2.3.4 -- Set static IPv4 address*
+ ip6=2001:0:130f::9c0:876a:130b -- Set static IPv6 address*
+ mac=00:01:02:c0:ff:ee -- Set fixed MAC address
+ interface_name=foo0 -- Set interface name
+
+ NOTE: Some (*) options only work with masquerading container bridges,
+ which automatically create VETH pairs with one end in the host
+ bridge and the other in the container.";
type string;
}
}
diff --git a/src/confd/yang/infix-containers@2024-03-27.yang b/src/confd/yang/infix-containers@2024-10-14.yang
similarity index 100%
rename from src/confd/yang/infix-containers@2024-03-27.yang
rename to src/confd/yang/infix-containers@2024-10-14.yang