1 /**
2  * collectd - src/netlink_test.c
3  *
4  * Copyright(c) 2020 Intel Corporation. All rights reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  *
24  * Authors:
25  *   Kamil Wiatrowski <kamilx.wiatrowski@intel.com>
26  **/
27 
28 #define plugin_dispatch_values plugin_dispatch_values_nl_test
29 
30 #include "netlink.c" /* sic */
31 #include "testing.h"
32 
33 #ifdef HAVE_IFLA_VF_STATS
34 static vf_stats_t g_test_res;
35 static char g_instance[512];
36 static int g_type_valid;
37 static void *g_test_payload;
38 static uint16_t g_attr_type;
39 
40 /* mock functions */
plugin_dispatch_values_nl_test(value_list_t const * vl)41 int plugin_dispatch_values_nl_test(value_list_t const *vl) {
42   if (g_instance[0] == '\0')
43     sstrncpy(g_instance, vl->plugin_instance, sizeof(g_instance));
44 
45   if (strcmp("vf_link_info", vl->type) == 0 &&
46       strcmp("vlan", vl->type_instance) == 0)
47     g_test_res.vlan = vl->values[0].gauge;
48 
49   if (strcmp("vf_link_info", vl->type) == 0 &&
50       strcmp("spoofcheck", vl->type_instance) == 0)
51     g_test_res.spoofcheck = vl->values[0].gauge;
52 
53   if (strcmp("vf_link_info", vl->type) == 0 &&
54       strcmp("link_state", vl->type_instance) == 0)
55     g_test_res.link_state = vl->values[0].gauge;
56 
57   if (strcmp("vf_broadcast", vl->type) == 0)
58     g_test_res.broadcast = vl->values[0].derive;
59 
60   if (strcmp("vf_multicast", vl->type) == 0)
61     g_test_res.multicast = vl->values[0].derive;
62 
63   if (strcmp("vf_packets", vl->type) == 0) {
64     g_test_res.rx_packets = vl->values[0].derive;
65     g_test_res.tx_packets = vl->values[1].derive;
66   }
67 
68   if (strcmp("vf_bytes", vl->type) == 0) {
69     g_test_res.rx_bytes = vl->values[0].derive;
70     g_test_res.tx_bytes = vl->values[1].derive;
71   }
72 
73   return 0;
74 }
75 
mnl_attr_type_valid(const struct nlattr * attr,uint16_t maxtype)76 int mnl_attr_type_valid(__attribute__((unused)) const struct nlattr *attr,
77                         __attribute__((unused)) uint16_t maxtype) {
78   return g_type_valid;
79 }
80 
mnl_attr_get_type(const struct nlattr * attr)81 uint16_t mnl_attr_get_type(__attribute__((unused)) const struct nlattr *attr) {
82   return g_attr_type;
83 }
84 
mnl_attr_validate(const struct nlattr * attr,enum mnl_attr_data_type type)85 int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type) {
86   return attr->nla_type == type ? 0 : -1;
87 }
88 
mnl_attr_validate2(const struct nlattr * attr,enum mnl_attr_data_type type,size_t len)89 int mnl_attr_validate2(const struct nlattr *attr, enum mnl_attr_data_type type,
90                        __attribute__((unused)) size_t len) {
91   return attr->nla_type == type ? 0 : -1;
92 }
93 
mnl_attr_get_payload(const struct nlattr * attr)94 void *mnl_attr_get_payload(__attribute__((unused)) const struct nlattr *attr) {
95   return g_test_payload;
96 }
97 #else /* HAVE_IFLA_VF_STATS */
plugin_dispatch_values_nl_test(value_list_t const * vl)98 int plugin_dispatch_values_nl_test(__attribute__((unused))
99                                    value_list_t const *vl) {
100   return 0;
101 }
102 #endif
103 /* end mock functions */
104 
105 #ifdef HAVE_IFLA_VF_STATS
DEF_TEST(plugin_nl_config)106 DEF_TEST(plugin_nl_config) {
107   EXPECT_EQ_INT(0, collect_vf_stats);
108   int ret = ir_config("CollectVFStats", "true");
109   EXPECT_EQ_INT(0, ret);
110   EXPECT_EQ_INT(1, collect_vf_stats);
111   ret = ir_config("CollectVFStats", "0");
112   EXPECT_EQ_INT(0, ret);
113   EXPECT_EQ_INT(0, collect_vf_stats);
114   ret = ir_config("CollectVFStats", "true false");
115   EXPECT_EQ_INT(-1, ret);
116   EXPECT_EQ_INT(0, collect_vf_stats);
117   ret = ir_config("CollectVFStats", "false");
118   EXPECT_EQ_INT(0, ret);
119   EXPECT_EQ_INT(0, collect_vf_stats);
120   ret = ir_config("CollectVFStats", "yes");
121   EXPECT_EQ_INT(0, ret);
122   EXPECT_EQ_INT(1, collect_vf_stats);
123 
124   return 0;
125 }
126 #endif
127 
DEF_TEST(ignorelist_test)128 DEF_TEST(ignorelist_test) {
129   ir_ignorelist_invert = 1;
130   int ret = add_ignorelist("eno1", "interface", NULL);
131   EXPECT_EQ_INT(0, ret);
132   ret = add_ignorelist("eno2", "if_detail", NULL);
133   EXPECT_EQ_INT(0, ret);
134 
135   ret = check_ignorelist("eno1", "interface", NULL);
136   EXPECT_EQ_INT(0, ret);
137   ret = check_ignorelist("eno2", "if_detail", NULL);
138   EXPECT_EQ_INT(0, ret);
139   ret = check_ignorelist("eno1", "if_detail", NULL);
140   EXPECT_EQ_INT(1, ret);
141   ret = check_ignorelist("eno2", "interface", NULL);
142   EXPECT_EQ_INT(1, ret);
143 
144 #if HAVE_REGEX_H
145   ret = add_ignorelist("/^eno[1-3]|^eth[0-2|4]/", "interface", NULL);
146   EXPECT_EQ_INT(0, ret);
147   ret = add_ignorelist("/^ens0[1|3]/", "if_detail", NULL);
148   EXPECT_EQ_INT(0, ret);
149 
150   ret = check_ignorelist("eno1", "interface", NULL);
151   EXPECT_EQ_INT(0, ret);
152   ret = check_ignorelist("eno3", "interface", NULL);
153   EXPECT_EQ_INT(0, ret);
154   ret = check_ignorelist("eth0", "interface", NULL);
155   EXPECT_EQ_INT(0, ret);
156   ret = check_ignorelist("eth1", "interface", NULL);
157   EXPECT_EQ_INT(0, ret);
158   ret = check_ignorelist("eth2", "interface", NULL);
159   EXPECT_EQ_INT(0, ret);
160   ret = check_ignorelist("eth3", "interface", NULL);
161   EXPECT_EQ_INT(1, ret);
162   ret = check_ignorelist("eth4", "interface", NULL);
163   EXPECT_EQ_INT(0, ret);
164 
165   ret = check_ignorelist("ens01", "if_detail", NULL);
166   EXPECT_EQ_INT(0, ret);
167   ret = check_ignorelist("ens02", "if_detail", NULL);
168   EXPECT_EQ_INT(1, ret);
169   ret = check_ignorelist("ens03", "if_detail", NULL);
170   EXPECT_EQ_INT(0, ret);
171 
172   ret = check_ignorelist("eth0", "if_detail", NULL);
173   EXPECT_EQ_INT(1, ret);
174   ret = check_ignorelist("ens01", "interface", NULL);
175   EXPECT_EQ_INT(1, ret);
176 #endif
177 
178   ir_ignorelist_invert = 0;
179   ret = check_ignorelist("eno1", "interface", NULL);
180   EXPECT_EQ_INT(1, ret);
181   ret = check_ignorelist("eno2", "if_detail", NULL);
182   EXPECT_EQ_INT(1, ret);
183   ret = check_ignorelist("abcdf", "if_detail", NULL);
184   EXPECT_EQ_INT(0, ret);
185   ret = check_ignorelist("abcfdf", "interface", NULL);
186   EXPECT_EQ_INT(0, ret);
187 
188 #if HAVE_REGEX_H
189   ret = check_ignorelist("ens03", "if_detail", NULL);
190   EXPECT_EQ_INT(1, ret);
191 #endif
192   ir_ignorelist_invert = 1;
193 
194   ir_ignorelist_t *next = NULL;
195   for (ir_ignorelist_t *i = ir_ignorelist_head; i != NULL; i = next) {
196     next = i->next;
197 #if HAVE_REGEX_H
198     if (i->rdevice != NULL) {
199       regfree(i->rdevice);
200       sfree(i->rdevice);
201     }
202 #endif
203     sfree(i->inst);
204     sfree(i->type);
205     sfree(i->device);
206     sfree(i);
207   }
208   ir_ignorelist_head = NULL;
209 
210   return 0;
211 }
212 
213 #ifdef HAVE_IFLA_VF_STATS
DEF_TEST(vf_submit_test)214 DEF_TEST(vf_submit_test) {
215   const char *test_dev = "eth0";
216   vf_stats_t test_stats;
217   struct ifla_vf_mac test_mac;
218   test_mac.mac[0] = 0x01;
219   test_mac.mac[1] = 0x1a;
220   test_mac.mac[2] = 0x2b;
221   test_mac.mac[3] = 0x3c;
222   test_mac.mac[4] = 0x4d;
223   test_mac.mac[5] = 0x5e;
224   test_mac.vf = 2;
225   test_stats.vf_mac = &test_mac;
226   test_stats.vlan = 100;
227   test_stats.spoofcheck = 1;
228   test_stats.link_state = 2;
229   test_stats.broadcast = 1234;
230   test_stats.multicast = 0;
231   test_stats.rx_packets = 21110;
232   test_stats.tx_packets = 31110;
233   test_stats.rx_bytes = 4294967295;
234   test_stats.tx_bytes = 8;
235 
236   g_instance[0] = '\0';
237   vf_info_submit(test_dev, &test_stats);
238 
239   EXPECT_EQ_STR("eth0_vf2_01:1a:2b:3c:4d:5e", g_instance);
240   EXPECT_EQ_UINT64(100, g_test_res.vlan);
241   EXPECT_EQ_UINT64(1, g_test_res.spoofcheck);
242   EXPECT_EQ_UINT64(2, g_test_res.link_state);
243   EXPECT_EQ_UINT64(1234, g_test_res.broadcast);
244   EXPECT_EQ_UINT64(0, g_test_res.multicast);
245   EXPECT_EQ_UINT64(21110, g_test_res.rx_packets);
246   EXPECT_EQ_UINT64(31110, g_test_res.tx_packets);
247   EXPECT_EQ_UINT64(4294967295, g_test_res.rx_bytes);
248   EXPECT_EQ_UINT64(8, g_test_res.tx_bytes);
249 
250   return 0;
251 }
252 
DEF_TEST(vf_info_attr_cb_test)253 DEF_TEST(vf_info_attr_cb_test) {
254   struct nlattr attr;
255   vf_stats_t test_stats = {0};
256 
257   attr.nla_type = -1;
258   g_type_valid = -1;
259   int ret = vf_info_attr_cb(&attr, &test_stats);
260   EXPECT_EQ_INT(MNL_CB_OK, ret);
261 
262   struct ifla_vf_mac test_mac;
263   g_test_payload = &test_mac;
264   g_type_valid = 0;
265   g_attr_type = IFLA_VF_MAC;
266   ret = vf_info_attr_cb(&attr, &test_stats);
267   EXPECT_EQ_INT(MNL_CB_ERROR, ret);
268 
269   attr.nla_type = MNL_TYPE_UNSPEC;
270   ret = vf_info_attr_cb(&attr, &test_stats);
271   EXPECT_EQ_INT(MNL_CB_OK, ret);
272   EXPECT_EQ_PTR(&test_mac, test_stats.vf_mac);
273 
274   struct ifla_vf_vlan test_vlan = {.vlan = 1024, .qos = 2};
275   g_test_payload = &test_vlan;
276   g_attr_type = IFLA_VF_VLAN;
277   attr.nla_type = -1;
278   ret = vf_info_attr_cb(&attr, &test_stats);
279   EXPECT_EQ_INT(MNL_CB_ERROR, ret);
280 
281   attr.nla_type = MNL_TYPE_UNSPEC;
282   ret = vf_info_attr_cb(&attr, &test_stats);
283   EXPECT_EQ_INT(MNL_CB_OK, ret);
284   EXPECT_EQ_UINT64(1024, test_stats.vlan);
285   EXPECT_EQ_UINT64(2, test_stats.qos);
286 
287   struct ifla_vf_tx_rate test_tx_rate = {.rate = 100};
288   g_test_payload = &test_tx_rate;
289   g_attr_type = IFLA_VF_TX_RATE;
290   attr.nla_type = -1;
291   ret = vf_info_attr_cb(&attr, &test_stats);
292   EXPECT_EQ_INT(MNL_CB_ERROR, ret);
293 
294   attr.nla_type = MNL_TYPE_UNSPEC;
295   ret = vf_info_attr_cb(&attr, &test_stats);
296   EXPECT_EQ_INT(MNL_CB_OK, ret);
297   EXPECT_EQ_UINT64(100, test_stats.txrate);
298 
299   struct ifla_vf_spoofchk test_spoofchk = {.setting = 1};
300   g_test_payload = &test_spoofchk;
301   g_attr_type = IFLA_VF_SPOOFCHK;
302   attr.nla_type = -1;
303   ret = vf_info_attr_cb(&attr, &test_stats);
304   EXPECT_EQ_INT(MNL_CB_ERROR, ret);
305 
306   attr.nla_type = MNL_TYPE_UNSPEC;
307   ret = vf_info_attr_cb(&attr, &test_stats);
308   EXPECT_EQ_INT(MNL_CB_OK, ret);
309   EXPECT_EQ_UINT64(1, test_stats.spoofcheck);
310 
311   struct ifla_vf_link_state test_link_state = {.link_state = 2};
312   g_test_payload = &test_link_state;
313   g_attr_type = IFLA_VF_LINK_STATE;
314   attr.nla_type = -1;
315   ret = vf_info_attr_cb(&attr, &test_stats);
316   EXPECT_EQ_INT(MNL_CB_ERROR, ret);
317 
318   attr.nla_type = MNL_TYPE_UNSPEC;
319   ret = vf_info_attr_cb(&attr, &test_stats);
320   EXPECT_EQ_INT(MNL_CB_OK, ret);
321   EXPECT_EQ_UINT64(2, test_stats.link_state);
322 
323   struct ifla_vf_rate test_rate = {.min_tx_rate = 1000, .max_tx_rate = 2001};
324   g_test_payload = &test_rate;
325   g_attr_type = IFLA_VF_RATE;
326   attr.nla_type = -1;
327   ret = vf_info_attr_cb(&attr, &test_stats);
328   EXPECT_EQ_INT(MNL_CB_ERROR, ret);
329 
330   attr.nla_type = MNL_TYPE_UNSPEC;
331   ret = vf_info_attr_cb(&attr, &test_stats);
332   EXPECT_EQ_INT(MNL_CB_OK, ret);
333   EXPECT_EQ_UINT64(1000, test_stats.min_txrate);
334   EXPECT_EQ_UINT64(2001, test_stats.max_txrate);
335 
336   struct ifla_vf_rss_query_en test_query_en = {.setting = 1};
337   g_test_payload = &test_query_en;
338   g_attr_type = IFLA_VF_RSS_QUERY_EN;
339   attr.nla_type = -1;
340   ret = vf_info_attr_cb(&attr, &test_stats);
341   EXPECT_EQ_INT(MNL_CB_ERROR, ret);
342 
343   attr.nla_type = MNL_TYPE_UNSPEC;
344   ret = vf_info_attr_cb(&attr, &test_stats);
345   EXPECT_EQ_INT(MNL_CB_OK, ret);
346   EXPECT_EQ_UINT64(1, test_stats.rss_query_en);
347 
348   struct ifla_vf_trust test_trust = {.setting = 1};
349   g_test_payload = &test_trust;
350   g_attr_type = IFLA_VF_TRUST;
351   attr.nla_type = -1;
352   ret = vf_info_attr_cb(&attr, &test_stats);
353   EXPECT_EQ_INT(MNL_CB_ERROR, ret);
354 
355   attr.nla_type = MNL_TYPE_UNSPEC;
356   ret = vf_info_attr_cb(&attr, &test_stats);
357   EXPECT_EQ_INT(MNL_CB_OK, ret);
358   EXPECT_EQ_UINT64(1, test_stats.trust);
359 
360   g_attr_type = IFLA_VF_STATS;
361   ret = vf_info_attr_cb(&attr, &test_stats);
362   EXPECT_EQ_INT(MNL_CB_ERROR, ret);
363 
364   return 0;
365 }
366 #endif /* HAVE_IFLA_VF_STATS */
367 
main(void)368 int main(void) {
369 #ifdef HAVE_IFLA_VF_STATS
370   RUN_TEST(plugin_nl_config);
371 #endif
372   RUN_TEST(ignorelist_test);
373 
374 #ifdef HAVE_IFLA_VF_STATS
375   RUN_TEST(vf_submit_test);
376   RUN_TEST(vf_info_attr_cb_test);
377 #endif
378   END_TEST;
379 }
380