• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * tsinfo.c - netlink implementation of timestamping commands
3  *
4  * Implementation of "ethtool -T <dev>"
5  */
6 
7 #include <errno.h>
8 #include <inttypes.h>
9 #include <string.h>
10 #include <stdio.h>
11 
12 #include "../internal.h"
13 #include "../common.h"
14 #include "netlink.h"
15 #include "bitset.h"
16 
17 /* TSINFO_GET */
18 
tsinfo_show_stats(const struct nlattr * nest)19 static int tsinfo_show_stats(const struct nlattr *nest)
20 {
21 	const struct nlattr *tb[ETHTOOL_A_TS_STAT_MAX + 1] = {};
22 	DECLARE_ATTR_TB_INFO(tb);
23 	static const struct {
24 		unsigned int attr;
25 		char *name;
26 	} stats[] = {
27 		{ ETHTOOL_A_TS_STAT_TX_PKTS, "tx_pkts" },
28 		{ ETHTOOL_A_TS_STAT_TX_LOST, "tx_lost" },
29 		{ ETHTOOL_A_TS_STAT_TX_ERR, "tx_err" },
30 	};
31 	bool header = false;
32 	unsigned int i;
33 	__u64 val;
34 	int ret;
35 
36 	ret = mnl_attr_parse_nested(nest, attr_cb, &tb_info);
37 	if (ret < 0)
38 		return ret;
39 
40 	open_json_object("statistics");
41 	for (i = 0; i < ARRAY_SIZE(stats); i++) {
42 		char fmt[64];
43 
44 		if (!tb[stats[i].attr])
45 			continue;
46 
47 		if (!header && !is_json_context()) {
48 			printf("Statistics:\n");
49 			header = true;
50 		}
51 
52 		if (!mnl_attr_validate(tb[stats[i].attr], MNL_TYPE_U32)) {
53 			val = mnl_attr_get_u32(tb[stats[i].attr]);
54 		} else if (!mnl_attr_validate(tb[stats[i].attr], MNL_TYPE_U64)) {
55 			val = mnl_attr_get_u64(tb[stats[i].attr]);
56 		} else {
57 			fprintf(stderr, "malformed netlink message (statistic)\n");
58 			goto err_close_stats;
59 		}
60 
61 		snprintf(fmt, sizeof(fmt), "  %s: %%" PRIu64 "\n", stats[i].name);
62 		print_u64(PRINT_ANY, stats[i].name, fmt, val);
63 	}
64 	close_json_object();
65 
66 	return 0;
67 
68 err_close_stats:
69 	close_json_object();
70 	return -1;
71 }
72 
tsinfo_dump_cb(unsigned int idx,const char * name,bool val,void * data __maybe_unused)73 static void tsinfo_dump_cb(unsigned int idx, const char *name, bool val,
74 			   void *data __maybe_unused)
75 {
76 	if (!val)
77 		return;
78 
79 	if (name)
80 		printf("\t%s\n", name);
81 	else
82 		printf("\tbit%u\n", idx);
83 }
84 
tsinfo_dump_list(struct nl_context * nlctx,const struct nlattr * attr,const char * label,const char * if_empty,unsigned int stringset_id)85 static int tsinfo_dump_list(struct nl_context *nlctx, const struct nlattr *attr,
86 			    const char *label, const char *if_empty,
87 			    unsigned int stringset_id)
88 {
89 	const struct stringset *strings = NULL;
90 	int ret;
91 
92 	printf("%s:", label);
93 	ret = 0;
94 	if (!attr || bitset_is_empty(attr, false, &ret)) {
95 		printf("%s\n", if_empty);
96 		return ret;
97 	}
98 	putchar('\n');
99 	if (ret < 0)
100 		return ret;
101 
102 	if (bitset_is_compact(attr)) {
103 		ret = netlink_init_ethnl2_socket(nlctx);
104 		if (ret < 0)
105 			return ret;
106 		strings = global_stringset(stringset_id, nlctx->ethnl2_socket);
107 	}
108 	return walk_bitset(attr, strings, tsinfo_dump_cb, NULL);
109 }
110 
tsinfo_reply_cb(const struct nlmsghdr * nlhdr,void * data)111 int tsinfo_reply_cb(const struct nlmsghdr *nlhdr, void *data)
112 {
113 	const struct nlattr *tb[ETHTOOL_A_TSINFO_MAX + 1] = {};
114 	DECLARE_ATTR_TB_INFO(tb);
115 	struct nl_context *nlctx = data;
116 	bool silent;
117 	int err_ret;
118 	int ret;
119 
120 	silent = nlctx->is_dump;
121 	err_ret = silent ? MNL_CB_OK : MNL_CB_ERROR;
122 	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
123 	if (ret < 0)
124 		return err_ret;
125 	nlctx->devname = get_dev_name(tb[ETHTOOL_A_TSINFO_HEADER]);
126 	if (!dev_ok(nlctx))
127 		return err_ret;
128 
129 	if (silent)
130 		putchar('\n');
131 	printf("Time stamping parameters for %s:\n", nlctx->devname);
132 
133 	ret = tsinfo_dump_list(nlctx, tb[ETHTOOL_A_TSINFO_TIMESTAMPING],
134 			       "Capabilities", "", ETH_SS_SOF_TIMESTAMPING);
135 	if (ret < 0)
136 		return err_ret;
137 
138 	printf("PTP Hardware Clock: ");
139 	if (tb[ETHTOOL_A_TSINFO_PHC_INDEX])
140 		printf("%d\n",
141 		       mnl_attr_get_u32(tb[ETHTOOL_A_TSINFO_PHC_INDEX]));
142 	else
143 		printf("none\n");
144 
145 	ret = tsinfo_dump_list(nlctx, tb[ETHTOOL_A_TSINFO_TX_TYPES],
146 			       "Hardware Transmit Timestamp Modes", " none",
147 			       ETH_SS_TS_TX_TYPES);
148 	if (ret < 0)
149 		return err_ret;
150 
151 	ret = tsinfo_dump_list(nlctx, tb[ETHTOOL_A_TSINFO_RX_FILTERS],
152 			       "Hardware Receive Filter Modes", " none",
153 			       ETH_SS_TS_RX_FILTERS);
154 	if (ret < 0)
155 		return err_ret;
156 
157 	if (tb[ETHTOOL_A_TSINFO_STATS]) {
158 		ret = tsinfo_show_stats(tb[ETHTOOL_A_TSINFO_STATS]);
159 		if (ret < 0)
160 			return err_ret;
161 	}
162 
163 	return MNL_CB_OK;
164 }
165 
nl_tsinfo(struct cmd_context * ctx)166 int nl_tsinfo(struct cmd_context *ctx)
167 {
168 	struct nl_context *nlctx = ctx->nlctx;
169 	struct nl_socket *nlsk = nlctx->ethnl_socket;
170 	u32 flags;
171 	int ret;
172 
173 	if (netlink_cmd_check(ctx, ETHTOOL_MSG_TSINFO_GET, true))
174 		return -EOPNOTSUPP;
175 	if (ctx->argc > 0) {
176 		fprintf(stderr, "ethtool: unexpected parameter '%s'\n",
177 			*ctx->argp);
178 		return 1;
179 	}
180 
181 	flags = get_stats_flag(nlctx, ETHTOOL_MSG_TSINFO_GET, ETHTOOL_A_TSINFO_HEADER);
182 	ret = nlsock_prep_get_request(nlsk, ETHTOOL_MSG_TSINFO_GET,
183 				      ETHTOOL_A_TSINFO_HEADER, flags);
184 	if (ret < 0)
185 		return ret;
186 	return nlsock_send_get_request(nlsk, tsinfo_reply_cb);
187 }
188