udp: remove buggy assert in udp encap
[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, icmptypes, icmpcodes
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             self.assertEqual(icmptypes[rx[ICMP].type], "dest-unreach")
965             self.assertEqual(icmpcodes[rx[ICMP].type][rx[ICMP].code],
966                              "fragmentation-needed")
967             # the link MTU is 9000, the MPLS over head is 4 bytes
968             self.assertEqual(rx[ICMP].nexthopmtu, 9000 - 4)
969
970         self.assertEqual(self.statistics.get_err_counter(
971             "/err/mpls-frag/can't fragment this packet"),
972                          len(tx))
973         #
974         # a stream that matches the route for 1000::1/128
975         # PG0 is in the default table
976         #
977         tx = self.create_stream_ip6(self.pg0, "1000::1")
978         for i in range(0, 257):
979             self.extend_packet(tx[i], 10000)
980
981         rxs = self.send_and_expect_some(self.pg0, tx, self.pg0)
982         for rx in rxs:
983             self.assertEqual(rx[ICMPv6PacketTooBig].mtu, 9000 - 4)
984
985         #
986         # cleanup
987         #
988         route_10_0_0_1.remove_vpp_config()
989
990     def test_tunnel_pipe(self):
991         """ MPLS Tunnel Tests - Pipe """
992
993         #
994         # Create a tunnel with two out labels
995         #
996         mpls_tun = VppMPLSTunnelInterface(
997             self,
998             [VppRoutePath(self.pg0.remote_ip4,
999                           self.pg0.sw_if_index,
1000                           labels=[VppMplsLabel(44),
1001                                   VppMplsLabel(46)])])
1002         mpls_tun.add_vpp_config()
1003         mpls_tun.admin_up()
1004
1005         #
1006         # add an unlabelled route through the new tunnel
1007         #
1008         route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1009                                     [VppRoutePath("0.0.0.0",
1010                                                   mpls_tun._sw_if_index)])
1011         route_10_0_0_3.add_vpp_config()
1012
1013         self.vapi.cli("clear trace")
1014         tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1015         self.pg0.add_stream(tx)
1016
1017         self.pg_enable_capture(self.pg_interfaces)
1018         self.pg_start()
1019
1020         rx = self.pg0.get_capture()
1021         self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1022                                          [VppMplsLabel(44),
1023                                           VppMplsLabel(46)])
1024
1025         #
1026         # add a labelled route through the new tunnel
1027         #
1028         route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
1029                                     [VppRoutePath("0.0.0.0",
1030                                                   mpls_tun._sw_if_index,
1031                                                   labels=[33])])
1032         route_10_0_0_4.add_vpp_config()
1033
1034         self.vapi.cli("clear trace")
1035         tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1036         self.pg0.add_stream(tx)
1037
1038         self.pg_enable_capture(self.pg_interfaces)
1039         self.pg_start()
1040
1041         rx = self.pg0.get_capture()
1042         self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1043                                          [VppMplsLabel(44),
1044                                           VppMplsLabel(46),
1045                                           VppMplsLabel(33, ttl=255)])
1046
1047         #
1048         # change tunnel's MTU to a low value
1049         #
1050         mpls_tun.set_l3_mtu(1200)
1051
1052         # send IP into the tunnel to be fragmented
1053         tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
1054                                     payload_size=1500)
1055         rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx)*2)
1056
1057         fake_tx = []
1058         for p in tx:
1059             fake_tx.append(p)
1060             fake_tx.append(p)
1061         self.verify_capture_tunneled_ip4(self.pg0, rx, fake_tx,
1062                                          [VppMplsLabel(44),
1063                                           VppMplsLabel(46)])
1064
1065         # send MPLS into the tunnel to be fragmented
1066         tx = self.create_stream_ip4(self.pg0, "10.0.0.4",
1067                                     payload_size=1500)
1068         rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx)*2)
1069
1070         fake_tx = []
1071         for p in tx:
1072             fake_tx.append(p)
1073             fake_tx.append(p)
1074         self.verify_capture_tunneled_ip4(self.pg0, rx, fake_tx,
1075                                          [VppMplsLabel(44),
1076                                           VppMplsLabel(46),
1077                                           VppMplsLabel(33, ttl=255)])
1078
1079     def test_tunnel_uniform(self):
1080         """ MPLS Tunnel Tests - Uniform """
1081
1082         #
1083         # Create a tunnel with a single out label
1084         # The label stack is specified here from outer to inner
1085         #
1086         mpls_tun = VppMPLSTunnelInterface(
1087             self,
1088             [VppRoutePath(self.pg0.remote_ip4,
1089                           self.pg0.sw_if_index,
1090                           labels=[VppMplsLabel(44, ttl=32),
1091                                   VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1092         mpls_tun.add_vpp_config()
1093         mpls_tun.admin_up()
1094
1095         #
1096         # add an unlabelled route through the new tunnel
1097         #
1098         route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1099                                     [VppRoutePath("0.0.0.0",
1100                                                   mpls_tun._sw_if_index)])
1101         route_10_0_0_3.add_vpp_config()
1102
1103         self.vapi.cli("clear trace")
1104         tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
1105         self.pg0.add_stream(tx)
1106
1107         self.pg_enable_capture(self.pg_interfaces)
1108         self.pg_start()
1109
1110         rx = self.pg0.get_capture()
1111         self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1112                                          [VppMplsLabel(44, ttl=32),
1113                                           VppMplsLabel(46, ttl=23)])
1114
1115         #
1116         # add a labelled route through the new tunnel
1117         #
1118         route_10_0_0_4 = VppIpRoute(
1119             self, "10.0.0.4", 32,
1120             [VppRoutePath("0.0.0.0",
1121                           mpls_tun._sw_if_index,
1122                           labels=[VppMplsLabel(33, ttl=47)])])
1123         route_10_0_0_4.add_vpp_config()
1124
1125         self.vapi.cli("clear trace")
1126         tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1127         self.pg0.add_stream(tx)
1128
1129         self.pg_enable_capture(self.pg_interfaces)
1130         self.pg_start()
1131
1132         rx = self.pg0.get_capture()
1133         self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1134                                          [VppMplsLabel(44, ttl=32),
1135                                           VppMplsLabel(46, ttl=47),
1136                                           VppMplsLabel(33, ttl=47)])
1137
1138     def test_mpls_tunnel_many(self):
1139         """ MPLS Multiple Tunnels """
1140
1141         for ii in range(100):
1142             mpls_tun = VppMPLSTunnelInterface(
1143                 self,
1144                 [VppRoutePath(self.pg0.remote_ip4,
1145                               self.pg0.sw_if_index,
1146                               labels=[VppMplsLabel(44, ttl=32),
1147                                       VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1148             mpls_tun.add_vpp_config()
1149             mpls_tun.admin_up()
1150         for ii in range(100):
1151             mpls_tun = VppMPLSTunnelInterface(
1152                 self,
1153                 [VppRoutePath(self.pg0.remote_ip4,
1154                               self.pg0.sw_if_index,
1155                               labels=[VppMplsLabel(44, ttl=32),
1156                                       VppMplsLabel(46, MplsLspMode.UNIFORM)])],
1157                 is_l2=1)
1158             mpls_tun.add_vpp_config()
1159             mpls_tun.admin_up()
1160
1161     def test_v4_exp_null(self):
1162         """ MPLS V4 Explicit NULL test """
1163
1164         #
1165         # The first test case has an MPLS TTL of 0
1166         # all packet should be dropped
1167         #
1168         tx = self.create_stream_labelled_ip4(self.pg0,
1169                                              [VppMplsLabel(0, ttl=0)])
1170         self.send_and_assert_no_replies(self.pg0, tx,
1171                                         "MPLS TTL=0 packets forwarded")
1172
1173         #
1174         # a stream with a non-zero MPLS TTL
1175         # PG0 is in the default table
1176         #
1177         tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
1178         rx = self.send_and_expect(self.pg0, tx, self.pg0)
1179         self.verify_capture_ip4(self.pg0, rx, tx)
1180
1181         #
1182         # a stream with a non-zero MPLS TTL
1183         # PG1 is in table 1
1184         # we are ensuring the post-pop lookup occurs in the VRF table
1185         #
1186         tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
1187         rx = self.send_and_expect(self.pg1, tx, self.pg1)
1188         self.verify_capture_ip4(self.pg1, rx, tx)
1189
1190     def test_v6_exp_null(self):
1191         """ MPLS V6 Explicit NULL test """
1192
1193         #
1194         # a stream with a non-zero MPLS TTL
1195         # PG0 is in the default table
1196         #
1197         tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1198         rx = self.send_and_expect(self.pg0, tx, self.pg0)
1199         self.verify_capture_ip6(self.pg0, rx, tx)
1200
1201         #
1202         # a stream with a non-zero MPLS TTL
1203         # PG1 is in table 1
1204         # we are ensuring the post-pop lookup occurs in the VRF table
1205         #
1206         tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1207         rx = self.send_and_expect(self.pg1, tx, self.pg1)
1208         self.verify_capture_ip6(self.pg0, rx, tx)
1209
1210     def test_deag(self):
1211         """ MPLS Deagg """
1212
1213         #
1214         # A de-agg route - next-hop lookup in default table
1215         #
1216         route_34_eos = VppMplsRoute(self, 34, 1,
1217                                     [VppRoutePath("0.0.0.0",
1218                                                   0xffffffff,
1219                                                   nh_table_id=0)])
1220         route_34_eos.add_vpp_config()
1221
1222         #
1223         # ping an interface in the default table
1224         # PG0 is in the default table
1225         #
1226         tx = self.create_stream_labelled_ip4(self.pg0,
1227                                              [VppMplsLabel(34)],
1228                                              ping=1,
1229                                              ip_itf=self.pg0)
1230         rx = self.send_and_expect(self.pg0, tx, self.pg0)
1231         self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1232
1233         #
1234         # A de-agg route - next-hop lookup in non-default table
1235         #
1236         route_35_eos = VppMplsRoute(self, 35, 1,
1237                                     [VppRoutePath("0.0.0.0",
1238                                                   0xffffffff,
1239                                                   nh_table_id=1)])
1240         route_35_eos.add_vpp_config()
1241         route_356_eos = VppMplsRoute(
1242             self, 356, 1,
1243             [VppRoutePath("0::0",
1244                           0xffffffff,
1245                           nh_table_id=1)],
1246             eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
1247         route_356_eos.add_vpp_config()
1248
1249         #
1250         # ping an interface in the non-default table
1251         # PG0 is in the default table. packet arrive labelled in the
1252         # default table and egress unlabelled in the non-default
1253         #
1254         tx = self.create_stream_labelled_ip4(
1255             self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1256         rx = self.send_and_expect(self.pg0, tx, self.pg1)
1257         self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1258         tx = self.create_stream_labelled_ip6(
1259             self.pg0, [VppMplsLabel(356)], ping=1, ip_itf=self.pg1)
1260         rx = self.send_and_expect(self.pg0, tx, self.pg1)
1261         self.verify_capture_ip6(self.pg1, rx, tx, ping_resp=1)
1262
1263         #
1264         # Double pop
1265         #
1266         route_36_neos = VppMplsRoute(self, 36, 0,
1267                                      [VppRoutePath("0.0.0.0",
1268                                                    0xffffffff)])
1269         route_36_neos.add_vpp_config()
1270
1271         tx = self.create_stream_labelled_ip4(self.pg0,
1272                                              [VppMplsLabel(36),
1273                                               VppMplsLabel(35)],
1274                                              ping=1, ip_itf=self.pg1)
1275         rx = self.send_and_expect(self.pg0, tx, self.pg1)
1276         self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1277
1278         route_36_neos.remove_vpp_config()
1279         route_35_eos.remove_vpp_config()
1280         route_34_eos.remove_vpp_config()
1281
1282     def test_interface_rx(self):
1283         """ MPLS Interface Receive """
1284
1285         #
1286         # Add a non-recursive route that will forward the traffic
1287         # post-interface-rx
1288         #
1289         route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1290                                     table_id=1,
1291                                     paths=[VppRoutePath(self.pg1.remote_ip4,
1292                                                         self.pg1.sw_if_index)])
1293         route_10_0_0_1.add_vpp_config()
1294
1295         #
1296         # An interface receive label that maps traffic to RX on interface
1297         # pg1
1298         # by injecting the packet in on pg0, which is in table 0
1299         # doing an interface-rx on pg1 and matching a route in table 1
1300         # if the packet egresses, then we must have swapped to pg1
1301         # so as to have matched the route in table 1
1302         #
1303         route_34_eos = VppMplsRoute(
1304             self, 34, 1,
1305             [VppRoutePath("0.0.0.0",
1306                           self.pg1.sw_if_index,
1307                           type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)])
1308         route_34_eos.add_vpp_config()
1309
1310         #
1311         # ping an interface in the default table
1312         # PG0 is in the default table
1313         #
1314         tx = self.create_stream_labelled_ip4(self.pg0,
1315                                              [VppMplsLabel(34)],
1316                                              dst_ip="10.0.0.1")
1317         rx = self.send_and_expect(self.pg0, tx, self.pg1)
1318         self.verify_capture_ip4(self.pg1, rx, tx)
1319
1320     def test_mcast_mid_point(self):
1321         """ MPLS Multicast Mid Point """
1322
1323         #
1324         # Add a non-recursive route that will forward the traffic
1325         # post-interface-rx
1326         #
1327         route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1328                                     table_id=1,
1329                                     paths=[VppRoutePath(self.pg1.remote_ip4,
1330                                                         self.pg1.sw_if_index)])
1331         route_10_0_0_1.add_vpp_config()
1332
1333         #
1334         # Add a mcast entry that replicate to pg2 and pg3
1335         # and replicate to a interface-rx (like a bud node would)
1336         #
1337         route_3400_eos = VppMplsRoute(
1338             self, 3400, 1,
1339             [VppRoutePath(self.pg2.remote_ip4,
1340                           self.pg2.sw_if_index,
1341                           labels=[VppMplsLabel(3401)]),
1342              VppRoutePath(self.pg3.remote_ip4,
1343                           self.pg3.sw_if_index,
1344                           labels=[VppMplsLabel(3402)]),
1345              VppRoutePath("0.0.0.0",
1346                           self.pg1.sw_if_index,
1347                           type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)],
1348             is_multicast=1)
1349         route_3400_eos.add_vpp_config()
1350
1351         #
1352         # ping an interface in the default table
1353         # PG0 is in the default table
1354         #
1355         self.vapi.cli("clear trace")
1356         tx = self.create_stream_labelled_ip4(self.pg0,
1357                                              [VppMplsLabel(3400, ttl=64)],
1358                                              n=257,
1359                                              dst_ip="10.0.0.1")
1360         self.pg0.add_stream(tx)
1361
1362         self.pg_enable_capture(self.pg_interfaces)
1363         self.pg_start()
1364
1365         rx = self.pg1.get_capture(257)
1366         self.verify_capture_ip4(self.pg1, rx, tx)
1367
1368         rx = self.pg2.get_capture(257)
1369         self.verify_capture_labelled(self.pg2, rx, tx,
1370                                      [VppMplsLabel(3401, ttl=63)])
1371         rx = self.pg3.get_capture(257)
1372         self.verify_capture_labelled(self.pg3, rx, tx,
1373                                      [VppMplsLabel(3402, ttl=63)])
1374
1375     def test_mcast_head(self):
1376         """ MPLS Multicast Head-end """
1377
1378         MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1379         MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1380
1381         #
1382         # Create a multicast tunnel with two replications
1383         #
1384         mpls_tun = VppMPLSTunnelInterface(
1385             self,
1386             [VppRoutePath(self.pg2.remote_ip4,
1387                           self.pg2.sw_if_index,
1388                           labels=[VppMplsLabel(42)]),
1389              VppRoutePath(self.pg3.remote_ip4,
1390                           self.pg3.sw_if_index,
1391                           labels=[VppMplsLabel(43)])],
1392             is_multicast=1)
1393         mpls_tun.add_vpp_config()
1394         mpls_tun.admin_up()
1395
1396         #
1397         # add an unlabelled route through the new tunnel
1398         #
1399         route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1400                                     [VppRoutePath("0.0.0.0",
1401                                                   mpls_tun._sw_if_index)])
1402         route_10_0_0_3.add_vpp_config()
1403
1404         self.vapi.cli("clear trace")
1405         tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1406         self.pg0.add_stream(tx)
1407
1408         self.pg_enable_capture(self.pg_interfaces)
1409         self.pg_start()
1410
1411         rx = self.pg2.get_capture(257)
1412         self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1413         rx = self.pg3.get_capture(257)
1414         self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1415
1416         #
1417         # An an IP multicast route via the tunnel
1418         # A (*,G).
1419         # one accepting interface, pg0, 1 forwarding interface via the tunnel
1420         #
1421         route_232_1_1_1 = VppIpMRoute(
1422             self,
1423             "0.0.0.0",
1424             "232.1.1.1", 32,
1425             MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1426             [VppMRoutePath(self.pg0.sw_if_index,
1427                            MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT),
1428              VppMRoutePath(mpls_tun._sw_if_index,
1429                            MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD)])
1430         route_232_1_1_1.add_vpp_config()
1431         self.logger.info(self.vapi.cli("sh ip mfib index 0"))
1432
1433         self.vapi.cli("clear trace")
1434         tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1435         self.pg0.add_stream(tx)
1436
1437         self.pg_enable_capture(self.pg_interfaces)
1438         self.pg_start()
1439
1440         rx = self.pg2.get_capture(257)
1441         self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1442         rx = self.pg3.get_capture(257)
1443         self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1444
1445     def test_mcast_ip4_tail(self):
1446         """ MPLS IPv4 Multicast Tail """
1447
1448         MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1449         MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1450
1451         #
1452         # Add a multicast route that will forward the traffic
1453         # post-disposition
1454         #
1455         route_232_1_1_1 = VppIpMRoute(
1456             self,
1457             "0.0.0.0",
1458             "232.1.1.1", 32,
1459             MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1460             table_id=1,
1461             paths=[VppMRoutePath(self.pg1.sw_if_index,
1462                                  MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD)])
1463         route_232_1_1_1.add_vpp_config()
1464
1465         #
1466         # An interface receive label that maps traffic to RX on interface
1467         # pg1
1468         # by injecting the packet in on pg0, which is in table 0
1469         # doing an rpf-id  and matching a route in table 1
1470         # if the packet egresses, then we must have matched the route in
1471         # table 1
1472         #
1473         route_34_eos = VppMplsRoute(
1474             self, 34, 1,
1475             [VppRoutePath("0.0.0.0",
1476                           0xffffffff,
1477                           nh_table_id=1,
1478                           rpf_id=55)],
1479             is_multicast=1,
1480             eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)
1481
1482         route_34_eos.add_vpp_config()
1483
1484         #
1485         # Drop due to interface lookup miss
1486         #
1487         self.vapi.cli("clear trace")
1488         tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1489                                              dst_ip="232.1.1.1", n=1)
1490         self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1491
1492         #
1493         # set the RPF-ID of the entry to match the input packet's
1494         #
1495         route_232_1_1_1.update_rpf_id(55)
1496         self.logger.info(self.vapi.cli("sh ip mfib index 1 232.1.1.1"))
1497
1498         tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1499                                              dst_ip="232.1.1.1")
1500         rx = self.send_and_expect(self.pg0, tx, self.pg1)
1501         self.verify_capture_ip4(self.pg1, rx, tx)
1502
1503         #
1504         # disposed packets have an invalid IPv4 checksum
1505         #
1506         tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1507                                              dst_ip="232.1.1.1", n=65,
1508                                              chksum=1)
1509         self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1510
1511         #
1512         # set the RPF-ID of the entry to not match the input packet's
1513         #
1514         route_232_1_1_1.update_rpf_id(56)
1515         tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1516                                              dst_ip="232.1.1.1")
1517         self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1518
1519     def test_mcast_ip6_tail(self):
1520         """ MPLS IPv6 Multicast Tail """
1521
1522         MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1523         MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1524
1525         #
1526         # Add a multicast route that will forward the traffic
1527         # post-disposition
1528         #
1529         route_ff = VppIpMRoute(
1530             self,
1531             "::",
1532             "ff01::1", 32,
1533             MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1534             table_id=1,
1535             paths=[VppMRoutePath(self.pg1.sw_if_index,
1536                                  MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1537                                  proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
1538         route_ff.add_vpp_config()
1539
1540         #
1541         # An interface receive label that maps traffic to RX on interface
1542         # pg1
1543         # by injecting the packet in on pg0, which is in table 0
1544         # doing an rpf-id  and matching a route in table 1
1545         # if the packet egresses, then we must have matched the route in
1546         # table 1
1547         #
1548         route_34_eos = VppMplsRoute(
1549             self, 34, 1,
1550             [VppRoutePath("::",
1551                           0xffffffff,
1552                           nh_table_id=1,
1553                           rpf_id=55)],
1554             is_multicast=1,
1555             eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
1556
1557         route_34_eos.add_vpp_config()
1558
1559         #
1560         # Drop due to interface lookup miss
1561         #
1562         tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1563                                              dst_ip="ff01::1")
1564         self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1565
1566         #
1567         # set the RPF-ID of the entry to match the input packet's
1568         #
1569         route_ff.update_rpf_id(55)
1570
1571         tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1572                                              dst_ip="ff01::1")
1573         rx = self.send_and_expect(self.pg0, tx, self.pg1)
1574         self.verify_capture_ip6(self.pg1, rx, tx)
1575
1576         #
1577         # disposed packets have hop-limit = 1
1578         #
1579         tx = self.create_stream_labelled_ip6(self.pg0,
1580                                              [VppMplsLabel(34)],
1581                                              dst_ip="ff01::1",
1582                                              hlim=1)
1583         rx = self.send_and_expect_some(self.pg0, tx, self.pg0)
1584         self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1585
1586         #
1587         # set the RPF-ID of the entry to not match the input packet's
1588         #
1589         route_ff.update_rpf_id(56)
1590         tx = self.create_stream_labelled_ip6(self.pg0,
1591                                              [VppMplsLabel(34)],
1592                                              dst_ip="ff01::1")
1593         self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1594
1595     def test_6pe(self):
1596         """ MPLS 6PE """
1597
1598         #
1599         # Add a non-recursive route with a single out label
1600         #
1601         route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1602                                     [VppRoutePath(self.pg0.remote_ip4,
1603                                                   self.pg0.sw_if_index,
1604                                                   labels=[VppMplsLabel(45)])])
1605         route_10_0_0_1.add_vpp_config()
1606
1607         # bind a local label to the route
1608         binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
1609         binding.add_vpp_config()
1610
1611         #
1612         # a labelled v6 route that resolves through the v4
1613         #
1614         route_2001_3 = VppIpRoute(
1615             self, "2001::3", 128,
1616             [VppRoutePath("10.0.0.1",
1617                           INVALID_INDEX,
1618                           labels=[VppMplsLabel(32)])])
1619         route_2001_3.add_vpp_config()
1620
1621         tx = self.create_stream_ip6(self.pg0, "2001::3")
1622         rx = self.send_and_expect(self.pg0, tx, self.pg0)
1623
1624         self.verify_capture_labelled_ip6(self.pg0, rx, tx,
1625                                          [VppMplsLabel(45),
1626                                           VppMplsLabel(32)])
1627
1628         #
1629         # and a v4 recursive via the v6
1630         #
1631         route_20_3 = VppIpRoute(
1632             self, "20.0.0.3", 32,
1633             [VppRoutePath("2001::3",
1634                           INVALID_INDEX,
1635                           labels=[VppMplsLabel(99)])])
1636         route_20_3.add_vpp_config()
1637
1638         tx = self.create_stream_ip4(self.pg0, "20.0.0.3")
1639         rx = self.send_and_expect(self.pg0, tx, self.pg0)
1640
1641         self.verify_capture_labelled_ip4(self.pg0, rx, tx,
1642                                          [VppMplsLabel(45),
1643                                           VppMplsLabel(32),
1644                                           VppMplsLabel(99)])
1645
1646     def test_attached(self):
1647         """ Attach Routes with Local Label """
1648
1649         #
1650         # test that if a local label is associated with an attached/connected
1651         # prefix, that we can reach hosts in the prefix.
1652         #
1653         binding = VppMplsIpBind(self, 44,
1654                                 self.pg0._local_ip4_subnet,
1655                                 self.pg0.local_ip4_prefix_len)
1656         binding.add_vpp_config()
1657
1658         tx = (Ether(src=self.pg1.remote_mac,
1659                     dst=self.pg1.local_mac) /
1660               MPLS(label=44, ttl=64) /
1661               IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4) /
1662               UDP(sport=1234, dport=1234) /
1663               Raw(b'\xa5' * 100))
1664         rxs = self.send_and_expect(self.pg0, [tx], self.pg0)
1665         for rx in rxs:
1666             # if there's an ARP then the label is linked to the glean
1667             # which is wrong.
1668             self.assertFalse(rx.haslayer(ARP))
1669             # it should be unicasted to the host
1670             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1671             self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1672
1673
1674 class TestMPLSDisabled(VppTestCase):
1675     """ MPLS disabled """
1676
1677     @classmethod
1678     def setUpClass(cls):
1679         super(TestMPLSDisabled, cls).setUpClass()
1680
1681     @classmethod
1682     def tearDownClass(cls):
1683         super(TestMPLSDisabled, cls).tearDownClass()
1684
1685     def setUp(self):
1686         super(TestMPLSDisabled, self).setUp()
1687
1688         # create 2 pg interfaces
1689         self.create_pg_interfaces(range(2))
1690
1691         self.tbl = VppMplsTable(self, 0)
1692         self.tbl.add_vpp_config()
1693
1694         # PG0 is MPLS enabled
1695         self.pg0.admin_up()
1696         self.pg0.config_ip4()
1697         self.pg0.resolve_arp()
1698         self.pg0.enable_mpls()
1699
1700         # PG 1 is not MPLS enabled
1701         self.pg1.admin_up()
1702
1703     def tearDown(self):
1704         for i in self.pg_interfaces:
1705             i.unconfig_ip4()
1706             i.admin_down()
1707
1708         self.pg0.disable_mpls()
1709         super(TestMPLSDisabled, self).tearDown()
1710
1711     def test_mpls_disabled(self):
1712         """ MPLS Disabled """
1713
1714         self.logger.info(self.vapi.cli("show mpls interface"))
1715         self.logger.info(self.vapi.cli("show mpls interface pg1"))
1716         self.logger.info(self.vapi.cli("show mpls interface pg0"))
1717
1718         tx = (Ether(src=self.pg1.remote_mac,
1719                     dst=self.pg1.local_mac) /
1720               MPLS(label=32, ttl=64) /
1721               IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1722               UDP(sport=1234, dport=1234) /
1723               Raw(b'\xa5' * 100))
1724
1725         #
1726         # A simple MPLS xconnect - eos label in label out
1727         #
1728         route_32_eos = VppMplsRoute(self, 32, 1,
1729                                     [VppRoutePath(self.pg0.remote_ip4,
1730                                                   self.pg0.sw_if_index,
1731                                                   labels=[33])])
1732         route_32_eos.add_vpp_config()
1733
1734         #
1735         # PG1 does not forward IP traffic
1736         #
1737         self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1738
1739         #
1740         # MPLS enable PG1
1741         #
1742         self.pg1.enable_mpls()
1743
1744         self.logger.info(self.vapi.cli("show mpls interface"))
1745         self.logger.info(self.vapi.cli("show mpls interface pg1"))
1746
1747         #
1748         # Now we get packets through
1749         #
1750         self.pg1.add_stream(tx)
1751         self.pg_enable_capture(self.pg_interfaces)
1752         self.pg_start()
1753
1754         rx = self.pg0.get_capture(1)
1755
1756         #
1757         # Disable PG1
1758         #
1759         self.pg1.disable_mpls()
1760
1761         #
1762         # PG1 does not forward IP traffic
1763         #
1764         self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1765         self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1766
1767
1768 class TestMPLSPIC(VppTestCase):
1769     """ MPLS Prefix-Independent Convergence (PIC) edge convergence """
1770
1771     @classmethod
1772     def setUpClass(cls):
1773         super(TestMPLSPIC, cls).setUpClass()
1774
1775     @classmethod
1776     def tearDownClass(cls):
1777         super(TestMPLSPIC, cls).tearDownClass()
1778
1779     def setUp(self):
1780         super(TestMPLSPIC, self).setUp()
1781
1782         # create 2 pg interfaces
1783         self.create_pg_interfaces(range(4))
1784
1785         mpls_tbl = VppMplsTable(self, 0)
1786         mpls_tbl.add_vpp_config()
1787         tbl4 = VppIpTable(self, 1)
1788         tbl4.add_vpp_config()
1789         tbl6 = VppIpTable(self, 1, is_ip6=1)
1790         tbl6.add_vpp_config()
1791
1792         # core links
1793         self.pg0.admin_up()
1794         self.pg0.config_ip4()
1795         self.pg0.resolve_arp()
1796         self.pg0.enable_mpls()
1797
1798         self.pg1.admin_up()
1799         self.pg1.config_ip4()
1800         self.pg1.resolve_arp()
1801         self.pg1.enable_mpls()
1802
1803         # VRF (customer facing) link
1804         self.pg2.admin_up()
1805         self.pg2.set_table_ip4(1)
1806         self.pg2.config_ip4()
1807         self.pg2.resolve_arp()
1808         self.pg2.set_table_ip6(1)
1809         self.pg2.config_ip6()
1810         self.pg2.resolve_ndp()
1811
1812         self.pg3.admin_up()
1813         self.pg3.set_table_ip4(1)
1814         self.pg3.config_ip4()
1815         self.pg3.resolve_arp()
1816         self.pg3.set_table_ip6(1)
1817         self.pg3.config_ip6()
1818         self.pg3.resolve_ndp()
1819
1820     def tearDown(self):
1821         self.pg0.disable_mpls()
1822         self.pg1.disable_mpls()
1823         for i in self.pg_interfaces:
1824             i.unconfig_ip4()
1825             i.unconfig_ip6()
1826             i.set_table_ip4(0)
1827             i.set_table_ip6(0)
1828             i.admin_down()
1829         super(TestMPLSPIC, self).tearDown()
1830
1831     def test_mpls_ibgp_pic(self):
1832         """ MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
1833
1834         1) setup many iBGP VPN routes via a pair of iBGP peers.
1835         2) Check EMCP forwarding to these peers
1836         3) withdraw the IGP route to one of these peers.
1837         4) check forwarding continues to the remaining peer
1838         """
1839
1840         #
1841         # IGP+LDP core routes
1842         #
1843         core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1844                                     [VppRoutePath(self.pg0.remote_ip4,
1845                                                   self.pg0.sw_if_index,
1846                                                   labels=[45])])
1847         core_10_0_0_45.add_vpp_config()
1848
1849         core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1850                                     [VppRoutePath(self.pg1.remote_ip4,
1851                                                   self.pg1.sw_if_index,
1852                                                   labels=[46])])
1853         core_10_0_0_46.add_vpp_config()
1854
1855         #
1856         # Lot's of VPN routes. We need more the 64 so VPP will build
1857         # the fast convergence indirection
1858         #
1859         vpn_routes = []
1860         pkts = []
1861         for ii in range(NUM_PKTS):
1862             dst = "192.168.1.%d" % ii
1863             vpn_routes.append(VppIpRoute(
1864                 self, dst, 32,
1865                 [VppRoutePath(
1866                     "10.0.0.45",
1867                     0xffffffff,
1868                     labels=[145],
1869                     flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST),
1870                  VppRoutePath(
1871                      "10.0.0.46",
1872                      0xffffffff,
1873                      labels=[146],
1874                      flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST)],
1875                 table_id=1))
1876             vpn_routes[ii].add_vpp_config()
1877
1878             pkts.append(Ether(dst=self.pg2.local_mac,
1879                               src=self.pg2.remote_mac) /
1880                         IP(src=self.pg2.remote_ip4, dst=dst) /
1881                         UDP(sport=1234, dport=1234) /
1882                         Raw(b'\xa5' * 100))
1883
1884         #
1885         # Send the packet stream (one pkt to each VPN route)
1886         #  - expect a 50-50 split of the traffic
1887         #
1888         self.pg2.add_stream(pkts)
1889         self.pg_enable_capture(self.pg_interfaces)
1890         self.pg_start()
1891
1892         rx0 = self.pg0._get_capture(NUM_PKTS)
1893         rx1 = self.pg1._get_capture(NUM_PKTS)
1894
1895         # not testing the LB hashing algorithm so we're not concerned
1896         # with the split ratio, just as long as neither is 0
1897         self.assertNotEqual(0, len(rx0))
1898         self.assertNotEqual(0, len(rx1))
1899         self.assertEqual(len(pkts), len(rx0) + len(rx1),
1900                          "Expected all (%s) packets across both ECMP paths. "
1901                          "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1902
1903         #
1904         # use a test CLI command to stop the FIB walk process, this
1905         # will prevent the FIB converging the VPN routes and thus allow
1906         # us to probe the interim (post-fail, pre-converge) state
1907         #
1908         self.vapi.ppcli("test fib-walk-process disable")
1909
1910         #
1911         # Withdraw one of the IGP routes
1912         #
1913         core_10_0_0_46.remove_vpp_config()
1914
1915         #
1916         # now all packets should be forwarded through the remaining peer
1917         #
1918         self.vapi.ppcli("clear trace")
1919         self.pg2.add_stream(pkts)
1920         self.pg_enable_capture(self.pg_interfaces)
1921         self.pg_start()
1922
1923         rx0 = self.pg0.get_capture(NUM_PKTS)
1924         self.assertEqual(len(pkts), len(rx0),
1925                          "Expected all (%s) packets across single path. "
1926                          "rx0: %s." % (len(pkts), len(rx0)))
1927
1928         #
1929         # enable the FIB walk process to converge the FIB
1930         #
1931         self.vapi.ppcli("test fib-walk-process enable")
1932
1933         #
1934         # packets should still be forwarded through the remaining peer
1935         #
1936         self.pg2.add_stream(pkts)
1937         self.pg_enable_capture(self.pg_interfaces)
1938         self.pg_start()
1939
1940         rx0 = self.pg0.get_capture(NUM_PKTS)
1941         self.assertEqual(len(pkts), len(rx0),
1942                          "Expected all (%s) packets across single path. "
1943                          "rx0: %s." % (len(pkts), len(rx0)))
1944
1945         #
1946         # Add the IGP route back and we return to load-balancing
1947         #
1948         core_10_0_0_46.add_vpp_config()
1949
1950         self.pg2.add_stream(pkts)
1951         self.pg_enable_capture(self.pg_interfaces)
1952         self.pg_start()
1953
1954         rx0 = self.pg0._get_capture(NUM_PKTS)
1955         rx1 = self.pg1._get_capture(NUM_PKTS)
1956         self.assertNotEqual(0, len(rx0))
1957         self.assertNotEqual(0, len(rx1))
1958         self.assertEqual(len(pkts), len(rx0) + len(rx1),
1959                          "Expected all (%s) packets across both ECMP paths. "
1960                          "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1961
1962     def test_mpls_ebgp_pic(self):
1963         """ MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
1964
1965         1) setup many eBGP VPN routes via a pair of eBGP peers.
1966         2) Check EMCP forwarding to these peers
1967         3) withdraw one eBGP path - expect LB across remaining eBGP
1968         """
1969
1970         #
1971         # Lot's of VPN routes. We need more the 64 so VPP will build
1972         # the fast convergence indirection
1973         #
1974         vpn_routes = []
1975         vpn_bindings = []
1976         pkts = []
1977         for ii in range(NUM_PKTS):
1978             dst = "192.168.1.%d" % ii
1979             local_label = 1600 + ii
1980             vpn_routes.append(VppIpRoute(
1981                 self, dst, 32,
1982                 [VppRoutePath(
1983                     self.pg2.remote_ip4,
1984                     0xffffffff,
1985                     nh_table_id=1,
1986                     flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1987                  VppRoutePath(
1988                      self.pg3.remote_ip4,
1989                      0xffffffff,
1990                      nh_table_id=1,
1991                      flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1992                 table_id=1))
1993             vpn_routes[ii].add_vpp_config()
1994
1995             vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1996                                               ip_table_id=1))
1997             vpn_bindings[ii].add_vpp_config()
1998
1999             pkts.append(Ether(dst=self.pg0.local_mac,
2000                               src=self.pg0.remote_mac) /
2001                         MPLS(label=local_label, ttl=64) /
2002                         IP(src=self.pg0.remote_ip4, dst=dst) /
2003                         UDP(sport=1234, dport=1234) /
2004                         Raw(b'\xa5' * 100))
2005
2006         #
2007         # Send the packet stream (one pkt to each VPN route)
2008         #  - expect a 50-50 split of the traffic
2009         #
2010         self.pg0.add_stream(pkts)
2011         self.pg_enable_capture(self.pg_interfaces)
2012         self.pg_start()
2013
2014         rx0 = self.pg2._get_capture(NUM_PKTS)
2015         rx1 = self.pg3._get_capture(NUM_PKTS)
2016
2017         # not testing the LB hashing algorithm so we're not concerned
2018         # with the split ratio, just as long as neither is 0
2019         self.assertNotEqual(0, len(rx0))
2020         self.assertNotEqual(0, len(rx1))
2021         self.assertEqual(len(pkts), len(rx0) + len(rx1),
2022                          "Expected all (%s) packets across both ECMP paths. "
2023                          "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2024
2025         #
2026         # use a test CLI command to stop the FIB walk process, this
2027         # will prevent the FIB converging the VPN routes and thus allow
2028         # us to probe the interim (post-fail, pre-converge) state
2029         #
2030         self.vapi.ppcli("test fib-walk-process disable")
2031
2032         #
2033         # withdraw the connected prefix on the interface.
2034         #
2035         self.pg2.unconfig_ip4()
2036
2037         #
2038         # now all packets should be forwarded through the remaining peer
2039         #
2040         self.pg0.add_stream(pkts)
2041         self.pg_enable_capture(self.pg_interfaces)
2042         self.pg_start()
2043
2044         rx0 = self.pg3.get_capture(NUM_PKTS)
2045         self.assertEqual(len(pkts), len(rx0),
2046                          "Expected all (%s) packets across single path. "
2047                          "rx0: %s." % (len(pkts), len(rx0)))
2048
2049         #
2050         # enable the FIB walk process to converge the FIB
2051         #
2052         self.vapi.ppcli("test fib-walk-process enable")
2053
2054         #
2055         # packets should still be forwarded through the remaining peer
2056         #
2057         self.pg0.add_stream(pkts)
2058         self.pg_enable_capture(self.pg_interfaces)
2059         self.pg_start()
2060
2061         rx0 = self.pg3.get_capture(NUM_PKTS)
2062         self.assertEqual(len(pkts), len(rx0),
2063                          "Expected all (%s) packets across single path. "
2064                          "rx0: %s." % (len(pkts), len(rx0)))
2065
2066         #
2067         # put the connected routes back
2068         #
2069         self.pg2.config_ip4()
2070         self.pg2.resolve_arp()
2071
2072         self.pg0.add_stream(pkts)
2073         self.pg_enable_capture(self.pg_interfaces)
2074         self.pg_start()
2075
2076         rx0 = self.pg2._get_capture(NUM_PKTS)
2077         rx1 = self.pg3._get_capture(NUM_PKTS)
2078         self.assertNotEqual(0, len(rx0))
2079         self.assertNotEqual(0, len(rx1))
2080         self.assertEqual(len(pkts), len(rx0) + len(rx1),
2081                          "Expected all (%s) packets across both ECMP paths. "
2082                          "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2083
2084     def test_mpls_v6_ebgp_pic(self):
2085         """ MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
2086
2087         1) setup many eBGP VPNv6 routes via a pair of eBGP peers
2088         2) Check EMCP forwarding to these peers
2089         3) withdraw one eBGP path - expect LB across remaining eBGP
2090         """
2091
2092         #
2093         # Lot's of VPN routes. We need more the 64 so VPP will build
2094         # the fast convergence indirection
2095         #
2096         vpn_routes = []
2097         vpn_bindings = []
2098         pkts = []
2099         for ii in range(NUM_PKTS):
2100             dst = "3000::%d" % ii
2101             local_label = 1600 + ii
2102             vpn_routes.append(VppIpRoute(
2103                 self, dst, 128,
2104                 [VppRoutePath(
2105                     self.pg2.remote_ip6,
2106                     0xffffffff,
2107                     nh_table_id=1,
2108                     flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
2109                  VppRoutePath(
2110                      self.pg3.remote_ip6,
2111                      0xffffffff,
2112                      nh_table_id=1,
2113                      flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
2114                 table_id=1))
2115             vpn_routes[ii].add_vpp_config()
2116
2117             vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
2118                                               ip_table_id=1))
2119             vpn_bindings[ii].add_vpp_config()
2120
2121             pkts.append(Ether(dst=self.pg0.local_mac,
2122                               src=self.pg0.remote_mac) /
2123                         MPLS(label=local_label, ttl=64) /
2124                         IPv6(src=self.pg0.remote_ip6, dst=dst) /
2125                         UDP(sport=1234, dport=1234) /
2126                         Raw(b'\xa5' * 100))
2127             self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
2128
2129         self.pg0.add_stream(pkts)
2130         self.pg_enable_capture(self.pg_interfaces)
2131         self.pg_start()
2132
2133         rx0 = self.pg2._get_capture(NUM_PKTS)
2134         rx1 = self.pg3._get_capture(NUM_PKTS)
2135         self.assertNotEqual(0, len(rx0))
2136         self.assertNotEqual(0, len(rx1))
2137         self.assertEqual(len(pkts), len(rx0) + len(rx1),
2138                          "Expected all (%s) packets across both ECMP paths. "
2139                          "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2140
2141         #
2142         # use a test CLI command to stop the FIB walk process, this
2143         # will prevent the FIB converging the VPN routes and thus allow
2144         # us to probe the interim (post-fail, pre-converge) state
2145         #
2146         self.vapi.ppcli("test fib-walk-process disable")
2147
2148         #
2149         # withdraw the connected prefix on the interface.
2150         # and shutdown the interface so the ND cache is flushed.
2151         #
2152         self.pg2.unconfig_ip6()
2153         self.pg2.admin_down()
2154
2155         #
2156         # now all packets should be forwarded through the remaining peer
2157         #
2158         self.pg0.add_stream(pkts)
2159         self.pg_enable_capture(self.pg_interfaces)
2160         self.pg_start()
2161
2162         rx0 = self.pg3.get_capture(NUM_PKTS)
2163         self.assertEqual(len(pkts), len(rx0),
2164                          "Expected all (%s) packets across single path. "
2165                          "rx0: %s." % (len(pkts), len(rx0)))
2166
2167         #
2168         # enable the FIB walk process to converge the FIB
2169         #
2170         self.vapi.ppcli("test fib-walk-process enable")
2171         self.pg0.add_stream(pkts)
2172         self.pg_enable_capture(self.pg_interfaces)
2173         self.pg_start()
2174
2175         rx0 = self.pg3.get_capture(NUM_PKTS)
2176         self.assertEqual(len(pkts), len(rx0),
2177                          "Expected all (%s) packets across single path. "
2178                          "rx0: %s." % (len(pkts), len(rx0)))
2179
2180         #
2181         # put the connected routes back
2182         #
2183         self.logger.info(self.vapi.cli("sh log"))
2184         self.pg2.admin_up()
2185         self.pg2.config_ip6()
2186         self.pg2.resolve_ndp()
2187
2188         self.pg0.add_stream(pkts)
2189         self.pg_enable_capture(self.pg_interfaces)
2190         self.pg_start()
2191
2192         rx0 = self.pg2._get_capture(NUM_PKTS)
2193         rx1 = self.pg3._get_capture(NUM_PKTS)
2194         self.assertNotEqual(0, len(rx0))
2195         self.assertNotEqual(0, len(rx1))
2196         self.assertEqual(len(pkts), len(rx0) + len(rx1),
2197                          "Expected all (%s) packets across both ECMP paths. "
2198                          "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2199
2200
2201 class TestMPLSL2(VppTestCase):
2202     """ MPLS-L2 """
2203
2204     @classmethod
2205     def setUpClass(cls):
2206         super(TestMPLSL2, cls).setUpClass()
2207
2208     @classmethod
2209     def tearDownClass(cls):
2210         super(TestMPLSL2, cls).tearDownClass()
2211
2212     def setUp(self):
2213         super(TestMPLSL2, self).setUp()
2214
2215         # create 2 pg interfaces
2216         self.create_pg_interfaces(range(2))
2217
2218         # create the default MPLS table
2219         self.tables = []
2220         tbl = VppMplsTable(self, 0)
2221         tbl.add_vpp_config()
2222         self.tables.append(tbl)
2223
2224         # use pg0 as the core facing interface, don't resolve ARP
2225         self.pg0.admin_up()
2226         self.pg0.config_ip4()
2227         self.pg0.enable_mpls()
2228
2229         # use the other 2 for customer facing L2 links
2230         for i in self.pg_interfaces[1:]:
2231             i.admin_up()
2232
2233     def tearDown(self):
2234         for i in self.pg_interfaces[1:]:
2235             i.admin_down()
2236
2237         self.pg0.disable_mpls()
2238         self.pg0.unconfig_ip4()
2239         self.pg0.admin_down()
2240         super(TestMPLSL2, self).tearDown()
2241
2242     def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
2243         capture = verify_filter(capture, sent)
2244
2245         self.assertEqual(len(capture), len(sent))
2246
2247         for i in range(len(capture)):
2248             tx = sent[i]
2249             rx = capture[i]
2250
2251             # the MPLS TTL is 255 since it enters a new tunnel
2252             verify_mpls_stack(self, rx, mpls_labels)
2253
2254             tx_eth = tx[Ether]
2255             rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
2256
2257             self.assertEqual(rx_eth.src, tx_eth.src)
2258             self.assertEqual(rx_eth.dst, tx_eth.dst)
2259
2260     def verify_arp_req(self, rx, smac, sip, dip):
2261         ether = rx[Ether]
2262         self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2263         self.assertEqual(ether.src, smac)
2264
2265         arp = rx[ARP]
2266         self.assertEqual(arp.hwtype, 1)
2267         self.assertEqual(arp.ptype, 0x800)
2268         self.assertEqual(arp.hwlen, 6)
2269         self.assertEqual(arp.plen, 4)
2270         self.assertEqual(arp.op, ARP.who_has)
2271         self.assertEqual(arp.hwsrc, smac)
2272         self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2273         self.assertEqual(arp.psrc, sip)
2274         self.assertEqual(arp.pdst, dip)
2275
2276     def test_vpws(self):
2277         """ Virtual Private Wire Service """
2278
2279         #
2280         # Create an MPLS tunnel that pushes 1 label
2281         # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
2282         # information is not in the packet, but we test it works anyway
2283         #
2284         mpls_tun_1 = VppMPLSTunnelInterface(
2285             self,
2286             [VppRoutePath(self.pg0.remote_ip4,
2287                           self.pg0.sw_if_index,
2288                           labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
2289             is_l2=1)
2290         mpls_tun_1.add_vpp_config()
2291         mpls_tun_1.admin_up()
2292
2293         #
2294         # Create a label entry to for 55 that does L2 input to the tunnel
2295         #
2296         route_55_eos = VppMplsRoute(
2297             self, 55, 1,
2298             [VppRoutePath("0.0.0.0",
2299                           mpls_tun_1.sw_if_index,
2300                           type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2301                           proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2302             eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2303         route_55_eos.add_vpp_config()
2304
2305         #
2306         # Cross-connect the tunnel with one of the customers L2 interfaces
2307         #
2308         self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
2309                                                mpls_tun_1.sw_if_index,
2310                                                enable=1)
2311         self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
2312                                                self.pg1.sw_if_index,
2313                                                enable=1)
2314
2315         #
2316         # inject a packet from the core
2317         #
2318         pcore = (Ether(dst=self.pg0.local_mac,
2319                        src=self.pg0.remote_mac) /
2320                  MPLS(label=55, ttl=64) /
2321                  Ether(dst="00:00:de:ad:ba:be",
2322                        src="00:00:de:ad:be:ef") /
2323                  IP(src="10.10.10.10", dst="11.11.11.11") /
2324                  UDP(sport=1234, dport=1234) /
2325                  Raw(b'\xa5' * 100))
2326
2327         tx0 = pcore * NUM_PKTS
2328         rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2329         payload = pcore[MPLS].payload
2330
2331         self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2332         self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2333
2334         #
2335         # Inject a packet from the customer/L2 side
2336         # there's no resolved ARP entry so the first packet we see should be
2337         # an ARP request
2338         #
2339         tx1 = pcore[MPLS].payload
2340         rx1 = self.send_and_expect(self.pg1, [tx1], self.pg0)
2341
2342         self.verify_arp_req(rx1[0],
2343                             self.pg0.local_mac,
2344                             self.pg0.local_ip4,
2345                             self.pg0.remote_ip4)
2346
2347         #
2348         # resolve the ARP entries and send again
2349         #
2350         self.pg0.resolve_arp()
2351         tx1 = pcore[MPLS].payload * NUM_PKTS
2352         rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
2353
2354         self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
2355
2356     def test_vpls(self):
2357         """ Virtual Private LAN Service """
2358
2359         # we skipped this in the setup
2360         self.pg0.resolve_arp()
2361
2362         #
2363         # Create a L2 MPLS tunnels
2364         #
2365         mpls_tun1 = VppMPLSTunnelInterface(
2366             self,
2367             [VppRoutePath(self.pg0.remote_ip4,
2368                           self.pg0.sw_if_index,
2369                           labels=[VppMplsLabel(42)])],
2370             is_l2=1)
2371         mpls_tun1.add_vpp_config()
2372         mpls_tun1.admin_up()
2373
2374         mpls_tun2 = VppMPLSTunnelInterface(
2375             self,
2376             [VppRoutePath(self.pg0.remote_ip4,
2377                           self.pg0.sw_if_index,
2378                           labels=[VppMplsLabel(43)])],
2379             is_l2=1)
2380         mpls_tun2.add_vpp_config()
2381         mpls_tun2.admin_up()
2382
2383         #
2384         # Create a label entries, 55 and 56, that do L2 input to the tunnel
2385         # the latter includes a Psuedo Wire Control Word
2386         #
2387         route_55_eos = VppMplsRoute(
2388             self, 55, 1,
2389             [VppRoutePath("0.0.0.0",
2390                           mpls_tun1.sw_if_index,
2391                           type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2392                           proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2393             eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2394
2395         route_56_eos = VppMplsRoute(
2396             self, 56, 1,
2397             [VppRoutePath("0.0.0.0",
2398                           mpls_tun2.sw_if_index,
2399                           type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2400                           flags=FibPathFlags.FIB_PATH_FLAG_POP_PW_CW,
2401                           proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2402             eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2403
2404         # move me
2405         route_56_eos.add_vpp_config()
2406         route_55_eos.add_vpp_config()
2407
2408         self.logger.info(self.vapi.cli("sh mpls fib 56"))
2409
2410         #
2411         # add to tunnel to the customers bridge-domain
2412         #
2413         self.vapi.sw_interface_set_l2_bridge(
2414             rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1)
2415         self.vapi.sw_interface_set_l2_bridge(
2416             rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1)
2417         self.vapi.sw_interface_set_l2_bridge(
2418             rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
2419
2420         #
2421         # Packet from host on the customer interface to each host
2422         # reachable over the core, and vice-versa
2423         #
2424         p_cust1 = (Ether(dst="00:00:de:ad:ba:b1",
2425                          src="00:00:de:ad:be:ef") /
2426                    IP(src="10.10.10.10", dst="11.11.11.11") /
2427                    UDP(sport=1234, dport=1234) /
2428                    Raw(b'\xa5' * 100))
2429         p_cust2 = (Ether(dst="00:00:de:ad:ba:b2",
2430                          src="00:00:de:ad:be:ef") /
2431                    IP(src="10.10.10.10", dst="11.11.11.12") /
2432                    UDP(sport=1234, dport=1234) /
2433                    Raw(b'\xa5' * 100))
2434         p_core1 = (Ether(dst=self.pg0.local_mac,
2435                          src=self.pg0.remote_mac) /
2436                    MPLS(label=55, ttl=64) /
2437                    Ether(src="00:00:de:ad:ba:b1",
2438                          dst="00:00:de:ad:be:ef") /
2439                    IP(dst="10.10.10.10", src="11.11.11.11") /
2440                    UDP(sport=1234, dport=1234) /
2441                    Raw(b'\xa5' * 100))
2442         p_core2 = (Ether(dst=self.pg0.local_mac,
2443                          src=self.pg0.remote_mac) /
2444                    MPLS(label=56, ttl=64) /
2445                    Raw(b'\x01' * 4) /  # PW CW
2446                    Ether(src="00:00:de:ad:ba:b2",
2447                          dst="00:00:de:ad:be:ef") /
2448                    IP(dst="10.10.10.10", src="11.11.11.12") /
2449                    UDP(sport=1234, dport=1234) /
2450                    Raw(b'\xa5' * 100))
2451
2452         #
2453         # The BD is learning, so send in one of each packet to learn
2454         #
2455
2456         # 2 packets due to BD flooding
2457         rx = self.send_and_expect(self.pg1, p_cust1, self.pg0, n_rx=2)
2458         rx = self.send_and_expect(self.pg1, p_cust2, self.pg0, n_rx=2)
2459
2460         # we've learnt this so expect it be be forwarded not flooded
2461         rx = self.send_and_expect(self.pg0, [p_core1], self.pg1)
2462         self.assertEqual(rx[0][Ether].dst, p_cust1[Ether].src)
2463         self.assertEqual(rx[0][Ether].src, p_cust1[Ether].dst)
2464
2465         rx = self.send_and_expect(self.pg0, [p_core2], self.pg1)
2466         self.assertEqual(rx[0][Ether].dst, p_cust2[Ether].src)
2467         self.assertEqual(rx[0][Ether].src, p_cust2[Ether].dst)
2468
2469         #
2470         # now a stream in each direction from each host
2471         #
2472         rx = self.send_and_expect(self.pg1, p_cust1 * NUM_PKTS, self.pg0)
2473         self.verify_capture_tunneled_ethernet(rx, p_cust1 * NUM_PKTS,
2474                                               [VppMplsLabel(42)])
2475
2476         rx = self.send_and_expect(self.pg1, p_cust2 * NUM_PKTS, self.pg0)
2477         self.verify_capture_tunneled_ethernet(rx, p_cust2 * NUM_PKTS,
2478                                               [VppMplsLabel(43)])
2479
2480         rx = self.send_and_expect(self.pg0, p_core1 * NUM_PKTS, self.pg1)
2481         rx = self.send_and_expect(self.pg0, p_core2 * NUM_PKTS, self.pg1)
2482
2483         #
2484         # remove interfaces from customers bridge-domain
2485         #
2486         self.vapi.sw_interface_set_l2_bridge(
2487             rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1, enable=0)
2488         self.vapi.sw_interface_set_l2_bridge(
2489             rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1, enable=0)
2490         self.vapi.sw_interface_set_l2_bridge(
2491             rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
2492
2493
2494 if __name__ == '__main__':
2495     unittest.main(testRunner=VppTestRunner)