diff --git a/data/templates/frr/daemons.frr.tmpl b/data/templates/frr/daemons.frr.tmpl
index fe2610724..5057bb937 100644
--- a/data/templates/frr/daemons.frr.tmpl
+++ b/data/templates/frr/daemons.frr.tmpl
@@ -1,57 +1,112 @@
-zebra=yes
+#
+# The watchfrr, zebra, mgmtd and staticd daemons are always started.
+#
+# Note: The following FRR-services must be kept disabled because they are replaced by other packages in VyOS:
+#
+# pimd   Replaced by package igmpproxy.
+# nhrpd  Replaced by package opennhrp.
+# pbrd   Replaced by PBR in nftables.
+# vrrpd  Replaced by package keepalived.
+#
+# And these must be disabled aswell since they are currently missing a VyOS CLI:
+#
+# eigrp
+# sharpd
+# fabricd
+# pathd
+#
+
+#zebra=yes
+#mgmtd=yes
+#staticd=yes
 bgpd=yes
 ospfd=yes
 ospf6d=yes
 ripd=yes
 ripngd=yes
 isisd=yes
 pimd=no
 pim6d=yes
 ldpd=yes
 nhrpd=no
-eigrpd=yes
+eigrpd=no
 babeld=yes
 sharpd=no
 pbrd=no
 bfdd=yes
-staticd=yes
+fabricd=no
+vrrpd=no
+pathd=no
 
-vtysh_enable=yes
-zebra_options="   --daemon -A 127.0.0.1 -s 90000000
-{%- if irdp is defined %} -M irdp{% endif -%}
-{%- if snmp is defined and snmp.zebra is defined %} -M snmp{% endif -%}
-"
-bgpd_options="    --daemon -A 127.0.0.1 -M rpki
-{%- if bmp is defined %} -M bmp{% endif -%}
-{%- if snmp is defined and snmp.bgpd is defined %} -M snmp{% endif -%}
-"
-ospfd_options="   --daemon -A 127.0.0.1
-{%- if snmp is defined and snmp.ospfd is defined %} -M snmp{% endif -%}
-"
-ospf6d_options="  --daemon -A ::1
-{%- if snmp is defined and snmp.ospf6d is defined %} -M snmp{% endif -%}
-"
-ripd_options="    --daemon -A 127.0.0.1
-{%- if snmp is defined and snmp.ripd is defined %} -M snmp{% endif -%}
-"
-ripngd_options="  --daemon -A ::1"
-isisd_options="   --daemon -A 127.0.0.1
-{%- if snmp is defined and snmp.isisd is defined %} -M snmp{% endif -%}
-"
-pimd_options="    --daemon -A 127.0.0.1"
-pim6d_options="   --daemon -A ::1"
-ldpd_options="    --daemon -A 127.0.0.1
-{%- if snmp is defined and snmp.ldpd is defined %} -M snmp{% endif -%}
-"
-mgmtd_options="   --daemon -A 127.0.0.1"
-nhrpd_options="   --daemon -A 127.0.0.1"
-eigrpd_options="  --daemon -A 127.0.0.1"
-babeld_options="  --daemon -A 127.0.0.1"
-sharpd_options="  --daemon -A 127.0.0.1"
-pbrd_options="    --daemon -A 127.0.0.1"
-staticd_options=" --daemon -A 127.0.0.1"
-bfdd_options="    --daemon -A 127.0.0.1"
+#
+# Define defaults for all services even those who shall be kept disabled.
+#
+
+zebra_options="  --daemon -A 127.0.0.1 -s 90000000{{ ' -M snmp' if snmp.zebra is vyos_defined }}{{ ' -M irdp' if irdp is vyos_defined }}"
+mgmtd_options="  --daemon -A 127.0.0.1"
+staticd_options="--daemon -A 127.0.0.1"
+bgpd_options="   --daemon -A 127.0.0.1 -M rpki{{ ' -M snmp' if snmp.bgpd is vyos_defined }}{{ ' -M bmp' if bmp is vyos_defined }}"
+ospfd_options="  --daemon -A 127.0.0.1{{ ' -M snmp' if snmp.ospfd is vyos_defined }}"
+ospf6d_options=" --daemon -A ::1{{ ' -M snmp' if snmp.ospf6d is vyos_defined }}"
+ripd_options="   --daemon -A 127.0.0.1{{ ' -M snmp' if snmp.ripd is vyos_defined }}"
+ripngd_options=" --daemon -A ::1"
+isisd_options="  --daemon -A 127.0.0.1{{ ' -M snmp' if snmp.isisd is vyos_defined }}"
+pimd_options="   --daemon -A 127.0.0.1"
+pim6d_options="  --daemon -A ::1"
+ldpd_options="   --daemon -A 127.0.0.1{{ ' -M snmp' if snmp.ldpd is vyos_defined }}"
+nhrpd_options="  --daemon -A 127.0.0.1"
+eigrpd_options=" --daemon -A 127.0.0.1"
+babeld_options=" --daemon -A 127.0.0.1"
+sharpd_options=" --daemon -A 127.0.0.1"
+pbrd_options="   --daemon -A 127.0.0.1"
+bfdd_options="   --daemon -A 127.0.0.1"
+fabricd_options="--daemon -A 127.0.0.1"
+vrrpd_options="  --daemon -A 127.0.0.1"
+pathd_options="  --daemon -A 127.0.0.1"
+
+#frr_global_options=""
+
+#zebra_wrap=""
+#mgmtd_wrap=""
+#staticd_wrap=""
+#bgpd_wrap=""
+#ospfd_wrap=""
+#ospf6d_wrap=""
+#ripd_wrap=""
+#ripngd_wrap=""
+#isisd_wrap=""
+#pimd_wrap=""
+#pim6d_wrap=""
+#ldpd_wrap=""
+#nhrpd_wrap=""
+#eigrpd_wrap=""
+#babeld_wrap=""
+#sharpd_wrap=""
+#pbrd_wrap=""
+#bfdd_wrap=""
+#fabricd_wrap=""
+#vrrpd_wrap=""
+#pathd_wrap=""
+
+#all_wrap=""
 
+#
+# Other options.
+#
+# For more information see:
+# https://github.com/FRRouting/frr/blob/stable/9.0/tools/etc/frr/daemons
+# https://docs.frrouting.org/en/stable-9.0/setup.html
+#
+
+vtysh_enable=yes
 watchfrr_enable=no
 valgrind_enable=no
 
+#watchfrr_options=""
+
+frr_profile="traditional"
+
+#MAX_FDS=1024
+
+#FRR_NO_ROOT="yes"
+
diff --git a/op-mode-definitions/restart-frr.xml.in b/op-mode-definitions/restart-frr.xml.in
index 4572858b5..2c9d4b1cc 100644
--- a/op-mode-definitions/restart-frr.xml.in
+++ b/op-mode-definitions/restart-frr.xml.in
@@ -1,79 +1,85 @@
 <?xml version="1.0"?>
 <interfaceDefinition>
   <node name="restart">
     <children>
       <leafNode name="all">
         <properties>
           <help>Restart all routing daemons</help>
         </properties>
         <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart</command>
       </leafNode>
-      <leafNode name="bfd">
-        <properties>
-          <help>Restart Bidirectional Forwarding Detection (BFD) daemon</help>
-        </properties>
-        <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon bfdd</command>
-      </leafNode>
-      <leafNode name="bgp">
+      <leafNode name="zebra">
         <properties>
-          <help>Restart Border Gateway Protocol (BGP) routing daemon</help>
+          <help>Restart Routing Information Base (RIB) IP manager daemon</help>
         </properties>
-        <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon bgpd</command>
+        <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon zebra</command>
       </leafNode>
-      <leafNode name="isis">
+      <leafNode name="static">
         <properties>
-          <help>Restart Intermediate System to Intermediate System (IS-IS) routing daemon</help>
+          <help>Restart static routing daemon</help>
         </properties>
-        <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon isisd</command>
+        <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon staticd</command>
       </leafNode>
-      <leafNode name="ldp">
+      <leafNode name="bgp">
         <properties>
-          <help>Restart the Label Distribution Protocol (LDP) daemon</help>
+          <help>Restart Border Gateway Protocol (BGP) routing daemon</help>
         </properties>
-        <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon ldpd</command>
+        <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon bgpd</command>
       </leafNode>
       <leafNode name="ospf">
         <properties>
           <help>Restart Open Shortest Path First (OSPF) routing daemon</help>
         </properties>
         <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon ospfd</command>
       </leafNode>
       <leafNode name="ospfv3">
         <properties>
           <help>Restart IPv6 Open Shortest Path First (OSPFv3) routing daemon</help>
         </properties>
         <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon ospf6d</command>
       </leafNode>
       <leafNode name="rip">
         <properties>
           <help>Restart Routing Information Protocol (RIP) routing daemon</help>
         </properties>
         <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon ripd</command>
       </leafNode>
       <leafNode name="ripng">
         <properties>
-          <help>Restart Routing Information Protocol NG (RIPng) routing daemon</help>
+          <help>Restart IPv6 Routing Information Protocol (RIPng) routing daemon</help>
         </properties>
         <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon ripngd</command>
       </leafNode>
-      <leafNode name="static">
+      <leafNode name="isis">
         <properties>
-          <help>Restart static routing daemon</help>
+          <help>Restart Intermediate System to Intermediate System (IS-IS) routing daemon</help>
         </properties>
-        <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon staticd</command>
+        <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon isisd</command>
       </leafNode>
-      <leafNode name="zebra">
+      <leafNode name="pim6">
         <properties>
-          <help>Restart Routing Information Base (RIB) manager daemon</help>
+          <help>Restart IPv6 Protocol Independent Multicast (PIM) daemon</help>
         </properties>
-        <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon zebra</command>
+        <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon pim6d</command>
+      </leafNode>
+      <leafNode name="ldp">
+        <properties>
+          <help>Restart Label Distribution Protocol (LDP) daemon used by MPLS</help>
+        </properties>
+        <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon ldpd</command>
       </leafNode>
       <leafNode name="babel">
         <properties>
           <help>Restart Babel routing daemon</help>
         </properties>
         <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon babeld</command>
       </leafNode>
+      <leafNode name="bfd">
+        <properties>
+          <help>Restart Bidirectional Forwarding Detection (BFD) daemon</help>
+        </properties>
+        <command>sudo ${vyos_op_scripts_dir}/restart_frr.py --action restart --daemon bfdd</command>
+      </leafNode>
     </children>
   </node>
 </interfaceDefinition>
diff --git a/python/vyos/frr.py b/python/vyos/frr.py
index 9c9e50ff7..ad5c207f5 100644
--- a/python/vyos/frr.py
+++ b/python/vyos/frr.py
@@ -1,547 +1,550 @@
 # Copyright 2020 VyOS maintainers and contributors <maintainers@vyos.io>
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
 # License as published by the Free Software Foundation; either
 # version 2.1 of the License, or (at your option) any later version.
 #
 # This library is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 # Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with this library.  If not, see <http://www.gnu.org/licenses/>.
 
 r"""
 A Library for interracting with the FRR daemon suite.
 It supports simple configuration manipulation and loading using the official tools
 supplied with FRR (vtysh and frr-reload)
 
 All configuration management and manipulation is done using strings and regex.
 
 
 Example Usage
 #####
 
 # Reading configuration from frr:
 ```
 >>> original_config = get_configuration()
 >>> repr(original_config)
 '!\nfrr version 7.3.1\nfrr defaults traditional\nhostname debian\n......
 ```
 
 
 # Modify a configuration section:
 ```
 >>> new_bgp_section = 'router bgp 65000\n neighbor 192.0.2.1 remote-as 65000\n'
 >>> modified_config = replace_section(original_config, new_bgp_section, replace_re=r'router bgp \d+')
 >>> repr(modified_config)
 '............router bgp 65000\n neighbor 192.0.2.1 remote-as 65000\n...........'
 ```
 
 Remove a configuration section:
 ```
 >>> modified_config = remove_section(original_config, r'router ospf')
 ```
 
 Test the new configuration:
 ```
 >>> try:
 >>>     mark_configuration(modified configuration)
 >>> except ConfigurationNotValid as e:
 >>>     print('resulting configuration is not valid')
 >>>     sys.exit(1)
 ```
 
 Apply the new configuration:
 ```
 >>> try:
 >>>     replace_configuration(modified_config)
 >>> except CommitError as e:
 >>>     print('Exception while commiting the supplied configuration')
 >>>     print(e)
 >>>     exit(1)
 ```
 """
 
 import tempfile
 import re
 
 from vyos.utils.permission import chown
 from vyos.utils.process import cmd
 from vyos.utils.process import popen
 from vyos.utils.process import STDOUT
 
 import logging
 from logging.handlers import SysLogHandler
 import os
 import sys
 
 LOG = logging.getLogger(__name__)
 DEBUG = False
 
 ch = SysLogHandler(address='/dev/log')
 ch2 = logging.StreamHandler(stream=sys.stdout)
 LOG.addHandler(ch)
 LOG.addHandler(ch2)
 
-_frr_daemons = ['zebra', 'bgpd', 'fabricd', 'isisd', 'ospf6d', 'ospfd', 'pbrd',
-                'pimd', 'ripd', 'ripngd', 'sharpd', 'staticd', 'vrrpd', 'ldpd',
-                'bfdd', 'eigrpd', 'babeld' ,'pim6d']
+# Full list of FRR 9.0/stable daemons for reference
+#_frr_daemons = ['zebra', 'staticd', 'bgpd', 'ospfd', 'ospf6d', 'ripd', 'ripngd',
+#                'isisd', 'pim6d', 'ldpd', 'eigrpd', 'babeld', 'sharpd', 'bfdd',
+#                'fabricd', 'pathd']
+_frr_daemons = ['zebra', 'staticd', 'bgpd', 'ospfd', 'ospf6d', 'ripd', 'ripngd',
+                'isisd', 'pim6d', 'ldpd', 'babeld', 'bfdd']
 
 path_vtysh = '/usr/bin/vtysh'
 path_frr_reload = '/usr/lib/frr/frr-reload.py'
 path_config = '/run/frr'
 
 default_add_before = r'(ip prefix-list .*|route-map .*|line vty|end)'
 
 class FrrError(Exception):
     pass
 
 
 class ConfigurationNotValid(FrrError):
     """
     The configuratioin supplied to vtysh is not valid
     """
     pass
 
 
 class CommitError(FrrError):
     """
     Commiting the supplied configuration failed to commit by a unknown reason
     see commit error and/or run mark_configuration on the specified configuration
     to se error generated
 
     used by: reload_configuration()
     """
     pass
 
 
 class ConfigSectionNotFound(FrrError):
     """
     Removal of configuration failed because it is not existing in the supplied configuration
     """
     pass
 
 def init_debugging():
     global DEBUG
 
     DEBUG = os.path.exists('/tmp/vyos.frr.debug')
     if DEBUG:
         LOG.setLevel(logging.DEBUG)
 
 def get_configuration(daemon=None, marked=False):
     """ Get current running FRR configuration
     daemon:  Collect only configuration for the specified FRR daemon,
              supplying daemon=None retrieves the complete configuration
     marked:  Mark the configuration with "end" tags
 
     return:  string containing the running configuration from frr
 
     """
     if daemon and daemon not in _frr_daemons:
         raise ValueError(f'The specified daemon type is not supported {repr(daemon)}')
 
     cmd = f"{path_vtysh} -c 'show run'"
     if daemon:
         cmd += f' -d {daemon}'
 
     output, code = popen(cmd, stderr=STDOUT)
     if code:
         raise OSError(code, output)
 
     config = output.replace('\r', '')
     # Remove first header lines from FRR config
     config = config.split("\n", 3)[-1]
     # Mark the configuration with end tags
     if marked:
         config = mark_configuration(config)
 
     return config
 
 
 def mark_configuration(config):
     """ Add end marks and Test the configuration for syntax faults
     If the configuration is valid a marked version of the configuration is returned,
     or else it failes with a ConfigurationNotValid Exception
 
     config:  The configuration string to mark/test
     return:  The marked configuration from FRR
     """
     output, code = popen(f"{path_vtysh} -m -f -", stderr=STDOUT, input=config)
 
     if code == 2:
         raise ConfigurationNotValid(str(output))
     elif code:
         raise OSError(code, output)
 
     config = output.replace('\r', '')
     return config
 
 
 def reload_configuration(config, daemon=None):
     """ Execute frr-reload with the new configuration
     This will try to reapply the supplied configuration inside FRR.
     The configuration needs to be a complete configuration from the integrated config or
     from a daemon.
 
     config:  The configuration to apply
     daemon:  Apply the conigutaion to the specified FRR daemon,
              supplying daemon=None applies to the integrated configuration
     return:  None
     """
     if daemon and daemon not in _frr_daemons:
         raise ValueError(f'The specified daemon type is not supported {repr(daemon)}')
 
     f = tempfile.NamedTemporaryFile('w')
     f.write(config)
     f.flush()
 
     LOG.debug(f'reload_configuration: Reloading config using temporary file: {f.name}')
     cmd = f'{path_frr_reload} --reload'
     if daemon:
         cmd += f' --daemon {daemon}'
 
     if DEBUG:
         cmd += f' --debug --stdout'
 
     cmd += f' {f.name}'
 
     LOG.debug(f'reload_configuration: Executing command against frr-reload: "{cmd}"')
     output, code = popen(cmd, stderr=STDOUT)
     f.close()
     for i, e in enumerate(output.split('\n')):
         LOG.debug(f'frr-reload output: {i:3} {e}')
     if code == 1:
         raise CommitError('FRR configuration failed while running commit. Please ' \
                           'enable debugging to examine logs.\n\n\n' \
                           'To enable debugging run: "touch /tmp/vyos.frr.debug" ' \
                           'and "sudo systemctl stop vyos-configd"')
     elif code:
         raise OSError(code, output)
 
     return output
 
 
 def save_configuration():
     """ T3217: Save FRR configuration to /run/frr/config/frr.conf """
     return cmd(f'{path_vtysh} -n -w')
 
 
 def execute(command):
     """ Run commands inside vtysh
     command:  str containing commands to execute inside a vtysh session
     """
     if not isinstance(command, str):
         raise ValueError(f'command needs to be a string: {repr(command)}')
 
     cmd = f"{path_vtysh} -c '{command}'"
 
     output, code = popen(cmd, stderr=STDOUT)
     if code:
         raise OSError(code, output)
 
     config = output.replace('\r', '')
     return config
 
 
 def configure(lines, daemon=False):
     """ run commands inside config mode vtysh
     lines:  list or str conaining commands to execute inside a configure session
             only one command executed on each configure()
             Executing commands inside a subcontext uses the list to describe the context
             ex: ['router bgp 6500', 'neighbor 192.0.2.1 remote-as 65000']
     return: None
     """
     if isinstance(lines, str):
         lines = [lines]
     elif not isinstance(lines, list):
         raise ValueError('lines needs to be string or list of commands')
 
     if daemon and daemon not in _frr_daemons:
         raise ValueError(f'The specified daemon type is not supported {repr(daemon)}')
 
     cmd = f'{path_vtysh}'
     if daemon:
         cmd += f' -d {daemon}'
 
     cmd += " -c 'configure terminal'"
     for x in lines:
         cmd += f" -c '{x}'"
 
     output, code = popen(cmd, stderr=STDOUT)
     if code == 1:
         raise ConfigurationNotValid(f'Configuration FRR failed: {repr(output)}')
     elif code:
         raise OSError(code, output)
 
     config = output.replace('\r', '')
     return config
 
 
 def _replace_section(config, replacement, replace_re, before_re):
     r"""Replace a section of FRR config
     config:      full original configuration
     replacement: replacement configuration section
     replace_re:  The regex to replace
                  example: ^router bgp \d+$.?*^!$
                  this will replace everything between ^router bgp X$ and ^!$
     before_re:   When replace_re is not existant, the config will be added before this tag
                  example: ^line vty$
 
     return:      modified configuration as a text file
     """
     # DEPRECATED, this is replaced by a new implementation
     # Check if block is configured, remove the existing instance else add a new one
     if re.findall(replace_re, config, flags=re.MULTILINE | re.DOTALL):
         # Section is in the configration, replace it
         return re.sub(replace_re, replacement, config, count=1,
                       flags=re.MULTILINE | re.DOTALL)
     if before_re:
         if not re.findall(before_re, config, flags=re.MULTILINE | re.DOTALL):
             raise ConfigSectionNotFound(f"Config section {before_re} not found in config")
 
         # If no section is in the configuration, add it before the line vty line
         return re.sub(before_re, rf'{replacement}\n\g<1>', config, count=1,
                       flags=re.MULTILINE | re.DOTALL)
 
     raise ConfigSectionNotFound(f"Config section {replacement} not found in config")
 
 
 def replace_section(config, replacement, from_re, to_re=r'!', before_re=r'line vty'):
     r"""Replace a section of FRR config
     config:      full original configuration
     replacement: replacement configuration section
     from_re:     Regex for the start of section matching
                  example: 'router bgp \d+'
     to_re:       Regex for stop of section matching
                  default: '!'
                  example: '!'  or  'end'
     before_re:   When from_re/to_re  does not return a match, the config will
                  be added before this tag
                  default: ^line vty$
 
     startline and endline tags will be automatically added to the resulting from_re/to_re and before_re regex'es
     """
     # DEPRECATED, this is replaced by a new implementation
     return _replace_section(config, replacement, replace_re=rf'^{from_re}$.*?^{to_re}$', before_re=rf'^({before_re})$')
 
 
 def remove_section(config, from_re, to_re='!'):
     # DEPRECATED, this is replaced by a new implementation
     return _replace_section(config, '', replace_re=rf'^{from_re}$.*?^{to_re}$', before_re=None)
 
 
 def _find_first_block(config, start_pattern, stop_pattern, start_at=0):
     '''Find start and stop line numbers for a config block
     config:        (list) A list conaining the configuration that is searched
     start_pattern: (raw-str) The pattern searched for a a start of block tag
     stop_pattern:  (raw-str) The pattern searched for to signify the end of the block
     start_at:      (int) The index to start searching at in the <config>
 
     Returns:
         None: No complete block could be found
         set(int, int): A complete block found between the line numbers returned in the set
 
     The object <config> is searched from the start for the regex <start_pattern> until the first match is found.
     On a successful match it continues the search for the regex <stop_pattern> until it is found.
     After a successful run a set is returned containing the start and stop line numbers.
     '''
     LOG.debug(f'_find_first_block: find start={repr(start_pattern)} stop={repr(stop_pattern)} start_at={start_at}')
     _start = None
     for i, element in enumerate(config[start_at:], start=start_at):
         # LOG.debug(f'_find_first_block: running line {i:3} "{element}"')
         if not _start:
             if not re.match(start_pattern, element):
                 LOG.debug(f'_find_first_block: no match     {i:3} "{element}"')
                 continue
             _start = i
             LOG.debug(f'_find_first_block: Found start  {i:3} "{element}"')
             continue
 
         if not re.match(stop_pattern, element):
             LOG.debug(f'_find_first_block: no match     {i:3} "{element}"')
             continue
 
         LOG.debug(f'_find_first_block: Found stop   {i:3} "{element}"')
         return (_start, i)
 
     LOG.debug('_find_first_block: exit start={repr(start_pattern)} stop={repr(stop_pattern)} start_at={start_at}')
     return None
 
 
 def _find_first_element(config, pattern, start_at=0):
     '''Find the first element that matches the current pattern in config
     config:        (list) A list containing the configuration that is searched
     start_pattern: (raw-str) The pattern searched for
     start_at:      (int) The index to start searching at in the <config>
 
     return:   Line index of the line containing the searched pattern
 
     TODO: for now it returns -1 on a no-match because 0 also returns as False
     TODO: that means that we can not use False matching to tell if its
     '''
     LOG.debug(f'_find_first_element: find start="{pattern}" start_at={start_at}')
     for i, element in enumerate(config[start_at:], start=0):
         if re.match(pattern + '$', element):
             LOG.debug(f'_find_first_element: Found stop {i:3} "{element}"')
             return i
         LOG.debug(f'_find_first_element: no match   {i:3} "{element}"')
     LOG.debug(f'_find_first_element: Did not find any match, exiting')
     return -1
 
 
 def _find_elements(config, pattern, start_at=0):
     '''Find all instances of pattern and return a list containing all element indexes
     config:        (list) A list containing the configuration that is searched
     start_pattern: (raw-str) The pattern searched for
     start_at:      (int) The index to start searching at in the <config>
 
     return:    A list of line indexes containing the searched pattern
     TODO: refactor this to return a generator instead
     '''
     return [i for i, element in enumerate(config[start_at:], start=0) if re.match(pattern + '$', element)]
 
 
 class FRRConfig:
     '''Main FRR Configuration manipulation object
     Using this object the user could load, manipulate and commit the configuration to FRR
     '''
     def __init__(self, config=[]):
         self.imported_config = ''
 
         if isinstance(config, list):
             self.config = config.copy()
             self.original_config = config.copy()
         elif isinstance(config, str):
             self.config = config.split('\n')
             self.original_config = self.config.copy()
         else:
             raise ValueError(
                 'The config element needs to be a string or list type object')
 
         if config:
             LOG.debug(f'__init__: frr library initiated with initial config')
             for i, e in enumerate(self.config):
                 LOG.debug(f'__init__: initial              {i:3} {e}')
 
     def load_configuration(self, daemon=None):
         '''Load the running configuration from FRR into the config object
         daemon: str with name of the FRR Daemon to load configuration from or
                 None to load the consolidated config
 
         Using this overwrites the current loaded config objects and replaces the original loaded config
         '''
         init_debugging()
 
         self.imported_config = get_configuration(daemon=daemon)
         if daemon:
             LOG.debug(f'load_configuration: Configuration loaded from FRR daemon {daemon}')
         else:
             LOG.debug(f'load_configuration: Configuration loaded from FRR integrated config')
 
         self.original_config = self.imported_config.split('\n')
         self.config = self.original_config.copy()
 
         for i, e in enumerate(self.imported_config.split('\n')):
             LOG.debug(f'load_configuration:  loaded    {i:3} {e}')
         return
 
     def test_configuration(self):
         '''Test the current configuration against FRR
         This will exception if FRR failes to load the current configuration object
         '''
         LOG.debug('test_configation: Testing configuration')
         mark_configuration('\n'.join(self.config))
 
     def commit_configuration(self, daemon=None):
         '''
         Commit the current configuration to FRR daemon: str with name of the
         FRR daemon to commit to or None to use the consolidated config.
 
         Configuration is automatically saved after apply
         '''
         LOG.debug('commit_configuration:  Commiting configuration')
         for i, e in enumerate(self.config):
             LOG.debug(f'commit_configuration: new_config {i:3} {e}')
 
         # https://github.com/FRRouting/frr/issues/10132
         # https://github.com/FRRouting/frr/issues/10133
         count = 0
         count_max = 5
         while count < count_max:
             count += 1
             try:
                 reload_configuration('\n'.join(self.config), daemon=daemon)
                 break
             except:
                 # we just need to re-try the commit of the configuration
                 # for the listed FRR issues above
                 pass
         if count >= count_max:
             raise ConfigurationNotValid(f'Config commit retry counter ({count_max}) exceeded for {daemon} dameon!')
 
         # Save configuration to /run/frr/config/frr.conf
         save_configuration()
 
 
     def modify_section(self, start_pattern, replacement='!', stop_pattern=r'\S+', remove_stop_mark=False, count=0):
         if isinstance(replacement, str):
             replacement = replacement.split('\n')
         elif not isinstance(replacement, list):
             return ValueError("The replacement element needs to be a string or list type object")
         LOG.debug(f'modify_section: starting search for {repr(start_pattern)} until {repr(stop_pattern)}')
 
         _count = 0
         _next_start = 0
         while True:
             if count and count <= _count:
                 # Break out of the loop after specified amount of matches
                 LOG.debug(f'modify_section: reached limit ({_count}), exiting loop at line {_next_start}')
                 break
             # While searching, always assume that the user wants to search for the exact pattern he entered
             # To be more specific the user needs a override, eg. a "pattern.*"
             _w = _find_first_block(
                 self.config, start_pattern+'$', stop_pattern, start_at=_next_start)
             if not _w:
                 # Reached the end, no more elements to remove
                 LOG.debug(f'modify_section: No more config sections found, exiting')
                 break
             start_element, end_element = _w
             LOG.debug(f'modify_section:   found match between {start_element} and {end_element}')
             for i, e in enumerate(self.config[start_element:end_element+1 if remove_stop_mark else end_element],
                                   start=start_element):
                 LOG.debug(f'modify_section:   remove       {i:3} {e}')
             del self.config[start_element:end_element +
                             1 if remove_stop_mark else end_element]
             if replacement:
                 # Append the replacement config at the current position
                 for i, e in enumerate(replacement, start=start_element):
                     LOG.debug(f'modify_section:   add          {i:3} {e}')
                 self.config[start_element:start_element] = replacement
             _count += 1
             _next_start = start_element + len(replacement)
 
         return _count
 
     def add_before(self, before_pattern, addition):
         '''Add config block before this element in the configuration'''
         if isinstance(addition, str):
             addition = addition.split('\n')
         elif not isinstance(addition, list):
             return ValueError("The replacement element needs to be a string or list type object")
 
         start = _find_first_element(self.config, before_pattern)
         if start < 0:
             return False
         for i, e in enumerate(addition, start=start):
             LOG.debug(f'add_before:   add          {i:3} {e}')
         self.config[start:start] = addition
         return True
 
     def __str__(self):
         return '\n'.join(self.config)
 
     def __repr__(self):
         return f'frr({repr(str(self))})'
diff --git a/src/conf_mode/snmp.py b/src/conf_mode/snmp.py
index 7882f8510..d2ed5414f 100755
--- a/src/conf_mode/snmp.py
+++ b/src/conf_mode/snmp.py
@@ -1,274 +1,273 @@
 #!/usr/bin/env python3
 #
 # Copyright (C) 2018-2021 VyOS maintainers and contributors
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License version 2 or later as
 # published by the Free Software Foundation.
 #
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import os
 
 from sys import exit
 
 from vyos.base import Warning
 from vyos.config import Config
 from vyos.configdict import dict_merge
 from vyos.configverify import verify_vrf
 from vyos.snmpv3_hashgen import plaintext_to_md5
 from vyos.snmpv3_hashgen import plaintext_to_sha1
 from vyos.snmpv3_hashgen import random
 from vyos.template import render
 from vyos.utils.process import call
 from vyos.utils.permission import chmod_755
 from vyos.utils.dict import dict_search
 from vyos.utils.network import is_addr_assigned
 from vyos.version import get_version_data
 from vyos import ConfigError
 from vyos import airbag
 airbag.enable()
 
 config_file_client  = r'/etc/snmp/snmp.conf'
 config_file_daemon  = r'/etc/snmp/snmpd.conf'
 config_file_access  = r'/usr/share/snmp/snmpd.conf'
 config_file_user    = r'/var/lib/snmp/snmpd.conf'
 systemd_override    = r'/run/systemd/system/snmpd.service.d/override.conf'
 systemd_service     = 'snmpd.service'
 
 def get_config(config=None):
     if config:
         conf = config
     else:
         conf = Config()
     base = ['service', 'snmp']
 
     snmp = conf.get_config_dict(base, key_mangling=('-', '_'),
                                 get_first_key=True, no_tag_node_value_mangle=True)
     if not conf.exists(base):
         snmp.update({'deleted' : ''})
 
     if conf.exists(['service', 'lldp', 'snmp', 'enable']):
         snmp.update({'lldp_snmp' : ''})
 
     if 'deleted' in snmp:
         return snmp
 
     version_data = get_version_data()
     snmp['version'] = version_data['version']
 
     # create an internal snmpv3 user of the form 'vyosxxxxxxxxxxxxxxxx'
     snmp['vyos_user'] = 'vyos' + random(8)
     snmp['vyos_user_pass'] = random(16)
 
     # We have gathered the dict representation of the CLI, but there are default
     # options which we need to update into the dictionary retrived.
     snmp = conf.merge_defaults(snmp, recursive=True)
 
     if 'listen_address' in snmp:
         # Always listen on localhost if an explicit address has been configured
         # This is a safety measure to not end up with invalid listen addresses
         # that are not configured on this system. See https://vyos.dev/T850
         if '127.0.0.1' not in snmp['listen_address']:
             tmp = {'127.0.0.1': {'port': '161'}}
             snmp['listen_address'] = dict_merge(tmp, snmp['listen_address'])
 
         if '::1' not in snmp['listen_address']:
             tmp = {'::1': {'port': '161'}}
             snmp['listen_address'] = dict_merge(tmp, snmp['listen_address'])
 
     return snmp
 
 def verify(snmp):
     if not snmp:
         return None
 
     if {'deleted', 'lldp_snmp'} <= set(snmp):
         raise ConfigError('Can not delete SNMP service, as LLDP still uses SNMP!')
 
     ### check if the configured script actually exist
     if 'script_extensions' in snmp and 'extension_name' in snmp['script_extensions']:
         for extension, extension_opt in snmp['script_extensions']['extension_name'].items():
             if 'script' not in extension_opt:
                 raise ConfigError(f'Script extension "{extension}" requires an actual script to be configured!')
 
             tmp = extension_opt['script']
             if not os.path.isfile(tmp):
                 Warning(f'script "{tmp}" does not exist!')
             else:
                 chmod_755(extension_opt['script'])
 
     if 'listen_address' in snmp:
         for address in snmp['listen_address']:
             # We only wan't to configure addresses that exist on the system.
             # Hint the user if they don't exist
             if 'vrf' in snmp:
                 vrf_name = snmp['vrf']
                 if not is_addr_assigned(address, vrf_name) and address not in ['::1','127.0.0.1']:
                     raise ConfigError(f'SNMP listen address "{address}" not configured in vrf "{vrf_name}"!')
             elif not is_addr_assigned(address):
                 raise ConfigError(f'SNMP listen address "{address}" not configured in default vrf!')
 
     if 'trap_target' in snmp:
         for trap, trap_config in snmp['trap_target'].items():
             if 'community' not in trap_config:
                 raise ConfigError(f'Trap target "{trap}" requires a community to be set!')
 
     if 'oid_enable' in snmp:
         Warning(f'Custom OIDs are enabled and may lead to system instability and high resource consumption')
 
 
     verify_vrf(snmp)
 
     # bail out early if SNMP v3 is not configured
     if 'v3' not in snmp:
         return None
 
     if 'user' in snmp['v3']:
         for user, user_config in snmp['v3']['user'].items():
             if 'group' not in user_config:
                 raise ConfigError(f'Group membership required for user "{user}"!')
 
             if 'plaintext_password' not in user_config['auth'] and 'encrypted_password' not in user_config['auth']:
                 raise ConfigError(f'Must specify authentication encrypted-password or plaintext-password for user "{user}"!')
 
             if 'plaintext_password' not in user_config['privacy'] and 'encrypted_password' not in user_config['privacy']:
                 raise ConfigError(f'Must specify privacy encrypted-password or plaintext-password for user "{user}"!')
 
     if 'group' in snmp['v3']:
         for group, group_config in snmp['v3']['group'].items():
             if 'seclevel' not in group_config:
                 raise ConfigError(f'Must configure "seclevel" for group "{group}"!')
             if 'view' not in group_config:
                 raise ConfigError(f'Must configure "view" for group "{group}"!')
 
             # Check if 'view' exists
             view = group_config['view']
             if 'view' not in snmp['v3'] or view not in snmp['v3']['view']:
                 raise ConfigError(f'You must create view "{view}" first!')
 
     if 'view' in snmp['v3']:
         for view, view_config in snmp['v3']['view'].items():
             if 'oid' not in view_config:
                 raise ConfigError(f'Must configure an "oid" for view "{view}"!')
 
     if 'trap_target' in snmp['v3']:
         for trap, trap_config in snmp['v3']['trap_target'].items():
             if 'plaintext_password' not in trap_config['auth'] and 'encrypted_password' not in trap_config['auth']:
                 raise ConfigError(f'Must specify one of authentication encrypted-password or plaintext-password for trap "{trap}"!')
 
             if {'plaintext_password', 'encrypted_password'} <= set(trap_config['auth']):
                 raise ConfigError(f'Can not specify both authentication encrypted-password and plaintext-password for trap "{trap}"!')
 
             if 'plaintext_password' not in trap_config['privacy'] and 'encrypted_password' not in trap_config['privacy']:
                 raise ConfigError(f'Must specify one of privacy encrypted-password or plaintext-password for trap "{trap}"!')
 
             if {'plaintext_password', 'encrypted_password'} <= set(trap_config['privacy']):
                 raise ConfigError(f'Can not specify both privacy encrypted-password and plaintext-password for trap "{trap}"!')
 
             if 'type' not in trap_config:
                 raise ConfigError('SNMP v3 trap "type" must be specified!')
 
     return None
 
 def generate(snmp):
 
     #
     # As we are manipulating the snmpd user database we have to stop it first!
     # This is even save if service is going to be removed
     call(f'systemctl stop {systemd_service}')
     # Clean config files
     config_files = [config_file_client, config_file_daemon,
                     config_file_access, config_file_user, systemd_override]
     for file in config_files:
         if os.path.isfile(file):
             os.unlink(file)
 
     if not snmp:
         return None
 
     if 'v3' in snmp:
         # net-snmp is now regenerating the configuration file in the background
         # thus we need to re-open and re-read the file as the content changed.
         # After that we can no read the encrypted password from the config and
         # replace the CLI plaintext password with its encrypted version.
         os.environ['vyos_libexec_dir'] = '/usr/libexec/vyos'
 
         if 'user' in snmp['v3']:
             for user, user_config in snmp['v3']['user'].items():
                 if dict_search('auth.type', user_config)  == 'sha':
                     hash = plaintext_to_sha1
                 else:
                     hash = plaintext_to_md5
 
                 if dict_search('auth.plaintext_password', user_config) is not None:
                     tmp = hash(dict_search('auth.plaintext_password', user_config),
                         dict_search('v3.engineid', snmp))
 
                     snmp['v3']['user'][user]['auth']['encrypted_password'] = tmp
                     del snmp['v3']['user'][user]['auth']['plaintext_password']
 
                     call(f'/opt/vyatta/sbin/my_set service snmp v3 user "{user}" auth encrypted-password "{tmp}" > /dev/null')
                     call(f'/opt/vyatta/sbin/my_delete service snmp v3 user "{user}" auth plaintext-password > /dev/null')
 
                 if dict_search('privacy.plaintext_password', user_config) is not None:
                     tmp = hash(dict_search('privacy.plaintext_password', user_config),
                         dict_search('v3.engineid', snmp))
 
                     snmp['v3']['user'][user]['privacy']['encrypted_password'] = tmp
                     del snmp['v3']['user'][user]['privacy']['plaintext_password']
 
                     call(f'/opt/vyatta/sbin/my_set service snmp v3 user "{user}" privacy encrypted-password "{tmp}" > /dev/null')
                     call(f'/opt/vyatta/sbin/my_delete service snmp v3 user "{user}" privacy plaintext-password > /dev/null')
 
     # Write client config file
     render(config_file_client, 'snmp/etc.snmp.conf.j2', snmp)
     # Write server config file
     render(config_file_daemon, 'snmp/etc.snmpd.conf.j2', snmp)
     # Write access rights config file
     render(config_file_access, 'snmp/usr.snmpd.conf.j2', snmp)
     # Write access rights config file
     render(config_file_user, 'snmp/var.snmpd.conf.j2', snmp)
     # Write daemon configuration file
     render(systemd_override, 'snmp/override.conf.j2', snmp)
 
     return None
 
 def apply(snmp):
     # Always reload systemd manager configuration
     call('systemctl daemon-reload')
 
     if not snmp:
         return None
 
     # start SNMP daemon
     call(f'systemctl restart {systemd_service}')
 
     # Enable AgentX in FRR
     # This should be done for each daemon individually because common command
     # works only if all the daemons started with SNMP support
-    frr_daemons_list = [
-        'bgpd', 'ospf6d', 'ospfd', 'ripd', 'ripngd', 'isisd', 'ldpd', 'zebra'
-    ]
+    # Following daemons from FRR 9.0/stable have SNMP module compiled in VyOS
+    frr_daemons_list = ['zebra', 'bgpd', 'ospf6d', 'ospfd', 'ripd', 'isisd', 'ldpd']
     for frr_daemon in frr_daemons_list:
         call(
             f'vtysh -c "configure terminal" -d {frr_daemon} -c "agentx" >/dev/null'
         )
 
     return None
 
 if __name__ == '__main__':
     try:
         c = get_config()
         verify(c)
         generate(c)
         apply(c)
     except ConfigError as e:
         print(e)
         exit(1)
diff --git a/src/op_mode/restart_frr.py b/src/op_mode/restart_frr.py
index 5cce377eb..820a3846c 100755
--- a/src/op_mode/restart_frr.py
+++ b/src/op_mode/restart_frr.py
@@ -1,181 +1,183 @@
 #!/usr/bin/env python3
 #
 # Copyright (C) 2019-2023 VyOS maintainers and contributors
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License version 2 or later as
 # published by the Free Software Foundation.
 #
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import os
 import argparse
 import logging
 import psutil
 
 from logging.handlers import SysLogHandler
 from shutil import rmtree
 
 from vyos.base import Warning
 from vyos.utils.io import ask_yes_no
 from vyos.utils.file import makedir
 from vyos.utils.process import call
 from vyos.utils.process import process_named_running
 
 # some default values
 watchfrr = '/usr/lib/frr/watchfrr.sh'
 vtysh = '/usr/bin/vtysh'
 frrconfig_tmp = '/tmp/frr_restart'
 
 # configure logging
 logger = logging.getLogger(__name__)
 logs_handler = SysLogHandler('/dev/log')
 logs_handler.setFormatter(logging.Formatter('%(filename)s: %(message)s'))
 logger.addHandler(logs_handler)
 logger.setLevel(logging.INFO)
 
 # check if it is safe to restart FRR
 def _check_safety():
     try:
         # print warning
         if not ask_yes_no('WARNING: This is a potentially unsafe function!\n' \
                           'You may lose the connection to the router or active configuration after\n' \
                           'running this command. Use it at your own risk!\n\n'
                           'Continue?'):
             return False
 
         # check if another restart process already running
         if len([process for process in psutil.process_iter(attrs=['pid', 'name', 'cmdline']) if 'python' in process.info['name'] and 'restart_frr.py' in process.info['cmdline'][1]]) > 1:
             message = 'Another restart_frr.py process is already running!'
             logger.error(message)
             if not ask_yes_no(f'\n{message} It is unsafe to continue.\n\n' \
                               'Do you want to process anyway?'):
                 return False
 
         # check if watchfrr.sh is running
         tmp = os.path.basename(watchfrr)
         if process_named_running(tmp):
             message = f'Another {tmp} process is already running.'
             logger.error(message)
             if not ask_yes_no(f'{message} It is unsafe to continue.\n\n' \
                               'Do you want to process anyway?'):
                 return False
 
         # check if vtysh is running
         if process_named_running('vtysh'):
             message = 'vtysh process is executed by another task.'
             logger.error(message)
             if not ask_yes_no(f'{message} It is unsafe to continue.\n\n' \
                               'Do you want to process anyway?'):
                 return False
 
         # check if temporary directory exists
         if os.path.exists(frrconfig_tmp):
             message = f'Temporary directory "{frrconfig_tmp}" already exists!'
             logger.error(message)
             if not ask_yes_no(f'{message} It is unsafe to continue.\n\n' \
                               'Do you want to process anyway?'):
                 return False
 
     except:
         logger.error("Something goes wrong in _check_safety()")
         return False
 
     # return True if all check was passed or user confirmed to ignore they results
     return True
 
 # write active config to file
 def _write_config():
     # create temporary directory
     makedir(frrconfig_tmp)
     # save frr.conf to it
     command = f'{vtysh} -n -w --config_dir {frrconfig_tmp} 2> /dev/null'
     return_code = call(command)
     if return_code != 0:
         logger.error(f'Failed to save active config: "{command}" returned exit code: {return_code}')
         return False
     logger.info(f'Active config saved to {frrconfig_tmp}')
     return True
 
 # clear and remove temporary directory
 def _cleanup():
     if os.path.isdir(frrconfig_tmp):
         rmtree(frrconfig_tmp)
 
 # restart daemon
 def _daemon_restart(daemon):
     command = f'{watchfrr} restart {daemon}'
     return_code = call(command)
     if not return_code == 0:
         logger.error(f'Failed to restart daemon "{daemon}"!')
         return False
 
     # return True if restarted successfully
     logger.info(f'Daemon "{daemon}" restarted!')
     return True
 
 # reload old config
 def _reload_config(daemon):
     if daemon != '':
         command = f'{vtysh} -n -b --config_dir {frrconfig_tmp} -d {daemon} 2> /dev/null'
     else:
         command = f'{vtysh} -n -b --config_dir {frrconfig_tmp} 2> /dev/null'
 
     return_code = call(command)
     if not return_code == 0:
         logger.error('Failed to re-install configuration!')
         return False
 
     # return True if restarted successfully
     logger.info('Configuration re-installed successfully!')
     return True
 
 # define program arguments
 cmd_args_parser = argparse.ArgumentParser(description='restart frr daemons')
 cmd_args_parser.add_argument('--action', choices=['restart'], required=True, help='action to frr daemons')
-cmd_args_parser.add_argument('--daemon', choices=['bfdd', 'bgpd', 'ldpd', 'ospfd', 'ospf6d', 'isisd', 'ripd', 'ripngd', 'staticd', 'zebra', 'babeld'], required=False,  nargs='*', help='select single or multiple daemons')
+# Full list of FRR 9.0/stable daemons for reference
+#cmd_args_parser.add_argument('--daemon', choices=['zebra', 'staticd', 'bgpd', 'ospfd', 'ospf6d', 'ripd', 'ripngd', 'isisd', 'pim6d', 'ldpd', 'eigrpd', 'babeld', 'sharpd', 'bfdd', 'fabricd', 'pathd'], required=False,  nargs='*', help='select single or multiple daemons')
+cmd_args_parser.add_argument('--daemon', choices=['zebra', 'staticd', 'bgpd', 'ospfd', 'ospf6d', 'ripd', 'ripngd', 'isisd', 'pim6d', 'ldpd', 'babeld', 'bfdd'], required=False,  nargs='*', help='select single or multiple daemons')
 # parse arguments
 cmd_args = cmd_args_parser.parse_args()
 
 # main logic
 # restart daemon
 if cmd_args.action == 'restart':
     # check if it is safe to restart FRR
     if not _check_safety():
         print("\nOne of the safety checks was failed or user aborted command. Exiting.")
         exit(1)
 
     if not _write_config():
         print("Failed to save active config")
         _cleanup()
         exit(1)
 
     # a little trick to make further commands more clear
     if not cmd_args.daemon:
         cmd_args.daemon = ['']
 
     # check all daemons if they are running
     if cmd_args.daemon != ['']:
         for daemon in cmd_args.daemon:
             if not process_named_running(daemon):
                 Warning('some of listed daemons are not running!')
 
     # run command to restart daemon
     for daemon in cmd_args.daemon:
         if not _daemon_restart(daemon):
             print('Failed to restart daemon: {daemon}')
             _cleanup()
             exit(1)
         # reinstall old configuration
         _reload_config(daemon)
 
     # cleanup after all actions
     _cleanup()
 
 exit(0)