From 8e392a3dbc16f7b80a979f7b4e9c11408d700e6f Mon Sep 17 00:00:00 2001
From: Christian Poessinger <christian@poessinger.com>
Date: Thu, 13 May 2021 10:49:39 +0200
Subject: bonding: T3543: add support to configure lact-rate (slow or fast)

Option specifying the rate in which we'll ask our link partner to transmit
LACPDU packets in 802.3ad mode.

  set interfaces bonding bond0 lacp-rate <slow|fast>

slow: Request partner to transmit LACPDUs every 30 seconds (default)
fast: Request partner to transmit LACPDUs every 1 second
---
 interface-definitions/interfaces-bonding.xml.in  | 20 ++++++++++++++
 python/vyos/ifconfig/bond.py                     | 34 +++++++++++++++++++++---
 smoketest/scripts/cli/test_interfaces_bonding.py | 19 +++++++++++++
 src/conf_mode/interfaces-bonding.py              |  3 +++
 4 files changed, 73 insertions(+), 3 deletions(-)

diff --git a/interface-definitions/interfaces-bonding.xml.in b/interface-definitions/interfaces-bonding.xml.in
index 846f6eb54..2efdaea3d 100644
--- a/interface-definitions/interfaces-bonding.xml.in
+++ b/interface-definitions/interfaces-bonding.xml.in
@@ -97,6 +97,26 @@
             </properties>
             <defaultValue>0</defaultValue>
           </leafNode>
+          <leafNode name="lacp-rate">
+            <properties>
+              <help>Rate in which we will ask our link partner to transmit LACPDU packets</help>
+              <completionHelp>
+                <list>slow fast</list>
+              </completionHelp>
+              <valueHelp>
+                <format>slow</format>
+                <description>Request partner to transmit LACPDUs every 30 seconds (default)</description>
+              </valueHelp>
+              <valueHelp>
+                <format>fast</format>
+                <description>Request partner to transmit LACPDUs every 1 second</description>
+              </valueHelp>
+              <constraint>
+                <regex>^(slow|fast)$</regex>
+              </constraint>
+            </properties>
+            <defaultValue>slow</defaultValue>
+          </leafNode>
           <leafNode name="mode">
             <properties>
               <help>Bonding mode</help>
diff --git a/python/vyos/ifconfig/bond.py b/python/vyos/ifconfig/bond.py
index bfa3b0025..233d53688 100644
--- a/python/vyos/ifconfig/bond.py
+++ b/python/vyos/ifconfig/bond.py
@@ -51,6 +51,10 @@ class BondIf(Interface):
             'validate': assert_positive,
             'location': '/sys/class/net/{ifname}/bonding/min_links',
         },
+        'bond_lacp_rate': {
+            'validate': lambda v: assert_list(v, ['slow', 'fast']),
+            'location': '/sys/class/net/{ifname}/bonding/lacp_rate',
+        },
         'bond_miimon': {
             'validate': assert_positive,
             'location': '/sys/class/net/{ifname}/bonding/miimon'
@@ -152,6 +156,26 @@ class BondIf(Interface):
         """
         self.set_interface('bond_min_links', number)
 
+    def set_lacp_rate(self, slow_fast):
+        """
+        Option specifying the rate in which we'll ask our link partner
+	    to transmit LACPDU packets in 802.3ad mode.  Possible values
+	    are:
+
+	    slow or 0
+		    Request partner to transmit LACPDUs every 30 seconds
+
+	    fast or 1
+		    Request partner to transmit LACPDUs every 1 second
+
+	    The default is slow.
+
+        Example:
+        >>> from vyos.ifconfig import BondIf
+        >>> BondIf('bond0').set_lacp_rate('slow')
+        """
+        self.set_interface('bond_lacp_rate', slow_fast)
+
     def set_arp_interval(self, interval):
         """
         Specifies the ARP link monitoring frequency in milliseconds.
@@ -382,9 +406,13 @@ class BondIf(Interface):
                 if not dict_search(f'member.interface_remove.{interface}.disable', config):
                     Interface(interface).set_admin_state('up')
 
-            # Bonding policy/mode
-            value = config.get('mode')
-            if value: self.set_mode(value)
+            # Bonding policy/mode - default value, always present
+            mode = config.get('mode')
+            self.set_mode(mode)
+
+            # LACPDU transmission rate - default value
+            if mode == '802.3ad':
+                self.set_lacp_rate(config.get('lacp_rate'))
 
             # Add (enslave) interfaces to bond
             value = dict_search('member.interface', config)
diff --git a/smoketest/scripts/cli/test_interfaces_bonding.py b/smoketest/scripts/cli/test_interfaces_bonding.py
index ab949c8bd..cf147fe58 100755
--- a/smoketest/scripts/cli/test_interfaces_bonding.py
+++ b/smoketest/scripts/cli/test_interfaces_bonding.py
@@ -114,5 +114,24 @@ class BondingInterfaceTest(BasicInterfaceTest.TestCase):
             # check LACP default rate
             self.assertEqual('slow',    tmp['linkinfo']['info_data']['ad_lacp_rate'])
 
+    def test_bonding_lacp_rate(self):
+        # configure member interfaces
+        lacp_rate = 'fast'
+        for interface in self._interfaces:
+            for option in self._options.get(interface, []):
+                self.cli_set(self._base_path + [interface] + option.split())
+
+            self.cli_set(self._base_path + [interface, 'lacp-rate', lacp_rate])
+
+        self.cli_commit()
+
+        # verify config
+        for interface in self._interfaces:
+            tmp = get_interface_config(interface)
+
+            # check LACP minimum links (default value)
+            self.assertEqual(0,         tmp['linkinfo']['info_data']['min_links'])
+            self.assertEqual(lacp_rate, tmp['linkinfo']['info_data']['ad_lacp_rate'])
+
 if __name__ == '__main__':
     unittest.main(verbosity=2)
diff --git a/src/conf_mode/interfaces-bonding.py b/src/conf_mode/interfaces-bonding.py
index 1a549f27d..431d65f1f 100755
--- a/src/conf_mode/interfaces-bonding.py
+++ b/src/conf_mode/interfaces-bonding.py
@@ -83,6 +83,9 @@ def get_config(config=None):
     tmp = leaf_node_changed(conf, ['mode'])
     if tmp: bond.update({'shutdown_required': {}})
 
+    tmp = leaf_node_changed(conf, ['lacp-rate'])
+    if tmp: bond.update({'shutdown_required': {}})
+
     # determine which members have been removed
     interfaces_removed = leaf_node_changed(conf, ['member', 'interface'])
     if interfaces_removed:
-- 
cgit v1.2.3