blob: c1397d7049299c66c4db97340691eb50db3a7639 [file] [log] [blame]
Neale Ranns32e1c012016-11-22 17:07:28 +00001#!/usr/bin/env python
2
3import unittest
4
5from framework import VppTestCase, VppTestRunner
6from vpp_sub_interface import VppSubInterface, VppDot1QSubint, VppDot1ADSubint
Neale Ranns180279b2017-03-16 15:49:09 -04007from vpp_ip_route import VppIpMRoute, VppMRoutePath, VppMFibSignal, \
8 MRouteItfFlags, MRouteEntryFlags
Neale Ranns32e1c012016-11-22 17:07:28 +00009
10from scapy.packet import Raw
11from scapy.layers.l2 import Ether
Neale Ranns9d676af2017-03-15 01:28:31 -070012from scapy.layers.inet import IP, UDP, getmacbyip, ICMP
Neale Ranns32e1c012016-11-22 17:07:28 +000013from scapy.layers.inet6 import IPv6, getmacbyip6
14from util import ppp
15
Neale Ranns9bea8fb2017-02-03 04:34:01 -080016#
17# The number of packets sent is set to 90 so that when we replicate more than 3
18# times, which we do for some entries, we will generate more than 256 packets
Neale Rannsaaa396a2017-02-05 09:12:02 -080019# to the next node in the VLIB graph. Thus we are testing the code's
20# correctness handling this over-flow
Neale Ranns9bea8fb2017-02-03 04:34:01 -080021#
22N_PKTS_IN_STREAM = 90
23
Neale Ranns32e1c012016-11-22 17:07:28 +000024
Neale Ranns5a8123b2017-01-26 01:18:23 -080025class TestMFIB(VppTestCase):
26 """ MFIB Test Case """
27
28 def setUp(self):
29 super(TestMFIB, self).setUp()
30
31 def test_mfib(self):
32 """ MFIB Unit Tests """
33 error = self.vapi.cli("test mfib")
34
35 if error:
36 self.logger.critical(error)
37 self.assertEqual(error.find("Failed"), -1)
38
39
Neale Ranns32e1c012016-11-22 17:07:28 +000040class TestIPMcast(VppTestCase):
41 """ IP Multicast Test Case """
42
43 def setUp(self):
44 super(TestIPMcast, self).setUp()
45
Neale Ranns37be7362017-02-21 17:30:26 -080046 # create 8 pg interfaces
47 self.create_pg_interfaces(range(8))
Neale Ranns32e1c012016-11-22 17:07:28 +000048
49 # setup interfaces
50 for i in self.pg_interfaces:
51 i.admin_up()
52 i.config_ip4()
53 i.config_ip6()
54 i.resolve_arp()
55 i.resolve_ndp()
56
Neale Ranns9d676af2017-03-15 01:28:31 -070057 def create_stream_ip4(self, src_if, src_ip, dst_ip, payload_size=0):
Neale Ranns32e1c012016-11-22 17:07:28 +000058 pkts = []
Neale Ranns9d676af2017-03-15 01:28:31 -070059 # default to small packet sizes
60 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
61 IP(src=src_ip, dst=dst_ip) /
62 UDP(sport=1234, dport=1234))
63 if not payload_size:
64 payload_size = 64 - len(p)
65 p = p / Raw('\xa5' * payload_size)
66
Neale Ranns9bea8fb2017-02-03 04:34:01 -080067 for i in range(0, N_PKTS_IN_STREAM):
Neale Ranns32e1c012016-11-22 17:07:28 +000068 pkts.append(p)
69 return pkts
70
71 def create_stream_ip6(self, src_if, src_ip, dst_ip):
72 pkts = []
Neale Ranns9bea8fb2017-02-03 04:34:01 -080073 for i in range(0, N_PKTS_IN_STREAM):
Neale Ranns32e1c012016-11-22 17:07:28 +000074 info = self.create_packet_info(src_if, src_if)
75 payload = self.info_to_payload(info)
76 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
77 IPv6(src=src_ip, dst=dst_ip) /
78 UDP(sport=1234, dport=1234) /
79 Raw(payload))
80 info.data = p.copy()
81 pkts.append(p)
82 return pkts
83
84 def verify_filter(self, capture, sent):
85 if not len(capture) == len(sent):
86 # filter out any IPv6 RAs from the captur
87 for p in capture:
88 if (p.haslayer(IPv6)):
89 capture.remove(p)
90 return capture
91
92 def verify_capture_ip4(self, src_if, sent):
Neale Ranns9bea8fb2017-02-03 04:34:01 -080093 rxd = self.pg1.get_capture(N_PKTS_IN_STREAM)
Neale Ranns32e1c012016-11-22 17:07:28 +000094
95 try:
96 capture = self.verify_filter(rxd, sent)
97
98 self.assertEqual(len(capture), len(sent))
99
100 for i in range(len(capture)):
101 tx = sent[i]
102 rx = capture[i]
103
Neale Ranns32e1c012016-11-22 17:07:28 +0000104 eth = rx[Ether]
105 self.assertEqual(eth.type, 0x800)
106
107 tx_ip = tx[IP]
108 rx_ip = rx[IP]
109
110 # check the MAC address on the RX'd packet is correctly formed
111 self.assertEqual(eth.dst, getmacbyip(rx_ip.dst))
112
113 self.assertEqual(rx_ip.src, tx_ip.src)
114 self.assertEqual(rx_ip.dst, tx_ip.dst)
115 # IP processing post pop has decremented the TTL
116 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
117
118 except:
119 raise
120
121 def verify_capture_ip6(self, src_if, sent):
Neale Ranns9bea8fb2017-02-03 04:34:01 -0800122 capture = self.pg1.get_capture(N_PKTS_IN_STREAM)
Neale Ranns32e1c012016-11-22 17:07:28 +0000123
124 self.assertEqual(len(capture), len(sent))
125
126 for i in range(len(capture)):
127 tx = sent[i]
128 rx = capture[i]
129
Neale Ranns32e1c012016-11-22 17:07:28 +0000130 eth = rx[Ether]
131 self.assertEqual(eth.type, 0x86DD)
132
133 tx_ip = tx[IPv6]
134 rx_ip = rx[IPv6]
135
136 # check the MAC address on the RX'd packet is correctly formed
137 self.assertEqual(eth.dst, getmacbyip6(rx_ip.dst))
138
139 self.assertEqual(rx_ip.src, tx_ip.src)
140 self.assertEqual(rx_ip.dst, tx_ip.dst)
141 # IP processing post pop has decremented the TTL
142 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
143
144 def test_ip_mcast(self):
145 """ IP Multicast Replication """
146
147 #
148 # a stream that matches the default route. gets dropped.
149 #
150 self.vapi.cli("clear trace")
151 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1")
152 self.pg0.add_stream(tx)
153
154 self.pg_enable_capture(self.pg_interfaces)
155 self.pg_start()
156
157 self.pg0.assert_nothing_captured(
158 remark="IP multicast packets forwarded on default route")
159
160 #
161 # A (*,G).
Neale Ranns37be7362017-02-21 17:30:26 -0800162 # one accepting interface, pg0, 7 forwarding interfaces
163 # many forwarding interfaces test the case where the replicare DPO
164 # needs to use extra cache lines for the buckets.
Neale Ranns32e1c012016-11-22 17:07:28 +0000165 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800166 route_232_1_1_1 = VppIpMRoute(
Neale Ranns32e1c012016-11-22 17:07:28 +0000167 self,
168 "0.0.0.0",
169 "232.1.1.1", 32,
170 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800171 [VppMRoutePath(self.pg0.sw_if_index,
172 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
173 VppMRoutePath(self.pg1.sw_if_index,
174 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
175 VppMRoutePath(self.pg2.sw_if_index,
176 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
177 VppMRoutePath(self.pg3.sw_if_index,
Neale Ranns37be7362017-02-21 17:30:26 -0800178 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
179 VppMRoutePath(self.pg4.sw_if_index,
180 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
181 VppMRoutePath(self.pg5.sw_if_index,
182 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
183 VppMRoutePath(self.pg6.sw_if_index,
184 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
185 VppMRoutePath(self.pg7.sw_if_index,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800186 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
Neale Ranns32e1c012016-11-22 17:07:28 +0000187 route_232_1_1_1.add_vpp_config()
188
189 #
190 # An (S,G).
191 # one accepting interface, pg0, 2 forwarding interfaces
192 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800193 route_1_1_1_1_232_1_1_1 = VppIpMRoute(
Neale Ranns32e1c012016-11-22 17:07:28 +0000194 self,
195 "1.1.1.1",
196 "232.1.1.1", 64,
197 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800198 [VppMRoutePath(self.pg0.sw_if_index,
199 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
200 VppMRoutePath(self.pg1.sw_if_index,
201 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
202 VppMRoutePath(self.pg2.sw_if_index,
203 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
Neale Ranns32e1c012016-11-22 17:07:28 +0000204 route_1_1_1_1_232_1_1_1.add_vpp_config()
205
206 #
207 # An (*,G/m).
208 # one accepting interface, pg0, 1 forwarding interfaces
209 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800210 route_232 = VppIpMRoute(
Neale Ranns32e1c012016-11-22 17:07:28 +0000211 self,
212 "0.0.0.0",
213 "232.0.0.0", 8,
214 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800215 [VppMRoutePath(self.pg0.sw_if_index,
216 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
217 VppMRoutePath(self.pg1.sw_if_index,
218 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
Neale Ranns32e1c012016-11-22 17:07:28 +0000219 route_232.add_vpp_config()
220
221 #
222 # a stream that matches the route for (1.1.1.1,232.1.1.1)
Neale Ranns9d676af2017-03-15 01:28:31 -0700223 # small packets
Neale Ranns32e1c012016-11-22 17:07:28 +0000224 #
225 self.vapi.cli("clear trace")
226 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1")
227 self.pg0.add_stream(tx)
228
229 self.pg_enable_capture(self.pg_interfaces)
230 self.pg_start()
231
Neale Ranns37be7362017-02-21 17:30:26 -0800232 # We expect replications on Pg1->7
Neale Ranns32e1c012016-11-22 17:07:28 +0000233 self.verify_capture_ip4(self.pg1, tx)
234 self.verify_capture_ip4(self.pg2, tx)
Neale Ranns37be7362017-02-21 17:30:26 -0800235 self.verify_capture_ip4(self.pg3, tx)
236 self.verify_capture_ip4(self.pg4, tx)
237 self.verify_capture_ip4(self.pg5, tx)
238 self.verify_capture_ip4(self.pg6, tx)
239 self.verify_capture_ip4(self.pg7, tx)
Neale Ranns32e1c012016-11-22 17:07:28 +0000240
241 # no replications on Pg0
242 self.pg0.assert_nothing_captured(
243 remark="IP multicast packets forwarded on PG0")
244 self.pg3.assert_nothing_captured(
245 remark="IP multicast packets forwarded on PG3")
246
247 #
Neale Ranns9d676af2017-03-15 01:28:31 -0700248 # a stream that matches the route for (1.1.1.1,232.1.1.1)
249 # large packets
250 #
251 self.vapi.cli("clear trace")
252 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1",
253 payload_size=1024)
254 self.pg0.add_stream(tx)
255
256 self.pg_enable_capture(self.pg_interfaces)
257 self.pg_start()
258
259 # We expect replications on Pg1->7
260 self.verify_capture_ip4(self.pg1, tx)
261 self.verify_capture_ip4(self.pg2, tx)
262 self.verify_capture_ip4(self.pg3, tx)
263 self.verify_capture_ip4(self.pg4, tx)
264 self.verify_capture_ip4(self.pg5, tx)
265 self.verify_capture_ip4(self.pg6, tx)
266 self.verify_capture_ip4(self.pg7, tx)
267
268 # no replications on Pg0
269 self.pg0.assert_nothing_captured(
270 remark="IP multicast packets forwarded on PG0")
271 self.pg3.assert_nothing_captured(
272 remark="IP multicast packets forwarded on PG3")
273
274 #
Neale Ranns32e1c012016-11-22 17:07:28 +0000275 # a stream that matches the route for (*,232.0.0.0/8)
276 # Send packets with the 9th bit set so we test the correct clearing
277 # of that bit in the mac rewrite
278 #
279 self.vapi.cli("clear trace")
280 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.255.255.255")
281 self.pg0.add_stream(tx)
282
283 self.pg_enable_capture(self.pg_interfaces)
284 self.pg_start()
285
286 # We expect replications on Pg1 only
287 self.verify_capture_ip4(self.pg1, tx)
288
289 # no replications on Pg0, Pg2 not Pg3
290 self.pg0.assert_nothing_captured(
291 remark="IP multicast packets forwarded on PG0")
292 self.pg2.assert_nothing_captured(
293 remark="IP multicast packets forwarded on PG2")
294 self.pg3.assert_nothing_captured(
295 remark="IP multicast packets forwarded on PG3")
296
297 #
298 # a stream that matches the route for (*,232.1.1.1)
299 #
300 self.vapi.cli("clear trace")
301 tx = self.create_stream_ip4(self.pg0, "1.1.1.2", "232.1.1.1")
302 self.pg0.add_stream(tx)
303
304 self.pg_enable_capture(self.pg_interfaces)
305 self.pg_start()
306
307 # We expect replications on Pg1, 2, 3.
308 self.verify_capture_ip4(self.pg1, tx)
309 self.verify_capture_ip4(self.pg2, tx)
310 self.verify_capture_ip4(self.pg3, tx)
311
312 # no replications on Pg0
313 self.pg0.assert_nothing_captured(
314 remark="IP multicast packets forwarded on PG0")
315
316 route_232_1_1_1.remove_vpp_config()
317 route_1_1_1_1_232_1_1_1.remove_vpp_config()
318 route_232.remove_vpp_config()
319
320 def test_ip6_mcast(self):
321 """ IPv6 Multicast Replication """
322
323 #
324 # a stream that matches the default route. gets dropped.
325 #
326 self.vapi.cli("clear trace")
327 tx = self.create_stream_ip6(self.pg0, "2001::1", "ff01::1")
328 self.pg0.add_stream(tx)
329
330 self.pg_enable_capture(self.pg_interfaces)
331 self.pg_start()
332
333 self.pg0.assert_nothing_captured(
334 remark="IPv6 multicast packets forwarded on default route")
335
336 #
337 # A (*,G).
338 # one accepting interface, pg0, 3 forwarding interfaces
339 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800340 route_ff01_1 = VppIpMRoute(
Neale Ranns32e1c012016-11-22 17:07:28 +0000341 self,
342 "::",
343 "ff01::1", 128,
344 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800345 [VppMRoutePath(self.pg0.sw_if_index,
346 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
347 VppMRoutePath(self.pg1.sw_if_index,
348 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
349 VppMRoutePath(self.pg2.sw_if_index,
350 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
351 VppMRoutePath(self.pg3.sw_if_index,
352 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)],
Neale Ranns32e1c012016-11-22 17:07:28 +0000353 is_ip6=1)
354 route_ff01_1.add_vpp_config()
355
356 #
357 # An (S,G).
358 # one accepting interface, pg0, 2 forwarding interfaces
359 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800360 route_2001_ff01_1 = VppIpMRoute(
Neale Ranns32e1c012016-11-22 17:07:28 +0000361 self,
362 "2001::1",
363 "ff01::1", 256,
364 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800365 [VppMRoutePath(self.pg0.sw_if_index,
366 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
367 VppMRoutePath(self.pg1.sw_if_index,
368 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
369 VppMRoutePath(self.pg2.sw_if_index,
370 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)],
Neale Ranns32e1c012016-11-22 17:07:28 +0000371 is_ip6=1)
372 route_2001_ff01_1.add_vpp_config()
373
374 #
375 # An (*,G/m).
376 # one accepting interface, pg0, 1 forwarding interface
377 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800378 route_ff01 = VppIpMRoute(
Neale Ranns32e1c012016-11-22 17:07:28 +0000379 self,
380 "::",
381 "ff01::", 16,
382 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800383 [VppMRoutePath(self.pg0.sw_if_index,
384 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
385 VppMRoutePath(self.pg1.sw_if_index,
386 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)],
Neale Ranns32e1c012016-11-22 17:07:28 +0000387 is_ip6=1)
388 route_ff01.add_vpp_config()
389
390 #
391 # a stream that matches the route for (*, ff01::/16)
392 #
393 self.vapi.cli("clear trace")
394 tx = self.create_stream_ip6(self.pg0, "2002::1", "ff01:2::255")
395 self.pg0.add_stream(tx)
396
397 self.pg_enable_capture(self.pg_interfaces)
398 self.pg_start()
399
400 # We expect replications on Pg1
401 self.verify_capture_ip6(self.pg1, tx)
402
403 # no replications on Pg0, Pg3
404 self.pg0.assert_nothing_captured(
405 remark="IP multicast packets forwarded on PG0")
406 self.pg2.assert_nothing_captured(
407 remark="IP multicast packets forwarded on PG2")
408 self.pg3.assert_nothing_captured(
409 remark="IP multicast packets forwarded on PG3")
410
411 #
412 # a stream that matches the route for (*,ff01::1)
413 #
414 self.vapi.cli("clear trace")
415 tx = self.create_stream_ip6(self.pg0, "2002::2", "ff01::1")
416 self.pg0.add_stream(tx)
417
418 self.pg_enable_capture(self.pg_interfaces)
419 self.pg_start()
420
421 # We expect replications on Pg1, 2, 3.
422 self.verify_capture_ip6(self.pg1, tx)
423 self.verify_capture_ip6(self.pg2, tx)
424 self.verify_capture_ip6(self.pg3, tx)
425
426 # no replications on Pg0
427 self.pg0.assert_nothing_captured(
428 remark="IPv6 multicast packets forwarded on PG0")
429
430 #
431 # a stream that matches the route for (2001::1, ff00::1)
432 #
433 self.vapi.cli("clear trace")
434 tx = self.create_stream_ip6(self.pg0, "2001::1", "ff01::1")
435 self.pg0.add_stream(tx)
436
437 self.pg_enable_capture(self.pg_interfaces)
438 self.pg_start()
439
440 # We expect replications on Pg1, 2,
441 self.verify_capture_ip6(self.pg1, tx)
442 self.verify_capture_ip6(self.pg2, tx)
443
444 # no replications on Pg0, Pg3
445 self.pg0.assert_nothing_captured(
446 remark="IP multicast packets forwarded on PG0")
447 self.pg3.assert_nothing_captured(
448 remark="IP multicast packets forwarded on PG3")
449
450 route_ff01.remove_vpp_config()
451 route_ff01_1.remove_vpp_config()
452 route_2001_ff01_1.remove_vpp_config()
453
454 def _mcast_connected_send_stream(self, dst_ip):
455 self.vapi.cli("clear trace")
456 tx = self.create_stream_ip4(self.pg0,
457 self.pg0.remote_ip4,
458 dst_ip)
459 self.pg0.add_stream(tx)
460
461 self.pg_enable_capture(self.pg_interfaces)
462 self.pg_start()
463
464 # We expect replications on Pg1.
465 self.verify_capture_ip4(self.pg1, tx)
466
467 return tx
468
469 def test_ip_mcast_connected(self):
470 """ IP Multicast Connected Source check """
471
472 #
473 # A (*,G).
474 # one accepting interface, pg0, 1 forwarding interfaces
475 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800476 route_232_1_1_1 = VppIpMRoute(
Neale Ranns32e1c012016-11-22 17:07:28 +0000477 self,
478 "0.0.0.0",
479 "232.1.1.1", 32,
480 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800481 [VppMRoutePath(self.pg0.sw_if_index,
482 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
483 VppMRoutePath(self.pg1.sw_if_index,
484 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
Neale Ranns32e1c012016-11-22 17:07:28 +0000485
486 route_232_1_1_1.add_vpp_config()
487 route_232_1_1_1.update_entry_flags(
488 MRouteEntryFlags.MFIB_ENTRY_FLAG_CONNECTED)
489
490 #
491 # Now the (*,G) is present, send from connected source
492 #
493 tx = self._mcast_connected_send_stream("232.1.1.1")
494
495 #
496 # Constrct a representation of the signal we expect on pg0
497 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800498 signal_232_1_1_1_itf_0 = VppMFibSignal(self,
499 route_232_1_1_1,
500 self.pg0.sw_if_index,
501 tx[0])
Neale Ranns32e1c012016-11-22 17:07:28 +0000502
503 #
504 # read the only expected signal
505 #
506 signals = self.vapi.mfib_signal_dump()
507
508 self.assertEqual(1, len(signals))
509
510 signal_232_1_1_1_itf_0.compare(signals[0])
511
512 #
513 # reading the signal allows for the generation of another
514 # so send more packets and expect the next signal
515 #
516 tx = self._mcast_connected_send_stream("232.1.1.1")
517
518 signals = self.vapi.mfib_signal_dump()
519 self.assertEqual(1, len(signals))
520 signal_232_1_1_1_itf_0.compare(signals[0])
521
522 #
523 # A Second entry with connected check
524 # one accepting interface, pg0, 1 forwarding interfaces
525 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800526 route_232_1_1_2 = VppIpMRoute(
Neale Ranns32e1c012016-11-22 17:07:28 +0000527 self,
528 "0.0.0.0",
529 "232.1.1.2", 32,
530 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800531 [VppMRoutePath(self.pg0.sw_if_index,
532 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
533 VppMRoutePath(self.pg1.sw_if_index,
534 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
Neale Ranns32e1c012016-11-22 17:07:28 +0000535
536 route_232_1_1_2.add_vpp_config()
537 route_232_1_1_2.update_entry_flags(
538 MRouteEntryFlags.MFIB_ENTRY_FLAG_CONNECTED)
539
540 #
541 # Send traffic to both entries. One read should net us two signals
542 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800543 signal_232_1_1_2_itf_0 = VppMFibSignal(self,
544 route_232_1_1_2,
545 self.pg0.sw_if_index,
546 tx[0])
Neale Ranns32e1c012016-11-22 17:07:28 +0000547 tx = self._mcast_connected_send_stream("232.1.1.1")
548 tx2 = self._mcast_connected_send_stream("232.1.1.2")
549
550 #
551 # read the only expected signal
552 #
553 signals = self.vapi.mfib_signal_dump()
554
555 self.assertEqual(2, len(signals))
556
557 signal_232_1_1_1_itf_0.compare(signals[1])
558 signal_232_1_1_2_itf_0.compare(signals[0])
559
560 route_232_1_1_1.remove_vpp_config()
561 route_232_1_1_2.remove_vpp_config()
562
563 def test_ip_mcast_signal(self):
564 """ IP Multicast Signal """
565
566 #
567 # A (*,G).
568 # one accepting interface, pg0, 1 forwarding interfaces
569 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800570 route_232_1_1_1 = VppIpMRoute(
Neale Ranns32e1c012016-11-22 17:07:28 +0000571 self,
572 "0.0.0.0",
573 "232.1.1.1", 32,
574 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800575 [VppMRoutePath(self.pg0.sw_if_index,
576 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
577 VppMRoutePath(self.pg1.sw_if_index,
578 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
Neale Ranns32e1c012016-11-22 17:07:28 +0000579
580 route_232_1_1_1.add_vpp_config()
581 route_232_1_1_1.update_entry_flags(
582 MRouteEntryFlags.MFIB_ENTRY_FLAG_SIGNAL)
583
584 #
585 # Now the (*,G) is present, send from connected source
586 #
587 tx = self._mcast_connected_send_stream("232.1.1.1")
588
589 #
590 # Constrct a representation of the signal we expect on pg0
591 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800592 signal_232_1_1_1_itf_0 = VppMFibSignal(self,
593 route_232_1_1_1,
594 self.pg0.sw_if_index,
595 tx[0])
Neale Ranns32e1c012016-11-22 17:07:28 +0000596
597 #
598 # read the only expected signal
599 #
600 signals = self.vapi.mfib_signal_dump()
601
602 self.assertEqual(1, len(signals))
603
604 signal_232_1_1_1_itf_0.compare(signals[0])
605
606 #
607 # reading the signal allows for the generation of another
608 # so send more packets and expect the next signal
609 #
610 tx = self._mcast_connected_send_stream("232.1.1.1")
611
612 signals = self.vapi.mfib_signal_dump()
613 self.assertEqual(1, len(signals))
614 signal_232_1_1_1_itf_0.compare(signals[0])
615
616 #
617 # Set the negate-signal on the accepting interval - the signals
618 # should stop
619 #
620 route_232_1_1_1.update_path_flags(
621 self.pg0.sw_if_index,
622 (MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT |
623 MRouteItfFlags.MFIB_ITF_FLAG_NEGATE_SIGNAL))
624
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800625 self.vapi.cli("clear trace")
Neale Ranns32e1c012016-11-22 17:07:28 +0000626 tx = self._mcast_connected_send_stream("232.1.1.1")
627
628 signals = self.vapi.mfib_signal_dump()
629 self.assertEqual(0, len(signals))
630
631 #
632 # Clear the SIGNAL flag on the entry and the signals should
633 # come back since the interface is still NEGATE-SIGNAL
634 #
635 route_232_1_1_1.update_entry_flags(
636 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE)
637
638 tx = self._mcast_connected_send_stream("232.1.1.1")
639
640 signals = self.vapi.mfib_signal_dump()
641 self.assertEqual(1, len(signals))
642 signal_232_1_1_1_itf_0.compare(signals[0])
643
644 #
645 # Lastly remove the NEGATE-SIGNAL from the interface and the
646 # signals should stop
647 #
648 route_232_1_1_1.update_path_flags(self.pg0.sw_if_index,
649 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT)
650
651 tx = self._mcast_connected_send_stream("232.1.1.1")
652 signals = self.vapi.mfib_signal_dump()
653 self.assertEqual(0, len(signals))
654
655 #
656 # Cleanup
657 #
658 route_232_1_1_1.remove_vpp_config()
659
660
661if __name__ == '__main__':
662 unittest.main(testRunner=VppTestRunner)