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