Files
zpericic 86a0d2cdd1 Initial import of qos-profiles
Role subpackages set the system-wide default qdisc and TCP congestion
control via /usr/lib/sysctl.d, without pulling in the base package:

  server   fq + bbr        bare metal, VM guests
  vmhost   fq_codel + bbr  hypervisors, container hosts
  router   fq_codel + cubic
  desktop  fq_codel + cubic

The base package applies cake per interface from
/etc/qos-profiles/<iface>.conf, layered over role defaults and
/etc/qos-profiles/defaults.conf:

- LINK_RATE with per-direction overrides, shaped to SHAPE_PERCENT
  (default 95, per direction overridable)
- outbound fairness per source host and diffserv4; inbound via ifb,
  fairness per destination host, besteffort with DSCP wash
- NAT awareness, extra cake args (shared and per direction), raw
  qdisc overrides
- config parsed without executing it, validated before any change,
  previous state undone on each run

Applied by the qos-profiles@<iface> unit (bound to the device) or the
qos-profiles-networkmanager dispatcher subpackage, installed
automatically on hosts with NetworkManager. Includes ready-made
examples for VM hosts, OVH dual-NIC servers, DC and home routers.
2026-10-10 22:41:12 +02:00

97 lines
4.8 KiB
Markdown

# qos-profiles
Default qdisc and TCP congestion control per machine role, plus optional
per-interface qdiscs (cake, with ifb for inbound traffic).
## Roles
Install exactly one role subpackage:
| Subpackage | default_qdisc | congestion control | cake NAT | Use for |
| ---------------------- | ------------- | ------------------ | -------- | -------------------------------------------- |
| `qos-profiles-server` | fq | bbr | no | bare-metal servers without guests, VM guests |
| `qos-profiles-vmhost` | fq_codel | bbr | no | hypervisors, container hosts |
| `qos-profiles-router` | fq_codel | cubic | yes | routers |
| `qos-profiles-desktop` | fq_codel | cubic | no | workstations |
The sysctl file is `/usr/lib/sysctl.d/60-qos-profiles-<role>.conf`; override it
in `/etc/sysctl.d/`. `default_qdisc` only applies to interfaces created after
it is set, so reboot after installing or switching roles. Congestion control
is system-wide (or per route), not per interface.
## Per-interface qdiscs
Needs the `qos-profiles` package; the role packages don't pull it in.
Create `/etc/qos-profiles/<iface>.conf`, see
`/usr/share/qos-profiles/example.conf` for all variables and
`/usr/share/qos-profiles/examples/` for ready-made setups:
| Example | Setup |
| --------------------------- | -------------------------------------------------- |
| `defaults.conf` | site-wide `/etc/qos-profiles/defaults.conf` |
| `vmhost-routed-uplink.conf` | VM host, guests routed via the host uplink (EVPN) |
| `vmhost-egress-only.conf` | VM host, outbound fairness only at NIC line rate |
| `vmhost-nat-guests.conf` | VM/container host with masqueraded guests |
| `ovh-public.conf` | dual-NIC dedicated server, public NIC |
| `ovh-vrack-private.conf` | private NIC capped by the provider, outbound only |
| `dc-router-transit.conf` | datacenter router, transit uplink, no NAT |
| `router-ftth.conf` | fibre with Ethernet handoff, NAT |
| `router-vdsl-pppoe.conf` | VDSL2 with PPPoE on `ppp0`, NAT, ACK filtering |
| `router-docsis.conf` | cable, NAT, ACK filtering |
| `backup-nic-raw.conf` | raw `fq` qdisc with a per-flow cap instead of cake |
Minimal example:
```
LINK_RATE=1gbit
```
This shapes both directions to 95% of the link rate with cake. Outbound,
traffic is shared per source host and DiffServ classes are applied
(`diffserv4`). Inbound, traffic is shared per destination host, DSCP marks
are ignored (`besteffort`) and cleared (`wash`), since they come from the
internet. `EGRESS_SHAPE_PERCENT` and `INGRESS_SHAPE_PERCENT` set the
percentage per direction.
Configuration is read in order, later overriding earlier:
1. `/usr/lib/qos-profiles/role-<role>.conf` — installed role package
2. `/etc/qos-profiles/defaults.conf` — site-wide
3. `/etc/qos-profiles/<iface>.conf` — the interface
It is applied by either:
- `qos-profiles-networkmanager` (installed automatically with NetworkManager)
when NetworkManager brings the interface up, or
- `systemctl enable --now qos-profiles@<iface>` for interfaces NetworkManager
doesn't manage. It runs whenever the device appears.
Both may be active; they're serialised and idempotent. To apply changes run
`systemctl restart qos-profiles@<iface>` or
`/usr/libexec/qos-profiles/qos-apply start <iface>`. Stopping restores the
default qdisc and removes the ifb device.
Inbound shaping replaces any existing `clsact` qdisc on the interface (and its
tc/BPF filters).
## DiffServ
`diffserv4` sorts outbound packets by DSCP into bulk (CS1), best effort, video
(AF4x, CS3, ...) and voice (EF, CS6, ...). Higher classes get priority only up
to a share of the rate, so they can't starve the others. Marking backup or
replication traffic CS1 (e.g. nftables `ip dscp set cs1`) makes it yield to
everything else.
## Topologies
- **VM host, VMs routed via the host uplink (EVPN anycast gateway):** cake on
the uplink NIC gives each guest an equal share. VXLAN-encapsulated traffic on
the same NIC is seen by its outer header (the VTEP address), so it shares as
a single host.
- **VM host, VMs bridged to a switch, routing elsewhere:** the WAN bottleneck
is at the router; put cake on the router WAN (`qos-profiles-router`). The
host only needs the role package.
- **Host with separate public and private NICs:** configure the public NIC only.
- **Bond or VLAN uplink:** these devices have no queue of their own; put cake
on the physical NIC, or set a rate explicitly.