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