xref: /aosp_15_r20/external/ethtool/netlink/mm.c (revision 1b481fc3bb1b45d4cf28d1ec12969dc1055f555d)
1 /*
2  * mm.c - netlink implementation of MAC merge layer settings
3  *
4  * Implementation of "ethtool --show-mm <dev>" and "ethtool --set-mm <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 #include "parser.h"
17 
18 /* MM_GET */
19 
20 static const char *
mm_verify_state_to_string(enum ethtool_mm_verify_status state)21 mm_verify_state_to_string(enum ethtool_mm_verify_status state)
22 {
23 	switch (state) {
24 	case ETHTOOL_MM_VERIFY_STATUS_INITIAL:
25 		return "INITIAL";
26 	case ETHTOOL_MM_VERIFY_STATUS_VERIFYING:
27 		return "VERIFYING";
28 	case ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED:
29 		return "SUCCEEDED";
30 	case ETHTOOL_MM_VERIFY_STATUS_FAILED:
31 		return "FAILED";
32 	case ETHTOOL_MM_VERIFY_STATUS_DISABLED:
33 		return "DISABLED";
34 	default:
35 		return "UNKNOWN";
36 	}
37 }
38 
show_mm_stats(const struct nlattr * nest)39 static int show_mm_stats(const struct nlattr *nest)
40 {
41 	const struct nlattr *tb[ETHTOOL_A_MM_STAT_MAX + 1] = {};
42 	DECLARE_ATTR_TB_INFO(tb);
43 	static const struct {
44 		unsigned int attr;
45 		char *name;
46 	} stats[] = {
47 		{ ETHTOOL_A_MM_STAT_REASSEMBLY_ERRORS, "MACMergeFrameAssErrorCount" },
48 		{ ETHTOOL_A_MM_STAT_SMD_ERRORS, "MACMergeFrameSmdErrorCount" },
49 		{ ETHTOOL_A_MM_STAT_REASSEMBLY_OK, "MACMergeFrameAssOkCount" },
50 		{ ETHTOOL_A_MM_STAT_RX_FRAG_COUNT, "MACMergeFragCountRx" },
51 		{ ETHTOOL_A_MM_STAT_TX_FRAG_COUNT, "MACMergeFragCountTx" },
52 		{ ETHTOOL_A_MM_STAT_HOLD_COUNT, "MACMergeHoldCount" },
53 	};
54 	bool header = false;
55 	unsigned int i;
56 	size_t n;
57 	int ret;
58 
59 	ret = mnl_attr_parse_nested(nest, attr_cb, &tb_info);
60 	if (ret < 0)
61 		return ret;
62 
63 	open_json_object("statistics");
64 	for (i = 0; i < ARRAY_SIZE(stats); i++) {
65 		char fmt[64];
66 
67 		if (!tb[stats[i].attr])
68 			continue;
69 
70 		if (!header && !is_json_context()) {
71 			printf("Statistics:\n");
72 			header = true;
73 		}
74 
75 		if (mnl_attr_validate(tb[stats[i].attr], MNL_TYPE_U64)) {
76 			fprintf(stderr, "malformed netlink message (statistic)\n");
77 			goto err_close_stats;
78 		}
79 
80 		n = snprintf(fmt, sizeof(fmt), "  %s: %%" PRIu64 "\n",
81 			     stats[i].name);
82 		if (n >= sizeof(fmt)) {
83 			fprintf(stderr, "internal error - malformed label\n");
84 			continue;
85 		}
86 
87 		print_u64(PRINT_ANY, stats[i].name, fmt,
88 			  mnl_attr_get_u64(tb[stats[i].attr]));
89 	}
90 	close_json_object();
91 
92 	return 0;
93 
94 err_close_stats:
95 	close_json_object();
96 	return -1;
97 }
98 
mm_reply_cb(const struct nlmsghdr * nlhdr,void * data)99 int mm_reply_cb(const struct nlmsghdr *nlhdr, void *data)
100 {
101 	const struct nlattr *tb[ETHTOOL_A_MM_MAX + 1] = {};
102 	struct nl_context *nlctx = data;
103 	DECLARE_ATTR_TB_INFO(tb);
104 	bool silent;
105 	int err_ret;
106 	int ret;
107 
108 	silent = nlctx->is_dump || nlctx->is_monitor;
109 	err_ret = silent ? MNL_CB_OK : MNL_CB_ERROR;
110 	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
111 	if (ret < 0)
112 		return err_ret;
113 	nlctx->devname = get_dev_name(tb[ETHTOOL_A_MM_HEADER]);
114 	if (!dev_ok(nlctx))
115 		return err_ret;
116 
117 	if (silent)
118 		print_nl();
119 
120 	open_json_object(NULL);
121 
122 	print_string(PRINT_ANY, "ifname", "MAC Merge layer state for %s:\n",
123 		     nlctx->devname);
124 
125 	show_bool("pmac-enabled", "pMAC enabled: %s\n",
126 		  tb[ETHTOOL_A_MM_PMAC_ENABLED]);
127 	show_bool("tx-enabled", "TX enabled: %s\n",
128 		  tb[ETHTOOL_A_MM_TX_ENABLED]);
129 	show_bool("tx-active", "TX active: %s\n", tb[ETHTOOL_A_MM_TX_ACTIVE]);
130 	show_u32("tx-min-frag-size", "TX minimum fragment size: ",
131 		 tb[ETHTOOL_A_MM_TX_MIN_FRAG_SIZE]);
132 	show_u32("rx-min-frag-size", "RX minimum fragment size: ",
133 		 tb[ETHTOOL_A_MM_RX_MIN_FRAG_SIZE]);
134 	show_bool("verify-enabled", "Verify enabled: %s\n",
135 		  tb[ETHTOOL_A_MM_VERIFY_ENABLED]);
136 	show_u32("verify-time", "Verify time: ",
137 		 tb[ETHTOOL_A_MM_VERIFY_TIME]);
138 	show_u32("max-verify-time", "Max verify time: ",
139 		 tb[ETHTOOL_A_MM_MAX_VERIFY_TIME]);
140 
141 	if (tb[ETHTOOL_A_MM_VERIFY_STATUS]) {
142 		u8 val = mnl_attr_get_u8(tb[ETHTOOL_A_MM_VERIFY_STATUS]);
143 
144 		print_string(PRINT_ANY, "verify-status", "Verification status: %s\n",
145 			     mm_verify_state_to_string(val));
146 	}
147 
148 	if (tb[ETHTOOL_A_MM_STATS]) {
149 		ret = show_mm_stats(tb[ETHTOOL_A_MM_STATS]);
150 		if (ret) {
151 			fprintf(stderr, "Failed to print stats: %d\n", ret);
152 			goto err;
153 		}
154 	}
155 
156 	if (!silent)
157 		print_nl();
158 
159 	close_json_object();
160 
161 	return MNL_CB_OK;
162 
163 err:
164 	close_json_object();
165 	return err_ret;
166 }
167 
nl_get_mm(struct cmd_context * ctx)168 int nl_get_mm(struct cmd_context *ctx)
169 {
170 	struct nl_context *nlctx = ctx->nlctx;
171 	struct nl_socket *nlsk = nlctx->ethnl_socket;
172 	u32 flags;
173 	int ret;
174 
175 	if (netlink_cmd_check(ctx, ETHTOOL_MSG_MM_GET, true))
176 		return -EOPNOTSUPP;
177 	if (ctx->argc > 0) {
178 		fprintf(stderr, "ethtool: unexpected parameter '%s'\n",
179 			*ctx->argp);
180 		return 1;
181 	}
182 
183 	flags = get_stats_flag(nlctx, ETHTOOL_MSG_MM_GET, ETHTOOL_A_MM_HEADER);
184 	ret = nlsock_prep_get_request(nlsk, ETHTOOL_MSG_MM_GET,
185 				      ETHTOOL_A_MM_HEADER, flags);
186 	if (ret)
187 		return ret;
188 
189 	new_json_obj(ctx->json);
190 	ret = nlsock_send_get_request(nlsk, mm_reply_cb);
191 	delete_json_obj();
192 	return ret;
193 }
194 
195 /* MM_SET */
196 
197 static const struct param_parser mm_set_params[] = {
198 	{
199 		.arg		= "verify-enabled",
200 		.type		= ETHTOOL_A_MM_VERIFY_ENABLED,
201 		.handler	= nl_parse_u8bool,
202 		.min_argc	= 1,
203 	},
204 	{
205 		.arg		= "verify-time",
206 		.type		= ETHTOOL_A_MM_VERIFY_TIME,
207 		.handler	= nl_parse_direct_u32,
208 		.min_argc	= 1,
209 	},
210 	{
211 		.arg		= "tx-enabled",
212 		.type		= ETHTOOL_A_MM_TX_ENABLED,
213 		.handler	= nl_parse_u8bool,
214 		.min_argc	= 1,
215 	},
216 	{
217 		.arg		= "pmac-enabled",
218 		.type		= ETHTOOL_A_MM_PMAC_ENABLED,
219 		.handler	= nl_parse_u8bool,
220 		.min_argc	= 1,
221 	},
222 	{
223 		.arg		= "tx-min-frag-size",
224 		.type		= ETHTOOL_A_MM_TX_MIN_FRAG_SIZE,
225 		.handler	= nl_parse_direct_u32,
226 		.min_argc	= 1,
227 	},
228 	{}
229 };
230 
nl_set_mm(struct cmd_context * ctx)231 int nl_set_mm(struct cmd_context *ctx)
232 {
233 	struct nl_context *nlctx = ctx->nlctx;
234 	struct nl_msg_buff *msgbuff;
235 	struct nl_socket *nlsk;
236 	int ret;
237 
238 	if (netlink_cmd_check(ctx, ETHTOOL_MSG_MM_SET, false))
239 		return -EOPNOTSUPP;
240 
241 	nlctx->cmd = "--set-mm";
242 	nlctx->argp = ctx->argp;
243 	nlctx->argc = ctx->argc;
244 	nlctx->devname = ctx->devname;
245 	nlsk = nlctx->ethnl_socket;
246 	msgbuff = &nlsk->msgbuff;
247 
248 	ret = msg_init(nlctx, msgbuff, ETHTOOL_MSG_MM_SET,
249 		       NLM_F_REQUEST | NLM_F_ACK);
250 	if (ret)
251 		return ret;
252 
253 	if (ethnla_fill_header(msgbuff, ETHTOOL_A_MM_HEADER,
254 			       ctx->devname, 0))
255 		return -EMSGSIZE;
256 
257 	ret = nl_parser(nlctx, mm_set_params, NULL, PARSER_GROUP_NONE, NULL);
258 	if (ret)
259 		return ret;
260 
261 	ret = nlsock_sendmsg(nlsk, NULL);
262 	if (ret < 0)
263 		return ret;
264 
265 	ret = nlsock_process_reply(nlsk, nomsg_reply_cb, nlctx);
266 	if (ret)
267 		return nlctx->exit_code;
268 
269 	return 0;
270 }
271