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