blob: ce0cca555168974e464034f1154aaf3b64658ef3 [file] [log] [blame]
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001#!/usr/bin/env python
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
Klement Sekera0e3c0de2016-09-29 14:43:44 +02005import unittest
Klement Sekerab17dd962017-01-09 07:43:48 +01006import hashlib
7import binascii
Klement Sekera0e3c0de2016-09-29 14:43:44 +02008import time
Klement Sekera239790f2017-02-16 10:53:53 +01009from random import randint, shuffle, getrandbits
Klement Sekerad3ba5152017-02-14 03:09:17 +010010from socket import AF_INET, AF_INET6
Klement Sekeraaeeac3b2017-02-14 07:11:52 +010011from scapy.packet import Raw
Klement Sekerad3ba5152017-02-14 03:09:17 +010012from scapy.layers.l2 import Ether
13from scapy.layers.inet import UDP, IP
14from scapy.layers.inet6 import IPv6
15from bfd import VppBFDAuthKey, BFD, BFDAuthType, VppBFDUDPSession, \
Klement Sekera239790f2017-02-16 10:53:53 +010016 BFDDiagCode, BFDState, BFD_vpp_echo
Klement Sekerad3ba5152017-02-14 03:09:17 +010017from framework import VppTestCase, VppTestRunner
18from vpp_pg_interface import CaptureTimeoutError
Klement Sekera0e3c0de2016-09-29 14:43:44 +020019from util import ppp
20
Klement Sekerad3ba5152017-02-14 03:09:17 +010021USEC_IN_SEC = 1000000
Klement Sekera3e0a3562016-12-19 09:05:21 +010022
Klement Sekera0e3c0de2016-09-29 14:43:44 +020023
Klement Sekerab17dd962017-01-09 07:43:48 +010024class AuthKeyFactory(object):
25 """Factory class for creating auth keys with unique conf key ID"""
26
27 def __init__(self):
28 self._conf_key_ids = {}
29
30 def create_random_key(self, test, auth_type=BFDAuthType.keyed_sha1):
Klement Sekerad3ba5152017-02-14 03:09:17 +010031 """ create a random key with unique conf key id """
Klement Sekerab17dd962017-01-09 07:43:48 +010032 conf_key_id = randint(0, 0xFFFFFFFF)
33 while conf_key_id in self._conf_key_ids:
34 conf_key_id = randint(0, 0xFFFFFFFF)
35 self._conf_key_ids[conf_key_id] = 1
Klement Sekerad3ba5152017-02-14 03:09:17 +010036 key = str(bytearray([randint(0, 255) for _ in range(randint(1, 20))]))
Klement Sekerab17dd962017-01-09 07:43:48 +010037 return VppBFDAuthKey(test=test, auth_type=auth_type,
38 conf_key_id=conf_key_id, key=key)
39
40
Klement Sekerae4504c62016-12-08 10:16:41 +010041class BFDAPITestCase(VppTestCase):
42 """Bidirectional Forwarding Detection (BFD) - API"""
Klement Sekera0e3c0de2016-09-29 14:43:44 +020043
Klement Sekerad3ba5152017-02-14 03:09:17 +010044 pg0 = None
45 pg1 = None
46
Klement Sekera0e3c0de2016-09-29 14:43:44 +020047 @classmethod
48 def setUpClass(cls):
Klement Sekerae4504c62016-12-08 10:16:41 +010049 super(BFDAPITestCase, cls).setUpClass()
Klement Sekera0e3c0de2016-09-29 14:43:44 +020050
51 try:
Klement Sekera10db26f2017-01-11 08:16:53 +010052 cls.create_pg_interfaces(range(2))
53 for i in cls.pg_interfaces:
54 i.config_ip4()
Klement Sekerab17dd962017-01-09 07:43:48 +010055 i.config_ip6()
Klement Sekera10db26f2017-01-11 08:16:53 +010056 i.resolve_arp()
Klement Sekera0e3c0de2016-09-29 14:43:44 +020057
58 except Exception:
Klement Sekerae4504c62016-12-08 10:16:41 +010059 super(BFDAPITestCase, cls).tearDownClass()
Klement Sekera0e3c0de2016-09-29 14:43:44 +020060 raise
61
Klement Sekerab17dd962017-01-09 07:43:48 +010062 def setUp(self):
63 super(BFDAPITestCase, self).setUp()
64 self.factory = AuthKeyFactory()
65
Klement Sekera0e3c0de2016-09-29 14:43:44 +020066 def test_add_bfd(self):
67 """ create a BFD session """
68 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
69 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +010070 self.logger.debug("Session state is %s", session.state)
Klement Sekera0e3c0de2016-09-29 14:43:44 +020071 session.remove_vpp_config()
Klement Sekera0e3c0de2016-09-29 14:43:44 +020072 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +010073 self.logger.debug("Session state is %s", session.state)
Klement Sekera0e3c0de2016-09-29 14:43:44 +020074 session.remove_vpp_config()
75
76 def test_double_add(self):
77 """ create the same BFD session twice (negative case) """
78 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
79 session.add_vpp_config()
Klement Sekerae0545ef2017-01-25 08:00:40 +010080
81 with self.vapi.expect_negative_api_retval():
Klement Sekera0e3c0de2016-09-29 14:43:44 +020082 session.add_vpp_config()
Klement Sekerae0545ef2017-01-25 08:00:40 +010083
Klement Sekera0e3c0de2016-09-29 14:43:44 +020084 session.remove_vpp_config()
Klement Sekera0e3c0de2016-09-29 14:43:44 +020085
Klement Sekerab17dd962017-01-09 07:43:48 +010086 def test_add_bfd6(self):
87 """ create IPv6 BFD session """
88 session = VppBFDUDPSession(
89 self, self.pg0, self.pg0.remote_ip6, af=AF_INET6)
90 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +010091 self.logger.debug("Session state is %s", session.state)
Klement Sekerab17dd962017-01-09 07:43:48 +010092 session.remove_vpp_config()
93 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +010094 self.logger.debug("Session state is %s", session.state)
Klement Sekerab17dd962017-01-09 07:43:48 +010095 session.remove_vpp_config()
96
Klement Sekeraa57a9702017-02-02 06:58:07 +010097 def test_mod_bfd(self):
98 """ modify BFD session parameters """
99 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4,
100 desired_min_tx=50000,
101 required_min_rx=10000,
102 detect_mult=1)
103 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100104 s = session.get_bfd_udp_session_dump_entry()
Klement Sekeraa57a9702017-02-02 06:58:07 +0100105 self.assert_equal(session.desired_min_tx,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100106 s.desired_min_tx,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100107 "desired min transmit interval")
108 self.assert_equal(session.required_min_rx,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100109 s.required_min_rx,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100110 "required min receive interval")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100111 self.assert_equal(session.detect_mult, s.detect_mult, "detect mult")
Klement Sekeraa57a9702017-02-02 06:58:07 +0100112 session.modify_parameters(desired_min_tx=session.desired_min_tx * 2,
113 required_min_rx=session.required_min_rx * 2,
114 detect_mult=session.detect_mult * 2)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100115 s = session.get_bfd_udp_session_dump_entry()
Klement Sekeraa57a9702017-02-02 06:58:07 +0100116 self.assert_equal(session.desired_min_tx,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100117 s.desired_min_tx,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100118 "desired min transmit interval")
119 self.assert_equal(session.required_min_rx,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100120 s.required_min_rx,
Klement Sekeraa57a9702017-02-02 06:58:07 +0100121 "required min receive interval")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100122 self.assert_equal(session.detect_mult, s.detect_mult, "detect mult")
Klement Sekeraa57a9702017-02-02 06:58:07 +0100123
Klement Sekerab17dd962017-01-09 07:43:48 +0100124 def test_add_sha1_keys(self):
125 """ add SHA1 keys """
126 key_count = 10
127 keys = [self.factory.create_random_key(
128 self) for i in range(0, key_count)]
129 for key in keys:
130 self.assertFalse(key.query_vpp_config())
131 for key in keys:
132 key.add_vpp_config()
133 for key in keys:
134 self.assertTrue(key.query_vpp_config())
135 # remove randomly
136 indexes = range(key_count)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100137 shuffle(indexes)
Klement Sekerab17dd962017-01-09 07:43:48 +0100138 removed = []
139 for i in indexes:
140 key = keys[i]
141 key.remove_vpp_config()
142 removed.append(i)
143 for j in range(key_count):
144 key = keys[j]
145 if j in removed:
146 self.assertFalse(key.query_vpp_config())
147 else:
148 self.assertTrue(key.query_vpp_config())
149 # should be removed now
150 for key in keys:
151 self.assertFalse(key.query_vpp_config())
152 # add back and remove again
153 for key in keys:
154 key.add_vpp_config()
155 for key in keys:
156 self.assertTrue(key.query_vpp_config())
157 for key in keys:
158 key.remove_vpp_config()
159 for key in keys:
160 self.assertFalse(key.query_vpp_config())
161
162 def test_add_bfd_sha1(self):
163 """ create a BFD session (SHA1) """
164 key = self.factory.create_random_key(self)
165 key.add_vpp_config()
166 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4,
167 sha1_key=key)
168 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100169 self.logger.debug("Session state is %s", session.state)
Klement Sekerab17dd962017-01-09 07:43:48 +0100170 session.remove_vpp_config()
171 session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100172 self.logger.debug("Session state is %s", session.state)
Klement Sekerab17dd962017-01-09 07:43:48 +0100173 session.remove_vpp_config()
174
175 def test_double_add_sha1(self):
176 """ create the same BFD session twice (negative case) (SHA1) """
177 key = self.factory.create_random_key(self)
178 key.add_vpp_config()
179 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4,
180 sha1_key=key)
181 session.add_vpp_config()
182 with self.assertRaises(Exception):
183 session.add_vpp_config()
184
Klement Sekerad3ba5152017-02-14 03:09:17 +0100185 def test_add_auth_nonexistent_key(self):
Klement Sekerab17dd962017-01-09 07:43:48 +0100186 """ create BFD session using non-existent SHA1 (negative case) """
187 session = VppBFDUDPSession(
188 self, self.pg0, self.pg0.remote_ip4,
189 sha1_key=self.factory.create_random_key(self))
190 with self.assertRaises(Exception):
191 session.add_vpp_config()
192
193 def test_shared_sha1_key(self):
194 """ share single SHA1 key between multiple BFD sessions """
195 key = self.factory.create_random_key(self)
196 key.add_vpp_config()
197 sessions = [
198 VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4,
199 sha1_key=key),
200 VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip6,
201 sha1_key=key, af=AF_INET6),
202 VppBFDUDPSession(self, self.pg1, self.pg1.remote_ip4,
203 sha1_key=key),
204 VppBFDUDPSession(self, self.pg1, self.pg1.remote_ip6,
205 sha1_key=key, af=AF_INET6)]
206 for s in sessions:
207 s.add_vpp_config()
208 removed = 0
209 for s in sessions:
210 e = key.get_bfd_auth_keys_dump_entry()
211 self.assert_equal(e.use_count, len(sessions) - removed,
212 "Use count for shared key")
213 s.remove_vpp_config()
214 removed += 1
215 e = key.get_bfd_auth_keys_dump_entry()
216 self.assert_equal(e.use_count, len(sessions) - removed,
217 "Use count for shared key")
218
219 def test_activate_auth(self):
220 """ activate SHA1 authentication """
221 key = self.factory.create_random_key(self)
222 key.add_vpp_config()
223 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
224 session.add_vpp_config()
225 session.activate_auth(key)
226
227 def test_deactivate_auth(self):
228 """ deactivate SHA1 authentication """
229 key = self.factory.create_random_key(self)
230 key.add_vpp_config()
231 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4)
232 session.add_vpp_config()
233 session.activate_auth(key)
234 session.deactivate_auth()
235
236 def test_change_key(self):
Klement Sekeraa57a9702017-02-02 06:58:07 +0100237 """ change SHA1 key """
Klement Sekerab17dd962017-01-09 07:43:48 +0100238 key1 = self.factory.create_random_key(self)
239 key2 = self.factory.create_random_key(self)
240 while key2.conf_key_id == key1.conf_key_id:
241 key2 = self.factory.create_random_key(self)
242 key1.add_vpp_config()
243 key2.add_vpp_config()
244 session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4,
245 sha1_key=key1)
246 session.add_vpp_config()
247 session.activate_auth(key2)
Klement Sekera10db26f2017-01-11 08:16:53 +0100248
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200249
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200250class BFDTestSession(object):
Klement Sekera3e0a3562016-12-19 09:05:21 +0100251 """ BFD session as seen from test framework side """
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200252
Klement Sekerab17dd962017-01-09 07:43:48 +0100253 def __init__(self, test, interface, af, detect_mult=3, sha1_key=None,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100254 bfd_key_id=None, our_seq_number=None):
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200255 self.test = test
Klement Sekera46a87ad2017-01-02 08:22:23 +0100256 self.af = af
Klement Sekerab17dd962017-01-09 07:43:48 +0100257 self.sha1_key = sha1_key
258 self.bfd_key_id = bfd_key_id
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200259 self.interface = interface
Klement Sekerad3ba5152017-02-14 03:09:17 +0100260 self.udp_sport = randint(49152, 65535)
261 if our_seq_number is None:
262 self.our_seq_number = randint(0, 40000000)
263 else:
264 self.our_seq_number = our_seq_number
Klement Sekerab17dd962017-01-09 07:43:48 +0100265 self.vpp_seq_number = None
Klement Sekerad3ba5152017-02-14 03:09:17 +0100266 self.my_discriminator = 0
267 self.desired_min_tx = 100000
268 self.required_min_rx = 100000
Klement Sekera239790f2017-02-16 10:53:53 +0100269 self.required_min_echo_rx = None
Klement Sekerad3ba5152017-02-14 03:09:17 +0100270 self.detect_mult = detect_mult
271 self.diag = BFDDiagCode.no_diagnostic
272 self.your_discriminator = None
273 self.state = BFDState.down
274 self.auth_type = BFDAuthType.no_auth
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200275
Klement Sekerab17dd962017-01-09 07:43:48 +0100276 def inc_seq_num(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100277 """ increment sequence number, wrapping if needed """
Klement Sekerab17dd962017-01-09 07:43:48 +0100278 if self.our_seq_number == 0xFFFFFFFF:
279 self.our_seq_number = 0
280 else:
281 self.our_seq_number += 1
282
Klement Sekerad3ba5152017-02-14 03:09:17 +0100283 def update(self, my_discriminator=None, your_discriminator=None,
Klement Sekera239790f2017-02-16 10:53:53 +0100284 desired_min_tx=None, required_min_rx=None,
285 required_min_echo_rx=None, detect_mult=None,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100286 diag=None, state=None, auth_type=None):
287 """ update BFD parameters associated with session """
Klement Sekera239790f2017-02-16 10:53:53 +0100288 if my_discriminator is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100289 self.my_discriminator = my_discriminator
Klement Sekera239790f2017-02-16 10:53:53 +0100290 if your_discriminator is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100291 self.your_discriminator = your_discriminator
Klement Sekera239790f2017-02-16 10:53:53 +0100292 if required_min_rx is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100293 self.required_min_rx = required_min_rx
Klement Sekera239790f2017-02-16 10:53:53 +0100294 if required_min_echo_rx is not None:
295 self.required_min_echo_rx = required_min_echo_rx
296 if desired_min_tx is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100297 self.desired_min_tx = desired_min_tx
Klement Sekera239790f2017-02-16 10:53:53 +0100298 if detect_mult is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100299 self.detect_mult = detect_mult
Klement Sekera239790f2017-02-16 10:53:53 +0100300 if diag is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100301 self.diag = diag
Klement Sekera239790f2017-02-16 10:53:53 +0100302 if state is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100303 self.state = state
Klement Sekera239790f2017-02-16 10:53:53 +0100304 if auth_type is not None:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100305 self.auth_type = auth_type
306
307 def fill_packet_fields(self, packet):
308 """ set packet fields with known values in packet """
309 bfd = packet[BFD]
310 if self.my_discriminator:
311 self.test.logger.debug("BFD: setting packet.my_discriminator=%s",
312 self.my_discriminator)
313 bfd.my_discriminator = self.my_discriminator
314 if self.your_discriminator:
315 self.test.logger.debug("BFD: setting packet.your_discriminator=%s",
316 self.your_discriminator)
317 bfd.your_discriminator = self.your_discriminator
318 if self.required_min_rx:
319 self.test.logger.debug(
320 "BFD: setting packet.required_min_rx_interval=%s",
321 self.required_min_rx)
322 bfd.required_min_rx_interval = self.required_min_rx
Klement Sekera239790f2017-02-16 10:53:53 +0100323 if self.required_min_echo_rx:
324 self.test.logger.debug(
325 "BFD: setting packet.required_min_echo_rx=%s",
326 self.required_min_echo_rx)
327 bfd.required_min_echo_rx_interval = self.required_min_echo_rx
Klement Sekerad3ba5152017-02-14 03:09:17 +0100328 if self.desired_min_tx:
329 self.test.logger.debug(
330 "BFD: setting packet.desired_min_tx_interval=%s",
331 self.desired_min_tx)
332 bfd.desired_min_tx_interval = self.desired_min_tx
333 if self.detect_mult:
334 self.test.logger.debug(
335 "BFD: setting packet.detect_mult=%s", self.detect_mult)
336 bfd.detect_mult = self.detect_mult
337 if self.diag:
338 self.test.logger.debug("BFD: setting packet.diag=%s", self.diag)
339 bfd.diag = self.diag
340 if self.state:
341 self.test.logger.debug("BFD: setting packet.state=%s", self.state)
342 bfd.state = self.state
343 if self.auth_type:
344 # this is used by a negative test-case
345 self.test.logger.debug("BFD: setting packet.auth_type=%s",
346 self.auth_type)
347 bfd.auth_type = self.auth_type
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200348
349 def create_packet(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100350 """ create a BFD packet, reflecting the current state of session """
Klement Sekerab17dd962017-01-09 07:43:48 +0100351 if self.sha1_key:
352 bfd = BFD(flags="A")
353 bfd.auth_type = self.sha1_key.auth_type
354 bfd.auth_len = BFD.sha1_auth_len
355 bfd.auth_key_id = self.bfd_key_id
356 bfd.auth_seq_num = self.our_seq_number
357 bfd.length = BFD.sha1_auth_len + BFD.bfd_pkt_len
358 else:
359 bfd = BFD()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100360 if self.af == AF_INET6:
361 packet = (Ether(src=self.interface.remote_mac,
362 dst=self.interface.local_mac) /
363 IPv6(src=self.interface.remote_ip6,
364 dst=self.interface.local_ip6,
365 hlim=255) /
366 UDP(sport=self.udp_sport, dport=BFD.udp_dport) /
Klement Sekerab17dd962017-01-09 07:43:48 +0100367 bfd)
Klement Sekera46a87ad2017-01-02 08:22:23 +0100368 else:
369 packet = (Ether(src=self.interface.remote_mac,
370 dst=self.interface.local_mac) /
371 IP(src=self.interface.remote_ip4,
372 dst=self.interface.local_ip4,
373 ttl=255) /
374 UDP(sport=self.udp_sport, dport=BFD.udp_dport) /
Klement Sekerab17dd962017-01-09 07:43:48 +0100375 bfd)
Klement Sekera3e0a3562016-12-19 09:05:21 +0100376 self.test.logger.debug("BFD: Creating packet")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100377 self.fill_packet_fields(packet)
Klement Sekerab17dd962017-01-09 07:43:48 +0100378 if self.sha1_key:
379 hash_material = str(packet[BFD])[:32] + self.sha1_key.key + \
380 "\0" * (20 - len(self.sha1_key.key))
381 self.test.logger.debug("BFD: Calculated SHA1 hash: %s" %
382 hashlib.sha1(hash_material).hexdigest())
383 packet[BFD].auth_key_hash = hashlib.sha1(hash_material).digest()
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200384 return packet
385
Klement Sekerad3ba5152017-02-14 03:09:17 +0100386 def send_packet(self, packet=None, interface=None):
387 """ send packet on interface, creating the packet if needed """
Klement Sekeraa57a9702017-02-02 06:58:07 +0100388 if packet is None:
389 packet = self.create_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100390 if interface is None:
391 interface = self.test.pg0
Klement Sekeraa57a9702017-02-02 06:58:07 +0100392 self.test.logger.debug(ppp("Sending packet:", packet))
Klement Sekerad3ba5152017-02-14 03:09:17 +0100393 interface.add_stream(packet)
Klement Sekera9225dee2016-12-12 08:36:58 +0100394 self.test.pg_start()
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200395
Klement Sekerab17dd962017-01-09 07:43:48 +0100396 def verify_sha1_auth(self, packet):
397 """ Verify correctness of authentication in BFD layer. """
398 bfd = packet[BFD]
399 self.test.assert_equal(bfd.auth_len, 28, "Auth section length")
400 self.test.assert_equal(bfd.auth_type, self.sha1_key.auth_type,
401 BFDAuthType)
402 self.test.assert_equal(bfd.auth_key_id, self.bfd_key_id, "Key ID")
403 self.test.assert_equal(bfd.auth_reserved, 0, "Reserved")
404 if self.vpp_seq_number is None:
405 self.vpp_seq_number = bfd.auth_seq_num
406 self.test.logger.debug("Received initial sequence number: %s" %
407 self.vpp_seq_number)
408 else:
409 recvd_seq_num = bfd.auth_seq_num
410 self.test.logger.debug("Received followup sequence number: %s" %
411 recvd_seq_num)
412 if self.vpp_seq_number < 0xffffffff:
413 if self.sha1_key.auth_type == \
414 BFDAuthType.meticulous_keyed_sha1:
415 self.test.assert_equal(recvd_seq_num,
416 self.vpp_seq_number + 1,
417 "BFD sequence number")
418 else:
419 self.test.assert_in_range(recvd_seq_num,
420 self.vpp_seq_number,
421 self.vpp_seq_number + 1,
422 "BFD sequence number")
423 else:
424 if self.sha1_key.auth_type == \
425 BFDAuthType.meticulous_keyed_sha1:
426 self.test.assert_equal(recvd_seq_num, 0,
427 "BFD sequence number")
428 else:
429 self.test.assertIn(recvd_seq_num, (self.vpp_seq_number, 0),
430 "BFD sequence number not one of "
431 "(%s, 0)" % self.vpp_seq_number)
432 self.vpp_seq_number = recvd_seq_num
433 # last 20 bytes represent the hash - so replace them with the key,
434 # pad the result with zeros and hash the result
435 hash_material = bfd.original[:-20] + self.sha1_key.key + \
436 "\0" * (20 - len(self.sha1_key.key))
437 expected_hash = hashlib.sha1(hash_material).hexdigest()
438 self.test.assert_equal(binascii.hexlify(bfd.auth_key_hash),
439 expected_hash, "Auth key hash")
440
441 def verify_bfd(self, packet):
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200442 """ Verify correctness of BFD layer. """
443 bfd = packet[BFD]
444 self.test.assert_equal(bfd.version, 1, "BFD version")
445 self.test.assert_equal(bfd.your_discriminator,
Klement Sekerad3ba5152017-02-14 03:09:17 +0100446 self.my_discriminator,
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200447 "BFD - your discriminator")
Klement Sekerab17dd962017-01-09 07:43:48 +0100448 if self.sha1_key:
449 self.verify_sha1_auth(packet)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200450
451
Klement Sekerad3ba5152017-02-14 03:09:17 +0100452def bfd_session_up(test):
453 """ Bring BFD session up """
454 test.logger.info("BFD: Waiting for slow hello")
455 p = wait_for_bfd_packet(test, 2)
456 old_offset = None
457 if hasattr(test, 'vpp_clock_offset'):
458 old_offset = test.vpp_clock_offset
459 test.vpp_clock_offset = time.time() - p.time
460 test.logger.debug("BFD: Calculated vpp clock offset: %s",
461 test.vpp_clock_offset)
462 if old_offset:
463 test.assertAlmostEqual(
464 old_offset, test.vpp_clock_offset, delta=0.1,
465 msg="vpp clock offset not stable (new: %s, old: %s)" %
466 (test.vpp_clock_offset, old_offset))
467 test.logger.info("BFD: Sending Init")
468 test.test_session.update(my_discriminator=randint(0, 40000000),
469 your_discriminator=p[BFD].my_discriminator,
470 state=BFDState.init)
471 test.test_session.send_packet()
472 test.logger.info("BFD: Waiting for event")
473 e = test.vapi.wait_for_event(1, "bfd_udp_session_details")
474 verify_event(test, e, expected_state=BFDState.up)
475 test.logger.info("BFD: Session is Up")
476 test.test_session.update(state=BFDState.up)
477 test.test_session.send_packet()
478 test.assert_equal(test.vpp_session.state, BFDState.up, BFDState)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200479
Klement Sekera46a87ad2017-01-02 08:22:23 +0100480
Klement Sekerad3ba5152017-02-14 03:09:17 +0100481def bfd_session_down(test):
482 """ Bring BFD session down """
483 test.assert_equal(test.vpp_session.state, BFDState.up, BFDState)
484 test.test_session.update(state=BFDState.down)
485 test.test_session.send_packet()
486 test.logger.info("BFD: Waiting for event")
487 e = test.vapi.wait_for_event(1, "bfd_udp_session_details")
488 verify_event(test, e, expected_state=BFDState.down)
489 test.logger.info("BFD: Session is Down")
490 test.assert_equal(test.vpp_session.state, BFDState.down, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +0100491
Klement Sekera46a87ad2017-01-02 08:22:23 +0100492
Klement Sekerad3ba5152017-02-14 03:09:17 +0100493def verify_ip(test, packet):
494 """ Verify correctness of IP layer. """
495 if test.vpp_session.af == AF_INET6:
496 ip = packet[IPv6]
497 local_ip = test.pg0.local_ip6
498 remote_ip = test.pg0.remote_ip6
499 test.assert_equal(ip.hlim, 255, "IPv6 hop limit")
500 else:
501 ip = packet[IP]
502 local_ip = test.pg0.local_ip4
503 remote_ip = test.pg0.remote_ip4
504 test.assert_equal(ip.ttl, 255, "IPv4 TTL")
505 test.assert_equal(ip.src, local_ip, "IP source address")
506 test.assert_equal(ip.dst, remote_ip, "IP destination address")
507
508
509def verify_udp(test, packet):
510 """ Verify correctness of UDP layer. """
511 udp = packet[UDP]
512 test.assert_equal(udp.dport, BFD.udp_dport, "UDP destination port")
513 test.assert_in_range(udp.sport, BFD.udp_sport_min, BFD.udp_sport_max,
514 "UDP source port")
515
516
517def verify_event(test, event, expected_state):
518 """ Verify correctness of event values. """
519 e = event
520 test.logger.debug("BFD: Event: %s" % repr(e))
521 test.assert_equal(e.sw_if_index,
522 test.vpp_session.interface.sw_if_index,
523 "BFD interface index")
524 is_ipv6 = 0
525 if test.vpp_session.af == AF_INET6:
526 is_ipv6 = 1
527 test.assert_equal(e.is_ipv6, is_ipv6, "is_ipv6")
528 if test.vpp_session.af == AF_INET:
529 test.assert_equal(e.local_addr[:4], test.vpp_session.local_addr_n,
530 "Local IPv4 address")
531 test.assert_equal(e.peer_addr[:4], test.vpp_session.peer_addr_n,
532 "Peer IPv4 address")
533 else:
534 test.assert_equal(e.local_addr, test.vpp_session.local_addr_n,
535 "Local IPv6 address")
536 test.assert_equal(e.peer_addr, test.vpp_session.peer_addr_n,
537 "Peer IPv6 address")
538 test.assert_equal(e.state, expected_state, BFDState)
539
540
541def wait_for_bfd_packet(test, timeout=1, pcap_time_min=None):
542 """ wait for BFD packet and verify its correctness
543
544 :param timeout: how long to wait
545 :param pcap_time_min: ignore packets with pcap timestamp lower than this
546
547 :returns: tuple (packet, time spent waiting for packet)
548 """
549 test.logger.info("BFD: Waiting for BFD packet")
550 deadline = time.time() + timeout
551 counter = 0
552 while True:
553 counter += 1
554 # sanity check
555 test.assert_in_range(counter, 0, 100, "number of packets ignored")
556 time_left = deadline - time.time()
557 if time_left < 0:
558 raise CaptureTimeoutError("Packet did not arrive within timeout")
559 p = test.pg0.wait_for_packet(timeout=time_left)
560 test.logger.debug(ppp("BFD: Got packet:", p))
561 if pcap_time_min is not None and p.time < pcap_time_min:
562 test.logger.debug(ppp("BFD: ignoring packet (pcap time %s < "
563 "pcap time min %s):" %
564 (p.time, pcap_time_min), p))
Klement Sekera46a87ad2017-01-02 08:22:23 +0100565 else:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100566 break
567 bfd = p[BFD]
568 if bfd is None:
569 raise Exception(ppp("Unexpected or invalid BFD packet:", p))
570 if bfd.payload:
571 raise Exception(ppp("Unexpected payload in BFD packet:", bfd))
572 verify_ip(test, p)
573 verify_udp(test, p)
574 test.test_session.verify_bfd(p)
575 return p
Klement Sekera3e0a3562016-12-19 09:05:21 +0100576
Klement Sekera46a87ad2017-01-02 08:22:23 +0100577
Klement Sekerad3ba5152017-02-14 03:09:17 +0100578class BFD4TestCase(VppTestCase):
Klement Sekera46a87ad2017-01-02 08:22:23 +0100579 """Bidirectional Forwarding Detection (BFD)"""
580
Klement Sekerad3ba5152017-02-14 03:09:17 +0100581 pg0 = None
582 vpp_clock_offset = None
583 vpp_session = None
584 test_session = None
585
Klement Sekera46a87ad2017-01-02 08:22:23 +0100586 @classmethod
587 def setUpClass(cls):
588 super(BFD4TestCase, cls).setUpClass()
589 try:
590 cls.create_pg_interfaces([0])
Klement Sekera239790f2017-02-16 10:53:53 +0100591 cls.create_loopback_interfaces([0])
592 cls.loopback0 = cls.lo_interfaces[0]
593 cls.loopback0.config_ip4()
594 cls.loopback0.admin_up()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100595 cls.pg0.config_ip4()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100596 cls.pg0.configure_ipv4_neighbors()
597 cls.pg0.admin_up()
598 cls.pg0.resolve_arp()
599
600 except Exception:
601 super(BFD4TestCase, cls).tearDownClass()
602 raise
603
604 def setUp(self):
605 super(BFD4TestCase, self).setUp()
Klement Sekerab17dd962017-01-09 07:43:48 +0100606 self.factory = AuthKeyFactory()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100607 self.vapi.want_bfd_events()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100608 self.pg0.enable_capture()
Klement Sekera46a87ad2017-01-02 08:22:23 +0100609 try:
610 self.vpp_session = VppBFDUDPSession(self, self.pg0,
611 self.pg0.remote_ip4)
612 self.vpp_session.add_vpp_config()
613 self.vpp_session.admin_up()
614 self.test_session = BFDTestSession(self, self.pg0, AF_INET)
615 except:
616 self.vapi.want_bfd_events(enable_disable=0)
617 raise
618
619 def tearDown(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100620 if not self.vpp_dead:
621 self.vapi.want_bfd_events(enable_disable=0)
622 self.vapi.collect_events() # clear the event queue
623 super(BFD4TestCase, self).tearDown()
Klement Sekerab17dd962017-01-09 07:43:48 +0100624
625 def test_session_up(self):
626 """ bring BFD session up """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100627 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +0100628
629 def test_session_down(self):
630 """ bring BFD session down """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100631 bfd_session_up(self)
632 bfd_session_down(self)
Klement Sekerab17dd962017-01-09 07:43:48 +0100633
634 def test_hold_up(self):
635 """ hold BFD session up """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100636 bfd_session_up(self)
637 for dummy in range(self.test_session.detect_mult * 2):
638 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +0100639 self.test_session.send_packet()
640 self.assert_equal(len(self.vapi.collect_events()), 0,
641 "number of bfd events")
Klement Sekera46a87ad2017-01-02 08:22:23 +0100642
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200643 def test_slow_timer(self):
Klement Sekerae4504c62016-12-08 10:16:41 +0100644 """ verify slow periodic control frames while session down """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100645 packet_count = 3
646 self.logger.info("BFD: Waiting for %d BFD packets", packet_count)
647 prev_packet = wait_for_bfd_packet(self, 2)
648 for dummy in range(packet_count):
649 next_packet = wait_for_bfd_packet(self, 2)
650 time_diff = next_packet.time - prev_packet.time
Klement Sekerae4504c62016-12-08 10:16:41 +0100651 # spec says the range should be <0.75, 1>, allow extra 0.05 margin
652 # to work around timing issues
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200653 self.assert_in_range(
Klement Sekerad3ba5152017-02-14 03:09:17 +0100654 time_diff, 0.70, 1.05, "time between slow packets")
655 prev_packet = next_packet
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200656
657 def test_zero_remote_min_rx(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100658 """ no packets when zero remote required min rx interval """
659 bfd_session_up(self)
660 self.test_session.update(required_min_rx=0)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200661 self.test_session.send_packet()
Klement Sekera239790f2017-02-16 10:53:53 +0100662 for dummy in range(self.test_session.detect_mult):
663 self.sleep(self.vpp_session.required_min_rx / USEC_IN_SEC,
664 "sleep before transmitting bfd packet")
665 self.test_session.send_packet()
Klement Sekeraa57a9702017-02-02 06:58:07 +0100666 try:
Klement Sekera239790f2017-02-16 10:53:53 +0100667 p = wait_for_bfd_packet(self, timeout=0)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100668 self.logger.error(ppp("Received unexpected packet:", p))
Klement Sekerad3ba5152017-02-14 03:09:17 +0100669 except CaptureTimeoutError:
Klement Sekeraa57a9702017-02-02 06:58:07 +0100670 pass
Klement Sekera239790f2017-02-16 10:53:53 +0100671 self.assert_equal(
672 len(self.vapi.collect_events()), 0, "number of bfd events")
673 self.test_session.update(required_min_rx=100000)
674 for dummy in range(3):
675 self.test_session.send_packet()
676 wait_for_bfd_packet(
677 self, timeout=self.test_session.required_min_rx / USEC_IN_SEC)
678 self.assert_equal(
679 len(self.vapi.collect_events()), 0, "number of bfd events")
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200680
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200681 def test_conn_down(self):
Klement Sekerae4504c62016-12-08 10:16:41 +0100682 """ verify session goes down after inactivity """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100683 bfd_session_up(self)
Klement Sekera239790f2017-02-16 10:53:53 +0100684 detection_time = self.test_session.detect_mult *\
Klement Sekerac48829b2017-02-14 07:55:57 +0100685 self.vpp_session.required_min_rx / USEC_IN_SEC
686 self.sleep(detection_time, "waiting for BFD session time-out")
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200687 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100688 verify_event(self, e, expected_state=BFDState.down)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200689
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200690 def test_large_required_min_rx(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100691 """ large remote required min rx interval """
692 bfd_session_up(self)
693 p = wait_for_bfd_packet(self)
Klement Sekera637b9c42016-12-08 05:19:14 +0100694 interval = 3000000
Klement Sekerad3ba5152017-02-14 03:09:17 +0100695 self.test_session.update(required_min_rx=interval)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200696 self.test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100697 time_mark = time.time()
Klement Sekera637b9c42016-12-08 05:19:14 +0100698 count = 0
Klement Sekeraa57a9702017-02-02 06:58:07 +0100699 # busy wait here, trying to collect a packet or event, vpp is not
700 # allowed to send packets and the session will timeout first - so the
701 # Up->Down event must arrive before any packets do
Klement Sekerad3ba5152017-02-14 03:09:17 +0100702 while time.time() < time_mark + interval / USEC_IN_SEC:
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200703 try:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100704 p = wait_for_bfd_packet(self, timeout=0)
705 # if vpp managed to send a packet before we did the session
706 # session update, then that's fine, ignore it
707 if p.time < time_mark - self.vpp_clock_offset:
708 continue
Klement Sekeraa57a9702017-02-02 06:58:07 +0100709 self.logger.error(ppp("Received unexpected packet:", p))
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200710 count += 1
Klement Sekerad3ba5152017-02-14 03:09:17 +0100711 except CaptureTimeoutError:
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200712 pass
Klement Sekeraa57a9702017-02-02 06:58:07 +0100713 events = self.vapi.collect_events()
714 if len(events) > 0:
Klement Sekerad3ba5152017-02-14 03:09:17 +0100715 verify_event(self, events[0], BFDState.down)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100716 break
717 self.assert_equal(count, 0, "number of packets received")
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200718
Klement Sekerad3ba5152017-02-14 03:09:17 +0100719 def test_immediate_remote_min_rx_reduction(self):
720 """ immediately honor remote required min rx reduction """
Klement Sekera3e0a3562016-12-19 09:05:21 +0100721 self.vpp_session.remove_vpp_config()
Klement Sekera10db26f2017-01-11 08:16:53 +0100722 self.vpp_session = VppBFDUDPSession(
723 self, self.pg0, self.pg0.remote_ip4, desired_min_tx=10000)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100724 self.pg0.enable_capture()
Klement Sekera3e0a3562016-12-19 09:05:21 +0100725 self.vpp_session.add_vpp_config()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100726 self.test_session.update(desired_min_tx=1000000,
727 required_min_rx=1000000)
728 bfd_session_up(self)
729 reference_packet = wait_for_bfd_packet(self)
730 time_mark = time.time()
731 interval = 300000
732 self.test_session.update(required_min_rx=interval)
Klement Sekera3e0a3562016-12-19 09:05:21 +0100733 self.test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100734 extra_time = time.time() - time_mark
735 p = wait_for_bfd_packet(self)
736 # first packet is allowed to be late by time we spent doing the update
737 # calculated in extra_time
738 self.assert_in_range(p.time - reference_packet.time,
739 .95 * 0.75 * interval / USEC_IN_SEC,
740 1.05 * interval / USEC_IN_SEC + extra_time,
Klement Sekera3e0a3562016-12-19 09:05:21 +0100741 "time between BFD packets")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100742 reference_packet = p
743 for dummy in range(3):
744 p = wait_for_bfd_packet(self)
745 diff = p.time - reference_packet.time
746 self.assert_in_range(diff, .95 * .75 * interval / USEC_IN_SEC,
747 1.05 * interval / USEC_IN_SEC,
748 "time between BFD packets")
749 reference_packet = p
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200750
Klement Sekeraa57a9702017-02-02 06:58:07 +0100751 def test_modify_req_min_rx_double(self):
752 """ modify session - double required min rx """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100753 bfd_session_up(self)
754 p = wait_for_bfd_packet(self)
755 self.test_session.update(desired_min_tx=10000,
756 required_min_rx=10000)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100757 self.test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100758 # double required min rx
Klement Sekeraa57a9702017-02-02 06:58:07 +0100759 self.vpp_session.modify_parameters(
760 required_min_rx=2 * self.vpp_session.required_min_rx)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100761 p = wait_for_bfd_packet(
762 self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100763 # poll bit needs to be set
764 self.assertIn("P", p.sprintf("%BFD.flags%"),
765 "Poll bit not set in BFD packet")
766 # finish poll sequence with final packet
767 final = self.test_session.create_packet()
768 final[BFD].flags = "F"
Klement Sekerad3ba5152017-02-14 03:09:17 +0100769 timeout = self.test_session.detect_mult * \
770 max(self.test_session.desired_min_tx,
771 self.vpp_session.required_min_rx) / USEC_IN_SEC
Klement Sekeraa57a9702017-02-02 06:58:07 +0100772 self.test_session.send_packet(final)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100773 time_mark = time.time()
774 e = self.vapi.wait_for_event(2 * timeout, "bfd_udp_session_details")
775 verify_event(self, e, expected_state=BFDState.down)
776 time_to_event = time.time() - time_mark
777 self.assert_in_range(time_to_event, .9 * timeout,
778 1.1 * timeout, "session timeout")
Klement Sekeraa57a9702017-02-02 06:58:07 +0100779
780 def test_modify_req_min_rx_halve(self):
781 """ modify session - halve required min rx """
782 self.vpp_session.modify_parameters(
783 required_min_rx=2 * self.vpp_session.required_min_rx)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100784 bfd_session_up(self)
785 p = wait_for_bfd_packet(self)
786 self.test_session.update(desired_min_tx=10000,
787 required_min_rx=10000)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100788 self.test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +0100789 p = wait_for_bfd_packet(
790 self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100791 # halve required min rx
792 old_required_min_rx = self.vpp_session.required_min_rx
793 self.vpp_session.modify_parameters(
794 required_min_rx=0.5 * self.vpp_session.required_min_rx)
795 # now we wait 0.8*3*old-req-min-rx and the session should still be up
796 self.sleep(0.8 * self.vpp_session.detect_mult *
Klement Sekerad3ba5152017-02-14 03:09:17 +0100797 old_required_min_rx / USEC_IN_SEC)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100798 self.assert_equal(len(self.vapi.collect_events()), 0,
799 "number of bfd events")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100800 p = wait_for_bfd_packet(self)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100801 # poll bit needs to be set
802 self.assertIn("P", p.sprintf("%BFD.flags%"),
803 "Poll bit not set in BFD packet")
804 # finish poll sequence with final packet
805 final = self.test_session.create_packet()
806 final[BFD].flags = "F"
807 self.test_session.send_packet(final)
808 # now the session should time out under new conditions
809 before = time.time()
810 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
811 after = time.time()
Klement Sekera239790f2017-02-16 10:53:53 +0100812 detection_time = self.test_session.detect_mult *\
Klement Sekerad3ba5152017-02-14 03:09:17 +0100813 self.vpp_session.required_min_rx / USEC_IN_SEC
Klement Sekeraa57a9702017-02-02 06:58:07 +0100814 self.assert_in_range(after - before,
815 0.9 * detection_time,
816 1.1 * detection_time,
817 "time before bfd session goes down")
Klement Sekerad3ba5152017-02-14 03:09:17 +0100818 verify_event(self, e, expected_state=BFDState.down)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100819
Klement Sekeraa57a9702017-02-02 06:58:07 +0100820 def test_modify_detect_mult(self):
821 """ modify detect multiplier """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100822 bfd_session_up(self)
823 p = wait_for_bfd_packet(self)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100824 self.vpp_session.modify_parameters(detect_mult=1)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100825 p = wait_for_bfd_packet(
826 self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100827 self.assert_equal(self.vpp_session.detect_mult,
828 p[BFD].detect_mult,
829 "detect mult")
830 # poll bit must not be set
831 self.assertNotIn("P", p.sprintf("%BFD.flags%"),
832 "Poll bit not set in BFD packet")
833 self.vpp_session.modify_parameters(detect_mult=10)
Klement Sekerad3ba5152017-02-14 03:09:17 +0100834 p = wait_for_bfd_packet(
835 self, pcap_time_min=time.time() - self.vpp_clock_offset)
Klement Sekeraa57a9702017-02-02 06:58:07 +0100836 self.assert_equal(self.vpp_session.detect_mult,
837 p[BFD].detect_mult,
838 "detect mult")
839 # poll bit must not be set
840 self.assertNotIn("P", p.sprintf("%BFD.flags%"),
841 "Poll bit not set in BFD packet")
842
Klement Sekera239790f2017-02-16 10:53:53 +0100843 def test_queued_poll(self):
844 """ test poll sequence queueing """
845 bfd_session_up(self)
846 p = wait_for_bfd_packet(self)
847 self.vpp_session.modify_parameters(
848 required_min_rx=2 * self.vpp_session.required_min_rx)
849 p = wait_for_bfd_packet(self)
850 poll_sequence_start = time.time()
851 poll_sequence_length_min = 0.5
852 send_final_after = time.time() + poll_sequence_length_min
853 # poll bit needs to be set
854 self.assertIn("P", p.sprintf("%BFD.flags%"),
855 "Poll bit not set in BFD packet")
856 self.assert_equal(p[BFD].required_min_rx_interval,
857 self.vpp_session.required_min_rx,
858 "BFD required min rx interval")
859 self.vpp_session.modify_parameters(
860 required_min_rx=2 * self.vpp_session.required_min_rx)
861 # 2nd poll sequence should be queued now
862 # don't send the reply back yet, wait for some time to emulate
863 # longer round-trip time
864 packet_count = 0
865 while time.time() < send_final_after:
866 self.test_session.send_packet()
867 p = wait_for_bfd_packet(self)
868 self.assert_equal(len(self.vapi.collect_events()), 0,
869 "number of bfd events")
870 self.assert_equal(p[BFD].required_min_rx_interval,
871 self.vpp_session.required_min_rx,
872 "BFD required min rx interval")
873 packet_count += 1
874 # poll bit must be set
875 self.assertIn("P", p.sprintf("%BFD.flags%"),
876 "Poll bit not set in BFD packet")
877 final = self.test_session.create_packet()
878 final[BFD].flags = "F"
879 self.test_session.send_packet(final)
880 # finish 1st with final
881 poll_sequence_length = time.time() - poll_sequence_start
882 # vpp must wait for some time before starting new poll sequence
883 poll_no_2_started = False
884 for dummy in range(2 * packet_count):
885 p = wait_for_bfd_packet(self)
886 self.assert_equal(len(self.vapi.collect_events()), 0,
887 "number of bfd events")
888 if "P" in p.sprintf("%BFD.flags%"):
889 poll_no_2_started = True
890 if time.time() < poll_sequence_start + poll_sequence_length:
891 raise Exception("VPP started 2nd poll sequence too soon")
892 final = self.test_session.create_packet()
893 final[BFD].flags = "F"
894 self.test_session.send_packet(final)
895 break
896 else:
897 self.test_session.send_packet()
898 self.assertTrue(poll_no_2_started, "2nd poll sequence not performed")
899 # finish 2nd with final
900 final = self.test_session.create_packet()
901 final[BFD].flags = "F"
902 self.test_session.send_packet(final)
903 p = wait_for_bfd_packet(self)
904 # poll bit must not be set
905 self.assertNotIn("P", p.sprintf("%BFD.flags%"),
906 "Poll bit set in BFD packet")
907
Klement Sekerad3ba5152017-02-14 03:09:17 +0100908 def test_no_periodic_if_remote_demand(self):
909 """ no periodic frames outside poll sequence if remote demand set """
Klement Sekerad3ba5152017-02-14 03:09:17 +0100910 bfd_session_up(self)
911 demand = self.test_session.create_packet()
912 demand[BFD].flags = "D"
913 self.test_session.send_packet(demand)
914 transmit_time = 0.9 \
915 * max(self.vpp_session.required_min_rx,
916 self.test_session.desired_min_tx) \
917 / USEC_IN_SEC
918 count = 0
Klement Sekeraaeeac3b2017-02-14 07:11:52 +0100919 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +0100920 time.sleep(transmit_time)
921 self.test_session.send_packet(demand)
922 try:
923 p = wait_for_bfd_packet(self, timeout=0)
924 self.logger.error(ppp("Received unexpected packet:", p))
925 count += 1
926 except CaptureTimeoutError:
927 pass
928 events = self.vapi.collect_events()
929 for e in events:
930 self.logger.error("Received unexpected event: %s", e)
931 self.assert_equal(count, 0, "number of packets received")
932 self.assert_equal(len(events), 0, "number of events received")
Klement Sekera46a87ad2017-01-02 08:22:23 +0100933
Klement Sekeraaeeac3b2017-02-14 07:11:52 +0100934 def test_echo_looped_back(self):
935 """ echo packets looped back """
936 # don't need a session in this case..
937 self.vpp_session.remove_vpp_config()
938 self.pg0.enable_capture()
939 echo_packet_count = 10
940 # random source port low enough to increment a few times..
941 udp_sport_tx = randint(1, 50000)
942 udp_sport_rx = udp_sport_tx
943 echo_packet = (Ether(src=self.pg0.remote_mac,
944 dst=self.pg0.local_mac) /
945 IP(src=self.pg0.remote_ip4,
Klement Sekera239790f2017-02-16 10:53:53 +0100946 dst=self.pg0.remote_ip4) /
Klement Sekeraaeeac3b2017-02-14 07:11:52 +0100947 UDP(dport=BFD.udp_dport_echo) /
948 Raw("this should be looped back"))
949 for dummy in range(echo_packet_count):
950 self.sleep(.01, "delay between echo packets")
951 echo_packet[UDP].sport = udp_sport_tx
952 udp_sport_tx += 1
953 self.logger.debug(ppp("Sending packet:", echo_packet))
954 self.pg0.add_stream(echo_packet)
955 self.pg_start()
956 for dummy in range(echo_packet_count):
957 p = self.pg0.wait_for_packet(1)
958 self.logger.debug(ppp("Got packet:", p))
959 ether = p[Ether]
960 self.assert_equal(self.pg0.remote_mac,
961 ether.dst, "Destination MAC")
962 self.assert_equal(self.pg0.local_mac, ether.src, "Source MAC")
963 ip = p[IP]
964 self.assert_equal(self.pg0.remote_ip4, ip.dst, "Destination IP")
Klement Sekera239790f2017-02-16 10:53:53 +0100965 self.assert_equal(self.pg0.remote_ip4, ip.src, "Destination IP")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +0100966 udp = p[UDP]
967 self.assert_equal(udp.dport, BFD.udp_dport_echo,
968 "UDP destination port")
969 self.assert_equal(udp.sport, udp_sport_rx, "UDP source port")
970 udp_sport_rx += 1
Klement Sekera239790f2017-02-16 10:53:53 +0100971 # need to compare the hex payload here, otherwise BFD_vpp_echo
972 # gets in way
973 self.assertEqual(str(p[UDP].payload),
974 str(echo_packet[UDP].payload),
975 "Received packet is not the echo packet sent")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +0100976 self.assert_equal(udp_sport_tx, udp_sport_rx, "UDP source port (== "
977 "ECHO packet identifier for test purposes)")
978
Klement Sekera239790f2017-02-16 10:53:53 +0100979 def test_echo(self):
980 """ echo function """
981 bfd_session_up(self)
982 self.test_session.update(required_min_echo_rx=50000)
983 self.test_session.send_packet()
984 detection_time = self.test_session.detect_mult *\
985 self.vpp_session.required_min_rx / USEC_IN_SEC
986 # echo shouldn't work without echo source set
987 for dummy in range(3):
988 sleep = 0.75 * detection_time
989 self.sleep(sleep, "delay before sending bfd packet")
990 self.test_session.send_packet()
991 p = wait_for_bfd_packet(
992 self, pcap_time_min=time.time() - self.vpp_clock_offset)
993 self.assert_equal(p[BFD].required_min_rx_interval,
994 self.vpp_session.required_min_rx,
995 "BFD required min rx interval")
996 self.vapi.bfd_udp_set_echo_source(self.loopback0.sw_if_index)
997 # should be turned on - loopback echo packets
998 for dummy in range(3):
999 loop_until = time.time() + 0.75 * detection_time
1000 while time.time() < loop_until:
1001 p = self.pg0.wait_for_packet(1)
1002 self.logger.debug(ppp("Got packet:", p))
1003 if p[UDP].dport == BFD.udp_dport_echo:
1004 self.assert_equal(
1005 p[IP].dst, self.pg0.local_ip4, "BFD ECHO dst IP")
1006 self.assertNotEqual(p[IP].src, self.loopback0.local_ip4,
1007 "BFD ECHO src IP equal to loopback IP")
1008 self.logger.debug(ppp("Looping back packet:", p))
1009 self.pg0.add_stream(p)
1010 self.pg_start()
1011 elif p.haslayer(BFD):
1012 self.assertGreaterEqual(p[BFD].required_min_rx_interval,
1013 1000000)
1014 if "P" in p.sprintf("%BFD.flags%"):
1015 final = self.test_session.create_packet()
1016 final[BFD].flags = "F"
1017 self.test_session.send_packet(final)
1018 else:
1019 raise Exception(ppp("Received unknown packet:", p))
1020
1021 self.assert_equal(len(self.vapi.collect_events()), 0,
1022 "number of bfd events")
1023 self.test_session.send_packet()
1024
1025 def test_echo_fail(self):
1026 """ session goes down if echo function fails """
1027 bfd_session_up(self)
1028 self.test_session.update(required_min_echo_rx=50000)
1029 self.test_session.send_packet()
1030 detection_time = self.test_session.detect_mult *\
1031 self.vpp_session.required_min_rx / USEC_IN_SEC
1032 self.vapi.bfd_udp_set_echo_source(self.loopback0.sw_if_index)
1033 # echo function should be used now, but we will drop the echo packets
1034 verified_diag = False
1035 for dummy in range(3):
1036 loop_until = time.time() + 0.75 * detection_time
1037 while time.time() < loop_until:
1038 p = self.pg0.wait_for_packet(1)
1039 self.logger.debug(ppp("Got packet:", p))
1040 if p[UDP].dport == BFD.udp_dport_echo:
1041 # dropped
1042 pass
1043 elif p.haslayer(BFD):
1044 if "P" in p.sprintf("%BFD.flags%"):
1045 self.assertGreaterEqual(
1046 p[BFD].required_min_rx_interval,
1047 1000000)
1048 final = self.test_session.create_packet()
1049 final[BFD].flags = "F"
1050 self.test_session.send_packet(final)
1051 if p[BFD].state == BFDState.down:
1052 self.assert_equal(p[BFD].diag,
1053 BFDDiagCode.echo_function_failed,
1054 BFDDiagCode)
1055 verified_diag = True
1056 else:
1057 raise Exception(ppp("Received unknown packet:", p))
1058 self.test_session.send_packet()
1059 events = self.vapi.collect_events()
1060 self.assert_equal(len(events), 1, "number of bfd events")
1061 self.assert_equal(events[0].state, BFDState.down, BFDState)
1062 self.assertTrue(verified_diag, "Incorrect diagnostics code received")
1063
1064 def test_echo_stop(self):
1065 """ echo function stops if peer sets required min echo rx zero """
1066 bfd_session_up(self)
1067 self.test_session.update(required_min_echo_rx=50000)
1068 self.test_session.send_packet()
1069 self.vapi.bfd_udp_set_echo_source(self.loopback0.sw_if_index)
1070 # wait for first echo packet
1071 while True:
1072 p = self.pg0.wait_for_packet(1)
1073 self.logger.debug(ppp("Got packet:", p))
1074 if p[UDP].dport == BFD.udp_dport_echo:
1075 self.logger.debug(ppp("Looping back packet:", p))
1076 self.pg0.add_stream(p)
1077 self.pg_start()
1078 break
1079 elif p.haslayer(BFD):
1080 # ignore BFD
1081 pass
1082 else:
1083 raise Exception(ppp("Received unknown packet:", p))
1084 self.test_session.update(required_min_echo_rx=0)
1085 self.test_session.send_packet()
1086 # echo packets shouldn't arrive anymore
1087 for dummy in range(5):
1088 wait_for_bfd_packet(
1089 self, pcap_time_min=time.time() - self.vpp_clock_offset)
1090 self.test_session.send_packet()
1091 events = self.vapi.collect_events()
1092 self.assert_equal(len(events), 0, "number of bfd events")
1093
1094 def test_stale_echo(self):
1095 """ stale echo packets don't keep a session up """
1096 bfd_session_up(self)
1097 self.test_session.update(required_min_echo_rx=50000)
1098 self.vapi.bfd_udp_set_echo_source(self.loopback0.sw_if_index)
1099 self.test_session.send_packet()
1100 # should be turned on - loopback echo packets
1101 echo_packet = None
1102 timeout_at = None
1103 timeout_ok = False
1104 for dummy in range(10 * self.vpp_session.detect_mult):
1105 p = self.pg0.wait_for_packet(1)
1106 if p[UDP].dport == BFD.udp_dport_echo:
1107 if echo_packet is None:
1108 self.logger.debug(ppp("Got first echo packet:", p))
1109 echo_packet = p
1110 timeout_at = time.time() + self.vpp_session.detect_mult * \
1111 self.test_session.required_min_echo_rx / USEC_IN_SEC
1112 else:
1113 self.logger.debug(ppp("Got followup echo packet:", p))
1114 self.logger.debug(ppp("Looping back first echo packet:", p))
1115 self.pg0.add_stream(echo_packet)
1116 self.pg_start()
1117 elif p.haslayer(BFD):
1118 self.logger.debug(ppp("Got packet:", p))
1119 if "P" in p.sprintf("%BFD.flags%"):
1120 final = self.test_session.create_packet()
1121 final[BFD].flags = "F"
1122 self.test_session.send_packet(final)
1123 if p[BFD].state == BFDState.down:
1124 self.assertIsNotNone(
1125 timeout_at,
1126 "Session went down before first echo packet received")
1127 now = time.time()
1128 self.assertGreaterEqual(
1129 now, timeout_at,
1130 "Session timeout at %s, but is expected at %s" %
1131 (now, timeout_at))
1132 self.assert_equal(p[BFD].diag,
1133 BFDDiagCode.echo_function_failed,
1134 BFDDiagCode)
1135 events = self.vapi.collect_events()
1136 self.assert_equal(len(events), 1, "number of bfd events")
1137 self.assert_equal(events[0].state, BFDState.down, BFDState)
1138 timeout_ok = True
1139 break
1140 else:
1141 raise Exception(ppp("Received unknown packet:", p))
1142 self.test_session.send_packet()
1143 self.assertTrue(timeout_ok, "Expected timeout event didn't occur")
1144
1145 def test_invalid_echo_checksum(self):
1146 """ echo packets with invalid checksum don't keep a session up """
1147 bfd_session_up(self)
1148 self.test_session.update(required_min_echo_rx=50000)
1149 self.vapi.bfd_udp_set_echo_source(self.loopback0.sw_if_index)
1150 self.test_session.send_packet()
1151 # should be turned on - loopback echo packets
1152 timeout_at = None
1153 timeout_ok = False
1154 for dummy in range(10 * self.vpp_session.detect_mult):
1155 p = self.pg0.wait_for_packet(1)
1156 if p[UDP].dport == BFD.udp_dport_echo:
1157 self.logger.debug(ppp("Got echo packet:", p))
1158 if timeout_at is None:
1159 timeout_at = time.time() + self.vpp_session.detect_mult * \
1160 self.test_session.required_min_echo_rx / USEC_IN_SEC
1161 p[BFD_vpp_echo].checksum = getrandbits(64)
1162 self.logger.debug(ppp("Looping back modified echo packet:", p))
1163 self.pg0.add_stream(p)
1164 self.pg_start()
1165 elif p.haslayer(BFD):
1166 self.logger.debug(ppp("Got packet:", p))
1167 if "P" in p.sprintf("%BFD.flags%"):
1168 final = self.test_session.create_packet()
1169 final[BFD].flags = "F"
1170 self.test_session.send_packet(final)
1171 if p[BFD].state == BFDState.down:
1172 self.assertIsNotNone(
1173 timeout_at,
1174 "Session went down before first echo packet received")
1175 now = time.time()
1176 self.assertGreaterEqual(
1177 now, timeout_at,
1178 "Session timeout at %s, but is expected at %s" %
1179 (now, timeout_at))
1180 self.assert_equal(p[BFD].diag,
1181 BFDDiagCode.echo_function_failed,
1182 BFDDiagCode)
1183 events = self.vapi.collect_events()
1184 self.assert_equal(len(events), 1, "number of bfd events")
1185 self.assert_equal(events[0].state, BFDState.down, BFDState)
1186 timeout_ok = True
1187 break
1188 else:
1189 raise Exception(ppp("Received unknown packet:", p))
1190 self.test_session.send_packet()
1191 self.assertTrue(timeout_ok, "Expected timeout event didn't occur")
1192
Klement Sekerac48829b2017-02-14 07:55:57 +01001193 def test_admin_up_down(self):
Klement Sekera239790f2017-02-16 10:53:53 +01001194 """ put session admin-up and admin-down """
Klement Sekerac48829b2017-02-14 07:55:57 +01001195 bfd_session_up(self)
1196 self.vpp_session.admin_down()
1197 self.pg0.enable_capture()
1198 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
1199 verify_event(self, e, expected_state=BFDState.admin_down)
1200 for dummy in range(2):
1201 p = wait_for_bfd_packet(self)
1202 self.assert_equal(BFDState.admin_down, p[BFD].state, BFDState)
1203 # try to bring session up - shouldn't be possible
1204 self.test_session.update(state=BFDState.init)
1205 self.test_session.send_packet()
1206 for dummy in range(2):
1207 p = wait_for_bfd_packet(self)
1208 self.assert_equal(BFDState.admin_down, p[BFD].state, BFDState)
1209 self.vpp_session.admin_up()
1210 self.test_session.update(state=BFDState.down)
1211 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
1212 verify_event(self, e, expected_state=BFDState.down)
1213 p = wait_for_bfd_packet(self)
1214 self.assert_equal(BFDState.down, p[BFD].state, BFDState)
1215 self.test_session.send_packet()
1216 p = wait_for_bfd_packet(self)
1217 self.assert_equal(BFDState.init, p[BFD].state, BFDState)
1218 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
1219 verify_event(self, e, expected_state=BFDState.init)
1220 self.test_session.update(state=BFDState.up)
1221 self.test_session.send_packet()
1222 p = wait_for_bfd_packet(self)
1223 self.assert_equal(BFDState.up, p[BFD].state, BFDState)
1224 e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
1225 verify_event(self, e, expected_state=BFDState.up)
1226
Klement Sekera239790f2017-02-16 10:53:53 +01001227 def test_config_change_remote_demand(self):
1228 """ configuration change while peer in demand mode """
1229 bfd_session_up(self)
1230 demand = self.test_session.create_packet()
1231 demand[BFD].flags = "D"
1232 self.test_session.send_packet(demand)
1233 self.vpp_session.modify_parameters(
1234 required_min_rx=2 * self.vpp_session.required_min_rx)
1235 p = wait_for_bfd_packet(self)
1236 # poll bit must be set
1237 self.assertIn("P", p.sprintf("%BFD.flags%"), "Poll bit not set")
1238 # terminate poll sequence
1239 final = self.test_session.create_packet()
1240 final[BFD].flags = "D+F"
1241 self.test_session.send_packet(final)
1242 # vpp should be quiet now again
1243 transmit_time = 0.9 \
1244 * max(self.vpp_session.required_min_rx,
1245 self.test_session.desired_min_tx) \
1246 / USEC_IN_SEC
1247 count = 0
1248 for dummy in range(self.test_session.detect_mult * 2):
1249 time.sleep(transmit_time)
1250 self.test_session.send_packet(demand)
1251 try:
1252 p = wait_for_bfd_packet(self, timeout=0)
1253 self.logger.error(ppp("Received unexpected packet:", p))
1254 count += 1
1255 except CaptureTimeoutError:
1256 pass
1257 events = self.vapi.collect_events()
1258 for e in events:
1259 self.logger.error("Received unexpected event: %s", e)
1260 self.assert_equal(count, 0, "number of packets received")
1261 self.assert_equal(len(events), 0, "number of events received")
1262
Klement Sekerad3ba5152017-02-14 03:09:17 +01001263
1264class BFD6TestCase(VppTestCase):
Klement Sekera46a87ad2017-01-02 08:22:23 +01001265 """Bidirectional Forwarding Detection (BFD) (IPv6) """
1266
Klement Sekerad3ba5152017-02-14 03:09:17 +01001267 pg0 = None
1268 vpp_clock_offset = None
1269 vpp_session = None
1270 test_session = None
1271
Klement Sekera46a87ad2017-01-02 08:22:23 +01001272 @classmethod
1273 def setUpClass(cls):
1274 super(BFD6TestCase, cls).setUpClass()
1275 try:
1276 cls.create_pg_interfaces([0])
1277 cls.pg0.config_ip6()
1278 cls.pg0.configure_ipv6_neighbors()
1279 cls.pg0.admin_up()
1280 cls.pg0.resolve_ndp()
Klement Sekera239790f2017-02-16 10:53:53 +01001281 cls.create_loopback_interfaces([0])
1282 cls.loopback0 = cls.lo_interfaces[0]
1283 cls.loopback0.config_ip6()
1284 cls.loopback0.admin_up()
Klement Sekera46a87ad2017-01-02 08:22:23 +01001285
1286 except Exception:
1287 super(BFD6TestCase, cls).tearDownClass()
1288 raise
1289
1290 def setUp(self):
1291 super(BFD6TestCase, self).setUp()
Klement Sekerab17dd962017-01-09 07:43:48 +01001292 self.factory = AuthKeyFactory()
Klement Sekera46a87ad2017-01-02 08:22:23 +01001293 self.vapi.want_bfd_events()
Klement Sekerad3ba5152017-02-14 03:09:17 +01001294 self.pg0.enable_capture()
Klement Sekera46a87ad2017-01-02 08:22:23 +01001295 try:
1296 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1297 self.pg0.remote_ip6,
1298 af=AF_INET6)
1299 self.vpp_session.add_vpp_config()
1300 self.vpp_session.admin_up()
1301 self.test_session = BFDTestSession(self, self.pg0, AF_INET6)
1302 self.logger.debug(self.vapi.cli("show adj nbr"))
1303 except:
1304 self.vapi.want_bfd_events(enable_disable=0)
1305 raise
1306
1307 def tearDown(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001308 if not self.vpp_dead:
1309 self.vapi.want_bfd_events(enable_disable=0)
1310 self.vapi.collect_events() # clear the event queue
1311 super(BFD6TestCase, self).tearDown()
Klement Sekerab17dd962017-01-09 07:43:48 +01001312
1313 def test_session_up(self):
1314 """ bring BFD session up """
Klement Sekerad3ba5152017-02-14 03:09:17 +01001315 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001316
1317 def test_hold_up(self):
1318 """ hold BFD session up """
Klement Sekerad3ba5152017-02-14 03:09:17 +01001319 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001320 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001321 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001322 self.test_session.send_packet()
1323 self.assert_equal(len(self.vapi.collect_events()), 0,
1324 "number of bfd events")
1325 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1326
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001327 def test_echo_looped_back(self):
1328 """ echo packets looped back """
1329 # don't need a session in this case..
1330 self.vpp_session.remove_vpp_config()
1331 self.pg0.enable_capture()
1332 echo_packet_count = 10
1333 # random source port low enough to increment a few times..
1334 udp_sport_tx = randint(1, 50000)
1335 udp_sport_rx = udp_sport_tx
1336 echo_packet = (Ether(src=self.pg0.remote_mac,
1337 dst=self.pg0.local_mac) /
1338 IPv6(src=self.pg0.remote_ip6,
Klement Sekera239790f2017-02-16 10:53:53 +01001339 dst=self.pg0.remote_ip6) /
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001340 UDP(dport=BFD.udp_dport_echo) /
1341 Raw("this should be looped back"))
1342 for dummy in range(echo_packet_count):
1343 self.sleep(.01, "delay between echo packets")
1344 echo_packet[UDP].sport = udp_sport_tx
1345 udp_sport_tx += 1
1346 self.logger.debug(ppp("Sending packet:", echo_packet))
1347 self.pg0.add_stream(echo_packet)
1348 self.pg_start()
1349 for dummy in range(echo_packet_count):
1350 p = self.pg0.wait_for_packet(1)
1351 self.logger.debug(ppp("Got packet:", p))
1352 ether = p[Ether]
1353 self.assert_equal(self.pg0.remote_mac,
1354 ether.dst, "Destination MAC")
1355 self.assert_equal(self.pg0.local_mac, ether.src, "Source MAC")
1356 ip = p[IPv6]
1357 self.assert_equal(self.pg0.remote_ip6, ip.dst, "Destination IP")
Klement Sekera239790f2017-02-16 10:53:53 +01001358 self.assert_equal(self.pg0.remote_ip6, ip.src, "Destination IP")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001359 udp = p[UDP]
1360 self.assert_equal(udp.dport, BFD.udp_dport_echo,
1361 "UDP destination port")
1362 self.assert_equal(udp.sport, udp_sport_rx, "UDP source port")
1363 udp_sport_rx += 1
Klement Sekera239790f2017-02-16 10:53:53 +01001364 # need to compare the hex payload here, otherwise BFD_vpp_echo
1365 # gets in way
1366 self.assertEqual(str(p[UDP].payload),
1367 str(echo_packet[UDP].payload),
1368 "Received packet is not the echo packet sent")
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001369 self.assert_equal(udp_sport_tx, udp_sport_rx, "UDP source port (== "
1370 "ECHO packet identifier for test purposes)")
Klement Sekera239790f2017-02-16 10:53:53 +01001371 self.assert_equal(udp_sport_tx, udp_sport_rx, "UDP source port (== "
1372 "ECHO packet identifier for test purposes)")
1373
1374 def test_echo(self):
1375 """ echo function used """
1376 bfd_session_up(self)
1377 self.test_session.update(required_min_echo_rx=50000)
1378 self.test_session.send_packet()
1379 detection_time = self.test_session.detect_mult *\
1380 self.vpp_session.required_min_rx / USEC_IN_SEC
1381 # echo shouldn't work without echo source set
1382 for dummy in range(3):
1383 sleep = 0.75 * detection_time
1384 self.sleep(sleep, "delay before sending bfd packet")
1385 self.test_session.send_packet()
1386 p = wait_for_bfd_packet(
1387 self, pcap_time_min=time.time() - self.vpp_clock_offset)
1388 self.assert_equal(p[BFD].required_min_rx_interval,
1389 self.vpp_session.required_min_rx,
1390 "BFD required min rx interval")
1391 self.vapi.bfd_udp_set_echo_source(self.loopback0.sw_if_index)
1392 # should be turned on - loopback echo packets
1393 for dummy in range(3):
1394 loop_until = time.time() + 0.75 * detection_time
1395 while time.time() < loop_until:
1396 p = self.pg0.wait_for_packet(1)
1397 self.logger.debug(ppp("Got packet:", p))
1398 if p[UDP].dport == BFD.udp_dport_echo:
1399 self.assert_equal(
1400 p[IPv6].dst, self.pg0.local_ip6, "BFD ECHO dst IP")
1401 self.assertNotEqual(p[IPv6].src, self.loopback0.local_ip6,
1402 "BFD ECHO src IP equal to loopback IP")
1403 self.logger.debug(ppp("Looping back packet:", p))
1404 self.pg0.add_stream(p)
1405 self.pg_start()
1406 elif p.haslayer(BFD):
1407 self.assertGreaterEqual(p[BFD].required_min_rx_interval,
1408 1000000)
1409 if "P" in p.sprintf("%BFD.flags%"):
1410 final = self.test_session.create_packet()
1411 final[BFD].flags = "F"
1412 self.test_session.send_packet(final)
1413 else:
1414 raise Exception(ppp("Received unknown packet:", p))
1415
1416 self.assert_equal(len(self.vapi.collect_events()), 0,
1417 "number of bfd events")
1418 self.test_session.send_packet()
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001419
Klement Sekerab17dd962017-01-09 07:43:48 +01001420
Klement Sekerad3ba5152017-02-14 03:09:17 +01001421class BFDSHA1TestCase(VppTestCase):
Klement Sekerab17dd962017-01-09 07:43:48 +01001422 """Bidirectional Forwarding Detection (BFD) (SHA1 auth) """
1423
Klement Sekerad3ba5152017-02-14 03:09:17 +01001424 pg0 = None
1425 vpp_clock_offset = None
1426 vpp_session = None
1427 test_session = None
1428
Klement Sekerab17dd962017-01-09 07:43:48 +01001429 @classmethod
1430 def setUpClass(cls):
1431 super(BFDSHA1TestCase, cls).setUpClass()
1432 try:
1433 cls.create_pg_interfaces([0])
1434 cls.pg0.config_ip4()
1435 cls.pg0.admin_up()
1436 cls.pg0.resolve_arp()
1437
1438 except Exception:
1439 super(BFDSHA1TestCase, cls).tearDownClass()
1440 raise
1441
1442 def setUp(self):
1443 super(BFDSHA1TestCase, self).setUp()
1444 self.factory = AuthKeyFactory()
1445 self.vapi.want_bfd_events()
Klement Sekerad3ba5152017-02-14 03:09:17 +01001446 self.pg0.enable_capture()
Klement Sekerab17dd962017-01-09 07:43:48 +01001447
1448 def tearDown(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001449 if not self.vpp_dead:
1450 self.vapi.want_bfd_events(enable_disable=0)
1451 self.vapi.collect_events() # clear the event queue
1452 super(BFDSHA1TestCase, self).tearDown()
Klement Sekerab17dd962017-01-09 07:43:48 +01001453
1454 def test_session_up(self):
1455 """ bring BFD session up """
1456 key = self.factory.create_random_key(self)
1457 key.add_vpp_config()
1458 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1459 self.pg0.remote_ip4,
1460 sha1_key=key)
1461 self.vpp_session.add_vpp_config()
1462 self.vpp_session.admin_up()
1463 self.test_session = BFDTestSession(
1464 self, self.pg0, AF_INET, sha1_key=key,
1465 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001466 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001467
1468 def test_hold_up(self):
1469 """ hold BFD session up """
1470 key = self.factory.create_random_key(self)
1471 key.add_vpp_config()
1472 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1473 self.pg0.remote_ip4,
1474 sha1_key=key)
1475 self.vpp_session.add_vpp_config()
1476 self.vpp_session.admin_up()
1477 self.test_session = BFDTestSession(
1478 self, self.pg0, AF_INET, sha1_key=key,
1479 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001480 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001481 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001482 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001483 self.test_session.send_packet()
1484 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1485
1486 def test_hold_up_meticulous(self):
1487 """ hold BFD session up - meticulous auth """
1488 key = self.factory.create_random_key(
1489 self, BFDAuthType.meticulous_keyed_sha1)
1490 key.add_vpp_config()
1491 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1492 self.pg0.remote_ip4, sha1_key=key)
1493 self.vpp_session.add_vpp_config()
1494 self.vpp_session.admin_up()
Klement Sekerad3ba5152017-02-14 03:09:17 +01001495 # specify sequence number so that it wraps
Klement Sekerab17dd962017-01-09 07:43:48 +01001496 self.test_session = BFDTestSession(
1497 self, self.pg0, AF_INET, sha1_key=key,
Klement Sekerad3ba5152017-02-14 03:09:17 +01001498 bfd_key_id=self.vpp_session.bfd_key_id,
1499 our_seq_number=0xFFFFFFFF - 4)
1500 bfd_session_up(self)
1501 for dummy in range(30):
1502 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001503 self.test_session.inc_seq_num()
1504 self.test_session.send_packet()
1505 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1506
1507 def test_send_bad_seq_number(self):
Klement Sekera239790f2017-02-16 10:53:53 +01001508 """ session is not kept alive by msgs with bad sequence numbers"""
Klement Sekerab17dd962017-01-09 07:43:48 +01001509 key = self.factory.create_random_key(
1510 self, BFDAuthType.meticulous_keyed_sha1)
1511 key.add_vpp_config()
1512 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1513 self.pg0.remote_ip4, sha1_key=key)
1514 self.vpp_session.add_vpp_config()
1515 self.vpp_session.admin_up()
1516 self.test_session = BFDTestSession(
1517 self, self.pg0, AF_INET, sha1_key=key,
1518 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001519 bfd_session_up(self)
Klement Sekera239790f2017-02-16 10:53:53 +01001520 detection_time = self.test_session.detect_mult *\
Klement Sekerad3ba5152017-02-14 03:09:17 +01001521 self.vpp_session.required_min_rx / USEC_IN_SEC
Klement Sekera239790f2017-02-16 10:53:53 +01001522 send_until = time.time() + 2 * detection_time
1523 while time.time() < send_until:
Klement Sekerad3ba5152017-02-14 03:09:17 +01001524 self.test_session.send_packet()
Klement Sekera239790f2017-02-16 10:53:53 +01001525 self.sleep(0.7 * self.vpp_session.required_min_rx / USEC_IN_SEC,
1526 "time between bfd packets")
Klement Sekerab17dd962017-01-09 07:43:48 +01001527 e = self.vapi.collect_events()
1528 # session should be down now, because the sequence numbers weren't
1529 # updated
1530 self.assert_equal(len(e), 1, "number of bfd events")
Klement Sekerad3ba5152017-02-14 03:09:17 +01001531 verify_event(self, e[0], expected_state=BFDState.down)
Klement Sekerab17dd962017-01-09 07:43:48 +01001532
1533 def execute_rogue_session_scenario(self, vpp_bfd_udp_session,
1534 legitimate_test_session,
1535 rogue_test_session,
1536 rogue_bfd_values=None):
1537 """ execute a rogue session interaction scenario
1538
1539 1. create vpp session, add config
1540 2. bring the legitimate session up
1541 3. copy the bfd values from legitimate session to rogue session
1542 4. apply rogue_bfd_values to rogue session
1543 5. set rogue session state to down
1544 6. send message to take the session down from the rogue session
1545 7. assert that the legitimate session is unaffected
1546 """
1547
1548 self.vpp_session = vpp_bfd_udp_session
1549 self.vpp_session.add_vpp_config()
1550 self.vpp_session.admin_up()
1551 self.test_session = legitimate_test_session
1552 # bring vpp session up
Klement Sekerad3ba5152017-02-14 03:09:17 +01001553 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001554 # send packet from rogue session
Klement Sekerad3ba5152017-02-14 03:09:17 +01001555 rogue_test_session.update(
1556 my_discriminator=self.test_session.my_discriminator,
1557 your_discriminator=self.test_session.your_discriminator,
1558 desired_min_tx=self.test_session.desired_min_tx,
1559 required_min_rx=self.test_session.required_min_rx,
1560 detect_mult=self.test_session.detect_mult,
1561 diag=self.test_session.diag,
1562 state=self.test_session.state,
1563 auth_type=self.test_session.auth_type)
Klement Sekerab17dd962017-01-09 07:43:48 +01001564 if rogue_bfd_values:
1565 rogue_test_session.update(**rogue_bfd_values)
1566 rogue_test_session.update(state=BFDState.down)
1567 rogue_test_session.send_packet()
Klement Sekerad3ba5152017-02-14 03:09:17 +01001568 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001569 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1570
1571 def test_mismatch_auth(self):
1572 """ session is not brought down by unauthenticated msg """
1573 key = self.factory.create_random_key(self)
1574 key.add_vpp_config()
1575 vpp_session = VppBFDUDPSession(
1576 self, self.pg0, self.pg0.remote_ip4, sha1_key=key)
1577 legitimate_test_session = BFDTestSession(
1578 self, self.pg0, AF_INET, sha1_key=key,
1579 bfd_key_id=vpp_session.bfd_key_id)
1580 rogue_test_session = BFDTestSession(self, self.pg0, AF_INET)
1581 self.execute_rogue_session_scenario(vpp_session,
1582 legitimate_test_session,
1583 rogue_test_session)
1584
1585 def test_mismatch_bfd_key_id(self):
1586 """ session is not brought down by msg with non-existent key-id """
1587 key = self.factory.create_random_key(self)
1588 key.add_vpp_config()
1589 vpp_session = VppBFDUDPSession(
1590 self, self.pg0, self.pg0.remote_ip4, sha1_key=key)
1591 # pick a different random bfd key id
1592 x = randint(0, 255)
1593 while x == vpp_session.bfd_key_id:
1594 x = randint(0, 255)
1595 legitimate_test_session = BFDTestSession(
1596 self, self.pg0, AF_INET, sha1_key=key,
1597 bfd_key_id=vpp_session.bfd_key_id)
1598 rogue_test_session = BFDTestSession(
1599 self, self.pg0, AF_INET, sha1_key=key, bfd_key_id=x)
1600 self.execute_rogue_session_scenario(vpp_session,
1601 legitimate_test_session,
1602 rogue_test_session)
1603
1604 def test_mismatched_auth_type(self):
1605 """ session is not brought down by msg with wrong auth type """
1606 key = self.factory.create_random_key(self)
1607 key.add_vpp_config()
1608 vpp_session = VppBFDUDPSession(
1609 self, self.pg0, self.pg0.remote_ip4, sha1_key=key)
1610 legitimate_test_session = BFDTestSession(
1611 self, self.pg0, AF_INET, sha1_key=key,
1612 bfd_key_id=vpp_session.bfd_key_id)
1613 rogue_test_session = BFDTestSession(
1614 self, self.pg0, AF_INET, sha1_key=key,
1615 bfd_key_id=vpp_session.bfd_key_id)
1616 self.execute_rogue_session_scenario(
1617 vpp_session, legitimate_test_session, rogue_test_session,
1618 {'auth_type': BFDAuthType.keyed_md5})
1619
1620 def test_restart(self):
1621 """ simulate remote peer restart and resynchronization """
1622 key = self.factory.create_random_key(
1623 self, BFDAuthType.meticulous_keyed_sha1)
1624 key.add_vpp_config()
1625 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1626 self.pg0.remote_ip4, sha1_key=key)
1627 self.vpp_session.add_vpp_config()
1628 self.vpp_session.admin_up()
1629 self.test_session = BFDTestSession(
1630 self, self.pg0, AF_INET, sha1_key=key,
1631 bfd_key_id=self.vpp_session.bfd_key_id, our_seq_number=0)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001632 bfd_session_up(self)
1633 # don't send any packets for 2*detection_time
Klement Sekera239790f2017-02-16 10:53:53 +01001634 detection_time = self.test_session.detect_mult *\
Klement Sekerad3ba5152017-02-14 03:09:17 +01001635 self.vpp_session.required_min_rx / USEC_IN_SEC
1636 self.sleep(detection_time, "simulating peer restart")
1637 events = self.vapi.collect_events()
1638 self.assert_equal(len(events), 1, "number of bfd events")
1639 verify_event(self, events[0], expected_state=BFDState.down)
Klement Sekerab17dd962017-01-09 07:43:48 +01001640 self.test_session.update(state=BFDState.down)
Klement Sekerab17dd962017-01-09 07:43:48 +01001641 # reset sequence number
1642 self.test_session.our_seq_number = 0
Klement Sekerad3ba5152017-02-14 03:09:17 +01001643 self.test_session.vpp_seq_number = None
1644 # now throw away any pending packets
1645 self.pg0.enable_capture()
1646 bfd_session_up(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001647
1648
Klement Sekerad3ba5152017-02-14 03:09:17 +01001649class BFDAuthOnOffTestCase(VppTestCase):
Klement Sekerab17dd962017-01-09 07:43:48 +01001650 """Bidirectional Forwarding Detection (BFD) (changing auth) """
1651
Klement Sekerad3ba5152017-02-14 03:09:17 +01001652 pg0 = None
1653 vpp_session = None
1654 test_session = None
1655
Klement Sekerab17dd962017-01-09 07:43:48 +01001656 @classmethod
1657 def setUpClass(cls):
1658 super(BFDAuthOnOffTestCase, cls).setUpClass()
1659 try:
1660 cls.create_pg_interfaces([0])
1661 cls.pg0.config_ip4()
1662 cls.pg0.admin_up()
1663 cls.pg0.resolve_arp()
1664
1665 except Exception:
1666 super(BFDAuthOnOffTestCase, cls).tearDownClass()
1667 raise
1668
1669 def setUp(self):
1670 super(BFDAuthOnOffTestCase, self).setUp()
1671 self.factory = AuthKeyFactory()
1672 self.vapi.want_bfd_events()
Klement Sekerad3ba5152017-02-14 03:09:17 +01001673 self.pg0.enable_capture()
Klement Sekerab17dd962017-01-09 07:43:48 +01001674
1675 def tearDown(self):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001676 if not self.vpp_dead:
1677 self.vapi.want_bfd_events(enable_disable=0)
1678 self.vapi.collect_events() # clear the event queue
1679 super(BFDAuthOnOffTestCase, self).tearDown()
Klement Sekerab17dd962017-01-09 07:43:48 +01001680
1681 def test_auth_on_immediate(self):
1682 """ turn auth on without disturbing session state (immediate) """
1683 key = self.factory.create_random_key(self)
1684 key.add_vpp_config()
1685 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1686 self.pg0.remote_ip4)
1687 self.vpp_session.add_vpp_config()
1688 self.vpp_session.admin_up()
1689 self.test_session = BFDTestSession(self, self.pg0, AF_INET)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001690 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001691 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001692 p = wait_for_bfd_packet(self)
1693 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01001694 self.test_session.send_packet()
1695 self.vpp_session.activate_auth(key)
1696 self.test_session.bfd_key_id = self.vpp_session.bfd_key_id
1697 self.test_session.sha1_key = key
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001698 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001699 p = wait_for_bfd_packet(self)
1700 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01001701 self.test_session.send_packet()
1702 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1703 self.assert_equal(len(self.vapi.collect_events()), 0,
1704 "number of bfd events")
1705
1706 def test_auth_off_immediate(self):
1707 """ turn auth off without disturbing session state (immediate) """
1708 key = self.factory.create_random_key(self)
1709 key.add_vpp_config()
1710 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1711 self.pg0.remote_ip4, sha1_key=key)
1712 self.vpp_session.add_vpp_config()
1713 self.vpp_session.admin_up()
1714 self.test_session = BFDTestSession(
1715 self, self.pg0, AF_INET, sha1_key=key,
1716 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001717 bfd_session_up(self)
1718 # self.vapi.want_bfd_events(enable_disable=0)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001719 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001720 p = wait_for_bfd_packet(self)
1721 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
1722 self.test_session.inc_seq_num()
Klement Sekerab17dd962017-01-09 07:43:48 +01001723 self.test_session.send_packet()
1724 self.vpp_session.deactivate_auth()
1725 self.test_session.bfd_key_id = None
1726 self.test_session.sha1_key = None
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001727 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001728 p = wait_for_bfd_packet(self)
1729 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
1730 self.test_session.inc_seq_num()
Klement Sekerab17dd962017-01-09 07:43:48 +01001731 self.test_session.send_packet()
1732 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1733 self.assert_equal(len(self.vapi.collect_events()), 0,
1734 "number of bfd events")
1735
1736 def test_auth_change_key_immediate(self):
1737 """ change auth key without disturbing session state (immediate) """
1738 key1 = self.factory.create_random_key(self)
1739 key1.add_vpp_config()
1740 key2 = self.factory.create_random_key(self)
1741 key2.add_vpp_config()
1742 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1743 self.pg0.remote_ip4, sha1_key=key1)
1744 self.vpp_session.add_vpp_config()
1745 self.vpp_session.admin_up()
1746 self.test_session = BFDTestSession(
1747 self, self.pg0, AF_INET, sha1_key=key1,
1748 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001749 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001750 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001751 p = wait_for_bfd_packet(self)
1752 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01001753 self.test_session.send_packet()
1754 self.vpp_session.activate_auth(key2)
1755 self.test_session.bfd_key_id = self.vpp_session.bfd_key_id
1756 self.test_session.sha1_key = key2
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001757 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001758 p = wait_for_bfd_packet(self)
1759 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01001760 self.test_session.send_packet()
1761 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1762 self.assert_equal(len(self.vapi.collect_events()), 0,
1763 "number of bfd events")
1764
1765 def test_auth_on_delayed(self):
1766 """ turn auth on without disturbing session state (delayed) """
1767 key = self.factory.create_random_key(self)
1768 key.add_vpp_config()
1769 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1770 self.pg0.remote_ip4)
1771 self.vpp_session.add_vpp_config()
1772 self.vpp_session.admin_up()
1773 self.test_session = BFDTestSession(self, self.pg0, AF_INET)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001774 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001775 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001776 wait_for_bfd_packet(self)
Klement Sekerab17dd962017-01-09 07:43:48 +01001777 self.test_session.send_packet()
1778 self.vpp_session.activate_auth(key, delayed=True)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001779 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001780 p = wait_for_bfd_packet(self)
1781 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01001782 self.test_session.send_packet()
1783 self.test_session.bfd_key_id = self.vpp_session.bfd_key_id
1784 self.test_session.sha1_key = key
1785 self.test_session.send_packet()
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001786 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001787 p = wait_for_bfd_packet(self)
1788 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01001789 self.test_session.send_packet()
1790 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1791 self.assert_equal(len(self.vapi.collect_events()), 0,
1792 "number of bfd events")
1793
1794 def test_auth_off_delayed(self):
1795 """ turn auth off without disturbing session state (delayed) """
1796 key = self.factory.create_random_key(self)
1797 key.add_vpp_config()
1798 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1799 self.pg0.remote_ip4, sha1_key=key)
1800 self.vpp_session.add_vpp_config()
1801 self.vpp_session.admin_up()
1802 self.test_session = BFDTestSession(
1803 self, self.pg0, AF_INET, sha1_key=key,
1804 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001805 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001806 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001807 p = wait_for_bfd_packet(self)
1808 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01001809 self.test_session.send_packet()
1810 self.vpp_session.deactivate_auth(delayed=True)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001811 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001812 p = wait_for_bfd_packet(self)
1813 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01001814 self.test_session.send_packet()
1815 self.test_session.bfd_key_id = None
1816 self.test_session.sha1_key = None
1817 self.test_session.send_packet()
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001818 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001819 p = wait_for_bfd_packet(self)
1820 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01001821 self.test_session.send_packet()
1822 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1823 self.assert_equal(len(self.vapi.collect_events()), 0,
1824 "number of bfd events")
1825
1826 def test_auth_change_key_delayed(self):
1827 """ change auth key without disturbing session state (delayed) """
1828 key1 = self.factory.create_random_key(self)
1829 key1.add_vpp_config()
1830 key2 = self.factory.create_random_key(self)
1831 key2.add_vpp_config()
1832 self.vpp_session = VppBFDUDPSession(self, self.pg0,
1833 self.pg0.remote_ip4, sha1_key=key1)
1834 self.vpp_session.add_vpp_config()
1835 self.vpp_session.admin_up()
1836 self.test_session = BFDTestSession(
1837 self, self.pg0, AF_INET, sha1_key=key1,
1838 bfd_key_id=self.vpp_session.bfd_key_id)
Klement Sekerad3ba5152017-02-14 03:09:17 +01001839 bfd_session_up(self)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001840 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001841 p = wait_for_bfd_packet(self)
1842 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01001843 self.test_session.send_packet()
1844 self.vpp_session.activate_auth(key2, delayed=True)
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001845 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001846 p = wait_for_bfd_packet(self)
1847 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01001848 self.test_session.send_packet()
1849 self.test_session.bfd_key_id = self.vpp_session.bfd_key_id
1850 self.test_session.sha1_key = key2
1851 self.test_session.send_packet()
Klement Sekeraaeeac3b2017-02-14 07:11:52 +01001852 for dummy in range(self.test_session.detect_mult * 2):
Klement Sekerad3ba5152017-02-14 03:09:17 +01001853 p = wait_for_bfd_packet(self)
1854 self.assert_equal(p[BFD].state, BFDState.up, BFDState)
Klement Sekerab17dd962017-01-09 07:43:48 +01001855 self.test_session.send_packet()
1856 self.assert_equal(self.vpp_session.state, BFDState.up, BFDState)
1857 self.assert_equal(len(self.vapi.collect_events()), 0,
1858 "number of bfd events")
Klement Sekera46a87ad2017-01-02 08:22:23 +01001859
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001860if __name__ == '__main__':
1861 unittest.main(testRunner=VppTestRunner)