1 /*
2 * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
3 * Copyright (c) 2017-2023 The strace developers.
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "tests.h"
10
11 #include <stdio.h>
12 #include "test_nlattr.h"
13 #include <linux/pkt_cls.h>
14 #include <linux/rtnetlink.h>
15
16 #if !HAVE_DECL_TCA_ACT_PAD
17 enum { TCA_ACT_PAD = 5 };
18 #endif
19 #if !HAVE_DECL_TCA_ACT_COOKIE
20 enum { TCA_ACT_COOKIE = 6 };
21 #endif
22 #if !HAVE_DECL_TCA_ACT_FLAGS
23 enum { TCA_ACT_FLAGS = 7 };
24 #endif
25 #if !HAVE_DECL_TCA_ACT_HW_STATS
26 enum { TCA_ACT_HW_STATS = 8 };
27 #endif
28 #if !HAVE_DECL_TCA_ACT_USED_HW_STATS
29 enum { TCA_ACT_USED_HW_STATS = 9 };
30 #endif
31 #if !HAVE_DECL_TCA_ACT_IN_HW_COUNT
32 enum { TCA_ACT_IN_HW_COUNT = 10 };
33 #endif
34
35 static const unsigned int hdrlen = sizeof(struct tcamsg);
36
37 static void
38 init_tcamsg(struct nlmsghdr *const nlh, const unsigned int msg_len)
39 {
40 SET_STRUCT(struct nlmsghdr, nlh,
41 .nlmsg_len = msg_len,
42 .nlmsg_type = RTM_GETACTION,
43 .nlmsg_flags = NLM_F_DUMP
44 );
45
46 struct tcamsg *const msg = NLMSG_DATA(nlh);
47 SET_STRUCT(struct tcamsg, msg,
48 .tca_family = AF_INET
49 );
50 }
51
52 static void
53 print_tcamsg(const unsigned int msg_len)
54 {
55 printf("{nlmsg_len=%u, nlmsg_type=" XLAT_FMT ", nlmsg_flags=" XLAT_FMT
56 ", nlmsg_seq=0, nlmsg_pid=0}, {tca_family=" XLAT_FMT "}",
57 msg_len, XLAT_ARGS(RTM_GETACTION), XLAT_ARGS(NLM_F_DUMP),
58 XLAT_ARGS(AF_INET));
59 }
60
61 static void
62 init_tcamsg_tab(struct nlmsghdr *const nlh, const unsigned int msg_len)
63 {
64 init_tcamsg(nlh, msg_len);
65
66 struct nlattr *nla = NLMSG_ATTR(nlh, hdrlen);
67 SET_STRUCT(struct nlattr, nla,
68 .nla_len = msg_len - NLMSG_SPACE(hdrlen),
69 .nla_type = 1,
70 );
71 }
72
73 static void
74 print_tcamsg_tab(const unsigned int msg_len)
75 {
76 print_tcamsg(msg_len);
77 printf(", [{nla_len=%u, nla_type=" XLAT_FMT "}",
78 msg_len - NLMSG_SPACE(hdrlen), XLAT_ARGS(TCA_ROOT_TAB));
79 }
80
81 static uint16_t tab_idx;
82
83 static void
84 init_tcamsg_tab_item(struct nlmsghdr *const nlh, const unsigned int msg_len)
85 {
86 init_tcamsg_tab(nlh, msg_len);
87
88 struct nlattr *nla = NLMSG_ATTR(nlh, hdrlen + NLA_HDRLEN);
89 SET_STRUCT(struct nlattr, nla,
90 .nla_len = msg_len - NLMSG_SPACE(hdrlen) - NLA_HDRLEN,
91 .nla_type = tab_idx,
92 );
93 }
94
95 static void
96 print_tcamsg_tab_item(const unsigned int msg_len)
97 {
98 print_tcamsg_tab(msg_len);
99 printf(", [{nla_len=%u, nla_type=%#x}",
100 msg_len - NLMSG_SPACE(hdrlen) - NLA_HDRLEN, tab_idx);
101 }
102
103 int
104 main(void)
105 {
106 skip_if_unavailable("/proc/self/fd/");
107
108 const int fd = create_nl_socket(NETLINK_ROUTE);
109 const unsigned int hdrlen = sizeof(struct tcamsg);
110 void *nlh0 = midtail_alloc(NLMSG_SPACE(hdrlen), NLA_HDRLEN + 4);
111
112 static char pattern[4096];
113 fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1);
114
115 /* Invalid */
116 static const unsigned int nla_invalid[] = { 6, 0xffff & NLA_TYPE_MASK };
117 for (size_t i = 0; i < ARRAY_SIZE(nla_invalid); i++) {
118 char nla_type_str[256];
119 sprintf(nla_type_str, "%#x" NRAW(" /* TCA_ROOT_??? */"),
120 nla_invalid[i]);
121 TEST_NLATTR_(fd, nlh0, hdrlen,
122 init_tcamsg, print_tcamsg,
123 nla_invalid[i], nla_type_str,
124 21, pattern, 21,
125 print_quoted_hex(pattern, 21));
126 }
127
128 /* Default decoder */
129 static const struct {
130 unsigned int val;
131 const char *str;
132 } nla_default[] = {
133 { ARG_XLAT_KNOWN(0, "TCA_ROOT_UNSPEC") },
134 };
135 for (size_t i = 0; i < ARRAY_SIZE(nla_default); i++) {
136 TEST_NLATTR_(fd, nlh0, hdrlen,
137 init_tcamsg, print_tcamsg,
138 nla_default[i].val, nla_default[i].str,
139 17, pattern, 17,
140 print_quoted_hex(pattern, 17));
141 }
142
143 /* TCA_ROOT_TAB: Invalid */
144 TEST_NLATTR_(fd, nlh0, hdrlen,
145 init_tcamsg, print_tcamsg,
146 TCA_ROOT_TAB, XLAT_KNOWN(0x1, "TCA_ROOT_TAB"),
147 3, &pattern, 3,
148 printf("\"\\x61\\x62\\x63\""));
149
150 /* TCA_ROOT_TAB: item: invalid */
151 TEST_NESTED_NLATTR_(fd, nlh0, hdrlen,
152 init_tcamsg_tab, print_tcamsg_tab,
153 0, "0", 3, &pattern, 3, 1,
154 printf("\"\\x61\\x62\\x63\""));
155 tab_idx++;
156
157 /* TCA_ROOT_TAB: item: default decoder */
158 static const struct {
159 unsigned int val;
160 const char *str;
161 } tcaa_default[] = {
162 { ARG_XLAT_KNOWN(0, "TCA_ACT_UNSPEC") },
163 { ARG_XLAT_KNOWN(0x2, "TCA_ACT_OPTIONS") },
164 { ARG_XLAT_KNOWN(0x5, "TCA_ACT_PAD") },
165 { ARG_XLAT_KNOWN(0x6, "TCA_ACT_COOKIE") },
166 { 11, "0xb" NRAW(" /* TCA_ACT_??? */") },
167 };
168 for (size_t i = 0; i < ARRAY_SIZE(tcaa_default); i++) {
169 TEST_NESTED_NLATTR_(fd, nlh0, hdrlen,
170 init_tcamsg_tab_item, print_tcamsg_tab_item,
171 tcaa_default[i].val, tcaa_default[i].str,
172 17, pattern, 17, 2,
173 print_quoted_hex(pattern, 17));
174 tab_idx++;
175 }
176
177 /* TCA_ROOT_TAB: item: TCA_ACT_KIND */
178 TEST_NESTED_NLATTR_(fd, nlh0, hdrlen,
179 init_tcamsg_tab_item, print_tcamsg_tab_item,
180 TCA_ACT_KIND, XLAT_KNOWN(0x1, "TCA_ACT_KIND"),
181 21, pattern, 21, 2,
182 print_quoted_cstring(pattern, 22));
183 tab_idx++;
184
185 static const char kind[] = "Hello\tthere";
186 TEST_NESTED_NLATTR_(fd, nlh0, hdrlen,
187 init_tcamsg_tab_item, print_tcamsg_tab_item,
188 TCA_ACT_KIND, XLAT_KNOWN(0x1, "TCA_ACT_KIND"),
189 sizeof(kind), kind, sizeof(kind), 2,
190 print_quoted_string(kind));
191 tab_idx++;
192
193 /* TCA_ROOT_TAB: item: TCA_ACT_INDEX */
194 static uint32_t idx = 0xdeadc0de;
195 TEST_NESTED_NLATTR_(fd, nlh0, hdrlen,
196 init_tcamsg_tab_item, print_tcamsg_tab_item,
197 TCA_ACT_INDEX, XLAT_KNOWN(0x3, "TCA_ACT_INDEX"),
198 sizeof(idx), &idx, sizeof(idx), 2,
199 printf("%u", idx));
200 tab_idx++;
201
202 /* TCA_ROOT_TAB: item: TCA_ACT_FLAGS */
203 static uint32_t flags = 0xfacebeff;
204 TEST_NESTED_NLATTR_(fd, nlh0, hdrlen,
205 init_tcamsg_tab_item, print_tcamsg_tab_item,
206 TCA_ACT_FLAGS, XLAT_KNOWN(0x7, "TCA_ACT_FLAGS"),
207 sizeof(flags), &flags, sizeof(flags), 2,
208 printf(XLAT_FMT, XLAT_SEL(0xfacebeff,
209 "TCA_ACT_FLAGS_NO_PERCPU_STATS|"
210 "TCA_ACT_FLAGS_SKIP_HW|"
211 "TCA_ACT_FLAGS_SKIP_SW|0xfacebef8")));
212 tab_idx++;
213
214 /* TCA_ROOT_TAB: item: TCA_ACT_HW_STATS, TCA_ACT_USED_HW_STATS */
215 static const struct strval32 nla_hw_st[] = {
216 { ARG_XLAT_KNOWN(0x8, "TCA_ACT_HW_STATS") },
217 { ARG_XLAT_KNOWN(0x9, "TCA_ACT_USED_HW_STATS") },
218 };
219
220 static uint32_t hw_st = 0xfacebeef;
221 for (size_t i = 0; i < ARRAY_SIZE(nla_hw_st); i++) {
222 TEST_NESTED_NLATTR_(fd, nlh0, hdrlen,
223 init_tcamsg_tab_item, print_tcamsg_tab_item,
224 nla_hw_st[i].val, nla_hw_st[i].str,
225 sizeof(hw_st), &hw_st, sizeof(hw_st), 2,
226 printf(XLAT_FMT, XLAT_SEL(0xfacebeef,
227 "TCA_ACT_HW_STATS_IMMEDIATE|"
228 "TCA_ACT_HW_STATS_DELAYED|"
229 "0xfacebeec")));
230 tab_idx++;
231 }
232
233 /* TCA_ROOT_TAB: item: TCA_ACT_IN_HW_COUNT */
234 static uint32_t hw_count = 0xdeadface;
235 TEST_NESTED_NLATTR_(fd, nlh0, hdrlen,
236 init_tcamsg_tab_item, print_tcamsg_tab_item,
237 TCA_ACT_IN_HW_COUNT,
238 XLAT_KNOWN(0xa, "TCA_ACT_IN_HW_COUNT"),
239 sizeof(hw_count), &hw_count, sizeof(hw_count), 2,
240 printf("%u", hw_count));
241
242 /* TCA_ROOT_FLAGS */
243 static const struct strval32 root_flags[] = {
244 { ARG_STR(0) },
245 { ARG_XLAT_KNOWN(0x1, "TCA_ACT_FLAG_LARGE_DUMP_ON") },
246 { ARG_XLAT_KNOWN(0x3, "TCA_ACT_FLAG_LARGE_DUMP_ON|"
247 "TCA_ACT_FLAG_TERSE_DUMP") },
248 { ARG_XLAT_KNOWN(0xcafebeef, "TCA_ACT_FLAG_LARGE_DUMP_ON|"
249 "TCA_ACT_FLAG_TERSE_DUMP|"
250 "0xcafebeec") },
251 { ARG_XLAT_UNKNOWN(0xbadc0dec, "TCA_ACT_FLAG_???") },
252 };
253
254 for (size_t i = 0; i < ARRAY_SIZE(root_flags); i++) {
255 TEST_NLATTR_(fd, nlh0, hdrlen, init_tcamsg, print_tcamsg,
256 TCA_ROOT_FLAGS, XLAT_KNOWN(0x2, "TCA_ROOT_FLAGS"),
257 4, &root_flags[i].val, 4,
258 printf("%s", root_flags[i].str));
259 }
260
261 /* TCA_ROOT_COUNT */
262 static const uint32_t cnt_vals[] = { 0, 1, 0xbac0ded };
263
264 for (size_t i = 0; i < ARRAY_SIZE(cnt_vals); i++) {
265 TEST_NLATTR_(fd, nlh0, hdrlen, init_tcamsg, print_tcamsg,
266 TCA_ROOT_COUNT, XLAT_KNOWN(0x3, "TCA_ROOT_COUNT"),
267 4, &cnt_vals[i], 4,
268 printf("%u", cnt_vals[i]));
269 }
270
271 /* TCA_ROOT_TIME_DELTA */
272 static const struct strval32 time_deltas[] = {
273 { 0, "0" },
274 { 1, "1" NRAW(" /* 0.001 s */") },
275 { 10, "10" NRAW(" /* 0.010 s */") },
276 { 100, "100" NRAW(" /* 0.100 s */") },
277 { 999, "999" NRAW(" /* 0.999 s */") },
278 { 1000, "1000" NRAW(" /* 1.000 s */") },
279 { 1001, "1001" NRAW(" /* 1.001 s */") },
280 { 1010, "1010" NRAW(" /* 1.010 s */") },
281 { 0xfeedface, "4277009102" NRAW(" /* 4277009.102 s */") },
282 };
283
284 for (size_t i = 0; i < ARRAY_SIZE(time_deltas); i++) {
285 TEST_NLATTR_(fd, nlh0, hdrlen, init_tcamsg, print_tcamsg,
286 TCA_ROOT_TIME_DELTA,
287 XLAT_KNOWN(0x4, "TCA_ROOT_TIME_DELTA"),
288 4, &time_deltas[i].val, 4,
289 printf("%s", time_deltas[i].str));
290 }
291
292 static const struct strval64 time_deltas64[] = {
293 { 0, "0" },
294 { 1, "1" NRAW(" /* 0.001 s */") },
295 { 10, "10" NRAW(" /* 0.010 s */") },
296 { 100, "100" NRAW(" /* 0.100 s */") },
297 { 999, "999" NRAW(" /* 0.999 s */") },
298 { 1000, "1000" NRAW(" /* 1.000 s */") },
299 { 1001, "1001" NRAW(" /* 1.001 s */") },
300 { 1010, "1010" NRAW(" /* 1.010 s */") },
301 { 0xfeedface, "4277009102" NRAW(" /* 4277009.102 s */") },
302 { 0xbadfacedeadc0ded, "13465671548708589037"
303 NRAW(" /* 13465671548708589.037 s */") },
304 };
305
306 for (size_t i = 0; i < ARRAY_SIZE(time_deltas64); i++) {
307 TEST_NLATTR_(fd, nlh0, hdrlen, init_tcamsg, print_tcamsg,
308 TCA_ROOT_TIME_DELTA,
309 XLAT_KNOWN(0x4, "TCA_ROOT_TIME_DELTA"),
310 8, &time_deltas64[i].val, 8,
311 printf("%s", time_deltas64[i].str));
312 }
313
314 /* TCA_ROOT_EXT_WARN_MSG */
315 static const char msg[] = "Hello\tthere";
316 TEST_NLATTR_(fd, nlh0, hdrlen, init_tcamsg, print_tcamsg,
317 TCA_ROOT_EXT_WARN_MSG,
318 XLAT_KNOWN(0x5, "TCA_ROOT_EXT_WARN_MSG"),
319 sizeof(msg), msg, sizeof(msg),
320 print_quoted_string(msg));
321
322 puts("+++ exited with 0 +++");
323 return 0;
324 }