Improve Load-Balance MAPs
[vpp.git] / test / test_mpls.py
1 #!/usr/bin/env python
2
3 import unittest
4 import socket
5
6 from framework import VppTestCase, VppTestRunner
7 from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
8     VppMplsIpBind, VppIpMRoute, VppMRoutePath, \
9     MRouteItfFlags, MRouteEntryFlags
10 from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface
11
12 from scapy.packet import Raw
13 from scapy.layers.l2 import Ether
14 from scapy.layers.inet import IP, UDP, ICMP
15 from scapy.layers.inet6 import IPv6
16 from scapy.contrib.mpls import MPLS
17
18
19 class TestMPLS(VppTestCase):
20     """ MPLS Test Case """
21
22     def setUp(self):
23         super(TestMPLS, self).setUp()
24
25         # create 2 pg interfaces
26         self.create_pg_interfaces(range(4))
27
28         # setup both interfaces
29         # assign them different tables.
30         table_id = 0
31
32         for i in self.pg_interfaces:
33             i.admin_up()
34             i.set_table_ip4(table_id)
35             i.set_table_ip6(table_id)
36             i.config_ip4()
37             i.resolve_arp()
38             i.config_ip6()
39             i.resolve_ndp()
40             i.enable_mpls()
41             table_id += 1
42
43     def tearDown(self):
44         super(TestMPLS, self).tearDown()
45         for i in self.pg_interfaces:
46             i.unconfig_ip4()
47             i.unconfig_ip6()
48             i.ip6_disable()
49             i.admin_down()
50
51     # the default of 64 matches the IP packet TTL default
52     def create_stream_labelled_ip4(
53             self,
54             src_if,
55             mpls_labels,
56             mpls_ttl=255,
57             ping=0,
58             ip_itf=None,
59             dst_ip=None,
60             n=257):
61         self.reset_packet_infos()
62         pkts = []
63         for i in range(0, n):
64             info = self.create_packet_info(src_if, src_if)
65             payload = self.info_to_payload(info)
66             p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
67
68             for ii in range(len(mpls_labels)):
69                 if ii == len(mpls_labels) - 1:
70                     p = p / MPLS(label=mpls_labels[ii], ttl=mpls_ttl, s=1)
71                 else:
72                     p = p / MPLS(label=mpls_labels[ii], ttl=mpls_ttl, s=0)
73             if not ping:
74                 if not dst_ip:
75                     p = (p / IP(src=src_if.local_ip4, dst=src_if.remote_ip4) /
76                          UDP(sport=1234, dport=1234) /
77                          Raw(payload))
78                 else:
79                     p = (p / IP(src=src_if.local_ip4, dst=dst_ip) /
80                          UDP(sport=1234, dport=1234) /
81                          Raw(payload))
82             else:
83                 p = (p / IP(src=ip_itf.remote_ip4,
84                             dst=ip_itf.local_ip4) /
85                      ICMP())
86
87             info.data = p.copy()
88             pkts.append(p)
89         return pkts
90
91     def create_stream_ip4(self, src_if, dst_ip):
92         self.reset_packet_infos()
93         pkts = []
94         for i in range(0, 257):
95             info = self.create_packet_info(src_if, src_if)
96             payload = self.info_to_payload(info)
97             p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
98                  IP(src=src_if.remote_ip4, dst=dst_ip) /
99                  UDP(sport=1234, dport=1234) /
100                  Raw(payload))
101             info.data = p.copy()
102             pkts.append(p)
103         return pkts
104
105     def create_stream_labelled_ip6(self, src_if, mpls_label, mpls_ttl):
106         self.reset_packet_infos()
107         pkts = []
108         for i in range(0, 257):
109             info = self.create_packet_info(src_if, src_if)
110             payload = self.info_to_payload(info)
111             p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
112                  MPLS(label=mpls_label, ttl=mpls_ttl) /
113                  IPv6(src=src_if.remote_ip6, dst=src_if.remote_ip6) /
114                  UDP(sport=1234, dport=1234) /
115                  Raw(payload))
116             info.data = p.copy()
117             pkts.append(p)
118         return pkts
119
120     @staticmethod
121     def verify_filter(capture, sent):
122         if not len(capture) == len(sent):
123             # filter out any IPv6 RAs from the capture
124             for p in capture:
125                 if p.haslayer(IPv6):
126                     capture.remove(p)
127         return capture
128
129     def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0):
130         try:
131             capture = self.verify_filter(capture, sent)
132
133             self.assertEqual(len(capture), len(sent))
134
135             for i in range(len(capture)):
136                 tx = sent[i]
137                 rx = capture[i]
138
139                 # the rx'd packet has the MPLS label popped
140                 eth = rx[Ether]
141                 self.assertEqual(eth.type, 0x800)
142
143                 tx_ip = tx[IP]
144                 rx_ip = rx[IP]
145
146                 if not ping_resp:
147                     self.assertEqual(rx_ip.src, tx_ip.src)
148                     self.assertEqual(rx_ip.dst, tx_ip.dst)
149                     # IP processing post pop has decremented the TTL
150                     self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
151                 else:
152                     self.assertEqual(rx_ip.src, tx_ip.dst)
153                     self.assertEqual(rx_ip.dst, tx_ip.src)
154
155         except:
156             raise
157
158     def verify_mpls_stack(self, rx, mpls_labels, ttl=255, num=0):
159         # the rx'd packet has the MPLS label popped
160         eth = rx[Ether]
161         self.assertEqual(eth.type, 0x8847)
162
163         rx_mpls = rx[MPLS]
164
165         for ii in range(len(mpls_labels)):
166             self.assertEqual(rx_mpls.label, mpls_labels[ii])
167             self.assertEqual(rx_mpls.cos, 0)
168             if ii == num:
169                 self.assertEqual(rx_mpls.ttl, ttl)
170             else:
171                 self.assertEqual(rx_mpls.ttl, 255)
172
173             if ii == len(mpls_labels) - 1:
174                 self.assertEqual(rx_mpls.s, 1)
175             else:
176                 # not end of stack
177                 self.assertEqual(rx_mpls.s, 0)
178                 # pop the label to expose the next
179                 rx_mpls = rx_mpls[MPLS].payload
180
181     def verify_capture_labelled_ip4(self, src_if, capture, sent,
182                                     mpls_labels):
183         try:
184             capture = self.verify_filter(capture, sent)
185
186             self.assertEqual(len(capture), len(sent))
187
188             for i in range(len(capture)):
189                 tx = sent[i]
190                 rx = capture[i]
191                 tx_ip = tx[IP]
192                 rx_ip = rx[IP]
193
194                 # the MPLS TTL is copied from the IP
195                 self.verify_mpls_stack(
196                     rx, mpls_labels, rx_ip.ttl, len(mpls_labels) - 1)
197
198                 self.assertEqual(rx_ip.src, tx_ip.src)
199                 self.assertEqual(rx_ip.dst, tx_ip.dst)
200                 # IP processing post pop has decremented the TTL
201                 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
202
203         except:
204             raise
205
206     def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
207         try:
208             capture = self.verify_filter(capture, sent)
209
210             self.assertEqual(len(capture), len(sent))
211
212             for i in range(len(capture)):
213                 tx = sent[i]
214                 rx = capture[i]
215                 tx_ip = tx[IP]
216                 rx_ip = rx[IP]
217
218                 # the MPLS TTL is 255 since it enters a new tunnel
219                 self.verify_mpls_stack(
220                     rx, mpls_labels, 255, len(mpls_labels) - 1)
221
222                 self.assertEqual(rx_ip.src, tx_ip.src)
223                 self.assertEqual(rx_ip.dst, tx_ip.dst)
224                 # IP processing post pop has decremented the TTL
225                 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
226
227         except:
228             raise
229
230     def verify_capture_labelled(self, src_if, capture, sent,
231                                 mpls_labels, ttl=254, num=0):
232         try:
233             capture = self.verify_filter(capture, sent)
234
235             self.assertEqual(len(capture), len(sent))
236
237             for i in range(len(capture)):
238                 rx = capture[i]
239                 self.verify_mpls_stack(rx, mpls_labels, ttl, num)
240         except:
241             raise
242
243     def verify_capture_ip6(self, src_if, capture, sent):
244         try:
245             self.assertEqual(len(capture), len(sent))
246
247             for i in range(len(capture)):
248                 tx = sent[i]
249                 rx = capture[i]
250
251                 # the rx'd packet has the MPLS label popped
252                 eth = rx[Ether]
253                 self.assertEqual(eth.type, 0x86DD)
254
255                 tx_ip = tx[IPv6]
256                 rx_ip = rx[IPv6]
257
258                 self.assertEqual(rx_ip.src, tx_ip.src)
259                 self.assertEqual(rx_ip.dst, tx_ip.dst)
260                 # IP processing post pop has decremented the TTL
261                 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
262
263         except:
264             raise
265
266     def send_and_assert_no_replies(self, intf, pkts, remark):
267         intf.add_stream(pkts)
268         self.pg_enable_capture(self.pg_interfaces)
269         self.pg_start()
270         for i in self.pg_interfaces:
271             i.assert_nothing_captured(remark=remark)
272
273     def test_swap(self):
274         """ MPLS label swap tests """
275
276         #
277         # A simple MPLS xconnect - eos label in label out
278         #
279         route_32_eos = VppMplsRoute(self, 32, 1,
280                                     [VppRoutePath(self.pg0.remote_ip4,
281                                                   self.pg0.sw_if_index,
282                                                   labels=[33])])
283         route_32_eos.add_vpp_config()
284
285         #
286         # a stream that matches the route for 10.0.0.1
287         # PG0 is in the default table
288         #
289         self.vapi.cli("clear trace")
290         tx = self.create_stream_labelled_ip4(self.pg0, [32])
291         self.pg0.add_stream(tx)
292
293         self.pg_enable_capture(self.pg_interfaces)
294         self.pg_start()
295
296         rx = self.pg0.get_capture()
297         self.verify_capture_labelled(self.pg0, rx, tx, [33])
298
299         #
300         # A simple MPLS xconnect - non-eos label in label out
301         #
302         route_32_neos = VppMplsRoute(self, 32, 0,
303                                      [VppRoutePath(self.pg0.remote_ip4,
304                                                    self.pg0.sw_if_index,
305                                                    labels=[33])])
306         route_32_neos.add_vpp_config()
307
308         #
309         # a stream that matches the route for 10.0.0.1
310         # PG0 is in the default table
311         #
312         self.vapi.cli("clear trace")
313         tx = self.create_stream_labelled_ip4(self.pg0, [32, 99])
314         self.pg0.add_stream(tx)
315
316         self.pg_enable_capture(self.pg_interfaces)
317         self.pg_start()
318
319         rx = self.pg0.get_capture()
320         self.verify_capture_labelled(self.pg0, rx, tx, [33, 99])
321
322         #
323         # An MPLS xconnect - EOS label in IP out
324         #
325         route_33_eos = VppMplsRoute(self, 33, 1,
326                                     [VppRoutePath(self.pg0.remote_ip4,
327                                                   self.pg0.sw_if_index,
328                                                   labels=[])])
329         route_33_eos.add_vpp_config()
330
331         self.vapi.cli("clear trace")
332         tx = self.create_stream_labelled_ip4(self.pg0, [33])
333         self.pg0.add_stream(tx)
334
335         self.pg_enable_capture(self.pg_interfaces)
336         self.pg_start()
337
338         rx = self.pg0.get_capture()
339         self.verify_capture_ip4(self.pg0, rx, tx)
340
341         #
342         # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
343         # so this traffic should be dropped.
344         #
345         route_33_neos = VppMplsRoute(self, 33, 0,
346                                      [VppRoutePath(self.pg0.remote_ip4,
347                                                    self.pg0.sw_if_index,
348                                                    labels=[])])
349         route_33_neos.add_vpp_config()
350
351         self.vapi.cli("clear trace")
352         tx = self.create_stream_labelled_ip4(self.pg0, [33, 99])
353         self.pg0.add_stream(tx)
354
355         self.pg_enable_capture(self.pg_interfaces)
356         self.pg_start()
357         self.pg0.assert_nothing_captured(
358             remark="MPLS non-EOS packets popped and forwarded")
359
360         #
361         # A recursive EOS x-connect, which resolves through another x-connect
362         #
363         route_34_eos = VppMplsRoute(self, 34, 1,
364                                     [VppRoutePath("0.0.0.0",
365                                                   0xffffffff,
366                                                   nh_via_label=32,
367                                                   labels=[44, 45])])
368         route_34_eos.add_vpp_config()
369
370         tx = self.create_stream_labelled_ip4(self.pg0, [34])
371         self.pg0.add_stream(tx)
372
373         self.pg_enable_capture(self.pg_interfaces)
374         self.pg_start()
375
376         rx = self.pg0.get_capture()
377         self.verify_capture_labelled(self.pg0, rx, tx, [33, 44, 45], num=2)
378
379         #
380         # A recursive non-EOS x-connect, which resolves through another
381         # x-connect
382         #
383         route_34_neos = VppMplsRoute(self, 34, 0,
384                                      [VppRoutePath("0.0.0.0",
385                                                    0xffffffff,
386                                                    nh_via_label=32,
387                                                    labels=[44, 46])])
388         route_34_neos.add_vpp_config()
389
390         self.vapi.cli("clear trace")
391         tx = self.create_stream_labelled_ip4(self.pg0, [34, 99])
392         self.pg0.add_stream(tx)
393
394         self.pg_enable_capture(self.pg_interfaces)
395         self.pg_start()
396
397         rx = self.pg0.get_capture()
398         # it's the 2nd (counting from 0) label in the stack that is swapped
399         self.verify_capture_labelled(self.pg0, rx, tx, [33, 44, 46, 99], num=2)
400
401         #
402         # an recursive IP route that resolves through the recursive non-eos
403         # x-connect
404         #
405         ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
406                                  [VppRoutePath("0.0.0.0",
407                                                0xffffffff,
408                                                nh_via_label=34,
409                                                labels=[55])])
410         ip_10_0_0_1.add_vpp_config()
411
412         self.vapi.cli("clear trace")
413         tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
414         self.pg0.add_stream(tx)
415
416         self.pg_enable_capture(self.pg_interfaces)
417         self.pg_start()
418
419         rx = self.pg0.get_capture()
420         self.verify_capture_labelled_ip4(self.pg0, rx, tx, [33, 44, 46, 55])
421
422         ip_10_0_0_1.remove_vpp_config()
423         route_34_neos.remove_vpp_config()
424         route_34_eos.remove_vpp_config()
425         route_33_neos.remove_vpp_config()
426         route_33_eos.remove_vpp_config()
427         route_32_neos.remove_vpp_config()
428         route_32_eos.remove_vpp_config()
429
430     def test_bind(self):
431         """ MPLS Local Label Binding test """
432
433         #
434         # Add a non-recursive route with a single out label
435         #
436         route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
437                                     [VppRoutePath(self.pg0.remote_ip4,
438                                                   self.pg0.sw_if_index,
439                                                   labels=[45])])
440         route_10_0_0_1.add_vpp_config()
441
442         # bind a local label to the route
443         binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
444         binding.add_vpp_config()
445
446         # non-EOS stream
447         self.vapi.cli("clear trace")
448         tx = self.create_stream_labelled_ip4(self.pg0, [44, 99])
449         self.pg0.add_stream(tx)
450
451         self.pg_enable_capture(self.pg_interfaces)
452         self.pg_start()
453
454         rx = self.pg0.get_capture()
455         self.verify_capture_labelled(self.pg0, rx, tx, [45, 99])
456
457         # EOS stream
458         self.vapi.cli("clear trace")
459         tx = self.create_stream_labelled_ip4(self.pg0, [44])
460         self.pg0.add_stream(tx)
461
462         self.pg_enable_capture(self.pg_interfaces)
463         self.pg_start()
464
465         rx = self.pg0.get_capture()
466         self.verify_capture_labelled(self.pg0, rx, tx, [45])
467
468         # IP stream
469         self.vapi.cli("clear trace")
470         tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
471         self.pg0.add_stream(tx)
472
473         self.pg_enable_capture(self.pg_interfaces)
474         self.pg_start()
475
476         rx = self.pg0.get_capture()
477         self.verify_capture_labelled_ip4(self.pg0, rx, tx, [45])
478
479         #
480         # cleanup
481         #
482         binding.remove_vpp_config()
483         route_10_0_0_1.remove_vpp_config()
484
485     def test_imposition(self):
486         """ MPLS label imposition test """
487
488         #
489         # Add a non-recursive route with a single out label
490         #
491         route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
492                                     [VppRoutePath(self.pg0.remote_ip4,
493                                                   self.pg0.sw_if_index,
494                                                   labels=[32])])
495         route_10_0_0_1.add_vpp_config()
496
497         #
498         # a stream that matches the route for 10.0.0.1
499         # PG0 is in the default table
500         #
501         self.vapi.cli("clear trace")
502         tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
503         self.pg0.add_stream(tx)
504
505         self.pg_enable_capture(self.pg_interfaces)
506         self.pg_start()
507
508         rx = self.pg0.get_capture()
509         self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32])
510
511         #
512         # Add a non-recursive route with a 3 out labels
513         #
514         route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
515                                     [VppRoutePath(self.pg0.remote_ip4,
516                                                   self.pg0.sw_if_index,
517                                                   labels=[32, 33, 34])])
518         route_10_0_0_2.add_vpp_config()
519
520         #
521         # a stream that matches the route for 10.0.0.1
522         # PG0 is in the default table
523         #
524         self.vapi.cli("clear trace")
525         tx = self.create_stream_ip4(self.pg0, "10.0.0.2")
526         self.pg0.add_stream(tx)
527
528         self.pg_enable_capture(self.pg_interfaces)
529         self.pg_start()
530
531         rx = self.pg0.get_capture()
532         self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32, 33, 34])
533
534         #
535         # add a recursive path, with output label, via the 1 label route
536         #
537         route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
538                                     [VppRoutePath("10.0.0.1",
539                                                   0xffffffff,
540                                                   labels=[44])])
541         route_11_0_0_1.add_vpp_config()
542
543         #
544         # a stream that matches the route for 11.0.0.1, should pick up
545         # the label stack for 11.0.0.1 and 10.0.0.1
546         #
547         self.vapi.cli("clear trace")
548         tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
549         self.pg0.add_stream(tx)
550
551         self.pg_enable_capture(self.pg_interfaces)
552         self.pg_start()
553
554         rx = self.pg0.get_capture()
555         self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32, 44])
556
557         #
558         # add a recursive path, with 2 labels, via the 3 label route
559         #
560         route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
561                                     [VppRoutePath("10.0.0.2",
562                                                   0xffffffff,
563                                                   labels=[44, 45])])
564         route_11_0_0_2.add_vpp_config()
565
566         #
567         # a stream that matches the route for 11.0.0.1, should pick up
568         # the label stack for 11.0.0.1 and 10.0.0.1
569         #
570         self.vapi.cli("clear trace")
571         tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
572         self.pg0.add_stream(tx)
573
574         self.pg_enable_capture(self.pg_interfaces)
575         self.pg_start()
576
577         rx = self.pg0.get_capture()
578         self.verify_capture_labelled_ip4(
579             self.pg0, rx, tx, [32, 33, 34, 44, 45])
580
581         #
582         # cleanup
583         #
584         route_11_0_0_2.remove_vpp_config()
585         route_11_0_0_1.remove_vpp_config()
586         route_10_0_0_2.remove_vpp_config()
587         route_10_0_0_1.remove_vpp_config()
588
589     def test_tunnel(self):
590         """ MPLS Tunnel Tests """
591
592         #
593         # Create a tunnel with a single out label
594         #
595         mpls_tun = VppMPLSTunnelInterface(self,
596                                           [VppRoutePath(self.pg0.remote_ip4,
597                                                         self.pg0.sw_if_index,
598                                                         labels=[44, 46])])
599         mpls_tun.add_vpp_config()
600         mpls_tun.admin_up()
601
602         #
603         # add an unlabelled route through the new tunnel
604         #
605         route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
606                                     [VppRoutePath("0.0.0.0",
607                                                   mpls_tun._sw_if_index)])
608         route_10_0_0_3.add_vpp_config()
609
610         self.vapi.cli("clear trace")
611         tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
612         self.pg0.add_stream(tx)
613
614         self.pg_enable_capture(self.pg_interfaces)
615         self.pg_start()
616
617         rx = self.pg0.get_capture()
618         self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [44, 46])
619
620     def test_v4_exp_null(self):
621         """ MPLS V4 Explicit NULL test """
622
623         #
624         # The first test case has an MPLS TTL of 0
625         # all packet should be dropped
626         #
627         tx = self.create_stream_labelled_ip4(self.pg0, [0], 0)
628         self.pg0.add_stream(tx)
629
630         self.pg_enable_capture(self.pg_interfaces)
631         self.pg_start()
632
633         self.pg0.assert_nothing_captured(remark="MPLS TTL=0 packets forwarded")
634
635         #
636         # a stream with a non-zero MPLS TTL
637         # PG0 is in the default table
638         #
639         tx = self.create_stream_labelled_ip4(self.pg0, [0])
640         self.pg0.add_stream(tx)
641
642         self.pg_enable_capture(self.pg_interfaces)
643         self.pg_start()
644
645         rx = self.pg0.get_capture()
646         self.verify_capture_ip4(self.pg0, rx, tx)
647
648         #
649         # a stream with a non-zero MPLS TTL
650         # PG1 is in table 1
651         # we are ensuring the post-pop lookup occurs in the VRF table
652         #
653         self.vapi.cli("clear trace")
654         tx = self.create_stream_labelled_ip4(self.pg1, [0])
655         self.pg1.add_stream(tx)
656
657         self.pg_enable_capture(self.pg_interfaces)
658         self.pg_start()
659
660         rx = self.pg1.get_capture()
661         self.verify_capture_ip4(self.pg0, rx, tx)
662
663     def test_v6_exp_null(self):
664         """ MPLS V6 Explicit NULL test """
665
666         #
667         # a stream with a non-zero MPLS TTL
668         # PG0 is in the default table
669         #
670         self.vapi.cli("clear trace")
671         tx = self.create_stream_labelled_ip6(self.pg0, 2, 2)
672         self.pg0.add_stream(tx)
673
674         self.pg_enable_capture(self.pg_interfaces)
675         self.pg_start()
676
677         rx = self.pg0.get_capture()
678         self.verify_capture_ip6(self.pg0, rx, tx)
679
680         #
681         # a stream with a non-zero MPLS TTL
682         # PG1 is in table 1
683         # we are ensuring the post-pop lookup occurs in the VRF table
684         #
685         self.vapi.cli("clear trace")
686         tx = self.create_stream_labelled_ip6(self.pg1, 2, 2)
687         self.pg1.add_stream(tx)
688
689         self.pg_enable_capture(self.pg_interfaces)
690         self.pg_start()
691
692         rx = self.pg1.get_capture()
693         self.verify_capture_ip6(self.pg0, rx, tx)
694
695     def test_deag(self):
696         """ MPLS Deagg """
697
698         #
699         # A de-agg route - next-hop lookup in default table
700         #
701         route_34_eos = VppMplsRoute(self, 34, 1,
702                                     [VppRoutePath("0.0.0.0",
703                                                   0xffffffff,
704                                                   nh_table_id=0)])
705         route_34_eos.add_vpp_config()
706
707         #
708         # ping an interface in the default table
709         # PG0 is in the default table
710         #
711         self.vapi.cli("clear trace")
712         tx = self.create_stream_labelled_ip4(self.pg0, [34], ping=1,
713                                              ip_itf=self.pg0)
714         self.pg0.add_stream(tx)
715
716         self.pg_enable_capture(self.pg_interfaces)
717         self.pg_start()
718
719         rx = self.pg0.get_capture()
720         self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
721
722         #
723         # A de-agg route - next-hop lookup in non-default table
724         #
725         route_35_eos = VppMplsRoute(self, 35, 1,
726                                     [VppRoutePath("0.0.0.0",
727                                                   0xffffffff,
728                                                   nh_table_id=1)])
729         route_35_eos.add_vpp_config()
730
731         #
732         # ping an interface in the non-default table
733         # PG0 is in the default table. packet arrive labelled in the
734         # default table and egress unlabelled in the non-default
735         #
736         self.vapi.cli("clear trace")
737         tx = self.create_stream_labelled_ip4(
738             self.pg0, [35], ping=1, ip_itf=self.pg1)
739         self.pg0.add_stream(tx)
740
741         self.pg_enable_capture(self.pg_interfaces)
742         self.pg_start()
743
744         packet_count = self.get_packet_count_for_if_idx(self.pg0.sw_if_index)
745         rx = self.pg1.get_capture(packet_count)
746         self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
747
748         route_35_eos.remove_vpp_config()
749         route_34_eos.remove_vpp_config()
750
751     def test_interface_rx(self):
752         """ MPLS Interface Receive """
753
754         #
755         # Add a non-recursive route that will forward the traffic
756         # post-interface-rx
757         #
758         route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
759                                     table_id=1,
760                                     paths=[VppRoutePath(self.pg1.remote_ip4,
761                                                         self.pg1.sw_if_index)])
762         route_10_0_0_1.add_vpp_config()
763
764         #
765         # An interface receive label that maps traffic to RX on interface
766         # pg1
767         # by injecting the packet in on pg0, which is in table 0
768         # doing an interface-rx on pg1 and matching a route in table 1
769         # if the packet egresses, then we must have swapped to pg1
770         # so as to have matched the route in table 1
771         #
772         route_34_eos = VppMplsRoute(self, 34, 1,
773                                     [VppRoutePath("0.0.0.0",
774                                                   self.pg1.sw_if_index,
775                                                   is_interface_rx=1)])
776         route_34_eos.add_vpp_config()
777
778         #
779         # ping an interface in the default table
780         # PG0 is in the default table
781         #
782         self.vapi.cli("clear trace")
783         tx = self.create_stream_labelled_ip4(self.pg0, [34], n=257,
784                                              dst_ip="10.0.0.1")
785         self.pg0.add_stream(tx)
786
787         self.pg_enable_capture(self.pg_interfaces)
788         self.pg_start()
789
790         rx = self.pg1.get_capture(257)
791         self.verify_capture_ip4(self.pg1, rx, tx)
792
793     def test_mcast_mid_point(self):
794         """ MPLS Multicast Mid Point """
795
796         #
797         # Add a non-recursive route that will forward the traffic
798         # post-interface-rx
799         #
800         route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
801                                     table_id=1,
802                                     paths=[VppRoutePath(self.pg1.remote_ip4,
803                                                         self.pg1.sw_if_index)])
804         route_10_0_0_1.add_vpp_config()
805
806         #
807         # Add a mcast entry that replicate to pg2 and pg3
808         # and replicate to a interface-rx (like a bud node would)
809         #
810         route_3400_eos = VppMplsRoute(self, 3400, 1,
811                                       [VppRoutePath(self.pg2.remote_ip4,
812                                                     self.pg2.sw_if_index,
813                                                     labels=[3401]),
814                                        VppRoutePath(self.pg3.remote_ip4,
815                                                     self.pg3.sw_if_index,
816                                                     labels=[3402]),
817                                        VppRoutePath("0.0.0.0",
818                                                     self.pg1.sw_if_index,
819                                                     is_interface_rx=1)],
820                                       is_multicast=1)
821         route_3400_eos.add_vpp_config()
822
823         #
824         # ping an interface in the default table
825         # PG0 is in the default table
826         #
827         self.vapi.cli("clear trace")
828         tx = self.create_stream_labelled_ip4(self.pg0, [3400], n=257,
829                                              dst_ip="10.0.0.1")
830         self.pg0.add_stream(tx)
831
832         self.pg_enable_capture(self.pg_interfaces)
833         self.pg_start()
834
835         rx = self.pg1.get_capture(257)
836         self.verify_capture_ip4(self.pg1, rx, tx)
837
838         rx = self.pg2.get_capture(257)
839         self.verify_capture_labelled(self.pg2, rx, tx, [3401])
840         rx = self.pg3.get_capture(257)
841         self.verify_capture_labelled(self.pg3, rx, tx, [3402])
842
843     def test_mcast_head(self):
844         """ MPLS Multicast Head-end """
845
846         #
847         # Create a multicast tunnel with two replications
848         #
849         mpls_tun = VppMPLSTunnelInterface(self,
850                                           [VppRoutePath(self.pg2.remote_ip4,
851                                                         self.pg2.sw_if_index,
852                                                         labels=[42]),
853                                            VppRoutePath(self.pg3.remote_ip4,
854                                                         self.pg3.sw_if_index,
855                                                         labels=[43])],
856                                           is_multicast=1)
857         mpls_tun.add_vpp_config()
858         mpls_tun.admin_up()
859
860         #
861         # add an unlabelled route through the new tunnel
862         #
863         route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
864                                     [VppRoutePath("0.0.0.0",
865                                                   mpls_tun._sw_if_index)])
866         route_10_0_0_3.add_vpp_config()
867
868         self.vapi.cli("clear trace")
869         tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
870         self.pg0.add_stream(tx)
871
872         self.pg_enable_capture(self.pg_interfaces)
873         self.pg_start()
874
875         rx = self.pg2.get_capture(257)
876         self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [42])
877         rx = self.pg3.get_capture(257)
878         self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [43])
879
880         #
881         # An an IP multicast route via the tunnel
882         # A (*,G).
883         # one accepting interface, pg0, 1 forwarding interface via the tunnel
884         #
885         route_232_1_1_1 = VppIpMRoute(
886             self,
887             "0.0.0.0",
888             "232.1.1.1", 32,
889             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
890             [VppMRoutePath(self.pg0.sw_if_index,
891                            MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
892              VppMRoutePath(mpls_tun._sw_if_index,
893                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
894         route_232_1_1_1.add_vpp_config()
895
896         self.vapi.cli("clear trace")
897         tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
898         self.pg0.add_stream(tx)
899
900         self.pg_enable_capture(self.pg_interfaces)
901         self.pg_start()
902
903         rx = self.pg2.get_capture(257)
904         self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [42])
905         rx = self.pg3.get_capture(257)
906         self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [43])
907
908     def test_mcast_tail(self):
909         """ MPLS Multicast Tail """
910
911         #
912         # Add a multicast route that will forward the traffic
913         # post-disposition
914         #
915         route_232_1_1_1 = VppIpMRoute(
916             self,
917             "0.0.0.0",
918             "232.1.1.1", 32,
919             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
920             table_id=1,
921             paths=[VppMRoutePath(self.pg1.sw_if_index,
922                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
923         route_232_1_1_1.add_vpp_config()
924
925         #
926         # An interface receive label that maps traffic to RX on interface
927         # pg1
928         # by injecting the packet in on pg0, which is in table 0
929         # doing an rpf-id  and matching a route in table 1
930         # if the packet egresses, then we must have matched the route in
931         # table 1
932         #
933         route_34_eos = VppMplsRoute(self, 34, 1,
934                                     [VppRoutePath("0.0.0.0",
935                                                   self.pg1.sw_if_index,
936                                                   nh_table_id=1,
937                                                   rpf_id=55)],
938                                     is_multicast=1)
939
940         route_34_eos.add_vpp_config()
941
942         #
943         # Drop due to interface lookup miss
944         #
945         self.vapi.cli("clear trace")
946         tx = self.create_stream_labelled_ip4(self.pg0, [34],
947                                              dst_ip="232.1.1.1", n=1)
948         self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
949
950         #
951         # set the RPF-ID of the enrtry to match the input packet's
952         #
953         route_232_1_1_1.update_rpf_id(55)
954
955         self.vapi.cli("clear trace")
956         tx = self.create_stream_labelled_ip4(self.pg0, [34],
957                                              dst_ip="232.1.1.1", n=257)
958         self.pg0.add_stream(tx)
959
960         self.pg_enable_capture(self.pg_interfaces)
961         self.pg_start()
962
963         rx = self.pg1.get_capture(257)
964         self.verify_capture_ip4(self.pg1, rx, tx)
965
966         #
967         # set the RPF-ID of the enrtry to not match the input packet's
968         #
969         route_232_1_1_1.update_rpf_id(56)
970         tx = self.create_stream_labelled_ip4(self.pg0, [34],
971                                              dst_ip="232.1.1.1")
972         self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
973
974
975 class TestMPLSDisabled(VppTestCase):
976     """ MPLS disabled """
977
978     def setUp(self):
979         super(TestMPLSDisabled, self).setUp()
980
981         # create 2 pg interfaces
982         self.create_pg_interfaces(range(2))
983
984         # PG0 is MPLS enalbed
985         self.pg0.admin_up()
986         self.pg0.config_ip4()
987         self.pg0.resolve_arp()
988         self.pg0.enable_mpls()
989
990         # PG 1 is not MPLS enabled
991         self.pg1.admin_up()
992
993     def tearDown(self):
994         super(TestMPLSDisabled, self).tearDown()
995         for i in self.pg_interfaces:
996             i.unconfig_ip4()
997             i.admin_down()
998
999     def send_and_assert_no_replies(self, intf, pkts, remark):
1000         intf.add_stream(pkts)
1001         self.pg_enable_capture(self.pg_interfaces)
1002         self.pg_start()
1003         for i in self.pg_interfaces:
1004             i.get_capture(0)
1005             i.assert_nothing_captured(remark=remark)
1006
1007     def test_mpls_disabled(self):
1008         """ MPLS Disabled """
1009
1010         tx = (Ether(src=self.pg1.remote_mac,
1011                     dst=self.pg1.local_mac) /
1012               MPLS(label=32, ttl=64) /
1013               IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1014               UDP(sport=1234, dport=1234) /
1015               Raw('\xa5' * 100))
1016
1017         #
1018         # A simple MPLS xconnect - eos label in label out
1019         #
1020         route_32_eos = VppMplsRoute(self, 32, 1,
1021                                     [VppRoutePath(self.pg0.remote_ip4,
1022                                                   self.pg0.sw_if_index,
1023                                                   labels=[33])])
1024         route_32_eos.add_vpp_config()
1025
1026         #
1027         # PG1 does not forward IP traffic
1028         #
1029         self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1030
1031         #
1032         # MPLS enable PG1
1033         #
1034         self.pg1.enable_mpls()
1035
1036         #
1037         # Now we get packets through
1038         #
1039         self.pg1.add_stream(tx)
1040         self.pg_enable_capture(self.pg_interfaces)
1041         self.pg_start()
1042
1043         rx = self.pg0.get_capture(1)
1044
1045         #
1046         # Disable PG1
1047         #
1048         self.pg1.disable_mpls()
1049
1050         #
1051         # PG1 does not forward IP traffic
1052         #
1053         self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1054         self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1055
1056
1057 class TestMPLSPIC(VppTestCase):
1058     """ MPLS PIC edge convergence """
1059
1060     def setUp(self):
1061         super(TestMPLSPIC, self).setUp()
1062
1063         # create 2 pg interfaces
1064         self.create_pg_interfaces(range(4))
1065
1066         # core links
1067         self.pg0.admin_up()
1068         self.pg0.config_ip4()
1069         self.pg0.resolve_arp()
1070         self.pg0.enable_mpls()
1071         self.pg1.admin_up()
1072         self.pg1.config_ip4()
1073         self.pg1.resolve_arp()
1074         self.pg1.enable_mpls()
1075
1076         # VRF (customer facing) link
1077         self.pg2.admin_up()
1078         self.pg2.set_table_ip4(1)
1079         self.pg2.config_ip4()
1080         self.pg2.resolve_arp()
1081         self.pg2.set_table_ip6(1)
1082         self.pg2.config_ip6()
1083         self.pg2.resolve_ndp()
1084         self.pg3.admin_up()
1085         self.pg3.set_table_ip4(1)
1086         self.pg3.config_ip4()
1087         self.pg3.resolve_arp()
1088         self.pg3.set_table_ip6(1)
1089         self.pg3.config_ip6()
1090         self.pg3.resolve_ndp()
1091
1092     def tearDown(self):
1093         super(TestMPLSPIC, self).tearDown()
1094         self.pg0.disable_mpls()
1095         for i in self.pg_interfaces:
1096             i.unconfig_ip4()
1097             i.unconfig_ip6()
1098             i.set_table_ip4(0)
1099             i.set_table_ip6(0)
1100             i.admin_down()
1101
1102     def test_mpls_ibgp_pic(self):
1103         """ MPLS iBGP PIC edge convergence
1104
1105         1) setup many iBGP VPN routes via a pair of iBGP peers.
1106         2) Check EMCP forwarding to these peers
1107         3) withdraw the IGP route to one of these peers.
1108         4) check forwarding continues to the remaining peer
1109         """
1110
1111         #
1112         # IGP+LDP core routes
1113         #
1114         core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1115                                     [VppRoutePath(self.pg0.remote_ip4,
1116                                                   self.pg0.sw_if_index,
1117                                                   labels=[45])])
1118         core_10_0_0_45.add_vpp_config()
1119
1120         core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1121                                     [VppRoutePath(self.pg1.remote_ip4,
1122                                                   self.pg1.sw_if_index,
1123                                                   labels=[46])])
1124         core_10_0_0_46.add_vpp_config()
1125
1126         #
1127         # Lot's of VPN routes. We need more the 64 so VPP will build
1128         # the fast convergence indirection
1129         #
1130         vpn_routes = []
1131         pkts = []
1132         for ii in range(64):
1133             dst = "192.168.1.%d" % ii
1134             vpn_routes.append(VppIpRoute(self, dst, 32,
1135                                          [VppRoutePath("10.0.0.45",
1136                                                        0xffffffff,
1137                                                        labels=[145],
1138                                                        is_resolve_host=1),
1139                                           VppRoutePath("10.0.0.46",
1140                                                        0xffffffff,
1141                                                        labels=[146],
1142                                                        is_resolve_host=1)],
1143                                          table_id=1))
1144             vpn_routes[ii].add_vpp_config()
1145
1146             pkts.append(Ether(dst=self.pg2.local_mac,
1147                               src=self.pg2.remote_mac) /
1148                         IP(src=self.pg2.remote_ip4, dst=dst) /
1149                         UDP(sport=1234, dport=1234) /
1150                         Raw('\xa5' * 100))
1151
1152         #
1153         # Send the packet stream (one pkt to each VPN route)
1154         #  - expect a 50-50 split of the traffic
1155         #
1156         self.pg2.add_stream(pkts)
1157         self.pg_enable_capture(self.pg_interfaces)
1158         self.pg_start()
1159
1160         rx0 = self.pg0._get_capture(1)
1161         rx1 = self.pg1._get_capture(1)
1162
1163         # not testig the LB hashing algorithm so we're not concerned
1164         # with the split ratio, just as long as neither is 0
1165         self.assertNotEqual(0, len(rx0))
1166         self.assertNotEqual(0, len(rx1))
1167
1168         #
1169         # use a test CLI command to stop the FIB walk process, this
1170         # will prevent the FIB converging the VPN routes and thus allow
1171         # us to probe the interim (psot-fail, pre-converge) state
1172         #
1173         self.vapi.ppcli("test fib-walk-process disable")
1174
1175         #
1176         # Withdraw one of the IGP routes
1177         #
1178         core_10_0_0_46.remove_vpp_config()
1179
1180         #
1181         # now all packets should be forwarded through the remaining peer
1182         #
1183         self.vapi.ppcli("clear trace")
1184         self.pg2.add_stream(pkts)
1185         self.pg_enable_capture(self.pg_interfaces)
1186         self.pg_start()
1187
1188         rx0 = self.pg0.get_capture(len(pkts))
1189
1190         #
1191         # enable the FIB walk process to converge the FIB
1192         #
1193         self.vapi.ppcli("test fib-walk-process enable")
1194
1195         #
1196         # packets should still be forwarded through the remaining peer
1197         #
1198         self.pg2.add_stream(pkts)
1199         self.pg_enable_capture(self.pg_interfaces)
1200         self.pg_start()
1201
1202         rx0 = self.pg0.get_capture(64)
1203
1204         #
1205         # Add the IGP route back and we return to load-balancing
1206         #
1207         core_10_0_0_46.add_vpp_config()
1208
1209         self.pg2.add_stream(pkts)
1210         self.pg_enable_capture(self.pg_interfaces)
1211         self.pg_start()
1212
1213         rx0 = self.pg0._get_capture(1)
1214         rx1 = self.pg1._get_capture(1)
1215         self.assertNotEqual(0, len(rx0))
1216         self.assertNotEqual(0, len(rx1))
1217
1218     def test_mpls_ebgp_pic(self):
1219         """ MPLS eBGP PIC edge convergence
1220
1221         1) setup many eBGP VPN routes via a pair of eBGP peers
1222         2) Check EMCP forwarding to these peers
1223         3) withdraw one eBGP path - expect LB across remaining eBGP
1224         """
1225
1226         #
1227         # Lot's of VPN routes. We need more the 64 so VPP will build
1228         # the fast convergence indirection
1229         #
1230         vpn_routes = []
1231         vpn_bindings = []
1232         pkts = []
1233         for ii in range(64):
1234             dst = "192.168.1.%d" % ii
1235             local_label = 1600 + ii
1236             vpn_routes.append(VppIpRoute(self, dst, 32,
1237                                          [VppRoutePath(self.pg2.remote_ip4,
1238                                                        0xffffffff,
1239                                                        nh_table_id=1,
1240                                                        is_resolve_attached=1),
1241                                           VppRoutePath(self.pg3.remote_ip4,
1242                                                        0xffffffff,
1243                                                        nh_table_id=1,
1244                                                        is_resolve_attached=1)],
1245                                          table_id=1))
1246             vpn_routes[ii].add_vpp_config()
1247
1248             vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1249                                               ip_table_id=1))
1250             vpn_bindings[ii].add_vpp_config()
1251
1252             pkts.append(Ether(dst=self.pg0.local_mac,
1253                               src=self.pg0.remote_mac) /
1254                         MPLS(label=local_label, ttl=64) /
1255                         IP(src=self.pg0.remote_ip4, dst=dst) /
1256                         UDP(sport=1234, dport=1234) /
1257                         Raw('\xa5' * 100))
1258
1259         self.pg0.add_stream(pkts)
1260         self.pg_enable_capture(self.pg_interfaces)
1261         self.pg_start()
1262
1263         rx0 = self.pg2._get_capture(1)
1264         rx1 = self.pg3._get_capture(1)
1265         self.assertNotEqual(0, len(rx0))
1266         self.assertNotEqual(0, len(rx1))
1267
1268         #
1269         # use a test CLI command to stop the FIB walk process, this
1270         # will prevent the FIB converging the VPN routes and thus allow
1271         # us to probe the interim (psot-fail, pre-converge) state
1272         #
1273         self.vapi.ppcli("test fib-walk-process disable")
1274
1275         #
1276         # withdraw the connected prefix on the interface.
1277         #
1278         self.pg2.unconfig_ip4()
1279
1280         #
1281         # now all packets should be forwarded through the remaining peer
1282         #
1283         self.pg0.add_stream(pkts)
1284         self.pg_enable_capture(self.pg_interfaces)
1285         self.pg_start()
1286
1287         rx0 = self.pg3.get_capture(len(pkts))
1288
1289         #
1290         # enable the FIB walk process to converge the FIB
1291         #
1292         self.vapi.ppcli("test fib-walk-process enable")
1293         self.pg0.add_stream(pkts)
1294         self.pg_enable_capture(self.pg_interfaces)
1295         self.pg_start()
1296
1297         rx0 = self.pg3.get_capture(len(pkts))
1298
1299         #
1300         # put the connecteds back
1301         #
1302         self.pg2.config_ip4()
1303
1304         self.pg0.add_stream(pkts)
1305         self.pg_enable_capture(self.pg_interfaces)
1306         self.pg_start()
1307
1308         rx0 = self.pg2._get_capture(1)
1309         rx1 = self.pg3._get_capture(1)
1310         self.assertNotEqual(0, len(rx0))
1311         self.assertNotEqual(0, len(rx1))
1312
1313     def test_mpls_v6_ebgp_pic(self):
1314         """ MPLSv6 eBGP PIC edge convergence
1315
1316         1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1317         2) Check EMCP forwarding to these peers
1318         3) withdraw one eBGP path - expect LB across remaining eBGP
1319         """
1320
1321         #
1322         # Lot's of VPN routes. We need more the 64 so VPP will build
1323         # the fast convergence indirection
1324         #
1325         vpn_routes = []
1326         vpn_bindings = []
1327         pkts = []
1328         for ii in range(64):
1329             dst = "3000::%d" % ii
1330             local_label = 1600 + ii
1331             vpn_routes.append(VppIpRoute(self, dst, 128,
1332                                          [VppRoutePath(self.pg2.remote_ip6,
1333                                                        0xffffffff,
1334                                                        nh_table_id=1,
1335                                                        is_resolve_attached=1,
1336                                                        is_ip6=1),
1337                                           VppRoutePath(self.pg3.remote_ip6,
1338                                                        0xffffffff,
1339                                                        nh_table_id=1,
1340                                                        is_ip6=1,
1341                                                        is_resolve_attached=1)],
1342                                          table_id=1,
1343                                          is_ip6=1))
1344             vpn_routes[ii].add_vpp_config()
1345
1346             vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1347                                               ip_table_id=1,
1348                                               is_ip6=1))
1349             vpn_bindings[ii].add_vpp_config()
1350
1351             pkts.append(Ether(dst=self.pg0.local_mac,
1352                               src=self.pg0.remote_mac) /
1353                         MPLS(label=local_label, ttl=64) /
1354                         IPv6(src=self.pg0.remote_ip6, dst=dst) /
1355                         UDP(sport=1234, dport=1234) /
1356                         Raw('\xa5' * 100))
1357
1358         self.pg0.add_stream(pkts)
1359         self.pg_enable_capture(self.pg_interfaces)
1360         self.pg_start()
1361
1362         rx0 = self.pg2._get_capture(1)
1363         rx1 = self.pg3._get_capture(1)
1364         self.assertNotEqual(0, len(rx0))
1365         self.assertNotEqual(0, len(rx1))
1366
1367         #
1368         # use a test CLI command to stop the FIB walk process, this
1369         # will prevent the FIB converging the VPN routes and thus allow
1370         # us to probe the interim (psot-fail, pre-converge) state
1371         #
1372         self.vapi.ppcli("test fib-walk-process disable")
1373
1374         #
1375         # withdraw the connected prefix on the interface.
1376         # and shutdown the interface so the ND cache is flushed.
1377         #
1378         self.pg2.unconfig_ip6()
1379         self.pg2.admin_down()
1380
1381         #
1382         # now all packets should be forwarded through the remaining peer
1383         #
1384         self.pg0.add_stream(pkts)
1385         self.pg_enable_capture(self.pg_interfaces)
1386         self.pg_start()
1387
1388         rx0 = self.pg3.get_capture(len(pkts))
1389
1390         #
1391         # enable the FIB walk process to converge the FIB
1392         #
1393         self.vapi.ppcli("test fib-walk-process enable")
1394         self.pg0.add_stream(pkts)
1395         self.pg_enable_capture(self.pg_interfaces)
1396         self.pg_start()
1397
1398         rx0 = self.pg3.get_capture(len(pkts))
1399
1400         #
1401         # put the connecteds back
1402         #
1403         self.pg2.admin_up()
1404         self.pg2.config_ip6()
1405
1406         self.pg0.add_stream(pkts)
1407         self.pg_enable_capture(self.pg_interfaces)
1408         self.pg_start()
1409
1410         rx0 = self.pg2._get_capture(1)
1411         rx1 = self.pg3._get_capture(1)
1412         self.assertNotEqual(0, len(rx0))
1413         self.assertNotEqual(0, len(rx1))
1414
1415
1416 if __name__ == '__main__':
1417     unittest.main(testRunner=VppTestRunner)