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