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