4 from scapy.layers.inet import IP, UDP
5 from scapy.layers.inet6 import IPv6
6 from scapy.layers.l2 import Ether, GRE
7 from scapy.packet import Raw
8 from scapy.data import IP_PROTOS
10 from framework import VppTestCase
13 """ TestLB is a subclass of VPPTestCase classes.
15 TestLB class defines Load Balancer test cases for:
16 - IP4 to GRE4 encap on per-port vip case
17 - IP4 to GRE6 encap on per-port vip case
18 - IP6 to GRE4 encap on per-port vip case
19 - IP6 to GRE6 encap on per-port vip case
20 - IP4 to L3DSR encap on vip case
21 - IP4 to L3DSR encap on per-port vip case
22 - IP4 to NAT4 encap on per-port vip case
23 - IP6 to NAT6 encap on per-port vip case
25 As stated in comments below, GRE has issues with IPv6.
26 All test cases involving IPv6 are executed, but
27 received packets are not parsed and checked.
32 class TestLB(VppTestCase):
33 """ Load Balancer Test Case """
37 super(TestLB, cls).setUpClass()
40 cls.packets = range(1)
43 cls.create_pg_interfaces(range(2))
44 cls.interfaces = list(cls.pg_interfaces)
46 for i in cls.interfaces:
53 dst4 = socket.inet_pton(socket.AF_INET, "10.0.0.0")
54 dst6 = socket.inet_pton(socket.AF_INET6, "2002::")
55 cls.vapi.ip_add_del_route(dst4, 24, cls.pg1.remote_ip4n)
56 cls.vapi.ip_add_del_route(dst6, 16, cls.pg1.remote_ip6n, is_ipv6=1)
57 cls.vapi.cli("lb conf ip4-src-address 39.40.41.42")
58 cls.vapi.cli("lb conf ip6-src-address 2004::1")
60 super(TestLB, cls).tearDownClass()
64 super(TestLB, self).tearDown()
66 self.logger.info(self.vapi.cli("show lb vip verbose"))
68 def getIPv4Flow(self, id):
69 return (IP(dst="90.0.%u.%u" % (id / 255, id % 255),
70 src="40.0.%u.%u" % (id / 255, id % 255)) /
71 UDP(sport=10000 + id, dport=20000))
73 def getIPv6Flow(self, id):
74 return (IPv6(dst="2001::%u" % (id), src="fd00:f00d:ffff::%u" % (id)) /
75 UDP(sport=10000 + id, dport=20000))
77 def generatePackets(self, src_if, isv4):
78 self.reset_packet_infos()
80 for pktid in self.packets:
81 info = self.create_packet_info(src_if, self.pg1)
82 payload = self.info_to_payload(info)
83 ip = self.getIPv4Flow(pktid) if isv4 else self.getIPv6Flow(pktid)
84 packet = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
87 self.extend_packet(packet, 128)
88 info.data = packet.copy()
92 def checkInner(self, gre, isv4):
93 IPver = IP if isv4 else IPv6
94 self.assertEqual(gre.proto, 0x0800 if isv4 else 0x86DD)
95 self.assertEqual(gre.flags, 0)
96 self.assertEqual(gre.version, 0)
97 inner = IPver(scapy.compat.raw(gre.payload))
98 payload_info = self.payload_to_info(inner[Raw])
99 self.info = self.packet_infos[payload_info.index]
100 self.assertEqual(payload_info.src, self.pg0.sw_if_index)
101 self.assertEqual(scapy.compat.raw(inner),
102 scapy.compat.raw(self.info.data[IPver]))
104 def checkCapture(self, encap, isv4):
105 self.pg0.assert_nothing_captured()
106 out = self.pg1.get_capture(len(self.packets))
108 load = [0] * len(self.ass)
114 if (encap == 'gre4'):
116 asid = int(ip.dst.split(".")[3])
117 self.assertEqual(ip.version, 4)
118 self.assertEqual(ip.flags, 0)
119 self.assertEqual(ip.src, "39.40.41.42")
120 self.assertEqual(ip.dst, "10.0.0.%u" % asid)
121 self.assertEqual(ip.proto, 47)
122 self.assertEqual(len(ip.options), 0)
124 self.checkInner(gre, isv4)
125 elif (encap == 'gre6'):
127 asid = ip.dst.split(":")
128 asid = asid[len(asid) - 1]
129 asid = 0 if asid == "" else int(asid)
130 self.assertEqual(ip.version, 6)
131 self.assertEqual(ip.tc, 0)
132 self.assertEqual(ip.fl, 0)
133 self.assertEqual(ip.src, "2004::1")
135 socket.inet_pton(socket.AF_INET6, ip.dst),
136 socket.inet_pton(socket.AF_INET6, "2002::%u" % asid)
138 self.assertEqual(ip.nh, 47)
139 # self.assertEqual(len(ip.options), 0)
140 gre = GRE(scapy.compat.raw(p[IPv6].payload))
141 self.checkInner(gre, isv4)
142 elif (encap == 'l3dsr'):
144 asid = int(ip.dst.split(".")[3])
145 self.assertEqual(ip.version, 4)
146 self.assertEqual(ip.flags, 0)
147 self.assertEqual(ip.dst, "10.0.0.%u" % asid)
148 self.assertEqual(ip.tos, 0x1c)
149 self.assertEqual(len(ip.options), 0)
150 self.assert_ip_checksum_valid(p)
151 if ip.proto == IP_PROTOS.tcp:
152 self.assert_tcp_checksum_valid(p)
153 elif ip.proto == IP_PROTOS.udp:
154 self.assert_udp_checksum_valid(p)
155 elif (encap == 'nat4'):
157 asid = int(ip.dst.split(".")[3])
158 self.assertEqual(ip.version, 4)
159 self.assertEqual(ip.flags, 0)
160 self.assertEqual(ip.dst, "10.0.0.%u" % asid)
161 self.assertEqual(ip.proto, 17)
162 self.assertEqual(len(ip.options), 0)
164 self.assertEqual(udp.dport, 3307)
165 elif (encap == 'nat6'):
167 asid = ip.dst.split(":")
168 asid = asid[len(asid) - 1]
169 asid = 0 if asid == "" else int(asid)
170 self.assertEqual(ip.version, 6)
171 self.assertEqual(ip.tc, 0)
172 self.assertEqual(ip.fl, 0)
174 socket.inet_pton(socket.AF_INET6, ip.dst),
175 socket.inet_pton(socket.AF_INET6, "2002::%u" % asid)
177 self.assertEqual(ip.nh, 17)
178 self.assertGreaterEqual(ip.hlim, 63)
179 udp = UDP(scapy.compat.raw(p[IPv6].payload))
180 self.assertEqual(udp.dport, 3307)
183 self.logger.error(ppp("Unexpected or invalid packet:", p))
186 # This is just to 1roughly check that the balancing algorithm
187 # is not completly biased.
188 for asid in self.ass:
189 if load[asid] < len(self.packets) / (len(self.ass) * 2):
191 "ASS is not balanced: load[%d] = %d" % (asid, load[asid]))
192 raise Exception("Load Balancer algorithm is biased")
194 def test_lb_ip4_gre4(self):
195 """ Load Balancer IP4 GRE4 on vip case """
198 "lb vip 90.0.0.0/8 encap gre4")
199 for asid in self.ass:
201 "lb as 90.0.0.0/8 10.0.0.%u"
204 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
205 self.pg_enable_capture(self.pg_interfaces)
207 self.checkCapture(encap='gre4', isv4=True)
210 for asid in self.ass:
212 "lb as 90.0.0.0/8 10.0.0.%u del"
215 "lb vip 90.0.0.0/8 encap gre4 del")
216 self.vapi.cli("test lb flowtable flush")
218 def test_lb_ip6_gre4(self):
219 """ Load Balancer IP6 GRE4 on vip case """
223 "lb vip 2001::/16 encap gre4")
224 for asid in self.ass:
226 "lb as 2001::/16 10.0.0.%u"
229 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
230 self.pg_enable_capture(self.pg_interfaces)
233 self.checkCapture(encap='gre4', isv4=False)
235 for asid in self.ass:
237 "lb as 2001::/16 10.0.0.%u del"
240 "lb vip 2001::/16 encap gre4 del")
241 self.vapi.cli("test lb flowtable flush")
243 def test_lb_ip4_gre6(self):
244 """ Load Balancer IP4 GRE6 on vip case """
247 "lb vip 90.0.0.0/8 encap gre6")
248 for asid in self.ass:
250 "lb as 90.0.0.0/8 2002::%u"
253 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
254 self.pg_enable_capture(self.pg_interfaces)
257 self.checkCapture(encap='gre6', isv4=True)
259 for asid in self.ass:
261 "lb as 90.0.0.0/8 2002::%u del"
264 "lb vip 90.0.0.0/8 encap gre6 del")
265 self.vapi.cli("test lb flowtable flush")
267 def test_lb_ip6_gre6(self):
268 """ Load Balancer IP6 GRE6 on vip case """
271 "lb vip 2001::/16 encap gre6")
272 for asid in self.ass:
274 "lb as 2001::/16 2002::%u"
277 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
278 self.pg_enable_capture(self.pg_interfaces)
281 self.checkCapture(encap='gre6', isv4=False)
283 for asid in self.ass:
285 "lb as 2001::/16 2002::%u del"
288 "lb vip 2001::/16 encap gre6 del")
289 self.vapi.cli("test lb flowtable flush")
291 def test_lb_ip4_gre4_port(self):
292 """ Load Balancer IP4 GRE4 on per-port-vip case """
295 "lb vip 90.0.0.0/8 protocol udp port 20000 encap gre4")
296 for asid in self.ass:
298 "lb as 90.0.0.0/8 protocol udp port 20000 10.0.0.%u"
301 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
302 self.pg_enable_capture(self.pg_interfaces)
304 self.checkCapture(encap='gre4', isv4=True)
307 for asid in self.ass:
309 "lb as 90.0.0.0/8 protocol udp port 20000 10.0.0.%u del"
312 "lb vip 90.0.0.0/8 protocol udp port 20000 encap gre4 del")
313 self.vapi.cli("test lb flowtable flush")
315 def test_lb_ip6_gre4_port(self):
316 """ Load Balancer IP6 GRE4 on per-port-vip case """
320 "lb vip 2001::/16 protocol udp port 20000 encap gre4")
321 for asid in self.ass:
323 "lb as 2001::/16 protocol udp port 20000 10.0.0.%u"
326 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
327 self.pg_enable_capture(self.pg_interfaces)
330 self.checkCapture(encap='gre4', isv4=False)
332 for asid in self.ass:
334 "lb as 2001::/16 protocol udp port 20000 10.0.0.%u del"
337 "lb vip 2001::/16 protocol udp port 20000 encap gre4 del")
338 self.vapi.cli("test lb flowtable flush")
340 def test_lb_ip4_gre6_port(self):
341 """ Load Balancer IP4 GRE6 on per-port-vip case """
344 "lb vip 90.0.0.0/8 protocol udp port 20000 encap gre6")
345 for asid in self.ass:
347 "lb as 90.0.0.0/8 protocol udp port 20000 2002::%u"
350 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
351 self.pg_enable_capture(self.pg_interfaces)
354 self.checkCapture(encap='gre6', isv4=True)
356 for asid in self.ass:
358 "lb as 90.0.0.0/8 protocol udp port 20000 2002::%u del"
361 "lb vip 90.0.0.0/8 protocol udp port 20000 encap gre6 del")
362 self.vapi.cli("test lb flowtable flush")
364 def test_lb_ip6_gre6_port(self):
365 """ Load Balancer IP6 GRE6 on per-port-vip case """
368 "lb vip 2001::/16 protocol udp port 20000 encap gre6")
369 for asid in self.ass:
371 "lb as 2001::/16 protocol udp port 20000 2002::%u"
374 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
375 self.pg_enable_capture(self.pg_interfaces)
378 self.checkCapture(encap='gre6', isv4=False)
380 for asid in self.ass:
382 "lb as 2001::/16 protocol udp port 20000 2002::%u del"
385 "lb vip 2001::/16 protocol udp port 20000 encap gre6 del")
386 self.vapi.cli("test lb flowtable flush")
388 def test_lb_ip4_l3dsr(self):
389 """ Load Balancer IP4 L3DSR on vip case """
392 "lb vip 90.0.0.0/8 encap l3dsr dscp 7")
393 for asid in self.ass:
395 "lb as 90.0.0.0/8 10.0.0.%u"
398 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
399 self.pg_enable_capture(self.pg_interfaces)
401 self.checkCapture(encap='l3dsr', isv4=True)
404 for asid in self.ass:
406 "lb as 90.0.0.0/8 10.0.0.%u del"
409 "lb vip 90.0.0.0/8 encap l3dsr"
411 self.vapi.cli("test lb flowtable flush")
413 def test_lb_ip4_l3dsr_port(self):
414 """ Load Balancer IP4 L3DSR on per-port-vip case """
417 "lb vip 90.0.0.0/8 protocol udp port 20000 encap l3dsr dscp 7")
418 for asid in self.ass:
420 "lb as 90.0.0.0/8 protocol udp port 20000 10.0.0.%u"
423 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
424 self.pg_enable_capture(self.pg_interfaces)
426 self.checkCapture(encap='l3dsr', isv4=True)
429 for asid in self.ass:
431 "lb as 90.0.0.0/8 protocol udp port 20000 10.0.0.%u del"
434 "lb vip 90.0.0.0/8 protocol udp port 20000 encap l3dsr"
436 self.vapi.cli("test lb flowtable flush")
438 def test_lb_ip4_nat4_port(self):
439 """ Load Balancer IP4 NAT4 on per-port-vip case """
442 "lb vip 90.0.0.0/8 protocol udp port 20000 encap nat4"
443 " type clusterip target_port 3307")
444 for asid in self.ass:
446 "lb as 90.0.0.0/8 protocol udp port 20000 10.0.0.%u"
449 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
450 self.pg_enable_capture(self.pg_interfaces)
452 self.checkCapture(encap='nat4', isv4=True)
455 for asid in self.ass:
457 "lb as 90.0.0.0/8 protocol udp port 20000 10.0.0.%u del"
460 "lb vip 90.0.0.0/8 protocol udp port 20000 encap nat4"
461 " type clusterip target_port 3307 del")
462 self.vapi.cli("test lb flowtable flush")
464 def test_lb_ip6_nat6_port(self):
465 """ Load Balancer IP6 NAT6 on per-port-vip case """
468 "lb vip 2001::/16 protocol udp port 20000 encap nat6"
469 " type clusterip target_port 3307")
470 for asid in self.ass:
472 "lb as 2001::/16 protocol udp port 20000 2002::%u"
475 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
476 self.pg_enable_capture(self.pg_interfaces)
478 self.checkCapture(encap='nat6', isv4=False)
481 for asid in self.ass:
483 "lb as 2001::/16 protocol udp port 20000 2002::%u del"
486 "lb vip 2001::/16 protocol udp port 20000 encap nat6"
487 " type clusterip target_port 3307 del")
488 self.vapi.cli("test lb flowtable flush")