Règle UDEV pour redémarrter un service via systemd

Tags: #<Tag:0x00007f50a0181508> #<Tag:0x00007f50a0181378> #<Tag:0x00007f50a0181288>

J’ai créé la règle udev suivante:

ACTION!="add", GOTO="yubico_end"

SUBSYSTEM=="usb", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0407", RUN+="/usr/bin/systemctl restart usbip.service"

LABEL="yubico_end"

Le service lancé est le suivant:

[Unit]
Description=Exports USB device over IP
Requires=network-online.target
After=network-online.target

[Service]
Type=simple
Restart=on-failure
User=root
Group=root
ExecStart=/usr/sbin/usbipd -4 -d
ExecStartPost=/usr/sbin/usbip bind --busid=1-2
ExecStop=/usr/sbin/usbip unbind --busid=1-2

[Install]
WantedBy=multi-user.target

Quand je branche my clef Yubikey, la règle udev se déclenche bien, et systemd redémarre bien le service usbip.service.
malheureusement, le redémarrage se produit plusieurs fois et finit donc en erreur.

Comment faire pour que le redémarrage n’ai lieu qu’une seule fois?

Si tu branches la yubikey pendant que udevadm monitor tourne, tu verras qu’il y a beaucoup d’actions ADD parce que plusieurs périphériques différents sont créés.

Questions bêtes :

  • Pourquoi redémarrer le service ? Un simple usbip bind ne suffit pas ?
  • Quid si la yubikey a un busid différent de 1-2 (branchée sur un autre port) ?

Oui c’est ce que j’ai remarqué. Mais je n’arrive pas à faire en sorte qu’il ne prenne en compte qu’un seul de ces évènements.

Apparement il y a un soucis avec le service systemd ou avec usbipd/usbip. Le service est up mais la clé n’est pas attachée correctement. Avec le redémarrage du service la clé est alors attachée.

C’est l’étape suivante :smiley:
Actuellement je fais des tests avec une machine virtuelle sous VirtualBox. Donc c’est toujours le même busid.

Il faut que la règle udev soit plus restrictive. Je commencerais par remplacer ATTRS par ATTR pour qu’elle ne se déclenche pas sur les périphériques enfants. Et si ça ne suffit pas, il va falloir ajouter des critères.

Par ailleurs il est recommandé que les actions déclenchées par une règle udev se terminent rapidement, il faudrait donc peut-être exécuter systemctl avec l’option --no-block.

Il faudrait déterminer si ça vient de usbipd ou de systemd, par exemple en lançant usbipd hors de systemd. Par défaut systemd peut appliquer des restrictions aux processus qu’il lance.
C’est un peu triste si usbipd ne gère correctement que les périphériques USB présents lors son lancement et pas les nouveaux.

Usbip en fait.
D’où systemd.
USBIPD ne prend en compte les nouveaux périphérique que si un usbip bind est executé.
Mais usbip n’est pas un daemon. Du coup il ne se passe rien.

USBIP est assez vieux malheureusement et ne dispose pas de configuration lui permettant de gérer cette partie automatique (ceci dit c’est aussi bien car cela éviterait d’avoir une clef non autorisée qui soit partagée.

J’ai testé avec ça, et ça marche, ATTRS → ATTR et ajoute de no-block en option, et ça marche nickel merci :slight_smile:
C’est la première fois que j’essaye de faire une règle UDEV pour démarrer un service :slight_smile:

Qu’entends-tu exactement par « prend en compte » ? Exporte ? Il faut bien sûr exécuter usbip bind pour exporter un périphérique, nouveau ou pas.

Naïvement, je suppose qu’il devrait suffire de lancer usbipd une fois pour toutes, puis exécuter usbip bind pour chaque périphérique à exporter. Et c’est seulement usbip bind que j’exécuterais dans la règle udev avec en argument %k qui devrait contenir le busid (et éventuellement une autre règle pour exécuter usbip unbind sur ACTION=remove). Est-ce que tu as essayé ?

oui exporte pardon.

Normalement c’est justement le service systemd qui fait ça.
mais j’en déduis de ce que tu me dit, que le service ne le fait qu’une fois et ensuite il ne le fait plus. Et c’est pour ça qu’il faut que je le relance.
Je vais tester en ne refaisant que le bind.

Le service systemd que tu as créé ne se déclenche pas de lui-même lorsqu’un périphérique USB est branché ou débranché. Il exécute les actions spécifiées lors de son lancement ou son arrêt et c’est tout. D’autre part il exécute les commandes bind ou unbind même si la yubikey n’est pas branchée, ce qui n’est pas génial.

À mon avis le service devrait seulement lancer ou arrêter usbipd, et la règle udev devrait seulement exécuter les actions bind et unbind. Le point délicat est d’exécuter l’action bind si la clé est déjà branchée lorsque le service est démarré. Cela doit pouvoir se faire avec quelque chose comme

udevadm trigger --action=add --subsystem-match=usb

Ca n’a pas vraiment marché. La relance du service fonctionne bien, mais en ne mettant que le bind et l’unbind ça n’a pas bien marché.
je vais rester sur le redémarrage du service car celui-ci marche bien.
J’ai pu ajouter les attributs idVendor, idProduct et serial, pour bien identifier ma clef Yubico car j’en ai deux et seule une doit être prise en compte, une autre clef ne donnera rien.

Petite astuce, pour connaître les paramètres UDEV d’un device:

udevadm info --attribute-walk --path=$(udevadm info --query=path --name=/dev/video2)

Peux-tu montrer la configuration (fichier service et règles udev) qui n’a pas marché ?

ACTION!="bind", GOTO="yubico_end"

SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", \
ATTR{idVendor}=="1050", ATTR{idProduct}=="0407", ATTR{serial}=="0018137557", RUN+="/usr/sbin/usbip bind --busid=1-2"

LABEL="yubico_end"

sauf qu’à partir de là, le service ne redémarre plus correctement. A chaque fois j’ai le problème de Start request repeated too quickly.

Je ne vais pas y passer plus de temps. Le redémarrage du service fonctionne désormais. Considérant que cette clef ne vas pas être connectée et déconnectée toutes les 5 mn bien au contraire, ça va rester comme ça.

Car j’ai encore la partie tunnel à faire, car l’accès n’est pas sécurisé sur usbipd, donc je veux sécuriser avec un tunnel machine à machine, qui permet au client de se conecter sur un port local (i.e.: 127.0.0.1:port) qui accède ainsi au port local sur serveur usbipd en local (i.e.: 127.0.0.1:). Ce que je ne sais plus faire :slight_smile:
EDIT: finalement j’ai retrouvé c’est assez simple:

ssh -N -L SPORT:IPLOCAL:DPORT user@server

ou

ssh -N -L SPORT:IPLOCAL:DPORT -i KEYFILE user@server

Mais pourquoi redémarrer le service ? Et comment, si la règle udev a pour seule action usbip bind ?

J’ai un peu testé manuellement, en démarrant usbipd sans service systemd et en exécutant usbip sans règle udev et je parviens bien à exporter une souris USB sans devoir redémarrer usbipd, que la souris ait été branchée avant ou après le démarrage de usbipd. Donc on doit pouvoir y arriver aussi avec systemd et udev.

PS pour ma mémoire : modules noyau nécessaires : usbip-host côté serveur, usbip-vudc et/ou vhci-hcd côté client.

Je suis tout à fait d’accord avec toi @PascalHambourg , pas de soucis en manuel.
Mais avec systemd ça ne prend pas correctement. Je n’ai pas trouvé pourquoi. Pour le moment il faut que j’avance sur mon projet, j’y reviendrais peut être plus tard.