Changing the IP table for an interface is an error if the interface already has an...
[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     def setUp(self):
21         super(TestMPLS, self).setUp()
22
23         # create 2 pg interfaces
24         self.create_pg_interfaces(range(2))
25
26         # setup both interfaces
27         # assign them different tables.
28         table_id = 0
29
30         for i in self.pg_interfaces:
31             i.admin_up()
32             i.set_table_ip4(table_id)
33             i.set_table_ip6(table_id)
34             i.config_ip4()
35             i.resolve_arp()
36             i.config_ip6()
37             i.resolve_ndp()
38             i.enable_mpls()
39             table_id += 1
40
41     def tearDown(self):
42         super(TestMPLS, self).tearDown()
43         for i in self.pg_interfaces:
44             i.unconfig_ip4()
45             i.unconfig_ip6()
46             i.ip6_disable()
47             i.admin_down()
48
49     # the default of 64 matches the IP packet TTL default
50     def create_stream_labelled_ip4(
51             self,
52             src_if,
53             mpls_labels,
54             mpls_ttl=255,
55             ping=0,
56             ip_itf=None):
57         self.reset_packet_infos()
58         pkts = []
59         for i in range(0, 257):
60             info = self.create_packet_info(src_if, src_if)
61             payload = self.info_to_payload(info)
62             p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
63
64             for ii in range(len(mpls_labels)):
65                 if ii == len(mpls_labels) - 1:
66                     p = p / MPLS(label=mpls_labels[ii], ttl=mpls_ttl, s=1)
67                 else:
68                     p = p / MPLS(label=mpls_labels[ii], ttl=mpls_ttl, s=0)
69             if not ping:
70                 p = (p / IP(src=src_if.local_ip4, dst=src_if.remote_ip4) /
71                      UDP(sport=1234, dport=1234) /
72                      Raw(payload))
73             else:
74                 p = (p / IP(src=ip_itf.remote_ip4,
75                             dst=ip_itf.local_ip4) /
76                      ICMP())
77
78             info.data = p.copy()
79             pkts.append(p)
80         return pkts
81
82     def create_stream_ip4(self, src_if, dst_ip):
83         self.reset_packet_infos()
84         pkts = []
85         for i in range(0, 257):
86             info = self.create_packet_info(src_if, src_if)
87             payload = self.info_to_payload(info)
88             p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
89                  IP(src=src_if.remote_ip4, dst=dst_ip) /
90                  UDP(sport=1234, dport=1234) /
91                  Raw(payload))
92             info.data = p.copy()
93             pkts.append(p)
94         return pkts
95
96     def create_stream_labelled_ip6(self, src_if, mpls_label, mpls_ttl):
97         self.reset_packet_infos()
98         pkts = []
99         for i in range(0, 257):
100             info = self.create_packet_info(src_if, src_if)
101             payload = self.info_to_payload(info)
102             p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
103                  MPLS(label=mpls_label, ttl=mpls_ttl) /
104                  IPv6(src=src_if.remote_ip6, dst=src_if.remote_ip6) /
105                  UDP(sport=1234, dport=1234) /
106                  Raw(payload))
107             info.data = p.copy()
108             pkts.append(p)
109         return pkts
110
111     @staticmethod
112     def verify_filter(capture, sent):
113         if not len(capture) == len(sent):
114             # filter out any IPv6 RAs from the capture
115             for p in capture:
116                 if p.haslayer(IPv6):
117                     capture.remove(p)
118         return capture
119
120     def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0):
121         try:
122             capture = self.verify_filter(capture, sent)
123
124             self.assertEqual(len(capture), len(sent))
125
126             for i in range(len(capture)):
127                 tx = sent[i]
128                 rx = capture[i]
129
130                 # the rx'd packet has the MPLS label popped
131                 eth = rx[Ether]
132                 self.assertEqual(eth.type, 0x800)
133
134                 tx_ip = tx[IP]
135                 rx_ip = rx[IP]
136
137                 if not ping_resp:
138                     self.assertEqual(rx_ip.src, tx_ip.src)
139                     self.assertEqual(rx_ip.dst, tx_ip.dst)
140                     # IP processing post pop has decremented the TTL
141                     self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
142                 else:
143                     self.assertEqual(rx_ip.src, tx_ip.dst)
144                     self.assertEqual(rx_ip.dst, tx_ip.src)
145
146         except:
147             raise
148
149     def verify_mpls_stack(self, rx, mpls_labels, ttl=255, num=0):
150         # the rx'd packet has the MPLS label popped
151         eth = rx[Ether]
152         self.assertEqual(eth.type, 0x8847)
153
154         rx_mpls = rx[MPLS]
155
156         for ii in range(len(mpls_labels)):
157             self.assertEqual(rx_mpls.label, mpls_labels[ii])
158             self.assertEqual(rx_mpls.cos, 0)
159             if ii == num:
160                 self.assertEqual(rx_mpls.ttl, ttl)
161             else:
162                 self.assertEqual(rx_mpls.ttl, 255)
163
164             if ii == len(mpls_labels) - 1:
165                 self.assertEqual(rx_mpls.s, 1)
166             else:
167                 # not end of stack
168                 self.assertEqual(rx_mpls.s, 0)
169                 # pop the label to expose the next
170                 rx_mpls = rx_mpls[MPLS].payload
171
172     def verify_capture_labelled_ip4(self, src_if, capture, sent,
173                                     mpls_labels):
174         try:
175             capture = self.verify_filter(capture, sent)
176
177             self.assertEqual(len(capture), len(sent))
178
179             for i in range(len(capture)):
180                 tx = sent[i]
181                 rx = capture[i]
182                 tx_ip = tx[IP]
183                 rx_ip = rx[IP]
184
185                 # the MPLS TTL is copied from the IP
186                 self.verify_mpls_stack(
187                     rx, mpls_labels, rx_ip.ttl, len(mpls_labels) - 1)
188
189                 self.assertEqual(rx_ip.src, tx_ip.src)
190                 self.assertEqual(rx_ip.dst, tx_ip.dst)
191                 # IP processing post pop has decremented the TTL
192                 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
193
194         except:
195             raise
196
197     def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
198         try:
199             capture = self.verify_filter(capture, sent)
200
201             self.assertEqual(len(capture), len(sent))
202
203             for i in range(len(capture)):
204                 tx = sent[i]
205                 rx = capture[i]
206                 tx_ip = tx[IP]
207                 rx_ip = rx[IP]
208
209                 # the MPLS TTL is 255 since it enters a new tunnel
210                 self.verify_mpls_stack(
211                     rx, mpls_labels, 255, len(mpls_labels) - 1)
212
213                 self.assertEqual(rx_ip.src, tx_ip.src)
214                 self.assertEqual(rx_ip.dst, tx_ip.dst)
215                 # IP processing post pop has decremented the TTL
216                 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
217
218         except:
219             raise
220
221     def verify_capture_labelled(self, src_if, capture, sent,
222                                 mpls_labels, ttl=254, num=0):
223         try:
224             capture = self.verify_filter(capture, sent)
225
226             self.assertEqual(len(capture), len(sent))
227
228             for i in range(len(capture)):
229                 rx = capture[i]
230                 self.verify_mpls_stack(rx, mpls_labels, ttl, num)
231         except:
232             raise
233
234     def verify_capture_ip6(self, src_if, capture, sent):
235         try:
236             self.assertEqual(len(capture), len(sent))
237
238             for i in range(len(capture)):
239                 tx = sent[i]
240                 rx = capture[i]
241
242                 # the rx'd packet has the MPLS label popped
243                 eth = rx[Ether]
244                 self.assertEqual(eth.type, 0x86DD)
245
246                 tx_ip = tx[IPv6]
247                 rx_ip = rx[IPv6]
248
249                 self.assertEqual(rx_ip.src, tx_ip.src)
250                 self.assertEqual(rx_ip.dst, tx_ip.dst)
251                 # IP processing post pop has decremented the TTL
252                 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
253
254         except:
255             raise
256
257     def test_swap(self):
258         """ MPLS label swap tests """
259
260         #
261         # A simple MPLS xconnect - eos label in label out
262         #
263         route_32_eos = VppMplsRoute(self, 32, 1,
264                                     [VppRoutePath(self.pg0.remote_ip4,
265                                                   self.pg0.sw_if_index,
266                                                   labels=[33])])
267         route_32_eos.add_vpp_config()
268
269         #
270         # a stream that matches the route for 10.0.0.1
271         # PG0 is in the default table
272         #
273         self.vapi.cli("clear trace")
274         tx = self.create_stream_labelled_ip4(self.pg0, [32])
275         self.pg0.add_stream(tx)
276
277         self.pg_enable_capture(self.pg_interfaces)
278         self.pg_start()
279
280         rx = self.pg0.get_capture()
281         self.verify_capture_labelled_ip4(self.pg0, rx, tx, [33])
282
283         #
284         # A simple MPLS xconnect - non-eos label in label out
285         #
286         route_32_neos = VppMplsRoute(self, 32, 0,
287                                      [VppRoutePath(self.pg0.remote_ip4,
288                                                    self.pg0.sw_if_index,
289                                                    labels=[33])])
290         route_32_neos.add_vpp_config()
291
292         #
293         # a stream that matches the route for 10.0.0.1
294         # PG0 is in the default table
295         #
296         self.vapi.cli("clear trace")
297         tx = self.create_stream_labelled_ip4(self.pg0, [32, 99])
298         self.pg0.add_stream(tx)
299
300         self.pg_enable_capture(self.pg_interfaces)
301         self.pg_start()
302
303         rx = self.pg0.get_capture()
304         self.verify_capture_labelled(self.pg0, rx, tx, [33, 99])
305
306         #
307         # An MPLS xconnect - EOS label in IP out
308         #
309         route_33_eos = VppMplsRoute(self, 33, 1,
310                                     [VppRoutePath(self.pg0.remote_ip4,
311                                                   self.pg0.sw_if_index,
312                                                   labels=[])])
313         route_33_eos.add_vpp_config()
314
315         self.vapi.cli("clear trace")
316         tx = self.create_stream_labelled_ip4(self.pg0, [33])
317         self.pg0.add_stream(tx)
318
319         self.pg_enable_capture(self.pg_interfaces)
320         self.pg_start()
321
322         rx = self.pg0.get_capture()
323         self.verify_capture_ip4(self.pg0, rx, tx)
324
325         #
326         # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
327         # so this traffic should be dropped.
328         #
329         route_33_neos = VppMplsRoute(self, 33, 0,
330                                      [VppRoutePath(self.pg0.remote_ip4,
331                                                    self.pg0.sw_if_index,
332                                                    labels=[])])
333         route_33_neos.add_vpp_config()
334
335         self.vapi.cli("clear trace")
336         tx = self.create_stream_labelled_ip4(self.pg0, [33, 99])
337         self.pg0.add_stream(tx)
338
339         self.pg_enable_capture(self.pg_interfaces)
340         self.pg_start()
341         self.pg0.assert_nothing_captured(
342             remark="MPLS non-EOS packets popped and forwarded")
343
344         #
345         # A recursive EOS x-connect, which resolves through another x-connect
346         #
347         route_34_eos = VppMplsRoute(self, 34, 1,
348                                     [VppRoutePath("0.0.0.0",
349                                                   0xffffffff,
350                                                   nh_via_label=32,
351                                                   labels=[44, 45])])
352         route_34_eos.add_vpp_config()
353
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 = VppMplsRoute(self, 34, 0,
368                                      [VppRoutePath("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 = VppIpRoute(self, "10.0.0.1", 32,
390                                  [VppRoutePath("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 = VppIpRoute(self, "10.0.0.1", 32,
421                                     [VppRoutePath(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 = VppMplsIpBind(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 = VppIpRoute(self, "10.0.0.1", 32,
476                                     [VppRoutePath(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 = VppIpRoute(self, "10.0.0.2", 32,
499                                     [VppRoutePath(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 = VppIpRoute(self, "11.0.0.1", 32,
522                                     [VppRoutePath("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 = VppIpRoute(self, "11.0.0.2", 32,
545                                     [VppRoutePath("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         self.vapi.sw_interface_set_flags(reply.sw_if_index, admin_up_down=1)
591
592         #
593         # add an unlabelled route through the new tunnel
594         #
595         route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
596                                     [VppRoutePath("0.0.0.0",
597                                                   reply.sw_if_index)])
598         route_10_0_0_3.add_vpp_config()
599
600         self.vapi.cli("clear trace")
601         tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
602         self.pg0.add_stream(tx)
603
604         self.pg_enable_capture(self.pg_interfaces)
605         self.pg_start()
606
607         rx = self.pg0.get_capture()
608         self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [44, 46])
609
610     def test_v4_exp_null(self):
611         """ MPLS V4 Explicit NULL test """
612
613         #
614         # The first test case has an MPLS TTL of 0
615         # all packet should be dropped
616         #
617         tx = self.create_stream_labelled_ip4(self.pg0, [0], 0)
618         self.pg0.add_stream(tx)
619
620         self.pg_enable_capture(self.pg_interfaces)
621         self.pg_start()
622
623         self.pg0.assert_nothing_captured(remark="MPLS TTL=0 packets forwarded")
624
625         #
626         # a stream with a non-zero MPLS TTL
627         # PG0 is in the default table
628         #
629         tx = self.create_stream_labelled_ip4(self.pg0, [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         self.verify_capture_ip4(self.pg0, rx, tx)
637
638         #
639         # a stream with a non-zero MPLS TTL
640         # PG1 is in table 1
641         # we are ensuring the post-pop lookup occurs in the VRF table
642         #
643         self.vapi.cli("clear trace")
644         tx = self.create_stream_labelled_ip4(self.pg1, [0])
645         self.pg1.add_stream(tx)
646
647         self.pg_enable_capture(self.pg_interfaces)
648         self.pg_start()
649
650         rx = self.pg1.get_capture()
651         self.verify_capture_ip4(self.pg0, rx, tx)
652
653     def test_v6_exp_null(self):
654         """ MPLS V6 Explicit NULL test """
655
656         #
657         # a stream with a non-zero MPLS TTL
658         # PG0 is in the default table
659         #
660         self.vapi.cli("clear trace")
661         tx = self.create_stream_labelled_ip6(self.pg0, 2, 2)
662         self.pg0.add_stream(tx)
663
664         self.pg_enable_capture(self.pg_interfaces)
665         self.pg_start()
666
667         rx = self.pg0.get_capture()
668         self.verify_capture_ip6(self.pg0, rx, tx)
669
670         #
671         # a stream with a non-zero MPLS TTL
672         # PG1 is in table 1
673         # we are ensuring the post-pop lookup occurs in the VRF table
674         #
675         self.vapi.cli("clear trace")
676         tx = self.create_stream_labelled_ip6(self.pg1, 2, 2)
677         self.pg1.add_stream(tx)
678
679         self.pg_enable_capture(self.pg_interfaces)
680         self.pg_start()
681
682         rx = self.pg1.get_capture()
683         self.verify_capture_ip6(self.pg0, rx, tx)
684
685     def test_deag(self):
686         """ MPLS Deagg """
687
688         #
689         # A de-agg route - next-hop lookup in default table
690         #
691         route_34_eos = VppMplsRoute(self, 34, 1,
692                                     [VppRoutePath("0.0.0.0",
693                                                   0xffffffff,
694                                                   nh_table_id=0)])
695         route_34_eos.add_vpp_config()
696
697         #
698         # ping an interface in the default table
699         # PG0 is in the default table
700         #
701         self.vapi.cli("clear trace")
702         tx = self.create_stream_labelled_ip4(self.pg0, [34], ping=1,
703                                              ip_itf=self.pg0)
704         self.pg0.add_stream(tx)
705
706         self.pg_enable_capture(self.pg_interfaces)
707         self.pg_start()
708
709         rx = self.pg0.get_capture()
710         self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
711
712         #
713         # A de-agg route - next-hop lookup in non-default table
714         #
715         route_35_eos = VppMplsRoute(self, 35, 1,
716                                     [VppRoutePath("0.0.0.0",
717                                                   0xffffffff,
718                                                   nh_table_id=1)])
719         route_35_eos.add_vpp_config()
720
721         #
722         # ping an interface in the non-default table
723         # PG0 is in the default table. packet arrive labelled in the
724         # default table and egress unlabelled in the non-default
725         #
726         self.vapi.cli("clear trace")
727         tx = self.create_stream_labelled_ip4(
728             self.pg0, [35], ping=1, ip_itf=self.pg1)
729         self.pg0.add_stream(tx)
730
731         self.pg_enable_capture(self.pg_interfaces)
732         self.pg_start()
733
734         packet_count = self.get_packet_count_for_if_idx(self.pg0.sw_if_index)
735         rx = self.pg1.get_capture(packet_count)
736         self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
737
738         route_35_eos.remove_vpp_config()
739         route_34_eos.remove_vpp_config()
740
741 if __name__ == '__main__':
742     unittest.main(testRunner=VppTestRunner)