3 from scapy.layers.inet import IP, UDP
4 from scapy.layers.inet6 import IPv6
5 from scapy.layers.l2 import Ether, GRE
6 from scapy.packet import Raw
7 from scapy.data import IP_PROTOS
9 from framework import VppTestCase
12 """ TestLB is a subclass of VPPTestCase classes.
14 TestLB class defines Load Balancer test cases for:
15 - IP4 to GRE4 encap on per-port vip case
16 - IP4 to GRE6 encap on per-port vip case
17 - IP6 to GRE4 encap on per-port vip case
18 - IP6 to GRE6 encap on per-port vip case
19 - IP4 to L3DSR encap on vip case
20 - IP4 to L3DSR encap on per-port vip case
21 - IP4 to NAT4 encap on per-port vip case
22 - IP6 to NAT6 encap on per-port vip case
24 As stated in comments below, GRE has issues with IPv6.
25 All test cases involving IPv6 are executed, but
26 received packets are not parsed and checked.
31 class TestLB(VppTestCase):
32 """ Load Balancer Test Case """
36 super(TestLB, cls).setUpClass()
39 cls.packets = range(1)
42 cls.create_pg_interfaces(range(2))
43 cls.interfaces = list(cls.pg_interfaces)
45 for i in cls.interfaces:
52 dst4 = socket.inet_pton(socket.AF_INET, "10.0.0.0")
53 dst6 = socket.inet_pton(socket.AF_INET6, "2002::")
54 cls.vapi.ip_add_del_route(dst4, 24, cls.pg1.remote_ip4n)
55 cls.vapi.ip_add_del_route(dst6, 16, cls.pg1.remote_ip6n, is_ipv6=1)
56 cls.vapi.cli("lb conf ip4-src-address 39.40.41.42")
57 cls.vapi.cli("lb conf ip6-src-address 2004::1")
59 super(TestLB, cls).tearDownClass()
63 super(TestLB, self).tearDown()
65 self.logger.info(self.vapi.cli("show lb vip verbose"))
67 def getIPv4Flow(self, id):
68 return (IP(dst="90.0.%u.%u" % (id / 255, id % 255),
69 src="40.0.%u.%u" % (id / 255, id % 255)) /
70 UDP(sport=10000 + id, dport=20000))
72 def getIPv6Flow(self, id):
73 return (IPv6(dst="2001::%u" % (id), src="fd00:f00d:ffff::%u" % (id)) /
74 UDP(sport=10000 + id, dport=20000))
76 def generatePackets(self, src_if, isv4):
77 self.reset_packet_infos()
79 for pktid in self.packets:
80 info = self.create_packet_info(src_if, self.pg1)
81 payload = self.info_to_payload(info)
82 ip = self.getIPv4Flow(pktid) if isv4 else self.getIPv6Flow(pktid)
83 packet = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
86 self.extend_packet(packet, 128)
87 info.data = packet.copy()
91 def checkInner(self, gre, isv4):
92 IPver = IP if isv4 else IPv6
93 self.assertEqual(gre.proto, 0x0800 if isv4 else 0x86DD)
94 self.assertEqual(gre.flags, 0)
95 self.assertEqual(gre.version, 0)
96 inner = IPver(str(gre.payload))
97 payload_info = self.payload_to_info(str(inner[Raw]))
98 self.info = self.packet_infos[payload_info.index]
99 self.assertEqual(payload_info.src, self.pg0.sw_if_index)
100 self.assertEqual(str(inner), str(self.info.data[IPver]))
102 def checkCapture(self, encap, isv4):
103 self.pg0.assert_nothing_captured()
104 out = self.pg1.get_capture(len(self.packets))
106 load = [0] * len(self.ass)
112 if (encap == 'gre4'):
114 asid = int(ip.dst.split(".")[3])
115 self.assertEqual(ip.version, 4)
116 self.assertEqual(ip.flags, 0)
117 self.assertEqual(ip.src, "39.40.41.42")
118 self.assertEqual(ip.dst, "10.0.0.%u" % asid)
119 self.assertEqual(ip.proto, 47)
120 self.assertEqual(len(ip.options), 0)
122 self.checkInner(gre, isv4)
123 elif (encap == 'gre6'):
125 asid = ip.dst.split(":")
126 asid = asid[len(asid) - 1]
127 asid = 0 if asid == "" else int(asid)
128 self.assertEqual(ip.version, 6)
129 self.assertEqual(ip.tc, 0)
130 self.assertEqual(ip.fl, 0)
131 self.assertEqual(ip.src, "2004::1")
133 socket.inet_pton(socket.AF_INET6, ip.dst),
134 socket.inet_pton(socket.AF_INET6, "2002::%u" % asid)
136 self.assertEqual(ip.nh, 47)
137 # self.assertEqual(len(ip.options), 0)
138 gre = GRE(str(p[IPv6].payload))
139 self.checkInner(gre, isv4)
140 elif (encap == 'l3dsr'):
142 asid = int(ip.dst.split(".")[3])
143 self.assertEqual(ip.version, 4)
144 self.assertEqual(ip.flags, 0)
145 self.assertEqual(ip.dst, "10.0.0.%u" % asid)
146 self.assertEqual(ip.tos, 0x1c)
147 self.assertEqual(len(ip.options), 0)
148 self.assert_ip_checksum_valid(p)
149 if ip.proto == IP_PROTOS.tcp:
150 self.assert_tcp_checksum_valid(p)
151 elif ip.proto == IP_PROTOS.udp:
152 self.assert_udp_checksum_valid(p)
153 elif (encap == 'nat4'):
155 asid = int(ip.dst.split(".")[3])
156 self.assertEqual(ip.version, 4)
157 self.assertEqual(ip.flags, 0)
158 self.assertEqual(ip.dst, "10.0.0.%u" % asid)
159 self.assertEqual(ip.proto, 17)
160 self.assertEqual(len(ip.options), 0)
162 self.assertEqual(udp.dport, 3307)
163 elif (encap == 'nat6'):
165 asid = ip.dst.split(":")
166 asid = asid[len(asid) - 1]
167 asid = 0 if asid == "" else int(asid)
168 self.assertEqual(ip.version, 6)
169 self.assertEqual(ip.tc, 0)
170 self.assertEqual(ip.fl, 0)
172 socket.inet_pton(socket.AF_INET6, ip.dst),
173 socket.inet_pton(socket.AF_INET6, "2002::%u" % asid)
175 self.assertEqual(ip.nh, 17)
176 self.assertGreaterEqual(ip.hlim, 63)
177 udp = UDP(str(p[IPv6].payload))
178 self.assertEqual(udp.dport, 3307)
181 self.logger.error(ppp("Unexpected or invalid packet:", p))
184 # This is just to 1roughly check that the balancing algorithm
185 # is not completly biased.
186 for asid in self.ass:
187 if load[asid] < len(self.packets) / (len(self.ass) * 2):
189 "ASS is not balanced: load[%d] = %d" % (asid, load[asid]))
190 raise Exception("Load Balancer algorithm is biased")
192 def test_lb_ip4_gre4(self):
193 """ Load Balancer IP4 GRE4 on vip case """
196 "lb vip 90.0.0.0/8 encap gre4")
197 for asid in self.ass:
199 "lb as 90.0.0.0/8 10.0.0.%u"
202 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
203 self.pg_enable_capture(self.pg_interfaces)
205 self.checkCapture(encap='gre4', isv4=True)
208 for asid in self.ass:
210 "lb as 90.0.0.0/8 10.0.0.%u del"
213 "lb vip 90.0.0.0/8 encap gre4 del")
214 self.vapi.cli("test lb flowtable flush")
216 def test_lb_ip6_gre4(self):
217 """ Load Balancer IP6 GRE4 on vip case """
221 "lb vip 2001::/16 encap gre4")
222 for asid in self.ass:
224 "lb as 2001::/16 10.0.0.%u"
227 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
228 self.pg_enable_capture(self.pg_interfaces)
231 self.checkCapture(encap='gre4', isv4=False)
233 for asid in self.ass:
235 "lb as 2001::/16 10.0.0.%u del"
238 "lb vip 2001::/16 encap gre4 del")
239 self.vapi.cli("test lb flowtable flush")
241 def test_lb_ip4_gre6(self):
242 """ Load Balancer IP4 GRE6 on vip case """
245 "lb vip 90.0.0.0/8 encap gre6")
246 for asid in self.ass:
248 "lb as 90.0.0.0/8 2002::%u"
251 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
252 self.pg_enable_capture(self.pg_interfaces)
255 self.checkCapture(encap='gre6', isv4=True)
257 for asid in self.ass:
259 "lb as 90.0.0.0/8 2002::%u del"
262 "lb vip 90.0.0.0/8 encap gre6 del")
263 self.vapi.cli("test lb flowtable flush")
265 def test_lb_ip6_gre6(self):
266 """ Load Balancer IP6 GRE6 on vip case """
269 "lb vip 2001::/16 encap gre6")
270 for asid in self.ass:
272 "lb as 2001::/16 2002::%u"
275 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
276 self.pg_enable_capture(self.pg_interfaces)
279 self.checkCapture(encap='gre6', isv4=False)
281 for asid in self.ass:
283 "lb as 2001::/16 2002::%u del"
286 "lb vip 2001::/16 encap gre6 del")
287 self.vapi.cli("test lb flowtable flush")
289 def test_lb_ip4_gre4_port(self):
290 """ Load Balancer IP4 GRE4 on per-port-vip case """
293 "lb vip 90.0.0.0/8 protocol udp port 20000 encap gre4")
294 for asid in self.ass:
296 "lb as 90.0.0.0/8 protocol udp port 20000 10.0.0.%u"
299 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
300 self.pg_enable_capture(self.pg_interfaces)
302 self.checkCapture(encap='gre4', isv4=True)
305 for asid in self.ass:
307 "lb as 90.0.0.0/8 protocol udp port 20000 10.0.0.%u del"
310 "lb vip 90.0.0.0/8 protocol udp port 20000 encap gre4 del")
311 self.vapi.cli("test lb flowtable flush")
313 def test_lb_ip6_gre4_port(self):
314 """ Load Balancer IP6 GRE4 on per-port-vip case """
318 "lb vip 2001::/16 protocol udp port 20000 encap gre4")
319 for asid in self.ass:
321 "lb as 2001::/16 protocol udp port 20000 10.0.0.%u"
324 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
325 self.pg_enable_capture(self.pg_interfaces)
328 self.checkCapture(encap='gre4', isv4=False)
330 for asid in self.ass:
332 "lb as 2001::/16 protocol udp port 20000 10.0.0.%u del"
335 "lb vip 2001::/16 protocol udp port 20000 encap gre4 del")
336 self.vapi.cli("test lb flowtable flush")
338 def test_lb_ip4_gre6_port(self):
339 """ Load Balancer IP4 GRE6 on per-port-vip case """
342 "lb vip 90.0.0.0/8 protocol udp port 20000 encap gre6")
343 for asid in self.ass:
345 "lb as 90.0.0.0/8 protocol udp port 20000 2002::%u"
348 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
349 self.pg_enable_capture(self.pg_interfaces)
352 self.checkCapture(encap='gre6', isv4=True)
354 for asid in self.ass:
356 "lb as 90.0.0.0/8 protocol udp port 20000 2002::%u del"
359 "lb vip 90.0.0.0/8 protocol udp port 20000 encap gre6 del")
360 self.vapi.cli("test lb flowtable flush")
362 def test_lb_ip6_gre6_port(self):
363 """ Load Balancer IP6 GRE6 on per-port-vip case """
366 "lb vip 2001::/16 protocol udp port 20000 encap gre6")
367 for asid in self.ass:
369 "lb as 2001::/16 protocol udp port 20000 2002::%u"
372 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
373 self.pg_enable_capture(self.pg_interfaces)
376 self.checkCapture(encap='gre6', isv4=False)
378 for asid in self.ass:
380 "lb as 2001::/16 protocol udp port 20000 2002::%u del"
383 "lb vip 2001::/16 protocol udp port 20000 encap gre6 del")
384 self.vapi.cli("test lb flowtable flush")
386 def test_lb_ip4_l3dsr(self):
387 """ Load Balancer IP4 L3DSR on vip case """
390 "lb vip 90.0.0.0/8 encap l3dsr dscp 7")
391 for asid in self.ass:
393 "lb as 90.0.0.0/8 10.0.0.%u"
396 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
397 self.pg_enable_capture(self.pg_interfaces)
399 self.checkCapture(encap='l3dsr', isv4=True)
402 for asid in self.ass:
404 "lb as 90.0.0.0/8 10.0.0.%u del"
407 "lb vip 90.0.0.0/8 encap l3dsr"
409 self.vapi.cli("test lb flowtable flush")
411 def test_lb_ip4_l3dsr_port(self):
412 """ Load Balancer IP4 L3DSR on per-port-vip case """
415 "lb vip 90.0.0.0/8 protocol udp port 20000 encap l3dsr dscp 7")
416 for asid in self.ass:
418 "lb as 90.0.0.0/8 protocol udp port 20000 10.0.0.%u"
421 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
422 self.pg_enable_capture(self.pg_interfaces)
424 self.checkCapture(encap='l3dsr', isv4=True)
427 for asid in self.ass:
429 "lb as 90.0.0.0/8 protocol udp port 20000 10.0.0.%u del"
432 "lb vip 90.0.0.0/8 protocol udp port 20000 encap l3dsr"
434 self.vapi.cli("test lb flowtable flush")
436 def test_lb_ip4_nat4_port(self):
437 """ Load Balancer IP4 NAT4 on per-port-vip case """
440 "lb vip 90.0.0.0/8 protocol udp port 20000 encap nat4"
441 " type clusterip target_port 3307")
442 for asid in self.ass:
444 "lb as 90.0.0.0/8 protocol udp port 20000 10.0.0.%u"
447 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
448 self.pg_enable_capture(self.pg_interfaces)
450 self.checkCapture(encap='nat4', isv4=True)
453 for asid in self.ass:
455 "lb as 90.0.0.0/8 protocol udp port 20000 10.0.0.%u del"
458 "lb vip 90.0.0.0/8 protocol udp port 20000 encap nat4"
459 " type clusterip target_port 3307 del")
460 self.vapi.cli("test lb flowtable flush")
462 def test_lb_ip6_nat6_port(self):
463 """ Load Balancer IP6 NAT6 on per-port-vip case """
466 "lb vip 2001::/16 protocol udp port 20000 encap nat6"
467 " type clusterip target_port 3307")
468 for asid in self.ass:
470 "lb as 2001::/16 protocol udp port 20000 2002::%u"
473 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
474 self.pg_enable_capture(self.pg_interfaces)
476 self.checkCapture(encap='nat6', isv4=False)
479 for asid in self.ass:
481 "lb as 2001::/16 protocol udp port 20000 2002::%u del"
484 "lb vip 2001::/16 protocol udp port 20000 encap nat6"
485 " type clusterip target_port 3307 del")
486 self.vapi.cli("test lb flowtable flush")