blob: 76fdd6933976bf0046e5bfdb0aad81c078520df8 [file] [log] [blame]
Pierre Pfisterf588f352016-10-07 16:31:57 +01001import socket
Klement Sekeraf62ae122016-10-11 11:47:09 +02002import unittest
3from logging import *
Pierre Pfisterf588f352016-10-07 16:31:57 +01004
Pierre Pfisterf588f352016-10-07 16:31:57 +01005from scapy.layers.inet import IP, UDP
6from scapy.layers.inet6 import IPv6
Klement Sekeraf62ae122016-10-11 11:47:09 +02007from scapy.layers.l2 import Ether, GRE
8from scapy.packet import Raw
Pierre Pfisterf588f352016-10-07 16:31:57 +01009
Klement Sekeraf62ae122016-10-11 11:47:09 +020010from framework import VppTestCase
11
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
19
20 As stated in comments below, GRE has issues with IPv6.
21 All test cases involving IPv6 are executed, but
22 received packets are not parsed and checked.
23
24"""
25
26
27class TestLB(VppTestCase):
Pierre Pfisterf588f352016-10-07 16:31:57 +010028 """ Load Balancer Test Case """
29
30 @classmethod
31 def setUpClass(cls):
32 super(TestLB, cls).setUpClass()
33
34 cls.ass = range(5)
35 cls.packets = range(100)
36
37 try:
Klement Sekeraf62ae122016-10-11 11:47:09 +020038 cls.create_pg_interfaces(range(2))
39 cls.interfaces = list(cls.pg_interfaces)
Pierre Pfisterf588f352016-10-07 16:31:57 +010040
Klement Sekeraf62ae122016-10-11 11:47:09 +020041 for i in cls.interfaces:
42 i.admin_up()
43 i.config_ip4()
44 i.config_ip6()
45 i.disable_ipv6_ra()
46 i.resolve_arp()
47 i.resolve_ndp()
48 dst4 = socket.inet_pton(socket.AF_INET, "10.0.0.0")
49 dst6 = socket.inet_pton(socket.AF_INET6, "2002::")
50 cls.vapi.ip_add_del_route(dst4, 24, cls.pg1.remote_ip4n)
51 cls.vapi.ip_add_del_route(dst6, 16, cls.pg1.remote_ip6n, is_ipv6=1)
52 cls.vapi.cli("lb conf ip4-src-address 39.40.41.42")
53 cls.vapi.cli("lb conf ip6-src-address 2004::1")
54 except Exception:
Pierre Pfisterf588f352016-10-07 16:31:57 +010055 super(TestLB, cls).tearDownClass()
56 raise
57
58 def tearDown(self):
Klement Sekeraf62ae122016-10-11 11:47:09 +020059 super(TestLB, self).tearDown()
60 if not self.vpp_dead:
61 info(self.vapi.cli("show lb vip verbose"))
Pierre Pfisterf588f352016-10-07 16:31:57 +010062
63 def getIPv4Flow(self, id):
64 return (IP(dst="90.0.%u.%u" % (id / 255, id % 255),
Klement Sekeraf62ae122016-10-11 11:47:09 +020065 src="40.0.%u.%u" % (id / 255, id % 255)) /
Pierre Pfisterf588f352016-10-07 16:31:57 +010066 UDP(sport=10000 + id, dport=20000 + id))
67
68 def getIPv6Flow(self, id):
69 return (IPv6(dst="2001::%u" % (id), src="fd00:f00d:ffff::%u" % (id)) /
Klement Sekeraf62ae122016-10-11 11:47:09 +020070 UDP(sport=10000 + id, dport=20000 + id))
Pierre Pfisterf588f352016-10-07 16:31:57 +010071
Klement Sekeraf62ae122016-10-11 11:47:09 +020072 def generatePackets(self, src_if, isv4):
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]))
Pierre Pfisterf588f352016-10-07 16:31:57 +010093 packet_index = payload_info.index
Klement Sekeraf62ae122016-10-11 11:47:09 +020094 self.info = self.get_next_packet_info_for_interface2(self.pg0.sw_if_index,
95 payload_info.dst,
96 self.info)
97 self.assertEqual(str(inner), str(self.info.data[IPver]))
Pierre Pfisterf588f352016-10-07 16:31:57 +010098
99 def checkCapture(self, gre4, isv4):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200100 out = self.pg0.get_capture()
101 # This check is edited because RA appears in output, maybe disable RA?
102 # self.assertEqual(len(out), 0)
103 self.assertLess(len(out), 20)
104 out = self.pg1.get_capture()
Pierre Pfisterf588f352016-10-07 16:31:57 +0100105 self.assertEqual(len(out), len(self.packets))
106
107 load = [0] * len(self.ass)
108 self.info = None
109 for p in out:
110 try:
111 asid = 0
112 gre = None
113 if gre4:
114 ip = p[IP]
Pierre Pfisterf588f352016-10-07 16:31:57 +0100115 asid = int(ip.dst.split(".")[3])
116 self.assertEqual(ip.version, 4)
117 self.assertEqual(ip.flags, 0)
118 self.assertEqual(ip.src, "39.40.41.42")
119 self.assertEqual(ip.dst, "10.0.0.%u" % asid)
120 self.assertEqual(ip.proto, 47)
121 self.assertEqual(len(ip.options), 0)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200122 self.assertGreaterEqual(ip.ttl, 64)
123 gre = p[GRE]
Pierre Pfisterf588f352016-10-07 16:31:57 +0100124 else:
125 ip = p[IPv6]
Pierre Pfisterf588f352016-10-07 16:31:57 +0100126 asid = ip.dst.split(":")
127 asid = asid[len(asid) - 1]
Klement Sekeraf62ae122016-10-11 11:47:09 +0200128 asid = 0 if asid == "" else int(asid)
Pierre Pfisterf588f352016-10-07 16:31:57 +0100129 self.assertEqual(ip.version, 6)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200130 self.assertEqual(ip.tc, 0)
131 self.assertEqual(ip.fl, 0)
132 self.assertEqual(ip.src, "2004::1")
133 self.assertEqual(
134 socket.inet_pton(socket.AF_INET6, ip.dst),
135 socket.inet_pton(socket.AF_INET6, "2002::%u" % asid)
136 )
137 self.assertEqual(ip.nh, 47)
138 self.assertGreaterEqual(ip.hlim, 64)
139 # self.assertEqual(len(ip.options), 0)
140 gre = GRE(str(p[IPv6].payload))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100141 self.checkInner(gre, isv4)
142 load[asid] += 1
143 except:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200144 error("Unexpected or invalid packet:")
Pierre Pfisterf588f352016-10-07 16:31:57 +0100145 p.show()
146 raise
147
148 # This is just to roughly check that the balancing algorithm
149 # is not completly biased.
150 for asid in self.ass:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200151 if load[asid] < len(self.packets) / (len(self.ass) * 2):
152 self.log(
153 "ASS is not balanced: load[%d] = %d" % (asid, load[asid]))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100154 raise Exception("Load Balancer algorithm is biased")
155
Pierre Pfisterf588f352016-10-07 16:31:57 +0100156 def test_lb_ip4_gre4(self):
157 """ Load Balancer IP4 GRE4 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200158 try:
159 self.vapi.cli("lb vip 90.0.0.0/8 encap gre4")
160 for asid in self.ass:
161 self.vapi.cli("lb as 90.0.0.0/8 10.0.0.%u" % (asid))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100162
Klement Sekeraf62ae122016-10-11 11:47:09 +0200163 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
164 self.pg_enable_capture(self.pg_interfaces)
165 self.pg_start()
166 self.checkCapture(gre4=True, isv4=True)
Pierre Pfisterf588f352016-10-07 16:31:57 +0100167
Klement Sekeraf62ae122016-10-11 11:47:09 +0200168 finally:
169 for asid in self.ass:
170 self.vapi.cli("lb as 90.0.0.0/8 10.0.0.%u del" % (asid))
171 self.vapi.cli("lb vip 90.0.0.0/8 encap gre4 del")
Pierre Pfisterf588f352016-10-07 16:31:57 +0100172
173 def test_lb_ip6_gre4(self):
174 """ Load Balancer IP6 GRE4 """
175
Klement Sekeraf62ae122016-10-11 11:47:09 +0200176 try:
177 self.vapi.cli("lb vip 2001::/16 encap gre4")
178 for asid in self.ass:
179 self.vapi.cli("lb as 2001::/16 10.0.0.%u" % (asid))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100180
Klement Sekeraf62ae122016-10-11 11:47:09 +0200181 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
182 self.pg_enable_capture(self.pg_interfaces)
183 self.pg_start()
Pierre Pfisterf588f352016-10-07 16:31:57 +0100184
Klement Sekeraf62ae122016-10-11 11:47:09 +0200185 self.checkCapture(gre4=True, isv4=False)
186 finally:
187 for asid in self.ass:
188 self.vapi.cli("lb as 2001::/16 10.0.0.%u del" % (asid))
189 self.vapi.cli("lb vip 2001::/16 encap gre4 del")
Pierre Pfisterf588f352016-10-07 16:31:57 +0100190
191 def test_lb_ip4_gre6(self):
192 """ Load Balancer IP4 GRE6 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200193 try:
194 self.vapi.cli("lb vip 90.0.0.0/8 encap gre6")
195 for asid in self.ass:
196 self.vapi.cli("lb as 90.0.0.0/8 2002::%u" % (asid))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100197
Klement Sekeraf62ae122016-10-11 11:47:09 +0200198 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
199 self.pg_enable_capture(self.pg_interfaces)
200 self.pg_start()
Pierre Pfisterf588f352016-10-07 16:31:57 +0100201
Klement Sekeraf62ae122016-10-11 11:47:09 +0200202 # Scapy fails parsing GRE over IPv6.
203 # This check is therefore disabled for now.
204 # One can easily patch layers/inet6.py to fix the issue.
205 self.checkCapture(gre4=False, isv4=True)
206 finally:
207 for asid in self.ass:
208 self.vapi.cli("lb as 90.0.0.0/8 2002::%u" % (asid))
209 self.vapi.cli("lb vip 90.0.0.0/8 encap gre6 del")
Pierre Pfisterf588f352016-10-07 16:31:57 +0100210
211 def test_lb_ip6_gre6(self):
212 """ Load Balancer IP6 GRE6 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200213 try:
214 self.vapi.cli("lb vip 2001::/16 encap gre6")
215 for asid in self.ass:
216 self.vapi.cli("lb as 2001::/16 2002::%u" % (asid))
Pierre Pfisterf588f352016-10-07 16:31:57 +0100217
Klement Sekeraf62ae122016-10-11 11:47:09 +0200218 self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
219 self.pg_enable_capture(self.pg_interfaces)
220 self.pg_start()
Pierre Pfisterf588f352016-10-07 16:31:57 +0100221
Klement Sekeraf62ae122016-10-11 11:47:09 +0200222 self.checkCapture(gre4=False, isv4=False)
223 finally:
224 for asid in self.ass:
225 self.vapi.cli("lb as 2001::/16 2002::%u del" % (asid))
226 self.vapi.cli("lb vip 2001::/16 encap gre6 del")