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