1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (C) 2022 Linutronix GmbH */
3
4#include <test_progs.h>
5#include <network_helpers.h>
6
7#include "test_time_tai.skel.h"
8
9#include <time.h>
10#include <stdint.h>
11
12#define TAI_THRESHOLD	1000000000ULL /* 1s */
13#define NSEC_PER_SEC	1000000000ULL
14
15static __u64 ts_to_ns(const struct timespec *ts)
16{
17	return ts->tv_sec * NSEC_PER_SEC + ts->tv_nsec;
18}
19
20void test_time_tai(void)
21{
22	struct __sk_buff skb = {
23		.cb[0] = 0,
24		.cb[1] = 0,
25		.tstamp = 0,
26	};
27	LIBBPF_OPTS(bpf_test_run_opts, topts,
28		.data_in = &pkt_v4,
29		.data_size_in = sizeof(pkt_v4),
30		.ctx_in = &skb,
31		.ctx_size_in = sizeof(skb),
32		.ctx_out = &skb,
33		.ctx_size_out = sizeof(skb),
34	);
35	struct test_time_tai *skel;
36	struct timespec now_tai;
37	__u64 ts1, ts2, now;
38	int ret, prog_fd;
39
40	/* Open and load */
41	skel = test_time_tai__open_and_load();
42	if (!ASSERT_OK_PTR(skel, "tai_open"))
43		return;
44
45	/* Run test program */
46	prog_fd = bpf_program__fd(skel->progs.time_tai);
47	ret = bpf_prog_test_run_opts(prog_fd, &topts);
48	ASSERT_OK(ret, "test_run");
49
50	/* Retrieve generated TAI timestamps */
51	ts1 = skb.tstamp;
52	ts2 = skb.cb[0] | ((__u64)skb.cb[1] << 32);
53
54	/* TAI != 0 */
55	ASSERT_NEQ(ts1, 0, "tai_ts1");
56	ASSERT_NEQ(ts2, 0, "tai_ts2");
57
58	/* TAI is moving forward only */
59	ASSERT_GE(ts2, ts1, "tai_forward");
60
61	/* Check for future */
62	ret = clock_gettime(CLOCK_TAI, &now_tai);
63	ASSERT_EQ(ret, 0, "tai_gettime");
64	now = ts_to_ns(&now_tai);
65
66	ASSERT_TRUE(now > ts1, "tai_future_ts1");
67	ASSERT_TRUE(now > ts2, "tai_future_ts2");
68
69	/* Check for reasonable range */
70	ASSERT_TRUE(now - ts1 < TAI_THRESHOLD, "tai_range_ts1");
71	ASSERT_TRUE(now - ts2 < TAI_THRESHOLD, "tai_range_ts2");
72
73	test_time_tai__destroy(skel);
74}
75