blob: 711337014208d1c01f60331ef56d0f438606da4a [file] [log] [blame]
Renato Botelho do Coutoead1e532019-10-31 13:31:07 -05001#!/usr/bin/env python3
Klement Sekerad3ba5152017-02-14 03:09:17 +01002""" BFD tests """
Klement Sekera0e3c0de2016-09-29 14:43:44 +02003
Klement Sekeraa57a9702017-02-02 06:58:07 +01004from __future__ import division
Paul Vinciguerra00671cf2018-11-25 12:47:04 -08005
Klement Sekerab17dd962017-01-09 07:43:48 +01006import binascii
Klement Sekeracdaf0d82022-02-14 20:20:22 +00007from collections import namedtuple
Paul Vinciguerra00671cf2018-11-25 12:47:04 -08008import hashlib
Paul Vinciguerra2f156312020-05-02 22:34:40 -04009import ipaddress
Paul Vinciguerra090096b2020-12-03 00:42:46 -050010import reprlib
Klement Sekera0e3c0de2016-09-29 14:43:44 +020011import time
Paul Vinciguerra00671cf2018-11-25 12:47:04 -080012import unittest
Klement Sekera239790f2017-02-16 10:53:53 +010013from random import randint, shuffle, getrandbits
Klement Sekera73884482017-02-23 09:26:30 +010014from socket import AF_INET, AF_INET6, inet_ntop
Paul Vinciguerra00671cf2018-11-25 12:47:04 -080015from struct import pack, unpack
16
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -070017import scapy.compat
Klement Sekerad3ba5152017-02-14 03:09:17 +010018from scapy.layers.inet import UDP, IP
19from scapy.layers.inet6 import IPv6
Neale Ranns52cd4962019-06-05 10:28:17 +000020from scapy.layers.l2 import Ether, GRE
Paul Vinciguerra00671cf2018-11-25 12:47:04 -080021from scapy.packet import Raw
22
Klement Sekerab23ffd72021-05-31 16:08:53 +020023from config import config
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020024from bfd import (
25 VppBFDAuthKey,
26 BFD,
27 BFDAuthType,
28 VppBFDUDPSession,
29 BFDDiagCode,
30 BFDState,
31 BFD_vpp_echo,
32)
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +000033from framework import tag_fixme_vpp_workers
Klement Sekerab23ffd72021-05-31 16:08:53 +020034from framework import VppTestCase, VppTestRunner
Andrew Yourtchenko06f32812021-01-14 10:19:08 +000035from framework import tag_run_solo
Klement Sekera0e3c0de2016-09-29 14:43:44 +020036from util import ppp
Neale Rannsc0a93142018-09-05 15:42:26 -070037from vpp_ip import DpoProto
38from vpp_ip_route import VppIpRoute, VppRoutePath
Paul Vinciguerra00671cf2018-11-25 12:47:04 -080039from vpp_lo_interface import VppLoInterface
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020040from vpp_papi_provider import UnexpectedApiReturnValueError, CliFailedCommandError
Paul Vinciguerra00671cf2018-11-25 12:47:04 -080041from vpp_pg_interface import CaptureTimeoutError, is_ipv6_misc
Neale Ranns52cd4962019-06-05 10:28:17 +000042from vpp_gre_interface import VppGreInterface
Jakub Grajciar4682feb2019-09-02 13:28:52 +020043from vpp_papi import VppEnum
Klement Sekera0e3c0de2016-09-29 14:43:44 +020044
Klement Sekerad3ba5152017-02-14 03:09:17 +010045USEC_IN_SEC = 1000000
Klement Sekera3e0a3562016-12-19 09:05:21 +010046
Klement Sekera0e3c0de2016-09-29 14:43:44 +020047
Klement Sekerab17dd962017-01-09 07:43:48 +010048class AuthKeyFactory(object):
49 """Factory class for creating auth keys with unique conf key ID"""
50
51 def __init__(self):
52 self._conf_key_ids = {}
53
54 def create_random_key(self, test, auth_type=BFDAuthType.keyed_sha1):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020055 """create a random key with unique conf key id"""
Klement Sekerab17dd962017-01-09 07:43:48 +010056 conf_key_id = randint(0, 0xFFFFFFFF)
57 while conf_key_id in self._conf_key_ids:
58 conf_key_id = randint(0, 0xFFFFFFFF)
59 self._conf_key_ids[conf_key_id] = 1
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -070060 key = scapy.compat.raw(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020061 bytearray([randint(0, 255) for _ in range(randint(1, 20))])
62 )
63 return VppBFDAuthKey(
64 test=test, auth_type=auth_type, conf_key_id=conf_key_id, key=key
65 )
Klement Sekerab17dd962017-01-09 07:43:48 +010066
67
Klement Sekerae4504c62016-12-08 10:16:41 +010068class BFDAPITestCase(VppTestCase):
69 """Bidirectional Forwarding Detection (BFD) - API"""
Klement Sekera0e3c0de2016-09-29 14:43:44 +020070
Klement Sekerad3ba5152017-02-14 03:09:17 +010071 pg0 = None
72 pg1 = None
73
Klement Sekera0e3c0de2016-09-29 14:43:44 +020074 @classmethod
75 def setUpClass(cls):
Klement Sekerae4504c62016-12-08 10:16:41 +010076 super(BFDAPITestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -080077 cls.vapi.cli("set log class bfd level debug")
Klement Sekera0e3c0de2016-09-29 14:43:44 +020078 try:
Klement Sekera10db26f2017-01-11 08:16:53 +010079 cls.create_pg_interfaces(range(2))
80 for i in cls.pg_interfaces:
81 i.config_ip4()
Klement Sekerab17dd962017-01-09 07:43:48 +010082 i.config_ip6()
Klement Sekera10db26f2017-01-11 08:16:53 +010083 i.resolve_arp()
Klement Sekera0e3c0de2016-09-29 14:43:44 +020084
85 except Exception:
Klement Sekerae4504c62016-12-08 10:16:41 +010086 super(BFDAPITestCase, cls).tearDownClass()
Klement Sekera0e3c0de2016-09-29 14:43:44 +020087 raise
88
Paul Vinciguerra8d991d92019-01-25 14:05:48 -080089 @classmethod
90 def tearDownClass(cls):
91 super(BFDAPITestCase, cls).tearDownClass()
92
Klement Sekerab17dd962017-01-09 07:43:48 +010093 def setUp(self):
94 super(BFDAPITestCase, self).setUp()
95 self.factory = AuthKeyFactory()
96
Klement Sekera0e3c0de2016-09-29 14:43:44 +020097 def test_add_bfd(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020098 """create a BFD session"""
Klement Sekera0e3c0de2016-09-29 14:43:44 +020099 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
100 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100101 self.logger.debug("Session state is %s", session.state)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200102 session.remove_vpp_config()
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200103 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100104 self.logger.debug("Session state is %s", session.state)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200105 session.remove_vpp_config()
106
107 def test_double_add(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200108 """create the same BFD session twice (negative case)"""
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200109 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
110 session.add_vpp_config()
Klement Sekerae0545ef2017-01-25 08:00:40 +0100111
Klement Sekera7d6afb32018-11-08 11:52:04 +0100112 with self.vapi.assert_negative_api_retval():
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200113 session.add_vpp_config()
Klement Sekerae0545ef2017-01-25 08:00:40 +0100114
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200115 session.remove_vpp_config()
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200116
Klement Sekerab17dd962017-01-09 07:43:48 +0100117 def test_add_bfd6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200118 """create IPv6 BFD session"""
119 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip6, af=AF_INET6)
Klement Sekerab17dd962017-01-09 07:43:48 +0100120 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100121 self.logger.debug("Session state is %s", session.state)
Klement Sekerab17dd962017-01-09 07:43:48 +0100122 session.remove_vpp_config()
123 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100124 self.logger.debug("Session state is %s", session.state)
Klement Sekerab17dd962017-01-09 07:43:48 +0100125 session.remove_vpp_config()
126
Klement Sekeraa57a9702017-02-02 06:58:07 +0100127 def test_mod_bfd(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200128 """modify BFD session parameters"""
129 session = VppBFDUDPSession(
130 self,
131 self.pg0,
132 self.pg0.remote_ip4,
133 desired_min_tx=50000,
134 required_min_rx=10000,
135 detect_mult=1,
136 )
Klement Sekeraa57a9702017-02-02 06:58:07 +0100137 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100138 s = session.get_bfd_udp_session_dump_entry()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200139 self.assert_equal(
140 session.desired_min_tx, s.desired_min_tx, "desired min transmit interval"
141 )
142 self.assert_equal(
143 session.required_min_rx, s.required_min_rx, "required min receive interval"
144 )
Klement Sekerad3ba5152017-02-14 03:09:17 +0100145 self.assert_equal(session.detect_mult, s.detect_mult, "detect mult")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200146 session.modify_parameters(
147 desired_min_tx=session.desired_min_tx * 2,
148 required_min_rx=session.required_min_rx * 2,
149 detect_mult=session.detect_mult * 2,
150 )
Klement Sekerad3ba5152017-02-14 03:09:17 +0100151 s = session.get_bfd_udp_session_dump_entry()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200152 self.assert_equal(
153 session.desired_min_tx, s.desired_min_tx, "desired min transmit interval"
154 )
155 self.assert_equal(
156 session.required_min_rx, s.required_min_rx, "required min receive interval"
157 )
Klement Sekerad3ba5152017-02-14 03:09:17 +0100158 self.assert_equal(session.detect_mult, s.detect_mult, "detect mult")
Klement Sekeraa57a9702017-02-02 06:58:07 +0100159
Neale Ranns63f2c7d2022-02-09 13:47:29 +0000160 def test_upd_bfd(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200161 """Create/Modify w/ Update BFD session parameters"""
162 session = VppBFDUDPSession(
163 self,
164 self.pg0,
165 self.pg0.remote_ip4,
166 desired_min_tx=50000,
167 required_min_rx=10000,
168 detect_mult=1,
169 )
Neale Ranns63f2c7d2022-02-09 13:47:29 +0000170 session.upd_vpp_config()
171 s = session.get_bfd_udp_session_dump_entry()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200172 self.assert_equal(
173 session.desired_min_tx, s.desired_min_tx, "desired min transmit interval"
174 )
175 self.assert_equal(
176 session.required_min_rx, s.required_min_rx, "required min receive interval"
177 )
Neale Ranns63f2c7d2022-02-09 13:47:29 +0000178
179 self.assert_equal(session.detect_mult, s.detect_mult, "detect mult")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200180 session.upd_vpp_config(
181 desired_min_tx=session.desired_min_tx * 2,
182 required_min_rx=session.required_min_rx * 2,
183 detect_mult=session.detect_mult * 2,
184 )
Neale Ranns63f2c7d2022-02-09 13:47:29 +0000185 s = session.get_bfd_udp_session_dump_entry()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200186 self.assert_equal(
187 session.desired_min_tx, s.desired_min_tx, "desired min transmit interval"
188 )
189 self.assert_equal(
190 session.required_min_rx, s.required_min_rx, "required min receive interval"
191 )
Neale Ranns63f2c7d2022-02-09 13:47:29 +0000192 self.assert_equal(session.detect_mult, s.detect_mult, "detect mult")
193
Klement Sekerab17dd962017-01-09 07:43:48 +0100194 def test_add_sha1_keys(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200195 """add SHA1 keys"""
Klement Sekerab17dd962017-01-09 07:43:48 +0100196 key_count = 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200197 keys = [self.factory.create_random_key(self) for i in range(0, key_count)]
Klement Sekerab17dd962017-01-09 07:43:48 +0100198 for key in keys:
199 self.assertFalse(key.query_vpp_config())
200 for key in keys:
201 key.add_vpp_config()
202 for key in keys:
203 self.assertTrue(key.query_vpp_config())
204 # remove randomly
snaramre73aff472019-12-02 05:49:28 +0000205 indexes = list(range(key_count))
Klement Sekerad3ba5152017-02-14 03:09:17 +0100206 shuffle(indexes)
Klement Sekerab17dd962017-01-09 07:43:48 +0100207 removed = []
208 for i in indexes:
209 key = keys[i]
210 key.remove_vpp_config()
211 removed.append(i)
212 for j in range(key_count):
213 key = keys[j]
214 if j in removed:
215 self.assertFalse(key.query_vpp_config())
216 else:
217 self.assertTrue(key.query_vpp_config())
218 # should be removed now
219 for key in keys:
220 self.assertFalse(key.query_vpp_config())
221 # add back and remove again
222 for key in keys:
223 key.add_vpp_config()
224 for key in keys:
225 self.assertTrue(key.query_vpp_config())
226 for key in keys:
227 key.remove_vpp_config()
228 for key in keys:
229 self.assertFalse(key.query_vpp_config())
230
231 def test_add_bfd_sha1(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200232 """create a BFD session (SHA1)"""
Klement Sekerab17dd962017-01-09 07:43:48 +0100233 key = self.factory.create_random_key(self)
234 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200235 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4, sha1_key=key)
Klement Sekerab17dd962017-01-09 07:43:48 +0100236 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100237 self.logger.debug("Session state is %s", session.state)
Klement Sekerab17dd962017-01-09 07:43:48 +0100238 session.remove_vpp_config()
239 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100240 self.logger.debug("Session state is %s", session.state)
Klement Sekerab17dd962017-01-09 07:43:48 +0100241 session.remove_vpp_config()
242
243 def test_double_add_sha1(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200244 """create the same BFD session twice (negative case) (SHA1)"""
Klement Sekerab17dd962017-01-09 07:43:48 +0100245 key = self.factory.create_random_key(self)
246 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200247 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4, sha1_key=key)
Klement Sekerab17dd962017-01-09 07:43:48 +0100248 session.add_vpp_config()
249 with self.assertRaises(Exception):
250 session.add_vpp_config()
251
Klement Sekerad3ba5152017-02-14 03:09:17 +0100252 def test_add_auth_nonexistent_key(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200253 """create BFD session using non-existent SHA1 (negative case)"""
Klement Sekerab17dd962017-01-09 07:43:48 +0100254 session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200255 self,
256 self.pg0,
257 self.pg0.remote_ip4,
258 sha1_key=self.factory.create_random_key(self),
259 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100260 with self.assertRaises(Exception):
261 session.add_vpp_config()
262
263 def test_shared_sha1_key(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200264 """single SHA1 key shared by multiple BFD sessions"""
Klement Sekerab17dd962017-01-09 07:43:48 +0100265 key = self.factory.create_random_key(self)
266 key.add_vpp_config()
267 sessions = [
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200268 VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4, sha1_key=key),
269 VppBFDUDPSession(
270 self, self.pg0, self.pg0.remote_ip6, sha1_key=key, af=AF_INET6
271 ),
272 VppBFDUDPSession(self, self.pg1, self.pg1.remote_ip4, sha1_key=key),
273 VppBFDUDPSession(
274 self, self.pg1, self.pg1.remote_ip6, sha1_key=key, af=AF_INET6
275 ),
276 ]
Klement Sekerab17dd962017-01-09 07:43:48 +0100277 for s in sessions:
278 s.add_vpp_config()
279 removed = 0
280 for s in sessions:
281 e = key.get_bfd_auth_keys_dump_entry()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200282 self.assert_equal(
283 e.use_count, len(sessions) - removed, "Use count for shared key"
284 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100285 s.remove_vpp_config()
286 removed += 1
287 e = key.get_bfd_auth_keys_dump_entry()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200288 self.assert_equal(
289 e.use_count, len(sessions) - removed, "Use count for shared key"
290 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100291
292 def test_activate_auth(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200293 """activate SHA1 authentication"""
Klement Sekerab17dd962017-01-09 07:43:48 +0100294 key = self.factory.create_random_key(self)
295 key.add_vpp_config()
296 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
297 session.add_vpp_config()
298 session.activate_auth(key)
299
300 def test_deactivate_auth(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200301 """deactivate SHA1 authentication"""
Klement Sekerab17dd962017-01-09 07:43:48 +0100302 key = self.factory.create_random_key(self)
303 key.add_vpp_config()
304 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
305 session.add_vpp_config()
306 session.activate_auth(key)
307 session.deactivate_auth()
308
309 def test_change_key(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200310 """change SHA1 key"""
Klement Sekerab17dd962017-01-09 07:43:48 +0100311 key1 = self.factory.create_random_key(self)
312 key2 = self.factory.create_random_key(self)
313 while key2.conf_key_id == key1.conf_key_id:
314 key2 = self.factory.create_random_key(self)
315 key1.add_vpp_config()
316 key2.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200317 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4, sha1_key=key1)
Klement Sekerab17dd962017-01-09 07:43:48 +0100318 session.add_vpp_config()
319 session.activate_auth(key2)
Klement Sekera10db26f2017-01-11 08:16:53 +0100320
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700321 def test_set_del_udp_echo_source(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200322 """set/del udp echo source"""
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700323 self.create_loopback_interfaces(1)
324 self.loopback0 = self.lo_interfaces[0]
325 self.loopback0.admin_up()
326 echo_source = self.vapi.bfd_udp_get_echo_source()
327 self.assertFalse(echo_source.is_set)
328 self.assertFalse(echo_source.have_usable_ip4)
329 self.assertFalse(echo_source.have_usable_ip6)
330
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200331 self.vapi.bfd_udp_set_echo_source(sw_if_index=self.loopback0.sw_if_index)
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700332 echo_source = self.vapi.bfd_udp_get_echo_source()
333 self.assertTrue(echo_source.is_set)
334 self.assertEqual(echo_source.sw_if_index, self.loopback0.sw_if_index)
335 self.assertFalse(echo_source.have_usable_ip4)
336 self.assertFalse(echo_source.have_usable_ip6)
337
338 self.loopback0.config_ip4()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200339 echo_ip4 = ipaddress.IPv4Address(
340 int(ipaddress.IPv4Address(self.loopback0.local_ip4)) ^ 1
341 ).packed
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700342 echo_source = self.vapi.bfd_udp_get_echo_source()
343 self.assertTrue(echo_source.is_set)
344 self.assertEqual(echo_source.sw_if_index, self.loopback0.sw_if_index)
345 self.assertTrue(echo_source.have_usable_ip4)
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200346 self.assertEqual(echo_source.ip4_addr.packed, echo_ip4)
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700347 self.assertFalse(echo_source.have_usable_ip6)
348
349 self.loopback0.config_ip6()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200350 echo_ip6 = ipaddress.IPv6Address(
351 int(ipaddress.IPv6Address(self.loopback0.local_ip6)) ^ 1
352 ).packed
Paul Vinciguerra2f156312020-05-02 22:34:40 -0400353
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700354 echo_source = self.vapi.bfd_udp_get_echo_source()
355 self.assertTrue(echo_source.is_set)
356 self.assertEqual(echo_source.sw_if_index, self.loopback0.sw_if_index)
357 self.assertTrue(echo_source.have_usable_ip4)
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200358 self.assertEqual(echo_source.ip4_addr.packed, echo_ip4)
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700359 self.assertTrue(echo_source.have_usable_ip6)
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200360 self.assertEqual(echo_source.ip6_addr.packed, echo_ip6)
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700361
362 self.vapi.bfd_udp_del_echo_source()
363 echo_source = self.vapi.bfd_udp_get_echo_source()
364 self.assertFalse(echo_source.is_set)
365 self.assertFalse(echo_source.have_usable_ip4)
366 self.assertFalse(echo_source.have_usable_ip6)
367
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200368
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200369class BFDTestSession(object):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200370 """BFD session as seen from test framework side"""
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200371
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200372 def __init__(
373 self,
374 test,
375 interface,
376 af,
377 detect_mult=3,
378 sha1_key=None,
379 bfd_key_id=None,
380 our_seq_number=None,
381 tunnel_header=None,
382 phy_interface=None,
383 ):
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200384 self.test = test
Klement Sekera46a87ad2017-01-02 08:22:23 +0100385 self.af = af
Klement Sekerab17dd962017-01-09 07:43:48 +0100386 self.sha1_key = sha1_key
387 self.bfd_key_id = bfd_key_id
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200388 self.interface = interface
Neale Ranns52cd4962019-06-05 10:28:17 +0000389 if phy_interface:
390 self.phy_interface = phy_interface
391 else:
392 self.phy_interface = self.interface
Klement Sekerad3ba5152017-02-14 03:09:17 +0100393 self.udp_sport = randint(49152, 65535)
394 if our_seq_number is None:
395 self.our_seq_number = randint(0, 40000000)
396 else:
397 self.our_seq_number = our_seq_number
Klement Sekerab17dd962017-01-09 07:43:48 +0100398 self.vpp_seq_number = None
Klement Sekerad3ba5152017-02-14 03:09:17 +0100399 self.my_discriminator = 0
Klement Sekera2e01dfa2017-04-03 08:10:08 +0200400 self.desired_min_tx = 300000
401 self.required_min_rx = 300000
Klement Sekera239790f2017-02-16 10:53:53 +0100402 self.required_min_echo_rx = None
Klement Sekerad3ba5152017-02-14 03:09:17 +0100403 self.detect_mult = detect_mult
404 self.diag = BFDDiagCode.no_diagnostic
405 self.your_discriminator = None
406 self.state = BFDState.down
407 self.auth_type = BFDAuthType.no_auth
Neale Ranns52cd4962019-06-05 10:28:17 +0000408 self.tunnel_header = tunnel_header
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000409 self.tx_packets = 0
410 self.rx_packets = 0
411 self.tx_packets_echo = 0
412 self.rx_packets_echo = 0
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200413
Klement Sekerab17dd962017-01-09 07:43:48 +0100414 def inc_seq_num(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200415 """increment sequence number, wrapping if needed"""
Klement Sekerab17dd962017-01-09 07:43:48 +0100416 if self.our_seq_number == 0xFFFFFFFF:
417 self.our_seq_number = 0
418 else:
419 self.our_seq_number += 1
420
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200421 def update(
422 self,
423 my_discriminator=None,
424 your_discriminator=None,
425 desired_min_tx=None,
426 required_min_rx=None,
427 required_min_echo_rx=None,
428 detect_mult=None,
429 diag=None,
430 state=None,
431 auth_type=None,
432 ):
433 """update BFD parameters associated with session"""
Klement Sekera239790f2017-02-16 10:53:53 +0100434 if my_discriminator is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100435 self.my_discriminator = my_discriminator
Klement Sekera239790f2017-02-16 10:53:53 +0100436 if your_discriminator is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100437 self.your_discriminator = your_discriminator
Klement Sekera239790f2017-02-16 10:53:53 +0100438 if required_min_rx is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100439 self.required_min_rx = required_min_rx
Klement Sekera239790f2017-02-16 10:53:53 +0100440 if required_min_echo_rx is not None:
441 self.required_min_echo_rx = required_min_echo_rx
442 if desired_min_tx is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100443 self.desired_min_tx = desired_min_tx
Klement Sekera239790f2017-02-16 10:53:53 +0100444 if detect_mult is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100445 self.detect_mult = detect_mult
Klement Sekera239790f2017-02-16 10:53:53 +0100446 if diag is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100447 self.diag = diag
Klement Sekera239790f2017-02-16 10:53:53 +0100448 if state is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100449 self.state = state
Klement Sekera239790f2017-02-16 10:53:53 +0100450 if auth_type is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100451 self.auth_type = auth_type
452
453 def fill_packet_fields(self, packet):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200454 """set packet fields with known values in packet"""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100455 bfd = packet[BFD]
456 if self.my_discriminator:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200457 self.test.logger.debug(
458 "BFD: setting packet.my_discriminator=%s", self.my_discriminator
459 )
Klement Sekerad3ba5152017-02-14 03:09:17 +0100460 bfd.my_discriminator = self.my_discriminator
461 if self.your_discriminator:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200462 self.test.logger.debug(
463 "BFD: setting packet.your_discriminator=%s", self.your_discriminator
464 )
Klement Sekerad3ba5152017-02-14 03:09:17 +0100465 bfd.your_discriminator = self.your_discriminator
466 if self.required_min_rx:
467 self.test.logger.debug(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200468 "BFD: setting packet.required_min_rx_interval=%s", self.required_min_rx
469 )
Klement Sekerad3ba5152017-02-14 03:09:17 +0100470 bfd.required_min_rx_interval = self.required_min_rx
Klement Sekera239790f2017-02-16 10:53:53 +0100471 if self.required_min_echo_rx:
472 self.test.logger.debug(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200473 "BFD: setting packet.required_min_echo_rx=%s", self.required_min_echo_rx
474 )
Klement Sekera239790f2017-02-16 10:53:53 +0100475 bfd.required_min_echo_rx_interval = self.required_min_echo_rx
Klement Sekerad3ba5152017-02-14 03:09:17 +0100476 if self.desired_min_tx:
477 self.test.logger.debug(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200478 "BFD: setting packet.desired_min_tx_interval=%s", self.desired_min_tx
479 )
Klement Sekerad3ba5152017-02-14 03:09:17 +0100480 bfd.desired_min_tx_interval = self.desired_min_tx
481 if self.detect_mult:
482 self.test.logger.debug(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200483 "BFD: setting packet.detect_mult=%s", self.detect_mult
484 )
Klement Sekerad3ba5152017-02-14 03:09:17 +0100485 bfd.detect_mult = self.detect_mult
486 if self.diag:
487 self.test.logger.debug("BFD: setting packet.diag=%s", self.diag)
488 bfd.diag = self.diag
489 if self.state:
490 self.test.logger.debug("BFD: setting packet.state=%s", self.state)
491 bfd.state = self.state
492 if self.auth_type:
493 # this is used by a negative test-case
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200494 self.test.logger.debug("BFD: setting packet.auth_type=%s", self.auth_type)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100495 bfd.auth_type = self.auth_type
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200496
497 def create_packet(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200498 """create a BFD packet, reflecting the current state of session"""
Klement Sekerab17dd962017-01-09 07:43:48 +0100499 if self.sha1_key:
500 bfd = BFD(flags="A")
501 bfd.auth_type = self.sha1_key.auth_type
502 bfd.auth_len = BFD.sha1_auth_len
503 bfd.auth_key_id = self.bfd_key_id
504 bfd.auth_seq_num = self.our_seq_number
505 bfd.length = BFD.sha1_auth_len + BFD.bfd_pkt_len
506 else:
507 bfd = BFD()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200508 packet = Ether(
509 src=self.phy_interface.remote_mac, dst=self.phy_interface.local_mac
510 )
Neale Ranns52cd4962019-06-05 10:28:17 +0000511 if self.tunnel_header:
512 packet = packet / self.tunnel_header
Klement Sekera46a87ad2017-01-02 08:22:23 +0100513 if self.af == AF_INET6:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200514 packet = (
515 packet
516 / IPv6(
517 src=self.interface.remote_ip6,
518 dst=self.interface.local_ip6,
519 hlim=255,
520 )
521 / UDP(sport=self.udp_sport, dport=BFD.udp_dport)
522 / bfd
523 )
Klement Sekera46a87ad2017-01-02 08:22:23 +0100524 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200525 packet = (
526 packet
527 / IP(
528 src=self.interface.remote_ip4, dst=self.interface.local_ip4, ttl=255
529 )
530 / UDP(sport=self.udp_sport, dport=BFD.udp_dport)
531 / bfd
532 )
Klement Sekera3e0a3562016-12-19 09:05:21 +0100533 self.test.logger.debug("BFD: Creating packet")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100534 self.fill_packet_fields(packet)
Klement Sekerab17dd962017-01-09 07:43:48 +0100535 if self.sha1_key:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200536 hash_material = (
537 scapy.compat.raw(packet[BFD])[:32]
538 + self.sha1_key.key
539 + b"\0" * (20 - len(self.sha1_key.key))
540 )
541 self.test.logger.debug(
542 "BFD: Calculated SHA1 hash: %s"
543 % hashlib.sha1(hash_material).hexdigest()
544 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100545 packet[BFD].auth_key_hash = hashlib.sha1(hash_material).digest()
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200546 return packet
547
Klement Sekerad3ba5152017-02-14 03:09:17 +0100548 def send_packet(self, packet=None, interface=None):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200549 """send packet on interface, creating the packet if needed"""
Klement Sekeraa57a9702017-02-02 06:58:07 +0100550 if packet is None:
551 packet = self.create_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100552 if interface is None:
Neale Ranns52cd4962019-06-05 10:28:17 +0000553 interface = self.phy_interface
Klement Sekeraa57a9702017-02-02 06:58:07 +0100554 self.test.logger.debug(ppp("Sending packet:", packet))
Klement Sekerad3ba5152017-02-14 03:09:17 +0100555 interface.add_stream(packet)
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000556 self.tx_packets += 1
Klement Sekera9225dee2016-12-12 08:36:58 +0100557 self.test.pg_start()
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200558
Klement Sekerab17dd962017-01-09 07:43:48 +0100559 def verify_sha1_auth(self, packet):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200560 """Verify correctness of authentication in BFD layer."""
Klement Sekerab17dd962017-01-09 07:43:48 +0100561 bfd = packet[BFD]
562 self.test.assert_equal(bfd.auth_len, 28, "Auth section length")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200563 self.test.assert_equal(bfd.auth_type, self.sha1_key.auth_type, BFDAuthType)
Klement Sekerab17dd962017-01-09 07:43:48 +0100564 self.test.assert_equal(bfd.auth_key_id, self.bfd_key_id, "Key ID")
565 self.test.assert_equal(bfd.auth_reserved, 0, "Reserved")
566 if self.vpp_seq_number is None:
567 self.vpp_seq_number = bfd.auth_seq_num
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200568 self.test.logger.debug(
569 "Received initial sequence number: %s" % self.vpp_seq_number
570 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100571 else:
572 recvd_seq_num = bfd.auth_seq_num
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200573 self.test.logger.debug(
574 "Received followup sequence number: %s" % recvd_seq_num
575 )
576 if self.vpp_seq_number < 0xFFFFFFFF:
577 if self.sha1_key.auth_type == BFDAuthType.meticulous_keyed_sha1:
578 self.test.assert_equal(
579 recvd_seq_num, self.vpp_seq_number + 1, "BFD sequence number"
580 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100581 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200582 self.test.assert_in_range(
583 recvd_seq_num,
584 self.vpp_seq_number,
585 self.vpp_seq_number + 1,
586 "BFD sequence number",
587 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100588 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200589 if self.sha1_key.auth_type == BFDAuthType.meticulous_keyed_sha1:
590 self.test.assert_equal(recvd_seq_num, 0, "BFD sequence number")
Klement Sekerab17dd962017-01-09 07:43:48 +0100591 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200592 self.test.assertIn(
593 recvd_seq_num,
594 (self.vpp_seq_number, 0),
595 "BFD sequence number not one of "
596 "(%s, 0)" % self.vpp_seq_number,
597 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100598 self.vpp_seq_number = recvd_seq_num
599 # last 20 bytes represent the hash - so replace them with the key,
600 # pad the result with zeros and hash the result
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200601 hash_material = (
602 bfd.original[:-20]
603 + self.sha1_key.key
604 + b"\0" * (20 - len(self.sha1_key.key))
605 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100606 expected_hash = hashlib.sha1(hash_material).hexdigest()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200607 self.test.assert_equal(
608 binascii.hexlify(bfd.auth_key_hash), expected_hash.encode(), "Auth key hash"
609 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100610
611 def verify_bfd(self, packet):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200612 """Verify correctness of BFD layer."""
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200613 bfd = packet[BFD]
614 self.test.assert_equal(bfd.version, 1, "BFD version")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200615 self.test.assert_equal(
616 bfd.your_discriminator, self.my_discriminator, "BFD - your discriminator"
617 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100618 if self.sha1_key:
619 self.verify_sha1_auth(packet)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200620
621
Klement Sekerad3ba5152017-02-14 03:09:17 +0100622def bfd_session_up(test):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200623 """Bring BFD session up"""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100624 test.logger.info("BFD: Waiting for slow hello")
Neale Ranns52cd4962019-06-05 10:28:17 +0000625 p = wait_for_bfd_packet(test, 2, is_tunnel=test.vpp_session.is_tunnel)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100626 old_offset = None
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200627 if hasattr(test, "vpp_clock_offset"):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100628 old_offset = test.vpp_clock_offset
snaramre73aff472019-12-02 05:49:28 +0000629 test.vpp_clock_offset = time.time() - float(p.time)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200630 test.logger.debug("BFD: Calculated vpp clock offset: %s", test.vpp_clock_offset)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100631 if old_offset:
632 test.assertAlmostEqual(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200633 old_offset,
634 test.vpp_clock_offset,
635 delta=0.5,
636 msg="vpp clock offset not stable (new: %s, old: %s)"
637 % (test.vpp_clock_offset, old_offset),
638 )
Klement Sekerad3ba5152017-02-14 03:09:17 +0100639 test.logger.info("BFD: Sending Init")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200640 test.test_session.update(
641 my_discriminator=randint(0, 40000000),
642 your_discriminator=p[BFD].my_discriminator,
643 state=BFDState.init,
644 )
645 if (
646 test.test_session.sha1_key
647 and test.test_session.sha1_key.auth_type == BFDAuthType.meticulous_keyed_sha1
648 ):
Klement Sekera73884482017-02-23 09:26:30 +0100649 test.test_session.inc_seq_num()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100650 test.test_session.send_packet()
651 test.logger.info("BFD: Waiting for event")
Ole Troan4376ab22021-03-03 10:40:05 +0100652 e = test.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100653 verify_event(test, e, expected_state=BFDState.up)
654 test.logger.info("BFD: Session is Up")
655 test.test_session.update(state=BFDState.up)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200656 if (
657 test.test_session.sha1_key
658 and test.test_session.sha1_key.auth_type == BFDAuthType.meticulous_keyed_sha1
659 ):
Klement Sekera73884482017-02-23 09:26:30 +0100660 test.test_session.inc_seq_num()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100661 test.test_session.send_packet()
662 test.assert_equal(test.vpp_session.state, BFDState.up, BFDState)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200663
Klement Sekera46a87ad2017-01-02 08:22:23 +0100664
Klement Sekerad3ba5152017-02-14 03:09:17 +0100665def bfd_session_down(test):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200666 """Bring BFD session down"""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100667 test.assert_equal(test.vpp_session.state, BFDState.up, BFDState)
668 test.test_session.update(state=BFDState.down)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200669 if (
670 test.test_session.sha1_key
671 and test.test_session.sha1_key.auth_type == BFDAuthType.meticulous_keyed_sha1
672 ):
Klement Sekera73884482017-02-23 09:26:30 +0100673 test.test_session.inc_seq_num()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100674 test.test_session.send_packet()
675 test.logger.info("BFD: Waiting for event")
Ole Troan4376ab22021-03-03 10:40:05 +0100676 e = test.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100677 verify_event(test, e, expected_state=BFDState.down)
678 test.logger.info("BFD: Session is Down")
679 test.assert_equal(test.vpp_session.state, BFDState.down, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +0100680
Klement Sekera46a87ad2017-01-02 08:22:23 +0100681
Klement Sekera73884482017-02-23 09:26:30 +0100682def verify_bfd_session_config(test, session, state=None):
683 dump = session.get_bfd_udp_session_dump_entry()
684 test.assertIsNotNone(dump)
685 # since dump is not none, we have verified that sw_if_index and addresses
686 # are valid (in get_bfd_udp_session_dump_entry)
687 if state:
688 test.assert_equal(dump.state, state, "session state")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200689 test.assert_equal(
690 dump.required_min_rx, session.required_min_rx, "required min rx interval"
691 )
692 test.assert_equal(
693 dump.desired_min_tx, session.desired_min_tx, "desired min tx interval"
694 )
695 test.assert_equal(dump.detect_mult, session.detect_mult, "detect multiplier")
Klement Sekera73884482017-02-23 09:26:30 +0100696 if session.sha1_key is None:
697 test.assert_equal(dump.is_authenticated, 0, "is_authenticated flag")
698 else:
699 test.assert_equal(dump.is_authenticated, 1, "is_authenticated flag")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200700 test.assert_equal(dump.bfd_key_id, session.bfd_key_id, "bfd key id")
701 test.assert_equal(
702 dump.conf_key_id, session.sha1_key.conf_key_id, "config key id"
703 )
Klement Sekera73884482017-02-23 09:26:30 +0100704
705
Klement Sekerad3ba5152017-02-14 03:09:17 +0100706def verify_ip(test, packet):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200707 """Verify correctness of IP layer."""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100708 if test.vpp_session.af == AF_INET6:
709 ip = packet[IPv6]
Neale Ranns52cd4962019-06-05 10:28:17 +0000710 local_ip = test.vpp_session.interface.local_ip6
711 remote_ip = test.vpp_session.interface.remote_ip6
Klement Sekerad3ba5152017-02-14 03:09:17 +0100712 test.assert_equal(ip.hlim, 255, "IPv6 hop limit")
713 else:
714 ip = packet[IP]
Neale Ranns52cd4962019-06-05 10:28:17 +0000715 local_ip = test.vpp_session.interface.local_ip4
716 remote_ip = test.vpp_session.interface.remote_ip4
Klement Sekerad3ba5152017-02-14 03:09:17 +0100717 test.assert_equal(ip.ttl, 255, "IPv4 TTL")
718 test.assert_equal(ip.src, local_ip, "IP source address")
719 test.assert_equal(ip.dst, remote_ip, "IP destination address")
720
721
722def verify_udp(test, packet):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200723 """Verify correctness of UDP layer."""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100724 udp = packet[UDP]
725 test.assert_equal(udp.dport, BFD.udp_dport, "UDP destination port")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200726 test.assert_in_range(
727 udp.sport, BFD.udp_sport_min, BFD.udp_sport_max, "UDP source port"
728 )
Klement Sekerad3ba5152017-02-14 03:09:17 +0100729
730
731def verify_event(test, event, expected_state):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200732 """Verify correctness of event values."""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100733 e = event
Paul Vinciguerra090096b2020-12-03 00:42:46 -0500734 test.logger.debug("BFD: Event: %s" % reprlib.repr(e))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200735 test.assert_equal(
736 e.sw_if_index, test.vpp_session.interface.sw_if_index, "BFD interface index"
737 )
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200738
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200739 test.assert_equal(
740 str(e.local_addr), test.vpp_session.local_addr, "Local IPv6 address"
741 )
742 test.assert_equal(str(e.peer_addr), test.vpp_session.peer_addr, "Peer IPv6 address")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100743 test.assert_equal(e.state, expected_state, BFDState)
744
745
Neale Ranns52cd4962019-06-05 10:28:17 +0000746def wait_for_bfd_packet(test, timeout=1, pcap_time_min=None, is_tunnel=False):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200747 """wait for BFD packet and verify its correctness
Klement Sekerad3ba5152017-02-14 03:09:17 +0100748
749 :param timeout: how long to wait
750 :param pcap_time_min: ignore packets with pcap timestamp lower than this
751
752 :returns: tuple (packet, time spent waiting for packet)
753 """
754 test.logger.info("BFD: Waiting for BFD packet")
755 deadline = time.time() + timeout
756 counter = 0
757 while True:
758 counter += 1
759 # sanity check
760 test.assert_in_range(counter, 0, 100, "number of packets ignored")
761 time_left = deadline - time.time()
762 if time_left < 0:
763 raise CaptureTimeoutError("Packet did not arrive within timeout")
764 p = test.pg0.wait_for_packet(timeout=time_left)
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000765 test.test_session.rx_packets += 1
Klement Sekerad3ba5152017-02-14 03:09:17 +0100766 test.logger.debug(ppp("BFD: Got packet:", p))
767 if pcap_time_min is not None and p.time < pcap_time_min:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200768 test.logger.debug(
769 ppp(
770 "BFD: ignoring packet (pcap time %s < "
771 "pcap time min %s):" % (p.time, pcap_time_min),
772 p,
773 )
774 )
Klement Sekera46a87ad2017-01-02 08:22:23 +0100775 else:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100776 break
Klement Sekera617d4292022-09-20 15:10:10 +0200777 test.logger.debug(test.vapi.ppcli("show trace"))
Neale Ranns52cd4962019-06-05 10:28:17 +0000778 if is_tunnel:
779 # strip an IP layer and move to the next
780 p = p[IP].payload
781
Klement Sekerad3ba5152017-02-14 03:09:17 +0100782 bfd = p[BFD]
783 if bfd is None:
784 raise Exception(ppp("Unexpected or invalid BFD packet:", p))
785 if bfd.payload:
786 raise Exception(ppp("Unexpected payload in BFD packet:", bfd))
787 verify_ip(test, p)
788 verify_udp(test, p)
789 test.test_session.verify_bfd(p)
790 return p
Klement Sekera3e0a3562016-12-19 09:05:21 +0100791
Klement Sekera46a87ad2017-01-02 08:22:23 +0100792
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000793BFDStats = namedtuple("BFDStats", "rx rx_echo tx tx_echo")
794
795
796def bfd_grab_stats_snapshot(test, bs_idx=0, thread_index=None):
797 s = test.statistics
798 ti = thread_index
799 if ti is None:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200800 rx = s["/bfd/rx-session-counters"][:, bs_idx].sum_packets()
801 rx_echo = s["/bfd/rx-session-echo-counters"][:, bs_idx].sum_packets()
802 tx = s["/bfd/tx-session-counters"][:, bs_idx].sum_packets()
803 tx_echo = s["/bfd/tx-session-echo-counters"][:, bs_idx].sum_packets()
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000804 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200805 rx = s["/bfd/rx-session-counters"][ti, bs_idx].sum_packets()
806 rx_echo = s["/bfd/rx-session-echo-counters"][ti, bs_idx].sum_packets()
807 tx = s["/bfd/tx-session-counters"][ti, bs_idx].sum_packets()
808 tx_echo = s["/bfd/tx-session-echo-counters"][ti, bs_idx].sum_packets()
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000809 return BFDStats(rx, rx_echo, tx, tx_echo)
810
811
812def bfd_stats_diff(stats_before, stats_after):
813 rx = stats_after.rx - stats_before.rx
814 rx_echo = stats_after.rx_echo - stats_before.rx_echo
815 tx = stats_after.tx - stats_before.tx
816 tx_echo = stats_after.tx_echo - stats_before.tx_echo
817 return BFDStats(rx, rx_echo, tx, tx_echo)
818
819
Andrew Yourtchenko06f32812021-01-14 10:19:08 +0000820@tag_run_solo
Klement Sekerad3ba5152017-02-14 03:09:17 +0100821class BFD4TestCase(VppTestCase):
Klement Sekera46a87ad2017-01-02 08:22:23 +0100822 """Bidirectional Forwarding Detection (BFD)"""
823
Klement Sekerad3ba5152017-02-14 03:09:17 +0100824 pg0 = None
825 vpp_clock_offset = None
826 vpp_session = None
827 test_session = None
828
Klement Sekera46a87ad2017-01-02 08:22:23 +0100829 @classmethod
830 def setUpClass(cls):
831 super(BFD4TestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -0800832 cls.vapi.cli("set log class bfd level debug")
Klement Sekera46a87ad2017-01-02 08:22:23 +0100833 try:
834 cls.create_pg_interfaces([0])
Klement Sekerab9ef2732018-06-24 22:49:33 +0200835 cls.create_loopback_interfaces(1)
Klement Sekera239790f2017-02-16 10:53:53 +0100836 cls.loopback0 = cls.lo_interfaces[0]
837 cls.loopback0.config_ip4()
838 cls.loopback0.admin_up()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100839 cls.pg0.config_ip4()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100840 cls.pg0.configure_ipv4_neighbors()
841 cls.pg0.admin_up()
842 cls.pg0.resolve_arp()
843
844 except Exception:
845 super(BFD4TestCase, cls).tearDownClass()
846 raise
847
Paul Vinciguerra8d991d92019-01-25 14:05:48 -0800848 @classmethod
849 def tearDownClass(cls):
850 super(BFD4TestCase, cls).tearDownClass()
851
Klement Sekera46a87ad2017-01-02 08:22:23 +0100852 def setUp(self):
853 super(BFD4TestCase, self).setUp()
Klement Sekerab17dd962017-01-09 07:43:48 +0100854 self.factory = AuthKeyFactory()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100855 self.vapi.want_bfd_events()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100856 self.pg0.enable_capture()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100857 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200858 self.bfd_udp4_sessions = self.statistics["/bfd/udp4/sessions"]
859 self.bfd_udp6_sessions = self.statistics["/bfd/udp6/sessions"]
Klement Sekera617d4292022-09-20 15:10:10 +0200860 self.vapi.cli("trace add bfd-process 500")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200861 self.vpp_session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
Klement Sekera46a87ad2017-01-02 08:22:23 +0100862 self.vpp_session.add_vpp_config()
863 self.vpp_session.admin_up()
864 self.test_session = BFDTestSession(self, self.pg0, AF_INET)
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200865 except BaseException:
Klement Sekera46a87ad2017-01-02 08:22:23 +0100866 self.vapi.want_bfd_events(enable_disable=0)
867 raise
868
869 def tearDown(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100870 if not self.vpp_dead:
871 self.vapi.want_bfd_events(enable_disable=0)
872 self.vapi.collect_events() # clear the event queue
873 super(BFD4TestCase, self).tearDown()
Klement Sekerab17dd962017-01-09 07:43:48 +0100874
875 def test_session_up(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200876 """bring BFD session up"""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100877 bfd_session_up(self)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200878 bfd_udp4_sessions = self.statistics["/bfd/udp4/sessions"]
879 bfd_udp6_sessions = self.statistics["/bfd/udp6/sessions"]
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000880 self.assert_equal(bfd_udp4_sessions - self.bfd_udp4_sessions, 1)
881 self.assert_equal(bfd_udp6_sessions, self.bfd_udp6_sessions)
Klement Sekerab17dd962017-01-09 07:43:48 +0100882
Klement Sekera73884482017-02-23 09:26:30 +0100883 def test_session_up_by_ip(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200884 """bring BFD session up - first frame looked up by address pair"""
Klement Sekera73884482017-02-23 09:26:30 +0100885 self.logger.info("BFD: Sending Slow control frame")
886 self.test_session.update(my_discriminator=randint(0, 40000000))
887 self.test_session.send_packet()
888 self.pg0.enable_capture()
889 p = self.pg0.wait_for_packet(1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200890 self.assert_equal(
891 p[BFD].your_discriminator,
892 self.test_session.my_discriminator,
893 "BFD - your discriminator",
894 )
Klement Sekera73884482017-02-23 09:26:30 +0100895 self.assert_equal(p[BFD].state, BFDState.init, BFDState)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200896 self.test_session.update(
897 your_discriminator=p[BFD].my_discriminator, state=BFDState.up
898 )
Klement Sekera73884482017-02-23 09:26:30 +0100899 self.logger.info("BFD: Waiting for event")
Ole Troan4376ab22021-03-03 10:40:05 +0100900 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekera73884482017-02-23 09:26:30 +0100901 verify_event(self, e, expected_state=BFDState.init)
902 self.logger.info("BFD: Sending Up")
903 self.test_session.send_packet()
904 self.logger.info("BFD: Waiting for event")
Ole Troan4376ab22021-03-03 10:40:05 +0100905 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekera73884482017-02-23 09:26:30 +0100906 verify_event(self, e, expected_state=BFDState.up)
907 self.logger.info("BFD: Session is Up")
908 self.test_session.update(state=BFDState.up)
909 self.test_session.send_packet()
910 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
911
Klement Sekerab17dd962017-01-09 07:43:48 +0100912 def test_session_down(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200913 """bring BFD session down"""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100914 bfd_session_up(self)
915 bfd_session_down(self)
Klement Sekerab17dd962017-01-09 07:43:48 +0100916
917 def test_hold_up(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200918 """hold BFD session up"""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100919 bfd_session_up(self)
920 for dummy in range(self.test_session.detect_mult * 2):
921 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +0100922 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200923 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekera46a87ad2017-01-02 08:22:23 +0100924
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200925 def test_slow_timer(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200926 """verify slow periodic control frames while session down"""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100927 packet_count = 3
928 self.logger.info("BFD: Waiting for %d BFD packets", packet_count)
929 prev_packet = wait_for_bfd_packet(self, 2)
930 for dummy in range(packet_count):
931 next_packet = wait_for_bfd_packet(self, 2)
932 time_diff = next_packet.time - prev_packet.time
Klement Sekerae4504c62016-12-08 10:16:41 +0100933 # spec says the range should be <0.75, 1>, allow extra 0.05 margin
934 # to work around timing issues
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200935 self.assert_in_range(time_diff, 0.70, 1.05, "time between slow packets")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100936 prev_packet = next_packet
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200937
938 def test_zero_remote_min_rx(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200939 """no packets when zero remote required min rx interval"""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100940 bfd_session_up(self)
941 self.test_session.update(required_min_rx=0)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200942 self.test_session.send_packet()
Klement Sekera239790f2017-02-16 10:53:53 +0100943 for dummy in range(self.test_session.detect_mult):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200944 self.sleep(
945 self.vpp_session.required_min_rx / USEC_IN_SEC,
946 "sleep before transmitting bfd packet",
947 )
Klement Sekera239790f2017-02-16 10:53:53 +0100948 self.test_session.send_packet()
Klement Sekeraa57a9702017-02-02 06:58:07 +0100949 try:
Klement Sekera239790f2017-02-16 10:53:53 +0100950 p = wait_for_bfd_packet(self, timeout=0)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100951 self.logger.error(ppp("Received unexpected packet:", p))
Klement Sekerad3ba5152017-02-14 03:09:17 +0100952 except CaptureTimeoutError:
Klement Sekeraa57a9702017-02-02 06:58:07 +0100953 pass
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200954 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekera2e01dfa2017-04-03 08:10:08 +0200955 self.test_session.update(required_min_rx=300000)
Klement Sekera239790f2017-02-16 10:53:53 +0100956 for dummy in range(3):
957 self.test_session.send_packet()
958 wait_for_bfd_packet(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200959 self, timeout=self.test_session.required_min_rx / USEC_IN_SEC
960 )
961 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200962
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200963 def test_conn_down(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200964 """verify session goes down after inactivity"""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100965 bfd_session_up(self)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200966 detection_time = (
967 self.test_session.detect_mult
968 * self.vpp_session.required_min_rx
969 / USEC_IN_SEC
970 )
Klement Sekerac48829b2017-02-14 07:55:57 +0100971 self.sleep(detection_time, "waiting for BFD session time-out")
Ole Troan4376ab22021-03-03 10:40:05 +0100972 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100973 verify_event(self, e, expected_state=BFDState.down)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200974
Klement Sekera4d39f9c2020-01-17 10:01:52 +0000975 def test_peer_discr_reset_sess_down(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200976 """peer discriminator reset after session goes down"""
Klement Sekera4d39f9c2020-01-17 10:01:52 +0000977 bfd_session_up(self)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200978 detection_time = (
979 self.test_session.detect_mult
980 * self.vpp_session.required_min_rx
981 / USEC_IN_SEC
982 )
Klement Sekera4d39f9c2020-01-17 10:01:52 +0000983 self.sleep(detection_time, "waiting for BFD session time-out")
984 self.test_session.my_discriminator = 0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200985 wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekera4d39f9c2020-01-17 10:01:52 +0000986
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200987 def test_large_required_min_rx(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200988 """large remote required min rx interval"""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100989 bfd_session_up(self)
990 p = wait_for_bfd_packet(self)
Klement Sekera637b9c42016-12-08 05:19:14 +0100991 interval = 3000000
Klement Sekerad3ba5152017-02-14 03:09:17 +0100992 self.test_session.update(required_min_rx=interval)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200993 self.test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100994 time_mark = time.time()
Klement Sekera637b9c42016-12-08 05:19:14 +0100995 count = 0
Klement Sekeraa57a9702017-02-02 06:58:07 +0100996 # busy wait here, trying to collect a packet or event, vpp is not
997 # allowed to send packets and the session will timeout first - so the
998 # Up->Down event must arrive before any packets do
Klement Sekerad3ba5152017-02-14 03:09:17 +0100999 while time.time() < time_mark + interval / USEC_IN_SEC:
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001000 try:
Klement Sekerad3ba5152017-02-14 03:09:17 +01001001 p = wait_for_bfd_packet(self, timeout=0)
1002 # if vpp managed to send a packet before we did the session
1003 # session update, then that's fine, ignore it
1004 if p.time < time_mark - self.vpp_clock_offset:
1005 continue
Klement Sekeraa57a9702017-02-02 06:58:07 +01001006 self.logger.error(ppp("Received unexpected packet:", p))
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001007 count += 1
Klement Sekerad3ba5152017-02-14 03:09:17 +01001008 except CaptureTimeoutError:
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001009 pass
Klement Sekeraa57a9702017-02-02 06:58:07 +01001010 events = self.vapi.collect_events()
1011 if len(events) > 0:
Klement Sekerad3ba5152017-02-14 03:09:17 +01001012 verify_event(self, events[0], BFDState.down)
Klement Sekeraa57a9702017-02-02 06:58:07 +01001013 break
1014 self.assert_equal(count, 0, "number of packets received")
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001015
Klement Sekerad3ba5152017-02-14 03:09:17 +01001016 def test_immediate_remote_min_rx_reduction(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001017 """immediately honor remote required min rx reduction"""
Klement Sekera3e0a3562016-12-19 09:05:21 +01001018 self.vpp_session.remove_vpp_config()
Klement Sekera10db26f2017-01-11 08:16:53 +01001019 self.vpp_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001020 self, self.pg0, self.pg0.remote_ip4, desired_min_tx=10000
1021 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01001022 self.pg0.enable_capture()
Klement Sekera3e0a3562016-12-19 09:05:21 +01001023 self.vpp_session.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001024 self.test_session.update(desired_min_tx=1000000, required_min_rx=1000000)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001025 bfd_session_up(self)
1026 reference_packet = wait_for_bfd_packet(self)
1027 time_mark = time.time()
1028 interval = 300000
1029 self.test_session.update(required_min_rx=interval)
Klement Sekera3e0a3562016-12-19 09:05:21 +01001030 self.test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +01001031 extra_time = time.time() - time_mark
1032 p = wait_for_bfd_packet(self)
1033 # first packet is allowed to be late by time we spent doing the update
1034 # calculated in extra_time
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001035 self.assert_in_range(
1036 p.time - reference_packet.time,
1037 0.95 * 0.75 * interval / USEC_IN_SEC,
1038 1.05 * interval / USEC_IN_SEC + extra_time,
1039 "time between BFD packets",
1040 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01001041 reference_packet = p
1042 for dummy in range(3):
1043 p = wait_for_bfd_packet(self)
1044 diff = p.time - reference_packet.time
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001045 self.assert_in_range(
1046 diff,
1047 0.95 * 0.75 * interval / USEC_IN_SEC,
1048 1.05 * interval / USEC_IN_SEC,
1049 "time between BFD packets",
1050 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01001051 reference_packet = p
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001052
Klement Sekeraa57a9702017-02-02 06:58:07 +01001053 def test_modify_req_min_rx_double(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001054 """modify session - double required min rx"""
Klement Sekerad3ba5152017-02-14 03:09:17 +01001055 bfd_session_up(self)
1056 p = wait_for_bfd_packet(self)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001057 self.test_session.update(desired_min_tx=10000, required_min_rx=10000)
Klement Sekeraa57a9702017-02-02 06:58:07 +01001058 self.test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +01001059 # double required min rx
Klement Sekeraa57a9702017-02-02 06:58:07 +01001060 self.vpp_session.modify_parameters(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001061 required_min_rx=2 * self.vpp_session.required_min_rx
1062 )
1063 p = wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekeraa57a9702017-02-02 06:58:07 +01001064 # poll bit needs to be set
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001065 self.assertIn("P", p.sprintf("%BFD.flags%"), "Poll bit not set in BFD packet")
Klement Sekeraa57a9702017-02-02 06:58:07 +01001066 # finish poll sequence with final packet
1067 final = self.test_session.create_packet()
1068 final[BFD].flags = "F"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001069 timeout = (
1070 self.test_session.detect_mult
1071 * max(self.test_session.desired_min_tx, self.vpp_session.required_min_rx)
1072 / USEC_IN_SEC
1073 )
Klement Sekeraa57a9702017-02-02 06:58:07 +01001074 self.test_session.send_packet(final)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001075 time_mark = time.time()
Ole Troan4376ab22021-03-03 10:40:05 +01001076 e = self.vapi.wait_for_event(2 * timeout, "bfd_udp_session_event")
Klement Sekerad3ba5152017-02-14 03:09:17 +01001077 verify_event(self, e, expected_state=BFDState.down)
1078 time_to_event = time.time() - time_mark
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001079 self.assert_in_range(
1080 time_to_event, 0.9 * timeout, 1.1 * timeout, "session timeout"
1081 )
Klement Sekeraa57a9702017-02-02 06:58:07 +01001082
1083 def test_modify_req_min_rx_halve(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001084 """modify session - halve required min rx"""
Klement Sekeraa57a9702017-02-02 06:58:07 +01001085 self.vpp_session.modify_parameters(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001086 required_min_rx=2 * self.vpp_session.required_min_rx
1087 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01001088 bfd_session_up(self)
1089 p = wait_for_bfd_packet(self)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001090 self.test_session.update(desired_min_tx=10000, required_min_rx=10000)
Klement Sekeraa57a9702017-02-02 06:58:07 +01001091 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001092 p = wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekeraa57a9702017-02-02 06:58:07 +01001093 # halve required min rx
1094 old_required_min_rx = self.vpp_session.required_min_rx
1095 self.vpp_session.modify_parameters(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001096 required_min_rx=self.vpp_session.required_min_rx // 2
1097 )
Klement Sekeraa57a9702017-02-02 06:58:07 +01001098 # now we wait 0.8*3*old-req-min-rx and the session should still be up
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001099 self.sleep(
1100 0.8 * self.vpp_session.detect_mult * old_required_min_rx / USEC_IN_SEC,
1101 "wait before finishing poll sequence",
1102 )
1103 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekerad3ba5152017-02-14 03:09:17 +01001104 p = wait_for_bfd_packet(self)
Klement Sekeraa57a9702017-02-02 06:58:07 +01001105 # poll bit needs to be set
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001106 self.assertIn("P", p.sprintf("%BFD.flags%"), "Poll bit not set in BFD packet")
Klement Sekeraa57a9702017-02-02 06:58:07 +01001107 # finish poll sequence with final packet
1108 final = self.test_session.create_packet()
1109 final[BFD].flags = "F"
1110 self.test_session.send_packet(final)
1111 # now the session should time out under new conditions
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001112 detection_time = (
1113 self.test_session.detect_mult
1114 * self.vpp_session.required_min_rx
1115 / USEC_IN_SEC
1116 )
Klement Sekera2e01dfa2017-04-03 08:10:08 +02001117 before = time.time()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001118 e = self.vapi.wait_for_event(2 * detection_time, "bfd_udp_session_event")
Klement Sekera2e01dfa2017-04-03 08:10:08 +02001119 after = time.time()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001120 self.assert_in_range(
1121 after - before,
1122 0.9 * detection_time,
1123 1.1 * detection_time,
1124 "time before bfd session goes down",
1125 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01001126 verify_event(self, e, expected_state=BFDState.down)
Klement Sekeraa57a9702017-02-02 06:58:07 +01001127
Klement Sekeraa57a9702017-02-02 06:58:07 +01001128 def test_modify_detect_mult(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001129 """modify detect multiplier"""
Klement Sekerad3ba5152017-02-14 03:09:17 +01001130 bfd_session_up(self)
1131 p = wait_for_bfd_packet(self)
Klement Sekeraa57a9702017-02-02 06:58:07 +01001132 self.vpp_session.modify_parameters(detect_mult=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001133 p = wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
1134 self.assert_equal(
1135 self.vpp_session.detect_mult, p[BFD].detect_mult, "detect mult"
1136 )
Klement Sekeraa57a9702017-02-02 06:58:07 +01001137 # poll bit must not be set
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001138 self.assertNotIn(
1139 "P", p.sprintf("%BFD.flags%"), "Poll bit not set in BFD packet"
1140 )
Klement Sekeraa57a9702017-02-02 06:58:07 +01001141 self.vpp_session.modify_parameters(detect_mult=10)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001142 p = wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
1143 self.assert_equal(
1144 self.vpp_session.detect_mult, p[BFD].detect_mult, "detect mult"
1145 )
Klement Sekeraa57a9702017-02-02 06:58:07 +01001146 # poll bit must not be set
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001147 self.assertNotIn(
1148 "P", p.sprintf("%BFD.flags%"), "Poll bit not set in BFD packet"
1149 )
Klement Sekeraa57a9702017-02-02 06:58:07 +01001150
Klement Sekera239790f2017-02-16 10:53:53 +01001151 def test_queued_poll(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001152 """test poll sequence queueing"""
Klement Sekera239790f2017-02-16 10:53:53 +01001153 bfd_session_up(self)
1154 p = wait_for_bfd_packet(self)
1155 self.vpp_session.modify_parameters(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001156 required_min_rx=2 * self.vpp_session.required_min_rx
1157 )
Klement Sekera239790f2017-02-16 10:53:53 +01001158 p = wait_for_bfd_packet(self)
1159 poll_sequence_start = time.time()
1160 poll_sequence_length_min = 0.5
1161 send_final_after = time.time() + poll_sequence_length_min
1162 # poll bit needs to be set
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001163 self.assertIn("P", p.sprintf("%BFD.flags%"), "Poll bit not set in BFD packet")
1164 self.assert_equal(
1165 p[BFD].required_min_rx_interval,
1166 self.vpp_session.required_min_rx,
1167 "BFD required min rx interval",
1168 )
Klement Sekera239790f2017-02-16 10:53:53 +01001169 self.vpp_session.modify_parameters(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001170 required_min_rx=2 * self.vpp_session.required_min_rx
1171 )
Klement Sekera239790f2017-02-16 10:53:53 +01001172 # 2nd poll sequence should be queued now
1173 # don't send the reply back yet, wait for some time to emulate
1174 # longer round-trip time
1175 packet_count = 0
1176 while time.time() < send_final_after:
1177 self.test_session.send_packet()
1178 p = wait_for_bfd_packet(self)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001179 self.assert_equal(
1180 len(self.vapi.collect_events()), 0, "number of bfd events"
1181 )
1182 self.assert_equal(
1183 p[BFD].required_min_rx_interval,
1184 self.vpp_session.required_min_rx,
1185 "BFD required min rx interval",
1186 )
Klement Sekera239790f2017-02-16 10:53:53 +01001187 packet_count += 1
1188 # poll bit must be set
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001189 self.assertIn(
1190 "P", p.sprintf("%BFD.flags%"), "Poll bit not set in BFD packet"
1191 )
Klement Sekera239790f2017-02-16 10:53:53 +01001192 final = self.test_session.create_packet()
1193 final[BFD].flags = "F"
1194 self.test_session.send_packet(final)
1195 # finish 1st with final
1196 poll_sequence_length = time.time() - poll_sequence_start
1197 # vpp must wait for some time before starting new poll sequence
1198 poll_no_2_started = False
1199 for dummy in range(2 * packet_count):
1200 p = wait_for_bfd_packet(self)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001201 self.assert_equal(
1202 len(self.vapi.collect_events()), 0, "number of bfd events"
1203 )
Klement Sekera239790f2017-02-16 10:53:53 +01001204 if "P" in p.sprintf("%BFD.flags%"):
1205 poll_no_2_started = True
1206 if time.time() < poll_sequence_start + poll_sequence_length:
1207 raise Exception("VPP started 2nd poll sequence too soon")
1208 final = self.test_session.create_packet()
1209 final[BFD].flags = "F"
1210 self.test_session.send_packet(final)
1211 break
1212 else:
1213 self.test_session.send_packet()
1214 self.assertTrue(poll_no_2_started, "2nd poll sequence not performed")
1215 # finish 2nd with final
1216 final = self.test_session.create_packet()
1217 final[BFD].flags = "F"
1218 self.test_session.send_packet(final)
1219 p = wait_for_bfd_packet(self)
1220 # poll bit must not be set
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001221 self.assertNotIn("P", p.sprintf("%BFD.flags%"), "Poll bit set in BFD packet")
Klement Sekera239790f2017-02-16 10:53:53 +01001222
Paul Vinciguerra7ade2f52019-12-06 11:06:02 -05001223 # returning inconsistent results requiring retries in per-patch tests
Klement Sekerab23ffd72021-05-31 16:08:53 +02001224 @unittest.skipUnless(config.extended, "part of extended tests")
Klement Sekera73884482017-02-23 09:26:30 +01001225 def test_poll_response(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001226 """test correct response to control frame with poll bit set"""
Klement Sekera73884482017-02-23 09:26:30 +01001227 bfd_session_up(self)
1228 poll = self.test_session.create_packet()
1229 poll[BFD].flags = "P"
1230 self.test_session.send_packet(poll)
1231 final = wait_for_bfd_packet(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001232 self, pcap_time_min=time.time() - self.vpp_clock_offset
1233 )
Klement Sekera73884482017-02-23 09:26:30 +01001234 self.assertIn("F", final.sprintf("%BFD.flags%"))
1235
Klement Sekerad3ba5152017-02-14 03:09:17 +01001236 def test_no_periodic_if_remote_demand(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001237 """no periodic frames outside poll sequence if remote demand set"""
Klement Sekerad3ba5152017-02-14 03:09:17 +01001238 bfd_session_up(self)
1239 demand = self.test_session.create_packet()
1240 demand[BFD].flags = "D"
1241 self.test_session.send_packet(demand)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001242 transmit_time = (
1243 0.9
1244 * max(self.vpp_session.required_min_rx, self.test_session.desired_min_tx)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001245 / USEC_IN_SEC
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001246 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01001247 count = 0
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001248 for dummy in range(self.test_session.detect_mult * 2):
Paul Vinciguerra0f6602c2019-03-10 09:10:54 -07001249 self.sleep(transmit_time)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001250 self.test_session.send_packet(demand)
1251 try:
1252 p = wait_for_bfd_packet(self, timeout=0)
1253 self.logger.error(ppp("Received unexpected packet:", p))
1254 count += 1
1255 except CaptureTimeoutError:
1256 pass
1257 events = self.vapi.collect_events()
1258 for e in events:
1259 self.logger.error("Received unexpected event: %s", e)
1260 self.assert_equal(count, 0, "number of packets received")
1261 self.assert_equal(len(events), 0, "number of events received")
Klement Sekera46a87ad2017-01-02 08:22:23 +01001262
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001263 def test_echo_looped_back(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001264 """echo packets looped back"""
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001265 bfd_session_up(self)
1266 stats_before = bfd_grab_stats_snapshot(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001267 self.pg0.enable_capture()
1268 echo_packet_count = 10
1269 # random source port low enough to increment a few times..
1270 udp_sport_tx = randint(1, 50000)
1271 udp_sport_rx = udp_sport_tx
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001272 echo_packet = (
1273 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1274 / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4)
1275 / UDP(dport=BFD.udp_dport_echo)
1276 / Raw("this should be looped back")
1277 )
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001278 for dummy in range(echo_packet_count):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001279 self.sleep(0.01, "delay between echo packets")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001280 echo_packet[UDP].sport = udp_sport_tx
1281 udp_sport_tx += 1
1282 self.logger.debug(ppp("Sending packet:", echo_packet))
1283 self.pg0.add_stream(echo_packet)
1284 self.pg_start()
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001285 self.logger.debug(self.vapi.ppcli("show trace"))
1286 counter = 0
1287 bfd_control_packets_rx = 0
1288 while counter < echo_packet_count:
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001289 p = self.pg0.wait_for_packet(1)
1290 self.logger.debug(ppp("Got packet:", p))
1291 ether = p[Ether]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001292 self.assert_equal(self.pg0.remote_mac, ether.dst, "Destination MAC")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001293 self.assert_equal(self.pg0.local_mac, ether.src, "Source MAC")
1294 ip = p[IP]
1295 self.assert_equal(self.pg0.remote_ip4, ip.dst, "Destination IP")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001296 udp = p[UDP]
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001297 if udp.dport == BFD.udp_dport:
1298 bfd_control_packets_rx += 1
1299 continue
1300 self.assert_equal(self.pg0.remote_ip4, ip.src, "Source IP")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001301 self.assert_equal(udp.dport, BFD.udp_dport_echo, "UDP destination port")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001302 self.assert_equal(udp.sport, udp_sport_rx, "UDP source port")
1303 udp_sport_rx += 1
Klement Sekera239790f2017-02-16 10:53:53 +01001304 # need to compare the hex payload here, otherwise BFD_vpp_echo
1305 # gets in way
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001306 self.assertEqual(
1307 scapy.compat.raw(p[UDP].payload),
1308 scapy.compat.raw(echo_packet[UDP].payload),
1309 "Received packet is not the echo packet sent",
1310 )
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001311 counter += 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001312 self.assert_equal(
1313 udp_sport_tx,
1314 udp_sport_rx,
1315 "UDP source port (== ECHO packet identifier for test purposes)",
1316 )
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001317 stats_after = bfd_grab_stats_snapshot(self)
1318 diff = bfd_stats_diff(stats_before, stats_after)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001319 self.assertEqual(0, diff.rx, "RX counter bumped but no BFD packets sent")
1320 self.assertEqual(bfd_control_packets_rx, diff.tx, "TX counter incorrect")
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001321 self.assertEqual(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001322 0, diff.rx_echo, "RX echo counter bumped but no BFD session exists"
1323 )
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001324 self.assertEqual(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001325 0, diff.tx_echo, "TX echo counter bumped but no BFD session exists"
1326 )
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001327
Klement Sekera239790f2017-02-16 10:53:53 +01001328 def test_echo(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001329 """echo function"""
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001330 stats_before = bfd_grab_stats_snapshot(self)
Klement Sekera239790f2017-02-16 10:53:53 +01001331 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001332 self.test_session.update(required_min_echo_rx=150000)
Klement Sekera239790f2017-02-16 10:53:53 +01001333 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001334 detection_time = (
1335 self.test_session.detect_mult
1336 * self.vpp_session.required_min_rx
1337 / USEC_IN_SEC
1338 )
Klement Sekera239790f2017-02-16 10:53:53 +01001339 # echo shouldn't work without echo source set
Klement Sekera3cfa5582017-04-19 07:10:58 +00001340 for dummy in range(10):
1341 sleep = self.vpp_session.required_min_rx / USEC_IN_SEC
Klement Sekera239790f2017-02-16 10:53:53 +01001342 self.sleep(sleep, "delay before sending bfd packet")
1343 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001344 p = wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
1345 self.assert_equal(
1346 p[BFD].required_min_rx_interval,
1347 self.vpp_session.required_min_rx,
1348 "BFD required min rx interval",
1349 )
Klement Sekera3cfa5582017-04-19 07:10:58 +00001350 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001351 self.vapi.bfd_udp_set_echo_source(sw_if_index=self.loopback0.sw_if_index)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001352 echo_seen = False
Klement Sekera239790f2017-02-16 10:53:53 +01001353 # should be turned on - loopback echo packets
1354 for dummy in range(3):
1355 loop_until = time.time() + 0.75 * detection_time
1356 while time.time() < loop_until:
1357 p = self.pg0.wait_for_packet(1)
1358 self.logger.debug(ppp("Got packet:", p))
1359 if p[UDP].dport == BFD.udp_dport_echo:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001360 self.assert_equal(p[IP].dst, self.pg0.local_ip4, "BFD ECHO dst IP")
1361 self.assertNotEqual(
1362 p[IP].src,
1363 self.loopback0.local_ip4,
1364 "BFD ECHO src IP equal to loopback IP",
1365 )
Klement Sekera239790f2017-02-16 10:53:53 +01001366 self.logger.debug(ppp("Looping back packet:", p))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001367 self.assert_equal(
1368 p[Ether].dst,
1369 self.pg0.remote_mac,
1370 "ECHO packet destination MAC address",
1371 )
John Lo1904c472017-03-10 17:15:22 -05001372 p[Ether].dst = self.pg0.local_mac
Klement Sekera239790f2017-02-16 10:53:53 +01001373 self.pg0.add_stream(p)
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001374 self.test_session.rx_packets_echo += 1
1375 self.test_session.tx_packets_echo += 1
Klement Sekera239790f2017-02-16 10:53:53 +01001376 self.pg_start()
Klement Sekera3cfa5582017-04-19 07:10:58 +00001377 echo_seen = True
Klement Sekera239790f2017-02-16 10:53:53 +01001378 elif p.haslayer(BFD):
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001379 self.test_session.rx_packets += 1
Klement Sekera3cfa5582017-04-19 07:10:58 +00001380 if echo_seen:
1381 self.assertGreaterEqual(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001382 p[BFD].required_min_rx_interval, 1000000
1383 )
Klement Sekera239790f2017-02-16 10:53:53 +01001384 if "P" in p.sprintf("%BFD.flags%"):
1385 final = self.test_session.create_packet()
1386 final[BFD].flags = "F"
1387 self.test_session.send_packet(final)
1388 else:
1389 raise Exception(ppp("Received unknown packet:", p))
1390
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001391 self.assert_equal(
1392 len(self.vapi.collect_events()), 0, "number of bfd events"
1393 )
Klement Sekera239790f2017-02-16 10:53:53 +01001394 self.test_session.send_packet()
Klement Sekera3cfa5582017-04-19 07:10:58 +00001395 self.assertTrue(echo_seen, "No echo packets received")
Klement Sekera239790f2017-02-16 10:53:53 +01001396
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001397 stats_after = bfd_grab_stats_snapshot(self)
1398 diff = bfd_stats_diff(stats_before, stats_after)
1399 # our rx is vpp tx and vice versa, also tolerate one packet off
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001400 self.assert_in_range(
1401 self.test_session.tx_packets, diff.rx - 1, diff.rx + 1, "RX counter"
1402 )
1403 self.assert_in_range(
1404 self.test_session.rx_packets, diff.tx - 1, diff.tx + 1, "TX counter"
1405 )
1406 self.assert_in_range(
1407 self.test_session.tx_packets_echo,
1408 diff.rx_echo - 1,
1409 diff.rx_echo + 1,
1410 "RX echo counter",
1411 )
1412 self.assert_in_range(
1413 self.test_session.rx_packets_echo,
1414 diff.tx_echo - 1,
1415 diff.tx_echo + 1,
1416 "TX echo counter",
1417 )
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001418
Klement Sekera239790f2017-02-16 10:53:53 +01001419 def test_echo_fail(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001420 """session goes down if echo function fails"""
Klement Sekera239790f2017-02-16 10:53:53 +01001421 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001422 self.test_session.update(required_min_echo_rx=150000)
Klement Sekera239790f2017-02-16 10:53:53 +01001423 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001424 detection_time = (
1425 self.test_session.detect_mult
1426 * self.vpp_session.required_min_rx
1427 / USEC_IN_SEC
1428 )
1429 self.vapi.bfd_udp_set_echo_source(sw_if_index=self.loopback0.sw_if_index)
Klement Sekera239790f2017-02-16 10:53:53 +01001430 # echo function should be used now, but we will drop the echo packets
1431 verified_diag = False
1432 for dummy in range(3):
1433 loop_until = time.time() + 0.75 * detection_time
1434 while time.time() < loop_until:
1435 p = self.pg0.wait_for_packet(1)
1436 self.logger.debug(ppp("Got packet:", p))
1437 if p[UDP].dport == BFD.udp_dport_echo:
1438 # dropped
1439 pass
1440 elif p.haslayer(BFD):
1441 if "P" in p.sprintf("%BFD.flags%"):
1442 self.assertGreaterEqual(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001443 p[BFD].required_min_rx_interval, 1000000
1444 )
Klement Sekera239790f2017-02-16 10:53:53 +01001445 final = self.test_session.create_packet()
1446 final[BFD].flags = "F"
1447 self.test_session.send_packet(final)
1448 if p[BFD].state == BFDState.down:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001449 self.assert_equal(
1450 p[BFD].diag, BFDDiagCode.echo_function_failed, BFDDiagCode
1451 )
Klement Sekera239790f2017-02-16 10:53:53 +01001452 verified_diag = True
1453 else:
1454 raise Exception(ppp("Received unknown packet:", p))
1455 self.test_session.send_packet()
1456 events = self.vapi.collect_events()
1457 self.assert_equal(len(events), 1, "number of bfd events")
1458 self.assert_equal(events[0].state, BFDState.down, BFDState)
1459 self.assertTrue(verified_diag, "Incorrect diagnostics code received")
1460
1461 def test_echo_stop(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001462 """echo function stops if peer sets required min echo rx zero"""
Klement Sekera239790f2017-02-16 10:53:53 +01001463 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001464 self.test_session.update(required_min_echo_rx=150000)
Klement Sekera239790f2017-02-16 10:53:53 +01001465 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001466 self.vapi.bfd_udp_set_echo_source(sw_if_index=self.loopback0.sw_if_index)
Klement Sekera239790f2017-02-16 10:53:53 +01001467 # wait for first echo packet
1468 while True:
1469 p = self.pg0.wait_for_packet(1)
1470 self.logger.debug(ppp("Got packet:", p))
1471 if p[UDP].dport == BFD.udp_dport_echo:
1472 self.logger.debug(ppp("Looping back packet:", p))
John Lo1904c472017-03-10 17:15:22 -05001473 p[Ether].dst = self.pg0.local_mac
Klement Sekera239790f2017-02-16 10:53:53 +01001474 self.pg0.add_stream(p)
1475 self.pg_start()
1476 break
1477 elif p.haslayer(BFD):
1478 # ignore BFD
1479 pass
1480 else:
1481 raise Exception(ppp("Received unknown packet:", p))
1482 self.test_session.update(required_min_echo_rx=0)
1483 self.test_session.send_packet()
1484 # echo packets shouldn't arrive anymore
1485 for dummy in range(5):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001486 wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekera239790f2017-02-16 10:53:53 +01001487 self.test_session.send_packet()
1488 events = self.vapi.collect_events()
1489 self.assert_equal(len(events), 0, "number of bfd events")
1490
Klement Sekera73884482017-02-23 09:26:30 +01001491 def test_echo_source_removed(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001492 """echo function stops if echo source is removed"""
Klement Sekera73884482017-02-23 09:26:30 +01001493 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001494 self.test_session.update(required_min_echo_rx=150000)
Klement Sekera73884482017-02-23 09:26:30 +01001495 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001496 self.vapi.bfd_udp_set_echo_source(sw_if_index=self.loopback0.sw_if_index)
Klement Sekera73884482017-02-23 09:26:30 +01001497 # wait for first echo packet
1498 while True:
1499 p = self.pg0.wait_for_packet(1)
1500 self.logger.debug(ppp("Got packet:", p))
1501 if p[UDP].dport == BFD.udp_dport_echo:
1502 self.logger.debug(ppp("Looping back packet:", p))
John Lo1904c472017-03-10 17:15:22 -05001503 p[Ether].dst = self.pg0.local_mac
Klement Sekera73884482017-02-23 09:26:30 +01001504 self.pg0.add_stream(p)
1505 self.pg_start()
1506 break
1507 elif p.haslayer(BFD):
1508 # ignore BFD
1509 pass
1510 else:
1511 raise Exception(ppp("Received unknown packet:", p))
1512 self.vapi.bfd_udp_del_echo_source()
1513 self.test_session.send_packet()
1514 # echo packets shouldn't arrive anymore
1515 for dummy in range(5):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001516 wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekera73884482017-02-23 09:26:30 +01001517 self.test_session.send_packet()
1518 events = self.vapi.collect_events()
1519 self.assert_equal(len(events), 0, "number of bfd events")
1520
Klement Sekera239790f2017-02-16 10:53:53 +01001521 def test_stale_echo(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001522 """stale echo packets don't keep a session up"""
Klement Sekera239790f2017-02-16 10:53:53 +01001523 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001524 self.test_session.update(required_min_echo_rx=150000)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001525 self.vapi.bfd_udp_set_echo_source(sw_if_index=self.loopback0.sw_if_index)
Klement Sekera239790f2017-02-16 10:53:53 +01001526 self.test_session.send_packet()
1527 # should be turned on - loopback echo packets
1528 echo_packet = None
1529 timeout_at = None
1530 timeout_ok = False
1531 for dummy in range(10 * self.vpp_session.detect_mult):
1532 p = self.pg0.wait_for_packet(1)
1533 if p[UDP].dport == BFD.udp_dport_echo:
1534 if echo_packet is None:
1535 self.logger.debug(ppp("Got first echo packet:", p))
1536 echo_packet = p
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001537 timeout_at = (
1538 time.time()
1539 + self.vpp_session.detect_mult
1540 * self.test_session.required_min_echo_rx
1541 / USEC_IN_SEC
1542 )
Klement Sekera239790f2017-02-16 10:53:53 +01001543 else:
1544 self.logger.debug(ppp("Got followup echo packet:", p))
1545 self.logger.debug(ppp("Looping back first echo packet:", p))
John Lo1904c472017-03-10 17:15:22 -05001546 echo_packet[Ether].dst = self.pg0.local_mac
Klement Sekera239790f2017-02-16 10:53:53 +01001547 self.pg0.add_stream(echo_packet)
1548 self.pg_start()
1549 elif p.haslayer(BFD):
1550 self.logger.debug(ppp("Got packet:", p))
1551 if "P" in p.sprintf("%BFD.flags%"):
1552 final = self.test_session.create_packet()
1553 final[BFD].flags = "F"
1554 self.test_session.send_packet(final)
1555 if p[BFD].state == BFDState.down:
1556 self.assertIsNotNone(
1557 timeout_at,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001558 "Session went down before first echo packet received",
1559 )
Klement Sekera239790f2017-02-16 10:53:53 +01001560 now = time.time()
1561 self.assertGreaterEqual(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001562 now,
1563 timeout_at,
1564 "Session timeout at %s, but is expected at %s"
1565 % (now, timeout_at),
1566 )
1567 self.assert_equal(
1568 p[BFD].diag, BFDDiagCode.echo_function_failed, BFDDiagCode
1569 )
Klement Sekera239790f2017-02-16 10:53:53 +01001570 events = self.vapi.collect_events()
1571 self.assert_equal(len(events), 1, "number of bfd events")
1572 self.assert_equal(events[0].state, BFDState.down, BFDState)
1573 timeout_ok = True
1574 break
1575 else:
1576 raise Exception(ppp("Received unknown packet:", p))
1577 self.test_session.send_packet()
1578 self.assertTrue(timeout_ok, "Expected timeout event didn't occur")
1579
1580 def test_invalid_echo_checksum(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001581 """echo packets with invalid checksum don't keep a session up"""
Klement Sekera239790f2017-02-16 10:53:53 +01001582 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001583 self.test_session.update(required_min_echo_rx=150000)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001584 self.vapi.bfd_udp_set_echo_source(sw_if_index=self.loopback0.sw_if_index)
Klement Sekera239790f2017-02-16 10:53:53 +01001585 self.test_session.send_packet()
1586 # should be turned on - loopback echo packets
1587 timeout_at = None
1588 timeout_ok = False
1589 for dummy in range(10 * self.vpp_session.detect_mult):
1590 p = self.pg0.wait_for_packet(1)
1591 if p[UDP].dport == BFD.udp_dport_echo:
1592 self.logger.debug(ppp("Got echo packet:", p))
1593 if timeout_at is None:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001594 timeout_at = (
1595 time.time()
1596 + self.vpp_session.detect_mult
1597 * self.test_session.required_min_echo_rx
1598 / USEC_IN_SEC
1599 )
Klement Sekera239790f2017-02-16 10:53:53 +01001600 p[BFD_vpp_echo].checksum = getrandbits(64)
John Lo1904c472017-03-10 17:15:22 -05001601 p[Ether].dst = self.pg0.local_mac
Klement Sekera239790f2017-02-16 10:53:53 +01001602 self.logger.debug(ppp("Looping back modified echo packet:", p))
1603 self.pg0.add_stream(p)
1604 self.pg_start()
1605 elif p.haslayer(BFD):
1606 self.logger.debug(ppp("Got packet:", p))
1607 if "P" in p.sprintf("%BFD.flags%"):
1608 final = self.test_session.create_packet()
1609 final[BFD].flags = "F"
1610 self.test_session.send_packet(final)
1611 if p[BFD].state == BFDState.down:
1612 self.assertIsNotNone(
1613 timeout_at,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001614 "Session went down before first echo packet received",
1615 )
Klement Sekera239790f2017-02-16 10:53:53 +01001616 now = time.time()
1617 self.assertGreaterEqual(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001618 now,
1619 timeout_at,
1620 "Session timeout at %s, but is expected at %s"
1621 % (now, timeout_at),
1622 )
1623 self.assert_equal(
1624 p[BFD].diag, BFDDiagCode.echo_function_failed, BFDDiagCode
1625 )
Klement Sekera239790f2017-02-16 10:53:53 +01001626 events = self.vapi.collect_events()
1627 self.assert_equal(len(events), 1, "number of bfd events")
1628 self.assert_equal(events[0].state, BFDState.down, BFDState)
1629 timeout_ok = True
1630 break
1631 else:
1632 raise Exception(ppp("Received unknown packet:", p))
1633 self.test_session.send_packet()
1634 self.assertTrue(timeout_ok, "Expected timeout event didn't occur")
1635
Klement Sekerac48829b2017-02-14 07:55:57 +01001636 def test_admin_up_down(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001637 """put session admin-up and admin-down"""
Klement Sekerac48829b2017-02-14 07:55:57 +01001638 bfd_session_up(self)
1639 self.vpp_session.admin_down()
1640 self.pg0.enable_capture()
Ole Troan4376ab22021-03-03 10:40:05 +01001641 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekerac48829b2017-02-14 07:55:57 +01001642 verify_event(self, e, expected_state=BFDState.admin_down)
1643 for dummy in range(2):
1644 p = wait_for_bfd_packet(self)
Klement Sekera73884482017-02-23 09:26:30 +01001645 self.assert_equal(p[BFD].state, BFDState.admin_down, BFDState)
Klement Sekerac48829b2017-02-14 07:55:57 +01001646 # try to bring session up - shouldn't be possible
1647 self.test_session.update(state=BFDState.init)
1648 self.test_session.send_packet()
1649 for dummy in range(2):
1650 p = wait_for_bfd_packet(self)
Klement Sekera73884482017-02-23 09:26:30 +01001651 self.assert_equal(p[BFD].state, BFDState.admin_down, BFDState)
Klement Sekerac48829b2017-02-14 07:55:57 +01001652 self.vpp_session.admin_up()
1653 self.test_session.update(state=BFDState.down)
Ole Troan4376ab22021-03-03 10:40:05 +01001654 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekerac48829b2017-02-14 07:55:57 +01001655 verify_event(self, e, expected_state=BFDState.down)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001656 p = wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekera73884482017-02-23 09:26:30 +01001657 self.assert_equal(p[BFD].state, BFDState.down, BFDState)
Klement Sekerac48829b2017-02-14 07:55:57 +01001658 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001659 p = wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekera73884482017-02-23 09:26:30 +01001660 self.assert_equal(p[BFD].state, BFDState.init, BFDState)
Ole Troan4376ab22021-03-03 10:40:05 +01001661 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekerac48829b2017-02-14 07:55:57 +01001662 verify_event(self, e, expected_state=BFDState.init)
1663 self.test_session.update(state=BFDState.up)
1664 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001665 p = wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekera73884482017-02-23 09:26:30 +01001666 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Ole Troan4376ab22021-03-03 10:40:05 +01001667 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekerac48829b2017-02-14 07:55:57 +01001668 verify_event(self, e, expected_state=BFDState.up)
1669
Klement Sekera239790f2017-02-16 10:53:53 +01001670 def test_config_change_remote_demand(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001671 """configuration change while peer in demand mode"""
Klement Sekera239790f2017-02-16 10:53:53 +01001672 bfd_session_up(self)
1673 demand = self.test_session.create_packet()
1674 demand[BFD].flags = "D"
1675 self.test_session.send_packet(demand)
1676 self.vpp_session.modify_parameters(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001677 required_min_rx=2 * self.vpp_session.required_min_rx
1678 )
1679 p = wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekera239790f2017-02-16 10:53:53 +01001680 # poll bit must be set
1681 self.assertIn("P", p.sprintf("%BFD.flags%"), "Poll bit not set")
1682 # terminate poll sequence
1683 final = self.test_session.create_packet()
1684 final[BFD].flags = "D+F"
1685 self.test_session.send_packet(final)
1686 # vpp should be quiet now again
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001687 transmit_time = (
1688 0.9
1689 * max(self.vpp_session.required_min_rx, self.test_session.desired_min_tx)
Klement Sekera239790f2017-02-16 10:53:53 +01001690 / USEC_IN_SEC
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001691 )
Klement Sekera239790f2017-02-16 10:53:53 +01001692 count = 0
1693 for dummy in range(self.test_session.detect_mult * 2):
Paul Vinciguerra0f6602c2019-03-10 09:10:54 -07001694 self.sleep(transmit_time)
Klement Sekera239790f2017-02-16 10:53:53 +01001695 self.test_session.send_packet(demand)
1696 try:
1697 p = wait_for_bfd_packet(self, timeout=0)
1698 self.logger.error(ppp("Received unexpected packet:", p))
1699 count += 1
1700 except CaptureTimeoutError:
1701 pass
1702 events = self.vapi.collect_events()
1703 for e in events:
1704 self.logger.error("Received unexpected event: %s", e)
1705 self.assert_equal(count, 0, "number of packets received")
1706 self.assert_equal(len(events), 0, "number of events received")
1707
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001708 def test_intf_deleted(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001709 """interface with bfd session deleted"""
Klement Sekerabeaded52018-06-24 10:30:37 +02001710 intf = VppLoInterface(self)
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001711 intf.config_ip4()
1712 intf.admin_up()
1713 sw_if_index = intf.sw_if_index
1714 vpp_session = VppBFDUDPSession(self, intf, intf.remote_ip4)
1715 vpp_session.add_vpp_config()
1716 vpp_session.admin_up()
1717 intf.remove_vpp_config()
Ole Troan4376ab22021-03-03 10:40:05 +01001718 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001719 self.assert_equal(e.sw_if_index, sw_if_index, "sw_if_index")
1720 self.assertFalse(vpp_session.query_vpp_config())
1721
Klement Sekerad3ba5152017-02-14 03:09:17 +01001722
Andrew Yourtchenko06f32812021-01-14 10:19:08 +00001723@tag_run_solo
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00001724@tag_fixme_vpp_workers
Klement Sekerad3ba5152017-02-14 03:09:17 +01001725class BFD6TestCase(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001726 """Bidirectional Forwarding Detection (BFD) (IPv6)"""
Klement Sekera46a87ad2017-01-02 08:22:23 +01001727
Klement Sekerad3ba5152017-02-14 03:09:17 +01001728 pg0 = None
1729 vpp_clock_offset = None
1730 vpp_session = None
1731 test_session = None
1732
Klement Sekera46a87ad2017-01-02 08:22:23 +01001733 @classmethod
1734 def setUpClass(cls):
1735 super(BFD6TestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -08001736 cls.vapi.cli("set log class bfd level debug")
Klement Sekera46a87ad2017-01-02 08:22:23 +01001737 try:
1738 cls.create_pg_interfaces([0])
1739 cls.pg0.config_ip6()
1740 cls.pg0.configure_ipv6_neighbors()
1741 cls.pg0.admin_up()
1742 cls.pg0.resolve_ndp()
Klement Sekerab9ef2732018-06-24 22:49:33 +02001743 cls.create_loopback_interfaces(1)
Klement Sekera239790f2017-02-16 10:53:53 +01001744 cls.loopback0 = cls.lo_interfaces[0]
1745 cls.loopback0.config_ip6()
1746 cls.loopback0.admin_up()
Klement Sekera46a87ad2017-01-02 08:22:23 +01001747
1748 except Exception:
1749 super(BFD6TestCase, cls).tearDownClass()
1750 raise
1751
Paul Vinciguerra8d991d92019-01-25 14:05:48 -08001752 @classmethod
1753 def tearDownClass(cls):
1754 super(BFD6TestCase, cls).tearDownClass()
1755
Klement Sekera46a87ad2017-01-02 08:22:23 +01001756 def setUp(self):
1757 super(BFD6TestCase, self).setUp()
Klement Sekerab17dd962017-01-09 07:43:48 +01001758 self.factory = AuthKeyFactory()
Klement Sekera46a87ad2017-01-02 08:22:23 +01001759 self.vapi.want_bfd_events()
Klement Sekerad3ba5152017-02-14 03:09:17 +01001760 self.pg0.enable_capture()
Klement Sekera46a87ad2017-01-02 08:22:23 +01001761 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001762 self.bfd_udp4_sessions = self.statistics["/bfd/udp4/sessions"]
1763 self.bfd_udp6_sessions = self.statistics["/bfd/udp6/sessions"]
1764 self.vpp_session = VppBFDUDPSession(
1765 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6
1766 )
Klement Sekera46a87ad2017-01-02 08:22:23 +01001767 self.vpp_session.add_vpp_config()
1768 self.vpp_session.admin_up()
1769 self.test_session = BFDTestSession(self, self.pg0, AF_INET6)
1770 self.logger.debug(self.vapi.cli("show adj nbr"))
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001771 except BaseException:
Klement Sekera46a87ad2017-01-02 08:22:23 +01001772 self.vapi.want_bfd_events(enable_disable=0)
1773 raise
1774
1775 def tearDown(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001776 if not self.vpp_dead:
1777 self.vapi.want_bfd_events(enable_disable=0)
1778 self.vapi.collect_events() # clear the event queue
1779 super(BFD6TestCase, self).tearDown()
Klement Sekerab17dd962017-01-09 07:43:48 +01001780
1781 def test_session_up(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001782 """bring BFD session up"""
Klement Sekerad3ba5152017-02-14 03:09:17 +01001783 bfd_session_up(self)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001784 bfd_udp4_sessions = self.statistics["/bfd/udp4/sessions"]
1785 bfd_udp6_sessions = self.statistics["/bfd/udp6/sessions"]
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001786 self.assert_equal(bfd_udp4_sessions, self.bfd_udp4_sessions)
1787 self.assert_equal(bfd_udp6_sessions - self.bfd_udp6_sessions, 1)
Klement Sekerab17dd962017-01-09 07:43:48 +01001788
Klement Sekera73884482017-02-23 09:26:30 +01001789 def test_session_up_by_ip(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001790 """bring BFD session up - first frame looked up by address pair"""
Klement Sekera73884482017-02-23 09:26:30 +01001791 self.logger.info("BFD: Sending Slow control frame")
1792 self.test_session.update(my_discriminator=randint(0, 40000000))
1793 self.test_session.send_packet()
1794 self.pg0.enable_capture()
1795 p = self.pg0.wait_for_packet(1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001796 self.assert_equal(
1797 p[BFD].your_discriminator,
1798 self.test_session.my_discriminator,
1799 "BFD - your discriminator",
1800 )
Klement Sekera73884482017-02-23 09:26:30 +01001801 self.assert_equal(p[BFD].state, BFDState.init, BFDState)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001802 self.test_session.update(
1803 your_discriminator=p[BFD].my_discriminator, state=BFDState.up
1804 )
Klement Sekera73884482017-02-23 09:26:30 +01001805 self.logger.info("BFD: Waiting for event")
Ole Troan4376ab22021-03-03 10:40:05 +01001806 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekera73884482017-02-23 09:26:30 +01001807 verify_event(self, e, expected_state=BFDState.init)
1808 self.logger.info("BFD: Sending Up")
1809 self.test_session.send_packet()
1810 self.logger.info("BFD: Waiting for event")
Ole Troan4376ab22021-03-03 10:40:05 +01001811 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekera73884482017-02-23 09:26:30 +01001812 verify_event(self, e, expected_state=BFDState.up)
1813 self.logger.info("BFD: Session is Up")
1814 self.test_session.update(state=BFDState.up)
1815 self.test_session.send_packet()
1816 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1817
Klement Sekerab17dd962017-01-09 07:43:48 +01001818 def test_hold_up(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001819 """hold BFD session up"""
Klement Sekerad3ba5152017-02-14 03:09:17 +01001820 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001821 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001822 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001823 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001824 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekerab17dd962017-01-09 07:43:48 +01001825 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1826
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001827 def test_echo_looped_back(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001828 """echo packets looped back"""
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001829 bfd_session_up(self)
1830 stats_before = bfd_grab_stats_snapshot(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001831 self.pg0.enable_capture()
1832 echo_packet_count = 10
1833 # random source port low enough to increment a few times..
1834 udp_sport_tx = randint(1, 50000)
1835 udp_sport_rx = udp_sport_tx
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001836 echo_packet = (
1837 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1838 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6)
1839 / UDP(dport=BFD.udp_dport_echo)
1840 / Raw("this should be looped back")
1841 )
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001842 for dummy in range(echo_packet_count):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001843 self.sleep(0.01, "delay between echo packets")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001844 echo_packet[UDP].sport = udp_sport_tx
1845 udp_sport_tx += 1
1846 self.logger.debug(ppp("Sending packet:", echo_packet))
1847 self.pg0.add_stream(echo_packet)
1848 self.pg_start()
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001849 counter = 0
1850 bfd_control_packets_rx = 0
1851 while counter < echo_packet_count:
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001852 p = self.pg0.wait_for_packet(1)
1853 self.logger.debug(ppp("Got packet:", p))
1854 ether = p[Ether]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001855 self.assert_equal(self.pg0.remote_mac, ether.dst, "Destination MAC")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001856 self.assert_equal(self.pg0.local_mac, ether.src, "Source MAC")
1857 ip = p[IPv6]
1858 self.assert_equal(self.pg0.remote_ip6, ip.dst, "Destination IP")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001859 udp = p[UDP]
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001860 if udp.dport == BFD.udp_dport:
1861 bfd_control_packets_rx += 1
1862 continue
1863 self.assert_equal(self.pg0.remote_ip6, ip.src, "Source IP")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001864 self.assert_equal(udp.dport, BFD.udp_dport_echo, "UDP destination port")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001865 self.assert_equal(udp.sport, udp_sport_rx, "UDP source port")
1866 udp_sport_rx += 1
Klement Sekera239790f2017-02-16 10:53:53 +01001867 # need to compare the hex payload here, otherwise BFD_vpp_echo
1868 # gets in way
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001869 self.assertEqual(
1870 scapy.compat.raw(p[UDP].payload),
1871 scapy.compat.raw(echo_packet[UDP].payload),
1872 "Received packet is not the echo packet sent",
1873 )
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001874 counter += 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001875 self.assert_equal(
1876 udp_sport_tx,
1877 udp_sport_rx,
1878 "UDP source port (== ECHO packet identifier for test purposes)",
1879 )
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001880 stats_after = bfd_grab_stats_snapshot(self)
1881 diff = bfd_stats_diff(stats_before, stats_after)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001882 self.assertEqual(0, diff.rx, "RX counter bumped but no BFD packets sent")
1883 self.assertEqual(bfd_control_packets_rx, diff.tx, "TX counter incorrect")
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001884 self.assertEqual(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001885 0, diff.rx_echo, "RX echo counter bumped but no BFD session exists"
1886 )
1887 self.assertEqual(
1888 0, diff.tx_echo, "TX echo counter bumped but no BFD session exists"
1889 )
Klement Sekera239790f2017-02-16 10:53:53 +01001890
1891 def test_echo(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001892 """echo function"""
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001893 stats_before = bfd_grab_stats_snapshot(self)
Klement Sekera239790f2017-02-16 10:53:53 +01001894 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001895 self.test_session.update(required_min_echo_rx=150000)
Klement Sekera239790f2017-02-16 10:53:53 +01001896 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001897 detection_time = (
1898 self.test_session.detect_mult
1899 * self.vpp_session.required_min_rx
1900 / USEC_IN_SEC
1901 )
Klement Sekera239790f2017-02-16 10:53:53 +01001902 # echo shouldn't work without echo source set
Klement Sekera3cfa5582017-04-19 07:10:58 +00001903 for dummy in range(10):
1904 sleep = self.vpp_session.required_min_rx / USEC_IN_SEC
Klement Sekera239790f2017-02-16 10:53:53 +01001905 self.sleep(sleep, "delay before sending bfd packet")
1906 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001907 p = wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
1908 self.assert_equal(
1909 p[BFD].required_min_rx_interval,
1910 self.vpp_session.required_min_rx,
1911 "BFD required min rx interval",
1912 )
Klement Sekera3cfa5582017-04-19 07:10:58 +00001913 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001914 self.vapi.bfd_udp_set_echo_source(sw_if_index=self.loopback0.sw_if_index)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001915 echo_seen = False
Klement Sekera239790f2017-02-16 10:53:53 +01001916 # should be turned on - loopback echo packets
1917 for dummy in range(3):
1918 loop_until = time.time() + 0.75 * detection_time
1919 while time.time() < loop_until:
1920 p = self.pg0.wait_for_packet(1)
1921 self.logger.debug(ppp("Got packet:", p))
1922 if p[UDP].dport == BFD.udp_dport_echo:
1923 self.assert_equal(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001924 p[IPv6].dst, self.pg0.local_ip6, "BFD ECHO dst IP"
1925 )
1926 self.assertNotEqual(
1927 p[IPv6].src,
1928 self.loopback0.local_ip6,
1929 "BFD ECHO src IP equal to loopback IP",
1930 )
Klement Sekera239790f2017-02-16 10:53:53 +01001931 self.logger.debug(ppp("Looping back packet:", p))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001932 self.assert_equal(
1933 p[Ether].dst,
1934 self.pg0.remote_mac,
1935 "ECHO packet destination MAC address",
1936 )
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001937 self.test_session.rx_packets_echo += 1
1938 self.test_session.tx_packets_echo += 1
John Lo1904c472017-03-10 17:15:22 -05001939 p[Ether].dst = self.pg0.local_mac
Klement Sekera239790f2017-02-16 10:53:53 +01001940 self.pg0.add_stream(p)
1941 self.pg_start()
Klement Sekera3cfa5582017-04-19 07:10:58 +00001942 echo_seen = True
Klement Sekera239790f2017-02-16 10:53:53 +01001943 elif p.haslayer(BFD):
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001944 self.test_session.rx_packets += 1
Klement Sekera3cfa5582017-04-19 07:10:58 +00001945 if echo_seen:
1946 self.assertGreaterEqual(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001947 p[BFD].required_min_rx_interval, 1000000
1948 )
Klement Sekera239790f2017-02-16 10:53:53 +01001949 if "P" in p.sprintf("%BFD.flags%"):
1950 final = self.test_session.create_packet()
1951 final[BFD].flags = "F"
1952 self.test_session.send_packet(final)
1953 else:
1954 raise Exception(ppp("Received unknown packet:", p))
1955
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001956 self.assert_equal(
1957 len(self.vapi.collect_events()), 0, "number of bfd events"
1958 )
Klement Sekera239790f2017-02-16 10:53:53 +01001959 self.test_session.send_packet()
Klement Sekera3cfa5582017-04-19 07:10:58 +00001960 self.assertTrue(echo_seen, "No echo packets received")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001961
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001962 stats_after = bfd_grab_stats_snapshot(self)
1963 diff = bfd_stats_diff(stats_before, stats_after)
1964 # our rx is vpp tx and vice versa, also tolerate one packet off
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001965 self.assert_in_range(
1966 self.test_session.tx_packets, diff.rx - 1, diff.rx + 1, "RX counter"
1967 )
1968 self.assert_in_range(
1969 self.test_session.rx_packets, diff.tx - 1, diff.tx + 1, "TX counter"
1970 )
1971 self.assert_in_range(
1972 self.test_session.tx_packets_echo,
1973 diff.rx_echo - 1,
1974 diff.rx_echo + 1,
1975 "RX echo counter",
1976 )
1977 self.assert_in_range(
1978 self.test_session.rx_packets_echo,
1979 diff.tx_echo - 1,
1980 diff.tx_echo + 1,
1981 "TX echo counter",
1982 )
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001983
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001984 def test_intf_deleted(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001985 """interface with bfd session deleted"""
Klement Sekerabeaded52018-06-24 10:30:37 +02001986 intf = VppLoInterface(self)
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001987 intf.config_ip6()
1988 intf.admin_up()
1989 sw_if_index = intf.sw_if_index
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001990 vpp_session = VppBFDUDPSession(self, intf, intf.remote_ip6, af=AF_INET6)
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001991 vpp_session.add_vpp_config()
1992 vpp_session.admin_up()
1993 intf.remove_vpp_config()
Ole Troan4376ab22021-03-03 10:40:05 +01001994 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001995 self.assert_equal(e.sw_if_index, sw_if_index, "sw_if_index")
1996 self.assertFalse(vpp_session.query_vpp_config())
1997
Klement Sekerab17dd962017-01-09 07:43:48 +01001998
Andrew Yourtchenko06f32812021-01-14 10:19:08 +00001999@tag_run_solo
Neale Ranns88fc83e2017-04-05 08:11:14 -07002000class BFDFIBTestCase(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002001 """BFD-FIB interactions (IPv6)"""
Neale Ranns88fc83e2017-04-05 08:11:14 -07002002
2003 vpp_session = None
2004 test_session = None
2005
Paul Vinciguerra8d991d92019-01-25 14:05:48 -08002006 @classmethod
2007 def setUpClass(cls):
2008 super(BFDFIBTestCase, cls).setUpClass()
2009
2010 @classmethod
2011 def tearDownClass(cls):
2012 super(BFDFIBTestCase, cls).tearDownClass()
2013
Neale Ranns88fc83e2017-04-05 08:11:14 -07002014 def setUp(self):
2015 super(BFDFIBTestCase, self).setUp()
2016 self.create_pg_interfaces(range(1))
2017
2018 self.vapi.want_bfd_events()
2019 self.pg0.enable_capture()
2020
2021 for i in self.pg_interfaces:
2022 i.admin_up()
2023 i.config_ip6()
2024 i.configure_ipv6_neighbors()
2025
2026 def tearDown(self):
2027 if not self.vpp_dead:
Jakub Grajciar4682feb2019-09-02 13:28:52 +02002028 self.vapi.want_bfd_events(enable_disable=False)
Neale Ranns88fc83e2017-04-05 08:11:14 -07002029
2030 super(BFDFIBTestCase, self).tearDown()
2031
2032 @staticmethod
2033 def pkt_is_not_data_traffic(p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002034 """not data traffic implies BFD or the usual IPv6 ND/RA"""
Neale Ranns88fc83e2017-04-05 08:11:14 -07002035 if p.haslayer(BFD) or is_ipv6_misc(p):
2036 return True
2037 return False
2038
2039 def test_session_with_fib(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002040 """BFD-FIB interactions"""
Neale Ranns88fc83e2017-04-05 08:11:14 -07002041
2042 # packets to match against both of the routes
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002043 p = [
2044 (
2045 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2046 / IPv6(src="3001::1", dst="2001::1")
2047 / UDP(sport=1234, dport=1234)
2048 / Raw(b"\xa5" * 100)
2049 ),
2050 (
2051 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2052 / IPv6(src="3001::1", dst="2002::1")
2053 / UDP(sport=1234, dport=1234)
2054 / Raw(b"\xa5" * 100)
2055 ),
2056 ]
Neale Ranns88fc83e2017-04-05 08:11:14 -07002057
2058 # A recursive and a non-recursive route via a next-hop that
2059 # will have a BFD session
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002060 ip_2001_s_64 = VppIpRoute(
2061 self,
2062 "2001::",
2063 64,
2064 [VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index)],
2065 )
2066 ip_2002_s_64 = VppIpRoute(
2067 self, "2002::", 64, [VppRoutePath(self.pg0.remote_ip6, 0xFFFFFFFF)]
2068 )
Neale Ranns88fc83e2017-04-05 08:11:14 -07002069 ip_2001_s_64.add_vpp_config()
2070 ip_2002_s_64.add_vpp_config()
2071
2072 # bring the session up now the routes are present
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002073 self.vpp_session = VppBFDUDPSession(
2074 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6
2075 )
Neale Ranns88fc83e2017-04-05 08:11:14 -07002076 self.vpp_session.add_vpp_config()
2077 self.vpp_session.admin_up()
2078 self.test_session = BFDTestSession(self, self.pg0, AF_INET6)
2079
2080 # session is up - traffic passes
2081 bfd_session_up(self)
2082
2083 self.pg0.add_stream(p)
2084 self.pg_start()
2085 for packet in p:
2086 captured = self.pg0.wait_for_packet(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002087 1, filter_out_fn=self.pkt_is_not_data_traffic
2088 )
2089 self.assertEqual(captured[IPv6].dst, packet[IPv6].dst)
Neale Ranns88fc83e2017-04-05 08:11:14 -07002090
2091 # session is up - traffic is dropped
2092 bfd_session_down(self)
2093
2094 self.pg0.add_stream(p)
2095 self.pg_start()
2096 with self.assertRaises(CaptureTimeoutError):
2097 self.pg0.wait_for_packet(1, self.pkt_is_not_data_traffic)
2098
2099 # session is up - traffic passes
2100 bfd_session_up(self)
2101
2102 self.pg0.add_stream(p)
2103 self.pg_start()
2104 for packet in p:
2105 captured = self.pg0.wait_for_packet(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002106 1, filter_out_fn=self.pkt_is_not_data_traffic
2107 )
2108 self.assertEqual(captured[IPv6].dst, packet[IPv6].dst)
Neale Ranns88fc83e2017-04-05 08:11:14 -07002109
2110
Klement Sekerab23ffd72021-05-31 16:08:53 +02002111@unittest.skipUnless(config.extended, "part of extended tests")
Neale Ranns52cd4962019-06-05 10:28:17 +00002112class BFDTunTestCase(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002113 """BFD over GRE tunnel"""
Neale Ranns52cd4962019-06-05 10:28:17 +00002114
2115 vpp_session = None
2116 test_session = None
2117
2118 @classmethod
2119 def setUpClass(cls):
2120 super(BFDTunTestCase, cls).setUpClass()
2121
2122 @classmethod
2123 def tearDownClass(cls):
2124 super(BFDTunTestCase, cls).tearDownClass()
2125
2126 def setUp(self):
2127 super(BFDTunTestCase, self).setUp()
2128 self.create_pg_interfaces(range(1))
2129
2130 self.vapi.want_bfd_events()
2131 self.pg0.enable_capture()
2132
2133 for i in self.pg_interfaces:
2134 i.admin_up()
2135 i.config_ip4()
2136 i.resolve_arp()
2137
2138 def tearDown(self):
2139 if not self.vpp_dead:
2140 self.vapi.want_bfd_events(enable_disable=0)
2141
2142 super(BFDTunTestCase, self).tearDown()
2143
2144 @staticmethod
2145 def pkt_is_not_data_traffic(p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002146 """not data traffic implies BFD or the usual IPv6 ND/RA"""
Neale Ranns52cd4962019-06-05 10:28:17 +00002147 if p.haslayer(BFD) or is_ipv6_misc(p):
2148 return True
2149 return False
2150
2151 def test_bfd_o_gre(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002152 """BFD-o-GRE"""
Neale Ranns52cd4962019-06-05 10:28:17 +00002153
2154 # A GRE interface over which to run a BFD session
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002155 gre_if = VppGreInterface(self, self.pg0.local_ip4, self.pg0.remote_ip4)
Neale Ranns52cd4962019-06-05 10:28:17 +00002156 gre_if.add_vpp_config()
2157 gre_if.admin_up()
2158 gre_if.config_ip4()
2159
2160 # bring the session up now the routes are present
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002161 self.vpp_session = VppBFDUDPSession(
2162 self, gre_if, gre_if.remote_ip4, is_tunnel=True
2163 )
Neale Ranns52cd4962019-06-05 10:28:17 +00002164 self.vpp_session.add_vpp_config()
2165 self.vpp_session.admin_up()
2166
2167 self.test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002168 self,
2169 gre_if,
2170 AF_INET,
2171 tunnel_header=(IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / GRE()),
2172 phy_interface=self.pg0,
2173 )
Neale Ranns52cd4962019-06-05 10:28:17 +00002174
2175 # packets to match against both of the routes
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002176 p = [
2177 (
2178 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2179 / IP(src=self.pg0.remote_ip4, dst=gre_if.remote_ip4)
2180 / UDP(sport=1234, dport=1234)
2181 / Raw(b"\xa5" * 100)
2182 )
2183 ]
Neale Ranns52cd4962019-06-05 10:28:17 +00002184
2185 # session is up - traffic passes
2186 bfd_session_up(self)
2187
2188 self.send_and_expect(self.pg0, p, self.pg0)
2189
2190 # bring session down
2191 bfd_session_down(self)
2192
2193
Andrew Yourtchenko06f32812021-01-14 10:19:08 +00002194@tag_run_solo
Klement Sekerad3ba5152017-02-14 03:09:17 +01002195class BFDSHA1TestCase(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002196 """Bidirectional Forwarding Detection (BFD) (SHA1 auth)"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002197
Klement Sekerad3ba5152017-02-14 03:09:17 +01002198 pg0 = None
2199 vpp_clock_offset = None
2200 vpp_session = None
2201 test_session = None
2202
Klement Sekerab17dd962017-01-09 07:43:48 +01002203 @classmethod
2204 def setUpClass(cls):
2205 super(BFDSHA1TestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -08002206 cls.vapi.cli("set log class bfd level debug")
Klement Sekerab17dd962017-01-09 07:43:48 +01002207 try:
2208 cls.create_pg_interfaces([0])
2209 cls.pg0.config_ip4()
2210 cls.pg0.admin_up()
2211 cls.pg0.resolve_arp()
2212
2213 except Exception:
2214 super(BFDSHA1TestCase, cls).tearDownClass()
2215 raise
2216
Paul Vinciguerra8d991d92019-01-25 14:05:48 -08002217 @classmethod
2218 def tearDownClass(cls):
2219 super(BFDSHA1TestCase, cls).tearDownClass()
2220
Klement Sekerab17dd962017-01-09 07:43:48 +01002221 def setUp(self):
2222 super(BFDSHA1TestCase, self).setUp()
2223 self.factory = AuthKeyFactory()
2224 self.vapi.want_bfd_events()
Klement Sekerad3ba5152017-02-14 03:09:17 +01002225 self.pg0.enable_capture()
Klement Sekerab17dd962017-01-09 07:43:48 +01002226
2227 def tearDown(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002228 if not self.vpp_dead:
Jakub Grajciar4682feb2019-09-02 13:28:52 +02002229 self.vapi.want_bfd_events(enable_disable=False)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002230 self.vapi.collect_events() # clear the event queue
2231 super(BFDSHA1TestCase, self).tearDown()
Klement Sekerab17dd962017-01-09 07:43:48 +01002232
2233 def test_session_up(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002234 """bring BFD session up"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002235 key = self.factory.create_random_key(self)
2236 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002237 self.vpp_session = VppBFDUDPSession(
2238 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2239 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002240 self.vpp_session.add_vpp_config()
2241 self.vpp_session.admin_up()
2242 self.test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002243 self,
2244 self.pg0,
2245 AF_INET,
2246 sha1_key=key,
2247 bfd_key_id=self.vpp_session.bfd_key_id,
2248 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01002249 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002250
2251 def test_hold_up(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002252 """hold BFD session up"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002253 key = self.factory.create_random_key(self)
2254 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002255 self.vpp_session = VppBFDUDPSession(
2256 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2257 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002258 self.vpp_session.add_vpp_config()
2259 self.vpp_session.admin_up()
2260 self.test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002261 self,
2262 self.pg0,
2263 AF_INET,
2264 sha1_key=key,
2265 bfd_key_id=self.vpp_session.bfd_key_id,
2266 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01002267 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002268 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002269 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002270 self.test_session.send_packet()
2271 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
2272
2273 def test_hold_up_meticulous(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002274 """hold BFD session up - meticulous auth"""
2275 key = self.factory.create_random_key(self, BFDAuthType.meticulous_keyed_sha1)
Klement Sekerab17dd962017-01-09 07:43:48 +01002276 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002277 self.vpp_session = VppBFDUDPSession(
2278 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2279 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002280 self.vpp_session.add_vpp_config()
2281 self.vpp_session.admin_up()
Klement Sekerad3ba5152017-02-14 03:09:17 +01002282 # specify sequence number so that it wraps
Klement Sekerab17dd962017-01-09 07:43:48 +01002283 self.test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002284 self,
2285 self.pg0,
2286 AF_INET,
2287 sha1_key=key,
Klement Sekerad3ba5152017-02-14 03:09:17 +01002288 bfd_key_id=self.vpp_session.bfd_key_id,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002289 our_seq_number=0xFFFFFFFF - 4,
2290 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01002291 bfd_session_up(self)
2292 for dummy in range(30):
2293 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002294 self.test_session.inc_seq_num()
2295 self.test_session.send_packet()
2296 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
2297
2298 def test_send_bad_seq_number(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002299 """session is not kept alive by msgs with bad sequence numbers"""
2300 key = self.factory.create_random_key(self, BFDAuthType.meticulous_keyed_sha1)
Klement Sekerab17dd962017-01-09 07:43:48 +01002301 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002302 self.vpp_session = VppBFDUDPSession(
2303 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2304 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002305 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002306 self.test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002307 self,
2308 self.pg0,
2309 AF_INET,
2310 sha1_key=key,
2311 bfd_key_id=self.vpp_session.bfd_key_id,
2312 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01002313 bfd_session_up(self)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002314 detection_time = (
2315 self.test_session.detect_mult
2316 * self.vpp_session.required_min_rx
2317 / USEC_IN_SEC
2318 )
Klement Sekera239790f2017-02-16 10:53:53 +01002319 send_until = time.time() + 2 * detection_time
2320 while time.time() < send_until:
Klement Sekerad3ba5152017-02-14 03:09:17 +01002321 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002322 self.sleep(
2323 0.7 * self.vpp_session.required_min_rx / USEC_IN_SEC,
2324 "time between bfd packets",
2325 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002326 e = self.vapi.collect_events()
2327 # session should be down now, because the sequence numbers weren't
2328 # updated
2329 self.assert_equal(len(e), 1, "number of bfd events")
Klement Sekerad3ba5152017-02-14 03:09:17 +01002330 verify_event(self, e[0], expected_state=BFDState.down)
Klement Sekerab17dd962017-01-09 07:43:48 +01002331
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002332 def execute_rogue_session_scenario(
2333 self,
2334 vpp_bfd_udp_session,
2335 legitimate_test_session,
2336 rogue_test_session,
2337 rogue_bfd_values=None,
2338 ):
2339 """execute a rogue session interaction scenario
Klement Sekerab17dd962017-01-09 07:43:48 +01002340
2341 1. create vpp session, add config
2342 2. bring the legitimate session up
2343 3. copy the bfd values from legitimate session to rogue session
2344 4. apply rogue_bfd_values to rogue session
2345 5. set rogue session state to down
2346 6. send message to take the session down from the rogue session
2347 7. assert that the legitimate session is unaffected
2348 """
2349
2350 self.vpp_session = vpp_bfd_udp_session
2351 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002352 self.test_session = legitimate_test_session
2353 # bring vpp session up
Klement Sekerad3ba5152017-02-14 03:09:17 +01002354 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002355 # send packet from rogue session
Klement Sekerad3ba5152017-02-14 03:09:17 +01002356 rogue_test_session.update(
2357 my_discriminator=self.test_session.my_discriminator,
2358 your_discriminator=self.test_session.your_discriminator,
2359 desired_min_tx=self.test_session.desired_min_tx,
2360 required_min_rx=self.test_session.required_min_rx,
2361 detect_mult=self.test_session.detect_mult,
2362 diag=self.test_session.diag,
2363 state=self.test_session.state,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002364 auth_type=self.test_session.auth_type,
2365 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002366 if rogue_bfd_values:
2367 rogue_test_session.update(**rogue_bfd_values)
2368 rogue_test_session.update(state=BFDState.down)
2369 rogue_test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +01002370 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002371 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
2372
2373 def test_mismatch_auth(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002374 """session is not brought down by unauthenticated msg"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002375 key = self.factory.create_random_key(self)
2376 key.add_vpp_config()
2377 vpp_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002378 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2379 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002380 legitimate_test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002381 self, self.pg0, AF_INET, sha1_key=key, bfd_key_id=vpp_session.bfd_key_id
2382 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002383 rogue_test_session = BFDTestSession(self, self.pg0, AF_INET)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002384 self.execute_rogue_session_scenario(
2385 vpp_session, legitimate_test_session, rogue_test_session
2386 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002387
2388 def test_mismatch_bfd_key_id(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002389 """session is not brought down by msg with non-existent key-id"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002390 key = self.factory.create_random_key(self)
2391 key.add_vpp_config()
2392 vpp_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002393 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2394 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002395 # pick a different random bfd key id
2396 x = randint(0, 255)
2397 while x == vpp_session.bfd_key_id:
2398 x = randint(0, 255)
2399 legitimate_test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002400 self, self.pg0, AF_INET, sha1_key=key, bfd_key_id=vpp_session.bfd_key_id
2401 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002402 rogue_test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002403 self, self.pg0, AF_INET, sha1_key=key, bfd_key_id=x
2404 )
2405 self.execute_rogue_session_scenario(
2406 vpp_session, legitimate_test_session, rogue_test_session
2407 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002408
2409 def test_mismatched_auth_type(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002410 """session is not brought down by msg with wrong auth type"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002411 key = self.factory.create_random_key(self)
2412 key.add_vpp_config()
2413 vpp_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002414 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2415 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002416 legitimate_test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002417 self, self.pg0, AF_INET, sha1_key=key, bfd_key_id=vpp_session.bfd_key_id
2418 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002419 rogue_test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002420 self, self.pg0, AF_INET, sha1_key=key, bfd_key_id=vpp_session.bfd_key_id
2421 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002422 self.execute_rogue_session_scenario(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002423 vpp_session,
2424 legitimate_test_session,
2425 rogue_test_session,
2426 {"auth_type": BFDAuthType.keyed_md5},
2427 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002428
2429 def test_restart(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002430 """simulate remote peer restart and resynchronization"""
2431 key = self.factory.create_random_key(self, BFDAuthType.meticulous_keyed_sha1)
Klement Sekerab17dd962017-01-09 07:43:48 +01002432 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002433 self.vpp_session = VppBFDUDPSession(
2434 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2435 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002436 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002437 self.test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002438 self,
2439 self.pg0,
2440 AF_INET,
2441 sha1_key=key,
2442 bfd_key_id=self.vpp_session.bfd_key_id,
2443 our_seq_number=0,
2444 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01002445 bfd_session_up(self)
2446 # don't send any packets for 2*detection_time
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002447 detection_time = (
2448 self.test_session.detect_mult
2449 * self.vpp_session.required_min_rx
2450 / USEC_IN_SEC
2451 )
Klement Sekera87134932017-03-07 11:39:27 +01002452 self.sleep(2 * detection_time, "simulating peer restart")
Klement Sekerad3ba5152017-02-14 03:09:17 +01002453 events = self.vapi.collect_events()
2454 self.assert_equal(len(events), 1, "number of bfd events")
2455 verify_event(self, events[0], expected_state=BFDState.down)
Klement Sekerab17dd962017-01-09 07:43:48 +01002456 self.test_session.update(state=BFDState.down)
Klement Sekerab17dd962017-01-09 07:43:48 +01002457 # reset sequence number
2458 self.test_session.our_seq_number = 0
Klement Sekerad3ba5152017-02-14 03:09:17 +01002459 self.test_session.vpp_seq_number = None
2460 # now throw away any pending packets
2461 self.pg0.enable_capture()
Klement Sekera4d39f9c2020-01-17 10:01:52 +00002462 self.test_session.my_discriminator = 0
Klement Sekerad3ba5152017-02-14 03:09:17 +01002463 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002464
2465
Andrew Yourtchenko06f32812021-01-14 10:19:08 +00002466@tag_run_solo
Klement Sekerad3ba5152017-02-14 03:09:17 +01002467class BFDAuthOnOffTestCase(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002468 """Bidirectional Forwarding Detection (BFD) (changing auth)"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002469
Klement Sekerad3ba5152017-02-14 03:09:17 +01002470 pg0 = None
2471 vpp_session = None
2472 test_session = None
2473
Klement Sekerab17dd962017-01-09 07:43:48 +01002474 @classmethod
2475 def setUpClass(cls):
2476 super(BFDAuthOnOffTestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -08002477 cls.vapi.cli("set log class bfd level debug")
Klement Sekerab17dd962017-01-09 07:43:48 +01002478 try:
2479 cls.create_pg_interfaces([0])
2480 cls.pg0.config_ip4()
2481 cls.pg0.admin_up()
2482 cls.pg0.resolve_arp()
2483
2484 except Exception:
2485 super(BFDAuthOnOffTestCase, cls).tearDownClass()
2486 raise
2487
Paul Vinciguerra8d991d92019-01-25 14:05:48 -08002488 @classmethod
2489 def tearDownClass(cls):
2490 super(BFDAuthOnOffTestCase, cls).tearDownClass()
2491
Klement Sekerab17dd962017-01-09 07:43:48 +01002492 def setUp(self):
2493 super(BFDAuthOnOffTestCase, self).setUp()
2494 self.factory = AuthKeyFactory()
2495 self.vapi.want_bfd_events()
Klement Sekerad3ba5152017-02-14 03:09:17 +01002496 self.pg0.enable_capture()
Klement Sekerab17dd962017-01-09 07:43:48 +01002497
2498 def tearDown(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002499 if not self.vpp_dead:
Jakub Grajciar4682feb2019-09-02 13:28:52 +02002500 self.vapi.want_bfd_events(enable_disable=False)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002501 self.vapi.collect_events() # clear the event queue
2502 super(BFDAuthOnOffTestCase, self).tearDown()
Klement Sekerab17dd962017-01-09 07:43:48 +01002503
2504 def test_auth_on_immediate(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002505 """turn auth on without disturbing session state (immediate)"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002506 key = self.factory.create_random_key(self)
2507 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002508 self.vpp_session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
Klement Sekerab17dd962017-01-09 07:43:48 +01002509 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002510 self.test_session = BFDTestSession(self, self.pg0, AF_INET)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002511 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002512 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002513 p = wait_for_bfd_packet(self)
2514 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002515 self.test_session.send_packet()
2516 self.vpp_session.activate_auth(key)
2517 self.test_session.bfd_key_id = self.vpp_session.bfd_key_id
2518 self.test_session.sha1_key = key
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002519 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002520 p = wait_for_bfd_packet(self)
2521 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002522 self.test_session.send_packet()
2523 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002524 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekerab17dd962017-01-09 07:43:48 +01002525
2526 def test_auth_off_immediate(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002527 """turn auth off without disturbing session state (immediate)"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002528 key = self.factory.create_random_key(self)
2529 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002530 self.vpp_session = VppBFDUDPSession(
2531 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2532 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002533 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002534 self.test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002535 self,
2536 self.pg0,
2537 AF_INET,
2538 sha1_key=key,
2539 bfd_key_id=self.vpp_session.bfd_key_id,
2540 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01002541 bfd_session_up(self)
2542 # self.vapi.want_bfd_events(enable_disable=0)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002543 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002544 p = wait_for_bfd_packet(self)
2545 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
2546 self.test_session.inc_seq_num()
Klement Sekerab17dd962017-01-09 07:43:48 +01002547 self.test_session.send_packet()
2548 self.vpp_session.deactivate_auth()
2549 self.test_session.bfd_key_id = None
2550 self.test_session.sha1_key = None
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002551 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002552 p = wait_for_bfd_packet(self)
2553 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
2554 self.test_session.inc_seq_num()
Klement Sekerab17dd962017-01-09 07:43:48 +01002555 self.test_session.send_packet()
2556 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002557 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekerab17dd962017-01-09 07:43:48 +01002558
2559 def test_auth_change_key_immediate(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002560 """change auth key without disturbing session state (immediate)"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002561 key1 = self.factory.create_random_key(self)
2562 key1.add_vpp_config()
2563 key2 = self.factory.create_random_key(self)
2564 key2.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002565 self.vpp_session = VppBFDUDPSession(
2566 self, self.pg0, self.pg0.remote_ip4, sha1_key=key1
2567 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002568 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002569 self.test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002570 self,
2571 self.pg0,
2572 AF_INET,
2573 sha1_key=key1,
2574 bfd_key_id=self.vpp_session.bfd_key_id,
2575 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01002576 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002577 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002578 p = wait_for_bfd_packet(self)
2579 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002580 self.test_session.send_packet()
2581 self.vpp_session.activate_auth(key2)
2582 self.test_session.bfd_key_id = self.vpp_session.bfd_key_id
2583 self.test_session.sha1_key = key2
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002584 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002585 p = wait_for_bfd_packet(self)
2586 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002587 self.test_session.send_packet()
2588 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002589 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekerab17dd962017-01-09 07:43:48 +01002590
2591 def test_auth_on_delayed(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002592 """turn auth on without disturbing session state (delayed)"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002593 key = self.factory.create_random_key(self)
2594 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002595 self.vpp_session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
Klement Sekerab17dd962017-01-09 07:43:48 +01002596 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002597 self.test_session = BFDTestSession(self, self.pg0, AF_INET)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002598 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002599 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002600 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002601 self.test_session.send_packet()
2602 self.vpp_session.activate_auth(key, delayed=True)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002603 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002604 p = wait_for_bfd_packet(self)
2605 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002606 self.test_session.send_packet()
2607 self.test_session.bfd_key_id = self.vpp_session.bfd_key_id
2608 self.test_session.sha1_key = key
2609 self.test_session.send_packet()
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002610 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002611 p = wait_for_bfd_packet(self)
2612 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002613 self.test_session.send_packet()
2614 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002615 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekerab17dd962017-01-09 07:43:48 +01002616
2617 def test_auth_off_delayed(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002618 """turn auth off without disturbing session state (delayed)"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002619 key = self.factory.create_random_key(self)
2620 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002621 self.vpp_session = VppBFDUDPSession(
2622 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2623 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002624 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002625 self.test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002626 self,
2627 self.pg0,
2628 AF_INET,
2629 sha1_key=key,
2630 bfd_key_id=self.vpp_session.bfd_key_id,
2631 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01002632 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002633 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002634 p = wait_for_bfd_packet(self)
2635 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002636 self.test_session.send_packet()
2637 self.vpp_session.deactivate_auth(delayed=True)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002638 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002639 p = wait_for_bfd_packet(self)
2640 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002641 self.test_session.send_packet()
2642 self.test_session.bfd_key_id = None
2643 self.test_session.sha1_key = None
2644 self.test_session.send_packet()
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002645 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002646 p = wait_for_bfd_packet(self)
2647 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002648 self.test_session.send_packet()
2649 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002650 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekerab17dd962017-01-09 07:43:48 +01002651
2652 def test_auth_change_key_delayed(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002653 """change auth key without disturbing session state (delayed)"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002654 key1 = self.factory.create_random_key(self)
2655 key1.add_vpp_config()
2656 key2 = self.factory.create_random_key(self)
2657 key2.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002658 self.vpp_session = VppBFDUDPSession(
2659 self, self.pg0, self.pg0.remote_ip4, sha1_key=key1
2660 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002661 self.vpp_session.add_vpp_config()
2662 self.vpp_session.admin_up()
2663 self.test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002664 self,
2665 self.pg0,
2666 AF_INET,
2667 sha1_key=key1,
2668 bfd_key_id=self.vpp_session.bfd_key_id,
2669 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01002670 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002671 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002672 p = wait_for_bfd_packet(self)
2673 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002674 self.test_session.send_packet()
2675 self.vpp_session.activate_auth(key2, delayed=True)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002676 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002677 p = wait_for_bfd_packet(self)
2678 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002679 self.test_session.send_packet()
2680 self.test_session.bfd_key_id = self.vpp_session.bfd_key_id
2681 self.test_session.sha1_key = key2
2682 self.test_session.send_packet()
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002683 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002684 p = wait_for_bfd_packet(self)
2685 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002686 self.test_session.send_packet()
2687 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002688 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekera46a87ad2017-01-02 08:22:23 +01002689
Klement Sekera73884482017-02-23 09:26:30 +01002690
Andrew Yourtchenko06f32812021-01-14 10:19:08 +00002691@tag_run_solo
Klement Sekera73884482017-02-23 09:26:30 +01002692class BFDCLITestCase(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002693 """Bidirectional Forwarding Detection (BFD) (CLI)"""
2694
Klement Sekera73884482017-02-23 09:26:30 +01002695 pg0 = None
2696
2697 @classmethod
2698 def setUpClass(cls):
2699 super(BFDCLITestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -08002700 cls.vapi.cli("set log class bfd level debug")
Klement Sekera73884482017-02-23 09:26:30 +01002701 try:
2702 cls.create_pg_interfaces((0,))
2703 cls.pg0.config_ip4()
2704 cls.pg0.config_ip6()
2705 cls.pg0.resolve_arp()
2706 cls.pg0.resolve_ndp()
2707
2708 except Exception:
2709 super(BFDCLITestCase, cls).tearDownClass()
2710 raise
2711
Paul Vinciguerra8d991d92019-01-25 14:05:48 -08002712 @classmethod
2713 def tearDownClass(cls):
2714 super(BFDCLITestCase, cls).tearDownClass()
2715
Klement Sekera73884482017-02-23 09:26:30 +01002716 def setUp(self):
2717 super(BFDCLITestCase, self).setUp()
2718 self.factory = AuthKeyFactory()
2719 self.pg0.enable_capture()
2720
2721 def tearDown(self):
2722 try:
Jakub Grajciar4682feb2019-09-02 13:28:52 +02002723 self.vapi.want_bfd_events(enable_disable=False)
Klement Sekera73884482017-02-23 09:26:30 +01002724 except UnexpectedApiReturnValueError:
2725 # some tests aren't subscribed, so this is not an issue
2726 pass
2727 self.vapi.collect_events() # clear the event queue
2728 super(BFDCLITestCase, self).tearDown()
2729
2730 def cli_verify_no_response(self, cli):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002731 """execute a CLI, asserting that the response is empty"""
2732 self.assert_equal(self.vapi.cli(cli), "", "CLI command response")
Klement Sekera73884482017-02-23 09:26:30 +01002733
2734 def cli_verify_response(self, cli, expected):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002735 """execute a CLI, asserting that the response matches expectation"""
Jakub Grajciar4682feb2019-09-02 13:28:52 +02002736 try:
2737 reply = self.vapi.cli(cli)
2738 except CliFailedCommandError as cli_error:
2739 reply = str(cli_error)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002740 self.assert_equal(reply.strip(), expected, "CLI command response")
Klement Sekera73884482017-02-23 09:26:30 +01002741
2742 def test_show(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002743 """show commands"""
Klement Sekera73884482017-02-23 09:26:30 +01002744 k1 = self.factory.create_random_key(self)
2745 k1.add_vpp_config()
2746 k2 = self.factory.create_random_key(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002747 self, auth_type=BFDAuthType.meticulous_keyed_sha1
2748 )
Klement Sekera73884482017-02-23 09:26:30 +01002749 k2.add_vpp_config()
2750 s1 = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
2751 s1.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002752 s2 = VppBFDUDPSession(
2753 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6, sha1_key=k2
2754 )
Klement Sekera73884482017-02-23 09:26:30 +01002755 s2.add_vpp_config()
2756 self.logger.info(self.vapi.ppcli("show bfd keys"))
2757 self.logger.info(self.vapi.ppcli("show bfd sessions"))
2758 self.logger.info(self.vapi.ppcli("show bfd"))
2759
2760 def test_set_del_sha1_key(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002761 """set/delete SHA1 auth key"""
Klement Sekera73884482017-02-23 09:26:30 +01002762 k = self.factory.create_random_key(self)
2763 self.registry.register(k, self.logger)
2764 self.cli_verify_no_response(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002765 "bfd key set conf-key-id %s type keyed-sha1 secret %s"
2766 % (
2767 k.conf_key_id,
2768 "".join("{:02x}".format(scapy.compat.orb(c)) for c in k.key),
2769 )
2770 )
Klement Sekera73884482017-02-23 09:26:30 +01002771 self.assertTrue(k.query_vpp_config())
2772 self.vpp_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002773 self, self.pg0, self.pg0.remote_ip4, sha1_key=k
2774 )
Klement Sekera73884482017-02-23 09:26:30 +01002775 self.vpp_session.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002776 self.test_session = BFDTestSession(
2777 self, self.pg0, AF_INET, sha1_key=k, bfd_key_id=self.vpp_session.bfd_key_id
2778 )
Klement Sekera73884482017-02-23 09:26:30 +01002779 self.vapi.want_bfd_events()
2780 bfd_session_up(self)
2781 bfd_session_down(self)
2782 # try to replace the secret for the key - should fail because the key
2783 # is in-use
2784 k2 = self.factory.create_random_key(self)
2785 self.cli_verify_response(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002786 "bfd key set conf-key-id %s type keyed-sha1 secret %s"
2787 % (
2788 k.conf_key_id,
2789 "".join("{:02x}".format(scapy.compat.orb(c)) for c in k2.key),
2790 ),
Klement Sekera73884482017-02-23 09:26:30 +01002791 "bfd key set: `bfd_auth_set_key' API call failed, "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002792 "rv=-103:BFD object in use",
2793 )
Klement Sekera73884482017-02-23 09:26:30 +01002794 # manipulating the session using old secret should still work
2795 bfd_session_up(self)
2796 bfd_session_down(self)
2797 self.vpp_session.remove_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002798 self.cli_verify_no_response("bfd key del conf-key-id %s" % k.conf_key_id)
Klement Sekera73884482017-02-23 09:26:30 +01002799 self.assertFalse(k.query_vpp_config())
2800
2801 def test_set_del_meticulous_sha1_key(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002802 """set/delete meticulous SHA1 auth key"""
Klement Sekera73884482017-02-23 09:26:30 +01002803 k = self.factory.create_random_key(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002804 self, auth_type=BFDAuthType.meticulous_keyed_sha1
2805 )
Klement Sekera73884482017-02-23 09:26:30 +01002806 self.registry.register(k, self.logger)
2807 self.cli_verify_no_response(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002808 "bfd key set conf-key-id %s type meticulous-keyed-sha1 secret %s"
2809 % (
2810 k.conf_key_id,
2811 "".join("{:02x}".format(scapy.compat.orb(c)) for c in k.key),
2812 )
2813 )
Klement Sekera73884482017-02-23 09:26:30 +01002814 self.assertTrue(k.query_vpp_config())
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002815 self.vpp_session = VppBFDUDPSession(
2816 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6, sha1_key=k
2817 )
Klement Sekera73884482017-02-23 09:26:30 +01002818 self.vpp_session.add_vpp_config()
2819 self.vpp_session.admin_up()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002820 self.test_session = BFDTestSession(
2821 self, self.pg0, AF_INET6, sha1_key=k, bfd_key_id=self.vpp_session.bfd_key_id
2822 )
Klement Sekera73884482017-02-23 09:26:30 +01002823 self.vapi.want_bfd_events()
2824 bfd_session_up(self)
2825 bfd_session_down(self)
2826 # try to replace the secret for the key - should fail because the key
2827 # is in-use
2828 k2 = self.factory.create_random_key(self)
2829 self.cli_verify_response(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002830 "bfd key set conf-key-id %s type keyed-sha1 secret %s"
2831 % (
2832 k.conf_key_id,
2833 "".join("{:02x}".format(scapy.compat.orb(c)) for c in k2.key),
2834 ),
Klement Sekera73884482017-02-23 09:26:30 +01002835 "bfd key set: `bfd_auth_set_key' API call failed, "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002836 "rv=-103:BFD object in use",
2837 )
Klement Sekera73884482017-02-23 09:26:30 +01002838 # manipulating the session using old secret should still work
2839 bfd_session_up(self)
2840 bfd_session_down(self)
2841 self.vpp_session.remove_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002842 self.cli_verify_no_response("bfd key del conf-key-id %s" % k.conf_key_id)
Klement Sekera73884482017-02-23 09:26:30 +01002843 self.assertFalse(k.query_vpp_config())
2844
2845 def test_add_mod_del_bfd_udp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002846 """create/modify/delete IPv4 BFD UDP session"""
2847 vpp_session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
Klement Sekera73884482017-02-23 09:26:30 +01002848 self.registry.register(vpp_session, self.logger)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002849 cli_add_cmd = (
2850 "bfd udp session add interface %s local-addr %s "
2851 "peer-addr %s desired-min-tx %s required-min-rx %s "
2852 "detect-mult %s"
2853 % (
2854 self.pg0.name,
2855 self.pg0.local_ip4,
2856 self.pg0.remote_ip4,
2857 vpp_session.desired_min_tx,
2858 vpp_session.required_min_rx,
2859 vpp_session.detect_mult,
2860 )
2861 )
Klement Sekera73884482017-02-23 09:26:30 +01002862 self.cli_verify_no_response(cli_add_cmd)
2863 # 2nd add should fail
2864 self.cli_verify_response(
2865 cli_add_cmd,
2866 "bfd udp session add: `bfd_add_add_session' API call"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002867 " failed, rv=-101:Duplicate BFD object",
2868 )
Klement Sekera73884482017-02-23 09:26:30 +01002869 verify_bfd_session_config(self, vpp_session)
2870 mod_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002871 self,
2872 self.pg0,
2873 self.pg0.remote_ip4,
Klement Sekera73884482017-02-23 09:26:30 +01002874 required_min_rx=2 * vpp_session.required_min_rx,
2875 desired_min_tx=3 * vpp_session.desired_min_tx,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002876 detect_mult=4 * vpp_session.detect_mult,
2877 )
Klement Sekera73884482017-02-23 09:26:30 +01002878 self.cli_verify_no_response(
2879 "bfd udp session mod interface %s local-addr %s peer-addr %s "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002880 "desired-min-tx %s required-min-rx %s detect-mult %s"
2881 % (
2882 self.pg0.name,
2883 self.pg0.local_ip4,
2884 self.pg0.remote_ip4,
2885 mod_session.desired_min_tx,
2886 mod_session.required_min_rx,
2887 mod_session.detect_mult,
2888 )
2889 )
Klement Sekera73884482017-02-23 09:26:30 +01002890 verify_bfd_session_config(self, mod_session)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002891 cli_del_cmd = (
2892 "bfd udp session del interface %s local-addr %s "
2893 "peer-addr %s" % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4)
2894 )
Klement Sekera73884482017-02-23 09:26:30 +01002895 self.cli_verify_no_response(cli_del_cmd)
2896 # 2nd del is expected to fail
2897 self.cli_verify_response(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002898 cli_del_cmd,
2899 "bfd udp session del: `bfd_udp_del_session' API call"
2900 " failed, rv=-102:No such BFD object",
2901 )
Klement Sekera73884482017-02-23 09:26:30 +01002902 self.assertFalse(vpp_session.query_vpp_config())
2903
2904 def test_add_mod_del_bfd_udp6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002905 """create/modify/delete IPv6 BFD UDP session"""
2906 vpp_session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip6, af=AF_INET6)
Klement Sekera73884482017-02-23 09:26:30 +01002907 self.registry.register(vpp_session, self.logger)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002908 cli_add_cmd = (
2909 "bfd udp session add interface %s local-addr %s "
2910 "peer-addr %s desired-min-tx %s required-min-rx %s "
2911 "detect-mult %s"
2912 % (
2913 self.pg0.name,
2914 self.pg0.local_ip6,
2915 self.pg0.remote_ip6,
2916 vpp_session.desired_min_tx,
2917 vpp_session.required_min_rx,
2918 vpp_session.detect_mult,
2919 )
2920 )
Klement Sekera73884482017-02-23 09:26:30 +01002921 self.cli_verify_no_response(cli_add_cmd)
2922 # 2nd add should fail
2923 self.cli_verify_response(
2924 cli_add_cmd,
2925 "bfd udp session add: `bfd_add_add_session' API call"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002926 " failed, rv=-101:Duplicate BFD object",
2927 )
Klement Sekera73884482017-02-23 09:26:30 +01002928 verify_bfd_session_config(self, vpp_session)
2929 mod_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002930 self,
2931 self.pg0,
2932 self.pg0.remote_ip6,
2933 af=AF_INET6,
Klement Sekera73884482017-02-23 09:26:30 +01002934 required_min_rx=2 * vpp_session.required_min_rx,
2935 desired_min_tx=3 * vpp_session.desired_min_tx,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002936 detect_mult=4 * vpp_session.detect_mult,
2937 )
Klement Sekera73884482017-02-23 09:26:30 +01002938 self.cli_verify_no_response(
2939 "bfd udp session mod interface %s local-addr %s peer-addr %s "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002940 "desired-min-tx %s required-min-rx %s detect-mult %s"
2941 % (
2942 self.pg0.name,
2943 self.pg0.local_ip6,
2944 self.pg0.remote_ip6,
2945 mod_session.desired_min_tx,
2946 mod_session.required_min_rx,
2947 mod_session.detect_mult,
2948 )
2949 )
Klement Sekera73884482017-02-23 09:26:30 +01002950 verify_bfd_session_config(self, mod_session)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002951 cli_del_cmd = (
2952 "bfd udp session del interface %s local-addr %s "
2953 "peer-addr %s" % (self.pg0.name, self.pg0.local_ip6, self.pg0.remote_ip6)
2954 )
Klement Sekera73884482017-02-23 09:26:30 +01002955 self.cli_verify_no_response(cli_del_cmd)
2956 # 2nd del is expected to fail
2957 self.cli_verify_response(
2958 cli_del_cmd,
2959 "bfd udp session del: `bfd_udp_del_session' API call"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002960 " failed, rv=-102:No such BFD object",
2961 )
Klement Sekera73884482017-02-23 09:26:30 +01002962 self.assertFalse(vpp_session.query_vpp_config())
2963
2964 def test_add_mod_del_bfd_udp_auth(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002965 """create/modify/delete IPv4 BFD UDP session (authenticated)"""
Klement Sekera73884482017-02-23 09:26:30 +01002966 key = self.factory.create_random_key(self)
2967 key.add_vpp_config()
2968 vpp_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002969 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2970 )
Klement Sekera73884482017-02-23 09:26:30 +01002971 self.registry.register(vpp_session, self.logger)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002972 cli_add_cmd = (
2973 "bfd udp session add interface %s local-addr %s "
2974 "peer-addr %s desired-min-tx %s required-min-rx %s "
2975 "detect-mult %s conf-key-id %s bfd-key-id %s"
2976 % (
2977 self.pg0.name,
2978 self.pg0.local_ip4,
2979 self.pg0.remote_ip4,
2980 vpp_session.desired_min_tx,
2981 vpp_session.required_min_rx,
2982 vpp_session.detect_mult,
2983 key.conf_key_id,
2984 vpp_session.bfd_key_id,
2985 )
2986 )
Klement Sekera73884482017-02-23 09:26:30 +01002987 self.cli_verify_no_response(cli_add_cmd)
2988 # 2nd add should fail
2989 self.cli_verify_response(
2990 cli_add_cmd,
2991 "bfd udp session add: `bfd_add_add_session' API call"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002992 " failed, rv=-101:Duplicate BFD object",
2993 )
Klement Sekera73884482017-02-23 09:26:30 +01002994 verify_bfd_session_config(self, vpp_session)
2995 mod_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002996 self,
2997 self.pg0,
2998 self.pg0.remote_ip4,
2999 sha1_key=key,
Klement Sekera73884482017-02-23 09:26:30 +01003000 bfd_key_id=vpp_session.bfd_key_id,
3001 required_min_rx=2 * vpp_session.required_min_rx,
3002 desired_min_tx=3 * vpp_session.desired_min_tx,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003003 detect_mult=4 * vpp_session.detect_mult,
3004 )
Klement Sekera73884482017-02-23 09:26:30 +01003005 self.cli_verify_no_response(
3006 "bfd udp session mod interface %s local-addr %s peer-addr %s "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003007 "desired-min-tx %s required-min-rx %s detect-mult %s"
3008 % (
3009 self.pg0.name,
3010 self.pg0.local_ip4,
3011 self.pg0.remote_ip4,
3012 mod_session.desired_min_tx,
3013 mod_session.required_min_rx,
3014 mod_session.detect_mult,
3015 )
3016 )
Klement Sekera73884482017-02-23 09:26:30 +01003017 verify_bfd_session_config(self, mod_session)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003018 cli_del_cmd = (
3019 "bfd udp session del interface %s local-addr %s "
3020 "peer-addr %s" % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4)
3021 )
Klement Sekera73884482017-02-23 09:26:30 +01003022 self.cli_verify_no_response(cli_del_cmd)
3023 # 2nd del is expected to fail
3024 self.cli_verify_response(
3025 cli_del_cmd,
3026 "bfd udp session del: `bfd_udp_del_session' API call"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003027 " failed, rv=-102:No such BFD object",
3028 )
Klement Sekera73884482017-02-23 09:26:30 +01003029 self.assertFalse(vpp_session.query_vpp_config())
3030
3031 def test_add_mod_del_bfd_udp6_auth(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003032 """create/modify/delete IPv6 BFD UDP session (authenticated)"""
Klement Sekera73884482017-02-23 09:26:30 +01003033 key = self.factory.create_random_key(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003034 self, auth_type=BFDAuthType.meticulous_keyed_sha1
3035 )
Klement Sekera73884482017-02-23 09:26:30 +01003036 key.add_vpp_config()
3037 vpp_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003038 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6, sha1_key=key
3039 )
Klement Sekera73884482017-02-23 09:26:30 +01003040 self.registry.register(vpp_session, self.logger)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003041 cli_add_cmd = (
3042 "bfd udp session add interface %s local-addr %s "
3043 "peer-addr %s desired-min-tx %s required-min-rx %s "
3044 "detect-mult %s conf-key-id %s bfd-key-id %s"
3045 % (
3046 self.pg0.name,
3047 self.pg0.local_ip6,
3048 self.pg0.remote_ip6,
3049 vpp_session.desired_min_tx,
3050 vpp_session.required_min_rx,
3051 vpp_session.detect_mult,
3052 key.conf_key_id,
3053 vpp_session.bfd_key_id,
3054 )
3055 )
Klement Sekera73884482017-02-23 09:26:30 +01003056 self.cli_verify_no_response(cli_add_cmd)
3057 # 2nd add should fail
3058 self.cli_verify_response(
3059 cli_add_cmd,
3060 "bfd udp session add: `bfd_add_add_session' API call"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003061 " failed, rv=-101:Duplicate BFD object",
3062 )
Klement Sekera73884482017-02-23 09:26:30 +01003063 verify_bfd_session_config(self, vpp_session)
3064 mod_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003065 self,
3066 self.pg0,
3067 self.pg0.remote_ip6,
3068 af=AF_INET6,
3069 sha1_key=key,
Klement Sekera73884482017-02-23 09:26:30 +01003070 bfd_key_id=vpp_session.bfd_key_id,
3071 required_min_rx=2 * vpp_session.required_min_rx,
3072 desired_min_tx=3 * vpp_session.desired_min_tx,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003073 detect_mult=4 * vpp_session.detect_mult,
3074 )
Klement Sekera73884482017-02-23 09:26:30 +01003075 self.cli_verify_no_response(
3076 "bfd udp session mod interface %s local-addr %s peer-addr %s "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003077 "desired-min-tx %s required-min-rx %s detect-mult %s"
3078 % (
3079 self.pg0.name,
3080 self.pg0.local_ip6,
3081 self.pg0.remote_ip6,
3082 mod_session.desired_min_tx,
3083 mod_session.required_min_rx,
3084 mod_session.detect_mult,
3085 )
3086 )
Klement Sekera73884482017-02-23 09:26:30 +01003087 verify_bfd_session_config(self, mod_session)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003088 cli_del_cmd = (
3089 "bfd udp session del interface %s local-addr %s "
3090 "peer-addr %s" % (self.pg0.name, self.pg0.local_ip6, self.pg0.remote_ip6)
3091 )
Klement Sekera73884482017-02-23 09:26:30 +01003092 self.cli_verify_no_response(cli_del_cmd)
3093 # 2nd del is expected to fail
3094 self.cli_verify_response(
3095 cli_del_cmd,
3096 "bfd udp session del: `bfd_udp_del_session' API call"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003097 " failed, rv=-102:No such BFD object",
3098 )
Klement Sekera73884482017-02-23 09:26:30 +01003099 self.assertFalse(vpp_session.query_vpp_config())
3100
3101 def test_auth_on_off(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003102 """turn authentication on and off"""
Klement Sekera73884482017-02-23 09:26:30 +01003103 key = self.factory.create_random_key(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003104 self, auth_type=BFDAuthType.meticulous_keyed_sha1
3105 )
Klement Sekera73884482017-02-23 09:26:30 +01003106 key.add_vpp_config()
3107 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003108 auth_session = VppBFDUDPSession(
3109 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
3110 )
Klement Sekera73884482017-02-23 09:26:30 +01003111 session.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003112 cli_activate = (
3113 "bfd udp session auth activate interface %s local-addr %s "
3114 "peer-addr %s conf-key-id %s bfd-key-id %s"
3115 % (
3116 self.pg0.name,
3117 self.pg0.local_ip4,
3118 self.pg0.remote_ip4,
3119 key.conf_key_id,
3120 auth_session.bfd_key_id,
3121 )
3122 )
Klement Sekera73884482017-02-23 09:26:30 +01003123 self.cli_verify_no_response(cli_activate)
3124 verify_bfd_session_config(self, auth_session)
3125 self.cli_verify_no_response(cli_activate)
3126 verify_bfd_session_config(self, auth_session)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003127 cli_deactivate = (
3128 "bfd udp session auth deactivate interface %s local-addr %s "
3129 "peer-addr %s " % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4)
3130 )
Klement Sekera73884482017-02-23 09:26:30 +01003131 self.cli_verify_no_response(cli_deactivate)
3132 verify_bfd_session_config(self, session)
3133 self.cli_verify_no_response(cli_deactivate)
3134 verify_bfd_session_config(self, session)
3135
3136 def test_auth_on_off_delayed(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003137 """turn authentication on and off (delayed)"""
Klement Sekera73884482017-02-23 09:26:30 +01003138 key = self.factory.create_random_key(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003139 self, auth_type=BFDAuthType.meticulous_keyed_sha1
3140 )
Klement Sekera73884482017-02-23 09:26:30 +01003141 key.add_vpp_config()
3142 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003143 auth_session = VppBFDUDPSession(
3144 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
3145 )
Klement Sekera73884482017-02-23 09:26:30 +01003146 session.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003147 cli_activate = (
3148 "bfd udp session auth activate interface %s local-addr %s "
3149 "peer-addr %s conf-key-id %s bfd-key-id %s delayed yes"
3150 % (
3151 self.pg0.name,
3152 self.pg0.local_ip4,
3153 self.pg0.remote_ip4,
3154 key.conf_key_id,
3155 auth_session.bfd_key_id,
3156 )
3157 )
Klement Sekera73884482017-02-23 09:26:30 +01003158 self.cli_verify_no_response(cli_activate)
3159 verify_bfd_session_config(self, auth_session)
3160 self.cli_verify_no_response(cli_activate)
3161 verify_bfd_session_config(self, auth_session)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003162 cli_deactivate = (
3163 "bfd udp session auth deactivate interface %s local-addr %s "
3164 "peer-addr %s delayed yes"
Klement Sekera73884482017-02-23 09:26:30 +01003165 % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003166 )
Klement Sekera73884482017-02-23 09:26:30 +01003167 self.cli_verify_no_response(cli_deactivate)
3168 verify_bfd_session_config(self, session)
3169 self.cli_verify_no_response(cli_deactivate)
3170 verify_bfd_session_config(self, session)
3171
3172 def test_admin_up_down(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003173 """put session admin-up and admin-down"""
Klement Sekera73884482017-02-23 09:26:30 +01003174 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
3175 session.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003176 cli_down = (
3177 "bfd udp session set-flags admin down interface %s local-addr %s "
3178 "peer-addr %s " % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4)
3179 )
3180 cli_up = (
3181 "bfd udp session set-flags admin up interface %s local-addr %s "
3182 "peer-addr %s " % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4)
3183 )
Klement Sekera73884482017-02-23 09:26:30 +01003184 self.cli_verify_no_response(cli_down)
3185 verify_bfd_session_config(self, session, state=BFDState.admin_down)
3186 self.cli_verify_no_response(cli_up)
3187 verify_bfd_session_config(self, session, state=BFDState.down)
3188
3189 def test_set_del_udp_echo_source(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003190 """set/del udp echo source"""
Klement Sekerab9ef2732018-06-24 22:49:33 +02003191 self.create_loopback_interfaces(1)
Klement Sekera73884482017-02-23 09:26:30 +01003192 self.loopback0 = self.lo_interfaces[0]
3193 self.loopback0.admin_up()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003194 self.cli_verify_response("show bfd echo-source", "UDP echo source is not set.")
Klement Sekera73884482017-02-23 09:26:30 +01003195 cli_set = "bfd udp echo-source set interface %s" % self.loopback0.name
3196 self.cli_verify_no_response(cli_set)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003197 self.cli_verify_response(
3198 "show bfd echo-source",
3199 "UDP echo source is: %s\n"
3200 "IPv4 address usable as echo source: none\n"
3201 "IPv6 address usable as echo source: none" % self.loopback0.name,
3202 )
Klement Sekera73884482017-02-23 09:26:30 +01003203 self.loopback0.config_ip4()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003204 echo_ip4 = str(
3205 ipaddress.IPv4Address(
3206 int(ipaddress.IPv4Address(self.loopback0.local_ip4)) ^ 1
3207 )
3208 )
3209 self.cli_verify_response(
3210 "show bfd echo-source",
3211 "UDP echo source is: %s\n"
3212 "IPv4 address usable as echo source: %s\n"
3213 "IPv6 address usable as echo source: none"
3214 % (self.loopback0.name, echo_ip4),
3215 )
3216 echo_ip6 = str(
3217 ipaddress.IPv6Address(
3218 int(ipaddress.IPv6Address(self.loopback0.local_ip6)) ^ 1
3219 )
3220 )
Klement Sekera73884482017-02-23 09:26:30 +01003221 self.loopback0.config_ip6()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003222 self.cli_verify_response(
3223 "show bfd echo-source",
3224 "UDP echo source is: %s\n"
3225 "IPv4 address usable as echo source: %s\n"
3226 "IPv6 address usable as echo source: %s"
3227 % (self.loopback0.name, echo_ip4, echo_ip6),
3228 )
Klement Sekera73884482017-02-23 09:26:30 +01003229 cli_del = "bfd udp echo-source del"
3230 self.cli_verify_no_response(cli_del)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003231 self.cli_verify_response("show bfd echo-source", "UDP echo source is not set.")
Klement Sekera73884482017-02-23 09:26:30 +01003232
Jakub Grajciar4682feb2019-09-02 13:28:52 +02003233
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003234if __name__ == "__main__":
Klement Sekera0e3c0de2016-09-29 14:43:44 +02003235 unittest.main(testRunner=VppTestRunner)