Netsim Driver¶
jumpstarter-driver-netsim controls
Cuttlefish
netsim virtual radio interfaces through the netsim REST API.
It manages Bluetooth (classic + BLE), WiFi, and UWB radios on
Cuttlefish virtual devices:
toggle state and capture HCI packets.
Installation¶
$ pip3 install --extra-index-url https://pkg.jumpstarter.dev/simple jumpstarter-driver-netsim
Prerequisites¶
A running netsim instance. Launch Cuttlefish with
--netsim=trueto enable all virtual radios (Bluetooth, WiFi, UWB). For Bluetooth only, use--netsim_bt=true.netsim REST API accessible (see port notes below)
Configuration¶
Example exporter configuration:
export:
netsim:
type: jumpstarter_driver_netsim.driver.Netsim
config:
host: localhost
port: 7681
netsim_cli: /usr/lib/cuttlefish-common/bin/netsim
Configuration Parameters¶
Parameter |
Description |
Type |
Required |
Default |
|---|---|---|---|---|
host |
netsim hostname |
str |
no |
“localhost” |
port |
netsim REST API port |
int |
no |
7681 |
netsim_cli |
Path to netsim CLI (for captures) |
str |
no |
“” |
Port discovery: netsimd assigns its REST port as
7681 + netsim_instance_num. The instance number depends on CVD numbering and isn’t directly controllable - failed CVD creates consume instance numbers. Port 7681 is only correct fornetsim_instance_num=0. Check your CVD config’snetsim_instance_numfield and setport: 7681 + Nin your exporter config.
ExporterConfig Example¶
apiVersion: jumpstarter.dev/v1alpha1
kind: ExporterConfig
metadata:
namespace: default
name: netsim-local
export:
netsim:
type: jumpstarter_driver_netsim.driver.Netsim
config:
host: localhost
port: 7681
netsim_cli: /usr/lib/cuttlefish-common/bin/netsim
netsim_cli: Required for packet capture toggle (start/stop). The REST PATCH endpoint for captures is broken in netsim <=0.3.100. Without this config,start_capture,stop_capture, andset_capturewill raise an error.list_capturesandget_capture(download) work via REST without it.
Usage¶
CLI¶
# Health check returns device count
j netsim status
# List all devices and radio states
j netsim devices
# Show a single device (by name or numeric ID)
j netsim device cvd-1
j netsim device 1
# Toggle Bluetooth radios
j netsim radio cvd-1 bt_classic on
j netsim radio cvd-1 ble off
# Toggle WiFi / UWB
j netsim radio cvd-1 wifi on
j netsim radio cvd-1 uwb off
# Raw device patch (full flexibility)
j netsim patch cvd-1 '{"visible": false}'
# Reset all devices (WARNING: host-wide, see below)
j netsim reset
# Packet capture
j netsim capture list
j netsim capture start cvd-1 # starts BT capture, returns ID
j netsim capture start cvd-1 --chip UWB # start UWB capture
j netsim capture stop 10 # stop by capture ID
j netsim capture get 10 -o capture.pcap # download pcap
Python API¶
from jumpstarter.common.utils import serve
from jumpstarter_driver_netsim.driver import Netsim
driver = Netsim(
host="localhost",
port=7684, # port = 7681 + netsim_instance_num
netsim_cli="/usr/lib/cuttlefish-common/bin/netsim", # for capture toggle
)
with serve(driver) as client:
# Health check returns device count
print(client.status()) # e.g. "OK (2 devices)"
# List devices
devices = client.list_devices()
print(devices)
# Get a single device (name, numeric ID, or substring)
cvd1 = client.get_device("cvd-1")
cvd1 = client.get_device("1") # numeric ID
# Toggle Bluetooth
client.set_radio("cvd-1", "bt_classic", "on")
client.set_radio("cvd-1", "ble", "off")
# Start packet capture for a device (finds matching capture entry)
cap_id = client.start_capture("cvd-1") # returns capture ID
# ... perform BT operations ...
client.stop_capture(cap_id)
# Download pcap
pcap_data = client.get_capture(cap_id)
with open("capture.pcap", "wb") as f:
f.write(pcap_data)
# Low-level capture control (by capture ID)
client.set_capture("1", "on")
client.set_capture("1", "off")
# Reset all (host-wide!)
client.reset_devices()
Architecture¶
┌────────────┐ gRPC ┌────────────────┐ HTTP ┌──────────────────┐
│ jmp shell │──────────────►│ Netsim │────────────►│ netsim │
│ (client) │ │ Driver │ port 7681 │ (netsimd) │
└────────────┘ └────────────────┘ └────────┬─────────┘
│
┌──────┴──────┐
│ rootcanal │
│ (BT HCI) │
└──────┬──────┘
│
┌────────┴────────┐
│ CVD-1 CVD-2 │
│ (virtual BT/ │
│ WiFi/UWB) │
└─────────────────┘
The driver is a thin REST client that translates Jumpstarter driver calls into netsim API requests. netsim embeds rootcanal as the virtual Bluetooth HCI controller, each Cuttlefish CVD auto-registers its radio chips with netsim, and all CVDs on the same netsim instance share the virtual radio medium.
Radio Types¶
Radio |
CLI name |
Controls |
|---|---|---|
BT Classic |
|
Classic Bluetooth (A2DP, HFP, etc.) |
BLE |
|
Bluetooth Low Energy |
WiFi |
|
Virtual WiFi |
UWB |
|
Ultra-Wideband |
Host-Wide Operations¶
Warning:
reset_devices(CLI:j netsim reset) resets all devices on the netsim instance, not just the ones you own. On a shared host with multiple CVDs or tenants, this will affect everyone. Use with care in multi-tenant environments.
API Reference¶
Driver¶
- class jumpstarter_driver_netsim.driver.Netsim¶
Android netsim driver for controlling virtual radio interfaces (Bluetooth, WiFi, UWB).
- classmethod client() str¶
Return full import path of the corresponding driver client class
- async get_capture(capture_id: str) AsyncGenerator[str, None]¶
Download a packet capture as streaming base64-encoded pcap chunks.
Yields base64-encoded chunks to avoid gRPC message size limits.
- get_device(name_or_id: str) str¶
Get a single device by name or ID.
- list_captures() str¶
List all packet captures.
- list_devices() str¶
List all devices and their chips/radio states.
- patch_device(name_or_id: str, patch_json: str) str¶
Send raw patch to a device. patch_json is the device object fields to update.
- reset_devices() str¶
Reset all devices to initial state.
WARNING: this is host-wide - resets radios for ALL devices on this netsim instance, not just yours. On a shared host, this affects other tenants.
- set_capture(capture_id: str, enabled: str) str¶
Start or stop a packet capture by capture ID. enabled: on/off.
Requires netsim_cli config. REST PATCH broken in netsim <=0.3.100.
- set_radio(name_or_id: str, radio: str, enabled: str) str¶
Toggle a radio on/off. radio: bt_classic, ble, wifi, uwb. enabled: on/off.
- start_capture(name_or_id: str, chip_kind: str = 'BLUETOOTH') str¶
Start packet capture for a device, resolved by chip kind.
Finds the capture entry matching this device and chip kind, then enables it via CLI. Returns the capture ID used. Requires netsim_cli config.
- status() str¶
Health check — verifies netsim is reachable. Returns device count.
- stop_capture(capture_id: str) str¶
Stop a packet capture. Requires netsim_cli config.
Client¶
- class jumpstarter_driver_netsim.client.NetsimClient¶
Client for controlling Android netsim virtual radios.
- get_capture(capture_id: str) bytes¶
Download a packet capture via chunked streaming transfer.
- status() str¶
Get current cached status (non-blocking).
Returns None if status monitor not started.