[PR #10] [wolf-agent] act as fake-udev for hotplugged input devices #12

Open
opened 2026-10-15 12:46:38 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/games-on-whales/fenrir/pull/10
Author: @shrinedogg
Created: 6/13/2026
Status: 🔄 Open

Base: main ← Head: feat/wolf-agent-fake-udev


📝 Commits (1)

  • b621069 [wolf-agent] act as fake-udev for hotplugged input devices

📊 Changes

6 files changed (+385 additions, -1 deletions)

View changed files

📝 pkg/controllers/agent.go (+84 -0)
➕ pkg/fakeudev/fakeudev.go (+173 -0)
➕ pkg/fakeudev/fakeudev_linux.go (+26 -0)
➕ pkg/fakeudev/fakeudev_other.go (+9 -0)
➕ pkg/fakeudev/fakeudev_test.go (+54 -0)
📝 pkg/wolfapi/client.go (+39 -1)

📄 Description

Problem

Wolf creates virtual input devices (gamepads, mouse, keyboard) at runtime and publishes PlugDeviceEvent / UnplugDeviceEvent over its API, carrying the raw udev properties and hwdb entries for each device. In the Docker runner, Wolf's fake-udev helper consumes those events and injects the matching udev database entry plus a libudev netlink event, so that SDL/Steam inside the container actually detect the device.

Under Kubernetes (direwolf), nothing performs that fake-udev injection. The kernel only broadcasts real uevents in the host network namespace, so a device hotplugged by Wolf is invisible to clients in the session pod — controllers never show up in-game.

Fix

Implement the fake-udev role in wolf-agent:

  • Subscribe to Wolf's device plug/unplug events (pkg/wolfapi).
  • On plug, write the /run/udev/data/ entry to a volume shared with the app container, and broadcast a synthetic libudev netlink event inside the pod network namespace so libudev clients (SDL/Steam) discover the device.
  • Resolve MAJOR/MINOR from sysfs, since Wolf cannot stat /dev/input from its own container.
  • Remove the entry again on unplug.

This adds a new pkg/fakeudev package (with unit tests) and wires it into pkg/controllers/agent.go.

Deployment note: broadcasting libudev netlink events requires CAP_NET_ADMIN in the pod netns, and the agent and app containers must share the udev-data volume. Cluster-side wiring is documented at the link below.

Testing


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/games-on-whales/fenrir/pull/10 **Author:** [@shrinedogg](https://github.com/shrinedogg) **Created:** 6/13/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `feat/wolf-agent-fake-udev` --- ### 📝 Commits (1) - [`b621069`](https://github.com/games-on-whales/fenrir/commit/b6210699c2e1439a46f21fb0818d1289ee463dd3) [wolf-agent] act as fake-udev for hotplugged input devices ### 📊 Changes **6 files changed** (+385 additions, -1 deletions) <details> <summary>View changed files</summary> 📝 `pkg/controllers/agent.go` (+84 -0) ➕ `pkg/fakeudev/fakeudev.go` (+173 -0) ➕ `pkg/fakeudev/fakeudev_linux.go` (+26 -0) ➕ `pkg/fakeudev/fakeudev_other.go` (+9 -0) ➕ `pkg/fakeudev/fakeudev_test.go` (+54 -0) 📝 `pkg/wolfapi/client.go` (+39 -1) </details> ### 📄 Description ## Problem Wolf creates virtual input devices (gamepads, mouse, keyboard) at runtime and publishes `PlugDeviceEvent` / `UnplugDeviceEvent` over its API, carrying the raw udev properties and hwdb entries for each device. In the Docker runner, Wolf's `fake-udev` helper consumes those events and injects the matching udev database entry plus a libudev netlink event, so that SDL/Steam inside the container actually detect the device. Under Kubernetes (direwolf), nothing performs that fake-udev injection. The kernel only broadcasts real uevents in the host network namespace, so a device hotplugged by Wolf is invisible to clients in the session pod — controllers never show up in-game. ## Fix Implement the fake-udev role in `wolf-agent`: * Subscribe to Wolf's device plug/unplug events (`pkg/wolfapi`). * On plug, write the `/run/udev/data/` entry to a volume shared with the app container, and broadcast a synthetic libudev netlink event inside the pod network namespace so `libudev` clients (SDL/Steam) discover the device. * Resolve `MAJOR`/`MINOR` from sysfs, since Wolf cannot `stat` `/dev/input` from its own container. * Remove the entry again on unplug. This adds a new `pkg/fakeudev` package (with unit tests) and wires it into `pkg/controllers/agent.go`. > Deployment note: broadcasting libudev netlink events requires `CAP_NET_ADMIN` in the pod netns, and the agent and app containers must share the udev-data volume. Cluster-side wiring is documented at the link below. ## Testing * `go build ./...` (native and `GOOS=linux GOARCH=amd64`) and `go test ./pkg/fakeudev/...` pass. * Running on my Talos cluster (RTX 5090, fenrir/wolf): Steam/SDL now detect the Moonlight controller in-game, where previously no controller appeared. Engineering notes / full context: https://github.com/shrinedogg/biggs.dog#patched-fork--engineering-notes --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Sign in to join this conversation.
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
games-on-whales/fenrir#12
No description provided.