blob: 0ad1ee6977ef06e3846990f0564769b6650be8ae [file] [log] [blame]
Neale Ranns8fe8cc22016-11-01 10:05:08 +00001#!/usr/bin/env python
2
3import unittest
Gabriel Gannea9b2d582016-12-06 10:25:34 +01004import socket
Neale Ranns8fe8cc22016-11-01 10:05:08 +00005
6from framework import VppTestCase, VppTestRunner
Neale Ranns5a8123b2017-01-26 01:18:23 -08007from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
Neale Ranns0f26c5a2017-03-01 15:12:11 -08008 VppMplsIpBind, VppIpMRoute, VppMRoutePath, \
9 MRouteItfFlags, MRouteEntryFlags
10from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface
Neale Ranns8fe8cc22016-11-01 10:05:08 +000011
12from scapy.packet import Raw
Klement Sekera7bb873a2016-11-18 07:38:42 +010013from scapy.layers.l2 import Ether
Neale Rannscb630ff2016-12-14 13:31:29 +010014from scapy.layers.inet import IP, UDP, ICMP
Klement Sekera7bb873a2016-11-18 07:38:42 +010015from scapy.layers.inet6 import IPv6
Neale Ranns8fe8cc22016-11-01 10:05:08 +000016from scapy.contrib.mpls import MPLS
17
Klement Sekeradab231a2016-12-21 08:50:14 +010018
Neale Ranns8fe8cc22016-11-01 10:05:08 +000019class TestMPLS(VppTestCase):
20 """ MPLS Test Case """
21
Neale Ranns8fe8cc22016-11-01 10:05:08 +000022 def setUp(self):
23 super(TestMPLS, self).setUp()
24
25 # create 2 pg interfaces
Neale Ranns0f26c5a2017-03-01 15:12:11 -080026 self.create_pg_interfaces(range(4))
Neale Ranns8fe8cc22016-11-01 10:05:08 +000027
28 # setup both interfaces
29 # assign them different tables.
30 table_id = 0
31
32 for i in self.pg_interfaces:
33 i.admin_up()
34 i.set_table_ip4(table_id)
35 i.set_table_ip6(table_id)
36 i.config_ip4()
Neale Ranns8fe8cc22016-11-01 10:05:08 +000037 i.resolve_arp()
Neale Rannsad422ed2016-11-02 14:20:04 +000038 i.config_ip6()
Neale Ranns8fe8cc22016-11-01 10:05:08 +000039 i.resolve_ndp()
Neale Rannsad422ed2016-11-02 14:20:04 +000040 i.enable_mpls()
Neale Ranns8fe8cc22016-11-01 10:05:08 +000041 table_id += 1
42
43 def tearDown(self):
44 super(TestMPLS, self).tearDown()
Neale Ranns4008ac92017-02-13 23:20:04 -080045 for i in self.pg_interfaces:
46 i.unconfig_ip4()
47 i.unconfig_ip6()
48 i.ip6_disable()
49 i.admin_down()
Neale Ranns8fe8cc22016-11-01 10:05:08 +000050
Neale Rannsad422ed2016-11-02 14:20:04 +000051 # the default of 64 matches the IP packet TTL default
Klement Sekeradab231a2016-12-21 08:50:14 +010052 def create_stream_labelled_ip4(
53 self,
54 src_if,
55 mpls_labels,
56 mpls_ttl=255,
57 ping=0,
Neale Ranns0f26c5a2017-03-01 15:12:11 -080058 ip_itf=None,
59 dst_ip=None,
60 n=257):
Klement Sekeradab231a2016-12-21 08:50:14 +010061 self.reset_packet_infos()
Neale Ranns8fe8cc22016-11-01 10:05:08 +000062 pkts = []
Neale Ranns0f26c5a2017-03-01 15:12:11 -080063 for i in range(0, n):
Klement Sekeradab231a2016-12-21 08:50:14 +010064 info = self.create_packet_info(src_if, src_if)
Neale Ranns8fe8cc22016-11-01 10:05:08 +000065 payload = self.info_to_payload(info)
Neale Rannsad422ed2016-11-02 14:20:04 +000066 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
67
68 for ii in range(len(mpls_labels)):
69 if ii == len(mpls_labels) - 1:
70 p = p / MPLS(label=mpls_labels[ii], ttl=mpls_ttl, s=1)
71 else:
72 p = p / MPLS(label=mpls_labels[ii], ttl=mpls_ttl, s=0)
Neale Rannscb630ff2016-12-14 13:31:29 +010073 if not ping:
Neale Ranns0f26c5a2017-03-01 15:12:11 -080074 if not dst_ip:
75 p = (p / IP(src=src_if.local_ip4, dst=src_if.remote_ip4) /
76 UDP(sport=1234, dport=1234) /
77 Raw(payload))
78 else:
79 p = (p / IP(src=src_if.local_ip4, dst=dst_ip) /
80 UDP(sport=1234, dport=1234) /
81 Raw(payload))
Neale Rannscb630ff2016-12-14 13:31:29 +010082 else:
83 p = (p / IP(src=ip_itf.remote_ip4,
84 dst=ip_itf.local_ip4) /
85 ICMP())
86
Neale Ranns8fe8cc22016-11-01 10:05:08 +000087 info.data = p.copy()
88 pkts.append(p)
89 return pkts
90
Neale Rannsad422ed2016-11-02 14:20:04 +000091 def create_stream_ip4(self, src_if, dst_ip):
Klement Sekeradab231a2016-12-21 08:50:14 +010092 self.reset_packet_infos()
Neale Rannsad422ed2016-11-02 14:20:04 +000093 pkts = []
94 for i in range(0, 257):
Klement Sekeradab231a2016-12-21 08:50:14 +010095 info = self.create_packet_info(src_if, src_if)
Neale Rannsad422ed2016-11-02 14:20:04 +000096 payload = self.info_to_payload(info)
97 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
98 IP(src=src_if.remote_ip4, dst=dst_ip) /
99 UDP(sport=1234, dport=1234) /
100 Raw(payload))
101 info.data = p.copy()
102 pkts.append(p)
103 return pkts
104
105 def create_stream_labelled_ip6(self, src_if, mpls_label, mpls_ttl):
Klement Sekeradab231a2016-12-21 08:50:14 +0100106 self.reset_packet_infos()
Neale Ranns8fe8cc22016-11-01 10:05:08 +0000107 pkts = []
108 for i in range(0, 257):
Klement Sekeradab231a2016-12-21 08:50:14 +0100109 info = self.create_packet_info(src_if, src_if)
Neale Ranns8fe8cc22016-11-01 10:05:08 +0000110 payload = self.info_to_payload(info)
111 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
112 MPLS(label=mpls_label, ttl=mpls_ttl) /
113 IPv6(src=src_if.remote_ip6, dst=src_if.remote_ip6) /
114 UDP(sport=1234, dport=1234) /
115 Raw(payload))
116 info.data = p.copy()
117 pkts.append(p)
118 return pkts
119
Matej Klottondeb69842016-12-09 15:05:46 +0100120 @staticmethod
121 def verify_filter(capture, sent):
Neale Rannsad422ed2016-11-02 14:20:04 +0000122 if not len(capture) == len(sent):
Matej Klottondeb69842016-12-09 15:05:46 +0100123 # filter out any IPv6 RAs from the capture
Neale Rannsad422ed2016-11-02 14:20:04 +0000124 for p in capture:
Matej Klottondeb69842016-12-09 15:05:46 +0100125 if p.haslayer(IPv6):
Neale Rannsad422ed2016-11-02 14:20:04 +0000126 capture.remove(p)
127 return capture
128
Neale Rannscb630ff2016-12-14 13:31:29 +0100129 def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0):
Neale Ranns8fe8cc22016-11-01 10:05:08 +0000130 try:
Neale Rannsad422ed2016-11-02 14:20:04 +0000131 capture = self.verify_filter(capture, sent)
132
Neale Ranns8fe8cc22016-11-01 10:05:08 +0000133 self.assertEqual(len(capture), len(sent))
134
135 for i in range(len(capture)):
136 tx = sent[i]
137 rx = capture[i]
138
139 # the rx'd packet has the MPLS label popped
Neale Rannsad422ed2016-11-02 14:20:04 +0000140 eth = rx[Ether]
141 self.assertEqual(eth.type, 0x800)
Neale Ranns8fe8cc22016-11-01 10:05:08 +0000142
143 tx_ip = tx[IP]
144 rx_ip = rx[IP]
145
Neale Rannscb630ff2016-12-14 13:31:29 +0100146 if not ping_resp:
147 self.assertEqual(rx_ip.src, tx_ip.src)
148 self.assertEqual(rx_ip.dst, tx_ip.dst)
149 # IP processing post pop has decremented the TTL
150 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
151 else:
152 self.assertEqual(rx_ip.src, tx_ip.dst)
153 self.assertEqual(rx_ip.dst, tx_ip.src)
Neale Ranns8fe8cc22016-11-01 10:05:08 +0000154
155 except:
Neale Rannsad422ed2016-11-02 14:20:04 +0000156 raise
157
158 def verify_mpls_stack(self, rx, mpls_labels, ttl=255, num=0):
159 # the rx'd packet has the MPLS label popped
160 eth = rx[Ether]
161 self.assertEqual(eth.type, 0x8847)
162
163 rx_mpls = rx[MPLS]
164
165 for ii in range(len(mpls_labels)):
166 self.assertEqual(rx_mpls.label, mpls_labels[ii])
167 self.assertEqual(rx_mpls.cos, 0)
168 if ii == num:
169 self.assertEqual(rx_mpls.ttl, ttl)
170 else:
171 self.assertEqual(rx_mpls.ttl, 255)
172
173 if ii == len(mpls_labels) - 1:
174 self.assertEqual(rx_mpls.s, 1)
175 else:
176 # not end of stack
177 self.assertEqual(rx_mpls.s, 0)
178 # pop the label to expose the next
179 rx_mpls = rx_mpls[MPLS].payload
180
181 def verify_capture_labelled_ip4(self, src_if, capture, sent,
182 mpls_labels):
183 try:
184 capture = self.verify_filter(capture, sent)
185
186 self.assertEqual(len(capture), len(sent))
187
188 for i in range(len(capture)):
189 tx = sent[i]
190 rx = capture[i]
191 tx_ip = tx[IP]
192 rx_ip = rx[IP]
193
194 # the MPLS TTL is copied from the IP
195 self.verify_mpls_stack(
196 rx, mpls_labels, rx_ip.ttl, len(mpls_labels) - 1)
197
198 self.assertEqual(rx_ip.src, tx_ip.src)
199 self.assertEqual(rx_ip.dst, tx_ip.dst)
200 # IP processing post pop has decremented the TTL
201 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
202
203 except:
204 raise
205
206 def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
207 try:
208 capture = self.verify_filter(capture, sent)
209
210 self.assertEqual(len(capture), len(sent))
211
212 for i in range(len(capture)):
213 tx = sent[i]
214 rx = capture[i]
215 tx_ip = tx[IP]
216 rx_ip = rx[IP]
217
218 # the MPLS TTL is 255 since it enters a new tunnel
219 self.verify_mpls_stack(
220 rx, mpls_labels, 255, len(mpls_labels) - 1)
221
222 self.assertEqual(rx_ip.src, tx_ip.src)
223 self.assertEqual(rx_ip.dst, tx_ip.dst)
224 # IP processing post pop has decremented the TTL
225 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
226
227 except:
228 raise
229
230 def verify_capture_labelled(self, src_if, capture, sent,
231 mpls_labels, ttl=254, num=0):
232 try:
233 capture = self.verify_filter(capture, sent)
234
235 self.assertEqual(len(capture), len(sent))
236
237 for i in range(len(capture)):
238 rx = capture[i]
239 self.verify_mpls_stack(rx, mpls_labels, ttl, num)
240 except:
241 raise
Neale Ranns8fe8cc22016-11-01 10:05:08 +0000242
243 def verify_capture_ip6(self, src_if, capture, sent):
244 try:
245 self.assertEqual(len(capture), len(sent))
246
247 for i in range(len(capture)):
248 tx = sent[i]
249 rx = capture[i]
250
251 # the rx'd packet has the MPLS label popped
Neale Rannsad422ed2016-11-02 14:20:04 +0000252 eth = rx[Ether]
253 self.assertEqual(eth.type, 0x86DD)
Neale Ranns8fe8cc22016-11-01 10:05:08 +0000254
255 tx_ip = tx[IPv6]
256 rx_ip = rx[IPv6]
257
258 self.assertEqual(rx_ip.src, tx_ip.src)
259 self.assertEqual(rx_ip.dst, tx_ip.dst)
260 # IP processing post pop has decremented the TTL
261 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
262
263 except:
Neale Rannsad422ed2016-11-02 14:20:04 +0000264 raise
Neale Ranns8fe8cc22016-11-01 10:05:08 +0000265
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800266 def send_and_assert_no_replies(self, intf, pkts, remark):
267 intf.add_stream(pkts)
268 self.pg_enable_capture(self.pg_interfaces)
269 self.pg_start()
270 for i in self.pg_interfaces:
271 i.assert_nothing_captured(remark=remark)
272
Neale Rannsad422ed2016-11-02 14:20:04 +0000273 def test_swap(self):
274 """ MPLS label swap tests """
275
276 #
277 # A simple MPLS xconnect - eos label in label out
278 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800279 route_32_eos = VppMplsRoute(self, 32, 1,
280 [VppRoutePath(self.pg0.remote_ip4,
281 self.pg0.sw_if_index,
282 labels=[33])])
Neale Rannsad422ed2016-11-02 14:20:04 +0000283 route_32_eos.add_vpp_config()
284
285 #
286 # a stream that matches the route for 10.0.0.1
287 # PG0 is in the default table
288 #
289 self.vapi.cli("clear trace")
290 tx = self.create_stream_labelled_ip4(self.pg0, [32])
291 self.pg0.add_stream(tx)
292
293 self.pg_enable_capture(self.pg_interfaces)
294 self.pg_start()
295
296 rx = self.pg0.get_capture()
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800297 self.verify_capture_labelled(self.pg0, rx, tx, [33])
Neale Rannsad422ed2016-11-02 14:20:04 +0000298
299 #
300 # A simple MPLS xconnect - non-eos label in label out
301 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800302 route_32_neos = VppMplsRoute(self, 32, 0,
303 [VppRoutePath(self.pg0.remote_ip4,
304 self.pg0.sw_if_index,
305 labels=[33])])
Neale Rannsad422ed2016-11-02 14:20:04 +0000306 route_32_neos.add_vpp_config()
307
308 #
309 # a stream that matches the route for 10.0.0.1
310 # PG0 is in the default table
311 #
312 self.vapi.cli("clear trace")
313 tx = self.create_stream_labelled_ip4(self.pg0, [32, 99])
314 self.pg0.add_stream(tx)
315
316 self.pg_enable_capture(self.pg_interfaces)
317 self.pg_start()
318
319 rx = self.pg0.get_capture()
320 self.verify_capture_labelled(self.pg0, rx, tx, [33, 99])
321
322 #
323 # An MPLS xconnect - EOS label in IP out
324 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800325 route_33_eos = VppMplsRoute(self, 33, 1,
326 [VppRoutePath(self.pg0.remote_ip4,
327 self.pg0.sw_if_index,
328 labels=[])])
Neale Rannsad422ed2016-11-02 14:20:04 +0000329 route_33_eos.add_vpp_config()
330
331 self.vapi.cli("clear trace")
332 tx = self.create_stream_labelled_ip4(self.pg0, [33])
333 self.pg0.add_stream(tx)
334
335 self.pg_enable_capture(self.pg_interfaces)
336 self.pg_start()
337
338 rx = self.pg0.get_capture()
339 self.verify_capture_ip4(self.pg0, rx, tx)
340
341 #
342 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
343 # so this traffic should be dropped.
344 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800345 route_33_neos = VppMplsRoute(self, 33, 0,
346 [VppRoutePath(self.pg0.remote_ip4,
347 self.pg0.sw_if_index,
348 labels=[])])
Neale Rannsad422ed2016-11-02 14:20:04 +0000349 route_33_neos.add_vpp_config()
350
351 self.vapi.cli("clear trace")
352 tx = self.create_stream_labelled_ip4(self.pg0, [33, 99])
353 self.pg0.add_stream(tx)
354
355 self.pg_enable_capture(self.pg_interfaces)
356 self.pg_start()
Klement Sekera9225dee2016-12-12 08:36:58 +0100357 self.pg0.assert_nothing_captured(
358 remark="MPLS non-EOS packets popped and forwarded")
Neale Rannsad422ed2016-11-02 14:20:04 +0000359
360 #
361 # A recursive EOS x-connect, which resolves through another x-connect
362 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800363 route_34_eos = VppMplsRoute(self, 34, 1,
364 [VppRoutePath("0.0.0.0",
365 0xffffffff,
366 nh_via_label=32,
367 labels=[44, 45])])
Neale Rannsad422ed2016-11-02 14:20:04 +0000368 route_34_eos.add_vpp_config()
369
Neale Rannsad422ed2016-11-02 14:20:04 +0000370 tx = self.create_stream_labelled_ip4(self.pg0, [34])
371 self.pg0.add_stream(tx)
372
373 self.pg_enable_capture(self.pg_interfaces)
374 self.pg_start()
375
376 rx = self.pg0.get_capture()
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800377 self.verify_capture_labelled(self.pg0, rx, tx, [33, 44, 45], num=2)
Neale Rannsad422ed2016-11-02 14:20:04 +0000378
379 #
Matej Klottondeb69842016-12-09 15:05:46 +0100380 # A recursive non-EOS x-connect, which resolves through another
381 # x-connect
Neale Rannsad422ed2016-11-02 14:20:04 +0000382 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800383 route_34_neos = VppMplsRoute(self, 34, 0,
384 [VppRoutePath("0.0.0.0",
385 0xffffffff,
386 nh_via_label=32,
387 labels=[44, 46])])
Neale Rannsad422ed2016-11-02 14:20:04 +0000388 route_34_neos.add_vpp_config()
389
390 self.vapi.cli("clear trace")
391 tx = self.create_stream_labelled_ip4(self.pg0, [34, 99])
392 self.pg0.add_stream(tx)
393
394 self.pg_enable_capture(self.pg_interfaces)
395 self.pg_start()
396
397 rx = self.pg0.get_capture()
Matej Klottondeb69842016-12-09 15:05:46 +0100398 # it's the 2nd (counting from 0) label in the stack that is swapped
Neale Rannsad422ed2016-11-02 14:20:04 +0000399 self.verify_capture_labelled(self.pg0, rx, tx, [33, 44, 46, 99], num=2)
400
401 #
Matej Klottondeb69842016-12-09 15:05:46 +0100402 # an recursive IP route that resolves through the recursive non-eos
403 # x-connect
Neale Rannsad422ed2016-11-02 14:20:04 +0000404 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800405 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
406 [VppRoutePath("0.0.0.0",
407 0xffffffff,
408 nh_via_label=34,
409 labels=[55])])
Neale Rannsad422ed2016-11-02 14:20:04 +0000410 ip_10_0_0_1.add_vpp_config()
411
412 self.vapi.cli("clear trace")
413 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
414 self.pg0.add_stream(tx)
415
416 self.pg_enable_capture(self.pg_interfaces)
417 self.pg_start()
418
419 rx = self.pg0.get_capture()
420 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [33, 44, 46, 55])
421
422 ip_10_0_0_1.remove_vpp_config()
423 route_34_neos.remove_vpp_config()
424 route_34_eos.remove_vpp_config()
425 route_33_neos.remove_vpp_config()
426 route_33_eos.remove_vpp_config()
427 route_32_neos.remove_vpp_config()
428 route_32_eos.remove_vpp_config()
429
430 def test_bind(self):
431 """ MPLS Local Label Binding test """
432
433 #
434 # Add a non-recursive route with a single out label
435 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800436 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
437 [VppRoutePath(self.pg0.remote_ip4,
438 self.pg0.sw_if_index,
439 labels=[45])])
Neale Rannsad422ed2016-11-02 14:20:04 +0000440 route_10_0_0_1.add_vpp_config()
441
442 # bind a local label to the route
Neale Ranns5a8123b2017-01-26 01:18:23 -0800443 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
Neale Rannsad422ed2016-11-02 14:20:04 +0000444 binding.add_vpp_config()
445
446 # non-EOS stream
447 self.vapi.cli("clear trace")
448 tx = self.create_stream_labelled_ip4(self.pg0, [44, 99])
449 self.pg0.add_stream(tx)
450
451 self.pg_enable_capture(self.pg_interfaces)
452 self.pg_start()
453
454 rx = self.pg0.get_capture()
455 self.verify_capture_labelled(self.pg0, rx, tx, [45, 99])
456
457 # EOS stream
458 self.vapi.cli("clear trace")
459 tx = self.create_stream_labelled_ip4(self.pg0, [44])
460 self.pg0.add_stream(tx)
461
462 self.pg_enable_capture(self.pg_interfaces)
463 self.pg_start()
464
465 rx = self.pg0.get_capture()
466 self.verify_capture_labelled(self.pg0, rx, tx, [45])
467
468 # IP stream
469 self.vapi.cli("clear trace")
470 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
471 self.pg0.add_stream(tx)
472
473 self.pg_enable_capture(self.pg_interfaces)
474 self.pg_start()
475
476 rx = self.pg0.get_capture()
477 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [45])
478
479 #
480 # cleanup
481 #
482 binding.remove_vpp_config()
483 route_10_0_0_1.remove_vpp_config()
484
485 def test_imposition(self):
486 """ MPLS label imposition test """
487
488 #
489 # Add a non-recursive route with a single out label
490 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800491 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
492 [VppRoutePath(self.pg0.remote_ip4,
493 self.pg0.sw_if_index,
494 labels=[32])])
Neale Rannsad422ed2016-11-02 14:20:04 +0000495 route_10_0_0_1.add_vpp_config()
496
497 #
498 # a stream that matches the route for 10.0.0.1
499 # PG0 is in the default table
500 #
501 self.vapi.cli("clear trace")
502 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
503 self.pg0.add_stream(tx)
504
505 self.pg_enable_capture(self.pg_interfaces)
506 self.pg_start()
507
508 rx = self.pg0.get_capture()
509 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32])
510
511 #
512 # Add a non-recursive route with a 3 out labels
513 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800514 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
515 [VppRoutePath(self.pg0.remote_ip4,
516 self.pg0.sw_if_index,
517 labels=[32, 33, 34])])
Neale Rannsad422ed2016-11-02 14:20:04 +0000518 route_10_0_0_2.add_vpp_config()
519
520 #
521 # a stream that matches the route for 10.0.0.1
522 # PG0 is in the default table
523 #
524 self.vapi.cli("clear trace")
525 tx = self.create_stream_ip4(self.pg0, "10.0.0.2")
526 self.pg0.add_stream(tx)
527
528 self.pg_enable_capture(self.pg_interfaces)
529 self.pg_start()
530
531 rx = self.pg0.get_capture()
532 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32, 33, 34])
533
534 #
Matej Klottondeb69842016-12-09 15:05:46 +0100535 # add a recursive path, with output label, via the 1 label route
Neale Rannsad422ed2016-11-02 14:20:04 +0000536 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800537 route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
538 [VppRoutePath("10.0.0.1",
539 0xffffffff,
540 labels=[44])])
Neale Rannsad422ed2016-11-02 14:20:04 +0000541 route_11_0_0_1.add_vpp_config()
542
543 #
544 # a stream that matches the route for 11.0.0.1, should pick up
545 # the label stack for 11.0.0.1 and 10.0.0.1
546 #
547 self.vapi.cli("clear trace")
548 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
549 self.pg0.add_stream(tx)
550
551 self.pg_enable_capture(self.pg_interfaces)
552 self.pg_start()
553
554 rx = self.pg0.get_capture()
555 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32, 44])
556
557 #
558 # add a recursive path, with 2 labels, via the 3 label route
559 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800560 route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
561 [VppRoutePath("10.0.0.2",
562 0xffffffff,
563 labels=[44, 45])])
Neale Rannsad422ed2016-11-02 14:20:04 +0000564 route_11_0_0_2.add_vpp_config()
565
566 #
567 # a stream that matches the route for 11.0.0.1, should pick up
568 # the label stack for 11.0.0.1 and 10.0.0.1
569 #
570 self.vapi.cli("clear trace")
571 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
572 self.pg0.add_stream(tx)
573
574 self.pg_enable_capture(self.pg_interfaces)
575 self.pg_start()
576
577 rx = self.pg0.get_capture()
578 self.verify_capture_labelled_ip4(
579 self.pg0, rx, tx, [32, 33, 34, 44, 45])
580
581 #
582 # cleanup
583 #
584 route_11_0_0_2.remove_vpp_config()
585 route_11_0_0_1.remove_vpp_config()
586 route_10_0_0_2.remove_vpp_config()
587 route_10_0_0_1.remove_vpp_config()
588
589 def test_tunnel(self):
590 """ MPLS Tunnel Tests """
591
592 #
593 # Create a tunnel with a single out label
594 #
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800595 mpls_tun = VppMPLSTunnelInterface(self,
596 [VppRoutePath(self.pg0.remote_ip4,
597 self.pg0.sw_if_index,
598 labels=[44, 46])])
599 mpls_tun.add_vpp_config()
600 mpls_tun.admin_up()
Neale Rannsad422ed2016-11-02 14:20:04 +0000601
602 #
603 # add an unlabelled route through the new tunnel
604 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800605 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
606 [VppRoutePath("0.0.0.0",
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800607 mpls_tun._sw_if_index)])
Neale Ranns5a8123b2017-01-26 01:18:23 -0800608 route_10_0_0_3.add_vpp_config()
Neale Rannsad422ed2016-11-02 14:20:04 +0000609
610 self.vapi.cli("clear trace")
611 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
612 self.pg0.add_stream(tx)
613
614 self.pg_enable_capture(self.pg_interfaces)
615 self.pg_start()
616
617 rx = self.pg0.get_capture()
618 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [44, 46])
Neale Ranns8fe8cc22016-11-01 10:05:08 +0000619
620 def test_v4_exp_null(self):
621 """ MPLS V4 Explicit NULL test """
622
623 #
624 # The first test case has an MPLS TTL of 0
625 # all packet should be dropped
626 #
Neale Rannsad422ed2016-11-02 14:20:04 +0000627 tx = self.create_stream_labelled_ip4(self.pg0, [0], 0)
Neale Ranns8fe8cc22016-11-01 10:05:08 +0000628 self.pg0.add_stream(tx)
629
630 self.pg_enable_capture(self.pg_interfaces)
631 self.pg_start()
632
Klement Sekera9225dee2016-12-12 08:36:58 +0100633 self.pg0.assert_nothing_captured(remark="MPLS TTL=0 packets forwarded")
Neale Ranns8fe8cc22016-11-01 10:05:08 +0000634
635 #
636 # a stream with a non-zero MPLS TTL
637 # PG0 is in the default table
638 #
Neale Rannsad422ed2016-11-02 14:20:04 +0000639 tx = self.create_stream_labelled_ip4(self.pg0, [0])
Neale Ranns8fe8cc22016-11-01 10:05:08 +0000640 self.pg0.add_stream(tx)
641
642 self.pg_enable_capture(self.pg_interfaces)
643 self.pg_start()
644
645 rx = self.pg0.get_capture()
646 self.verify_capture_ip4(self.pg0, rx, tx)
647
648 #
649 # a stream with a non-zero MPLS TTL
650 # PG1 is in table 1
651 # we are ensuring the post-pop lookup occurs in the VRF table
652 #
653 self.vapi.cli("clear trace")
Neale Rannsad422ed2016-11-02 14:20:04 +0000654 tx = self.create_stream_labelled_ip4(self.pg1, [0])
Neale Ranns8fe8cc22016-11-01 10:05:08 +0000655 self.pg1.add_stream(tx)
656
657 self.pg_enable_capture(self.pg_interfaces)
658 self.pg_start()
659
660 rx = self.pg1.get_capture()
661 self.verify_capture_ip4(self.pg0, rx, tx)
662
663 def test_v6_exp_null(self):
664 """ MPLS V6 Explicit NULL test """
665
666 #
667 # a stream with a non-zero MPLS TTL
668 # PG0 is in the default table
669 #
670 self.vapi.cli("clear trace")
Neale Rannsad422ed2016-11-02 14:20:04 +0000671 tx = self.create_stream_labelled_ip6(self.pg0, 2, 2)
Neale Ranns8fe8cc22016-11-01 10:05:08 +0000672 self.pg0.add_stream(tx)
673
674 self.pg_enable_capture(self.pg_interfaces)
675 self.pg_start()
676
677 rx = self.pg0.get_capture()
678 self.verify_capture_ip6(self.pg0, rx, tx)
679
680 #
681 # a stream with a non-zero MPLS TTL
682 # PG1 is in table 1
683 # we are ensuring the post-pop lookup occurs in the VRF table
684 #
685 self.vapi.cli("clear trace")
Neale Rannsad422ed2016-11-02 14:20:04 +0000686 tx = self.create_stream_labelled_ip6(self.pg1, 2, 2)
Neale Ranns8fe8cc22016-11-01 10:05:08 +0000687 self.pg1.add_stream(tx)
688
689 self.pg_enable_capture(self.pg_interfaces)
690 self.pg_start()
691
692 rx = self.pg1.get_capture()
693 self.verify_capture_ip6(self.pg0, rx, tx)
694
Neale Rannscb630ff2016-12-14 13:31:29 +0100695 def test_deag(self):
696 """ MPLS Deagg """
697
698 #
699 # A de-agg route - next-hop lookup in default table
700 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800701 route_34_eos = VppMplsRoute(self, 34, 1,
702 [VppRoutePath("0.0.0.0",
703 0xffffffff,
704 nh_table_id=0)])
Neale Rannscb630ff2016-12-14 13:31:29 +0100705 route_34_eos.add_vpp_config()
706
707 #
708 # ping an interface in the default table
709 # PG0 is in the default table
710 #
711 self.vapi.cli("clear trace")
712 tx = self.create_stream_labelled_ip4(self.pg0, [34], ping=1,
713 ip_itf=self.pg0)
714 self.pg0.add_stream(tx)
715
716 self.pg_enable_capture(self.pg_interfaces)
717 self.pg_start()
718
719 rx = self.pg0.get_capture()
720 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
721
722 #
723 # A de-agg route - next-hop lookup in non-default table
724 #
Neale Ranns5a8123b2017-01-26 01:18:23 -0800725 route_35_eos = VppMplsRoute(self, 35, 1,
726 [VppRoutePath("0.0.0.0",
727 0xffffffff,
728 nh_table_id=1)])
Neale Rannscb630ff2016-12-14 13:31:29 +0100729 route_35_eos.add_vpp_config()
730
731 #
732 # ping an interface in the non-default table
733 # PG0 is in the default table. packet arrive labelled in the
734 # default table and egress unlabelled in the non-default
735 #
736 self.vapi.cli("clear trace")
Klement Sekeradab231a2016-12-21 08:50:14 +0100737 tx = self.create_stream_labelled_ip4(
738 self.pg0, [35], ping=1, ip_itf=self.pg1)
Neale Rannscb630ff2016-12-14 13:31:29 +0100739 self.pg0.add_stream(tx)
740
741 self.pg_enable_capture(self.pg_interfaces)
742 self.pg_start()
743
Klement Sekeradab231a2016-12-21 08:50:14 +0100744 packet_count = self.get_packet_count_for_if_idx(self.pg0.sw_if_index)
745 rx = self.pg1.get_capture(packet_count)
Neale Rannscb630ff2016-12-14 13:31:29 +0100746 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
747
748 route_35_eos.remove_vpp_config()
749 route_34_eos.remove_vpp_config()
Neale Ranns8fe8cc22016-11-01 10:05:08 +0000750
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800751 def test_interface_rx(self):
752 """ MPLS Interface Receive """
753
754 #
755 # Add a non-recursive route that will forward the traffic
756 # post-interface-rx
757 #
758 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
759 table_id=1,
760 paths=[VppRoutePath(self.pg1.remote_ip4,
761 self.pg1.sw_if_index)])
762 route_10_0_0_1.add_vpp_config()
763
764 #
765 # An interface receive label that maps traffic to RX on interface
766 # pg1
767 # by injecting the packet in on pg0, which is in table 0
768 # doing an interface-rx on pg1 and matching a route in table 1
769 # if the packet egresses, then we must have swapped to pg1
770 # so as to have matched the route in table 1
771 #
772 route_34_eos = VppMplsRoute(self, 34, 1,
773 [VppRoutePath("0.0.0.0",
774 self.pg1.sw_if_index,
775 is_interface_rx=1)])
776 route_34_eos.add_vpp_config()
777
778 #
779 # ping an interface in the default table
780 # PG0 is in the default table
781 #
782 self.vapi.cli("clear trace")
783 tx = self.create_stream_labelled_ip4(self.pg0, [34], n=257,
784 dst_ip="10.0.0.1")
785 self.pg0.add_stream(tx)
786
787 self.pg_enable_capture(self.pg_interfaces)
788 self.pg_start()
789
790 rx = self.pg1.get_capture(257)
791 self.verify_capture_ip4(self.pg1, rx, tx)
792
793 def test_mcast_mid_point(self):
794 """ MPLS Multicast Mid Point """
795
796 #
797 # Add a non-recursive route that will forward the traffic
798 # post-interface-rx
799 #
800 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
801 table_id=1,
802 paths=[VppRoutePath(self.pg1.remote_ip4,
803 self.pg1.sw_if_index)])
804 route_10_0_0_1.add_vpp_config()
805
806 #
807 # Add a mcast entry that replicate to pg2 and pg3
808 # and replicate to a interface-rx (like a bud node would)
809 #
810 route_3400_eos = VppMplsRoute(self, 3400, 1,
811 [VppRoutePath(self.pg2.remote_ip4,
812 self.pg2.sw_if_index,
813 labels=[3401]),
814 VppRoutePath(self.pg3.remote_ip4,
815 self.pg3.sw_if_index,
816 labels=[3402]),
817 VppRoutePath("0.0.0.0",
818 self.pg1.sw_if_index,
819 is_interface_rx=1)],
820 is_multicast=1)
821 route_3400_eos.add_vpp_config()
822
823 #
824 # ping an interface in the default table
825 # PG0 is in the default table
826 #
827 self.vapi.cli("clear trace")
828 tx = self.create_stream_labelled_ip4(self.pg0, [3400], n=257,
829 dst_ip="10.0.0.1")
830 self.pg0.add_stream(tx)
831
832 self.pg_enable_capture(self.pg_interfaces)
833 self.pg_start()
834
835 rx = self.pg1.get_capture(257)
836 self.verify_capture_ip4(self.pg1, rx, tx)
837
838 rx = self.pg2.get_capture(257)
839 self.verify_capture_labelled(self.pg2, rx, tx, [3401])
840 rx = self.pg3.get_capture(257)
841 self.verify_capture_labelled(self.pg3, rx, tx, [3402])
842
843 def test_mcast_head(self):
844 """ MPLS Multicast Head-end """
845
846 #
847 # Create a multicast tunnel with two replications
848 #
849 mpls_tun = VppMPLSTunnelInterface(self,
850 [VppRoutePath(self.pg2.remote_ip4,
851 self.pg2.sw_if_index,
852 labels=[42]),
853 VppRoutePath(self.pg3.remote_ip4,
854 self.pg3.sw_if_index,
855 labels=[43])],
856 is_multicast=1)
857 mpls_tun.add_vpp_config()
858 mpls_tun.admin_up()
859
860 #
861 # add an unlabelled route through the new tunnel
862 #
863 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
864 [VppRoutePath("0.0.0.0",
865 mpls_tun._sw_if_index)])
866 route_10_0_0_3.add_vpp_config()
867
868 self.vapi.cli("clear trace")
869 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
870 self.pg0.add_stream(tx)
871
872 self.pg_enable_capture(self.pg_interfaces)
873 self.pg_start()
874
875 rx = self.pg2.get_capture(257)
876 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [42])
877 rx = self.pg3.get_capture(257)
878 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [43])
879
880 #
881 # An an IP multicast route via the tunnel
882 # A (*,G).
883 # one accepting interface, pg0, 1 forwarding interface via the tunnel
884 #
885 route_232_1_1_1 = VppIpMRoute(
886 self,
887 "0.0.0.0",
888 "232.1.1.1", 32,
889 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
890 [VppMRoutePath(self.pg0.sw_if_index,
891 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
892 VppMRoutePath(mpls_tun._sw_if_index,
893 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
894 route_232_1_1_1.add_vpp_config()
895
896 self.vapi.cli("clear trace")
897 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
898 self.pg0.add_stream(tx)
899
900 self.pg_enable_capture(self.pg_interfaces)
901 self.pg_start()
902
903 rx = self.pg2.get_capture(257)
904 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [42])
905 rx = self.pg3.get_capture(257)
906 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [43])
907
908 def test_mcast_tail(self):
909 """ MPLS Multicast Tail """
910
911 #
912 # Add a multicast route that will forward the traffic
913 # post-disposition
914 #
915 route_232_1_1_1 = VppIpMRoute(
916 self,
917 "0.0.0.0",
918 "232.1.1.1", 32,
919 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
920 table_id=1,
921 paths=[VppMRoutePath(self.pg1.sw_if_index,
922 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
923 route_232_1_1_1.add_vpp_config()
924
925 #
926 # An interface receive label that maps traffic to RX on interface
927 # pg1
928 # by injecting the packet in on pg0, which is in table 0
929 # doing an rpf-id and matching a route in table 1
930 # if the packet egresses, then we must have matched the route in
931 # table 1
932 #
933 route_34_eos = VppMplsRoute(self, 34, 1,
934 [VppRoutePath("0.0.0.0",
935 self.pg1.sw_if_index,
936 nh_table_id=1,
937 rpf_id=55)],
938 is_multicast=1)
939
940 route_34_eos.add_vpp_config()
941
942 #
943 # Drop due to interface lookup miss
944 #
945 self.vapi.cli("clear trace")
946 tx = self.create_stream_labelled_ip4(self.pg0, [34],
947 dst_ip="232.1.1.1", n=1)
948 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
949
950 #
951 # set the RPF-ID of the enrtry to match the input packet's
952 #
953 route_232_1_1_1.update_rpf_id(55)
954
955 self.vapi.cli("clear trace")
956 tx = self.create_stream_labelled_ip4(self.pg0, [34],
957 dst_ip="232.1.1.1", n=257)
958 self.pg0.add_stream(tx)
959
960 self.pg_enable_capture(self.pg_interfaces)
961 self.pg_start()
962
963 rx = self.pg1.get_capture(257)
964 self.verify_capture_ip4(self.pg1, rx, tx)
965
966 #
967 # set the RPF-ID of the enrtry to not match the input packet's
968 #
969 route_232_1_1_1.update_rpf_id(56)
970 tx = self.create_stream_labelled_ip4(self.pg0, [34],
971 dst_ip="232.1.1.1")
972 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
973
Neale Ranns180279b2017-03-16 15:49:09 -0400974
975class TestMPLSDisabled(VppTestCase):
976 """ MPLS disabled """
977
978 def setUp(self):
979 super(TestMPLSDisabled, self).setUp()
980
981 # create 2 pg interfaces
982 self.create_pg_interfaces(range(2))
983
984 # PG0 is MPLS enalbed
985 self.pg0.admin_up()
986 self.pg0.config_ip4()
987 self.pg0.resolve_arp()
988 self.pg0.enable_mpls()
989
990 # PG 1 is not MPLS enabled
991 self.pg1.admin_up()
992
993 def tearDown(self):
994 super(TestMPLSDisabled, self).tearDown()
995 for i in self.pg_interfaces:
996 i.unconfig_ip4()
997 i.admin_down()
998
999 def send_and_assert_no_replies(self, intf, pkts, remark):
1000 intf.add_stream(pkts)
1001 self.pg_enable_capture(self.pg_interfaces)
1002 self.pg_start()
1003 for i in self.pg_interfaces:
1004 i.get_capture(0)
1005 i.assert_nothing_captured(remark=remark)
1006
1007 def test_mpls_disabled(self):
1008 """ MPLS Disabled """
1009
1010 tx = (Ether(src=self.pg1.remote_mac,
1011 dst=self.pg1.local_mac) /
1012 MPLS(label=32, ttl=64) /
1013 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1014 UDP(sport=1234, dport=1234) /
1015 Raw('\xa5' * 100))
1016
1017 #
1018 # A simple MPLS xconnect - eos label in label out
1019 #
1020 route_32_eos = VppMplsRoute(self, 32, 1,
1021 [VppRoutePath(self.pg0.remote_ip4,
1022 self.pg0.sw_if_index,
1023 labels=[33])])
1024 route_32_eos.add_vpp_config()
1025
1026 #
1027 # PG1 does not forward IP traffic
1028 #
1029 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1030
1031 #
1032 # MPLS enable PG1
1033 #
1034 self.pg1.enable_mpls()
1035
1036 #
1037 # Now we get packets through
1038 #
1039 self.pg1.add_stream(tx)
1040 self.pg_enable_capture(self.pg_interfaces)
1041 self.pg_start()
1042
1043 rx = self.pg0.get_capture(1)
1044
1045 #
1046 # Disable PG1
1047 #
1048 self.pg1.disable_mpls()
1049
1050 #
1051 # PG1 does not forward IP traffic
1052 #
1053 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1054 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1055
1056
Neale Rannsf12a83f2017-04-18 09:09:40 -07001057class TestMPLSPIC(VppTestCase):
1058 """ MPLS PIC edge convergence """
1059
1060 def setUp(self):
1061 super(TestMPLSPIC, self).setUp()
1062
1063 # create 2 pg interfaces
1064 self.create_pg_interfaces(range(4))
1065
1066 # core links
1067 self.pg0.admin_up()
1068 self.pg0.config_ip4()
1069 self.pg0.resolve_arp()
1070 self.pg0.enable_mpls()
1071 self.pg1.admin_up()
1072 self.pg1.config_ip4()
1073 self.pg1.resolve_arp()
1074 self.pg1.enable_mpls()
1075
1076 # VRF (customer facing) link
1077 self.pg2.admin_up()
1078 self.pg2.set_table_ip4(1)
1079 self.pg2.config_ip4()
1080 self.pg2.resolve_arp()
1081 self.pg2.set_table_ip6(1)
1082 self.pg2.config_ip6()
1083 self.pg2.resolve_ndp()
1084 self.pg3.admin_up()
1085 self.pg3.set_table_ip4(1)
1086 self.pg3.config_ip4()
1087 self.pg3.resolve_arp()
1088 self.pg3.set_table_ip6(1)
1089 self.pg3.config_ip6()
1090 self.pg3.resolve_ndp()
1091
1092 def tearDown(self):
1093 super(TestMPLSPIC, self).tearDown()
1094 self.pg0.disable_mpls()
1095 for i in self.pg_interfaces:
1096 i.unconfig_ip4()
1097 i.unconfig_ip6()
1098 i.set_table_ip4(0)
1099 i.set_table_ip6(0)
1100 i.admin_down()
1101
1102 def test_mpls_ibgp_pic(self):
1103 """ MPLS iBGP PIC edge convergence
1104
1105 1) setup many iBGP VPN routes via a pair of iBGP peers.
1106 2) Check EMCP forwarding to these peers
1107 3) withdraw the IGP route to one of these peers.
1108 4) check forwarding continues to the remaining peer
1109 """
1110
1111 #
1112 # IGP+LDP core routes
1113 #
1114 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1115 [VppRoutePath(self.pg0.remote_ip4,
1116 self.pg0.sw_if_index,
1117 labels=[45])])
1118 core_10_0_0_45.add_vpp_config()
1119
1120 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1121 [VppRoutePath(self.pg1.remote_ip4,
1122 self.pg1.sw_if_index,
1123 labels=[46])])
1124 core_10_0_0_46.add_vpp_config()
1125
1126 #
1127 # Lot's of VPN routes. We need more the 64 so VPP will build
1128 # the fast convergence indirection
1129 #
1130 vpn_routes = []
1131 pkts = []
1132 for ii in range(64):
1133 dst = "192.168.1.%d" % ii
1134 vpn_routes.append(VppIpRoute(self, dst, 32,
1135 [VppRoutePath("10.0.0.45",
1136 0xffffffff,
1137 labels=[145],
1138 is_resolve_host=1),
1139 VppRoutePath("10.0.0.46",
1140 0xffffffff,
1141 labels=[146],
1142 is_resolve_host=1)],
1143 table_id=1))
1144 vpn_routes[ii].add_vpp_config()
1145
1146 pkts.append(Ether(dst=self.pg2.local_mac,
1147 src=self.pg2.remote_mac) /
1148 IP(src=self.pg2.remote_ip4, dst=dst) /
1149 UDP(sport=1234, dport=1234) /
1150 Raw('\xa5' * 100))
1151
1152 #
1153 # Send the packet stream (one pkt to each VPN route)
1154 # - expect a 50-50 split of the traffic
1155 #
1156 self.pg2.add_stream(pkts)
1157 self.pg_enable_capture(self.pg_interfaces)
1158 self.pg_start()
1159
1160 rx0 = self.pg0._get_capture(1)
1161 rx1 = self.pg1._get_capture(1)
1162
1163 # not testig the LB hashing algorithm so we're not concerned
1164 # with the split ratio, just as long as neither is 0
1165 self.assertNotEqual(0, len(rx0))
1166 self.assertNotEqual(0, len(rx1))
1167
1168 #
1169 # use a test CLI command to stop the FIB walk process, this
1170 # will prevent the FIB converging the VPN routes and thus allow
1171 # us to probe the interim (psot-fail, pre-converge) state
1172 #
1173 self.vapi.ppcli("test fib-walk-process disable")
1174
1175 #
1176 # Withdraw one of the IGP routes
1177 #
1178 core_10_0_0_46.remove_vpp_config()
1179
1180 #
1181 # now all packets should be forwarded through the remaining peer
1182 #
1183 self.vapi.ppcli("clear trace")
1184 self.pg2.add_stream(pkts)
1185 self.pg_enable_capture(self.pg_interfaces)
1186 self.pg_start()
1187
1188 rx0 = self.pg0.get_capture(len(pkts))
1189
1190 #
1191 # enable the FIB walk process to converge the FIB
1192 #
1193 self.vapi.ppcli("test fib-walk-process enable")
1194
1195 #
1196 # packets should still be forwarded through the remaining peer
1197 #
1198 self.pg2.add_stream(pkts)
1199 self.pg_enable_capture(self.pg_interfaces)
1200 self.pg_start()
1201
1202 rx0 = self.pg0.get_capture(64)
1203
1204 #
1205 # Add the IGP route back and we return to load-balancing
1206 #
1207 core_10_0_0_46.add_vpp_config()
1208
1209 self.pg2.add_stream(pkts)
1210 self.pg_enable_capture(self.pg_interfaces)
1211 self.pg_start()
1212
1213 rx0 = self.pg0._get_capture(1)
1214 rx1 = self.pg1._get_capture(1)
1215 self.assertNotEqual(0, len(rx0))
1216 self.assertNotEqual(0, len(rx1))
1217
1218 def test_mpls_ebgp_pic(self):
1219 """ MPLS eBGP PIC edge convergence
1220
1221 1) setup many eBGP VPN routes via a pair of eBGP peers
1222 2) Check EMCP forwarding to these peers
1223 3) withdraw one eBGP path - expect LB across remaining eBGP
1224 """
1225
1226 #
1227 # Lot's of VPN routes. We need more the 64 so VPP will build
1228 # the fast convergence indirection
1229 #
1230 vpn_routes = []
1231 vpn_bindings = []
1232 pkts = []
1233 for ii in range(64):
1234 dst = "192.168.1.%d" % ii
1235 local_label = 1600 + ii
1236 vpn_routes.append(VppIpRoute(self, dst, 32,
1237 [VppRoutePath(self.pg2.remote_ip4,
1238 0xffffffff,
1239 nh_table_id=1,
1240 is_resolve_attached=1),
1241 VppRoutePath(self.pg3.remote_ip4,
1242 0xffffffff,
1243 nh_table_id=1,
1244 is_resolve_attached=1)],
1245 table_id=1))
1246 vpn_routes[ii].add_vpp_config()
1247
1248 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1249 ip_table_id=1))
1250 vpn_bindings[ii].add_vpp_config()
1251
1252 pkts.append(Ether(dst=self.pg0.local_mac,
1253 src=self.pg0.remote_mac) /
1254 MPLS(label=local_label, ttl=64) /
1255 IP(src=self.pg0.remote_ip4, dst=dst) /
1256 UDP(sport=1234, dport=1234) /
1257 Raw('\xa5' * 100))
1258
1259 self.pg0.add_stream(pkts)
1260 self.pg_enable_capture(self.pg_interfaces)
1261 self.pg_start()
1262
1263 rx0 = self.pg2._get_capture(1)
1264 rx1 = self.pg3._get_capture(1)
1265 self.assertNotEqual(0, len(rx0))
1266 self.assertNotEqual(0, len(rx1))
1267
1268 #
1269 # use a test CLI command to stop the FIB walk process, this
1270 # will prevent the FIB converging the VPN routes and thus allow
1271 # us to probe the interim (psot-fail, pre-converge) state
1272 #
1273 self.vapi.ppcli("test fib-walk-process disable")
1274
1275 #
1276 # withdraw the connected prefix on the interface.
1277 #
1278 self.pg2.unconfig_ip4()
1279
1280 #
1281 # now all packets should be forwarded through the remaining peer
1282 #
1283 self.pg0.add_stream(pkts)
1284 self.pg_enable_capture(self.pg_interfaces)
1285 self.pg_start()
1286
1287 rx0 = self.pg3.get_capture(len(pkts))
1288
1289 #
1290 # enable the FIB walk process to converge the FIB
1291 #
1292 self.vapi.ppcli("test fib-walk-process enable")
1293 self.pg0.add_stream(pkts)
1294 self.pg_enable_capture(self.pg_interfaces)
1295 self.pg_start()
1296
1297 rx0 = self.pg3.get_capture(len(pkts))
1298
1299 #
1300 # put the connecteds back
1301 #
1302 self.pg2.config_ip4()
1303
1304 self.pg0.add_stream(pkts)
1305 self.pg_enable_capture(self.pg_interfaces)
1306 self.pg_start()
1307
1308 rx0 = self.pg2._get_capture(1)
1309 rx1 = self.pg3._get_capture(1)
1310 self.assertNotEqual(0, len(rx0))
1311 self.assertNotEqual(0, len(rx1))
1312
1313 def test_mpls_v6_ebgp_pic(self):
1314 """ MPLSv6 eBGP PIC edge convergence
1315
1316 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1317 2) Check EMCP forwarding to these peers
1318 3) withdraw one eBGP path - expect LB across remaining eBGP
1319 """
1320
1321 #
1322 # Lot's of VPN routes. We need more the 64 so VPP will build
1323 # the fast convergence indirection
1324 #
1325 vpn_routes = []
1326 vpn_bindings = []
1327 pkts = []
1328 for ii in range(64):
1329 dst = "3000::%d" % ii
1330 local_label = 1600 + ii
1331 vpn_routes.append(VppIpRoute(self, dst, 128,
1332 [VppRoutePath(self.pg2.remote_ip6,
1333 0xffffffff,
1334 nh_table_id=1,
1335 is_resolve_attached=1,
1336 is_ip6=1),
1337 VppRoutePath(self.pg3.remote_ip6,
1338 0xffffffff,
1339 nh_table_id=1,
1340 is_ip6=1,
1341 is_resolve_attached=1)],
1342 table_id=1,
1343 is_ip6=1))
1344 vpn_routes[ii].add_vpp_config()
1345
1346 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1347 ip_table_id=1,
1348 is_ip6=1))
1349 vpn_bindings[ii].add_vpp_config()
1350
1351 pkts.append(Ether(dst=self.pg0.local_mac,
1352 src=self.pg0.remote_mac) /
1353 MPLS(label=local_label, ttl=64) /
1354 IPv6(src=self.pg0.remote_ip6, dst=dst) /
1355 UDP(sport=1234, dport=1234) /
1356 Raw('\xa5' * 100))
1357
1358 self.pg0.add_stream(pkts)
1359 self.pg_enable_capture(self.pg_interfaces)
1360 self.pg_start()
1361
1362 rx0 = self.pg2._get_capture(1)
1363 rx1 = self.pg3._get_capture(1)
1364 self.assertNotEqual(0, len(rx0))
1365 self.assertNotEqual(0, len(rx1))
1366
1367 #
1368 # use a test CLI command to stop the FIB walk process, this
1369 # will prevent the FIB converging the VPN routes and thus allow
1370 # us to probe the interim (psot-fail, pre-converge) state
1371 #
1372 self.vapi.ppcli("test fib-walk-process disable")
1373
1374 #
1375 # withdraw the connected prefix on the interface.
1376 # and shutdown the interface so the ND cache is flushed.
1377 #
1378 self.pg2.unconfig_ip6()
1379 self.pg2.admin_down()
1380
1381 #
1382 # now all packets should be forwarded through the remaining peer
1383 #
1384 self.pg0.add_stream(pkts)
1385 self.pg_enable_capture(self.pg_interfaces)
1386 self.pg_start()
1387
1388 rx0 = self.pg3.get_capture(len(pkts))
1389
1390 #
1391 # enable the FIB walk process to converge the FIB
1392 #
1393 self.vapi.ppcli("test fib-walk-process enable")
1394 self.pg0.add_stream(pkts)
1395 self.pg_enable_capture(self.pg_interfaces)
1396 self.pg_start()
1397
1398 rx0 = self.pg3.get_capture(len(pkts))
1399
1400 #
1401 # put the connecteds back
1402 #
1403 self.pg2.admin_up()
1404 self.pg2.config_ip6()
1405
1406 self.pg0.add_stream(pkts)
1407 self.pg_enable_capture(self.pg_interfaces)
1408 self.pg_start()
1409
1410 rx0 = self.pg2._get_capture(1)
1411 rx1 = self.pg3._get_capture(1)
1412 self.assertNotEqual(0, len(rx0))
1413 self.assertNotEqual(0, len(rx1))
1414
1415
Neale Ranns8fe8cc22016-11-01 10:05:08 +00001416if __name__ == '__main__':
1417 unittest.main(testRunner=VppTestRunner)