|
| 1 | +--- |
| 2 | +title: "Inside Infix" |
| 3 | +description: "Built on YANG, Built to Last" |
| 4 | +author: troglobit |
| 5 | +date: 2026-03-11 12:25:00 +0100 |
| 6 | +categories: [architecture] |
| 7 | +tags: [design, architecture, yang, netconf, buildroot, sysrepo] |
| 8 | +image: |
| 9 | + path: /assets/img/architecture-overview.svg |
| 10 | + alt: Infix architecture overview showing the management stack |
| 11 | + show_in_post: false |
| 12 | +--- |
| 13 | + |
| 14 | +How does Infix work, what is it based on, and what is YANG? These are a |
| 15 | +few of the questions we get from time to time, and this time we will |
| 16 | +attempt to answer them. Let's dive in! |
| 17 | + |
| 18 | +> If your questions are not answered here, please feel free to engage |
| 19 | +> with us in our [Discussion Forum][1] or join us on [Discord][2]! |
| 20 | +{: .prompt-info } |
| 21 | + |
| 22 | +### Overview |
| 23 | + |
| 24 | +Let's start by zooming out and identify the major components: |
| 25 | + |
| 26 | + - *sysrepo:* the engine which all other major components connect to, |
| 27 | + funnels all actions to callbacks in *confd* |
| 28 | + - *netopeer2:* provides the NETCONF interface (XML over SSH) for |
| 29 | + external management |
| 30 | + - *rousette:* provides the RESTCONF interface (JSON over HTTPS) for |
| 31 | + external management, this is also where the upcoming WebUI will |
| 32 | + connect to, meaning the same WebUI can be used to manage all Infix |
| 33 | + devices on the LAN |
| 34 | + - *klish:* provides the built-in Command Line Interface (CLI) |
| 35 | + - *confd:* gets callbacks for all changes from *sysrepo* which is |
| 36 | + translated into C-library API calls, configuration file changes in |
| 37 | + `/etc`, and network interface setup calls to `iproute2` |
| 38 | + |
| 39 | + |
| 40 | +_**Figure 1:** Infix Architecture Overview_ |
| 41 | + |
| 42 | +Infix runs on a [broad range of hardware][3] — from Raspberry Pi home lab |
| 43 | +boards and compact dual-port routers like the NanoPi R2S, through |
| 44 | +general-purpose ARM and RISC-V end devices such as the NXP i.MX8MP EVK |
| 45 | +and StarFive VisionFive2, all the way up to enterprise switch platforms |
| 46 | +like the Microchip SparX-5i. It also runs on x86_64, making it easy to |
| 47 | +spin up instances in Qemu or GNS3 for development and testing without |
| 48 | +any dedicated hardware. The same OS, the same tooling, the same |
| 49 | +management interfaces throughout. |
| 50 | + |
| 51 | +From a bottom-up perspective, one of the critical design choices for |
| 52 | +switch platforms is to rely on Linux *switchdev* for switch silicon |
| 53 | +abstraction. It is what makes it possible to configure actual hardware |
| 54 | +switch cores using the common Linux bridge. Underneath switchdev sits |
| 55 | +DSA (Distributed Switch Architecture), a kernel sub-layer that models |
| 56 | +the individual ports and internal links of a switch chip and translates |
| 57 | +bridge operations into hardware-specific commands. All operations on the |
| 58 | +bridge are thus "offloaded" to the DSA driver, e.g., adding an interface |
| 59 | +to a bridge enables hardware switching on that port, and adding a VLAN |
| 60 | +enables VLAN filtering in the switch silicon. On platforms without a |
| 61 | +switch core, the same bridge model applies in software — the management |
| 62 | +interface is identical regardless of whether forwarding happens in |
| 63 | +silicon or in the kernel. |
| 64 | + |
| 65 | +Unlike many other Linux-based network operating systems, Infix is not a |
| 66 | +flavor of OpenWRT. Instead it is built on top of the developer-friendly |
| 67 | +[Buildroot][0], tracking its long-term support (LTS) releases. |
| 68 | +Buildroot's LTS cadence is one release every two years (in February), |
| 69 | +each supported for three years, with quarterly stable releases in |
| 70 | +between. This provides a solid base and forms the majority of all Open |
| 71 | +Source packages. A few of those are locally upgraded by the Infix team, |
| 72 | +e.g., sysrepo and netopeer2, and another few are tailor made for Infix, |
| 73 | +e.g., `confd`. |
| 74 | + |
| 75 | +### YANG |
| 76 | + |
| 77 | +The real hero, however, is YANG. |
| 78 | + |
| 79 | +YANG (RFC 6020/7950) is a data modeling language designed specifically |
| 80 | +for network devices. At its core, YANG lets you formally describe what |
| 81 | +configuration and state a device has — what knobs exist, what values |
| 82 | +they accept, how they relate to each other — in a machine-readable way. |
| 83 | +Think of it as a schema, but one that carries enough semantic weight for |
| 84 | +tools to do genuinely useful things with it automatically. |
| 85 | + |
| 86 | +In Infix, the entire system is modeled in YANG. This has one profound |
| 87 | +consequence: every management interface — the CLI, NETCONF, RESTCONF, |
| 88 | +and the upcoming WebUI — is ultimately backed by the same models. There |
| 89 | +is no separate CLI grammar to maintain, no divergence between what the |
| 90 | +web interface can do and what NETCONF can do. When a new feature is |
| 91 | +added to YANG, it appears everywhere at once. |
| 92 | + |
| 93 | +Infix follows industry-standard IETF models wherever they exist. So |
| 94 | +`ietf-interfaces`, `ietf-routing`, `ietf-ip`, and friends describe |
| 95 | +interfaces, routes, and addresses — the same models you would find on |
| 96 | +any standards-compliant device. Where no standard model exists, Infix |
| 97 | +defines its own, prefixed with `infix-`. |
| 98 | + |
| 99 | +Here is a small, simplified excerpt to give a flavour of what a YANG |
| 100 | +module looks like. Real modules are larger, but the structure is |
| 101 | +always the same: |
| 102 | + |
| 103 | +```yang |
| 104 | +container interface { |
| 105 | + leaf name { |
| 106 | + type string { |
| 107 | + length "1..15"; |
| 108 | + pattern '[a-zA-Z][a-zA-Z0-9_-]*'; |
| 109 | + } |
| 110 | + description |
| 111 | + "Interface name, e.g. eth0 or br0. Linux limits |
| 112 | + interface names to 15 characters."; |
| 113 | + } |
| 114 | +
|
| 115 | + leaf description { |
| 116 | + type string { |
| 117 | + length "0..64"; |
| 118 | + } |
| 119 | + description "Human-readable interface label."; |
| 120 | + } |
| 121 | +
|
| 122 | + leaf enabled { |
| 123 | + type boolean; |
| 124 | + default true; |
| 125 | + description |
| 126 | + "Administrative state. Set to false to bring the |
| 127 | + interface down without removing its configuration."; |
| 128 | + } |
| 129 | +
|
| 130 | + leaf mtu { |
| 131 | + type uint16 { |
| 132 | + range "68..9000"; |
| 133 | + } |
| 134 | + units "bytes"; |
| 135 | + default 1500; |
| 136 | + description |
| 137 | + "Maximum transmission unit. Standard Ethernet is 1500 |
| 138 | + bytes; jumbo frames typically go up to 9000."; |
| 139 | + } |
| 140 | +} |
| 141 | +``` |
| 142 | + |
| 143 | +The `pattern` on `name` is a regular expression — only valid Linux |
| 144 | +interface names are accepted. The `range` on `mtu` means a value of |
| 145 | +`42` is rejected before it ever reaches the device; the model itself |
| 146 | +is the contract. This is what makes *offline validation* possible: a |
| 147 | +configuration file can be checked against the loaded YANG modules at |
| 148 | +any point — on a developer's laptop, in CI, or in a management system |
| 149 | +— and any constraint violation is caught immediately, before anything |
| 150 | +is sent over the wire. |
| 151 | + |
| 152 | +#### The CLI is generated from YANG |
| 153 | + |
| 154 | +One of the most visible benefits is the CLI. *klish* generates the |
| 155 | +entire command hierarchy directly from the loaded YANG modules. This |
| 156 | +means `?` and `TAB` completion always reflect the actual model — |
| 157 | +if a node is in YANG, it is in the CLI; if it is not, it is not. There |
| 158 | +is no hand-written command parser to drift out of sync. |
| 159 | + |
| 160 | +#### Datastores |
| 161 | + |
| 162 | +*sysrepo* organises configuration into a set of datastores: |
| 163 | + |
| 164 | + - `factory-config` — generated at first boot, holds per-device defaults |
| 165 | + such as a unique hostname and the correct number of ports; can be |
| 166 | + customised per product by OEMs |
| 167 | + - `failure-config` — also generated at boot; used when the system |
| 168 | + enters *Fail Secure Mode* to ensure the device remains accessible |
| 169 | + even if `startup-config` is broken |
| 170 | + - `startup-config` — created from `factory-config` if it does not yet |
| 171 | + exist; loaded as the active configuration on every boot |
| 172 | + - `running-config` — what is actually running right now; identical to |
| 173 | + `startup-config` at boot unless changes have been made since |
| 174 | + - `candidate-config` — a scratch space created from `running-config` |
| 175 | + when entering the configure context; changes here can be freely |
| 176 | + discarded with `abort` or committed with `leave` |
| 177 | + |
| 178 | +The separation between `candidate` and `running` means you can stage a |
| 179 | +set of changes, inspect the diff, and apply them atomically — or throw |
| 180 | +them away without touching the live system. |
| 181 | + |
| 182 | +### Immutable by Design |
| 183 | + |
| 184 | +Infix runs from a read-only *SquashFS* root filesystem. There is |
| 185 | +nothing to corrupt, no package manager to leave the system in a |
| 186 | +half-upgraded state, and no way for a bad configuration to break the OS |
| 187 | +itself. Configuration lives separately in a writable partition, and the |
| 188 | +YANG datastore sits on top of that. |
| 189 | + |
| 190 | +Software upgrades use an A/B partition scheme. A new image is written |
| 191 | +to the inactive slot while the system keeps running, and the bootloader |
| 192 | +is only pointed at the new slot once the write completes successfully. |
| 193 | +If the new image fails to boot, the system automatically falls back to |
| 194 | +the previous slot. Upgrades are therefore atomic: you either end up on |
| 195 | +the new version or the old one — never in between. |
| 196 | + |
| 197 | +### Built for Continuous Testing |
| 198 | + |
| 199 | +The same design choices that make Infix robust in production also make |
| 200 | +it straightforward to test thoroughly. Because *sysrepo* is the |
| 201 | +authoritative source of truth and configuration is fully decoupled from |
| 202 | +the OS, the Infix regression suite can push NETCONF configuration to a |
| 203 | +device under test (DUT), verify the resulting operational state via |
| 204 | +RESTCONF, and reset it to a known-good baseline — all without touching |
| 205 | +the filesystem directly and without any CLI scraping. |
| 206 | + |
| 207 | +The test suite, *Infamy*, runs against both virtual topologies in Qemu |
| 208 | +and real physical hardware using identical test cases. Virtual |
| 209 | +topologies make it cheap to catch regressions early in development; |
| 210 | +physical runs ensure that hardware-specific paths — DSA offloads, WiFi, |
| 211 | +switch silicon — are exercised regularly. |
| 212 | + |
| 213 | +This level of automation means Infix is not constrained to a fixed |
| 214 | +monthly release cadence. When a fix or feature is ready and passes the |
| 215 | +full suite, a release can go out the same day. The result is a project |
| 216 | +that moves quickly without sacrificing stability. |
| 217 | + |
| 218 | + |
| 219 | +### Wrapping Up |
| 220 | + |
| 221 | +Three ideas run through everything described here. YANG gives the |
| 222 | +system a single source of truth that every interface — CLI, NETCONF, |
| 223 | +RESTCONF, WebUI — derives from automatically, and whose constraints |
| 224 | +catch mistakes before they reach a device. Buildroot gives it a |
| 225 | +stable, well-understood foundation that is easy to audit and extend. |
| 226 | +And the immutable, A/B filesystem means that neither a bad upgrade nor |
| 227 | +a broken configuration can leave a device in an unrecoverable state. |
| 228 | + |
| 229 | +Together they add up to a system that is easier to manage at scale, easier |
| 230 | +to automate, and easier to trust in production — whether you are running |
| 231 | +it on a $35 Raspberry Pi or a data-centre switch. |
| 232 | + |
| 233 | +If you want to go deeper, the [full documentation][4] covers every |
| 234 | +feature in detail. Questions and feedback are always welcome in the |
| 235 | +[Discussion Forum][1] and on [Discord][2]! |
| 236 | + |
| 237 | +[0]: https://buildroot.org/lts.html |
| 238 | +[1]: https://github.com/orgs/kernelkit/discussions |
| 239 | +[2]: https://discord.gg/6bHJWQNVxN |
| 240 | +[3]: /posts/router-boards/ |
| 241 | +[4]: https://www.kernelkit.org/infix/ |
0 commit comments