MPLS Mcast
[vpp.git] / test / test_ip_mcast.py
1 #!/usr/bin/env python
2
3 import unittest
4
5 from framework import VppTestCase, VppTestRunner
6 from vpp_sub_interface import VppSubInterface, VppDot1QSubint, VppDot1ADSubint
7 from vpp_ip_route import VppIpMRoute, VppMRoutePath, VppMFibSignal, \
8     MRouteItfFlags, MRouteEntryFlags
9
10 from scapy.packet import Raw
11 from scapy.layers.l2 import Ether
12 from scapy.layers.inet import IP, UDP, getmacbyip, ICMP
13 from scapy.layers.inet6 import IPv6, getmacbyip6
14 from util import ppp
15
16 #
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
19 # to the next node in the VLIB graph. Thus we are testing the code's
20 # correctness handling this over-flow
21 #
22 N_PKTS_IN_STREAM = 90
23
24
25 class 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
40 class TestIPMcast(VppTestCase):
41     """ IP Multicast Test Case """
42
43     def setUp(self):
44         super(TestIPMcast, self).setUp()
45
46         # create 8 pg interfaces
47         self.create_pg_interfaces(range(8))
48
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
57     def create_stream_ip4(self, src_if, src_ip, dst_ip, payload_size=0):
58         pkts = []
59         # 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
67         for i in range(0, N_PKTS_IN_STREAM):
68             pkts.append(p)
69         return pkts
70
71     def create_stream_ip6(self, src_if, src_ip, dst_ip):
72         pkts = []
73         for i in range(0, N_PKTS_IN_STREAM):
74             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):
93         rxd = self.pg1.get_capture(N_PKTS_IN_STREAM)
94
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
104                 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):
122         capture = self.pg1.get_capture(N_PKTS_IN_STREAM)
123
124         self.assertEqual(len(capture), len(sent))
125
126         for i in range(len(capture)):
127             tx = sent[i]
128             rx = capture[i]
129
130             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).
162         # 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.
165         #
166         route_232_1_1_1 = VppIpMRoute(
167             self,
168             "0.0.0.0",
169             "232.1.1.1", 32,
170             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
171             [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,
178                            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,
186                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
187         route_232_1_1_1.add_vpp_config()
188
189         #
190         # An (S,G).
191         # one accepting interface, pg0, 2 forwarding interfaces
192         #
193         route_1_1_1_1_232_1_1_1 = VppIpMRoute(
194             self,
195             "1.1.1.1",
196             "232.1.1.1", 64,
197             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
198             [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)])
204         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         #
210         route_232 = VppIpMRoute(
211             self,
212             "0.0.0.0",
213             "232.0.0.0", 8,
214             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
215             [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)])
219         route_232.add_vpp_config()
220
221         #
222         # a stream that matches the route for (1.1.1.1,232.1.1.1)
223         #  small packets
224         #
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
232         # We expect replications on Pg1->7
233         self.verify_capture_ip4(self.pg1, tx)
234         self.verify_capture_ip4(self.pg2, tx)
235         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)
240
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         #
248         # 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         #
275         # 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         #
340         route_ff01_1 = VppIpMRoute(
341             self,
342             "::",
343             "ff01::1", 128,
344             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
345             [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)],
353             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         #
360         route_2001_ff01_1 = VppIpMRoute(
361             self,
362             "2001::1",
363             "ff01::1", 256,
364             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
365             [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)],
371             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         #
378         route_ff01 = VppIpMRoute(
379             self,
380             "::",
381             "ff01::", 16,
382             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
383             [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)],
387             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         #
476         route_232_1_1_1 = VppIpMRoute(
477             self,
478             "0.0.0.0",
479             "232.1.1.1", 32,
480             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
481             [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)])
485
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         #
498         signal_232_1_1_1_itf_0 = VppMFibSignal(self,
499                                                route_232_1_1_1,
500                                                self.pg0.sw_if_index,
501                                                tx[0])
502
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         #
526         route_232_1_1_2 = VppIpMRoute(
527             self,
528             "0.0.0.0",
529             "232.1.1.2", 32,
530             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
531             [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)])
535
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         #
543         signal_232_1_1_2_itf_0 = VppMFibSignal(self,
544                                                route_232_1_1_2,
545                                                self.pg0.sw_if_index,
546                                                tx[0])
547         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         #
570         route_232_1_1_1 = VppIpMRoute(
571             self,
572             "0.0.0.0",
573             "232.1.1.1", 32,
574             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
575             [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)])
579
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         #
592         signal_232_1_1_1_itf_0 = VppMFibSignal(self,
593                                                route_232_1_1_1,
594                                                self.pg0.sw_if_index,
595                                                tx[0])
596
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
625         self.vapi.cli("clear trace")
626         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
661 if __name__ == '__main__':
662     unittest.main(testRunner=VppTestRunner)