blob: 0842fd77429205cdad77a1781835e9b1d1f3341c [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
Dave Wallace8800f732023-08-31 00:47:44 -040014from socket import AF_INET, AF_INET6
Paul Vinciguerra00671cf2018-11-25 12:47:04 -080015
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -070016import scapy.compat
Klement Sekerad3ba5152017-02-14 03:09:17 +010017from scapy.layers.inet import UDP, IP
18from scapy.layers.inet6 import IPv6
Neale Ranns52cd4962019-06-05 10:28:17 +000019from scapy.layers.l2 import Ether, GRE
Paul Vinciguerra00671cf2018-11-25 12:47:04 -080020from scapy.packet import Raw
21
Klement Sekerab23ffd72021-05-31 16:08:53 +020022from config import config
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020023from bfd import (
24 VppBFDAuthKey,
25 BFD,
26 BFDAuthType,
27 VppBFDUDPSession,
28 BFDDiagCode,
29 BFDState,
30 BFD_vpp_echo,
31)
Dave Wallace8800f732023-08-31 00:47:44 -040032from framework import VppTestCase
33from asfframework import (
34 tag_fixme_vpp_workers,
35 tag_fixme_debian11,
36 tag_run_solo,
37 VppTestRunner,
38)
Klement Sekera0e3c0de2016-09-29 14:43:44 +020039from util import ppp
Neale Rannsc0a93142018-09-05 15:42:26 -070040from vpp_ip import DpoProto
41from vpp_ip_route import VppIpRoute, VppRoutePath
Paul Vinciguerra00671cf2018-11-25 12:47:04 -080042from vpp_lo_interface import VppLoInterface
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020043from vpp_papi_provider import UnexpectedApiReturnValueError, CliFailedCommandError
Paul Vinciguerra00671cf2018-11-25 12:47:04 -080044from vpp_pg_interface import CaptureTimeoutError, is_ipv6_misc
Neale Ranns52cd4962019-06-05 10:28:17 +000045from vpp_gre_interface import VppGreInterface
Klement Sekera0e3c0de2016-09-29 14:43:44 +020046
Klement Sekerad3ba5152017-02-14 03:09:17 +010047USEC_IN_SEC = 1000000
Klement Sekera3e0a3562016-12-19 09:05:21 +010048
Klement Sekera0e3c0de2016-09-29 14:43:44 +020049
Klement Sekerab17dd962017-01-09 07:43:48 +010050class AuthKeyFactory(object):
51 """Factory class for creating auth keys with unique conf key ID"""
52
53 def __init__(self):
54 self._conf_key_ids = {}
55
56 def create_random_key(self, test, auth_type=BFDAuthType.keyed_sha1):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020057 """create a random key with unique conf key id"""
Klement Sekerab17dd962017-01-09 07:43:48 +010058 conf_key_id = randint(0, 0xFFFFFFFF)
59 while conf_key_id in self._conf_key_ids:
60 conf_key_id = randint(0, 0xFFFFFFFF)
61 self._conf_key_ids[conf_key_id] = 1
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -070062 key = scapy.compat.raw(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020063 bytearray([randint(0, 255) for _ in range(randint(1, 20))])
64 )
65 return VppBFDAuthKey(
66 test=test, auth_type=auth_type, conf_key_id=conf_key_id, key=key
67 )
Klement Sekerab17dd962017-01-09 07:43:48 +010068
69
Klement Sekerae4504c62016-12-08 10:16:41 +010070class BFDAPITestCase(VppTestCase):
71 """Bidirectional Forwarding Detection (BFD) - API"""
Klement Sekera0e3c0de2016-09-29 14:43:44 +020072
Klement Sekerad3ba5152017-02-14 03:09:17 +010073 pg0 = None
74 pg1 = None
75
Klement Sekera0e3c0de2016-09-29 14:43:44 +020076 @classmethod
77 def setUpClass(cls):
Klement Sekerae4504c62016-12-08 10:16:41 +010078 super(BFDAPITestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -080079 cls.vapi.cli("set log class bfd level debug")
Klement Sekera0e3c0de2016-09-29 14:43:44 +020080 try:
Klement Sekera10db26f2017-01-11 08:16:53 +010081 cls.create_pg_interfaces(range(2))
82 for i in cls.pg_interfaces:
83 i.config_ip4()
Klement Sekerab17dd962017-01-09 07:43:48 +010084 i.config_ip6()
Klement Sekera10db26f2017-01-11 08:16:53 +010085 i.resolve_arp()
Klement Sekera0e3c0de2016-09-29 14:43:44 +020086
87 except Exception:
Klement Sekerae4504c62016-12-08 10:16:41 +010088 super(BFDAPITestCase, cls).tearDownClass()
Klement Sekera0e3c0de2016-09-29 14:43:44 +020089 raise
90
Paul Vinciguerra8d991d92019-01-25 14:05:48 -080091 @classmethod
92 def tearDownClass(cls):
93 super(BFDAPITestCase, cls).tearDownClass()
94
Klement Sekerab17dd962017-01-09 07:43:48 +010095 def setUp(self):
96 super(BFDAPITestCase, self).setUp()
97 self.factory = AuthKeyFactory()
98
Klement Sekera0e3c0de2016-09-29 14:43:44 +020099 def test_add_bfd(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200100 """create a BFD session"""
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200101 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
102 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100103 self.logger.debug("Session state is %s", session.state)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200104 session.remove_vpp_config()
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200105 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100106 self.logger.debug("Session state is %s", session.state)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200107 session.remove_vpp_config()
108
109 def test_double_add(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200110 """create the same BFD session twice (negative case)"""
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200111 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
112 session.add_vpp_config()
Klement Sekerae0545ef2017-01-25 08:00:40 +0100113
Klement Sekera7d6afb32018-11-08 11:52:04 +0100114 with self.vapi.assert_negative_api_retval():
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200115 session.add_vpp_config()
Klement Sekerae0545ef2017-01-25 08:00:40 +0100116
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200117 session.remove_vpp_config()
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200118
Klement Sekerab17dd962017-01-09 07:43:48 +0100119 def test_add_bfd6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200120 """create IPv6 BFD session"""
121 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip6, af=AF_INET6)
Klement Sekerab17dd962017-01-09 07:43:48 +0100122 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100123 self.logger.debug("Session state is %s", session.state)
Klement Sekerab17dd962017-01-09 07:43:48 +0100124 session.remove_vpp_config()
125 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100126 self.logger.debug("Session state is %s", session.state)
Klement Sekerab17dd962017-01-09 07:43:48 +0100127 session.remove_vpp_config()
128
Klement Sekeraa57a9702017-02-02 06:58:07 +0100129 def test_mod_bfd(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200130 """modify BFD session parameters"""
131 session = VppBFDUDPSession(
132 self,
133 self.pg0,
134 self.pg0.remote_ip4,
135 desired_min_tx=50000,
136 required_min_rx=10000,
137 detect_mult=1,
138 )
Klement Sekeraa57a9702017-02-02 06:58:07 +0100139 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100140 s = session.get_bfd_udp_session_dump_entry()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200141 self.assert_equal(
142 session.desired_min_tx, s.desired_min_tx, "desired min transmit interval"
143 )
144 self.assert_equal(
145 session.required_min_rx, s.required_min_rx, "required min receive interval"
146 )
Klement Sekerad3ba5152017-02-14 03:09:17 +0100147 self.assert_equal(session.detect_mult, s.detect_mult, "detect mult")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200148 session.modify_parameters(
149 desired_min_tx=session.desired_min_tx * 2,
150 required_min_rx=session.required_min_rx * 2,
151 detect_mult=session.detect_mult * 2,
152 )
Klement Sekerad3ba5152017-02-14 03:09:17 +0100153 s = session.get_bfd_udp_session_dump_entry()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200154 self.assert_equal(
155 session.desired_min_tx, s.desired_min_tx, "desired min transmit interval"
156 )
157 self.assert_equal(
158 session.required_min_rx, s.required_min_rx, "required min receive interval"
159 )
Klement Sekerad3ba5152017-02-14 03:09:17 +0100160 self.assert_equal(session.detect_mult, s.detect_mult, "detect mult")
Klement Sekeraa57a9702017-02-02 06:58:07 +0100161
Neale Ranns63f2c7d2022-02-09 13:47:29 +0000162 def test_upd_bfd(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200163 """Create/Modify w/ Update BFD session parameters"""
164 session = VppBFDUDPSession(
165 self,
166 self.pg0,
167 self.pg0.remote_ip4,
168 desired_min_tx=50000,
169 required_min_rx=10000,
170 detect_mult=1,
171 )
Neale Ranns63f2c7d2022-02-09 13:47:29 +0000172 session.upd_vpp_config()
173 s = session.get_bfd_udp_session_dump_entry()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200174 self.assert_equal(
175 session.desired_min_tx, s.desired_min_tx, "desired min transmit interval"
176 )
177 self.assert_equal(
178 session.required_min_rx, s.required_min_rx, "required min receive interval"
179 )
Neale Ranns63f2c7d2022-02-09 13:47:29 +0000180
181 self.assert_equal(session.detect_mult, s.detect_mult, "detect mult")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200182 session.upd_vpp_config(
183 desired_min_tx=session.desired_min_tx * 2,
184 required_min_rx=session.required_min_rx * 2,
185 detect_mult=session.detect_mult * 2,
186 )
Neale Ranns63f2c7d2022-02-09 13:47:29 +0000187 s = session.get_bfd_udp_session_dump_entry()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200188 self.assert_equal(
189 session.desired_min_tx, s.desired_min_tx, "desired min transmit interval"
190 )
191 self.assert_equal(
192 session.required_min_rx, s.required_min_rx, "required min receive interval"
193 )
Neale Ranns63f2c7d2022-02-09 13:47:29 +0000194 self.assert_equal(session.detect_mult, s.detect_mult, "detect mult")
195
Klement Sekerab17dd962017-01-09 07:43:48 +0100196 def test_add_sha1_keys(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200197 """add SHA1 keys"""
Klement Sekerab17dd962017-01-09 07:43:48 +0100198 key_count = 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200199 keys = [self.factory.create_random_key(self) for i in range(0, key_count)]
Klement Sekerab17dd962017-01-09 07:43:48 +0100200 for key in keys:
201 self.assertFalse(key.query_vpp_config())
202 for key in keys:
203 key.add_vpp_config()
204 for key in keys:
205 self.assertTrue(key.query_vpp_config())
206 # remove randomly
snaramre73aff472019-12-02 05:49:28 +0000207 indexes = list(range(key_count))
Klement Sekerad3ba5152017-02-14 03:09:17 +0100208 shuffle(indexes)
Klement Sekerab17dd962017-01-09 07:43:48 +0100209 removed = []
210 for i in indexes:
211 key = keys[i]
212 key.remove_vpp_config()
213 removed.append(i)
214 for j in range(key_count):
215 key = keys[j]
216 if j in removed:
217 self.assertFalse(key.query_vpp_config())
218 else:
219 self.assertTrue(key.query_vpp_config())
220 # should be removed now
221 for key in keys:
222 self.assertFalse(key.query_vpp_config())
223 # add back and remove again
224 for key in keys:
225 key.add_vpp_config()
226 for key in keys:
227 self.assertTrue(key.query_vpp_config())
228 for key in keys:
229 key.remove_vpp_config()
230 for key in keys:
231 self.assertFalse(key.query_vpp_config())
232
233 def test_add_bfd_sha1(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200234 """create a BFD session (SHA1)"""
Klement Sekerab17dd962017-01-09 07:43:48 +0100235 key = self.factory.create_random_key(self)
236 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200237 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4, sha1_key=key)
Klement Sekerab17dd962017-01-09 07:43:48 +0100238 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100239 self.logger.debug("Session state is %s", session.state)
Klement Sekerab17dd962017-01-09 07:43:48 +0100240 session.remove_vpp_config()
241 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100242 self.logger.debug("Session state is %s", session.state)
Klement Sekerab17dd962017-01-09 07:43:48 +0100243 session.remove_vpp_config()
244
245 def test_double_add_sha1(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200246 """create the same BFD session twice (negative case) (SHA1)"""
Klement Sekerab17dd962017-01-09 07:43:48 +0100247 key = self.factory.create_random_key(self)
248 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200249 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4, sha1_key=key)
Klement Sekerab17dd962017-01-09 07:43:48 +0100250 session.add_vpp_config()
251 with self.assertRaises(Exception):
252 session.add_vpp_config()
253
Klement Sekerad3ba5152017-02-14 03:09:17 +0100254 def test_add_auth_nonexistent_key(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200255 """create BFD session using non-existent SHA1 (negative case)"""
Klement Sekerab17dd962017-01-09 07:43:48 +0100256 session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200257 self,
258 self.pg0,
259 self.pg0.remote_ip4,
260 sha1_key=self.factory.create_random_key(self),
261 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100262 with self.assertRaises(Exception):
263 session.add_vpp_config()
264
265 def test_shared_sha1_key(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200266 """single SHA1 key shared by multiple BFD sessions"""
Klement Sekerab17dd962017-01-09 07:43:48 +0100267 key = self.factory.create_random_key(self)
268 key.add_vpp_config()
269 sessions = [
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200270 VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4, sha1_key=key),
271 VppBFDUDPSession(
272 self, self.pg0, self.pg0.remote_ip6, sha1_key=key, af=AF_INET6
273 ),
274 VppBFDUDPSession(self, self.pg1, self.pg1.remote_ip4, sha1_key=key),
275 VppBFDUDPSession(
276 self, self.pg1, self.pg1.remote_ip6, sha1_key=key, af=AF_INET6
277 ),
278 ]
Klement Sekerab17dd962017-01-09 07:43:48 +0100279 for s in sessions:
280 s.add_vpp_config()
281 removed = 0
282 for s in sessions:
283 e = key.get_bfd_auth_keys_dump_entry()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200284 self.assert_equal(
285 e.use_count, len(sessions) - removed, "Use count for shared key"
286 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100287 s.remove_vpp_config()
288 removed += 1
289 e = key.get_bfd_auth_keys_dump_entry()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200290 self.assert_equal(
291 e.use_count, len(sessions) - removed, "Use count for shared key"
292 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100293
294 def test_activate_auth(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200295 """activate SHA1 authentication"""
Klement Sekerab17dd962017-01-09 07:43:48 +0100296 key = self.factory.create_random_key(self)
297 key.add_vpp_config()
298 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
299 session.add_vpp_config()
300 session.activate_auth(key)
301
302 def test_deactivate_auth(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200303 """deactivate SHA1 authentication"""
Klement Sekerab17dd962017-01-09 07:43:48 +0100304 key = self.factory.create_random_key(self)
305 key.add_vpp_config()
306 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
307 session.add_vpp_config()
308 session.activate_auth(key)
309 session.deactivate_auth()
310
311 def test_change_key(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200312 """change SHA1 key"""
Klement Sekerab17dd962017-01-09 07:43:48 +0100313 key1 = self.factory.create_random_key(self)
314 key2 = self.factory.create_random_key(self)
315 while key2.conf_key_id == key1.conf_key_id:
316 key2 = self.factory.create_random_key(self)
317 key1.add_vpp_config()
318 key2.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200319 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4, sha1_key=key1)
Klement Sekerab17dd962017-01-09 07:43:48 +0100320 session.add_vpp_config()
321 session.activate_auth(key2)
Klement Sekera10db26f2017-01-11 08:16:53 +0100322
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700323 def test_set_del_udp_echo_source(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200324 """set/del udp echo source"""
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700325 self.create_loopback_interfaces(1)
326 self.loopback0 = self.lo_interfaces[0]
327 self.loopback0.admin_up()
328 echo_source = self.vapi.bfd_udp_get_echo_source()
329 self.assertFalse(echo_source.is_set)
330 self.assertFalse(echo_source.have_usable_ip4)
331 self.assertFalse(echo_source.have_usable_ip6)
332
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200333 self.vapi.bfd_udp_set_echo_source(sw_if_index=self.loopback0.sw_if_index)
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700334 echo_source = self.vapi.bfd_udp_get_echo_source()
335 self.assertTrue(echo_source.is_set)
336 self.assertEqual(echo_source.sw_if_index, self.loopback0.sw_if_index)
337 self.assertFalse(echo_source.have_usable_ip4)
338 self.assertFalse(echo_source.have_usable_ip6)
339
340 self.loopback0.config_ip4()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200341 echo_ip4 = ipaddress.IPv4Address(
342 int(ipaddress.IPv4Address(self.loopback0.local_ip4)) ^ 1
343 ).packed
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700344 echo_source = self.vapi.bfd_udp_get_echo_source()
345 self.assertTrue(echo_source.is_set)
346 self.assertEqual(echo_source.sw_if_index, self.loopback0.sw_if_index)
347 self.assertTrue(echo_source.have_usable_ip4)
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200348 self.assertEqual(echo_source.ip4_addr.packed, echo_ip4)
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700349 self.assertFalse(echo_source.have_usable_ip6)
350
351 self.loopback0.config_ip6()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200352 echo_ip6 = ipaddress.IPv6Address(
353 int(ipaddress.IPv6Address(self.loopback0.local_ip6)) ^ 1
354 ).packed
Paul Vinciguerra2f156312020-05-02 22:34:40 -0400355
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700356 echo_source = self.vapi.bfd_udp_get_echo_source()
357 self.assertTrue(echo_source.is_set)
358 self.assertEqual(echo_source.sw_if_index, self.loopback0.sw_if_index)
359 self.assertTrue(echo_source.have_usable_ip4)
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200360 self.assertEqual(echo_source.ip4_addr.packed, echo_ip4)
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700361 self.assertTrue(echo_source.have_usable_ip6)
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200362 self.assertEqual(echo_source.ip6_addr.packed, echo_ip6)
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700363
364 self.vapi.bfd_udp_del_echo_source()
365 echo_source = self.vapi.bfd_udp_get_echo_source()
366 self.assertFalse(echo_source.is_set)
367 self.assertFalse(echo_source.have_usable_ip4)
368 self.assertFalse(echo_source.have_usable_ip6)
369
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200370
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200371class BFDTestSession(object):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200372 """BFD session as seen from test framework side"""
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200373
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200374 def __init__(
375 self,
376 test,
377 interface,
378 af,
379 detect_mult=3,
380 sha1_key=None,
381 bfd_key_id=None,
382 our_seq_number=None,
383 tunnel_header=None,
384 phy_interface=None,
385 ):
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200386 self.test = test
Klement Sekera46a87ad2017-01-02 08:22:23 +0100387 self.af = af
Klement Sekerab17dd962017-01-09 07:43:48 +0100388 self.sha1_key = sha1_key
389 self.bfd_key_id = bfd_key_id
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200390 self.interface = interface
Neale Ranns52cd4962019-06-05 10:28:17 +0000391 if phy_interface:
392 self.phy_interface = phy_interface
393 else:
394 self.phy_interface = self.interface
Klement Sekerad3ba5152017-02-14 03:09:17 +0100395 self.udp_sport = randint(49152, 65535)
396 if our_seq_number is None:
397 self.our_seq_number = randint(0, 40000000)
398 else:
399 self.our_seq_number = our_seq_number
Klement Sekerab17dd962017-01-09 07:43:48 +0100400 self.vpp_seq_number = None
Klement Sekerad3ba5152017-02-14 03:09:17 +0100401 self.my_discriminator = 0
Klement Sekera2e01dfa2017-04-03 08:10:08 +0200402 self.desired_min_tx = 300000
403 self.required_min_rx = 300000
Klement Sekera239790f2017-02-16 10:53:53 +0100404 self.required_min_echo_rx = None
Klement Sekerad3ba5152017-02-14 03:09:17 +0100405 self.detect_mult = detect_mult
406 self.diag = BFDDiagCode.no_diagnostic
407 self.your_discriminator = None
408 self.state = BFDState.down
409 self.auth_type = BFDAuthType.no_auth
Neale Ranns52cd4962019-06-05 10:28:17 +0000410 self.tunnel_header = tunnel_header
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000411 self.tx_packets = 0
412 self.rx_packets = 0
413 self.tx_packets_echo = 0
414 self.rx_packets_echo = 0
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200415
Klement Sekerab17dd962017-01-09 07:43:48 +0100416 def inc_seq_num(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200417 """increment sequence number, wrapping if needed"""
Klement Sekerab17dd962017-01-09 07:43:48 +0100418 if self.our_seq_number == 0xFFFFFFFF:
419 self.our_seq_number = 0
420 else:
421 self.our_seq_number += 1
422
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200423 def update(
424 self,
425 my_discriminator=None,
426 your_discriminator=None,
427 desired_min_tx=None,
428 required_min_rx=None,
429 required_min_echo_rx=None,
430 detect_mult=None,
431 diag=None,
432 state=None,
433 auth_type=None,
434 ):
435 """update BFD parameters associated with session"""
Klement Sekera239790f2017-02-16 10:53:53 +0100436 if my_discriminator is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100437 self.my_discriminator = my_discriminator
Klement Sekera239790f2017-02-16 10:53:53 +0100438 if your_discriminator is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100439 self.your_discriminator = your_discriminator
Klement Sekera239790f2017-02-16 10:53:53 +0100440 if required_min_rx is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100441 self.required_min_rx = required_min_rx
Klement Sekera239790f2017-02-16 10:53:53 +0100442 if required_min_echo_rx is not None:
443 self.required_min_echo_rx = required_min_echo_rx
444 if desired_min_tx is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100445 self.desired_min_tx = desired_min_tx
Klement Sekera239790f2017-02-16 10:53:53 +0100446 if detect_mult is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100447 self.detect_mult = detect_mult
Klement Sekera239790f2017-02-16 10:53:53 +0100448 if diag is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100449 self.diag = diag
Klement Sekera239790f2017-02-16 10:53:53 +0100450 if state is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100451 self.state = state
Klement Sekera239790f2017-02-16 10:53:53 +0100452 if auth_type is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100453 self.auth_type = auth_type
454
455 def fill_packet_fields(self, packet):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200456 """set packet fields with known values in packet"""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100457 bfd = packet[BFD]
458 if self.my_discriminator:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200459 self.test.logger.debug(
460 "BFD: setting packet.my_discriminator=%s", self.my_discriminator
461 )
Klement Sekerad3ba5152017-02-14 03:09:17 +0100462 bfd.my_discriminator = self.my_discriminator
463 if self.your_discriminator:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200464 self.test.logger.debug(
465 "BFD: setting packet.your_discriminator=%s", self.your_discriminator
466 )
Klement Sekerad3ba5152017-02-14 03:09:17 +0100467 bfd.your_discriminator = self.your_discriminator
468 if self.required_min_rx:
469 self.test.logger.debug(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200470 "BFD: setting packet.required_min_rx_interval=%s", self.required_min_rx
471 )
Klement Sekerad3ba5152017-02-14 03:09:17 +0100472 bfd.required_min_rx_interval = self.required_min_rx
Klement Sekera239790f2017-02-16 10:53:53 +0100473 if self.required_min_echo_rx:
474 self.test.logger.debug(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200475 "BFD: setting packet.required_min_echo_rx=%s", self.required_min_echo_rx
476 )
Klement Sekera239790f2017-02-16 10:53:53 +0100477 bfd.required_min_echo_rx_interval = self.required_min_echo_rx
Klement Sekerad3ba5152017-02-14 03:09:17 +0100478 if self.desired_min_tx:
479 self.test.logger.debug(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200480 "BFD: setting packet.desired_min_tx_interval=%s", self.desired_min_tx
481 )
Klement Sekerad3ba5152017-02-14 03:09:17 +0100482 bfd.desired_min_tx_interval = self.desired_min_tx
483 if self.detect_mult:
484 self.test.logger.debug(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200485 "BFD: setting packet.detect_mult=%s", self.detect_mult
486 )
Klement Sekerad3ba5152017-02-14 03:09:17 +0100487 bfd.detect_mult = self.detect_mult
488 if self.diag:
489 self.test.logger.debug("BFD: setting packet.diag=%s", self.diag)
490 bfd.diag = self.diag
491 if self.state:
492 self.test.logger.debug("BFD: setting packet.state=%s", self.state)
493 bfd.state = self.state
494 if self.auth_type:
495 # this is used by a negative test-case
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200496 self.test.logger.debug("BFD: setting packet.auth_type=%s", self.auth_type)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100497 bfd.auth_type = self.auth_type
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200498
499 def create_packet(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200500 """create a BFD packet, reflecting the current state of session"""
Klement Sekerab17dd962017-01-09 07:43:48 +0100501 if self.sha1_key:
502 bfd = BFD(flags="A")
503 bfd.auth_type = self.sha1_key.auth_type
504 bfd.auth_len = BFD.sha1_auth_len
505 bfd.auth_key_id = self.bfd_key_id
506 bfd.auth_seq_num = self.our_seq_number
507 bfd.length = BFD.sha1_auth_len + BFD.bfd_pkt_len
508 else:
509 bfd = BFD()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200510 packet = Ether(
511 src=self.phy_interface.remote_mac, dst=self.phy_interface.local_mac
512 )
Neale Ranns52cd4962019-06-05 10:28:17 +0000513 if self.tunnel_header:
514 packet = packet / self.tunnel_header
Klement Sekera46a87ad2017-01-02 08:22:23 +0100515 if self.af == AF_INET6:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200516 packet = (
517 packet
518 / IPv6(
519 src=self.interface.remote_ip6,
520 dst=self.interface.local_ip6,
521 hlim=255,
522 )
523 / UDP(sport=self.udp_sport, dport=BFD.udp_dport)
524 / bfd
525 )
Klement Sekera46a87ad2017-01-02 08:22:23 +0100526 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200527 packet = (
528 packet
529 / IP(
530 src=self.interface.remote_ip4, dst=self.interface.local_ip4, ttl=255
531 )
532 / UDP(sport=self.udp_sport, dport=BFD.udp_dport)
533 / bfd
534 )
Klement Sekera3e0a3562016-12-19 09:05:21 +0100535 self.test.logger.debug("BFD: Creating packet")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100536 self.fill_packet_fields(packet)
Klement Sekerab17dd962017-01-09 07:43:48 +0100537 if self.sha1_key:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200538 hash_material = (
539 scapy.compat.raw(packet[BFD])[:32]
540 + self.sha1_key.key
541 + b"\0" * (20 - len(self.sha1_key.key))
542 )
543 self.test.logger.debug(
544 "BFD: Calculated SHA1 hash: %s"
545 % hashlib.sha1(hash_material).hexdigest()
546 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100547 packet[BFD].auth_key_hash = hashlib.sha1(hash_material).digest()
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200548 return packet
549
Klement Sekerad3ba5152017-02-14 03:09:17 +0100550 def send_packet(self, packet=None, interface=None):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200551 """send packet on interface, creating the packet if needed"""
Klement Sekeraa57a9702017-02-02 06:58:07 +0100552 if packet is None:
553 packet = self.create_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100554 if interface is None:
Neale Ranns52cd4962019-06-05 10:28:17 +0000555 interface = self.phy_interface
Klement Sekeraa57a9702017-02-02 06:58:07 +0100556 self.test.logger.debug(ppp("Sending packet:", packet))
Klement Sekerad3ba5152017-02-14 03:09:17 +0100557 interface.add_stream(packet)
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000558 self.tx_packets += 1
Klement Sekera9225dee2016-12-12 08:36:58 +0100559 self.test.pg_start()
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200560
Klement Sekerab17dd962017-01-09 07:43:48 +0100561 def verify_sha1_auth(self, packet):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200562 """Verify correctness of authentication in BFD layer."""
Klement Sekerab17dd962017-01-09 07:43:48 +0100563 bfd = packet[BFD]
564 self.test.assert_equal(bfd.auth_len, 28, "Auth section length")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200565 self.test.assert_equal(bfd.auth_type, self.sha1_key.auth_type, BFDAuthType)
Klement Sekerab17dd962017-01-09 07:43:48 +0100566 self.test.assert_equal(bfd.auth_key_id, self.bfd_key_id, "Key ID")
567 self.test.assert_equal(bfd.auth_reserved, 0, "Reserved")
568 if self.vpp_seq_number is None:
569 self.vpp_seq_number = bfd.auth_seq_num
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200570 self.test.logger.debug(
571 "Received initial sequence number: %s" % self.vpp_seq_number
572 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100573 else:
574 recvd_seq_num = bfd.auth_seq_num
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200575 self.test.logger.debug(
576 "Received followup sequence number: %s" % recvd_seq_num
577 )
578 if self.vpp_seq_number < 0xFFFFFFFF:
579 if self.sha1_key.auth_type == BFDAuthType.meticulous_keyed_sha1:
580 self.test.assert_equal(
581 recvd_seq_num, self.vpp_seq_number + 1, "BFD sequence number"
582 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100583 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200584 self.test.assert_in_range(
585 recvd_seq_num,
586 self.vpp_seq_number,
587 self.vpp_seq_number + 1,
588 "BFD sequence number",
589 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100590 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200591 if self.sha1_key.auth_type == BFDAuthType.meticulous_keyed_sha1:
592 self.test.assert_equal(recvd_seq_num, 0, "BFD sequence number")
Klement Sekerab17dd962017-01-09 07:43:48 +0100593 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200594 self.test.assertIn(
595 recvd_seq_num,
596 (self.vpp_seq_number, 0),
597 "BFD sequence number not one of "
598 "(%s, 0)" % self.vpp_seq_number,
599 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100600 self.vpp_seq_number = recvd_seq_num
601 # last 20 bytes represent the hash - so replace them with the key,
602 # pad the result with zeros and hash the result
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200603 hash_material = (
604 bfd.original[:-20]
605 + self.sha1_key.key
606 + b"\0" * (20 - len(self.sha1_key.key))
607 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100608 expected_hash = hashlib.sha1(hash_material).hexdigest()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200609 self.test.assert_equal(
610 binascii.hexlify(bfd.auth_key_hash), expected_hash.encode(), "Auth key hash"
611 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100612
613 def verify_bfd(self, packet):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200614 """Verify correctness of BFD layer."""
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200615 bfd = packet[BFD]
616 self.test.assert_equal(bfd.version, 1, "BFD version")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200617 self.test.assert_equal(
618 bfd.your_discriminator, self.my_discriminator, "BFD - your discriminator"
619 )
Klement Sekerab17dd962017-01-09 07:43:48 +0100620 if self.sha1_key:
621 self.verify_sha1_auth(packet)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200622
623
Klement Sekerad3ba5152017-02-14 03:09:17 +0100624def bfd_session_up(test):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200625 """Bring BFD session up"""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100626 test.logger.info("BFD: Waiting for slow hello")
Neale Ranns52cd4962019-06-05 10:28:17 +0000627 p = wait_for_bfd_packet(test, 2, is_tunnel=test.vpp_session.is_tunnel)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100628 old_offset = None
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200629 if hasattr(test, "vpp_clock_offset"):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100630 old_offset = test.vpp_clock_offset
snaramre73aff472019-12-02 05:49:28 +0000631 test.vpp_clock_offset = time.time() - float(p.time)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200632 test.logger.debug("BFD: Calculated vpp clock offset: %s", test.vpp_clock_offset)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100633 if old_offset:
634 test.assertAlmostEqual(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200635 old_offset,
636 test.vpp_clock_offset,
637 delta=0.5,
638 msg="vpp clock offset not stable (new: %s, old: %s)"
639 % (test.vpp_clock_offset, old_offset),
640 )
Klement Sekerad3ba5152017-02-14 03:09:17 +0100641 test.logger.info("BFD: Sending Init")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200642 test.test_session.update(
643 my_discriminator=randint(0, 40000000),
644 your_discriminator=p[BFD].my_discriminator,
645 state=BFDState.init,
646 )
647 if (
648 test.test_session.sha1_key
649 and test.test_session.sha1_key.auth_type == BFDAuthType.meticulous_keyed_sha1
650 ):
Klement Sekera73884482017-02-23 09:26:30 +0100651 test.test_session.inc_seq_num()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100652 test.test_session.send_packet()
653 test.logger.info("BFD: Waiting for event")
Ole Troan4376ab22021-03-03 10:40:05 +0100654 e = test.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100655 verify_event(test, e, expected_state=BFDState.up)
656 test.logger.info("BFD: Session is Up")
657 test.test_session.update(state=BFDState.up)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200658 if (
659 test.test_session.sha1_key
660 and test.test_session.sha1_key.auth_type == BFDAuthType.meticulous_keyed_sha1
661 ):
Klement Sekera73884482017-02-23 09:26:30 +0100662 test.test_session.inc_seq_num()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100663 test.test_session.send_packet()
664 test.assert_equal(test.vpp_session.state, BFDState.up, BFDState)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200665
Klement Sekera46a87ad2017-01-02 08:22:23 +0100666
Klement Sekerad3ba5152017-02-14 03:09:17 +0100667def bfd_session_down(test):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200668 """Bring BFD session down"""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100669 test.assert_equal(test.vpp_session.state, BFDState.up, BFDState)
670 test.test_session.update(state=BFDState.down)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200671 if (
672 test.test_session.sha1_key
673 and test.test_session.sha1_key.auth_type == BFDAuthType.meticulous_keyed_sha1
674 ):
Klement Sekera73884482017-02-23 09:26:30 +0100675 test.test_session.inc_seq_num()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100676 test.test_session.send_packet()
677 test.logger.info("BFD: Waiting for event")
Ole Troan4376ab22021-03-03 10:40:05 +0100678 e = test.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100679 verify_event(test, e, expected_state=BFDState.down)
680 test.logger.info("BFD: Session is Down")
681 test.assert_equal(test.vpp_session.state, BFDState.down, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +0100682
Klement Sekera46a87ad2017-01-02 08:22:23 +0100683
Klement Sekera73884482017-02-23 09:26:30 +0100684def verify_bfd_session_config(test, session, state=None):
685 dump = session.get_bfd_udp_session_dump_entry()
686 test.assertIsNotNone(dump)
687 # since dump is not none, we have verified that sw_if_index and addresses
688 # are valid (in get_bfd_udp_session_dump_entry)
689 if state:
690 test.assert_equal(dump.state, state, "session state")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200691 test.assert_equal(
692 dump.required_min_rx, session.required_min_rx, "required min rx interval"
693 )
694 test.assert_equal(
695 dump.desired_min_tx, session.desired_min_tx, "desired min tx interval"
696 )
697 test.assert_equal(dump.detect_mult, session.detect_mult, "detect multiplier")
Klement Sekera73884482017-02-23 09:26:30 +0100698 if session.sha1_key is None:
699 test.assert_equal(dump.is_authenticated, 0, "is_authenticated flag")
700 else:
701 test.assert_equal(dump.is_authenticated, 1, "is_authenticated flag")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200702 test.assert_equal(dump.bfd_key_id, session.bfd_key_id, "bfd key id")
703 test.assert_equal(
704 dump.conf_key_id, session.sha1_key.conf_key_id, "config key id"
705 )
Klement Sekera73884482017-02-23 09:26:30 +0100706
707
Klement Sekerad3ba5152017-02-14 03:09:17 +0100708def verify_ip(test, packet):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200709 """Verify correctness of IP layer."""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100710 if test.vpp_session.af == AF_INET6:
711 ip = packet[IPv6]
Neale Ranns52cd4962019-06-05 10:28:17 +0000712 local_ip = test.vpp_session.interface.local_ip6
713 remote_ip = test.vpp_session.interface.remote_ip6
Klement Sekerad3ba5152017-02-14 03:09:17 +0100714 test.assert_equal(ip.hlim, 255, "IPv6 hop limit")
715 else:
716 ip = packet[IP]
Neale Ranns52cd4962019-06-05 10:28:17 +0000717 local_ip = test.vpp_session.interface.local_ip4
718 remote_ip = test.vpp_session.interface.remote_ip4
Klement Sekerad3ba5152017-02-14 03:09:17 +0100719 test.assert_equal(ip.ttl, 255, "IPv4 TTL")
720 test.assert_equal(ip.src, local_ip, "IP source address")
721 test.assert_equal(ip.dst, remote_ip, "IP destination address")
722
723
724def verify_udp(test, packet):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200725 """Verify correctness of UDP layer."""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100726 udp = packet[UDP]
727 test.assert_equal(udp.dport, BFD.udp_dport, "UDP destination port")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200728 test.assert_in_range(
729 udp.sport, BFD.udp_sport_min, BFD.udp_sport_max, "UDP source port"
730 )
Klement Sekerad3ba5152017-02-14 03:09:17 +0100731
732
733def verify_event(test, event, expected_state):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200734 """Verify correctness of event values."""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100735 e = event
Paul Vinciguerra090096b2020-12-03 00:42:46 -0500736 test.logger.debug("BFD: Event: %s" % reprlib.repr(e))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200737 test.assert_equal(
738 e.sw_if_index, test.vpp_session.interface.sw_if_index, "BFD interface index"
739 )
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200740
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200741 test.assert_equal(
742 str(e.local_addr), test.vpp_session.local_addr, "Local IPv6 address"
743 )
744 test.assert_equal(str(e.peer_addr), test.vpp_session.peer_addr, "Peer IPv6 address")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100745 test.assert_equal(e.state, expected_state, BFDState)
746
747
Neale Ranns52cd4962019-06-05 10:28:17 +0000748def wait_for_bfd_packet(test, timeout=1, pcap_time_min=None, is_tunnel=False):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200749 """wait for BFD packet and verify its correctness
Klement Sekerad3ba5152017-02-14 03:09:17 +0100750
751 :param timeout: how long to wait
752 :param pcap_time_min: ignore packets with pcap timestamp lower than this
753
754 :returns: tuple (packet, time spent waiting for packet)
755 """
756 test.logger.info("BFD: Waiting for BFD packet")
757 deadline = time.time() + timeout
758 counter = 0
759 while True:
760 counter += 1
761 # sanity check
762 test.assert_in_range(counter, 0, 100, "number of packets ignored")
763 time_left = deadline - time.time()
764 if time_left < 0:
765 raise CaptureTimeoutError("Packet did not arrive within timeout")
766 p = test.pg0.wait_for_packet(timeout=time_left)
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000767 test.test_session.rx_packets += 1
Klement Sekerad3ba5152017-02-14 03:09:17 +0100768 test.logger.debug(ppp("BFD: Got packet:", p))
769 if pcap_time_min is not None and p.time < pcap_time_min:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200770 test.logger.debug(
771 ppp(
772 "BFD: ignoring packet (pcap time %s < "
773 "pcap time min %s):" % (p.time, pcap_time_min),
774 p,
775 )
776 )
Klement Sekera46a87ad2017-01-02 08:22:23 +0100777 else:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100778 break
Klement Sekera617d4292022-09-20 15:10:10 +0200779 test.logger.debug(test.vapi.ppcli("show trace"))
Neale Ranns52cd4962019-06-05 10:28:17 +0000780 if is_tunnel:
781 # strip an IP layer and move to the next
782 p = p[IP].payload
783
Klement Sekerad3ba5152017-02-14 03:09:17 +0100784 bfd = p[BFD]
785 if bfd is None:
786 raise Exception(ppp("Unexpected or invalid BFD packet:", p))
787 if bfd.payload:
788 raise Exception(ppp("Unexpected payload in BFD packet:", bfd))
789 verify_ip(test, p)
790 verify_udp(test, p)
791 test.test_session.verify_bfd(p)
792 return p
Klement Sekera3e0a3562016-12-19 09:05:21 +0100793
Klement Sekera46a87ad2017-01-02 08:22:23 +0100794
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000795BFDStats = namedtuple("BFDStats", "rx rx_echo tx tx_echo")
796
797
798def bfd_grab_stats_snapshot(test, bs_idx=0, thread_index=None):
799 s = test.statistics
800 ti = thread_index
801 if ti is None:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200802 rx = s["/bfd/rx-session-counters"][:, bs_idx].sum_packets()
803 rx_echo = s["/bfd/rx-session-echo-counters"][:, bs_idx].sum_packets()
804 tx = s["/bfd/tx-session-counters"][:, bs_idx].sum_packets()
805 tx_echo = s["/bfd/tx-session-echo-counters"][:, bs_idx].sum_packets()
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000806 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200807 rx = s["/bfd/rx-session-counters"][ti, bs_idx].sum_packets()
808 rx_echo = s["/bfd/rx-session-echo-counters"][ti, bs_idx].sum_packets()
809 tx = s["/bfd/tx-session-counters"][ti, bs_idx].sum_packets()
810 tx_echo = s["/bfd/tx-session-echo-counters"][ti, bs_idx].sum_packets()
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000811 return BFDStats(rx, rx_echo, tx, tx_echo)
812
813
814def bfd_stats_diff(stats_before, stats_after):
815 rx = stats_after.rx - stats_before.rx
816 rx_echo = stats_after.rx_echo - stats_before.rx_echo
817 tx = stats_after.tx - stats_before.tx
818 tx_echo = stats_after.tx_echo - stats_before.tx_echo
819 return BFDStats(rx, rx_echo, tx, tx_echo)
820
821
Andrew Yourtchenko06f32812021-01-14 10:19:08 +0000822@tag_run_solo
Dave Wallace670724c2022-09-20 21:52:18 -0400823@tag_fixme_debian11
Klement Sekerad3ba5152017-02-14 03:09:17 +0100824class BFD4TestCase(VppTestCase):
Klement Sekera46a87ad2017-01-02 08:22:23 +0100825 """Bidirectional Forwarding Detection (BFD)"""
826
Klement Sekerad3ba5152017-02-14 03:09:17 +0100827 pg0 = None
828 vpp_clock_offset = None
829 vpp_session = None
830 test_session = None
831
Klement Sekera46a87ad2017-01-02 08:22:23 +0100832 @classmethod
833 def setUpClass(cls):
834 super(BFD4TestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -0800835 cls.vapi.cli("set log class bfd level debug")
Klement Sekera46a87ad2017-01-02 08:22:23 +0100836 try:
837 cls.create_pg_interfaces([0])
Klement Sekerab9ef2732018-06-24 22:49:33 +0200838 cls.create_loopback_interfaces(1)
Klement Sekera239790f2017-02-16 10:53:53 +0100839 cls.loopback0 = cls.lo_interfaces[0]
840 cls.loopback0.config_ip4()
841 cls.loopback0.admin_up()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100842 cls.pg0.config_ip4()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100843 cls.pg0.configure_ipv4_neighbors()
844 cls.pg0.admin_up()
845 cls.pg0.resolve_arp()
846
847 except Exception:
848 super(BFD4TestCase, cls).tearDownClass()
849 raise
850
Paul Vinciguerra8d991d92019-01-25 14:05:48 -0800851 @classmethod
852 def tearDownClass(cls):
853 super(BFD4TestCase, cls).tearDownClass()
854
Klement Sekera46a87ad2017-01-02 08:22:23 +0100855 def setUp(self):
856 super(BFD4TestCase, self).setUp()
Klement Sekerab17dd962017-01-09 07:43:48 +0100857 self.factory = AuthKeyFactory()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100858 self.vapi.want_bfd_events()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100859 self.pg0.enable_capture()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100860 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200861 self.bfd_udp4_sessions = self.statistics["/bfd/udp4/sessions"]
862 self.bfd_udp6_sessions = self.statistics["/bfd/udp6/sessions"]
Klement Sekera617d4292022-09-20 15:10:10 +0200863 self.vapi.cli("trace add bfd-process 500")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200864 self.vpp_session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
Klement Sekera46a87ad2017-01-02 08:22:23 +0100865 self.vpp_session.add_vpp_config()
866 self.vpp_session.admin_up()
867 self.test_session = BFDTestSession(self, self.pg0, AF_INET)
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200868 except BaseException:
Klement Sekera46a87ad2017-01-02 08:22:23 +0100869 self.vapi.want_bfd_events(enable_disable=0)
870 raise
871
872 def tearDown(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100873 if not self.vpp_dead:
874 self.vapi.want_bfd_events(enable_disable=0)
875 self.vapi.collect_events() # clear the event queue
876 super(BFD4TestCase, self).tearDown()
Klement Sekerab17dd962017-01-09 07:43:48 +0100877
878 def test_session_up(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200879 """bring BFD session up"""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100880 bfd_session_up(self)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200881 bfd_udp4_sessions = self.statistics["/bfd/udp4/sessions"]
882 bfd_udp6_sessions = self.statistics["/bfd/udp6/sessions"]
Klement Sekeracdaf0d82022-02-14 20:20:22 +0000883 self.assert_equal(bfd_udp4_sessions - self.bfd_udp4_sessions, 1)
884 self.assert_equal(bfd_udp6_sessions, self.bfd_udp6_sessions)
Klement Sekerab17dd962017-01-09 07:43:48 +0100885
Klement Sekera73884482017-02-23 09:26:30 +0100886 def test_session_up_by_ip(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200887 """bring BFD session up - first frame looked up by address pair"""
Klement Sekera73884482017-02-23 09:26:30 +0100888 self.logger.info("BFD: Sending Slow control frame")
889 self.test_session.update(my_discriminator=randint(0, 40000000))
890 self.test_session.send_packet()
891 self.pg0.enable_capture()
892 p = self.pg0.wait_for_packet(1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200893 self.assert_equal(
894 p[BFD].your_discriminator,
895 self.test_session.my_discriminator,
896 "BFD - your discriminator",
897 )
Klement Sekera73884482017-02-23 09:26:30 +0100898 self.assert_equal(p[BFD].state, BFDState.init, BFDState)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200899 self.test_session.update(
900 your_discriminator=p[BFD].my_discriminator, state=BFDState.up
901 )
Klement Sekera73884482017-02-23 09:26:30 +0100902 self.logger.info("BFD: Waiting for event")
Ole Troan4376ab22021-03-03 10:40:05 +0100903 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekera73884482017-02-23 09:26:30 +0100904 verify_event(self, e, expected_state=BFDState.init)
905 self.logger.info("BFD: Sending Up")
906 self.test_session.send_packet()
907 self.logger.info("BFD: Waiting for event")
Ole Troan4376ab22021-03-03 10:40:05 +0100908 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekera73884482017-02-23 09:26:30 +0100909 verify_event(self, e, expected_state=BFDState.up)
910 self.logger.info("BFD: Session is Up")
911 self.test_session.update(state=BFDState.up)
912 self.test_session.send_packet()
913 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
914
Klement Sekerab17dd962017-01-09 07:43:48 +0100915 def test_session_down(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200916 """bring BFD session down"""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100917 bfd_session_up(self)
918 bfd_session_down(self)
Klement Sekerab17dd962017-01-09 07:43:48 +0100919
920 def test_hold_up(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200921 """hold BFD session up"""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100922 bfd_session_up(self)
923 for dummy in range(self.test_session.detect_mult * 2):
924 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +0100925 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200926 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekera46a87ad2017-01-02 08:22:23 +0100927
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200928 def test_slow_timer(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200929 """verify slow periodic control frames while session down"""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100930 packet_count = 3
931 self.logger.info("BFD: Waiting for %d BFD packets", packet_count)
932 prev_packet = wait_for_bfd_packet(self, 2)
933 for dummy in range(packet_count):
934 next_packet = wait_for_bfd_packet(self, 2)
935 time_diff = next_packet.time - prev_packet.time
Klement Sekerae4504c62016-12-08 10:16:41 +0100936 # spec says the range should be <0.75, 1>, allow extra 0.05 margin
937 # to work around timing issues
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200938 self.assert_in_range(time_diff, 0.70, 1.05, "time between slow packets")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100939 prev_packet = next_packet
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200940
941 def test_zero_remote_min_rx(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200942 """no packets when zero remote required min rx interval"""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100943 bfd_session_up(self)
944 self.test_session.update(required_min_rx=0)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200945 self.test_session.send_packet()
Klement Sekera239790f2017-02-16 10:53:53 +0100946 for dummy in range(self.test_session.detect_mult):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200947 self.sleep(
948 self.vpp_session.required_min_rx / USEC_IN_SEC,
949 "sleep before transmitting bfd packet",
950 )
Klement Sekera239790f2017-02-16 10:53:53 +0100951 self.test_session.send_packet()
Klement Sekeraa57a9702017-02-02 06:58:07 +0100952 try:
Klement Sekera239790f2017-02-16 10:53:53 +0100953 p = wait_for_bfd_packet(self, timeout=0)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100954 self.logger.error(ppp("Received unexpected packet:", p))
Klement Sekerad3ba5152017-02-14 03:09:17 +0100955 except CaptureTimeoutError:
Klement Sekeraa57a9702017-02-02 06:58:07 +0100956 pass
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200957 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekera2e01dfa2017-04-03 08:10:08 +0200958 self.test_session.update(required_min_rx=300000)
Klement Sekera239790f2017-02-16 10:53:53 +0100959 for dummy in range(3):
960 self.test_session.send_packet()
961 wait_for_bfd_packet(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200962 self, timeout=self.test_session.required_min_rx / USEC_IN_SEC
963 )
964 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200965
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200966 def test_conn_down(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200967 """verify session goes down after inactivity"""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100968 bfd_session_up(self)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200969 detection_time = (
970 self.test_session.detect_mult
971 * self.vpp_session.required_min_rx
972 / USEC_IN_SEC
973 )
Klement Sekerac48829b2017-02-14 07:55:57 +0100974 self.sleep(detection_time, "waiting for BFD session time-out")
Ole Troan4376ab22021-03-03 10:40:05 +0100975 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100976 verify_event(self, e, expected_state=BFDState.down)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200977
Klement Sekera4d39f9c2020-01-17 10:01:52 +0000978 def test_peer_discr_reset_sess_down(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200979 """peer discriminator reset after session goes down"""
Klement Sekera4d39f9c2020-01-17 10:01:52 +0000980 bfd_session_up(self)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200981 detection_time = (
982 self.test_session.detect_mult
983 * self.vpp_session.required_min_rx
984 / USEC_IN_SEC
985 )
Klement Sekera4d39f9c2020-01-17 10:01:52 +0000986 self.sleep(detection_time, "waiting for BFD session time-out")
987 self.test_session.my_discriminator = 0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200988 wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekera4d39f9c2020-01-17 10:01:52 +0000989
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200990 def test_large_required_min_rx(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200991 """large remote required min rx interval"""
Klement Sekerad3ba5152017-02-14 03:09:17 +0100992 bfd_session_up(self)
993 p = wait_for_bfd_packet(self)
Klement Sekera637b9c42016-12-08 05:19:14 +0100994 interval = 3000000
Klement Sekerad3ba5152017-02-14 03:09:17 +0100995 self.test_session.update(required_min_rx=interval)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200996 self.test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100997 time_mark = time.time()
Klement Sekera637b9c42016-12-08 05:19:14 +0100998 count = 0
Klement Sekeraa57a9702017-02-02 06:58:07 +0100999 # busy wait here, trying to collect a packet or event, vpp is not
1000 # allowed to send packets and the session will timeout first - so the
1001 # Up->Down event must arrive before any packets do
Klement Sekerad3ba5152017-02-14 03:09:17 +01001002 while time.time() < time_mark + interval / USEC_IN_SEC:
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001003 try:
Klement Sekerad3ba5152017-02-14 03:09:17 +01001004 p = wait_for_bfd_packet(self, timeout=0)
1005 # if vpp managed to send a packet before we did the session
1006 # session update, then that's fine, ignore it
1007 if p.time < time_mark - self.vpp_clock_offset:
1008 continue
Klement Sekeraa57a9702017-02-02 06:58:07 +01001009 self.logger.error(ppp("Received unexpected packet:", p))
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001010 count += 1
Klement Sekerad3ba5152017-02-14 03:09:17 +01001011 except CaptureTimeoutError:
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001012 pass
Klement Sekeraa57a9702017-02-02 06:58:07 +01001013 events = self.vapi.collect_events()
1014 if len(events) > 0:
Klement Sekerad3ba5152017-02-14 03:09:17 +01001015 verify_event(self, events[0], BFDState.down)
Klement Sekeraa57a9702017-02-02 06:58:07 +01001016 break
1017 self.assert_equal(count, 0, "number of packets received")
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001018
Klement Sekerad3ba5152017-02-14 03:09:17 +01001019 def test_immediate_remote_min_rx_reduction(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001020 """immediately honor remote required min rx reduction"""
Klement Sekera3e0a3562016-12-19 09:05:21 +01001021 self.vpp_session.remove_vpp_config()
Klement Sekera10db26f2017-01-11 08:16:53 +01001022 self.vpp_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001023 self, self.pg0, self.pg0.remote_ip4, desired_min_tx=10000
1024 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01001025 self.pg0.enable_capture()
Klement Sekera3e0a3562016-12-19 09:05:21 +01001026 self.vpp_session.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001027 self.test_session.update(desired_min_tx=1000000, required_min_rx=1000000)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001028 bfd_session_up(self)
1029 reference_packet = wait_for_bfd_packet(self)
1030 time_mark = time.time()
1031 interval = 300000
1032 self.test_session.update(required_min_rx=interval)
Klement Sekera3e0a3562016-12-19 09:05:21 +01001033 self.test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +01001034 extra_time = time.time() - time_mark
1035 p = wait_for_bfd_packet(self)
1036 # first packet is allowed to be late by time we spent doing the update
1037 # calculated in extra_time
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001038 self.assert_in_range(
1039 p.time - reference_packet.time,
1040 0.95 * 0.75 * interval / USEC_IN_SEC,
1041 1.05 * interval / USEC_IN_SEC + extra_time,
1042 "time between BFD packets",
1043 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01001044 reference_packet = p
1045 for dummy in range(3):
1046 p = wait_for_bfd_packet(self)
1047 diff = p.time - reference_packet.time
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001048 self.assert_in_range(
1049 diff,
1050 0.95 * 0.75 * interval / USEC_IN_SEC,
1051 1.05 * interval / USEC_IN_SEC,
1052 "time between BFD packets",
1053 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01001054 reference_packet = p
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001055
Klement Sekeraa57a9702017-02-02 06:58:07 +01001056 def test_modify_req_min_rx_double(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001057 """modify session - double required min rx"""
Klement Sekerad3ba5152017-02-14 03:09:17 +01001058 bfd_session_up(self)
1059 p = wait_for_bfd_packet(self)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001060 self.test_session.update(desired_min_tx=10000, required_min_rx=10000)
Klement Sekeraa57a9702017-02-02 06:58:07 +01001061 self.test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +01001062 # double required min rx
Klement Sekeraa57a9702017-02-02 06:58:07 +01001063 self.vpp_session.modify_parameters(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001064 required_min_rx=2 * self.vpp_session.required_min_rx
1065 )
1066 p = wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekeraa57a9702017-02-02 06:58:07 +01001067 # poll bit needs to be set
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001068 self.assertIn("P", p.sprintf("%BFD.flags%"), "Poll bit not set in BFD packet")
Klement Sekeraa57a9702017-02-02 06:58:07 +01001069 # finish poll sequence with final packet
1070 final = self.test_session.create_packet()
1071 final[BFD].flags = "F"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001072 timeout = (
1073 self.test_session.detect_mult
1074 * max(self.test_session.desired_min_tx, self.vpp_session.required_min_rx)
1075 / USEC_IN_SEC
1076 )
Klement Sekeraa57a9702017-02-02 06:58:07 +01001077 self.test_session.send_packet(final)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001078 time_mark = time.time()
Ole Troan4376ab22021-03-03 10:40:05 +01001079 e = self.vapi.wait_for_event(2 * timeout, "bfd_udp_session_event")
Klement Sekerad3ba5152017-02-14 03:09:17 +01001080 verify_event(self, e, expected_state=BFDState.down)
1081 time_to_event = time.time() - time_mark
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001082 self.assert_in_range(
1083 time_to_event, 0.9 * timeout, 1.1 * timeout, "session timeout"
1084 )
Klement Sekeraa57a9702017-02-02 06:58:07 +01001085
1086 def test_modify_req_min_rx_halve(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001087 """modify session - halve required min rx"""
Klement Sekeraa57a9702017-02-02 06:58:07 +01001088 self.vpp_session.modify_parameters(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001089 required_min_rx=2 * self.vpp_session.required_min_rx
1090 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01001091 bfd_session_up(self)
1092 p = wait_for_bfd_packet(self)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001093 self.test_session.update(desired_min_tx=10000, required_min_rx=10000)
Klement Sekeraa57a9702017-02-02 06:58:07 +01001094 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001095 p = wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekeraa57a9702017-02-02 06:58:07 +01001096 # halve required min rx
1097 old_required_min_rx = self.vpp_session.required_min_rx
1098 self.vpp_session.modify_parameters(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001099 required_min_rx=self.vpp_session.required_min_rx // 2
1100 )
Klement Sekeraa57a9702017-02-02 06:58:07 +01001101 # now we wait 0.8*3*old-req-min-rx and the session should still be up
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001102 self.sleep(
1103 0.8 * self.vpp_session.detect_mult * old_required_min_rx / USEC_IN_SEC,
1104 "wait before finishing poll sequence",
1105 )
1106 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekerad3ba5152017-02-14 03:09:17 +01001107 p = wait_for_bfd_packet(self)
Klement Sekeraa57a9702017-02-02 06:58:07 +01001108 # poll bit needs to be set
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001109 self.assertIn("P", p.sprintf("%BFD.flags%"), "Poll bit not set in BFD packet")
Klement Sekeraa57a9702017-02-02 06:58:07 +01001110 # finish poll sequence with final packet
1111 final = self.test_session.create_packet()
1112 final[BFD].flags = "F"
1113 self.test_session.send_packet(final)
1114 # now the session should time out under new conditions
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001115 detection_time = (
1116 self.test_session.detect_mult
1117 * self.vpp_session.required_min_rx
1118 / USEC_IN_SEC
1119 )
Klement Sekera2e01dfa2017-04-03 08:10:08 +02001120 before = time.time()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001121 e = self.vapi.wait_for_event(2 * detection_time, "bfd_udp_session_event")
Klement Sekera2e01dfa2017-04-03 08:10:08 +02001122 after = time.time()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001123 self.assert_in_range(
1124 after - before,
1125 0.9 * detection_time,
1126 1.1 * detection_time,
1127 "time before bfd session goes down",
1128 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01001129 verify_event(self, e, expected_state=BFDState.down)
Klement Sekeraa57a9702017-02-02 06:58:07 +01001130
Klement Sekeraa57a9702017-02-02 06:58:07 +01001131 def test_modify_detect_mult(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001132 """modify detect multiplier"""
Klement Sekerad3ba5152017-02-14 03:09:17 +01001133 bfd_session_up(self)
1134 p = wait_for_bfd_packet(self)
Klement Sekeraa57a9702017-02-02 06:58:07 +01001135 self.vpp_session.modify_parameters(detect_mult=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001136 p = wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
1137 self.assert_equal(
1138 self.vpp_session.detect_mult, p[BFD].detect_mult, "detect mult"
1139 )
Klement Sekeraa57a9702017-02-02 06:58:07 +01001140 # poll bit must not be set
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001141 self.assertNotIn(
1142 "P", p.sprintf("%BFD.flags%"), "Poll bit not set in BFD packet"
1143 )
Klement Sekeraa57a9702017-02-02 06:58:07 +01001144 self.vpp_session.modify_parameters(detect_mult=10)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001145 p = wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
1146 self.assert_equal(
1147 self.vpp_session.detect_mult, p[BFD].detect_mult, "detect mult"
1148 )
Klement Sekeraa57a9702017-02-02 06:58:07 +01001149 # poll bit must not be set
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001150 self.assertNotIn(
1151 "P", p.sprintf("%BFD.flags%"), "Poll bit not set in BFD packet"
1152 )
Klement Sekeraa57a9702017-02-02 06:58:07 +01001153
Klement Sekera239790f2017-02-16 10:53:53 +01001154 def test_queued_poll(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001155 """test poll sequence queueing"""
Klement Sekera239790f2017-02-16 10:53:53 +01001156 bfd_session_up(self)
1157 p = wait_for_bfd_packet(self)
1158 self.vpp_session.modify_parameters(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001159 required_min_rx=2 * self.vpp_session.required_min_rx
1160 )
Klement Sekera239790f2017-02-16 10:53:53 +01001161 p = wait_for_bfd_packet(self)
1162 poll_sequence_start = time.time()
1163 poll_sequence_length_min = 0.5
1164 send_final_after = time.time() + poll_sequence_length_min
1165 # poll bit needs to be set
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001166 self.assertIn("P", p.sprintf("%BFD.flags%"), "Poll bit not set in BFD packet")
1167 self.assert_equal(
1168 p[BFD].required_min_rx_interval,
1169 self.vpp_session.required_min_rx,
1170 "BFD required min rx interval",
1171 )
Klement Sekera239790f2017-02-16 10:53:53 +01001172 self.vpp_session.modify_parameters(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001173 required_min_rx=2 * self.vpp_session.required_min_rx
1174 )
Klement Sekera239790f2017-02-16 10:53:53 +01001175 # 2nd poll sequence should be queued now
1176 # don't send the reply back yet, wait for some time to emulate
1177 # longer round-trip time
1178 packet_count = 0
1179 while time.time() < send_final_after:
1180 self.test_session.send_packet()
1181 p = wait_for_bfd_packet(self)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001182 self.assert_equal(
1183 len(self.vapi.collect_events()), 0, "number of bfd events"
1184 )
1185 self.assert_equal(
1186 p[BFD].required_min_rx_interval,
1187 self.vpp_session.required_min_rx,
1188 "BFD required min rx interval",
1189 )
Klement Sekera239790f2017-02-16 10:53:53 +01001190 packet_count += 1
1191 # poll bit must be set
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001192 self.assertIn(
1193 "P", p.sprintf("%BFD.flags%"), "Poll bit not set in BFD packet"
1194 )
Klement Sekera239790f2017-02-16 10:53:53 +01001195 final = self.test_session.create_packet()
1196 final[BFD].flags = "F"
1197 self.test_session.send_packet(final)
1198 # finish 1st with final
1199 poll_sequence_length = time.time() - poll_sequence_start
1200 # vpp must wait for some time before starting new poll sequence
1201 poll_no_2_started = False
1202 for dummy in range(2 * packet_count):
1203 p = wait_for_bfd_packet(self)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001204 self.assert_equal(
1205 len(self.vapi.collect_events()), 0, "number of bfd events"
1206 )
Klement Sekera239790f2017-02-16 10:53:53 +01001207 if "P" in p.sprintf("%BFD.flags%"):
1208 poll_no_2_started = True
1209 if time.time() < poll_sequence_start + poll_sequence_length:
1210 raise Exception("VPP started 2nd poll sequence too soon")
1211 final = self.test_session.create_packet()
1212 final[BFD].flags = "F"
1213 self.test_session.send_packet(final)
1214 break
1215 else:
1216 self.test_session.send_packet()
1217 self.assertTrue(poll_no_2_started, "2nd poll sequence not performed")
1218 # finish 2nd with final
1219 final = self.test_session.create_packet()
1220 final[BFD].flags = "F"
1221 self.test_session.send_packet(final)
1222 p = wait_for_bfd_packet(self)
1223 # poll bit must not be set
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001224 self.assertNotIn("P", p.sprintf("%BFD.flags%"), "Poll bit set in BFD packet")
Klement Sekera239790f2017-02-16 10:53:53 +01001225
Paul Vinciguerra7ade2f52019-12-06 11:06:02 -05001226 # returning inconsistent results requiring retries in per-patch tests
Klement Sekerab23ffd72021-05-31 16:08:53 +02001227 @unittest.skipUnless(config.extended, "part of extended tests")
Klement Sekera73884482017-02-23 09:26:30 +01001228 def test_poll_response(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001229 """test correct response to control frame with poll bit set"""
Klement Sekera73884482017-02-23 09:26:30 +01001230 bfd_session_up(self)
1231 poll = self.test_session.create_packet()
1232 poll[BFD].flags = "P"
1233 self.test_session.send_packet(poll)
1234 final = wait_for_bfd_packet(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001235 self, pcap_time_min=time.time() - self.vpp_clock_offset
1236 )
Klement Sekera73884482017-02-23 09:26:30 +01001237 self.assertIn("F", final.sprintf("%BFD.flags%"))
1238
Klement Sekerad3ba5152017-02-14 03:09:17 +01001239 def test_no_periodic_if_remote_demand(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001240 """no periodic frames outside poll sequence if remote demand set"""
Klement Sekerad3ba5152017-02-14 03:09:17 +01001241 bfd_session_up(self)
1242 demand = self.test_session.create_packet()
1243 demand[BFD].flags = "D"
1244 self.test_session.send_packet(demand)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001245 transmit_time = (
1246 0.9
1247 * max(self.vpp_session.required_min_rx, self.test_session.desired_min_tx)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001248 / USEC_IN_SEC
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001249 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01001250 count = 0
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001251 for dummy in range(self.test_session.detect_mult * 2):
Paul Vinciguerra0f6602c2019-03-10 09:10:54 -07001252 self.sleep(transmit_time)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001253 self.test_session.send_packet(demand)
1254 try:
1255 p = wait_for_bfd_packet(self, timeout=0)
1256 self.logger.error(ppp("Received unexpected packet:", p))
1257 count += 1
1258 except CaptureTimeoutError:
1259 pass
1260 events = self.vapi.collect_events()
1261 for e in events:
1262 self.logger.error("Received unexpected event: %s", e)
1263 self.assert_equal(count, 0, "number of packets received")
1264 self.assert_equal(len(events), 0, "number of events received")
Klement Sekera46a87ad2017-01-02 08:22:23 +01001265
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001266 def test_echo_looped_back(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001267 """echo packets looped back"""
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001268 bfd_session_up(self)
1269 stats_before = bfd_grab_stats_snapshot(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001270 self.pg0.enable_capture()
1271 echo_packet_count = 10
1272 # random source port low enough to increment a few times..
1273 udp_sport_tx = randint(1, 50000)
1274 udp_sport_rx = udp_sport_tx
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001275 echo_packet = (
1276 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1277 / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4)
1278 / UDP(dport=BFD.udp_dport_echo)
1279 / Raw("this should be looped back")
1280 )
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001281 for dummy in range(echo_packet_count):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001282 self.sleep(0.01, "delay between echo packets")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001283 echo_packet[UDP].sport = udp_sport_tx
1284 udp_sport_tx += 1
1285 self.logger.debug(ppp("Sending packet:", echo_packet))
1286 self.pg0.add_stream(echo_packet)
1287 self.pg_start()
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001288 self.logger.debug(self.vapi.ppcli("show trace"))
1289 counter = 0
1290 bfd_control_packets_rx = 0
1291 while counter < echo_packet_count:
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001292 p = self.pg0.wait_for_packet(1)
1293 self.logger.debug(ppp("Got packet:", p))
1294 ether = p[Ether]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001295 self.assert_equal(self.pg0.remote_mac, ether.dst, "Destination MAC")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001296 self.assert_equal(self.pg0.local_mac, ether.src, "Source MAC")
1297 ip = p[IP]
1298 self.assert_equal(self.pg0.remote_ip4, ip.dst, "Destination IP")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001299 udp = p[UDP]
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001300 if udp.dport == BFD.udp_dport:
1301 bfd_control_packets_rx += 1
1302 continue
1303 self.assert_equal(self.pg0.remote_ip4, ip.src, "Source IP")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001304 self.assert_equal(udp.dport, BFD.udp_dport_echo, "UDP destination port")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001305 self.assert_equal(udp.sport, udp_sport_rx, "UDP source port")
1306 udp_sport_rx += 1
Klement Sekera239790f2017-02-16 10:53:53 +01001307 # need to compare the hex payload here, otherwise BFD_vpp_echo
1308 # gets in way
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001309 self.assertEqual(
1310 scapy.compat.raw(p[UDP].payload),
1311 scapy.compat.raw(echo_packet[UDP].payload),
1312 "Received packet is not the echo packet sent",
1313 )
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001314 counter += 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001315 self.assert_equal(
1316 udp_sport_tx,
1317 udp_sport_rx,
1318 "UDP source port (== ECHO packet identifier for test purposes)",
1319 )
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001320 stats_after = bfd_grab_stats_snapshot(self)
1321 diff = bfd_stats_diff(stats_before, stats_after)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001322 self.assertEqual(0, diff.rx, "RX counter bumped but no BFD packets sent")
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001323 self.assertEqual(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001324 0, diff.rx_echo, "RX echo counter bumped but no BFD session exists"
1325 )
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001326 self.assertEqual(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001327 0, diff.tx_echo, "TX echo counter bumped but no BFD session exists"
1328 )
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001329
Klement Sekera239790f2017-02-16 10:53:53 +01001330 def test_echo(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001331 """echo function"""
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001332 stats_before = bfd_grab_stats_snapshot(self)
Klement Sekera239790f2017-02-16 10:53:53 +01001333 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001334 self.test_session.update(required_min_echo_rx=150000)
Klement Sekera239790f2017-02-16 10:53:53 +01001335 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001336 detection_time = (
1337 self.test_session.detect_mult
1338 * self.vpp_session.required_min_rx
1339 / USEC_IN_SEC
1340 )
Klement Sekera239790f2017-02-16 10:53:53 +01001341 # echo shouldn't work without echo source set
Klement Sekera3cfa5582017-04-19 07:10:58 +00001342 for dummy in range(10):
1343 sleep = self.vpp_session.required_min_rx / USEC_IN_SEC
Klement Sekera239790f2017-02-16 10:53:53 +01001344 self.sleep(sleep, "delay before sending bfd packet")
1345 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001346 p = wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
1347 self.assert_equal(
1348 p[BFD].required_min_rx_interval,
1349 self.vpp_session.required_min_rx,
1350 "BFD required min rx interval",
1351 )
Klement Sekera3cfa5582017-04-19 07:10:58 +00001352 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001353 self.vapi.bfd_udp_set_echo_source(sw_if_index=self.loopback0.sw_if_index)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001354 echo_seen = False
Klement Sekera239790f2017-02-16 10:53:53 +01001355 # should be turned on - loopback echo packets
1356 for dummy in range(3):
1357 loop_until = time.time() + 0.75 * detection_time
1358 while time.time() < loop_until:
1359 p = self.pg0.wait_for_packet(1)
1360 self.logger.debug(ppp("Got packet:", p))
1361 if p[UDP].dport == BFD.udp_dport_echo:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001362 self.assert_equal(p[IP].dst, self.pg0.local_ip4, "BFD ECHO dst IP")
1363 self.assertNotEqual(
1364 p[IP].src,
1365 self.loopback0.local_ip4,
1366 "BFD ECHO src IP equal to loopback IP",
1367 )
Klement Sekera239790f2017-02-16 10:53:53 +01001368 self.logger.debug(ppp("Looping back packet:", p))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001369 self.assert_equal(
1370 p[Ether].dst,
1371 self.pg0.remote_mac,
1372 "ECHO packet destination MAC address",
1373 )
John Lo1904c472017-03-10 17:15:22 -05001374 p[Ether].dst = self.pg0.local_mac
Klement Sekera239790f2017-02-16 10:53:53 +01001375 self.pg0.add_stream(p)
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001376 self.test_session.rx_packets_echo += 1
1377 self.test_session.tx_packets_echo += 1
Klement Sekera239790f2017-02-16 10:53:53 +01001378 self.pg_start()
Klement Sekera3cfa5582017-04-19 07:10:58 +00001379 echo_seen = True
Klement Sekera239790f2017-02-16 10:53:53 +01001380 elif p.haslayer(BFD):
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001381 self.test_session.rx_packets += 1
Klement Sekera3cfa5582017-04-19 07:10:58 +00001382 if echo_seen:
1383 self.assertGreaterEqual(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001384 p[BFD].required_min_rx_interval, 1000000
1385 )
Klement Sekera239790f2017-02-16 10:53:53 +01001386 if "P" in p.sprintf("%BFD.flags%"):
1387 final = self.test_session.create_packet()
1388 final[BFD].flags = "F"
1389 self.test_session.send_packet(final)
1390 else:
1391 raise Exception(ppp("Received unknown packet:", p))
1392
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001393 self.assert_equal(
1394 len(self.vapi.collect_events()), 0, "number of bfd events"
1395 )
Klement Sekera239790f2017-02-16 10:53:53 +01001396 self.test_session.send_packet()
Klement Sekera3cfa5582017-04-19 07:10:58 +00001397 self.assertTrue(echo_seen, "No echo packets received")
Klement Sekera239790f2017-02-16 10:53:53 +01001398
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001399 stats_after = bfd_grab_stats_snapshot(self)
1400 diff = bfd_stats_diff(stats_before, stats_after)
1401 # our rx is vpp tx and vice versa, also tolerate one packet off
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001402 self.assert_in_range(
1403 self.test_session.tx_packets, diff.rx - 1, diff.rx + 1, "RX counter"
1404 )
1405 self.assert_in_range(
1406 self.test_session.rx_packets, diff.tx - 1, diff.tx + 1, "TX counter"
1407 )
1408 self.assert_in_range(
1409 self.test_session.tx_packets_echo,
1410 diff.rx_echo - 1,
1411 diff.rx_echo + 1,
1412 "RX echo counter",
1413 )
1414 self.assert_in_range(
1415 self.test_session.rx_packets_echo,
1416 diff.tx_echo - 1,
1417 diff.tx_echo + 1,
1418 "TX echo counter",
1419 )
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001420
Klement Sekera239790f2017-02-16 10:53:53 +01001421 def test_echo_fail(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001422 """session goes down if echo function fails"""
Klement Sekera239790f2017-02-16 10:53:53 +01001423 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001424 self.test_session.update(required_min_echo_rx=150000)
Klement Sekera239790f2017-02-16 10:53:53 +01001425 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001426 detection_time = (
1427 self.test_session.detect_mult
1428 * self.vpp_session.required_min_rx
1429 / USEC_IN_SEC
1430 )
1431 self.vapi.bfd_udp_set_echo_source(sw_if_index=self.loopback0.sw_if_index)
Klement Sekera239790f2017-02-16 10:53:53 +01001432 # echo function should be used now, but we will drop the echo packets
1433 verified_diag = False
1434 for dummy in range(3):
1435 loop_until = time.time() + 0.75 * detection_time
1436 while time.time() < loop_until:
1437 p = self.pg0.wait_for_packet(1)
1438 self.logger.debug(ppp("Got packet:", p))
1439 if p[UDP].dport == BFD.udp_dport_echo:
1440 # dropped
1441 pass
1442 elif p.haslayer(BFD):
1443 if "P" in p.sprintf("%BFD.flags%"):
1444 self.assertGreaterEqual(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001445 p[BFD].required_min_rx_interval, 1000000
1446 )
Klement Sekera239790f2017-02-16 10:53:53 +01001447 final = self.test_session.create_packet()
1448 final[BFD].flags = "F"
1449 self.test_session.send_packet(final)
1450 if p[BFD].state == BFDState.down:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001451 self.assert_equal(
1452 p[BFD].diag, BFDDiagCode.echo_function_failed, BFDDiagCode
1453 )
Klement Sekera239790f2017-02-16 10:53:53 +01001454 verified_diag = True
1455 else:
1456 raise Exception(ppp("Received unknown packet:", p))
1457 self.test_session.send_packet()
1458 events = self.vapi.collect_events()
1459 self.assert_equal(len(events), 1, "number of bfd events")
1460 self.assert_equal(events[0].state, BFDState.down, BFDState)
1461 self.assertTrue(verified_diag, "Incorrect diagnostics code received")
1462
1463 def test_echo_stop(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001464 """echo function stops if peer sets required min echo rx zero"""
Klement Sekera239790f2017-02-16 10:53:53 +01001465 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001466 self.test_session.update(required_min_echo_rx=150000)
Klement Sekera239790f2017-02-16 10:53:53 +01001467 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001468 self.vapi.bfd_udp_set_echo_source(sw_if_index=self.loopback0.sw_if_index)
Klement Sekera239790f2017-02-16 10:53:53 +01001469 # wait for first echo packet
1470 while True:
1471 p = self.pg0.wait_for_packet(1)
1472 self.logger.debug(ppp("Got packet:", p))
1473 if p[UDP].dport == BFD.udp_dport_echo:
1474 self.logger.debug(ppp("Looping back packet:", p))
John Lo1904c472017-03-10 17:15:22 -05001475 p[Ether].dst = self.pg0.local_mac
Klement Sekera239790f2017-02-16 10:53:53 +01001476 self.pg0.add_stream(p)
1477 self.pg_start()
1478 break
1479 elif p.haslayer(BFD):
1480 # ignore BFD
1481 pass
1482 else:
1483 raise Exception(ppp("Received unknown packet:", p))
1484 self.test_session.update(required_min_echo_rx=0)
1485 self.test_session.send_packet()
1486 # echo packets shouldn't arrive anymore
1487 for dummy in range(5):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001488 wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekera239790f2017-02-16 10:53:53 +01001489 self.test_session.send_packet()
1490 events = self.vapi.collect_events()
1491 self.assert_equal(len(events), 0, "number of bfd events")
1492
Klement Sekera73884482017-02-23 09:26:30 +01001493 def test_echo_source_removed(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001494 """echo function stops if echo source is removed"""
Klement Sekera73884482017-02-23 09:26:30 +01001495 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001496 self.test_session.update(required_min_echo_rx=150000)
Klement Sekera73884482017-02-23 09:26:30 +01001497 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001498 self.vapi.bfd_udp_set_echo_source(sw_if_index=self.loopback0.sw_if_index)
Klement Sekera73884482017-02-23 09:26:30 +01001499 # wait for first echo packet
1500 while True:
1501 p = self.pg0.wait_for_packet(1)
1502 self.logger.debug(ppp("Got packet:", p))
1503 if p[UDP].dport == BFD.udp_dport_echo:
1504 self.logger.debug(ppp("Looping back packet:", p))
John Lo1904c472017-03-10 17:15:22 -05001505 p[Ether].dst = self.pg0.local_mac
Klement Sekera73884482017-02-23 09:26:30 +01001506 self.pg0.add_stream(p)
1507 self.pg_start()
1508 break
1509 elif p.haslayer(BFD):
1510 # ignore BFD
1511 pass
1512 else:
1513 raise Exception(ppp("Received unknown packet:", p))
1514 self.vapi.bfd_udp_del_echo_source()
1515 self.test_session.send_packet()
1516 # echo packets shouldn't arrive anymore
1517 for dummy in range(5):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001518 wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekera73884482017-02-23 09:26:30 +01001519 self.test_session.send_packet()
1520 events = self.vapi.collect_events()
1521 self.assert_equal(len(events), 0, "number of bfd events")
1522
Klement Sekera239790f2017-02-16 10:53:53 +01001523 def test_stale_echo(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001524 """stale echo packets don't keep a session up"""
Klement Sekera239790f2017-02-16 10:53:53 +01001525 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001526 self.test_session.update(required_min_echo_rx=150000)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001527 self.vapi.bfd_udp_set_echo_source(sw_if_index=self.loopback0.sw_if_index)
Klement Sekera239790f2017-02-16 10:53:53 +01001528 self.test_session.send_packet()
1529 # should be turned on - loopback echo packets
1530 echo_packet = None
1531 timeout_at = None
1532 timeout_ok = False
1533 for dummy in range(10 * self.vpp_session.detect_mult):
1534 p = self.pg0.wait_for_packet(1)
1535 if p[UDP].dport == BFD.udp_dport_echo:
1536 if echo_packet is None:
1537 self.logger.debug(ppp("Got first echo packet:", p))
1538 echo_packet = p
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001539 timeout_at = (
1540 time.time()
1541 + self.vpp_session.detect_mult
1542 * self.test_session.required_min_echo_rx
1543 / USEC_IN_SEC
1544 )
Klement Sekera239790f2017-02-16 10:53:53 +01001545 else:
1546 self.logger.debug(ppp("Got followup echo packet:", p))
1547 self.logger.debug(ppp("Looping back first echo packet:", p))
John Lo1904c472017-03-10 17:15:22 -05001548 echo_packet[Ether].dst = self.pg0.local_mac
Klement Sekera239790f2017-02-16 10:53:53 +01001549 self.pg0.add_stream(echo_packet)
1550 self.pg_start()
1551 elif p.haslayer(BFD):
1552 self.logger.debug(ppp("Got packet:", p))
1553 if "P" in p.sprintf("%BFD.flags%"):
1554 final = self.test_session.create_packet()
1555 final[BFD].flags = "F"
1556 self.test_session.send_packet(final)
1557 if p[BFD].state == BFDState.down:
1558 self.assertIsNotNone(
1559 timeout_at,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001560 "Session went down before first echo packet received",
1561 )
Klement Sekera239790f2017-02-16 10:53:53 +01001562 now = time.time()
1563 self.assertGreaterEqual(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001564 now,
1565 timeout_at,
1566 "Session timeout at %s, but is expected at %s"
1567 % (now, timeout_at),
1568 )
1569 self.assert_equal(
1570 p[BFD].diag, BFDDiagCode.echo_function_failed, BFDDiagCode
1571 )
Klement Sekera239790f2017-02-16 10:53:53 +01001572 events = self.vapi.collect_events()
1573 self.assert_equal(len(events), 1, "number of bfd events")
1574 self.assert_equal(events[0].state, BFDState.down, BFDState)
1575 timeout_ok = True
1576 break
1577 else:
1578 raise Exception(ppp("Received unknown packet:", p))
1579 self.test_session.send_packet()
1580 self.assertTrue(timeout_ok, "Expected timeout event didn't occur")
1581
1582 def test_invalid_echo_checksum(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001583 """echo packets with invalid checksum don't keep a session up"""
Klement Sekera239790f2017-02-16 10:53:53 +01001584 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001585 self.test_session.update(required_min_echo_rx=150000)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001586 self.vapi.bfd_udp_set_echo_source(sw_if_index=self.loopback0.sw_if_index)
Klement Sekera239790f2017-02-16 10:53:53 +01001587 self.test_session.send_packet()
1588 # should be turned on - loopback echo packets
1589 timeout_at = None
1590 timeout_ok = False
1591 for dummy in range(10 * self.vpp_session.detect_mult):
1592 p = self.pg0.wait_for_packet(1)
1593 if p[UDP].dport == BFD.udp_dport_echo:
1594 self.logger.debug(ppp("Got echo packet:", p))
1595 if timeout_at is None:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001596 timeout_at = (
1597 time.time()
1598 + self.vpp_session.detect_mult
1599 * self.test_session.required_min_echo_rx
1600 / USEC_IN_SEC
1601 )
Klement Sekera239790f2017-02-16 10:53:53 +01001602 p[BFD_vpp_echo].checksum = getrandbits(64)
John Lo1904c472017-03-10 17:15:22 -05001603 p[Ether].dst = self.pg0.local_mac
Klement Sekera239790f2017-02-16 10:53:53 +01001604 self.logger.debug(ppp("Looping back modified echo packet:", p))
1605 self.pg0.add_stream(p)
1606 self.pg_start()
1607 elif p.haslayer(BFD):
1608 self.logger.debug(ppp("Got packet:", p))
1609 if "P" in p.sprintf("%BFD.flags%"):
1610 final = self.test_session.create_packet()
1611 final[BFD].flags = "F"
1612 self.test_session.send_packet(final)
1613 if p[BFD].state == BFDState.down:
1614 self.assertIsNotNone(
1615 timeout_at,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001616 "Session went down before first echo packet received",
1617 )
Klement Sekera239790f2017-02-16 10:53:53 +01001618 now = time.time()
1619 self.assertGreaterEqual(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001620 now,
1621 timeout_at,
1622 "Session timeout at %s, but is expected at %s"
1623 % (now, timeout_at),
1624 )
1625 self.assert_equal(
1626 p[BFD].diag, BFDDiagCode.echo_function_failed, BFDDiagCode
1627 )
Klement Sekera239790f2017-02-16 10:53:53 +01001628 events = self.vapi.collect_events()
1629 self.assert_equal(len(events), 1, "number of bfd events")
1630 self.assert_equal(events[0].state, BFDState.down, BFDState)
1631 timeout_ok = True
1632 break
1633 else:
1634 raise Exception(ppp("Received unknown packet:", p))
1635 self.test_session.send_packet()
1636 self.assertTrue(timeout_ok, "Expected timeout event didn't occur")
1637
Klement Sekerac48829b2017-02-14 07:55:57 +01001638 def test_admin_up_down(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001639 """put session admin-up and admin-down"""
Klement Sekerac48829b2017-02-14 07:55:57 +01001640 bfd_session_up(self)
1641 self.vpp_session.admin_down()
1642 self.pg0.enable_capture()
Ole Troan4376ab22021-03-03 10:40:05 +01001643 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekerac48829b2017-02-14 07:55:57 +01001644 verify_event(self, e, expected_state=BFDState.admin_down)
1645 for dummy in range(2):
1646 p = wait_for_bfd_packet(self)
Klement Sekera73884482017-02-23 09:26:30 +01001647 self.assert_equal(p[BFD].state, BFDState.admin_down, BFDState)
Klement Sekerac48829b2017-02-14 07:55:57 +01001648 # try to bring session up - shouldn't be possible
1649 self.test_session.update(state=BFDState.init)
1650 self.test_session.send_packet()
1651 for dummy in range(2):
1652 p = wait_for_bfd_packet(self)
Klement Sekera73884482017-02-23 09:26:30 +01001653 self.assert_equal(p[BFD].state, BFDState.admin_down, BFDState)
Klement Sekerac48829b2017-02-14 07:55:57 +01001654 self.vpp_session.admin_up()
1655 self.test_session.update(state=BFDState.down)
Ole Troan4376ab22021-03-03 10:40:05 +01001656 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekerac48829b2017-02-14 07:55:57 +01001657 verify_event(self, e, expected_state=BFDState.down)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001658 p = wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekera73884482017-02-23 09:26:30 +01001659 self.assert_equal(p[BFD].state, BFDState.down, BFDState)
Klement Sekerac48829b2017-02-14 07:55:57 +01001660 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001661 p = wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekera73884482017-02-23 09:26:30 +01001662 self.assert_equal(p[BFD].state, BFDState.init, BFDState)
Ole Troan4376ab22021-03-03 10:40:05 +01001663 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekerac48829b2017-02-14 07:55:57 +01001664 verify_event(self, e, expected_state=BFDState.init)
1665 self.test_session.update(state=BFDState.up)
1666 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001667 p = wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekera73884482017-02-23 09:26:30 +01001668 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Ole Troan4376ab22021-03-03 10:40:05 +01001669 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekerac48829b2017-02-14 07:55:57 +01001670 verify_event(self, e, expected_state=BFDState.up)
1671
Klement Sekera239790f2017-02-16 10:53:53 +01001672 def test_config_change_remote_demand(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001673 """configuration change while peer in demand mode"""
Klement Sekera239790f2017-02-16 10:53:53 +01001674 bfd_session_up(self)
1675 demand = self.test_session.create_packet()
1676 demand[BFD].flags = "D"
1677 self.test_session.send_packet(demand)
1678 self.vpp_session.modify_parameters(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001679 required_min_rx=2 * self.vpp_session.required_min_rx
1680 )
1681 p = wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekera239790f2017-02-16 10:53:53 +01001682 # poll bit must be set
1683 self.assertIn("P", p.sprintf("%BFD.flags%"), "Poll bit not set")
1684 # terminate poll sequence
1685 final = self.test_session.create_packet()
1686 final[BFD].flags = "D+F"
1687 self.test_session.send_packet(final)
1688 # vpp should be quiet now again
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001689 transmit_time = (
1690 0.9
1691 * max(self.vpp_session.required_min_rx, self.test_session.desired_min_tx)
Klement Sekera239790f2017-02-16 10:53:53 +01001692 / USEC_IN_SEC
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001693 )
Klement Sekera239790f2017-02-16 10:53:53 +01001694 count = 0
1695 for dummy in range(self.test_session.detect_mult * 2):
Paul Vinciguerra0f6602c2019-03-10 09:10:54 -07001696 self.sleep(transmit_time)
Klement Sekera239790f2017-02-16 10:53:53 +01001697 self.test_session.send_packet(demand)
1698 try:
1699 p = wait_for_bfd_packet(self, timeout=0)
1700 self.logger.error(ppp("Received unexpected packet:", p))
1701 count += 1
1702 except CaptureTimeoutError:
1703 pass
1704 events = self.vapi.collect_events()
1705 for e in events:
1706 self.logger.error("Received unexpected event: %s", e)
1707 self.assert_equal(count, 0, "number of packets received")
1708 self.assert_equal(len(events), 0, "number of events received")
1709
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001710 def test_intf_deleted(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001711 """interface with bfd session deleted"""
Klement Sekerabeaded52018-06-24 10:30:37 +02001712 intf = VppLoInterface(self)
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001713 intf.config_ip4()
1714 intf.admin_up()
1715 sw_if_index = intf.sw_if_index
1716 vpp_session = VppBFDUDPSession(self, intf, intf.remote_ip4)
1717 vpp_session.add_vpp_config()
1718 vpp_session.admin_up()
1719 intf.remove_vpp_config()
Ole Troan4376ab22021-03-03 10:40:05 +01001720 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001721 self.assert_equal(e.sw_if_index, sw_if_index, "sw_if_index")
1722 self.assertFalse(vpp_session.query_vpp_config())
1723
Klement Sekerad3ba5152017-02-14 03:09:17 +01001724
Andrew Yourtchenko06f32812021-01-14 10:19:08 +00001725@tag_run_solo
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00001726@tag_fixme_vpp_workers
Klement Sekerad3ba5152017-02-14 03:09:17 +01001727class BFD6TestCase(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001728 """Bidirectional Forwarding Detection (BFD) (IPv6)"""
Klement Sekera46a87ad2017-01-02 08:22:23 +01001729
Klement Sekerad3ba5152017-02-14 03:09:17 +01001730 pg0 = None
1731 vpp_clock_offset = None
1732 vpp_session = None
1733 test_session = None
1734
Klement Sekera46a87ad2017-01-02 08:22:23 +01001735 @classmethod
1736 def setUpClass(cls):
1737 super(BFD6TestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -08001738 cls.vapi.cli("set log class bfd level debug")
Klement Sekera46a87ad2017-01-02 08:22:23 +01001739 try:
1740 cls.create_pg_interfaces([0])
1741 cls.pg0.config_ip6()
1742 cls.pg0.configure_ipv6_neighbors()
1743 cls.pg0.admin_up()
1744 cls.pg0.resolve_ndp()
Klement Sekerab9ef2732018-06-24 22:49:33 +02001745 cls.create_loopback_interfaces(1)
Klement Sekera239790f2017-02-16 10:53:53 +01001746 cls.loopback0 = cls.lo_interfaces[0]
1747 cls.loopback0.config_ip6()
1748 cls.loopback0.admin_up()
Klement Sekera46a87ad2017-01-02 08:22:23 +01001749
1750 except Exception:
1751 super(BFD6TestCase, cls).tearDownClass()
1752 raise
1753
Paul Vinciguerra8d991d92019-01-25 14:05:48 -08001754 @classmethod
1755 def tearDownClass(cls):
1756 super(BFD6TestCase, cls).tearDownClass()
1757
Klement Sekera46a87ad2017-01-02 08:22:23 +01001758 def setUp(self):
1759 super(BFD6TestCase, self).setUp()
Klement Sekerab17dd962017-01-09 07:43:48 +01001760 self.factory = AuthKeyFactory()
Klement Sekera46a87ad2017-01-02 08:22:23 +01001761 self.vapi.want_bfd_events()
Klement Sekerad3ba5152017-02-14 03:09:17 +01001762 self.pg0.enable_capture()
Klement Sekera46a87ad2017-01-02 08:22:23 +01001763 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001764 self.bfd_udp4_sessions = self.statistics["/bfd/udp4/sessions"]
1765 self.bfd_udp6_sessions = self.statistics["/bfd/udp6/sessions"]
1766 self.vpp_session = VppBFDUDPSession(
1767 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6
1768 )
Klement Sekera46a87ad2017-01-02 08:22:23 +01001769 self.vpp_session.add_vpp_config()
1770 self.vpp_session.admin_up()
1771 self.test_session = BFDTestSession(self, self.pg0, AF_INET6)
1772 self.logger.debug(self.vapi.cli("show adj nbr"))
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001773 except BaseException:
Klement Sekera46a87ad2017-01-02 08:22:23 +01001774 self.vapi.want_bfd_events(enable_disable=0)
1775 raise
1776
1777 def tearDown(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001778 if not self.vpp_dead:
1779 self.vapi.want_bfd_events(enable_disable=0)
1780 self.vapi.collect_events() # clear the event queue
1781 super(BFD6TestCase, self).tearDown()
Klement Sekerab17dd962017-01-09 07:43:48 +01001782
1783 def test_session_up(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001784 """bring BFD session up"""
Klement Sekerad3ba5152017-02-14 03:09:17 +01001785 bfd_session_up(self)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001786 bfd_udp4_sessions = self.statistics["/bfd/udp4/sessions"]
1787 bfd_udp6_sessions = self.statistics["/bfd/udp6/sessions"]
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001788 self.assert_equal(bfd_udp4_sessions, self.bfd_udp4_sessions)
1789 self.assert_equal(bfd_udp6_sessions - self.bfd_udp6_sessions, 1)
Klement Sekerab17dd962017-01-09 07:43:48 +01001790
Klement Sekera73884482017-02-23 09:26:30 +01001791 def test_session_up_by_ip(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001792 """bring BFD session up - first frame looked up by address pair"""
Klement Sekera73884482017-02-23 09:26:30 +01001793 self.logger.info("BFD: Sending Slow control frame")
1794 self.test_session.update(my_discriminator=randint(0, 40000000))
1795 self.test_session.send_packet()
1796 self.pg0.enable_capture()
1797 p = self.pg0.wait_for_packet(1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001798 self.assert_equal(
1799 p[BFD].your_discriminator,
1800 self.test_session.my_discriminator,
1801 "BFD - your discriminator",
1802 )
Klement Sekera73884482017-02-23 09:26:30 +01001803 self.assert_equal(p[BFD].state, BFDState.init, BFDState)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001804 self.test_session.update(
1805 your_discriminator=p[BFD].my_discriminator, state=BFDState.up
1806 )
Klement Sekera73884482017-02-23 09:26:30 +01001807 self.logger.info("BFD: Waiting for event")
Ole Troan4376ab22021-03-03 10:40:05 +01001808 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekera73884482017-02-23 09:26:30 +01001809 verify_event(self, e, expected_state=BFDState.init)
1810 self.logger.info("BFD: Sending Up")
1811 self.test_session.send_packet()
1812 self.logger.info("BFD: Waiting for event")
Ole Troan4376ab22021-03-03 10:40:05 +01001813 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekera73884482017-02-23 09:26:30 +01001814 verify_event(self, e, expected_state=BFDState.up)
1815 self.logger.info("BFD: Session is Up")
1816 self.test_session.update(state=BFDState.up)
1817 self.test_session.send_packet()
1818 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1819
Klement Sekerab17dd962017-01-09 07:43:48 +01001820 def test_hold_up(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001821 """hold BFD session up"""
Klement Sekerad3ba5152017-02-14 03:09:17 +01001822 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001823 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001824 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001825 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001826 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekerab17dd962017-01-09 07:43:48 +01001827 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1828
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001829 def test_echo_looped_back(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001830 """echo packets looped back"""
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001831 bfd_session_up(self)
1832 stats_before = bfd_grab_stats_snapshot(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001833 self.pg0.enable_capture()
1834 echo_packet_count = 10
1835 # random source port low enough to increment a few times..
1836 udp_sport_tx = randint(1, 50000)
1837 udp_sport_rx = udp_sport_tx
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001838 echo_packet = (
1839 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1840 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6)
1841 / UDP(dport=BFD.udp_dport_echo)
1842 / Raw("this should be looped back")
1843 )
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001844 for dummy in range(echo_packet_count):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001845 self.sleep(0.01, "delay between echo packets")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001846 echo_packet[UDP].sport = udp_sport_tx
1847 udp_sport_tx += 1
1848 self.logger.debug(ppp("Sending packet:", echo_packet))
1849 self.pg0.add_stream(echo_packet)
1850 self.pg_start()
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001851 counter = 0
1852 bfd_control_packets_rx = 0
1853 while counter < echo_packet_count:
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001854 p = self.pg0.wait_for_packet(1)
1855 self.logger.debug(ppp("Got packet:", p))
1856 ether = p[Ether]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001857 self.assert_equal(self.pg0.remote_mac, ether.dst, "Destination MAC")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001858 self.assert_equal(self.pg0.local_mac, ether.src, "Source MAC")
1859 ip = p[IPv6]
1860 self.assert_equal(self.pg0.remote_ip6, ip.dst, "Destination IP")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001861 udp = p[UDP]
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001862 if udp.dport == BFD.udp_dport:
1863 bfd_control_packets_rx += 1
1864 continue
1865 self.assert_equal(self.pg0.remote_ip6, ip.src, "Source IP")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001866 self.assert_equal(udp.dport, BFD.udp_dport_echo, "UDP destination port")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001867 self.assert_equal(udp.sport, udp_sport_rx, "UDP source port")
1868 udp_sport_rx += 1
Klement Sekera239790f2017-02-16 10:53:53 +01001869 # need to compare the hex payload here, otherwise BFD_vpp_echo
1870 # gets in way
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001871 self.assertEqual(
1872 scapy.compat.raw(p[UDP].payload),
1873 scapy.compat.raw(echo_packet[UDP].payload),
1874 "Received packet is not the echo packet sent",
1875 )
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001876 counter += 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001877 self.assert_equal(
1878 udp_sport_tx,
1879 udp_sport_rx,
1880 "UDP source port (== ECHO packet identifier for test purposes)",
1881 )
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001882 stats_after = bfd_grab_stats_snapshot(self)
1883 diff = bfd_stats_diff(stats_before, stats_after)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001884 self.assertEqual(0, diff.rx, "RX counter bumped but no BFD packets sent")
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001885 self.assertEqual(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001886 0, diff.rx_echo, "RX echo counter bumped but no BFD session exists"
1887 )
1888 self.assertEqual(
1889 0, diff.tx_echo, "TX echo counter bumped but no BFD session exists"
1890 )
Klement Sekera239790f2017-02-16 10:53:53 +01001891
1892 def test_echo(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001893 """echo function"""
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001894 stats_before = bfd_grab_stats_snapshot(self)
Klement Sekera239790f2017-02-16 10:53:53 +01001895 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001896 self.test_session.update(required_min_echo_rx=150000)
Klement Sekera239790f2017-02-16 10:53:53 +01001897 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001898 detection_time = (
1899 self.test_session.detect_mult
1900 * self.vpp_session.required_min_rx
1901 / USEC_IN_SEC
1902 )
Klement Sekera239790f2017-02-16 10:53:53 +01001903 # echo shouldn't work without echo source set
Klement Sekera3cfa5582017-04-19 07:10:58 +00001904 for dummy in range(10):
1905 sleep = self.vpp_session.required_min_rx / USEC_IN_SEC
Klement Sekera239790f2017-02-16 10:53:53 +01001906 self.sleep(sleep, "delay before sending bfd packet")
1907 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001908 p = wait_for_bfd_packet(self, pcap_time_min=time.time() - self.vpp_clock_offset)
1909 self.assert_equal(
1910 p[BFD].required_min_rx_interval,
1911 self.vpp_session.required_min_rx,
1912 "BFD required min rx interval",
1913 )
Klement Sekera3cfa5582017-04-19 07:10:58 +00001914 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001915 self.vapi.bfd_udp_set_echo_source(sw_if_index=self.loopback0.sw_if_index)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001916 echo_seen = False
Klement Sekera239790f2017-02-16 10:53:53 +01001917 # should be turned on - loopback echo packets
1918 for dummy in range(3):
1919 loop_until = time.time() + 0.75 * detection_time
1920 while time.time() < loop_until:
1921 p = self.pg0.wait_for_packet(1)
1922 self.logger.debug(ppp("Got packet:", p))
1923 if p[UDP].dport == BFD.udp_dport_echo:
1924 self.assert_equal(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001925 p[IPv6].dst, self.pg0.local_ip6, "BFD ECHO dst IP"
1926 )
1927 self.assertNotEqual(
1928 p[IPv6].src,
1929 self.loopback0.local_ip6,
1930 "BFD ECHO src IP equal to loopback IP",
1931 )
Klement Sekera239790f2017-02-16 10:53:53 +01001932 self.logger.debug(ppp("Looping back packet:", p))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001933 self.assert_equal(
1934 p[Ether].dst,
1935 self.pg0.remote_mac,
1936 "ECHO packet destination MAC address",
1937 )
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001938 self.test_session.rx_packets_echo += 1
1939 self.test_session.tx_packets_echo += 1
John Lo1904c472017-03-10 17:15:22 -05001940 p[Ether].dst = self.pg0.local_mac
Klement Sekera239790f2017-02-16 10:53:53 +01001941 self.pg0.add_stream(p)
1942 self.pg_start()
Klement Sekera3cfa5582017-04-19 07:10:58 +00001943 echo_seen = True
Klement Sekera239790f2017-02-16 10:53:53 +01001944 elif p.haslayer(BFD):
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001945 self.test_session.rx_packets += 1
Klement Sekera3cfa5582017-04-19 07:10:58 +00001946 if echo_seen:
1947 self.assertGreaterEqual(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001948 p[BFD].required_min_rx_interval, 1000000
1949 )
Klement Sekera239790f2017-02-16 10:53:53 +01001950 if "P" in p.sprintf("%BFD.flags%"):
1951 final = self.test_session.create_packet()
1952 final[BFD].flags = "F"
1953 self.test_session.send_packet(final)
1954 else:
1955 raise Exception(ppp("Received unknown packet:", p))
1956
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001957 self.assert_equal(
1958 len(self.vapi.collect_events()), 0, "number of bfd events"
1959 )
Klement Sekera239790f2017-02-16 10:53:53 +01001960 self.test_session.send_packet()
Klement Sekera3cfa5582017-04-19 07:10:58 +00001961 self.assertTrue(echo_seen, "No echo packets received")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001962
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001963 stats_after = bfd_grab_stats_snapshot(self)
1964 diff = bfd_stats_diff(stats_before, stats_after)
1965 # our rx is vpp tx and vice versa, also tolerate one packet off
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001966 self.assert_in_range(
1967 self.test_session.tx_packets, diff.rx - 1, diff.rx + 1, "RX counter"
1968 )
1969 self.assert_in_range(
1970 self.test_session.rx_packets, diff.tx - 1, diff.tx + 1, "TX counter"
1971 )
1972 self.assert_in_range(
1973 self.test_session.tx_packets_echo,
1974 diff.rx_echo - 1,
1975 diff.rx_echo + 1,
1976 "RX echo counter",
1977 )
1978 self.assert_in_range(
1979 self.test_session.rx_packets_echo,
1980 diff.tx_echo - 1,
1981 diff.tx_echo + 1,
1982 "TX echo counter",
1983 )
Klement Sekeracdaf0d82022-02-14 20:20:22 +00001984
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001985 def test_intf_deleted(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001986 """interface with bfd session deleted"""
Klement Sekerabeaded52018-06-24 10:30:37 +02001987 intf = VppLoInterface(self)
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001988 intf.config_ip6()
1989 intf.admin_up()
1990 sw_if_index = intf.sw_if_index
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001991 vpp_session = VppBFDUDPSession(self, intf, intf.remote_ip6, af=AF_INET6)
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001992 vpp_session.add_vpp_config()
1993 vpp_session.admin_up()
1994 intf.remove_vpp_config()
Ole Troan4376ab22021-03-03 10:40:05 +01001995 e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001996 self.assert_equal(e.sw_if_index, sw_if_index, "sw_if_index")
1997 self.assertFalse(vpp_session.query_vpp_config())
1998
Klement Sekerab17dd962017-01-09 07:43:48 +01001999
Andrew Yourtchenko06f32812021-01-14 10:19:08 +00002000@tag_run_solo
Neale Ranns88fc83e2017-04-05 08:11:14 -07002001class BFDFIBTestCase(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002002 """BFD-FIB interactions (IPv6)"""
Neale Ranns88fc83e2017-04-05 08:11:14 -07002003
2004 vpp_session = None
2005 test_session = None
2006
Paul Vinciguerra8d991d92019-01-25 14:05:48 -08002007 @classmethod
2008 def setUpClass(cls):
2009 super(BFDFIBTestCase, cls).setUpClass()
2010
2011 @classmethod
2012 def tearDownClass(cls):
2013 super(BFDFIBTestCase, cls).tearDownClass()
2014
Neale Ranns88fc83e2017-04-05 08:11:14 -07002015 def setUp(self):
2016 super(BFDFIBTestCase, self).setUp()
2017 self.create_pg_interfaces(range(1))
2018
2019 self.vapi.want_bfd_events()
2020 self.pg0.enable_capture()
2021
2022 for i in self.pg_interfaces:
2023 i.admin_up()
2024 i.config_ip6()
2025 i.configure_ipv6_neighbors()
2026
2027 def tearDown(self):
2028 if not self.vpp_dead:
Jakub Grajciar4682feb2019-09-02 13:28:52 +02002029 self.vapi.want_bfd_events(enable_disable=False)
Neale Ranns88fc83e2017-04-05 08:11:14 -07002030
2031 super(BFDFIBTestCase, self).tearDown()
2032
2033 @staticmethod
2034 def pkt_is_not_data_traffic(p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002035 """not data traffic implies BFD or the usual IPv6 ND/RA"""
Neale Ranns88fc83e2017-04-05 08:11:14 -07002036 if p.haslayer(BFD) or is_ipv6_misc(p):
2037 return True
2038 return False
2039
2040 def test_session_with_fib(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002041 """BFD-FIB interactions"""
Neale Ranns88fc83e2017-04-05 08:11:14 -07002042
2043 # packets to match against both of the routes
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002044 p = [
2045 (
2046 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2047 / IPv6(src="3001::1", dst="2001::1")
2048 / UDP(sport=1234, dport=1234)
2049 / Raw(b"\xa5" * 100)
2050 ),
2051 (
2052 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2053 / IPv6(src="3001::1", dst="2002::1")
2054 / UDP(sport=1234, dport=1234)
2055 / Raw(b"\xa5" * 100)
2056 ),
2057 ]
Neale Ranns88fc83e2017-04-05 08:11:14 -07002058
2059 # A recursive and a non-recursive route via a next-hop that
2060 # will have a BFD session
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002061 ip_2001_s_64 = VppIpRoute(
2062 self,
2063 "2001::",
2064 64,
2065 [VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index)],
2066 )
2067 ip_2002_s_64 = VppIpRoute(
2068 self, "2002::", 64, [VppRoutePath(self.pg0.remote_ip6, 0xFFFFFFFF)]
2069 )
Neale Ranns88fc83e2017-04-05 08:11:14 -07002070 ip_2001_s_64.add_vpp_config()
2071 ip_2002_s_64.add_vpp_config()
2072
2073 # bring the session up now the routes are present
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002074 self.vpp_session = VppBFDUDPSession(
2075 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6
2076 )
Neale Ranns88fc83e2017-04-05 08:11:14 -07002077 self.vpp_session.add_vpp_config()
2078 self.vpp_session.admin_up()
2079 self.test_session = BFDTestSession(self, self.pg0, AF_INET6)
2080
2081 # session is up - traffic passes
2082 bfd_session_up(self)
2083
2084 self.pg0.add_stream(p)
2085 self.pg_start()
2086 for packet in p:
2087 captured = self.pg0.wait_for_packet(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002088 1, filter_out_fn=self.pkt_is_not_data_traffic
2089 )
2090 self.assertEqual(captured[IPv6].dst, packet[IPv6].dst)
Neale Ranns88fc83e2017-04-05 08:11:14 -07002091
2092 # session is up - traffic is dropped
2093 bfd_session_down(self)
2094
2095 self.pg0.add_stream(p)
2096 self.pg_start()
2097 with self.assertRaises(CaptureTimeoutError):
2098 self.pg0.wait_for_packet(1, self.pkt_is_not_data_traffic)
2099
2100 # session is up - traffic passes
2101 bfd_session_up(self)
2102
2103 self.pg0.add_stream(p)
2104 self.pg_start()
2105 for packet in p:
2106 captured = self.pg0.wait_for_packet(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002107 1, filter_out_fn=self.pkt_is_not_data_traffic
2108 )
2109 self.assertEqual(captured[IPv6].dst, packet[IPv6].dst)
Neale Ranns88fc83e2017-04-05 08:11:14 -07002110
2111
Klement Sekerab23ffd72021-05-31 16:08:53 +02002112@unittest.skipUnless(config.extended, "part of extended tests")
Neale Ranns52cd4962019-06-05 10:28:17 +00002113class BFDTunTestCase(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002114 """BFD over GRE tunnel"""
Neale Ranns52cd4962019-06-05 10:28:17 +00002115
2116 vpp_session = None
2117 test_session = None
2118
2119 @classmethod
2120 def setUpClass(cls):
2121 super(BFDTunTestCase, cls).setUpClass()
2122
2123 @classmethod
2124 def tearDownClass(cls):
2125 super(BFDTunTestCase, cls).tearDownClass()
2126
2127 def setUp(self):
2128 super(BFDTunTestCase, self).setUp()
2129 self.create_pg_interfaces(range(1))
2130
2131 self.vapi.want_bfd_events()
2132 self.pg0.enable_capture()
2133
2134 for i in self.pg_interfaces:
2135 i.admin_up()
2136 i.config_ip4()
2137 i.resolve_arp()
2138
2139 def tearDown(self):
2140 if not self.vpp_dead:
2141 self.vapi.want_bfd_events(enable_disable=0)
2142
2143 super(BFDTunTestCase, self).tearDown()
2144
2145 @staticmethod
2146 def pkt_is_not_data_traffic(p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002147 """not data traffic implies BFD or the usual IPv6 ND/RA"""
Neale Ranns52cd4962019-06-05 10:28:17 +00002148 if p.haslayer(BFD) or is_ipv6_misc(p):
2149 return True
2150 return False
2151
2152 def test_bfd_o_gre(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002153 """BFD-o-GRE"""
Neale Ranns52cd4962019-06-05 10:28:17 +00002154
2155 # A GRE interface over which to run a BFD session
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002156 gre_if = VppGreInterface(self, self.pg0.local_ip4, self.pg0.remote_ip4)
Neale Ranns52cd4962019-06-05 10:28:17 +00002157 gre_if.add_vpp_config()
2158 gre_if.admin_up()
2159 gre_if.config_ip4()
2160
2161 # bring the session up now the routes are present
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002162 self.vpp_session = VppBFDUDPSession(
2163 self, gre_if, gre_if.remote_ip4, is_tunnel=True
2164 )
Neale Ranns52cd4962019-06-05 10:28:17 +00002165 self.vpp_session.add_vpp_config()
2166 self.vpp_session.admin_up()
2167
2168 self.test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002169 self,
2170 gre_if,
2171 AF_INET,
2172 tunnel_header=(IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / GRE()),
2173 phy_interface=self.pg0,
2174 )
Neale Ranns52cd4962019-06-05 10:28:17 +00002175
2176 # packets to match against both of the routes
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002177 p = [
2178 (
2179 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2180 / IP(src=self.pg0.remote_ip4, dst=gre_if.remote_ip4)
2181 / UDP(sport=1234, dport=1234)
2182 / Raw(b"\xa5" * 100)
2183 )
2184 ]
Neale Ranns52cd4962019-06-05 10:28:17 +00002185
2186 # session is up - traffic passes
2187 bfd_session_up(self)
2188
2189 self.send_and_expect(self.pg0, p, self.pg0)
2190
2191 # bring session down
2192 bfd_session_down(self)
2193
2194
Andrew Yourtchenko06f32812021-01-14 10:19:08 +00002195@tag_run_solo
Klement Sekerad3ba5152017-02-14 03:09:17 +01002196class BFDSHA1TestCase(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002197 """Bidirectional Forwarding Detection (BFD) (SHA1 auth)"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002198
Klement Sekerad3ba5152017-02-14 03:09:17 +01002199 pg0 = None
2200 vpp_clock_offset = None
2201 vpp_session = None
2202 test_session = None
2203
Klement Sekerab17dd962017-01-09 07:43:48 +01002204 @classmethod
2205 def setUpClass(cls):
2206 super(BFDSHA1TestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -08002207 cls.vapi.cli("set log class bfd level debug")
Klement Sekerab17dd962017-01-09 07:43:48 +01002208 try:
2209 cls.create_pg_interfaces([0])
2210 cls.pg0.config_ip4()
2211 cls.pg0.admin_up()
2212 cls.pg0.resolve_arp()
2213
2214 except Exception:
2215 super(BFDSHA1TestCase, cls).tearDownClass()
2216 raise
2217
Paul Vinciguerra8d991d92019-01-25 14:05:48 -08002218 @classmethod
2219 def tearDownClass(cls):
2220 super(BFDSHA1TestCase, cls).tearDownClass()
2221
Klement Sekerab17dd962017-01-09 07:43:48 +01002222 def setUp(self):
2223 super(BFDSHA1TestCase, self).setUp()
2224 self.factory = AuthKeyFactory()
2225 self.vapi.want_bfd_events()
Klement Sekerad3ba5152017-02-14 03:09:17 +01002226 self.pg0.enable_capture()
Klement Sekerab17dd962017-01-09 07:43:48 +01002227
2228 def tearDown(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002229 if not self.vpp_dead:
Jakub Grajciar4682feb2019-09-02 13:28:52 +02002230 self.vapi.want_bfd_events(enable_disable=False)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002231 self.vapi.collect_events() # clear the event queue
2232 super(BFDSHA1TestCase, self).tearDown()
Klement Sekerab17dd962017-01-09 07:43:48 +01002233
2234 def test_session_up(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002235 """bring BFD session up"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002236 key = self.factory.create_random_key(self)
2237 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002238 self.vpp_session = VppBFDUDPSession(
2239 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2240 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002241 self.vpp_session.add_vpp_config()
2242 self.vpp_session.admin_up()
2243 self.test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002244 self,
2245 self.pg0,
2246 AF_INET,
2247 sha1_key=key,
2248 bfd_key_id=self.vpp_session.bfd_key_id,
2249 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01002250 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002251
2252 def test_hold_up(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002253 """hold BFD session up"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002254 key = self.factory.create_random_key(self)
2255 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002256 self.vpp_session = VppBFDUDPSession(
2257 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2258 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002259 self.vpp_session.add_vpp_config()
2260 self.vpp_session.admin_up()
2261 self.test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002262 self,
2263 self.pg0,
2264 AF_INET,
2265 sha1_key=key,
2266 bfd_key_id=self.vpp_session.bfd_key_id,
2267 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01002268 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002269 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002270 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002271 self.test_session.send_packet()
2272 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
2273
2274 def test_hold_up_meticulous(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002275 """hold BFD session up - meticulous auth"""
2276 key = self.factory.create_random_key(self, BFDAuthType.meticulous_keyed_sha1)
Klement Sekerab17dd962017-01-09 07:43:48 +01002277 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002278 self.vpp_session = VppBFDUDPSession(
2279 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2280 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002281 self.vpp_session.add_vpp_config()
2282 self.vpp_session.admin_up()
Klement Sekerad3ba5152017-02-14 03:09:17 +01002283 # specify sequence number so that it wraps
Klement Sekerab17dd962017-01-09 07:43:48 +01002284 self.test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002285 self,
2286 self.pg0,
2287 AF_INET,
2288 sha1_key=key,
Klement Sekerad3ba5152017-02-14 03:09:17 +01002289 bfd_key_id=self.vpp_session.bfd_key_id,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002290 our_seq_number=0xFFFFFFFF - 4,
2291 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01002292 bfd_session_up(self)
2293 for dummy in range(30):
2294 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002295 self.test_session.inc_seq_num()
2296 self.test_session.send_packet()
2297 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
2298
2299 def test_send_bad_seq_number(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002300 """session is not kept alive by msgs with bad sequence numbers"""
2301 key = self.factory.create_random_key(self, BFDAuthType.meticulous_keyed_sha1)
Klement Sekerab17dd962017-01-09 07:43:48 +01002302 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002303 self.vpp_session = VppBFDUDPSession(
2304 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2305 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002306 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002307 self.test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002308 self,
2309 self.pg0,
2310 AF_INET,
2311 sha1_key=key,
2312 bfd_key_id=self.vpp_session.bfd_key_id,
2313 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01002314 bfd_session_up(self)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002315 detection_time = (
2316 self.test_session.detect_mult
2317 * self.vpp_session.required_min_rx
2318 / USEC_IN_SEC
2319 )
Klement Sekera239790f2017-02-16 10:53:53 +01002320 send_until = time.time() + 2 * detection_time
2321 while time.time() < send_until:
Klement Sekerad3ba5152017-02-14 03:09:17 +01002322 self.test_session.send_packet()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002323 self.sleep(
2324 0.7 * self.vpp_session.required_min_rx / USEC_IN_SEC,
2325 "time between bfd packets",
2326 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002327 e = self.vapi.collect_events()
2328 # session should be down now, because the sequence numbers weren't
2329 # updated
2330 self.assert_equal(len(e), 1, "number of bfd events")
Klement Sekerad3ba5152017-02-14 03:09:17 +01002331 verify_event(self, e[0], expected_state=BFDState.down)
Klement Sekerab17dd962017-01-09 07:43:48 +01002332
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002333 def execute_rogue_session_scenario(
2334 self,
2335 vpp_bfd_udp_session,
2336 legitimate_test_session,
2337 rogue_test_session,
2338 rogue_bfd_values=None,
2339 ):
2340 """execute a rogue session interaction scenario
Klement Sekerab17dd962017-01-09 07:43:48 +01002341
2342 1. create vpp session, add config
2343 2. bring the legitimate session up
2344 3. copy the bfd values from legitimate session to rogue session
2345 4. apply rogue_bfd_values to rogue session
2346 5. set rogue session state to down
2347 6. send message to take the session down from the rogue session
2348 7. assert that the legitimate session is unaffected
2349 """
2350
2351 self.vpp_session = vpp_bfd_udp_session
2352 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002353 self.test_session = legitimate_test_session
2354 # bring vpp session up
Klement Sekerad3ba5152017-02-14 03:09:17 +01002355 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002356 # send packet from rogue session
Klement Sekerad3ba5152017-02-14 03:09:17 +01002357 rogue_test_session.update(
2358 my_discriminator=self.test_session.my_discriminator,
2359 your_discriminator=self.test_session.your_discriminator,
2360 desired_min_tx=self.test_session.desired_min_tx,
2361 required_min_rx=self.test_session.required_min_rx,
2362 detect_mult=self.test_session.detect_mult,
2363 diag=self.test_session.diag,
2364 state=self.test_session.state,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002365 auth_type=self.test_session.auth_type,
2366 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002367 if rogue_bfd_values:
2368 rogue_test_session.update(**rogue_bfd_values)
2369 rogue_test_session.update(state=BFDState.down)
2370 rogue_test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +01002371 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002372 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
2373
2374 def test_mismatch_auth(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002375 """session is not brought down by unauthenticated msg"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002376 key = self.factory.create_random_key(self)
2377 key.add_vpp_config()
2378 vpp_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002379 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2380 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002381 legitimate_test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002382 self, self.pg0, AF_INET, sha1_key=key, bfd_key_id=vpp_session.bfd_key_id
2383 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002384 rogue_test_session = BFDTestSession(self, self.pg0, AF_INET)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002385 self.execute_rogue_session_scenario(
2386 vpp_session, legitimate_test_session, rogue_test_session
2387 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002388
2389 def test_mismatch_bfd_key_id(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002390 """session is not brought down by msg with non-existent key-id"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002391 key = self.factory.create_random_key(self)
2392 key.add_vpp_config()
2393 vpp_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002394 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2395 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002396 # pick a different random bfd key id
2397 x = randint(0, 255)
2398 while x == vpp_session.bfd_key_id:
2399 x = randint(0, 255)
2400 legitimate_test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002401 self, self.pg0, AF_INET, sha1_key=key, bfd_key_id=vpp_session.bfd_key_id
2402 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002403 rogue_test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002404 self, self.pg0, AF_INET, sha1_key=key, bfd_key_id=x
2405 )
2406 self.execute_rogue_session_scenario(
2407 vpp_session, legitimate_test_session, rogue_test_session
2408 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002409
2410 def test_mismatched_auth_type(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002411 """session is not brought down by msg with wrong auth type"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002412 key = self.factory.create_random_key(self)
2413 key.add_vpp_config()
2414 vpp_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002415 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2416 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002417 legitimate_test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002418 self, self.pg0, AF_INET, sha1_key=key, bfd_key_id=vpp_session.bfd_key_id
2419 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002420 rogue_test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002421 self, self.pg0, AF_INET, sha1_key=key, bfd_key_id=vpp_session.bfd_key_id
2422 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002423 self.execute_rogue_session_scenario(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002424 vpp_session,
2425 legitimate_test_session,
2426 rogue_test_session,
2427 {"auth_type": BFDAuthType.keyed_md5},
2428 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002429
2430 def test_restart(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002431 """simulate remote peer restart and resynchronization"""
2432 key = self.factory.create_random_key(self, BFDAuthType.meticulous_keyed_sha1)
Klement Sekerab17dd962017-01-09 07:43:48 +01002433 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002434 self.vpp_session = VppBFDUDPSession(
2435 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2436 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002437 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002438 self.test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002439 self,
2440 self.pg0,
2441 AF_INET,
2442 sha1_key=key,
2443 bfd_key_id=self.vpp_session.bfd_key_id,
2444 our_seq_number=0,
2445 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01002446 bfd_session_up(self)
2447 # don't send any packets for 2*detection_time
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002448 detection_time = (
2449 self.test_session.detect_mult
2450 * self.vpp_session.required_min_rx
2451 / USEC_IN_SEC
2452 )
Klement Sekera87134932017-03-07 11:39:27 +01002453 self.sleep(2 * detection_time, "simulating peer restart")
Klement Sekerad3ba5152017-02-14 03:09:17 +01002454 events = self.vapi.collect_events()
2455 self.assert_equal(len(events), 1, "number of bfd events")
2456 verify_event(self, events[0], expected_state=BFDState.down)
Klement Sekerab17dd962017-01-09 07:43:48 +01002457 self.test_session.update(state=BFDState.down)
Klement Sekerab17dd962017-01-09 07:43:48 +01002458 # reset sequence number
2459 self.test_session.our_seq_number = 0
Klement Sekerad3ba5152017-02-14 03:09:17 +01002460 self.test_session.vpp_seq_number = None
2461 # now throw away any pending packets
2462 self.pg0.enable_capture()
Klement Sekera4d39f9c2020-01-17 10:01:52 +00002463 self.test_session.my_discriminator = 0
Klement Sekerad3ba5152017-02-14 03:09:17 +01002464 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002465
2466
Andrew Yourtchenko06f32812021-01-14 10:19:08 +00002467@tag_run_solo
Klement Sekerad3ba5152017-02-14 03:09:17 +01002468class BFDAuthOnOffTestCase(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002469 """Bidirectional Forwarding Detection (BFD) (changing auth)"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002470
Klement Sekerad3ba5152017-02-14 03:09:17 +01002471 pg0 = None
2472 vpp_session = None
2473 test_session = None
2474
Klement Sekerab17dd962017-01-09 07:43:48 +01002475 @classmethod
2476 def setUpClass(cls):
2477 super(BFDAuthOnOffTestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -08002478 cls.vapi.cli("set log class bfd level debug")
Klement Sekerab17dd962017-01-09 07:43:48 +01002479 try:
2480 cls.create_pg_interfaces([0])
2481 cls.pg0.config_ip4()
2482 cls.pg0.admin_up()
2483 cls.pg0.resolve_arp()
2484
2485 except Exception:
2486 super(BFDAuthOnOffTestCase, cls).tearDownClass()
2487 raise
2488
Paul Vinciguerra8d991d92019-01-25 14:05:48 -08002489 @classmethod
2490 def tearDownClass(cls):
2491 super(BFDAuthOnOffTestCase, cls).tearDownClass()
2492
Klement Sekerab17dd962017-01-09 07:43:48 +01002493 def setUp(self):
2494 super(BFDAuthOnOffTestCase, self).setUp()
2495 self.factory = AuthKeyFactory()
2496 self.vapi.want_bfd_events()
Klement Sekerad3ba5152017-02-14 03:09:17 +01002497 self.pg0.enable_capture()
Klement Sekerab17dd962017-01-09 07:43:48 +01002498
2499 def tearDown(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002500 if not self.vpp_dead:
Jakub Grajciar4682feb2019-09-02 13:28:52 +02002501 self.vapi.want_bfd_events(enable_disable=False)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002502 self.vapi.collect_events() # clear the event queue
2503 super(BFDAuthOnOffTestCase, self).tearDown()
Klement Sekerab17dd962017-01-09 07:43:48 +01002504
2505 def test_auth_on_immediate(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002506 """turn auth on without disturbing session state (immediate)"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002507 key = self.factory.create_random_key(self)
2508 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002509 self.vpp_session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
Klement Sekerab17dd962017-01-09 07:43:48 +01002510 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002511 self.test_session = BFDTestSession(self, self.pg0, AF_INET)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002512 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002513 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002514 p = wait_for_bfd_packet(self)
2515 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002516 self.test_session.send_packet()
2517 self.vpp_session.activate_auth(key)
2518 self.test_session.bfd_key_id = self.vpp_session.bfd_key_id
2519 self.test_session.sha1_key = key
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002520 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002521 p = wait_for_bfd_packet(self)
2522 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002523 self.test_session.send_packet()
2524 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002525 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekerab17dd962017-01-09 07:43:48 +01002526
2527 def test_auth_off_immediate(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002528 """turn auth off without disturbing session state (immediate)"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002529 key = self.factory.create_random_key(self)
2530 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002531 self.vpp_session = VppBFDUDPSession(
2532 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2533 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002534 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002535 self.test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002536 self,
2537 self.pg0,
2538 AF_INET,
2539 sha1_key=key,
2540 bfd_key_id=self.vpp_session.bfd_key_id,
2541 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01002542 bfd_session_up(self)
2543 # self.vapi.want_bfd_events(enable_disable=0)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002544 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002545 p = wait_for_bfd_packet(self)
2546 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
2547 self.test_session.inc_seq_num()
Klement Sekerab17dd962017-01-09 07:43:48 +01002548 self.test_session.send_packet()
2549 self.vpp_session.deactivate_auth()
2550 self.test_session.bfd_key_id = None
2551 self.test_session.sha1_key = None
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002552 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002553 p = wait_for_bfd_packet(self)
2554 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
2555 self.test_session.inc_seq_num()
Klement Sekerab17dd962017-01-09 07:43:48 +01002556 self.test_session.send_packet()
2557 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002558 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekerab17dd962017-01-09 07:43:48 +01002559
2560 def test_auth_change_key_immediate(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002561 """change auth key without disturbing session state (immediate)"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002562 key1 = self.factory.create_random_key(self)
2563 key1.add_vpp_config()
2564 key2 = self.factory.create_random_key(self)
2565 key2.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002566 self.vpp_session = VppBFDUDPSession(
2567 self, self.pg0, self.pg0.remote_ip4, sha1_key=key1
2568 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002569 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002570 self.test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002571 self,
2572 self.pg0,
2573 AF_INET,
2574 sha1_key=key1,
2575 bfd_key_id=self.vpp_session.bfd_key_id,
2576 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01002577 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002578 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002579 p = wait_for_bfd_packet(self)
2580 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002581 self.test_session.send_packet()
2582 self.vpp_session.activate_auth(key2)
2583 self.test_session.bfd_key_id = self.vpp_session.bfd_key_id
2584 self.test_session.sha1_key = key2
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002585 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002586 p = wait_for_bfd_packet(self)
2587 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002588 self.test_session.send_packet()
2589 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002590 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekerab17dd962017-01-09 07:43:48 +01002591
2592 def test_auth_on_delayed(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002593 """turn auth on without disturbing session state (delayed)"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002594 key = self.factory.create_random_key(self)
2595 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002596 self.vpp_session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
Klement Sekerab17dd962017-01-09 07:43:48 +01002597 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002598 self.test_session = BFDTestSession(self, self.pg0, AF_INET)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002599 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002600 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002601 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002602 self.test_session.send_packet()
2603 self.vpp_session.activate_auth(key, delayed=True)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002604 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002605 p = wait_for_bfd_packet(self)
2606 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002607 self.test_session.send_packet()
2608 self.test_session.bfd_key_id = self.vpp_session.bfd_key_id
2609 self.test_session.sha1_key = key
2610 self.test_session.send_packet()
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002611 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002612 p = wait_for_bfd_packet(self)
2613 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002614 self.test_session.send_packet()
2615 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002616 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekerab17dd962017-01-09 07:43:48 +01002617
2618 def test_auth_off_delayed(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002619 """turn auth off without disturbing session state (delayed)"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002620 key = self.factory.create_random_key(self)
2621 key.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002622 self.vpp_session = VppBFDUDPSession(
2623 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2624 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002625 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002626 self.test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002627 self,
2628 self.pg0,
2629 AF_INET,
2630 sha1_key=key,
2631 bfd_key_id=self.vpp_session.bfd_key_id,
2632 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01002633 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002634 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002635 p = wait_for_bfd_packet(self)
2636 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002637 self.test_session.send_packet()
2638 self.vpp_session.deactivate_auth(delayed=True)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002639 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002640 p = wait_for_bfd_packet(self)
2641 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002642 self.test_session.send_packet()
2643 self.test_session.bfd_key_id = None
2644 self.test_session.sha1_key = None
2645 self.test_session.send_packet()
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002646 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002647 p = wait_for_bfd_packet(self)
2648 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002649 self.test_session.send_packet()
2650 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002651 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekerab17dd962017-01-09 07:43:48 +01002652
2653 def test_auth_change_key_delayed(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002654 """change auth key without disturbing session state (delayed)"""
Klement Sekerab17dd962017-01-09 07:43:48 +01002655 key1 = self.factory.create_random_key(self)
2656 key1.add_vpp_config()
2657 key2 = self.factory.create_random_key(self)
2658 key2.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002659 self.vpp_session = VppBFDUDPSession(
2660 self, self.pg0, self.pg0.remote_ip4, sha1_key=key1
2661 )
Klement Sekerab17dd962017-01-09 07:43:48 +01002662 self.vpp_session.add_vpp_config()
2663 self.vpp_session.admin_up()
2664 self.test_session = BFDTestSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002665 self,
2666 self.pg0,
2667 AF_INET,
2668 sha1_key=key1,
2669 bfd_key_id=self.vpp_session.bfd_key_id,
2670 )
Klement Sekerad3ba5152017-02-14 03:09:17 +01002671 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002672 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002673 p = wait_for_bfd_packet(self)
2674 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002675 self.test_session.send_packet()
2676 self.vpp_session.activate_auth(key2, delayed=True)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002677 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002678 p = wait_for_bfd_packet(self)
2679 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002680 self.test_session.send_packet()
2681 self.test_session.bfd_key_id = self.vpp_session.bfd_key_id
2682 self.test_session.sha1_key = key2
2683 self.test_session.send_packet()
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002684 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002685 p = wait_for_bfd_packet(self)
2686 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002687 self.test_session.send_packet()
2688 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002689 self.assert_equal(len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekera46a87ad2017-01-02 08:22:23 +01002690
Klement Sekera73884482017-02-23 09:26:30 +01002691
Andrew Yourtchenko06f32812021-01-14 10:19:08 +00002692@tag_run_solo
Klement Sekera73884482017-02-23 09:26:30 +01002693class BFDCLITestCase(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002694 """Bidirectional Forwarding Detection (BFD) (CLI)"""
2695
Klement Sekera73884482017-02-23 09:26:30 +01002696 pg0 = None
2697
2698 @classmethod
2699 def setUpClass(cls):
2700 super(BFDCLITestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -08002701 cls.vapi.cli("set log class bfd level debug")
Klement Sekera73884482017-02-23 09:26:30 +01002702 try:
2703 cls.create_pg_interfaces((0,))
2704 cls.pg0.config_ip4()
2705 cls.pg0.config_ip6()
2706 cls.pg0.resolve_arp()
2707 cls.pg0.resolve_ndp()
2708
2709 except Exception:
2710 super(BFDCLITestCase, cls).tearDownClass()
2711 raise
2712
Paul Vinciguerra8d991d92019-01-25 14:05:48 -08002713 @classmethod
2714 def tearDownClass(cls):
2715 super(BFDCLITestCase, cls).tearDownClass()
2716
Klement Sekera73884482017-02-23 09:26:30 +01002717 def setUp(self):
2718 super(BFDCLITestCase, self).setUp()
2719 self.factory = AuthKeyFactory()
2720 self.pg0.enable_capture()
2721
2722 def tearDown(self):
2723 try:
Jakub Grajciar4682feb2019-09-02 13:28:52 +02002724 self.vapi.want_bfd_events(enable_disable=False)
Klement Sekera73884482017-02-23 09:26:30 +01002725 except UnexpectedApiReturnValueError:
2726 # some tests aren't subscribed, so this is not an issue
2727 pass
2728 self.vapi.collect_events() # clear the event queue
2729 super(BFDCLITestCase, self).tearDown()
2730
2731 def cli_verify_no_response(self, cli):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002732 """execute a CLI, asserting that the response is empty"""
2733 self.assert_equal(self.vapi.cli(cli), "", "CLI command response")
Klement Sekera73884482017-02-23 09:26:30 +01002734
2735 def cli_verify_response(self, cli, expected):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002736 """execute a CLI, asserting that the response matches expectation"""
Jakub Grajciar4682feb2019-09-02 13:28:52 +02002737 try:
2738 reply = self.vapi.cli(cli)
2739 except CliFailedCommandError as cli_error:
2740 reply = str(cli_error)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002741 self.assert_equal(reply.strip(), expected, "CLI command response")
Klement Sekera73884482017-02-23 09:26:30 +01002742
2743 def test_show(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002744 """show commands"""
Klement Sekera73884482017-02-23 09:26:30 +01002745 k1 = self.factory.create_random_key(self)
2746 k1.add_vpp_config()
2747 k2 = self.factory.create_random_key(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002748 self, auth_type=BFDAuthType.meticulous_keyed_sha1
2749 )
Klement Sekera73884482017-02-23 09:26:30 +01002750 k2.add_vpp_config()
2751 s1 = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
2752 s1.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002753 s2 = VppBFDUDPSession(
2754 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6, sha1_key=k2
2755 )
Klement Sekera73884482017-02-23 09:26:30 +01002756 s2.add_vpp_config()
2757 self.logger.info(self.vapi.ppcli("show bfd keys"))
2758 self.logger.info(self.vapi.ppcli("show bfd sessions"))
2759 self.logger.info(self.vapi.ppcli("show bfd"))
2760
2761 def test_set_del_sha1_key(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002762 """set/delete SHA1 auth key"""
Klement Sekera73884482017-02-23 09:26:30 +01002763 k = self.factory.create_random_key(self)
2764 self.registry.register(k, self.logger)
2765 self.cli_verify_no_response(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002766 "bfd key set conf-key-id %s type keyed-sha1 secret %s"
2767 % (
2768 k.conf_key_id,
2769 "".join("{:02x}".format(scapy.compat.orb(c)) for c in k.key),
2770 )
2771 )
Klement Sekera73884482017-02-23 09:26:30 +01002772 self.assertTrue(k.query_vpp_config())
2773 self.vpp_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002774 self, self.pg0, self.pg0.remote_ip4, sha1_key=k
2775 )
Klement Sekera73884482017-02-23 09:26:30 +01002776 self.vpp_session.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002777 self.test_session = BFDTestSession(
2778 self, self.pg0, AF_INET, sha1_key=k, bfd_key_id=self.vpp_session.bfd_key_id
2779 )
Klement Sekera73884482017-02-23 09:26:30 +01002780 self.vapi.want_bfd_events()
2781 bfd_session_up(self)
2782 bfd_session_down(self)
2783 # try to replace the secret for the key - should fail because the key
2784 # is in-use
2785 k2 = self.factory.create_random_key(self)
2786 self.cli_verify_response(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002787 "bfd key set conf-key-id %s type keyed-sha1 secret %s"
2788 % (
2789 k.conf_key_id,
2790 "".join("{:02x}".format(scapy.compat.orb(c)) for c in k2.key),
2791 ),
Klement Sekera73884482017-02-23 09:26:30 +01002792 "bfd key set: `bfd_auth_set_key' API call failed, "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002793 "rv=-103:BFD object in use",
2794 )
Klement Sekera73884482017-02-23 09:26:30 +01002795 # manipulating the session using old secret should still work
2796 bfd_session_up(self)
2797 bfd_session_down(self)
2798 self.vpp_session.remove_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002799 self.cli_verify_no_response("bfd key del conf-key-id %s" % k.conf_key_id)
Klement Sekera73884482017-02-23 09:26:30 +01002800 self.assertFalse(k.query_vpp_config())
2801
2802 def test_set_del_meticulous_sha1_key(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002803 """set/delete meticulous SHA1 auth key"""
Klement Sekera73884482017-02-23 09:26:30 +01002804 k = self.factory.create_random_key(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002805 self, auth_type=BFDAuthType.meticulous_keyed_sha1
2806 )
Klement Sekera73884482017-02-23 09:26:30 +01002807 self.registry.register(k, self.logger)
2808 self.cli_verify_no_response(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002809 "bfd key set conf-key-id %s type meticulous-keyed-sha1 secret %s"
2810 % (
2811 k.conf_key_id,
2812 "".join("{:02x}".format(scapy.compat.orb(c)) for c in k.key),
2813 )
2814 )
Klement Sekera73884482017-02-23 09:26:30 +01002815 self.assertTrue(k.query_vpp_config())
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002816 self.vpp_session = VppBFDUDPSession(
2817 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6, sha1_key=k
2818 )
Klement Sekera73884482017-02-23 09:26:30 +01002819 self.vpp_session.add_vpp_config()
2820 self.vpp_session.admin_up()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002821 self.test_session = BFDTestSession(
2822 self, self.pg0, AF_INET6, sha1_key=k, bfd_key_id=self.vpp_session.bfd_key_id
2823 )
Klement Sekera73884482017-02-23 09:26:30 +01002824 self.vapi.want_bfd_events()
2825 bfd_session_up(self)
2826 bfd_session_down(self)
2827 # try to replace the secret for the key - should fail because the key
2828 # is in-use
2829 k2 = self.factory.create_random_key(self)
2830 self.cli_verify_response(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002831 "bfd key set conf-key-id %s type keyed-sha1 secret %s"
2832 % (
2833 k.conf_key_id,
2834 "".join("{:02x}".format(scapy.compat.orb(c)) for c in k2.key),
2835 ),
Klement Sekera73884482017-02-23 09:26:30 +01002836 "bfd key set: `bfd_auth_set_key' API call failed, "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002837 "rv=-103:BFD object in use",
2838 )
Klement Sekera73884482017-02-23 09:26:30 +01002839 # manipulating the session using old secret should still work
2840 bfd_session_up(self)
2841 bfd_session_down(self)
2842 self.vpp_session.remove_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002843 self.cli_verify_no_response("bfd key del conf-key-id %s" % k.conf_key_id)
Klement Sekera73884482017-02-23 09:26:30 +01002844 self.assertFalse(k.query_vpp_config())
2845
2846 def test_add_mod_del_bfd_udp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002847 """create/modify/delete IPv4 BFD UDP session"""
2848 vpp_session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
Klement Sekera73884482017-02-23 09:26:30 +01002849 self.registry.register(vpp_session, self.logger)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002850 cli_add_cmd = (
2851 "bfd udp session add interface %s local-addr %s "
2852 "peer-addr %s desired-min-tx %s required-min-rx %s "
2853 "detect-mult %s"
2854 % (
2855 self.pg0.name,
2856 self.pg0.local_ip4,
2857 self.pg0.remote_ip4,
2858 vpp_session.desired_min_tx,
2859 vpp_session.required_min_rx,
2860 vpp_session.detect_mult,
2861 )
2862 )
Klement Sekera73884482017-02-23 09:26:30 +01002863 self.cli_verify_no_response(cli_add_cmd)
2864 # 2nd add should fail
2865 self.cli_verify_response(
2866 cli_add_cmd,
2867 "bfd udp session add: `bfd_add_add_session' API call"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002868 " failed, rv=-101:Duplicate BFD object",
2869 )
Klement Sekera73884482017-02-23 09:26:30 +01002870 verify_bfd_session_config(self, vpp_session)
2871 mod_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002872 self,
2873 self.pg0,
2874 self.pg0.remote_ip4,
Klement Sekera73884482017-02-23 09:26:30 +01002875 required_min_rx=2 * vpp_session.required_min_rx,
2876 desired_min_tx=3 * vpp_session.desired_min_tx,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002877 detect_mult=4 * vpp_session.detect_mult,
2878 )
Klement Sekera73884482017-02-23 09:26:30 +01002879 self.cli_verify_no_response(
2880 "bfd udp session mod interface %s local-addr %s peer-addr %s "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002881 "desired-min-tx %s required-min-rx %s detect-mult %s"
2882 % (
2883 self.pg0.name,
2884 self.pg0.local_ip4,
2885 self.pg0.remote_ip4,
2886 mod_session.desired_min_tx,
2887 mod_session.required_min_rx,
2888 mod_session.detect_mult,
2889 )
2890 )
Klement Sekera73884482017-02-23 09:26:30 +01002891 verify_bfd_session_config(self, mod_session)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002892 cli_del_cmd = (
2893 "bfd udp session del interface %s local-addr %s "
2894 "peer-addr %s" % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4)
2895 )
Klement Sekera73884482017-02-23 09:26:30 +01002896 self.cli_verify_no_response(cli_del_cmd)
2897 # 2nd del is expected to fail
2898 self.cli_verify_response(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002899 cli_del_cmd,
2900 "bfd udp session del: `bfd_udp_del_session' API call"
2901 " failed, rv=-102:No such BFD object",
2902 )
Klement Sekera73884482017-02-23 09:26:30 +01002903 self.assertFalse(vpp_session.query_vpp_config())
2904
2905 def test_add_mod_del_bfd_udp6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002906 """create/modify/delete IPv6 BFD UDP session"""
2907 vpp_session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip6, af=AF_INET6)
Klement Sekera73884482017-02-23 09:26:30 +01002908 self.registry.register(vpp_session, self.logger)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002909 cli_add_cmd = (
2910 "bfd udp session add interface %s local-addr %s "
2911 "peer-addr %s desired-min-tx %s required-min-rx %s "
2912 "detect-mult %s"
2913 % (
2914 self.pg0.name,
2915 self.pg0.local_ip6,
2916 self.pg0.remote_ip6,
2917 vpp_session.desired_min_tx,
2918 vpp_session.required_min_rx,
2919 vpp_session.detect_mult,
2920 )
2921 )
Klement Sekera73884482017-02-23 09:26:30 +01002922 self.cli_verify_no_response(cli_add_cmd)
2923 # 2nd add should fail
2924 self.cli_verify_response(
2925 cli_add_cmd,
2926 "bfd udp session add: `bfd_add_add_session' API call"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002927 " failed, rv=-101:Duplicate BFD object",
2928 )
Klement Sekera73884482017-02-23 09:26:30 +01002929 verify_bfd_session_config(self, vpp_session)
2930 mod_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002931 self,
2932 self.pg0,
2933 self.pg0.remote_ip6,
2934 af=AF_INET6,
Klement Sekera73884482017-02-23 09:26:30 +01002935 required_min_rx=2 * vpp_session.required_min_rx,
2936 desired_min_tx=3 * vpp_session.desired_min_tx,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002937 detect_mult=4 * vpp_session.detect_mult,
2938 )
Klement Sekera73884482017-02-23 09:26:30 +01002939 self.cli_verify_no_response(
2940 "bfd udp session mod interface %s local-addr %s peer-addr %s "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002941 "desired-min-tx %s required-min-rx %s detect-mult %s"
2942 % (
2943 self.pg0.name,
2944 self.pg0.local_ip6,
2945 self.pg0.remote_ip6,
2946 mod_session.desired_min_tx,
2947 mod_session.required_min_rx,
2948 mod_session.detect_mult,
2949 )
2950 )
Klement Sekera73884482017-02-23 09:26:30 +01002951 verify_bfd_session_config(self, mod_session)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002952 cli_del_cmd = (
2953 "bfd udp session del interface %s local-addr %s "
2954 "peer-addr %s" % (self.pg0.name, self.pg0.local_ip6, self.pg0.remote_ip6)
2955 )
Klement Sekera73884482017-02-23 09:26:30 +01002956 self.cli_verify_no_response(cli_del_cmd)
2957 # 2nd del is expected to fail
2958 self.cli_verify_response(
2959 cli_del_cmd,
2960 "bfd udp session del: `bfd_udp_del_session' API call"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002961 " failed, rv=-102:No such BFD object",
2962 )
Klement Sekera73884482017-02-23 09:26:30 +01002963 self.assertFalse(vpp_session.query_vpp_config())
2964
2965 def test_add_mod_del_bfd_udp_auth(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002966 """create/modify/delete IPv4 BFD UDP session (authenticated)"""
Klement Sekera73884482017-02-23 09:26:30 +01002967 key = self.factory.create_random_key(self)
2968 key.add_vpp_config()
2969 vpp_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002970 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
2971 )
Klement Sekera73884482017-02-23 09:26:30 +01002972 self.registry.register(vpp_session, self.logger)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002973 cli_add_cmd = (
2974 "bfd udp session add interface %s local-addr %s "
2975 "peer-addr %s desired-min-tx %s required-min-rx %s "
2976 "detect-mult %s conf-key-id %s bfd-key-id %s"
2977 % (
2978 self.pg0.name,
2979 self.pg0.local_ip4,
2980 self.pg0.remote_ip4,
2981 vpp_session.desired_min_tx,
2982 vpp_session.required_min_rx,
2983 vpp_session.detect_mult,
2984 key.conf_key_id,
2985 vpp_session.bfd_key_id,
2986 )
2987 )
Klement Sekera73884482017-02-23 09:26:30 +01002988 self.cli_verify_no_response(cli_add_cmd)
2989 # 2nd add should fail
2990 self.cli_verify_response(
2991 cli_add_cmd,
2992 "bfd udp session add: `bfd_add_add_session' API call"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002993 " failed, rv=-101:Duplicate BFD object",
2994 )
Klement Sekera73884482017-02-23 09:26:30 +01002995 verify_bfd_session_config(self, vpp_session)
2996 mod_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002997 self,
2998 self.pg0,
2999 self.pg0.remote_ip4,
3000 sha1_key=key,
Klement Sekera73884482017-02-23 09:26:30 +01003001 bfd_key_id=vpp_session.bfd_key_id,
3002 required_min_rx=2 * vpp_session.required_min_rx,
3003 desired_min_tx=3 * vpp_session.desired_min_tx,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003004 detect_mult=4 * vpp_session.detect_mult,
3005 )
Klement Sekera73884482017-02-23 09:26:30 +01003006 self.cli_verify_no_response(
3007 "bfd udp session mod interface %s local-addr %s peer-addr %s "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003008 "desired-min-tx %s required-min-rx %s detect-mult %s"
3009 % (
3010 self.pg0.name,
3011 self.pg0.local_ip4,
3012 self.pg0.remote_ip4,
3013 mod_session.desired_min_tx,
3014 mod_session.required_min_rx,
3015 mod_session.detect_mult,
3016 )
3017 )
Klement Sekera73884482017-02-23 09:26:30 +01003018 verify_bfd_session_config(self, mod_session)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003019 cli_del_cmd = (
3020 "bfd udp session del interface %s local-addr %s "
3021 "peer-addr %s" % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4)
3022 )
Klement Sekera73884482017-02-23 09:26:30 +01003023 self.cli_verify_no_response(cli_del_cmd)
3024 # 2nd del is expected to fail
3025 self.cli_verify_response(
3026 cli_del_cmd,
3027 "bfd udp session del: `bfd_udp_del_session' API call"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003028 " failed, rv=-102:No such BFD object",
3029 )
Klement Sekera73884482017-02-23 09:26:30 +01003030 self.assertFalse(vpp_session.query_vpp_config())
3031
3032 def test_add_mod_del_bfd_udp6_auth(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003033 """create/modify/delete IPv6 BFD UDP session (authenticated)"""
Klement Sekera73884482017-02-23 09:26:30 +01003034 key = self.factory.create_random_key(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003035 self, auth_type=BFDAuthType.meticulous_keyed_sha1
3036 )
Klement Sekera73884482017-02-23 09:26:30 +01003037 key.add_vpp_config()
3038 vpp_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003039 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6, sha1_key=key
3040 )
Klement Sekera73884482017-02-23 09:26:30 +01003041 self.registry.register(vpp_session, self.logger)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003042 cli_add_cmd = (
3043 "bfd udp session add interface %s local-addr %s "
3044 "peer-addr %s desired-min-tx %s required-min-rx %s "
3045 "detect-mult %s conf-key-id %s bfd-key-id %s"
3046 % (
3047 self.pg0.name,
3048 self.pg0.local_ip6,
3049 self.pg0.remote_ip6,
3050 vpp_session.desired_min_tx,
3051 vpp_session.required_min_rx,
3052 vpp_session.detect_mult,
3053 key.conf_key_id,
3054 vpp_session.bfd_key_id,
3055 )
3056 )
Klement Sekera73884482017-02-23 09:26:30 +01003057 self.cli_verify_no_response(cli_add_cmd)
3058 # 2nd add should fail
3059 self.cli_verify_response(
3060 cli_add_cmd,
3061 "bfd udp session add: `bfd_add_add_session' API call"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003062 " failed, rv=-101:Duplicate BFD object",
3063 )
Klement Sekera73884482017-02-23 09:26:30 +01003064 verify_bfd_session_config(self, vpp_session)
3065 mod_session = VppBFDUDPSession(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003066 self,
3067 self.pg0,
3068 self.pg0.remote_ip6,
3069 af=AF_INET6,
3070 sha1_key=key,
Klement Sekera73884482017-02-23 09:26:30 +01003071 bfd_key_id=vpp_session.bfd_key_id,
3072 required_min_rx=2 * vpp_session.required_min_rx,
3073 desired_min_tx=3 * vpp_session.desired_min_tx,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003074 detect_mult=4 * vpp_session.detect_mult,
3075 )
Klement Sekera73884482017-02-23 09:26:30 +01003076 self.cli_verify_no_response(
3077 "bfd udp session mod interface %s local-addr %s peer-addr %s "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003078 "desired-min-tx %s required-min-rx %s detect-mult %s"
3079 % (
3080 self.pg0.name,
3081 self.pg0.local_ip6,
3082 self.pg0.remote_ip6,
3083 mod_session.desired_min_tx,
3084 mod_session.required_min_rx,
3085 mod_session.detect_mult,
3086 )
3087 )
Klement Sekera73884482017-02-23 09:26:30 +01003088 verify_bfd_session_config(self, mod_session)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003089 cli_del_cmd = (
3090 "bfd udp session del interface %s local-addr %s "
3091 "peer-addr %s" % (self.pg0.name, self.pg0.local_ip6, self.pg0.remote_ip6)
3092 )
Klement Sekera73884482017-02-23 09:26:30 +01003093 self.cli_verify_no_response(cli_del_cmd)
3094 # 2nd del is expected to fail
3095 self.cli_verify_response(
3096 cli_del_cmd,
3097 "bfd udp session del: `bfd_udp_del_session' API call"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003098 " failed, rv=-102:No such BFD object",
3099 )
Klement Sekera73884482017-02-23 09:26:30 +01003100 self.assertFalse(vpp_session.query_vpp_config())
3101
3102 def test_auth_on_off(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003103 """turn authentication on and off"""
Klement Sekera73884482017-02-23 09:26:30 +01003104 key = self.factory.create_random_key(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003105 self, auth_type=BFDAuthType.meticulous_keyed_sha1
3106 )
Klement Sekera73884482017-02-23 09:26:30 +01003107 key.add_vpp_config()
3108 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003109 auth_session = VppBFDUDPSession(
3110 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
3111 )
Klement Sekera73884482017-02-23 09:26:30 +01003112 session.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003113 cli_activate = (
3114 "bfd udp session auth activate interface %s local-addr %s "
3115 "peer-addr %s conf-key-id %s bfd-key-id %s"
3116 % (
3117 self.pg0.name,
3118 self.pg0.local_ip4,
3119 self.pg0.remote_ip4,
3120 key.conf_key_id,
3121 auth_session.bfd_key_id,
3122 )
3123 )
Klement Sekera73884482017-02-23 09:26:30 +01003124 self.cli_verify_no_response(cli_activate)
3125 verify_bfd_session_config(self, auth_session)
3126 self.cli_verify_no_response(cli_activate)
3127 verify_bfd_session_config(self, auth_session)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003128 cli_deactivate = (
3129 "bfd udp session auth deactivate interface %s local-addr %s "
3130 "peer-addr %s " % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4)
3131 )
Klement Sekera73884482017-02-23 09:26:30 +01003132 self.cli_verify_no_response(cli_deactivate)
3133 verify_bfd_session_config(self, session)
3134 self.cli_verify_no_response(cli_deactivate)
3135 verify_bfd_session_config(self, session)
3136
3137 def test_auth_on_off_delayed(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003138 """turn authentication on and off (delayed)"""
Klement Sekera73884482017-02-23 09:26:30 +01003139 key = self.factory.create_random_key(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003140 self, auth_type=BFDAuthType.meticulous_keyed_sha1
3141 )
Klement Sekera73884482017-02-23 09:26:30 +01003142 key.add_vpp_config()
3143 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003144 auth_session = VppBFDUDPSession(
3145 self, self.pg0, self.pg0.remote_ip4, sha1_key=key
3146 )
Klement Sekera73884482017-02-23 09:26:30 +01003147 session.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003148 cli_activate = (
3149 "bfd udp session auth activate interface %s local-addr %s "
3150 "peer-addr %s conf-key-id %s bfd-key-id %s delayed yes"
3151 % (
3152 self.pg0.name,
3153 self.pg0.local_ip4,
3154 self.pg0.remote_ip4,
3155 key.conf_key_id,
3156 auth_session.bfd_key_id,
3157 )
3158 )
Klement Sekera73884482017-02-23 09:26:30 +01003159 self.cli_verify_no_response(cli_activate)
3160 verify_bfd_session_config(self, auth_session)
3161 self.cli_verify_no_response(cli_activate)
3162 verify_bfd_session_config(self, auth_session)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003163 cli_deactivate = (
3164 "bfd udp session auth deactivate interface %s local-addr %s "
3165 "peer-addr %s delayed yes"
Klement Sekera73884482017-02-23 09:26:30 +01003166 % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003167 )
Klement Sekera73884482017-02-23 09:26:30 +01003168 self.cli_verify_no_response(cli_deactivate)
3169 verify_bfd_session_config(self, session)
3170 self.cli_verify_no_response(cli_deactivate)
3171 verify_bfd_session_config(self, session)
3172
3173 def test_admin_up_down(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003174 """put session admin-up and admin-down"""
Klement Sekera73884482017-02-23 09:26:30 +01003175 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
3176 session.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003177 cli_down = (
3178 "bfd udp session set-flags admin down interface %s local-addr %s "
3179 "peer-addr %s " % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4)
3180 )
3181 cli_up = (
3182 "bfd udp session set-flags admin up interface %s local-addr %s "
3183 "peer-addr %s " % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4)
3184 )
Klement Sekera73884482017-02-23 09:26:30 +01003185 self.cli_verify_no_response(cli_down)
3186 verify_bfd_session_config(self, session, state=BFDState.admin_down)
3187 self.cli_verify_no_response(cli_up)
3188 verify_bfd_session_config(self, session, state=BFDState.down)
3189
3190 def test_set_del_udp_echo_source(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003191 """set/del udp echo source"""
Klement Sekerab9ef2732018-06-24 22:49:33 +02003192 self.create_loopback_interfaces(1)
Klement Sekera73884482017-02-23 09:26:30 +01003193 self.loopback0 = self.lo_interfaces[0]
3194 self.loopback0.admin_up()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003195 self.cli_verify_response("show bfd echo-source", "UDP echo source is not set.")
Klement Sekera73884482017-02-23 09:26:30 +01003196 cli_set = "bfd udp echo-source set interface %s" % self.loopback0.name
3197 self.cli_verify_no_response(cli_set)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003198 self.cli_verify_response(
3199 "show bfd echo-source",
3200 "UDP echo source is: %s\n"
3201 "IPv4 address usable as echo source: none\n"
3202 "IPv6 address usable as echo source: none" % self.loopback0.name,
3203 )
Klement Sekera73884482017-02-23 09:26:30 +01003204 self.loopback0.config_ip4()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003205 echo_ip4 = str(
3206 ipaddress.IPv4Address(
3207 int(ipaddress.IPv4Address(self.loopback0.local_ip4)) ^ 1
3208 )
3209 )
3210 self.cli_verify_response(
3211 "show bfd echo-source",
3212 "UDP echo source is: %s\n"
3213 "IPv4 address usable as echo source: %s\n"
3214 "IPv6 address usable as echo source: none"
3215 % (self.loopback0.name, echo_ip4),
3216 )
3217 echo_ip6 = str(
3218 ipaddress.IPv6Address(
3219 int(ipaddress.IPv6Address(self.loopback0.local_ip6)) ^ 1
3220 )
3221 )
Klement Sekera73884482017-02-23 09:26:30 +01003222 self.loopback0.config_ip6()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003223 self.cli_verify_response(
3224 "show bfd echo-source",
3225 "UDP echo source is: %s\n"
3226 "IPv4 address usable as echo source: %s\n"
3227 "IPv6 address usable as echo source: %s"
3228 % (self.loopback0.name, echo_ip4, echo_ip6),
3229 )
Klement Sekera73884482017-02-23 09:26:30 +01003230 cli_del = "bfd udp echo-source del"
3231 self.cli_verify_no_response(cli_del)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003232 self.cli_verify_response("show bfd echo-source", "UDP echo source is not set.")
Klement Sekera73884482017-02-23 09:26:30 +01003233
Jakub Grajciar4682feb2019-09-02 13:28:52 +02003234
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003235if __name__ == "__main__":
Klement Sekera0e3c0de2016-09-29 14:43:44 +02003236 unittest.main(testRunner=VppTestRunner)