6 from framework import VppTestCase, VppTestRunner
7 from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
8 VppMplsTable, VppIpMRoute, VppMRoutePath, VppIpTable, \
9 MRouteEntryFlags, MRouteItfFlags, MPLS_LABEL_INVALID, DpoProto
10 from vpp_bier import *
12 from scapy.packet import Raw
13 from scapy.layers.l2 import Ether
14 from scapy.layers.inet import IP, UDP, ICMP
15 from scapy.layers.inet6 import IPv6
16 from scapy.contrib.mpls import MPLS
17 from scapy.contrib.bier import *
20 class TestBFIB(VppTestCase):
21 """ BIER FIB Test Case """
24 """ BFIB Unit Tests """
25 error = self.vapi.cli("test bier")
28 self.logger.critical(error)
29 self.assertEqual(error.find("Failed"), -1)
32 class TestBier(VppTestCase):
33 """ BIER Test Case """
36 super(TestBier, self).setUp()
38 # create 2 pg interfaces
39 self.create_pg_interfaces(range(3))
41 # create the default MPLS table
43 tbl = VppMplsTable(self, 0)
45 self.tables.append(tbl)
47 tbl = VppIpTable(self, 10)
49 self.tables.append(tbl)
51 # setup both interfaces
52 for i in self.pg_interfaces:
61 for i in self.pg_interfaces:
66 super(TestBier, self).tearDown()
68 def send_and_assert_no_replies(self, intf, pkts, remark):
70 self.pg_enable_capture(self.pg_interfaces)
72 for i in self.pg_interfaces:
73 i.assert_nothing_captured(remark=remark)
75 def send_and_expect(self, input, pkts, output):
76 self.vapi.cli("trace add bier-mpls-lookup 10")
77 input.add_stream(pkts)
78 self.pg_enable_capture(self.pg_interfaces)
80 rx = output.get_capture(len(pkts))
82 def test_bier_midpoint(self):
86 # Add a BIER table for sub-domain 0, set 0, and BSL 256
88 bti = VppBierTableID(0, 0, BIERLength.BIER_LEN_256)
89 bt = VppBierTable(self, bti, 77)
93 # A packet with no bits set gets dropped
95 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
96 MPLS(label=77, ttl=255) /
97 BIER(length=BIERLength.BIER_LEN_256,
98 BitString=chr(0)*64) /
99 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6) /
100 UDP(sport=1234, dport=1234) /
104 self.send_and_assert_no_replies(self.pg0, pkts,
108 # Add a BIER route for each bit-position in the table via a different
109 # next-hop. Testing whether the BIER walk and replicate forwarding
110 # function works for all bit posisitons.
114 for i in range(1, 256):
115 nh = "10.0.%d.%d" % (i / 255, i % 255)
116 nh_routes.append(VppIpRoute(self, nh, 32,
117 [VppRoutePath(self.pg1.remote_ip4,
118 self.pg1.sw_if_index,
120 nh_routes[-1].add_vpp_config()
122 bier_routes.append(VppBierRoute(self, bti, i, nh, 100+i))
123 bier_routes[-1].add_vpp_config()
126 # A packet with all bits set gets spat out to BP:1
128 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
129 MPLS(label=77, ttl=255) /
130 BIER(length=BIERLength.BIER_LEN_256) /
131 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6) /
132 UDP(sport=1234, dport=1234) /
136 self.pg0.add_stream(pkts)
137 self.pg_enable_capture(self.pg_interfaces)
140 rx = self.pg1.get_capture(255)
144 # The packets are not required to be sent in bit-position order
145 # when we setup the routes above we used the bit-position to
146 # construct the out-label. so use that here to determine the BP
149 bp = olabel.label - 2000
151 blabel = olabel[MPLS].payload
152 self.assertEqual(blabel.label, 100+bp)
154 bier_hdr = blabel[MPLS].payload
156 self.assertEqual(bier_hdr.id, 5)
157 self.assertEqual(bier_hdr.version, 0)
158 self.assertEqual(bier_hdr.length, BIERLength.BIER_LEN_256)
159 self.assertEqual(bier_hdr.entropy, 0)
160 self.assertEqual(bier_hdr.OAM, 0)
161 self.assertEqual(bier_hdr.RSV, 0)
162 self.assertEqual(bier_hdr.DSCP, 0)
163 self.assertEqual(bier_hdr.Proto, 5)
165 # The bit-string should consist only of the BP given by i.
170 bitstring = chr(0) + bitstring
172 bitstring = chr(1 << bpi % 8) + bitstring
174 while len(bitstring) < 32:
175 bitstring = chr(0) + bitstring
177 self.assertEqual(len(bitstring), len(bier_hdr.BitString))
178 self.assertEqual(bitstring, bier_hdr.BitString)
180 def test_bier_head(self):
184 # Add a BIER table for sub-domain 0, set 0, and BSL 256
186 bti = VppBierTableID(0, 0, BIERLength.BIER_LEN_256)
187 bt = VppBierTable(self, bti, 77)
191 # 2 bit positions via two next hops
195 ip_route_1 = VppIpRoute(self, nh1, 32,
196 [VppRoutePath(self.pg1.remote_ip4,
197 self.pg1.sw_if_index,
199 ip_route_2 = VppIpRoute(self, nh2, 32,
200 [VppRoutePath(self.pg1.remote_ip4,
201 self.pg1.sw_if_index,
203 ip_route_1.add_vpp_config()
204 ip_route_2.add_vpp_config()
206 bier_route_1 = VppBierRoute(self, bti, 1, nh1, 101)
207 bier_route_2 = VppBierRoute(self, bti, 2, nh2, 102)
208 bier_route_1.add_vpp_config()
209 bier_route_2.add_vpp_config()
212 # An imposition object with both bit-positions set
214 bi = VppBierImp(self, bti, 333, chr(0x3) * 32)
218 # Add a multicast route that will forward into the BIER doamin
220 route_ing_232_1_1_1 = VppIpMRoute(
224 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
225 paths=[VppMRoutePath(self.pg0.sw_if_index,
226 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
227 VppMRoutePath(0xffffffff,
228 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
229 proto=DpoProto.DPO_PROTO_BIER,
230 bier_imp=bi.bi_index)])
231 route_ing_232_1_1_1.add_vpp_config()
234 # inject a packet an IP. We expect it to be BIER encapped,
237 p = (Ether(dst=self.pg0.local_mac,
238 src=self.pg0.remote_mac) /
239 IP(src="1.1.1.1", dst="232.1.1.1") /
240 UDP(sport=1234, dport=1234))
242 self.pg0.add_stream([p])
243 self.pg_enable_capture(self.pg_interfaces)
246 rx = self.pg1.get_capture(2)
248 def test_bier_tail(self):
252 # Add a BIER table for sub-domain 0, set 0, and BSL 256
254 bti = VppBierTableID(0, 0, BIERLength.BIER_LEN_256)
255 bt = VppBierTable(self, bti, 77)
261 bdt = VppBierDispTable(self, 8)
265 # BIER route in table that's for-us
267 bier_route_1 = VppBierRoute(self, bti, 1, "0.0.0.0", 0,
269 bier_route_1.add_vpp_config()
272 # An entry in the disposition table
274 bier_de_1 = VppBierDispEntry(self, bdt.id, 99,
275 BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
276 "0.0.0.0", 0, rpf_id=8192)
277 bier_de_1.add_vpp_config()
280 # A multicast route to forward post BIER disposition
282 route_eg_232_1_1_1 = VppIpMRoute(
286 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
287 paths=[VppMRoutePath(self.pg1.sw_if_index,
288 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
289 route_eg_232_1_1_1.add_vpp_config()
290 route_eg_232_1_1_1.update_rpf_id(8192)
293 # A packet with all bits set gets spat out to BP:1
295 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
296 MPLS(label=77, ttl=255) /
297 BIER(length=BIERLength.BIER_LEN_256, BFRID=99) /
298 IP(src="1.1.1.1", dst="232.1.1.1") /
299 UDP(sport=1234, dport=1234) /
302 self.send_and_expect(self.pg0, [p], self.pg1)
304 def test_bier_e2e(self):
305 """ BIER end-to-end """
308 # Add a BIER table for sub-domain 0, set 0, and BSL 256
310 bti = VppBierTableID(0, 0, BIERLength.BIER_LEN_256)
311 bt = VppBierTable(self, bti, 77)
315 # Impostion Sets bit string 101010101....
318 bi = VppBierImp(self, bti, 333, chr(0x5) * 32)
322 # Add a multicast route that will forward into the BIER doamin
324 route_ing_232_1_1_1 = VppIpMRoute(
328 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
329 paths=[VppMRoutePath(self.pg0.sw_if_index,
330 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
331 VppMRoutePath(0xffffffff,
332 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
333 proto=DpoProto.DPO_PROTO_BIER,
334 bier_imp=bi.bi_index)])
335 route_ing_232_1_1_1.add_vpp_config()
338 # disposition table 8
340 bdt = VppBierDispTable(self, 8)
344 # BIER route in table that's for-us, resolving through
347 bier_route_1 = VppBierRoute(self, bti, 1, "0.0.0.0",
350 bier_route_1.add_vpp_config()
353 # An entry in the disposition table for sender 333
356 bier_de_1 = VppBierDispEntry(self, bdt.id, 333,
357 BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
358 "0.0.0.0", 10, rpf_id=8192)
359 bier_de_1.add_vpp_config()
362 # Add a multicast route that will forward the traffic
365 route_eg_232_1_1_1 = VppIpMRoute(
369 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
371 paths=[VppMRoutePath(self.pg1.sw_if_index,
372 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
373 route_eg_232_1_1_1.add_vpp_config()
374 route_eg_232_1_1_1.update_rpf_id(8192)
377 # inject a packet in VRF-0. We expect it to be BIER encapped,
378 # replicated, then hit the disposition and be forwarded
379 # out of VRF 10, i.e. on pg1
381 p = (Ether(dst=self.pg0.local_mac,
382 src=self.pg0.remote_mac) /
383 IP(src="1.1.1.1", dst="232.1.1.1") /
384 UDP(sport=1234, dport=1234))
386 self.send_and_expect(self.pg0, p*65, self.pg1)
389 if __name__ == '__main__':
390 unittest.main(testRunner=VppTestRunner)