Skip to main content

Commands, flags and environment

Rivora ships five programs. This page lists every flag and environment variable they read. Options that only apply in one mode say so.

ProgramRuns whereWhat it is
rivoradevery nodeThe per-node daemon: loads and attaches the BPF programs, programs the maps, health-checks backends, serves the API.
rivoractlanywhere that can reach a rivoradCommand-line client for rivorad's API.
rivora-controllercluster (2 replicas, one leader)Kubernetes IPAM and status writer.
rivorayour workstationInstalls, upgrades and inspects Rivora in a cluster.
rivora-doctorevery node, before installingHost readiness checker.

rivorad

rivorad -config /etc/rivora/config.yaml -bpf-dir /usr/local/share/rivora/bpf # static YAML
rivorad -kubernetes -interface eth0 -bpf-dir /usr/local/share/rivora/bpf # Kubernetes

Both modes

FlagDefaultMeaning
-bpf-dir/usr/local/share/rivora/bpfDirectory holding xdp_ingress.o and tc_nat.o.
-persist-datapathoffPin the XDP/TCX links so the datapath keeps forwarding while rivorad is down, and hot-swap the program on the next start. It stays attached after rivorad exits: remove it with -detach. See Restarting without a traffic gap.
-detachoffRemove datapath links left by a -persist-datapath run, keep the maps, and exit.
-metrics-listen:9871Address of /healthz, /readyz and /metrics, meant to be reachable from outside the node.
-log-levelinfodebug, info, warn or error.
-log-formattexttext or json.
-versionPrint the version and exit.

Static-YAML mode

FlagDefaultMeaning
-config/etc/rivora/config.yamlThe configuration file. Interface, API address, health-check timing, rate limit, BGP and the XDP mode all come from it. SIGHUP reloads its VIPs.

-kubernetes mode

The file's settings become flags, and the VIPs come from Services (and Gateways) instead of a file.

FlagDefaultMeaning
-kubernetesoffRun the Service/EndpointSlice reconciler and L2 speaker instead of loading -config.
-interfaceRequired. The interface to attach to.
-kubeconfigin-cluster, then $KUBECONFIGPath to a kubeconfig.
-api-listen127.0.0.1:9870API address.
-xdp-modegenericgeneric, native or auto.
-loadbalancer-class""Manage only Services whose spec.loadBalancerClass matches; empty manages Services with none set. Must match the controller's.
-namespace$POD_NAMESPACE, else rivora-systemNamespace of the speaker's Lease and of BGP password Secrets.
-node-name$NODE_NAMEThis node's name. Needed for externalTrafficPolicy: Local and for BGPPeer node selectors.
-workers2Concurrent Service reconcile workers.
-speakertrueRun the L2 ARP + NDP speaker (needs CAP_NET_RAW).
-service-policyfalseHonour ServicePolicy objects. Needs the CRD.
-gateway-apifalseAlso reconcile Gateway, TCPRoute and UDPRoute. Needs the Gateway API CRDs.
-health-interval, -health-timeout, -health-fail-threshold, -health-success-threshold3s, 1s, 2, 2Health-check timing.
-rate-limit, -rate-limit-pps, -rate-limit-burstoff, 0, 0Node-wide per-source SYN limit.
-bgp, -bgp-asn, -bgp-router-id, -bgp-ipv6-next-hop, -bgp-peersoffSimple BGP setup: -bgp-peers "10.0.0.1:65000:bfd,10.0.0.2:65001".
-bgp-configA YAML file with a bgp: section, for everything the flags cannot say (passwords, multihop, graceful restart, communities, local-pref, aggregates, per-node peers). Replaces the other -bgp* flags.
-bgp-peer-resourcesfalseAlso read cluster-scoped BGPPeer resources. Needs BGP and the CRD.

rivora-controller

FlagDefaultMeaning
-kubeconfigin-clusterPath to a kubeconfig.
-namespace$POD_NAMESPACE, else rivora-systemNamespace of its leader-election Lease.
-loadbalancer-class""Must match rivorad's.
-workers2Concurrent reconcile workers.
-gateway-apifalseAlso assign addresses to Gateways and write route and listener status.
-metrics-listen:9871Address of /healthz, /readyz and /metrics.
-log-level, -log-format, -versionAs for rivorad.

rivoractl

rivoractl status # one VIP: its detail; several: a line per VIP
rivoractl vips # every VIP: mode, backends, packets
rivoractl backends # every backend of every VIP: VIP, ID, address, weight, state, counters
rivoractl drain 12 # no new flows to backend 12
rivoractl undrain 12
rivoractl weight 12 5 [--vip 10.0.0.1:80:tcp] # override a Maglev weight; 0 clears it
rivoractl validate /etc/rivora/config.yaml # offline; needs no daemon
rivoractl version

status, vips and backends accept --format json. status describes the node's VIP in detail when there is one and prints a line per VIP when there are several. backends has one row per (VIP, backend), so a backend serving two VIPs appears twice, with each VIP's weight; its VIP column is the key weight --vip takes. Drain and weight changes are live and are not persisted: they survive reconciles and reloads but not a restart.

OptionMeaning
--api HOST:PORT or URLWhich rivorad; default 127.0.0.1:9870.
--api-key KEYBearer token; default $RIVORA_API_KEY.
--ca-file FILEVerify the server certificate against this PEM (or its CA); default $RIVORA_CA_FILE. Implies HTTPS. Preferred over --tls-insecure.
--cert FILE --key FILEPresent a client certificate for a server that trusts a client CA; defaults $RIVORA_CLIENT_CERT, $RIVORA_CLIENT_KEY. Replaces --api-key.
--tls-insecureSkip certificate verification; default $RIVORA_TLS_INSECURE. Implies HTTPS.

rivora (cluster lifecycle)

Drives the same Helm chart as helm, through the Helm SDK, so no helm binary is needed. Each release embeds exactly the chart it shipped with.

rivora install --set rivorad.interface=eth0 --set addressPools[0].name=default --set addressPools[0].addresses='{10.0.0.0/24}'
rivora upgrade -f values.yaml
rivora status # cluster-wide rollout status
rivora uninstall
rivora version
OptionDefaultMeaning
--namespacerivora-systemNamespace to install into.
--release-namerivoraHelm release name.
--kubeconfig, --context$KUBECONFIG, current contextWhich cluster.
-f, --valuesValues file (repeatable, applied in order).
--setA value, key=value (repeatable, later wins).
--create-namespacetrueCreate the namespace if it is missing (install).

Like helm upgrade, rivora upgrade does not update CRDs: see CRD lifecycle.

rivora-doctor

Checks a host before you install: privileges, kernel version (TCX, which full-NAT needs, arrived in 6.6), bpffs mounted, BTF present, clang/bpftool if you build on it, the API security settings in force, and optionally an interface's driver.

FlagMeaning
--jsonMachine-readable report.
--strictExit non-zero on warnings as well as failures.
--require-tcxTreat a kernel older than 6.6 as a failure (a warning by default, since DSR-only nodes do not need TCX).
--interface NAMEAlso report that interface's driver, a hint for native XDP.
--root PATHInspect another filesystem root, for example a mounted support bundle.

Exit status is 0 on pass, 2 when a check fails (or warns, with --strict).

Environment variables

API security (rivorad)

VariableEffect
RIVORA_API_KEYAdmin key(s). Setting it turns authentication on. id:NAME=KEY names a key in the audit log; a comma-separated list rotates keys.
RIVORA_API_READONLY_KEYRead-only key(s): may read the API and console, gets 403 on any change. Needs RIVORA_API_KEY too.
RIVORA_TLS_CERT, RIVORA_TLS_KEYServe HTTPS with this certificate.
RIVORA_TLS_SELF_SIGNEDServe HTTPS with a certificate generated at start-up (new on every start).
RIVORA_TLS_CLIENT_CAPEM CA bundle: accept client certificates it signed (mutual TLS). Needs TLS on.
RIVORA_TLS_CLIENT_REQUIRED1 turns away callers without a verified client certificate at the handshake.
RIVORA_API_CERT_ADMIN_CNSComma-separated certificate common names that get the admin role; any other verified certificate is read-only.

Details, rotation and the audit trail: API and console.

Client (rivoractl)

RIVORA_API_KEY, RIVORA_CA_FILE, RIVORA_TLS_INSECURE, RIVORA_CLIENT_CERT, RIVORA_CLIENT_KEY, as above.

Kubernetes

POD_NAMESPACE and NODE_NAME default -namespace and -node-name; the chart sets both from the pod. KUBECONFIG is honoured outside a cluster.

Under systemd

/etc/rivora/rivorad.env (mode 0600, from deploy/systemd/rivorad.env.example) is the unit's EnvironmentFile; put the variables above there. RIVORAD_ARGS in the same file is appended to the command line (for example -persist-datapath). scripts/install-systemd.sh installs the unit and refuses to expose the API on a non-loopback address without a key.