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