1 /*
2 * prettymsg.c - human readable message dump
3 *
4 * Support for pretty print of an ethtool netlink message
5 */
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <errno.h>
10 #include <stdint.h>
11 #include <limits.h>
12 #include <inttypes.h>
13 #include <linux/genetlink.h>
14 #include <linux/rtnetlink.h>
15 #include <linux/if_link.h>
16 #include <libmnl/libmnl.h>
17
18 #include "prettymsg.h"
19
20 #define __INDENT 4
21 #define __DUMP_LINE 16
22 #define __DUMP_BLOCK 4
23
__print_binary_short(uint8_t * adata,unsigned int alen)24 static void __print_binary_short(uint8_t *adata, unsigned int alen)
25 {
26 unsigned int i;
27
28 if (!alen)
29 return;
30 printf("%02x", adata[0]);
31 for (i = 1; i < alen; i++)
32 printf("%c%02x", (i % __DUMP_BLOCK) ? ':' : ' ', adata[i]);
33 }
34
__print_binary_long(uint8_t * adata,unsigned int alen,unsigned int level)35 static void __print_binary_long(uint8_t *adata, unsigned int alen,
36 unsigned int level)
37 {
38 unsigned int i;
39
40 for (i = 0; i < alen; i++) {
41 if (i % __DUMP_LINE == 0)
42 printf("\n%*s", __INDENT * (level + 2), "");
43 else if (i % __DUMP_BLOCK == 0)
44 printf(" ");
45 else
46 putchar(' ');
47 printf("%02x", adata[i]);
48 }
49 }
50
pretty_print_attr(const struct nlattr * attr,const struct pretty_nla_desc * desc,unsigned int ndesc,unsigned int level,int err_offset,bool in_array)51 static int pretty_print_attr(const struct nlattr *attr,
52 const struct pretty_nla_desc *desc,
53 unsigned int ndesc, unsigned int level,
54 int err_offset, bool in_array)
55 {
56 unsigned int alen = mnl_attr_get_payload_len(attr);
57 unsigned int atype = mnl_attr_get_type(attr);
58 unsigned int desc_idx = in_array ? 0 : atype;
59 void *adata = mnl_attr_get_payload(attr);
60 const struct pretty_nla_desc *adesc;
61 const char *prefix = " ";
62 bool nested;
63
64 adesc = (desc && desc_idx < ndesc) ? &desc[desc_idx] : NULL;
65 nested = (adesc && (adesc->format == NLA_NESTED ||
66 adesc->format == NLA_ARRAY)) ||
67 (attr->nla_type & NLA_F_NESTED);
68 if (err_offset >= 0 &&
69 err_offset < (nested ? NLA_HDRLEN : attr->nla_len)) {
70 prefix = "===>";
71 if (err_offset)
72 fprintf(stderr,
73 "ethtool: bad_attr inside an attribute (offset %d)\n",
74 err_offset);
75 }
76 if (adesc && adesc->name && !in_array)
77 printf("%s%*s%s", prefix, level * __INDENT, "", adesc->name);
78 else
79 printf("%s%*s[%u]", prefix, level * __INDENT, "", atype);
80
81 if (nested) {
82 struct nlattr *child;
83 int ret = 0;
84
85 putchar('\n');
86 mnl_attr_for_each_nested(child, attr) {
87 bool array = adesc && adesc->format == NLA_ARRAY;
88 unsigned int child_off;
89
90 child_off = (const char *)child - (const char *)attr;
91 ret = pretty_print_attr(child,
92 adesc ? adesc->children : NULL,
93 adesc ? adesc->n_children : 0,
94 level + 1,
95 err_offset - child_off, array);
96 if (ret < 0)
97 break;
98 }
99
100 return ret;
101 }
102
103 printf(" = ");
104 switch(adesc ? adesc->format : NLA_BINARY) {
105 case NLA_U8:
106 printf("%u", mnl_attr_get_u8(attr));
107 break;
108 case NLA_U16:
109 printf("%u", mnl_attr_get_u16(attr));
110 break;
111 case NLA_U32:
112 printf("%u", mnl_attr_get_u32(attr));
113 break;
114 case NLA_U64:
115 printf("%" PRIu64, mnl_attr_get_u64(attr));
116 break;
117 case NLA_X8:
118 printf("0x%02x", mnl_attr_get_u8(attr));
119 break;
120 case NLA_X16:
121 printf("0x%04x", mnl_attr_get_u16(attr));
122 break;
123 case NLA_X32:
124 printf("0x%08x", mnl_attr_get_u32(attr));
125 break;
126 case NLA_X64:
127 printf("%" PRIx64, mnl_attr_get_u64(attr));
128 break;
129 case NLA_S8:
130 printf("%d", (int)mnl_attr_get_u8(attr));
131 break;
132 case NLA_S16:
133 printf("%d", (int)mnl_attr_get_u16(attr));
134 break;
135 case NLA_S32:
136 printf("%d", (int)mnl_attr_get_u32(attr));
137 break;
138 case NLA_S64:
139 printf("%" PRId64, (int64_t)mnl_attr_get_u64(attr));
140 break;
141 case NLA_STRING:
142 printf("\"%.*s\"", alen, (const char *)adata);
143 break;
144 case NLA_FLAG:
145 printf("true");
146 break;
147 case NLA_BOOL:
148 printf("%s", mnl_attr_get_u8(attr) ? "on" : "off");
149 break;
150 case NLA_U8_ENUM:
151 case NLA_U32_ENUM: {
152 uint32_t val;
153
154 if (adesc->format == NLA_U8_ENUM)
155 val = mnl_attr_get_u8(attr);
156 else
157 val = mnl_attr_get_u32(attr);
158
159 if (adesc && val < adesc->n_names && adesc->names[val])
160 printf("%s", adesc->names[val]);
161 else
162 printf("%u", val);
163 break;
164 }
165 default:
166 if (alen <= __DUMP_LINE)
167 __print_binary_short(adata, alen);
168 else
169 __print_binary_long(adata, alen, level);
170 }
171 putchar('\n');
172
173 return 0;
174 }
175
pretty_print_nlmsg(const struct nlmsghdr * nlhdr,unsigned int payload_offset,const struct pretty_nla_desc * desc,unsigned int ndesc,unsigned int err_offset)176 static int pretty_print_nlmsg(const struct nlmsghdr *nlhdr,
177 unsigned int payload_offset,
178 const struct pretty_nla_desc *desc,
179 unsigned int ndesc, unsigned int err_offset)
180 {
181 const struct nlattr *attr;
182 int attr_offset;
183 int ret;
184
185 mnl_attr_for_each(attr, nlhdr, payload_offset) {
186 attr_offset = (const char *)attr - (const char *)nlhdr;
187 ret = pretty_print_attr(attr, desc, ndesc, 1,
188 err_offset - attr_offset, false);
189 if (ret < 0)
190 return ret;
191 }
192
193 return 0;
194 }
195
pretty_print_genlmsg(const struct nlmsghdr * nlhdr,const struct pretty_nlmsg_desc * desc,unsigned int ndesc,unsigned int err_offset)196 int pretty_print_genlmsg(const struct nlmsghdr *nlhdr,
197 const struct pretty_nlmsg_desc *desc,
198 unsigned int ndesc, unsigned int err_offset)
199 {
200 const struct pretty_nlmsg_desc *msg_desc;
201 const struct genlmsghdr *genlhdr;
202
203 if (mnl_nlmsg_get_payload_len(nlhdr) < GENL_HDRLEN) {
204 fprintf(stderr, "ethtool: message too short (%u bytes)\n",
205 nlhdr->nlmsg_len);
206 return -EINVAL;
207 }
208 genlhdr = mnl_nlmsg_get_payload(nlhdr);
209 msg_desc = (desc && genlhdr->cmd < ndesc) ? &desc[genlhdr->cmd] : NULL;
210 if (msg_desc && msg_desc->name)
211 printf(" %s\n", msg_desc->name);
212 else
213 printf(" [%u]\n", genlhdr->cmd);
214
215 return pretty_print_nlmsg(nlhdr, GENL_HDRLEN,
216 msg_desc ? msg_desc->attrs : NULL,
217 msg_desc ? msg_desc->n_attrs : 0, err_offset);
218 }
219
rtm_link_summary(const struct ifinfomsg * ifinfo)220 static void rtm_link_summary(const struct ifinfomsg *ifinfo)
221 {
222 if (ifinfo->ifi_family)
223 printf(" family=%u", ifinfo->ifi_family);
224 if (ifinfo->ifi_type)
225 printf(" type=0x%04x", ifinfo->ifi_type);
226 if (ifinfo->ifi_index)
227 printf(" ifindex=%d", ifinfo->ifi_index);
228 if (ifinfo->ifi_flags)
229 printf(" flags=0x%x", ifinfo->ifi_flags);
230 if (ifinfo->ifi_change)
231 printf(" change=0x%x", ifinfo->ifi_change);
232 }
233
pretty_print_rtnlmsg(const struct nlmsghdr * nlhdr,unsigned int err_offset)234 int pretty_print_rtnlmsg(const struct nlmsghdr *nlhdr, unsigned int err_offset)
235 {
236 const unsigned int idx = (nlhdr->nlmsg_type - RTM_BASE) / 4;
237 const struct pretty_nlmsg_desc *msg_desc = NULL;
238 unsigned int hdrlen = USHRT_MAX;
239
240 if (nlhdr->nlmsg_type < rtnl_msg_n_desc)
241 msg_desc = &rtnl_msg_desc[nlhdr->nlmsg_type];
242 if (idx < rtnl_msghdr_n_len)
243 hdrlen = rtnl_msghdr_lengths[idx];
244 if (hdrlen < USHRT_MAX && mnl_nlmsg_get_payload_len(nlhdr) < hdrlen) {
245 fprintf(stderr, "ethtool: message too short (%u bytes)\n",
246 nlhdr->nlmsg_len);
247 return -EINVAL;
248 }
249 if (msg_desc && msg_desc->name)
250 printf(" %s", msg_desc->name);
251 else
252 printf(" [%u]", nlhdr->nlmsg_type);
253 if (idx == (RTM_NEWLINK - RTM_BASE) / 4)
254 rtm_link_summary(mnl_nlmsg_get_payload(nlhdr));
255 putchar('\n');
256 if (hdrlen == USHRT_MAX)
257 return 0;
258
259 return pretty_print_nlmsg(nlhdr, hdrlen,
260 msg_desc ? msg_desc->attrs : NULL,
261 msg_desc ? msg_desc->n_attrs : 0, err_offset);
262 }
263