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