blob: 3e7f5e13faf78fd083e396b6f1c322bdb16180e7 [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
4from 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
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:
Klement Sekera7bb873a2016-11-18 07:38:42 +010060 self.logger.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 Sekera7bb873a2016-11-18 07:38:42 +0100142 self.logger.error(ppp("Unexpected or invalid packet:", p))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100143 raise
144
145 # This is just to roughly check that the balancing algorithm
146 # is not completly biased.
147 for asid in self.ass:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200148 if load[asid] < len(self.packets) / (len(self.ass) * 2):
149 self.log(
150 "ASS is not balanced: load[%d] = %d" % (asid, load[asid]))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100151 raise Exception("Load Balancer algorithm is biased")
152
Pierre Pfisterf588f352016-10-07 16:31:57 +0100153 def test_lb_ip4_gre4(self):
154 """ Load Balancer IP4 GRE4 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200155 try:
156 self.vapi.cli("lb vip 90.0.0.0/8 encap gre4")
157 for asid in self.ass:
158 self.vapi.cli("lb as 90.0.0.0/8 10.0.0.%u" % (asid))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100159
Klement Sekeraf62ae122016-10-11 11:47:09 +0200160 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
161 self.pg_enable_capture(self.pg_interfaces)
162 self.pg_start()
163 self.checkCapture(gre4=True, isv4=True)
Pierre Pfisterf588f352016-10-07 16:31:57 +0100164
Klement Sekeraf62ae122016-10-11 11:47:09 +0200165 finally:
166 for asid in self.ass:
167 self.vapi.cli("lb as 90.0.0.0/8 10.0.0.%u del" % (asid))
168 self.vapi.cli("lb vip 90.0.0.0/8 encap gre4 del")
Pierre Pfisterf588f352016-10-07 16:31:57 +0100169
170 def test_lb_ip6_gre4(self):
171 """ Load Balancer IP6 GRE4 """
172
Klement Sekeraf62ae122016-10-11 11:47:09 +0200173 try:
174 self.vapi.cli("lb vip 2001::/16 encap gre4")
175 for asid in self.ass:
176 self.vapi.cli("lb as 2001::/16 10.0.0.%u" % (asid))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100177
Klement Sekeraf62ae122016-10-11 11:47:09 +0200178 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
179 self.pg_enable_capture(self.pg_interfaces)
180 self.pg_start()
Pierre Pfisterf588f352016-10-07 16:31:57 +0100181
Matej Klottond6338ab2016-11-10 15:36:19 +0100182 self.checkCapture(gre4=True, isv4=False)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200183 finally:
184 for asid in self.ass:
185 self.vapi.cli("lb as 2001::/16 10.0.0.%u del" % (asid))
186 self.vapi.cli("lb vip 2001::/16 encap gre4 del")
Pierre Pfisterf588f352016-10-07 16:31:57 +0100187
188 def test_lb_ip4_gre6(self):
189 """ Load Balancer IP4 GRE6 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200190 try:
191 self.vapi.cli("lb vip 90.0.0.0/8 encap gre6")
192 for asid in self.ass:
193 self.vapi.cli("lb as 90.0.0.0/8 2002::%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()
Pierre Pfisterf588f352016-10-07 16:31:57 +0100198
Matej Klottond6338ab2016-11-10 15:36:19 +0100199 self.checkCapture(gre4=False, isv4=True)
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 2002::%u" % (asid))
203 self.vapi.cli("lb vip 90.0.0.0/8 encap gre6 del")
Pierre Pfisterf588f352016-10-07 16:31:57 +0100204
205 def test_lb_ip6_gre6(self):
206 """ Load Balancer IP6 GRE6 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200207 try:
208 self.vapi.cli("lb vip 2001::/16 encap gre6")
209 for asid in self.ass:
210 self.vapi.cli("lb as 2001::/16 2002::%u" % (asid))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100211
Klement Sekeraf62ae122016-10-11 11:47:09 +0200212 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
213 self.pg_enable_capture(self.pg_interfaces)
214 self.pg_start()
Pierre Pfisterf588f352016-10-07 16:31:57 +0100215
Matej Klottond6338ab2016-11-10 15:36:19 +0100216 self.checkCapture(gre4=False, isv4=False)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200217 finally:
218 for asid in self.ass:
219 self.vapi.cli("lb as 2001::/16 2002::%u del" % (asid))
220 self.vapi.cli("lb vip 2001::/16 encap gre6 del")