stats: fix memory leaks
[vpp.git] / test / test_stats_client.py
1 #!/usr/bin/env python3
2
3 import unittest
4 import psutil
5 from vpp_papi.vpp_stats import VPPStats
6
7 from framework import tag_fixme_vpp_workers
8 from framework import VppTestCase, VppTestRunner
9 from scapy.layers.l2 import Ether
10 from scapy.layers.inet import IP
11
12
13 @tag_fixme_vpp_workers
14 class StatsClientTestCase(VppTestCase):
15     """Test Stats Client"""
16
17     @classmethod
18     def setUpClass(cls):
19         super(StatsClientTestCase, cls).setUpClass()
20
21     @classmethod
22     def tearDownClass(cls):
23         super(StatsClientTestCase, cls).tearDownClass()
24
25     @classmethod
26     def setUpConstants(cls):
27         cls.extra_vpp_statseg_config = "per-node-counters on"
28         cls.extra_vpp_statseg_config += "update-interval 0.05"
29         super(StatsClientTestCase, cls).setUpConstants()
30
31     def test_set_errors(self):
32         """Test set errors"""
33         self.assertEqual(self.statistics.set_errors(), {})
34         self.assertEqual(
35             self.statistics.get_counter('/err/ethernet-input/no error'), [0])
36
37     def test_client_fd_leak(self):
38         """Test file descriptor count - VPP-1486"""
39
40         cls = self.__class__
41         p = psutil.Process()
42         initial_fds = p.num_fds()
43
44         for _ in range(100):
45             stats = VPPStats(socketname=cls.get_stats_sock_path())
46             stats.disconnect()
47
48         ending_fds = p.num_fds()
49         self.assertEqual(initial_fds, ending_fds,
50                          "initial client side file descriptor count: %s "
51                          "is not equal to "
52                          "ending client side file descriptor count: %s" % (
53                              initial_fds, ending_fds))
54
55     def test_symlink_values(self):
56         """Test symlinks reported values"""
57         self.create_pg_interfaces(range(2))
58
59         for i in self.pg_interfaces:
60             i.admin_up()
61             i.config_ip4()
62             i.resolve_arp()
63
64         p = list()
65         for i in range(5):
66             packet = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
67                       IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4))
68             p.append(packet)
69
70         self.send_and_expect(self.pg0, p, self.pg1)
71         pg1_tx = self.statistics.get_counter('/interfaces/pg1/tx')
72         if_tx = self.statistics.get_counter('/if/tx')
73
74         self.assertEqual(pg1_tx[0]['bytes'],
75                          if_tx[0][self.pg1.sw_if_index]['bytes'])
76         for i in self.pg_interfaces:
77             i.unconfig()
78             i.admin_down()
79
80     def test_symlink_add_del_interfaces(self):
81         """Test symlinks when adding and deleting interfaces"""
82         # We first create and delete interfaces
83         self.create_loopback_interfaces(1)
84         self.create_pg_interfaces(range(1))
85         self.loop0.remove_vpp_config()
86         self.create_pg_interfaces(range(2))
87
88         for i in self.pg_interfaces:
89             i.admin_up()
90             i.config_ip4()
91             i.resolve_arp()
92
93         p = list()
94         bytes_to_send = 0
95         for i in range(5):
96             packet = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
97                       IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4))
98             bytes_to_send += len(packet)
99             p.append(packet)
100
101         tx_before_sending = self.statistics.get_counter('/interfaces/pg1/tx')
102         rx_before_sending = self.statistics.get_counter('/interfaces/pg0/rx')
103         self.send_and_expect(self.pg0, p, self.pg1)
104         tx = self.statistics.get_counter('/interfaces/pg1/tx')
105         rx = self.statistics.get_counter('/interfaces/pg0/rx')
106
107         # We wait for nodes symlinks to update (interfaces created/deleted).
108         # ... and packets to be sent
109         self.sleep(0.1)
110         vectors = self.statistics.get_counter('/nodes/pg1-tx/vectors')
111
112         self.assertEqual(tx[0]['bytes'] - tx_before_sending[0]['bytes'],
113                          bytes_to_send)
114         self.assertEqual(tx[0]['packets'] - tx_before_sending[0]['packets'],
115                          5)
116         self.assertEqual(rx[0]['bytes'] - rx_before_sending[0]['bytes'],
117                          bytes_to_send)
118         self.assertEqual(rx[0]['packets'] - rx_before_sending[0]['packets'],
119                          5)
120         self.assertEqual(vectors[0], rx[0]['packets'])
121
122         for i in self.pg_interfaces:
123             i.unconfig()
124             i.admin_down()
125
126     def test_index_consistency(self):
127         """Test index consistency despite changes in the stats"""
128         d = self.statistics.ls(['/if/names'])
129         self.create_loopback_interfaces(10)
130         for i in range(10):
131             try:
132                 s = self.statistics.dump(d)
133                 break
134             except:
135                 pass
136         k, v = s.popitem()
137         self.assertEqual(len(v), 11)
138
139         for i in self.lo_interfaces:
140             i.remove_vpp_config()
141
142     @unittest.skip("Manual only")
143     def test_mem_leak(self):
144         def loop():
145             print('Running loop')
146             for i in range(50):
147                 rv = self.vapi.papi.tap_create_v2(id=i, use_random_mac=1)
148                 self.assertEqual(rv.retval, 0)
149                 rv = self.vapi.papi.tap_delete_v2(sw_if_index=rv.sw_if_index)
150                 self.assertEqual(rv.retval, 0)
151
152         before = self.statistics.get_counter('/mem/statseg/used')
153         loop()
154         self.vapi.cli("memory-trace on stats-segment")
155         for j in range(100):
156             loop()
157         print(self.vapi.cli("show memory stats-segment verbose"))
158         print('AFTER', before,
159               self.statistics.get_counter('/mem/statseg/used'))
160
161
162 if __name__ == '__main__':
163     unittest.main(testRunner=VppTestRunner)