BIER API and load-balancing fixes
[vpp.git] / test / test_bier.py
1 #!/usr/bin/env python
2
3 import unittest
4 import socket
5
6 from framework import VppTestCase, VppTestRunner, running_extended_tests
7 from vpp_ip import DpoProto
8 from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
9     VppMplsTable, VppIpMRoute, VppMRoutePath, VppIpTable, \
10     MRouteEntryFlags, MRouteItfFlags, MPLS_LABEL_INVALID, \
11     VppMplsLabel
12 from vpp_bier import *
13 from vpp_udp_encap import *
14
15 from scapy.packet import Raw
16 from scapy.layers.l2 import Ether
17 from scapy.layers.inet import IP, UDP, ICMP
18 from scapy.layers.inet6 import IPv6
19 from scapy.contrib.mpls import MPLS
20 from scapy.contrib.bier import *
21
22
23 class TestBFIB(VppTestCase):
24     """ BIER FIB Test Case """
25
26     def test_bfib(self):
27         """ BFIB Unit Tests """
28         error = self.vapi.cli("test bier")
29
30         if error:
31             self.logger.critical(error)
32         self.assertEqual(error.find("Failed"), -1)
33
34
35 class TestBier(VppTestCase):
36     """ BIER Test Case """
37
38     def setUp(self):
39         super(TestBier, self).setUp()
40
41         # create 2 pg interfaces
42         self.create_pg_interfaces(range(3))
43
44         # create the default MPLS table
45         self.tables = []
46         tbl = VppMplsTable(self, 0)
47         tbl.add_vpp_config()
48         self.tables.append(tbl)
49
50         tbl = VppIpTable(self, 10)
51         tbl.add_vpp_config()
52         self.tables.append(tbl)
53
54         # setup both interfaces
55         for i in self.pg_interfaces:
56             if i == self.pg2:
57                 i.set_table_ip4(10)
58             i.admin_up()
59             i.config_ip4()
60             i.resolve_arp()
61             i.enable_mpls()
62
63     def tearDown(self):
64         for i in self.pg_interfaces:
65             i.disable_mpls()
66             i.unconfig_ip4()
67             i.set_table_ip4(0)
68             i.admin_down()
69         super(TestBier, self).tearDown()
70
71     def bier_midpoint(self, hdr_len_id, n_bytes, max_bp):
72         """BIER midpoint"""
73
74         #
75         # Add a BIER table for sub-domain 0, set 0, and BSL 256
76         #
77         bti = VppBierTableID(0, 0, hdr_len_id)
78         bt = VppBierTable(self, bti, 77)
79         bt.add_vpp_config()
80
81         #
82         # A packet with no bits set gets dropped
83         #
84         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
85              MPLS(label=77, ttl=255) /
86              BIER(length=hdr_len_id) /
87              IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6) /
88              UDP(sport=1234, dport=1234) /
89              Raw())
90         pkts = [p]
91
92         self.send_and_assert_no_replies(self.pg0, pkts,
93                                         "Empty Bit-String")
94
95         #
96         # Add a BIER route for each bit-position in the table via a different
97         # next-hop. Testing whether the BIER walk and replicate forwarding
98         # function works for all bit posisitons.
99         #
100         nh_routes = []
101         bier_routes = []
102         for i in range(1, max_bp+1):
103             nh = "10.0.%d.%d" % (i / 255, i % 255)
104             nh_routes.append(
105                 VppIpRoute(self, nh, 32,
106                            [VppRoutePath(self.pg1.remote_ip4,
107                                          self.pg1.sw_if_index,
108                                          labels=[VppMplsLabel(2000+i)])]))
109             nh_routes[-1].add_vpp_config()
110
111             bier_routes.append(
112                 VppBierRoute(self, bti, i,
113                              [VppRoutePath(nh, 0xffffffff,
114                                            labels=[VppMplsLabel(100+i)])]))
115             bier_routes[-1].add_vpp_config()
116
117         #
118         # A packet with all bits set gets replicated once for each bit
119         #
120         pkt_sizes = [64, 1400]
121
122         for pkt_size in pkt_sizes:
123             p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
124                  MPLS(label=77, ttl=255) /
125                  BIER(length=hdr_len_id, BitString=chr(255)*n_bytes) /
126                  IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6) /
127                  UDP(sport=1234, dport=1234) /
128                  Raw(chr(5) * pkt_size))
129             pkts = p
130
131             self.pg0.add_stream(pkts)
132             self.pg_enable_capture(self.pg_interfaces)
133             self.pg_start()
134
135             rx = self.pg1.get_capture(max_bp)
136
137             for rxp in rx:
138                 #
139                 # The packets are not required to be sent in bit-position order
140                 # when we setup the routes above we used the bit-position to
141                 # construct the out-label. so use that here to determine the BP
142                 #
143                 olabel = rxp[MPLS]
144                 bp = olabel.label - 2000
145
146                 blabel = olabel[MPLS].payload
147                 self.assertEqual(blabel.label, 100+bp)
148                 self.assertEqual(blabel.ttl, 254)
149
150                 bier_hdr = blabel[MPLS].payload
151
152                 self.assertEqual(bier_hdr.id, 5)
153                 self.assertEqual(bier_hdr.version, 0)
154                 self.assertEqual(bier_hdr.length, hdr_len_id)
155                 self.assertEqual(bier_hdr.entropy, 0)
156                 self.assertEqual(bier_hdr.OAM, 0)
157                 self.assertEqual(bier_hdr.RSV, 0)
158                 self.assertEqual(bier_hdr.DSCP, 0)
159                 self.assertEqual(bier_hdr.Proto, 5)
160
161                 # The bit-string should consist only of the BP given by i.
162                 byte_array = ['\0'] * (n_bytes)
163                 byte_val = chr(1 << (bp - 1) % 8)
164                 byte_pos = n_bytes - (((bp - 1) / 8) + 1)
165                 byte_array[byte_pos] = byte_val
166                 bitstring = ''.join(byte_array)
167
168                 self.assertEqual(len(bitstring), len(bier_hdr.BitString))
169                 self.assertEqual(bitstring, bier_hdr.BitString)
170
171         #
172         # cleanup. not strictly necessary, but it's much quicker this way
173         # becuase the bier_fib_dump and ip_fib_dump will be empty when the
174         # auto-cleanup kicks in
175         #
176         for br in bier_routes:
177             br.remove_vpp_config()
178         for nhr in nh_routes:
179             nhr.remove_vpp_config()
180
181     @unittest.skipUnless(running_extended_tests(), "part of extended tests")
182     def test_bier_midpoint_1024(self):
183         """BIER midpoint BSL:1024"""
184         self.bier_midpoint(BIERLength.BIER_LEN_1024, 128, 1024)
185
186     @unittest.skipUnless(running_extended_tests(), "part of extended tests")
187     def test_bier_midpoint_512(self):
188         """BIER midpoint BSL:512"""
189         self.bier_midpoint(BIERLength.BIER_LEN_512, 64, 512)
190
191     @unittest.skipUnless(running_extended_tests(), "part of extended tests")
192     def test_bier_midpoint_256(self):
193         """BIER midpoint BSL:256"""
194         self.bier_midpoint(BIERLength.BIER_LEN_256, 32, 256)
195
196     @unittest.skipUnless(running_extended_tests(), "part of extended tests")
197     def test_bier_midpoint_128(self):
198         """BIER midpoint BSL:128"""
199         self.bier_midpoint(BIERLength.BIER_LEN_128, 16, 128)
200
201     def test_bier_midpoint_64(self):
202         """BIER midpoint BSL:64"""
203         self.bier_midpoint(BIERLength.BIER_LEN_64, 8, 64)
204
205     def test_bier_load_balance(self):
206         """BIER load-balance"""
207
208         #
209         # Add a BIER table for sub-domain 0, set 0, and BSL 256
210         #
211         bti = VppBierTableID(0, 0, BIERLength.BIER_LEN_64)
212         bt = VppBierTable(self, bti, 77)
213         bt.add_vpp_config()
214
215         #
216         # packets with varying entropy
217         #
218         pkts = []
219         for ii in range(257):
220             pkts.append((Ether(dst=self.pg0.local_mac,
221                                src=self.pg0.remote_mac) /
222                          MPLS(label=77, ttl=255) /
223                          BIER(length=BIERLength.BIER_LEN_64,
224                               entropy=ii,
225                               BitString=chr(255)*16) /
226                          IPv6(src=self.pg0.remote_ip6,
227                               dst=self.pg0.remote_ip6) /
228                          UDP(sport=1234, dport=1234) /
229                          Raw()))
230
231         #
232         # 4 next hops
233         #
234         nhs = [{'ip': "10.0.0.1", 'label': 201},
235                {'ip': "10.0.0.2", 'label': 202},
236                {'ip': "10.0.0.3", 'label': 203},
237                {'ip': "10.0.0.4", 'label': 204}]
238
239         for nh in nhs:
240             ipr = VppIpRoute(
241                 self, nh['ip'], 32,
242                 [VppRoutePath(self.pg1.remote_ip4,
243                               self.pg1.sw_if_index,
244                               labels=[VppMplsLabel(nh['label'])])])
245             ipr.add_vpp_config()
246
247         bier_route = VppBierRoute(
248             self, bti, 1,
249             [VppRoutePath(nhs[0]['ip'], 0xffffffff,
250                           labels=[VppMplsLabel(101)]),
251              VppRoutePath(nhs[1]['ip'], 0xffffffff,
252                           labels=[VppMplsLabel(101)])])
253         bier_route.add_vpp_config()
254
255         rx = self.send_and_expect(self.pg0, pkts, self.pg1)
256
257         #
258         # we should have recieved a packet from each neighbor
259         #
260         for nh in nhs[:2]:
261             self.assertTrue(sum(p[MPLS].label == nh['label'] for p in rx))
262
263         #
264         # add the other paths
265         #
266         bier_route.update_paths(
267             [VppRoutePath(nhs[0]['ip'], 0xffffffff,
268                           labels=[VppMplsLabel(101)]),
269              VppRoutePath(nhs[1]['ip'], 0xffffffff,
270                           labels=[VppMplsLabel(101)]),
271              VppRoutePath(nhs[2]['ip'], 0xffffffff,
272                           labels=[VppMplsLabel(101)]),
273              VppRoutePath(nhs[3]['ip'], 0xffffffff,
274                           labels=[VppMplsLabel(101)])])
275
276         rx = self.send_and_expect(self.pg0, pkts, self.pg1)
277         for nh in nhs:
278             self.assertTrue(sum(p[MPLS].label == nh['label'] for p in rx))
279
280         #
281         # remove first two paths
282         #
283         bier_route.remove_path(VppRoutePath(nhs[0]['ip'], 0xffffffff,
284                                             labels=[VppMplsLabel(101)]))
285         bier_route.remove_path(VppRoutePath(nhs[1]['ip'], 0xffffffff,
286                                             labels=[VppMplsLabel(101)]))
287
288         rx = self.send_and_expect(self.pg0, pkts, self.pg1)
289         for nh in nhs[2:]:
290             self.assertTrue(sum(p[MPLS].label == nh['label'] for p in rx))
291
292         #
293         # remove the last of the paths, deleteing the entry
294         #
295         bier_route.remove_all_paths()
296
297         self.send_and_assert_no_replies(self.pg0, pkts)
298
299     def test_bier_head(self):
300         """BIER head"""
301
302         #
303         # Add a BIER table for sub-domain 0, set 0, and BSL 256
304         #
305         bti = VppBierTableID(0, 0, BIERLength.BIER_LEN_256)
306         bt = VppBierTable(self, bti, 77)
307         bt.add_vpp_config()
308
309         #
310         # 2 bit positions via two next hops
311         #
312         nh1 = "10.0.0.1"
313         nh2 = "10.0.0.2"
314         ip_route_1 = VppIpRoute(self, nh1, 32,
315                                 [VppRoutePath(self.pg1.remote_ip4,
316                                               self.pg1.sw_if_index,
317                                               labels=[VppMplsLabel(2001)])])
318         ip_route_2 = VppIpRoute(self, nh2, 32,
319                                 [VppRoutePath(self.pg1.remote_ip4,
320                                               self.pg1.sw_if_index,
321                                               labels=[VppMplsLabel(2002)])])
322         ip_route_1.add_vpp_config()
323         ip_route_2.add_vpp_config()
324
325         bier_route_1 = VppBierRoute(self, bti, 1,
326                                     [VppRoutePath(nh1, 0xffffffff,
327                                                   labels=[VppMplsLabel(101)])])
328         bier_route_2 = VppBierRoute(self, bti, 2,
329                                     [VppRoutePath(nh2, 0xffffffff,
330                                                   labels=[VppMplsLabel(102)])])
331         bier_route_1.add_vpp_config()
332         bier_route_2.add_vpp_config()
333
334         #
335         # An imposition object with both bit-positions set
336         #
337         bi = VppBierImp(self, bti, 333, chr(0x3) * 32)
338         bi.add_vpp_config()
339
340         #
341         # Add a multicast route that will forward into the BIER doamin
342         #
343         route_ing_232_1_1_1 = VppIpMRoute(
344             self,
345             "0.0.0.0",
346             "232.1.1.1", 32,
347             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
348             paths=[VppMRoutePath(self.pg0.sw_if_index,
349                                  MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
350                    VppMRoutePath(0xffffffff,
351                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
352                                  proto=DpoProto.DPO_PROTO_BIER,
353                                  bier_imp=bi.bi_index)])
354         route_ing_232_1_1_1.add_vpp_config()
355
356         #
357         # inject an IP packet. We expect it to be BIER encapped and
358         # replicated.
359         #
360         p = (Ether(dst=self.pg0.local_mac,
361                    src=self.pg0.remote_mac) /
362              IP(src="1.1.1.1", dst="232.1.1.1") /
363              UDP(sport=1234, dport=1234))
364
365         self.pg0.add_stream([p])
366         self.pg_enable_capture(self.pg_interfaces)
367         self.pg_start()
368
369         rx = self.pg1.get_capture(2)
370
371         #
372         # Encap Stack is; eth, MPLS, MPLS, BIER
373         #
374         igp_mpls = rx[0][MPLS]
375         self.assertEqual(igp_mpls.label, 2001)
376         self.assertEqual(igp_mpls.ttl, 64)
377         self.assertEqual(igp_mpls.s, 0)
378         bier_mpls = igp_mpls[MPLS].payload
379         self.assertEqual(bier_mpls.label, 101)
380         self.assertEqual(bier_mpls.ttl, 64)
381         self.assertEqual(bier_mpls.s, 1)
382         self.assertEqual(rx[0][BIER].length, 2)
383
384         igp_mpls = rx[1][MPLS]
385         self.assertEqual(igp_mpls.label, 2002)
386         self.assertEqual(igp_mpls.ttl, 64)
387         self.assertEqual(igp_mpls.s, 0)
388         bier_mpls = igp_mpls[MPLS].payload
389         self.assertEqual(bier_mpls.label, 102)
390         self.assertEqual(bier_mpls.ttl, 64)
391         self.assertEqual(bier_mpls.s, 1)
392         self.assertEqual(rx[0][BIER].length, 2)
393
394     def test_bier_tail(self):
395         """BIER Tail"""
396
397         #
398         # Add a BIER table for sub-domain 0, set 0, and BSL 256
399         #
400         bti = VppBierTableID(0, 0, BIERLength.BIER_LEN_256)
401         bt = VppBierTable(self, bti, 77)
402         bt.add_vpp_config()
403
404         #
405         # disposition table
406         #
407         bdt = VppBierDispTable(self, 8)
408         bdt.add_vpp_config()
409
410         #
411         # BIER route in table that's for-us
412         #
413         bier_route_1 = VppBierRoute(
414             self, bti, 1,
415             [VppRoutePath("0.0.0.0",
416                           0xffffffff,
417                           proto=DpoProto.DPO_PROTO_BIER,
418                           nh_table_id=8)])
419         bier_route_1.add_vpp_config()
420
421         #
422         # An entry in the disposition table
423         #
424         bier_de_1 = VppBierDispEntry(self, bdt.id, 99,
425                                      BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
426                                      DpoProto.DPO_PROTO_BIER,
427                                      "0.0.0.0", 0, rpf_id=8192)
428         bier_de_1.add_vpp_config()
429
430         #
431         # A multicast route to forward post BIER disposition
432         #
433         route_eg_232_1_1_1 = VppIpMRoute(
434             self,
435             "0.0.0.0",
436             "232.1.1.1", 32,
437             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
438             paths=[VppMRoutePath(self.pg1.sw_if_index,
439                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
440         route_eg_232_1_1_1.add_vpp_config()
441         route_eg_232_1_1_1.update_rpf_id(8192)
442
443         #
444         # A packet with all bits set gets spat out to BP:1
445         #
446         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
447              MPLS(label=77, ttl=255) /
448              BIER(length=BIERLength.BIER_LEN_256,
449                   BitString=chr(255)*32,
450                   BFRID=99) /
451              IP(src="1.1.1.1", dst="232.1.1.1") /
452              UDP(sport=1234, dport=1234) /
453              Raw())
454
455         self.send_and_expect(self.pg0, [p], self.pg1)
456
457         #
458         # A packet that does not match the Disposition entry gets dropped
459         #
460         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
461              MPLS(label=77, ttl=255) /
462              BIER(length=BIERLength.BIER_LEN_256,
463                   BitString=chr(255)*32,
464                   BFRID=77) /
465              IP(src="1.1.1.1", dst="232.1.1.1") /
466              UDP(sport=1234, dport=1234) /
467              Raw())
468         self.send_and_assert_no_replies(self.pg0, p*2,
469                                         "no matching disposition entry")
470
471         #
472         # Add the default route to the disposition table
473         #
474         bier_de_2 = VppBierDispEntry(self, bdt.id, 0,
475                                      BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
476                                      DpoProto.DPO_PROTO_BIER,
477                                      "0.0.0.0", 0, rpf_id=8192)
478         bier_de_2.add_vpp_config()
479
480         #
481         # now the previous packet is forwarded
482         #
483         self.send_and_expect(self.pg0, [p], self.pg1)
484
485     def bier_e2e(self, hdr_len_id, n_bytes, max_bp):
486         """ BIER end-to-end"""
487
488         #
489         # Add a BIER table for sub-domain 0, set 0, and BSL 256
490         #
491         bti = VppBierTableID(0, 0, hdr_len_id)
492         bt = VppBierTable(self, bti, 77)
493         bt.add_vpp_config()
494
495         lowest = ['\0'] * (n_bytes)
496         lowest[-1] = chr(1)
497         highest = ['\0'] * (n_bytes)
498         highest[0] = chr(128)
499
500         #
501         # Impostion Sets bit strings
502         #
503         bi_low = VppBierImp(self, bti, 333, lowest)
504         bi_low.add_vpp_config()
505         bi_high = VppBierImp(self, bti, 334, highest)
506         bi_high.add_vpp_config()
507
508         #
509         # Add a multicast route that will forward into the BIER doamin
510         #
511         route_ing_232_1_1_1 = VppIpMRoute(
512             self,
513             "0.0.0.0",
514             "232.1.1.1", 32,
515             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
516             paths=[VppMRoutePath(self.pg0.sw_if_index,
517                                  MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
518                    VppMRoutePath(0xffffffff,
519                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
520                                  proto=DpoProto.DPO_PROTO_BIER,
521                                  bier_imp=bi_low.bi_index)])
522         route_ing_232_1_1_1.add_vpp_config()
523         route_ing_232_1_1_2 = VppIpMRoute(
524             self,
525             "0.0.0.0",
526             "232.1.1.2", 32,
527             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
528             paths=[VppMRoutePath(self.pg0.sw_if_index,
529                                  MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
530                    VppMRoutePath(0xffffffff,
531                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
532                                  proto=DpoProto.DPO_PROTO_BIER,
533                                  bier_imp=bi_high.bi_index)])
534         route_ing_232_1_1_2.add_vpp_config()
535
536         #
537         # disposition table 8
538         #
539         bdt = VppBierDispTable(self, 8)
540         bdt.add_vpp_config()
541
542         #
543         # BIER routes in table that are for-us, resolving through
544         # disp table 8.
545         #
546         bier_route_1 = VppBierRoute(
547             self, bti, 1,
548             [VppRoutePath("0.0.0.0",
549                           0xffffffff,
550                           proto=DpoProto.DPO_PROTO_BIER,
551                           nh_table_id=8)])
552         bier_route_1.add_vpp_config()
553         bier_route_max = VppBierRoute(self, bti, max_bp,
554                                       [VppRoutePath("0.0.0.0",
555                                                     0xffffffff,
556                                                     nh_table_id=8)])
557         bier_route_max.add_vpp_config()
558
559         #
560         # An entry in the disposition table for sender 333
561         #  lookup in VRF 10
562         #
563         bier_de_1 = VppBierDispEntry(self, bdt.id, 333,
564                                      BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
565                                      DpoProto.DPO_PROTO_BIER,
566                                      "0.0.0.0", 10, rpf_id=8192)
567         bier_de_1.add_vpp_config()
568         bier_de_1 = VppBierDispEntry(self, bdt.id, 334,
569                                      BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
570                                      DpoProto.DPO_PROTO_BIER,
571                                      "0.0.0.0", 10, rpf_id=8193)
572         bier_de_1.add_vpp_config()
573
574         #
575         # Add a multicast routes that will forward the traffic
576         # post-disposition
577         #
578         route_eg_232_1_1_1 = VppIpMRoute(
579             self,
580             "0.0.0.0",
581             "232.1.1.1", 32,
582             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
583             table_id=10,
584             paths=[VppMRoutePath(self.pg1.sw_if_index,
585                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
586         route_eg_232_1_1_1.add_vpp_config()
587         route_eg_232_1_1_1.update_rpf_id(8192)
588         route_eg_232_1_1_2 = VppIpMRoute(
589             self,
590             "0.0.0.0",
591             "232.1.1.2", 32,
592             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
593             table_id=10,
594             paths=[VppMRoutePath(self.pg1.sw_if_index,
595                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
596         route_eg_232_1_1_2.add_vpp_config()
597         route_eg_232_1_1_2.update_rpf_id(8193)
598
599         #
600         # inject a packet in VRF-0. We expect it to be BIER encapped,
601         # replicated, then hit the disposition and be forwarded
602         # out of VRF 10, i.e. on pg1
603         #
604         p = (Ether(dst=self.pg0.local_mac,
605                    src=self.pg0.remote_mac) /
606              IP(src="1.1.1.1", dst="232.1.1.1") /
607              UDP(sport=1234, dport=1234) /
608              Raw(chr(5) * 32))
609
610         rx = self.send_and_expect(self.pg0, p*65, self.pg1)
611
612         self.assertEqual(rx[0][IP].src, "1.1.1.1")
613         self.assertEqual(rx[0][IP].dst, "232.1.1.1")
614
615         p = (Ether(dst=self.pg0.local_mac,
616                    src=self.pg0.remote_mac) /
617              IP(src="1.1.1.1", dst="232.1.1.2") /
618              UDP(sport=1234, dport=1234) /
619              Raw(chr(5) * 512))
620
621         rx = self.send_and_expect(self.pg0, p*65, self.pg1)
622         self.assertEqual(rx[0][IP].src, "1.1.1.1")
623         self.assertEqual(rx[0][IP].dst, "232.1.1.2")
624
625     @unittest.skipUnless(running_extended_tests(), "part of extended tests")
626     def test_bier_e2e_1024(self):
627         """ BIER end-to-end BSL:1024"""
628         self.bier_e2e(BIERLength.BIER_LEN_1024, 128, 1024)
629
630     @unittest.skipUnless(running_extended_tests(), "part of extended tests")
631     def test_bier_e2e_512(self):
632         """ BIER end-to-end BSL:512"""
633         self.bier_e2e(BIERLength.BIER_LEN_512, 64, 512)
634
635     @unittest.skipUnless(running_extended_tests(), "part of extended tests")
636     def test_bier_e2e_256(self):
637         """ BIER end-to-end BSL:256"""
638         self.bier_e2e(BIERLength.BIER_LEN_256, 32, 256)
639
640     @unittest.skipUnless(running_extended_tests(), "part of extended tests")
641     def test_bier_e2e_128(self):
642         """ BIER end-to-end BSL:128"""
643         self.bier_e2e(BIERLength.BIER_LEN_128, 16, 128)
644
645     def test_bier_e2e_64(self):
646         """ BIER end-to-end BSL:64"""
647         self.bier_e2e(BIERLength.BIER_LEN_64, 8, 64)
648
649     def test_bier_head_o_udp(self):
650         """BIER head over UDP"""
651
652         #
653         # Add a BIER table for sub-domain 1, set 0, and BSL 256
654         #
655         bti = VppBierTableID(1, 0, BIERLength.BIER_LEN_256)
656         bt = VppBierTable(self, bti, 77)
657         bt.add_vpp_config()
658
659         #
660         # 1 bit positions via 1 next hops
661         #
662         nh1 = "10.0.0.1"
663         ip_route = VppIpRoute(self, nh1, 32,
664                               [VppRoutePath(self.pg1.remote_ip4,
665                                             self.pg1.sw_if_index,
666                                             labels=[VppMplsLabel(2001)])])
667         ip_route.add_vpp_config()
668
669         udp_encap = VppUdpEncap(self, 4,
670                                 self.pg0.local_ip4,
671                                 nh1,
672                                 330, 8138)
673         udp_encap.add_vpp_config()
674
675         bier_route = VppBierRoute(
676             self, bti, 1,
677             [VppRoutePath("0.0.0.0",
678                           0xFFFFFFFF,
679                           is_udp_encap=1,
680                           next_hop_id=4)])
681         bier_route.add_vpp_config()
682
683         #
684         # An 2 imposition objects with all bit-positions set
685         # only use the second, but creating 2 tests with a non-zero
686         # value index in the route add
687         #
688         bi = VppBierImp(self, bti, 333, chr(0xff) * 32)
689         bi.add_vpp_config()
690         bi2 = VppBierImp(self, bti, 334, chr(0xff) * 32)
691         bi2.add_vpp_config()
692
693         #
694         # Add a multicast route that will forward into the BIER doamin
695         #
696         route_ing_232_1_1_1 = VppIpMRoute(
697             self,
698             "0.0.0.0",
699             "232.1.1.1", 32,
700             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
701             paths=[VppMRoutePath(self.pg0.sw_if_index,
702                                  MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
703                    VppMRoutePath(0xffffffff,
704                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
705                                  proto=DpoProto.DPO_PROTO_BIER,
706                                  bier_imp=bi2.bi_index)])
707         route_ing_232_1_1_1.add_vpp_config()
708
709         #
710         # inject a packet an IP. We expect it to be BIER and UDP encapped,
711         #
712         p = (Ether(dst=self.pg0.local_mac,
713                    src=self.pg0.remote_mac) /
714              IP(src="1.1.1.1", dst="232.1.1.1") /
715              UDP(sport=1234, dport=1234))
716
717         self.pg0.add_stream([p])
718         self.pg_enable_capture(self.pg_interfaces)
719         self.pg_start()
720
721         rx = self.pg1.get_capture(1)
722
723         #
724         # Encap Stack is, eth, IP, UDP, BIFT, BIER
725         #
726         self.assertEqual(rx[0][IP].src, self.pg0.local_ip4)
727         self.assertEqual(rx[0][IP].dst, nh1)
728         self.assertEqual(rx[0][UDP].sport, 330)
729         self.assertEqual(rx[0][UDP].dport, 8138)
730         self.assertEqual(rx[0][BIFT].bsl, 2)
731         self.assertEqual(rx[0][BIFT].sd, 1)
732         self.assertEqual(rx[0][BIFT].set, 0)
733         self.assertEqual(rx[0][BIFT].ttl, 64)
734         self.assertEqual(rx[0][BIER].length, 2)
735
736     def test_bier_tail_o_udp(self):
737         """BIER Tail over UDP"""
738
739         #
740         # Add a BIER table for sub-domain 0, set 0, and BSL 256
741         #
742         bti = VppBierTableID(1, 0, BIERLength.BIER_LEN_256)
743         bt = VppBierTable(self, bti, MPLS_LABEL_INVALID)
744         bt.add_vpp_config()
745
746         #
747         # disposition table
748         #
749         bdt = VppBierDispTable(self, 8)
750         bdt.add_vpp_config()
751
752         #
753         # BIER route in table that's for-us
754         #
755         bier_route_1 = VppBierRoute(
756             self, bti, 1,
757             [VppRoutePath("0.0.0.0",
758                           0xffffffff,
759                           proto=DpoProto.DPO_PROTO_BIER,
760                           nh_table_id=8)])
761         bier_route_1.add_vpp_config()
762
763         #
764         # An entry in the disposition table
765         #
766         bier_de_1 = VppBierDispEntry(self, bdt.id, 99,
767                                      BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
768                                      DpoProto.DPO_PROTO_BIER,
769                                      "0.0.0.0", 0, rpf_id=8192)
770         bier_de_1.add_vpp_config()
771
772         #
773         # A multicast route to forward post BIER disposition
774         #
775         route_eg_232_1_1_1 = VppIpMRoute(
776             self,
777             "0.0.0.0",
778             "232.1.1.1", 32,
779             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
780             paths=[VppMRoutePath(self.pg1.sw_if_index,
781                                  MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
782         route_eg_232_1_1_1.add_vpp_config()
783         route_eg_232_1_1_1.update_rpf_id(8192)
784
785         #
786         # A packet with all bits set gets spat out to BP:1
787         #
788         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
789              IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
790              UDP(sport=333, dport=8138) /
791              BIFT(sd=1, set=0, bsl=2, ttl=255) /
792              BIER(length=BIERLength.BIER_LEN_256,
793                   BitString=chr(255)*32,
794                   BFRID=99) /
795              IP(src="1.1.1.1", dst="232.1.1.1") /
796              UDP(sport=1234, dport=1234) /
797              Raw())
798
799         rx = self.send_and_expect(self.pg0, [p], self.pg1)
800
801
802 if __name__ == '__main__':
803     unittest.main(testRunner=VppTestRunner)