Add buffer pointer-to-index and index-to-pointer array functions
[vpp.git] / test / test_kubeproxy.py
1 import socket
2 import unittest
3
4 from scapy.layers.inet import IP, UDP
5 from scapy.layers.inet6 import IPv6
6 from scapy.layers.l2 import Ether
7 from scapy.packet import Raw
8
9 from framework import VppTestCase, running_extended_tests
10 from util import ppp
11
12 """ TestKP is a subclass of VPPTestCase classes.
13
14  TestKP class defines Four NAT test case for:
15   - IP4 to IP4 NAT
16   - IP4 to IP6 NAT
17   - IP6 to IP4 NAT
18   - IP6 to IP6 NAT
19
20 """
21
22
23 class TestKP(VppTestCase):
24     """ Kube-proxy Test Case """
25
26     @classmethod
27     def setUpClass(cls):
28         super(TestKP, cls).setUpClass()
29         cls.pods = range(5)
30         cls.packets = range(5)
31
32         try:
33             cls.create_pg_interfaces(range(2))
34             cls.interfaces = list(cls.pg_interfaces)
35
36             for i in cls.interfaces:
37                 i.admin_up()
38                 i.config_ip4()
39                 i.config_ip6()
40                 i.disable_ipv6_ra()
41                 i.resolve_arp()
42                 i.resolve_ndp()
43             dst4 = socket.inet_pton(socket.AF_INET, "10.0.0.0")
44             dst6 = socket.inet_pton(socket.AF_INET6, "2002::")
45             cls.vapi.ip_add_del_route(dst4, 24, cls.pg1.remote_ip4n)
46             cls.vapi.ip_add_del_route(dst6, 16, cls.pg1.remote_ip6n, is_ipv6=1)
47         except Exception:
48             super(TestKP, cls).tearDownClass()
49             raise
50
51     def tearDown(self):
52         super(TestKP, self).tearDown()
53         if not self.vpp_dead:
54             self.logger.info(self.vapi.cli("show ku vip verbose"))
55
56     def getIPv4Flow(self, id):
57         return (IP(dst="90.0.%u.%u" % (id / 255, id % 255),
58                    src="40.0.%u.%u" % (id / 255, id % 255)) /
59                 UDP(sport=10000 + id, dport=3306))
60
61     def getIPv6Flow(self, id):
62         return (IPv6(dst="2001::%u" % (id), src="fd00:f00d:ffff::%u" % (id)) /
63                 UDP(sport=10000 + id, dport=3306))
64
65     def generatePackets(self, src_if, isv4):
66         self.reset_packet_infos()
67         pkts = []
68         for pktid in self.packets:
69             info = self.create_packet_info(src_if, self.pg1)
70             payload = self.info_to_payload(info)
71             ip = self.getIPv4Flow(pktid) if isv4 else self.getIPv6Flow(pktid)
72             packet = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
73                       ip /
74                       Raw(payload))
75             self.extend_packet(packet, 128)
76             info.data = packet.copy()
77             pkts.append(packet)
78         return pkts
79
80     def checkInner(self, udp):
81         self.assertEqual(udp.dport, 3307)
82
83     def checkCapture(self, nat4, isv4):
84         self.pg0.assert_nothing_captured()
85         out = self.pg1.get_capture(len(self.packets))
86
87         load = [0] * len(self.pods)
88         self.info = None
89         for p in out:
90             try:
91                 podid = 0
92                 udp = None
93                 if nat4:
94                     ip = p[IP]
95                     podid = int(ip.dst.split(".")[3])
96                     self.assertEqual(ip.version, 4)
97                     self.assertEqual(ip.flags, 0)
98                     self.assertEqual(ip.dst, "10.0.0.%u" % podid)
99                     self.assertEqual(ip.proto, 17)
100                     self.assertEqual(len(ip.options), 0)
101                     self.assertGreaterEqual(ip.ttl, 63)
102                     udp = p[UDP]
103                 else:
104                     ip = p[IPv6]
105                     podid = ip.dst.split(":")
106                     podid = podid[len(podid) - 1]
107                     podid = 0 if podid == "" else int(podid)
108                     self.assertEqual(ip.version, 6)
109                     self.assertEqual(ip.tc, 0)
110                     self.assertEqual(ip.fl, 0)
111                     self.assertEqual(
112                         socket.inet_pton(socket.AF_INET6, ip.dst),
113                         socket.inet_pton(socket.AF_INET6, "2002::%u" % podid)
114                     )
115                     self.assertEqual(ip.nh, 17)
116                     self.assertGreaterEqual(ip.hlim, 63)
117                     udp = UDP(str(p[IPv6].payload))
118                     # self.assertEqual(len(ip.options), 0)
119                 self.checkInner(udp)
120                 load[podid] += 1
121             except:
122                 self.logger.error(ppp("Unexpected or invalid packet:", p))
123                 raise
124
125         # This is just to roughly check that the balancing algorithm
126         # is not completly biased.
127         for podid in self.pods:
128             if load[podid] < len(self.packets) / (len(self.pods) * 2):
129                 self.log(
130                     "Pod isn't balanced: load[%d] = %d" % (podid, load[podid]))
131                 raise Exception("Kube-proxy algorithm is biased")
132
133     def test_kp_ip4_nat4(self):
134         """ Kube-proxy NAT44 """
135         try:
136             self.vapi.cli("ku vip 90.0.0.0/8 port 3306 target_port 3307 nat4")
137             for podid in self.pods:
138                 self.vapi.cli("ku pod 90.0.0.0/8 10.0.0.%u" % (podid))
139
140             self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
141             self.pg_enable_capture(self.pg_interfaces)
142             self.pg_start()
143             self.checkCapture(nat4=True, isv4=True)
144
145         finally:
146             for podid in self.pods:
147                 self.vapi.cli("ku pod 90.0.0.0/8 10.0.0.%u del" % (podid))
148             self.vapi.cli("ku vip 90.0.0.0/8 nat4 del")
149             self.vapi.cli("test kube-proxy flowtable flush")
150
151     @unittest.skip("this test is broken")
152     def test_kp_ip6_nat4(self):
153         """ Kube-proxy NAT64 """
154
155         try:
156             self.vapi.cli("ku vip 90.0.0.0/8 port 3306 target_port 3307 nat4")
157             for podid in self.pods:
158                 self.vapi.cli("ku pod 2001::/16 10.0.0.%u" % (podid))
159
160             self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
161             self.pg_enable_capture(self.pg_interfaces)
162             self.pg_start()
163
164             self.checkCapture(nat4=True, isv4=False)
165         finally:
166             for podid in self.pods:
167                 self.vapi.cli("ku pod 2001::/16 10.0.0.%u del" % (podid))
168             self.vapi.cli("ku vip 2001::/16 nat4 del")
169             self.vapi.cli("test kube-proxy flowtable flush")
170
171     @unittest.skip("this test is broken")
172     def test_kp_ip4_nat6(self):
173         """ Kube-proxy NAT46 """
174         try:
175             self.vapi.cli("ku vip 90.0.0.0/8 port 3306 target_port 3307 nat6")
176             for podid in self.pods:
177                 self.vapi.cli("ku pod 90.0.0.0/8 2002::%u" % (podid))
178
179             self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
180             self.pg_enable_capture(self.pg_interfaces)
181             self.pg_start()
182
183             self.checkCapture(nat4=False, isv4=True)
184         finally:
185             for podid in self.pods:
186                 self.vapi.cli("ku pod 90.0.0.0/8 2002::%u del" % (podid))
187             self.vapi.cli("ku vip 90.0.0.0/8 nat6 del")
188             self.vapi.cli("test kube-proxy flowtable flush")
189
190     @unittest.skipUnless(running_extended_tests(), "part of extended tests")
191     def test_kp_ip6_nat6(self):
192         """ Kube-proxy NAT66 """
193         try:
194             self.vapi.cli("ku vip 2001::/16 port 3306 target_port 3307 nat6")
195             for podid in self.pods:
196                 self.vapi.cli("ku pod 2001::/16 2002::%u" % (podid))
197
198             self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
199             self.pg_enable_capture(self.pg_interfaces)
200             self.pg_start()
201
202             self.checkCapture(nat4=False, isv4=False)
203         finally:
204             for podid in self.pods:
205                 self.vapi.cli("ku pod 2001::/16 2002::%u del" % (podid))
206             self.vapi.cli("ku vip 2001::/16 nat6 del")
207             self.vapi.cli("test kube-proxy flowtable flush")