misc: Fix python scripts shebang line
[vpp.git] / test / test_mpls.py
1 #!/usr/bin/env python3
2
3 import unittest
4 import socket
5
6 from framework import VppTestCase, VppTestRunner
7 from vpp_ip import DpoProto, INVALID_INDEX
8 from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
9     VppMplsIpBind, VppIpMRoute, VppMRoutePath, \
10     MRouteItfFlags, MRouteEntryFlags, VppIpTable, VppMplsTable, \
11     VppMplsLabel, MplsLspMode, find_mpls_route, \
12     FibPathProto, FibPathType, FibPathFlags, VppMplsLabel, MplsLspMode
13 from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface
14
15 import scapy.compat
16 from scapy.packet import Raw
17 from scapy.layers.l2 import Ether
18 from scapy.layers.inet import IP, UDP, ICMP
19 from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded
20 from scapy.contrib.mpls import MPLS
21
22 NUM_PKTS = 67
23
24
25 def verify_filter(capture, sent):
26     if not len(capture) == len(sent):
27         # filter out any IPv6 RAs from the capture
28         for p in capture:
29             if p.haslayer(IPv6):
30                 capture.remove(p)
31     return capture
32
33
34 def verify_mpls_stack(tst, rx, mpls_labels):
35     # the rx'd packet has the MPLS label popped
36     eth = rx[Ether]
37     tst.assertEqual(eth.type, 0x8847)
38
39     rx_mpls = rx[MPLS]
40
41     for ii in range(len(mpls_labels)):
42         tst.assertEqual(rx_mpls.label, mpls_labels[ii].value)
43         tst.assertEqual(rx_mpls.cos, mpls_labels[ii].exp)
44         tst.assertEqual(rx_mpls.ttl, mpls_labels[ii].ttl)
45
46         if ii == len(mpls_labels) - 1:
47             tst.assertEqual(rx_mpls.s, 1)
48         else:
49             # not end of stack
50             tst.assertEqual(rx_mpls.s, 0)
51             # pop the label to expose the next
52             rx_mpls = rx_mpls[MPLS].payload
53
54
55 class TestMPLS(VppTestCase):
56     """ MPLS Test Case """
57
58     @classmethod
59     def setUpClass(cls):
60         super(TestMPLS, cls).setUpClass()
61
62     @classmethod
63     def tearDownClass(cls):
64         super(TestMPLS, cls).tearDownClass()
65
66     def setUp(self):
67         super(TestMPLS, self).setUp()
68
69         # create 2 pg interfaces
70         self.create_pg_interfaces(range(4))
71
72         # setup both interfaces
73         # assign them different tables.
74         table_id = 0
75         self.tables = []
76
77         tbl = VppMplsTable(self, 0)
78         tbl.add_vpp_config()
79         self.tables.append(tbl)
80
81         for i in self.pg_interfaces:
82             i.admin_up()
83
84             if table_id != 0:
85                 tbl = VppIpTable(self, table_id)
86                 tbl.add_vpp_config()
87                 self.tables.append(tbl)
88                 tbl = VppIpTable(self, table_id, is_ip6=1)
89                 tbl.add_vpp_config()
90                 self.tables.append(tbl)
91
92             i.set_table_ip4(table_id)
93             i.set_table_ip6(table_id)
94             i.config_ip4()
95             i.resolve_arp()
96             i.config_ip6()
97             i.resolve_ndp()
98             i.enable_mpls()
99             table_id += 1
100
101     def tearDown(self):
102         for i in self.pg_interfaces:
103             i.unconfig_ip4()
104             i.unconfig_ip6()
105             i.ip6_disable()
106             i.set_table_ip4(0)
107             i.set_table_ip6(0)
108             i.disable_mpls()
109             i.admin_down()
110         super(TestMPLS, self).tearDown()
111
112     # the default of 64 matches the IP packet TTL default
113     def create_stream_labelled_ip4(
114             self,
115             src_if,
116             mpls_labels,
117             ping=0,
118             ip_itf=None,
119             dst_ip=None,
120             chksum=None,
121             ip_ttl=64,
122             n=257):
123         self.reset_packet_infos()
124         pkts = []
125         for i in range(0, n):
126             info = self.create_packet_info(src_if, src_if)
127             payload = self.info_to_payload(info)
128             p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
129
130             for ii in range(len(mpls_labels)):
131                 p = p / MPLS(label=mpls_labels[ii].value,
132                              ttl=mpls_labels[ii].ttl,
133                              cos=mpls_labels[ii].exp)
134             if not ping:
135                 if not dst_ip:
136                     p = (p / IP(src=src_if.local_ip4,
137                                 dst=src_if.remote_ip4,
138                                 ttl=ip_ttl) /
139                          UDP(sport=1234, dport=1234) /
140                          Raw(payload))
141                 else:
142                     p = (p / IP(src=src_if.local_ip4, dst=dst_ip, ttl=ip_ttl) /
143                          UDP(sport=1234, dport=1234) /
144                          Raw(payload))
145             else:
146                 p = (p / IP(src=ip_itf.remote_ip4,
147                             dst=ip_itf.local_ip4,
148                             ttl=ip_ttl) /
149                      ICMP())
150
151             if chksum:
152                 p[IP].chksum = chksum
153             info.data = p.copy()
154             pkts.append(p)
155         return pkts
156
157     def create_stream_ip4(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
158         self.reset_packet_infos()
159         pkts = []
160         for i in range(0, 257):
161             info = self.create_packet_info(src_if, src_if)
162             payload = self.info_to_payload(info)
163             p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
164                  IP(src=src_if.remote_ip4, dst=dst_ip,
165                     ttl=ip_ttl, tos=ip_dscp) /
166                  UDP(sport=1234, dport=1234) /
167                  Raw(payload))
168             info.data = p.copy()
169             pkts.append(p)
170         return pkts
171
172     def create_stream_ip6(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
173         self.reset_packet_infos()
174         pkts = []
175         for i in range(0, 257):
176             info = self.create_packet_info(src_if, src_if)
177             payload = self.info_to_payload(info)
178             p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
179                  IPv6(src=src_if.remote_ip6, dst=dst_ip,
180                       hlim=ip_ttl, tc=ip_dscp) /
181                  UDP(sport=1234, dport=1234) /
182                  Raw(payload))
183             info.data = p.copy()
184             pkts.append(p)
185         return pkts
186
187     def create_stream_labelled_ip6(self, src_if, mpls_labels,
188                                    hlim=64, dst_ip=None):
189         if dst_ip is None:
190             dst_ip = src_if.remote_ip6
191         self.reset_packet_infos()
192         pkts = []
193         for i in range(0, 257):
194             info = self.create_packet_info(src_if, src_if)
195             payload = self.info_to_payload(info)
196             p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
197             for l in mpls_labels:
198                 p = p / MPLS(label=l.value, ttl=l.ttl, cos=l.exp)
199
200             p = p / (IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim) /
201                      UDP(sport=1234, dport=1234) /
202                      Raw(payload))
203             info.data = p.copy()
204             pkts.append(p)
205         return pkts
206
207     def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0,
208                            ip_ttl=None, ip_dscp=0):
209         try:
210             capture = verify_filter(capture, sent)
211
212             self.assertEqual(len(capture), len(sent))
213
214             for i in range(len(capture)):
215                 tx = sent[i]
216                 rx = capture[i]
217
218                 # the rx'd packet has the MPLS label popped
219                 eth = rx[Ether]
220                 self.assertEqual(eth.type, 0x800)
221
222                 tx_ip = tx[IP]
223                 rx_ip = rx[IP]
224
225                 if not ping_resp:
226                     self.assertEqual(rx_ip.src, tx_ip.src)
227                     self.assertEqual(rx_ip.dst, tx_ip.dst)
228                     self.assertEqual(rx_ip.tos, ip_dscp)
229                     if not ip_ttl:
230                         # IP processing post pop has decremented the TTL
231                         self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
232                     else:
233                         self.assertEqual(rx_ip.ttl, ip_ttl)
234                 else:
235                     self.assertEqual(rx_ip.src, tx_ip.dst)
236                     self.assertEqual(rx_ip.dst, tx_ip.src)
237
238         except:
239             raise
240
241     def verify_capture_labelled_ip4(self, src_if, capture, sent,
242                                     mpls_labels, ip_ttl=None):
243         try:
244             capture = verify_filter(capture, sent)
245
246             self.assertEqual(len(capture), len(sent))
247
248             for i in range(len(capture)):
249                 tx = sent[i]
250                 rx = capture[i]
251                 tx_ip = tx[IP]
252                 rx_ip = rx[IP]
253
254                 verify_mpls_stack(self, rx, mpls_labels)
255
256                 self.assertEqual(rx_ip.src, tx_ip.src)
257                 self.assertEqual(rx_ip.dst, tx_ip.dst)
258                 if not ip_ttl:
259                     # IP processing post pop has decremented the TTL
260                     self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
261                 else:
262                     self.assertEqual(rx_ip.ttl, ip_ttl)
263
264         except:
265             raise
266
267     def verify_capture_labelled_ip6(self, src_if, capture, sent,
268                                     mpls_labels, ip_ttl=None):
269         try:
270             capture = verify_filter(capture, sent)
271
272             self.assertEqual(len(capture), len(sent))
273
274             for i in range(len(capture)):
275                 tx = sent[i]
276                 rx = capture[i]
277                 tx_ip = tx[IPv6]
278                 rx_ip = rx[IPv6]
279
280                 verify_mpls_stack(self, rx, mpls_labels)
281
282                 self.assertEqual(rx_ip.src, tx_ip.src)
283                 self.assertEqual(rx_ip.dst, tx_ip.dst)
284                 if not ip_ttl:
285                     # IP processing post pop has decremented the TTL
286                     self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
287                 else:
288                     self.assertEqual(rx_ip.hlim, ip_ttl)
289
290         except:
291             raise
292
293     def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
294         try:
295             capture = verify_filter(capture, sent)
296
297             self.assertEqual(len(capture), len(sent))
298
299             for i in range(len(capture)):
300                 tx = sent[i]
301                 rx = capture[i]
302                 tx_ip = tx[IP]
303                 rx_ip = rx[IP]
304
305                 verify_mpls_stack(self, rx, mpls_labels)
306
307                 self.assertEqual(rx_ip.src, tx_ip.src)
308                 self.assertEqual(rx_ip.dst, tx_ip.dst)
309                 # IP processing post pop has decremented the TTL
310                 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
311
312         except:
313             raise
314
315     def verify_capture_labelled(self, src_if, capture, sent,
316                                 mpls_labels):
317         try:
318             capture = verify_filter(capture, sent)
319
320             self.assertEqual(len(capture), len(sent))
321
322             for i in range(len(capture)):
323                 rx = capture[i]
324                 verify_mpls_stack(self, rx, mpls_labels)
325         except:
326             raise
327
328     def verify_capture_ip6(self, src_if, capture, sent,
329                            ip_hlim=None, ip_dscp=0):
330         try:
331             self.assertEqual(len(capture), len(sent))
332
333             for i in range(len(capture)):
334                 tx = sent[i]
335                 rx = capture[i]
336
337                 # the rx'd packet has the MPLS label popped
338                 eth = rx[Ether]
339                 self.assertEqual(eth.type, 0x86DD)
340
341                 tx_ip = tx[IPv6]
342                 rx_ip = rx[IPv6]
343
344                 self.assertEqual(rx_ip.src, tx_ip.src)
345                 self.assertEqual(rx_ip.dst, tx_ip.dst)
346                 self.assertEqual(rx_ip.tc,  ip_dscp)
347                 # IP processing post pop has decremented the TTL
348                 if not ip_hlim:
349                     self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
350                 else:
351                     self.assertEqual(rx_ip.hlim, ip_hlim)
352
353         except:
354             raise
355
356     def verify_capture_ip6_icmp(self, src_if, capture, sent):
357         try:
358             self.assertEqual(len(capture), len(sent))
359
360             for i in range(len(capture)):
361                 tx = sent[i]
362                 rx = capture[i]
363
364                 # the rx'd packet has the MPLS label popped
365                 eth = rx[Ether]
366                 self.assertEqual(eth.type, 0x86DD)
367
368                 tx_ip = tx[IPv6]
369                 rx_ip = rx[IPv6]
370
371                 self.assertEqual(rx_ip.dst, tx_ip.src)
372                 # ICMP sourced from the interface's address
373                 self.assertEqual(rx_ip.src, src_if.local_ip6)
374                 # hop-limit reset to 255 for IMCP packet
375                 self.assertEqual(rx_ip.hlim, 255)
376
377                 icmp = rx[ICMPv6TimeExceeded]
378
379         except:
380             raise
381
382     def verify_capture_fragmented_labelled_ip4(self, src_if, capture, sent,
383                                                mpls_labels, ip_ttl=None):
384         try:
385             capture = verify_filter(capture, sent)
386
387             for i in range(len(capture)):
388                 tx = sent[0]
389                 rx = capture[i]
390                 tx_ip = tx[IP]
391                 rx_ip = rx[IP]
392
393                 verify_mpls_stack(self, rx, mpls_labels)
394
395                 self.assertEqual(rx_ip.src, tx_ip.src)
396                 self.assertEqual(rx_ip.dst, tx_ip.dst)
397                 if not ip_ttl:
398                     # IP processing post pop has decremented the TTL
399                     self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
400                 else:
401                     self.assertEqual(rx_ip.ttl, ip_ttl)
402
403         except:
404             raise
405
406     def test_swap(self):
407         """ MPLS label swap tests """
408
409         #
410         # A simple MPLS xconnect - eos label in label out
411         #
412         route_32_eos = VppMplsRoute(self, 32, 1,
413                                     [VppRoutePath(self.pg0.remote_ip4,
414                                                   self.pg0.sw_if_index,
415                                                   labels=[VppMplsLabel(33)])])
416         route_32_eos.add_vpp_config()
417
418         self.assertTrue(
419             find_mpls_route(self, 0, 32, 1,
420                             [VppRoutePath(self.pg0.remote_ip4,
421                                           self.pg0.sw_if_index,
422                                           labels=[VppMplsLabel(33)])]))
423
424         #
425         # a stream that matches the route for 10.0.0.1
426         # PG0 is in the default table
427         #
428         tx = self.create_stream_labelled_ip4(self.pg0,
429                                              [VppMplsLabel(32, ttl=32, exp=1)])
430         rx = self.send_and_expect(self.pg0, tx, self.pg0)
431         self.verify_capture_labelled(self.pg0, rx, tx,
432                                      [VppMplsLabel(33, ttl=31, exp=1)])
433
434         self.assertEqual(route_32_eos.get_stats_to()['packets'], 257)
435
436         #
437         # A simple MPLS xconnect - non-eos label in label out
438         #
439         route_32_neos = VppMplsRoute(self, 32, 0,
440                                      [VppRoutePath(self.pg0.remote_ip4,
441                                                    self.pg0.sw_if_index,
442                                                    labels=[VppMplsLabel(33)])])
443         route_32_neos.add_vpp_config()
444
445         #
446         # a stream that matches the route for 10.0.0.1
447         # PG0 is in the default table
448         #
449         tx = self.create_stream_labelled_ip4(self.pg0,
450                                              [VppMplsLabel(32, ttl=21, exp=7),
451                                               VppMplsLabel(99)])
452         rx = self.send_and_expect(self.pg0, tx, self.pg0)
453         self.verify_capture_labelled(self.pg0, rx, tx,
454                                      [VppMplsLabel(33, ttl=20, exp=7),
455                                       VppMplsLabel(99)])
456         self.assertEqual(route_32_neos.get_stats_to()['packets'], 257)
457
458         #
459         # A simple MPLS xconnect - non-eos label in label out, uniform mode
460         #
461         route_42_neos = VppMplsRoute(
462             self, 42, 0,
463             [VppRoutePath(self.pg0.remote_ip4,
464                           self.pg0.sw_if_index,
465                           labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)])])
466         route_42_neos.add_vpp_config()
467
468         tx = self.create_stream_labelled_ip4(self.pg0,
469                                              [VppMplsLabel(42, ttl=21, exp=7),
470                                               VppMplsLabel(99)])
471         rx = self.send_and_expect(self.pg0, tx, self.pg0)
472         self.verify_capture_labelled(self.pg0, rx, tx,
473                                      [VppMplsLabel(43, ttl=20, exp=7),
474                                       VppMplsLabel(99)])
475
476         #
477         # An MPLS xconnect - EOS label in IP out
478         #
479         route_33_eos = VppMplsRoute(self, 33, 1,
480                                     [VppRoutePath(self.pg0.remote_ip4,
481                                                   self.pg0.sw_if_index,
482                                                   labels=[])])
483         route_33_eos.add_vpp_config()
484
485         tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)])
486         rx = self.send_and_expect(self.pg0, tx, self.pg0)
487         self.verify_capture_ip4(self.pg0, rx, tx)
488
489         #
490         # disposed packets have an invalid IPv4 checksum
491         #
492         tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)],
493                                              dst_ip=self.pg0.remote_ip4,
494                                              n=65,
495                                              chksum=1)
496         self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
497
498         #
499         # An MPLS xconnect - EOS label in IP out, uniform mode
500         #
501         route_3333_eos = VppMplsRoute(
502             self, 3333, 1,
503             [VppRoutePath(self.pg0.remote_ip4,
504                           self.pg0.sw_if_index,
505                           labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])])
506         route_3333_eos.add_vpp_config()
507
508         tx = self.create_stream_labelled_ip4(
509             self.pg0,
510             [VppMplsLabel(3333, ttl=55, exp=3)])
511         rx = self.send_and_expect(self.pg0, tx, self.pg0)
512         self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60)
513         tx = self.create_stream_labelled_ip4(
514             self.pg0,
515             [VppMplsLabel(3333, ttl=66, exp=4)])
516         rx = self.send_and_expect(self.pg0, tx, self.pg0)
517         self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80)
518
519         #
520         # An MPLS xconnect - EOS label in IPv6 out
521         #
522         route_333_eos = VppMplsRoute(
523             self, 333, 1,
524             [VppRoutePath(self.pg0.remote_ip6,
525                           self.pg0.sw_if_index,
526                           labels=[])],
527             eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
528         route_333_eos.add_vpp_config()
529
530         tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)])
531         rx = self.send_and_expect(self.pg0, tx, self.pg0)
532         self.verify_capture_ip6(self.pg0, rx, tx)
533
534         #
535         # disposed packets have an TTL expired
536         #
537         tx = self.create_stream_labelled_ip6(self.pg0,
538                                              [VppMplsLabel(333, ttl=64)],
539                                              dst_ip=self.pg1.remote_ip6,
540                                              hlim=1)
541         rx = self.send_and_expect(self.pg0, tx, self.pg0)
542         self.verify_capture_ip6_icmp(self.pg0, rx, tx)
543
544         #
545         # An MPLS xconnect - EOS label in IPv6 out w imp-null
546         #
547         route_334_eos = VppMplsRoute(
548             self, 334, 1,
549             [VppRoutePath(self.pg0.remote_ip6,
550                           self.pg0.sw_if_index,
551                           labels=[VppMplsLabel(3)])],
552             eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
553         route_334_eos.add_vpp_config()
554
555         tx = self.create_stream_labelled_ip6(self.pg0,
556                                              [VppMplsLabel(334, ttl=64)])
557         rx = self.send_and_expect(self.pg0, tx, self.pg0)
558         self.verify_capture_ip6(self.pg0, rx, tx)
559
560         #
561         # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode
562         #
563         route_335_eos = VppMplsRoute(
564             self, 335, 1,
565             [VppRoutePath(self.pg0.remote_ip6,
566                           self.pg0.sw_if_index,
567                           labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])],
568             eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
569         route_335_eos.add_vpp_config()
570
571         tx = self.create_stream_labelled_ip6(
572             self.pg0,
573             [VppMplsLabel(335, ttl=27, exp=4)])
574         rx = self.send_and_expect(self.pg0, tx, self.pg0)
575         self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80)
576
577         #
578         # disposed packets have an TTL expired
579         #
580         tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334)],
581                                              dst_ip=self.pg1.remote_ip6,
582                                              hlim=0)
583         rx = self.send_and_expect(self.pg0, tx, self.pg0)
584         self.verify_capture_ip6_icmp(self.pg0, rx, tx)
585
586         #
587         # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
588         # so this traffic should be dropped.
589         #
590         route_33_neos = VppMplsRoute(self, 33, 0,
591                                      [VppRoutePath(self.pg0.remote_ip4,
592                                                    self.pg0.sw_if_index,
593                                                    labels=[])])
594         route_33_neos.add_vpp_config()
595
596         tx = self.create_stream_labelled_ip4(self.pg0,
597                                              [VppMplsLabel(33),
598                                               VppMplsLabel(99)])
599         self.send_and_assert_no_replies(
600             self.pg0, tx,
601             "MPLS non-EOS packets popped and forwarded")
602
603         #
604         # A recursive EOS x-connect, which resolves through another x-connect
605         # in pipe mode
606         #
607         route_34_eos = VppMplsRoute(self, 34, 1,
608                                     [VppRoutePath("0.0.0.0",
609                                                   0xffffffff,
610                                                   nh_via_label=32,
611                                                   labels=[VppMplsLabel(44),
612                                                           VppMplsLabel(45)])])
613         route_34_eos.add_vpp_config()
614         self.logger.info(self.vapi.cli("sh mpls fib 34"))
615
616         tx = self.create_stream_labelled_ip4(self.pg0,
617                                              [VppMplsLabel(34, ttl=3)])
618         rx = self.send_and_expect(self.pg0, tx, self.pg0)
619         self.verify_capture_labelled(self.pg0, rx, tx,
620                                      [VppMplsLabel(33),
621                                       VppMplsLabel(44),
622                                       VppMplsLabel(45, ttl=2)])
623
624         self.assertEqual(route_34_eos.get_stats_to()['packets'], 257)
625         self.assertEqual(route_32_neos.get_stats_via()['packets'], 257)
626
627         #
628         # A recursive EOS x-connect, which resolves through another x-connect
629         # in uniform mode
630         #
631         route_35_eos = VppMplsRoute(
632             self, 35, 1,
633             [VppRoutePath("0.0.0.0",
634                           0xffffffff,
635                           nh_via_label=42,
636                           labels=[VppMplsLabel(44)])])
637         route_35_eos.add_vpp_config()
638
639         tx = self.create_stream_labelled_ip4(self.pg0,
640                                              [VppMplsLabel(35, ttl=3)])
641         rx = self.send_and_expect(self.pg0, tx, self.pg0)
642         self.verify_capture_labelled(self.pg0, rx, tx,
643                                      [VppMplsLabel(43, ttl=2),
644                                       VppMplsLabel(44, ttl=2)])
645
646         #
647         # A recursive non-EOS x-connect, which resolves through another
648         # x-connect
649         #
650         route_34_neos = VppMplsRoute(self, 34, 0,
651                                      [VppRoutePath("0.0.0.0",
652                                                    0xffffffff,
653                                                    nh_via_label=32,
654                                                    labels=[VppMplsLabel(44),
655                                                            VppMplsLabel(46)])])
656         route_34_neos.add_vpp_config()
657
658         tx = self.create_stream_labelled_ip4(self.pg0,
659                                              [VppMplsLabel(34, ttl=45),
660                                               VppMplsLabel(99)])
661         rx = self.send_and_expect(self.pg0, tx, self.pg0)
662         # it's the 2nd (counting from 0) label in the stack that is swapped
663         self.verify_capture_labelled(self.pg0, rx, tx,
664                                      [VppMplsLabel(33),
665                                       VppMplsLabel(44),
666                                       VppMplsLabel(46, ttl=44),
667                                       VppMplsLabel(99)])
668
669         #
670         # an recursive IP route that resolves through the recursive non-eos
671         # x-connect
672         #
673         ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
674                                  [VppRoutePath("0.0.0.0",
675                                                0xffffffff,
676                                                nh_via_label=34,
677                                                labels=[VppMplsLabel(55)])])
678         ip_10_0_0_1.add_vpp_config()
679
680         tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
681         rx = self.send_and_expect(self.pg0, tx, self.pg0)
682         self.verify_capture_labelled_ip4(self.pg0, rx, tx,
683                                          [VppMplsLabel(33),
684                                           VppMplsLabel(44),
685                                           VppMplsLabel(46),
686                                           VppMplsLabel(55)])
687         self.assertEqual(ip_10_0_0_1.get_stats_to()['packets'], 257)
688
689         ip_10_0_0_1.remove_vpp_config()
690         route_34_neos.remove_vpp_config()
691         route_34_eos.remove_vpp_config()
692         route_33_neos.remove_vpp_config()
693         route_33_eos.remove_vpp_config()
694         route_32_neos.remove_vpp_config()
695         route_32_eos.remove_vpp_config()
696
697     def test_bind(self):
698         """ MPLS Local Label Binding test """
699
700         #
701         # Add a non-recursive route with a single out label
702         #
703         route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
704                                     [VppRoutePath(self.pg0.remote_ip4,
705                                                   self.pg0.sw_if_index,
706                                                   labels=[VppMplsLabel(45)])])
707         route_10_0_0_1.add_vpp_config()
708
709         # bind a local label to the route
710         binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
711         binding.add_vpp_config()
712
713         # non-EOS stream
714         tx = self.create_stream_labelled_ip4(self.pg0,
715                                              [VppMplsLabel(44),
716                                               VppMplsLabel(99)])
717         rx = self.send_and_expect(self.pg0, tx, self.pg0)
718         self.verify_capture_labelled(self.pg0, rx, tx,
719                                      [VppMplsLabel(45, ttl=63),
720                                       VppMplsLabel(99)])
721
722         # EOS stream
723         tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)])
724         rx = self.send_and_expect(self.pg0, tx, self.pg0)
725         self.verify_capture_labelled(self.pg0, rx, tx,
726                                      [VppMplsLabel(45, ttl=63)])
727
728         # IP stream
729         tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
730         rx = self.send_and_expect(self.pg0, tx, self.pg0)
731         self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)])
732
733         #
734         # cleanup
735         #
736         binding.remove_vpp_config()
737         route_10_0_0_1.remove_vpp_config()
738
739     def test_imposition(self):
740         """ MPLS label imposition test """
741
742         #
743         # Add a non-recursive route with a single out label
744         #
745         route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
746                                     [VppRoutePath(self.pg0.remote_ip4,
747                                                   self.pg0.sw_if_index,
748                                                   labels=[VppMplsLabel(32)])])
749         route_10_0_0_1.add_vpp_config()
750
751         #
752         # a stream that matches the route for 10.0.0.1
753         # PG0 is in the default table
754         #
755         tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
756         rx = self.send_and_expect(self.pg0, tx, self.pg0)
757         self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)])
758
759         #
760         # Add a non-recursive route with a 3 out labels
761         #
762         route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
763                                     [VppRoutePath(self.pg0.remote_ip4,
764                                                   self.pg0.sw_if_index,
765                                                   labels=[VppMplsLabel(32),
766                                                           VppMplsLabel(33),
767                                                           VppMplsLabel(34)])])
768         route_10_0_0_2.add_vpp_config()
769
770         tx = self.create_stream_ip4(self.pg0, "10.0.0.2",
771                                     ip_ttl=44, ip_dscp=0xff)
772         rx = self.send_and_expect(self.pg0, tx, self.pg0)
773         self.verify_capture_labelled_ip4(self.pg0, rx, tx,
774                                          [VppMplsLabel(32),
775                                           VppMplsLabel(33),
776                                           VppMplsLabel(34)],
777                                          ip_ttl=43)
778
779         #
780         # Add a non-recursive route with a single out label in uniform mode
781         #
782         route_10_0_0_3 = VppIpRoute(
783             self, "10.0.0.3", 32,
784             [VppRoutePath(self.pg0.remote_ip4,
785                           self.pg0.sw_if_index,
786                           labels=[VppMplsLabel(32,
787                                                mode=MplsLspMode.UNIFORM)])])
788         route_10_0_0_3.add_vpp_config()
789
790         tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
791                                     ip_ttl=54, ip_dscp=0xbe)
792         rx = self.send_and_expect(self.pg0, tx, self.pg0)
793         self.verify_capture_labelled_ip4(self.pg0, rx, tx,
794                                          [VppMplsLabel(32, ttl=53, exp=5)])
795
796         #
797         # Add a IPv6 non-recursive route with a single out label in
798         # uniform mode
799         #
800         route_2001_3 = VppIpRoute(
801             self, "2001::3", 128,
802             [VppRoutePath(self.pg0.remote_ip6,
803                           self.pg0.sw_if_index,
804                           labels=[VppMplsLabel(32,
805                                                mode=MplsLspMode.UNIFORM)])])
806         route_2001_3.add_vpp_config()
807
808         tx = self.create_stream_ip6(self.pg0, "2001::3",
809                                     ip_ttl=54, ip_dscp=0xbe)
810         rx = self.send_and_expect(self.pg0, tx, self.pg0)
811         self.verify_capture_labelled_ip6(self.pg0, rx, tx,
812                                          [VppMplsLabel(32, ttl=53, exp=5)])
813
814         #
815         # add a recursive path, with output label, via the 1 label route
816         #
817         route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
818                                     [VppRoutePath("10.0.0.1",
819                                                   0xffffffff,
820                                                   labels=[VppMplsLabel(44)])])
821         route_11_0_0_1.add_vpp_config()
822
823         #
824         # a stream that matches the route for 11.0.0.1, should pick up
825         # the label stack for 11.0.0.1 and 10.0.0.1
826         #
827         tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
828         rx = self.send_and_expect(self.pg0, tx, self.pg0)
829         self.verify_capture_labelled_ip4(self.pg0, rx, tx,
830                                          [VppMplsLabel(32),
831                                           VppMplsLabel(44)])
832
833         self.assertEqual(route_11_0_0_1.get_stats_to()['packets'], 257)
834
835         #
836         # add a recursive path, with 2 labels, via the 3 label route
837         #
838         route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
839                                     [VppRoutePath("10.0.0.2",
840                                                   0xffffffff,
841                                                   labels=[VppMplsLabel(44),
842                                                           VppMplsLabel(45)])])
843         route_11_0_0_2.add_vpp_config()
844
845         #
846         # a stream that matches the route for 11.0.0.1, should pick up
847         # the label stack for 11.0.0.1 and 10.0.0.1
848         #
849         tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
850         rx = self.send_and_expect(self.pg0, tx, self.pg0)
851         self.verify_capture_labelled_ip4(self.pg0, rx, tx,
852                                          [VppMplsLabel(32),
853                                           VppMplsLabel(33),
854                                           VppMplsLabel(34),
855                                           VppMplsLabel(44),
856                                           VppMplsLabel(45)])
857
858         self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 257)
859
860         rx = self.send_and_expect(self.pg0, tx, self.pg0)
861         self.verify_capture_labelled_ip4(self.pg0, rx, tx,
862                                          [VppMplsLabel(32),
863                                           VppMplsLabel(33),
864                                           VppMplsLabel(34),
865                                           VppMplsLabel(44),
866                                           VppMplsLabel(45)])
867
868         self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 514)
869
870         #
871         # cleanup
872         #
873         route_11_0_0_2.remove_vpp_config()
874         route_11_0_0_1.remove_vpp_config()
875         route_10_0_0_2.remove_vpp_config()
876         route_10_0_0_1.remove_vpp_config()
877
878     def test_imposition_fragmentation(self):
879         """ MPLS label imposition fragmentation test """
880
881         #
882         # Add a ipv4 non-recursive route with a single out label
883         #
884         route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
885                                     [VppRoutePath(self.pg0.remote_ip4,
886                                                   self.pg0.sw_if_index,
887                                                   labels=[VppMplsLabel(32)])])
888         route_10_0_0_1.add_vpp_config()
889
890         #
891         # a stream that matches the route for 10.0.0.1
892         # PG0 is in the default table
893         #
894         tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
895         for i in range(0, 257):
896             self.extend_packet(tx[i], 10000)
897
898         #
899         # 5 fragments per packet (257*5=1285)
900         #
901         rx = self.send_and_expect(self.pg0, tx, self.pg0, 1285)
902         self.verify_capture_fragmented_labelled_ip4(self.pg0, rx, tx,
903                                                     [VppMplsLabel(32)])
904
905         #
906         # cleanup
907         #
908         route_10_0_0_1.remove_vpp_config()
909
910     def test_tunnel_pipe(self):
911         """ MPLS Tunnel Tests - Pipe """
912
913         #
914         # Create a tunnel with a single out label
915         #
916         mpls_tun = VppMPLSTunnelInterface(
917             self,
918             [VppRoutePath(self.pg0.remote_ip4,
919                           self.pg0.sw_if_index,
920                           labels=[VppMplsLabel(44),
921                                   VppMplsLabel(46)])])
922         mpls_tun.add_vpp_config()
923         mpls_tun.admin_up()
924
925         #
926         # add an unlabelled route through the new tunnel
927         #
928         route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
929                                     [VppRoutePath("0.0.0.0",
930                                                   mpls_tun._sw_if_index)])
931         route_10_0_0_3.add_vpp_config()
932
933         self.vapi.cli("clear trace")
934         tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
935         self.pg0.add_stream(tx)
936
937         self.pg_enable_capture(self.pg_interfaces)
938         self.pg_start()
939
940         rx = self.pg0.get_capture()
941         self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
942                                          [VppMplsLabel(44),
943                                           VppMplsLabel(46)])
944
945         #
946         # add a labelled route through the new tunnel
947         #
948         route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
949                                     [VppRoutePath("0.0.0.0",
950                                                   mpls_tun._sw_if_index,
951                                                   labels=[33])])
952         route_10_0_0_4.add_vpp_config()
953
954         self.vapi.cli("clear trace")
955         tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
956         self.pg0.add_stream(tx)
957
958         self.pg_enable_capture(self.pg_interfaces)
959         self.pg_start()
960
961         rx = self.pg0.get_capture()
962         self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
963                                          [VppMplsLabel(44),
964                                           VppMplsLabel(46),
965                                           VppMplsLabel(33, ttl=255)])
966
967     def test_tunnel_uniform(self):
968         """ MPLS Tunnel Tests - Uniform """
969
970         #
971         # Create a tunnel with a single out label
972         # The label stack is specified here from outer to inner
973         #
974         mpls_tun = VppMPLSTunnelInterface(
975             self,
976             [VppRoutePath(self.pg0.remote_ip4,
977                           self.pg0.sw_if_index,
978                           labels=[VppMplsLabel(44, ttl=32),
979                                   VppMplsLabel(46, MplsLspMode.UNIFORM)])])
980         mpls_tun.add_vpp_config()
981         mpls_tun.admin_up()
982
983         #
984         # add an unlabelled route through the new tunnel
985         #
986         route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
987                                     [VppRoutePath("0.0.0.0",
988                                                   mpls_tun._sw_if_index)])
989         route_10_0_0_3.add_vpp_config()
990
991         self.vapi.cli("clear trace")
992         tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
993         self.pg0.add_stream(tx)
994
995         self.pg_enable_capture(self.pg_interfaces)
996         self.pg_start()
997
998         rx = self.pg0.get_capture()
999         self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1000                                          [VppMplsLabel(44, ttl=32),
1001                                           VppMplsLabel(46, ttl=23)])
1002
1003         #
1004         # add a labelled route through the new tunnel
1005         #
1006         route_10_0_0_4 = VppIpRoute(
1007             self, "10.0.0.4", 32,
1008             [VppRoutePath("0.0.0.0",
1009                           mpls_tun._sw_if_index,
1010                           labels=[VppMplsLabel(33, ttl=47)])])
1011         route_10_0_0_4.add_vpp_config()
1012
1013         self.vapi.cli("clear trace")
1014         tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1015         self.pg0.add_stream(tx)
1016
1017         self.pg_enable_capture(self.pg_interfaces)
1018         self.pg_start()
1019
1020         rx = self.pg0.get_capture()
1021         self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1022                                          [VppMplsLabel(44, ttl=32),
1023                                           VppMplsLabel(46, ttl=47),
1024                                           VppMplsLabel(33, ttl=47)])
1025
1026     def test_mpls_tunnel_many(self):
1027         """ MPLS Multiple Tunnels """
1028
1029         for ii in range(10):
1030             mpls_tun = VppMPLSTunnelInterface(
1031                 self,
1032                 [VppRoutePath(self.pg0.remote_ip4,
1033                               self.pg0.sw_if_index,
1034                               labels=[VppMplsLabel(44, ttl=32),
1035                                       VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1036             mpls_tun.add_vpp_config()
1037             mpls_tun.admin_up()
1038
1039     def test_v4_exp_null(self):
1040         """ MPLS V4 Explicit NULL test """
1041
1042         #
1043         # The first test case has an MPLS TTL of 0
1044         # all packet should be dropped
1045         #
1046         tx = self.create_stream_labelled_ip4(self.pg0,
1047                                              [VppMplsLabel(0, ttl=0)])
1048         self.send_and_assert_no_replies(self.pg0, tx,
1049                                         "MPLS TTL=0 packets forwarded")
1050
1051         #
1052         # a stream with a non-zero MPLS TTL
1053         # PG0 is in the default table
1054         #
1055         tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
1056         rx = self.send_and_expect(self.pg0, tx, self.pg0)
1057         self.verify_capture_ip4(self.pg0, rx, tx)
1058
1059         #
1060         # a stream with a non-zero MPLS TTL
1061         # PG1 is in table 1
1062         # we are ensuring the post-pop lookup occurs in the VRF table
1063         #
1064         tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
1065         rx = self.send_and_expect(self.pg1, tx, self.pg1)
1066         self.verify_capture_ip4(self.pg1, rx, tx)
1067
1068     def test_v6_exp_null(self):
1069         """ MPLS V6 Explicit NULL test """
1070
1071         #
1072         # a stream with a non-zero MPLS TTL
1073         # PG0 is in the default table
1074         #
1075         tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1076         rx = self.send_and_expect(self.pg0, tx, self.pg0)
1077         self.verify_capture_ip6(self.pg0, rx, tx)
1078
1079         #
1080         # a stream with a non-zero MPLS TTL
1081         # PG1 is in table 1
1082         # we are ensuring the post-pop lookup occurs in the VRF table
1083         #
1084         tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1085         rx = self.send_and_expect(self.pg1, tx, self.pg1)
1086         self.verify_capture_ip6(self.pg0, rx, tx)
1087
1088     def test_deag(self):
1089         """ MPLS Deagg """
1090
1091         #
1092         # A de-agg route - next-hop lookup in default table
1093         #
1094         route_34_eos = VppMplsRoute(self, 34, 1,
1095                                     [VppRoutePath("0.0.0.0",
1096                                                   0xffffffff,
1097                                                   nh_table_id=0)])
1098         route_34_eos.add_vpp_config()
1099
1100         #
1101         # ping an interface in the default table
1102         # PG0 is in the default table
1103         #
1104         tx = self.create_stream_labelled_ip4(self.pg0,
1105                                              [VppMplsLabel(34)],
1106                                              ping=1,
1107                                              ip_itf=self.pg0)
1108         rx = self.send_and_expect(self.pg0, tx, self.pg0)
1109         self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1110
1111         #
1112         # A de-agg route - next-hop lookup in non-default table
1113         #
1114         route_35_eos = VppMplsRoute(self, 35, 1,
1115                                     [VppRoutePath("0.0.0.0",
1116                                                   0xffffffff,
1117                                                   nh_table_id=1)])
1118         route_35_eos.add_vpp_config()
1119
1120         #
1121         # ping an interface in the non-default table
1122         # PG0 is in the default table. packet arrive labelled in the
1123         # default table and egress unlabelled in the non-default
1124         #
1125         tx = self.create_stream_labelled_ip4(
1126             self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1127         rx = self.send_and_expect(self.pg0, tx, self.pg1)
1128         self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1129
1130         #
1131         # Double pop
1132         #
1133         route_36_neos = VppMplsRoute(self, 36, 0,
1134                                      [VppRoutePath("0.0.0.0",
1135                                                    0xffffffff)])
1136         route_36_neos.add_vpp_config()
1137
1138         tx = self.create_stream_labelled_ip4(self.pg0,
1139                                              [VppMplsLabel(36),
1140                                               VppMplsLabel(35)],
1141                                              ping=1, ip_itf=self.pg1)
1142         rx = self.send_and_expect(self.pg0, tx, self.pg1)
1143         self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1144
1145         route_36_neos.remove_vpp_config()
1146         route_35_eos.remove_vpp_config()
1147         route_34_eos.remove_vpp_config()
1148
1149     def test_interface_rx(self):
1150         """ MPLS Interface Receive """
1151
1152         #
1153         # Add a non-recursive route that will forward the traffic
1154         # post-interface-rx
1155         #
1156         route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1157                                     table_id=1,
1158                                     paths=[VppRoutePath(self.pg1.remote_ip4,
1159                                                         self.pg1.sw_if_index)])
1160         route_10_0_0_1.add_vpp_config()
1161
1162         #
1163         # An interface receive label that maps traffic to RX on interface
1164         # pg1
1165         # by injecting the packet in on pg0, which is in table 0
1166         # doing an interface-rx on pg1 and matching a route in table 1
1167         # if the packet egresses, then we must have swapped to pg1
1168         # so as to have matched the route in table 1
1169         #
1170         route_34_eos = VppMplsRoute(
1171             self, 34, 1,
1172             [VppRoutePath("0.0.0.0",
1173                           self.pg1.sw_if_index,
1174                           type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)])
1175         route_34_eos.add_vpp_config()
1176
1177         #
1178         # ping an interface in the default table
1179         # PG0 is in the default table
1180         #
1181         tx = self.create_stream_labelled_ip4(self.pg0,
1182                                              [VppMplsLabel(34)],
1183                                              dst_ip="10.0.0.1")
1184         rx = self.send_and_expect(self.pg0, tx, self.pg1)
1185         self.verify_capture_ip4(self.pg1, rx, tx)
1186
1187     def test_mcast_mid_point(self):
1188         """ MPLS Multicast Mid Point """
1189
1190         #
1191         # Add a non-recursive route that will forward the traffic
1192         # post-interface-rx
1193         #
1194         route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1195                                     table_id=1,
1196                                     paths=[VppRoutePath(self.pg1.remote_ip4,
1197                                                         self.pg1.sw_if_index)])
1198         route_10_0_0_1.add_vpp_config()
1199
1200         #
1201         # Add a mcast entry that replicate to pg2 and pg3
1202         # and replicate to a interface-rx (like a bud node would)
1203         #
1204         route_3400_eos = VppMplsRoute(
1205             self, 3400, 1,
1206             [VppRoutePath(self.pg2.remote_ip4,
1207                           self.pg2.sw_if_index,
1208                           labels=[VppMplsLabel(3401)]),
1209              VppRoutePath(self.pg3.remote_ip4,
1210                           self.pg3.sw_if_index,
1211                           labels=[VppMplsLabel(3402)]),
1212              VppRoutePath("0.0.0.0",
1213                           self.pg1.sw_if_index,
1214                           type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)],
1215             is_multicast=1)
1216         route_3400_eos.add_vpp_config()
1217
1218         #
1219         # ping an interface in the default table
1220         # PG0 is in the default table
1221         #
1222         self.vapi.cli("clear trace")
1223         tx = self.create_stream_labelled_ip4(self.pg0,
1224                                              [VppMplsLabel(3400, ttl=64)],
1225                                              n=257,
1226                                              dst_ip="10.0.0.1")
1227         self.pg0.add_stream(tx)
1228
1229         self.pg_enable_capture(self.pg_interfaces)
1230         self.pg_start()
1231
1232         rx = self.pg1.get_capture(257)
1233         self.verify_capture_ip4(self.pg1, rx, tx)
1234
1235         rx = self.pg2.get_capture(257)
1236         self.verify_capture_labelled(self.pg2, rx, tx,
1237                                      [VppMplsLabel(3401, ttl=63)])
1238         rx = self.pg3.get_capture(257)
1239         self.verify_capture_labelled(self.pg3, rx, tx,
1240                                      [VppMplsLabel(3402, ttl=63)])
1241
1242     def test_mcast_head(self):
1243         """ MPLS Multicast Head-end """
1244
1245         #
1246         # Create a multicast tunnel with two replications
1247         #
1248         mpls_tun = VppMPLSTunnelInterface(
1249             self,
1250             [VppRoutePath(self.pg2.remote_ip4,
1251                           self.pg2.sw_if_index,
1252                           labels=[VppMplsLabel(42)]),
1253              VppRoutePath(self.pg3.remote_ip4,
1254                           self.pg3.sw_if_index,
1255                           labels=[VppMplsLabel(43)])],
1256             is_multicast=1)
1257         mpls_tun.add_vpp_config()
1258         mpls_tun.admin_up()
1259
1260         #
1261         # add an unlabelled route through the new tunnel
1262         #
1263         route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1264                                     [VppRoutePath("0.0.0.0",
1265                                                   mpls_tun._sw_if_index)])
1266         route_10_0_0_3.add_vpp_config()
1267
1268         self.vapi.cli("clear trace")
1269         tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1270         self.pg0.add_stream(tx)
1271
1272         self.pg_enable_capture(self.pg_interfaces)
1273         self.pg_start()
1274
1275         rx = self.pg2.get_capture(257)
1276         self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1277         rx = self.pg3.get_capture(257)
1278         self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1279
1280         #
1281         # An an IP multicast route via the tunnel
1282         # A (*,G).
1283         # one accepting interface, pg0, 1 forwarding interface via the tunnel
1284         #
1285         route_232_1_1_1 = VppIpMRoute(
1286             self,
1287             "0.0.0.0",
1288             "232.1.1.1", 32,
1289             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1290             [VppMRoutePath(self.pg0.sw_if_index,
1291                            MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
1292              VppMRoutePath(mpls_tun._sw_if_index,
1293                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1294         route_232_1_1_1.add_vpp_config()
1295         self.logger.info(self.vapi.cli("sh ip mfib index 0"))
1296
1297         self.vapi.cli("clear trace")
1298         tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1299         self.pg0.add_stream(tx)
1300
1301         self.pg_enable_capture(self.pg_interfaces)
1302         self.pg_start()
1303
1304         rx = self.pg2.get_capture(257)
1305         self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1306         rx = self.pg3.get_capture(257)
1307         self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1308
1309     def test_mcast_ip4_tail(self):
1310         """ MPLS IPv4 Multicast Tail """
1311
1312         #
1313         # Add a multicast route that will forward the traffic
1314         # post-disposition
1315         #
1316         route_232_1_1_1 = VppIpMRoute(
1317             self,
1318             "0.0.0.0",
1319             "232.1.1.1", 32,
1320             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1321             table_id=1,
1322             paths=[VppMRoutePath(self.pg1.sw_if_index,
1323                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1324         route_232_1_1_1.add_vpp_config()
1325
1326         #
1327         # An interface receive label that maps traffic to RX on interface
1328         # pg1
1329         # by injecting the packet in on pg0, which is in table 0
1330         # doing an rpf-id  and matching a route in table 1
1331         # if the packet egresses, then we must have matched the route in
1332         # table 1
1333         #
1334         route_34_eos = VppMplsRoute(
1335             self, 34, 1,
1336             [VppRoutePath("0.0.0.0",
1337                           0xffffffff,
1338                           nh_table_id=1,
1339                           rpf_id=55)],
1340             is_multicast=1,
1341             eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)
1342
1343         route_34_eos.add_vpp_config()
1344
1345         #
1346         # Drop due to interface lookup miss
1347         #
1348         self.vapi.cli("clear trace")
1349         tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1350                                              dst_ip="232.1.1.1", n=1)
1351         self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1352
1353         #
1354         # set the RPF-ID of the entry to match the input packet's
1355         #
1356         route_232_1_1_1.update_rpf_id(55)
1357         self.logger.info(self.vapi.cli("sh ip mfib index 1 232.1.1.1"))
1358
1359         tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1360                                              dst_ip="232.1.1.1")
1361         rx = self.send_and_expect(self.pg0, tx, self.pg1)
1362         self.verify_capture_ip4(self.pg1, rx, tx)
1363
1364         #
1365         # disposed packets have an invalid IPv4 checksum
1366         #
1367         tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1368                                              dst_ip="232.1.1.1", n=65,
1369                                              chksum=1)
1370         self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1371
1372         #
1373         # set the RPF-ID of the entry to not match the input packet's
1374         #
1375         route_232_1_1_1.update_rpf_id(56)
1376         tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1377                                              dst_ip="232.1.1.1")
1378         self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1379
1380     def test_mcast_ip6_tail(self):
1381         """ MPLS IPv6 Multicast Tail """
1382
1383         #
1384         # Add a multicast route that will forward the traffic
1385         # post-disposition
1386         #
1387         route_ff = VppIpMRoute(
1388             self,
1389             "::",
1390             "ff01::1", 32,
1391             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1392             table_id=1,
1393             paths=[VppMRoutePath(self.pg1.sw_if_index,
1394                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
1395                                  proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
1396         route_ff.add_vpp_config()
1397
1398         #
1399         # An interface receive label that maps traffic to RX on interface
1400         # pg1
1401         # by injecting the packet in on pg0, which is in table 0
1402         # doing an rpf-id  and matching a route in table 1
1403         # if the packet egresses, then we must have matched the route in
1404         # table 1
1405         #
1406         route_34_eos = VppMplsRoute(
1407             self, 34, 1,
1408             [VppRoutePath("::",
1409                           0xffffffff,
1410                           nh_table_id=1,
1411                           rpf_id=55)],
1412             is_multicast=1,
1413             eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
1414
1415         route_34_eos.add_vpp_config()
1416
1417         #
1418         # Drop due to interface lookup miss
1419         #
1420         tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1421                                              dst_ip="ff01::1")
1422         self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1423
1424         #
1425         # set the RPF-ID of the entry to match the input packet's
1426         #
1427         route_ff.update_rpf_id(55)
1428
1429         tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1430                                              dst_ip="ff01::1")
1431         rx = self.send_and_expect(self.pg0, tx, self.pg1)
1432         self.verify_capture_ip6(self.pg1, rx, tx)
1433
1434         #
1435         # disposed packets have hop-limit = 1
1436         #
1437         tx = self.create_stream_labelled_ip6(self.pg0,
1438                                              [VppMplsLabel(34)],
1439                                              dst_ip="ff01::1",
1440                                              hlim=1)
1441         rx = self.send_and_expect(self.pg0, tx, self.pg0)
1442         self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1443
1444         #
1445         # set the RPF-ID of the entry to not match the input packet's
1446         #
1447         route_ff.update_rpf_id(56)
1448         tx = self.create_stream_labelled_ip6(self.pg0,
1449                                              [VppMplsLabel(34)],
1450                                              dst_ip="ff01::1")
1451         self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1452
1453     def test_6pe(self):
1454         """ MPLS 6PE """
1455
1456         #
1457         # Add a non-recursive route with a single out label
1458         #
1459         route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1460                                     [VppRoutePath(self.pg0.remote_ip4,
1461                                                   self.pg0.sw_if_index,
1462                                                   labels=[VppMplsLabel(45)])])
1463         route_10_0_0_1.add_vpp_config()
1464
1465         # bind a local label to the route
1466         binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
1467         binding.add_vpp_config()
1468
1469         #
1470         # a labelled v6 route that resolves through the v4
1471         #
1472         route_2001_3 = VppIpRoute(
1473             self, "2001::3", 128,
1474             [VppRoutePath("10.0.0.1",
1475                           INVALID_INDEX,
1476                           labels=[VppMplsLabel(32)])])
1477         route_2001_3.add_vpp_config()
1478
1479         tx = self.create_stream_ip6(self.pg0, "2001::3")
1480         rx = self.send_and_expect(self.pg0, tx, self.pg0)
1481
1482         self.verify_capture_labelled_ip6(self.pg0, rx, tx,
1483                                          [VppMplsLabel(45),
1484                                           VppMplsLabel(32)])
1485
1486         #
1487         # and a v4 recursive via the v6
1488         #
1489         route_20_3 = VppIpRoute(
1490             self, "20.0.0.3", 32,
1491             [VppRoutePath("2001::3",
1492                           INVALID_INDEX,
1493                           labels=[VppMplsLabel(99)])])
1494         route_20_3.add_vpp_config()
1495
1496         tx = self.create_stream_ip4(self.pg0, "20.0.0.3")
1497         rx = self.send_and_expect(self.pg0, tx, self.pg0)
1498
1499         self.verify_capture_labelled_ip4(self.pg0, rx, tx,
1500                                          [VppMplsLabel(45),
1501                                           VppMplsLabel(32),
1502                                           VppMplsLabel(99)])
1503
1504
1505 class TestMPLSDisabled(VppTestCase):
1506     """ MPLS disabled """
1507
1508     @classmethod
1509     def setUpClass(cls):
1510         super(TestMPLSDisabled, cls).setUpClass()
1511
1512     @classmethod
1513     def tearDownClass(cls):
1514         super(TestMPLSDisabled, cls).tearDownClass()
1515
1516     def setUp(self):
1517         super(TestMPLSDisabled, self).setUp()
1518
1519         # create 2 pg interfaces
1520         self.create_pg_interfaces(range(2))
1521
1522         self.tbl = VppMplsTable(self, 0)
1523         self.tbl.add_vpp_config()
1524
1525         # PG0 is MPLS enabled
1526         self.pg0.admin_up()
1527         self.pg0.config_ip4()
1528         self.pg0.resolve_arp()
1529         self.pg0.enable_mpls()
1530
1531         # PG 1 is not MPLS enabled
1532         self.pg1.admin_up()
1533
1534     def tearDown(self):
1535         for i in self.pg_interfaces:
1536             i.unconfig_ip4()
1537             i.admin_down()
1538
1539         self.pg0.disable_mpls()
1540         super(TestMPLSDisabled, self).tearDown()
1541
1542     def test_mpls_disabled(self):
1543         """ MPLS Disabled """
1544
1545         tx = (Ether(src=self.pg1.remote_mac,
1546                     dst=self.pg1.local_mac) /
1547               MPLS(label=32, ttl=64) /
1548               IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1549               UDP(sport=1234, dport=1234) /
1550               Raw('\xa5' * 100))
1551
1552         #
1553         # A simple MPLS xconnect - eos label in label out
1554         #
1555         route_32_eos = VppMplsRoute(self, 32, 1,
1556                                     [VppRoutePath(self.pg0.remote_ip4,
1557                                                   self.pg0.sw_if_index,
1558                                                   labels=[33])])
1559         route_32_eos.add_vpp_config()
1560
1561         #
1562         # PG1 does not forward IP traffic
1563         #
1564         self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1565
1566         #
1567         # MPLS enable PG1
1568         #
1569         self.pg1.enable_mpls()
1570
1571         #
1572         # Now we get packets through
1573         #
1574         self.pg1.add_stream(tx)
1575         self.pg_enable_capture(self.pg_interfaces)
1576         self.pg_start()
1577
1578         rx = self.pg0.get_capture(1)
1579
1580         #
1581         # Disable PG1
1582         #
1583         self.pg1.disable_mpls()
1584
1585         #
1586         # PG1 does not forward IP traffic
1587         #
1588         self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1589         self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1590
1591
1592 class TestMPLSPIC(VppTestCase):
1593     """ MPLS Prefix-Independent Convergence (PIC) edge convergence """
1594
1595     @classmethod
1596     def setUpClass(cls):
1597         super(TestMPLSPIC, cls).setUpClass()
1598
1599     @classmethod
1600     def tearDownClass(cls):
1601         super(TestMPLSPIC, cls).tearDownClass()
1602
1603     def setUp(self):
1604         super(TestMPLSPIC, self).setUp()
1605
1606         # create 2 pg interfaces
1607         self.create_pg_interfaces(range(4))
1608
1609         mpls_tbl = VppMplsTable(self, 0)
1610         mpls_tbl.add_vpp_config()
1611         tbl4 = VppIpTable(self, 1)
1612         tbl4.add_vpp_config()
1613         tbl6 = VppIpTable(self, 1, is_ip6=1)
1614         tbl6.add_vpp_config()
1615
1616         # core links
1617         self.pg0.admin_up()
1618         self.pg0.config_ip4()
1619         self.pg0.resolve_arp()
1620         self.pg0.enable_mpls()
1621
1622         self.pg1.admin_up()
1623         self.pg1.config_ip4()
1624         self.pg1.resolve_arp()
1625         self.pg1.enable_mpls()
1626
1627         # VRF (customer facing) link
1628         self.pg2.admin_up()
1629         self.pg2.set_table_ip4(1)
1630         self.pg2.config_ip4()
1631         self.pg2.resolve_arp()
1632         self.pg2.set_table_ip6(1)
1633         self.pg2.config_ip6()
1634         self.pg2.resolve_ndp()
1635
1636         self.pg3.admin_up()
1637         self.pg3.set_table_ip4(1)
1638         self.pg3.config_ip4()
1639         self.pg3.resolve_arp()
1640         self.pg3.set_table_ip6(1)
1641         self.pg3.config_ip6()
1642         self.pg3.resolve_ndp()
1643
1644     def tearDown(self):
1645         self.pg0.disable_mpls()
1646         self.pg1.disable_mpls()
1647         for i in self.pg_interfaces:
1648             i.unconfig_ip4()
1649             i.unconfig_ip6()
1650             i.set_table_ip4(0)
1651             i.set_table_ip6(0)
1652             i.admin_down()
1653         super(TestMPLSPIC, self).tearDown()
1654
1655     def test_mpls_ibgp_pic(self):
1656         """ MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
1657
1658         1) setup many iBGP VPN routes via a pair of iBGP peers.
1659         2) Check EMCP forwarding to these peers
1660         3) withdraw the IGP route to one of these peers.
1661         4) check forwarding continues to the remaining peer
1662         """
1663
1664         #
1665         # IGP+LDP core routes
1666         #
1667         core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1668                                     [VppRoutePath(self.pg0.remote_ip4,
1669                                                   self.pg0.sw_if_index,
1670                                                   labels=[45])])
1671         core_10_0_0_45.add_vpp_config()
1672
1673         core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1674                                     [VppRoutePath(self.pg1.remote_ip4,
1675                                                   self.pg1.sw_if_index,
1676                                                   labels=[46])])
1677         core_10_0_0_46.add_vpp_config()
1678
1679         #
1680         # Lot's of VPN routes. We need more the 64 so VPP will build
1681         # the fast convergence indirection
1682         #
1683         vpn_routes = []
1684         pkts = []
1685         for ii in range(NUM_PKTS):
1686             dst = "192.168.1.%d" % ii
1687             vpn_routes.append(VppIpRoute(
1688                 self, dst, 32,
1689                 [VppRoutePath(
1690                     "10.0.0.45",
1691                     0xffffffff,
1692                     labels=[145],
1693                     flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST),
1694                  VppRoutePath(
1695                      "10.0.0.46",
1696                      0xffffffff,
1697                      labels=[146],
1698                      flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST)],
1699                 table_id=1))
1700             vpn_routes[ii].add_vpp_config()
1701
1702             pkts.append(Ether(dst=self.pg2.local_mac,
1703                               src=self.pg2.remote_mac) /
1704                         IP(src=self.pg2.remote_ip4, dst=dst) /
1705                         UDP(sport=1234, dport=1234) /
1706                         Raw('\xa5' * 100))
1707
1708         #
1709         # Send the packet stream (one pkt to each VPN route)
1710         #  - expect a 50-50 split of the traffic
1711         #
1712         self.pg2.add_stream(pkts)
1713         self.pg_enable_capture(self.pg_interfaces)
1714         self.pg_start()
1715
1716         rx0 = self.pg0._get_capture(NUM_PKTS)
1717         rx1 = self.pg1._get_capture(NUM_PKTS)
1718
1719         # not testing the LB hashing algorithm so we're not concerned
1720         # with the split ratio, just as long as neither is 0
1721         self.assertNotEqual(0, len(rx0))
1722         self.assertNotEqual(0, len(rx1))
1723         self.assertEqual(len(pkts), len(rx0) + len(rx1),
1724                          "Expected all (%s) packets across both ECMP paths. "
1725                          "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1726
1727         #
1728         # use a test CLI command to stop the FIB walk process, this
1729         # will prevent the FIB converging the VPN routes and thus allow
1730         # us to probe the interim (post-fail, pre-converge) state
1731         #
1732         self.vapi.ppcli("test fib-walk-process disable")
1733
1734         #
1735         # Withdraw one of the IGP routes
1736         #
1737         core_10_0_0_46.remove_vpp_config()
1738
1739         #
1740         # now all packets should be forwarded through the remaining peer
1741         #
1742         self.vapi.ppcli("clear trace")
1743         self.pg2.add_stream(pkts)
1744         self.pg_enable_capture(self.pg_interfaces)
1745         self.pg_start()
1746
1747         rx0 = self.pg0.get_capture(NUM_PKTS)
1748         self.assertEqual(len(pkts), len(rx0),
1749                          "Expected all (%s) packets across single path. "
1750                          "rx0: %s." % (len(pkts), len(rx0)))
1751
1752         #
1753         # enable the FIB walk process to converge the FIB
1754         #
1755         self.vapi.ppcli("test fib-walk-process enable")
1756
1757         #
1758         # packets should still be forwarded through the remaining peer
1759         #
1760         self.pg2.add_stream(pkts)
1761         self.pg_enable_capture(self.pg_interfaces)
1762         self.pg_start()
1763
1764         rx0 = self.pg0.get_capture(NUM_PKTS)
1765         self.assertEqual(len(pkts), len(rx0),
1766                          "Expected all (%s) packets across single path. "
1767                          "rx0: %s." % (len(pkts), len(rx0)))
1768
1769         #
1770         # Add the IGP route back and we return to load-balancing
1771         #
1772         core_10_0_0_46.add_vpp_config()
1773
1774         self.pg2.add_stream(pkts)
1775         self.pg_enable_capture(self.pg_interfaces)
1776         self.pg_start()
1777
1778         rx0 = self.pg0._get_capture(NUM_PKTS)
1779         rx1 = self.pg1._get_capture(NUM_PKTS)
1780         self.assertNotEqual(0, len(rx0))
1781         self.assertNotEqual(0, len(rx1))
1782         self.assertEqual(len(pkts), len(rx0) + len(rx1),
1783                          "Expected all (%s) packets across both ECMP paths. "
1784                          "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1785
1786     def test_mpls_ebgp_pic(self):
1787         """ MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
1788
1789         1) setup many eBGP VPN routes via a pair of eBGP peers.
1790         2) Check EMCP forwarding to these peers
1791         3) withdraw one eBGP path - expect LB across remaining eBGP
1792         """
1793
1794         #
1795         # Lot's of VPN routes. We need more the 64 so VPP will build
1796         # the fast convergence indirection
1797         #
1798         vpn_routes = []
1799         vpn_bindings = []
1800         pkts = []
1801         for ii in range(NUM_PKTS):
1802             dst = "192.168.1.%d" % ii
1803             local_label = 1600 + ii
1804             vpn_routes.append(VppIpRoute(
1805                 self, dst, 32,
1806                 [VppRoutePath(
1807                     self.pg2.remote_ip4,
1808                     0xffffffff,
1809                     nh_table_id=1,
1810                     flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1811                  VppRoutePath(
1812                      self.pg3.remote_ip4,
1813                      0xffffffff,
1814                      nh_table_id=1,
1815                      flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1816                 table_id=1))
1817             vpn_routes[ii].add_vpp_config()
1818
1819             vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1820                                               ip_table_id=1))
1821             vpn_bindings[ii].add_vpp_config()
1822
1823             pkts.append(Ether(dst=self.pg0.local_mac,
1824                               src=self.pg0.remote_mac) /
1825                         MPLS(label=local_label, ttl=64) /
1826                         IP(src=self.pg0.remote_ip4, dst=dst) /
1827                         UDP(sport=1234, dport=1234) /
1828                         Raw('\xa5' * 100))
1829
1830         #
1831         # Send the packet stream (one pkt to each VPN route)
1832         #  - expect a 50-50 split of the traffic
1833         #
1834         self.pg0.add_stream(pkts)
1835         self.pg_enable_capture(self.pg_interfaces)
1836         self.pg_start()
1837
1838         rx0 = self.pg2._get_capture(NUM_PKTS)
1839         rx1 = self.pg3._get_capture(NUM_PKTS)
1840
1841         # not testing the LB hashing algorithm so we're not concerned
1842         # with the split ratio, just as long as neither is 0
1843         self.assertNotEqual(0, len(rx0))
1844         self.assertNotEqual(0, len(rx1))
1845         self.assertEqual(len(pkts), len(rx0) + len(rx1),
1846                          "Expected all (%s) packets across both ECMP paths. "
1847                          "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1848
1849         #
1850         # use a test CLI command to stop the FIB walk process, this
1851         # will prevent the FIB converging the VPN routes and thus allow
1852         # us to probe the interim (post-fail, pre-converge) state
1853         #
1854         self.vapi.ppcli("test fib-walk-process disable")
1855
1856         #
1857         # withdraw the connected prefix on the interface.
1858         #
1859         self.pg2.unconfig_ip4()
1860
1861         #
1862         # now all packets should be forwarded through the remaining peer
1863         #
1864         self.pg0.add_stream(pkts)
1865         self.pg_enable_capture(self.pg_interfaces)
1866         self.pg_start()
1867
1868         rx0 = self.pg3.get_capture(NUM_PKTS)
1869         self.assertEqual(len(pkts), len(rx0),
1870                          "Expected all (%s) packets across single path. "
1871                          "rx0: %s." % (len(pkts), len(rx0)))
1872
1873         #
1874         # enable the FIB walk process to converge the FIB
1875         #
1876         self.vapi.ppcli("test fib-walk-process enable")
1877
1878         #
1879         # packets should still be forwarded through the remaining peer
1880         #
1881         self.pg0.add_stream(pkts)
1882         self.pg_enable_capture(self.pg_interfaces)
1883         self.pg_start()
1884
1885         rx0 = self.pg3.get_capture(NUM_PKTS)
1886         self.assertEqual(len(pkts), len(rx0),
1887                          "Expected all (%s) packets across single path. "
1888                          "rx0: %s." % (len(pkts), len(rx0)))
1889
1890         #
1891         # put the connected routes back
1892         #
1893         self.pg2.config_ip4()
1894         self.pg2.resolve_arp()
1895
1896         self.pg0.add_stream(pkts)
1897         self.pg_enable_capture(self.pg_interfaces)
1898         self.pg_start()
1899
1900         rx0 = self.pg2._get_capture(NUM_PKTS)
1901         rx1 = self.pg3._get_capture(NUM_PKTS)
1902         self.assertNotEqual(0, len(rx0))
1903         self.assertNotEqual(0, len(rx1))
1904         self.assertEqual(len(pkts), len(rx0) + len(rx1),
1905                          "Expected all (%s) packets across both ECMP paths. "
1906                          "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1907
1908     def test_mpls_v6_ebgp_pic(self):
1909         """ MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
1910
1911         1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1912         2) Check EMCP forwarding to these peers
1913         3) withdraw one eBGP path - expect LB across remaining eBGP
1914         """
1915
1916         #
1917         # Lot's of VPN routes. We need more the 64 so VPP will build
1918         # the fast convergence indirection
1919         #
1920         vpn_routes = []
1921         vpn_bindings = []
1922         pkts = []
1923         for ii in range(NUM_PKTS):
1924             dst = "3000::%d" % ii
1925             local_label = 1600 + ii
1926             vpn_routes.append(VppIpRoute(
1927                 self, dst, 128,
1928                 [VppRoutePath(
1929                     self.pg2.remote_ip6,
1930                     0xffffffff,
1931                     nh_table_id=1,
1932                     flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1933                  VppRoutePath(
1934                      self.pg3.remote_ip6,
1935                      0xffffffff,
1936                      nh_table_id=1,
1937                      flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1938                 table_id=1))
1939             vpn_routes[ii].add_vpp_config()
1940
1941             vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1942                                               ip_table_id=1))
1943             vpn_bindings[ii].add_vpp_config()
1944
1945             pkts.append(Ether(dst=self.pg0.local_mac,
1946                               src=self.pg0.remote_mac) /
1947                         MPLS(label=local_label, ttl=64) /
1948                         IPv6(src=self.pg0.remote_ip6, dst=dst) /
1949                         UDP(sport=1234, dport=1234) /
1950                         Raw('\xa5' * 100))
1951             self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
1952
1953         self.pg0.add_stream(pkts)
1954         self.pg_enable_capture(self.pg_interfaces)
1955         self.pg_start()
1956
1957         rx0 = self.pg2._get_capture(NUM_PKTS)
1958         rx1 = self.pg3._get_capture(NUM_PKTS)
1959         self.assertNotEqual(0, len(rx0))
1960         self.assertNotEqual(0, len(rx1))
1961         self.assertEqual(len(pkts), len(rx0) + len(rx1),
1962                          "Expected all (%s) packets across both ECMP paths. "
1963                          "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1964
1965         #
1966         # use a test CLI command to stop the FIB walk process, this
1967         # will prevent the FIB converging the VPN routes and thus allow
1968         # us to probe the interim (post-fail, pre-converge) state
1969         #
1970         self.vapi.ppcli("test fib-walk-process disable")
1971
1972         #
1973         # withdraw the connected prefix on the interface.
1974         # and shutdown the interface so the ND cache is flushed.
1975         #
1976         self.pg2.unconfig_ip6()
1977         self.pg2.admin_down()
1978
1979         #
1980         # now all packets should be forwarded through the remaining peer
1981         #
1982         self.pg0.add_stream(pkts)
1983         self.pg_enable_capture(self.pg_interfaces)
1984         self.pg_start()
1985
1986         rx0 = self.pg3.get_capture(NUM_PKTS)
1987         self.assertEqual(len(pkts), len(rx0),
1988                          "Expected all (%s) packets across single path. "
1989                          "rx0: %s." % (len(pkts), len(rx0)))
1990
1991         #
1992         # enable the FIB walk process to converge the FIB
1993         #
1994         self.vapi.ppcli("test fib-walk-process enable")
1995         self.pg0.add_stream(pkts)
1996         self.pg_enable_capture(self.pg_interfaces)
1997         self.pg_start()
1998
1999         rx0 = self.pg3.get_capture(NUM_PKTS)
2000         self.assertEqual(len(pkts), len(rx0),
2001                          "Expected all (%s) packets across single path. "
2002                          "rx0: %s." % (len(pkts), len(rx0)))
2003
2004         #
2005         # put the connected routes back
2006         #
2007         self.pg2.admin_up()
2008         self.pg2.config_ip6()
2009         self.pg2.resolve_ndp()
2010
2011         self.pg0.add_stream(pkts)
2012         self.pg_enable_capture(self.pg_interfaces)
2013         self.pg_start()
2014
2015         rx0 = self.pg2._get_capture(NUM_PKTS)
2016         rx1 = self.pg3._get_capture(NUM_PKTS)
2017         self.assertNotEqual(0, len(rx0))
2018         self.assertNotEqual(0, len(rx1))
2019         self.assertEqual(len(pkts), len(rx0) + len(rx1),
2020                          "Expected all (%s) packets across both ECMP paths. "
2021                          "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2022
2023
2024 class TestMPLSL2(VppTestCase):
2025     """ MPLS-L2 """
2026
2027     @classmethod
2028     def setUpClass(cls):
2029         super(TestMPLSL2, cls).setUpClass()
2030
2031     @classmethod
2032     def tearDownClass(cls):
2033         super(TestMPLSL2, cls).tearDownClass()
2034
2035     def setUp(self):
2036         super(TestMPLSL2, self).setUp()
2037
2038         # create 2 pg interfaces
2039         self.create_pg_interfaces(range(2))
2040
2041         # create the default MPLS table
2042         self.tables = []
2043         tbl = VppMplsTable(self, 0)
2044         tbl.add_vpp_config()
2045         self.tables.append(tbl)
2046
2047         # use pg0 as the core facing interface
2048         self.pg0.admin_up()
2049         self.pg0.config_ip4()
2050         self.pg0.resolve_arp()
2051         self.pg0.enable_mpls()
2052
2053         # use the other 2 for customer facing L2 links
2054         for i in self.pg_interfaces[1:]:
2055             i.admin_up()
2056
2057     def tearDown(self):
2058         for i in self.pg_interfaces[1:]:
2059             i.admin_down()
2060
2061         self.pg0.disable_mpls()
2062         self.pg0.unconfig_ip4()
2063         self.pg0.admin_down()
2064         super(TestMPLSL2, self).tearDown()
2065
2066     def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
2067         capture = verify_filter(capture, sent)
2068
2069         self.assertEqual(len(capture), len(sent))
2070
2071         for i in range(len(capture)):
2072             tx = sent[i]
2073             rx = capture[i]
2074
2075             # the MPLS TTL is 255 since it enters a new tunnel
2076             verify_mpls_stack(self, rx, mpls_labels)
2077
2078             tx_eth = tx[Ether]
2079             rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
2080
2081             self.assertEqual(rx_eth.src, tx_eth.src)
2082             self.assertEqual(rx_eth.dst, tx_eth.dst)
2083
2084     def test_vpws(self):
2085         """ Virtual Private Wire Service """
2086
2087         #
2088         # Create an MPLS tunnel that pushes 1 label
2089         # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
2090         # information is not in the packet, but we test it works anyway
2091         #
2092         mpls_tun_1 = VppMPLSTunnelInterface(
2093             self,
2094             [VppRoutePath(self.pg0.remote_ip4,
2095                           self.pg0.sw_if_index,
2096                           labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
2097             is_l2=1)
2098         mpls_tun_1.add_vpp_config()
2099         mpls_tun_1.admin_up()
2100
2101         #
2102         # Create a label entry to for 55 that does L2 input to the tunnel
2103         #
2104         route_55_eos = VppMplsRoute(
2105             self, 55, 1,
2106             [VppRoutePath("0.0.0.0",
2107                           mpls_tun_1.sw_if_index,
2108                           type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2109                           proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2110             eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2111         route_55_eos.add_vpp_config()
2112
2113         #
2114         # Cross-connect the tunnel with one of the customers L2 interfaces
2115         #
2116         self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
2117                                                mpls_tun_1.sw_if_index,
2118                                                enable=1)
2119         self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
2120                                                self.pg1.sw_if_index,
2121                                                enable=1)
2122
2123         #
2124         # inject a packet from the core
2125         #
2126         pcore = (Ether(dst=self.pg0.local_mac,
2127                        src=self.pg0.remote_mac) /
2128                  MPLS(label=55, ttl=64) /
2129                  Ether(dst="00:00:de:ad:ba:be",
2130                        src="00:00:de:ad:be:ef") /
2131                  IP(src="10.10.10.10", dst="11.11.11.11") /
2132                  UDP(sport=1234, dport=1234) /
2133                  Raw('\xa5' * 100))
2134
2135         tx0 = pcore * NUM_PKTS
2136         rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2137         payload = pcore[MPLS].payload
2138
2139         self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2140         self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2141
2142         #
2143         # Inject a packet from the customer/L2 side
2144         #
2145         tx1 = pcore[MPLS].payload * NUM_PKTS
2146         rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
2147
2148         self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
2149
2150     def test_vpls(self):
2151         """ Virtual Private LAN Service """
2152         #
2153         # Create a L2 MPLS tunnels
2154         #
2155         mpls_tun1 = VppMPLSTunnelInterface(
2156             self,
2157             [VppRoutePath(self.pg0.remote_ip4,
2158                           self.pg0.sw_if_index,
2159                           labels=[VppMplsLabel(42)])],
2160             is_l2=1)
2161         mpls_tun1.add_vpp_config()
2162         mpls_tun1.admin_up()
2163
2164         mpls_tun2 = VppMPLSTunnelInterface(
2165             self,
2166             [VppRoutePath(self.pg0.remote_ip4,
2167                           self.pg0.sw_if_index,
2168                           labels=[VppMplsLabel(43)])],
2169             is_l2=1)
2170         mpls_tun2.add_vpp_config()
2171         mpls_tun2.admin_up()
2172
2173         #
2174         # Create a label entries, 55 and 56, that do L2 input to the tunnel
2175         # the latter includes a Psuedo Wire Control Word
2176         #
2177         route_55_eos = VppMplsRoute(
2178             self, 55, 1,
2179             [VppRoutePath("0.0.0.0",
2180                           mpls_tun1.sw_if_index,
2181                           type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2182                           proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2183             eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2184
2185         route_56_eos = VppMplsRoute(
2186             self, 56, 1,
2187             [VppRoutePath("0.0.0.0",
2188                           mpls_tun2.sw_if_index,
2189                           type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2190                           flags=FibPathFlags.FIB_PATH_FLAG_POP_PW_CW,
2191                           proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2192             eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2193
2194         # move me
2195         route_56_eos.add_vpp_config()
2196         route_55_eos.add_vpp_config()
2197
2198         self.logger.info(self.vapi.cli("sh mpls fib 56"))
2199
2200         #
2201         # add to tunnel to the customers bridge-domain
2202         #
2203         self.vapi.sw_interface_set_l2_bridge(
2204             rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1)
2205         self.vapi.sw_interface_set_l2_bridge(
2206             rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1)
2207         self.vapi.sw_interface_set_l2_bridge(
2208             rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
2209
2210         #
2211         # Packet from host on the customer interface to each host
2212         # reachable over the core, and vice-versa
2213         #
2214         p_cust1 = (Ether(dst="00:00:de:ad:ba:b1",
2215                          src="00:00:de:ad:be:ef") /
2216                    IP(src="10.10.10.10", dst="11.11.11.11") /
2217                    UDP(sport=1234, dport=1234) /
2218                    Raw('\xa5' * 100))
2219         p_cust2 = (Ether(dst="00:00:de:ad:ba:b2",
2220                          src="00:00:de:ad:be:ef") /
2221                    IP(src="10.10.10.10", dst="11.11.11.12") /
2222                    UDP(sport=1234, dport=1234) /
2223                    Raw('\xa5' * 100))
2224         p_core1 = (Ether(dst=self.pg0.local_mac,
2225                          src=self.pg0.remote_mac) /
2226                    MPLS(label=55, ttl=64) /
2227                    Ether(src="00:00:de:ad:ba:b1",
2228                          dst="00:00:de:ad:be:ef") /
2229                    IP(dst="10.10.10.10", src="11.11.11.11") /
2230                    UDP(sport=1234, dport=1234) /
2231                    Raw('\xa5' * 100))
2232         p_core2 = (Ether(dst=self.pg0.local_mac,
2233                          src=self.pg0.remote_mac) /
2234                    MPLS(label=56, ttl=64) /
2235                    Raw('\x01' * 4) /  # PW CW
2236                    Ether(src="00:00:de:ad:ba:b2",
2237                          dst="00:00:de:ad:be:ef") /
2238                    IP(dst="10.10.10.10", src="11.11.11.12") /
2239                    UDP(sport=1234, dport=1234) /
2240                    Raw('\xa5' * 100))
2241
2242         #
2243         # The BD is learning, so send in one of each packet to learn
2244         #
2245
2246         # 2 packets due to BD flooding
2247         rx = self.send_and_expect(self.pg1, p_cust1, self.pg0, n_rx=2)
2248         rx = self.send_and_expect(self.pg1, p_cust2, self.pg0, n_rx=2)
2249
2250         # we've learnt this so expect it be be forwarded not flooded
2251         rx = self.send_and_expect(self.pg0, [p_core1], self.pg1)
2252         self.assertEqual(rx[0][Ether].dst, p_cust1[Ether].src)
2253         self.assertEqual(rx[0][Ether].src, p_cust1[Ether].dst)
2254
2255         rx = self.send_and_expect(self.pg0, [p_core2], self.pg1)
2256         self.assertEqual(rx[0][Ether].dst, p_cust2[Ether].src)
2257         self.assertEqual(rx[0][Ether].src, p_cust2[Ether].dst)
2258
2259         #
2260         # now a stream in each direction from each host
2261         #
2262         rx = self.send_and_expect(self.pg1, p_cust1 * NUM_PKTS, self.pg0)
2263         self.verify_capture_tunneled_ethernet(rx, p_cust1 * NUM_PKTS,
2264                                               [VppMplsLabel(42)])
2265
2266         rx = self.send_and_expect(self.pg1, p_cust2 * NUM_PKTS, self.pg0)
2267         self.verify_capture_tunneled_ethernet(rx, p_cust2 * NUM_PKTS,
2268                                               [VppMplsLabel(43)])
2269
2270         rx = self.send_and_expect(self.pg0, p_core1 * NUM_PKTS, self.pg1)
2271         rx = self.send_and_expect(self.pg0, p_core2 * NUM_PKTS, self.pg1)
2272
2273         #
2274         # remove interfaces from customers bridge-domain
2275         #
2276         self.vapi.sw_interface_set_l2_bridge(
2277             rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1, enable=0)
2278         self.vapi.sw_interface_set_l2_bridge(
2279             rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1, enable=0)
2280         self.vapi.sw_interface_set_l2_bridge(
2281             rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
2282
2283
2284 if __name__ == '__main__':
2285     unittest.main(testRunner=VppTestRunner)