1 /*
2 * Copyright (c) 2018-2021 Eugene Syromyatnikov <evgsyr@gmail.com>
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6 */
7
8 #include "defs.h"
9 #include "netlink_route.h"
10 #include "nlattr.h"
11 #include "print_fields.h"
12
13 #include "netlink.h"
14
15 #include <netinet/in.h>
16
17 #include <linux/if_bonding.h>
18 #include <linux/if_bridge.h>
19 #include <linux/if_link.h>
20 #include <linux/mpls.h>
21 #include <linux/rtnetlink.h>
22
23 #include "xlat/ifstats_af_spec_mpls_attrs.h"
24 #include "xlat/ifstats_attrs.h"
25 #include "xlat/ifstats_attr_flags.h"
26 #include "xlat/ifstats_offload_attrs.h"
27 #include "xlat/ifstats_xstats_bond_attrs.h"
28 #include "xlat/ifstats_xstats_bond_3ad_attrs.h"
29 #include "xlat/ifstats_xstats_bridge_attrs.h"
30 #include "xlat/ifstats_xstats_bridge_mcast_indices.h"
31 #include "xlat/ifstats_xstats_type_attrs.h"
32 #include "xlat/nl_bridge_vlan_flags.h"
33
34 #define XLAT_MACROS_ONLY
35 # include "xlat/addrfams.h" /* AF_MPLS */
36 #undef XLAT_MACROS_ONLY
37
38 static bool
39 decode_ifstats_link_xstats_bridge_vlan(struct tcb *const tcp,
40 const kernel_ulong_t addr,
41 const unsigned int len,
42 const void *const opaque_data)
43 {
44 struct bridge_vlan_xstats st;
45
46 if (len < sizeof(st))
47 return false;
48
49 if (umove_or_printaddr(tcp, addr, &st))
50 return true;
51
52 tprint_struct_begin();
53 PRINT_FIELD_U(st, rx_bytes);
54 tprint_struct_next();
55 PRINT_FIELD_U(st, rx_packets);
56 tprint_struct_next();
57 PRINT_FIELD_U(st, tx_bytes);
58 tprint_struct_next();
59 PRINT_FIELD_U(st, tx_packets);
60 tprint_struct_next();
61 PRINT_FIELD_U(st, vid);
62 tprint_struct_next();
63 PRINT_FIELD_FLAGS(st, flags, nl_bridge_vlan_flags,
64 "BRIDGE_VLAN_INFO_???");
65 if (st.pad2) {
66 tprint_struct_next();
67 PRINT_FIELD_X(st, pad2);
68 }
69 tprint_struct_end();
70
71 if (len > sizeof(st)) {
72 tprint_array_next();
73 printstr_ex(tcp, addr + sizeof(st), len - sizeof(st),
74 QUOTE_FORCE_HEX);
75 }
76
77 return true;
78 }
79
80 static bool
81 decode_ifstats_link_xstats_bridge_mcast(struct tcb *const tcp,
82 const kernel_ulong_t addr,
83 const unsigned int len,
84 const void *const opaque_data)
85 {
86 struct br_mcast_stats st;
87
88 if (len < sizeof(st))
89 return false;
90
91 if (umove_or_printaddr(tcp, addr, &st))
92 return true;
93
94 #define PRINT_FIELD_MCAST_ARRAY_(where_, field_) \
95 PRINT_FIELD_ARRAY_INDEXED(where_, field_, \
96 tcp, print_uint_array_member, \
97 ifstats_xstats_bridge_mcast_indices, \
98 NULL);
99
100 tprint_struct_begin();
101 PRINT_FIELD_MCAST_ARRAY_(st, igmp_v1queries);
102 tprint_struct_next();
103 PRINT_FIELD_MCAST_ARRAY_(st, igmp_v2queries);
104 tprint_struct_next();
105 PRINT_FIELD_MCAST_ARRAY_(st, igmp_v3queries);
106 tprint_struct_next();
107 PRINT_FIELD_MCAST_ARRAY_(st, igmp_leaves);
108 tprint_struct_next();
109 PRINT_FIELD_MCAST_ARRAY_(st, igmp_v1reports);
110 tprint_struct_next();
111 PRINT_FIELD_MCAST_ARRAY_(st, igmp_v2reports);
112 tprint_struct_next();
113 PRINT_FIELD_MCAST_ARRAY_(st, igmp_v3reports);
114 tprint_struct_next();
115 PRINT_FIELD_U(st, igmp_parse_errors);
116 tprint_struct_next();
117 PRINT_FIELD_MCAST_ARRAY_(st, mld_v1queries);
118 tprint_struct_next();
119 PRINT_FIELD_MCAST_ARRAY_(st, mld_v2queries);
120 tprint_struct_next();
121 PRINT_FIELD_MCAST_ARRAY_(st, mld_leaves);
122 tprint_struct_next();
123 PRINT_FIELD_MCAST_ARRAY_(st, mld_v1reports);
124 tprint_struct_next();
125 PRINT_FIELD_MCAST_ARRAY_(st, mld_v2reports);
126 tprint_struct_next();
127 PRINT_FIELD_U(st, mld_parse_errors);
128 tprint_struct_next();
129 PRINT_FIELD_MCAST_ARRAY_(st, mcast_bytes);
130 tprint_struct_next();
131 PRINT_FIELD_MCAST_ARRAY_(st, mcast_packets);
132 tprint_struct_end();
133
134 #undef PRINT_FIELD_MCAST_ARRAY_
135
136 if (len > sizeof(st)) {
137 tprint_array_next();
138 printstr_ex(tcp, addr + sizeof(st), len - sizeof(st),
139 QUOTE_FORCE_HEX);
140 }
141
142 return true;
143 }
144
145 static bool
146 decode_ifstats_link_xstats_bridge_stp(struct tcb *const tcp,
147 const kernel_ulong_t addr,
148 const unsigned int len,
149 const void *const opaque_data)
150 {
151 struct bridge_stp_xstats st;
152
153 if (len < sizeof(st))
154 return false;
155
156 if (umove_or_printaddr(tcp, addr, &st))
157 return true;
158
159 tprint_struct_begin();
160 PRINT_FIELD_U(st, transition_blk);
161 tprint_struct_next();
162 PRINT_FIELD_U(st, transition_fwd);
163 tprint_struct_next();
164 PRINT_FIELD_U(st, rx_bpdu);
165 tprint_struct_next();
166 PRINT_FIELD_U(st, tx_bpdu);
167 tprint_struct_next();
168 PRINT_FIELD_U(st, rx_tcn);
169 tprint_struct_next();
170 PRINT_FIELD_U(st, tx_tcn);
171 tprint_struct_end();
172
173 if (len > sizeof(st)) {
174 tprint_array_next();
175 printstr_ex(tcp, addr + sizeof(st), len - sizeof(st),
176 QUOTE_FORCE_HEX);
177 }
178
179 return true;
180 }
181
182 static const nla_decoder_t ifstats_xstats_bridge_decoders[] = {
183 [BRIDGE_XSTATS_UNSPEC] = NULL,
184 [BRIDGE_XSTATS_VLAN] = decode_ifstats_link_xstats_bridge_vlan,
185 [BRIDGE_XSTATS_MCAST] = decode_ifstats_link_xstats_bridge_mcast,
186 [BRIDGE_XSTATS_PAD] = NULL,
187 [BRIDGE_XSTATS_STP] = decode_ifstats_link_xstats_bridge_stp,
188 };
189
190 static bool
191 decode_ifstats_link_xstats_bridge(struct tcb *const tcp,
192 const kernel_ulong_t addr,
193 const unsigned int len,
194 const void *const opaque_data)
195 {
196 decode_nlattr(tcp, addr, len, ifstats_xstats_bridge_attrs,
197 "BRIDGE_XSTATS_???",
198 ARRSZ_PAIR(ifstats_xstats_bridge_decoders),
199 opaque_data);
200
201 return true;
202 }
203
204 static const nla_decoder_t ifstats_xstats_bond_3ad_decoders[] = {
205 [BOND_3AD_STAT_LACPDU_RX] = decode_nla_u64,
206 [BOND_3AD_STAT_LACPDU_TX] = decode_nla_u64,
207 [BOND_3AD_STAT_LACPDU_UNKNOWN_RX] = decode_nla_u64,
208 [BOND_3AD_STAT_LACPDU_ILLEGAL_RX] = decode_nla_u64,
209 [BOND_3AD_STAT_MARKER_RX] = decode_nla_u64,
210 [BOND_3AD_STAT_MARKER_TX] = decode_nla_u64,
211 [BOND_3AD_STAT_MARKER_RESP_RX] = decode_nla_u64,
212 [BOND_3AD_STAT_MARKER_RESP_TX] = decode_nla_u64,
213 [BOND_3AD_STAT_MARKER_UNKNOWN_RX] = decode_nla_u64,
214 [BOND_3AD_STAT_PAD] = NULL,
215 };
216
217 static bool
218 decode_ifstats_link_xstats_bond_3ad(struct tcb *const tcp,
219 const kernel_ulong_t addr,
220 const unsigned int len,
221 const void *const opaque_data)
222 {
223 decode_nlattr(tcp, addr, len, ifstats_xstats_bond_3ad_attrs,
224 "BOND_XSTATS_???",
225 ARRSZ_PAIR(ifstats_xstats_bond_3ad_decoders),
226 opaque_data);
227
228 return true;
229 }
230
231 static const nla_decoder_t ifstats_xstats_bond_decoders[] = {
232 [BOND_XSTATS_UNSPEC] = NULL,
233 [BOND_XSTATS_3AD] = decode_ifstats_link_xstats_bond_3ad,
234 };
235
236 static bool
237 decode_ifstats_link_xstats_bond(struct tcb *const tcp,
238 const kernel_ulong_t addr,
239 const unsigned int len,
240 const void *const opaque_data)
241 {
242 decode_nlattr(tcp, addr, len, ifstats_xstats_bond_attrs,
243 "BOND_XSTATS_???",
244 ARRSZ_PAIR(ifstats_xstats_bond_decoders),
245 opaque_data);
246
247 return true;
248 }
249
250 static const nla_decoder_t ifstats_xstats_decoders[] = {
251 [LINK_XSTATS_TYPE_UNSPEC] = NULL,
252 [LINK_XSTATS_TYPE_BRIDGE] = decode_ifstats_link_xstats_bridge,
253 [LINK_XSTATS_TYPE_BOND] = decode_ifstats_link_xstats_bond,
254 };
255
256 static bool
257 decode_ifstats_link_xstats(struct tcb *const tcp,
258 const kernel_ulong_t addr,
259 const unsigned int len,
260 const void *const opaque_data)
261 {
262 decode_nlattr(tcp, addr, len, ifstats_xstats_type_attrs,
263 "LINK_XSTATS_TYPE_???",
264 ARRSZ_PAIR(ifstats_xstats_decoders),
265 opaque_data);
266
267 return true;
268 }
269
270 static const nla_decoder_t ifstats_offload_xstats_decoders[] = {
271 [IFLA_OFFLOAD_XSTATS_UNSPEC] = NULL,
272 [IFLA_OFFLOAD_XSTATS_CPU_HIT] = decode_nla_rtnl_link_stats64,
273 };
274
275 static bool
276 decode_ifstats_link_offload_xstats(struct tcb *const tcp,
277 const kernel_ulong_t addr,
278 const unsigned int len,
279 const void *const opaque_data)
280 {
281 decode_nlattr(tcp, addr, len, ifstats_offload_attrs,
282 "IFLA_OFFLOAD_XSTATS_???",
283 ARRSZ_PAIR(ifstats_offload_xstats_decoders),
284 opaque_data);
285
286 return true;
287 }
288
289 static bool
290 decode_ifstats_af_mpls_stats_link(struct tcb *const tcp,
291 const kernel_ulong_t addr,
292 const unsigned int len,
293 const void *const opaque_data)
294 {
295 struct mpls_link_stats st;
296
297 if (len < sizeof(st))
298 return false;
299
300 if (umove_or_printaddr(tcp, addr, &st))
301 return true;
302
303 tprint_struct_begin();
304 PRINT_FIELD_U(st, rx_packets);
305 tprint_struct_next();
306 PRINT_FIELD_U(st, tx_packets);
307 tprint_struct_next();
308 PRINT_FIELD_U(st, rx_bytes);
309 tprint_struct_next();
310 PRINT_FIELD_U(st, tx_bytes);
311 tprint_struct_next();
312 PRINT_FIELD_U(st, rx_errors);
313 tprint_struct_next();
314 PRINT_FIELD_U(st, tx_errors);
315 tprint_struct_next();
316 PRINT_FIELD_U(st, rx_dropped);
317 tprint_struct_next();
318 PRINT_FIELD_U(st, tx_dropped);
319 tprint_struct_next();
320 PRINT_FIELD_U(st, rx_noroute);
321 tprint_struct_end();
322
323 if (len > sizeof(st)) {
324 tprint_array_next();
325 printstr_ex(tcp, addr + sizeof(st), len - sizeof(st),
326 QUOTE_FORCE_HEX);
327 }
328
329 return true;
330 }
331
332 static const nla_decoder_t ifla_stats_mpls_nla_decoders[] = {
333 [MPLS_STATS_UNSPEC] = NULL,
334 [MPLS_STATS_LINK] = decode_ifstats_af_mpls_stats_link,
335 };
336
337 static bool
338 decode_ifstats_af(struct tcb *const tcp,
339 const kernel_ulong_t addr,
340 const unsigned int len,
341 const void *const opaque_data)
342 {
343 static const struct af_spec_decoder_desc protos[] = {
344 { AF_MPLS, ifstats_af_spec_mpls_attrs, "MPLS_STATS_???",
345 ARRSZ_PAIR(ifla_stats_mpls_nla_decoders) },
346 };
347
348 decode_nla_af_spec(tcp, addr, len,
349 (uintptr_t) opaque_data, ARRSZ_PAIR(protos));
350
351 return true;
352 }
353
354 static bool
355 decode_ifstats_af_spec(struct tcb *const tcp,
356 const kernel_ulong_t addr,
357 const unsigned int len,
358 const void *const opaque_data)
359 {
360 static const nla_decoder_t af_spec_decoder = &decode_ifstats_af;
361
362 decode_nlattr(tcp, addr, len, addrfams, "AF_???",
363 &af_spec_decoder, 0, 0);
364
365 return true;
366 }
367
368
369 static const nla_decoder_t ifstatsmsg_nla_decoders[] = {
370 [IFLA_STATS_UNSPEC] = NULL,
371 [IFLA_STATS_LINK_64] = decode_nla_rtnl_link_stats64,
372 [IFLA_STATS_LINK_XSTATS] = decode_ifstats_link_xstats,
373 [IFLA_STATS_LINK_XSTATS_SLAVE] = decode_ifstats_link_xstats,
374 [IFLA_STATS_LINK_OFFLOAD_XSTATS] = decode_ifstats_link_offload_xstats,
375 [IFLA_STATS_AF_SPEC] = decode_ifstats_af_spec,
376 };
377
378 DECL_NETLINK_ROUTE_DECODER(decode_ifstatsmsg)
379 {
380 struct if_stats_msg ifstats = { .family = family };
381 size_t offset = sizeof(ifstats.family);
382 bool decode_nla = false;
383
384 tprint_struct_begin();
385 PRINT_FIELD_XVAL(ifstats, family, addrfams, "AF_???");
386 tprint_struct_next();
387
388 if (len >= sizeof(ifstats)) {
389 if (!umoven_or_printaddr(tcp, addr + offset,
390 sizeof(ifstats) - offset,
391 (char *) &ifstats + offset)) {
392 if (ifstats.pad1) {
393 PRINT_FIELD_X(ifstats, pad1);
394 tprint_struct_next();
395 }
396 if (ifstats.pad2) {
397 PRINT_FIELD_X(ifstats, pad2);
398 tprint_struct_next();
399 }
400 PRINT_FIELD_IFINDEX(ifstats, ifindex);
401 tprint_struct_next();
402 PRINT_FIELD_FLAGS(ifstats, filter_mask,
403 ifstats_attr_flags,
404 "1<<IFLA_STATS_???");
405 decode_nla = true;
406 }
407 } else {
408 tprint_more_data_follows();
409 }
410 tprint_struct_end();
411
412 offset = NLMSG_ALIGN(sizeof(ifstats));
413 if (decode_nla && len > offset) {
414 tprint_array_next();
415 decode_nlattr(tcp, addr + offset, len - offset,
416 ifstats_attrs, "IFLA_STATS_???",
417 ARRSZ_PAIR(ifstatsmsg_nla_decoders), &ifstats);
418 }
419 }