blob: fa4900d2b5fa2d4f57d3a9c0eade0f790029c59e [file] [log] [blame]
Pierre Pfisterf588f352016-10-07 16:31:57 +01001import socket
Klement Sekeraf62ae122016-10-11 11:47:09 +02002from logging import *
Pierre Pfisterf588f352016-10-07 16:31:57 +01003
Pierre Pfisterf588f352016-10-07 16:31:57 +01004from scapy.layers.inet import IP, UDP
5from scapy.layers.inet6 import IPv6
Klement Sekeraf62ae122016-10-11 11:47:09 +02006from scapy.layers.l2 import Ether, GRE
7from scapy.packet import Raw
Pierre Pfisterf588f352016-10-07 16:31:57 +01008
Klement Sekeraf62ae122016-10-11 11:47:09 +02009from framework import VppTestCase
10
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
18
19 As stated in comments below, GRE has issues with IPv6.
20 All test cases involving IPv6 are executed, but
21 received packets are not parsed and checked.
22
23"""
24
25
26class TestLB(VppTestCase):
Pierre Pfisterf588f352016-10-07 16:31:57 +010027 """ Load Balancer Test Case """
28
29 @classmethod
30 def setUpClass(cls):
31 super(TestLB, cls).setUpClass()
32
33 cls.ass = range(5)
34 cls.packets = range(100)
35
36 try:
Klement Sekeraf62ae122016-10-11 11:47:09 +020037 cls.create_pg_interfaces(range(2))
38 cls.interfaces = list(cls.pg_interfaces)
Pierre Pfisterf588f352016-10-07 16:31:57 +010039
Klement Sekeraf62ae122016-10-11 11:47:09 +020040 for i in cls.interfaces:
41 i.admin_up()
42 i.config_ip4()
43 i.config_ip6()
44 i.disable_ipv6_ra()
45 i.resolve_arp()
46 i.resolve_ndp()
47 dst4 = socket.inet_pton(socket.AF_INET, "10.0.0.0")
48 dst6 = socket.inet_pton(socket.AF_INET6, "2002::")
49 cls.vapi.ip_add_del_route(dst4, 24, cls.pg1.remote_ip4n)
50 cls.vapi.ip_add_del_route(dst6, 16, cls.pg1.remote_ip6n, is_ipv6=1)
51 cls.vapi.cli("lb conf ip4-src-address 39.40.41.42")
52 cls.vapi.cli("lb conf ip6-src-address 2004::1")
53 except Exception:
Pierre Pfisterf588f352016-10-07 16:31:57 +010054 super(TestLB, cls).tearDownClass()
55 raise
56
57 def tearDown(self):
Klement Sekeraf62ae122016-10-11 11:47:09 +020058 super(TestLB, self).tearDown()
59 if not self.vpp_dead:
60 info(self.vapi.cli("show lb vip verbose"))
Pierre Pfisterf588f352016-10-07 16:31:57 +010061
62 def getIPv4Flow(self, id):
63 return (IP(dst="90.0.%u.%u" % (id / 255, id % 255),
Klement Sekeraf62ae122016-10-11 11:47:09 +020064 src="40.0.%u.%u" % (id / 255, id % 255)) /
Pierre Pfisterf588f352016-10-07 16:31:57 +010065 UDP(sport=10000 + id, dport=20000 + id))
66
67 def getIPv6Flow(self, id):
68 return (IPv6(dst="2001::%u" % (id), src="fd00:f00d:ffff::%u" % (id)) /
Klement Sekeraf62ae122016-10-11 11:47:09 +020069 UDP(sport=10000 + id, dport=20000 + id))
Pierre Pfisterf588f352016-10-07 16:31:57 +010070
Klement Sekeraf62ae122016-10-11 11:47:09 +020071 def generatePackets(self, src_if, isv4):
Matej Klottond6338ab2016-11-10 15:36:19 +010072 self.packet_infos = {}
Pierre Pfisterf588f352016-10-07 16:31:57 +010073 pkts = []
74 for pktid in self.packets:
Klement Sekeraf62ae122016-10-11 11:47:09 +020075 info = self.create_packet_info(src_if.sw_if_index, pktid)
Pierre Pfisterf588f352016-10-07 16:31:57 +010076 payload = self.info_to_payload(info)
77 ip = self.getIPv4Flow(pktid) if isv4 else self.getIPv6Flow(pktid)
Klement Sekeraf62ae122016-10-11 11:47:09 +020078 packet = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
79 ip /
80 Raw(payload))
Pierre Pfisterf588f352016-10-07 16:31:57 +010081 self.extend_packet(packet, 128)
82 info.data = packet.copy()
83 pkts.append(packet)
84 return pkts
85
86 def checkInner(self, gre, isv4):
Klement Sekeraf62ae122016-10-11 11:47:09 +020087 IPver = IP if isv4 else IPv6
Pierre Pfisterf588f352016-10-07 16:31:57 +010088 self.assertEqual(gre.proto, 0x0800 if isv4 else 0x86DD)
89 self.assertEqual(gre.flags, 0)
90 self.assertEqual(gre.version, 0)
Klement Sekeraf62ae122016-10-11 11:47:09 +020091 inner = IPver(str(gre.payload))
92 payload_info = self.payload_to_info(str(inner[Raw]))
Klement Sekerad72fdf52016-11-08 08:48:30 +010093 self.info = self.get_next_packet_info_for_interface2(
94 self.pg0.sw_if_index, payload_info.dst, self.info)
Klement Sekeraf62ae122016-10-11 11:47:09 +020095 self.assertEqual(str(inner), str(self.info.data[IPver]))
Pierre Pfisterf588f352016-10-07 16:31:57 +010096
97 def checkCapture(self, gre4, isv4):
Klement Sekeraf62ae122016-10-11 11:47:09 +020098 out = self.pg0.get_capture()
99 # This check is edited because RA appears in output, maybe disable RA?
100 # self.assertEqual(len(out), 0)
101 self.assertLess(len(out), 20)
102 out = self.pg1.get_capture()
Pierre Pfisterf588f352016-10-07 16:31:57 +0100103 self.assertEqual(len(out), len(self.packets))
104
105 load = [0] * len(self.ass)
106 self.info = None
107 for p in out:
108 try:
109 asid = 0
110 gre = None
111 if gre4:
112 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]
Pierre Pfisterf588f352016-10-07 16:31:57 +0100122 else:
123 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))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100139 self.checkInner(gre, isv4)
140 load[asid] += 1
141 except:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200142 error("Unexpected or invalid packet:")
Pierre Pfisterf588f352016-10-07 16:31:57 +0100143 p.show()
144 raise
145
146 # This is just to roughly check that the balancing algorithm
147 # is not completly biased.
148 for asid in self.ass:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200149 if load[asid] < len(self.packets) / (len(self.ass) * 2):
150 self.log(
151 "ASS is not balanced: load[%d] = %d" % (asid, load[asid]))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100152 raise Exception("Load Balancer algorithm is biased")
153
Pierre Pfisterf588f352016-10-07 16:31:57 +0100154 def test_lb_ip4_gre4(self):
155 """ Load Balancer IP4 GRE4 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200156 try:
157 self.vapi.cli("lb vip 90.0.0.0/8 encap gre4")
158 for asid in self.ass:
159 self.vapi.cli("lb as 90.0.0.0/8 10.0.0.%u" % (asid))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100160
Klement Sekeraf62ae122016-10-11 11:47:09 +0200161 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
162 self.pg_enable_capture(self.pg_interfaces)
163 self.pg_start()
164 self.checkCapture(gre4=True, isv4=True)
Pierre Pfisterf588f352016-10-07 16:31:57 +0100165
Klement Sekeraf62ae122016-10-11 11:47:09 +0200166 finally:
167 for asid in self.ass:
168 self.vapi.cli("lb as 90.0.0.0/8 10.0.0.%u del" % (asid))
169 self.vapi.cli("lb vip 90.0.0.0/8 encap gre4 del")
Pierre Pfisterf588f352016-10-07 16:31:57 +0100170
171 def test_lb_ip6_gre4(self):
172 """ Load Balancer IP6 GRE4 """
173
Klement Sekeraf62ae122016-10-11 11:47:09 +0200174 try:
175 self.vapi.cli("lb vip 2001::/16 encap gre4")
176 for asid in self.ass:
177 self.vapi.cli("lb as 2001::/16 10.0.0.%u" % (asid))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100178
Klement Sekeraf62ae122016-10-11 11:47:09 +0200179 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
180 self.pg_enable_capture(self.pg_interfaces)
181 self.pg_start()
Pierre Pfisterf588f352016-10-07 16:31:57 +0100182
Matej Klottond6338ab2016-11-10 15:36:19 +0100183 self.checkCapture(gre4=True, isv4=False)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200184 finally:
185 for asid in self.ass:
186 self.vapi.cli("lb as 2001::/16 10.0.0.%u del" % (asid))
187 self.vapi.cli("lb vip 2001::/16 encap gre4 del")
Pierre Pfisterf588f352016-10-07 16:31:57 +0100188
189 def test_lb_ip4_gre6(self):
190 """ Load Balancer IP4 GRE6 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200191 try:
192 self.vapi.cli("lb vip 90.0.0.0/8 encap gre6")
193 for asid in self.ass:
194 self.vapi.cli("lb as 90.0.0.0/8 2002::%u" % (asid))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100195
Klement Sekeraf62ae122016-10-11 11:47:09 +0200196 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
197 self.pg_enable_capture(self.pg_interfaces)
198 self.pg_start()
Pierre Pfisterf588f352016-10-07 16:31:57 +0100199
Matej Klottond6338ab2016-11-10 15:36:19 +0100200 self.checkCapture(gre4=False, isv4=True)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200201 finally:
202 for asid in self.ass:
203 self.vapi.cli("lb as 90.0.0.0/8 2002::%u" % (asid))
204 self.vapi.cli("lb vip 90.0.0.0/8 encap gre6 del")
Pierre Pfisterf588f352016-10-07 16:31:57 +0100205
206 def test_lb_ip6_gre6(self):
207 """ Load Balancer IP6 GRE6 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200208 try:
209 self.vapi.cli("lb vip 2001::/16 encap gre6")
210 for asid in self.ass:
211 self.vapi.cli("lb as 2001::/16 2002::%u" % (asid))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100212
Klement Sekeraf62ae122016-10-11 11:47:09 +0200213 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
214 self.pg_enable_capture(self.pg_interfaces)
215 self.pg_start()
Pierre Pfisterf588f352016-10-07 16:31:57 +0100216
Matej Klottond6338ab2016-11-10 15:36:19 +0100217 self.checkCapture(gre4=False, isv4=False)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200218 finally:
219 for asid in self.ass:
220 self.vapi.cli("lb as 2001::/16 2002::%u del" % (asid))
221 self.vapi.cli("lb vip 2001::/16 encap gre6 del")