blob: c8bda736b5e80030aa9a2073577b5fa8eb6680c1 [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
Klement Sekera0e3c0de2016-09-29 14:43:44 +02008import time
Paul Vinciguerra00671cf2018-11-25 12:47:04 -08009import unittest
Klement Sekera239790f2017-02-16 10:53:53 +010010from random import randint, shuffle, getrandbits
Klement Sekera73884482017-02-23 09:26:30 +010011from socket import AF_INET, AF_INET6, inet_ntop
Paul Vinciguerra00671cf2018-11-25 12:47:04 -080012from struct import pack, unpack
13
Paul Vinciguerra6c746172018-11-26 09:57:21 -080014from six import moves
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -070015import scapy.compat
Klement Sekerad3ba5152017-02-14 03:09:17 +010016from scapy.layers.inet import UDP, IP
17from scapy.layers.inet6 import IPv6
Neale Ranns52cd4962019-06-05 10:28:17 +000018from scapy.layers.l2 import Ether, GRE
Paul Vinciguerra00671cf2018-11-25 12:47:04 -080019from scapy.packet import Raw
20
Klement Sekerad3ba5152017-02-14 03:09:17 +010021from bfd import VppBFDAuthKey, BFD, BFDAuthType, VppBFDUDPSession, \
Klement Sekera239790f2017-02-16 10:53:53 +010022 BFDDiagCode, BFDState, BFD_vpp_echo
Klement Sekera87134932017-03-07 11:39:27 +010023from framework import VppTestCase, VppTestRunner, running_extended_tests
Klement Sekera0e3c0de2016-09-29 14:43:44 +020024from util import ppp
Neale Rannsc0a93142018-09-05 15:42:26 -070025from vpp_ip import DpoProto
26from vpp_ip_route import VppIpRoute, VppRoutePath
Paul Vinciguerra00671cf2018-11-25 12:47:04 -080027from vpp_lo_interface import VppLoInterface
Jakub Grajciar4682feb2019-09-02 13:28:52 +020028from vpp_papi_provider import UnexpectedApiReturnValueError, \
29 CliFailedCommandError
Paul Vinciguerra00671cf2018-11-25 12:47:04 -080030from vpp_pg_interface import CaptureTimeoutError, is_ipv6_misc
Neale Ranns52cd4962019-06-05 10:28:17 +000031from vpp_gre_interface import VppGreInterface
Jakub Grajciar4682feb2019-09-02 13:28:52 +020032from vpp_papi import VppEnum
Klement Sekera0e3c0de2016-09-29 14:43:44 +020033
Klement Sekerad3ba5152017-02-14 03:09:17 +010034USEC_IN_SEC = 1000000
Klement Sekera3e0a3562016-12-19 09:05:21 +010035
Klement Sekera0e3c0de2016-09-29 14:43:44 +020036
Klement Sekerab17dd962017-01-09 07:43:48 +010037class AuthKeyFactory(object):
38 """Factory class for creating auth keys with unique conf key ID"""
39
40 def __init__(self):
41 self._conf_key_ids = {}
42
43 def create_random_key(self, test, auth_type=BFDAuthType.keyed_sha1):
Klement Sekerad3ba5152017-02-14 03:09:17 +010044 """ create a random key with unique conf key id """
Klement Sekerab17dd962017-01-09 07:43:48 +010045 conf_key_id = randint(0, 0xFFFFFFFF)
46 while conf_key_id in self._conf_key_ids:
47 conf_key_id = randint(0, 0xFFFFFFFF)
48 self._conf_key_ids[conf_key_id] = 1
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -070049 key = scapy.compat.raw(
50 bytearray([randint(0, 255) for _ in range(randint(1, 20))]))
Klement Sekerab17dd962017-01-09 07:43:48 +010051 return VppBFDAuthKey(test=test, auth_type=auth_type,
52 conf_key_id=conf_key_id, key=key)
53
54
Paul Vinciguerradefde0f2018-12-06 07:46:13 -080055@unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekerae4504c62016-12-08 10:16:41 +010056class BFDAPITestCase(VppTestCase):
57 """Bidirectional Forwarding Detection (BFD) - API"""
Klement Sekera0e3c0de2016-09-29 14:43:44 +020058
Klement Sekerad3ba5152017-02-14 03:09:17 +010059 pg0 = None
60 pg1 = None
61
Klement Sekera0e3c0de2016-09-29 14:43:44 +020062 @classmethod
63 def setUpClass(cls):
Klement Sekerae4504c62016-12-08 10:16:41 +010064 super(BFDAPITestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -080065 cls.vapi.cli("set log class bfd level debug")
Klement Sekera0e3c0de2016-09-29 14:43:44 +020066 try:
Klement Sekera10db26f2017-01-11 08:16:53 +010067 cls.create_pg_interfaces(range(2))
68 for i in cls.pg_interfaces:
69 i.config_ip4()
Klement Sekerab17dd962017-01-09 07:43:48 +010070 i.config_ip6()
Klement Sekera10db26f2017-01-11 08:16:53 +010071 i.resolve_arp()
Klement Sekera0e3c0de2016-09-29 14:43:44 +020072
73 except Exception:
Klement Sekerae4504c62016-12-08 10:16:41 +010074 super(BFDAPITestCase, cls).tearDownClass()
Klement Sekera0e3c0de2016-09-29 14:43:44 +020075 raise
76
Paul Vinciguerra8d991d92019-01-25 14:05:48 -080077 @classmethod
78 def tearDownClass(cls):
79 super(BFDAPITestCase, cls).tearDownClass()
80
Klement Sekerab17dd962017-01-09 07:43:48 +010081 def setUp(self):
82 super(BFDAPITestCase, self).setUp()
83 self.factory = AuthKeyFactory()
84
Klement Sekera0e3c0de2016-09-29 14:43:44 +020085 def test_add_bfd(self):
86 """ create a BFD session """
87 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
88 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +010089 self.logger.debug("Session state is %s", session.state)
Klement Sekera0e3c0de2016-09-29 14:43:44 +020090 session.remove_vpp_config()
Klement Sekera0e3c0de2016-09-29 14:43:44 +020091 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +010092 self.logger.debug("Session state is %s", session.state)
Klement Sekera0e3c0de2016-09-29 14:43:44 +020093 session.remove_vpp_config()
94
95 def test_double_add(self):
96 """ create the same BFD session twice (negative case) """
97 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
98 session.add_vpp_config()
Klement Sekerae0545ef2017-01-25 08:00:40 +010099
Klement Sekera7d6afb32018-11-08 11:52:04 +0100100 with self.vapi.assert_negative_api_retval():
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200101 session.add_vpp_config()
Klement Sekerae0545ef2017-01-25 08:00:40 +0100102
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200103 session.remove_vpp_config()
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200104
Klement Sekerab17dd962017-01-09 07:43:48 +0100105 def test_add_bfd6(self):
106 """ create IPv6 BFD session """
107 session = VppBFDUDPSession(
108 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6)
109 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100110 self.logger.debug("Session state is %s", session.state)
Klement Sekerab17dd962017-01-09 07:43:48 +0100111 session.remove_vpp_config()
112 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100113 self.logger.debug("Session state is %s", session.state)
Klement Sekerab17dd962017-01-09 07:43:48 +0100114 session.remove_vpp_config()
115
Klement Sekeraa57a9702017-02-02 06:58:07 +0100116 def test_mod_bfd(self):
117 """ modify BFD session parameters """
118 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4,
119 desired_min_tx=50000,
120 required_min_rx=10000,
121 detect_mult=1)
122 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100123 s = session.get_bfd_udp_session_dump_entry()
Klement Sekeraa57a9702017-02-02 06:58:07 +0100124 self.assert_equal(session.desired_min_tx,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100125 s.desired_min_tx,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100126 "desired min transmit interval")
127 self.assert_equal(session.required_min_rx,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100128 s.required_min_rx,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100129 "required min receive interval")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100130 self.assert_equal(session.detect_mult, s.detect_mult, "detect mult")
Klement Sekeraa57a9702017-02-02 06:58:07 +0100131 session.modify_parameters(desired_min_tx=session.desired_min_tx * 2,
132 required_min_rx=session.required_min_rx * 2,
133 detect_mult=session.detect_mult * 2)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100134 s = session.get_bfd_udp_session_dump_entry()
Klement Sekeraa57a9702017-02-02 06:58:07 +0100135 self.assert_equal(session.desired_min_tx,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100136 s.desired_min_tx,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100137 "desired min transmit interval")
138 self.assert_equal(session.required_min_rx,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100139 s.required_min_rx,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100140 "required min receive interval")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100141 self.assert_equal(session.detect_mult, s.detect_mult, "detect mult")
Klement Sekeraa57a9702017-02-02 06:58:07 +0100142
Klement Sekerab17dd962017-01-09 07:43:48 +0100143 def test_add_sha1_keys(self):
144 """ add SHA1 keys """
145 key_count = 10
146 keys = [self.factory.create_random_key(
147 self) for i in range(0, key_count)]
148 for key in keys:
149 self.assertFalse(key.query_vpp_config())
150 for key in keys:
151 key.add_vpp_config()
152 for key in keys:
153 self.assertTrue(key.query_vpp_config())
154 # remove randomly
155 indexes = range(key_count)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100156 shuffle(indexes)
Klement Sekerab17dd962017-01-09 07:43:48 +0100157 removed = []
158 for i in indexes:
159 key = keys[i]
160 key.remove_vpp_config()
161 removed.append(i)
162 for j in range(key_count):
163 key = keys[j]
164 if j in removed:
165 self.assertFalse(key.query_vpp_config())
166 else:
167 self.assertTrue(key.query_vpp_config())
168 # should be removed now
169 for key in keys:
170 self.assertFalse(key.query_vpp_config())
171 # add back and remove again
172 for key in keys:
173 key.add_vpp_config()
174 for key in keys:
175 self.assertTrue(key.query_vpp_config())
176 for key in keys:
177 key.remove_vpp_config()
178 for key in keys:
179 self.assertFalse(key.query_vpp_config())
180
181 def test_add_bfd_sha1(self):
182 """ create a BFD session (SHA1) """
183 key = self.factory.create_random_key(self)
184 key.add_vpp_config()
185 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4,
186 sha1_key=key)
187 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100188 self.logger.debug("Session state is %s", session.state)
Klement Sekerab17dd962017-01-09 07:43:48 +0100189 session.remove_vpp_config()
190 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100191 self.logger.debug("Session state is %s", session.state)
Klement Sekerab17dd962017-01-09 07:43:48 +0100192 session.remove_vpp_config()
193
194 def test_double_add_sha1(self):
195 """ create the same BFD session twice (negative case) (SHA1) """
196 key = self.factory.create_random_key(self)
197 key.add_vpp_config()
198 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4,
199 sha1_key=key)
200 session.add_vpp_config()
201 with self.assertRaises(Exception):
202 session.add_vpp_config()
203
Klement Sekerad3ba5152017-02-14 03:09:17 +0100204 def test_add_auth_nonexistent_key(self):
Klement Sekerab17dd962017-01-09 07:43:48 +0100205 """ create BFD session using non-existent SHA1 (negative case) """
206 session = VppBFDUDPSession(
207 self, self.pg0, self.pg0.remote_ip4,
208 sha1_key=self.factory.create_random_key(self))
209 with self.assertRaises(Exception):
210 session.add_vpp_config()
211
212 def test_shared_sha1_key(self):
213 """ share single SHA1 key between multiple BFD sessions """
214 key = self.factory.create_random_key(self)
215 key.add_vpp_config()
216 sessions = [
217 VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4,
218 sha1_key=key),
219 VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip6,
220 sha1_key=key, af=AF_INET6),
221 VppBFDUDPSession(self, self.pg1, self.pg1.remote_ip4,
222 sha1_key=key),
223 VppBFDUDPSession(self, self.pg1, self.pg1.remote_ip6,
224 sha1_key=key, af=AF_INET6)]
225 for s in sessions:
226 s.add_vpp_config()
227 removed = 0
228 for s in sessions:
229 e = key.get_bfd_auth_keys_dump_entry()
230 self.assert_equal(e.use_count, len(sessions) - removed,
231 "Use count for shared key")
232 s.remove_vpp_config()
233 removed += 1
234 e = key.get_bfd_auth_keys_dump_entry()
235 self.assert_equal(e.use_count, len(sessions) - removed,
236 "Use count for shared key")
237
238 def test_activate_auth(self):
239 """ activate SHA1 authentication """
240 key = self.factory.create_random_key(self)
241 key.add_vpp_config()
242 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
243 session.add_vpp_config()
244 session.activate_auth(key)
245
246 def test_deactivate_auth(self):
247 """ deactivate SHA1 authentication """
248 key = self.factory.create_random_key(self)
249 key.add_vpp_config()
250 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
251 session.add_vpp_config()
252 session.activate_auth(key)
253 session.deactivate_auth()
254
255 def test_change_key(self):
Klement Sekeraa57a9702017-02-02 06:58:07 +0100256 """ change SHA1 key """
Klement Sekerab17dd962017-01-09 07:43:48 +0100257 key1 = self.factory.create_random_key(self)
258 key2 = self.factory.create_random_key(self)
259 while key2.conf_key_id == key1.conf_key_id:
260 key2 = self.factory.create_random_key(self)
261 key1.add_vpp_config()
262 key2.add_vpp_config()
263 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4,
264 sha1_key=key1)
265 session.add_vpp_config()
266 session.activate_auth(key2)
Klement Sekera10db26f2017-01-11 08:16:53 +0100267
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700268 def test_set_del_udp_echo_source(self):
269 """ set/del udp echo source """
270 self.create_loopback_interfaces(1)
271 self.loopback0 = self.lo_interfaces[0]
272 self.loopback0.admin_up()
273 echo_source = self.vapi.bfd_udp_get_echo_source()
274 self.assertFalse(echo_source.is_set)
275 self.assertFalse(echo_source.have_usable_ip4)
276 self.assertFalse(echo_source.have_usable_ip6)
277
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200278 self.vapi.bfd_udp_set_echo_source(
279 sw_if_index=self.loopback0.sw_if_index)
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700280 echo_source = self.vapi.bfd_udp_get_echo_source()
281 self.assertTrue(echo_source.is_set)
282 self.assertEqual(echo_source.sw_if_index, self.loopback0.sw_if_index)
283 self.assertFalse(echo_source.have_usable_ip4)
284 self.assertFalse(echo_source.have_usable_ip6)
285
286 self.loopback0.config_ip4()
287 unpacked = unpack("!L", self.loopback0.local_ip4n)
288 echo_ip4 = pack("!L", unpacked[0] ^ 1)
289 echo_source = self.vapi.bfd_udp_get_echo_source()
290 self.assertTrue(echo_source.is_set)
291 self.assertEqual(echo_source.sw_if_index, self.loopback0.sw_if_index)
292 self.assertTrue(echo_source.have_usable_ip4)
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200293 self.assertEqual(echo_source.ip4_addr.packed, echo_ip4)
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700294 self.assertFalse(echo_source.have_usable_ip6)
295
296 self.loopback0.config_ip6()
297 unpacked = unpack("!LLLL", self.loopback0.local_ip6n)
298 echo_ip6 = pack("!LLLL", unpacked[0], unpacked[1], unpacked[2],
299 unpacked[3] ^ 1)
300 echo_source = self.vapi.bfd_udp_get_echo_source()
301 self.assertTrue(echo_source.is_set)
302 self.assertEqual(echo_source.sw_if_index, self.loopback0.sw_if_index)
303 self.assertTrue(echo_source.have_usable_ip4)
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200304 self.assertEqual(echo_source.ip4_addr.packed, echo_ip4)
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700305 self.assertTrue(echo_source.have_usable_ip6)
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200306 self.assertEqual(echo_source.ip6_addr.packed, echo_ip6)
Matus Fabian2d3c7b92018-10-02 03:22:18 -0700307
308 self.vapi.bfd_udp_del_echo_source()
309 echo_source = self.vapi.bfd_udp_get_echo_source()
310 self.assertFalse(echo_source.is_set)
311 self.assertFalse(echo_source.have_usable_ip4)
312 self.assertFalse(echo_source.have_usable_ip6)
313
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200314
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200315class BFDTestSession(object):
Klement Sekera3e0a3562016-12-19 09:05:21 +0100316 """ BFD session as seen from test framework side """
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200317
Klement Sekerab17dd962017-01-09 07:43:48 +0100318 def __init__(self, test, interface, af, detect_mult=3, sha1_key=None,
Neale Ranns52cd4962019-06-05 10:28:17 +0000319 bfd_key_id=None, our_seq_number=None,
320 tunnel_header=None, phy_interface=None):
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200321 self.test = test
Klement Sekera46a87ad2017-01-02 08:22:23 +0100322 self.af = af
Klement Sekerab17dd962017-01-09 07:43:48 +0100323 self.sha1_key = sha1_key
324 self.bfd_key_id = bfd_key_id
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200325 self.interface = interface
Neale Ranns52cd4962019-06-05 10:28:17 +0000326 if phy_interface:
327 self.phy_interface = phy_interface
328 else:
329 self.phy_interface = self.interface
Klement Sekerad3ba5152017-02-14 03:09:17 +0100330 self.udp_sport = randint(49152, 65535)
331 if our_seq_number is None:
332 self.our_seq_number = randint(0, 40000000)
333 else:
334 self.our_seq_number = our_seq_number
Klement Sekerab17dd962017-01-09 07:43:48 +0100335 self.vpp_seq_number = None
Klement Sekerad3ba5152017-02-14 03:09:17 +0100336 self.my_discriminator = 0
Klement Sekera2e01dfa2017-04-03 08:10:08 +0200337 self.desired_min_tx = 300000
338 self.required_min_rx = 300000
Klement Sekera239790f2017-02-16 10:53:53 +0100339 self.required_min_echo_rx = None
Klement Sekerad3ba5152017-02-14 03:09:17 +0100340 self.detect_mult = detect_mult
341 self.diag = BFDDiagCode.no_diagnostic
342 self.your_discriminator = None
343 self.state = BFDState.down
344 self.auth_type = BFDAuthType.no_auth
Neale Ranns52cd4962019-06-05 10:28:17 +0000345 self.tunnel_header = tunnel_header
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200346
Klement Sekerab17dd962017-01-09 07:43:48 +0100347 def inc_seq_num(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100348 """ increment sequence number, wrapping if needed """
Klement Sekerab17dd962017-01-09 07:43:48 +0100349 if self.our_seq_number == 0xFFFFFFFF:
350 self.our_seq_number = 0
351 else:
352 self.our_seq_number += 1
353
Klement Sekerad3ba5152017-02-14 03:09:17 +0100354 def update(self, my_discriminator=None, your_discriminator=None,
Klement Sekera239790f2017-02-16 10:53:53 +0100355 desired_min_tx=None, required_min_rx=None,
356 required_min_echo_rx=None, detect_mult=None,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100357 diag=None, state=None, auth_type=None):
358 """ update BFD parameters associated with session """
Klement Sekera239790f2017-02-16 10:53:53 +0100359 if my_discriminator is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100360 self.my_discriminator = my_discriminator
Klement Sekera239790f2017-02-16 10:53:53 +0100361 if your_discriminator is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100362 self.your_discriminator = your_discriminator
Klement Sekera239790f2017-02-16 10:53:53 +0100363 if required_min_rx is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100364 self.required_min_rx = required_min_rx
Klement Sekera239790f2017-02-16 10:53:53 +0100365 if required_min_echo_rx is not None:
366 self.required_min_echo_rx = required_min_echo_rx
367 if desired_min_tx is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100368 self.desired_min_tx = desired_min_tx
Klement Sekera239790f2017-02-16 10:53:53 +0100369 if detect_mult is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100370 self.detect_mult = detect_mult
Klement Sekera239790f2017-02-16 10:53:53 +0100371 if diag is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100372 self.diag = diag
Klement Sekera239790f2017-02-16 10:53:53 +0100373 if state is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100374 self.state = state
Klement Sekera239790f2017-02-16 10:53:53 +0100375 if auth_type is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100376 self.auth_type = auth_type
377
378 def fill_packet_fields(self, packet):
379 """ set packet fields with known values in packet """
380 bfd = packet[BFD]
381 if self.my_discriminator:
382 self.test.logger.debug("BFD: setting packet.my_discriminator=%s",
383 self.my_discriminator)
384 bfd.my_discriminator = self.my_discriminator
385 if self.your_discriminator:
386 self.test.logger.debug("BFD: setting packet.your_discriminator=%s",
387 self.your_discriminator)
388 bfd.your_discriminator = self.your_discriminator
389 if self.required_min_rx:
390 self.test.logger.debug(
391 "BFD: setting packet.required_min_rx_interval=%s",
392 self.required_min_rx)
393 bfd.required_min_rx_interval = self.required_min_rx
Klement Sekera239790f2017-02-16 10:53:53 +0100394 if self.required_min_echo_rx:
395 self.test.logger.debug(
396 "BFD: setting packet.required_min_echo_rx=%s",
397 self.required_min_echo_rx)
398 bfd.required_min_echo_rx_interval = self.required_min_echo_rx
Klement Sekerad3ba5152017-02-14 03:09:17 +0100399 if self.desired_min_tx:
400 self.test.logger.debug(
401 "BFD: setting packet.desired_min_tx_interval=%s",
402 self.desired_min_tx)
403 bfd.desired_min_tx_interval = self.desired_min_tx
404 if self.detect_mult:
405 self.test.logger.debug(
406 "BFD: setting packet.detect_mult=%s", self.detect_mult)
407 bfd.detect_mult = self.detect_mult
408 if self.diag:
409 self.test.logger.debug("BFD: setting packet.diag=%s", self.diag)
410 bfd.diag = self.diag
411 if self.state:
412 self.test.logger.debug("BFD: setting packet.state=%s", self.state)
413 bfd.state = self.state
414 if self.auth_type:
415 # this is used by a negative test-case
416 self.test.logger.debug("BFD: setting packet.auth_type=%s",
417 self.auth_type)
418 bfd.auth_type = self.auth_type
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200419
420 def create_packet(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100421 """ create a BFD packet, reflecting the current state of session """
Klement Sekerab17dd962017-01-09 07:43:48 +0100422 if self.sha1_key:
423 bfd = BFD(flags="A")
424 bfd.auth_type = self.sha1_key.auth_type
425 bfd.auth_len = BFD.sha1_auth_len
426 bfd.auth_key_id = self.bfd_key_id
427 bfd.auth_seq_num = self.our_seq_number
428 bfd.length = BFD.sha1_auth_len + BFD.bfd_pkt_len
429 else:
430 bfd = BFD()
Neale Ranns52cd4962019-06-05 10:28:17 +0000431 packet = Ether(src=self.phy_interface.remote_mac,
432 dst=self.phy_interface.local_mac)
433 if self.tunnel_header:
434 packet = packet / self.tunnel_header
Klement Sekera46a87ad2017-01-02 08:22:23 +0100435 if self.af == AF_INET6:
Neale Ranns52cd4962019-06-05 10:28:17 +0000436 packet = (packet /
Klement Sekera46a87ad2017-01-02 08:22:23 +0100437 IPv6(src=self.interface.remote_ip6,
438 dst=self.interface.local_ip6,
439 hlim=255) /
440 UDP(sport=self.udp_sport, dport=BFD.udp_dport) /
Klement Sekerab17dd962017-01-09 07:43:48 +0100441 bfd)
Klement Sekera46a87ad2017-01-02 08:22:23 +0100442 else:
Neale Ranns52cd4962019-06-05 10:28:17 +0000443 packet = (packet /
Klement Sekera46a87ad2017-01-02 08:22:23 +0100444 IP(src=self.interface.remote_ip4,
445 dst=self.interface.local_ip4,
446 ttl=255) /
447 UDP(sport=self.udp_sport, dport=BFD.udp_dport) /
Klement Sekerab17dd962017-01-09 07:43:48 +0100448 bfd)
Klement Sekera3e0a3562016-12-19 09:05:21 +0100449 self.test.logger.debug("BFD: Creating packet")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100450 self.fill_packet_fields(packet)
Klement Sekerab17dd962017-01-09 07:43:48 +0100451 if self.sha1_key:
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700452 hash_material = scapy.compat.raw(
453 packet[BFD])[:32] + self.sha1_key.key + \
Klement Sekerab17dd962017-01-09 07:43:48 +0100454 "\0" * (20 - len(self.sha1_key.key))
455 self.test.logger.debug("BFD: Calculated SHA1 hash: %s" %
456 hashlib.sha1(hash_material).hexdigest())
457 packet[BFD].auth_key_hash = hashlib.sha1(hash_material).digest()
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200458 return packet
459
Klement Sekerad3ba5152017-02-14 03:09:17 +0100460 def send_packet(self, packet=None, interface=None):
461 """ send packet on interface, creating the packet if needed """
Klement Sekeraa57a9702017-02-02 06:58:07 +0100462 if packet is None:
463 packet = self.create_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100464 if interface is None:
Neale Ranns52cd4962019-06-05 10:28:17 +0000465 interface = self.phy_interface
Klement Sekeraa57a9702017-02-02 06:58:07 +0100466 self.test.logger.debug(ppp("Sending packet:", packet))
Klement Sekerad3ba5152017-02-14 03:09:17 +0100467 interface.add_stream(packet)
Klement Sekera9225dee2016-12-12 08:36:58 +0100468 self.test.pg_start()
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200469
Klement Sekerab17dd962017-01-09 07:43:48 +0100470 def verify_sha1_auth(self, packet):
471 """ Verify correctness of authentication in BFD layer. """
472 bfd = packet[BFD]
473 self.test.assert_equal(bfd.auth_len, 28, "Auth section length")
474 self.test.assert_equal(bfd.auth_type, self.sha1_key.auth_type,
475 BFDAuthType)
476 self.test.assert_equal(bfd.auth_key_id, self.bfd_key_id, "Key ID")
477 self.test.assert_equal(bfd.auth_reserved, 0, "Reserved")
478 if self.vpp_seq_number is None:
479 self.vpp_seq_number = bfd.auth_seq_num
480 self.test.logger.debug("Received initial sequence number: %s" %
481 self.vpp_seq_number)
482 else:
483 recvd_seq_num = bfd.auth_seq_num
484 self.test.logger.debug("Received followup sequence number: %s" %
485 recvd_seq_num)
486 if self.vpp_seq_number < 0xffffffff:
487 if self.sha1_key.auth_type == \
488 BFDAuthType.meticulous_keyed_sha1:
489 self.test.assert_equal(recvd_seq_num,
490 self.vpp_seq_number + 1,
491 "BFD sequence number")
492 else:
493 self.test.assert_in_range(recvd_seq_num,
494 self.vpp_seq_number,
495 self.vpp_seq_number + 1,
496 "BFD sequence number")
497 else:
498 if self.sha1_key.auth_type == \
499 BFDAuthType.meticulous_keyed_sha1:
500 self.test.assert_equal(recvd_seq_num, 0,
501 "BFD sequence number")
502 else:
503 self.test.assertIn(recvd_seq_num, (self.vpp_seq_number, 0),
504 "BFD sequence number not one of "
505 "(%s, 0)" % self.vpp_seq_number)
506 self.vpp_seq_number = recvd_seq_num
507 # last 20 bytes represent the hash - so replace them with the key,
508 # pad the result with zeros and hash the result
509 hash_material = bfd.original[:-20] + self.sha1_key.key + \
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700510 b"\0" * (20 - len(self.sha1_key.key))
Klement Sekerab17dd962017-01-09 07:43:48 +0100511 expected_hash = hashlib.sha1(hash_material).hexdigest()
512 self.test.assert_equal(binascii.hexlify(bfd.auth_key_hash),
513 expected_hash, "Auth key hash")
514
515 def verify_bfd(self, packet):
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200516 """ Verify correctness of BFD layer. """
517 bfd = packet[BFD]
518 self.test.assert_equal(bfd.version, 1, "BFD version")
519 self.test.assert_equal(bfd.your_discriminator,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100520 self.my_discriminator,
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200521 "BFD - your discriminator")
Klement Sekerab17dd962017-01-09 07:43:48 +0100522 if self.sha1_key:
523 self.verify_sha1_auth(packet)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200524
525
Klement Sekerad3ba5152017-02-14 03:09:17 +0100526def bfd_session_up(test):
527 """ Bring BFD session up """
528 test.logger.info("BFD: Waiting for slow hello")
Neale Ranns52cd4962019-06-05 10:28:17 +0000529 p = wait_for_bfd_packet(test, 2, is_tunnel=test.vpp_session.is_tunnel)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100530 old_offset = None
531 if hasattr(test, 'vpp_clock_offset'):
532 old_offset = test.vpp_clock_offset
533 test.vpp_clock_offset = time.time() - p.time
534 test.logger.debug("BFD: Calculated vpp clock offset: %s",
535 test.vpp_clock_offset)
536 if old_offset:
537 test.assertAlmostEqual(
Klement Sekera73884482017-02-23 09:26:30 +0100538 old_offset, test.vpp_clock_offset, delta=0.5,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100539 msg="vpp clock offset not stable (new: %s, old: %s)" %
540 (test.vpp_clock_offset, old_offset))
541 test.logger.info("BFD: Sending Init")
542 test.test_session.update(my_discriminator=randint(0, 40000000),
543 your_discriminator=p[BFD].my_discriminator,
544 state=BFDState.init)
Klement Sekera73884482017-02-23 09:26:30 +0100545 if test.test_session.sha1_key and test.test_session.sha1_key.auth_type == \
546 BFDAuthType.meticulous_keyed_sha1:
547 test.test_session.inc_seq_num()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100548 test.test_session.send_packet()
549 test.logger.info("BFD: Waiting for event")
550 e = test.vapi.wait_for_event(1, "bfd_udp_session_details")
551 verify_event(test, e, expected_state=BFDState.up)
552 test.logger.info("BFD: Session is Up")
553 test.test_session.update(state=BFDState.up)
Klement Sekera73884482017-02-23 09:26:30 +0100554 if test.test_session.sha1_key and test.test_session.sha1_key.auth_type == \
555 BFDAuthType.meticulous_keyed_sha1:
556 test.test_session.inc_seq_num()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100557 test.test_session.send_packet()
558 test.assert_equal(test.vpp_session.state, BFDState.up, BFDState)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200559
Klement Sekera46a87ad2017-01-02 08:22:23 +0100560
Klement Sekerad3ba5152017-02-14 03:09:17 +0100561def bfd_session_down(test):
562 """ Bring BFD session down """
563 test.assert_equal(test.vpp_session.state, BFDState.up, BFDState)
564 test.test_session.update(state=BFDState.down)
Klement Sekera73884482017-02-23 09:26:30 +0100565 if test.test_session.sha1_key and test.test_session.sha1_key.auth_type == \
566 BFDAuthType.meticulous_keyed_sha1:
567 test.test_session.inc_seq_num()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100568 test.test_session.send_packet()
569 test.logger.info("BFD: Waiting for event")
570 e = test.vapi.wait_for_event(1, "bfd_udp_session_details")
571 verify_event(test, e, expected_state=BFDState.down)
572 test.logger.info("BFD: Session is Down")
573 test.assert_equal(test.vpp_session.state, BFDState.down, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +0100574
Klement Sekera46a87ad2017-01-02 08:22:23 +0100575
Klement Sekera73884482017-02-23 09:26:30 +0100576def verify_bfd_session_config(test, session, state=None):
577 dump = session.get_bfd_udp_session_dump_entry()
578 test.assertIsNotNone(dump)
579 # since dump is not none, we have verified that sw_if_index and addresses
580 # are valid (in get_bfd_udp_session_dump_entry)
581 if state:
582 test.assert_equal(dump.state, state, "session state")
583 test.assert_equal(dump.required_min_rx, session.required_min_rx,
584 "required min rx interval")
585 test.assert_equal(dump.desired_min_tx, session.desired_min_tx,
586 "desired min tx interval")
587 test.assert_equal(dump.detect_mult, session.detect_mult,
588 "detect multiplier")
589 if session.sha1_key is None:
590 test.assert_equal(dump.is_authenticated, 0, "is_authenticated flag")
591 else:
592 test.assert_equal(dump.is_authenticated, 1, "is_authenticated flag")
593 test.assert_equal(dump.bfd_key_id, session.bfd_key_id,
594 "bfd key id")
595 test.assert_equal(dump.conf_key_id,
596 session.sha1_key.conf_key_id,
597 "config key id")
598
599
Klement Sekerad3ba5152017-02-14 03:09:17 +0100600def verify_ip(test, packet):
601 """ Verify correctness of IP layer. """
602 if test.vpp_session.af == AF_INET6:
603 ip = packet[IPv6]
Neale Ranns52cd4962019-06-05 10:28:17 +0000604 local_ip = test.vpp_session.interface.local_ip6
605 remote_ip = test.vpp_session.interface.remote_ip6
Klement Sekerad3ba5152017-02-14 03:09:17 +0100606 test.assert_equal(ip.hlim, 255, "IPv6 hop limit")
607 else:
608 ip = packet[IP]
Neale Ranns52cd4962019-06-05 10:28:17 +0000609 local_ip = test.vpp_session.interface.local_ip4
610 remote_ip = test.vpp_session.interface.remote_ip4
Klement Sekerad3ba5152017-02-14 03:09:17 +0100611 test.assert_equal(ip.ttl, 255, "IPv4 TTL")
612 test.assert_equal(ip.src, local_ip, "IP source address")
613 test.assert_equal(ip.dst, remote_ip, "IP destination address")
614
615
616def verify_udp(test, packet):
617 """ Verify correctness of UDP layer. """
618 udp = packet[UDP]
619 test.assert_equal(udp.dport, BFD.udp_dport, "UDP destination port")
620 test.assert_in_range(udp.sport, BFD.udp_sport_min, BFD.udp_sport_max,
621 "UDP source port")
622
623
624def verify_event(test, event, expected_state):
625 """ Verify correctness of event values. """
626 e = event
Paul Vinciguerra6c746172018-11-26 09:57:21 -0800627 test.logger.debug("BFD: Event: %s" % moves.reprlib.repr(e))
Klement Sekerad3ba5152017-02-14 03:09:17 +0100628 test.assert_equal(e.sw_if_index,
629 test.vpp_session.interface.sw_if_index,
630 "BFD interface index")
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200631
632 test.assert_equal(str(e.local_addr), test.vpp_session.local_addr,
633 "Local IPv6 address")
634 test.assert_equal(str(e.peer_addr), test.vpp_session.peer_addr,
635 "Peer IPv6 address")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100636 test.assert_equal(e.state, expected_state, BFDState)
637
638
Neale Ranns52cd4962019-06-05 10:28:17 +0000639def wait_for_bfd_packet(test, timeout=1, pcap_time_min=None, is_tunnel=False):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100640 """ wait for BFD packet and verify its correctness
641
642 :param timeout: how long to wait
643 :param pcap_time_min: ignore packets with pcap timestamp lower than this
644
645 :returns: tuple (packet, time spent waiting for packet)
646 """
647 test.logger.info("BFD: Waiting for BFD packet")
648 deadline = time.time() + timeout
649 counter = 0
650 while True:
651 counter += 1
652 # sanity check
653 test.assert_in_range(counter, 0, 100, "number of packets ignored")
654 time_left = deadline - time.time()
655 if time_left < 0:
656 raise CaptureTimeoutError("Packet did not arrive within timeout")
657 p = test.pg0.wait_for_packet(timeout=time_left)
658 test.logger.debug(ppp("BFD: Got packet:", p))
659 if pcap_time_min is not None and p.time < pcap_time_min:
660 test.logger.debug(ppp("BFD: ignoring packet (pcap time %s < "
661 "pcap time min %s):" %
662 (p.time, pcap_time_min), p))
Klement Sekera46a87ad2017-01-02 08:22:23 +0100663 else:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100664 break
Neale Ranns52cd4962019-06-05 10:28:17 +0000665 if is_tunnel:
666 # strip an IP layer and move to the next
667 p = p[IP].payload
668
Klement Sekerad3ba5152017-02-14 03:09:17 +0100669 bfd = p[BFD]
670 if bfd is None:
671 raise Exception(ppp("Unexpected or invalid BFD packet:", p))
672 if bfd.payload:
673 raise Exception(ppp("Unexpected payload in BFD packet:", bfd))
674 verify_ip(test, p)
675 verify_udp(test, p)
676 test.test_session.verify_bfd(p)
677 return p
Klement Sekera3e0a3562016-12-19 09:05:21 +0100678
Klement Sekera46a87ad2017-01-02 08:22:23 +0100679
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800680@unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100681class BFD4TestCase(VppTestCase):
Klement Sekera46a87ad2017-01-02 08:22:23 +0100682 """Bidirectional Forwarding Detection (BFD)"""
683
Klement Sekerad3ba5152017-02-14 03:09:17 +0100684 pg0 = None
685 vpp_clock_offset = None
686 vpp_session = None
687 test_session = None
688
Klement Sekera46a87ad2017-01-02 08:22:23 +0100689 @classmethod
690 def setUpClass(cls):
691 super(BFD4TestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -0800692 cls.vapi.cli("set log class bfd level debug")
Klement Sekera46a87ad2017-01-02 08:22:23 +0100693 try:
694 cls.create_pg_interfaces([0])
Klement Sekerab9ef2732018-06-24 22:49:33 +0200695 cls.create_loopback_interfaces(1)
Klement Sekera239790f2017-02-16 10:53:53 +0100696 cls.loopback0 = cls.lo_interfaces[0]
697 cls.loopback0.config_ip4()
698 cls.loopback0.admin_up()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100699 cls.pg0.config_ip4()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100700 cls.pg0.configure_ipv4_neighbors()
701 cls.pg0.admin_up()
702 cls.pg0.resolve_arp()
703
704 except Exception:
705 super(BFD4TestCase, cls).tearDownClass()
706 raise
707
Paul Vinciguerra8d991d92019-01-25 14:05:48 -0800708 @classmethod
709 def tearDownClass(cls):
710 super(BFD4TestCase, cls).tearDownClass()
711
Klement Sekera46a87ad2017-01-02 08:22:23 +0100712 def setUp(self):
713 super(BFD4TestCase, self).setUp()
Klement Sekerab17dd962017-01-09 07:43:48 +0100714 self.factory = AuthKeyFactory()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100715 self.vapi.want_bfd_events()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100716 self.pg0.enable_capture()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100717 try:
718 self.vpp_session = VppBFDUDPSession(self, self.pg0,
719 self.pg0.remote_ip4)
720 self.vpp_session.add_vpp_config()
721 self.vpp_session.admin_up()
722 self.test_session = BFDTestSession(self, self.pg0, AF_INET)
Jakub Grajciar4682feb2019-09-02 13:28:52 +0200723 except BaseException:
Klement Sekera46a87ad2017-01-02 08:22:23 +0100724 self.vapi.want_bfd_events(enable_disable=0)
725 raise
726
727 def tearDown(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100728 if not self.vpp_dead:
729 self.vapi.want_bfd_events(enable_disable=0)
730 self.vapi.collect_events() # clear the event queue
731 super(BFD4TestCase, self).tearDown()
Klement Sekerab17dd962017-01-09 07:43:48 +0100732
733 def test_session_up(self):
734 """ bring BFD session up """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100735 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +0100736
Klement Sekera73884482017-02-23 09:26:30 +0100737 def test_session_up_by_ip(self):
738 """ bring BFD session up - first frame looked up by address pair """
739 self.logger.info("BFD: Sending Slow control frame")
740 self.test_session.update(my_discriminator=randint(0, 40000000))
741 self.test_session.send_packet()
742 self.pg0.enable_capture()
743 p = self.pg0.wait_for_packet(1)
744 self.assert_equal(p[BFD].your_discriminator,
745 self.test_session.my_discriminator,
746 "BFD - your discriminator")
747 self.assert_equal(p[BFD].state, BFDState.init, BFDState)
748 self.test_session.update(your_discriminator=p[BFD].my_discriminator,
749 state=BFDState.up)
750 self.logger.info("BFD: Waiting for event")
751 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
752 verify_event(self, e, expected_state=BFDState.init)
753 self.logger.info("BFD: Sending Up")
754 self.test_session.send_packet()
755 self.logger.info("BFD: Waiting for event")
756 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
757 verify_event(self, e, expected_state=BFDState.up)
758 self.logger.info("BFD: Session is Up")
759 self.test_session.update(state=BFDState.up)
760 self.test_session.send_packet()
761 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
762
Klement Sekerab17dd962017-01-09 07:43:48 +0100763 def test_session_down(self):
764 """ bring BFD session down """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100765 bfd_session_up(self)
766 bfd_session_down(self)
Klement Sekerab17dd962017-01-09 07:43:48 +0100767
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800768 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekerab17dd962017-01-09 07:43:48 +0100769 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
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800778 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200779 def test_slow_timer(self):
Klement Sekerae4504c62016-12-08 10:16:41 +0100780 """ verify slow periodic control frames while session down """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100781 packet_count = 3
782 self.logger.info("BFD: Waiting for %d BFD packets", packet_count)
783 prev_packet = wait_for_bfd_packet(self, 2)
784 for dummy in range(packet_count):
785 next_packet = wait_for_bfd_packet(self, 2)
786 time_diff = next_packet.time - prev_packet.time
Klement Sekerae4504c62016-12-08 10:16:41 +0100787 # spec says the range should be <0.75, 1>, allow extra 0.05 margin
788 # to work around timing issues
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200789 self.assert_in_range(
Klement Sekerad3ba5152017-02-14 03:09:17 +0100790 time_diff, 0.70, 1.05, "time between slow packets")
791 prev_packet = next_packet
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200792
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800793 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200794 def test_zero_remote_min_rx(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100795 """ no packets when zero remote required min rx interval """
796 bfd_session_up(self)
797 self.test_session.update(required_min_rx=0)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200798 self.test_session.send_packet()
Klement Sekera239790f2017-02-16 10:53:53 +0100799 for dummy in range(self.test_session.detect_mult):
800 self.sleep(self.vpp_session.required_min_rx / USEC_IN_SEC,
801 "sleep before transmitting bfd packet")
802 self.test_session.send_packet()
Klement Sekeraa57a9702017-02-02 06:58:07 +0100803 try:
Klement Sekera239790f2017-02-16 10:53:53 +0100804 p = wait_for_bfd_packet(self, timeout=0)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100805 self.logger.error(ppp("Received unexpected packet:", p))
Klement Sekerad3ba5152017-02-14 03:09:17 +0100806 except CaptureTimeoutError:
Klement Sekeraa57a9702017-02-02 06:58:07 +0100807 pass
Klement Sekera239790f2017-02-16 10:53:53 +0100808 self.assert_equal(
809 len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekera2e01dfa2017-04-03 08:10:08 +0200810 self.test_session.update(required_min_rx=300000)
Klement Sekera239790f2017-02-16 10:53:53 +0100811 for dummy in range(3):
812 self.test_session.send_packet()
813 wait_for_bfd_packet(
814 self, timeout=self.test_session.required_min_rx / USEC_IN_SEC)
815 self.assert_equal(
816 len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200817
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800818 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200819 def test_conn_down(self):
Klement Sekerae4504c62016-12-08 10:16:41 +0100820 """ verify session goes down after inactivity """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100821 bfd_session_up(self)
Klement Sekera239790f2017-02-16 10:53:53 +0100822 detection_time = self.test_session.detect_mult *\
Klement Sekerac48829b2017-02-14 07:55:57 +0100823 self.vpp_session.required_min_rx / USEC_IN_SEC
824 self.sleep(detection_time, "waiting for BFD session time-out")
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200825 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100826 verify_event(self, e, expected_state=BFDState.down)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200827
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800828 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200829 def test_large_required_min_rx(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100830 """ large remote required min rx interval """
831 bfd_session_up(self)
832 p = wait_for_bfd_packet(self)
Klement Sekera637b9c42016-12-08 05:19:14 +0100833 interval = 3000000
Klement Sekerad3ba5152017-02-14 03:09:17 +0100834 self.test_session.update(required_min_rx=interval)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200835 self.test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100836 time_mark = time.time()
Klement Sekera637b9c42016-12-08 05:19:14 +0100837 count = 0
Klement Sekeraa57a9702017-02-02 06:58:07 +0100838 # busy wait here, trying to collect a packet or event, vpp is not
839 # allowed to send packets and the session will timeout first - so the
840 # Up->Down event must arrive before any packets do
Klement Sekerad3ba5152017-02-14 03:09:17 +0100841 while time.time() < time_mark + interval / USEC_IN_SEC:
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200842 try:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100843 p = wait_for_bfd_packet(self, timeout=0)
844 # if vpp managed to send a packet before we did the session
845 # session update, then that's fine, ignore it
846 if p.time < time_mark - self.vpp_clock_offset:
847 continue
Klement Sekeraa57a9702017-02-02 06:58:07 +0100848 self.logger.error(ppp("Received unexpected packet:", p))
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200849 count += 1
Klement Sekerad3ba5152017-02-14 03:09:17 +0100850 except CaptureTimeoutError:
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200851 pass
Klement Sekeraa57a9702017-02-02 06:58:07 +0100852 events = self.vapi.collect_events()
853 if len(events) > 0:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100854 verify_event(self, events[0], BFDState.down)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100855 break
856 self.assert_equal(count, 0, "number of packets received")
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200857
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800858 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100859 def test_immediate_remote_min_rx_reduction(self):
860 """ immediately honor remote required min rx reduction """
Klement Sekera3e0a3562016-12-19 09:05:21 +0100861 self.vpp_session.remove_vpp_config()
Klement Sekera10db26f2017-01-11 08:16:53 +0100862 self.vpp_session = VppBFDUDPSession(
863 self, self.pg0, self.pg0.remote_ip4, desired_min_tx=10000)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100864 self.pg0.enable_capture()
Klement Sekera3e0a3562016-12-19 09:05:21 +0100865 self.vpp_session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100866 self.test_session.update(desired_min_tx=1000000,
867 required_min_rx=1000000)
868 bfd_session_up(self)
869 reference_packet = wait_for_bfd_packet(self)
870 time_mark = time.time()
871 interval = 300000
872 self.test_session.update(required_min_rx=interval)
Klement Sekera3e0a3562016-12-19 09:05:21 +0100873 self.test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100874 extra_time = time.time() - time_mark
875 p = wait_for_bfd_packet(self)
876 # first packet is allowed to be late by time we spent doing the update
877 # calculated in extra_time
878 self.assert_in_range(p.time - reference_packet.time,
879 .95 * 0.75 * interval / USEC_IN_SEC,
880 1.05 * interval / USEC_IN_SEC + extra_time,
Klement Sekera3e0a3562016-12-19 09:05:21 +0100881 "time between BFD packets")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100882 reference_packet = p
883 for dummy in range(3):
884 p = wait_for_bfd_packet(self)
885 diff = p.time - reference_packet.time
886 self.assert_in_range(diff, .95 * .75 * interval / USEC_IN_SEC,
887 1.05 * interval / USEC_IN_SEC,
888 "time between BFD packets")
889 reference_packet = p
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200890
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800891 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekeraa57a9702017-02-02 06:58:07 +0100892 def test_modify_req_min_rx_double(self):
893 """ modify session - double required min rx """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100894 bfd_session_up(self)
895 p = wait_for_bfd_packet(self)
896 self.test_session.update(desired_min_tx=10000,
897 required_min_rx=10000)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100898 self.test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100899 # double required min rx
Klement Sekeraa57a9702017-02-02 06:58:07 +0100900 self.vpp_session.modify_parameters(
901 required_min_rx=2 * self.vpp_session.required_min_rx)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100902 p = wait_for_bfd_packet(
903 self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100904 # poll bit needs to be set
905 self.assertIn("P", p.sprintf("%BFD.flags%"),
906 "Poll bit not set in BFD packet")
907 # finish poll sequence with final packet
908 final = self.test_session.create_packet()
909 final[BFD].flags = "F"
Klement Sekerad3ba5152017-02-14 03:09:17 +0100910 timeout = self.test_session.detect_mult * \
911 max(self.test_session.desired_min_tx,
912 self.vpp_session.required_min_rx) / USEC_IN_SEC
Klement Sekeraa57a9702017-02-02 06:58:07 +0100913 self.test_session.send_packet(final)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100914 time_mark = time.time()
915 e = self.vapi.wait_for_event(2 * timeout, "bfd_udp_session_details")
916 verify_event(self, e, expected_state=BFDState.down)
917 time_to_event = time.time() - time_mark
918 self.assert_in_range(time_to_event, .9 * timeout,
919 1.1 * timeout, "session timeout")
Klement Sekeraa57a9702017-02-02 06:58:07 +0100920
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800921 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekeraa57a9702017-02-02 06:58:07 +0100922 def test_modify_req_min_rx_halve(self):
923 """ modify session - halve required min rx """
924 self.vpp_session.modify_parameters(
925 required_min_rx=2 * self.vpp_session.required_min_rx)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100926 bfd_session_up(self)
927 p = wait_for_bfd_packet(self)
928 self.test_session.update(desired_min_tx=10000,
929 required_min_rx=10000)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100930 self.test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100931 p = wait_for_bfd_packet(
932 self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100933 # halve required min rx
934 old_required_min_rx = self.vpp_session.required_min_rx
935 self.vpp_session.modify_parameters(
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700936 required_min_rx=self.vpp_session.required_min_rx // 2)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100937 # now we wait 0.8*3*old-req-min-rx and the session should still be up
938 self.sleep(0.8 * self.vpp_session.detect_mult *
Klement Sekera2e01dfa2017-04-03 08:10:08 +0200939 old_required_min_rx / USEC_IN_SEC,
940 "wait before finishing poll sequence")
Klement Sekeraa57a9702017-02-02 06:58:07 +0100941 self.assert_equal(len(self.vapi.collect_events()), 0,
942 "number of bfd events")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100943 p = wait_for_bfd_packet(self)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100944 # poll bit needs to be set
945 self.assertIn("P", p.sprintf("%BFD.flags%"),
946 "Poll bit not set in BFD packet")
947 # finish poll sequence with final packet
948 final = self.test_session.create_packet()
949 final[BFD].flags = "F"
950 self.test_session.send_packet(final)
951 # now the session should time out under new conditions
Klement Sekera239790f2017-02-16 10:53:53 +0100952 detection_time = self.test_session.detect_mult *\
Klement Sekerad3ba5152017-02-14 03:09:17 +0100953 self.vpp_session.required_min_rx / USEC_IN_SEC
Klement Sekera2e01dfa2017-04-03 08:10:08 +0200954 before = time.time()
955 e = self.vapi.wait_for_event(
956 2 * detection_time, "bfd_udp_session_details")
957 after = time.time()
Klement Sekeraa57a9702017-02-02 06:58:07 +0100958 self.assert_in_range(after - before,
959 0.9 * detection_time,
960 1.1 * detection_time,
961 "time before bfd session goes down")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100962 verify_event(self, e, expected_state=BFDState.down)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100963
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800964 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekeraa57a9702017-02-02 06:58:07 +0100965 def test_modify_detect_mult(self):
966 """ modify detect multiplier """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100967 bfd_session_up(self)
968 p = wait_for_bfd_packet(self)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100969 self.vpp_session.modify_parameters(detect_mult=1)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100970 p = wait_for_bfd_packet(
971 self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100972 self.assert_equal(self.vpp_session.detect_mult,
973 p[BFD].detect_mult,
974 "detect mult")
975 # poll bit must not be set
976 self.assertNotIn("P", p.sprintf("%BFD.flags%"),
977 "Poll bit not set in BFD packet")
978 self.vpp_session.modify_parameters(detect_mult=10)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100979 p = wait_for_bfd_packet(
980 self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100981 self.assert_equal(self.vpp_session.detect_mult,
982 p[BFD].detect_mult,
983 "detect mult")
984 # poll bit must not be set
985 self.assertNotIn("P", p.sprintf("%BFD.flags%"),
986 "Poll bit not set in BFD packet")
987
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800988 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekera239790f2017-02-16 10:53:53 +0100989 def test_queued_poll(self):
990 """ test poll sequence queueing """
991 bfd_session_up(self)
992 p = wait_for_bfd_packet(self)
993 self.vpp_session.modify_parameters(
994 required_min_rx=2 * self.vpp_session.required_min_rx)
995 p = wait_for_bfd_packet(self)
996 poll_sequence_start = time.time()
997 poll_sequence_length_min = 0.5
998 send_final_after = time.time() + poll_sequence_length_min
999 # poll bit needs to be set
1000 self.assertIn("P", p.sprintf("%BFD.flags%"),
1001 "Poll bit not set in BFD packet")
1002 self.assert_equal(p[BFD].required_min_rx_interval,
1003 self.vpp_session.required_min_rx,
1004 "BFD required min rx interval")
1005 self.vpp_session.modify_parameters(
1006 required_min_rx=2 * self.vpp_session.required_min_rx)
1007 # 2nd poll sequence should be queued now
1008 # don't send the reply back yet, wait for some time to emulate
1009 # longer round-trip time
1010 packet_count = 0
1011 while time.time() < send_final_after:
1012 self.test_session.send_packet()
1013 p = wait_for_bfd_packet(self)
1014 self.assert_equal(len(self.vapi.collect_events()), 0,
1015 "number of bfd events")
1016 self.assert_equal(p[BFD].required_min_rx_interval,
1017 self.vpp_session.required_min_rx,
1018 "BFD required min rx interval")
1019 packet_count += 1
1020 # poll bit must be set
1021 self.assertIn("P", p.sprintf("%BFD.flags%"),
1022 "Poll bit not set in BFD packet")
1023 final = self.test_session.create_packet()
1024 final[BFD].flags = "F"
1025 self.test_session.send_packet(final)
1026 # finish 1st with final
1027 poll_sequence_length = time.time() - poll_sequence_start
1028 # vpp must wait for some time before starting new poll sequence
1029 poll_no_2_started = False
1030 for dummy in range(2 * packet_count):
1031 p = wait_for_bfd_packet(self)
1032 self.assert_equal(len(self.vapi.collect_events()), 0,
1033 "number of bfd events")
1034 if "P" in p.sprintf("%BFD.flags%"):
1035 poll_no_2_started = True
1036 if time.time() < poll_sequence_start + poll_sequence_length:
1037 raise Exception("VPP started 2nd poll sequence too soon")
1038 final = self.test_session.create_packet()
1039 final[BFD].flags = "F"
1040 self.test_session.send_packet(final)
1041 break
1042 else:
1043 self.test_session.send_packet()
1044 self.assertTrue(poll_no_2_started, "2nd poll sequence not performed")
1045 # finish 2nd with final
1046 final = self.test_session.create_packet()
1047 final[BFD].flags = "F"
1048 self.test_session.send_packet(final)
1049 p = wait_for_bfd_packet(self)
1050 # poll bit must not be set
1051 self.assertNotIn("P", p.sprintf("%BFD.flags%"),
1052 "Poll bit set in BFD packet")
1053
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08001054 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekera73884482017-02-23 09:26:30 +01001055 def test_poll_response(self):
1056 """ test correct response to control frame with poll bit set """
1057 bfd_session_up(self)
1058 poll = self.test_session.create_packet()
1059 poll[BFD].flags = "P"
1060 self.test_session.send_packet(poll)
1061 final = wait_for_bfd_packet(
1062 self, pcap_time_min=time.time() - self.vpp_clock_offset)
1063 self.assertIn("F", final.sprintf("%BFD.flags%"))
1064
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08001065 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekerad3ba5152017-02-14 03:09:17 +01001066 def test_no_periodic_if_remote_demand(self):
1067 """ no periodic frames outside poll sequence if remote demand set """
Klement Sekerad3ba5152017-02-14 03:09:17 +01001068 bfd_session_up(self)
1069 demand = self.test_session.create_packet()
1070 demand[BFD].flags = "D"
1071 self.test_session.send_packet(demand)
1072 transmit_time = 0.9 \
1073 * max(self.vpp_session.required_min_rx,
1074 self.test_session.desired_min_tx) \
1075 / USEC_IN_SEC
1076 count = 0
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001077 for dummy in range(self.test_session.detect_mult * 2):
Paul Vinciguerra0f6602c2019-03-10 09:10:54 -07001078 self.sleep(transmit_time)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001079 self.test_session.send_packet(demand)
1080 try:
1081 p = wait_for_bfd_packet(self, timeout=0)
1082 self.logger.error(ppp("Received unexpected packet:", p))
1083 count += 1
1084 except CaptureTimeoutError:
1085 pass
1086 events = self.vapi.collect_events()
1087 for e in events:
1088 self.logger.error("Received unexpected event: %s", e)
1089 self.assert_equal(count, 0, "number of packets received")
1090 self.assert_equal(len(events), 0, "number of events received")
Klement Sekera46a87ad2017-01-02 08:22:23 +01001091
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001092 def test_echo_looped_back(self):
1093 """ echo packets looped back """
1094 # don't need a session in this case..
1095 self.vpp_session.remove_vpp_config()
1096 self.pg0.enable_capture()
1097 echo_packet_count = 10
1098 # random source port low enough to increment a few times..
1099 udp_sport_tx = randint(1, 50000)
1100 udp_sport_rx = udp_sport_tx
1101 echo_packet = (Ether(src=self.pg0.remote_mac,
1102 dst=self.pg0.local_mac) /
1103 IP(src=self.pg0.remote_ip4,
Klement Sekera239790f2017-02-16 10:53:53 +01001104 dst=self.pg0.remote_ip4) /
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001105 UDP(dport=BFD.udp_dport_echo) /
1106 Raw("this should be looped back"))
1107 for dummy in range(echo_packet_count):
1108 self.sleep(.01, "delay between echo packets")
1109 echo_packet[UDP].sport = udp_sport_tx
1110 udp_sport_tx += 1
1111 self.logger.debug(ppp("Sending packet:", echo_packet))
1112 self.pg0.add_stream(echo_packet)
1113 self.pg_start()
1114 for dummy in range(echo_packet_count):
1115 p = self.pg0.wait_for_packet(1)
1116 self.logger.debug(ppp("Got packet:", p))
1117 ether = p[Ether]
1118 self.assert_equal(self.pg0.remote_mac,
1119 ether.dst, "Destination MAC")
1120 self.assert_equal(self.pg0.local_mac, ether.src, "Source MAC")
1121 ip = p[IP]
1122 self.assert_equal(self.pg0.remote_ip4, ip.dst, "Destination IP")
Klement Sekera239790f2017-02-16 10:53:53 +01001123 self.assert_equal(self.pg0.remote_ip4, ip.src, "Destination IP")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001124 udp = p[UDP]
1125 self.assert_equal(udp.dport, BFD.udp_dport_echo,
1126 "UDP destination port")
1127 self.assert_equal(udp.sport, udp_sport_rx, "UDP source port")
1128 udp_sport_rx += 1
Klement Sekera239790f2017-02-16 10:53:53 +01001129 # need to compare the hex payload here, otherwise BFD_vpp_echo
1130 # gets in way
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07001131 self.assertEqual(scapy.compat.raw(p[UDP].payload),
1132 scapy.compat.raw(echo_packet[UDP].payload),
Klement Sekera239790f2017-02-16 10:53:53 +01001133 "Received packet is not the echo packet sent")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001134 self.assert_equal(udp_sport_tx, udp_sport_rx, "UDP source port (== "
1135 "ECHO packet identifier for test purposes)")
1136
Klement Sekera239790f2017-02-16 10:53:53 +01001137 def test_echo(self):
1138 """ echo function """
1139 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001140 self.test_session.update(required_min_echo_rx=150000)
Klement Sekera239790f2017-02-16 10:53:53 +01001141 self.test_session.send_packet()
1142 detection_time = self.test_session.detect_mult *\
1143 self.vpp_session.required_min_rx / USEC_IN_SEC
1144 # echo shouldn't work without echo source set
Klement Sekera3cfa5582017-04-19 07:10:58 +00001145 for dummy in range(10):
1146 sleep = self.vpp_session.required_min_rx / USEC_IN_SEC
Klement Sekera239790f2017-02-16 10:53:53 +01001147 self.sleep(sleep, "delay before sending bfd packet")
1148 self.test_session.send_packet()
1149 p = wait_for_bfd_packet(
1150 self, pcap_time_min=time.time() - self.vpp_clock_offset)
1151 self.assert_equal(p[BFD].required_min_rx_interval,
1152 self.vpp_session.required_min_rx,
1153 "BFD required min rx interval")
Klement Sekera3cfa5582017-04-19 07:10:58 +00001154 self.test_session.send_packet()
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001155 self.vapi.bfd_udp_set_echo_source(
1156 sw_if_index=self.loopback0.sw_if_index)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001157 echo_seen = False
Klement Sekera239790f2017-02-16 10:53:53 +01001158 # should be turned on - loopback echo packets
1159 for dummy in range(3):
1160 loop_until = time.time() + 0.75 * detection_time
1161 while time.time() < loop_until:
1162 p = self.pg0.wait_for_packet(1)
1163 self.logger.debug(ppp("Got packet:", p))
1164 if p[UDP].dport == BFD.udp_dport_echo:
1165 self.assert_equal(
1166 p[IP].dst, self.pg0.local_ip4, "BFD ECHO dst IP")
1167 self.assertNotEqual(p[IP].src, self.loopback0.local_ip4,
1168 "BFD ECHO src IP equal to loopback IP")
1169 self.logger.debug(ppp("Looping back packet:", p))
John Lo1904c472017-03-10 17:15:22 -05001170 self.assert_equal(p[Ether].dst, self.pg0.remote_mac,
1171 "ECHO packet destination MAC address")
1172 p[Ether].dst = self.pg0.local_mac
Klement Sekera239790f2017-02-16 10:53:53 +01001173 self.pg0.add_stream(p)
1174 self.pg_start()
Klement Sekera3cfa5582017-04-19 07:10:58 +00001175 echo_seen = True
Klement Sekera239790f2017-02-16 10:53:53 +01001176 elif p.haslayer(BFD):
Klement Sekera3cfa5582017-04-19 07:10:58 +00001177 if echo_seen:
1178 self.assertGreaterEqual(
1179 p[BFD].required_min_rx_interval,
1180 1000000)
Klement Sekera239790f2017-02-16 10:53:53 +01001181 if "P" in p.sprintf("%BFD.flags%"):
1182 final = self.test_session.create_packet()
1183 final[BFD].flags = "F"
1184 self.test_session.send_packet(final)
1185 else:
1186 raise Exception(ppp("Received unknown packet:", p))
1187
1188 self.assert_equal(len(self.vapi.collect_events()), 0,
1189 "number of bfd events")
1190 self.test_session.send_packet()
Klement Sekera3cfa5582017-04-19 07:10:58 +00001191 self.assertTrue(echo_seen, "No echo packets received")
Klement Sekera239790f2017-02-16 10:53:53 +01001192
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08001193 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekera239790f2017-02-16 10:53:53 +01001194 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
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08001234 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekera239790f2017-02-16 10:53:53 +01001235 def test_echo_stop(self):
1236 """ echo function stops if peer sets required min echo rx zero """
1237 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001238 self.test_session.update(required_min_echo_rx=150000)
Klement Sekera239790f2017-02-16 10:53:53 +01001239 self.test_session.send_packet()
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001240 self.vapi.bfd_udp_set_echo_source(
1241 sw_if_index=self.loopback0.sw_if_index)
Klement Sekera239790f2017-02-16 10:53:53 +01001242 # wait for first echo packet
1243 while True:
1244 p = self.pg0.wait_for_packet(1)
1245 self.logger.debug(ppp("Got packet:", p))
1246 if p[UDP].dport == BFD.udp_dport_echo:
1247 self.logger.debug(ppp("Looping back packet:", p))
John Lo1904c472017-03-10 17:15:22 -05001248 p[Ether].dst = self.pg0.local_mac
Klement Sekera239790f2017-02-16 10:53:53 +01001249 self.pg0.add_stream(p)
1250 self.pg_start()
1251 break
1252 elif p.haslayer(BFD):
1253 # ignore BFD
1254 pass
1255 else:
1256 raise Exception(ppp("Received unknown packet:", p))
1257 self.test_session.update(required_min_echo_rx=0)
1258 self.test_session.send_packet()
1259 # echo packets shouldn't arrive anymore
1260 for dummy in range(5):
1261 wait_for_bfd_packet(
1262 self, pcap_time_min=time.time() - self.vpp_clock_offset)
1263 self.test_session.send_packet()
1264 events = self.vapi.collect_events()
1265 self.assert_equal(len(events), 0, "number of bfd events")
1266
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08001267 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekera73884482017-02-23 09:26:30 +01001268 def test_echo_source_removed(self):
1269 """ echo function stops if echo source is removed """
1270 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001271 self.test_session.update(required_min_echo_rx=150000)
Klement Sekera73884482017-02-23 09:26:30 +01001272 self.test_session.send_packet()
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001273 self.vapi.bfd_udp_set_echo_source(
1274 sw_if_index=self.loopback0.sw_if_index)
Klement Sekera73884482017-02-23 09:26:30 +01001275 # wait for first echo packet
1276 while True:
1277 p = self.pg0.wait_for_packet(1)
1278 self.logger.debug(ppp("Got packet:", p))
1279 if p[UDP].dport == BFD.udp_dport_echo:
1280 self.logger.debug(ppp("Looping back packet:", p))
John Lo1904c472017-03-10 17:15:22 -05001281 p[Ether].dst = self.pg0.local_mac
Klement Sekera73884482017-02-23 09:26:30 +01001282 self.pg0.add_stream(p)
1283 self.pg_start()
1284 break
1285 elif p.haslayer(BFD):
1286 # ignore BFD
1287 pass
1288 else:
1289 raise Exception(ppp("Received unknown packet:", p))
1290 self.vapi.bfd_udp_del_echo_source()
1291 self.test_session.send_packet()
1292 # echo packets shouldn't arrive anymore
1293 for dummy in range(5):
1294 wait_for_bfd_packet(
1295 self, pcap_time_min=time.time() - self.vpp_clock_offset)
1296 self.test_session.send_packet()
1297 events = self.vapi.collect_events()
1298 self.assert_equal(len(events), 0, "number of bfd events")
1299
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08001300 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekera239790f2017-02-16 10:53:53 +01001301 def test_stale_echo(self):
1302 """ stale echo packets don't keep a session up """
1303 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001304 self.test_session.update(required_min_echo_rx=150000)
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001305 self.vapi.bfd_udp_set_echo_source(
1306 sw_if_index=self.loopback0.sw_if_index)
Klement Sekera239790f2017-02-16 10:53:53 +01001307 self.test_session.send_packet()
1308 # should be turned on - loopback echo packets
1309 echo_packet = None
1310 timeout_at = None
1311 timeout_ok = False
1312 for dummy in range(10 * self.vpp_session.detect_mult):
1313 p = self.pg0.wait_for_packet(1)
1314 if p[UDP].dport == BFD.udp_dport_echo:
1315 if echo_packet is None:
1316 self.logger.debug(ppp("Got first echo packet:", p))
1317 echo_packet = p
1318 timeout_at = time.time() + self.vpp_session.detect_mult * \
1319 self.test_session.required_min_echo_rx / USEC_IN_SEC
1320 else:
1321 self.logger.debug(ppp("Got followup echo packet:", p))
1322 self.logger.debug(ppp("Looping back first echo packet:", p))
John Lo1904c472017-03-10 17:15:22 -05001323 echo_packet[Ether].dst = self.pg0.local_mac
Klement Sekera239790f2017-02-16 10:53:53 +01001324 self.pg0.add_stream(echo_packet)
1325 self.pg_start()
1326 elif p.haslayer(BFD):
1327 self.logger.debug(ppp("Got packet:", p))
1328 if "P" in p.sprintf("%BFD.flags%"):
1329 final = self.test_session.create_packet()
1330 final[BFD].flags = "F"
1331 self.test_session.send_packet(final)
1332 if p[BFD].state == BFDState.down:
1333 self.assertIsNotNone(
1334 timeout_at,
1335 "Session went down before first echo packet received")
1336 now = time.time()
1337 self.assertGreaterEqual(
1338 now, timeout_at,
1339 "Session timeout at %s, but is expected at %s" %
1340 (now, timeout_at))
1341 self.assert_equal(p[BFD].diag,
1342 BFDDiagCode.echo_function_failed,
1343 BFDDiagCode)
1344 events = self.vapi.collect_events()
1345 self.assert_equal(len(events), 1, "number of bfd events")
1346 self.assert_equal(events[0].state, BFDState.down, BFDState)
1347 timeout_ok = True
1348 break
1349 else:
1350 raise Exception(ppp("Received unknown packet:", p))
1351 self.test_session.send_packet()
1352 self.assertTrue(timeout_ok, "Expected timeout event didn't occur")
1353
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08001354 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekera239790f2017-02-16 10:53:53 +01001355 def test_invalid_echo_checksum(self):
1356 """ echo packets with invalid checksum don't keep a session up """
1357 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001358 self.test_session.update(required_min_echo_rx=150000)
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001359 self.vapi.bfd_udp_set_echo_source(
1360 sw_if_index=self.loopback0.sw_if_index)
Klement Sekera239790f2017-02-16 10:53:53 +01001361 self.test_session.send_packet()
1362 # should be turned on - loopback echo packets
1363 timeout_at = None
1364 timeout_ok = False
1365 for dummy in range(10 * self.vpp_session.detect_mult):
1366 p = self.pg0.wait_for_packet(1)
1367 if p[UDP].dport == BFD.udp_dport_echo:
1368 self.logger.debug(ppp("Got echo packet:", p))
1369 if timeout_at is None:
1370 timeout_at = time.time() + self.vpp_session.detect_mult * \
1371 self.test_session.required_min_echo_rx / USEC_IN_SEC
1372 p[BFD_vpp_echo].checksum = getrandbits(64)
John Lo1904c472017-03-10 17:15:22 -05001373 p[Ether].dst = self.pg0.local_mac
Klement Sekera239790f2017-02-16 10:53:53 +01001374 self.logger.debug(ppp("Looping back modified echo packet:", p))
1375 self.pg0.add_stream(p)
1376 self.pg_start()
1377 elif p.haslayer(BFD):
1378 self.logger.debug(ppp("Got packet:", p))
1379 if "P" in p.sprintf("%BFD.flags%"):
1380 final = self.test_session.create_packet()
1381 final[BFD].flags = "F"
1382 self.test_session.send_packet(final)
1383 if p[BFD].state == BFDState.down:
1384 self.assertIsNotNone(
1385 timeout_at,
1386 "Session went down before first echo packet received")
1387 now = time.time()
1388 self.assertGreaterEqual(
1389 now, timeout_at,
1390 "Session timeout at %s, but is expected at %s" %
1391 (now, timeout_at))
1392 self.assert_equal(p[BFD].diag,
1393 BFDDiagCode.echo_function_failed,
1394 BFDDiagCode)
1395 events = self.vapi.collect_events()
1396 self.assert_equal(len(events), 1, "number of bfd events")
1397 self.assert_equal(events[0].state, BFDState.down, BFDState)
1398 timeout_ok = True
1399 break
1400 else:
1401 raise Exception(ppp("Received unknown packet:", p))
1402 self.test_session.send_packet()
1403 self.assertTrue(timeout_ok, "Expected timeout event didn't occur")
1404
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08001405 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekerac48829b2017-02-14 07:55:57 +01001406 def test_admin_up_down(self):
Klement Sekera239790f2017-02-16 10:53:53 +01001407 """ put session admin-up and admin-down """
Klement Sekerac48829b2017-02-14 07:55:57 +01001408 bfd_session_up(self)
1409 self.vpp_session.admin_down()
1410 self.pg0.enable_capture()
1411 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
1412 verify_event(self, e, expected_state=BFDState.admin_down)
1413 for dummy in range(2):
1414 p = wait_for_bfd_packet(self)
Klement Sekera73884482017-02-23 09:26:30 +01001415 self.assert_equal(p[BFD].state, BFDState.admin_down, BFDState)
Klement Sekerac48829b2017-02-14 07:55:57 +01001416 # try to bring session up - shouldn't be possible
1417 self.test_session.update(state=BFDState.init)
1418 self.test_session.send_packet()
1419 for dummy in range(2):
1420 p = wait_for_bfd_packet(self)
Klement Sekera73884482017-02-23 09:26:30 +01001421 self.assert_equal(p[BFD].state, BFDState.admin_down, BFDState)
Klement Sekerac48829b2017-02-14 07:55:57 +01001422 self.vpp_session.admin_up()
1423 self.test_session.update(state=BFDState.down)
1424 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
1425 verify_event(self, e, expected_state=BFDState.down)
Klement Sekera73884482017-02-23 09:26:30 +01001426 p = wait_for_bfd_packet(
1427 self, pcap_time_min=time.time() - self.vpp_clock_offset)
1428 self.assert_equal(p[BFD].state, BFDState.down, BFDState)
Klement Sekerac48829b2017-02-14 07:55:57 +01001429 self.test_session.send_packet()
Klement Sekera73884482017-02-23 09:26:30 +01001430 p = wait_for_bfd_packet(
1431 self, pcap_time_min=time.time() - self.vpp_clock_offset)
1432 self.assert_equal(p[BFD].state, BFDState.init, BFDState)
Klement Sekerac48829b2017-02-14 07:55:57 +01001433 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
1434 verify_event(self, e, expected_state=BFDState.init)
1435 self.test_session.update(state=BFDState.up)
1436 self.test_session.send_packet()
Klement Sekera73884482017-02-23 09:26:30 +01001437 p = wait_for_bfd_packet(
1438 self, pcap_time_min=time.time() - self.vpp_clock_offset)
1439 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerac48829b2017-02-14 07:55:57 +01001440 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
1441 verify_event(self, e, expected_state=BFDState.up)
1442
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08001443 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekera239790f2017-02-16 10:53:53 +01001444 def test_config_change_remote_demand(self):
1445 """ configuration change while peer in demand mode """
1446 bfd_session_up(self)
1447 demand = self.test_session.create_packet()
1448 demand[BFD].flags = "D"
1449 self.test_session.send_packet(demand)
1450 self.vpp_session.modify_parameters(
1451 required_min_rx=2 * self.vpp_session.required_min_rx)
Klement Sekera73884482017-02-23 09:26:30 +01001452 p = wait_for_bfd_packet(
1453 self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekera239790f2017-02-16 10:53:53 +01001454 # poll bit must be set
1455 self.assertIn("P", p.sprintf("%BFD.flags%"), "Poll bit not set")
1456 # terminate poll sequence
1457 final = self.test_session.create_packet()
1458 final[BFD].flags = "D+F"
1459 self.test_session.send_packet(final)
1460 # vpp should be quiet now again
1461 transmit_time = 0.9 \
1462 * max(self.vpp_session.required_min_rx,
1463 self.test_session.desired_min_tx) \
1464 / USEC_IN_SEC
1465 count = 0
1466 for dummy in range(self.test_session.detect_mult * 2):
Paul Vinciguerra0f6602c2019-03-10 09:10:54 -07001467 self.sleep(transmit_time)
Klement Sekera239790f2017-02-16 10:53:53 +01001468 self.test_session.send_packet(demand)
1469 try:
1470 p = wait_for_bfd_packet(self, timeout=0)
1471 self.logger.error(ppp("Received unexpected packet:", p))
1472 count += 1
1473 except CaptureTimeoutError:
1474 pass
1475 events = self.vapi.collect_events()
1476 for e in events:
1477 self.logger.error("Received unexpected event: %s", e)
1478 self.assert_equal(count, 0, "number of packets received")
1479 self.assert_equal(len(events), 0, "number of events received")
1480
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001481 def test_intf_deleted(self):
1482 """ interface with bfd session deleted """
Klement Sekerabeaded52018-06-24 10:30:37 +02001483 intf = VppLoInterface(self)
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001484 intf.config_ip4()
1485 intf.admin_up()
1486 sw_if_index = intf.sw_if_index
1487 vpp_session = VppBFDUDPSession(self, intf, intf.remote_ip4)
1488 vpp_session.add_vpp_config()
1489 vpp_session.admin_up()
1490 intf.remove_vpp_config()
1491 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
1492 self.assert_equal(e.sw_if_index, sw_if_index, "sw_if_index")
1493 self.assertFalse(vpp_session.query_vpp_config())
1494
Klement Sekerad3ba5152017-02-14 03:09:17 +01001495
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08001496@unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekerad3ba5152017-02-14 03:09:17 +01001497class BFD6TestCase(VppTestCase):
Klement Sekera46a87ad2017-01-02 08:22:23 +01001498 """Bidirectional Forwarding Detection (BFD) (IPv6) """
1499
Klement Sekerad3ba5152017-02-14 03:09:17 +01001500 pg0 = None
1501 vpp_clock_offset = None
1502 vpp_session = None
1503 test_session = None
1504
Klement Sekera46a87ad2017-01-02 08:22:23 +01001505 @classmethod
1506 def setUpClass(cls):
1507 super(BFD6TestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -08001508 cls.vapi.cli("set log class bfd level debug")
Klement Sekera46a87ad2017-01-02 08:22:23 +01001509 try:
1510 cls.create_pg_interfaces([0])
1511 cls.pg0.config_ip6()
1512 cls.pg0.configure_ipv6_neighbors()
1513 cls.pg0.admin_up()
1514 cls.pg0.resolve_ndp()
Klement Sekerab9ef2732018-06-24 22:49:33 +02001515 cls.create_loopback_interfaces(1)
Klement Sekera239790f2017-02-16 10:53:53 +01001516 cls.loopback0 = cls.lo_interfaces[0]
1517 cls.loopback0.config_ip6()
1518 cls.loopback0.admin_up()
Klement Sekera46a87ad2017-01-02 08:22:23 +01001519
1520 except Exception:
1521 super(BFD6TestCase, cls).tearDownClass()
1522 raise
1523
Paul Vinciguerra8d991d92019-01-25 14:05:48 -08001524 @classmethod
1525 def tearDownClass(cls):
1526 super(BFD6TestCase, cls).tearDownClass()
1527
Klement Sekera46a87ad2017-01-02 08:22:23 +01001528 def setUp(self):
1529 super(BFD6TestCase, self).setUp()
Klement Sekerab17dd962017-01-09 07:43:48 +01001530 self.factory = AuthKeyFactory()
Klement Sekera46a87ad2017-01-02 08:22:23 +01001531 self.vapi.want_bfd_events()
Klement Sekerad3ba5152017-02-14 03:09:17 +01001532 self.pg0.enable_capture()
Klement Sekera46a87ad2017-01-02 08:22:23 +01001533 try:
1534 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1535 self.pg0.remote_ip6,
1536 af=AF_INET6)
1537 self.vpp_session.add_vpp_config()
1538 self.vpp_session.admin_up()
1539 self.test_session = BFDTestSession(self, self.pg0, AF_INET6)
1540 self.logger.debug(self.vapi.cli("show adj nbr"))
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001541 except BaseException:
Klement Sekera46a87ad2017-01-02 08:22:23 +01001542 self.vapi.want_bfd_events(enable_disable=0)
1543 raise
1544
1545 def tearDown(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001546 if not self.vpp_dead:
1547 self.vapi.want_bfd_events(enable_disable=0)
1548 self.vapi.collect_events() # clear the event queue
1549 super(BFD6TestCase, self).tearDown()
Klement Sekerab17dd962017-01-09 07:43:48 +01001550
1551 def test_session_up(self):
1552 """ bring BFD session up """
Klement Sekerad3ba5152017-02-14 03:09:17 +01001553 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001554
Klement Sekera73884482017-02-23 09:26:30 +01001555 def test_session_up_by_ip(self):
1556 """ bring BFD session up - first frame looked up by address pair """
1557 self.logger.info("BFD: Sending Slow control frame")
1558 self.test_session.update(my_discriminator=randint(0, 40000000))
1559 self.test_session.send_packet()
1560 self.pg0.enable_capture()
1561 p = self.pg0.wait_for_packet(1)
1562 self.assert_equal(p[BFD].your_discriminator,
1563 self.test_session.my_discriminator,
1564 "BFD - your discriminator")
1565 self.assert_equal(p[BFD].state, BFDState.init, BFDState)
1566 self.test_session.update(your_discriminator=p[BFD].my_discriminator,
1567 state=BFDState.up)
1568 self.logger.info("BFD: Waiting for event")
1569 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
1570 verify_event(self, e, expected_state=BFDState.init)
1571 self.logger.info("BFD: Sending Up")
1572 self.test_session.send_packet()
1573 self.logger.info("BFD: Waiting for event")
1574 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
1575 verify_event(self, e, expected_state=BFDState.up)
1576 self.logger.info("BFD: Session is Up")
1577 self.test_session.update(state=BFDState.up)
1578 self.test_session.send_packet()
1579 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1580
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08001581 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekerab17dd962017-01-09 07:43:48 +01001582 def test_hold_up(self):
1583 """ hold BFD session up """
Klement Sekerad3ba5152017-02-14 03:09:17 +01001584 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001585 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001586 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001587 self.test_session.send_packet()
1588 self.assert_equal(len(self.vapi.collect_events()), 0,
1589 "number of bfd events")
1590 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1591
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001592 def test_echo_looped_back(self):
1593 """ echo packets looped back """
1594 # don't need a session in this case..
1595 self.vpp_session.remove_vpp_config()
1596 self.pg0.enable_capture()
1597 echo_packet_count = 10
1598 # random source port low enough to increment a few times..
1599 udp_sport_tx = randint(1, 50000)
1600 udp_sport_rx = udp_sport_tx
1601 echo_packet = (Ether(src=self.pg0.remote_mac,
1602 dst=self.pg0.local_mac) /
1603 IPv6(src=self.pg0.remote_ip6,
Klement Sekera239790f2017-02-16 10:53:53 +01001604 dst=self.pg0.remote_ip6) /
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001605 UDP(dport=BFD.udp_dport_echo) /
1606 Raw("this should be looped back"))
1607 for dummy in range(echo_packet_count):
1608 self.sleep(.01, "delay between echo packets")
1609 echo_packet[UDP].sport = udp_sport_tx
1610 udp_sport_tx += 1
1611 self.logger.debug(ppp("Sending packet:", echo_packet))
1612 self.pg0.add_stream(echo_packet)
1613 self.pg_start()
1614 for dummy in range(echo_packet_count):
1615 p = self.pg0.wait_for_packet(1)
1616 self.logger.debug(ppp("Got packet:", p))
1617 ether = p[Ether]
1618 self.assert_equal(self.pg0.remote_mac,
1619 ether.dst, "Destination MAC")
1620 self.assert_equal(self.pg0.local_mac, ether.src, "Source MAC")
1621 ip = p[IPv6]
1622 self.assert_equal(self.pg0.remote_ip6, ip.dst, "Destination IP")
Klement Sekera239790f2017-02-16 10:53:53 +01001623 self.assert_equal(self.pg0.remote_ip6, ip.src, "Destination IP")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001624 udp = p[UDP]
1625 self.assert_equal(udp.dport, BFD.udp_dport_echo,
1626 "UDP destination port")
1627 self.assert_equal(udp.sport, udp_sport_rx, "UDP source port")
1628 udp_sport_rx += 1
Klement Sekera239790f2017-02-16 10:53:53 +01001629 # need to compare the hex payload here, otherwise BFD_vpp_echo
1630 # gets in way
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07001631 self.assertEqual(scapy.compat.raw(p[UDP].payload),
1632 scapy.compat.raw(echo_packet[UDP].payload),
Klement Sekera239790f2017-02-16 10:53:53 +01001633 "Received packet is not the echo packet sent")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001634 self.assert_equal(udp_sport_tx, udp_sport_rx, "UDP source port (== "
1635 "ECHO packet identifier for test purposes)")
Klement Sekera239790f2017-02-16 10:53:53 +01001636 self.assert_equal(udp_sport_tx, udp_sport_rx, "UDP source port (== "
1637 "ECHO packet identifier for test purposes)")
1638
1639 def test_echo(self):
Klement Sekera3cfa5582017-04-19 07:10:58 +00001640 """ echo function """
Klement Sekera239790f2017-02-16 10:53:53 +01001641 bfd_session_up(self)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001642 self.test_session.update(required_min_echo_rx=150000)
Klement Sekera239790f2017-02-16 10:53:53 +01001643 self.test_session.send_packet()
1644 detection_time = self.test_session.detect_mult *\
1645 self.vpp_session.required_min_rx / USEC_IN_SEC
1646 # echo shouldn't work without echo source set
Klement Sekera3cfa5582017-04-19 07:10:58 +00001647 for dummy in range(10):
1648 sleep = self.vpp_session.required_min_rx / USEC_IN_SEC
Klement Sekera239790f2017-02-16 10:53:53 +01001649 self.sleep(sleep, "delay before sending bfd packet")
1650 self.test_session.send_packet()
1651 p = wait_for_bfd_packet(
1652 self, pcap_time_min=time.time() - self.vpp_clock_offset)
1653 self.assert_equal(p[BFD].required_min_rx_interval,
1654 self.vpp_session.required_min_rx,
1655 "BFD required min rx interval")
Klement Sekera3cfa5582017-04-19 07:10:58 +00001656 self.test_session.send_packet()
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001657 self.vapi.bfd_udp_set_echo_source(
1658 sw_if_index=self.loopback0.sw_if_index)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001659 echo_seen = False
Klement Sekera239790f2017-02-16 10:53:53 +01001660 # should be turned on - loopback echo packets
1661 for dummy in range(3):
1662 loop_until = time.time() + 0.75 * detection_time
1663 while time.time() < loop_until:
1664 p = self.pg0.wait_for_packet(1)
1665 self.logger.debug(ppp("Got packet:", p))
1666 if p[UDP].dport == BFD.udp_dport_echo:
1667 self.assert_equal(
1668 p[IPv6].dst, self.pg0.local_ip6, "BFD ECHO dst IP")
1669 self.assertNotEqual(p[IPv6].src, self.loopback0.local_ip6,
1670 "BFD ECHO src IP equal to loopback IP")
1671 self.logger.debug(ppp("Looping back packet:", p))
John Lo1904c472017-03-10 17:15:22 -05001672 self.assert_equal(p[Ether].dst, self.pg0.remote_mac,
1673 "ECHO packet destination MAC address")
1674 p[Ether].dst = self.pg0.local_mac
Klement Sekera239790f2017-02-16 10:53:53 +01001675 self.pg0.add_stream(p)
1676 self.pg_start()
Klement Sekera3cfa5582017-04-19 07:10:58 +00001677 echo_seen = True
Klement Sekera239790f2017-02-16 10:53:53 +01001678 elif p.haslayer(BFD):
Klement Sekera3cfa5582017-04-19 07:10:58 +00001679 if echo_seen:
1680 self.assertGreaterEqual(
1681 p[BFD].required_min_rx_interval,
1682 1000000)
Klement Sekera239790f2017-02-16 10:53:53 +01001683 if "P" in p.sprintf("%BFD.flags%"):
1684 final = self.test_session.create_packet()
1685 final[BFD].flags = "F"
1686 self.test_session.send_packet(final)
1687 else:
1688 raise Exception(ppp("Received unknown packet:", p))
1689
1690 self.assert_equal(len(self.vapi.collect_events()), 0,
1691 "number of bfd events")
1692 self.test_session.send_packet()
Klement Sekera3cfa5582017-04-19 07:10:58 +00001693 self.assertTrue(echo_seen, "No echo packets received")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001694
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001695 def test_intf_deleted(self):
1696 """ interface with bfd session deleted """
Klement Sekerabeaded52018-06-24 10:30:37 +02001697 intf = VppLoInterface(self)
Klement Sekeraf3bcdbf2017-05-02 07:38:01 +02001698 intf.config_ip6()
1699 intf.admin_up()
1700 sw_if_index = intf.sw_if_index
1701 vpp_session = VppBFDUDPSession(
1702 self, intf, intf.remote_ip6, af=AF_INET6)
1703 vpp_session.add_vpp_config()
1704 vpp_session.admin_up()
1705 intf.remove_vpp_config()
1706 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
1707 self.assert_equal(e.sw_if_index, sw_if_index, "sw_if_index")
1708 self.assertFalse(vpp_session.query_vpp_config())
1709
Klement Sekerab17dd962017-01-09 07:43:48 +01001710
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08001711@unittest.skipUnless(running_extended_tests, "part of extended tests")
Neale Ranns88fc83e2017-04-05 08:11:14 -07001712class BFDFIBTestCase(VppTestCase):
1713 """ BFD-FIB interactions (IPv6) """
1714
1715 vpp_session = None
1716 test_session = None
1717
Paul Vinciguerra8d991d92019-01-25 14:05:48 -08001718 @classmethod
1719 def setUpClass(cls):
1720 super(BFDFIBTestCase, cls).setUpClass()
1721
1722 @classmethod
1723 def tearDownClass(cls):
1724 super(BFDFIBTestCase, cls).tearDownClass()
1725
Neale Ranns88fc83e2017-04-05 08:11:14 -07001726 def setUp(self):
1727 super(BFDFIBTestCase, self).setUp()
1728 self.create_pg_interfaces(range(1))
1729
1730 self.vapi.want_bfd_events()
1731 self.pg0.enable_capture()
1732
1733 for i in self.pg_interfaces:
1734 i.admin_up()
1735 i.config_ip6()
1736 i.configure_ipv6_neighbors()
1737
1738 def tearDown(self):
1739 if not self.vpp_dead:
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001740 self.vapi.want_bfd_events(enable_disable=False)
Neale Ranns88fc83e2017-04-05 08:11:14 -07001741
1742 super(BFDFIBTestCase, self).tearDown()
1743
1744 @staticmethod
1745 def pkt_is_not_data_traffic(p):
1746 """ not data traffic implies BFD or the usual IPv6 ND/RA"""
1747 if p.haslayer(BFD) or is_ipv6_misc(p):
1748 return True
1749 return False
1750
1751 def test_session_with_fib(self):
1752 """ BFD-FIB interactions """
1753
1754 # packets to match against both of the routes
1755 p = [(Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
Klement Sekera3cfa5582017-04-19 07:10:58 +00001756 IPv6(src="3001::1", dst="2001::1") /
1757 UDP(sport=1234, dport=1234) /
Ole Troan770a0de2019-11-07 13:52:21 +01001758 Raw(b'\xa5' * 100)),
Neale Ranns88fc83e2017-04-05 08:11:14 -07001759 (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1760 IPv6(src="3001::1", dst="2002::1") /
1761 UDP(sport=1234, dport=1234) /
Ole Troan770a0de2019-11-07 13:52:21 +01001762 Raw(b'\xa5' * 100))]
Neale Ranns88fc83e2017-04-05 08:11:14 -07001763
1764 # A recursive and a non-recursive route via a next-hop that
1765 # will have a BFD session
1766 ip_2001_s_64 = VppIpRoute(self, "2001::", 64,
1767 [VppRoutePath(self.pg0.remote_ip6,
Neale Ranns097fa662018-05-01 05:17:55 -07001768 self.pg0.sw_if_index)])
Neale Ranns88fc83e2017-04-05 08:11:14 -07001769 ip_2002_s_64 = VppIpRoute(self, "2002::", 64,
1770 [VppRoutePath(self.pg0.remote_ip6,
Neale Ranns097fa662018-05-01 05:17:55 -07001771 0xffffffff)])
Neale Ranns88fc83e2017-04-05 08:11:14 -07001772 ip_2001_s_64.add_vpp_config()
1773 ip_2002_s_64.add_vpp_config()
1774
1775 # bring the session up now the routes are present
1776 self.vpp_session = VppBFDUDPSession(self,
1777 self.pg0,
1778 self.pg0.remote_ip6,
1779 af=AF_INET6)
1780 self.vpp_session.add_vpp_config()
1781 self.vpp_session.admin_up()
1782 self.test_session = BFDTestSession(self, self.pg0, AF_INET6)
1783
1784 # session is up - traffic passes
1785 bfd_session_up(self)
1786
1787 self.pg0.add_stream(p)
1788 self.pg_start()
1789 for packet in p:
1790 captured = self.pg0.wait_for_packet(
1791 1,
1792 filter_out_fn=self.pkt_is_not_data_traffic)
1793 self.assertEqual(captured[IPv6].dst,
1794 packet[IPv6].dst)
1795
1796 # session is up - traffic is dropped
1797 bfd_session_down(self)
1798
1799 self.pg0.add_stream(p)
1800 self.pg_start()
1801 with self.assertRaises(CaptureTimeoutError):
1802 self.pg0.wait_for_packet(1, self.pkt_is_not_data_traffic)
1803
1804 # session is up - traffic passes
1805 bfd_session_up(self)
1806
1807 self.pg0.add_stream(p)
1808 self.pg_start()
1809 for packet in p:
1810 captured = self.pg0.wait_for_packet(
1811 1,
1812 filter_out_fn=self.pkt_is_not_data_traffic)
1813 self.assertEqual(captured[IPv6].dst,
1814 packet[IPv6].dst)
1815
1816
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08001817@unittest.skipUnless(running_extended_tests, "part of extended tests")
Neale Ranns52cd4962019-06-05 10:28:17 +00001818class BFDTunTestCase(VppTestCase):
1819 """ BFD over GRE tunnel """
1820
1821 vpp_session = None
1822 test_session = None
1823
1824 @classmethod
1825 def setUpClass(cls):
1826 super(BFDTunTestCase, cls).setUpClass()
1827
1828 @classmethod
1829 def tearDownClass(cls):
1830 super(BFDTunTestCase, cls).tearDownClass()
1831
1832 def setUp(self):
1833 super(BFDTunTestCase, self).setUp()
1834 self.create_pg_interfaces(range(1))
1835
1836 self.vapi.want_bfd_events()
1837 self.pg0.enable_capture()
1838
1839 for i in self.pg_interfaces:
1840 i.admin_up()
1841 i.config_ip4()
1842 i.resolve_arp()
1843
1844 def tearDown(self):
1845 if not self.vpp_dead:
1846 self.vapi.want_bfd_events(enable_disable=0)
1847
1848 super(BFDTunTestCase, self).tearDown()
1849
1850 @staticmethod
1851 def pkt_is_not_data_traffic(p):
1852 """ not data traffic implies BFD or the usual IPv6 ND/RA"""
1853 if p.haslayer(BFD) or is_ipv6_misc(p):
1854 return True
1855 return False
1856
1857 def test_bfd_o_gre(self):
1858 """ BFD-o-GRE """
1859
1860 # A GRE interface over which to run a BFD session
1861 gre_if = VppGreInterface(self,
1862 self.pg0.local_ip4,
1863 self.pg0.remote_ip4)
1864 gre_if.add_vpp_config()
1865 gre_if.admin_up()
1866 gre_if.config_ip4()
1867
1868 # bring the session up now the routes are present
1869 self.vpp_session = VppBFDUDPSession(self,
1870 gre_if,
1871 gre_if.remote_ip4,
1872 is_tunnel=True)
1873 self.vpp_session.add_vpp_config()
1874 self.vpp_session.admin_up()
1875
1876 self.test_session = BFDTestSession(
1877 self, gre_if, AF_INET,
1878 tunnel_header=(IP(src=self.pg0.remote_ip4,
1879 dst=self.pg0.local_ip4) /
1880 GRE()),
1881 phy_interface=self.pg0)
1882
1883 # packets to match against both of the routes
1884 p = [(Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1885 IP(src=self.pg0.remote_ip4, dst=gre_if.remote_ip4) /
1886 UDP(sport=1234, dport=1234) /
Ole Troan770a0de2019-11-07 13:52:21 +01001887 Raw(b'\xa5' * 100))]
Neale Ranns52cd4962019-06-05 10:28:17 +00001888
1889 # session is up - traffic passes
1890 bfd_session_up(self)
1891
1892 self.send_and_expect(self.pg0, p, self.pg0)
1893
1894 # bring session down
1895 bfd_session_down(self)
1896
1897
1898@unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekerad3ba5152017-02-14 03:09:17 +01001899class BFDSHA1TestCase(VppTestCase):
Klement Sekerab17dd962017-01-09 07:43:48 +01001900 """Bidirectional Forwarding Detection (BFD) (SHA1 auth) """
1901
Klement Sekerad3ba5152017-02-14 03:09:17 +01001902 pg0 = None
1903 vpp_clock_offset = None
1904 vpp_session = None
1905 test_session = None
1906
Klement Sekerab17dd962017-01-09 07:43:48 +01001907 @classmethod
1908 def setUpClass(cls):
1909 super(BFDSHA1TestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -08001910 cls.vapi.cli("set log class bfd level debug")
Klement Sekerab17dd962017-01-09 07:43:48 +01001911 try:
1912 cls.create_pg_interfaces([0])
1913 cls.pg0.config_ip4()
1914 cls.pg0.admin_up()
1915 cls.pg0.resolve_arp()
1916
1917 except Exception:
1918 super(BFDSHA1TestCase, cls).tearDownClass()
1919 raise
1920
Paul Vinciguerra8d991d92019-01-25 14:05:48 -08001921 @classmethod
1922 def tearDownClass(cls):
1923 super(BFDSHA1TestCase, cls).tearDownClass()
1924
Klement Sekerab17dd962017-01-09 07:43:48 +01001925 def setUp(self):
1926 super(BFDSHA1TestCase, self).setUp()
1927 self.factory = AuthKeyFactory()
1928 self.vapi.want_bfd_events()
Klement Sekerad3ba5152017-02-14 03:09:17 +01001929 self.pg0.enable_capture()
Klement Sekerab17dd962017-01-09 07:43:48 +01001930
1931 def tearDown(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001932 if not self.vpp_dead:
Jakub Grajciar4682feb2019-09-02 13:28:52 +02001933 self.vapi.want_bfd_events(enable_disable=False)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001934 self.vapi.collect_events() # clear the event queue
1935 super(BFDSHA1TestCase, self).tearDown()
Klement Sekerab17dd962017-01-09 07:43:48 +01001936
1937 def test_session_up(self):
1938 """ bring BFD session up """
1939 key = self.factory.create_random_key(self)
1940 key.add_vpp_config()
1941 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1942 self.pg0.remote_ip4,
1943 sha1_key=key)
1944 self.vpp_session.add_vpp_config()
1945 self.vpp_session.admin_up()
1946 self.test_session = BFDTestSession(
1947 self, self.pg0, AF_INET, sha1_key=key,
1948 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001949 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001950
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08001951 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekerab17dd962017-01-09 07:43:48 +01001952 def test_hold_up(self):
1953 """ hold BFD session up """
1954 key = self.factory.create_random_key(self)
1955 key.add_vpp_config()
1956 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1957 self.pg0.remote_ip4,
1958 sha1_key=key)
1959 self.vpp_session.add_vpp_config()
1960 self.vpp_session.admin_up()
1961 self.test_session = BFDTestSession(
1962 self, self.pg0, AF_INET, sha1_key=key,
1963 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001964 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001965 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001966 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001967 self.test_session.send_packet()
1968 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1969
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08001970 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekerab17dd962017-01-09 07:43:48 +01001971 def test_hold_up_meticulous(self):
1972 """ hold BFD session up - meticulous auth """
1973 key = self.factory.create_random_key(
1974 self, BFDAuthType.meticulous_keyed_sha1)
1975 key.add_vpp_config()
1976 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1977 self.pg0.remote_ip4, sha1_key=key)
1978 self.vpp_session.add_vpp_config()
1979 self.vpp_session.admin_up()
Klement Sekerad3ba5152017-02-14 03:09:17 +01001980 # specify sequence number so that it wraps
Klement Sekerab17dd962017-01-09 07:43:48 +01001981 self.test_session = BFDTestSession(
1982 self, self.pg0, AF_INET, sha1_key=key,
Klement Sekerad3ba5152017-02-14 03:09:17 +01001983 bfd_key_id=self.vpp_session.bfd_key_id,
1984 our_seq_number=0xFFFFFFFF - 4)
1985 bfd_session_up(self)
1986 for dummy in range(30):
1987 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001988 self.test_session.inc_seq_num()
1989 self.test_session.send_packet()
1990 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1991
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08001992 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekerab17dd962017-01-09 07:43:48 +01001993 def test_send_bad_seq_number(self):
Klement Sekera239790f2017-02-16 10:53:53 +01001994 """ session is not kept alive by msgs with bad sequence numbers"""
Klement Sekerab17dd962017-01-09 07:43:48 +01001995 key = self.factory.create_random_key(
1996 self, BFDAuthType.meticulous_keyed_sha1)
1997 key.add_vpp_config()
1998 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1999 self.pg0.remote_ip4, sha1_key=key)
2000 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002001 self.test_session = BFDTestSession(
2002 self, self.pg0, AF_INET, sha1_key=key,
2003 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002004 bfd_session_up(self)
Klement Sekera239790f2017-02-16 10:53:53 +01002005 detection_time = self.test_session.detect_mult *\
Klement Sekerad3ba5152017-02-14 03:09:17 +01002006 self.vpp_session.required_min_rx / USEC_IN_SEC
Klement Sekera239790f2017-02-16 10:53:53 +01002007 send_until = time.time() + 2 * detection_time
2008 while time.time() < send_until:
Klement Sekerad3ba5152017-02-14 03:09:17 +01002009 self.test_session.send_packet()
Klement Sekera239790f2017-02-16 10:53:53 +01002010 self.sleep(0.7 * self.vpp_session.required_min_rx / USEC_IN_SEC,
2011 "time between bfd packets")
Klement Sekerab17dd962017-01-09 07:43:48 +01002012 e = self.vapi.collect_events()
2013 # session should be down now, because the sequence numbers weren't
2014 # updated
2015 self.assert_equal(len(e), 1, "number of bfd events")
Klement Sekerad3ba5152017-02-14 03:09:17 +01002016 verify_event(self, e[0], expected_state=BFDState.down)
Klement Sekerab17dd962017-01-09 07:43:48 +01002017
2018 def execute_rogue_session_scenario(self, vpp_bfd_udp_session,
2019 legitimate_test_session,
2020 rogue_test_session,
2021 rogue_bfd_values=None):
2022 """ execute a rogue session interaction scenario
2023
2024 1. create vpp session, add config
2025 2. bring the legitimate session up
2026 3. copy the bfd values from legitimate session to rogue session
2027 4. apply rogue_bfd_values to rogue session
2028 5. set rogue session state to down
2029 6. send message to take the session down from the rogue session
2030 7. assert that the legitimate session is unaffected
2031 """
2032
2033 self.vpp_session = vpp_bfd_udp_session
2034 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002035 self.test_session = legitimate_test_session
2036 # bring vpp session up
Klement Sekerad3ba5152017-02-14 03:09:17 +01002037 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002038 # send packet from rogue session
Klement Sekerad3ba5152017-02-14 03:09:17 +01002039 rogue_test_session.update(
2040 my_discriminator=self.test_session.my_discriminator,
2041 your_discriminator=self.test_session.your_discriminator,
2042 desired_min_tx=self.test_session.desired_min_tx,
2043 required_min_rx=self.test_session.required_min_rx,
2044 detect_mult=self.test_session.detect_mult,
2045 diag=self.test_session.diag,
2046 state=self.test_session.state,
2047 auth_type=self.test_session.auth_type)
Klement Sekerab17dd962017-01-09 07:43:48 +01002048 if rogue_bfd_values:
2049 rogue_test_session.update(**rogue_bfd_values)
2050 rogue_test_session.update(state=BFDState.down)
2051 rogue_test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +01002052 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002053 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
2054
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08002055 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekerab17dd962017-01-09 07:43:48 +01002056 def test_mismatch_auth(self):
2057 """ session is not brought down by unauthenticated msg """
2058 key = self.factory.create_random_key(self)
2059 key.add_vpp_config()
2060 vpp_session = VppBFDUDPSession(
2061 self, self.pg0, self.pg0.remote_ip4, sha1_key=key)
2062 legitimate_test_session = BFDTestSession(
2063 self, self.pg0, AF_INET, sha1_key=key,
2064 bfd_key_id=vpp_session.bfd_key_id)
2065 rogue_test_session = BFDTestSession(self, self.pg0, AF_INET)
2066 self.execute_rogue_session_scenario(vpp_session,
2067 legitimate_test_session,
2068 rogue_test_session)
2069
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08002070 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekerab17dd962017-01-09 07:43:48 +01002071 def test_mismatch_bfd_key_id(self):
2072 """ session is not brought down by msg with non-existent key-id """
2073 key = self.factory.create_random_key(self)
2074 key.add_vpp_config()
2075 vpp_session = VppBFDUDPSession(
2076 self, self.pg0, self.pg0.remote_ip4, sha1_key=key)
2077 # pick a different random bfd key id
2078 x = randint(0, 255)
2079 while x == vpp_session.bfd_key_id:
2080 x = randint(0, 255)
2081 legitimate_test_session = BFDTestSession(
2082 self, self.pg0, AF_INET, sha1_key=key,
2083 bfd_key_id=vpp_session.bfd_key_id)
2084 rogue_test_session = BFDTestSession(
2085 self, self.pg0, AF_INET, sha1_key=key, bfd_key_id=x)
2086 self.execute_rogue_session_scenario(vpp_session,
2087 legitimate_test_session,
2088 rogue_test_session)
2089
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08002090 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekerab17dd962017-01-09 07:43:48 +01002091 def test_mismatched_auth_type(self):
2092 """ session is not brought down by msg with wrong auth type """
2093 key = self.factory.create_random_key(self)
2094 key.add_vpp_config()
2095 vpp_session = VppBFDUDPSession(
2096 self, self.pg0, self.pg0.remote_ip4, sha1_key=key)
2097 legitimate_test_session = BFDTestSession(
2098 self, self.pg0, AF_INET, sha1_key=key,
2099 bfd_key_id=vpp_session.bfd_key_id)
2100 rogue_test_session = BFDTestSession(
2101 self, self.pg0, AF_INET, sha1_key=key,
2102 bfd_key_id=vpp_session.bfd_key_id)
2103 self.execute_rogue_session_scenario(
2104 vpp_session, legitimate_test_session, rogue_test_session,
2105 {'auth_type': BFDAuthType.keyed_md5})
2106
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08002107 @unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekerab17dd962017-01-09 07:43:48 +01002108 def test_restart(self):
2109 """ simulate remote peer restart and resynchronization """
2110 key = self.factory.create_random_key(
2111 self, BFDAuthType.meticulous_keyed_sha1)
2112 key.add_vpp_config()
2113 self.vpp_session = VppBFDUDPSession(self, self.pg0,
2114 self.pg0.remote_ip4, sha1_key=key)
2115 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002116 self.test_session = BFDTestSession(
2117 self, self.pg0, AF_INET, sha1_key=key,
2118 bfd_key_id=self.vpp_session.bfd_key_id, our_seq_number=0)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002119 bfd_session_up(self)
2120 # don't send any packets for 2*detection_time
Klement Sekera239790f2017-02-16 10:53:53 +01002121 detection_time = self.test_session.detect_mult *\
Klement Sekerad3ba5152017-02-14 03:09:17 +01002122 self.vpp_session.required_min_rx / USEC_IN_SEC
Klement Sekera87134932017-03-07 11:39:27 +01002123 self.sleep(2 * detection_time, "simulating peer restart")
Klement Sekerad3ba5152017-02-14 03:09:17 +01002124 events = self.vapi.collect_events()
2125 self.assert_equal(len(events), 1, "number of bfd events")
2126 verify_event(self, events[0], expected_state=BFDState.down)
Klement Sekerab17dd962017-01-09 07:43:48 +01002127 self.test_session.update(state=BFDState.down)
Klement Sekerab17dd962017-01-09 07:43:48 +01002128 # reset sequence number
2129 self.test_session.our_seq_number = 0
Klement Sekerad3ba5152017-02-14 03:09:17 +01002130 self.test_session.vpp_seq_number = None
2131 # now throw away any pending packets
2132 self.pg0.enable_capture()
2133 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002134
2135
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08002136@unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekerad3ba5152017-02-14 03:09:17 +01002137class BFDAuthOnOffTestCase(VppTestCase):
Klement Sekerab17dd962017-01-09 07:43:48 +01002138 """Bidirectional Forwarding Detection (BFD) (changing auth) """
2139
Klement Sekerad3ba5152017-02-14 03:09:17 +01002140 pg0 = None
2141 vpp_session = None
2142 test_session = None
2143
Klement Sekerab17dd962017-01-09 07:43:48 +01002144 @classmethod
2145 def setUpClass(cls):
2146 super(BFDAuthOnOffTestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -08002147 cls.vapi.cli("set log class bfd level debug")
Klement Sekerab17dd962017-01-09 07:43:48 +01002148 try:
2149 cls.create_pg_interfaces([0])
2150 cls.pg0.config_ip4()
2151 cls.pg0.admin_up()
2152 cls.pg0.resolve_arp()
2153
2154 except Exception:
2155 super(BFDAuthOnOffTestCase, cls).tearDownClass()
2156 raise
2157
Paul Vinciguerra8d991d92019-01-25 14:05:48 -08002158 @classmethod
2159 def tearDownClass(cls):
2160 super(BFDAuthOnOffTestCase, cls).tearDownClass()
2161
Klement Sekerab17dd962017-01-09 07:43:48 +01002162 def setUp(self):
2163 super(BFDAuthOnOffTestCase, self).setUp()
2164 self.factory = AuthKeyFactory()
2165 self.vapi.want_bfd_events()
Klement Sekerad3ba5152017-02-14 03:09:17 +01002166 self.pg0.enable_capture()
Klement Sekerab17dd962017-01-09 07:43:48 +01002167
2168 def tearDown(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002169 if not self.vpp_dead:
Jakub Grajciar4682feb2019-09-02 13:28:52 +02002170 self.vapi.want_bfd_events(enable_disable=False)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002171 self.vapi.collect_events() # clear the event queue
2172 super(BFDAuthOnOffTestCase, self).tearDown()
Klement Sekerab17dd962017-01-09 07:43:48 +01002173
2174 def test_auth_on_immediate(self):
2175 """ turn auth on without disturbing session state (immediate) """
2176 key = self.factory.create_random_key(self)
2177 key.add_vpp_config()
2178 self.vpp_session = VppBFDUDPSession(self, self.pg0,
2179 self.pg0.remote_ip4)
2180 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002181 self.test_session = BFDTestSession(self, self.pg0, AF_INET)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002182 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002183 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002184 p = wait_for_bfd_packet(self)
2185 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002186 self.test_session.send_packet()
2187 self.vpp_session.activate_auth(key)
2188 self.test_session.bfd_key_id = self.vpp_session.bfd_key_id
2189 self.test_session.sha1_key = key
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002190 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002191 p = wait_for_bfd_packet(self)
2192 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002193 self.test_session.send_packet()
2194 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
2195 self.assert_equal(len(self.vapi.collect_events()), 0,
2196 "number of bfd events")
2197
2198 def test_auth_off_immediate(self):
2199 """ turn auth off without disturbing session state (immediate) """
2200 key = self.factory.create_random_key(self)
2201 key.add_vpp_config()
2202 self.vpp_session = VppBFDUDPSession(self, self.pg0,
2203 self.pg0.remote_ip4, sha1_key=key)
2204 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002205 self.test_session = BFDTestSession(
2206 self, self.pg0, AF_INET, sha1_key=key,
2207 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002208 bfd_session_up(self)
2209 # self.vapi.want_bfd_events(enable_disable=0)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002210 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002211 p = wait_for_bfd_packet(self)
2212 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
2213 self.test_session.inc_seq_num()
Klement Sekerab17dd962017-01-09 07:43:48 +01002214 self.test_session.send_packet()
2215 self.vpp_session.deactivate_auth()
2216 self.test_session.bfd_key_id = None
2217 self.test_session.sha1_key = None
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002218 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002219 p = wait_for_bfd_packet(self)
2220 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
2221 self.test_session.inc_seq_num()
Klement Sekerab17dd962017-01-09 07:43:48 +01002222 self.test_session.send_packet()
2223 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
2224 self.assert_equal(len(self.vapi.collect_events()), 0,
2225 "number of bfd events")
2226
2227 def test_auth_change_key_immediate(self):
2228 """ change auth key without disturbing session state (immediate) """
2229 key1 = self.factory.create_random_key(self)
2230 key1.add_vpp_config()
2231 key2 = self.factory.create_random_key(self)
2232 key2.add_vpp_config()
2233 self.vpp_session = VppBFDUDPSession(self, self.pg0,
2234 self.pg0.remote_ip4, sha1_key=key1)
2235 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002236 self.test_session = BFDTestSession(
2237 self, self.pg0, AF_INET, sha1_key=key1,
2238 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002239 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002240 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002241 p = wait_for_bfd_packet(self)
2242 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002243 self.test_session.send_packet()
2244 self.vpp_session.activate_auth(key2)
2245 self.test_session.bfd_key_id = self.vpp_session.bfd_key_id
2246 self.test_session.sha1_key = key2
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002247 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002248 p = wait_for_bfd_packet(self)
2249 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002250 self.test_session.send_packet()
2251 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
2252 self.assert_equal(len(self.vapi.collect_events()), 0,
2253 "number of bfd events")
2254
2255 def test_auth_on_delayed(self):
2256 """ turn auth on without disturbing session state (delayed) """
2257 key = self.factory.create_random_key(self)
2258 key.add_vpp_config()
2259 self.vpp_session = VppBFDUDPSession(self, self.pg0,
2260 self.pg0.remote_ip4)
2261 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002262 self.test_session = BFDTestSession(self, self.pg0, AF_INET)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002263 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002264 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002265 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01002266 self.test_session.send_packet()
2267 self.vpp_session.activate_auth(key, delayed=True)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002268 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002269 p = wait_for_bfd_packet(self)
2270 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002271 self.test_session.send_packet()
2272 self.test_session.bfd_key_id = self.vpp_session.bfd_key_id
2273 self.test_session.sha1_key = key
2274 self.test_session.send_packet()
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002275 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002276 p = wait_for_bfd_packet(self)
2277 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002278 self.test_session.send_packet()
2279 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
2280 self.assert_equal(len(self.vapi.collect_events()), 0,
2281 "number of bfd events")
2282
2283 def test_auth_off_delayed(self):
2284 """ turn auth off without disturbing session state (delayed) """
2285 key = self.factory.create_random_key(self)
2286 key.add_vpp_config()
2287 self.vpp_session = VppBFDUDPSession(self, self.pg0,
2288 self.pg0.remote_ip4, sha1_key=key)
2289 self.vpp_session.add_vpp_config()
Klement Sekerab17dd962017-01-09 07:43:48 +01002290 self.test_session = BFDTestSession(
2291 self, self.pg0, AF_INET, sha1_key=key,
2292 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002293 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002294 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002295 p = wait_for_bfd_packet(self)
2296 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002297 self.test_session.send_packet()
2298 self.vpp_session.deactivate_auth(delayed=True)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002299 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002300 p = wait_for_bfd_packet(self)
2301 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002302 self.test_session.send_packet()
2303 self.test_session.bfd_key_id = None
2304 self.test_session.sha1_key = None
2305 self.test_session.send_packet()
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002306 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002307 p = wait_for_bfd_packet(self)
2308 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002309 self.test_session.send_packet()
2310 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
2311 self.assert_equal(len(self.vapi.collect_events()), 0,
2312 "number of bfd events")
2313
2314 def test_auth_change_key_delayed(self):
2315 """ change auth key without disturbing session state (delayed) """
2316 key1 = self.factory.create_random_key(self)
2317 key1.add_vpp_config()
2318 key2 = self.factory.create_random_key(self)
2319 key2.add_vpp_config()
2320 self.vpp_session = VppBFDUDPSession(self, self.pg0,
2321 self.pg0.remote_ip4, sha1_key=key1)
2322 self.vpp_session.add_vpp_config()
2323 self.vpp_session.admin_up()
2324 self.test_session = BFDTestSession(
2325 self, self.pg0, AF_INET, sha1_key=key1,
2326 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01002327 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002328 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002329 p = wait_for_bfd_packet(self)
2330 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002331 self.test_session.send_packet()
2332 self.vpp_session.activate_auth(key2, delayed=True)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002333 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002334 p = wait_for_bfd_packet(self)
2335 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002336 self.test_session.send_packet()
2337 self.test_session.bfd_key_id = self.vpp_session.bfd_key_id
2338 self.test_session.sha1_key = key2
2339 self.test_session.send_packet()
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01002340 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01002341 p = wait_for_bfd_packet(self)
2342 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01002343 self.test_session.send_packet()
2344 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
2345 self.assert_equal(len(self.vapi.collect_events()), 0,
2346 "number of bfd events")
Klement Sekera46a87ad2017-01-02 08:22:23 +01002347
Klement Sekera73884482017-02-23 09:26:30 +01002348
Paul Vinciguerradefde0f2018-12-06 07:46:13 -08002349@unittest.skipUnless(running_extended_tests, "part of extended tests")
Klement Sekera73884482017-02-23 09:26:30 +01002350class BFDCLITestCase(VppTestCase):
2351 """Bidirectional Forwarding Detection (BFD) (CLI) """
2352 pg0 = None
2353
2354 @classmethod
2355 def setUpClass(cls):
2356 super(BFDCLITestCase, cls).setUpClass()
Damjan Marion07a38572018-01-21 06:44:18 -08002357 cls.vapi.cli("set log class bfd level debug")
Klement Sekera73884482017-02-23 09:26:30 +01002358 try:
2359 cls.create_pg_interfaces((0,))
2360 cls.pg0.config_ip4()
2361 cls.pg0.config_ip6()
2362 cls.pg0.resolve_arp()
2363 cls.pg0.resolve_ndp()
2364
2365 except Exception:
2366 super(BFDCLITestCase, cls).tearDownClass()
2367 raise
2368
Paul Vinciguerra8d991d92019-01-25 14:05:48 -08002369 @classmethod
2370 def tearDownClass(cls):
2371 super(BFDCLITestCase, cls).tearDownClass()
2372
Klement Sekera73884482017-02-23 09:26:30 +01002373 def setUp(self):
2374 super(BFDCLITestCase, self).setUp()
2375 self.factory = AuthKeyFactory()
2376 self.pg0.enable_capture()
2377
2378 def tearDown(self):
2379 try:
Jakub Grajciar4682feb2019-09-02 13:28:52 +02002380 self.vapi.want_bfd_events(enable_disable=False)
Klement Sekera73884482017-02-23 09:26:30 +01002381 except UnexpectedApiReturnValueError:
2382 # some tests aren't subscribed, so this is not an issue
2383 pass
2384 self.vapi.collect_events() # clear the event queue
2385 super(BFDCLITestCase, self).tearDown()
2386
2387 def cli_verify_no_response(self, cli):
2388 """ execute a CLI, asserting that the response is empty """
2389 self.assert_equal(self.vapi.cli(cli),
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07002390 b"",
Klement Sekera73884482017-02-23 09:26:30 +01002391 "CLI command response")
2392
2393 def cli_verify_response(self, cli, expected):
2394 """ execute a CLI, asserting that the response matches expectation """
Jakub Grajciar4682feb2019-09-02 13:28:52 +02002395 try:
2396 reply = self.vapi.cli(cli)
2397 except CliFailedCommandError as cli_error:
2398 reply = str(cli_error)
2399 self.assert_equal(reply.strip(),
Klement Sekera73884482017-02-23 09:26:30 +01002400 expected,
2401 "CLI command response")
2402
2403 def test_show(self):
2404 """ show commands """
2405 k1 = self.factory.create_random_key(self)
2406 k1.add_vpp_config()
2407 k2 = self.factory.create_random_key(
2408 self, auth_type=BFDAuthType.meticulous_keyed_sha1)
2409 k2.add_vpp_config()
2410 s1 = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
2411 s1.add_vpp_config()
2412 s2 = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip6, af=AF_INET6,
2413 sha1_key=k2)
2414 s2.add_vpp_config()
2415 self.logger.info(self.vapi.ppcli("show bfd keys"))
2416 self.logger.info(self.vapi.ppcli("show bfd sessions"))
2417 self.logger.info(self.vapi.ppcli("show bfd"))
2418
2419 def test_set_del_sha1_key(self):
2420 """ set/delete SHA1 auth key """
2421 k = self.factory.create_random_key(self)
2422 self.registry.register(k, self.logger)
2423 self.cli_verify_no_response(
2424 "bfd key set conf-key-id %s type keyed-sha1 secret %s" %
2425 (k.conf_key_id,
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07002426 "".join("{:02x}".format(scapy.compat.orb(c)) for c in k.key)))
Klement Sekera73884482017-02-23 09:26:30 +01002427 self.assertTrue(k.query_vpp_config())
2428 self.vpp_session = VppBFDUDPSession(
2429 self, self.pg0, self.pg0.remote_ip4, sha1_key=k)
2430 self.vpp_session.add_vpp_config()
2431 self.test_session = \
2432 BFDTestSession(self, self.pg0, AF_INET, sha1_key=k,
2433 bfd_key_id=self.vpp_session.bfd_key_id)
2434 self.vapi.want_bfd_events()
2435 bfd_session_up(self)
2436 bfd_session_down(self)
2437 # try to replace the secret for the key - should fail because the key
2438 # is in-use
2439 k2 = self.factory.create_random_key(self)
2440 self.cli_verify_response(
2441 "bfd key set conf-key-id %s type keyed-sha1 secret %s" %
2442 (k.conf_key_id,
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07002443 "".join("{:02x}".format(scapy.compat.orb(c)) for c in k2.key)),
Klement Sekera73884482017-02-23 09:26:30 +01002444 "bfd key set: `bfd_auth_set_key' API call failed, "
2445 "rv=-103:BFD object in use")
2446 # manipulating the session using old secret should still work
2447 bfd_session_up(self)
2448 bfd_session_down(self)
2449 self.vpp_session.remove_vpp_config()
2450 self.cli_verify_no_response(
2451 "bfd key del conf-key-id %s" % k.conf_key_id)
2452 self.assertFalse(k.query_vpp_config())
2453
2454 def test_set_del_meticulous_sha1_key(self):
2455 """ set/delete meticulous SHA1 auth key """
2456 k = self.factory.create_random_key(
2457 self, auth_type=BFDAuthType.meticulous_keyed_sha1)
2458 self.registry.register(k, self.logger)
2459 self.cli_verify_no_response(
2460 "bfd key set conf-key-id %s type meticulous-keyed-sha1 secret %s" %
2461 (k.conf_key_id,
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07002462 "".join("{:02x}".format(scapy.compat.orb(c)) for c in k.key)))
Klement Sekera73884482017-02-23 09:26:30 +01002463 self.assertTrue(k.query_vpp_config())
2464 self.vpp_session = VppBFDUDPSession(self, self.pg0,
2465 self.pg0.remote_ip6, af=AF_INET6,
2466 sha1_key=k)
2467 self.vpp_session.add_vpp_config()
2468 self.vpp_session.admin_up()
2469 self.test_session = \
2470 BFDTestSession(self, self.pg0, AF_INET6, sha1_key=k,
2471 bfd_key_id=self.vpp_session.bfd_key_id)
2472 self.vapi.want_bfd_events()
2473 bfd_session_up(self)
2474 bfd_session_down(self)
2475 # try to replace the secret for the key - should fail because the key
2476 # is in-use
2477 k2 = self.factory.create_random_key(self)
2478 self.cli_verify_response(
2479 "bfd key set conf-key-id %s type keyed-sha1 secret %s" %
2480 (k.conf_key_id,
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07002481 "".join("{:02x}".format(scapy.compat.orb(c)) for c in k2.key)),
Klement Sekera73884482017-02-23 09:26:30 +01002482 "bfd key set: `bfd_auth_set_key' API call failed, "
2483 "rv=-103:BFD object in use")
2484 # manipulating the session using old secret should still work
2485 bfd_session_up(self)
2486 bfd_session_down(self)
2487 self.vpp_session.remove_vpp_config()
2488 self.cli_verify_no_response(
2489 "bfd key del conf-key-id %s" % k.conf_key_id)
2490 self.assertFalse(k.query_vpp_config())
2491
2492 def test_add_mod_del_bfd_udp(self):
2493 """ create/modify/delete IPv4 BFD UDP session """
2494 vpp_session = VppBFDUDPSession(
2495 self, self.pg0, self.pg0.remote_ip4)
2496 self.registry.register(vpp_session, self.logger)
2497 cli_add_cmd = "bfd udp session add interface %s local-addr %s " \
2498 "peer-addr %s desired-min-tx %s required-min-rx %s "\
2499 "detect-mult %s" % (self.pg0.name, self.pg0.local_ip4,
2500 self.pg0.remote_ip4,
2501 vpp_session.desired_min_tx,
2502 vpp_session.required_min_rx,
2503 vpp_session.detect_mult)
2504 self.cli_verify_no_response(cli_add_cmd)
2505 # 2nd add should fail
2506 self.cli_verify_response(
2507 cli_add_cmd,
2508 "bfd udp session add: `bfd_add_add_session' API call"
2509 " failed, rv=-101:Duplicate BFD object")
2510 verify_bfd_session_config(self, vpp_session)
2511 mod_session = VppBFDUDPSession(
2512 self, self.pg0, self.pg0.remote_ip4,
2513 required_min_rx=2 * vpp_session.required_min_rx,
2514 desired_min_tx=3 * vpp_session.desired_min_tx,
2515 detect_mult=4 * vpp_session.detect_mult)
2516 self.cli_verify_no_response(
2517 "bfd udp session mod interface %s local-addr %s peer-addr %s "
2518 "desired-min-tx %s required-min-rx %s detect-mult %s" %
2519 (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4,
2520 mod_session.desired_min_tx, mod_session.required_min_rx,
2521 mod_session.detect_mult))
2522 verify_bfd_session_config(self, mod_session)
2523 cli_del_cmd = "bfd udp session del interface %s local-addr %s "\
2524 "peer-addr %s" % (self.pg0.name,
2525 self.pg0.local_ip4, self.pg0.remote_ip4)
2526 self.cli_verify_no_response(cli_del_cmd)
2527 # 2nd del is expected to fail
2528 self.cli_verify_response(
2529 cli_del_cmd, "bfd udp session del: `bfd_udp_del_session' API call"
2530 " failed, rv=-102:No such BFD object")
2531 self.assertFalse(vpp_session.query_vpp_config())
2532
2533 def test_add_mod_del_bfd_udp6(self):
2534 """ create/modify/delete IPv6 BFD UDP session """
2535 vpp_session = VppBFDUDPSession(
2536 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6)
2537 self.registry.register(vpp_session, self.logger)
2538 cli_add_cmd = "bfd udp session add interface %s local-addr %s " \
2539 "peer-addr %s desired-min-tx %s required-min-rx %s "\
2540 "detect-mult %s" % (self.pg0.name, self.pg0.local_ip6,
2541 self.pg0.remote_ip6,
2542 vpp_session.desired_min_tx,
2543 vpp_session.required_min_rx,
2544 vpp_session.detect_mult)
2545 self.cli_verify_no_response(cli_add_cmd)
2546 # 2nd add should fail
2547 self.cli_verify_response(
2548 cli_add_cmd,
2549 "bfd udp session add: `bfd_add_add_session' API call"
2550 " failed, rv=-101:Duplicate BFD object")
2551 verify_bfd_session_config(self, vpp_session)
2552 mod_session = VppBFDUDPSession(
2553 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6,
2554 required_min_rx=2 * vpp_session.required_min_rx,
2555 desired_min_tx=3 * vpp_session.desired_min_tx,
2556 detect_mult=4 * vpp_session.detect_mult)
2557 self.cli_verify_no_response(
2558 "bfd udp session mod interface %s local-addr %s peer-addr %s "
2559 "desired-min-tx %s required-min-rx %s detect-mult %s" %
2560 (self.pg0.name, self.pg0.local_ip6, self.pg0.remote_ip6,
2561 mod_session.desired_min_tx,
2562 mod_session.required_min_rx, mod_session.detect_mult))
2563 verify_bfd_session_config(self, mod_session)
2564 cli_del_cmd = "bfd udp session del interface %s local-addr %s "\
2565 "peer-addr %s" % (self.pg0.name,
2566 self.pg0.local_ip6, self.pg0.remote_ip6)
2567 self.cli_verify_no_response(cli_del_cmd)
2568 # 2nd del is expected to fail
2569 self.cli_verify_response(
2570 cli_del_cmd,
2571 "bfd udp session del: `bfd_udp_del_session' API call"
2572 " failed, rv=-102:No such BFD object")
2573 self.assertFalse(vpp_session.query_vpp_config())
2574
2575 def test_add_mod_del_bfd_udp_auth(self):
2576 """ create/modify/delete IPv4 BFD UDP session (authenticated) """
2577 key = self.factory.create_random_key(self)
2578 key.add_vpp_config()
2579 vpp_session = VppBFDUDPSession(
2580 self, self.pg0, self.pg0.remote_ip4, sha1_key=key)
2581 self.registry.register(vpp_session, self.logger)
2582 cli_add_cmd = "bfd udp session add interface %s local-addr %s " \
2583 "peer-addr %s desired-min-tx %s required-min-rx %s "\
2584 "detect-mult %s conf-key-id %s bfd-key-id %s"\
2585 % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4,
2586 vpp_session.desired_min_tx, vpp_session.required_min_rx,
2587 vpp_session.detect_mult, key.conf_key_id,
2588 vpp_session.bfd_key_id)
2589 self.cli_verify_no_response(cli_add_cmd)
2590 # 2nd add should fail
2591 self.cli_verify_response(
2592 cli_add_cmd,
2593 "bfd udp session add: `bfd_add_add_session' API call"
2594 " failed, rv=-101:Duplicate BFD object")
2595 verify_bfd_session_config(self, vpp_session)
2596 mod_session = VppBFDUDPSession(
2597 self, self.pg0, self.pg0.remote_ip4, sha1_key=key,
2598 bfd_key_id=vpp_session.bfd_key_id,
2599 required_min_rx=2 * vpp_session.required_min_rx,
2600 desired_min_tx=3 * vpp_session.desired_min_tx,
2601 detect_mult=4 * vpp_session.detect_mult)
2602 self.cli_verify_no_response(
2603 "bfd udp session mod interface %s local-addr %s peer-addr %s "
2604 "desired-min-tx %s required-min-rx %s detect-mult %s" %
2605 (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4,
2606 mod_session.desired_min_tx,
2607 mod_session.required_min_rx, mod_session.detect_mult))
2608 verify_bfd_session_config(self, mod_session)
2609 cli_del_cmd = "bfd udp session del interface %s local-addr %s "\
2610 "peer-addr %s" % (self.pg0.name,
2611 self.pg0.local_ip4, self.pg0.remote_ip4)
2612 self.cli_verify_no_response(cli_del_cmd)
2613 # 2nd del is expected to fail
2614 self.cli_verify_response(
2615 cli_del_cmd,
2616 "bfd udp session del: `bfd_udp_del_session' API call"
2617 " failed, rv=-102:No such BFD object")
2618 self.assertFalse(vpp_session.query_vpp_config())
2619
2620 def test_add_mod_del_bfd_udp6_auth(self):
2621 """ create/modify/delete IPv6 BFD UDP session (authenticated) """
2622 key = self.factory.create_random_key(
2623 self, auth_type=BFDAuthType.meticulous_keyed_sha1)
2624 key.add_vpp_config()
2625 vpp_session = VppBFDUDPSession(
2626 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6, sha1_key=key)
2627 self.registry.register(vpp_session, self.logger)
2628 cli_add_cmd = "bfd udp session add interface %s local-addr %s " \
2629 "peer-addr %s desired-min-tx %s required-min-rx %s "\
2630 "detect-mult %s conf-key-id %s bfd-key-id %s" \
2631 % (self.pg0.name, self.pg0.local_ip6, self.pg0.remote_ip6,
2632 vpp_session.desired_min_tx, vpp_session.required_min_rx,
2633 vpp_session.detect_mult, key.conf_key_id,
2634 vpp_session.bfd_key_id)
2635 self.cli_verify_no_response(cli_add_cmd)
2636 # 2nd add should fail
2637 self.cli_verify_response(
2638 cli_add_cmd,
2639 "bfd udp session add: `bfd_add_add_session' API call"
2640 " failed, rv=-101:Duplicate BFD object")
2641 verify_bfd_session_config(self, vpp_session)
2642 mod_session = VppBFDUDPSession(
2643 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6, sha1_key=key,
2644 bfd_key_id=vpp_session.bfd_key_id,
2645 required_min_rx=2 * vpp_session.required_min_rx,
2646 desired_min_tx=3 * vpp_session.desired_min_tx,
2647 detect_mult=4 * vpp_session.detect_mult)
2648 self.cli_verify_no_response(
2649 "bfd udp session mod interface %s local-addr %s peer-addr %s "
2650 "desired-min-tx %s required-min-rx %s detect-mult %s" %
2651 (self.pg0.name, self.pg0.local_ip6, self.pg0.remote_ip6,
2652 mod_session.desired_min_tx,
2653 mod_session.required_min_rx, mod_session.detect_mult))
2654 verify_bfd_session_config(self, mod_session)
2655 cli_del_cmd = "bfd udp session del interface %s local-addr %s "\
2656 "peer-addr %s" % (self.pg0.name,
2657 self.pg0.local_ip6, self.pg0.remote_ip6)
2658 self.cli_verify_no_response(cli_del_cmd)
2659 # 2nd del is expected to fail
2660 self.cli_verify_response(
2661 cli_del_cmd,
2662 "bfd udp session del: `bfd_udp_del_session' API call"
2663 " failed, rv=-102:No such BFD object")
2664 self.assertFalse(vpp_session.query_vpp_config())
2665
2666 def test_auth_on_off(self):
2667 """ turn authentication on and off """
2668 key = self.factory.create_random_key(
2669 self, auth_type=BFDAuthType.meticulous_keyed_sha1)
2670 key.add_vpp_config()
2671 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
2672 auth_session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4,
2673 sha1_key=key)
2674 session.add_vpp_config()
2675 cli_activate = \
2676 "bfd udp session auth activate interface %s local-addr %s "\
2677 "peer-addr %s conf-key-id %s bfd-key-id %s"\
2678 % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4,
2679 key.conf_key_id, auth_session.bfd_key_id)
2680 self.cli_verify_no_response(cli_activate)
2681 verify_bfd_session_config(self, auth_session)
2682 self.cli_verify_no_response(cli_activate)
2683 verify_bfd_session_config(self, auth_session)
2684 cli_deactivate = \
2685 "bfd udp session auth deactivate interface %s local-addr %s "\
2686 "peer-addr %s "\
2687 % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4)
2688 self.cli_verify_no_response(cli_deactivate)
2689 verify_bfd_session_config(self, session)
2690 self.cli_verify_no_response(cli_deactivate)
2691 verify_bfd_session_config(self, session)
2692
2693 def test_auth_on_off_delayed(self):
2694 """ turn authentication on and off (delayed) """
2695 key = self.factory.create_random_key(
2696 self, auth_type=BFDAuthType.meticulous_keyed_sha1)
2697 key.add_vpp_config()
2698 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
2699 auth_session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4,
2700 sha1_key=key)
2701 session.add_vpp_config()
2702 cli_activate = \
2703 "bfd udp session auth activate interface %s local-addr %s "\
2704 "peer-addr %s conf-key-id %s bfd-key-id %s delayed yes"\
2705 % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4,
2706 key.conf_key_id, auth_session.bfd_key_id)
2707 self.cli_verify_no_response(cli_activate)
2708 verify_bfd_session_config(self, auth_session)
2709 self.cli_verify_no_response(cli_activate)
2710 verify_bfd_session_config(self, auth_session)
2711 cli_deactivate = \
2712 "bfd udp session auth deactivate interface %s local-addr %s "\
2713 "peer-addr %s delayed yes"\
2714 % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4)
2715 self.cli_verify_no_response(cli_deactivate)
2716 verify_bfd_session_config(self, session)
2717 self.cli_verify_no_response(cli_deactivate)
2718 verify_bfd_session_config(self, session)
2719
2720 def test_admin_up_down(self):
2721 """ put session admin-up and admin-down """
2722 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
2723 session.add_vpp_config()
2724 cli_down = \
2725 "bfd udp session set-flags admin down interface %s local-addr %s "\
2726 "peer-addr %s "\
2727 % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4)
2728 cli_up = \
2729 "bfd udp session set-flags admin up interface %s local-addr %s "\
2730 "peer-addr %s "\
2731 % (self.pg0.name, self.pg0.local_ip4, self.pg0.remote_ip4)
2732 self.cli_verify_no_response(cli_down)
2733 verify_bfd_session_config(self, session, state=BFDState.admin_down)
2734 self.cli_verify_no_response(cli_up)
2735 verify_bfd_session_config(self, session, state=BFDState.down)
2736
2737 def test_set_del_udp_echo_source(self):
2738 """ set/del udp echo source """
Klement Sekerab9ef2732018-06-24 22:49:33 +02002739 self.create_loopback_interfaces(1)
Klement Sekera73884482017-02-23 09:26:30 +01002740 self.loopback0 = self.lo_interfaces[0]
2741 self.loopback0.admin_up()
2742 self.cli_verify_response("show bfd echo-source",
2743 "UDP echo source is not set.")
2744 cli_set = "bfd udp echo-source set interface %s" % self.loopback0.name
2745 self.cli_verify_no_response(cli_set)
2746 self.cli_verify_response("show bfd echo-source",
2747 "UDP echo source is: %s\n"
2748 "IPv4 address usable as echo source: none\n"
2749 "IPv6 address usable as echo source: none" %
2750 self.loopback0.name)
2751 self.loopback0.config_ip4()
2752 unpacked = unpack("!L", self.loopback0.local_ip4n)
2753 echo_ip4 = inet_ntop(AF_INET, pack("!L", unpacked[0] ^ 1))
2754 self.cli_verify_response("show bfd echo-source",
2755 "UDP echo source is: %s\n"
2756 "IPv4 address usable as echo source: %s\n"
2757 "IPv6 address usable as echo source: none" %
2758 (self.loopback0.name, echo_ip4))
2759 unpacked = unpack("!LLLL", self.loopback0.local_ip6n)
2760 echo_ip6 = inet_ntop(AF_INET6, pack("!LLLL", unpacked[0], unpacked[1],
2761 unpacked[2], unpacked[3] ^ 1))
2762 self.loopback0.config_ip6()
2763 self.cli_verify_response("show bfd echo-source",
2764 "UDP echo source is: %s\n"
2765 "IPv4 address usable as echo source: %s\n"
2766 "IPv6 address usable as echo source: %s" %
2767 (self.loopback0.name, echo_ip4, echo_ip6))
2768 cli_del = "bfd udp echo-source del"
2769 self.cli_verify_no_response(cli_del)
2770 self.cli_verify_response("show bfd echo-source",
2771 "UDP echo source is not set.")
2772
Jakub Grajciar4682feb2019-09-02 13:28:52 +02002773
Klement Sekera0e3c0de2016-09-29 14:43:44 +02002774if __name__ == '__main__':
2775 unittest.main(testRunner=VppTestRunner)