Ping response in a VRF context uses correct FIB for response
[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 IpRoute, RoutePath, MplsRoute, MplsIpBind
8
9 from scapy.packet import Raw
10 from scapy.layers.l2 import Ether
11 from scapy.layers.inet import IP, UDP, ICMP
12 from scapy.layers.inet6 import IPv6
13 from scapy.contrib.mpls import MPLS
14 from util import ppp
15
16
17 class TestMPLS(VppTestCase):
18     """ MPLS Test Case """
19
20     @classmethod
21     def setUpClass(cls):
22         super(TestMPLS, cls).setUpClass()
23
24     def setUp(self):
25         super(TestMPLS, self).setUp()
26
27         # create 2 pg interfaces
28         self.create_pg_interfaces(range(2))
29
30         # setup both interfaces
31         # assign them different tables.
32         table_id = 0
33
34         for i in self.pg_interfaces:
35             i.admin_up()
36             i.set_table_ip4(table_id)
37             i.set_table_ip6(table_id)
38             i.config_ip4()
39             i.resolve_arp()
40             i.config_ip6()
41             i.resolve_ndp()
42             i.enable_mpls()
43             table_id += 1
44
45     def tearDown(self):
46         super(TestMPLS, self).tearDown()
47
48     # the default of 64 matches the IP packet TTL default
49     def create_stream_labelled_ip4(self, src_if, mpls_labels, mpls_ttl=255, ping=0, ip_itf=None):
50         pkts = []
51         for i in range(0, 257):
52             info = self.create_packet_info(src_if.sw_if_index,
53                                            src_if.sw_if_index)
54             payload = self.info_to_payload(info)
55             p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
56
57             for ii in range(len(mpls_labels)):
58                 if ii == len(mpls_labels) - 1:
59                     p = p / MPLS(label=mpls_labels[ii], ttl=mpls_ttl, s=1)
60                 else:
61                     p = p / MPLS(label=mpls_labels[ii], ttl=mpls_ttl, s=0)
62             if not ping:
63                 p = (p / IP(src=src_if.local_ip4, dst=src_if.remote_ip4) / 
64                      UDP(sport=1234, dport=1234) /
65                      Raw(payload))
66             else:
67                 p = (p / IP(src=ip_itf.remote_ip4,
68                             dst=ip_itf.local_ip4) /
69                      ICMP())
70
71             info.data = p.copy()
72             pkts.append(p)
73         return pkts
74
75     def create_stream_ip4(self, src_if, dst_ip):
76         pkts = []
77         for i in range(0, 257):
78             info = self.create_packet_info(src_if.sw_if_index,
79                                            src_if.sw_if_index)
80             payload = self.info_to_payload(info)
81             p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
82                  IP(src=src_if.remote_ip4, dst=dst_ip) /
83                  UDP(sport=1234, dport=1234) /
84                  Raw(payload))
85             info.data = p.copy()
86             pkts.append(p)
87         return pkts
88
89     def create_stream_labelled_ip6(self, src_if, mpls_label, mpls_ttl):
90         pkts = []
91         for i in range(0, 257):
92             info = self.create_packet_info(src_if.sw_if_index,
93                                            src_if.sw_if_index)
94             payload = self.info_to_payload(info)
95             p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
96                  MPLS(label=mpls_label, ttl=mpls_ttl) /
97                  IPv6(src=src_if.remote_ip6, dst=src_if.remote_ip6) /
98                  UDP(sport=1234, dport=1234) /
99                  Raw(payload))
100             info.data = p.copy()
101             pkts.append(p)
102         return pkts
103
104     @staticmethod
105     def verify_filter(capture, sent):
106         if not len(capture) == len(sent):
107             # filter out any IPv6 RAs from the capture
108             for p in capture:
109                 if p.haslayer(IPv6):
110                     capture.remove(p)
111         return capture
112
113     def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0):
114         try:
115             capture = self.verify_filter(capture, sent)
116
117             self.assertEqual(len(capture), len(sent))
118
119             for i in range(len(capture)):
120                 tx = sent[i]
121                 rx = capture[i]
122
123                 # the rx'd packet has the MPLS label popped
124                 eth = rx[Ether]
125                 self.assertEqual(eth.type, 0x800)
126
127                 tx_ip = tx[IP]
128                 rx_ip = rx[IP]
129
130                 if not ping_resp:
131                     self.assertEqual(rx_ip.src, tx_ip.src)
132                     self.assertEqual(rx_ip.dst, tx_ip.dst)
133                     # IP processing post pop has decremented the TTL
134                     self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
135                 else:
136                     self.assertEqual(rx_ip.src, tx_ip.dst)
137                     self.assertEqual(rx_ip.dst, tx_ip.src)
138
139         except:
140             raise
141
142     def verify_mpls_stack(self, rx, mpls_labels, ttl=255, num=0):
143         # the rx'd packet has the MPLS label popped
144         eth = rx[Ether]
145         self.assertEqual(eth.type, 0x8847)
146
147         rx_mpls = rx[MPLS]
148
149         for ii in range(len(mpls_labels)):
150             self.assertEqual(rx_mpls.label, mpls_labels[ii])
151             self.assertEqual(rx_mpls.cos, 0)
152             if ii == num:
153                 self.assertEqual(rx_mpls.ttl, ttl)
154             else:
155                 self.assertEqual(rx_mpls.ttl, 255)
156
157             if ii == len(mpls_labels) - 1:
158                 self.assertEqual(rx_mpls.s, 1)
159             else:
160                 # not end of stack
161                 self.assertEqual(rx_mpls.s, 0)
162                 # pop the label to expose the next
163                 rx_mpls = rx_mpls[MPLS].payload
164
165     def verify_capture_labelled_ip4(self, src_if, capture, sent,
166                                     mpls_labels):
167         try:
168             capture = self.verify_filter(capture, sent)
169
170             self.assertEqual(len(capture), len(sent))
171
172             for i in range(len(capture)):
173                 tx = sent[i]
174                 rx = capture[i]
175                 tx_ip = tx[IP]
176                 rx_ip = rx[IP]
177
178                 # the MPLS TTL is copied from the IP
179                 self.verify_mpls_stack(
180                     rx, mpls_labels, rx_ip.ttl, len(mpls_labels) - 1)
181
182                 self.assertEqual(rx_ip.src, tx_ip.src)
183                 self.assertEqual(rx_ip.dst, tx_ip.dst)
184                 # IP processing post pop has decremented the TTL
185                 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
186
187         except:
188             raise
189
190     def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
191         try:
192             capture = self.verify_filter(capture, sent)
193
194             self.assertEqual(len(capture), len(sent))
195
196             for i in range(len(capture)):
197                 tx = sent[i]
198                 rx = capture[i]
199                 tx_ip = tx[IP]
200                 rx_ip = rx[IP]
201
202                 # the MPLS TTL is 255 since it enters a new tunnel
203                 self.verify_mpls_stack(
204                     rx, mpls_labels, 255, len(mpls_labels) - 1)
205
206                 self.assertEqual(rx_ip.src, tx_ip.src)
207                 self.assertEqual(rx_ip.dst, tx_ip.dst)
208                 # IP processing post pop has decremented the TTL
209                 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
210
211         except:
212             raise
213
214     def verify_capture_labelled(self, src_if, capture, sent,
215                                 mpls_labels, ttl=254, num=0):
216         try:
217             capture = self.verify_filter(capture, sent)
218
219             self.assertEqual(len(capture), len(sent))
220
221             for i in range(len(capture)):
222                 rx = capture[i]
223                 self.verify_mpls_stack(rx, mpls_labels, ttl, num)
224         except:
225             raise
226
227     def verify_capture_ip6(self, src_if, capture, sent):
228         try:
229             self.assertEqual(len(capture), len(sent))
230
231             for i in range(len(capture)):
232                 tx = sent[i]
233                 rx = capture[i]
234
235                 # the rx'd packet has the MPLS label popped
236                 eth = rx[Ether]
237                 self.assertEqual(eth.type, 0x86DD)
238
239                 tx_ip = tx[IPv6]
240                 rx_ip = rx[IPv6]
241
242                 self.assertEqual(rx_ip.src, tx_ip.src)
243                 self.assertEqual(rx_ip.dst, tx_ip.dst)
244                 # IP processing post pop has decremented the TTL
245                 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
246
247         except:
248             raise
249
250     def test_swap(self):
251         """ MPLS label swap tests """
252
253         #
254         # A simple MPLS xconnect - eos label in label out
255         #
256         route_32_eos = MplsRoute(self, 32, 1,
257                                  [RoutePath(self.pg0.remote_ip4,
258                                             self.pg0.sw_if_index,
259                                             labels=[33])])
260         route_32_eos.add_vpp_config()
261
262         #
263         # a stream that matches the route for 10.0.0.1
264         # PG0 is in the default table
265         #
266         self.vapi.cli("clear trace")
267         tx = self.create_stream_labelled_ip4(self.pg0, [32])
268         self.pg0.add_stream(tx)
269
270         self.pg_enable_capture(self.pg_interfaces)
271         self.pg_start()
272
273         rx = self.pg0.get_capture()
274         self.verify_capture_labelled_ip4(self.pg0, rx, tx, [33])
275
276         #
277         # A simple MPLS xconnect - non-eos label in label out
278         #
279         route_32_neos = MplsRoute(self, 32, 0,
280                                   [RoutePath(self.pg0.remote_ip4,
281                                              self.pg0.sw_if_index,
282                                              labels=[33])])
283         route_32_neos.add_vpp_config()
284
285         #
286         # a stream that matches the route for 10.0.0.1
287         # PG0 is in the default table
288         #
289         self.vapi.cli("clear trace")
290         tx = self.create_stream_labelled_ip4(self.pg0, [32, 99])
291         self.pg0.add_stream(tx)
292
293         self.pg_enable_capture(self.pg_interfaces)
294         self.pg_start()
295
296         rx = self.pg0.get_capture()
297         self.verify_capture_labelled(self.pg0, rx, tx, [33, 99])
298
299         #
300         # An MPLS xconnect - EOS label in IP out
301         #
302         route_33_eos = MplsRoute(self, 33, 1,
303                                  [RoutePath(self.pg0.remote_ip4,
304                                             self.pg0.sw_if_index,
305                                             labels=[])])
306         route_33_eos.add_vpp_config()
307
308         self.vapi.cli("clear trace")
309         tx = self.create_stream_labelled_ip4(self.pg0, [33])
310         self.pg0.add_stream(tx)
311
312         self.pg_enable_capture(self.pg_interfaces)
313         self.pg_start()
314
315         rx = self.pg0.get_capture()
316         self.verify_capture_ip4(self.pg0, rx, tx)
317
318         #
319         # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
320         # so this traffic should be dropped.
321         #
322         route_33_neos = MplsRoute(self, 33, 0,
323                                   [RoutePath(self.pg0.remote_ip4,
324                                              self.pg0.sw_if_index,
325                                              labels=[])])
326         route_33_neos.add_vpp_config()
327
328         self.vapi.cli("clear trace")
329         tx = self.create_stream_labelled_ip4(self.pg0, [33, 99])
330         self.pg0.add_stream(tx)
331
332         self.pg_enable_capture(self.pg_interfaces)
333         self.pg_start()
334
335         rx = self.pg0.get_capture()
336         try:
337             self.assertEqual(0, len(rx))
338         except:
339             self.logger.error("MPLS non-EOS packets popped and forwarded")
340             self.logger.error(ppp("", rx))
341             raise
342
343         #
344         # A recursive EOS x-connect, which resolves through another x-connect
345         #
346         route_34_eos = MplsRoute(self, 34, 1,
347                                  [RoutePath("0.0.0.0",
348                                             0xffffffff,
349                                             nh_via_label=32,
350                                             labels=[44, 45])])
351         route_34_eos.add_vpp_config()
352
353         self.vapi.cli("clear trace")
354         tx = self.create_stream_labelled_ip4(self.pg0, [34])
355         self.pg0.add_stream(tx)
356
357         self.pg_enable_capture(self.pg_interfaces)
358         self.pg_start()
359
360         rx = self.pg0.get_capture()
361         self.verify_capture_labelled_ip4(self.pg0, rx, tx, [33, 44, 45])
362
363         #
364         # A recursive non-EOS x-connect, which resolves through another
365         # x-connect
366         #
367         route_34_neos = MplsRoute(self, 34, 0,
368                                   [RoutePath("0.0.0.0",
369                                              0xffffffff,
370                                              nh_via_label=32,
371                                              labels=[44, 46])])
372         route_34_neos.add_vpp_config()
373
374         self.vapi.cli("clear trace")
375         tx = self.create_stream_labelled_ip4(self.pg0, [34, 99])
376         self.pg0.add_stream(tx)
377
378         self.pg_enable_capture(self.pg_interfaces)
379         self.pg_start()
380
381         rx = self.pg0.get_capture()
382         # it's the 2nd (counting from 0) label in the stack that is swapped
383         self.verify_capture_labelled(self.pg0, rx, tx, [33, 44, 46, 99], num=2)
384
385         #
386         # an recursive IP route that resolves through the recursive non-eos
387         # x-connect
388         #
389         ip_10_0_0_1 = IpRoute(self, "10.0.0.1", 32,
390                               [RoutePath("0.0.0.0",
391                                          0xffffffff,
392                                          nh_via_label=34,
393                                          labels=[55])])
394         ip_10_0_0_1.add_vpp_config()
395
396         self.vapi.cli("clear trace")
397         tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
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         self.verify_capture_labelled_ip4(self.pg0, rx, tx, [33, 44, 46, 55])
405
406         ip_10_0_0_1.remove_vpp_config()
407         route_34_neos.remove_vpp_config()
408         route_34_eos.remove_vpp_config()
409         route_33_neos.remove_vpp_config()
410         route_33_eos.remove_vpp_config()
411         route_32_neos.remove_vpp_config()
412         route_32_eos.remove_vpp_config()
413
414     def test_bind(self):
415         """ MPLS Local Label Binding test """
416
417         #
418         # Add a non-recursive route with a single out label
419         #
420         route_10_0_0_1 = IpRoute(self, "10.0.0.1", 32,
421                                  [RoutePath(self.pg0.remote_ip4,
422                                             self.pg0.sw_if_index,
423                                             labels=[45])])
424         route_10_0_0_1.add_vpp_config()
425
426         # bind a local label to the route
427         binding = MplsIpBind(self, 44, "10.0.0.1", 32)
428         binding.add_vpp_config()
429
430         # non-EOS stream
431         self.vapi.cli("clear trace")
432         tx = self.create_stream_labelled_ip4(self.pg0, [44, 99])
433         self.pg0.add_stream(tx)
434
435         self.pg_enable_capture(self.pg_interfaces)
436         self.pg_start()
437
438         rx = self.pg0.get_capture()
439         self.verify_capture_labelled(self.pg0, rx, tx, [45, 99])
440
441         # EOS stream
442         self.vapi.cli("clear trace")
443         tx = self.create_stream_labelled_ip4(self.pg0, [44])
444         self.pg0.add_stream(tx)
445
446         self.pg_enable_capture(self.pg_interfaces)
447         self.pg_start()
448
449         rx = self.pg0.get_capture()
450         self.verify_capture_labelled(self.pg0, rx, tx, [45])
451
452         # IP stream
453         self.vapi.cli("clear trace")
454         tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
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_ip4(self.pg0, rx, tx, [45])
462
463         #
464         # cleanup
465         #
466         binding.remove_vpp_config()
467         route_10_0_0_1.remove_vpp_config()
468
469     def test_imposition(self):
470         """ MPLS label imposition test """
471
472         #
473         # Add a non-recursive route with a single out label
474         #
475         route_10_0_0_1 = IpRoute(self, "10.0.0.1", 32,
476                                  [RoutePath(self.pg0.remote_ip4,
477                                             self.pg0.sw_if_index,
478                                             labels=[32])])
479         route_10_0_0_1.add_vpp_config()
480
481         #
482         # a stream that matches the route for 10.0.0.1
483         # PG0 is in the default table
484         #
485         self.vapi.cli("clear trace")
486         tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
487         self.pg0.add_stream(tx)
488
489         self.pg_enable_capture(self.pg_interfaces)
490         self.pg_start()
491
492         rx = self.pg0.get_capture()
493         self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32])
494
495         #
496         # Add a non-recursive route with a 3 out labels
497         #
498         route_10_0_0_2 = IpRoute(self, "10.0.0.2", 32,
499                                  [RoutePath(self.pg0.remote_ip4,
500                                             self.pg0.sw_if_index,
501                                             labels=[32, 33, 34])])
502         route_10_0_0_2.add_vpp_config()
503
504         #
505         # a stream that matches the route for 10.0.0.1
506         # PG0 is in the default table
507         #
508         self.vapi.cli("clear trace")
509         tx = self.create_stream_ip4(self.pg0, "10.0.0.2")
510         self.pg0.add_stream(tx)
511
512         self.pg_enable_capture(self.pg_interfaces)
513         self.pg_start()
514
515         rx = self.pg0.get_capture()
516         self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32, 33, 34])
517
518         #
519         # add a recursive path, with output label, via the 1 label route
520         #
521         route_11_0_0_1 = IpRoute(self, "11.0.0.1", 32,
522                                  [RoutePath("10.0.0.1",
523                                             0xffffffff,
524                                             labels=[44])])
525         route_11_0_0_1.add_vpp_config()
526
527         #
528         # a stream that matches the route for 11.0.0.1, should pick up
529         # the label stack for 11.0.0.1 and 10.0.0.1
530         #
531         self.vapi.cli("clear trace")
532         tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
533         self.pg0.add_stream(tx)
534
535         self.pg_enable_capture(self.pg_interfaces)
536         self.pg_start()
537
538         rx = self.pg0.get_capture()
539         self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32, 44])
540
541         #
542         # add a recursive path, with 2 labels, via the 3 label route
543         #
544         route_11_0_0_2 = IpRoute(self, "11.0.0.2", 32,
545                                  [RoutePath("10.0.0.2",
546                                             0xffffffff,
547                                             labels=[44, 45])])
548         route_11_0_0_2.add_vpp_config()
549
550         #
551         # a stream that matches the route for 11.0.0.1, should pick up
552         # the label stack for 11.0.0.1 and 10.0.0.1
553         #
554         self.vapi.cli("clear trace")
555         tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
556         self.pg0.add_stream(tx)
557
558         self.pg_enable_capture(self.pg_interfaces)
559         self.pg_start()
560
561         rx = self.pg0.get_capture()
562         self.verify_capture_labelled_ip4(
563             self.pg0, rx, tx, [32, 33, 34, 44, 45])
564
565         #
566         # cleanup
567         #
568         route_11_0_0_2.remove_vpp_config()
569         route_11_0_0_1.remove_vpp_config()
570         route_10_0_0_2.remove_vpp_config()
571         route_10_0_0_1.remove_vpp_config()
572
573     def test_tunnel(self):
574         """ MPLS Tunnel Tests """
575
576         #
577         # Create a tunnel with a single out label
578         #
579         nh_addr = socket.inet_pton(socket.AF_INET, self.pg0.remote_ip4)
580
581         reply = self.vapi.mpls_tunnel_add_del(
582             0xffffffff,  # don't know the if index yet
583             1,  # IPv4 next-hop
584             nh_addr,
585             self.pg0.sw_if_index,
586             0,  # next-hop-table-id
587             1,  # next-hop-weight
588             2,  # num-out-labels,
589             [44, 46]
590         )
591         self.vapi.sw_interface_set_flags(reply.sw_if_index, admin_up_down=1)
592
593         #
594         # add an unlabelled route through the new tunnel
595         #
596         dest_addr = socket.inet_pton(socket.AF_INET, "10.0.0.3")
597         nh_addr = socket.inet_pton(socket.AF_INET, "0.0.0.0")
598         dest_addr_len = 32
599
600         self.vapi.ip_add_del_route(
601             dest_addr,
602             dest_addr_len,
603             nh_addr,  # all zeros next-hop - tunnel is p2p
604             reply.sw_if_index,  # sw_if_index of the new tunnel
605             0,  # table-id
606             0,  # next-hop-table-id
607             1,  # next-hop-weight
608             0,  # num-out-labels,
609             []  # out-label
610         )
611
612         self.vapi.cli("clear trace")
613         tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
614         self.pg0.add_stream(tx)
615
616         self.pg_enable_capture(self.pg_interfaces)
617         self.pg_start()
618
619         rx = self.pg0.get_capture()
620         self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [44, 46])
621
622     def test_v4_exp_null(self):
623         """ MPLS V4 Explicit NULL test """
624
625         #
626         # The first test case has an MPLS TTL of 0
627         # all packet should be dropped
628         #
629         tx = self.create_stream_labelled_ip4(self.pg0, [0], 0)
630         self.pg0.add_stream(tx)
631
632         self.pg_enable_capture(self.pg_interfaces)
633         self.pg_start()
634
635         rx = self.pg0.get_capture()
636
637         try:
638             self.assertEqual(0, len(rx))
639         except:
640             self.logger.error("MPLS TTL=0 packets forwarded")
641             self.logger.error(ppp("", rx))
642             raise
643
644         #
645         # a stream with a non-zero MPLS TTL
646         # PG0 is in the default table
647         #
648         self.vapi.cli("clear trace")
649         tx = self.create_stream_labelled_ip4(self.pg0, [0])
650         self.pg0.add_stream(tx)
651
652         self.pg_enable_capture(self.pg_interfaces)
653         self.pg_start()
654
655         rx = self.pg0.get_capture()
656         self.verify_capture_ip4(self.pg0, rx, tx)
657
658         #
659         # a stream with a non-zero MPLS TTL
660         # PG1 is in table 1
661         # we are ensuring the post-pop lookup occurs in the VRF table
662         #
663         self.vapi.cli("clear trace")
664         tx = self.create_stream_labelled_ip4(self.pg1, [0])
665         self.pg1.add_stream(tx)
666
667         self.pg_enable_capture(self.pg_interfaces)
668         self.pg_start()
669
670         rx = self.pg1.get_capture()
671         self.verify_capture_ip4(self.pg0, rx, tx)
672
673     def test_v6_exp_null(self):
674         """ MPLS V6 Explicit NULL test """
675
676         #
677         # a stream with a non-zero MPLS TTL
678         # PG0 is in the default table
679         #
680         self.vapi.cli("clear trace")
681         tx = self.create_stream_labelled_ip6(self.pg0, 2, 2)
682         self.pg0.add_stream(tx)
683
684         self.pg_enable_capture(self.pg_interfaces)
685         self.pg_start()
686
687         rx = self.pg0.get_capture()
688         self.verify_capture_ip6(self.pg0, rx, tx)
689
690         #
691         # a stream with a non-zero MPLS TTL
692         # PG1 is in table 1
693         # we are ensuring the post-pop lookup occurs in the VRF table
694         #
695         self.vapi.cli("clear trace")
696         tx = self.create_stream_labelled_ip6(self.pg1, 2, 2)
697         self.pg1.add_stream(tx)
698
699         self.pg_enable_capture(self.pg_interfaces)
700         self.pg_start()
701
702         rx = self.pg1.get_capture()
703         self.verify_capture_ip6(self.pg0, rx, tx)
704
705     def test_deag(self):
706         """ MPLS Deagg """
707
708         #
709         # A de-agg route - next-hop lookup in default table
710         #
711         route_34_eos = MplsRoute(self, 34, 1,
712                                   [RoutePath("0.0.0.0",
713                                              0xffffffff,
714                                              nh_table_id=0)])
715         route_34_eos.add_vpp_config()
716
717         #
718         # ping an interface in the default table
719         # PG0 is in the default table
720         #
721         self.vapi.cli("clear trace")
722         tx = self.create_stream_labelled_ip4(self.pg0, [34], ping=1,
723                                              ip_itf=self.pg0)
724         self.pg0.add_stream(tx)
725
726         self.pg_enable_capture(self.pg_interfaces)
727         self.pg_start()
728
729         rx = self.pg0.get_capture()
730         self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
731
732         #
733         # A de-agg route - next-hop lookup in non-default table
734         #
735         route_35_eos = MplsRoute(self, 35, 1,
736                                   [RoutePath("0.0.0.0",
737                                              0xffffffff,
738                                              nh_table_id=1)])
739         route_35_eos.add_vpp_config()
740
741         #
742         # ping an interface in the non-default table
743         # PG0 is in the default table. packet arrive labelled in the
744         # default table and egress unlabelled in the non-default
745         #
746         self.vapi.cli("clear trace")
747         tx = self.create_stream_labelled_ip4(self.pg0, [35], ping=1, ip_itf=self.pg1)
748         self.pg0.add_stream(tx)
749
750         self.pg_enable_capture(self.pg_interfaces)
751         self.pg_start()
752
753         rx = self.pg1.get_capture()
754         self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
755
756         route_35_eos.remove_vpp_config()
757         route_34_eos.remove_vpp_config()
758
759 if __name__ == '__main__':
760     unittest.main(testRunner=VppTestRunner)