From b55571138d2b08dd4fda6d8b34a70f9a84a1c721 Mon Sep 17 00:00:00 2001
From: Christian Breunig <christian@breunig.cc>
Date: Sun, 14 Jan 2024 11:35:24 +0100
Subject: bgp: T591: add SRv6 per address-family SID support

set protocols bgp address-family ipv4-unicast sid vpn export <auto|1-1048575>
set protocols bgp address-family ipv6-unicast sid vpn export <auto|1-1048575>

(cherry picked from commit d7e248ba514108461ca9d5875c0be077c80ceca7)
---
 data/templates/frr/bgpd.frr.j2                     |  3 ++
 interface-definitions/include/bgp/afi-sid.xml.i    | 36 ++++++++++++++++++++++
 .../include/bgp/protocol-common-config.xml.i       |  2 ++
 smoketest/scripts/cli/test_protocols_bgp.py        | 23 +++++++++++++-
 src/conf_mode/protocols_bgp.py                     |  4 +++
 5 files changed, 67 insertions(+), 1 deletion(-)
 create mode 100644 interface-definitions/include/bgp/afi-sid.xml.i

diff --git a/data/templates/frr/bgpd.frr.j2 b/data/templates/frr/bgpd.frr.j2
index 679ba8b04..f3ae56903 100644
--- a/data/templates/frr/bgpd.frr.j2
+++ b/data/templates/frr/bgpd.frr.j2
@@ -436,6 +436,9 @@ router bgp {{ system_as }} {{ 'vrf ' ~ vrf if vrf is vyos_defined }}
 {%         if afi_config.route_map.vpn.import is vyos_defined %}
   route-map vpn import {{ afi_config.route_map.vpn.import }}
 {%         endif %}
+{%         if afi_config.sid.vpn.export is vyos_defined %}
+ sid vpn export {{ afi_config.sid.vpn.export }}
+{%         endif %}
 {%         if afi_config.vni is vyos_defined %}
 {%             for vni, vni_config in afi_config.vni.items() %}
   vni {{ vni }}
diff --git a/interface-definitions/include/bgp/afi-sid.xml.i b/interface-definitions/include/bgp/afi-sid.xml.i
new file mode 100644
index 000000000..38a3dcf9b
--- /dev/null
+++ b/interface-definitions/include/bgp/afi-sid.xml.i
@@ -0,0 +1,36 @@
+<!-- include start from bgp/sid.xml.i -->
+<node name="sid">
+    <properties>
+      <help>SID value for VRF</help>
+    </properties>
+    <children>
+      <node name="vpn">
+        <properties>
+          <help>Between current VRF and VPN</help>
+        </properties>
+        <children>
+          <leafNode name="export">
+            <properties>
+              <help>For routes leaked from current VRF to VPN</help>
+              <completionHelp>
+                <list>auto</list>
+              </completionHelp>
+              <valueHelp>
+                <format>u32:1-1048575</format>
+                <description>SID allocation index</description>
+              </valueHelp>
+              <valueHelp>
+                <format>auto</format>
+                <description>Automatically assign a label</description>
+              </valueHelp>
+              <constraint>
+                <regex>auto</regex>
+                <validator name="numeric" argument="--range 1-1048575"/>
+              </constraint>
+            </properties>
+          </leafNode>
+        </children>
+      </node>
+    </children>
+  </node>
+  <!-- include end -->
diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i
index bb35efe94..51daf4e8b 100644
--- a/interface-definitions/include/bgp/protocol-common-config.xml.i
+++ b/interface-definitions/include/bgp/protocol-common-config.xml.i
@@ -188,6 +188,7 @@
             </leafNode>
           </children>
         </node>
+        #include <include/bgp/afi-sid.xml.i>
       </children>
     </node>
     <node name="ipv4-multicast">
@@ -555,6 +556,7 @@
             </leafNode>
           </children>
         </node>
+        #include <include/bgp/afi-sid.xml.i>
       </children>
     </node>
     <node name="ipv6-multicast">
diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py
index d5efae12c..0e9ac4f2d 100755
--- a/smoketest/scripts/cli/test_protocols_bgp.py
+++ b/smoketest/scripts/cli/test_protocols_bgp.py
@@ -1142,7 +1142,11 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
 
         self.cli_set(base_path + ['srv6', 'locator', locator_name])
         self.cli_set(base_path + ['sid', 'vpn', 'per-vrf', 'export', sid])
-
+        self.cli_set(base_path + ['address-family', 'ipv4-unicast', 'sid', 'vpn', 'export', sid])
+        # verify() - SID per VRF and SID per address-family are mutually exclusive!
+        with self.assertRaises(ConfigSessionError):
+            self.cli_commit()
+        self.cli_delete(base_path + ['address-family', 'ipv4-unicast', 'sid'])
         self.cli_commit()
 
         frrconfig = self.getFRRconfig(f'router bgp {ASN}')
@@ -1151,6 +1155,23 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
         self.assertIn(f'  locator {locator_name}', frrconfig)
         self.assertIn(f' sid vpn per-vrf export {sid}', frrconfig)
 
+        # Now test AFI SID
+        self.cli_delete(base_path + ['sid'])
+        self.cli_set(base_path + ['address-family', 'ipv4-unicast', 'sid', 'vpn', 'export', sid])
+        self.cli_set(base_path + ['address-family', 'ipv6-unicast', 'sid', 'vpn', 'export', sid])
+
+        self.cli_commit()
+
+        frrconfig = self.getFRRconfig(f'router bgp {ASN}')
+        self.assertIn(f'router bgp {ASN}', frrconfig)
+        self.assertIn(f' segment-routing srv6', frrconfig)
+        self.assertIn(f'  locator {locator_name}', frrconfig)
+
+        afiv4_config = self.getFRRconfig(' address-family ipv4 unicast')
+        self.assertIn(f' sid vpn export {sid}', afiv4_config)
+        afiv6_config = self.getFRRconfig(' address-family ipv6 unicast')
+        self.assertIn(f' sid vpn export {sid}', afiv6_config)
+
     def test_bgp_25_ipv4_ipv6_labeled_unicast_peer_group(self):
         pg_ipv4 = 'foo4'
         pg_ipv6 = 'foo6'
diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py
index 89e2aab8c..e8bb11828 100755
--- a/src/conf_mode/protocols_bgp.py
+++ b/src/conf_mode/protocols_bgp.py
@@ -542,6 +542,10 @@ def verify(bgp):
                     tmp = dict_search(f'route_map.vpn.{export_import}', afi_config)
                     if tmp: verify_route_map(tmp, bgp)
 
+                # per-vrf sid and per-af sid are mutually exclusive
+                if 'sid' in afi_config and 'sid' in bgp:
+                    raise ConfigError('SID per VRF and SID per address-family are mutually exclusive!')
+
             # Checks only required for L2VPN EVPN
             if afi in ['l2vpn_evpn']:
                 if 'vni' in afi_config:
-- 
cgit v1.2.3


From 42d6a8cd500b2a92e9dbe0e868b84f4b55b1e02b Mon Sep 17 00:00:00 2001
From: Christian Breunig <christian@breunig.cc>
Date: Sun, 14 Jan 2024 11:36:31 +0100
Subject: bgp: T591: add VPN nexthop support per address-family

set protocols bgp address-family ipv4-unicast nexthop vpn export <ipv4-address|ipv6-address>
set protocols bgp address-family ipv6-unicast nexthop vpn export <ipv4-address|ipv6-address>

(cherry picked from commit 7349927908206fa83a7295d643f56950309efb4f)
---
 data/templates/frr/bgpd.frr.j2                     |  3 ++
 .../include/bgp/afi-nexthop-vpn-export.xml.i       | 32 ++++++++++++++++++++++
 .../include/bgp/protocol-common-config.xml.i       |  2 ++
 smoketest/scripts/cli/test_protocols_bgp.py        |  6 ++++
 4 files changed, 43 insertions(+)
 create mode 100644 interface-definitions/include/bgp/afi-nexthop-vpn-export.xml.i

diff --git a/data/templates/frr/bgpd.frr.j2 b/data/templates/frr/bgpd.frr.j2
index f3ae56903..e02fdd1bb 100644
--- a/data/templates/frr/bgpd.frr.j2
+++ b/data/templates/frr/bgpd.frr.j2
@@ -402,6 +402,9 @@ router bgp {{ system_as }} {{ 'vrf ' ~ vrf if vrf is vyos_defined }}
 {%         if afi_config.flooding.head_end_replication is vyos_defined %}
   flooding head-end-replication
 {%         endif %}
+{%         if afi_config.nexthop.vpn.export is vyos_defined %}
+  nexthop vpn export {{ afi_config.nexthop.vpn.export }}
+{%         endif %}
 {%         if afi_config.rd.vpn.export is vyos_defined %}
   rd vpn export {{ afi_config.rd.vpn.export }}
 {%         endif %}
diff --git a/interface-definitions/include/bgp/afi-nexthop-vpn-export.xml.i b/interface-definitions/include/bgp/afi-nexthop-vpn-export.xml.i
new file mode 100644
index 000000000..d90597f37
--- /dev/null
+++ b/interface-definitions/include/bgp/afi-nexthop-vpn-export.xml.i
@@ -0,0 +1,32 @@
+<!-- include start from bgp/afi-nexthop-vpn-export.xml.i -->
+<node name="nexthop">
+  <properties>
+    <help>Specify next hop to use for VRF advertised prefixes</help>
+  </properties>
+  <children>
+    <node name="vpn">
+      <properties>
+        <help>Between current address-family and vpn</help>
+      </properties>
+      <children>
+        <leafNode name="export">
+          <properties>
+            <help>For routes leaked from current address-family to vpn</help>
+            <valueHelp>
+                <format>ipv4</format>
+                <description>BGP neighbor IP address</description>
+              </valueHelp>
+              <valueHelp>
+                <format>ipv6</format>
+                <description>BGP neighbor IPv6 address</description>
+              </valueHelp>
+              <constraint>
+                <validator name="ip-address"/>
+              </constraint>
+          </properties>
+        </leafNode>
+      </children>
+    </node>
+  </children>
+</node>
+  <!-- include end -->
diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i
index 51daf4e8b..9895b025c 100644
--- a/interface-definitions/include/bgp/protocol-common-config.xml.i
+++ b/interface-definitions/include/bgp/protocol-common-config.xml.i
@@ -120,6 +120,7 @@
         #include <include/bgp/afi-rd.xml.i>
         #include <include/bgp/afi-route-map-vpn.xml.i>
         #include <include/bgp/afi-route-target-vpn.xml.i>
+        #include <include/bgp/afi-nexthop-vpn-export.xml.i>
         <node name="redistribute">
           <properties>
             <help>Redistribute routes from other protocols into BGP</help>
@@ -496,6 +497,7 @@
         #include <include/bgp/afi-rd.xml.i>
         #include <include/bgp/afi-route-map-vpn.xml.i>
         #include <include/bgp/afi-route-target-vpn.xml.i>
+        #include <include/bgp/afi-nexthop-vpn-export.xml.i>
         <node name="redistribute">
           <properties>
             <help>Redistribute routes from other protocols into BGP</help>
diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py
index 0e9ac4f2d..2dbc30a41 100755
--- a/smoketest/scripts/cli/test_protocols_bgp.py
+++ b/smoketest/scripts/cli/test_protocols_bgp.py
@@ -1139,6 +1139,8 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
     def test_bgp_24_srv6_sid(self):
         locator_name = 'VyOS_foo'
         sid = 'auto'
+        nexthop_ipv4 = '192.0.0.1'
+        nexthop_ipv6 = '2001:db8:100:200::2'
 
         self.cli_set(base_path + ['srv6', 'locator', locator_name])
         self.cli_set(base_path + ['sid', 'vpn', 'per-vrf', 'export', sid])
@@ -1158,7 +1160,9 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
         # Now test AFI SID
         self.cli_delete(base_path + ['sid'])
         self.cli_set(base_path + ['address-family', 'ipv4-unicast', 'sid', 'vpn', 'export', sid])
+        self.cli_set(base_path + ['address-family', 'ipv4-unicast', 'nexthop', 'vpn', 'export', nexthop_ipv4])
         self.cli_set(base_path + ['address-family', 'ipv6-unicast', 'sid', 'vpn', 'export', sid])
+        self.cli_set(base_path + ['address-family', 'ipv6-unicast', 'nexthop', 'vpn', 'export', nexthop_ipv6])
 
         self.cli_commit()
 
@@ -1169,8 +1173,10 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
 
         afiv4_config = self.getFRRconfig(' address-family ipv4 unicast')
         self.assertIn(f' sid vpn export {sid}', afiv4_config)
+        self.assertIn(f' nexthop vpn export {nexthop_ipv4}', afiv4_config)
         afiv6_config = self.getFRRconfig(' address-family ipv6 unicast')
         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):
         pg_ipv4 = 'foo4'
-- 
cgit v1.2.3