blob: 71904a89f7f646cdbcdf56ddb5678ecd8f39ec70 [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
Paul Vinciguerra00671cf2018-11-25 12:47:04 -08007import hashlib
Paul Vinciguerra2f156312020-05-02 22:34:40 -04008import ipaddress
Paul Vinciguerra090096b2020-12-03 00:42:46 -05009import reprlib
Klement Sekera0e3c0de2016-09-29 14:43:44 +020010import time
Paul Vinciguerra00671cf2018-11-25 12:47:04 -080011import unittest
Klement Sekera239790f2017-02-16 10:53:53 +010012from random import randint, shuffle, getrandbits
Klement Sekera73884482017-02-23 09:26:30 +010013from socket import AF_INET, AF_INET6, inet_ntop
Paul Vinciguerra00671cf2018-11-25 12:47:04 -080014from struct import pack, unpack
15
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 Sekerad3ba5152017-02-14 03:09:17 +010022from bfd import VppBFDAuthKey, BFD, BFDAuthType, VppBFDUDPSession, \
Klement Sekera239790f2017-02-16 10:53:53 +010023 BFDDiagCode, BFDState, BFD_vpp_echo
Klement Sekera87134932017-03-07 11:39:27 +010024from framework import VppTestCase, VppTestRunner, running_extended_tests
Andrew Yourtchenko06f32812021-01-14 10:19:08 +000025from framework import tag_run_solo
Klement Sekera0e3c0de2016-09-29 14:43:44 +020026from util import ppp
Neale Rannsc0a93142018-09-05 15:42:26 -070027from vpp_ip import DpoProto
28from vpp_ip_route import VppIpRoute, VppRoutePath
Paul Vinciguerra00671cf2018-11-25 12:47:04 -080029from vpp_lo_interface import VppLoInterface
Jakub Grajciar4682feb2019-09-02 13:28:52 +020030from vpp_papi_provider import UnexpectedApiReturnValueError, \
31 CliFailedCommandError
Paul Vinciguerra00671cf2018-11-25 12:47:04 -080032from vpp_pg_interface import CaptureTimeoutError, is_ipv6_misc
Neale Ranns52cd4962019-06-05 10:28:17 +000033from vpp_gre_interface import VppGreInterface
Jakub Grajciar4682feb2019-09-02 13:28:52 +020034from vpp_papi import VppEnum
Klement Sekera0e3c0de2016-09-29 14:43:44 +020035
Klement Sekerad3ba5152017-02-14 03:09:17 +010036USEC_IN_SEC = 1000000
Klement Sekera3e0a3562016-12-19 09:05:21 +010037
Klement Sekera0e3c0de2016-09-29 14:43:44 +020038
Klement Sekerab17dd962017-01-09 07:43:48 +010039class AuthKeyFactory(object):
40 """Factory class for creating auth keys with unique conf key ID"""
41
42 def __init__(self):
43 self._conf_key_ids = {}
44
45 def create_random_key(self, test, auth_type=BFDAuthType.keyed_sha1):
Klement Sekerad3ba5152017-02-14 03:09:17 +010046 """ create a random key with unique conf key id """
Klement Sekerab17dd962017-01-09 07:43:48 +010047 conf_key_id = randint(0, 0xFFFFFFFF)
48 while conf_key_id in self._conf_key_ids:
49 conf_key_id = randint(0, 0xFFFFFFFF)
50 self._conf_key_ids[conf_key_id] = 1
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -070051 key = scapy.compat.raw(
52 bytearray([randint(0, 255) for _ in range(randint(1, 20))]))
Klement Sekerab17dd962017-01-09 07:43:48 +010053 return VppBFDAuthKey(test=test, auth_type=auth_type,
54 conf_key_id=conf_key_id, key=key)
55
56
Klement Sekerae4504c62016-12-08 10:16:41 +010057class BFDAPITestCase(VppTestCase):
58 """Bidirectional Forwarding Detection (BFD) - API"""
Klement Sekera0e3c0de2016-09-29 14:43:44 +020059
Klement Sekerad3ba5152017-02-14 03:09:17 +010060 pg0 = None
61 pg1 = None
62
Klement Sekera0e3c0de2016-09-29 14:43:44 +020063 @classmethod
64 def setUpClass(cls):
Klement Sekerae4504c62016-12-08 10:16:41 +010065 super(BFDAPITestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -080066 cls.vapi.cli("set log class bfd level debug")
Klement Sekera0e3c0de2016-09-29 14:43:44 +020067 try:
Klement Sekera10db26f2017-01-11 08:16:53 +010068 cls.create_pg_interfaces(range(2))
69 for i in cls.pg_interfaces:
70 i.config_ip4()
Klement Sekerab17dd962017-01-09 07:43:48 +010071 i.config_ip6()
Klement Sekera10db26f2017-01-11 08:16:53 +010072 i.resolve_arp()
Klement Sekera0e3c0de2016-09-29 14:43:44 +020073
74 except Exception:
Klement Sekerae4504c62016-12-08 10:16:41 +010075 super(BFDAPITestCase, cls).tearDownClass()
Klement Sekera0e3c0de2016-09-29 14:43:44 +020076 raise
77
Paul Vinciguerra8d991d92019-01-25 14:05:48 -080078 @classmethod
79 def tearDownClass(cls):
80 super(BFDAPITestCase, cls).tearDownClass()
81
Klement Sekerab17dd962017-01-09 07:43:48 +010082 def setUp(self):
83 super(BFDAPITestCase, self).setUp()
84 self.factory = AuthKeyFactory()
85
Klement Sekera0e3c0de2016-09-29 14:43:44 +020086 def test_add_bfd(self):
87 """ create a BFD session """
88 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
89 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +010090 self.logger.debug("Session state is %s", session.state)
Klement Sekera0e3c0de2016-09-29 14:43:44 +020091 session.remove_vpp_config()
Klement Sekera0e3c0de2016-09-29 14:43:44 +020092 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +010093 self.logger.debug("Session state is %s", session.state)
Klement Sekera0e3c0de2016-09-29 14:43:44 +020094 session.remove_vpp_config()
95
96 def test_double_add(self):
97 """ create the same BFD session twice (negative case) """
98 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
99 session.add_vpp_config()
Klement Sekerae0545ef2017-01-25 08:00:40 +0100100
Klement Sekera7d6afb32018-11-08 11:52:04 +0100101 with self.vapi.assert_negative_api_retval():
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200102 session.add_vpp_config()
Klement Sekerae0545ef2017-01-25 08:00:40 +0100103
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200104 session.remove_vpp_config()
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200105
Klement Sekerab17dd962017-01-09 07:43:48 +0100106 def test_add_bfd6(self):
107 """ create IPv6 BFD session """
108 session = VppBFDUDPSession(
109 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6)
110 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100111 self.logger.debug("Session state is %s", session.state)
Klement Sekerab17dd962017-01-09 07:43:48 +0100112 session.remove_vpp_config()
113 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100114 self.logger.debug("Session state is %s", session.state)
Klement Sekerab17dd962017-01-09 07:43:48 +0100115 session.remove_vpp_config()
116
Klement Sekeraa57a9702017-02-02 06:58:07 +0100117 def test_mod_bfd(self):
118 """ modify BFD session parameters """
119 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4,
120 desired_min_tx=50000,
121 required_min_rx=10000,
122 detect_mult=1)
123 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100124 s = session.get_bfd_udp_session_dump_entry()
Klement Sekeraa57a9702017-02-02 06:58:07 +0100125 self.assert_equal(session.desired_min_tx,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100126 s.desired_min_tx,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100127 "desired min transmit interval")
128 self.assert_equal(session.required_min_rx,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100129 s.required_min_rx,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100130 "required min receive interval")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100131 self.assert_equal(session.detect_mult, s.detect_mult, "detect mult")
Klement Sekeraa57a9702017-02-02 06:58:07 +0100132 session.modify_parameters(desired_min_tx=session.desired_min_tx * 2,
133 required_min_rx=session.required_min_rx * 2,
134 detect_mult=session.detect_mult * 2)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100135 s = session.get_bfd_udp_session_dump_entry()
Klement Sekeraa57a9702017-02-02 06:58:07 +0100136 self.assert_equal(session.desired_min_tx,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100137 s.desired_min_tx,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100138 "desired min transmit interval")
139 self.assert_equal(session.required_min_rx,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100140 s.required_min_rx,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100141 "required min receive interval")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100142 self.assert_equal(session.detect_mult, s.detect_mult, "detect mult")
Klement Sekeraa57a9702017-02-02 06:58:07 +0100143
Klement Sekerab17dd962017-01-09 07:43:48 +0100144 def test_add_sha1_keys(self):
145 """ add SHA1 keys """
146 key_count = 10
147 keys = [self.factory.create_random_key(
148 self) for i in range(0, key_count)]
149 for key in keys:
150 self.assertFalse(key.query_vpp_config())
151 for key in keys:
152 key.add_vpp_config()
153 for key in keys:
154 self.assertTrue(key.query_vpp_config())
155 # remove randomly
snaramre73aff472019-12-02 05:49:28 +0000156 indexes = list(range(key_count))
Klement Sekerad3ba5152017-02-14 03:09:17 +0100157 shuffle(indexes)
Klement Sekerab17dd962017-01-09 07:43:48 +0100158 removed = []
159 for i in indexes:
160 key = keys[i]
161 key.remove_vpp_config()
162 removed.append(i)
163 for j in range(key_count):
164 key = keys[j]
165 if j in removed:
166 self.assertFalse(key.query_vpp_config())
167 else:
168 self.assertTrue(key.query_vpp_config())
169 # should be removed now
170 for key in keys:
171 self.assertFalse(key.query_vpp_config())
172 # add back and remove again
173 for key in keys:
174 key.add_vpp_config()
175 for key in keys:
176 self.assertTrue(key.query_vpp_config())
177 for key in keys:
178 key.remove_vpp_config()
179 for key in keys:
180 self.assertFalse(key.query_vpp_config())
181
182 def test_add_bfd_sha1(self):
183 """ create a BFD session (SHA1) """
184 key = self.factory.create_random_key(self)
185 key.add_vpp_config()
186 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4,
187 sha1_key=key)
188 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100189 self.logger.debug("Session state is %s", session.state)
Klement Sekerab17dd962017-01-09 07:43:48 +0100190 session.remove_vpp_config()
191 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100192 self.logger.debug("Session state is %s", session.state)
Klement Sekerab17dd962017-01-09 07:43:48 +0100193 session.remove_vpp_config()
194
195 def test_double_add_sha1(self):
196 """ create the same BFD session twice (negative case) (SHA1) """
197 key = self.factory.create_random_key(self)
198 key.add_vpp_config()
199 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4,
200 sha1_key=key)
201 session.add_vpp_config()
202 with self.assertRaises(Exception):
203 session.add_vpp_config()
204
Klement Sekerad3ba5152017-02-14 03:09:17 +0100205 def test_add_auth_nonexistent_key(self):
Klement Sekerab17dd962017-01-09 07:43:48 +0100206 """ create BFD session using non-existent SHA1 (negative case) """
207 session = VppBFDUDPSession(
208 self, self.pg0, self.pg0.remote_ip4,
209 sha1_key=self.factory.create_random_key(self))
210 with self.assertRaises(Exception):
211 session.add_vpp_config()
212
213 def test_shared_sha1_key(self):
214 """ share single SHA1 key between multiple BFD sessions """
215 key = self.factory.create_random_key(self)
216 key.add_vpp_config()
217 sessions = [
218 VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4,
219 sha1_key=key),
220 VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip6,
221 sha1_key=key, af=AF_INET6),
222 VppBFDUDPSession(self, self.pg1, self.pg1.remote_ip4,
223 sha1_key=key),
224 VppBFDUDPSession(self, self.pg1, self.pg1.remote_ip6,
225 sha1_key=key, af=AF_INET6)]
226 for s in sessions:
227 s.add_vpp_config()
228 removed = 0
229 for s in sessions:
230 e = key.get_bfd_auth_keys_dump_entry()
231 self.assert_equal(e.use_count, len(sessions) - removed,
232 "Use count for shared key")
233 s.remove_vpp_config()
234 removed += 1
235 e = key.get_bfd_auth_keys_dump_entry()
236 self.assert_equal(e.use_count, len(sessions) - removed,
237 "Use count for shared key")
238
239 def test_activate_auth(self):
240 """ activate SHA1 authentication """
241 key = self.factory.create_random_key(self)
242 key.add_vpp_config()
243 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
244 session.add_vpp_config()
245 session.activate_auth(key)
246
247 def test_deactivate_auth(self):
248 """ deactivate SHA1 authentication """
249 key = self.factory.create_random_key(self)
250 key.add_vpp_config()
251 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
252 session.add_vpp_config()
253 session.activate_auth(key)
254 session.deactivate_auth()
255
256 def test_change_key(self):
Klement Sekeraa57a9702017-02-02 06:58:07 +0100257 """ change SHA1 key """
Klement Sekerab17dd962017-01-09 07:43:48 +0100258 key1 = self.factory.create_random_key(self)
259 key2 = self.factory.create_random_key(self)
260 while key2.conf_key_id == key1.conf_key_id:
261 key2 = self.factory.create_random_key(self)
262 key1.add_vpp_config()
263 key2.add_vpp_config()
264 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4,
265 sha1_key=key1)
266 session.add_vpp_config()
267 session.activate_auth(key2)
Klement Sekera10db26f2017-01-11 08:16:53 +0100268
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700269 def test_set_del_udp_echo_source(self):
270 """ set/del udp echo source """
271 self.create_loopback_interfaces(1)
272 self.loopback0 = self.lo_interfaces[0]
273 self.loopback0.admin_up()
274 echo_source = self.vapi.bfd_udp_get_echo_source()
275 self.assertFalse(echo_source.is_set)
276 self.assertFalse(echo_source.have_usable_ip4)
277 self.assertFalse(echo_source.have_usable_ip6)
278
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200279 self.vapi.bfd_udp_set_echo_source(
280 sw_if_index=self.loopback0.sw_if_index)
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700281 echo_source = self.vapi.bfd_udp_get_echo_source()
282 self.assertTrue(echo_source.is_set)
283 self.assertEqual(echo_source.sw_if_index, self.loopback0.sw_if_index)
284 self.assertFalse(echo_source.have_usable_ip4)
285 self.assertFalse(echo_source.have_usable_ip6)
286
287 self.loopback0.config_ip4()
Paul Vinciguerra2f156312020-05-02 22:34:40 -0400288 echo_ip4 = ipaddress.IPv4Address(int(ipaddress.IPv4Address(
289 self.loopback0.local_ip4)) ^ 1).packed
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700290 echo_source = self.vapi.bfd_udp_get_echo_source()
291 self.assertTrue(echo_source.is_set)
292 self.assertEqual(echo_source.sw_if_index, self.loopback0.sw_if_index)
293 self.assertTrue(echo_source.have_usable_ip4)
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200294 self.assertEqual(echo_source.ip4_addr.packed, echo_ip4)
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700295 self.assertFalse(echo_source.have_usable_ip6)
296
297 self.loopback0.config_ip6()
Paul Vinciguerra2f156312020-05-02 22:34:40 -0400298 echo_ip6 = ipaddress.IPv6Address(int(ipaddress.IPv6Address(
299 self.loopback0.local_ip6)) ^ 1).packed
300
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700301 echo_source = self.vapi.bfd_udp_get_echo_source()
302 self.assertTrue(echo_source.is_set)
303 self.assertEqual(echo_source.sw_if_index, self.loopback0.sw_if_index)
304 self.assertTrue(echo_source.have_usable_ip4)
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200305 self.assertEqual(echo_source.ip4_addr.packed, echo_ip4)
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700306 self.assertTrue(echo_source.have_usable_ip6)
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200307 self.assertEqual(echo_source.ip6_addr.packed, echo_ip6)
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700308
309 self.vapi.bfd_udp_del_echo_source()
310 echo_source = self.vapi.bfd_udp_get_echo_source()
311 self.assertFalse(echo_source.is_set)
312 self.assertFalse(echo_source.have_usable_ip4)
313 self.assertFalse(echo_source.have_usable_ip6)
314
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200315
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200316class BFDTestSession(object):
Klement Sekera3e0a3562016-12-19 09:05:21 +0100317 """ BFD session as seen from test framework side """
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200318
Klement Sekerab17dd962017-01-09 07:43:48 +0100319 def __init__(self, test, interface, af, detect_mult=3, sha1_key=None,
Neale Ranns52cd4962019-06-05 10:28:17 +0000320 bfd_key_id=None, our_seq_number=None,
321 tunnel_header=None, phy_interface=None):
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200322 self.test = test
Klement Sekera46a87ad2017-01-02 08:22:23 +0100323 self.af = af
Klement Sekerab17dd962017-01-09 07:43:48 +0100324 self.sha1_key = sha1_key
325 self.bfd_key_id = bfd_key_id
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200326 self.interface = interface
Neale Ranns52cd4962019-06-05 10:28:17 +0000327 if phy_interface:
328 self.phy_interface = phy_interface
329 else:
330 self.phy_interface = self.interface
Klement Sekerad3ba5152017-02-14 03:09:17 +0100331 self.udp_sport = randint(49152, 65535)
332 if our_seq_number is None:
333 self.our_seq_number = randint(0, 40000000)
334 else:
335 self.our_seq_number = our_seq_number
Klement Sekerab17dd962017-01-09 07:43:48 +0100336 self.vpp_seq_number = None
Klement Sekerad3ba5152017-02-14 03:09:17 +0100337 self.my_discriminator = 0
Klement Sekera2e01dfa2017-04-03 08:10:08 +0200338 self.desired_min_tx = 300000
339 self.required_min_rx = 300000
Klement Sekera239790f2017-02-16 10:53:53 +0100340 self.required_min_echo_rx = None
Klement Sekerad3ba5152017-02-14 03:09:17 +0100341 self.detect_mult = detect_mult
342 self.diag = BFDDiagCode.no_diagnostic
343 self.your_discriminator = None
344 self.state = BFDState.down
345 self.auth_type = BFDAuthType.no_auth
Neale Ranns52cd4962019-06-05 10:28:17 +0000346 self.tunnel_header = tunnel_header
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200347
Klement Sekerab17dd962017-01-09 07:43:48 +0100348 def inc_seq_num(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100349 """ increment sequence number, wrapping if needed """
Klement Sekerab17dd962017-01-09 07:43:48 +0100350 if self.our_seq_number == 0xFFFFFFFF:
351 self.our_seq_number = 0
352 else:
353 self.our_seq_number += 1
354
Klement Sekerad3ba5152017-02-14 03:09:17 +0100355 def update(self, my_discriminator=None, your_discriminator=None,
Klement Sekera239790f2017-02-16 10:53:53 +0100356 desired_min_tx=None, required_min_rx=None,
357 required_min_echo_rx=None, detect_mult=None,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100358 diag=None, state=None, auth_type=None):
359 """ update BFD parameters associated with session """
Klement Sekera239790f2017-02-16 10:53:53 +0100360 if my_discriminator is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100361 self.my_discriminator = my_discriminator
Klement Sekera239790f2017-02-16 10:53:53 +0100362 if your_discriminator is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100363 self.your_discriminator = your_discriminator
Klement Sekera239790f2017-02-16 10:53:53 +0100364 if required_min_rx is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100365 self.required_min_rx = required_min_rx
Klement Sekera239790f2017-02-16 10:53:53 +0100366 if required_min_echo_rx is not None:
367 self.required_min_echo_rx = required_min_echo_rx
368 if desired_min_tx is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100369 self.desired_min_tx = desired_min_tx
Klement Sekera239790f2017-02-16 10:53:53 +0100370 if detect_mult is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100371 self.detect_mult = detect_mult
Klement Sekera239790f2017-02-16 10:53:53 +0100372 if diag is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100373 self.diag = diag
Klement Sekera239790f2017-02-16 10:53:53 +0100374 if state is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100375 self.state = state
Klement Sekera239790f2017-02-16 10:53:53 +0100376 if auth_type is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100377 self.auth_type = auth_type
378
379 def fill_packet_fields(self, packet):
380 """ set packet fields with known values in packet """
381 bfd = packet[BFD]
382 if self.my_discriminator:
383 self.test.logger.debug("BFD: setting packet.my_discriminator=%s",
384 self.my_discriminator)
385 bfd.my_discriminator = self.my_discriminator
386 if self.your_discriminator:
387 self.test.logger.debug("BFD: setting packet.your_discriminator=%s",
388 self.your_discriminator)
389 bfd.your_discriminator = self.your_discriminator
390 if self.required_min_rx:
391 self.test.logger.debug(
392 "BFD: setting packet.required_min_rx_interval=%s",
393 self.required_min_rx)
394 bfd.required_min_rx_interval = self.required_min_rx
Klement Sekera239790f2017-02-16 10:53:53 +0100395 if self.required_min_echo_rx:
396 self.test.logger.debug(
397 "BFD: setting packet.required_min_echo_rx=%s",
398 self.required_min_echo_rx)
399 bfd.required_min_echo_rx_interval = self.required_min_echo_rx
Klement Sekerad3ba5152017-02-14 03:09:17 +0100400 if self.desired_min_tx:
401 self.test.logger.debug(
402 "BFD: setting packet.desired_min_tx_interval=%s",
403 self.desired_min_tx)
404 bfd.desired_min_tx_interval = self.desired_min_tx
405 if self.detect_mult:
406 self.test.logger.debug(
407 "BFD: setting packet.detect_mult=%s", self.detect_mult)
408 bfd.detect_mult = self.detect_mult
409 if self.diag:
410 self.test.logger.debug("BFD: setting packet.diag=%s", self.diag)
411 bfd.diag = self.diag
412 if self.state:
413 self.test.logger.debug("BFD: setting packet.state=%s", self.state)
414 bfd.state = self.state
415 if self.auth_type:
416 # this is used by a negative test-case
417 self.test.logger.debug("BFD: setting packet.auth_type=%s",
418 self.auth_type)
419 bfd.auth_type = self.auth_type
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200420
421 def create_packet(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100422 """ create a BFD packet, reflecting the current state of session """
Klement Sekerab17dd962017-01-09 07:43:48 +0100423 if self.sha1_key:
424 bfd = BFD(flags="A")
425 bfd.auth_type = self.sha1_key.auth_type
426 bfd.auth_len = BFD.sha1_auth_len
427 bfd.auth_key_id = self.bfd_key_id
428 bfd.auth_seq_num = self.our_seq_number
429 bfd.length = BFD.sha1_auth_len + BFD.bfd_pkt_len
430 else:
431 bfd = BFD()
Neale Ranns52cd4962019-06-05 10:28:17 +0000432 packet = Ether(src=self.phy_interface.remote_mac,
433 dst=self.phy_interface.local_mac)
434 if self.tunnel_header:
435 packet = packet / self.tunnel_header
Klement Sekera46a87ad2017-01-02 08:22:23 +0100436 if self.af == AF_INET6:
Neale Ranns52cd4962019-06-05 10:28:17 +0000437 packet = (packet /
Klement Sekera46a87ad2017-01-02 08:22:23 +0100438 IPv6(src=self.interface.remote_ip6,
439 dst=self.interface.local_ip6,
440 hlim=255) /
441 UDP(sport=self.udp_sport, dport=BFD.udp_dport) /
Klement Sekerab17dd962017-01-09 07:43:48 +0100442 bfd)
Klement Sekera46a87ad2017-01-02 08:22:23 +0100443 else:
Neale Ranns52cd4962019-06-05 10:28:17 +0000444 packet = (packet /
Klement Sekera46a87ad2017-01-02 08:22:23 +0100445 IP(src=self.interface.remote_ip4,
446 dst=self.interface.local_ip4,
447 ttl=255) /
448 UDP(sport=self.udp_sport, dport=BFD.udp_dport) /
Klement Sekerab17dd962017-01-09 07:43:48 +0100449 bfd)
Klement Sekera3e0a3562016-12-19 09:05:21 +0100450 self.test.logger.debug("BFD: Creating packet")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100451 self.fill_packet_fields(packet)
Klement Sekerab17dd962017-01-09 07:43:48 +0100452 if self.sha1_key:
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700453 hash_material = scapy.compat.raw(
454 packet[BFD])[:32] + self.sha1_key.key + \
snaramre73aff472019-12-02 05:49:28 +0000455 b"\0" * (20 - len(self.sha1_key.key))
Klement Sekerab17dd962017-01-09 07:43:48 +0100456 self.test.logger.debug("BFD: Calculated SHA1 hash: %s" %
457 hashlib.sha1(hash_material).hexdigest())
458 packet[BFD].auth_key_hash = hashlib.sha1(hash_material).digest()
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200459 return packet
460
Klement Sekerad3ba5152017-02-14 03:09:17 +0100461 def send_packet(self, packet=None, interface=None):
462 """ send packet on interface, creating the packet if needed """
Klement Sekeraa57a9702017-02-02 06:58:07 +0100463 if packet is None:
464 packet = self.create_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100465 if interface is None:
Neale Ranns52cd4962019-06-05 10:28:17 +0000466 interface = self.phy_interface
Klement Sekeraa57a9702017-02-02 06:58:07 +0100467 self.test.logger.debug(ppp("Sending packet:", packet))
Klement Sekerad3ba5152017-02-14 03:09:17 +0100468 interface.add_stream(packet)
Klement Sekera9225dee2016-12-12 08:36:58 +0100469 self.test.pg_start()
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200470
Klement Sekerab17dd962017-01-09 07:43:48 +0100471 def verify_sha1_auth(self, packet):
472 """ Verify correctness of authentication in BFD layer. """
473 bfd = packet[BFD]
474 self.test.assert_equal(bfd.auth_len, 28, "Auth section length")
475 self.test.assert_equal(bfd.auth_type, self.sha1_key.auth_type,
476 BFDAuthType)
477 self.test.assert_equal(bfd.auth_key_id, self.bfd_key_id, "Key ID")
478 self.test.assert_equal(bfd.auth_reserved, 0, "Reserved")
479 if self.vpp_seq_number is None:
480 self.vpp_seq_number = bfd.auth_seq_num
481 self.test.logger.debug("Received initial sequence number: %s" %
482 self.vpp_seq_number)
483 else:
484 recvd_seq_num = bfd.auth_seq_num
485 self.test.logger.debug("Received followup sequence number: %s" %
486 recvd_seq_num)
487 if self.vpp_seq_number < 0xffffffff:
488 if self.sha1_key.auth_type == \
489 BFDAuthType.meticulous_keyed_sha1:
490 self.test.assert_equal(recvd_seq_num,
491 self.vpp_seq_number + 1,
492 "BFD sequence number")
493 else:
494 self.test.assert_in_range(recvd_seq_num,
495 self.vpp_seq_number,
496 self.vpp_seq_number + 1,
497 "BFD sequence number")
498 else:
499 if self.sha1_key.auth_type == \
500 BFDAuthType.meticulous_keyed_sha1:
501 self.test.assert_equal(recvd_seq_num, 0,
502 "BFD sequence number")
503 else:
504 self.test.assertIn(recvd_seq_num, (self.vpp_seq_number, 0),
505 "BFD sequence number not one of "
506 "(%s, 0)" % self.vpp_seq_number)
507 self.vpp_seq_number = recvd_seq_num
508 # last 20 bytes represent the hash - so replace them with the key,
509 # pad the result with zeros and hash the result
510 hash_material = bfd.original[:-20] + self.sha1_key.key + \
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700511 b"\0" * (20 - len(self.sha1_key.key))
Klement Sekerab17dd962017-01-09 07:43:48 +0100512 expected_hash = hashlib.sha1(hash_material).hexdigest()
513 self.test.assert_equal(binascii.hexlify(bfd.auth_key_hash),
snaramre73aff472019-12-02 05:49:28 +0000514 expected_hash.encode(), "Auth key hash")
Klement Sekerab17dd962017-01-09 07:43:48 +0100515
516 def verify_bfd(self, packet):
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200517 """ Verify correctness of BFD layer. """
518 bfd = packet[BFD]
519 self.test.assert_equal(bfd.version, 1, "BFD version")
520 self.test.assert_equal(bfd.your_discriminator,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100521 self.my_discriminator,
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200522 "BFD - your discriminator")
Klement Sekerab17dd962017-01-09 07:43:48 +0100523 if self.sha1_key:
524 self.verify_sha1_auth(packet)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200525
526
Klement Sekerad3ba5152017-02-14 03:09:17 +0100527def bfd_session_up(test):
528 """ Bring BFD session up """
529 test.logger.info("BFD: Waiting for slow hello")
Neale Ranns52cd4962019-06-05 10:28:17 +0000530 p = wait_for_bfd_packet(test, 2, is_tunnel=test.vpp_session.is_tunnel)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100531 old_offset = None
532 if hasattr(test, 'vpp_clock_offset'):
533 old_offset = test.vpp_clock_offset
snaramre73aff472019-12-02 05:49:28 +0000534 test.vpp_clock_offset = time.time() - float(p.time)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100535 test.logger.debug("BFD: Calculated vpp clock offset: %s",
536 test.vpp_clock_offset)
537 if old_offset:
538 test.assertAlmostEqual(
Klement Sekera73884482017-02-23 09:26:30 +0100539 old_offset, test.vpp_clock_offset, delta=0.5,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100540 msg="vpp clock offset not stable (new: %s, old: %s)" %
541 (test.vpp_clock_offset, old_offset))
542 test.logger.info("BFD: Sending Init")
543 test.test_session.update(my_discriminator=randint(0, 40000000),
544 your_discriminator=p[BFD].my_discriminator,
545 state=BFDState.init)
Klement Sekera73884482017-02-23 09:26:30 +0100546 if test.test_session.sha1_key and test.test_session.sha1_key.auth_type == \
547 BFDAuthType.meticulous_keyed_sha1:
548 test.test_session.inc_seq_num()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100549 test.test_session.send_packet()
550 test.logger.info("BFD: Waiting for event")
551 e = test.vapi.wait_for_event(1, "bfd_udp_session_details")
552 verify_event(test, e, expected_state=BFDState.up)
553 test.logger.info("BFD: Session is Up")
554 test.test_session.update(state=BFDState.up)
Klement Sekera73884482017-02-23 09:26:30 +0100555 if test.test_session.sha1_key and test.test_session.sha1_key.auth_type == \
556 BFDAuthType.meticulous_keyed_sha1:
557 test.test_session.inc_seq_num()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100558 test.test_session.send_packet()
559 test.assert_equal(test.vpp_session.state, BFDState.up, BFDState)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200560
Klement Sekera46a87ad2017-01-02 08:22:23 +0100561
Klement Sekerad3ba5152017-02-14 03:09:17 +0100562def bfd_session_down(test):
563 """ Bring BFD session down """
564 test.assert_equal(test.vpp_session.state, BFDState.up, BFDState)
565 test.test_session.update(state=BFDState.down)
Klement Sekera73884482017-02-23 09:26:30 +0100566 if test.test_session.sha1_key and test.test_session.sha1_key.auth_type == \
567 BFDAuthType.meticulous_keyed_sha1:
568 test.test_session.inc_seq_num()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100569 test.test_session.send_packet()
570 test.logger.info("BFD: Waiting for event")
571 e = test.vapi.wait_for_event(1, "bfd_udp_session_details")
572 verify_event(test, e, expected_state=BFDState.down)
573 test.logger.info("BFD: Session is Down")
574 test.assert_equal(test.vpp_session.state, BFDState.down, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +0100575
Klement Sekera46a87ad2017-01-02 08:22:23 +0100576
Klement Sekera73884482017-02-23 09:26:30 +0100577def verify_bfd_session_config(test, session, state=None):
578 dump = session.get_bfd_udp_session_dump_entry()
579 test.assertIsNotNone(dump)
580 # since dump is not none, we have verified that sw_if_index and addresses
581 # are valid (in get_bfd_udp_session_dump_entry)
582 if state:
583 test.assert_equal(dump.state, state, "session state")
584 test.assert_equal(dump.required_min_rx, session.required_min_rx,
585 "required min rx interval")
586 test.assert_equal(dump.desired_min_tx, session.desired_min_tx,
587 "desired min tx interval")
588 test.assert_equal(dump.detect_mult, session.detect_mult,
589 "detect multiplier")
590 if session.sha1_key is None:
591 test.assert_equal(dump.is_authenticated, 0, "is_authenticated flag")
592 else:
593 test.assert_equal(dump.is_authenticated, 1, "is_authenticated flag")
594 test.assert_equal(dump.bfd_key_id, session.bfd_key_id,
595 "bfd key id")
596 test.assert_equal(dump.conf_key_id,
597 session.sha1_key.conf_key_id,
598 "config key id")
599
600
Klement Sekerad3ba5152017-02-14 03:09:17 +0100601def verify_ip(test, packet):
602 """ Verify correctness of IP layer. """
603 if test.vpp_session.af == AF_INET6:
604 ip = packet[IPv6]
Neale Ranns52cd4962019-06-05 10:28:17 +0000605 local_ip = test.vpp_session.interface.local_ip6
606 remote_ip = test.vpp_session.interface.remote_ip6
Klement Sekerad3ba5152017-02-14 03:09:17 +0100607 test.assert_equal(ip.hlim, 255, "IPv6 hop limit")
608 else:
609 ip = packet[IP]
Neale Ranns52cd4962019-06-05 10:28:17 +0000610 local_ip = test.vpp_session.interface.local_ip4
611 remote_ip = test.vpp_session.interface.remote_ip4
Klement Sekerad3ba5152017-02-14 03:09:17 +0100612 test.assert_equal(ip.ttl, 255, "IPv4 TTL")
613 test.assert_equal(ip.src, local_ip, "IP source address")
614 test.assert_equal(ip.dst, remote_ip, "IP destination address")
615
616
617def verify_udp(test, packet):
618 """ Verify correctness of UDP layer. """
619 udp = packet[UDP]
620 test.assert_equal(udp.dport, BFD.udp_dport, "UDP destination port")
621 test.assert_in_range(udp.sport, BFD.udp_sport_min, BFD.udp_sport_max,
622 "UDP source port")
623
624
625def verify_event(test, event, expected_state):
626 """ Verify correctness of event values. """
627 e = event
Paul Vinciguerra090096b2020-12-03 00:42:46 -0500628 test.logger.debug("BFD: Event: %s" % reprlib.repr(e))
Klement Sekerad3ba5152017-02-14 03:09:17 +0100629 test.assert_equal(e.sw_if_index,
630 test.vpp_session.interface.sw_if_index,
631 "BFD interface index")
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200632
633 test.assert_equal(str(e.local_addr), test.vpp_session.local_addr,
634 "Local IPv6 address")
635 test.assert_equal(str(e.peer_addr), test.vpp_session.peer_addr,
636 "Peer IPv6 address")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100637 test.assert_equal(e.state, expected_state, BFDState)
638
639
Neale Ranns52cd4962019-06-05 10:28:17 +0000640def wait_for_bfd_packet(test, timeout=1, pcap_time_min=None, is_tunnel=False):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100641 """ wait for BFD packet and verify its correctness
642
643 :param timeout: how long to wait
644 :param pcap_time_min: ignore packets with pcap timestamp lower than this
645
646 :returns: tuple (packet, time spent waiting for packet)
647 """
648 test.logger.info("BFD: Waiting for BFD packet")
649 deadline = time.time() + timeout
650 counter = 0
651 while True:
652 counter += 1
653 # sanity check
654 test.assert_in_range(counter, 0, 100, "number of packets ignored")
655 time_left = deadline - time.time()
656 if time_left < 0:
657 raise CaptureTimeoutError("Packet did not arrive within timeout")
658 p = test.pg0.wait_for_packet(timeout=time_left)
659 test.logger.debug(ppp("BFD: Got packet:", p))
660 if pcap_time_min is not None and p.time < pcap_time_min:
661 test.logger.debug(ppp("BFD: ignoring packet (pcap time %s < "
662 "pcap time min %s):" %
663 (p.time, pcap_time_min), p))
Klement Sekera46a87ad2017-01-02 08:22:23 +0100664 else:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100665 break
Neale Ranns52cd4962019-06-05 10:28:17 +0000666 if is_tunnel:
667 # strip an IP layer and move to the next
668 p = p[IP].payload
669
Klement Sekerad3ba5152017-02-14 03:09:17 +0100670 bfd = p[BFD]
671 if bfd is None:
672 raise Exception(ppp("Unexpected or invalid BFD packet:", p))
673 if bfd.payload:
674 raise Exception(ppp("Unexpected payload in BFD packet:", bfd))
675 verify_ip(test, p)
676 verify_udp(test, p)
677 test.test_session.verify_bfd(p)
678 return p
Klement Sekera3e0a3562016-12-19 09:05:21 +0100679
Klement Sekera46a87ad2017-01-02 08:22:23 +0100680
Andrew Yourtchenko06f32812021-01-14 10:19:08 +0000681@tag_run_solo
Klement Sekerad3ba5152017-02-14 03:09:17 +0100682class BFD4TestCase(VppTestCase):
Klement Sekera46a87ad2017-01-02 08:22:23 +0100683 """Bidirectional Forwarding Detection (BFD)"""
684
Klement Sekerad3ba5152017-02-14 03:09:17 +0100685 pg0 = None
686 vpp_clock_offset = None
687 vpp_session = None
688 test_session = None
689
Klement Sekera46a87ad2017-01-02 08:22:23 +0100690 @classmethod
691 def setUpClass(cls):
692 super(BFD4TestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -0800693 cls.vapi.cli("set log class bfd level debug")
Klement Sekera46a87ad2017-01-02 08:22:23 +0100694 try:
695 cls.create_pg_interfaces([0])
Klement Sekerab9ef2732018-06-24 22:49:33 +0200696 cls.create_loopback_interfaces(1)
Klement Sekera239790f2017-02-16 10:53:53 +0100697 cls.loopback0 = cls.lo_interfaces[0]
698 cls.loopback0.config_ip4()
699 cls.loopback0.admin_up()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100700 cls.pg0.config_ip4()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100701 cls.pg0.configure_ipv4_neighbors()
702 cls.pg0.admin_up()
703 cls.pg0.resolve_arp()
704
705 except Exception:
706 super(BFD4TestCase, cls).tearDownClass()
707 raise
708
Paul Vinciguerra8d991d92019-01-25 14:05:48 -0800709 @classmethod
710 def tearDownClass(cls):
711 super(BFD4TestCase, cls).tearDownClass()
712
Klement Sekera46a87ad2017-01-02 08:22:23 +0100713 def setUp(self):
714 super(BFD4TestCase, self).setUp()
Klement Sekerab17dd962017-01-09 07:43:48 +0100715 self.factory = AuthKeyFactory()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100716 self.vapi.want_bfd_events()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100717 self.pg0.enable_capture()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100718 try:
719 self.vpp_session = VppBFDUDPSession(self, self.pg0,
720 self.pg0.remote_ip4)
721 self.vpp_session.add_vpp_config()
722 self.vpp_session.admin_up()
723 self.test_session = BFDTestSession(self, self.pg0, AF_INET)
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200724 except BaseException:
Klement Sekera46a87ad2017-01-02 08:22:23 +0100725 self.vapi.want_bfd_events(enable_disable=0)
726 raise
727
728 def tearDown(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100729 if not self.vpp_dead:
730 self.vapi.want_bfd_events(enable_disable=0)
731 self.vapi.collect_events() # clear the event queue
732 super(BFD4TestCase, self).tearDown()
Klement Sekerab17dd962017-01-09 07:43:48 +0100733
734 def test_session_up(self):
735 """ bring BFD session up """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100736 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +0100737
Klement Sekera73884482017-02-23 09:26:30 +0100738 def test_session_up_by_ip(self):
739 """ bring BFD session up - first frame looked up by address pair """
740 self.logger.info("BFD: Sending Slow control frame")
741 self.test_session.update(my_discriminator=randint(0, 40000000))
742 self.test_session.send_packet()
743 self.pg0.enable_capture()
744 p = self.pg0.wait_for_packet(1)
745 self.assert_equal(p[BFD].your_discriminator,
746 self.test_session.my_discriminator,
747 "BFD - your discriminator")
748 self.assert_equal(p[BFD].state, BFDState.init, BFDState)
749 self.test_session.update(your_discriminator=p[BFD].my_discriminator,
750 state=BFDState.up)
751 self.logger.info("BFD: Waiting for event")
752 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
753 verify_event(self, e, expected_state=BFDState.init)
754 self.logger.info("BFD: Sending Up")
755 self.test_session.send_packet()
756 self.logger.info("BFD: Waiting for event")
757 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
758 verify_event(self, e, expected_state=BFDState.up)
759 self.logger.info("BFD: Session is Up")
760 self.test_session.update(state=BFDState.up)
761 self.test_session.send_packet()
762 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
763
Klement Sekerab17dd962017-01-09 07:43:48 +0100764 def test_session_down(self):
765 """ bring BFD session down """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100766 bfd_session_up(self)
767 bfd_session_down(self)
Klement Sekerab17dd962017-01-09 07:43:48 +0100768
769 def test_hold_up(self):
770 """ hold BFD session up """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100771 bfd_session_up(self)
772 for dummy in range(self.test_session.detect_mult * 2):
773 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +0100774 self.test_session.send_packet()
775 self.assert_equal(len(self.vapi.collect_events()), 0,
776 "number of bfd events")
Klement Sekera46a87ad2017-01-02 08:22:23 +0100777
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200778 def test_slow_timer(self):
Klement Sekerae4504c62016-12-08 10:16:41 +0100779 """ verify slow periodic control frames while session down """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100780 packet_count = 3
781 self.logger.info("BFD: Waiting for %d BFD packets", packet_count)
782 prev_packet = wait_for_bfd_packet(self, 2)
783 for dummy in range(packet_count):
784 next_packet = wait_for_bfd_packet(self, 2)
785 time_diff = next_packet.time - prev_packet.time
Klement Sekerae4504c62016-12-08 10:16:41 +0100786 # spec says the range should be <0.75, 1>, allow extra 0.05 margin
787 # to work around timing issues
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200788 self.assert_in_range(
Klement Sekerad3ba5152017-02-14 03:09:17 +0100789 time_diff, 0.70, 1.05, "time between slow packets")
790 prev_packet = next_packet
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200791
792 def test_zero_remote_min_rx(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100793 """ no packets when zero remote required min rx interval """
794 bfd_session_up(self)
795 self.test_session.update(required_min_rx=0)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200796 self.test_session.send_packet()
Klement Sekera239790f2017-02-16 10:53:53 +0100797 for dummy in range(self.test_session.detect_mult):
798 self.sleep(self.vpp_session.required_min_rx / USEC_IN_SEC,
799 "sleep before transmitting bfd packet")
800 self.test_session.send_packet()
Klement Sekeraa57a9702017-02-02 06:58:07 +0100801 try:
Klement Sekera239790f2017-02-16 10:53:53 +0100802 p = wait_for_bfd_packet(self, timeout=0)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100803 self.logger.error(ppp("Received unexpected packet:", p))
Klement Sekerad3ba5152017-02-14 03:09:17 +0100804 except CaptureTimeoutError:
Klement Sekeraa57a9702017-02-02 06:58:07 +0100805 pass
Klement Sekera239790f2017-02-16 10:53:53 +0100806 self.assert_equal(
807 len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekera2e01dfa2017-04-03 08:10:08 +0200808 self.test_session.update(required_min_rx=300000)
Klement Sekera239790f2017-02-16 10:53:53 +0100809 for dummy in range(3):
810 self.test_session.send_packet()
811 wait_for_bfd_packet(
812 self, timeout=self.test_session.required_min_rx / USEC_IN_SEC)
813 self.assert_equal(
814 len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200815
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200816 def test_conn_down(self):
Klement Sekerae4504c62016-12-08 10:16:41 +0100817 """ verify session goes down after inactivity """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100818 bfd_session_up(self)
Klement Sekera239790f2017-02-16 10:53:53 +0100819 detection_time = self.test_session.detect_mult *\
Klement Sekerac48829b2017-02-14 07:55:57 +0100820 self.vpp_session.required_min_rx / USEC_IN_SEC
821 self.sleep(detection_time, "waiting for BFD session time-out")
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200822 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100823 verify_event(self, e, expected_state=BFDState.down)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200824
Klement Sekera4d39f9c2020-01-17 10:01:52 +0000825 def test_peer_discr_reset_sess_down(self):
826 """ peer discriminator reset after session goes down """
827 bfd_session_up(self)
828 detection_time = self.test_session.detect_mult *\
829 self.vpp_session.required_min_rx / USEC_IN_SEC
830 self.sleep(detection_time, "waiting for BFD session time-out")
831 self.test_session.my_discriminator = 0
832 wait_for_bfd_packet(self,
833 pcap_time_min=time.time() - self.vpp_clock_offset)
834
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200835 def test_large_required_min_rx(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100836 """ large remote required min rx interval """
837 bfd_session_up(self)
838 p = wait_for_bfd_packet(self)
Klement Sekera637b9c42016-12-08 05:19:14 +0100839 interval = 3000000
Klement Sekerad3ba5152017-02-14 03:09:17 +0100840 self.test_session.update(required_min_rx=interval)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200841 self.test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100842 time_mark = time.time()
Klement Sekera637b9c42016-12-08 05:19:14 +0100843 count = 0
Klement Sekeraa57a9702017-02-02 06:58:07 +0100844 # busy wait here, trying to collect a packet or event, vpp is not
845 # allowed to send packets and the session will timeout first - so the
846 # Up->Down event must arrive before any packets do
Klement Sekerad3ba5152017-02-14 03:09:17 +0100847 while time.time() < time_mark + interval / USEC_IN_SEC:
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200848 try:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100849 p = wait_for_bfd_packet(self, timeout=0)
850 # if vpp managed to send a packet before we did the session
851 # session update, then that's fine, ignore it
852 if p.time < time_mark - self.vpp_clock_offset:
853 continue
Klement Sekeraa57a9702017-02-02 06:58:07 +0100854 self.logger.error(ppp("Received unexpected packet:", p))
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200855 count += 1
Klement Sekerad3ba5152017-02-14 03:09:17 +0100856 except CaptureTimeoutError:
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200857 pass
Klement Sekeraa57a9702017-02-02 06:58:07 +0100858 events = self.vapi.collect_events()
859 if len(events) > 0:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100860 verify_event(self, events[0], BFDState.down)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100861 break
862 self.assert_equal(count, 0, "number of packets received")
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200863
Klement Sekerad3ba5152017-02-14 03:09:17 +0100864 def test_immediate_remote_min_rx_reduction(self):
865 """ immediately honor remote required min rx reduction """
Klement Sekera3e0a3562016-12-19 09:05:21 +0100866 self.vpp_session.remove_vpp_config()
Klement Sekera10db26f2017-01-11 08:16:53 +0100867 self.vpp_session = VppBFDUDPSession(
868 self, self.pg0, self.pg0.remote_ip4, desired_min_tx=10000)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100869 self.pg0.enable_capture()
Klement Sekera3e0a3562016-12-19 09:05:21 +0100870 self.vpp_session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100871 self.test_session.update(desired_min_tx=1000000,
872 required_min_rx=1000000)
873 bfd_session_up(self)
874 reference_packet = wait_for_bfd_packet(self)
875 time_mark = time.time()
876 interval = 300000
877 self.test_session.update(required_min_rx=interval)
Klement Sekera3e0a3562016-12-19 09:05:21 +0100878 self.test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100879 extra_time = time.time() - time_mark
880 p = wait_for_bfd_packet(self)
881 # first packet is allowed to be late by time we spent doing the update
882 # calculated in extra_time
883 self.assert_in_range(p.time - reference_packet.time,
884 .95 * 0.75 * interval / USEC_IN_SEC,
885 1.05 * interval / USEC_IN_SEC + extra_time,
Klement Sekera3e0a3562016-12-19 09:05:21 +0100886 "time between BFD packets")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100887 reference_packet = p
888 for dummy in range(3):
889 p = wait_for_bfd_packet(self)
890 diff = p.time - reference_packet.time
891 self.assert_in_range(diff, .95 * .75 * interval / USEC_IN_SEC,
892 1.05 * interval / USEC_IN_SEC,
893 "time between BFD packets")
894 reference_packet = p
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200895
Klement Sekeraa57a9702017-02-02 06:58:07 +0100896 def test_modify_req_min_rx_double(self):
897 """ modify session - double required min rx """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100898 bfd_session_up(self)
899 p = wait_for_bfd_packet(self)
900 self.test_session.update(desired_min_tx=10000,
901 required_min_rx=10000)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100902 self.test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100903 # double required min rx
Klement Sekeraa57a9702017-02-02 06:58:07 +0100904 self.vpp_session.modify_parameters(
905 required_min_rx=2 * self.vpp_session.required_min_rx)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100906 p = wait_for_bfd_packet(
907 self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100908 # poll bit needs to be set
909 self.assertIn("P", p.sprintf("%BFD.flags%"),
910 "Poll bit not set in BFD packet")
911 # finish poll sequence with final packet
912 final = self.test_session.create_packet()
913 final[BFD].flags = "F"
Klement Sekerad3ba5152017-02-14 03:09:17 +0100914 timeout = self.test_session.detect_mult * \
915 max(self.test_session.desired_min_tx,
916 self.vpp_session.required_min_rx) / USEC_IN_SEC
Klement Sekeraa57a9702017-02-02 06:58:07 +0100917 self.test_session.send_packet(final)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100918 time_mark = time.time()
919 e = self.vapi.wait_for_event(2 * timeout, "bfd_udp_session_details")
920 verify_event(self, e, expected_state=BFDState.down)
921 time_to_event = time.time() - time_mark
922 self.assert_in_range(time_to_event, .9 * timeout,
923 1.1 * timeout, "session timeout")
Klement Sekeraa57a9702017-02-02 06:58:07 +0100924
925 def test_modify_req_min_rx_halve(self):
926 """ modify session - halve required min rx """
927 self.vpp_session.modify_parameters(
928 required_min_rx=2 * self.vpp_session.required_min_rx)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100929 bfd_session_up(self)
930 p = wait_for_bfd_packet(self)
931 self.test_session.update(desired_min_tx=10000,
932 required_min_rx=10000)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100933 self.test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100934 p = wait_for_bfd_packet(
935 self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100936 # halve required min rx
937 old_required_min_rx = self.vpp_session.required_min_rx
938 self.vpp_session.modify_parameters(
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700939 required_min_rx=self.vpp_session.required_min_rx // 2)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100940 # now we wait 0.8*3*old-req-min-rx and the session should still be up
941 self.sleep(0.8 * self.vpp_session.detect_mult *
Klement Sekera2e01dfa2017-04-03 08:10:08 +0200942 old_required_min_rx / USEC_IN_SEC,
943 "wait before finishing poll sequence")
Klement Sekeraa57a9702017-02-02 06:58:07 +0100944 self.assert_equal(len(self.vapi.collect_events()), 0,
945 "number of bfd events")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100946 p = wait_for_bfd_packet(self)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100947 # poll bit needs to be set
948 self.assertIn("P", p.sprintf("%BFD.flags%"),
949 "Poll bit not set in BFD packet")
950 # finish poll sequence with final packet
951 final = self.test_session.create_packet()
952 final[BFD].flags = "F"
953 self.test_session.send_packet(final)
954 # now the session should time out under new conditions
Klement Sekera239790f2017-02-16 10:53:53 +0100955 detection_time = self.test_session.detect_mult *\
Klement Sekerad3ba5152017-02-14 03:09:17 +0100956 self.vpp_session.required_min_rx / USEC_IN_SEC
Klement Sekera2e01dfa2017-04-03 08:10:08 +0200957 before = time.time()
958 e = self.vapi.wait_for_event(
959 2 * detection_time, "bfd_udp_session_details")
960 after = time.time()
Klement Sekeraa57a9702017-02-02 06:58:07 +0100961 self.assert_in_range(after - before,
962 0.9 * detection_time,
963 1.1 * detection_time,
964 "time before bfd session goes down")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100965 verify_event(self, e, expected_state=BFDState.down)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100966
Klement Sekeraa57a9702017-02-02 06:58:07 +0100967 def test_modify_detect_mult(self):
968 """ modify detect multiplier """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100969 bfd_session_up(self)
970 p = wait_for_bfd_packet(self)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100971 self.vpp_session.modify_parameters(detect_mult=1)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100972 p = wait_for_bfd_packet(
973 self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100974 self.assert_equal(self.vpp_session.detect_mult,
975 p[BFD].detect_mult,
976 "detect mult")
977 # poll bit must not be set
978 self.assertNotIn("P", p.sprintf("%BFD.flags%"),
979 "Poll bit not set in BFD packet")
980 self.vpp_session.modify_parameters(detect_mult=10)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100981 p = wait_for_bfd_packet(
982 self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100983 self.assert_equal(self.vpp_session.detect_mult,
984 p[BFD].detect_mult,
985 "detect mult")
986 # poll bit must not be set
987 self.assertNotIn("P", p.sprintf("%BFD.flags%"),
988 "Poll bit not set in BFD packet")
989
Klement Sekera239790f2017-02-16 10:53:53 +0100990 def test_queued_poll(self):
991 """ test poll sequence queueing """
992 bfd_session_up(self)
993 p = wait_for_bfd_packet(self)
994 self.vpp_session.modify_parameters(
995 required_min_rx=2 * self.vpp_session.required_min_rx)
996 p = wait_for_bfd_packet(self)
997 poll_sequence_start = time.time()
998 poll_sequence_length_min = 0.5
999 send_final_after = time.time() + poll_sequence_length_min
1000 # poll bit needs to be set
1001 self.assertIn("P", p.sprintf("%BFD.flags%"),
1002 "Poll bit not set in BFD packet")
1003 self.assert_equal(p[BFD].required_min_rx_interval,
1004 self.vpp_session.required_min_rx,
1005 "BFD required min rx interval")
1006 self.vpp_session.modify_parameters(
1007 required_min_rx=2 * self.vpp_session.required_min_rx)
1008 # 2nd poll sequence should be queued now
1009 # don't send the reply back yet, wait for some time to emulate
1010 # longer round-trip time
1011 packet_count = 0
1012 while time.time() < send_final_after:
1013 self.test_session.send_packet()
1014 p = wait_for_bfd_packet(self)
1015 self.assert_equal(len(self.vapi.collect_events()), 0,
1016 "number of bfd events")
1017 self.assert_equal(p[BFD].required_min_rx_interval,
1018 self.vpp_session.required_min_rx,
1019 "BFD required min rx interval")
1020 packet_count += 1
1021 # poll bit must be set
1022 self.assertIn("P", p.sprintf("%BFD.flags%"),
1023 "Poll bit not set in BFD packet")
1024 final = self.test_session.create_packet()
1025 final[BFD].flags = "F"
1026 self.test_session.send_packet(final)
1027 # finish 1st with final
1028 poll_sequence_length = time.time() - poll_sequence_start
1029 # vpp must wait for some time before starting new poll sequence
1030 poll_no_2_started = False
1031 for dummy in range(2 * packet_count):
1032 p = wait_for_bfd_packet(self)
1033 self.assert_equal(len(self.vapi.collect_events()), 0,
1034 "number of bfd events")
1035 if "P" in p.sprintf("%BFD.flags%"):
1036 poll_no_2_started = True
1037 if time.time() < poll_sequence_start + poll_sequence_length:
1038 raise Exception("VPP started 2nd poll sequence too soon")
1039 final = self.test_session.create_packet()
1040 final[BFD].flags = "F"
1041 self.test_session.send_packet(final)
1042 break
1043 else:
1044 self.test_session.send_packet()
1045 self.assertTrue(poll_no_2_started, "2nd poll sequence not performed")
1046 # finish 2nd with final
1047 final = self.test_session.create_packet()
1048 final[BFD].flags = "F"
1049 self.test_session.send_packet(final)
1050 p = wait_for_bfd_packet(self)
1051 # poll bit must not be set
1052 self.assertNotIn("P", p.sprintf("%BFD.flags%"),
1053 "Poll bit set in BFD packet")
1054
Paul Vinciguerra7ade2f52019-12-06 11:06:02 -05001055 # returning inconsistent results requiring retries in per-patch tests
1056 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekera73884482017-02-23 09:26:30 +01001057 def test_poll_response(self):
1058 """ test correct response to control frame with poll bit set """
1059 bfd_session_up(self)
1060 poll = self.test_session.create_packet()
1061 poll[BFD].flags = "P"
1062 self.test_session.send_packet(poll)
1063 final = wait_for_bfd_packet(
1064 self, pcap_time_min=time.time() - self.vpp_clock_offset)
1065 self.assertIn("F", final.sprintf("%BFD.flags%"))
1066
Klement Sekerad3ba5152017-02-14 03:09:17 +01001067 def test_no_periodic_if_remote_demand(self):
1068 """ no periodic frames outside poll sequence if remote demand set """
Klement Sekerad3ba5152017-02-14 03:09:17 +01001069 bfd_session_up(self)
1070 demand = self.test_session.create_packet()
1071 demand[BFD].flags = "D"
1072 self.test_session.send_packet(demand)
1073 transmit_time = 0.9 \
1074 * max(self.vpp_session.required_min_rx,
1075 self.test_session.desired_min_tx) \
1076 / USEC_IN_SEC
1077 count = 0
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001078 for dummy in range(self.test_session.detect_mult * 2):
Paul Vinciguerra0f6602c2019-03-10 09:10:54 -07001079 self.sleep(transmit_time)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001080 self.test_session.send_packet(demand)
1081 try:
1082 p = wait_for_bfd_packet(self, timeout=0)
1083 self.logger.error(ppp("Received unexpected packet:", p))
1084 count += 1
1085 except CaptureTimeoutError:
1086 pass
1087 events = self.vapi.collect_events()
1088 for e in events:
1089 self.logger.error("Received unexpected event: %s", e)
1090 self.assert_equal(count, 0, "number of packets received")
1091 self.assert_equal(len(events), 0, "number of events received")
Klement Sekera46a87ad2017-01-02 08:22:23 +01001092
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001093 def test_echo_looped_back(self):
1094 """ echo packets looped back """
1095 # don't need a session in this case..
1096 self.vpp_session.remove_vpp_config()
1097 self.pg0.enable_capture()
1098 echo_packet_count = 10
1099 # random source port low enough to increment a few times..
1100 udp_sport_tx = randint(1, 50000)
1101 udp_sport_rx = udp_sport_tx
1102 echo_packet = (Ether(src=self.pg0.remote_mac,
1103 dst=self.pg0.local_mac) /
1104 IP(src=self.pg0.remote_ip4,
Klement Sekera239790f2017-02-16 10:53:53 +01001105 dst=self.pg0.remote_ip4) /
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001106 UDP(dport=BFD.udp_dport_echo) /
1107 Raw("this should be looped back"))
1108 for dummy in range(echo_packet_count):
1109 self.sleep(.01, "delay between echo packets")
1110 echo_packet[UDP].sport = udp_sport_tx
1111 udp_sport_tx += 1
1112 self.logger.debug(ppp("Sending packet:", echo_packet))
1113 self.pg0.add_stream(echo_packet)
1114 self.pg_start()
1115 for dummy in range(echo_packet_count):
1116 p = self.pg0.wait_for_packet(1)
1117 self.logger.debug(ppp("Got packet:", p))
1118 ether = p[Ether]
1119 self.assert_equal(self.pg0.remote_mac,
1120 ether.dst, "Destination MAC")
1121 self.assert_equal(self.pg0.local_mac, ether.src, "Source MAC")
1122 ip = p[IP]
1123 self.assert_equal(self.pg0.remote_ip4, ip.dst, "Destination IP")
Klement Sekera239790f2017-02-16 10:53:53 +01001124 self.assert_equal(self.pg0.remote_ip4, ip.src, "Destination IP")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001125 udp = p[UDP]
1126 self.assert_equal(udp.dport, BFD.udp_dport_echo,
1127 "UDP destination port")
1128 self.assert_equal(udp.sport, udp_sport_rx, "UDP source port")
1129 udp_sport_rx += 1
Klement Sekera239790f2017-02-16 10:53:53 +01001130 # need to compare the hex payload here, otherwise BFD_vpp_echo
1131 # gets in way
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07001132 self.assertEqual(scapy.compat.raw(p[UDP].payload),
1133 scapy.compat.raw(echo_packet[UDP].payload),
Klement Sekera239790f2017-02-16 10:53:53 +01001134 "Received packet is not the echo packet sent")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001135 self.assert_equal(udp_sport_tx, udp_sport_rx, "UDP source port (== "
1136 "ECHO packet identifier for test purposes)")
1137
Klement Sekera239790f2017-02-16 10:53:53 +01001138 def test_echo(self):
1139 """ echo function """
1140 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001141 self.test_session.update(required_min_echo_rx=150000)
Klement Sekera239790f2017-02-16 10:53:53 +01001142 self.test_session.send_packet()
1143 detection_time = self.test_session.detect_mult *\
1144 self.vpp_session.required_min_rx / USEC_IN_SEC
1145 # echo shouldn't work without echo source set
Klement Sekera3cfa5582017-04-19 07:10:58 +00001146 for dummy in range(10):
1147 sleep = self.vpp_session.required_min_rx / USEC_IN_SEC
Klement Sekera239790f2017-02-16 10:53:53 +01001148 self.sleep(sleep, "delay before sending bfd packet")
1149 self.test_session.send_packet()
1150 p = wait_for_bfd_packet(
1151 self, pcap_time_min=time.time() - self.vpp_clock_offset)
1152 self.assert_equal(p[BFD].required_min_rx_interval,
1153 self.vpp_session.required_min_rx,
1154 "BFD required min rx interval")
Klement Sekera3cfa5582017-04-19 07:10:58 +00001155 self.test_session.send_packet()
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001156 self.vapi.bfd_udp_set_echo_source(
1157 sw_if_index=self.loopback0.sw_if_index)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001158 echo_seen = False
Klement Sekera239790f2017-02-16 10:53:53 +01001159 # should be turned on - loopback echo packets
1160 for dummy in range(3):
1161 loop_until = time.time() + 0.75 * detection_time
1162 while time.time() < loop_until:
1163 p = self.pg0.wait_for_packet(1)
1164 self.logger.debug(ppp("Got packet:", p))
1165 if p[UDP].dport == BFD.udp_dport_echo:
1166 self.assert_equal(
1167 p[IP].dst, self.pg0.local_ip4, "BFD ECHO dst IP")
1168 self.assertNotEqual(p[IP].src, self.loopback0.local_ip4,
1169 "BFD ECHO src IP equal to loopback IP")
1170 self.logger.debug(ppp("Looping back packet:", p))
John Lo1904c472017-03-10 17:15:22 -05001171 self.assert_equal(p[Ether].dst, self.pg0.remote_mac,
1172 "ECHO packet destination MAC address")
1173 p[Ether].dst = self.pg0.local_mac
Klement Sekera239790f2017-02-16 10:53:53 +01001174 self.pg0.add_stream(p)
1175 self.pg_start()
Klement Sekera3cfa5582017-04-19 07:10:58 +00001176 echo_seen = True
Klement Sekera239790f2017-02-16 10:53:53 +01001177 elif p.haslayer(BFD):
Klement Sekera3cfa5582017-04-19 07:10:58 +00001178 if echo_seen:
1179 self.assertGreaterEqual(
1180 p[BFD].required_min_rx_interval,
1181 1000000)
Klement Sekera239790f2017-02-16 10:53:53 +01001182 if "P" in p.sprintf("%BFD.flags%"):
1183 final = self.test_session.create_packet()
1184 final[BFD].flags = "F"
1185 self.test_session.send_packet(final)
1186 else:
1187 raise Exception(ppp("Received unknown packet:", p))
1188
1189 self.assert_equal(len(self.vapi.collect_events()), 0,
1190 "number of bfd events")
1191 self.test_session.send_packet()
Klement Sekera3cfa5582017-04-19 07:10:58 +00001192 self.assertTrue(echo_seen, "No echo packets received")
Klement Sekera239790f2017-02-16 10:53:53 +01001193
1194 def test_echo_fail(self):
1195 """ session goes down if echo function fails """
1196 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001197 self.test_session.update(required_min_echo_rx=150000)
Klement Sekera239790f2017-02-16 10:53:53 +01001198 self.test_session.send_packet()
1199 detection_time = self.test_session.detect_mult *\
1200 self.vpp_session.required_min_rx / USEC_IN_SEC
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001201 self.vapi.bfd_udp_set_echo_source(
1202 sw_if_index=self.loopback0.sw_if_index)
Klement Sekera239790f2017-02-16 10:53:53 +01001203 # echo function should be used now, but we will drop the echo packets
1204 verified_diag = False
1205 for dummy in range(3):
1206 loop_until = time.time() + 0.75 * detection_time
1207 while time.time() < loop_until:
1208 p = self.pg0.wait_for_packet(1)
1209 self.logger.debug(ppp("Got packet:", p))
1210 if p[UDP].dport == BFD.udp_dport_echo:
1211 # dropped
1212 pass
1213 elif p.haslayer(BFD):
1214 if "P" in p.sprintf("%BFD.flags%"):
1215 self.assertGreaterEqual(
1216 p[BFD].required_min_rx_interval,
1217 1000000)
1218 final = self.test_session.create_packet()
1219 final[BFD].flags = "F"
1220 self.test_session.send_packet(final)
1221 if p[BFD].state == BFDState.down:
1222 self.assert_equal(p[BFD].diag,
1223 BFDDiagCode.echo_function_failed,
1224 BFDDiagCode)
1225 verified_diag = True
1226 else:
1227 raise Exception(ppp("Received unknown packet:", p))
1228 self.test_session.send_packet()
1229 events = self.vapi.collect_events()
1230 self.assert_equal(len(events), 1, "number of bfd events")
1231 self.assert_equal(events[0].state, BFDState.down, BFDState)
1232 self.assertTrue(verified_diag, "Incorrect diagnostics code received")
1233
1234 def test_echo_stop(self):
1235 """ echo function stops if peer sets required min echo rx zero """
1236 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001237 self.test_session.update(required_min_echo_rx=150000)
Klement Sekera239790f2017-02-16 10:53:53 +01001238 self.test_session.send_packet()
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001239 self.vapi.bfd_udp_set_echo_source(
1240 sw_if_index=self.loopback0.sw_if_index)
Klement Sekera239790f2017-02-16 10:53:53 +01001241 # wait for first echo packet
1242 while True:
1243 p = self.pg0.wait_for_packet(1)
1244 self.logger.debug(ppp("Got packet:", p))
1245 if p[UDP].dport == BFD.udp_dport_echo:
1246 self.logger.debug(ppp("Looping back packet:", p))
John Lo1904c472017-03-10 17:15:22 -05001247 p[Ether].dst = self.pg0.local_mac
Klement Sekera239790f2017-02-16 10:53:53 +01001248 self.pg0.add_stream(p)
1249 self.pg_start()
1250 break
1251 elif p.haslayer(BFD):
1252 # ignore BFD
1253 pass
1254 else:
1255 raise Exception(ppp("Received unknown packet:", p))
1256 self.test_session.update(required_min_echo_rx=0)
1257 self.test_session.send_packet()
1258 # echo packets shouldn't arrive anymore
1259 for dummy in range(5):
1260 wait_for_bfd_packet(
1261 self, pcap_time_min=time.time() - self.vpp_clock_offset)
1262 self.test_session.send_packet()
1263 events = self.vapi.collect_events()
1264 self.assert_equal(len(events), 0, "number of bfd events")
1265
Klement Sekera73884482017-02-23 09:26:30 +01001266 def test_echo_source_removed(self):
1267 """ echo function stops if echo source is removed """
1268 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001269 self.test_session.update(required_min_echo_rx=150000)
Klement Sekera73884482017-02-23 09:26:30 +01001270 self.test_session.send_packet()
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001271 self.vapi.bfd_udp_set_echo_source(
1272 sw_if_index=self.loopback0.sw_if_index)
Klement Sekera73884482017-02-23 09:26:30 +01001273 # wait for first echo packet
1274 while True:
1275 p = self.pg0.wait_for_packet(1)
1276 self.logger.debug(ppp("Got packet:", p))
1277 if p[UDP].dport == BFD.udp_dport_echo:
1278 self.logger.debug(ppp("Looping back packet:", p))
John Lo1904c472017-03-10 17:15:22 -05001279 p[Ether].dst = self.pg0.local_mac
Klement Sekera73884482017-02-23 09:26:30 +01001280 self.pg0.add_stream(p)
1281 self.pg_start()
1282 break
1283 elif p.haslayer(BFD):
1284 # ignore BFD
1285 pass
1286 else:
1287 raise Exception(ppp("Received unknown packet:", p))
1288 self.vapi.bfd_udp_del_echo_source()
1289 self.test_session.send_packet()
1290 # echo packets shouldn't arrive anymore
1291 for dummy in range(5):
1292 wait_for_bfd_packet(
1293 self, pcap_time_min=time.time() - self.vpp_clock_offset)
1294 self.test_session.send_packet()
1295 events = self.vapi.collect_events()
1296 self.assert_equal(len(events), 0, "number of bfd events")
1297
Klement Sekera239790f2017-02-16 10:53:53 +01001298 def test_stale_echo(self):
1299 """ stale echo packets don't keep a session up """
1300 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001301 self.test_session.update(required_min_echo_rx=150000)
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001302 self.vapi.bfd_udp_set_echo_source(
1303 sw_if_index=self.loopback0.sw_if_index)
Klement Sekera239790f2017-02-16 10:53:53 +01001304 self.test_session.send_packet()
1305 # should be turned on - loopback echo packets
1306 echo_packet = None
1307 timeout_at = None
1308 timeout_ok = False
1309 for dummy in range(10 * self.vpp_session.detect_mult):
1310 p = self.pg0.wait_for_packet(1)
1311 if p[UDP].dport == BFD.udp_dport_echo:
1312 if echo_packet is None:
1313 self.logger.debug(ppp("Got first echo packet:", p))
1314 echo_packet = p
1315 timeout_at = time.time() + self.vpp_session.detect_mult * \
1316 self.test_session.required_min_echo_rx / USEC_IN_SEC
1317 else:
1318 self.logger.debug(ppp("Got followup echo packet:", p))
1319 self.logger.debug(ppp("Looping back first echo packet:", p))
John Lo1904c472017-03-10 17:15:22 -05001320 echo_packet[Ether].dst = self.pg0.local_mac
Klement Sekera239790f2017-02-16 10:53:53 +01001321 self.pg0.add_stream(echo_packet)
1322 self.pg_start()
1323 elif p.haslayer(BFD):
1324 self.logger.debug(ppp("Got packet:", p))
1325 if "P" in p.sprintf("%BFD.flags%"):
1326 final = self.test_session.create_packet()
1327 final[BFD].flags = "F"
1328 self.test_session.send_packet(final)
1329 if p[BFD].state == BFDState.down:
1330 self.assertIsNotNone(
1331 timeout_at,
1332 "Session went down before first echo packet received")
1333 now = time.time()
1334 self.assertGreaterEqual(
1335 now, timeout_at,
1336 "Session timeout at %s, but is expected at %s" %
1337 (now, timeout_at))
1338 self.assert_equal(p[BFD].diag,
1339 BFDDiagCode.echo_function_failed,
1340 BFDDiagCode)
1341 events = self.vapi.collect_events()
1342 self.assert_equal(len(events), 1, "number of bfd events")
1343 self.assert_equal(events[0].state, BFDState.down, BFDState)
1344 timeout_ok = True
1345 break
1346 else:
1347 raise Exception(ppp("Received unknown packet:", p))
1348 self.test_session.send_packet()
1349 self.assertTrue(timeout_ok, "Expected timeout event didn't occur")
1350
1351 def test_invalid_echo_checksum(self):
1352 """ echo packets with invalid checksum don't keep a session up """
1353 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001354 self.test_session.update(required_min_echo_rx=150000)
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001355 self.vapi.bfd_udp_set_echo_source(
1356 sw_if_index=self.loopback0.sw_if_index)
Klement Sekera239790f2017-02-16 10:53:53 +01001357 self.test_session.send_packet()
1358 # should be turned on - loopback echo packets
1359 timeout_at = None
1360 timeout_ok = False
1361 for dummy in range(10 * self.vpp_session.detect_mult):
1362 p = self.pg0.wait_for_packet(1)
1363 if p[UDP].dport == BFD.udp_dport_echo:
1364 self.logger.debug(ppp("Got echo packet:", p))
1365 if timeout_at is None:
1366 timeout_at = time.time() + self.vpp_session.detect_mult * \
1367 self.test_session.required_min_echo_rx / USEC_IN_SEC
1368 p[BFD_vpp_echo].checksum = getrandbits(64)
John Lo1904c472017-03-10 17:15:22 -05001369 p[Ether].dst = self.pg0.local_mac
Klement Sekera239790f2017-02-16 10:53:53 +01001370 self.logger.debug(ppp("Looping back modified echo packet:", p))
1371 self.pg0.add_stream(p)
1372 self.pg_start()
1373 elif p.haslayer(BFD):
1374 self.logger.debug(ppp("Got packet:", p))
1375 if "P" in p.sprintf("%BFD.flags%"):
1376 final = self.test_session.create_packet()
1377 final[BFD].flags = "F"
1378 self.test_session.send_packet(final)
1379 if p[BFD].state == BFDState.down:
1380 self.assertIsNotNone(
1381 timeout_at,
1382 "Session went down before first echo packet received")
1383 now = time.time()
1384 self.assertGreaterEqual(
1385 now, timeout_at,
1386 "Session timeout at %s, but is expected at %s" %
1387 (now, timeout_at))
1388 self.assert_equal(p[BFD].diag,
1389 BFDDiagCode.echo_function_failed,
1390 BFDDiagCode)
1391 events = self.vapi.collect_events()
1392 self.assert_equal(len(events), 1, "number of bfd events")
1393 self.assert_equal(events[0].state, BFDState.down, BFDState)
1394 timeout_ok = True
1395 break
1396 else:
1397 raise Exception(ppp("Received unknown packet:", p))
1398 self.test_session.send_packet()
1399 self.assertTrue(timeout_ok, "Expected timeout event didn't occur")
1400
Klement Sekerac48829b2017-02-14 07:55:57 +01001401 def test_admin_up_down(self):
Klement Sekera239790f2017-02-16 10:53:53 +01001402 """ put session admin-up and admin-down """
Klement Sekerac48829b2017-02-14 07:55:57 +01001403 bfd_session_up(self)
1404 self.vpp_session.admin_down()
1405 self.pg0.enable_capture()
1406 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
1407 verify_event(self, e, expected_state=BFDState.admin_down)
1408 for dummy in range(2):
1409 p = wait_for_bfd_packet(self)
Klement Sekera73884482017-02-23 09:26:30 +01001410 self.assert_equal(p[BFD].state, BFDState.admin_down, BFDState)
Klement Sekerac48829b2017-02-14 07:55:57 +01001411 # try to bring session up - shouldn't be possible
1412 self.test_session.update(state=BFDState.init)
1413 self.test_session.send_packet()
1414 for dummy in range(2):
1415 p = wait_for_bfd_packet(self)
Klement Sekera73884482017-02-23 09:26:30 +01001416 self.assert_equal(p[BFD].state, BFDState.admin_down, BFDState)
Klement Sekerac48829b2017-02-14 07:55:57 +01001417 self.vpp_session.admin_up()
1418 self.test_session.update(state=BFDState.down)
1419 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
1420 verify_event(self, e, expected_state=BFDState.down)
Klement Sekera73884482017-02-23 09:26:30 +01001421 p = wait_for_bfd_packet(
1422 self, pcap_time_min=time.time() - self.vpp_clock_offset)
1423 self.assert_equal(p[BFD].state, BFDState.down, BFDState)
Klement Sekerac48829b2017-02-14 07:55:57 +01001424 self.test_session.send_packet()
Klement Sekera73884482017-02-23 09:26:30 +01001425 p = wait_for_bfd_packet(
1426 self, pcap_time_min=time.time() - self.vpp_clock_offset)
1427 self.assert_equal(p[BFD].state, BFDState.init, BFDState)
Klement Sekerac48829b2017-02-14 07:55:57 +01001428 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
1429 verify_event(self, e, expected_state=BFDState.init)
1430 self.test_session.update(state=BFDState.up)
1431 self.test_session.send_packet()
Klement Sekera73884482017-02-23 09:26:30 +01001432 p = wait_for_bfd_packet(
1433 self, pcap_time_min=time.time() - self.vpp_clock_offset)
1434 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerac48829b2017-02-14 07:55:57 +01001435 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
1436 verify_event(self, e, expected_state=BFDState.up)
1437
Klement Sekera239790f2017-02-16 10:53:53 +01001438 def test_config_change_remote_demand(self):
1439 """ configuration change while peer in demand mode """
1440 bfd_session_up(self)
1441 demand = self.test_session.create_packet()
1442 demand[BFD].flags = "D"
1443 self.test_session.send_packet(demand)
1444 self.vpp_session.modify_parameters(
1445 required_min_rx=2 * self.vpp_session.required_min_rx)
Klement Sekera73884482017-02-23 09:26:30 +01001446 p = wait_for_bfd_packet(
1447 self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekera239790f2017-02-16 10:53:53 +01001448 # poll bit must be set
1449 self.assertIn("P", p.sprintf("%BFD.flags%"), "Poll bit not set")
1450 # terminate poll sequence
1451 final = self.test_session.create_packet()
1452 final[BFD].flags = "D+F"
1453 self.test_session.send_packet(final)
1454 # vpp should be quiet now again
1455 transmit_time = 0.9 \
1456 * max(self.vpp_session.required_min_rx,
1457 self.test_session.desired_min_tx) \
1458 / USEC_IN_SEC
1459 count = 0
1460 for dummy in range(self.test_session.detect_mult * 2):
Paul Vinciguerra0f6602c2019-03-10 09:10:54 -07001461 self.sleep(transmit_time)
Klement Sekera239790f2017-02-16 10:53:53 +01001462 self.test_session.send_packet(demand)
1463 try:
1464 p = wait_for_bfd_packet(self, timeout=0)
1465 self.logger.error(ppp("Received unexpected packet:", p))
1466 count += 1
1467 except CaptureTimeoutError:
1468 pass
1469 events = self.vapi.collect_events()
1470 for e in events:
1471 self.logger.error("Received unexpected event: %s", e)
1472 self.assert_equal(count, 0, "number of packets received")
1473 self.assert_equal(len(events), 0, "number of events received")
1474
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001475 def test_intf_deleted(self):
1476 """ interface with bfd session deleted """
Klement Sekerabeaded52018-06-24 10:30:37 +02001477 intf = VppLoInterface(self)
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001478 intf.config_ip4()
1479 intf.admin_up()
1480 sw_if_index = intf.sw_if_index
1481 vpp_session = VppBFDUDPSession(self, intf, intf.remote_ip4)
1482 vpp_session.add_vpp_config()
1483 vpp_session.admin_up()
1484 intf.remove_vpp_config()
1485 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
1486 self.assert_equal(e.sw_if_index, sw_if_index, "sw_if_index")
1487 self.assertFalse(vpp_session.query_vpp_config())
1488
Klement Sekerad3ba5152017-02-14 03:09:17 +01001489
Andrew Yourtchenko06f32812021-01-14 10:19:08 +00001490@tag_run_solo
Klement Sekerad3ba5152017-02-14 03:09:17 +01001491class BFD6TestCase(VppTestCase):
Klement Sekera46a87ad2017-01-02 08:22:23 +01001492 """Bidirectional Forwarding Detection (BFD) (IPv6) """
1493
Klement Sekerad3ba5152017-02-14 03:09:17 +01001494 pg0 = None
1495 vpp_clock_offset = None
1496 vpp_session = None
1497 test_session = None
1498
Klement Sekera46a87ad2017-01-02 08:22:23 +01001499 @classmethod
1500 def setUpClass(cls):
1501 super(BFD6TestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -08001502 cls.vapi.cli("set log class bfd level debug")
Klement Sekera46a87ad2017-01-02 08:22:23 +01001503 try:
1504 cls.create_pg_interfaces([0])
1505 cls.pg0.config_ip6()
1506 cls.pg0.configure_ipv6_neighbors()
1507 cls.pg0.admin_up()
1508 cls.pg0.resolve_ndp()
Klement Sekerab9ef2732018-06-24 22:49:33 +02001509 cls.create_loopback_interfaces(1)
Klement Sekera239790f2017-02-16 10:53:53 +01001510 cls.loopback0 = cls.lo_interfaces[0]
1511 cls.loopback0.config_ip6()
1512 cls.loopback0.admin_up()
Klement Sekera46a87ad2017-01-02 08:22:23 +01001513
1514 except Exception:
1515 super(BFD6TestCase, cls).tearDownClass()
1516 raise
1517
Paul Vinciguerra8d991d92019-01-25 14:05:48 -08001518 @classmethod
1519 def tearDownClass(cls):
1520 super(BFD6TestCase, cls).tearDownClass()
1521
Klement Sekera46a87ad2017-01-02 08:22:23 +01001522 def setUp(self):
1523 super(BFD6TestCase, self).setUp()
Klement Sekerab17dd962017-01-09 07:43:48 +01001524 self.factory = AuthKeyFactory()
Klement Sekera46a87ad2017-01-02 08:22:23 +01001525 self.vapi.want_bfd_events()
Klement Sekerad3ba5152017-02-14 03:09:17 +01001526 self.pg0.enable_capture()
Klement Sekera46a87ad2017-01-02 08:22:23 +01001527 try:
1528 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1529 self.pg0.remote_ip6,
1530 af=AF_INET6)
1531 self.vpp_session.add_vpp_config()
1532 self.vpp_session.admin_up()
1533 self.test_session = BFDTestSession(self, self.pg0, AF_INET6)
1534 self.logger.debug(self.vapi.cli("show adj nbr"))
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001535 except BaseException:
Klement Sekera46a87ad2017-01-02 08:22:23 +01001536 self.vapi.want_bfd_events(enable_disable=0)
1537 raise
1538
1539 def tearDown(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001540 if not self.vpp_dead:
1541 self.vapi.want_bfd_events(enable_disable=0)
1542 self.vapi.collect_events() # clear the event queue
1543 super(BFD6TestCase, self).tearDown()
Klement Sekerab17dd962017-01-09 07:43:48 +01001544
1545 def test_session_up(self):
1546 """ bring BFD session up """
Klement Sekerad3ba5152017-02-14 03:09:17 +01001547 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001548
Klement Sekera73884482017-02-23 09:26:30 +01001549 def test_session_up_by_ip(self):
1550 """ bring BFD session up - first frame looked up by address pair """
1551 self.logger.info("BFD: Sending Slow control frame")
1552 self.test_session.update(my_discriminator=randint(0, 40000000))
1553 self.test_session.send_packet()
1554 self.pg0.enable_capture()
1555 p = self.pg0.wait_for_packet(1)
1556 self.assert_equal(p[BFD].your_discriminator,
1557 self.test_session.my_discriminator,
1558 "BFD - your discriminator")
1559 self.assert_equal(p[BFD].state, BFDState.init, BFDState)
1560 self.test_session.update(your_discriminator=p[BFD].my_discriminator,
1561 state=BFDState.up)
1562 self.logger.info("BFD: Waiting for event")
1563 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
1564 verify_event(self, e, expected_state=BFDState.init)
1565 self.logger.info("BFD: Sending Up")
1566 self.test_session.send_packet()
1567 self.logger.info("BFD: Waiting for event")
1568 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
1569 verify_event(self, e, expected_state=BFDState.up)
1570 self.logger.info("BFD: Session is Up")
1571 self.test_session.update(state=BFDState.up)
1572 self.test_session.send_packet()
1573 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1574
Klement Sekerab17dd962017-01-09 07:43:48 +01001575 def test_hold_up(self):
1576 """ hold BFD session up """
Klement Sekerad3ba5152017-02-14 03:09:17 +01001577 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001578 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001579 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001580 self.test_session.send_packet()
1581 self.assert_equal(len(self.vapi.collect_events()), 0,
1582 "number of bfd events")
1583 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1584
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001585 def test_echo_looped_back(self):
1586 """ echo packets looped back """
1587 # don't need a session in this case..
1588 self.vpp_session.remove_vpp_config()
1589 self.pg0.enable_capture()
1590 echo_packet_count = 10
1591 # random source port low enough to increment a few times..
1592 udp_sport_tx = randint(1, 50000)
1593 udp_sport_rx = udp_sport_tx
1594 echo_packet = (Ether(src=self.pg0.remote_mac,
1595 dst=self.pg0.local_mac) /
1596 IPv6(src=self.pg0.remote_ip6,
Klement Sekera239790f2017-02-16 10:53:53 +01001597 dst=self.pg0.remote_ip6) /
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001598 UDP(dport=BFD.udp_dport_echo) /
1599 Raw("this should be looped back"))
1600 for dummy in range(echo_packet_count):
1601 self.sleep(.01, "delay between echo packets")
1602 echo_packet[UDP].sport = udp_sport_tx
1603 udp_sport_tx += 1
1604 self.logger.debug(ppp("Sending packet:", echo_packet))
1605 self.pg0.add_stream(echo_packet)
1606 self.pg_start()
1607 for dummy in range(echo_packet_count):
1608 p = self.pg0.wait_for_packet(1)
1609 self.logger.debug(ppp("Got packet:", p))
1610 ether = p[Ether]
1611 self.assert_equal(self.pg0.remote_mac,
1612 ether.dst, "Destination MAC")
1613 self.assert_equal(self.pg0.local_mac, ether.src, "Source MAC")
1614 ip = p[IPv6]
1615 self.assert_equal(self.pg0.remote_ip6, ip.dst, "Destination IP")
Klement Sekera239790f2017-02-16 10:53:53 +01001616 self.assert_equal(self.pg0.remote_ip6, ip.src, "Destination IP")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001617 udp = p[UDP]
1618 self.assert_equal(udp.dport, BFD.udp_dport_echo,
1619 "UDP destination port")
1620 self.assert_equal(udp.sport, udp_sport_rx, "UDP source port")
1621 udp_sport_rx += 1
Klement Sekera239790f2017-02-16 10:53:53 +01001622 # need to compare the hex payload here, otherwise BFD_vpp_echo
1623 # gets in way
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07001624 self.assertEqual(scapy.compat.raw(p[UDP].payload),
1625 scapy.compat.raw(echo_packet[UDP].payload),
Klement Sekera239790f2017-02-16 10:53:53 +01001626 "Received packet is not the echo packet sent")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001627 self.assert_equal(udp_sport_tx, udp_sport_rx, "UDP source port (== "
1628 "ECHO packet identifier for test purposes)")
Klement Sekera239790f2017-02-16 10:53:53 +01001629 self.assert_equal(udp_sport_tx, udp_sport_rx, "UDP source port (== "
1630 "ECHO packet identifier for test purposes)")
1631
1632 def test_echo(self):
Klement Sekera3cfa5582017-04-19 07:10:58 +00001633 """ echo function """
Klement Sekera239790f2017-02-16 10:53:53 +01001634 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001635 self.test_session.update(required_min_echo_rx=150000)
Klement Sekera239790f2017-02-16 10:53:53 +01001636 self.test_session.send_packet()
1637 detection_time = self.test_session.detect_mult *\
1638 self.vpp_session.required_min_rx / USEC_IN_SEC
1639 # echo shouldn't work without echo source set
Klement Sekera3cfa5582017-04-19 07:10:58 +00001640 for dummy in range(10):
1641 sleep = self.vpp_session.required_min_rx / USEC_IN_SEC
Klement Sekera239790f2017-02-16 10:53:53 +01001642 self.sleep(sleep, "delay before sending bfd packet")
1643 self.test_session.send_packet()
1644 p = wait_for_bfd_packet(
1645 self, pcap_time_min=time.time() - self.vpp_clock_offset)
1646 self.assert_equal(p[BFD].required_min_rx_interval,
1647 self.vpp_session.required_min_rx,
1648 "BFD required min rx interval")
Klement Sekera3cfa5582017-04-19 07:10:58 +00001649 self.test_session.send_packet()
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001650 self.vapi.bfd_udp_set_echo_source(
1651 sw_if_index=self.loopback0.sw_if_index)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001652 echo_seen = False
Klement Sekera239790f2017-02-16 10:53:53 +01001653 # should be turned on - loopback echo packets
1654 for dummy in range(3):
1655 loop_until = time.time() + 0.75 * detection_time
1656 while time.time() < loop_until:
1657 p = self.pg0.wait_for_packet(1)
1658 self.logger.debug(ppp("Got packet:", p))
1659 if p[UDP].dport == BFD.udp_dport_echo:
1660 self.assert_equal(
1661 p[IPv6].dst, self.pg0.local_ip6, "BFD ECHO dst IP")
1662 self.assertNotEqual(p[IPv6].src, self.loopback0.local_ip6,
1663 "BFD ECHO src IP equal to loopback IP")
1664 self.logger.debug(ppp("Looping back packet:", p))
John Lo1904c472017-03-10 17:15:22 -05001665 self.assert_equal(p[Ether].dst, self.pg0.remote_mac,
1666 "ECHO packet destination MAC address")
1667 p[Ether].dst = self.pg0.local_mac
Klement Sekera239790f2017-02-16 10:53:53 +01001668 self.pg0.add_stream(p)
1669 self.pg_start()
Klement Sekera3cfa5582017-04-19 07:10:58 +00001670 echo_seen = True
Klement Sekera239790f2017-02-16 10:53:53 +01001671 elif p.haslayer(BFD):
Klement Sekera3cfa5582017-04-19 07:10:58 +00001672 if echo_seen:
1673 self.assertGreaterEqual(
1674 p[BFD].required_min_rx_interval,
1675 1000000)
Klement Sekera239790f2017-02-16 10:53:53 +01001676 if "P" in p.sprintf("%BFD.flags%"):
1677 final = self.test_session.create_packet()
1678 final[BFD].flags = "F"
1679 self.test_session.send_packet(final)
1680 else:
1681 raise Exception(ppp("Received unknown packet:", p))
1682
1683 self.assert_equal(len(self.vapi.collect_events()), 0,
1684 "number of bfd events")
1685 self.test_session.send_packet()
Klement Sekera3cfa5582017-04-19 07:10:58 +00001686 self.assertTrue(echo_seen, "No echo packets received")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001687
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001688 def test_intf_deleted(self):
1689 """ interface with bfd session deleted """
Klement Sekerabeaded52018-06-24 10:30:37 +02001690 intf = VppLoInterface(self)
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001691 intf.config_ip6()
1692 intf.admin_up()
1693 sw_if_index = intf.sw_if_index
1694 vpp_session = VppBFDUDPSession(
1695 self, intf, intf.remote_ip6, af=AF_INET6)
1696 vpp_session.add_vpp_config()
1697 vpp_session.admin_up()
1698 intf.remove_vpp_config()
1699 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
1700 self.assert_equal(e.sw_if_index, sw_if_index, "sw_if_index")
1701 self.assertFalse(vpp_session.query_vpp_config())
1702
Klement Sekerab17dd962017-01-09 07:43:48 +01001703
Andrew Yourtchenko06f32812021-01-14 10:19:08 +00001704@tag_run_solo
Neale Ranns88fc83e2017-04-05 08:11:14 -07001705class BFDFIBTestCase(VppTestCase):
1706 """ BFD-FIB interactions (IPv6) """
1707
1708 vpp_session = None
1709 test_session = None
1710
Paul Vinciguerra8d991d92019-01-25 14:05:48 -08001711 @classmethod
1712 def setUpClass(cls):
1713 super(BFDFIBTestCase, cls).setUpClass()
1714
1715 @classmethod
1716 def tearDownClass(cls):
1717 super(BFDFIBTestCase, cls).tearDownClass()
1718
Neale Ranns88fc83e2017-04-05 08:11:14 -07001719 def setUp(self):
1720 super(BFDFIBTestCase, self).setUp()
1721 self.create_pg_interfaces(range(1))
1722
1723 self.vapi.want_bfd_events()
1724 self.pg0.enable_capture()
1725
1726 for i in self.pg_interfaces:
1727 i.admin_up()
1728 i.config_ip6()
1729 i.configure_ipv6_neighbors()
1730
1731 def tearDown(self):
1732 if not self.vpp_dead:
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001733 self.vapi.want_bfd_events(enable_disable=False)
Neale Ranns88fc83e2017-04-05 08:11:14 -07001734
1735 super(BFDFIBTestCase, self).tearDown()
1736
1737 @staticmethod
1738 def pkt_is_not_data_traffic(p):
1739 """ not data traffic implies BFD or the usual IPv6 ND/RA"""
1740 if p.haslayer(BFD) or is_ipv6_misc(p):
1741 return True
1742 return False
1743
1744 def test_session_with_fib(self):
1745 """ BFD-FIB interactions """
1746
1747 # packets to match against both of the routes
1748 p = [(Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
Klement Sekera3cfa5582017-04-19 07:10:58 +00001749 IPv6(src="3001::1", dst="2001::1") /
1750 UDP(sport=1234, dport=1234) /
Ole Troan770a0de2019-11-07 13:52:21 +01001751 Raw(b'\xa5' * 100)),
Neale Ranns88fc83e2017-04-05 08:11:14 -07001752 (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1753 IPv6(src="3001::1", dst="2002::1") /
1754 UDP(sport=1234, dport=1234) /
Ole Troan770a0de2019-11-07 13:52:21 +01001755 Raw(b'\xa5' * 100))]
Neale Ranns88fc83e2017-04-05 08:11:14 -07001756
1757 # A recursive and a non-recursive route via a next-hop that
1758 # will have a BFD session
1759 ip_2001_s_64 = VppIpRoute(self, "2001::", 64,
1760 [VppRoutePath(self.pg0.remote_ip6,
Neale Ranns097fa662018-05-01 05:17:55 -07001761 self.pg0.sw_if_index)])
Neale Ranns88fc83e2017-04-05 08:11:14 -07001762 ip_2002_s_64 = VppIpRoute(self, "2002::", 64,
1763 [VppRoutePath(self.pg0.remote_ip6,
Neale Ranns097fa662018-05-01 05:17:55 -07001764 0xffffffff)])
Neale Ranns88fc83e2017-04-05 08:11:14 -07001765 ip_2001_s_64.add_vpp_config()
1766 ip_2002_s_64.add_vpp_config()
1767
1768 # bring the session up now the routes are present
1769 self.vpp_session = VppBFDUDPSession(self,
1770 self.pg0,
1771 self.pg0.remote_ip6,
1772 af=AF_INET6)
1773 self.vpp_session.add_vpp_config()
1774 self.vpp_session.admin_up()
1775 self.test_session = BFDTestSession(self, self.pg0, AF_INET6)
1776
1777 # session is up - traffic passes
1778 bfd_session_up(self)
1779
1780 self.pg0.add_stream(p)
1781 self.pg_start()
1782 for packet in p:
1783 captured = self.pg0.wait_for_packet(
1784 1,
1785 filter_out_fn=self.pkt_is_not_data_traffic)
1786 self.assertEqual(captured[IPv6].dst,
1787 packet[IPv6].dst)
1788
1789 # session is up - traffic is dropped
1790 bfd_session_down(self)
1791
1792 self.pg0.add_stream(p)
1793 self.pg_start()
1794 with self.assertRaises(CaptureTimeoutError):
1795 self.pg0.wait_for_packet(1, self.pkt_is_not_data_traffic)
1796
1797 # session is up - traffic passes
1798 bfd_session_up(self)
1799
1800 self.pg0.add_stream(p)
1801 self.pg_start()
1802 for packet in p:
1803 captured = self.pg0.wait_for_packet(
1804 1,
1805 filter_out_fn=self.pkt_is_not_data_traffic)
1806 self.assertEqual(captured[IPv6].dst,
1807 packet[IPv6].dst)
1808
1809
Paul Vinciguerra61e3ade2019-12-04 23:38:12 -05001810@unittest.skipUnless(running_extended_tests, "part of extended tests")
Neale Ranns52cd4962019-06-05 10:28:17 +00001811class BFDTunTestCase(VppTestCase):
1812 """ BFD over GRE tunnel """
1813
1814 vpp_session = None
1815 test_session = None
1816
1817 @classmethod
1818 def setUpClass(cls):
1819 super(BFDTunTestCase, cls).setUpClass()
1820
1821 @classmethod
1822 def tearDownClass(cls):
1823 super(BFDTunTestCase, cls).tearDownClass()
1824
1825 def setUp(self):
1826 super(BFDTunTestCase, self).setUp()
1827 self.create_pg_interfaces(range(1))
1828
1829 self.vapi.want_bfd_events()
1830 self.pg0.enable_capture()
1831
1832 for i in self.pg_interfaces:
1833 i.admin_up()
1834 i.config_ip4()
1835 i.resolve_arp()
1836
1837 def tearDown(self):
1838 if not self.vpp_dead:
1839 self.vapi.want_bfd_events(enable_disable=0)
1840
1841 super(BFDTunTestCase, self).tearDown()
1842
1843 @staticmethod
1844 def pkt_is_not_data_traffic(p):
1845 """ not data traffic implies BFD or the usual IPv6 ND/RA"""
1846 if p.haslayer(BFD) or is_ipv6_misc(p):
1847 return True
1848 return False
1849
1850 def test_bfd_o_gre(self):
1851 """ BFD-o-GRE """
1852
1853 # A GRE interface over which to run a BFD session
1854 gre_if = VppGreInterface(self,
1855 self.pg0.local_ip4,
1856 self.pg0.remote_ip4)
1857 gre_if.add_vpp_config()
1858 gre_if.admin_up()
1859 gre_if.config_ip4()
1860
1861 # bring the session up now the routes are present
1862 self.vpp_session = VppBFDUDPSession(self,
1863 gre_if,
1864 gre_if.remote_ip4,
1865 is_tunnel=True)
1866 self.vpp_session.add_vpp_config()
1867 self.vpp_session.admin_up()
1868
1869 self.test_session = BFDTestSession(
1870 self, gre_if, AF_INET,
1871 tunnel_header=(IP(src=self.pg0.remote_ip4,
1872 dst=self.pg0.local_ip4) /
1873 GRE()),
1874 phy_interface=self.pg0)
1875
1876 # packets to match against both of the routes
1877 p = [(Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1878 IP(src=self.pg0.remote_ip4, dst=gre_if.remote_ip4) /
1879 UDP(sport=1234, dport=1234) /
Ole Troan770a0de2019-11-07 13:52:21 +01001880 Raw(b'\xa5' * 100))]
Neale Ranns52cd4962019-06-05 10:28:17 +00001881
1882 # session is up - traffic passes
1883 bfd_session_up(self)
1884
1885 self.send_and_expect(self.pg0, p, self.pg0)
1886
1887 # bring session down
1888 bfd_session_down(self)
1889
1890
Andrew Yourtchenko06f32812021-01-14 10:19:08 +00001891@tag_run_solo
Klement Sekerad3ba5152017-02-14 03:09:17 +01001892class BFDSHA1TestCase(VppTestCase):
Klement Sekerab17dd962017-01-09 07:43:48 +01001893 """Bidirectional Forwarding Detection (BFD) (SHA1 auth) """
1894
Klement Sekerad3ba5152017-02-14 03:09:17 +01001895 pg0 = None
1896 vpp_clock_offset = None
1897 vpp_session = None
1898 test_session = None
1899
Klement Sekerab17dd962017-01-09 07:43:48 +01001900 @classmethod
1901 def setUpClass(cls):
1902 super(BFDSHA1TestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -08001903 cls.vapi.cli("set log class bfd level debug")
Klement Sekerab17dd962017-01-09 07:43:48 +01001904 try:
1905 cls.create_pg_interfaces([0])
1906 cls.pg0.config_ip4()
1907 cls.pg0.admin_up()
1908 cls.pg0.resolve_arp()
1909
1910 except Exception:
1911 super(BFDSHA1TestCase, cls).tearDownClass()
1912 raise
1913
Paul Vinciguerra8d991d92019-01-25 14:05:48 -08001914 @classmethod
1915 def tearDownClass(cls):
1916 super(BFDSHA1TestCase, cls).tearDownClass()
1917
Klement Sekerab17dd962017-01-09 07:43:48 +01001918 def setUp(self):
1919 super(BFDSHA1TestCase, self).setUp()
1920 self.factory = AuthKeyFactory()
1921 self.vapi.want_bfd_events()
Klement Sekerad3ba5152017-02-14 03:09:17 +01001922 self.pg0.enable_capture()
Klement Sekerab17dd962017-01-09 07:43:48 +01001923
1924 def tearDown(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001925 if not self.vpp_dead:
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001926 self.vapi.want_bfd_events(enable_disable=False)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001927 self.vapi.collect_events() # clear the event queue
1928 super(BFDSHA1TestCase, self).tearDown()
Klement Sekerab17dd962017-01-09 07:43:48 +01001929
1930 def test_session_up(self):
1931 """ bring BFD session up """
1932 key = self.factory.create_random_key(self)
1933 key.add_vpp_config()
1934 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1935 self.pg0.remote_ip4,
1936 sha1_key=key)
1937 self.vpp_session.add_vpp_config()
1938 self.vpp_session.admin_up()
1939 self.test_session = BFDTestSession(
1940 self, self.pg0, AF_INET, sha1_key=key,
1941 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001942 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001943
1944 def test_hold_up(self):
1945 """ hold BFD session up """
1946 key = self.factory.create_random_key(self)
1947 key.add_vpp_config()
1948 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1949 self.pg0.remote_ip4,
1950 sha1_key=key)
1951 self.vpp_session.add_vpp_config()
1952 self.vpp_session.admin_up()
1953 self.test_session = BFDTestSession(
1954 self, self.pg0, AF_INET, sha1_key=key,
1955 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001956 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001957 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001958 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001959 self.test_session.send_packet()
1960 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1961
1962 def test_hold_up_meticulous(self):
1963 """ hold BFD session up - meticulous auth """
1964 key = self.factory.create_random_key(
1965 self, BFDAuthType.meticulous_keyed_sha1)
1966 key.add_vpp_config()
1967 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1968 self.pg0.remote_ip4, sha1_key=key)
1969 self.vpp_session.add_vpp_config()
1970 self.vpp_session.admin_up()
Klement Sekerad3ba5152017-02-14 03:09:17 +01001971 # specify sequence number so that it wraps
Klement Sekerab17dd962017-01-09 07:43:48 +01001972 self.test_session = BFDTestSession(
1973 self, self.pg0, AF_INET, sha1_key=key,
Klement Sekerad3ba5152017-02-14 03:09:17 +01001974 bfd_key_id=self.vpp_session.bfd_key_id,
1975 our_seq_number=0xFFFFFFFF - 4)
1976 bfd_session_up(self)
1977 for dummy in range(30):
1978 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001979 self.test_session.inc_seq_num()
1980 self.test_session.send_packet()
1981 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1982
1983 def test_send_bad_seq_number(self):
Klement Sekera239790f2017-02-16 10:53:53 +01001984 """ session is not kept alive by msgs with bad sequence numbers"""
Klement Sekerab17dd962017-01-09 07:43:48 +01001985 key = self.factory.create_random_key(
1986 self, BFDAuthType.meticulous_keyed_sha1)
1987 key.add_vpp_config()
1988 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1989 self.pg0.remote_ip4, sha1_key=key)
1990 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01001991 self.test_session = BFDTestSession(
1992 self, self.pg0, AF_INET, sha1_key=key,
1993 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001994 bfd_session_up(self)
Klement Sekera239790f2017-02-16 10:53:53 +01001995 detection_time = self.test_session.detect_mult *\
Klement Sekerad3ba5152017-02-14 03:09:17 +01001996 self.vpp_session.required_min_rx / USEC_IN_SEC
Klement Sekera239790f2017-02-16 10:53:53 +01001997 send_until = time.time() + 2 * detection_time
1998 while time.time() < send_until:
Klement Sekerad3ba5152017-02-14 03:09:17 +01001999 self.test_session.send_packet()
Klement Sekera239790f2017-02-16 10:53:53 +01002000 self.sleep(0.7 * self.vpp_session.required_min_rx / USEC_IN_SEC,
2001 "time between bfd packets")
Klement Sekerab17dd962017-01-09 07:43:48 +01002002 e = self.vapi.collect_events()
2003 # session should be down now, because the sequence numbers weren't
2004 # updated
2005 self.assert_equal(len(e), 1, "number of bfd events")
Klement Sekerad3ba5152017-02-14 03:09:17 +01002006 verify_event(self, e[0], expected_state=BFDState.down)
Klement Sekerab17dd962017-01-09 07:43:48 +01002007
2008 def execute_rogue_session_scenario(self, vpp_bfd_udp_session,
2009 legitimate_test_session,
2010 rogue_test_session,
2011 rogue_bfd_values=None):
2012 """ execute a rogue session interaction scenario
2013
2014 1. create vpp session, add config
2015 2. bring the legitimate session up
2016 3. copy the bfd values from legitimate session to rogue session
2017 4. apply rogue_bfd_values to rogue session
2018 5. set rogue session state to down
2019 6. send message to take the session down from the rogue session
2020 7. assert that the legitimate session is unaffected
2021 """
2022
2023 self.vpp_session = vpp_bfd_udp_session
2024 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002025 self.test_session = legitimate_test_session
2026 # bring vpp session up
Klement Sekerad3ba5152017-02-14 03:09:17 +01002027 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002028 # send packet from rogue session
Klement Sekerad3ba5152017-02-14 03:09:17 +01002029 rogue_test_session.update(
2030 my_discriminator=self.test_session.my_discriminator,
2031 your_discriminator=self.test_session.your_discriminator,
2032 desired_min_tx=self.test_session.desired_min_tx,
2033 required_min_rx=self.test_session.required_min_rx,
2034 detect_mult=self.test_session.detect_mult,
2035 diag=self.test_session.diag,
2036 state=self.test_session.state,
2037 auth_type=self.test_session.auth_type)
Klement Sekerab17dd962017-01-09 07:43:48 +01002038 if rogue_bfd_values:
2039 rogue_test_session.update(**rogue_bfd_values)
2040 rogue_test_session.update(state=BFDState.down)
2041 rogue_test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +01002042 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002043 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
2044
2045 def test_mismatch_auth(self):
2046 """ session is not brought down by unauthenticated msg """
2047 key = self.factory.create_random_key(self)
2048 key.add_vpp_config()
2049 vpp_session = VppBFDUDPSession(
2050 self, self.pg0, self.pg0.remote_ip4, sha1_key=key)
2051 legitimate_test_session = BFDTestSession(
2052 self, self.pg0, AF_INET, sha1_key=key,
2053 bfd_key_id=vpp_session.bfd_key_id)
2054 rogue_test_session = BFDTestSession(self, self.pg0, AF_INET)
2055 self.execute_rogue_session_scenario(vpp_session,
2056 legitimate_test_session,
2057 rogue_test_session)
2058
2059 def test_mismatch_bfd_key_id(self):
2060 """ session is not brought down by msg with non-existent key-id """
2061 key = self.factory.create_random_key(self)
2062 key.add_vpp_config()
2063 vpp_session = VppBFDUDPSession(
2064 self, self.pg0, self.pg0.remote_ip4, sha1_key=key)
2065 # pick a different random bfd key id
2066 x = randint(0, 255)
2067 while x == vpp_session.bfd_key_id:
2068 x = randint(0, 255)
2069 legitimate_test_session = BFDTestSession(
2070 self, self.pg0, AF_INET, sha1_key=key,
2071 bfd_key_id=vpp_session.bfd_key_id)
2072 rogue_test_session = BFDTestSession(
2073 self, self.pg0, AF_INET, sha1_key=key, bfd_key_id=x)
2074 self.execute_rogue_session_scenario(vpp_session,
2075 legitimate_test_session,
2076 rogue_test_session)
2077
2078 def test_mismatched_auth_type(self):
2079 """ session is not brought down by msg with wrong auth type """
2080 key = self.factory.create_random_key(self)
2081 key.add_vpp_config()
2082 vpp_session = VppBFDUDPSession(
2083 self, self.pg0, self.pg0.remote_ip4, sha1_key=key)
2084 legitimate_test_session = BFDTestSession(
2085 self, self.pg0, AF_INET, sha1_key=key,
2086 bfd_key_id=vpp_session.bfd_key_id)
2087 rogue_test_session = BFDTestSession(
2088 self, self.pg0, AF_INET, sha1_key=key,
2089 bfd_key_id=vpp_session.bfd_key_id)
2090 self.execute_rogue_session_scenario(
2091 vpp_session, legitimate_test_session, rogue_test_session,
2092 {'auth_type': BFDAuthType.keyed_md5})
2093
2094 def test_restart(self):
2095 """ simulate remote peer restart and resynchronization """
2096 key = self.factory.create_random_key(
2097 self, BFDAuthType.meticulous_keyed_sha1)
2098 key.add_vpp_config()
2099 self.vpp_session = VppBFDUDPSession(self, self.pg0,
2100 self.pg0.remote_ip4, sha1_key=key)
2101 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002102 self.test_session = BFDTestSession(
2103 self, self.pg0, AF_INET, sha1_key=key,
2104 bfd_key_id=self.vpp_session.bfd_key_id, our_seq_number=0)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002105 bfd_session_up(self)
2106 # don't send any packets for 2*detection_time
Klement Sekera239790f2017-02-16 10:53:53 +01002107 detection_time = self.test_session.detect_mult *\
Klement Sekerad3ba5152017-02-14 03:09:17 +01002108 self.vpp_session.required_min_rx / USEC_IN_SEC
Klement Sekera87134932017-03-07 11:39:27 +01002109 self.sleep(2 * detection_time, "simulating peer restart")
Klement Sekerad3ba5152017-02-14 03:09:17 +01002110 events = self.vapi.collect_events()
2111 self.assert_equal(len(events), 1, "number of bfd events")
2112 verify_event(self, events[0], expected_state=BFDState.down)
Klement Sekerab17dd962017-01-09 07:43:48 +01002113 self.test_session.update(state=BFDState.down)
Klement Sekerab17dd962017-01-09 07:43:48 +01002114 # reset sequence number
2115 self.test_session.our_seq_number = 0
Klement Sekerad3ba5152017-02-14 03:09:17 +01002116 self.test_session.vpp_seq_number = None
2117 # now throw away any pending packets
2118 self.pg0.enable_capture()
Klement Sekera4d39f9c2020-01-17 10:01:52 +00002119 self.test_session.my_discriminator = 0
Klement Sekerad3ba5152017-02-14 03:09:17 +01002120 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002121
2122
Andrew Yourtchenko06f32812021-01-14 10:19:08 +00002123@tag_run_solo
Klement Sekerad3ba5152017-02-14 03:09:17 +01002124class BFDAuthOnOffTestCase(VppTestCase):
Klement Sekerab17dd962017-01-09 07:43:48 +01002125 """Bidirectional Forwarding Detection (BFD) (changing auth) """
2126
Klement Sekerad3ba5152017-02-14 03:09:17 +01002127 pg0 = None
2128 vpp_session = None
2129 test_session = None
2130
Klement Sekerab17dd962017-01-09 07:43:48 +01002131 @classmethod
2132 def setUpClass(cls):
2133 super(BFDAuthOnOffTestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -08002134 cls.vapi.cli("set log class bfd level debug")
Klement Sekerab17dd962017-01-09 07:43:48 +01002135 try:
2136 cls.create_pg_interfaces([0])
2137 cls.pg0.config_ip4()
2138 cls.pg0.admin_up()
2139 cls.pg0.resolve_arp()
2140
2141 except Exception:
2142 super(BFDAuthOnOffTestCase, cls).tearDownClass()
2143 raise
2144
Paul Vinciguerra8d991d92019-01-25 14:05:48 -08002145 @classmethod
2146 def tearDownClass(cls):
2147 super(BFDAuthOnOffTestCase, cls).tearDownClass()
2148
Klement Sekerab17dd962017-01-09 07:43:48 +01002149 def setUp(self):
2150 super(BFDAuthOnOffTestCase, self).setUp()
2151 self.factory = AuthKeyFactory()
2152 self.vapi.want_bfd_events()
Klement Sekerad3ba5152017-02-14 03:09:17 +01002153 self.pg0.enable_capture()
Klement Sekerab17dd962017-01-09 07:43:48 +01002154
2155 def tearDown(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002156 if not self.vpp_dead:
Jakub Grajciar4682feb2019-09-02 13:28:52 +02002157 self.vapi.want_bfd_events(enable_disable=False)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002158 self.vapi.collect_events() # clear the event queue
2159 super(BFDAuthOnOffTestCase, self).tearDown()
Klement Sekerab17dd962017-01-09 07:43:48 +01002160
2161 def test_auth_on_immediate(self):
2162 """ turn auth on without disturbing session state (immediate) """
2163 key = self.factory.create_random_key(self)
2164 key.add_vpp_config()
2165 self.vpp_session = VppBFDUDPSession(self, self.pg0,
2166 self.pg0.remote_ip4)
2167 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002168 self.test_session = BFDTestSession(self, self.pg0, AF_INET)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002169 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002170 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002171 p = wait_for_bfd_packet(self)
2172 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002173 self.test_session.send_packet()
2174 self.vpp_session.activate_auth(key)
2175 self.test_session.bfd_key_id = self.vpp_session.bfd_key_id
2176 self.test_session.sha1_key = key
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002177 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002178 p = wait_for_bfd_packet(self)
2179 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002180 self.test_session.send_packet()
2181 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
2182 self.assert_equal(len(self.vapi.collect_events()), 0,
2183 "number of bfd events")
2184
2185 def test_auth_off_immediate(self):
2186 """ turn auth off without disturbing session state (immediate) """
2187 key = self.factory.create_random_key(self)
2188 key.add_vpp_config()
2189 self.vpp_session = VppBFDUDPSession(self, self.pg0,
2190 self.pg0.remote_ip4, sha1_key=key)
2191 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002192 self.test_session = BFDTestSession(
2193 self, self.pg0, AF_INET, sha1_key=key,
2194 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002195 bfd_session_up(self)
2196 # self.vapi.want_bfd_events(enable_disable=0)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002197 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002198 p = wait_for_bfd_packet(self)
2199 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
2200 self.test_session.inc_seq_num()
Klement Sekerab17dd962017-01-09 07:43:48 +01002201 self.test_session.send_packet()
2202 self.vpp_session.deactivate_auth()
2203 self.test_session.bfd_key_id = None
2204 self.test_session.sha1_key = None
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002205 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002206 p = wait_for_bfd_packet(self)
2207 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
2208 self.test_session.inc_seq_num()
Klement Sekerab17dd962017-01-09 07:43:48 +01002209 self.test_session.send_packet()
2210 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
2211 self.assert_equal(len(self.vapi.collect_events()), 0,
2212 "number of bfd events")
2213
2214 def test_auth_change_key_immediate(self):
2215 """ change auth key without disturbing session state (immediate) """
2216 key1 = self.factory.create_random_key(self)
2217 key1.add_vpp_config()
2218 key2 = self.factory.create_random_key(self)
2219 key2.add_vpp_config()
2220 self.vpp_session = VppBFDUDPSession(self, self.pg0,
2221 self.pg0.remote_ip4, sha1_key=key1)
2222 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002223 self.test_session = BFDTestSession(
2224 self, self.pg0, AF_INET, sha1_key=key1,
2225 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002226 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002227 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002228 p = wait_for_bfd_packet(self)
2229 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002230 self.test_session.send_packet()
2231 self.vpp_session.activate_auth(key2)
2232 self.test_session.bfd_key_id = self.vpp_session.bfd_key_id
2233 self.test_session.sha1_key = key2
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002234 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002235 p = wait_for_bfd_packet(self)
2236 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002237 self.test_session.send_packet()
2238 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
2239 self.assert_equal(len(self.vapi.collect_events()), 0,
2240 "number of bfd events")
2241
2242 def test_auth_on_delayed(self):
2243 """ turn auth on without disturbing session state (delayed) """
2244 key = self.factory.create_random_key(self)
2245 key.add_vpp_config()
2246 self.vpp_session = VppBFDUDPSession(self, self.pg0,
2247 self.pg0.remote_ip4)
2248 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002249 self.test_session = BFDTestSession(self, self.pg0, AF_INET)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002250 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002251 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002252 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002253 self.test_session.send_packet()
2254 self.vpp_session.activate_auth(key, delayed=True)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002255 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002256 p = wait_for_bfd_packet(self)
2257 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002258 self.test_session.send_packet()
2259 self.test_session.bfd_key_id = self.vpp_session.bfd_key_id
2260 self.test_session.sha1_key = key
2261 self.test_session.send_packet()
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002262 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002263 p = wait_for_bfd_packet(self)
2264 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002265 self.test_session.send_packet()
2266 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
2267 self.assert_equal(len(self.vapi.collect_events()), 0,
2268 "number of bfd events")
2269
2270 def test_auth_off_delayed(self):
2271 """ turn auth off without disturbing session state (delayed) """
2272 key = self.factory.create_random_key(self)
2273 key.add_vpp_config()
2274 self.vpp_session = VppBFDUDPSession(self, self.pg0,
2275 self.pg0.remote_ip4, sha1_key=key)
2276 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002277 self.test_session = BFDTestSession(
2278 self, self.pg0, AF_INET, sha1_key=key,
2279 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002280 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002281 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002282 p = wait_for_bfd_packet(self)
2283 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002284 self.test_session.send_packet()
2285 self.vpp_session.deactivate_auth(delayed=True)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002286 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002287 p = wait_for_bfd_packet(self)
2288 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002289 self.test_session.send_packet()
2290 self.test_session.bfd_key_id = None
2291 self.test_session.sha1_key = None
2292 self.test_session.send_packet()
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002293 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002294 p = wait_for_bfd_packet(self)
2295 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002296 self.test_session.send_packet()
2297 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
2298 self.assert_equal(len(self.vapi.collect_events()), 0,
2299 "number of bfd events")
2300
2301 def test_auth_change_key_delayed(self):
2302 """ change auth key without disturbing session state (delayed) """
2303 key1 = self.factory.create_random_key(self)
2304 key1.add_vpp_config()
2305 key2 = self.factory.create_random_key(self)
2306 key2.add_vpp_config()
2307 self.vpp_session = VppBFDUDPSession(self, self.pg0,
2308 self.pg0.remote_ip4, sha1_key=key1)
2309 self.vpp_session.add_vpp_config()
2310 self.vpp_session.admin_up()
2311 self.test_session = BFDTestSession(
2312 self, self.pg0, AF_INET, sha1_key=key1,
2313 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002314 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002315 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002316 p = wait_for_bfd_packet(self)
2317 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002318 self.test_session.send_packet()
2319 self.vpp_session.activate_auth(key2, delayed=True)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002320 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002321 p = wait_for_bfd_packet(self)
2322 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002323 self.test_session.send_packet()
2324 self.test_session.bfd_key_id = self.vpp_session.bfd_key_id
2325 self.test_session.sha1_key = key2
2326 self.test_session.send_packet()
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002327 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002328 p = wait_for_bfd_packet(self)
2329 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002330 self.test_session.send_packet()
2331 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
2332 self.assert_equal(len(self.vapi.collect_events()), 0,
2333 "number of bfd events")
Klement Sekera46a87ad2017-01-02 08:22:23 +01002334
Klement Sekera73884482017-02-23 09:26:30 +01002335
Andrew Yourtchenko06f32812021-01-14 10:19:08 +00002336@tag_run_solo
Klement Sekera73884482017-02-23 09:26:30 +01002337class BFDCLITestCase(VppTestCase):
2338 """Bidirectional Forwarding Detection (BFD) (CLI) """
2339 pg0 = None
2340
2341 @classmethod
2342 def setUpClass(cls):
2343 super(BFDCLITestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -08002344 cls.vapi.cli("set log class bfd level debug")
Klement Sekera73884482017-02-23 09:26:30 +01002345 try:
2346 cls.create_pg_interfaces((0,))
2347 cls.pg0.config_ip4()
2348 cls.pg0.config_ip6()
2349 cls.pg0.resolve_arp()
2350 cls.pg0.resolve_ndp()
2351
2352 except Exception:
2353 super(BFDCLITestCase, cls).tearDownClass()
2354 raise
2355
Paul Vinciguerra8d991d92019-01-25 14:05:48 -08002356 @classmethod
2357 def tearDownClass(cls):
2358 super(BFDCLITestCase, cls).tearDownClass()
2359
Klement Sekera73884482017-02-23 09:26:30 +01002360 def setUp(self):
2361 super(BFDCLITestCase, self).setUp()
2362 self.factory = AuthKeyFactory()
2363 self.pg0.enable_capture()
2364
2365 def tearDown(self):
2366 try:
Jakub Grajciar4682feb2019-09-02 13:28:52 +02002367 self.vapi.want_bfd_events(enable_disable=False)
Klement Sekera73884482017-02-23 09:26:30 +01002368 except UnexpectedApiReturnValueError:
2369 # some tests aren't subscribed, so this is not an issue
2370 pass
2371 self.vapi.collect_events() # clear the event queue
2372 super(BFDCLITestCase, self).tearDown()
2373
2374 def cli_verify_no_response(self, cli):
2375 """ execute a CLI, asserting that the response is empty """
2376 self.assert_equal(self.vapi.cli(cli),
snaramre73aff472019-12-02 05:49:28 +00002377 "",
Klement Sekera73884482017-02-23 09:26:30 +01002378 "CLI command response")
2379
2380 def cli_verify_response(self, cli, expected):
2381 """ execute a CLI, asserting that the response matches expectation """
Jakub Grajciar4682feb2019-09-02 13:28:52 +02002382 try:
2383 reply = self.vapi.cli(cli)
2384 except CliFailedCommandError as cli_error:
2385 reply = str(cli_error)
2386 self.assert_equal(reply.strip(),
Klement Sekera73884482017-02-23 09:26:30 +01002387 expected,
2388 "CLI command response")
2389
2390 def test_show(self):
2391 """ show commands """
2392 k1 = self.factory.create_random_key(self)
2393 k1.add_vpp_config()
2394 k2 = self.factory.create_random_key(
2395 self, auth_type=BFDAuthType.meticulous_keyed_sha1)
2396 k2.add_vpp_config()
2397 s1 = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
2398 s1.add_vpp_config()
2399 s2 = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip6, af=AF_INET6,
2400 sha1_key=k2)
2401 s2.add_vpp_config()
2402 self.logger.info(self.vapi.ppcli("show bfd keys"))
2403 self.logger.info(self.vapi.ppcli("show bfd sessions"))
2404 self.logger.info(self.vapi.ppcli("show bfd"))
2405
2406 def test_set_del_sha1_key(self):
2407 """ set/delete SHA1 auth key """
2408 k = self.factory.create_random_key(self)
2409 self.registry.register(k, self.logger)
2410 self.cli_verify_no_response(
2411 "bfd key set conf-key-id %s type keyed-sha1 secret %s" %
2412 (k.conf_key_id,
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07002413 "".join("{:02x}".format(scapy.compat.orb(c)) for c in k.key)))
Klement Sekera73884482017-02-23 09:26:30 +01002414 self.assertTrue(k.query_vpp_config())
2415 self.vpp_session = VppBFDUDPSession(
2416 self, self.pg0, self.pg0.remote_ip4, sha1_key=k)
2417 self.vpp_session.add_vpp_config()
2418 self.test_session = \
2419 BFDTestSession(self, self.pg0, AF_INET, sha1_key=k,
2420 bfd_key_id=self.vpp_session.bfd_key_id)
2421 self.vapi.want_bfd_events()
2422 bfd_session_up(self)
2423 bfd_session_down(self)
2424 # try to replace the secret for the key - should fail because the key
2425 # is in-use
2426 k2 = self.factory.create_random_key(self)
2427 self.cli_verify_response(
2428 "bfd key set conf-key-id %s type keyed-sha1 secret %s" %
2429 (k.conf_key_id,
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07002430 "".join("{:02x}".format(scapy.compat.orb(c)) for c in k2.key)),
Klement Sekera73884482017-02-23 09:26:30 +01002431 "bfd key set: `bfd_auth_set_key' API call failed, "
2432 "rv=-103:BFD object in use")
2433 # manipulating the session using old secret should still work
2434 bfd_session_up(self)
2435 bfd_session_down(self)
2436 self.vpp_session.remove_vpp_config()
2437 self.cli_verify_no_response(
2438 "bfd key del conf-key-id %s" % k.conf_key_id)
2439 self.assertFalse(k.query_vpp_config())
2440
2441 def test_set_del_meticulous_sha1_key(self):
2442 """ set/delete meticulous SHA1 auth key """
2443 k = self.factory.create_random_key(
2444 self, auth_type=BFDAuthType.meticulous_keyed_sha1)
2445 self.registry.register(k, self.logger)
2446 self.cli_verify_no_response(
2447 "bfd key set conf-key-id %s type meticulous-keyed-sha1 secret %s" %
2448 (k.conf_key_id,
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07002449 "".join("{:02x}".format(scapy.compat.orb(c)) for c in k.key)))
Klement Sekera73884482017-02-23 09:26:30 +01002450 self.assertTrue(k.query_vpp_config())
2451 self.vpp_session = VppBFDUDPSession(self, self.pg0,
2452 self.pg0.remote_ip6, af=AF_INET6,
2453 sha1_key=k)
2454 self.vpp_session.add_vpp_config()
2455 self.vpp_session.admin_up()
2456 self.test_session = \
2457 BFDTestSession(self, self.pg0, AF_INET6, sha1_key=k,
2458 bfd_key_id=self.vpp_session.bfd_key_id)
2459 self.vapi.want_bfd_events()
2460 bfd_session_up(self)
2461 bfd_session_down(self)
2462 # try to replace the secret for the key - should fail because the key
2463 # is in-use
2464 k2 = self.factory.create_random_key(self)
2465 self.cli_verify_response(
2466 "bfd key set conf-key-id %s type keyed-sha1 secret %s" %
2467 (k.conf_key_id,
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07002468 "".join("{:02x}".format(scapy.compat.orb(c)) for c in k2.key)),
Klement Sekera73884482017-02-23 09:26:30 +01002469 "bfd key set: `bfd_auth_set_key' API call failed, "
2470 "rv=-103:BFD object in use")
2471 # manipulating the session using old secret should still work
2472 bfd_session_up(self)
2473 bfd_session_down(self)
2474 self.vpp_session.remove_vpp_config()
2475 self.cli_verify_no_response(
2476 "bfd key del conf-key-id %s" % k.conf_key_id)
2477 self.assertFalse(k.query_vpp_config())
2478
2479 def test_add_mod_del_bfd_udp(self):
2480 """ create/modify/delete IPv4 BFD UDP session """
2481 vpp_session = VppBFDUDPSession(
2482 self, self.pg0, self.pg0.remote_ip4)
2483 self.registry.register(vpp_session, self.logger)
2484 cli_add_cmd = "bfd udp session add interface %s local-addr %s " \
2485 "peer-addr %s desired-min-tx %s required-min-rx %s "\
2486 "detect-mult %s" % (self.pg0.name, self.pg0.local_ip4,
2487 self.pg0.remote_ip4,
2488 vpp_session.desired_min_tx,
2489 vpp_session.required_min_rx,
2490 vpp_session.detect_mult)
2491 self.cli_verify_no_response(cli_add_cmd)
2492 # 2nd add should fail
2493 self.cli_verify_response(
2494 cli_add_cmd,
2495 "bfd udp session add: `bfd_add_add_session' API call"
2496 " failed, rv=-101:Duplicate BFD object")
2497 verify_bfd_session_config(self, vpp_session)
2498 mod_session = VppBFDUDPSession(
2499 self, self.pg0, self.pg0.remote_ip4,
2500 required_min_rx=2 * vpp_session.required_min_rx,
2501 desired_min_tx=3 * vpp_session.desired_min_tx,
2502 detect_mult=4 * vpp_session.detect_mult)
2503 self.cli_verify_no_response(
2504 "bfd udp session mod interface %s local-addr %s peer-addr %s "
2505 "desired-min-tx %s required-min-rx %s detect-mult %s" %
2506 (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4,
2507 mod_session.desired_min_tx, mod_session.required_min_rx,
2508 mod_session.detect_mult))
2509 verify_bfd_session_config(self, mod_session)
2510 cli_del_cmd = "bfd udp session del interface %s local-addr %s "\
2511 "peer-addr %s" % (self.pg0.name,
2512 self.pg0.local_ip4, self.pg0.remote_ip4)
2513 self.cli_verify_no_response(cli_del_cmd)
2514 # 2nd del is expected to fail
2515 self.cli_verify_response(
2516 cli_del_cmd, "bfd udp session del: `bfd_udp_del_session' API call"
2517 " failed, rv=-102:No such BFD object")
2518 self.assertFalse(vpp_session.query_vpp_config())
2519
2520 def test_add_mod_del_bfd_udp6(self):
2521 """ create/modify/delete IPv6 BFD UDP session """
2522 vpp_session = VppBFDUDPSession(
2523 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6)
2524 self.registry.register(vpp_session, self.logger)
2525 cli_add_cmd = "bfd udp session add interface %s local-addr %s " \
2526 "peer-addr %s desired-min-tx %s required-min-rx %s "\
2527 "detect-mult %s" % (self.pg0.name, self.pg0.local_ip6,
2528 self.pg0.remote_ip6,
2529 vpp_session.desired_min_tx,
2530 vpp_session.required_min_rx,
2531 vpp_session.detect_mult)
2532 self.cli_verify_no_response(cli_add_cmd)
2533 # 2nd add should fail
2534 self.cli_verify_response(
2535 cli_add_cmd,
2536 "bfd udp session add: `bfd_add_add_session' API call"
2537 " failed, rv=-101:Duplicate BFD object")
2538 verify_bfd_session_config(self, vpp_session)
2539 mod_session = VppBFDUDPSession(
2540 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6,
2541 required_min_rx=2 * vpp_session.required_min_rx,
2542 desired_min_tx=3 * vpp_session.desired_min_tx,
2543 detect_mult=4 * vpp_session.detect_mult)
2544 self.cli_verify_no_response(
2545 "bfd udp session mod interface %s local-addr %s peer-addr %s "
2546 "desired-min-tx %s required-min-rx %s detect-mult %s" %
2547 (self.pg0.name, self.pg0.local_ip6, self.pg0.remote_ip6,
2548 mod_session.desired_min_tx,
2549 mod_session.required_min_rx, mod_session.detect_mult))
2550 verify_bfd_session_config(self, mod_session)
2551 cli_del_cmd = "bfd udp session del interface %s local-addr %s "\
2552 "peer-addr %s" % (self.pg0.name,
2553 self.pg0.local_ip6, self.pg0.remote_ip6)
2554 self.cli_verify_no_response(cli_del_cmd)
2555 # 2nd del is expected to fail
2556 self.cli_verify_response(
2557 cli_del_cmd,
2558 "bfd udp session del: `bfd_udp_del_session' API call"
2559 " failed, rv=-102:No such BFD object")
2560 self.assertFalse(vpp_session.query_vpp_config())
2561
2562 def test_add_mod_del_bfd_udp_auth(self):
2563 """ create/modify/delete IPv4 BFD UDP session (authenticated) """
2564 key = self.factory.create_random_key(self)
2565 key.add_vpp_config()
2566 vpp_session = VppBFDUDPSession(
2567 self, self.pg0, self.pg0.remote_ip4, sha1_key=key)
2568 self.registry.register(vpp_session, self.logger)
2569 cli_add_cmd = "bfd udp session add interface %s local-addr %s " \
2570 "peer-addr %s desired-min-tx %s required-min-rx %s "\
2571 "detect-mult %s conf-key-id %s bfd-key-id %s"\
2572 % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4,
2573 vpp_session.desired_min_tx, vpp_session.required_min_rx,
2574 vpp_session.detect_mult, key.conf_key_id,
2575 vpp_session.bfd_key_id)
2576 self.cli_verify_no_response(cli_add_cmd)
2577 # 2nd add should fail
2578 self.cli_verify_response(
2579 cli_add_cmd,
2580 "bfd udp session add: `bfd_add_add_session' API call"
2581 " failed, rv=-101:Duplicate BFD object")
2582 verify_bfd_session_config(self, vpp_session)
2583 mod_session = VppBFDUDPSession(
2584 self, self.pg0, self.pg0.remote_ip4, sha1_key=key,
2585 bfd_key_id=vpp_session.bfd_key_id,
2586 required_min_rx=2 * vpp_session.required_min_rx,
2587 desired_min_tx=3 * vpp_session.desired_min_tx,
2588 detect_mult=4 * vpp_session.detect_mult)
2589 self.cli_verify_no_response(
2590 "bfd udp session mod interface %s local-addr %s peer-addr %s "
2591 "desired-min-tx %s required-min-rx %s detect-mult %s" %
2592 (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4,
2593 mod_session.desired_min_tx,
2594 mod_session.required_min_rx, mod_session.detect_mult))
2595 verify_bfd_session_config(self, mod_session)
2596 cli_del_cmd = "bfd udp session del interface %s local-addr %s "\
2597 "peer-addr %s" % (self.pg0.name,
2598 self.pg0.local_ip4, self.pg0.remote_ip4)
2599 self.cli_verify_no_response(cli_del_cmd)
2600 # 2nd del is expected to fail
2601 self.cli_verify_response(
2602 cli_del_cmd,
2603 "bfd udp session del: `bfd_udp_del_session' API call"
2604 " failed, rv=-102:No such BFD object")
2605 self.assertFalse(vpp_session.query_vpp_config())
2606
2607 def test_add_mod_del_bfd_udp6_auth(self):
2608 """ create/modify/delete IPv6 BFD UDP session (authenticated) """
2609 key = self.factory.create_random_key(
2610 self, auth_type=BFDAuthType.meticulous_keyed_sha1)
2611 key.add_vpp_config()
2612 vpp_session = VppBFDUDPSession(
2613 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6, sha1_key=key)
2614 self.registry.register(vpp_session, self.logger)
2615 cli_add_cmd = "bfd udp session add interface %s local-addr %s " \
2616 "peer-addr %s desired-min-tx %s required-min-rx %s "\
2617 "detect-mult %s conf-key-id %s bfd-key-id %s" \
2618 % (self.pg0.name, self.pg0.local_ip6, self.pg0.remote_ip6,
2619 vpp_session.desired_min_tx, vpp_session.required_min_rx,
2620 vpp_session.detect_mult, key.conf_key_id,
2621 vpp_session.bfd_key_id)
2622 self.cli_verify_no_response(cli_add_cmd)
2623 # 2nd add should fail
2624 self.cli_verify_response(
2625 cli_add_cmd,
2626 "bfd udp session add: `bfd_add_add_session' API call"
2627 " failed, rv=-101:Duplicate BFD object")
2628 verify_bfd_session_config(self, vpp_session)
2629 mod_session = VppBFDUDPSession(
2630 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6, sha1_key=key,
2631 bfd_key_id=vpp_session.bfd_key_id,
2632 required_min_rx=2 * vpp_session.required_min_rx,
2633 desired_min_tx=3 * vpp_session.desired_min_tx,
2634 detect_mult=4 * vpp_session.detect_mult)
2635 self.cli_verify_no_response(
2636 "bfd udp session mod interface %s local-addr %s peer-addr %s "
2637 "desired-min-tx %s required-min-rx %s detect-mult %s" %
2638 (self.pg0.name, self.pg0.local_ip6, self.pg0.remote_ip6,
2639 mod_session.desired_min_tx,
2640 mod_session.required_min_rx, mod_session.detect_mult))
2641 verify_bfd_session_config(self, mod_session)
2642 cli_del_cmd = "bfd udp session del interface %s local-addr %s "\
2643 "peer-addr %s" % (self.pg0.name,
2644 self.pg0.local_ip6, self.pg0.remote_ip6)
2645 self.cli_verify_no_response(cli_del_cmd)
2646 # 2nd del is expected to fail
2647 self.cli_verify_response(
2648 cli_del_cmd,
2649 "bfd udp session del: `bfd_udp_del_session' API call"
2650 " failed, rv=-102:No such BFD object")
2651 self.assertFalse(vpp_session.query_vpp_config())
2652
2653 def test_auth_on_off(self):
2654 """ turn authentication on and off """
2655 key = self.factory.create_random_key(
2656 self, auth_type=BFDAuthType.meticulous_keyed_sha1)
2657 key.add_vpp_config()
2658 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
2659 auth_session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4,
2660 sha1_key=key)
2661 session.add_vpp_config()
2662 cli_activate = \
2663 "bfd udp session auth activate interface %s local-addr %s "\
2664 "peer-addr %s conf-key-id %s bfd-key-id %s"\
2665 % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4,
2666 key.conf_key_id, auth_session.bfd_key_id)
2667 self.cli_verify_no_response(cli_activate)
2668 verify_bfd_session_config(self, auth_session)
2669 self.cli_verify_no_response(cli_activate)
2670 verify_bfd_session_config(self, auth_session)
2671 cli_deactivate = \
2672 "bfd udp session auth deactivate interface %s local-addr %s "\
2673 "peer-addr %s "\
2674 % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4)
2675 self.cli_verify_no_response(cli_deactivate)
2676 verify_bfd_session_config(self, session)
2677 self.cli_verify_no_response(cli_deactivate)
2678 verify_bfd_session_config(self, session)
2679
2680 def test_auth_on_off_delayed(self):
2681 """ turn authentication on and off (delayed) """
2682 key = self.factory.create_random_key(
2683 self, auth_type=BFDAuthType.meticulous_keyed_sha1)
2684 key.add_vpp_config()
2685 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
2686 auth_session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4,
2687 sha1_key=key)
2688 session.add_vpp_config()
2689 cli_activate = \
2690 "bfd udp session auth activate interface %s local-addr %s "\
2691 "peer-addr %s conf-key-id %s bfd-key-id %s delayed yes"\
2692 % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4,
2693 key.conf_key_id, auth_session.bfd_key_id)
2694 self.cli_verify_no_response(cli_activate)
2695 verify_bfd_session_config(self, auth_session)
2696 self.cli_verify_no_response(cli_activate)
2697 verify_bfd_session_config(self, auth_session)
2698 cli_deactivate = \
2699 "bfd udp session auth deactivate interface %s local-addr %s "\
2700 "peer-addr %s delayed yes"\
2701 % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4)
2702 self.cli_verify_no_response(cli_deactivate)
2703 verify_bfd_session_config(self, session)
2704 self.cli_verify_no_response(cli_deactivate)
2705 verify_bfd_session_config(self, session)
2706
2707 def test_admin_up_down(self):
2708 """ put session admin-up and admin-down """
2709 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
2710 session.add_vpp_config()
2711 cli_down = \
2712 "bfd udp session set-flags admin down interface %s local-addr %s "\
2713 "peer-addr %s "\
2714 % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4)
2715 cli_up = \
2716 "bfd udp session set-flags admin up interface %s local-addr %s "\
2717 "peer-addr %s "\
2718 % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4)
2719 self.cli_verify_no_response(cli_down)
2720 verify_bfd_session_config(self, session, state=BFDState.admin_down)
2721 self.cli_verify_no_response(cli_up)
2722 verify_bfd_session_config(self, session, state=BFDState.down)
2723
2724 def test_set_del_udp_echo_source(self):
2725 """ set/del udp echo source """
Klement Sekerab9ef2732018-06-24 22:49:33 +02002726 self.create_loopback_interfaces(1)
Klement Sekera73884482017-02-23 09:26:30 +01002727 self.loopback0 = self.lo_interfaces[0]
2728 self.loopback0.admin_up()
2729 self.cli_verify_response("show bfd echo-source",
2730 "UDP echo source is not set.")
2731 cli_set = "bfd udp echo-source set interface %s" % self.loopback0.name
2732 self.cli_verify_no_response(cli_set)
2733 self.cli_verify_response("show bfd echo-source",
2734 "UDP echo source is: %s\n"
2735 "IPv4 address usable as echo source: none\n"
2736 "IPv6 address usable as echo source: none" %
2737 self.loopback0.name)
2738 self.loopback0.config_ip4()
Paul Vinciguerra2f156312020-05-02 22:34:40 -04002739 echo_ip4 = str(ipaddress.IPv4Address(int(ipaddress.IPv4Address(
2740 self.loopback0.local_ip4)) ^ 1))
Klement Sekera73884482017-02-23 09:26:30 +01002741 self.cli_verify_response("show bfd echo-source",
2742 "UDP echo source is: %s\n"
2743 "IPv4 address usable as echo source: %s\n"
2744 "IPv6 address usable as echo source: none" %
2745 (self.loopback0.name, echo_ip4))
Paul Vinciguerra2f156312020-05-02 22:34:40 -04002746 echo_ip6 = str(ipaddress.IPv6Address(int(ipaddress.IPv6Address(
2747 self.loopback0.local_ip6)) ^ 1))
Klement Sekera73884482017-02-23 09:26:30 +01002748 self.loopback0.config_ip6()
2749 self.cli_verify_response("show bfd echo-source",
2750 "UDP echo source is: %s\n"
2751 "IPv4 address usable as echo source: %s\n"
2752 "IPv6 address usable as echo source: %s" %
2753 (self.loopback0.name, echo_ip4, echo_ip6))
2754 cli_del = "bfd udp echo-source del"
2755 self.cli_verify_no_response(cli_del)
2756 self.cli_verify_response("show bfd echo-source",
2757 "UDP echo source is not set.")
2758
Jakub Grajciar4682feb2019-09-02 13:28:52 +02002759
Klement Sekera0e3c0de2016-09-29 14:43:44 +02002760if __name__ == '__main__':
2761 unittest.main(testRunner=VppTestRunner)