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