how does systemd load units?

I did not even notice the existence of systemd in the past. On CentOS 6, I used commands such as “service iptables restart/start/stop” to start/stop/restart a service. I used commands such as “chkconfig iptables on” to auto-start a service at boot time. Why should I learn the notorious systemd? Now comes CentOS7 which does not install the iptables service by default to force me to switch to firewalld. No way! I install the service back using “install iptables-services” and continue to use “service iptables restart/start/stop”. Unfortunately, it seems I cannot use “chkconfig iptables on” to auto-start the iptables service at startup time. After running “chkconfig iptables on”, the output of “chkconfig” does not include the iptables service.  In fact, if you look carefully at the output of “chkconfig iptables on”, it says “Note: Forwarding request to ‘systemctl enable iptables.service’.”. Ok, iptables is now configured to run at boot time by systemd. I still do not need to care about how systemd did it. The problem arises when my machine is rebooted, and iptables is not started automatically as expected. It seems systemd did something bad and I have to figure it out.

I read a lot of articles about systemd and confused by the complex concepts such as target,unit,service,etc., and lots of directories such as /etc/systemd/system/, /usr/lib/systemd/system/, and the symbolic links in them.  They tell me “systemctl enable iptables” is actually creating a symbolic   link in /etc/systemd/system/multi-user.target.wants/ to point to the real unit file /usr/lib/systemd/system/iptables.service. But I did not find that symbolic link in /etc/systemd/system/multi-user.target.wants/. How does systemd load units?

The systemd process is the first process created at boot up time, after loading the kernel. Then, systemd looks at /etc/systemd/system/default.target which is a symbolic link to a target unit /lib/systemd/system/multi-user.target. The unit configuration file says it requires basic.target.

So systemd will load the basic target before loading multi-user.target. The basic target itself is dependent on many other units. Systemd loads required and wanted units before loading the unit in question. The required units are listed in the “Requires=” statement in the unit configuration file and the wanted units are listed in the “Wants=” statement. But I cannot find the iptables unit is listed in either the  “Requires=” statement or the the “Wants=” statement of multi-user.target and other units multi-user.target depends on. Does that mean iptables is not enabled? In fact, apart from the “Wants=” statement, the wanted units for a unit are also gotten from the directory named after unitname.wants directory under /etc/systemd/system/. The content of the unit iptables.service contains:

This means iptables.service, when enabled, is wanted by basic.target. When running “systemctl enable iptables”, it will create a directory(if not already existed) basic.target.wants under /etc/systemd/system/, and create a symbolic link in there pointing to the real iptables.service unit:iptables.service -> /usr/lib/systemd/system/iptables.service. When loading basic.target, its wanted units including iptables.service will be loaded first, so iptables is actually enabled. You can get the status of a unit using “systemctl status iptables”. The output would be:

The enabled indicates the unit is actually enabled, while the “vendor preset: disabled” means after you install the iptables’package, it is not enabled by default, and you should manually enable it if you want to do. An enabled unit may not be in active status, which is shown at the last line.

You can list the dependent units of a unit by “systemctl list-dependencies basic.target”.  You can see basic.target depends on iptables.service. Since multi-user.target depends on basic.target, multi-user.target also depends on iptables.service. In order to bring the machine to default target: multi-user.target, iptables.service will be run.

But why iptables is not run automatically on boot? This is because firewalld is enabled by default. The content of firewalld.service contains:

So there is a symbolic link in /etc/systemd/system/multi-user.target.wants/firewalld.service pointing to the real firewalld.service. The important thing is that firewalld.service also contains the following content:

which means firewalld conflicts with iptables. The dependency order is now:multi-user.target->firewalld.service,basic.target->iptables.service. To reach the multi-user run level, iptables must be shutdown.

The cue is now obvious: disable the firewalld to enable iptables: “systemctl disable firewalld”.

 

Posted in tips of hosting