ruvnet/RuView · error
EIO
EIO
Error message
veil: genl_connect failed\n
What it means
`genl_connect()` connects the allocated socket to the kernel's NETLINK_GENERIC subsystem; any non-zero return is flattened by this code to `-EIO`. In practice the underlying causes are environmental: AF_NETLINK blocked by a container/seccomp policy, insufficient privileges in a user namespace, or fd exhaustion (EMFILE) at startup — the daemon deliberately does not distinguish them.
Source
Thrown at firmware/privshield/openwrt/veil_shieldd.c:75
size_t passes; /* Givens passes */
volatile sig_atomic_t running;
};
static struct veil_ctx g_ctx;
static void on_signal(int sig) { (void)sig; g_ctx.running = 0; }
/* ---------------------------------------------------------------------- */
/* nl80211 bring-up — all REAL libnl-genl-3 API names. */
/* ---------------------------------------------------------------------- */
static int veil_nl_connect(struct veil_ctx *c) {
c->sock = nl_socket_alloc();
if (!c->sock) {
fprintf(stderr, "veil: nl_socket_alloc failed\n");
return -ENOMEM;
}
if (genl_connect(c->sock)) {
fprintf(stderr, "veil: genl_connect failed\n");
return -EIO;
}
c->family = genl_ctrl_resolve(c->sock, "nl80211");
if (c->family < 0) {
fprintf(stderr, "veil: genl_ctrl_resolve(nl80211) failed: %d\n",
c->family);
return c->family;
}
/* Observe MLME events (auth/assoc, and — where the driver forwards them —
* action-frame notifications). Real multicast group name is "mlme". */
int grp = genl_ctrl_resolve_grp(c->sock, "nl80211", "mlme");
if (grp >= 0) {
(void)nl_socket_add_membership(c->sock, grp);
}
return 0;
}
/* ---------------------------------------------------------------------- */View on GitHub (pinned to 4685618388)
Solutions
- Run on the target (or container) with host netns and privilege: `docker run --net=host --cap-add NET_ADMIN ...`.
- Raise/inspect fd limits: `ulimit -n`, `ls /proc/$(pidof veil_shieldd)/fd | wc -l`.
- Confirm generic netlink works for other tools on the same host (`genl-ctrl-list` or `iw list`); if they also fail, fix the kernel/policy, not the daemon.
Example fix
# before docker run openwrt/veil_shieldd -i 2 # veil: genl_connect failed # after docker run --net=host --cap-add NET_ADMIN openwrt/veil_shieldd -i 2
Defensive patterns
Strategy: validation
Validate before calling
/* connectivity pre-check before starting the daemon loop */
static int netlink_available(void) {
struct nl_sock *t = nl_socket_alloc();
if (!t) return -1;
int rc = genl_connect(t);
nl_socket_free(t);
return rc == 0 ? 0 : -1;
} Try / catch
int rc = veil_nl_connect(&g_ctx);
if (rc == -EIO) {
/* environment blocks AF_NETLINK: container policy, caps, or fd limits */
fprintf(stderr, "veil: netlink blocked — run with host netns + CAP_NET_ADMIN\n");
exit(rc);
} Prevention
- Always run with host network namespace and CAP_NET_ADMIN (or directly on the router).
- In systemd units allow AF_NETLINK in RestrictAddressFamilies.
- Smoke-test with `iw list` first; if that fails, fix the environment before debugging the daemon.
When it happens
Trigger: Running inside Docker/LXC with a default seccomp profile blocking netlink; unprivileged user namespace without CAP_NET_ADMIN; fd limit exhausted by a leaked loop before the daemon starts; kernel built without generic netlink.
Common situations: Smoke-testing the daemon in a container instead of on the router; systemd unit with restrictive `RestrictAddressFamilies`; long-running hosts with fd leaks from other processes under the same limits.
Related errors
AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16).
Data as JSON: /api/errors/f8ae06661360d8c0.
Report an issue: GitHub.