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