From fff6004d46c5b939800fc3e61fe2102224625c0d Mon Sep 17 00:00:00 2001
From: Christian Breunig <christian@breunig.cc>
Date: Wed, 7 Feb 2024 21:01:27 +0100
Subject: bgp: T6024: add additional missing FRR features

* set protocols bgp parameters labeled-unicast <explicit-null | ipv4-explicit-null | ipv6-explicit-null>
* set protocols bgp parameters allow-martian-nexthop
* set protocols bgp parameters no-hard-administrative-reset"
---
 data/templates/frr/bgpd.frr.j2                     | 18 +++++++--
 .../bgp/neighbor-afi-ipv4-ipv6-common.xml.i        |  1 -
 .../include/bgp/protocol-common-config.xml.i       | 35 ++++++++++++++++++
 smoketest/scripts/cli/test_protocols_bgp.py        | 43 +++++++++++++++-------
 4 files changed, 79 insertions(+), 18 deletions(-)

diff --git a/data/templates/frr/bgpd.frr.j2 b/data/templates/frr/bgpd.frr.j2
index e02fdd1bb..23f81348b 100644
--- a/data/templates/frr/bgpd.frr.j2
+++ b/data/templates/frr/bgpd.frr.j2
@@ -225,10 +225,10 @@
   neighbor {{ neighbor }} route-map {{ afi_config.route_map.import }} in
 {%         endif %}
 {%         if afi_config.prefix_list.export is vyos_defined %}
-  neighbor {{ neighbor }} prefix-list  {{ afi_config.prefix_list.export }} out
+  neighbor {{ neighbor }} prefix-list {{ afi_config.prefix_list.export }} out
 {%         endif %}
 {%         if afi_config.prefix_list.import is vyos_defined %}
-  neighbor {{ neighbor }} prefix-list  {{ afi_config.prefix_list.import }} in
+  neighbor {{ neighbor }} prefix-list {{ afi_config.prefix_list.import }} in
 {%         endif %}
 {%         if afi_config.soft_reconfiguration.inbound is vyos_defined %}
   neighbor {{ neighbor }} soft-reconfiguration inbound
@@ -237,10 +237,10 @@
   neighbor {{ neighbor }} unsuppress-map {{ afi_config.unsuppress_map }}
 {%         endif %}
 {%         if afi_config.disable_send_community.extended is vyos_defined %}
- no neighbor {{ neighbor }} send-community extended
+  no neighbor {{ neighbor }} send-community extended
 {%         endif %}
 {%         if afi_config.disable_send_community.standard is vyos_defined %}
- no neighbor {{ neighbor }} send-community standard
+  no neighbor {{ neighbor }} send-community standard
 {%         endif %}
   neighbor {{ neighbor }} activate
  exit-address-family
@@ -473,6 +473,7 @@ router bgp {{ system_as }} {{ 'vrf ' ~ vrf if vrf is vyos_defined }}
 {%             endfor %}
 {%         endif %}
  exit-address-family
+ !
 {%     endfor %}
 {% endif %}
  !
@@ -530,6 +531,9 @@ router bgp {{ system_as }} {{ 'vrf ' ~ vrf if vrf is vyos_defined }}
 {%         endif %}
 {%     endfor %}
 {% endif %}
+{% if parameters.allow_martian_nexthop is vyos_defined %}
+ bgp allow-martian-nexthop
+{% endif %}
 {% if parameters.always_compare_med is vyos_defined %}
  bgp always-compare-med
 {% endif %}
@@ -590,6 +594,12 @@ router bgp {{ system_as }} {{ 'vrf ' ~ vrf if vrf is vyos_defined }}
 {% if parameters.graceful_shutdown is vyos_defined %}
  bgp graceful-shutdown
 {% endif %}
+{% if parameters.no_hard_administrative_reset is vyos_defined %}
+ no bgp hard-administrative-reset
+{% endif %}
+{% if parameters.labeled_unicast is vyos_defined %}
+ bgp labeled-unicast {{ parameters.labeled_unicast }}
+{% endif %}
 {% if parameters.log_neighbor_changes is vyos_defined %}
  bgp log-neighbor-changes
 {% endif %}
diff --git a/interface-definitions/include/bgp/neighbor-afi-ipv4-ipv6-common.xml.i b/interface-definitions/include/bgp/neighbor-afi-ipv4-ipv6-common.xml.i
index c8ad68700..a433f7cc6 100644
--- a/interface-definitions/include/bgp/neighbor-afi-ipv4-ipv6-common.xml.i
+++ b/interface-definitions/include/bgp/neighbor-afi-ipv4-ipv6-common.xml.i
@@ -1,5 +1,4 @@
 <!-- include start from bgp/neighbor-afi-ipv4-ipv6-common.xml.i -->
-
 <leafNode name="addpath-tx-all">
   <properties>
     <help>Use addpath to advertise all paths to a neighbor</help>
diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i
index 9895b025c..ea6e75bbd 100644
--- a/interface-definitions/include/bgp/protocol-common-config.xml.i
+++ b/interface-definitions/include/bgp/protocol-common-config.xml.i
@@ -1219,6 +1219,12 @@
     <help>BGP parameters</help>
   </properties>
   <children>
+    <leafNode name="allow-martian-nexthop">
+      <properties>
+        <help>Allow Martian nexthops to be received in the NLRI from a peer</help>
+        <valueless/>
+      </properties>
+    </leafNode>
     <leafNode name="always-compare-med">
       <properties>
         <help>Always compare MEDs from different neighbors</help>
@@ -1576,6 +1582,35 @@
         <valueless/>
       </properties>
     </leafNode>
+    <leafNode name="no-hard-administrative-reset">
+      <properties>
+        <help>Do not send hard reset CEASE Notification for 'Administrative Reset'</help>
+        <valueless/>
+      </properties>
+    </leafNode>
+    <leafNode name="labeled-unicast">
+      <properties>
+        <help>BGP Labeled-unicast options</help>
+        <completionHelp>
+          <list>explicit-null ipv4-explicit-null ipv6-explicit-null</list>
+        </completionHelp>
+        <valueHelp>
+          <format>explicit-null</format>
+          <description>Use explicit-null label values for all local prefixes</description>
+        </valueHelp>
+        <valueHelp>
+          <format>ipv4-explicit-null</format>
+          <description>Use IPv4 explicit-null label value for IPv4 local prefixes</description>
+        </valueHelp>
+        <valueHelp>
+          <format>ipv6-explicit-null</format>
+          <description>Use IPv6 explicit-null label value for IPv4 local prefixes</description>
+        </valueHelp>
+        <constraint>
+          <regex>(explicit-null|ipv4-explicit-null|ipv6-explicit-null)</regex>
+        </constraint>
+      </properties>
+    </leafNode>
     <leafNode name="log-neighbor-changes">
       <properties>
         <help>Log neighbor up/down changes and reset reason</help>
diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py
index 2dbc30a41..08a6e1696 100755
--- a/smoketest/scripts/cli/test_protocols_bgp.py
+++ b/smoketest/scripts/cli/test_protocols_bgp.py
@@ -319,8 +319,11 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
         tcp_keepalive_interval = '77'
         tcp_keepalive_probes = '22'
 
-        self.cli_set(base_path + ['parameters', 'router-id', router_id])
+        self.cli_set(base_path + ['parameters', 'allow-martian-nexthop'])
+        self.cli_set(base_path + ['parameters', 'no-hard-administrative-reset'])
         self.cli_set(base_path + ['parameters', 'log-neighbor-changes'])
+        self.cli_set(base_path + ['parameters', 'labeled-unicast', 'explicit-null'])
+        self.cli_set(base_path + ['parameters', 'router-id', router_id])
 
         # System AS number MUST be defined - as this is set in setUp() we remove
         # this once for testing of the proper error
@@ -367,12 +370,15 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
         frrconfig = self.getFRRconfig(f'router bgp {ASN}')
         self.assertIn(f'router bgp {ASN}', frrconfig)
         self.assertIn(f' bgp router-id {router_id}', frrconfig)
+        self.assertIn(f' bgp allow-martian-nexthop', frrconfig)
         self.assertIn(f' bgp log-neighbor-changes', frrconfig)
         self.assertIn(f' bgp default local-preference {local_pref}', frrconfig)
         self.assertIn(f' bgp conditional-advertisement timer {cond_adv_timer}', frrconfig)
         self.assertIn(f' bgp fast-convergence', frrconfig)
         self.assertIn(f' bgp graceful-restart stalepath-time {stalepath_time}', frrconfig)
         self.assertIn(f' bgp graceful-shutdown', frrconfig)
+        self.assertIn(f' no bgp hard-administrative-reset', frrconfig)
+        self.assertIn(f' bgp labeled-unicast explicit-null', frrconfig)
         self.assertIn(f' bgp bestpath as-path multipath-relax', frrconfig)
         self.assertIn(f' bgp bestpath bandwidth default-weight-for-missing', frrconfig)
         self.assertIn(f' bgp bestpath compare-routerid', frrconfig)
@@ -1178,22 +1184,15 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
         self.assertIn(f' sid vpn export {sid}', afiv6_config)
         self.assertIn(f' nexthop vpn export {nexthop_ipv6}', afiv4_config)
 
-    def test_bgp_25_ipv4_ipv6_labeled_unicast_peer_group(self):
+    def test_bgp_25_ipv4_labeled_unicast_peer_group(self):
         pg_ipv4 = 'foo4'
-        pg_ipv6 = 'foo6'
-
         ipv4_max_prefix = '20'
-        ipv6_max_prefix = '200'
         ipv4_prefix = '192.0.2.0/24'
-        ipv6_prefix = '2001:db8:1000::/64'
 
         self.cli_set(base_path + ['listen', 'range', ipv4_prefix, 'peer-group', pg_ipv4])
-        self.cli_set(base_path + ['listen', 'range', ipv6_prefix, 'peer-group', pg_ipv6])
-
+        self.cli_set(base_path + ['parameters', 'labeled-unicast', 'ipv4-explicit-null'])
         self.cli_set(base_path + ['peer-group', pg_ipv4, 'address-family', 'ipv4-labeled-unicast', 'maximum-prefix', ipv4_max_prefix])
         self.cli_set(base_path + ['peer-group', pg_ipv4, 'remote-as', 'external'])
-        self.cli_set(base_path + ['peer-group', pg_ipv6, 'address-family', 'ipv6-labeled-unicast', 'maximum-prefix', ipv6_max_prefix])
-        self.cli_set(base_path + ['peer-group', pg_ipv6, 'remote-as', 'external'])
 
         self.cli_commit()
 
@@ -1201,15 +1200,33 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
         self.assertIn(f'router bgp {ASN}', frrconfig)
         self.assertIn(f' neighbor {pg_ipv4} peer-group', frrconfig)
         self.assertIn(f' neighbor {pg_ipv4} remote-as external', frrconfig)
-        self.assertIn(f' neighbor {pg_ipv6} peer-group', frrconfig)
-        self.assertIn(f' neighbor {pg_ipv6} remote-as external', frrconfig)
         self.assertIn(f' bgp listen range {ipv4_prefix} peer-group {pg_ipv4}', frrconfig)
-        self.assertIn(f' bgp listen range {ipv6_prefix} peer-group {pg_ipv6}', frrconfig)
+        self.assertIn(f' bgp labeled-unicast ipv4-explicit-null', frrconfig)
 
         afiv4_config = self.getFRRconfig(' address-family ipv4 labeled-unicast')
         self.assertIn(f'  neighbor {pg_ipv4} activate', afiv4_config)
         self.assertIn(f'  neighbor {pg_ipv4} maximum-prefix {ipv4_max_prefix}', afiv4_config)
 
+    def test_bgp_26_ipv6_labeled_unicast_peer_group(self):
+        pg_ipv6 = 'foo6'
+        ipv6_max_prefix = '200'
+        ipv6_prefix = '2001:db8:1000::/64'
+
+        self.cli_set(base_path + ['listen', 'range', ipv6_prefix, 'peer-group', pg_ipv6])
+        self.cli_set(base_path + ['parameters', 'labeled-unicast', 'ipv6-explicit-null'])
+
+        self.cli_set(base_path + ['peer-group', pg_ipv6, 'address-family', 'ipv6-labeled-unicast', 'maximum-prefix', ipv6_max_prefix])
+        self.cli_set(base_path + ['peer-group', pg_ipv6, 'remote-as', 'external'])
+
+        self.cli_commit()
+
+        frrconfig = self.getFRRconfig(f'router bgp {ASN}')
+        self.assertIn(f'router bgp {ASN}', frrconfig)
+        self.assertIn(f' neighbor {pg_ipv6} peer-group', frrconfig)
+        self.assertIn(f' neighbor {pg_ipv6} remote-as external', frrconfig)
+        self.assertIn(f' bgp listen range {ipv6_prefix} peer-group {pg_ipv6}', frrconfig)
+        self.assertIn(f' bgp labeled-unicast ipv6-explicit-null', frrconfig)
+
         afiv6_config = self.getFRRconfig(' address-family ipv6 labeled-unicast')
         self.assertIn(f'  neighbor {pg_ipv6} activate', afiv6_config)
         self.assertIn(f'  neighbor {pg_ipv6} maximum-prefix {ipv6_max_prefix}', afiv6_config)
-- 
cgit v1.2.3