systemd Firewall .service Unit: Type=exec or Type=oneshot?

I’m debugging a firewall .service unit and a few questions arise.

One of those questions is the unit’s best service type, either exec or oneshot. Virtually no comparisons of the two appear in my searches, probably because exec is a relatively recent addition to systemd (v.249 IIRC).

By way of background, the unit (call it iptables.service) is intended to activate and configure the firewall by running a Bash script (call it iptables.sh) before the network is up (i.e., before network-pre.target), e.g.,

ExecStart=/bin/bash -c '/home/locsh/iptables.sh'

Type=oneshot has the advantage of not entering the "active" state, so it subsequently can be restarted or reactivated, e.g., by a timer unit. It also is the more common of the two types in most examples, albeit without explanation.

Type=exec has the advantage that it will delay startup of follow-up units until the main service has been executed. This seems to make perfect sense for a firewall .service unit because the network should depend on the script running successfully and remain down otherwise, e.g., if the script temporarily can’t be read because somehow the relevant .mount unit hasn’t yet activated.

Restart=on-failure seems to be an obvious and prudent addition in either case.

The first question is whether one or the other might better for any reason.

The second question is whether Type=exec, because it delays the start of follow-up units, might introduce a subtle ordering cycle in some edge cases, either with or without "Restart=on-failure", in part because the unit’s ordering dependency

Before=network-pre.target

is relatively early in the boot process.

Asked By: ebsf

||

You want type=oneshot. If you use type=exec, other services will be able to start before the firewall is configured. From the systemd.service man page, for exec:

…Or in other words: simple proceeds with further jobs right after fork() returns, while exec will not proceed before both fork() and execve() in the service process succeeded.

And for oneshot:

Behavior of oneshot is similar to simple; however, the service manager will consider the unit up after the main process exits.

In other words, with Type=exec, systemd considers the service to
be "up" once the process has successfully started, while
for Type=oneshot, systemd considers the service to be "up" once
the process has successfully completed.

Answered By: larsks