diff --git a/data/templates/frr/staticd.frr.j2 b/data/templates/frr/staticd.frr.j2
index 227807c62..90d17ec14 100644
--- a/data/templates/frr/staticd.frr.j2
+++ b/data/templates/frr/staticd.frr.j2
@@ -1,143 +1,143 @@
 {# Common macro for recurroiing options for a static route #}
 {% macro route_options(route, interface_or_next_hop, config, table) %}
 {# j2lint: disable=jinja-statements-delimeter #}
 {% set ip_route = route ~ ' ' ~ interface_or_next_hop %}
 {% if config.interface is vyos_defined %}
 {%     set ip_route = ip_route ~ ' ' ~ config.interface %}
 {% endif %}
 {% if config.tag is vyos_defined %}
 {%     set ip_route = ip_route ~ ' tag ' ~ config.tag %}
 {% endif %}
 {% if config.distance is vyos_defined %}
 {%     set ip_route = ip_route ~ ' ' ~ config.distance %}
 {% endif %}
 {% if config.bfd is vyos_defined %}
 {%     set ip_route = ip_route ~ ' bfd' %}
 {%     if config.bfd.multi_hop is vyos_defined %}
 {%         set ip_route = ip_route ~ ' multi-hop' %}
-{%         if config.bfd.source_address is vyos_defined %}
-{%             set ip_route = ip_route ~ ' source ' ~ config.bfd.source_address %}
+{%         if config.bfd.multi_hop.source_address is vyos_defined %}
+{%             set ip_route = ip_route ~ ' source ' ~ config.bfd.multi_hop.source_address %}
 {%         endif %}
 {%     endif %}
 {%     if config.bfd.profile is vyos_defined %}
 {%         set ip_route = ip_route ~ ' profile ' ~ config.bfd.profile %}
 {%     endif %}
 {% endif %}
 {% if config.vrf is vyos_defined %}
 {%     set ip_route = ip_route ~ ' nexthop-vrf ' ~ config.vrf %}
 {% endif %}
 {% if config.segments is vyos_defined %}
 {# Segments used in/for SRv6 #}
 {%     set ip_route = ip_route ~ ' segments ' ~ config.segments %}
 {% endif %}
 {# Routing table to configure #}
 {% if table is vyos_defined %}
 {%     set ip_route = ip_route ~ ' table ' ~ table %}
 {% endif %}
 {{ ip_route }}
 {%- endmacro -%}
 {# Build static IPv4/IPv6 route #}
 {% macro static_routes(ip_ipv6, prefix, prefix_config, table=None) %}
 {% set route = ip_ipv6 ~ 'route ' ~ prefix %}
 {% if prefix_config.interface is vyos_defined %}
 {%     for interface, interface_config in prefix_config.interface.items() if interface_config.disable is not defined %}
 {{ route_options(route, interface, interface_config, table) }}
 {%     endfor %}
 {% endif %}
 {% if prefix_config.next_hop is vyos_defined and prefix_config.next_hop is not none %}
 {%     for next_hop, next_hop_config in prefix_config.next_hop.items() if next_hop_config.disable is not defined %}
 {{ route_options(route, next_hop, next_hop_config, table) }}
 {%     endfor %}
 {% endif %}
 {% if prefix_config.dhcp_interface is vyos_defined %}
 {%     for dhcp_interface in prefix_config.dhcp_interface %}
 {%         set next_hop = dhcp_interface | get_dhcp_router %}
 {%         if next_hop is vyos_defined %}
 {{ ip_ipv6 }} route {{ prefix }} {{ next_hop }} {{ dhcp_interface }} {{ 'table ' ~ table if table is vyos_defined }}
 {%         endif %}
 {%     endfor %}
 {% endif %}
 {% if prefix_config.blackhole is vyos_defined %}
 {{ route_options(route, 'blackhole', prefix_config.blackhole, table) }}
 {% elif prefix_config.reject is vyos_defined %}
 {{ route_options(route, 'reject', prefix_config.reject, table) }}
 {% endif %}
 {# j2lint: disable=jinja-statements-delimeter #}
 {%- endmacro -%}
 !
 {% set ip_prefix = 'ip ' %}
 {% set ipv6_prefix = 'ipv6 ' %}
 {% if vrf is vyos_defined %}
 {#     We need to add an additional whitespace in front of the prefix #}
 {#     when VRFs are in use, thus we use a variable for prefix handling #}
 {%     set ip_prefix = ' ip ' %}
 {%     set ipv6_prefix = ' ipv6 ' %}
 vrf {{ vrf }}
 {% endif %}
 {# IPv4 routing #}
 {% if route is vyos_defined %}
 {%     for prefix, prefix_config in route.items() %}
 {{ static_routes(ip_prefix, prefix, prefix_config) }}
 {# j2lint: disable=jinja-statements-delimeter #}
 {%-    endfor %}
 {% endif %}
 {# IPv4 default routes from DHCP interfaces #}
 {% if dhcp is vyos_defined %}
 {%     for interface, interface_config in dhcp.items() if interface_config.dhcp_options.no_default_route is not vyos_defined %}
 {%         set next_hop = interface | get_dhcp_router %}
 {%         if next_hop is vyos_defined %}
 {{ ip_prefix }} route 0.0.0.0/0 {{ next_hop }} {{ interface }} tag 210 {{ interface_config.dhcp_options.default_route_distance if interface_config.dhcp_options.default_route_distance is vyos_defined }}
 {%         endif %}
 {%     endfor %}
 {% endif %}
 {# IPv4 default routes from PPPoE interfaces #}
 {% if pppoe is vyos_defined %}
 {%     for interface, interface_config in pppoe.items() if interface_config.no_default_route is not vyos_defined %}
 {{ ip_prefix }} route 0.0.0.0/0 {{ interface }} tag 210 {{ interface_config.default_route_distance if interface_config.default_route_distance is vyos_defined }}
 {%-    endfor %}
 {% endif %}
 {# IPv6 routing #}
 {% if route6 is vyos_defined %}
 {%     for prefix, prefix_config in route6.items() %}
 {{ static_routes(ipv6_prefix, prefix, prefix_config) }}
 {# j2lint: disable=jinja-statements-delimeter #}
 {%-    endfor %}
 {% endif %}
 {% if vrf is vyos_defined %}
 exit-vrf
 {% endif %}
 !
 {# Policy route tables #}
 {% if table is vyos_defined %}
 {%     for table_id, table_config in table.items() %}
 {%         if table_config.route is vyos_defined %}
 {%             for prefix, prefix_config in table_config.route.items() %}
 {{ static_routes('ip ', prefix, prefix_config, table_id) }}
 {# j2lint: disable=jinja-statements-delimeter #}
 {%-            endfor %}
 {%         endif %}
 !
 {%         if table_config.route6 is vyos_defined %}
 {%             for prefix, prefix_config in table_config.route6.items() %}
 {{ static_routes('ipv6 ', prefix, prefix_config, table_id) }}
 {# j2lint: disable=jinja-statements-delimeter #}
 {%-            endfor %}
 {%         endif %}
 !
 {%     endfor %}
 {% endif %}
 !
 {# Multicast route #}
 {% if mroute is vyos_defined %}
 {%     set ip_prefix = 'ip m' %}
 {# IPv4 multicast routing #}
 {%     for prefix, prefix_config in mroute.items() %}
 {{ static_routes(ip_prefix, prefix, prefix_config) }}
 {# j2lint: disable=jinja-statements-delimeter #}
 {%-    endfor %}
 {% endif %}
 !
 {% if route_map is vyos_defined %}
 ip protocol static route-map {{ route_map }}
 !
 {% endif %}
diff --git a/interface-definitions/include/static/bfd-multi-hop.xml.i b/interface-definitions/include/static/bfd-multi-hop.xml.i
deleted file mode 100644
index e53994191..000000000
--- a/interface-definitions/include/static/bfd-multi-hop.xml.i
+++ /dev/null
@@ -1,8 +0,0 @@
-<!-- include start from static/bfd-multi-hop.xml.i -->
-<leafNode name="multi-hop">
-  <properties>
-    <help>Enable BFD multi-hop session (requires source-address)</help>
-    <valueless/>
-  </properties>
-</leafNode>
-<!-- include end -->
diff --git a/interface-definitions/include/static/static-route.xml.i b/interface-definitions/include/static/static-route.xml.i
index fa1131118..fd7366286 100644
--- a/interface-definitions/include/static/static-route.xml.i
+++ b/interface-definitions/include/static/static-route.xml.i
@@ -1,68 +1,74 @@
 <!-- include start from static/static-route.xml.i -->
 <tagNode name="route">
   <properties>
     <help>Static IPv4 route</help>
     <valueHelp>
       <format>ipv4net</format>
       <description>IPv4 static route</description>
     </valueHelp>
     <constraint>
       <validator name="ipv4-prefix"/>
     </constraint>
   </properties>
   <children>
     #include <include/static/static-route-blackhole.xml.i>
     #include <include/static/static-route-reject.xml.i>
     #include <include/dhcp-interface-multi.xml.i>
     #include <include/generic-description.xml.i>
     <tagNode name="interface">
       <properties>
         <help>Next-hop IPv4 router interface</help>
         <completionHelp>
           <script>${vyos_completion_dir}/list_interfaces</script>
         </completionHelp>
         <valueHelp>
           <format>txt</format>
           <description>Gateway interface name</description>
         </valueHelp>
         <constraint>
           #include <include/constraint/interface-name.xml.i>
         </constraint>
       </properties>
       <children>
         #include <include/generic-disable-node.xml.i>
         #include <include/static/static-route-distance.xml.i>
         #include <include/static/static-route-vrf.xml.i>
       </children>
     </tagNode>
     <tagNode name="next-hop">
       <properties>
         <help>Next-hop IPv4 router address</help>
         <valueHelp>
           <format>ipv4</format>
           <description>Next-hop router address</description>
         </valueHelp>
         <constraint>
           <validator name="ipv4-address"/>
         </constraint>
       </properties>
       <children>
         #include <include/generic-disable-node.xml.i>
         #include <include/static/static-route-distance.xml.i>
         #include <include/static/static-route-interface.xml.i>
         #include <include/static/static-route-vrf.xml.i>
         <node name="bfd">
           <properties>
             <help>BFD monitoring</help>
           </properties>
           <children>
             #include <include/bfd/profile.xml.i>
-            #include <include/static/bfd-multi-hop.xml.i>
-            #include <include/source-address-ipv4.xml.i>
+            <node name="multi-hop">
+              <properties>
+                <help>Configure BFD multi-hop session</help>
+              </properties>
+              <children>
+                #include <include/source-address-ipv4.xml.i>
+              </children>
+            </node>
           </children>
         </node>
       </children>
     </tagNode>
   </children>
 </tagNode>
 <!-- include end -->
diff --git a/interface-definitions/include/static/static-route6.xml.i b/interface-definitions/include/static/static-route6.xml.i
index e75385dc7..6fcc18b8a 100644
--- a/interface-definitions/include/static/static-route6.xml.i
+++ b/interface-definitions/include/static/static-route6.xml.i
@@ -1,69 +1,75 @@
 <!-- include start from static/static-route6.xml.i -->
 <tagNode name="route6">
   <properties>
     <help>Static IPv6 route</help>
     <valueHelp>
       <format>ipv6net</format>
       <description>IPv6 static route</description>
     </valueHelp>
     <constraint>
       <validator name="ipv6-prefix"/>
     </constraint>
   </properties>
   <children>
     #include <include/static/static-route-blackhole.xml.i>
     #include <include/static/static-route-reject.xml.i>
     #include <include/generic-description.xml.i>
     <tagNode name="interface">
       <properties>
         <help>IPv6 gateway interface name</help>
         <completionHelp>
           <script>${vyos_completion_dir}/list_interfaces</script>
         </completionHelp>
         <valueHelp>
           <format>txt</format>
           <description>Gateway interface name</description>
         </valueHelp>
         <constraint>
           #include <include/constraint/interface-name.xml.i>
         </constraint>
       </properties>
       <children>
         #include <include/generic-disable-node.xml.i>
         #include <include/static/static-route-distance.xml.i>
         #include <include/static/static-route-segments.xml.i>
         #include <include/static/static-route-vrf.xml.i>
       </children>
     </tagNode>
     <tagNode name="next-hop">
       <properties>
         <help>IPv6 gateway address</help>
         <valueHelp>
           <format>ipv6</format>
           <description>Next-hop IPv6 router</description>
         </valueHelp>
         <constraint>
           <validator name="ipv6-address"/>
         </constraint>
       </properties>
       <children>
         #include <include/generic-disable-node.xml.i>
         #include <include/static/static-route-distance.xml.i>
         #include <include/static/static-route-interface.xml.i>
         #include <include/static/static-route-segments.xml.i>
         #include <include/static/static-route-vrf.xml.i>
         <node name="bfd">
           <properties>
             <help>BFD monitoring</help>
           </properties>
           <children>
             #include <include/bfd/profile.xml.i>
-            #include <include/static/bfd-multi-hop.xml.i>
-            #include <include/source-address-ipv6.xml.i>
+            <node name="multi-hop">
+              <properties>
+                <help>Configure BFD multi-hop session</help>
+              </properties>
+              <children>
+                #include <include/source-address-ipv6.xml.i>
+              </children>
+            </node>
           </children>
         </node>
       </children>
     </tagNode>
   </children>
 </tagNode>
 <!-- include end -->
diff --git a/interface-definitions/include/version/quagga-version.xml.i b/interface-definitions/include/version/quagga-version.xml.i
index 23d884cd4..10ca2816e 100644
--- a/interface-definitions/include/version/quagga-version.xml.i
+++ b/interface-definitions/include/version/quagga-version.xml.i
@@ -1,3 +1,3 @@
 <!-- include start from include/version/quagga-version.xml.i -->
-<syntaxVersion component='quagga' version='11'></syntaxVersion>
+<syntaxVersion component='quagga' version='12'></syntaxVersion>
 <!-- include end -->
diff --git a/smoketest/config-tests/static-route-basic b/smoketest/config-tests/static-route-basic
new file mode 100644
index 000000000..4416e6b19
--- /dev/null
+++ b/smoketest/config-tests/static-route-basic
@@ -0,0 +1,35 @@
+set interfaces ethernet eth0 duplex 'auto'
+set interfaces ethernet eth0 speed 'auto'
+set interfaces ethernet eth0 vif 203 address '172.18.203.10/24'
+set interfaces ethernet eth1 duplex 'auto'
+set interfaces ethernet eth1 speed 'auto'
+set protocols static route 10.0.0.0/8 blackhole distance '200'
+set protocols static route 10.0.0.0/8 blackhole tag '333'
+set protocols static route 10.0.0.0/8 next-hop 192.0.2.140 bfd multi-hop source-address '192.0.2.10'
+set protocols static route 10.0.0.0/8 next-hop 192.0.2.140 bfd profile 'vyos-test'
+set protocols static route 10.0.0.0/8 next-hop 192.0.2.140 distance '123'
+set protocols static route 10.0.0.0/8 next-hop 192.0.2.140 interface 'eth0'
+set protocols static route 172.16.0.0/16 next-hop 172.18.203.254 bfd multi-hop source-address '172.18.203.254'
+set protocols static route 172.16.0.0/16 next-hop 172.18.203.254 bfd profile 'foo'
+set protocols static route6 2001:db8:1::/48 next-hop fe80::1 bfd multi-hop source-address 'fe80::1'
+set protocols static route6 2001:db8:1::/48 next-hop fe80::1 bfd profile 'bar'
+set protocols static route6 2001:db8:1::/48 next-hop fe80::1 interface 'eth0.203'
+set protocols static route6 2001:db8:2::/48 next-hop fe80::1 bfd multi-hop source-address 'fe80::1'
+set protocols static route6 2001:db8:2::/48 next-hop fe80::1 bfd profile 'bar'
+set protocols static route6 2001:db8:2::/48 next-hop fe80::1 interface 'eth0.203'
+set protocols static route6 2001:db8:3::/48 next-hop fe80::1 bfd
+set protocols static route6 2001:db8:3::/48 next-hop fe80::1 interface 'eth0.203'
+set service lldp interface all
+set service ntp allow-client address '0.0.0.0/0'
+set service ntp allow-client address '::/0'
+set service ntp server 172.16.100.10
+set service ntp server 172.16.100.20
+set service ntp server 172.16.110.30
+set system config-management commit-revisions '100'
+set system console device ttyS0 speed '115200'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
+set system login user vyos authentication plaintext-password ''
+set system syslog global facility all level 'info'
+set system syslog global facility local7 level 'debug'
+set system time-zone 'Asia/Macau'
diff --git a/smoketest/configs/static-route-basic b/smoketest/configs/static-route-basic
new file mode 100644
index 000000000..4bf114e33
--- /dev/null
+++ b/smoketest/configs/static-route-basic
@@ -0,0 +1,148 @@
+interfaces {
+    ethernet eth0 {
+        duplex "auto"
+        speed "auto"
+        vif 203 {
+            address "172.18.203.10/24"
+        }
+    }
+    ethernet eth1 {
+        duplex "auto"
+        speed "auto"
+    }
+}
+protocols {
+    static {
+        multicast {
+            interface-route 224.0.0.0/24 {
+                next-hop-interface eth0.203 {
+                    distance "10"
+                }
+            }
+            route 224.0.0.0/24 {
+                next-hop 172.18.203.254 {
+                    distance "20"
+                }
+            }
+        }
+        route 10.0.0.0/8 {
+            blackhole {
+                distance "200"
+                tag "333"
+            }
+            next-hop 192.0.2.140 {
+                bfd {
+                    multi-hop {
+                        source 192.0.2.10 {
+                            profile "vyos-test"
+                        }
+                    }
+                }
+                distance "123"
+                interface "eth0"
+            }
+        }
+        route 172.16.0.0/16 {
+            next-hop 172.18.203.254 {
+                bfd {
+                    multi-hop {
+                        source 172.18.203.254 {
+                            profile "foo"
+                        }
+                    }
+                }
+            }
+        }
+        route6 2001:db8:1::/48 {
+            next-hop fe80::1 {
+                bfd {
+                    multi-hop {
+                        source fe80::1 {
+                            profile "bar"
+                        }
+                    }
+                }
+                interface eth0.203
+            }
+        }
+        route6 2001:db8:2::/48 {
+            next-hop fe80::1 {
+                bfd {
+                    multi-hop {
+                        source fe80::1 {
+                            profile "bar"
+                        }
+                    }
+                }
+                interface eth0.203
+            }
+        }
+        route6 2001:db8:3::/48 {
+            next-hop fe80::1 {
+                bfd {
+                }
+                interface eth0.203
+            }
+        }
+    }
+}
+service {
+    lldp {
+        interface all {
+        }
+    }
+    ntp {
+        allow-client {
+            address "0.0.0.0/0"
+            address "::/0"
+        }
+        server 172.16.100.10 {
+        }
+        server 172.16.100.20 {
+        }
+        server 172.16.110.30 {
+        }
+    }
+}
+system {
+    config-management {
+        commit-revisions 100
+    }
+    console {
+        device ttyS0 {
+            speed 115200
+        }
+    }
+    host-name vyos
+    login {
+        user vyos {
+            authentication {
+                encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0
+                plaintext-password ""
+            }
+        }
+    }
+    ntp {
+        server 0.pool.ntp.org {
+        }
+        server 1.pool.ntp.org {
+        }
+        server 2.pool.ntp.org {
+        }
+    }
+    syslog {
+        global {
+            facility all {
+                level info
+            }
+            facility local7 {
+                level debug
+            }
+        }
+    }
+    time-zone "Asia/Macau"
+}
+
+// Warning: Do not remove the following line.
+// vyos-config-version: "bgp@5:broadcast-relay@1:cluster@2:config-management@1:conntrack@5:conntrack-sync@2:container@2:dhcp-relay@2:dhcp-server@8:dhcpv6-server@1:dns-dynamic@4:dns-forwarding@4:firewall@15:flow-accounting@1:https@6:ids@1:interfaces@32:ipoe-server@3:ipsec@13:isis@3:l2tp@9:lldp@2:mdns@1:monitoring@1:nat@8:nat66@3:ntp@3:openconnect@3:ospf@2:pim@1:policy@8:pppoe-server@10:pptp@5:qos@2:quagga@11:reverse-proxy@1:rip@1:rpki@2:salt@1:snmp@3:ssh@2:sstp@6:system@27:vrf@3:vrrp@4:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2"
+// Release version: 1.4.0
diff --git a/smoketest/scripts/cli/test_protocols_static.py b/smoketest/scripts/cli/test_protocols_static.py
index 086235086..a2cde0237 100755
--- a/smoketest/scripts/cli/test_protocols_static.py
+++ b/smoketest/scripts/cli/test_protocols_static.py
@@ -1,572 +1,571 @@
 #!/usr/bin/env python3
 #
 # Copyright (C) 2021-2024 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 unittest
 
 from base_vyostest_shim import VyOSUnitTestSHIM
 
 from vyos.configsession import ConfigSessionError
 from vyos.template import is_ipv6
 from vyos.utils.network import get_interface_config
 from vyos.utils.network import get_vrf_tableid
 
 base_path = ['protocols', 'static']
 vrf_path =  ['protocols', 'vrf']
 
 routes = {
     '10.0.0.0/8' : {
         'next_hop' : {
             '192.0.2.100' : { 'distance' : '100' },
             '192.0.2.110' : { 'distance' : '110', 'interface' : 'eth0' },
             '192.0.2.120' : { 'distance' : '120', 'disable' : '' },
             '192.0.2.130' : { 'bfd' : '' },
             '192.0.2.131' : { 'bfd' : '',
                               'bfd_profile' : 'vyos1' },
             '192.0.2.140' : { 'bfd' : '',
                               'bfd_source' : '192.0.2.10',
                               'bfd_profile' : 'vyos2' },
         },
         'interface' : {
             'eth0'  : { 'distance' : '130' },
             'eth1'  : { 'distance' : '140' },
         },
         'blackhole' : { 'distance' : '250', 'tag' : '500' },
     },
     '172.16.0.0/12' : {
         'interface' : {
             'eth0'  : { 'distance' : '50', 'vrf' : 'black' },
             'eth1'  : { 'distance' : '60', 'vrf' : 'black' },
         },
         'blackhole' : { 'distance' : '90' },
     },
     '192.0.2.0/24' : {
         'interface' : {
             'eth0'  : { 'distance' : '50', 'vrf' : 'black' },
             'eth1'  : { 'disable' : '' },
         },
         'blackhole' : { 'distance' : '90' },
     },
     '100.64.0.0/16' : {
         'blackhole' : {},
     },
     '100.65.0.0/16' : {
         'reject'    : { 'distance' : '10', 'tag' : '200' },
     },
     '100.66.0.0/16' : {
         'blackhole' : {},
         'reject'    : { 'distance' : '10', 'tag' : '200' },
     },
     '2001:db8:100::/40' : {
         'next_hop' : {
             '2001:db8::1' : { 'distance' : '10' },
             '2001:db8::2' : { 'distance' : '20', 'interface' : 'eth0' },
             '2001:db8::3' : { 'distance' : '30', 'disable' : '' },
             '2001:db8::4' : { 'bfd' : '' },
             '2001:db8::5' : { 'bfd_source' : '2001:db8::ffff' },
         },
         'interface' : {
             'eth0'  : { 'distance' : '40', 'vrf' : 'black' },
             'eth1'  : { 'distance' : '50', 'disable' : '' },
         },
         'blackhole' : { 'distance' : '250', 'tag' : '500' },
     },
     '2001:db8:200::/40' : {
         'interface' : {
             'eth0'  : { 'distance' : '40' },
             'eth1'  : { 'distance' : '50', 'disable' : '' },
         },
         'blackhole' : { 'distance' : '250', 'tag' : '500' },
     },
     '2001:db8:300::/40' : {
         'reject'    : { 'distance' : '250', 'tag' : '500' },
     },
     '2001:db8:400::/40' : {
         'next_hop' : {
             '2001:db8::400' : { 'segments' : '2001:db8:aaaa::400/2002::400/2003::400/2004::400' },
         },
     },
     '2001:db8:500::/40' : {
         'next_hop' : {
             '2001:db8::500' : { 'segments' : '2001:db8:aaaa::500/2002::500/2003::500/2004::500' },
         },
     },
     '2001:db8:600::/40' : {
         'interface' : {
             'eth0'  : { 'segments' : '2001:db8:aaaa::600/2002::600' },
         },
     },
     '2001:db8:700::/40' : {
         'interface' : {
             'eth1'  : { 'segments' : '2001:db8:aaaa::700' },
         },
     },
     '2001:db8::/32' : {
         'blackhole' : { 'distance' : '200', 'tag' : '600' }
     },
 }
 
 multicast_routes = {
     '224.0.0.0/24' : {
         'next_hop' : {
             '224.203.0.1' : { },
             '224.203.0.2' : { 'distance' : '110'},
         },
     },
     '224.1.0.0/24' : {
         'next_hop' : {
             '224.205.0.1' : { 'disable' : {} },
             '224.205.0.2' : { 'distance' : '110'},
         },
     },
     '224.2.0.0/24' : {
         'next_hop' : {
             '1.2.3.0' : { },
             '1.2.3.1' : { 'distance' : '110'},
         },
     },
     '224.10.0.0/24' : {
         'interface' : {
             'eth1' : { 'disable' : {} },
             'eth2' : { 'distance' : '110'},
         },
     },
     '224.11.0.0/24' : {
         'interface' : {
             'eth0' : { },
             'eth1' : { 'distance' : '10'},
         },
     },
     '224.12.0.0/24' : {
         'interface' : {
             'eth0' : { },
             'eth1' : { 'distance' : '200'},
         },
     },
 }
 
 tables = ['80', '81', '82']
 
 class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase):
     @classmethod
     def setUpClass(cls):
         super(TestProtocolsStatic, cls).setUpClass()
         cls.cli_delete(cls, ['vrf'])
         cls.cli_set(cls, ['vrf', 'name', 'black', 'table', '43210'])
 
     @classmethod
     def tearDownClass(cls):
         cls.cli_delete(cls, ['vrf'])
         super(TestProtocolsStatic, cls).tearDownClass()
 
     def tearDown(self):
         self.cli_delete(base_path)
         self.cli_commit()
 
         v4route = self.getFRRconfig('ip route', end='')
         self.assertFalse(v4route)
         v6route = self.getFRRconfig('ipv6 route', end='')
         self.assertFalse(v6route)
 
     def test_01_static(self):
         for route, route_config in routes.items():
             route_type = 'route'
             if is_ipv6(route):
                 route_type = 'route6'
             base = base_path + [route_type, route]
             if 'next_hop' in route_config:
                 for next_hop, next_hop_config in route_config['next_hop'].items():
                     self.cli_set(base + ['next-hop', next_hop])
                     if 'disable' in next_hop_config:
                         self.cli_set(base + ['next-hop', next_hop, 'disable'])
                     if 'distance' in next_hop_config:
                         self.cli_set(base + ['next-hop', next_hop, 'distance', next_hop_config['distance']])
                     if 'interface' in next_hop_config:
                         self.cli_set(base + ['next-hop', next_hop, 'interface', next_hop_config['interface']])
                     if 'vrf' in next_hop_config:
                         self.cli_set(base + ['next-hop', next_hop, 'vrf', next_hop_config['vrf']])
                     if 'bfd' in next_hop_config:
                         self.cli_set(base + ['next-hop', next_hop, 'bfd'])
                         if 'bfd_profile' in next_hop_config:
                             self.cli_set(base + ['next-hop', next_hop, 'bfd', 'profile', next_hop_config['bfd_profile']])
                         if 'bfd_source' in next_hop_config:
-                            self.cli_set(base + ['next-hop', next_hop, 'bfd', 'multi-hop'])
-                            self.cli_set(base + ['next-hop', next_hop, 'bfd', 'source-address', next_hop_config['bfd_source']])
+                            self.cli_set(base + ['next-hop', next_hop, 'bfd', 'multi-hop', 'source-address', next_hop_config['bfd_source']])
                     if 'segments' in next_hop_config:
                         self.cli_set(base + ['next-hop', next_hop, 'segments', next_hop_config['segments']])
 
             if 'interface' in route_config:
                 for interface, interface_config in route_config['interface'].items():
                     self.cli_set(base + ['interface', interface])
                     if 'disable' in interface_config:
                         self.cli_set(base + ['interface', interface, 'disable'])
                     if 'distance' in interface_config:
                         self.cli_set(base + ['interface', interface, 'distance', interface_config['distance']])
                     if 'vrf' in interface_config:
                         self.cli_set(base + ['interface', interface, 'vrf', interface_config['vrf']])
                     if 'segments' in interface_config:
                         self.cli_set(base + ['interface', interface, 'segments', interface_config['segments']])
 
             if 'blackhole' in route_config:
                 self.cli_set(base + ['blackhole'])
                 if 'distance' in route_config['blackhole']:
                     self.cli_set(base + ['blackhole', 'distance', route_config['blackhole']['distance']])
                 if 'tag' in route_config['blackhole']:
                     self.cli_set(base + ['blackhole', 'tag', route_config['blackhole']['tag']])
 
             if 'reject' in route_config:
                 self.cli_set(base + ['reject'])
                 if 'distance' in route_config['reject']:
                     self.cli_set(base + ['reject', 'distance', route_config['reject']['distance']])
                 if 'tag' in route_config['reject']:
                     self.cli_set(base + ['reject', 'tag', route_config['reject']['tag']])
 
             if {'blackhole', 'reject'} <= set(route_config):
                 # Can not use blackhole and reject at the same time
                 with self.assertRaises(ConfigSessionError):
                     self.cli_commit()
                 self.cli_delete(base + ['blackhole'])
                 self.cli_delete(base + ['reject'])
 
         # commit changes
         self.cli_commit()
 
         # Verify FRR bgpd configuration
         frrconfig = self.getFRRconfig('ip route', end='')
 
         # Verify routes
         for route, route_config in routes.items():
             ip_ipv6 = 'ip'
             if is_ipv6(route):
                 ip_ipv6 = 'ipv6'
 
             if 'next_hop' in route_config:
                 for next_hop, next_hop_config in route_config['next_hop'].items():
                     tmp = f'{ip_ipv6} route {route} {next_hop}'
                     if 'interface' in next_hop_config:
                         tmp += ' ' + next_hop_config['interface']
                     if 'distance' in next_hop_config:
                         tmp += ' ' + next_hop_config['distance']
                     if 'vrf' in next_hop_config:
                         tmp += ' nexthop-vrf ' + next_hop_config['vrf']
                     if 'bfd' in next_hop_config:
                         tmp += ' bfd'
                         if 'bfd_source' in next_hop_config:
                             tmp += ' multi-hop source ' + next_hop_config['bfd_source']
                         if 'bfd_profile' in next_hop_config:
                             tmp += ' profile ' + next_hop_config['bfd_profile']
                     if 'segments' in next_hop_config:
                         tmp += ' segments ' + next_hop_config['segments']
 
                     if 'disable' in next_hop_config:
                         self.assertNotIn(tmp, frrconfig)
                     else:
                         self.assertIn(tmp, frrconfig)
 
             if 'interface' in route_config:
                 for interface, interface_config in route_config['interface'].items():
                     tmp = f'{ip_ipv6} route {route} {interface}'
                     if 'interface' in interface_config:
                         tmp += ' ' + interface_config['interface']
                     if 'distance' in interface_config:
                         tmp += ' ' + interface_config['distance']
                     if 'vrf' in interface_config:
                         tmp += ' nexthop-vrf ' + interface_config['vrf']
                     if 'segments' in interface_config:
                         tmp += ' segments ' + interface_config['segments']
 
                     if 'disable' in interface_config:
                         self.assertNotIn(tmp, frrconfig)
                     else:
                         self.assertIn(tmp, frrconfig)
 
             if {'blackhole', 'reject'} <= set(route_config):
                 # Can not use blackhole and reject at the same time
                 # Config error validated above - skip this route
                 continue
 
             if 'blackhole' in route_config:
                 tmp = f'{ip_ipv6} route {route} blackhole'
                 if 'tag' in route_config['blackhole']:
                     tmp += ' tag ' + route_config['blackhole']['tag']
                 if 'distance' in route_config['blackhole']:
                     tmp += ' ' + route_config['blackhole']['distance']
 
                 self.assertIn(tmp, frrconfig)
 
             if 'reject' in route_config:
                 tmp = f'{ip_ipv6} route {route} reject'
                 if 'tag' in route_config['reject']:
                     tmp += ' tag ' + route_config['reject']['tag']
                 if 'distance' in route_config['reject']:
                     tmp += ' ' + route_config['reject']['distance']
 
                 self.assertIn(tmp, frrconfig)
 
     def test_02_static_table(self):
         for table in tables:
             for route, route_config in routes.items():
                 route_type = 'route'
                 if is_ipv6(route):
                     route_type = 'route6'
                 base = base_path + ['table', table, route_type, route]
 
                 if 'next_hop' in route_config:
                     for next_hop, next_hop_config in route_config['next_hop'].items():
                         self.cli_set(base + ['next-hop', next_hop])
                         if 'disable' in next_hop_config:
                             self.cli_set(base + ['next-hop', next_hop, 'disable'])
                         if 'distance' in next_hop_config:
                             self.cli_set(base + ['next-hop', next_hop, 'distance', next_hop_config['distance']])
                         if 'interface' in next_hop_config:
                             self.cli_set(base + ['next-hop', next_hop, 'interface', next_hop_config['interface']])
                         if 'vrf' in next_hop_config:
                             self.cli_set(base + ['next-hop', next_hop, 'vrf', next_hop_config['vrf']])
 
 
                 if 'interface' in route_config:
                     for interface, interface_config in route_config['interface'].items():
                         self.cli_set(base + ['interface', interface])
                         if 'disable' in interface_config:
                             self.cli_set(base + ['interface', interface, 'disable'])
                         if 'distance' in interface_config:
                             self.cli_set(base + ['interface', interface, 'distance', interface_config['distance']])
                         if 'vrf' in interface_config:
                             self.cli_set(base + ['interface', interface, 'vrf', interface_config['vrf']])
 
                 if 'blackhole' in route_config:
                     self.cli_set(base + ['blackhole'])
                     if 'distance' in route_config['blackhole']:
                         self.cli_set(base + ['blackhole', 'distance', route_config['blackhole']['distance']])
                     if 'tag' in route_config['blackhole']:
                         self.cli_set(base + ['blackhole', 'tag', route_config['blackhole']['tag']])
 
         # commit changes
         self.cli_commit()
 
         # Verify FRR bgpd configuration
         frrconfig = self.getFRRconfig('ip route', end='')
 
         for table in tables:
             # Verify routes
             for route, route_config in routes.items():
                 ip_ipv6 = 'ip'
                 if is_ipv6(route):
                     ip_ipv6 = 'ipv6'
 
                 if 'next_hop' in route_config:
                     for next_hop, next_hop_config in route_config['next_hop'].items():
                         tmp = f'{ip_ipv6} route {route} {next_hop}'
                         if 'interface' in next_hop_config:
                             tmp += ' ' + next_hop_config['interface']
                         if 'distance' in next_hop_config:
                             tmp += ' ' + next_hop_config['distance']
                         if 'vrf' in next_hop_config:
                             tmp += ' nexthop-vrf ' + next_hop_config['vrf']
 
                         tmp += ' table ' + table
                         if 'disable' in next_hop_config:
                             self.assertNotIn(tmp, frrconfig)
                         else:
                             self.assertIn(tmp, frrconfig)
 
                 if 'interface' in route_config:
                     for interface, interface_config in route_config['interface'].items():
                         tmp = f'{ip_ipv6} route {route} {interface}'
                         if 'interface' in interface_config:
                             tmp += ' ' + interface_config['interface']
                         if 'distance' in interface_config:
                             tmp += ' ' + interface_config['distance']
                         if 'vrf' in interface_config:
                             tmp += ' nexthop-vrf ' + interface_config['vrf']
 
                         tmp += ' table ' + table
                         if 'disable' in interface_config:
                             self.assertNotIn(tmp, frrconfig)
                         else:
                             self.assertIn(tmp, frrconfig)
 
                 if 'blackhole' in route_config:
                     tmp = f'{ip_ipv6} route {route} blackhole'
                     if 'tag' in route_config['blackhole']:
                         tmp += ' tag ' + route_config['blackhole']['tag']
                     if 'distance' in route_config['blackhole']:
                         tmp += ' ' + route_config['blackhole']['distance']
 
                     tmp += ' table ' + table
                     self.assertIn(tmp, frrconfig)
 
 
     def test_03_static_vrf(self):
         # Create VRF instances and apply the static routes from above to FRR.
         # Re-read the configured routes and match them if they are programmed
         # properly. This also includes VRF leaking
         vrfs = {
             'red'   : { 'table' : '1000' },
             'green' : { 'table' : '2000' },
             'blue'  : { 'table' : '3000' },
         }
 
         for vrf, vrf_config in vrfs.items():
             vrf_base_path = ['vrf', 'name', vrf]
             self.cli_set(vrf_base_path + ['table', vrf_config['table']])
 
             for route, route_config in routes.items():
                 route_type = 'route'
                 if is_ipv6(route):
                     route_type = 'route6'
                 route_base_path = vrf_base_path + ['protocols', 'static', route_type, route]
 
                 if 'next_hop' in route_config:
                     for next_hop, next_hop_config in route_config['next_hop'].items():
                         self.cli_set(route_base_path + ['next-hop', next_hop])
                         if 'disable' in next_hop_config:
                             self.cli_set(route_base_path + ['next-hop', next_hop, 'disable'])
                         if 'distance' in next_hop_config:
                             self.cli_set(route_base_path + ['next-hop', next_hop, 'distance', next_hop_config['distance']])
                         if 'interface' in next_hop_config:
                             self.cli_set(route_base_path + ['next-hop', next_hop, 'interface', next_hop_config['interface']])
                         if 'vrf' in next_hop_config:
                             self.cli_set(route_base_path + ['next-hop', next_hop, 'vrf', next_hop_config['vrf']])
                         if 'segments' in next_hop_config:
                             self.cli_set(route_base_path + ['next-hop', next_hop, 'segments', next_hop_config['segments']])
 
                 if 'interface' in route_config:
                     for interface, interface_config in route_config['interface'].items():
                         self.cli_set(route_base_path + ['interface', interface])
                         if 'disable' in interface_config:
                             self.cli_set(route_base_path + ['interface', interface, 'disable'])
                         if 'distance' in interface_config:
                             self.cli_set(route_base_path + ['interface', interface, 'distance', interface_config['distance']])
                         if 'vrf' in interface_config:
                             self.cli_set(route_base_path + ['interface', interface, 'vrf', interface_config['vrf']])
                         if 'segments' in interface_config:
                             self.cli_set(route_base_path + ['interface', interface, 'segments', interface_config['segments']])
 
                 if 'blackhole' in route_config:
                     self.cli_set(route_base_path + ['blackhole'])
                     if 'distance' in route_config['blackhole']:
                         self.cli_set(route_base_path + ['blackhole', 'distance', route_config['blackhole']['distance']])
                     if 'tag' in route_config['blackhole']:
                         self.cli_set(route_base_path + ['blackhole', 'tag', route_config['blackhole']['tag']])
 
         # commit changes
         self.cli_commit()
 
         for vrf, vrf_config in vrfs.items():
             tmp = get_interface_config(vrf)
 
             # Compare VRF table ID
             self.assertEqual(get_vrf_tableid(vrf), int(vrf_config['table']))
             self.assertEqual(tmp['linkinfo']['info_kind'],          'vrf')
 
             # Verify FRR bgpd configuration
             frrconfig = self.getFRRconfig(f'vrf {vrf}', endsection='^exit-vrf')
             self.assertIn(f'vrf {vrf}', frrconfig)
 
             # Verify routes
             for route, route_config in routes.items():
                 ip_ipv6 = 'ip'
                 if is_ipv6(route):
                     ip_ipv6 = 'ipv6'
 
                 if 'next_hop' in route_config:
                     for next_hop, next_hop_config in route_config['next_hop'].items():
                         tmp = f'{ip_ipv6} route {route} {next_hop}'
                         if 'interface' in next_hop_config:
                             tmp += ' ' + next_hop_config['interface']
                         if 'distance' in next_hop_config:
                             tmp += ' ' + next_hop_config['distance']
                         if 'vrf' in next_hop_config:
                             tmp += ' nexthop-vrf ' + next_hop_config['vrf']
                         if 'segments' in next_hop_config:
                             tmp += ' segments ' + next_hop_config['segments']
 
                         if 'disable' in next_hop_config:
                             self.assertNotIn(tmp, frrconfig)
                         else:
                             self.assertIn(tmp, frrconfig)
 
                 if 'interface' in route_config:
                     for interface, interface_config in route_config['interface'].items():
                         tmp = f'{ip_ipv6} route {route} {interface}'
                         if 'interface' in interface_config:
                             tmp += ' ' + interface_config['interface']
                         if 'distance' in interface_config:
                             tmp += ' ' + interface_config['distance']
                         if 'vrf' in interface_config:
                             tmp += ' nexthop-vrf ' + interface_config['vrf']
                         if 'segments' in interface_config:
                             tmp += ' segments ' + interface_config['segments']
 
                         if 'disable' in interface_config:
                             self.assertNotIn(tmp, frrconfig)
                         else:
                             self.assertIn(tmp, frrconfig)
 
                 if 'blackhole' in route_config:
                     tmp = f'{ip_ipv6} route {route} blackhole'
                     if 'tag' in route_config['blackhole']:
                         tmp += ' tag ' + route_config['blackhole']['tag']
                     if 'distance' in route_config['blackhole']:
                         tmp += ' ' + route_config['blackhole']['distance']
 
                     self.assertIn(tmp, frrconfig)
 
     def test_04_static_multicast(self):
         for route, route_config in multicast_routes.items():
             if 'next_hop' in route_config:
                 base = base_path + ['mroute', route]
                 for next_hop, next_hop_config in route_config['next_hop'].items():
                     self.cli_set(base + ['next-hop', next_hop])
                     if 'distance' in next_hop_config:
                         self.cli_set(base + ['next-hop', next_hop, 'distance', next_hop_config['distance']])
                     if 'disable' in next_hop_config:
                         self.cli_set(base + ['next-hop', next_hop, 'disable'])
 
             if 'interface' in route_config:
                 base = base_path + ['mroute', route]
                 for next_hop, next_hop_config in route_config['interface'].items():
                     self.cli_set(base + ['interface', next_hop])
                     if 'distance' in next_hop_config:
                         self.cli_set(base + ['interface', next_hop, 'distance', next_hop_config['distance']])
 
         self.cli_commit()
 
         # Verify FRR configuration
         frrconfig = self.getFRRconfig('ip mroute', end='')
         for route, route_config in multicast_routes.items():
             if 'next_hop' in route_config:
                 for next_hop, next_hop_config in route_config['next_hop'].items():
                     tmp = f'ip mroute {route} {next_hop}'
                     if 'distance' in next_hop_config:
                         tmp += ' ' + next_hop_config['distance']
                     if 'disable' in next_hop_config:
                         self.assertNotIn(tmp, frrconfig)
                     else:
                         self.assertIn(tmp, frrconfig)
 
             if 'next_hop_interface' in route_config:
                 for next_hop, next_hop_config in route_config['next_hop_interface'].items():
                     tmp = f'ip mroute {route} {next_hop}'
                     if 'distance' in next_hop_config:
                         tmp += ' ' + next_hop_config['distance']
                     if 'disable' in next_hop_config:
                         self.assertNotIn(tmp, frrconfig)
                     else:
                         self.assertIn(tmp, frrconfig)
 
 if __name__ == '__main__':
     unittest.main(verbosity=2)
diff --git a/src/migration-scripts/quagga/11-to-12 b/src/migration-scripts/quagga/11-to-12
new file mode 100644
index 000000000..becc44162
--- /dev/null
+++ b/src/migration-scripts/quagga/11-to-12
@@ -0,0 +1,54 @@
+# Copyright 2024 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/>.
+
+# T6747:
+#   - Migrate static BFD configuration to match FRR possibillities
+#   - Consolidate static multicast routing configuration under a new node
+
+from vyos.configtree import ConfigTree
+
+static_base = ['protocols', 'static']
+
+def migrate(config: ConfigTree) -> None:
+    # Check for static route/route6 configuration
+    for route_route6 in ['route', 'route6']:
+        route_route6_base = static_base + [route_route6]
+        if not config.exists(route_route6_base):
+            continue
+
+        for prefix in config.list_nodes(route_route6_base):
+            next_hop_base = route_route6_base + [prefix, 'next-hop']
+            if not config.exists(next_hop_base):
+                continue
+
+            for next_hop in config.list_nodes(next_hop_base):
+                multi_hop_base = next_hop_base + [next_hop, 'bfd', 'multi-hop']
+
+                if not config.exists(multi_hop_base):
+                    continue
+
+                mh_source_base = multi_hop_base + ['source']
+                source = None
+                profile = None
+                for src_ip in config.list_nodes(mh_source_base):
+                    source = src_ip
+                    if config.exists(mh_source_base + [source, 'profile']):
+                        profile = config.return_value(mh_source_base + [source, 'profile'])
+                    # FRR only supports one source, we will use the first one
+                    break
+
+                config.delete(multi_hop_base)
+                config.set(multi_hop_base + ['source-address'], value=source)
+                config.set(next_hop_base + [next_hop, 'bfd', 'profile'], value=profile)