Fix IP feature ordering.
[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                 # the rx'd packet has the MPLS label popped
105                 eth = rx[Ether]
106                 self.assertEqual(eth.type, 0x800)
107
108                 tx_ip = tx[IP]
109                 rx_ip = rx[IP]
110
111                 # check the MAC address on the RX'd packet is correctly formed
112                 self.assertEqual(eth.dst, getmacbyip(rx_ip.dst))
113
114                 self.assertEqual(rx_ip.src, tx_ip.src)
115                 self.assertEqual(rx_ip.dst, tx_ip.dst)
116                 # IP processing post pop has decremented the TTL
117                 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
118
119         except:
120             raise
121
122     def verify_capture_ip6(self, src_if, sent):
123         capture = self.pg1.get_capture(N_PKTS_IN_STREAM)
124
125         self.assertEqual(len(capture), len(sent))
126
127         for i in range(len(capture)):
128             tx = sent[i]
129             rx = capture[i]
130
131             # the rx'd packet has the MPLS label popped
132             eth = rx[Ether]
133             self.assertEqual(eth.type, 0x86DD)
134
135             tx_ip = tx[IPv6]
136             rx_ip = rx[IPv6]
137
138             # check the MAC address on the RX'd packet is correctly formed
139             self.assertEqual(eth.dst, getmacbyip6(rx_ip.dst))
140
141             self.assertEqual(rx_ip.src, tx_ip.src)
142             self.assertEqual(rx_ip.dst, tx_ip.dst)
143             # IP processing post pop has decremented the TTL
144             self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
145
146     def test_ip_mcast(self):
147         """ IP Multicast Replication """
148
149         #
150         # a stream that matches the default route. gets dropped.
151         #
152         self.vapi.cli("clear trace")
153         tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1")
154         self.pg0.add_stream(tx)
155
156         self.pg_enable_capture(self.pg_interfaces)
157         self.pg_start()
158
159         self.pg0.assert_nothing_captured(
160             remark="IP multicast packets forwarded on default route")
161
162         #
163         # A (*,G).
164         # one accepting interface, pg0, 7 forwarding interfaces
165         #  many forwarding interfaces test the case where the replicare DPO
166         #  needs to use extra cache lines for the buckets.
167         #
168         route_232_1_1_1 = VppIpMRoute(
169             self,
170             "0.0.0.0",
171             "232.1.1.1", 32,
172             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
173             [VppMRoutePath(self.pg0.sw_if_index,
174                            MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
175              VppMRoutePath(self.pg1.sw_if_index,
176                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
177              VppMRoutePath(self.pg2.sw_if_index,
178                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
179              VppMRoutePath(self.pg3.sw_if_index,
180                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
181              VppMRoutePath(self.pg4.sw_if_index,
182                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
183              VppMRoutePath(self.pg5.sw_if_index,
184                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
185              VppMRoutePath(self.pg6.sw_if_index,
186                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
187              VppMRoutePath(self.pg7.sw_if_index,
188                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
189         route_232_1_1_1.add_vpp_config()
190
191         #
192         # An (S,G).
193         # one accepting interface, pg0, 2 forwarding interfaces
194         #
195         route_1_1_1_1_232_1_1_1 = VppIpMRoute(
196             self,
197             "1.1.1.1",
198             "232.1.1.1", 64,
199             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
200             [VppMRoutePath(self.pg0.sw_if_index,
201                            MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
202              VppMRoutePath(self.pg1.sw_if_index,
203                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
204              VppMRoutePath(self.pg2.sw_if_index,
205                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
206         route_1_1_1_1_232_1_1_1.add_vpp_config()
207
208         #
209         # An (*,G/m).
210         # one accepting interface, pg0, 1 forwarding interfaces
211         #
212         route_232 = VppIpMRoute(
213             self,
214             "0.0.0.0",
215             "232.0.0.0", 8,
216             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
217             [VppMRoutePath(self.pg0.sw_if_index,
218                            MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
219              VppMRoutePath(self.pg1.sw_if_index,
220                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
221         route_232.add_vpp_config()
222
223         #
224         # a stream that matches the route for (1.1.1.1,232.1.1.1)
225         #  small packets
226         #
227         self.vapi.cli("clear trace")
228         tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1")
229         self.pg0.add_stream(tx)
230
231         self.pg_enable_capture(self.pg_interfaces)
232         self.pg_start()
233
234         # We expect replications on Pg1->7
235         self.verify_capture_ip4(self.pg1, tx)
236         self.verify_capture_ip4(self.pg2, tx)
237         self.verify_capture_ip4(self.pg3, tx)
238         self.verify_capture_ip4(self.pg4, tx)
239         self.verify_capture_ip4(self.pg5, tx)
240         self.verify_capture_ip4(self.pg6, tx)
241         self.verify_capture_ip4(self.pg7, tx)
242
243         # no replications on Pg0
244         self.pg0.assert_nothing_captured(
245             remark="IP multicast packets forwarded on PG0")
246         self.pg3.assert_nothing_captured(
247             remark="IP multicast packets forwarded on PG3")
248
249         #
250         # a stream that matches the route for (1.1.1.1,232.1.1.1)
251         #  large packets
252         #
253         self.vapi.cli("clear trace")
254         tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1",
255                                     payload_size=1024)
256         self.pg0.add_stream(tx)
257
258         self.pg_enable_capture(self.pg_interfaces)
259         self.pg_start()
260
261         # We expect replications on Pg1->7
262         self.verify_capture_ip4(self.pg1, tx)
263         self.verify_capture_ip4(self.pg2, tx)
264         self.verify_capture_ip4(self.pg3, tx)
265         self.verify_capture_ip4(self.pg4, tx)
266         self.verify_capture_ip4(self.pg5, tx)
267         self.verify_capture_ip4(self.pg6, tx)
268         self.verify_capture_ip4(self.pg7, tx)
269
270         # no replications on Pg0
271         self.pg0.assert_nothing_captured(
272             remark="IP multicast packets forwarded on PG0")
273         self.pg3.assert_nothing_captured(
274             remark="IP multicast packets forwarded on PG3")
275
276         #
277         # a stream that matches the route for (*,232.0.0.0/8)
278         # Send packets with the 9th bit set so we test the correct clearing
279         # of that bit in the mac rewrite
280         #
281         self.vapi.cli("clear trace")
282         tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.255.255.255")
283         self.pg0.add_stream(tx)
284
285         self.pg_enable_capture(self.pg_interfaces)
286         self.pg_start()
287
288         # We expect replications on Pg1 only
289         self.verify_capture_ip4(self.pg1, tx)
290
291         # no replications on Pg0, Pg2 not Pg3
292         self.pg0.assert_nothing_captured(
293             remark="IP multicast packets forwarded on PG0")
294         self.pg2.assert_nothing_captured(
295             remark="IP multicast packets forwarded on PG2")
296         self.pg3.assert_nothing_captured(
297             remark="IP multicast packets forwarded on PG3")
298
299         #
300         # a stream that matches the route for (*,232.1.1.1)
301         #
302         self.vapi.cli("clear trace")
303         tx = self.create_stream_ip4(self.pg0, "1.1.1.2", "232.1.1.1")
304         self.pg0.add_stream(tx)
305
306         self.pg_enable_capture(self.pg_interfaces)
307         self.pg_start()
308
309         # We expect replications on Pg1, 2, 3.
310         self.verify_capture_ip4(self.pg1, tx)
311         self.verify_capture_ip4(self.pg2, tx)
312         self.verify_capture_ip4(self.pg3, tx)
313
314         # no replications on Pg0
315         self.pg0.assert_nothing_captured(
316             remark="IP multicast packets forwarded on PG0")
317
318         route_232_1_1_1.remove_vpp_config()
319         route_1_1_1_1_232_1_1_1.remove_vpp_config()
320         route_232.remove_vpp_config()
321
322     def test_ip6_mcast(self):
323         """ IPv6 Multicast Replication """
324
325         #
326         # a stream that matches the default route. gets dropped.
327         #
328         self.vapi.cli("clear trace")
329         tx = self.create_stream_ip6(self.pg0, "2001::1", "ff01::1")
330         self.pg0.add_stream(tx)
331
332         self.pg_enable_capture(self.pg_interfaces)
333         self.pg_start()
334
335         self.pg0.assert_nothing_captured(
336             remark="IPv6 multicast packets forwarded on default route")
337
338         #
339         # A (*,G).
340         # one accepting interface, pg0, 3 forwarding interfaces
341         #
342         route_ff01_1 = VppIpMRoute(
343             self,
344             "::",
345             "ff01::1", 128,
346             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
347             [VppMRoutePath(self.pg0.sw_if_index,
348                            MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
349              VppMRoutePath(self.pg1.sw_if_index,
350                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
351              VppMRoutePath(self.pg2.sw_if_index,
352                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
353              VppMRoutePath(self.pg3.sw_if_index,
354                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)],
355             is_ip6=1)
356         route_ff01_1.add_vpp_config()
357
358         #
359         # An (S,G).
360         # one accepting interface, pg0, 2 forwarding interfaces
361         #
362         route_2001_ff01_1 = VppIpMRoute(
363             self,
364             "2001::1",
365             "ff01::1", 256,
366             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
367             [VppMRoutePath(self.pg0.sw_if_index,
368                            MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
369              VppMRoutePath(self.pg1.sw_if_index,
370                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
371              VppMRoutePath(self.pg2.sw_if_index,
372                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)],
373             is_ip6=1)
374         route_2001_ff01_1.add_vpp_config()
375
376         #
377         # An (*,G/m).
378         # one accepting interface, pg0, 1 forwarding interface
379         #
380         route_ff01 = VppIpMRoute(
381             self,
382             "::",
383             "ff01::", 16,
384             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
385             [VppMRoutePath(self.pg0.sw_if_index,
386                            MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
387              VppMRoutePath(self.pg1.sw_if_index,
388                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)],
389             is_ip6=1)
390         route_ff01.add_vpp_config()
391
392         #
393         # a stream that matches the route for (*, ff01::/16)
394         #
395         self.vapi.cli("clear trace")
396         tx = self.create_stream_ip6(self.pg0, "2002::1", "ff01:2::255")
397         self.pg0.add_stream(tx)
398
399         self.pg_enable_capture(self.pg_interfaces)
400         self.pg_start()
401
402         # We expect replications on Pg1
403         self.verify_capture_ip6(self.pg1, tx)
404
405         # no replications on Pg0, Pg3
406         self.pg0.assert_nothing_captured(
407             remark="IP multicast packets forwarded on PG0")
408         self.pg2.assert_nothing_captured(
409             remark="IP multicast packets forwarded on PG2")
410         self.pg3.assert_nothing_captured(
411             remark="IP multicast packets forwarded on PG3")
412
413         #
414         # a stream that matches the route for (*,ff01::1)
415         #
416         self.vapi.cli("clear trace")
417         tx = self.create_stream_ip6(self.pg0, "2002::2", "ff01::1")
418         self.pg0.add_stream(tx)
419
420         self.pg_enable_capture(self.pg_interfaces)
421         self.pg_start()
422
423         # We expect replications on Pg1, 2, 3.
424         self.verify_capture_ip6(self.pg1, tx)
425         self.verify_capture_ip6(self.pg2, tx)
426         self.verify_capture_ip6(self.pg3, tx)
427
428         # no replications on Pg0
429         self.pg0.assert_nothing_captured(
430             remark="IPv6 multicast packets forwarded on PG0")
431
432         #
433         # a stream that matches the route for (2001::1, ff00::1)
434         #
435         self.vapi.cli("clear trace")
436         tx = self.create_stream_ip6(self.pg0, "2001::1", "ff01::1")
437         self.pg0.add_stream(tx)
438
439         self.pg_enable_capture(self.pg_interfaces)
440         self.pg_start()
441
442         # We expect replications on Pg1, 2,
443         self.verify_capture_ip6(self.pg1, tx)
444         self.verify_capture_ip6(self.pg2, tx)
445
446         # no replications on Pg0, Pg3
447         self.pg0.assert_nothing_captured(
448             remark="IP multicast packets forwarded on PG0")
449         self.pg3.assert_nothing_captured(
450             remark="IP multicast packets forwarded on PG3")
451
452         route_ff01.remove_vpp_config()
453         route_ff01_1.remove_vpp_config()
454         route_2001_ff01_1.remove_vpp_config()
455
456     def _mcast_connected_send_stream(self, dst_ip):
457         self.vapi.cli("clear trace")
458         tx = self.create_stream_ip4(self.pg0,
459                                     self.pg0.remote_ip4,
460                                     dst_ip)
461         self.pg0.add_stream(tx)
462
463         self.pg_enable_capture(self.pg_interfaces)
464         self.pg_start()
465
466         # We expect replications on Pg1.
467         self.verify_capture_ip4(self.pg1, tx)
468
469         return tx
470
471     def test_ip_mcast_connected(self):
472         """ IP Multicast Connected Source check """
473
474         #
475         # A (*,G).
476         # one accepting interface, pg0, 1 forwarding interfaces
477         #
478         route_232_1_1_1 = VppIpMRoute(
479             self,
480             "0.0.0.0",
481             "232.1.1.1", 32,
482             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
483             [VppMRoutePath(self.pg0.sw_if_index,
484                            MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
485              VppMRoutePath(self.pg1.sw_if_index,
486                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
487
488         route_232_1_1_1.add_vpp_config()
489         route_232_1_1_1.update_entry_flags(
490             MRouteEntryFlags.MFIB_ENTRY_FLAG_CONNECTED)
491
492         #
493         # Now the (*,G) is present, send from connected source
494         #
495         tx = self._mcast_connected_send_stream("232.1.1.1")
496
497         #
498         # Constrct a representation of the signal we expect on pg0
499         #
500         signal_232_1_1_1_itf_0 = VppMFibSignal(self,
501                                                route_232_1_1_1,
502                                                self.pg0.sw_if_index,
503                                                tx[0])
504
505         #
506         # read the only expected signal
507         #
508         signals = self.vapi.mfib_signal_dump()
509
510         self.assertEqual(1, len(signals))
511
512         signal_232_1_1_1_itf_0.compare(signals[0])
513
514         #
515         # reading the signal allows for the generation of another
516         # so send more packets and expect the next signal
517         #
518         tx = self._mcast_connected_send_stream("232.1.1.1")
519
520         signals = self.vapi.mfib_signal_dump()
521         self.assertEqual(1, len(signals))
522         signal_232_1_1_1_itf_0.compare(signals[0])
523
524         #
525         # A Second entry with connected check
526         # one accepting interface, pg0, 1 forwarding interfaces
527         #
528         route_232_1_1_2 = VppIpMRoute(
529             self,
530             "0.0.0.0",
531             "232.1.1.2", 32,
532             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
533             [VppMRoutePath(self.pg0.sw_if_index,
534                            MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
535              VppMRoutePath(self.pg1.sw_if_index,
536                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
537
538         route_232_1_1_2.add_vpp_config()
539         route_232_1_1_2.update_entry_flags(
540             MRouteEntryFlags.MFIB_ENTRY_FLAG_CONNECTED)
541
542         #
543         # Send traffic to both entries. One read should net us two signals
544         #
545         signal_232_1_1_2_itf_0 = VppMFibSignal(self,
546                                                route_232_1_1_2,
547                                                self.pg0.sw_if_index,
548                                                tx[0])
549         tx = self._mcast_connected_send_stream("232.1.1.1")
550         tx2 = self._mcast_connected_send_stream("232.1.1.2")
551
552         #
553         # read the only expected signal
554         #
555         signals = self.vapi.mfib_signal_dump()
556
557         self.assertEqual(2, len(signals))
558
559         signal_232_1_1_1_itf_0.compare(signals[1])
560         signal_232_1_1_2_itf_0.compare(signals[0])
561
562         route_232_1_1_1.remove_vpp_config()
563         route_232_1_1_2.remove_vpp_config()
564
565     def test_ip_mcast_signal(self):
566         """ IP Multicast Signal """
567
568         #
569         # A (*,G).
570         # one accepting interface, pg0, 1 forwarding interfaces
571         #
572         route_232_1_1_1 = VppIpMRoute(
573             self,
574             "0.0.0.0",
575             "232.1.1.1", 32,
576             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
577             [VppMRoutePath(self.pg0.sw_if_index,
578                            MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
579              VppMRoutePath(self.pg1.sw_if_index,
580                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
581
582         route_232_1_1_1.add_vpp_config()
583         route_232_1_1_1.update_entry_flags(
584             MRouteEntryFlags.MFIB_ENTRY_FLAG_SIGNAL)
585
586         #
587         # Now the (*,G) is present, send from connected source
588         #
589         tx = self._mcast_connected_send_stream("232.1.1.1")
590
591         #
592         # Constrct a representation of the signal we expect on pg0
593         #
594         signal_232_1_1_1_itf_0 = VppMFibSignal(self,
595                                                route_232_1_1_1,
596                                                self.pg0.sw_if_index,
597                                                tx[0])
598
599         #
600         # read the only expected signal
601         #
602         signals = self.vapi.mfib_signal_dump()
603
604         self.assertEqual(1, len(signals))
605
606         signal_232_1_1_1_itf_0.compare(signals[0])
607
608         #
609         # reading the signal allows for the generation of another
610         # so send more packets and expect the next signal
611         #
612         tx = self._mcast_connected_send_stream("232.1.1.1")
613
614         signals = self.vapi.mfib_signal_dump()
615         self.assertEqual(1, len(signals))
616         signal_232_1_1_1_itf_0.compare(signals[0])
617
618         #
619         # Set the negate-signal on the accepting interval - the signals
620         # should stop
621         #
622         route_232_1_1_1.update_path_flags(
623             self.pg0.sw_if_index,
624             (MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT |
625              MRouteItfFlags.MFIB_ITF_FLAG_NEGATE_SIGNAL))
626
627         tx = self._mcast_connected_send_stream("232.1.1.1")
628
629         signals = self.vapi.mfib_signal_dump()
630         self.assertEqual(0, len(signals))
631
632         #
633         # Clear the SIGNAL flag on the entry and the signals should
634         # come back since the interface is still NEGATE-SIGNAL
635         #
636         route_232_1_1_1.update_entry_flags(
637             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE)
638
639         tx = self._mcast_connected_send_stream("232.1.1.1")
640
641         signals = self.vapi.mfib_signal_dump()
642         self.assertEqual(1, len(signals))
643         signal_232_1_1_1_itf_0.compare(signals[0])
644
645         #
646         # Lastly remove the NEGATE-SIGNAL from the interface and the
647         # signals should stop
648         #
649         route_232_1_1_1.update_path_flags(self.pg0.sw_if_index,
650                                           MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT)
651
652         tx = self._mcast_connected_send_stream("232.1.1.1")
653         signals = self.vapi.mfib_signal_dump()
654         self.assertEqual(0, len(signals))
655
656         #
657         # Cleanup
658         #
659         route_232_1_1_1.remove_vpp_config()
660
661
662 if __name__ == '__main__':
663     unittest.main(testRunner=VppTestRunner)