xref: /aosp_15_r20/external/libnl/tests/nl-test-util.h (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
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