Thursday, 2 July 2026

Chapter 3: SONiC Startup Process

Figure 3-1 illustrates a simplified SONiC container startup sequence. First, systemd reads the service unit files and evaluates their dependency and ordering directives. It then starts docker.service, making the Docker daemon available. After that, SONiC service containers are started according to the dependencies and ordering rules defined in their service unit files.

In this simplified example, database.service starts early because many SONiC services rely on the Redis databases to exchange configuration, state, and event information. Services such as pmon, syncd, and swss are then started according to their own dependencies and ordering rules. Higher-level SONiC service containers, such as bgp, lldp, teamd, and snmp, are started after the lower-level services they depend on are available.

It is also important to distinguish between host-level service management and process management inside containers. systemd is responsible for starting the host-level service units that create and manage SONiC service containers. After a container has started, the processes inside the container are launched and supervised by the container's own initialization logic, which in many SONiC containers is based on supervisord. For example, after the bgp container has started, processes such as bgpd, zebra, and fpmsyncd are started inside the container. Similarly, the swss container starts and supervises its own processes after the container has been created.

Figure 3-1: High-Level Overview of the SONiC Container Startup Process.
The following examples show how this startup model is expressed in actual systemd service unit files. Examples 3-1, 3-2, and 3-3 focus on docker.service, database.service, and pmon.service because they illustrate the relationship between the Docker Engine, the SONiC database container, and a platform management container.

Docker – Container Engine Foundation

Example 3-1 shows a simplified docker.service unit file. This service starts the Docker daemon (dockerd), which provides the Docker Engine used to create and manage SONiC service containers. SONiC service containers cannot be created or started until the Docker daemon is available. For that reason, many SONiC service unit files declare an explicit dependency on docker.service.
In the [Unit] section, Requires= creates a strong dependency on containerd.service. When docker.service is started, systemd also pulls in containerd.service. The After= directive defines startup ordering by specifying that docker.service is started after network-online.target, firewalld.service, and containerd.service. The Wants= directive expresses a weaker dependency on network-online.target. systemd attempts to start the target, but a failure of that target does not have the same effect as a failed required dependency.
The [Service] section defines the service lifecycle. In this example, ExecStart= starts dockerd, Type=notify tells systemd that the daemon will notify systemd when it is ready, and Restart=always together with RestartSec=2 instructs systemd to restart the Docker daemon after a short delay if it exits unexpectedly.

[Unit]
Description=Docker Application Container Engine
After=network-online.target firewalld.service containerd.service
Wants=network-online.target
Requires=containerd.service

[Service]
Type=notify
ExecStart=/usr/bin/dockerd
Restart=always
RestartSec=2

[Install]
WantedBy=multi-user.target

Example 3-1: Unit File Example – Docker Engine Service.

Database – Redis Database Container

Example 3-2 shows the database.service unit that starts the SONiC database container. The [Unit] section declares Requires=docker.service and After=docker.service, which means that Docker is both required and ordered to start before the database service. The Before= directive orders database.service before services such as swss.service, syncd.service, bgp.service, and lldp.service. This is consistent with the SONiC architecture because many SONiC services rely on the Redis databases to exchange configuration, state, and event information.
In the [Service] section, Type=oneshot tells systemd that the service performs a finite task rather than running continuously. RemainAfterExit=yes keeps the service in the active state after the start command has completed, allowing other services to recognize that the database container has already been initialized.

[Unit]
Description=SONiC database container
Requires=docker.service
After=docker.service
Before=swss.service syncd.service bgp.service lldp.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/docker-sonic-db start
ExecStop=/usr/local/bin/docker-sonic-db stop
TimeoutStartSec=300

[Install]
WantedBy=multi-user.target
Example 3-2: Unit File Example – SONiC Database Container Service.

PMON – Platform Monitor Container

Example 3-3 shows the pmon.service unit. The [Unit] section declares Requires=docker.service database.service together with After=docker.service database.service, ensuring that Docker and the database service are both available before pmon.service is started. The Before= directive orders pmon.service before selected services, including swss.service and bgp.service.

This ordering is consistent with the role of the pmon container, which provides platform management functions such as monitoring hardware sensors, fans, power supplies, LEDs, and transceivers. It also publishes platform state that can be used by other SONiC services.

[Unit]
Description=SONiC pmon container
Requires=docker.service database.service
After=docker.service database.service
Before=swss.service bgp.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/docker-pmon start
ExecStop=/usr/local/bin/docker-pmon stop
ExecReload=/usr/local/bin/docker-pmonreload
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
Example 3-3: Unit File Example – SONiC pmon Container Service.



Verifications


This section shows how to verify the SONiC boot process from the Linux command line. The following services are verified using the same three-step approach. The following services are verified using the same three-step approach. First, systemctl status verifies the host-level service state. Second, systemctl cat shows the dependency and ordering relationships defined in the service unit. Finally, docker exec is used to run supervisorctl status inside the container to verify that the expected processes are running. Together, these commands provide a practical way to connect the boot sequence described earlier in this chapter to the actual runtime state of a SONiC switch.

Docker – Container Engine


The first component to verify is the Docker service, because Docker provides the container engine used by the SONiC service units. If docker.service is not active, SONiC service containers cannot be created or started. In the status output, the most useful fields are Loaded, Active, Drop-In, and Main PID.

admin@sonic:~$ systemctl status docker.service
● docker.service - Docker Application Container Engine
     Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset>
    Drop-In: /etc/systemd/system/docker.service.d
             └─docker.service.conf
     Active: active (running) since Wed 2026-07-01 07:59:53 UTC; 17min ago
TriggeredBy: ● docker.socket
       Docs: https://docs.docker.com
   Main PID: 711 (dockerd)
      Tasks: 40
     Memory: 158.8M
     CGroup: /system.slice/docker.service
             └─711 /usr/bin/dockerd --experimental -H unix:// --storage-driver=>
admin@sonic:~$

Example 3-4: Docker - systemctl status docker.service.

The output shows that docker.service is loaded and active. The main process is dockerd, which confirms that the Docker daemon is running on the host. The drop-in file also shows that the effective Docker configuration may include SONiC- or platform-specific overrides in addition to the default unit file.
After confirming that Docker is running, the effective unit file can be inspected with systemctl cat. This is useful because it shows both the original unit file and any drop-in configuration files that modify the service behavior. When reading this output, focus on dependency directives such as Requires=, ordering directives such as After=, and the final ExecStart= command used to launch the Docker daemon.

admin@sonic:~$ systemctl cat docker.service
# /lib/systemd/system/docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service containerd.service containerd.ser>
Wants=network-online.target
Requires=docker.socket containerd.service

[Service]
Type=notify
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
OOMScoreAdjust=-500

[Install]
WantedBy=multi-user.target

# /etc/systemd/system/docker.service.d/docker.service.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd --experimental -H unix:// --storage-driver=overlay2 >

Example 3-5: Docker - systemctl cat docker.service.

In this example, the drop-in configuration clears the original ExecStart line and replaces it with a SONiC-specific Docker daemon command. This is an important detail because troubleshooting should be based on the effective unit file, not only on the default file installed by the operating system package
.

Database – Redis Database Container


The database container is one of the most important services to verify during boot because many SONiC components exchange configuration, state, counters, and events through Redis databases. A problem in database.service can prevent higher-level services from starting correctly or from exchanging state after they have started.

admin@sonic:~$ systemctl status database.service
● database.service - Database container
     Loaded: loaded (/lib/systemd/system/database.service; enabled; vendor pres>
     Active: active (running) since Wed 2026-07-01 08:00:02 UTC; 28min ago
    Process: 1075 ExecStartPre=/usr/bin/database.sh start (code=exited, status=>
   Main PID: 1973 (database.sh)
      Tasks: 2 (limit: 4289)
     Memory: 3.1M
     CGroup: /sonic.slice/sonic-core.slice/database.service
             ├─1973 /bin/bash /usr/bin/database.sh wait
             └─2010 tail --pid=1144 -f /dev/null

Example 3-6: Database - systemctl status database.service.

The status output shows that database.service is active. The service is represented on the host by the database.sh helper script, while the actual Redis processes run inside the database container. This is a typical SONiC pattern: systemd manages the container service at the host level, and the processes inside the container are managed separately.

admin@sonic:~$ systemctl cat database.service
# /lib/systemd/system/database.service
[Unit]
Description=Database container

Wants=database-chassis.service
After=database-chassis.service
Requires=docker.service
After=docker.service
After=rc-local.service
StartLimitIntervalSec=1200
StartLimitBurst=3

[Service]
User=root
ExecStartPre=/usr/bin/database.sh start
ExecStart=/usr/bin/database.sh wait
ExecStop=/usr/bin/database.sh stop
Restart=always
RestartSec=30
Slice=sonic-core.slice

[Install]
WantedBy=multi-user.target

Example 3-7: Database - systemctl cat database.service.

The unit file confirms that database.service requires docker.service and is ordered after it. The ExecStartPre command starts the database container, and the ExecStart command waits for the container process to remain available. This explains why database.service can appear as an active host-level service even though the important Redis processes are running inside the container.
To verify the internal state of the database container, use supervisorctl status inside the container. This command shows the processes that supervisord manages inside the container. In this example, several Redis processes are running, which is normal on SONiC systems that use a multi-Redis model.

admin@sonic:~$ docker exec -it database supervisorctl status
flushdb                          EXITED    Jul 01 08:00 AM
redis                            RUNNING   pid 71, uptime 0:42:32
redis2                           RUNNING   pid 72, uptime 0:42:32
redis3                           RUNNING   pid 75, uptime 0:42:32
redis4                           RUNNING   pid 77, uptime 0:42:32
redis6                           RUNNING   pid 80, uptime 0:42:32
rediswb                          RUNNING   pid 82, uptime 0:42:32
restart-rsyslogd                 EXITED    Jul 01 08:01 AM
rsyslogd                         RUNNING   pid 247, uptime 0:41:03
supervisor-proc-exit-listener    RUNNING   pid 69, uptime 0:42:32

Example 3-8: Database - docker exec -it database supervisorctl status.

Several Redis processes are shown because this SONiC image uses multiple Redis instances inside the database container. Instead of placing all logical databases behind a single Redis process, SONiC can split database workloads across separate Redis servers. A typical deployment may keep slower management-oriented databases, such as CONFIG_DB and STATE_DB, in the main redis instance, place hardware-programming data such as ASIC_DB in a separate instance such as redis2, move high-frequency telemetry data such as COUNTERS_DB to another instance such as redis3, and use a dedicated write-back instance such as rediswb for write-back-related databases. Other instances, such as redis4 or redis6, may be used for additional database groups depending on the SONiC image, platform, and enabled feature set. The exact database-to-instance mapping should therefore be verified from the database configuration files on the running system rather than assumed from the process names alone.

The output shows that the Redis instances are running and that one-shot initialization tasks such as flushdb and restart-rsyslogd have exited. An EXITED state is not automatically an error; it can be expected for processes that are designed to run once during startup and then terminate. The important point is to distinguish long-running daemons, such as Redis, from short-lived initialization tasks.

Note: When reading supervisord output, RUNNING usually means that the daemon is active, EXITED can be normal for one-shot initialization tasks, and STOPPED can be normal for optional processes that are not started in the current environment. A FATAL state usually requires further investigation, especially if the process is expected to run on the platform or in the selected feature configuration.

SWSS – Switch State Service


The SWSS container is central to the SONiC control-plane pipeline. It contains orchestration and synchronization processes that consume application state from Redis databases and translate it toward the hardware-oriented state used by syncd. For that reason, swss.service is one of the key services to verify after the database container has started.

admin@sonic:~$ systemctl status swss.service
● swss.service - switch state service
     Loaded: loaded (/lib/systemd/system/swss.service; enabled; vendor preset: >
     Active: active (running) since Wed 2026-07-01 11:38:29 UTC; 2min 38s ago
    Process: 1910 ExecStartPre=/usr/local/bin/swss.sh start (code=exited, statu>
   Main PID: 2894 (swss.sh)
      Tasks: 5 (limit: 4289)
     Memory: 28.3M
     CGroup: /sonic.slice/sonic-core.slice/swss.service
             ├─2894 /bin/bash /usr/local/bin/swss.sh wait
             └─8228 python3 /usr/bin/docker-wait-any -s swss -d syncd teamd -t >

Example 3-9: SWSS - systemctl status swss.service.

The status output confirms that swss.service is active from the host systemd viewpoint. The service is represented by the swss.sh helper script, which waits for the container process. This confirms that the host-level service is running, but it does not by itself prove that all orchestration processes inside the container are healthy.

admin@sonic:~$ systemctl cat swss.service
# /lib/systemd/system/swss.service
[Unit]
Description=switch state service
Requires=database.service
After=database.service


Requires=updategraph.service
After=updategraph.service
#After=interfaces-config.service
BindsTo=sonic.target
After=sonic.target
Before=ntp-config.service
StartLimitIntervalSec=1200
StartLimitBurst=20

[Service]
User=root
Environment=sonic_asic_platform=vs
ExecStartPre=/usr/local/bin/swss.sh start
ExecStart=/usr/local/bin/swss.sh wait
ExecStop=/usr/local/bin/swss.sh stop
Restart=always
RestartSec=30
Slice=sonic-core.slice

[Install]
WantedBy=sonic.target
admin@sonic:~$

Example 3-10: SWSS - systemctl cat swss.service.

The unit file shows that swss.service requires database.service and is ordered after it. This reflects the fact that SWSS consumes database state during startup and runtime. The service is also bound to sonic.target, which means it participates in the normal SONiC startup target rather than being an isolated host service.

admin@sonic:~$ docker exec -it swss supervisorctl status
aclsvcd                          RUNNING   pid 340, uptime 0:02:45
arsmgrd                          RUNNING   pid 325, uptime 0:02:46
buffermgrd                       RUNNING   pid 319, uptime 0:02:47
coppmgrd                         RUNNING   pid 310, uptime 0:02:48
delay-restore                    EXITED    Jul 01 11:38 AM
dependent-startup                EXITED    Jul 01 11:39 AM
enable_counters                  EXITED    Jul 01 11:39 AM
evpnmhmgrd                       RUNNING   pid 332, uptime 0:02:46
fdbsyncd                         RUNNING   pid 336, uptime 0:02:45
gearsyncd                        EXITED    Jul 01 11:38 AM
intfmgrd                         RUNNING   pid 314, uptime 0:02:47
iphelpermgrd                     RUNNING   pid 363, uptime 0:02:44
loopbackmgrd                     RUNNING   pid 316, uptime 0:02:47
nbrmgrd                          RUNNING   pid 328, uptime 0:02:46
neighsyncd                       RUNNING   pid 311, uptime 0:02:48
orchagent                        RUNNING   pid 253, uptime 0:02:57
portmgrd                         RUNNING   pid 315, uptime 0:02:47
portsyncd                        RUNNING   pid 168, uptime 0:02:59
ptp_1_d                          FATAL     Exited too quickly 
restart-rsyslogd                 EXITED    Jul 01 11:39 AM
restore_neighbors                EXITED    Jul 01 11:39 AM
rsyslogd                         RUNNING   pid 712, uptime 0:01:44
supervisor-proc-exit-listener    RUNNING   pid 20, uptime 0:03:05
switchmgrd                       RUNNING   pid 318, uptime 0:02:47
swssconfig                       EXITED    Jul 01 11:38 AM
swsswait                         EXITED    Jul 01 11:39 AM
tunnelmgrd                       RUNNING   pid 338, uptime 0:02:45
vlanmgrd                         RUNNING   pid 312, uptime 0:02:48
vrfmgrd                          RUNNING   pid 320, uptime 0:02:47
vxlanmgrd                        RUNNING   pid 333, uptime 0:02:46
admin@sonic:~$

Example 3-11: SWSS - docker exec -it swss supervisorctl status.

In the SWSS supervisor output, processes such as orchagent, portsyncd, neighsyncd, intfmgrd, and several manager daemons are running. These processes represent the internal work performed by the SWSS container after systemd has started the host-level service. Any FATAL process should be interpreted in context. For example, a PTP-related process may fail in a lab or virtual environment where the required platform support is not available.

PMON – Platform Monitor


The pmon container provides platform monitoring functions. Depending on the platform, it may monitor hardware sensors, fans, power supplies, transceivers, EEPROM information, and other platform-specific components. In virtual or lab environments, some platform-related helper processes may exit because the corresponding hardware is not present.

admin@sonic:~$ systemctl status pmon.service
● pmon.service - Platform monitor container
     Loaded: loaded (/lib/systemd/system/pmon.service; enabled; vendor preset: >
     Active: active (running) since Wed 2026-07-01 08:00:40 UTC; 29min ago
    Process: 4405 ExecStartPre=/usr/bin/pmon.sh start (code=exited, status=0/SU>
   Main PID: 6301 (pmon.sh)
      Tasks: 2 (limit: 4289)
     Memory: 1.6M
     CGroup: /system.slice/pmon.service
             ├─6301 /bin/bash /usr/bin/pmon.sh wait
             └─6671 tail --pid=6229 -f /dev/null
admin@sonic:~$

Example 3-12: PMON - systemctl status pmon.service.

The output indicates that pmon.service is active at the host level. As with other SONiC containers, systemd is waiting on the helper script rather than directly supervising every process inside the container. The internal platform-monitoring processes must therefore be checked separately with supervisorctl status.

admin@sonic:~$ systemctl cat pmon.service
# /lib/systemd/system/pmon.service
[Unit]
Description=Platform monitor container
Requires=database.service updategraph.service swss.service
After=database.service updategraph.service swss.service

BindsTo=sonic.target
After=sonic.target
Before=ntp-config.service
StartLimitIntervalSec=1200
StartLimitBurst=20

[Service]
User=admin
ExecStartPre=/usr/bin/pmon.sh start
ExecStart=/usr/bin/pmon.sh wait
ExecStop=/usr/bin/pmon.sh stop
Restart=always
RestartSec=30
TimeoutStartSec=360

[Install]
WantedBy=sonic.target swss.service

Example 3-13: PMON - systemctl cat pmon.service.

The unit file shows that pmon.service depends on database.service, updategraph.service, and swss.service. This ordering is important because platform monitoring may need database access and system state before its internal processes can operate correctly. The WantedBy line also shows that PMON is associated with both the SONiC startup target and SWSS-related startup.

admin@sonic:~$ docker exec -it pmon supervisorctl status
dependent-startup                EXITED    Jul 01 08:01 AM
i2cstatsd                        EXITED    Jul 01 08:01 AM
monitpmon                        EXITED    Jul 01 08:01 AM
restart-rsyslogd                 EXITED    Jul 01 08:01 AM
rsyslogd                         RUNNING   pid 222, uptime 0:41:22
ssdhealthd                       RUNNING   pid 73, uptime 0:41:48
supervisor-proc-exit-listener    RUNNING   pid 20, uptime 0:41:54
syseepromd                       EXITED    Jul 01 08:01 AM

Example 3-14: PMON - docker exec -it pmon supervisorctl status.

In this output, long-running processes such as ssdhealthd, rsyslogd, and supervisor-proc-exit-listener are active, while several initialization or platform-specific processes have exited. This does not automatically indicate a failure. The expected process set depends on the hardware platform, the SONiC image, and the available platform drivers.

syncd – ASIC Synchronization Service

The syncd container represents the synchronization path between SONiC's hardware-oriented database state and the vendor-specific ASIC implementation. It consumes ASIC_DB updates and passes the corresponding operations through the SAI layer toward the ASIC SDK. Verifying syncd is therefore important when checking whether the boot process has reached the hardware-programming layer.

admin@sonic:~$ systemctl status syncd.service
● syncd.service - syncd service
     Loaded: loaded (/lib/systemd/system/syncd.service; enabled; vendor preset:>
     Active: active (running) since Wed 2026-07-01 08:00:24 UTC; 31min ago
    Process: 4406 ExecStartPre=/usr/local/bin/syncd.sh start (code=exited, stat>
   Main PID: 4988 (syncd.sh)
      Tasks: 3 (limit: 4289)
     Memory: 1.1M
     CGroup: /sonic.slice/sonic-core.slice/syncd.service
             ├─4988 /bin/bash /usr/local/bin/syncd.sh wait
             ├─4993 /bin/bash /usr/bin/syncd.sh wait
             └─5052 tail --pid=4947 -f /dev/null
admin@sonic:~$

Example 3-15: syncd - systemctl status syncd.service.

The output shows that syncd.service is active from the systemd viewpoint. The host-level service is represented by the syncd helper scripts, while the actual syncd daemon runs inside the container. This means that the service status should be combined with the supervisor output before concluding that the ASIC synchronization path is healthy.

admin@sonic:~$ systemctl cat syncd.service
# /lib/systemd/system/syncd.service
[Unit]
Description=syncd service
Requires=database.service
After=database.service
After=swss.service


Requires=updategraph.service
After=updategraph.service
After=interfaces-config.service
BindsTo=sonic.target
After=sonic.target
Before=ntp-config.service

[Service]
User=root
Environment=sonic_asic_platform=vs
ExecStartPre=/usr/local/bin/syncd.sh start
ExecStart=/usr/local/bin/syncd.sh wait
ExecStop=/usr/local/bin/syncd.sh stop

Slice=sonic-core.slice

[Install]
WantedBy=sonic.target
admin@sonic:~$

Example 3-16: syncd - systemctl cat syncd.service.

The unit file orders syncd.service after both database.service and swss.service. This matches the SONiC data path described earlier: SWSS writes hardware-oriented state into ASIC_DB, and syncd consumes that state before passing operations to the SAI layer. The additional ordering after updategraph and interface configuration services helps ensure that the service starts with the required platform and interface context.

admin@sonic:~$ docker exec -it syncd supervisorctl status
dependent-startup                EXITED    Jul 01 08:00 AM
restart-rsyslogd                 EXITED    Jul 01 08:01 AM
rsyslogd                         RUNNING   pid 285, uptime 0:42:43
start                            EXITED    Jul 01 08:00 AM
supervisor-proc-exit-listener    RUNNING   pid 7, uptime 0:43:37
syncd                            RUNNING   pid 30, uptime 0:43:31

Example 3-17: syncd - docker exec -it syncd supervisorctl status.

The supervisor output confirms that the syncd process is running inside the container. In this type of verification, the systemd service status confirms that the container service is active, while the supervisor output confirms that the actual synchronization daemon inside the container is running.

BGP – FRR Routing Container


The same verification pattern applies to higher-level service containers. BGP, LLDP, teamd, and SNMP are started through systemd service units, but their internal daemons are managed inside their own containers. For these services, systemctl status confirms the host-level service state, systemctl cat shows dependencies and ordering, and supervisorctl status verifies the processes running inside the container.

admin@sonic:~$ systemctl status bgp.service
● bgp.service - BGP container
     Loaded: loaded (/lib/systemd/system/bgp.service; enabled; vendor preset: e>
     Active: active (running) since Wed 2026-07-01 08:00:16 UTC; 32min ago
    Process: 3391 ExecStartPre=/usr/local/bin/bgp.sh start (code=exited, status>
   Main PID: 3897 (bgp.sh)
      Tasks: 3 (limit: 4289)
     Memory: 1.1M
     CGroup: /sonic.slice/sonic-bgp.slice/bgp.service
             ├─3897 /bin/sh /usr/local/bin/bgp.sh wait
             ├─3898 /bin/bash /usr/bin/bgp.sh wait
             └─4089 tail --pid=3828 -f /dev/null
admin@sonic:~$

Example 3-18: BGP - systemctl status bgp.service.

From the systemd perspective, the bgp.service is active at the host level. The helper scripts keep the container service alive from the systemd perspective, but the routing daemons themselves run inside the BGP container. For routing verification, this host-level check should therefore be followed by the supervisor output inside the container.

admin@sonic:~$ systemctl cat bgp.service
# /lib/systemd/system/bgp.service
[Unit]
Description=BGP container
Requires=database.service
After=database.service
Requires=updategraph.service
After=updategraph.service
BindsTo=sonic.target
After=sonic.target
Before=ntp-config.service
StartLimitIntervalSec=1200
StartLimitBurst=20

[Service]
User=admin
ExecStartPre=/usr/local/bin/bgp.sh start
ExecStart=/usr/local/bin/bgp.sh wait
ExecStop=/usr/local/bin/bgp.sh stop

Restart=always
RestartSec=30
Slice=sonic-bgp.slice

[Install]
WantedBy=sonic.target

Example 3-19: BGP - systemctl cat bgp.service.

The unit file shows that bgp.service requires the database service and is ordered after it. This is expected because routing state learned by FRR is synchronized into SONiC databases and later consumed by other components. The service is also tied to sonic.target, which places it in the normal SONiC startup sequence.

admin@sonic:~$ docker exec -it bgp supervisorctl status
bfdd                             RUNNING   pid 284, uptime 0:43:17
bgpd                             RUNNING   pid 292, uptime 0:43:17
dependent-startup                EXITED    Jul 01 08:01 AM
fpmsyncd                         RUNNING   pid 493, uptime 0:43:09
frrcfgd                          RUNNING   pid 378, uptime 0:43:13
ipmcfpmsyncd                     RUNNING   pid 494, uptime 0:43:09
iptrackd                         RUNNING   pid 299, uptime 0:43:17
ospfd                            RUNNING   pid 305, uptime 0:43:17
pimd                             RUNNING   pid 321, uptime 0:43:16
restart-rsyslogd                 EXITED    Jul 01 08:01 AM
rsyslogd                         RUNNING   pid 693, uptime 0:42:48
set_docker_up_status             EXITED    Jul 01 08:01 AM
staticd                          RUNNING   pid 281, uptime 0:43:17
supervisor-proc-exit-listener    RUNNING   pid 30, uptime 0:43:58
wait_for_frrcfgd_conn            EXITED    Jul 01 08:01 AM
wait_for_replay_done             EXITED    Jul 01 08:00 AM
zebra                            RUNNING   pid 223, uptime 0:43:20
zsocket                          EXITED    Jul 01 08:01 AM

Example 3-20: BGP - docker exec -it bgp supervisorctl status.

The BGP supervisor output confirms that FRR-related processes such as bgpd, zebra, and staticd are running. bgpd handles BGP protocol processing, while zebra maintains routing information inside FRR. fpmsyncd is especially important in SONiC because it synchronizes routing information from FRR toward the SONiC database pipeline.

LLDP – Link Layer Discovery Protocol


The LLDP container is responsible for neighbor discovery and for exchanging link-layer information with directly connected devices. Verifying lldp.service confirms that the host-level container service has started. The supervisor output then confirms that processes such as lldpd, lldpmgrd, and lldp-syncd are running inside the container.

admin@sonic:~$ systemctl status lldp.service
● lldp.service - LLDP container
     Loaded: loaded (/lib/systemd/system/lldp.service; enabled; vendor preset: >
     Active: active (running) since Wed 2026-07-01 08:01:22 UTC; 31min ago
    Process: 7302 ExecStartPre=/usr/bin/lldp.sh start (code=exited, status=0/SU>
   Main PID: 9942 (lldp.sh)
      Tasks: 2 (limit: 4289)
     Memory: 688.0K
     CGroup: /system.slice/lldp.service
             ├─ 9942 /bin/bash /usr/bin/lldp.sh wait
             └─10450 tail --pid=9724 -f /dev/null
admin@sonic:~$

Example 3-21: LLDP - systemctl status lldp.service.

The output verifies that lldp.service is active from the systemd viewpoint. This means that the LLDP container service has started successfully, but it does not yet confirm that LLDP neighbor discovery processes are running inside the container. The internal process state is verified separately in the supervisor output.

admin@sonic:~$ systemctl cat lldp.service
# /lib/systemd/system/lldp.service
[Unit]
Description=LLDP container
Requires=database.service
After=database.service
After=swss.service
After=syncd.service
Requires=updategraph.service
After=updategraph.service portinitdone.service
BindsTo=sonic.target
After=sonic.target
Before=ntp-config.service
StartLimitIntervalSec=1200
StartLimitBurst=3

[Service]
User=admin
ExecStartPre=/usr/bin/lldp.sh start
ExecStart=/usr/bin/lldp.sh wait
ExecStop=/usr/bin/lldp.sh stop
Restart=always
RestartSec=30

[Install]
WantedBy=sonic.target

Example 3-22: LLDP - systemctl cat lldp.service.

The unit file orders lldp.service after the database, SWSS, syncd, and port-initialization services. This is logical because LLDP depends on initialized interfaces and on the SONiC state pipeline being available. If LLDP starts too early, it may not have the interface context needed to publish accurate neighbor information.

admin@sonic:~$ docker exec -it lldp supervisorctl status
dependent-startup                EXITED    Jul 01 08:01 AM
lldp-syncd                       RUNNING   pid 120, uptime 0:43:58
lldpd                            RUNNING   pid 63, uptime 0:44:00
lldpmgrd                         RUNNING   pid 145, uptime 0:43:55
restart-rsyslogd                 STOPPED   Not started
rsyslogd                         RUNNING   pid 37, uptime 0:44:04
start                            EXITED    Jul 01 08:01 AM
supervisor-proc-exit-listener    RUNNING   pid 9, uptime 0:44:05
waitfor_lldp_ready               EXITED    Jul 01 08:01 AM

Example 3-23: LLDP - docker exec -it lldp supervisorctl status.

The LLDP supervisor output shows that the main LLDP processes are running. lldpd handles the LLDP protocol function, lldpmgrd manages LLDP-related state in SONiC, and lldp-syncd synchronizes LLDP information with the rest of the system. As with other containers, one-shot startup tasks may appear as EXITED, and optional helper processes may remain STOPPED depending on the image and configuration.

teamd – Link Aggregation Service


The teamd container is used for link aggregation and port-channel-related functions. It works with SONiC orchestration components to maintain logical link aggregation state and synchronize port-channel information. Verifying teamd.service is useful when checking whether link aggregation services have started correctly after the lower-level switching services are available.

admin@sonic:~$ systemctl status teamd.service
● teamd.service - TEAMD container
     Loaded: loaded (/lib/systemd/system/teamd.service; enabled; vendor preset:>
     Active: active (running) since Wed 2026-07-01 08:00:37 UTC; 33min ago
    Process: 4407 ExecStartPre=/usr/local/bin/teamd.sh start (code=exited, stat>
   Main PID: 5933 (teamd.sh)
      Tasks: 3 (limit: 4289)
     Memory: 1.0M
     CGroup: /system.slice/teamd.service
             ├─5933 /bin/sh /usr/local/bin/teamd.sh wait
             ├─5934 /bin/bash /usr/bin/teamd.sh wait
             └─6482 tail --pid=5801 -f /dev/null
admin@sonic:~$

Example 3-24: teamd - systemctl status teamd.service.

The output indicates that teamd.service is active from the host systemd viewpoint. This indicates that the container service has started, but it does not confirm the health of the port-channel related daemons inside the container. Those internal processes must be checked with supervisorctl status.

admin@sonic:~$ systemctl cat teamd.service
# /lib/systemd/system/teamd.service
[Unit]
Description=TEAMD container
After=swss.service
Requires=updategraph.service
After=updategraph.service
BindsTo=sonic.target
After=sonic.target
Before=ntp-config.service
StartLimitIntervalSec=1200
StartLimitBurst=20

[Service]
User=admin
ExecStartPre=/usr/local/bin/teamd.sh start
ExecStart=/usr/local/bin/teamd.sh wait
ExecStop=/usr/local/bin/teamd.sh stop
Restart=always
RestartSec=30

[Install]
WantedBy=sonic.target

Example 3-25: teamd - systemctl cat teamd.service.

The unit file shows that teamd.service is ordered after swss.service and updategraph.service. This reflects the relationship between port-channel handling and the broader SONiC switching state pipeline. The service also binds to sonic.target, so it is part of the coordinated SONiC startup process.

admin@sonic:~$ docker exec -it teamd supervisorctl status
dependent-startup                EXITED    Jul 01 08:00 AM
portchannelstatsd                FATAL     Exited too quickly (process log may have details)
restart-rsyslogd                 EXITED    Jul 01 08:01 AM
rsyslogd                         RUNNING   pid 154, uptime 0:44:42
start                            EXITED    Jul 01 08:00 AM
supervisor-proc-exit-listener    RUNNING   pid 8, uptime 0:45:29
teammgrd                         RUNNING   pid 89, uptime 0:45:19
teamsyncd                        RUNNING   pid 84, uptime 0:45:22
tlm_teamd                        RUNNING   pid 92, uptime 0:45:17
admin@sonic:~$

Example 3-26: teamd - docker exec -it teamd supervisorctl status.

The teamd supervisor output shows the main teamd-related processes running inside the container. teammgrd participates in SONiC's port-channel management logic, teamsyncd synchronizes team state, and tlm_teamd represents the team daemon process itself. A FATAL state, such as the one shown for portchannelstatsd, should be investigated in context because the expected behavior may depend on the platform, enabled features, and whether port channels are configured in the environment.

SNMP – Simple Network Management Protocol


The SNMP container provides management-plane visibility for external monitoring systems. It exposes SONiC information through SNMP and uses internal helper processes to collect and publish the data that SNMP agents need. Verifying snmp.service confirms that the container is active, while the supervisor output confirms that the internal SNMP processes are running.

admin@sonic:~$ systemctl status snmp.service
● snmp.service - SNMP container
     Loaded: loaded (/lib/systemd/system/snmp.service; enabled; vendor preset: >
     Active: active (running) since Wed 2026-07-01 08:01:22 UTC; 33min ago
    Process: 7308 ExecStartPre=/usr/bin/snmp.sh start (code=exited, status=0/SU>
   Main PID: 9946 (snmp.sh)
      Tasks: 2 (limit: 4289)
     Memory: 708.0K
     CGroup: /system.slice/snmp.service
             ├─ 9946 /bin/bash /usr/bin/snmp.sh wait
             └─10459 tail --pid=9674 -f /dev/null
admin@sonic:~$

Example 3-27: SNMP - systemctl status snmp.service.

The output confirms that snmp.service is active from the systemd viewpoint. This means that the SNMP container service has started, but the actual SNMP agent and SONiC-specific helper processes run inside the container. The next verification step is therefore to inspect the supervisor state inside the SNMP container.

admin@sonic:~$ systemctl cat snmp.service
# /lib/systemd/system/snmp.service
[Unit]
Description=SNMP container
Requires=updategraph.service
Requisite=swss.service
After=updategraph.service swss.service syncd.service portinitdone.service
BindsTo=sonic.target
After=sonic.target
Before=ntp-config.service
#Conflicts=snmp.timer
StartLimitIntervalSec=1200
StartLimitBurst=20

[Service]
ExecStartPre=/usr/bin/snmp.sh start
ExecStart=/usr/bin/snmp.sh wait
ExecStop=/usr/bin/snmp.sh stop
Restart=always
RestartSec=30

[Install]
WantedBy=multi-user.target swss.service

Example 3-28: SNMP - systemctl cat snmp.service.

The unit file shows that snmp.service has a Requisite=swss.service relationship and is ordered after SWSS, syncd, and port initialization. This means SNMP expects the switching state pipeline to be available before the SNMP container is started. This ordering is useful because SNMP exposes management information that depends on data collected and published by other SONiC services.

admin@sonic:~$ docker exec -it snmp supervisorctl status
dependent-startup                EXITED    Jul 01 08:01 AM
restart-rsyslogd                 STOPPED   Not started
rsyslogd                         RUNNING   pid 30, uptime 0:44:52
snmp-statsd                      RUNNING   pid 50, uptime 0:44:46
snmp-subagent                    RUNNING   pid 47, uptime 0:44:47
snmpconfd                        RUNNING   pid 44, uptime 0:44:49
snmpd                            RUNNING   pid 46, uptime 0:44:48
start                            EXITED    Jul 01 08:01 AM
supervisor-proc-exit-listener    RUNNING   pid 8, uptime 0:44:56
admin@sonic:~$

Example 3-29: SNMP - docker exec -it snmp supervisorctl status.

The SNMP supervisor output confirms that the SNMP-related processes are running. snmpd provides the SNMP agent function, while snmp-subagent, snmpconfd, and snmp-statsd support SONiC-specific management data and statistics collection. As with the other containers, exited startup helpers are not necessarily errors if they are designed to run only during initialization.

Post-Boot Container Runtime Check


The previous examples verified selected services from the systemd and container-internal viewpoints. A final post-boot check can also be done from the Docker runtime view. This does not replace service-specific verification, but it provides a compact summary of which containers are running and how they are behaving at the moment of inspection.

Running Containers


After individual services have been verified, docker ps provides a quick container-level inventory. The formatted output is easier to read than the default Docker output because it focuses on the container name, image, command, and status. This is useful for confirming that the expected SONiC containers are present and have an uptime that is consistent with the current boot session.

admin@sonic:~$ docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Command}}"
NAMES            IMAGE                                COMMAND
radv             docker-router-advertiser:latest      "/usr/bin/docker-ini…"
sflow            docker-sflow:latest                  "/usr/local/bin/supe…"
udld             docker-udld:latest                   "/usr/local/bin/supe…"
lldp             docker-lldp:latest                   "/usr/bin/docker-lld…"
dhcp_relay       docker-dhcp-relay:latest             "/usr/bin/docker_ini…"
macsec           docker-macsec:latest                 "/usr/local/bin/supe…"
iccpd            docker-iccpd:latest                  "/usr/local/bin/supe…"
stp              docker-stp:latest                    "/usr/local/bin/supe…"
vrrp             docker-vrrp:latest                   "/usr/local/bin/supe…"
l2mcd            docker-l2mcd:latest                  "/usr/local/bin/supe…"
snmp             docker-snmp:latest                   "/usr/local/bin/supe…"
tam              docker-tam:latest                    "/usr/local/bin/supe…"
nat              docker-nat:latest                    "/usr/local/bin/supe…"
telemetry        docker-sonic-telemetry:latest        "/usr/local/bin/supe…"
teamd            docker-teamd:latest                  "/usr/local/bin/supe…"
pmon             docker-platform-monitor:latest       "/usr/bin/docker_ini…"
syncd            docker-syncd-vs:latest               "/usr/local/bin/supe…"
swss             docker-orchagent:latest              "/usr/bin/docker-ini…"
mgmt-framework   docker-sonic-mgmt-framework:latest   "/usr/local/bin/supe…"
bgp              docker-fpm-frr:latest                "/usr/bin/docker_ini…"
eventd           docker-eventd:latest                 "/usr/bin/docker-ini…"
database         docker-database:latest               "/usr/local/bin/dock…"
admin@sonic:~$

Example 3-30: Docker - docker ps formatted container inventory.

The container list gives a compact view of the running SONiC services. It does not replace service-specific verification, but it is a useful first check after boot. The exact container list depends on the SONiC image, platform, and enabled features. If an expected container is missing from this list, the next step is to check the corresponding systemd unit and its journal output.

Container Resource Usage


docker stats shows live resource usage for running containers. It is useful for observing CPU, memory, I/O, and process count behavior, but it should not be treated as a strict pass/fail test. The values depend on the platform, SONiC image, traffic level, enabled features, and the exact moment when the command is run.

admin@sonic:~$ docker stats
CONTAINER ID   NAME             CPU %     MEM USAGE / LIMIT    MEM %     NET I/O   BLOCK I/O         PIDS
39f35ad86528   radv             0.22%     22.8MiB / 1.09GiB    2.04%     0B / 0B   6.71MB / 77.8kB   6
383c6f129cf0   sflow            0.26%     41.68MiB / 1.09GiB   3.73%     0B / 0B   5.89MB / 73.7kB   10
41f8aceb0276   udld             0.35%     27.29MiB / 1.09GiB   2.44%     0B / 0B   6.76MB / 73.7kB   9
d00179c7ea91   lldp             1.75%     64.48MiB / 1.09GiB   5.78%     0B / 0B   11.9MB / 119kB    11
234984a05688   dhcp_relay       0.26%     27.41MiB / 1.09GiB   2.46%     0B / 0B   9.2MB / 102kB     8
8154d5347695   macsec           0.63%     79.97MiB / 1.09GiB   7.16%     0B / 0B   13.7MB / 131kB    42
1dd74fba4493   iccpd            0.73%     27.12MiB / 1.09GiB   2.43%     0B / 0B   8.29MB / 86kB     11
2ac43c450769   stp              0.38%     29.6MiB / 1.09GiB    2.65%     0B / 0B   6.53MB / 73.7kB   10
2445d3c5e915   vrrp             6.17%     26.2MiB / 1.08GiB    2.37%     0B / 0B   6.44MB / 73.7kB   11
d7edfc980943   l2mcd            0.36%     25.2MiB / 1.09GiB    2.26%     0B / 0B   6.2MB / 73.7kB    10
5aef3c71eb05   snmp             10.97%    119.6MiB / 1.09GiB   10.71%    0B / 0B   17.2MB / 152kB    20
2da13d8479fc   tam              0.48%     29.16MiB / 1.09GiB   2.61%     0B / 0B   9.29MB / 143kB    17
4ccfa496c465   nat              0.34%     24.18MiB / 1.09GiB   2.17%     0B / 0B   6.27MB / 143kB    10
e470557ea1bc   telemetry        2.05%     133.8MiB / 1.09GiB   11.99%    0B / 0B   54.6MB / 135kB    16
44a70e26dc76   teamd            0.41%     27.36MiB / 1.09GiB   2.45%     0B / 0B   6.61MB / 168kB    13
0862067c132d   pmon             0.39%     52.59MiB / 1.09GiB   4.71%     0B / 0B   19.5MB / 139kB    7
f61ead90462b   syncd            3.69%     42.28MiB / 1.09GiB   3.79%     0B / 0B   13.1MB / 115kB    47
70ca44b89efe   swss             8.26%     56.46MiB / 1.09GiB   5.06%     0B / 0B   42.8MB / 373kB    57
861772e23d91   mgmt-framework   0.61%     119.7MiB / 1.08GiB   10.82%    0B / 0B   48.2MB / 119kB    14
a9a0074ca931   bgp              3.06%     108.5MiB / 1.09GiB   9.72%     0B / 0B   27.1MB / 287kB    40
8a01d7562616   eventd           0.25%     26.34MiB / 1.09GiB   2.36%     0B / 0B   9.73MB / 106kB    7
e12203dba0e6   database         10.77%    114.5MiB / 1.09GiB   10.26%    0B / 0B   37.9MB / 520kB    36
<Additional refresh cycles omitted for brevity.>

Example 3-31: Docker - docker stats container resource usage.

The example shows that resource usage changes while the command is running. Short CPU spikes can be normal during startup, during Redis activity, or when services process configuration and state updates. A sustained high value, especially combined with service failures or delayed convergence, is more useful as a troubleshooting signal than a single sample.

The examples in this chapter demonstrate that verifying SONiC startup involves three complementary views. systemd confirms that the host-level service units have started, the service unit files explain the dependency and ordering relationships, and supervisorctl verifies that the expected processes are running inside each container. Together, these views provide a structured approach to troubleshooting SONiC startup problems.