summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Poessinger <christian@poessinger.com>2021-02-15 20:16:02 +0100
committerChristian Poessinger <christian@poessinger.com>2021-02-15 20:16:02 +0100
commit3d3d09d6e5d7350b09709447ed4d7a7790e09b81 (patch)
treec08e2227b4ffebfa81f2070b46c4d241f52c64cb
parent3a32c507134c4599f343dda54ccf4e80ea62def4 (diff)
downloadvyos-1x-3d3d09d6e5d7350b09709447ed4d7a7790e09b81.tar.gz
vyos-1x-3d3d09d6e5d7350b09709447ed4d7a7790e09b81.zip
bfd: T3310: implement peer profile support
-rw-r--r--data/templates/frr/bfd.frr.tmpl29
-rw-r--r--interface-definitions/include/bfd-common.xml.i72
-rw-r--r--interface-definitions/protocols-bfd.xml.in100
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_bfd.py69
-rwxr-xr-xsrc/conf_mode/protocols_bfd.py71
5 files changed, 223 insertions, 118 deletions
diff --git a/data/templates/frr/bfd.frr.tmpl b/data/templates/frr/bfd.frr.tmpl
index 921d9b0bc..3b3d13f9d 100644
--- a/data/templates/frr/bfd.frr.tmpl
+++ b/data/templates/frr/bfd.frr.tmpl
@@ -1,15 +1,35 @@
!
bfd
+{% if profile is defined and profile is not none %}
+{% for profile_name, profile_config in profile.items() %}
+ profile {{ profile_name }}
+ detect-multiplier {{ profile_config.interval.multiplier }}
+ receive-interval {{ profile_config.interval.receive }}
+ transmit-interval {{ profile_config.interval.transmit }}
+{% if profile_config.interval['echo-interval'] is defined and profile_config.interval['echo-interval'] is not none %}
+ echo-interval {{ profile_config.interval['echo-interval'] }}
+{% endif %}
+{% if profile_config['echo-mode'] is defined %}
+ echo-mode
+{% endif %}
+{% if profile_config.shutdown is defined %}
+ shutdown
+{% else %}
+ no shutdown
+{% endif %}
+ exit
+{% endfor %}
+{% endif %}
{% if peer is defined and peer is not none %}
{% for peer_name, peer_config in peer.items() %}
peer {{ peer_name }}{{ ' multihop' if peer_config.multihop is defined }}{{ ' local-address ' + peer_config.source.address if peer_config.source is defined and peer_config.source.address is defined }}{{ ' interface ' + peer_config.source.interface if peer_config.source is defined and peer_config.source.interface is defined }}
detect-multiplier {{ peer_config.interval.multiplier }}
receive-interval {{ peer_config.interval.receive }}
transmit-interval {{ peer_config.interval.transmit }}
-{% if peer_config.interval.echo_interval is defined and peer_config.interval.echo_interval is not none %}
- echo-interval {{ peer_config.interval.echo_interval }}
+{% if peer_config.interval['echo-interval'] is defined and peer_config.interval['echo-interval'] is not none %}
+ echo-interval {{ peer_config.interval['echo-interval'] }}
{% endif %}
-{% if peer_config.echo_mode is defined %}
+{% if peer_config['echo-mode'] is defined %}
echo-mode
{% endif %}
{% if peer_config.shutdown is defined %}
@@ -17,7 +37,8 @@ bfd
{% else %}
no shutdown
{% endif %}
- !
+ exit
{% endfor %}
{% endif %}
+ exit
!
diff --git a/interface-definitions/include/bfd-common.xml.i b/interface-definitions/include/bfd-common.xml.i
new file mode 100644
index 000000000..ff73e4b20
--- /dev/null
+++ b/interface-definitions/include/bfd-common.xml.i
@@ -0,0 +1,72 @@
+<!-- included start from bfd-common.xml.i -->
+<leafNode name="echo-mode">
+ <properties>
+ <help>Enables the echo transmission mode</help>
+ <valueless/>
+ </properties>
+</leafNode>
+<node name="interval">
+ <properties>
+ <help>Configure timer intervals</help>
+ </properties>
+ <children>
+ <leafNode name="receive">
+ <properties>
+ <help>Minimum interval of receiving control packets</help>
+ <valueHelp>
+ <format>10-60000</format>
+ <description>Interval in milliseconds</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 10-60000"/>
+ </constraint>
+ </properties>
+ <defaultValue>300</defaultValue>
+ </leafNode>
+ <leafNode name="transmit">
+ <properties>
+ <help>Minimum interval of transmitting control packets</help>
+ <valueHelp>
+ <format>10-60000</format>
+ <description>Interval in milliseconds</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 10-60000"/>
+ </constraint>
+ </properties>
+ <defaultValue>300</defaultValue>
+ </leafNode>
+ <leafNode name="multiplier">
+ <properties>
+ <help>Multiplier to determine packet loss</help>
+ <valueHelp>
+ <format>2-255</format>
+ <description>Remote transmission interval will be multiplied by this value</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 2-255"/>
+ </constraint>
+ </properties>
+ <defaultValue>3</defaultValue>
+ </leafNode>
+ <leafNode name="echo-interval">
+ <properties>
+ <help>Echo receive transmission interval</help>
+ <valueHelp>
+ <format>10-60000</format>
+ <description>The minimal echo receive transmission interval that this system is capable of handling</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 10-60000"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+</node>
+<leafNode name="shutdown">
+ <properties>
+ <help>Disable this peer</help>
+ <valueless/>
+ </properties>
+</leafNode>
+<!-- included end -->
diff --git a/interface-definitions/protocols-bfd.xml.in b/interface-definitions/protocols-bfd.xml.in
index 6f82a5c2b..cc3c3bf12 100644
--- a/interface-definitions/protocols-bfd.xml.in
+++ b/interface-definitions/protocols-bfd.xml.in
@@ -11,7 +11,7 @@
<children>
<tagNode name="peer">
<properties>
- <help>Configures a new BFD peer to listen and talk to</help>
+ <help>Configures BFD peer to listen and talk to</help>
<valueHelp>
<format>ipv4</format>
<description>BFD peer IPv4 address</description>
@@ -26,6 +26,18 @@
</constraint>
</properties>
<children>
+ <leafNode name="profile">
+ <properties>
+ <help>Use settings from BFD profile</help>
+ <completionHelp>
+ <path>protocols bfd profile</path>
+ </completionHelp>
+ <valueHelp>
+ <format>txt</format>
+ <description>BFD profile name</description>
+ </valueHelp>
+ </properties>
+ </leafNode>
<node name="source">
<properties>
<help>Bind listener to specified interface/address, mandatory for IPv6</help>
@@ -61,82 +73,28 @@
</leafNode>
</children>
</node>
- <node name="interval">
- <properties>
- <help>Configure timer intervals</help>
- </properties>
- <children>
- <leafNode name="receive">
- <properties>
- <help>Minimum interval of receiving control packets</help>
- <valueHelp>
- <format>10-60000</format>
- <description>Interval in milliseconds</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 10-60000"/>
- </constraint>
- </properties>
- <defaultValue>300</defaultValue>
- </leafNode>
- <leafNode name="transmit">
- <properties>
- <help>Minimum interval of transmitting control packets</help>
- <valueHelp>
- <format>10-60000</format>
- <description>Interval in milliseconds</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 10-60000"/>
- </constraint>
- </properties>
- <defaultValue>300</defaultValue>
- </leafNode>
- <leafNode name="multiplier">
- <properties>
- <help>Multiplier to determine packet loss</help>
- <valueHelp>
- <format>2-255</format>
- <description>Remote transmission interval will be multiplied by this value</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 2-255"/>
- </constraint>
- </properties>
- <defaultValue>3</defaultValue>
- </leafNode>
- <leafNode name="echo-interval">
- <properties>
- <help>Echo receive transmission interval</help>
- <valueHelp>
- <format>10-60000</format>
- <description>The minimal echo receive transmission interval that this system is capable of handling</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 10-60000"/>
- </constraint>
- </properties>
- </leafNode>
- </children>
- </node>
- <leafNode name="shutdown">
- <properties>
- <help>Disable this peer</help>
- <valueless/>
- </properties>
- </leafNode>
+ #include <include/bfd-common.xml.i>
<leafNode name="multihop">
<properties>
<help>Allow this BFD peer to not be directly connected</help>
<valueless/>
</properties>
</leafNode>
- <leafNode name="echo-mode">
- <properties>
- <help>Enables the echo transmission mode</help>
- <valueless/>
- </properties>
- </leafNode>
+ </children>
+ </tagNode>
+ <tagNode name="profile">
+ <properties>
+ <help>Configure BFD profile used by individual peer</help>
+ <valueHelp>
+ <format>txt</format>
+ <description>Name of BFD profile</description>
+ </valueHelp>
+ <constraint>
+ <regex>^[-_a-zA-Z0-9]{1,32}$</regex>
+ </constraint>
+ </properties>
+ <children>
+ #include <include/bfd-common.xml.i>
</children>
</tagNode>
</children>
diff --git a/smoketest/scripts/cli/test_protocols_bfd.py b/smoketest/scripts/cli/test_protocols_bfd.py
index 996a54a9d..80e5daa7c 100755
--- a/smoketest/scripts/cli/test_protocols_bfd.py
+++ b/smoketest/scripts/cli/test_protocols_bfd.py
@@ -26,7 +26,7 @@ PROCESS_NAME = 'bfdd'
base_path = ['protocols', 'bfd']
dum_if = 'dum1001'
-neighbor_config = {
+peers = {
'192.0.2.10' : {
'intv_rx' : '500',
'intv_tx' : '600',
@@ -36,7 +36,7 @@ neighbor_config = {
'192.0.2.20' : {
'echo_mode' : '',
'intv_echo' : '100',
- 'intv_mult' : '111',
+ 'intv_mult' : '100',
'intv_rx' : '222',
'intv_tx' : '333',
'shutdown' : '',
@@ -52,20 +52,35 @@ neighbor_config = {
},
}
+profiles = {
+ 'foo' : {
+ 'echo_mode' : '',
+ 'intv_echo' : '100',
+ 'intv_mult' : '101',
+ 'intv_rx' : '222',
+ 'intv_tx' : '333',
+ 'shutdown' : '',
+ },
+ 'bar' : {
+ 'intv_mult' : '102',
+ 'intv_rx' : '444',
+ },
+}
+
def getFRRconfig():
return cmd('vtysh -c "show run" | sed -n "/^bfd/,/^!/p"')
def getBFDPeerconfig(peer):
return cmd(f'vtysh -c "show run" | sed -n "/^ {peer}/,/^!/p"')
+def getBFDProfileconfig(profile):
+ return cmd(f'vtysh -c "show run" | sed -n "/^ {profile}/,/^!/p"')
+
class TestProtocolsBFD(unittest.TestCase):
def setUp(self):
self.session = ConfigSession(os.getpid())
- self.session.set(['interfaces', 'dummy', dum_if, 'address', '192.0.2.1/24'])
- self.session.set(['interfaces', 'dummy', dum_if, 'address', '2001:db8::1/64'])
def tearDown(self):
- self.session.delete(['interfaces', 'dummy', dum_if])
self.session.delete(base_path)
self.session.commit()
del self.session
@@ -73,8 +88,8 @@ class TestProtocolsBFD(unittest.TestCase):
# Check for running process
self.assertTrue(process_named_running(PROCESS_NAME))
- def test_bfd_simple(self):
- for peer, peer_config in neighbor_config.items():
+ def test_bfd_peer(self):
+ for peer, peer_config in peers.items():
if 'echo_mode' in peer_config:
self.session.set(base_path + ['peer', peer, 'echo-mode'])
if 'intv_echo' in peer_config:
@@ -99,7 +114,7 @@ class TestProtocolsBFD(unittest.TestCase):
# Verify FRR bgpd configuration
frrconfig = getFRRconfig()
- for peer, peer_config in neighbor_config.items():
+ for peer, peer_config in peers.items():
tmp = f'peer {peer}'
if 'multihop' in peer_config:
tmp += f' multihop'
@@ -124,5 +139,43 @@ class TestProtocolsBFD(unittest.TestCase):
if 'shutdown' not in peer_config:
self.assertIn(f' no shutdown', peerconfig)
+ def test_bfd_profile(self):
+ peer = '192.0.2.10'
+
+ for profile, profile_config in profiles.items():
+ if 'echo_mode' in profile_config:
+ self.session.set(base_path + ['profile', profile, 'echo-mode'])
+ if 'intv_echo' in profile_config:
+ self.session.set(base_path + ['profile', profile, 'interval', 'echo-interval', profile_config["intv_echo"]])
+ if 'intv_mult' in profile_config:
+ self.session.set(base_path + ['profile', profile, 'interval', 'multiplier', profile_config["intv_mult"]])
+ if 'intv_rx' in profile_config:
+ self.session.set(base_path + ['profile', profile, 'interval', 'receive', profile_config["intv_rx"]])
+ if 'intv_tx' in profile_config:
+ self.session.set(base_path + ['profile', profile, 'interval', 'transmit', profile_config["intv_tx"]])
+ if 'shutdown' in profile_config:
+ self.session.set(base_path + ['profile', profile, 'shutdown'])
+
+ self.session.set(base_path + ['peer', peer, 'profile', list(profiles)[0]])
+
+ # commit changes
+ self.session.commit()
+
+ # Verify FRR bgpd configuration
+ for profile, profile_config in profiles.items():
+ config = getBFDProfileconfig(f'profile {profile}')
+ if 'echo_mode' in profile_config:
+ self.assertIn(f' echo-mode', config)
+ if 'intv_echo' in profile_config:
+ self.assertIn(f' echo-interval {profile_config["intv_echo"]}', config)
+ if 'intv_mult' in profile_config:
+ self.assertIn(f' detect-multiplier {profile_config["intv_mult"]}', config)
+ if 'intv_rx' in profile_config:
+ self.assertIn(f' receive-interval {profile_config["intv_rx"]}', config)
+ if 'intv_tx' in profile_config:
+ self.assertIn(f' transmit-interval {profile_config["intv_tx"]}', config)
+ if 'shutdown' not in profile_config:
+ self.assertIn(f' no shutdown', config)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/conf_mode/protocols_bfd.py b/src/conf_mode/protocols_bfd.py
index 7737c6aa1..a43eed504 100755
--- a/src/conf_mode/protocols_bfd.py
+++ b/src/conf_mode/protocols_bfd.py
@@ -36,54 +36,55 @@ def get_config(config=None):
else:
conf = Config()
base = ['protocols', 'bfd']
- bfd = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
+ bfd = conf.get_config_dict(base, get_first_key=True)
# Bail out early if configuration tree does not exist
if not conf.exists(base):
return bfd
+ # We have gathered the dict representation of the CLI, but there are
+ # default options which we need to update into the dictionary retrived.
+ # XXX: T2665: we currently have no nice way for defaults under tag
+ # nodes, thus we load the defaults "by hand"
+ default_values = defaults(base + ['peer'])
if 'peer' in bfd:
- # We have gathered the dict representation of the CLI, but there are
- # default options which we need to update into the dictionary retrived.
- # XXX: T2665: we currently have no nice way for defaults under tag
- # nodes, thus we load the defaults "by hand"
- default_values = defaults(base + ['peer'])
for peer in bfd['peer']:
bfd['peer'][peer] = dict_merge(default_values, bfd['peer'][peer])
+ if 'profile' in bfd:
+ for profile in bfd['profile']:
+ bfd['profile'][profile] = dict_merge(default_values, bfd['profile'][profile])
+
return bfd
def verify(bfd):
- if not bfd or 'peer' not in bfd:
+ if not bfd:
return None
- for peer, peer_config in bfd['peer'].items():
- # IPv6 link local peers require an explicit local address/interface
- if is_ipv6_link_local(peer):
- if 'source' not in peer_config or len(peer_config['source'] < 2):
- raise ConfigError('BFD IPv6 link-local peers require explicit local address and interface setting')
-
- # IPv6 peers require an explicit local address
- if is_ipv6(peer):
- if 'source' not in peer_config or 'address' not in peer_config['source']:
- raise ConfigError('BFD IPv6 peers require explicit local address setting')
-
- if 'multihop' in peer_config:
- # multihop require source address
- if 'source' not in peer_config or 'address' not in peer_config['source']:
- raise ConfigError('BFD multihop require source address')
-
- # multihop and echo-mode cannot be used together
- if 'echo_mode' in peer_config:
- raise ConfigError('Multihop and echo-mode cannot be used together')
-
- # multihop doesn't accept interface names
- if 'source' in peer_config and 'interface' in peer_config['source']:
- raise ConfigError('Multihop and source interface cannot be used together')
-
- # echo interval can be configured only with enabled echo-mode
- if 'interval' in peer_config and 'echo_interval' in peer_config['interval'] and 'echo_mode' not in peer_config:
- raise ConfigError('echo-interval can be configured only with enabled echo-mode')
+ if 'peer' in bfd:
+ for peer, peer_config in bfd['peer'].items():
+ # IPv6 link local peers require an explicit local address/interface
+ if is_ipv6_link_local(peer):
+ if 'source' not in peer_config or len(peer_config['source'] < 2):
+ raise ConfigError('BFD IPv6 link-local peers require explicit local address and interface setting')
+
+ # IPv6 peers require an explicit local address
+ if is_ipv6(peer):
+ if 'source' not in peer_config or 'address' not in peer_config['source']:
+ raise ConfigError('BFD IPv6 peers require explicit local address setting')
+
+ if 'multihop' in peer_config:
+ # multihop require source address
+ if 'source' not in peer_config or 'address' not in peer_config['source']:
+ raise ConfigError('BFD multihop require source address')
+
+ # multihop and echo-mode cannot be used together
+ if 'echo_mode' in peer_config:
+ raise ConfigError('Multihop and echo-mode cannot be used together')
+
+ # multihop doesn't accept interface names
+ if 'source' in peer_config and 'interface' in peer_config['source']:
+ raise ConfigError('Multihop and source interface cannot be used together')
return None
@@ -98,7 +99,7 @@ def apply(bfd):
# Save original configuration prior to starting any commit actions
frr_cfg = frr.FRRConfig()
frr_cfg.load_configuration()
- frr_cfg.modify_section('bfd', '')
+ frr_cfg.modify_section('^bfd', '')
frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', bfd['new_frr_config'])
frr_cfg.commit_configuration()