You are not logged in.

#1 2020-10-22 04:46:37

MountainX
Member
Registered: 2016-02-08
Posts: 371

systemd: run a script upon any network interface status change

I need to run a small script each and every time the network connection is changed. For example, if switching to or from wifi, or to/from wired ethernet, or if a VPN tunnel is started/stopped. I have seen it mentioned that a unit file like this will trigger the script to run according to my stated conditions:

# /etc/systemd/system/network-connection-changed.service
[Unit]
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/path/to/script

[Install]
WantedBy=sys-subsystem-net-devices-%i.device

The important part is the "WantedBy=sys-subsystem-net-devices-%i.device". The blog mentioned that this triggers the script upon any network interface status change. I have not managed to confirm that in the systemd docs.

Elsewhere I read that this would be the way to implement the unit file:

# /etc/systemd/system/network-connection-changed.service
[Unit]
Requires=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device

[Service]
Type=oneshot
ExecStart=/path/to/script

[Install]
WantedBy=multi-user.target

I have also seen BindTo used like this:

BindsTo=sys-subsystem-net-devices-%i.device

Finally, I have seen NetworkManager dispatcher mentioned. I prefer to stay with systemd units. And I would prefer to do this in the standard way that most people are doing it. It would seem to be a common need, but I am not finding anything that looks like a universally adopted solution.

I could potentially use this for a lot of things, but the script I want to run now just does this:

#!/bin/bash
gw=$(ip r | awk 'match($0,/default via ([^ ]+)/,a){print a[1]}')
if [ -f /tmp/mytoken ]; then
	rm /tmp/mytoken
fi
if [ "$gw" == "123.456.78.90" ]; then 
	touch /tmp/mytoken
fi

That token should be added or removed according to the default gateway I'm connected to.

What is the best way to do this?

Offline

#2 2020-10-22 16:02:30

qinohe
Member
From: Netherlands
Registered: 2012-06-20
Posts: 1,494

Re: systemd: run a script upon any network interface status change

I guess that IP is a typo wink  & 'The blog mentioned that' ... what blog..?

Did not dive into what exactly it is you try to accomplish;), however, your service will enter a stopped/started state and exit 'Type=oneshot' , you need to at least remain this service after successful run else it will never run again.
https://www.freedesktop.org/software/sy … ml#Options

Your script, the token is there or it isn't

#!/bin/sh

gw=$(ip r | awk /via/'{print $3}')

[ "$gw" = "10.30.40.1" ] && touch /tmp/mytoken || rm /tmp/mytoken

or if multiple routes are a possibility...

#!/bin/sh

gw=$(ip r | awk /via/'{print $3}')

if [ "$gw" = "10.20.30.1" ] || [ "gw" = "10.30.40.1" ] then
  touch /tmp/token
else
  rm /tmp/token
fi

Offline

#3 2020-10-22 22:46:54

MountainX
Member
Registered: 2016-02-08
Posts: 371

Re: systemd: run a script upon any network interface status change

qinohe wrote:

'The blog mentioned that' ... what blog..?

I should have said "various blogs and other sites". I looked a dozens of different places trying to understand this solution. Here's one:
http://billauer.co.il/blog/2019/11/syst … p-usb-nic/

That one says:

A on-shot service depends on the relevant device. When it’s up, what’s on ExecStart is run. End of story.

That actually sounds like it could work. Each time a new interface comes up, it should run the script. Am I correct that this will work?

BTW, my script is working OK already. Your bash code looks better, but my question is about the systemd unit only.

Is this the right way to respond to any interface?

sys-subsystem-net-devices-%i.device

Should it be placed in the [Unit] or [Install] section?

This post shows another way of doing it that differs from the one linked above. (I gave both examples in my OP.)

Last edited by MountainX (2020-10-22 23:22:08)

Offline

#4 2020-10-23 00:36:43

qinohe
Member
From: Netherlands
Registered: 2012-06-20
Posts: 1,494

Re: systemd: run a script upon any network interface status change

MountainX wrote:

That one says:

A on-shot service depends on the relevant device. When it’s up, what’s on ExecStart is run. End of story.

That actually sounds like it could work. Each time a new interface comes up, it should run the script. Am I correct that this will work?

Quote from https://www.freedesktop.org/software/sy … ml#Options

Note that if this option is used without RemainAfterExit= the service will never enter "active" unit state, but directly transition from "activating" to "deactivating" or "dead" since no process is configured that shall run continuously. In particular this means that after a service of this type ran (and which has RemainAfterExit= not set) it will not show up as started afterwards, but as dead.

BTW, my script is working OK already. Your bash code looks better, but my question is about the systemd unit only.

Yeah, right, thought you wanted input on that too...;)

Is this the right way to respond to any interface?

sys-subsystem-net-devices-%i.device

Should it be placed in the [Unit] or [Install] section?

Yes, far as I know that's correct and should be in the Unit.
Could you try:

[Unit]
BindTo=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device
#Requisite=sys-subsystem-net-devices-%i.device  #or try this

[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/path/to/script

[Install]
WantedBy=sys-subsystem-net-devices-%i.device

Btw. I never tried this wink

Offline

#5 2020-10-23 02:52:27

MountainX
Member
Registered: 2016-02-08
Posts: 371

Re: systemd: run a script upon any network interface status change

qinohe wrote:

Could you try:

[Unit]
BindTo=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device
#Requisite=sys-subsystem-net-devices-%i.device  #or try this

[Install]
WantedBy=sys-subsystem-net-devices-%i.device

Btw. I never tried this wink

Thank you. But I worry about putting the "sys-subsystem-net-devices-%i.device" specification simultaneously in all those places. I am hoping to know the "correct" way to do this.

Offline

Board footer

Powered by FluxBB