diff --git a/data/templates/ids/fastnetmon.j2 b/data/templates/ids/fastnetmon.j2
index b9f77a257..0340d3c92 100644
--- a/data/templates/ids/fastnetmon.j2
+++ b/data/templates/ids/fastnetmon.j2
@@ -1,60 +1,112 @@
 # enable this option if you want to send logs to local syslog facility
 logging:logging_level = debug
 logging:local_syslog_logging = on
 
 # list of all your networks in CIDR format
 networks_list_path = /run/fastnetmon/networks_list
 
 # list networks in CIDR format which will be not monitored for attacks
 white_list_path = /run/fastnetmon/excluded_networks_list
 
 # Enable/Disable any actions in case of attack
 enable_ban = on
 enable_ban_ipv6 = on
 
 ## How many packets will be collected from attack traffic
 ban_details_records_count = 500
 
 ## How long (in seconds) we should keep an IP in blocked state
 ## If you set 0 here it completely disables unban capability
 {% if ban_time is vyos_defined %}
 ban_time = {{ ban_time }}
 {% endif %}
 
 # Check if the attack is still active, before triggering an unban callback with this option
 # If the attack is still active, check each run of the unban watchdog
 unban_only_if_attack_finished = on
 
 # enable per subnet speed meters
 # For each subnet, list track speed in bps and pps for both directions
 enable_subnet_counters = off
 
 {% if mode.mirror is vyos_defined %}
 mirror_afpacket = on
 {% endif %}
 
 process_incoming_traffic = {{ 'on' if direction is vyos_defined and 'in' in direction else 'off' }}
 process_outgoing_traffic = {{ 'on' if direction is vyos_defined and 'out' in direction else 'off' }}
 
 {% if threshold is vyos_defined %}
-{%     for thr, thr_value in threshold.items() %}
-{%         if thr is vyos_defined('fps') %}
+{%     if threshold.general is vyos_defined %}
+# General threshold
+{%         for thr, thr_value in threshold.general.items() %}
+{%             if thr is vyos_defined('fps') %}
 ban_for_flows = on
 threshold_flows = {{ thr_value }}
-{%         elif thr is vyos_defined('mbps') %}
+{%             elif thr is vyos_defined('mbps') %}
 ban_for_bandwidth = on
 threshold_mbps = {{ thr_value }}
-{%         elif thr is vyos_defined('pps') %}
+{%             elif thr is vyos_defined('pps') %}
 ban_for_pps = on
 threshold_pps = {{ thr_value }}
-{%         endif %}
-{%     endfor %}
+{%             endif %}
+{%         endfor %}
+{%     endif %}
+
+{%     if threshold.tcp is vyos_defined %}
+# TCP threshold
+{%         for thr, thr_value in threshold.tcp.items() %}
+{%             if thr is vyos_defined('fps') %}
+ban_for_tcp_flows = on
+threshold_tcp_flows = {{ thr_value }}
+{%             elif thr is vyos_defined('mbps') %}
+ban_for_tcp_bandwidth = on
+threshold_tcp_mbps = {{ thr_value }}
+{%             elif thr is vyos_defined('pps') %}
+ban_for_tcp_pps = on
+threshold_tcp_pps = {{ thr_value }}
+{%             endif %}
+{%         endfor %}
+{%     endif %}
+
+{%     if threshold.udp is vyos_defined %}
+# UDP threshold
+{%         for thr, thr_value in threshold.udp.items() %}
+{%             if thr is vyos_defined('fps') %}
+ban_for_udp_flows = on
+threshold_udp_flows = {{ thr_value }}
+{%             elif thr is vyos_defined('mbps') %}
+ban_for_udp_bandwidth = on
+threshold_udp_mbps = {{ thr_value }}
+{%             elif thr is vyos_defined('pps') %}
+ban_for_udp_pps = on
+threshold_udp_pps = {{ thr_value }}
+{%             endif %}
+{%         endfor %}
+{%     endif %}
+
+{%     if threshold.icmp is vyos_defined %}
+# ICMP threshold
+{%         for thr, thr_value in threshold.icmp.items() %}
+{%             if thr is vyos_defined('fps') %}
+ban_for_icmp_flows = on
+threshold_icmp_flows = {{ thr_value }}
+{%             elif thr is vyos_defined('mbps') %}
+ban_for_icmp_bandwidth = on
+threshold_icmp_mbps = {{ thr_value }}
+{%             elif thr is vyos_defined('pps') %}
+ban_for_icmp_pps = on
+threshold_icmp_pps = {{ thr_value }}
+{%             endif %}
+{%         endfor %}
+{%     endif %}
+
 {% endif %}
 
 {% if listen_interface is vyos_defined %}
 interfaces = {{ listen_interface | join(',') }}
 {% endif %}
 
 {% if alert_script is vyos_defined %}
 notify_script_path = {{ alert_script }}
 {% endif %}
diff --git a/interface-definitions/include/ids/threshold.xml.i b/interface-definitions/include/ids/threshold.xml.i
new file mode 100644
index 000000000..e21e3a005
--- /dev/null
+++ b/interface-definitions/include/ids/threshold.xml.i
@@ -0,0 +1,38 @@
+<!-- include start from ids/threshold.xml.i -->
+<leafNode name="fps">
+  <properties>
+    <help>Flows per second</help>
+    <valueHelp>
+      <format>u32:0-4294967294</format>
+      <description>Flows per second</description>
+    </valueHelp>
+    <constraint>
+      <validator name="numeric" argument="--range 0-4294967294"/>
+    </constraint>
+  </properties>
+</leafNode>
+<leafNode name="mbps">
+  <properties>
+    <help>Megabits per second</help>
+    <valueHelp>
+      <format>u32:0-4294967294</format>
+      <description>Megabits per second</description>
+    </valueHelp>
+    <constraint>
+      <validator name="numeric" argument="--range 0-4294967294"/>
+    </constraint>
+  </properties>
+</leafNode>
+<leafNode name="pps">
+  <properties>
+    <help>Packets per second</help>
+    <valueHelp>
+      <format>u32:0-4294967294</format>
+      <description>Packets per second</description>
+    </valueHelp>
+    <constraint>
+      <validator name="numeric" argument="--range 0-4294967294"/>
+    </constraint>
+  </properties>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/include/version/ids-version.xml.i b/interface-definitions/include/version/ids-version.xml.i
new file mode 100644
index 000000000..9133be02b
--- /dev/null
+++ b/interface-definitions/include/version/ids-version.xml.i
@@ -0,0 +1,3 @@
+<!-- include start from include/version/ids-version.xml.i -->
+<syntaxVersion component='ids' version='1'></syntaxVersion>
+<!-- include end -->
diff --git a/interface-definitions/service-ids-ddos-protection.xml.in b/interface-definitions/service-ids-ddos-protection.xml.in
index 86fc4dffa..a661b845d 100644
--- a/interface-definitions/service-ids-ddos-protection.xml.in
+++ b/interface-definitions/service-ids-ddos-protection.xml.in
@@ -1,154 +1,150 @@
 <?xml version="1.0"?>
 <interfaceDefinition>
   <node name="service">
     <children>
       <node name="ids">
         <properties>
           <help>Intrusion Detection System</help>
         </properties>
         <children>
           <node name="ddos-protection" owner="${vyos_conf_scripts_dir}/service_ids_fastnetmon.py">
             <properties>
               <help>FastNetMon detection and protection parameters</help>
               <priority>731</priority>
             </properties>
             <children>
               <leafNode name="alert-script">
                 <properties>
                   <help>Path to fastnetmon alert script</help>
                 </properties>
               </leafNode>
               <leafNode name="ban-time">
                 <properties>
                   <help>How long we should keep an IP in blocked state</help>
                   <valueHelp>
                     <format>u32:1-4294967294</format>
                     <description>Time in seconds</description>
                   </valueHelp>
                   <constraint>
                     <validator name="numeric" argument="--range 1-4294967294"/>
                   </constraint>
                 </properties>
                 <defaultValue>1900</defaultValue>
               </leafNode>
               <leafNode name="direction">
                 <properties>
                   <help>Direction for processing traffic</help>
                   <completionHelp>
                     <list>in out</list>
                   </completionHelp>
                   <constraint>
                     <regex>(in|out)</regex>
                   </constraint>
                   <multi/>
                 </properties>
               </leafNode>
               <leafNode name="excluded-network">
                 <properties>
                   <help>Specify IPv4 and IPv6 networks which are going to be excluded from protection</help>
                   <valueHelp>
                     <format>ipv4net</format>
                     <description>IPv4 prefix(es) to exclude</description>
                   </valueHelp>
                   <valueHelp>
                     <format>ipv6net</format>
                     <description>IPv6 prefix(es) to exclude</description>
                   </valueHelp>
                   <constraint>
                     <validator name="ipv4-prefix"/>
                     <validator name="ipv6-prefix"/>
                   </constraint>
                   <multi/>
                 </properties>
               </leafNode>
               <leafNode name="listen-interface">
                 <properties>
                   <help>Listen interface for mirroring traffic</help>
                   <completionHelp>
                     <script>${vyos_completion_dir}/list_interfaces.py</script>
                   </completionHelp>
                   <multi/>
                 </properties>
               </leafNode>
               <node name="mode">
                 <properties>
                   <help>Traffic capture modes</help>
                 </properties>
                 <children>
                   <!-- Future modes "mirror" "netflow" "combine (both)" -->
                   <leafNode name="mirror">
                     <properties>
                       <help>Listen mirrored traffic mode</help>
                       <valueless/>
                     </properties>
                   </leafNode>
                 </children>
               </node>
               <leafNode name="network">
                 <properties>
                   <help>Specify IPv4 and IPv6 networks which belong to you</help>
                   <valueHelp>
                     <format>ipv4net</format>
                     <description>Your IPv4 prefix(es)</description>
                   </valueHelp>
                   <valueHelp>
                     <format>ipv6net</format>
                     <description>Your IPv6 prefix(es)</description>
                   </valueHelp>
                   <constraint>
                     <validator name="ipv4-prefix"/>
                     <validator name="ipv6-prefix"/>
                   </constraint>
                   <multi/>
                 </properties>
               </leafNode>
               <node name="threshold">
                 <properties>
                   <help>Attack limits thresholds</help>
                 </properties>
                 <children>
-                  <leafNode name="fps">
+                  <node name="general">
                     <properties>
-                      <help>Flows per second</help>
-                      <valueHelp>
-                        <format>u32:0-4294967294</format>
-                        <description>Flows per second</description>
-                      </valueHelp>
-                      <constraint>
-                        <validator name="numeric" argument="--range 0-4294967294"/>
-                      </constraint>
+                      <help>General threshold</help>
                     </properties>
-                  </leafNode>
-                  <leafNode name="mbps">
+                    <children>
+                      #include <include/ids/threshold.xml.i>
+                    </children>
+                  </node>
+                  <node name="tcp">
                     <properties>
-                      <help>Megabits per second</help>
-                      <valueHelp>
-                        <format>u32:0-4294967294</format>
-                        <description>Megabits per second</description>
-                      </valueHelp>
-                      <constraint>
-                        <validator name="numeric" argument="--range 0-4294967294"/>
-                      </constraint>
+                      <help>TCP threshold</help>
                     </properties>
-                  </leafNode>
-                  <leafNode name="pps">
+                    <children>
+                      #include <include/ids/threshold.xml.i>
+                    </children>
+                  </node>
+                  <node name="udp">
                     <properties>
-                      <help>Packets per second</help>
-                      <valueHelp>
-                        <format>u32:0-4294967294</format>
-                        <description>Packets per second</description>
-                      </valueHelp>
-                      <constraint>
-                        <validator name="numeric" argument="--range 0-4294967294"/>
-                      </constraint>
+                      <help>UDP threshold</help>
                     </properties>
-                  </leafNode>
+                    <children>
+                      #include <include/ids/threshold.xml.i>
+                    </children>
+                  </node>
+                  <node name="icmp">
+                    <properties>
+                      <help>ICMP threshold</help>
+                    </properties>
+                    <children>
+                      #include <include/ids/threshold.xml.i>
+                    </children>
+                  </node>
                 </children>
               </node>
             </children>
           </node>
         </children>
       </node>
     </children>
   </node>
 </interfaceDefinition>
diff --git a/smoketest/scripts/cli/test_service_ids.py b/smoketest/scripts/cli/test_service_ids.py
index d471eeaed..dcf2bcefe 100755
--- a/smoketest/scripts/cli/test_service_ids.py
+++ b/smoketest/scripts/cli/test_service_ids.py
@@ -1,116 +1,116 @@
 #!/usr/bin/env python3
 #
 # Copyright (C) 2022 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 unittest
 
 from base_vyostest_shim import VyOSUnitTestSHIM
 
 from vyos.configsession import ConfigSessionError
 from vyos.util import process_named_running
 from vyos.util import read_file
 
 PROCESS_NAME = 'fastnetmon'
 FASTNETMON_CONF = '/run/fastnetmon/fastnetmon.conf'
 NETWORKS_CONF = '/run/fastnetmon/networks_list'
 EXCLUDED_NETWORKS_CONF = '/run/fastnetmon/excluded_networks_list'
 base_path = ['service', 'ids', 'ddos-protection']
 
 class TestServiceIDS(VyOSUnitTestSHIM.TestCase):
     @classmethod
     def setUpClass(cls):
         super(TestServiceIDS, cls).setUpClass()
 
         # ensure we can also run this test on a live system - so lets clean
         # out the current configuration :)
         cls.cli_delete(cls, base_path)
 
     def tearDown(self):
         # Check for running process
         self.assertTrue(process_named_running(PROCESS_NAME))
 
         # delete test config
         self.cli_delete(base_path)
         self.cli_commit()
 
         self.assertFalse(os.path.exists(FASTNETMON_CONF))
         self.assertFalse(process_named_running(PROCESS_NAME))
 
     def test_fastnetmon(self):
         networks = ['10.0.0.0/24', '10.5.5.0/24', '2001:db8:10::/64', '2001:db8:20::/64']
         excluded_networks = ['10.0.0.1/32', '2001:db8:10::1/128']
         interfaces = ['eth0', 'eth1']
         fps = '3500'
         mbps = '300'
         pps = '60000'
 
         self.cli_set(base_path + ['mode', 'mirror'])
         # Required network!
         with self.assertRaises(ConfigSessionError):
             self.cli_commit()
         for tmp in networks:
             self.cli_set(base_path + ['network', tmp])
 
         # optional excluded-network!
         with self.assertRaises(ConfigSessionError):
             self.cli_commit()
         for tmp in excluded_networks:
             self.cli_set(base_path + ['excluded-network', tmp])
 
         # Required interface(s)!
         with self.assertRaises(ConfigSessionError):
             self.cli_commit()
         for tmp in interfaces:
             self.cli_set(base_path + ['listen-interface', tmp])
 
         self.cli_set(base_path + ['direction', 'in'])
-        self.cli_set(base_path + ['threshold', 'fps', fps])
-        self.cli_set(base_path + ['threshold', 'pps', pps])
-        self.cli_set(base_path + ['threshold', 'mbps', mbps])
+        self.cli_set(base_path + ['threshold', 'general', 'fps', fps])
+        self.cli_set(base_path + ['threshold', 'general', 'pps', pps])
+        self.cli_set(base_path + ['threshold', 'general', 'mbps', mbps])
 
         # commit changes
         self.cli_commit()
 
         # Check configured port
         config = read_file(FASTNETMON_CONF)
         self.assertIn(f'mirror_afpacket = on', config)
         self.assertIn(f'process_incoming_traffic = on', config)
         self.assertIn(f'process_outgoing_traffic = off', config)
         self.assertIn(f'ban_for_flows = on', config)
         self.assertIn(f'threshold_flows = {fps}', config)
         self.assertIn(f'ban_for_bandwidth = on', config)
         self.assertIn(f'threshold_mbps = {mbps}', config)
         self.assertIn(f'ban_for_pps = on', config)
         self.assertIn(f'threshold_pps = {pps}', config)
         # default
         self.assertIn(f'enable_ban = on', config)
         self.assertIn(f'enable_ban_ipv6 = on', config)
         self.assertIn(f'ban_time = 1900', config)
 
         tmp = ','.join(interfaces)
         self.assertIn(f'interfaces = {tmp}', config)
 
 
         network_config = read_file(NETWORKS_CONF)
         for tmp in networks:
             self.assertIn(f'{tmp}', network_config)
 
         excluded_network_config = read_file(EXCLUDED_NETWORKS_CONF)
         for tmp in excluded_networks:
             self.assertIn(f'{tmp}', excluded_network_config)
 
 if __name__ == '__main__':
     unittest.main(verbosity=2)
diff --git a/src/migration-scripts/ids/0-to-1 b/src/migration-scripts/ids/0-to-1
new file mode 100755
index 000000000..9f08f7dc7
--- /dev/null
+++ b/src/migration-scripts/ids/0-to-1
@@ -0,0 +1,56 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2022 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/>.
+
+from sys import argv
+from sys import exit
+
+from vyos.configtree import ConfigTree
+
+if (len(argv) < 1):
+    print("Must specify file name!")
+    exit(1)
+
+file_name = argv[1]
+
+with open(file_name, 'r') as f:
+    config_file = f.read()
+
+base = ['service', 'ids', 'ddos-protection']
+config = ConfigTree(config_file)
+
+if not config.exists(base + ['threshold']):
+    # Nothing to do
+    exit(0)
+else:
+    if config.exists(base + ['threshold', 'fps']):
+        tmp = config.return_value(base + ['threshold', 'fps'])
+        config.delete(base + ['threshold', 'fps'])
+        config.set(base + ['threshold', 'general', 'fps'], value=tmp)
+    if config.exists(base + ['threshold', 'mbps']):
+        tmp = config.return_value(base + ['threshold', 'mbps'])
+        config.delete(base + ['threshold', 'mbps'])
+        config.set(base + ['threshold', 'general', 'mbps'], value=tmp)
+    if config.exists(base + ['threshold', 'pps']):
+        tmp = config.return_value(base + ['threshold', 'pps'])
+        config.delete(base + ['threshold', 'pps'])
+        config.set(base + ['threshold', 'general', 'pps'], value=tmp)
+
+try:
+    with open(file_name, 'w') as f:
+        f.write(config.to_string())
+except OSError as e:
+    print(f'Failed to save the modified config: {e}')
+    exit(1)