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