make test: fix missing log/packet messages
[vpp.git] / test / test_lb.py
1 import socket
2
3 from scapy.layers.inet import IP, UDP
4 from scapy.layers.inet6 import IPv6
5 from scapy.layers.l2 import Ether, GRE
6 from scapy.packet import Raw
7
8 from framework import VppTestCase
9 from util import ppp
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
26 class TestLB(VppTestCase):
27     """ 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:
37             cls.create_pg_interfaces(range(2))
38             cls.interfaces = list(cls.pg_interfaces)
39
40             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:
54             super(TestLB, cls).tearDownClass()
55             raise
56
57     def tearDown(self):
58         super(TestLB, self).tearDown()
59         if not self.vpp_dead:
60             self.logger.info(self.vapi.cli("show lb vip verbose"))
61
62     def getIPv4Flow(self, id):
63         return (IP(dst="90.0.%u.%u" % (id / 255, id % 255),
64                    src="40.0.%u.%u" % (id / 255, id % 255)) /
65                 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)) /
69                 UDP(sport=10000 + id, dport=20000 + id))
70
71     def generatePackets(self, src_if, isv4):
72         self.packet_infos = {}
73         pkts = []
74         for pktid in self.packets:
75             info = self.create_packet_info(src_if.sw_if_index, pktid)
76             payload = self.info_to_payload(info)
77             ip = self.getIPv4Flow(pktid) if isv4 else self.getIPv6Flow(pktid)
78             packet = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
79                       ip /
80                       Raw(payload))
81             self.extend_packet(packet, 128)
82             info.data = packet.copy()
83             pkts.append(packet)
84         return pkts
85
86     def checkInner(self, gre, isv4):
87         IPver = IP if isv4 else IPv6
88         self.assertEqual(gre.proto, 0x0800 if isv4 else 0x86DD)
89         self.assertEqual(gre.flags, 0)
90         self.assertEqual(gre.version, 0)
91         inner = IPver(str(gre.payload))
92         payload_info = self.payload_to_info(str(inner[Raw]))
93         self.info = self.get_next_packet_info_for_interface2(
94             self.pg0.sw_if_index, payload_info.dst, self.info)
95         self.assertEqual(str(inner), str(self.info.data[IPver]))
96
97     def checkCapture(self, gre4, isv4):
98         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()
103         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]
113                     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)
120                     self.assertGreaterEqual(ip.ttl, 64)
121                     gre = p[GRE]
122                 else:
123                     ip = p[IPv6]
124                     asid = ip.dst.split(":")
125                     asid = asid[len(asid) - 1]
126                     asid = 0 if asid == "" else int(asid)
127                     self.assertEqual(ip.version, 6)
128                     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))
139                 self.checkInner(gre, isv4)
140                 load[asid] += 1
141             except:
142                 self.logger.error(ppp("Unexpected or invalid packet:", p))
143                 raise
144
145         # This is just to roughly check that the balancing algorithm
146         # is not completly biased.
147         for asid in self.ass:
148             if load[asid] < len(self.packets) / (len(self.ass) * 2):
149                 self.log(
150                     "ASS is not balanced: load[%d] = %d" % (asid, load[asid]))
151                 raise Exception("Load Balancer algorithm is biased")
152
153     def test_lb_ip4_gre4(self):
154         """ Load Balancer IP4 GRE4 """
155         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))
159
160             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)
164
165         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")
169
170     def test_lb_ip6_gre4(self):
171         """ Load Balancer IP6 GRE4 """
172
173         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))
177
178             self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
179             self.pg_enable_capture(self.pg_interfaces)
180             self.pg_start()
181
182             self.checkCapture(gre4=True, isv4=False)
183         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")
187
188     def test_lb_ip4_gre6(self):
189         """ Load Balancer IP4 GRE6 """
190         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))
194
195             self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
196             self.pg_enable_capture(self.pg_interfaces)
197             self.pg_start()
198
199             self.checkCapture(gre4=False, isv4=True)
200         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")
204
205     def test_lb_ip6_gre6(self):
206         """ Load Balancer IP6 GRE6 """
207         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))
211
212             self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
213             self.pg_enable_capture(self.pg_interfaces)
214             self.pg_start()
215
216             self.checkCapture(gre4=False, isv4=False)
217         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")