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