blob: 79a95988671441bb1b0a0b62aee71614709a8a76 [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
Pierre Pfisterf588f352016-10-07 16:31:57 +01007
Klement Sekeraf62ae122016-10-11 11:47:09 +02008from framework import VppTestCase
Klement Sekera7bb873a2016-11-18 07:38:42 +01009from util import ppp
Klement Sekeraf62ae122016-10-11 11:47:09 +020010
11""" TestLB is a subclass of VPPTestCase classes.
12
13 TestLB class defines Load Balancer test cases for:
14 - IP4 to GRE4 encap
15 - IP4 to GRE6 encap
16 - IP6 to GRE4 encap
17 - IP6 to GRE6 encap
Hongjun Ni647f6092018-01-23 19:17:23 +080018 - IP4 to L3DSR encap
Hongjun Nid92a0b52018-02-06 23:00:22 +080019 - IP4 to NAT4 encap
20 - IP6 to NAT6 encap
Klement Sekeraf62ae122016-10-11 11:47:09 +020021
22 As stated in comments below, GRE has issues with IPv6.
23 All test cases involving IPv6 are executed, but
24 received packets are not parsed and checked.
25
26"""
27
28
29class TestLB(VppTestCase):
Pierre Pfisterf588f352016-10-07 16:31:57 +010030 """ Load Balancer Test Case """
31
32 @classmethod
33 def setUpClass(cls):
34 super(TestLB, cls).setUpClass()
35
36 cls.ass = range(5)
37 cls.packets = range(100)
38
39 try:
Klement Sekeraf62ae122016-10-11 11:47:09 +020040 cls.create_pg_interfaces(range(2))
41 cls.interfaces = list(cls.pg_interfaces)
Pierre Pfisterf588f352016-10-07 16:31:57 +010042
Klement Sekeraf62ae122016-10-11 11:47:09 +020043 for i in cls.interfaces:
44 i.admin_up()
45 i.config_ip4()
46 i.config_ip6()
47 i.disable_ipv6_ra()
48 i.resolve_arp()
49 i.resolve_ndp()
50 dst4 = socket.inet_pton(socket.AF_INET, "10.0.0.0")
51 dst6 = socket.inet_pton(socket.AF_INET6, "2002::")
52 cls.vapi.ip_add_del_route(dst4, 24, cls.pg1.remote_ip4n)
53 cls.vapi.ip_add_del_route(dst6, 16, cls.pg1.remote_ip6n, is_ipv6=1)
54 cls.vapi.cli("lb conf ip4-src-address 39.40.41.42")
55 cls.vapi.cli("lb conf ip6-src-address 2004::1")
56 except Exception:
Pierre Pfisterf588f352016-10-07 16:31:57 +010057 super(TestLB, cls).tearDownClass()
58 raise
59
60 def tearDown(self):
Klement Sekeraf62ae122016-10-11 11:47:09 +020061 super(TestLB, self).tearDown()
62 if not self.vpp_dead:
Klement Sekera7bb873a2016-11-18 07:38:42 +010063 self.logger.info(self.vapi.cli("show lb vip verbose"))
Pierre Pfisterf588f352016-10-07 16:31:57 +010064
65 def getIPv4Flow(self, id):
66 return (IP(dst="90.0.%u.%u" % (id / 255, id % 255),
Klement Sekeraf62ae122016-10-11 11:47:09 +020067 src="40.0.%u.%u" % (id / 255, id % 255)) /
Pierre Pfisterf588f352016-10-07 16:31:57 +010068 UDP(sport=10000 + id, dport=20000 + id))
69
70 def getIPv6Flow(self, id):
71 return (IPv6(dst="2001::%u" % (id), src="fd00:f00d:ffff::%u" % (id)) /
Klement Sekeraf62ae122016-10-11 11:47:09 +020072 UDP(sport=10000 + id, dport=20000 + id))
Pierre Pfisterf588f352016-10-07 16:31:57 +010073
Klement Sekeraf62ae122016-10-11 11:47:09 +020074 def generatePackets(self, src_if, isv4):
Klement Sekeradab231a2016-12-21 08:50:14 +010075 self.reset_packet_infos()
Pierre Pfisterf588f352016-10-07 16:31:57 +010076 pkts = []
77 for pktid in self.packets:
Klement Sekeradab231a2016-12-21 08:50:14 +010078 info = self.create_packet_info(src_if, self.pg1)
Pierre Pfisterf588f352016-10-07 16:31:57 +010079 payload = self.info_to_payload(info)
80 ip = self.getIPv4Flow(pktid) if isv4 else self.getIPv6Flow(pktid)
Klement Sekeraf62ae122016-10-11 11:47:09 +020081 packet = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
82 ip /
83 Raw(payload))
Pierre Pfisterf588f352016-10-07 16:31:57 +010084 self.extend_packet(packet, 128)
85 info.data = packet.copy()
86 pkts.append(packet)
87 return pkts
88
89 def checkInner(self, gre, isv4):
Klement Sekeraf62ae122016-10-11 11:47:09 +020090 IPver = IP if isv4 else IPv6
Pierre Pfisterf588f352016-10-07 16:31:57 +010091 self.assertEqual(gre.proto, 0x0800 if isv4 else 0x86DD)
92 self.assertEqual(gre.flags, 0)
93 self.assertEqual(gre.version, 0)
Klement Sekeraf62ae122016-10-11 11:47:09 +020094 inner = IPver(str(gre.payload))
95 payload_info = self.payload_to_info(str(inner[Raw]))
Klement Sekeradab231a2016-12-21 08:50:14 +010096 self.info = self.packet_infos[payload_info.index]
97 self.assertEqual(payload_info.src, self.pg0.sw_if_index)
Klement Sekeraf62ae122016-10-11 11:47:09 +020098 self.assertEqual(str(inner), str(self.info.data[IPver]))
Pierre Pfisterf588f352016-10-07 16:31:57 +010099
Hongjun Ni647f6092018-01-23 19:17:23 +0800100 def checkCapture(self, encap, isv4):
Klement Sekera65cc8c02016-12-18 15:49:54 +0100101 self.pg0.assert_nothing_captured()
Klement Sekeradab231a2016-12-21 08:50:14 +0100102 out = self.pg1.get_capture(len(self.packets))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100103
104 load = [0] * len(self.ass)
105 self.info = None
106 for p in out:
107 try:
108 asid = 0
109 gre = None
Hongjun Ni647f6092018-01-23 19:17:23 +0800110 if (encap == 'gre4'):
Pierre Pfisterf588f352016-10-07 16:31:57 +0100111 ip = p[IP]
Pierre Pfisterf588f352016-10-07 16:31:57 +0100112 asid = int(ip.dst.split(".")[3])
113 self.assertEqual(ip.version, 4)
114 self.assertEqual(ip.flags, 0)
115 self.assertEqual(ip.src, "39.40.41.42")
116 self.assertEqual(ip.dst, "10.0.0.%u" % asid)
117 self.assertEqual(ip.proto, 47)
118 self.assertEqual(len(ip.options), 0)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200119 self.assertGreaterEqual(ip.ttl, 64)
120 gre = p[GRE]
Hongjun Ni647f6092018-01-23 19:17:23 +0800121 self.checkInner(gre, isv4)
122 elif (encap == 'gre6'):
Pierre Pfisterf588f352016-10-07 16:31:57 +0100123 ip = p[IPv6]
Pierre Pfisterf588f352016-10-07 16:31:57 +0100124 asid = ip.dst.split(":")
125 asid = asid[len(asid) - 1]
Klement Sekeraf62ae122016-10-11 11:47:09 +0200126 asid = 0 if asid == "" else int(asid)
Pierre Pfisterf588f352016-10-07 16:31:57 +0100127 self.assertEqual(ip.version, 6)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200128 self.assertEqual(ip.tc, 0)
129 self.assertEqual(ip.fl, 0)
130 self.assertEqual(ip.src, "2004::1")
131 self.assertEqual(
132 socket.inet_pton(socket.AF_INET6, ip.dst),
133 socket.inet_pton(socket.AF_INET6, "2002::%u" % asid)
134 )
135 self.assertEqual(ip.nh, 47)
136 self.assertGreaterEqual(ip.hlim, 64)
137 # self.assertEqual(len(ip.options), 0)
138 gre = GRE(str(p[IPv6].payload))
Hongjun Ni647f6092018-01-23 19:17:23 +0800139 self.checkInner(gre, isv4)
Hongjun Nid92a0b52018-02-06 23:00:22 +0800140 elif (encap == 'l3dsr'):
Hongjun Ni647f6092018-01-23 19:17:23 +0800141 ip = p[IP]
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)
Hongjun Nid92a0b52018-02-06 23:00:22 +0800148 elif (encap == 'nat4'):
149 ip = p[IP]
150 asid = int(ip.dst.split(".")[3])
151 self.assertEqual(ip.version, 4)
152 self.assertEqual(ip.flags, 0)
153 self.assertEqual(ip.dst, "10.0.0.%u" % asid)
154 self.assertEqual(ip.proto, 17)
155 self.assertEqual(len(ip.options), 0)
156 self.assertGreaterEqual(ip.ttl, 63)
157 udp = p[UDP]
158 self.assertEqual(udp.dport, 3307)
159 elif (encap == 'nat6'):
160 ip = p[IPv6]
161 asid = ip.dst.split(":")
162 asid = asid[len(asid) - 1]
163 asid = 0 if asid == "" else int(asid)
164 self.assertEqual(ip.version, 6)
165 self.assertEqual(ip.tc, 0)
166 self.assertEqual(ip.fl, 0)
167 self.assertEqual(
168 socket.inet_pton(socket.AF_INET6, ip.dst),
169 socket.inet_pton(socket.AF_INET6, "2002::%u" % asid)
170 )
171 self.assertEqual(ip.nh, 17)
172 self.assertGreaterEqual(ip.hlim, 63)
173 udp = UDP(str(p[IPv6].payload))
174 self.assertEqual(udp.dport, 3307)
Pierre Pfisterf588f352016-10-07 16:31:57 +0100175 load[asid] += 1
176 except:
Klement Sekera7bb873a2016-11-18 07:38:42 +0100177 self.logger.error(ppp("Unexpected or invalid packet:", p))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100178 raise
179
180 # This is just to roughly check that the balancing algorithm
181 # is not completly biased.
182 for asid in self.ass:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200183 if load[asid] < len(self.packets) / (len(self.ass) * 2):
Gabriel Ganne8e66b9b2017-12-14 16:20:37 +0100184 self.logger.error(
Klement Sekeraf62ae122016-10-11 11:47:09 +0200185 "ASS is not balanced: load[%d] = %d" % (asid, load[asid]))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100186 raise Exception("Load Balancer algorithm is biased")
187
Pierre Pfisterf588f352016-10-07 16:31:57 +0100188 def test_lb_ip4_gre4(self):
189 """ Load Balancer IP4 GRE4 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200190 try:
191 self.vapi.cli("lb vip 90.0.0.0/8 encap gre4")
192 for asid in self.ass:
193 self.vapi.cli("lb as 90.0.0.0/8 10.0.0.%u" % (asid))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100194
Klement Sekeraf62ae122016-10-11 11:47:09 +0200195 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
196 self.pg_enable_capture(self.pg_interfaces)
197 self.pg_start()
Hongjun Ni647f6092018-01-23 19:17:23 +0800198 self.checkCapture(encap='gre4', isv4=True)
Pierre Pfisterf588f352016-10-07 16:31:57 +0100199
Klement Sekeraf62ae122016-10-11 11:47:09 +0200200 finally:
201 for asid in self.ass:
202 self.vapi.cli("lb as 90.0.0.0/8 10.0.0.%u del" % (asid))
203 self.vapi.cli("lb vip 90.0.0.0/8 encap gre4 del")
Gabriel Ganneb3d1b202017-10-30 15:44:31 +0100204 self.vapi.cli("test lb flowtable flush")
Pierre Pfisterf588f352016-10-07 16:31:57 +0100205
206 def test_lb_ip6_gre4(self):
207 """ Load Balancer IP6 GRE4 """
208
Klement Sekeraf62ae122016-10-11 11:47:09 +0200209 try:
210 self.vapi.cli("lb vip 2001::/16 encap gre4")
211 for asid in self.ass:
212 self.vapi.cli("lb as 2001::/16 10.0.0.%u" % (asid))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100213
Klement Sekeraf62ae122016-10-11 11:47:09 +0200214 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
215 self.pg_enable_capture(self.pg_interfaces)
216 self.pg_start()
Pierre Pfisterf588f352016-10-07 16:31:57 +0100217
Hongjun Ni647f6092018-01-23 19:17:23 +0800218 self.checkCapture(encap='gre4', isv4=False)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200219 finally:
220 for asid in self.ass:
221 self.vapi.cli("lb as 2001::/16 10.0.0.%u del" % (asid))
222 self.vapi.cli("lb vip 2001::/16 encap gre4 del")
Gabriel Ganneb3d1b202017-10-30 15:44:31 +0100223 self.vapi.cli("test lb flowtable flush")
Pierre Pfisterf588f352016-10-07 16:31:57 +0100224
225 def test_lb_ip4_gre6(self):
226 """ Load Balancer IP4 GRE6 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200227 try:
228 self.vapi.cli("lb vip 90.0.0.0/8 encap gre6")
229 for asid in self.ass:
230 self.vapi.cli("lb as 90.0.0.0/8 2002::%u" % (asid))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100231
Klement Sekeraf62ae122016-10-11 11:47:09 +0200232 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
233 self.pg_enable_capture(self.pg_interfaces)
234 self.pg_start()
Pierre Pfisterf588f352016-10-07 16:31:57 +0100235
Hongjun Ni647f6092018-01-23 19:17:23 +0800236 self.checkCapture(encap='gre6', isv4=True)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200237 finally:
238 for asid in self.ass:
Gabriel Ganneaa0dda42017-10-24 15:18:57 +0200239 self.vapi.cli("lb as 90.0.0.0/8 2002::%u del" % (asid))
Klement Sekeraf62ae122016-10-11 11:47:09 +0200240 self.vapi.cli("lb vip 90.0.0.0/8 encap gre6 del")
Gabriel Ganneb3d1b202017-10-30 15:44:31 +0100241 self.vapi.cli("test lb flowtable flush")
Pierre Pfisterf588f352016-10-07 16:31:57 +0100242
243 def test_lb_ip6_gre6(self):
244 """ Load Balancer IP6 GRE6 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200245 try:
246 self.vapi.cli("lb vip 2001::/16 encap gre6")
247 for asid in self.ass:
248 self.vapi.cli("lb as 2001::/16 2002::%u" % (asid))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100249
Klement Sekeraf62ae122016-10-11 11:47:09 +0200250 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
251 self.pg_enable_capture(self.pg_interfaces)
252 self.pg_start()
Pierre Pfisterf588f352016-10-07 16:31:57 +0100253
Hongjun Ni647f6092018-01-23 19:17:23 +0800254 self.checkCapture(encap='gre6', isv4=False)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200255 finally:
256 for asid in self.ass:
257 self.vapi.cli("lb as 2001::/16 2002::%u del" % (asid))
258 self.vapi.cli("lb vip 2001::/16 encap gre6 del")
Gabriel Ganneb3d1b202017-10-30 15:44:31 +0100259 self.vapi.cli("test lb flowtable flush")
Hongjun Ni647f6092018-01-23 19:17:23 +0800260
261 def test_lb_ip4_l3dsr(self):
262 """ Load Balancer IP4 L3DSR """
263 try:
264 self.vapi.cli("lb vip 90.0.0.0/8 encap l3dsr dscp 7")
265 for asid in self.ass:
266 self.vapi.cli("lb as 90.0.0.0/8 10.0.0.%u" % (asid))
267
268 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
269 self.pg_enable_capture(self.pg_interfaces)
270 self.pg_start()
271 self.checkCapture(encap='l3dsr', isv4=True)
272
273 finally:
274 for asid in self.ass:
275 self.vapi.cli("lb as 90.0.0.0/8 10.0.0.%u del" % (asid))
276 self.vapi.cli("lb vip 90.0.0.0/8 encap l3dsr dscp 7 del")
277 self.vapi.cli("test lb flowtable flush")
Hongjun Nid92a0b52018-02-06 23:00:22 +0800278
279 def test_lb_ip4_nat4(self):
280 """ Load Balancer IP4 NAT4 """
281 try:
282 self.vapi.cli("lb vip 90.0.0.0/8 encap nat4"
283 " type clusterip port 3306 target_port 3307")
284 for asid in self.ass:
285 self.vapi.cli("lb as 90.0.0.0/8 10.0.0.%u" % (asid))
286
287 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
288 self.pg_enable_capture(self.pg_interfaces)
289 self.pg_start()
290 self.checkCapture(encap='nat4', isv4=True)
291
292 finally:
293 for asid in self.ass:
294 self.vapi.cli("lb as 90.0.0.0/8 10.0.0.%u del" % (asid))
295 self.vapi.cli("lb vip 90.0.0.0/8 encap nat4"
296 " type clusterip port 3306 target_port 3307 del")
297 self.vapi.cli("test lb flowtable flush")
298
299 def test_lb_ip6_nat6(self):
300 """ Load Balancer IP6 NAT6 """
301 try:
302 self.vapi.cli("lb vip 2001::/16 encap nat6"
303 " type clusterip port 3306 target_port 3307")
304 for asid in self.ass:
305 self.vapi.cli("lb as 2001::/16 2002::%u" % (asid))
306
307 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
308 self.pg_enable_capture(self.pg_interfaces)
309 self.pg_start()
310 self.checkCapture(encap='nat6', isv4=False)
311
312 finally:
313 for asid in self.ass:
314 self.vapi.cli("lb as 2001::/16 2002::%u del" % (asid))
315 self.vapi.cli("lb vip 2001::/16 encap nat6"
316 " type clusterip port 3306 target_port 3307 del")
317 self.vapi.cli("test lb flowtable flush")