blob: d2e7185cf3f91a90d2d40eeb06de8e5fedfb57f7 [file] [log] [blame]
Pierre Pfisterf588f352016-10-07 16:31:57 +01001import socket
Pierre Pfisterf588f352016-10-07 16:31:57 +01002
Pierre Pfisterf588f352016-10-07 16:31:57 +01003from scapy.layers.inet import IP, UDP
Klement Sekera65cc8c02016-12-18 15:49:54 +01004from scapy.layers.inet6 import IPv6
Klement Sekeraf62ae122016-10-11 11:47:09 +02005from scapy.layers.l2 import Ether, GRE
6from scapy.packet import Raw
Hongjun Ni6fb0d9b2018-06-08 07:12:05 +08007from scapy.data import IP_PROTOS
Pierre Pfisterf588f352016-10-07 16:31:57 +01008
Klement Sekeraf62ae122016-10-11 11:47:09 +02009from framework import VppTestCase
Klement Sekera7bb873a2016-11-18 07:38:42 +010010from util import ppp
Klement Sekeraf62ae122016-10-11 11:47:09 +020011
12""" TestLB is a subclass of VPPTestCase classes.
13
14 TestLB class defines Load Balancer test cases for:
15 - IP4 to GRE4 encap
16 - IP4 to GRE6 encap
17 - IP6 to GRE4 encap
18 - IP6 to GRE6 encap
Hongjun Ni647f6092018-01-23 19:17:23 +080019 - IP4 to L3DSR encap
Hongjun Nid92a0b52018-02-06 23:00:22 +080020 - IP4 to NAT4 encap
21 - IP6 to NAT6 encap
Klement Sekeraf62ae122016-10-11 11:47:09 +020022
23 As stated in comments below, GRE has issues with IPv6.
24 All test cases involving IPv6 are executed, but
25 received packets are not parsed and checked.
26
27"""
28
29
30class TestLB(VppTestCase):
Pierre Pfisterf588f352016-10-07 16:31:57 +010031 """ Load Balancer Test Case """
32
33 @classmethod
34 def setUpClass(cls):
35 super(TestLB, cls).setUpClass()
36
37 cls.ass = range(5)
38 cls.packets = range(100)
39
40 try:
Klement Sekeraf62ae122016-10-11 11:47:09 +020041 cls.create_pg_interfaces(range(2))
42 cls.interfaces = list(cls.pg_interfaces)
Pierre Pfisterf588f352016-10-07 16:31:57 +010043
Klement Sekeraf62ae122016-10-11 11:47:09 +020044 for i in cls.interfaces:
45 i.admin_up()
46 i.config_ip4()
47 i.config_ip6()
48 i.disable_ipv6_ra()
49 i.resolve_arp()
50 i.resolve_ndp()
51 dst4 = socket.inet_pton(socket.AF_INET, "10.0.0.0")
52 dst6 = socket.inet_pton(socket.AF_INET6, "2002::")
53 cls.vapi.ip_add_del_route(dst4, 24, cls.pg1.remote_ip4n)
54 cls.vapi.ip_add_del_route(dst6, 16, cls.pg1.remote_ip6n, is_ipv6=1)
55 cls.vapi.cli("lb conf ip4-src-address 39.40.41.42")
56 cls.vapi.cli("lb conf ip6-src-address 2004::1")
57 except Exception:
Pierre Pfisterf588f352016-10-07 16:31:57 +010058 super(TestLB, cls).tearDownClass()
59 raise
60
61 def tearDown(self):
Klement Sekeraf62ae122016-10-11 11:47:09 +020062 super(TestLB, self).tearDown()
63 if not self.vpp_dead:
Klement Sekera7bb873a2016-11-18 07:38:42 +010064 self.logger.info(self.vapi.cli("show lb vip verbose"))
Pierre Pfisterf588f352016-10-07 16:31:57 +010065
66 def getIPv4Flow(self, id):
67 return (IP(dst="90.0.%u.%u" % (id / 255, id % 255),
Klement Sekeraf62ae122016-10-11 11:47:09 +020068 src="40.0.%u.%u" % (id / 255, id % 255)) /
Pierre Pfisterf588f352016-10-07 16:31:57 +010069 UDP(sport=10000 + id, dport=20000 + id))
70
71 def getIPv6Flow(self, id):
72 return (IPv6(dst="2001::%u" % (id), src="fd00:f00d:ffff::%u" % (id)) /
Klement Sekeraf62ae122016-10-11 11:47:09 +020073 UDP(sport=10000 + id, dport=20000 + id))
Pierre Pfisterf588f352016-10-07 16:31:57 +010074
Klement Sekeraf62ae122016-10-11 11:47:09 +020075 def generatePackets(self, src_if, isv4):
Klement Sekeradab231a2016-12-21 08:50:14 +010076 self.reset_packet_infos()
Pierre Pfisterf588f352016-10-07 16:31:57 +010077 pkts = []
78 for pktid in self.packets:
Klement Sekeradab231a2016-12-21 08:50:14 +010079 info = self.create_packet_info(src_if, self.pg1)
Pierre Pfisterf588f352016-10-07 16:31:57 +010080 payload = self.info_to_payload(info)
81 ip = self.getIPv4Flow(pktid) if isv4 else self.getIPv6Flow(pktid)
Klement Sekeraf62ae122016-10-11 11:47:09 +020082 packet = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
83 ip /
84 Raw(payload))
Pierre Pfisterf588f352016-10-07 16:31:57 +010085 self.extend_packet(packet, 128)
86 info.data = packet.copy()
87 pkts.append(packet)
88 return pkts
89
90 def checkInner(self, gre, isv4):
Klement Sekeraf62ae122016-10-11 11:47:09 +020091 IPver = IP if isv4 else IPv6
Pierre Pfisterf588f352016-10-07 16:31:57 +010092 self.assertEqual(gre.proto, 0x0800 if isv4 else 0x86DD)
93 self.assertEqual(gre.flags, 0)
94 self.assertEqual(gre.version, 0)
Klement Sekeraf62ae122016-10-11 11:47:09 +020095 inner = IPver(str(gre.payload))
96 payload_info = self.payload_to_info(str(inner[Raw]))
Klement Sekeradab231a2016-12-21 08:50:14 +010097 self.info = self.packet_infos[payload_info.index]
98 self.assertEqual(payload_info.src, self.pg0.sw_if_index)
Klement Sekeraf62ae122016-10-11 11:47:09 +020099 self.assertEqual(str(inner), str(self.info.data[IPver]))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100100
Hongjun Ni647f6092018-01-23 19:17:23 +0800101 def checkCapture(self, encap, isv4):
Klement Sekera65cc8c02016-12-18 15:49:54 +0100102 self.pg0.assert_nothing_captured()
Klement Sekeradab231a2016-12-21 08:50:14 +0100103 out = self.pg1.get_capture(len(self.packets))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100104
105 load = [0] * len(self.ass)
106 self.info = None
107 for p in out:
108 try:
109 asid = 0
110 gre = None
Hongjun Ni647f6092018-01-23 19:17:23 +0800111 if (encap == 'gre4'):
Pierre Pfisterf588f352016-10-07 16:31:57 +0100112 ip = p[IP]
Pierre Pfisterf588f352016-10-07 16:31:57 +0100113 asid = int(ip.dst.split(".")[3])
114 self.assertEqual(ip.version, 4)
115 self.assertEqual(ip.flags, 0)
116 self.assertEqual(ip.src, "39.40.41.42")
117 self.assertEqual(ip.dst, "10.0.0.%u" % asid)
118 self.assertEqual(ip.proto, 47)
119 self.assertEqual(len(ip.options), 0)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200120 self.assertGreaterEqual(ip.ttl, 64)
121 gre = p[GRE]
Hongjun Ni647f6092018-01-23 19:17:23 +0800122 self.checkInner(gre, isv4)
123 elif (encap == 'gre6'):
Pierre Pfisterf588f352016-10-07 16:31:57 +0100124 ip = p[IPv6]
Pierre Pfisterf588f352016-10-07 16:31:57 +0100125 asid = ip.dst.split(":")
126 asid = asid[len(asid) - 1]
Klement Sekeraf62ae122016-10-11 11:47:09 +0200127 asid = 0 if asid == "" else int(asid)
Pierre Pfisterf588f352016-10-07 16:31:57 +0100128 self.assertEqual(ip.version, 6)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200129 self.assertEqual(ip.tc, 0)
130 self.assertEqual(ip.fl, 0)
131 self.assertEqual(ip.src, "2004::1")
132 self.assertEqual(
133 socket.inet_pton(socket.AF_INET6, ip.dst),
134 socket.inet_pton(socket.AF_INET6, "2002::%u" % asid)
135 )
136 self.assertEqual(ip.nh, 47)
137 self.assertGreaterEqual(ip.hlim, 64)
138 # self.assertEqual(len(ip.options), 0)
139 gre = GRE(str(p[IPv6].payload))
Hongjun Ni647f6092018-01-23 19:17:23 +0800140 self.checkInner(gre, isv4)
Hongjun Nid92a0b52018-02-06 23:00:22 +0800141 elif (encap == 'l3dsr'):
Hongjun Ni647f6092018-01-23 19:17:23 +0800142 ip = p[IP]
143 asid = int(ip.dst.split(".")[3])
144 self.assertEqual(ip.version, 4)
145 self.assertEqual(ip.flags, 0)
146 self.assertEqual(ip.dst, "10.0.0.%u" % asid)
147 self.assertEqual(ip.tos, 0x1c)
148 self.assertEqual(len(ip.options), 0)
Hongjun Ni6fb0d9b2018-06-08 07:12:05 +0800149 self.assert_ip_checksum_valid(p)
150 if ip.proto == IP_PROTOS.tcp:
151 self.assert_tcp_checksum_valid(p)
152 elif ip.proto == IP_PROTOS.udp:
153 self.assert_udp_checksum_valid(p)
Hongjun Nid92a0b52018-02-06 23:00:22 +0800154 elif (encap == 'nat4'):
155 ip = p[IP]
156 asid = int(ip.dst.split(".")[3])
157 self.assertEqual(ip.version, 4)
158 self.assertEqual(ip.flags, 0)
159 self.assertEqual(ip.dst, "10.0.0.%u" % asid)
160 self.assertEqual(ip.proto, 17)
161 self.assertEqual(len(ip.options), 0)
162 self.assertGreaterEqual(ip.ttl, 63)
163 udp = p[UDP]
164 self.assertEqual(udp.dport, 3307)
165 elif (encap == 'nat6'):
166 ip = p[IPv6]
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)
173 self.assertEqual(
174 socket.inet_pton(socket.AF_INET6, ip.dst),
175 socket.inet_pton(socket.AF_INET6, "2002::%u" % asid)
176 )
177 self.assertEqual(ip.nh, 17)
178 self.assertGreaterEqual(ip.hlim, 63)
179 udp = UDP(str(p[IPv6].payload))
180 self.assertEqual(udp.dport, 3307)
Pierre Pfisterf588f352016-10-07 16:31:57 +0100181 load[asid] += 1
182 except:
Klement Sekera7bb873a2016-11-18 07:38:42 +0100183 self.logger.error(ppp("Unexpected or invalid packet:", p))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100184 raise
185
186 # This is just to roughly check that the balancing algorithm
187 # is not completly biased.
188 for asid in self.ass:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200189 if load[asid] < len(self.packets) / (len(self.ass) * 2):
Gabriel Ganne8e66b9b2017-12-14 16:20:37 +0100190 self.logger.error(
Klement Sekeraf62ae122016-10-11 11:47:09 +0200191 "ASS is not balanced: load[%d] = %d" % (asid, load[asid]))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100192 raise Exception("Load Balancer algorithm is biased")
193
Pierre Pfisterf588f352016-10-07 16:31:57 +0100194 def test_lb_ip4_gre4(self):
195 """ Load Balancer IP4 GRE4 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200196 try:
197 self.vapi.cli("lb vip 90.0.0.0/8 encap gre4")
198 for asid in self.ass:
199 self.vapi.cli("lb as 90.0.0.0/8 10.0.0.%u" % (asid))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100200
Klement Sekeraf62ae122016-10-11 11:47:09 +0200201 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
202 self.pg_enable_capture(self.pg_interfaces)
203 self.pg_start()
Hongjun Ni647f6092018-01-23 19:17:23 +0800204 self.checkCapture(encap='gre4', isv4=True)
Pierre Pfisterf588f352016-10-07 16:31:57 +0100205
Klement Sekeraf62ae122016-10-11 11:47:09 +0200206 finally:
207 for asid in self.ass:
208 self.vapi.cli("lb as 90.0.0.0/8 10.0.0.%u del" % (asid))
209 self.vapi.cli("lb vip 90.0.0.0/8 encap gre4 del")
Gabriel Ganneb3d1b202017-10-30 15:44:31 +0100210 self.vapi.cli("test lb flowtable flush")
Pierre Pfisterf588f352016-10-07 16:31:57 +0100211
212 def test_lb_ip6_gre4(self):
213 """ Load Balancer IP6 GRE4 """
214
Klement Sekeraf62ae122016-10-11 11:47:09 +0200215 try:
216 self.vapi.cli("lb vip 2001::/16 encap gre4")
217 for asid in self.ass:
218 self.vapi.cli("lb as 2001::/16 10.0.0.%u" % (asid))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100219
Klement Sekeraf62ae122016-10-11 11:47:09 +0200220 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
221 self.pg_enable_capture(self.pg_interfaces)
222 self.pg_start()
Pierre Pfisterf588f352016-10-07 16:31:57 +0100223
Hongjun Ni647f6092018-01-23 19:17:23 +0800224 self.checkCapture(encap='gre4', isv4=False)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200225 finally:
226 for asid in self.ass:
227 self.vapi.cli("lb as 2001::/16 10.0.0.%u del" % (asid))
228 self.vapi.cli("lb vip 2001::/16 encap gre4 del")
Gabriel Ganneb3d1b202017-10-30 15:44:31 +0100229 self.vapi.cli("test lb flowtable flush")
Pierre Pfisterf588f352016-10-07 16:31:57 +0100230
231 def test_lb_ip4_gre6(self):
232 """ Load Balancer IP4 GRE6 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200233 try:
234 self.vapi.cli("lb vip 90.0.0.0/8 encap gre6")
235 for asid in self.ass:
236 self.vapi.cli("lb as 90.0.0.0/8 2002::%u" % (asid))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100237
Klement Sekeraf62ae122016-10-11 11:47:09 +0200238 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
239 self.pg_enable_capture(self.pg_interfaces)
240 self.pg_start()
Pierre Pfisterf588f352016-10-07 16:31:57 +0100241
Hongjun Ni647f6092018-01-23 19:17:23 +0800242 self.checkCapture(encap='gre6', isv4=True)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200243 finally:
244 for asid in self.ass:
Gabriel Ganneaa0dda42017-10-24 15:18:57 +0200245 self.vapi.cli("lb as 90.0.0.0/8 2002::%u del" % (asid))
Klement Sekeraf62ae122016-10-11 11:47:09 +0200246 self.vapi.cli("lb vip 90.0.0.0/8 encap gre6 del")
Gabriel Ganneb3d1b202017-10-30 15:44:31 +0100247 self.vapi.cli("test lb flowtable flush")
Pierre Pfisterf588f352016-10-07 16:31:57 +0100248
249 def test_lb_ip6_gre6(self):
250 """ Load Balancer IP6 GRE6 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200251 try:
252 self.vapi.cli("lb vip 2001::/16 encap gre6")
253 for asid in self.ass:
254 self.vapi.cli("lb as 2001::/16 2002::%u" % (asid))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100255
Klement Sekeraf62ae122016-10-11 11:47:09 +0200256 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
257 self.pg_enable_capture(self.pg_interfaces)
258 self.pg_start()
Pierre Pfisterf588f352016-10-07 16:31:57 +0100259
Hongjun Ni647f6092018-01-23 19:17:23 +0800260 self.checkCapture(encap='gre6', isv4=False)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200261 finally:
262 for asid in self.ass:
263 self.vapi.cli("lb as 2001::/16 2002::%u del" % (asid))
264 self.vapi.cli("lb vip 2001::/16 encap gre6 del")
Gabriel Ganneb3d1b202017-10-30 15:44:31 +0100265 self.vapi.cli("test lb flowtable flush")
Hongjun Ni647f6092018-01-23 19:17:23 +0800266
267 def test_lb_ip4_l3dsr(self):
268 """ Load Balancer IP4 L3DSR """
269 try:
270 self.vapi.cli("lb vip 90.0.0.0/8 encap l3dsr dscp 7")
271 for asid in self.ass:
272 self.vapi.cli("lb as 90.0.0.0/8 10.0.0.%u" % (asid))
273
274 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
275 self.pg_enable_capture(self.pg_interfaces)
276 self.pg_start()
277 self.checkCapture(encap='l3dsr', isv4=True)
278
279 finally:
280 for asid in self.ass:
281 self.vapi.cli("lb as 90.0.0.0/8 10.0.0.%u del" % (asid))
282 self.vapi.cli("lb vip 90.0.0.0/8 encap l3dsr dscp 7 del")
283 self.vapi.cli("test lb flowtable flush")
Hongjun Nid92a0b52018-02-06 23:00:22 +0800284
285 def test_lb_ip4_nat4(self):
286 """ Load Balancer IP4 NAT4 """
287 try:
288 self.vapi.cli("lb vip 90.0.0.0/8 encap nat4"
289 " type clusterip port 3306 target_port 3307")
290 for asid in self.ass:
291 self.vapi.cli("lb as 90.0.0.0/8 10.0.0.%u" % (asid))
292
293 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
294 self.pg_enable_capture(self.pg_interfaces)
295 self.pg_start()
296 self.checkCapture(encap='nat4', isv4=True)
297
298 finally:
299 for asid in self.ass:
300 self.vapi.cli("lb as 90.0.0.0/8 10.0.0.%u del" % (asid))
301 self.vapi.cli("lb vip 90.0.0.0/8 encap nat4"
302 " type clusterip port 3306 target_port 3307 del")
303 self.vapi.cli("test lb flowtable flush")
304
305 def test_lb_ip6_nat6(self):
306 """ Load Balancer IP6 NAT6 """
307 try:
308 self.vapi.cli("lb vip 2001::/16 encap nat6"
309 " type clusterip port 3306 target_port 3307")
310 for asid in self.ass:
311 self.vapi.cli("lb as 2001::/16 2002::%u" % (asid))
312
313 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
314 self.pg_enable_capture(self.pg_interfaces)
315 self.pg_start()
316 self.checkCapture(encap='nat6', isv4=False)
317
318 finally:
319 for asid in self.ass:
320 self.vapi.cli("lb as 2001::/16 2002::%u del" % (asid))
321 self.vapi.cli("lb vip 2001::/16 encap nat6"
322 " type clusterip port 3306 target_port 3307 del")
323 self.vapi.cli("test lb flowtable flush")