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