1 /* SPDX-License-Identifier: LGPL-2.1-only */
2
3 #ifndef __NL_TEST_UTIL_H__
4 #define __NL_TEST_UTIL_H__
5
6 #include <sys/stat.h>
7 #include <check.h>
8
9 #include <netlink/object.h>
10 #include <netlink/cache.h>
11
12 #include "base/nl-base-utils.h"
13 #include "nl-aux-core/nl-core.h"
14 #include "nl-aux-route/nl-route.h"
15
16 /*****************************************************************************/
17
_nltst_strfreev(char ** strv)18 static inline void _nltst_strfreev(char **strv)
19 {
20 size_t i;
21
22 if (strv) {
23 for (i = 0; strv[i]; i++)
24 free(strv[i]);
25 free(strv);
26 }
27 }
28
29 #define _nltst_auto_strfreev _nl_auto(_nltst_auto_strfreev_fcn)
30 _NL_AUTO_DEFINE_FCN_TYPED0(char **, _nltst_auto_strfreev_fcn, _nltst_strfreev);
31
32 /*****************************************************************************/
33
34 #ifndef ck_assert_ptr_nonnull
35 #define ck_assert_ptr_nonnull(ptr) ck_assert(ptr)
36 #endif
37
38 #ifndef ck_assert_pstr_ne
39 #define ck_assert_pstr_ne(a, b) \
40 do { \
41 const char *_a = (a); \
42 const char *_b = (b); \
43 \
44 ck_assert(!(_a == _b || (_a && _b && strcmp(_a, _b) == 0))); \
45 } while (0)
46 #endif
47
48 #ifndef ck_assert_ptr_null
49 #define ck_assert_ptr_null(ptr) ck_assert(!(ptr))
50 #endif
51
52 /*****************************************************************************/
53
54 #define __nltst_assert_nonnull(uniq, x) \
55 ({ \
56 typeof(x) _NL_UNIQ_T(_x, uniq) = (x); \
57 \
58 ck_assert_ptr_nonnull(_NL_UNIQ_T(_x, uniq)); \
59 \
60 _NL_UNIQ_T(_x, uniq); \
61 })
62
63 #define _nltst_assert_nonnull(x) __nltst_assert_nonnull(_NL_UNIQ, x)
64
_nltst_strdup(const char * str)65 static inline char *_nltst_strdup(const char *str)
66 {
67 return str ? _nltst_assert_nonnull(strdup(str)) : NULL;
68 }
69
70 /*****************************************************************************/
71
72 #define __nltst_sprintf_arr(uniq, arr, fmt, ...) \
73 ({ \
74 char *const _NL_UNIQ_T(arr, uniq) = (arr); \
75 int _NL_UNIQ_T(c, uniq); \
76 \
77 _NL_STATIC_ASSERT(sizeof(arr) > \
78 sizeof(_NL_UNIQ_T(arr, uniq))); \
79 \
80 _NL_UNIQ_T(c, uniq) = snprintf(_NL_UNIQ_T(arr, uniq), \
81 sizeof(arr), fmt, \
82 ##__VA_ARGS__); \
83 \
84 ck_assert_int_lt(_NL_UNIQ_T(c, uniq), sizeof(arr)); \
85 \
86 _NL_UNIQ_T(arr, uniq); \
87 })
88
89 #define _nltst_sprintf_arr(arr, fmt, ...) \
90 __nltst_sprintf_arr(_NL_UNIQ, arr, fmt, ##__VA_ARGS__)
91
92 /*****************************************************************************/
93
94 void _nltst_get_urandom(void *ptr, size_t len);
95
96 uint32_t _nltst_rand_u32(void);
97
_nltst_rand_u32_range(uint32_t n)98 static inline uint32_t _nltst_rand_u32_range(uint32_t n)
99 {
100 uint32_t rem;
101 uint32_t i;
102
103 if (n == 0)
104 return _nltst_rand_u32();
105 if (n == 1)
106 return 0;
107
108 rem = UINT32_MAX % n;
109 for (;;) {
110 i = _nltst_rand_u32();
111 if (i < (UINT32_MAX - rem))
112 return i % n;
113 }
114 }
115
_nltst_rand_bool(void)116 static inline bool _nltst_rand_bool(void)
117 {
118 return _nltst_rand_u32() % 2 == 0;
119 }
120
121 #define _nltst_rand_select(a, ...) \
122 ({ \
123 const typeof(a) _lst[] = { (a), ##__VA_ARGS__ }; \
124 \
125 _lst[_nltst_rand_u32_range(_NL_N_ELEMENTS(_lst))]; \
126 })
127
128 /*****************************************************************************/
129
130 #define _nltst_assert(expr) \
131 ({ \
132 typeof(expr) _expr = (expr); \
133 \
134 if (!_expr) { \
135 ck_assert_msg(0, "assert(%s) failed", #expr); \
136 } \
137 _expr; \
138 })
139
140 #define _nltst_assert_errno(expr) \
141 do { \
142 if (expr) { \
143 } else { \
144 const int _errno = (errno); \
145 \
146 ck_assert_msg(0, "assert(%s) failed (errno=%d, %s)", \
147 #expr, _errno, strerror(_errno)); \
148 } \
149 } while (0)
150
151 #define _nltst_assert_retcode(expr) \
152 do { \
153 const int _r = (expr); \
154 \
155 if (_r < 0) { \
156 ck_assert_msg( \
157 0, "command(%s) failed with return code %d", \
158 #expr, _r); \
159 } \
160 if (_r > 0) { \
161 ck_assert_msg( \
162 0, \
163 "command(%s) has unexpected positive return code %d", \
164 #expr, _r); \
165 } \
166 } while (0)
167
168 #define _nltst_close(fd) \
169 do { \
170 int _r; \
171 \
172 _r = _nl_close((fd)); \
173 _nltst_assert_errno(_r == 0); \
174 } while (0)
175
176 #define _nltst_fclose(f) \
177 do { \
178 int _r; \
179 \
180 _r = fclose((f)); \
181 _nltst_assert_errno(_r == 0); \
182 } while (0)
183
184 void _nltst_assert_link_exists_full(const char *ifname, bool exists);
185
186 #define _nltst_assert_link_exists(ifname) \
187 _nltst_assert_link_exists_full((ifname), true)
188
189 #define _nltst_assert_link_not_exists(ifname) \
190 _nltst_assert_link_exists_full((ifname), false)
191
192 /*****************************************************************************/
193
194 typedef union {
195 in_addr_t addr4;
196 struct in_addr a4;
197 struct in6_addr a6;
198 } NLTstIPAddr;
199
_nltst_inet_ntop(int addr_family,const void * addr,char buf[static INET_ADDRSTRLEN])200 static inline char *_nltst_inet_ntop(int addr_family, const void *addr,
201 char buf[static INET_ADDRSTRLEN])
202 {
203 char *r;
204
205 ck_assert(addr_family == AF_INET || addr_family == AF_INET6);
206 ck_assert(addr);
207
208 r = (char *)inet_ntop(addr_family, addr, buf,
209 (addr_family == AF_INET) ? INET_ADDRSTRLEN :
210 INET6_ADDRSTRLEN);
211 ck_assert_ptr_eq(r, buf);
212 ck_assert_int_lt(strlen(r), (addr_family == AF_INET) ?
213 INET_ADDRSTRLEN :
214 INET6_ADDRSTRLEN);
215 return r;
216 }
217
_nltst_inet_ntop_dup(int addr_family,const void * addr)218 static inline char *_nltst_inet_ntop_dup(int addr_family, const void *addr)
219 {
220 return (char *)_nltst_inet_ntop(addr_family, addr,
221 malloc((addr_family == AF_INET) ?
222 INET_ADDRSTRLEN :
223 INET6_ADDRSTRLEN));
224 }
225
_nltst_inet_pton(int addr_family,const char * str,int * out_addr_family,void * out_addr)226 static inline bool _nltst_inet_pton(int addr_family, const char *str,
227 int *out_addr_family, void *out_addr)
228 {
229 NLTstIPAddr a;
230 int r;
231
232 ck_assert(addr_family == AF_UNSPEC || addr_family == AF_INET ||
233 addr_family == AF_INET6);
234
235 /* when requesting @out_addr, then the addr-family must either be
236 * pre-determined or requested too. */
237 ck_assert(!out_addr || out_addr_family || addr_family != AF_UNSPEC);
238
239 if (!str)
240 return false;
241
242 if (addr_family == AF_UNSPEC)
243 addr_family = strchr(str, ':') ? AF_INET6 : AF_INET;
244
245 r = inet_pton(addr_family, str, &a);
246 if (r != 1)
247 return false;
248
249 if (out_addr) {
250 memcpy(out_addr, &a,
251 addr_family == AF_INET ? sizeof(in_addr_t) :
252 sizeof(struct in6_addr));
253 }
254 if (out_addr_family)
255 *out_addr_family = addr_family;
256
257 return true;
258 }
259
_nltst_inet_valid(int addr_family,const char * addr)260 static inline bool _nltst_inet_valid(int addr_family, const char *addr)
261 {
262 return _nltst_inet_pton(addr_family, addr, NULL, NULL);
263 }
264
_nltst_inet4(const char * addr)265 static inline in_addr_t _nltst_inet4(const char *addr)
266 {
267 in_addr_t addr_bin = 0;
268
269 _nltst_assert(_nltst_inet_pton(AF_INET, addr, NULL, &addr_bin));
270 return addr_bin;
271 }
272
_nltst_inet6p(const char * addr)273 static inline struct in6_addr *_nltst_inet6p(const char *addr)
274 {
275 _nl_thread_local static struct in6_addr addr_bin;
276
277 ck_assert(_nltst_inet_pton(AF_INET6, addr, NULL, &addr_bin));
278 return &addr_bin;
279 }
280
_nltst_inet6(const char * addr)281 static inline struct in6_addr _nltst_inet6(const char *addr)
282 {
283 struct in6_addr addr_bin;
284
285 ck_assert(_nltst_inet_pton(AF_INET6, addr, NULL, &addr_bin));
286 return addr_bin;
287 }
288
_nltst_inet_addr_family(int addr_family,const char * addr)289 static inline int _nltst_inet_addr_family(int addr_family, const char *addr)
290 {
291 if (!_nltst_inet_pton(addr_family, addr, &addr_family, NULL))
292 return AF_UNSPEC;
293 return addr_family;
294 }
295
_nltst_inet_normalize(int addr_family,const char * addr,char buf[static INET_ADDRSTRLEN])296 static inline char *_nltst_inet_normalize(int addr_family, const char *addr,
297 char buf[static INET_ADDRSTRLEN])
298 {
299 NLTstIPAddr a;
300
301 buf[0] = '\0';
302 if (!_nltst_inet_pton(addr_family, addr, &addr_family, &a))
303 return NULL;
304 return _nltst_inet_ntop(addr_family, &a, buf);
305 }
306
307 /*****************************************************************************/
308
309 char *_nltst_strtok(const char **p_str);
310
311 char **_nltst_strtokv(const char *str);
312
313 #define _nltst_assert_strv_equal(strv1, strv2) \
314 do { \
315 typeof(strv1) _strv1 = (strv1); \
316 typeof(strv2) _strv2 = (strv2); \
317 _nl_unused const void *_strv1_typecheck1 = _strv1; \
318 _nl_unused const void *_strv2_typecheck1 = _strv2; \
319 _nl_unused const char *_strv1_typecheck2 = \
320 _strv1 ? _strv1[0] : NULL; \
321 _nl_unused const char *_strv2_typecheck2 = \
322 _strv2 ? _strv2[0] : NULL; \
323 size_t _i; \
324 \
325 ck_assert_int_eq(!!_strv1, !!_strv2); \
326 if (_strv1) { \
327 for (_i = 0; _strv1[_i] || _strv2[_i]; _i++) { \
328 ck_assert_str_eq(_strv1[_i], _strv2[_i]); \
329 } \
330 } \
331 } while (0)
332
333 #define _NLTST_CHARSET_SPACE " \n\r\t"
334
335 #define _nltst_char_is(ch, charset) (!!(strchr("" charset "", (ch))))
336
337 #define _nltst_char_is_space(ch) _nltst_char_is(ch, _NLTST_CHARSET_SPACE)
338
339 #define _nltst_str_skip_predicate(s, ch, predicate) \
340 ({ \
341 typeof(s) _s1 = (s); \
342 _nl_unused const char *_s1_typecheck = (_s1); \
343 \
344 if (_s1) { \
345 while (({ \
346 const char ch = _s1[0]; \
347 \
348 (ch != '\0') && (predicate); \
349 })) \
350 _s1++; \
351 } \
352 _s1; \
353 })
354
355 #define _nltst_str_skip_charset(s, charset) \
356 _nltst_str_skip_predicate(s, _ch, _nltst_char_is(_ch, "" charset ""))
357
358 #define _nltst_str_skip_space(s) \
359 _nltst_str_skip_charset(s, _NLTST_CHARSET_SPACE)
360
361 #define _nltst_str_has_prefix_and_space(s, prefix) \
362 ({ \
363 typeof(s) _s2 = (s); \
364 _nl_unused const char *_s2_typecheck = (_s2); \
365 const size_t _l = strlen("" prefix ""); \
366 \
367 if (_s2) { \
368 if ((strncmp(_s2, "" prefix "", _l)) == 0 && \
369 _nltst_char_is_space(_s2[_l])) \
370 _s2 = _nltst_str_skip_space(&_s2[_l + 1]); \
371 else \
372 _s2 = NULL; \
373 } \
374 _s2; \
375 })
376
377 #define _nltst_str_find_first_not_from_charset(s, charset) \
378 ({ \
379 typeof(s) _s3 = (s); \
380 _nl_unused const char *_s3_typecheck = (_s3); \
381 size_t _l3; \
382 \
383 _l3 = strspn(_s3, "" charset ""); \
384 \
385 &_s3[_l3]; \
386 })
387
388 #define _nltst_str_find_first_from_charset(s, charset) \
389 ({ \
390 typeof(s) _s3 = (s); \
391 _nl_unused const char *_s3_typecheck = (_s3); \
392 size_t _l3; \
393 \
394 _l3 = strcspn(_s3, "" charset ""); \
395 \
396 &_s3[_l3]; \
397 })
398
399 /*****************************************************************************/
400
401 void nltst_netns_fixture_setup(void);
402 void nltst_netns_fixture_teardown(void);
403
404 struct nltst_netns;
405
406 struct nltst_netns *nltst_netns_enter(void);
407 void nltst_netns_leave(struct nltst_netns *nsdata);
408
409 /*****************************************************************************/
410
411 #define _nltst_system(command) _nltst_assert_retcode(system(command))
412
413 bool _nltst_in_ci(void);
414
415 bool _nltst_has_iproute2(void);
416 bool _nltst_skip_no_iproute2(const char *msg);
417
418 /*****************************************************************************/
419
420 typedef struct {
421 int addr_family;
422 int ifindex;
423 int plen;
424 char *addr;
425 char *addr_pattern;
426 } NLTstSelectRoute;
427
428 #define _nltst_assert_select_route(select_route) \
429 do { \
430 const NLTstSelectRoute *_select_route_5 = (select_route); \
431 \
432 ck_assert_ptr_nonnull(_select_route_5); \
433 _nl_assert_addr_family_or_unspec( \
434 _select_route_5->addr_family); \
435 ck_assert_int_ge(_select_route_5->ifindex, 0); \
436 ck_assert_int_ge(_select_route_5->plen, -1); \
437 ck_assert_int_le( \
438 _select_route_5->plen, \
439 _select_route_5->addr_family == AF_INET ? 32 : 128); \
440 ck_assert(!_select_route_5->addr || ({ \
441 char _buf[INET6_ADDRSTRLEN]; \
442 const char *_s2; \
443 \
444 _s2 = _nltst_inet_normalize( \
445 _select_route_5->addr_family, \
446 _select_route_5->addr, _buf); \
447 (_select_route_5->addr_family != AF_UNSPEC && _s2 && \
448 _nl_streq(_s2, _select_route_5->addr)); \
449 })); \
450 ck_assert(!_select_route_5->addr_pattern || \
451 !_select_route_5->addr); \
452 ck_assert(!_select_route_5->addr_pattern || \
453 _select_route_5->addr_family != AF_UNSPEC); \
454 } while (0)
455
456 void _nltst_select_route_clear(NLTstSelectRoute *select_route);
457
458 #define _nltst_auto_clear_select_route \
459 _nl_auto(_nltst_auto_clear_select_route_fcn)
460 _NL_AUTO_DEFINE_FCN_STRUCT(NLTstSelectRoute, _nltst_auto_clear_select_route_fcn,
461 _nltst_select_route_clear);
462
463 int _nltst_select_route_cmp(const NLTstSelectRoute *select_route1,
464 const NLTstSelectRoute *select_route2);
465
466 static inline bool
_nltst_select_route_equal(const NLTstSelectRoute * select_route1,const NLTstSelectRoute * select_route2)467 _nltst_select_route_equal(const NLTstSelectRoute *select_route1,
468 const NLTstSelectRoute *select_route2)
469 {
470 return _nltst_select_route_cmp(select_route1, select_route2) == 0;
471 }
472
473 char *_nltst_select_route_to_string(const NLTstSelectRoute *select_route);
474
475 void _nltst_select_route_parse(const char *str,
476 NLTstSelectRoute *out_select_route);
477
478 bool _nltst_select_route_match(struct nl_object *route,
479 const NLTstSelectRoute *select_route,
480 bool do_assert);
481
482 /*****************************************************************************/
483
484 void _nltst_object_identical(const void *a, const void *b);
485
486 char *_nltst_object_to_string(const struct nl_object *obj);
487
488 struct nl_object **_nltst_cache_get_all(struct nl_cache *cache,
489 size_t *out_len);
490
491 struct rtnl_link *_nltst_cache_get_link(struct nl_cache *cache,
492 const char *ifname);
493
494 struct nl_cache *_nltst_rtnl_link_alloc_cache(struct nl_sock *sk,
495 int addr_family, unsigned flags);
496
497 struct nl_cache *_nltst_rtnl_route_alloc_cache(struct nl_sock *sk,
498 int addr_family);
499
500 struct nl_sock *_nltst_socket(int protocol);
501
502 void _nltst_add_link(struct nl_sock *sk, const char *ifname, const char *kind,
503 int *out_ifindex);
504
505 void _nltst_delete_link(struct nl_sock *sk, const char *ifname);
506
507 void _nltst_get_link(struct nl_sock *sk, const char *ifname, int *out_ifindex,
508 struct rtnl_link **out_link);
509
510 void _nltst_assert_route_list(struct nl_object *const *objs, ssize_t len,
511 const char *const *expected_routes);
512
513 void _nltst_assert_route_cache_v(struct nl_cache *cache,
514 const char *const *expected_routes);
515
516 #define _nltst_assert_route_cache(cache, ...) \
517 _nltst_assert_route_cache_v(cache, \
518 ((const char *const[200]){ __VA_ARGS__ }))
519
520 #endif /* __NL_TEST_UTIL_H__ */
521