diff --git a/.github/scripts/tests/test_usbip.py b/.github/scripts/tests/test_usbip.py index 226621bd..47fa7d40 100644 --- a/.github/scripts/tests/test_usbip.py +++ b/.github/scripts/tests/test_usbip.py @@ -37,7 +37,8 @@ class USBIPTests(unittest.TestCase): self.root = Path(self.temp.name) self.m = load() for attr, path in (("CONFIG_DIR", "config"), ("RUN_DIR", "client-run"), - ("SERVER_RUN_DIR", "server-run"), ("UNIT_DIR", "units"), ("SYSFS", "sysfs")): + ("SERVER_RUN_DIR", "server-run"), ("UNIT_DIR", "units"), ("SYSFS", "sysfs"), + ("NET_SYSFS", "net")): setattr(self.m, attr, self.root / path) getattr(self.m, attr).mkdir() class MatchTable: @@ -64,6 +65,15 @@ class USBIPTests(unittest.TestCase): self.m.atomic_json(self.m.CONFIG_DIR / "config.json", value) return value + def test_a_usb_network_adapter_is_not_offered(self): + self.device("1-3", serial="nic-1") + (self.m.NET_SYSFS / "enx001122").mkdir() + (self.m.NET_SYSFS / "enx001122" / "device").symlink_to(self.m.SYSFS / "1-3" / "1-3:1.0") + self.assertEqual(next(d for d in self.m.inventory() if d["busid"] == "1-3")["blocked"], + "USB network adapters cannot be shared") + self.device("1-4", serial="zigbee-9") + self.assertEqual(next(d for d in self.m.inventory() if d["busid"] == "1-4")["blocked"], "") + def device(self, busid="1-2", serial="zigbee-123", device_class="00", interface="03", driver="usb"): path = self.m.SYSFS / busid path.mkdir() diff --git a/docs/usbip.md b/docs/usbip.md index 193f809d..e0e1eab2 100644 --- a/docs/usbip.md +++ b/docs/usbip.md @@ -1,6 +1,6 @@ # USB/IP over SSH -Open **Hardware: GPUs, Coral-TPU and USB/IP → USB/IP over SSH** to share a +Open **Hardware: GPUs and Coral-TPU → USB/IP over SSH** to share a selected USB device or connect this Linux machine to a device on another host. The same menu is available through the main menu search (`usbip`, `zigbee`, `bluetooth` or `printer`). This implements the host and Linux client setup @@ -44,7 +44,8 @@ releases managed bindings before dropping the references. Without a serial number, the vendor/product and original bus ID must match; the manager will not guess which identical dongle to bind. Duplicate serial numbers are rejected as ambiguous. USB hubs and mass-storage devices, including -composite devices with a storage interface, are excluded. +composite devices with a storage interface, are excluded. So are USB network +adapters: on many mini PCs one is the management link of the host. **Stop sharing** removes one saved selection and waits for confirmed release. A cleanup error or timeout is reported instead of claiming that eject succeeded. diff --git a/lang/de.json b/lang/de.json index e4f493c9..28308bc2 100644 --- a/lang/de.json +++ b/lang/de.json @@ -9027,11 +9027,10 @@ "Disable USB/IP server": "USB/IP-Server deaktivieren", "Disable the server and release all USB devices managed by ProxMenux? Saved selections are kept for the next enable.": "Den Server deaktivieren und alle von ProxMenux verwalteten USB-Geräte freigeben? Die gespeicherte Auswahl bleibt für die nächste Aktivierung erhalten.", "Enable USB/IP server": "USB/IP-Server aktivieren", - "GPUs, Coral-TPU and USB/IP Menu": "Menü für GPUs, Coral-TPU und USB/IP", - "Hardware: GPUs, Coral-TPU and USB/IP": "Hardware: GPUs, Coral-TPU und USB/IP", "Install the USB/IP dependencies from the configured Debian repositories?": "USB/IP-Abhängigkeiten aus den konfigurierten Debian-Repositories installieren?", "Linux guest setup and migration notes": "Hinweise zur Einrichtung und Migration von Linux-Gästen", - "No eligible USB devices found. Hubs and mass storage are excluded.": "Keine geeigneten USB-Geräte gefunden. Hubs und Massenspeicher sind ausgeschlossen.", + "No eligible USB devices found. Hubs, mass storage and network adapters are excluded.": "Keine geeigneten USB-Geräte gefunden. Hubs, Massenspeicher und Netzwerkadapter sind ausgeschlossen.", + "If the USB/IP service stops unexpectedly, stop sharing while the device is still connected to release it. In rare cases only a host reboot releases it.": "Wenn der USB/IP-Dienst unerwartet stoppt, beenden Sie die Freigabe, solange das Gerät noch angeschlossen ist. In seltenen Fällen ist es erst nach einem Neustart des Hosts wieder verfügbar.", "No shared devices are available on this server.": "Auf diesem Server sind keine freigegebenen Geräte verfügbar.", "Remove a remote USB connection": "Entfernte USB-Verbindung entfernen", "Remove this connection and detach its USB device?": "Diese Verbindung entfernen und das USB-Gerät trennen?", diff --git a/lang/es.json b/lang/es.json index d4ff2d7b..15af5f5d 100644 --- a/lang/es.json +++ b/lang/es.json @@ -1,11 +1,10 @@ { - "Hardware: GPUs, Coral-TPU and USB/IP": "Hardware: GPU, Coral-TPU y USB/IP", - "GPUs, Coral-TPU and USB/IP Menu": "Menú de GPU, Coral-TPU y USB/IP", "USB/IP over SSH": "USB/IP mediante SSH", "Run this menu as root.": "Ejecuta este menú como root.", "USB/IP configuration updated. Open status to check the connection.": "Configuración de USB/IP actualizada. Abre el estado para comprobar la conexión.", "Install the USB/IP dependencies from the configured Debian repositories?": "¿Instalar las dependencias de USB/IP desde los repositorios de Debian configurados?", - "No eligible USB devices found. Hubs and mass storage are excluded.": "No hay dispositivos USB compatibles. Se excluyen los concentradores y el almacenamiento masivo.", + "No eligible USB devices found. Hubs, mass storage and network adapters are excluded.": "No hay dispositivos USB compatibles. Se excluyen los concentradores, el almacenamiento masivo y los adaptadores de red.", + "If the USB/IP service stops unexpectedly, stop sharing while the device is still connected to release it. In rare cases only a host reboot releases it.": "Si el servicio USB/IP se detiene de forma inesperada, deja de compartir el dispositivo mientras sigue conectado para liberarlo. En casos excepcionales solo se libera reiniciando el host.", "Select the USB device to share:": "Selecciona el dispositivo USB que quieres compartir:", "The selected USB device will become unavailable to local applications and guests. Only one remote client can use it at a time. Share this device?": "El dispositivo USB dejará de estar disponible para las aplicaciones y los invitados locales. Solo puede usarlo un cliente remoto a la vez. ¿Compartirlo?", "Select a saved USB/IP device:": "Selecciona un dispositivo USB/IP guardado:", diff --git a/lang/fr.json b/lang/fr.json index b3a4d8e8..f1714e7a 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -9026,11 +9026,10 @@ "Disable USB/IP server": "Désactiver le serveur USB/IP", "Disable the server and release all USB devices managed by ProxMenux? Saved selections are kept for the next enable.": "Désactiver le serveur et libérer tous les périphériques USB gérés par ProxMenux ? Les sélections enregistrées seront conservées pour la prochaine activation.", "Enable USB/IP server": "Activer le serveur USB/IP", - "GPUs, Coral-TPU and USB/IP Menu": "Menu GPUs, Coral-TPU et USB/IP", - "Hardware: GPUs, Coral-TPU and USB/IP": "Matériel : GPUs, Coral-TPU et USB/IP", "Install the USB/IP dependencies from the configured Debian repositories?": "Installer les dépendances USB/IP depuis les dépôts Debian configurés ?", "Linux guest setup and migration notes": "Configuration des invités Linux et notes de migration", - "No eligible USB devices found. Hubs and mass storage are excluded.": "Aucun périphérique USB éligible trouvé. Les concentrateurs et les périphériques de stockage de masse sont exclus.", + "No eligible USB devices found. Hubs, mass storage and network adapters are excluded.": "Aucun périphérique USB éligible trouvé. Les concentrateurs, les périphériques de stockage de masse et les adaptateurs réseau sont exclus.", + "If the USB/IP service stops unexpectedly, stop sharing while the device is still connected to release it. In rare cases only a host reboot releases it.": "Si le service USB/IP s'arrête de manière inattendue, arrêtez le partage tant que le périphérique est encore branché pour le libérer. Dans de rares cas, seul un redémarrage de l'hôte le libère.", "No shared devices are available on this server.": "Aucun périphérique partagé n'est disponible sur ce serveur.", "Remove a remote USB connection": "Supprimer une connexion USB distante", "Remove this connection and detach its USB device?": "Supprimer cette connexion et détacher son périphérique USB ?", diff --git a/lang/it.json b/lang/it.json index 96bde84f..af2f4c4d 100644 --- a/lang/it.json +++ b/lang/it.json @@ -9027,11 +9027,10 @@ "Disable USB/IP server": "Disabilita il server USB/IP", "Disable the server and release all USB devices managed by ProxMenux? Saved selections are kept for the next enable.": "Disabilitare il server e liberare tutti i dispositivi USB gestiti da ProxMenux? Le selezioni salvate verranno mantenute per la prossima attivazione.", "Enable USB/IP server": "Abilita il server USB/IP", - "GPUs, Coral-TPU and USB/IP Menu": "Menu GPUs, Coral-TPU e USB/IP", - "Hardware: GPUs, Coral-TPU and USB/IP": "Hardware: GPUs, Coral-TPU e USB/IP", "Install the USB/IP dependencies from the configured Debian repositories?": "Installare le dipendenze USB/IP dai repository Debian configurati?", "Linux guest setup and migration notes": "Configurazione degli ospiti Linux e note sulla migrazione", - "No eligible USB devices found. Hubs and mass storage are excluded.": "Nessun dispositivo USB idoneo trovato. Gli hub e i dispositivi di archiviazione di massa sono esclusi.", + "No eligible USB devices found. Hubs, mass storage and network adapters are excluded.": "Nessun dispositivo USB idoneo trovato. Gli hub, i dispositivi di archiviazione di massa e gli adattatori di rete sono esclusi.", + "If the USB/IP service stops unexpectedly, stop sharing while the device is still connected to release it. In rare cases only a host reboot releases it.": "Se il servizio USB/IP si arresta in modo imprevisto, interrompi la condivisione mentre il dispositivo è ancora collegato per liberarlo. In rari casi solo un riavvio dell'host lo libera.", "No shared devices are available on this server.": "Nessun dispositivo condiviso disponibile su questo server.", "Remove a remote USB connection": "Rimuovi una connessione USB remota", "Remove this connection and detach its USB device?": "Rimuovere questa connessione e scollegare il relativo dispositivo USB?", diff --git a/lang/pt.json b/lang/pt.json index 28496fb6..10fa90cd 100644 --- a/lang/pt.json +++ b/lang/pt.json @@ -9027,11 +9027,10 @@ "Disable USB/IP server": "Desativar o servidor USB/IP", "Disable the server and release all USB devices managed by ProxMenux? Saved selections are kept for the next enable.": "Desativar o servidor e libertar todos os dispositivos USB geridos pelo ProxMenux? As seleções guardadas serão mantidas para a próxima ativação.", "Enable USB/IP server": "Ativar o servidor USB/IP", - "GPUs, Coral-TPU and USB/IP Menu": "Menu de GPUs, Coral-TPU e USB/IP", - "Hardware: GPUs, Coral-TPU and USB/IP": "Hardware: GPUs, Coral-TPU e USB/IP", "Install the USB/IP dependencies from the configured Debian repositories?": "Instalar as dependências USB/IP a partir dos repositórios Debian configurados?", "Linux guest setup and migration notes": "Configuração de convidados Linux e notas de migração", - "No eligible USB devices found. Hubs and mass storage are excluded.": "Não foram encontrados dispositivos USB elegíveis. Os hubs e os dispositivos de armazenamento em massa estão excluídos.", + "No eligible USB devices found. Hubs, mass storage and network adapters are excluded.": "Não foram encontrados dispositivos USB elegíveis. Os hubs, os dispositivos de armazenamento em massa e os adaptadores de rede estão excluídos.", + "If the USB/IP service stops unexpectedly, stop sharing while the device is still connected to release it. In rare cases only a host reboot releases it.": "Se o serviço USB/IP parar inesperadamente, deixe de partilhar o dispositivo enquanto ainda estiver ligado para o libertar. Em casos raros, só um reinício do host o liberta.", "No shared devices are available on this server.": "Não há dispositivos partilhados disponíveis neste servidor.", "Remove a remote USB connection": "Remover uma ligação USB remota", "Remove this connection and detach its USB device?": "Remover esta ligação e desligar o respetivo dispositivo USB?", diff --git a/lang/sk.json b/lang/sk.json index 0801fd2c..64d93b74 100644 --- a/lang/sk.json +++ b/lang/sk.json @@ -9027,11 +9027,10 @@ "Disable USB/IP server": "Zakázať server USB/IP", "Disable the server and release all USB devices managed by ProxMenux? Saved selections are kept for the next enable.": "Zakázať server a uvoľniť všetky USB zariadenia spravované ProxMenuxom? Uložený výber sa zachová pre ďalšie povolenie.", "Enable USB/IP server": "Povoliť server USB/IP", - "GPUs, Coral-TPU and USB/IP Menu": "Ponuka GPUs, Coral-TPU a USB/IP", - "Hardware: GPUs, Coral-TPU and USB/IP": "Hardvér: GPUs, Coral-TPU a USB/IP", "Install the USB/IP dependencies from the configured Debian repositories?": "Nainštalovať závislosti USB/IP z nakonfigurovaných repozitárov Debianu?", "Linux guest setup and migration notes": "Nastavenie hostí Linux a poznámky k migrácii", - "No eligible USB devices found. Hubs and mass storage are excluded.": "Nenašli sa žiadne vhodné USB zariadenia. Rozbočovače a veľkokapacitné úložiská sú vylúčené.", + "No eligible USB devices found. Hubs, mass storage and network adapters are excluded.": "Nenašli sa žiadne vhodné USB zariadenia. Rozbočovače, veľkokapacitné úložiská a sieťové adaptéry sú vylúčené.", + "If the USB/IP service stops unexpectedly, stop sharing while the device is still connected to release it. In rare cases only a host reboot releases it.": "Ak sa služba USB/IP neočakávane zastaví, ukončite zdieľanie, kým je zariadenie ešte pripojené, aby sa uvoľnilo. V zriedkavých prípadoch ho uvoľní iba reštart hosta.", "No shared devices are available on this server.": "Na tomto serveri nie sú k dispozícii žiadne zdieľané zariadenia.", "Remove a remote USB connection": "Odstrániť vzdialené USB pripojenie", "Remove this connection and detach its USB device?": "Odstrániť toto pripojenie a odpojiť jeho USB zariadenie?", diff --git a/lang/sv.json b/lang/sv.json index 6be56ee7..56cedfeb 100644 --- a/lang/sv.json +++ b/lang/sv.json @@ -9027,11 +9027,10 @@ "Disable USB/IP server": "Inaktivera USB/IP-servern", "Disable the server and release all USB devices managed by ProxMenux? Saved selections are kept for the next enable.": "Inaktivera servern och frigör alla USB-enheter som hanteras av ProxMenux? Sparade val behålls till nästa aktivering.", "Enable USB/IP server": "Aktivera USB/IP-servern", - "GPUs, Coral-TPU and USB/IP Menu": "Meny för GPUs, Coral-TPU och USB/IP", - "Hardware: GPUs, Coral-TPU and USB/IP": "Maskinvara: GPUs, Coral-TPU och USB/IP", "Install the USB/IP dependencies from the configured Debian repositories?": "Installera USB/IP-beroendena från de konfigurerade Debian-paketförråden?", "Linux guest setup and migration notes": "Konfiguration av Linux-gäster och information om migrering", - "No eligible USB devices found. Hubs and mass storage are excluded.": "Inga lämpliga USB-enheter hittades. Hubbar och masslagringsenheter är undantagna.", + "No eligible USB devices found. Hubs, mass storage and network adapters are excluded.": "Inga lämpliga USB-enheter hittades. Hubbar, masslagringsenheter och nätverksadaptrar är undantagna.", + "If the USB/IP service stops unexpectedly, stop sharing while the device is still connected to release it. In rare cases only a host reboot releases it.": "Om USB/IP-tjänsten stoppas oväntat, sluta dela enheten medan den fortfarande är ansluten för att frigöra den. I sällsynta fall frigörs den bara genom en omstart av värden.", "No shared devices are available on this server.": "Inga delade enheter är tillgängliga på denna server.", "Remove a remote USB connection": "Ta bort en fjärransluten USB-anslutning", "Remove this connection and detach its USB device?": "Ta bort denna anslutning och koppla från dess USB-enhet?", diff --git a/scripts/devices/usbip_manager.py b/scripts/devices/usbip_manager.py index 87c56109..977735c2 100644 --- a/scripts/devices/usbip_manager.py +++ b/scripts/devices/usbip_manager.py @@ -42,6 +42,7 @@ MARKER = "# Managed by ProxMenux USB/IP" TRANSPORT_USER = "proxmenux-usbip" TRANSPORT_HOME = Path("/var/lib/proxmenux-usbip") MATCH_BUSID = Path("/sys/bus/usb/drivers/usbip-host/match_busid") +NET_SYSFS = Path("/sys/class/net") BUSID = re.compile(r"[0-9]+-[0-9]+(?:\.[0-9]+)*\Z") IDENTIFIER = re.compile(r"[a-f0-9]{12}\Z") @@ -118,6 +119,21 @@ def attribute(path, name): return "" +def network_interfaces(path): + """Kernel network interfaces provided by this USB device. On many mini PCs + a USB adapter is the management link: sharing it would cut the host off.""" + device = path.resolve() + names = [] + for interface in NET_SYSFS.glob("*"): + try: + source = (interface / "device").resolve(strict=True) + except OSError: + continue + if source == device or device in source.parents: + names.append(interface.name) + return sorted(names) + + def inventory(): devices = [] for path in sorted(SYSFS.glob("*")): @@ -137,6 +153,8 @@ def inventory(): blocked = "USB hubs cannot be shared" if "09" in classes else ( "USB mass storage cannot be shared" if "08" in classes else ( "USB class could not be read" if not re.fullmatch(r"[a-f0-9]{2}", attribute(path, "bDeviceClass").lower()) else "")) + if not blocked and network_interfaces(path): + blocked = "USB network adapters cannot be shared" try: driver = (path / "driver").resolve(strict=True).name except OSError: @@ -446,6 +464,9 @@ class LoopbackTunnel: tunnel.processes.discard(process) class Server(socketserver.ThreadingTCPServer): daemon_threads = True + # A restarted worker binds again while earlier connections are in + # TIME_WAIT. Linux still refuses a port another socket listens on. + allow_reuse_address = True self.closed = False try: self.server = Server(("127.0.0.1", selected["local_port"]), Handler) @@ -817,6 +838,7 @@ def add_import(remote, export_id, local_port): i["ssh_port"] == remote["ssh_port"] and i["export_id"] == export_id) for i in config["imports"]): raise USBIPError("This remote device or local port is already configured") with socket.socket() as check: + check.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: check.bind(("127.0.0.1", local_port)) except OSError as exc: diff --git a/scripts/devices/usbip_menu.sh b/scripts/devices/usbip_menu.sh index d7d386a2..41ef149e 100644 --- a/scripts/devices/usbip_menu.sh +++ b/scripts/devices/usbip_menu.sh @@ -101,11 +101,11 @@ usbip_add_export() { [[ -n "$busid" ]] && choices+=("$busid" "$label") done < <(python3 "$MANAGER" inventory | jq -r '.[] | select(.blocked == "" and .driver != "usbip-host") | [.busid, "\(.name) [\(.vendor):\(.product)] serial: \(.serial)"] | @tsv') if [[ ${#choices[@]} -eq 0 ]]; then - usbip_dialog --msgbox "$(translate 'No eligible USB devices found. Hubs and mass storage are excluded.')" 10 75 + usbip_dialog --msgbox "$(translate 'No eligible USB devices found. Hubs, mass storage and network adapters are excluded.')" 10 75 return fi chosen=$(usbip_dialog --stdout --menu "$(translate 'Select the USB device to share:')" 22 100 12 "${choices[@]}") || return - usbip_dialog --yesno "$(translate 'The selected USB device will become unavailable to local applications and guests. Only one remote client can use it at a time. Share this device?')\n\n$chosen" 12 80 || return + usbip_dialog --yesno "$(translate 'The selected USB device will become unavailable to local applications and guests. Only one remote client can use it at a time. Share this device?')\n\n$(translate 'If the USB/IP service stops unexpectedly, stop sharing while the device is still connected to release it. In rare cases only a host reboot releases it.')\n\n$chosen" 14 80 || return usbip_action add-export "$chosen" } diff --git a/scripts/menus/config_menu.sh b/scripts/menus/config_menu.sh index 786e0314..bde1536d 100644 --- a/scripts/menus/config_menu.sh +++ b/scripts/menus/config_menu.sh @@ -109,6 +109,16 @@ remove_usbip_sharing() { pmx_remove_file "$unit" done systemctl daemon-reload >/dev/null 2>&1 || true + # The transport account holds the authorized client keys. Remove it only + # when ProxMenux created it, so a reinstall does not revive old clients. + local home=/var/lib/proxmenux-usbip + if getent passwd proxmenux-usbip >/dev/null && [[ -f "$home/.proxmenux-owned" ]]; then + pkill -KILL -u proxmenux-usbip >/dev/null 2>&1 || true + pmx_record_execution "Remove USB/IP transport account" "userdel proxmenux-usbip" + userdel proxmenux-usbip >/dev/null 2>&1 || true + getent group proxmenux-usbip >/dev/null && groupdel proxmenux-usbip >/dev/null 2>&1 + rm -rf "$home" + fi if [[ -d /etc/proxmenux/usbip ]]; then pmx_record_execution "Remove USB/IP configuration" "rm -rf /etc/proxmenux/usbip" rm -rf /etc/proxmenux/usbip diff --git a/scripts/menus/hw_grafics_menu.sh b/scripts/menus/hw_grafics_menu.sh index 5678e89a..b2f85a58 100644 --- a/scripts/menus/hw_grafics_menu.sh +++ b/scripts/menus/hw_grafics_menu.sh @@ -1,6 +1,6 @@ #!/bin/bash # ========================================================== -# ProxMenux - GPU, TPU and USB/IP Menu +# ProxMenux - GPU and TPU Menu # ========================================================== # Author : MacRimi # Copyright : (c) 2024 MacRimi @@ -26,7 +26,7 @@ initialize_cache while true; do OPTION=$(dialog --colors --backtitle "ProxMenux" \ - --title "$(translate "GPUs, Coral-TPU and USB/IP Menu")" \ + --title "$(translate "GPUs and Coral-TPU Menu")" \ --menu "\n$(translate "Select an option:")" 26 80 16 \ "" "\Zb\Z4 HOST\Zn" \ "1" "$(translate "Install/Update NVIDIA Drivers (Host + LXC)")" \ diff --git a/scripts/menus/main_menu.sh b/scripts/menus/main_menu.sh index 2c8f19bd..69e81bd3 100644 --- a/scripts/menus/main_menu.sh +++ b/scripts/menus/main_menu.sh @@ -68,7 +68,7 @@ show_menu() { search "$(translate "Search options and applications")" \ "" "" \ 1 "$(translate "Settings post-install Proxmox")" \ - 2 "$(translate "Hardware: GPUs, Coral-TPU and USB/IP")" \ + 2 "$(translate "Hardware: GPUs and Coral-TPU")" \ 3 "$(translate "Create VM from template or script")" \ 4 "$(translate "Disk Manager")" \ 5 "$(translate "Storage & Share Manager")" \ diff --git a/scripts/menus/search_index.json b/scripts/menus/search_index.json index 8f336fd0..4f0571ad 100644 --- a/scripts/menus/search_index.json +++ b/scripts/menus/search_index.json @@ -1,7 +1,7 @@ [ { "title": "USB/IP over SSH", - "menu": "Hardware: GPUs, Coral-TPU and USB/IP", + "menu": "Hardware: GPUs and Coral-TPU", "script": "devices/usbip_menu.sh", "keywords": "usbip usb ip ssh remote zigbee bluetooth printer impresora remoto" }, @@ -12,8 +12,8 @@ "keywords": "" }, { - "title": "Hardware: GPUs, Coral-TPU and USB/IP", - "menu": "Hardware: GPUs, Coral-TPU and USB/IP", + "title": "Hardware: GPUs and Coral-TPU", + "menu": "Hardware: GPUs and Coral-TPU", "script": "menus/hw_grafics_menu.sh", "keywords": "" }, @@ -104,43 +104,43 @@ }, { "title": "Install/Update NVIDIA Drivers (Host + LXC)", - "menu": "Hardware: GPUs, Coral-TPU and USB/IP", + "menu": "Hardware: GPUs and Coral-TPU", "script": "gpu_tpu/nvidia_installer.sh", "keywords": "gpu nvidia driver" }, { "title": "Install/Update Coral TPU on Host", - "menu": "Hardware: GPUs, Coral-TPU and USB/IP", + "menu": "Hardware: GPUs and Coral-TPU", "script": "gpu_tpu/install_coral.sh", "keywords": "coral tpu usb" }, { "title": "Add GPU to LXC (Intel | AMD | NVIDIA)", - "menu": "Hardware: GPUs, Coral-TPU and USB/IP", + "menu": "Hardware: GPUs and Coral-TPU", "script": "gpu_tpu/add_gpu_lxc.sh", "keywords": "gpu passthrough lxc igpu" }, { "title": "Add Coral TPU to LXC", - "menu": "Hardware: GPUs, Coral-TPU and USB/IP", + "menu": "Hardware: GPUs and Coral-TPU", "script": "gpu_tpu/install_coral_lxc.sh", "keywords": "coral tpu lxc usb" }, { "title": "Add GPU to VM (Intel | AMD | NVIDIA)", - "menu": "Hardware: GPUs, Coral-TPU and USB/IP", + "menu": "Hardware: GPUs and Coral-TPU", "script": "gpu_tpu/add_gpu_vm.sh", "keywords": "gpu passthrough vm" }, { "title": "Switch GPU Mode (VM <-> LXC)", - "menu": "Hardware: GPUs, Coral-TPU and USB/IP", + "menu": "Hardware: GPUs and Coral-TPU", "script": "gpu_tpu/switch_gpu_mode.sh", "keywords": "gpu mode modo" }, { "title": "Manual CLI Guide (GPU/TPU)", - "menu": "Hardware: GPUs, Coral-TPU and USB/IP", + "menu": "Hardware: GPUs and Coral-TPU", "script": "gpu_tpu/gpu-tpu-manual-guide.sh", "keywords": "gpu tpu guide guia" },