1 /*
2 * rings.c - netlink implementation of ring commands
3 *
4 * Implementation of "ethtool -g <dev>" and "ethtool -G <dev> ..."
5 */
6
7 #include <errno.h>
8 #include <string.h>
9 #include <stdio.h>
10
11 #include "../internal.h"
12 #include "../common.h"
13 #include "netlink.h"
14 #include "parser.h"
15
16 /* RINGS_GET */
17
rings_reply_cb(const struct nlmsghdr * nlhdr,void * data)18 int rings_reply_cb(const struct nlmsghdr *nlhdr, void *data)
19 {
20 const struct nlattr *tb[ETHTOOL_A_RINGS_MAX + 1] = {};
21 DECLARE_ATTR_TB_INFO(tb);
22 struct nl_context *nlctx = data;
23 unsigned char tcp_hds;
24 char *tcp_hds_fmt;
25 char *tcp_hds_key;
26 char tcp_hds_buf[256];
27 bool silent;
28 int err_ret;
29 int ret;
30
31 silent = nlctx->is_dump || nlctx->is_monitor;
32 err_ret = silent ? MNL_CB_OK : MNL_CB_ERROR;
33 ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
34 if (ret < 0)
35 return err_ret;
36 nlctx->devname = get_dev_name(tb[ETHTOOL_A_RINGS_HEADER]);
37 if (!dev_ok(nlctx))
38 return err_ret;
39
40 open_json_object(NULL);
41
42 if (silent)
43 show_cr();
44 print_string(PRINT_ANY, "ifname", "Ring parameters for %s:\n",
45 nlctx->devname);
46 print_string(PRINT_FP, NULL, "Pre-set maximums:\n", NULL);
47 show_u32("rx-max", "RX:\t\t\t", tb[ETHTOOL_A_RINGS_RX_MAX]);
48 show_u32("rx-mini-max", "RX Mini:\t\t", tb[ETHTOOL_A_RINGS_RX_MINI_MAX]);
49 show_u32("rx-jumbo-max", "RX Jumbo:\t\t",
50 tb[ETHTOOL_A_RINGS_RX_JUMBO_MAX]);
51 show_u32("tx-max", "TX:\t\t\t", tb[ETHTOOL_A_RINGS_TX_MAX]);
52 show_u32("tx-push-buff-max-len", "TX push buff len:\t",
53 tb[ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX]);
54 print_string(PRINT_FP, NULL, "Current hardware settings:\n", NULL);
55 show_u32("rx", "RX:\t\t\t", tb[ETHTOOL_A_RINGS_RX]);
56 show_u32("rx-mini", "RX Mini:\t\t", tb[ETHTOOL_A_RINGS_RX_MINI]);
57 show_u32("rx-jumbo", "RX Jumbo:\t\t", tb[ETHTOOL_A_RINGS_RX_JUMBO]);
58 show_u32("tx", "TX:\t\t\t", tb[ETHTOOL_A_RINGS_TX]);
59 show_u32("rx-buf-len", "RX Buf Len:\t\t", tb[ETHTOOL_A_RINGS_RX_BUF_LEN]);
60 show_u32("cqe-size", "CQE Size:\t\t", tb[ETHTOOL_A_RINGS_CQE_SIZE]);
61 show_bool("tx-push", "TX Push:\t\t%s\n", tb[ETHTOOL_A_RINGS_TX_PUSH]);
62 show_bool("rx-push", "RX Push:\t\t%s\n", tb[ETHTOOL_A_RINGS_RX_PUSH]);
63 show_u32("tx-push-buf-len", "TX push buff len:\t",
64 tb[ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN]);
65
66 tcp_hds_fmt = "TCP data split:\t\t%s\n";
67 tcp_hds_key = "tcp-data-split";
68 tcp_hds = tb[ETHTOOL_A_RINGS_TCP_DATA_SPLIT] ?
69 mnl_attr_get_u8(tb[ETHTOOL_A_RINGS_TCP_DATA_SPLIT]) : 0;
70 switch (tcp_hds) {
71 case ETHTOOL_TCP_DATA_SPLIT_UNKNOWN:
72 print_string(PRINT_FP, tcp_hds_key, tcp_hds_fmt, "n/a");
73 break;
74 case ETHTOOL_TCP_DATA_SPLIT_DISABLED:
75 print_string(PRINT_ANY, tcp_hds_key, tcp_hds_fmt, "off");
76 break;
77 case ETHTOOL_TCP_DATA_SPLIT_ENABLED:
78 print_string(PRINT_ANY, tcp_hds_key, tcp_hds_fmt, "on");
79 break;
80 default:
81 snprintf(tcp_hds_buf, sizeof(tcp_hds_buf),
82 "unknown(%d)\n", tcp_hds);
83 print_string(PRINT_ANY, tcp_hds_key, tcp_hds_fmt, tcp_hds_buf);
84 break;
85 }
86
87 close_json_object();
88
89 return MNL_CB_OK;
90 }
91
nl_gring(struct cmd_context * ctx)92 int nl_gring(struct cmd_context *ctx)
93 {
94 struct nl_context *nlctx = ctx->nlctx;
95 struct nl_socket *nlsk = nlctx->ethnl_socket;
96 int ret;
97
98 if (netlink_cmd_check(ctx, ETHTOOL_MSG_RINGS_GET, true))
99 return -EOPNOTSUPP;
100 if (ctx->argc > 0) {
101 fprintf(stderr, "ethtool: unexpected parameter '%s'\n",
102 *ctx->argp);
103 return 1;
104 }
105
106 ret = nlsock_prep_get_request(nlsk, ETHTOOL_MSG_RINGS_GET,
107 ETHTOOL_A_RINGS_HEADER, 0);
108 if (ret < 0)
109 return ret;
110
111 new_json_obj(ctx->json);
112 ret = nlsock_send_get_request(nlsk, rings_reply_cb);
113 delete_json_obj();
114 return ret;
115 }
116
117 /* RINGS_SET */
118
119 static const struct param_parser sring_params[] = {
120 {
121 .arg = "rx",
122 .type = ETHTOOL_A_RINGS_RX,
123 .handler = nl_parse_direct_u32,
124 .min_argc = 1,
125 },
126 {
127 .arg = "rx-mini",
128 .type = ETHTOOL_A_RINGS_RX_MINI,
129 .handler = nl_parse_direct_u32,
130 .min_argc = 1,
131 },
132 {
133 .arg = "rx-jumbo",
134 .type = ETHTOOL_A_RINGS_RX_JUMBO,
135 .handler = nl_parse_direct_u32,
136 .min_argc = 1,
137 },
138 {
139 .arg = "tx",
140 .type = ETHTOOL_A_RINGS_TX,
141 .handler = nl_parse_direct_u32,
142 .min_argc = 1,
143 },
144 {
145 .arg = "tx-push-buf-len",
146 .type = ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN,
147 .handler = nl_parse_direct_u32,
148 .min_argc = 1,
149 },
150 {
151 .arg = "rx-buf-len",
152 .type = ETHTOOL_A_RINGS_RX_BUF_LEN,
153 .handler = nl_parse_direct_u32,
154 .min_argc = 1,
155 },
156 {
157 .arg = "cqe-size",
158 .type = ETHTOOL_A_RINGS_CQE_SIZE,
159 .handler = nl_parse_direct_u32,
160 .min_argc = 1,
161 },
162 {
163 .arg = "tx-push",
164 .type = ETHTOOL_A_RINGS_TX_PUSH,
165 .handler = nl_parse_u8bool,
166 .min_argc = 1,
167 },
168 {
169 .arg = "rx-push",
170 .type = ETHTOOL_A_RINGS_RX_PUSH,
171 .handler = nl_parse_u8bool,
172 .min_argc = 1,
173 },
174 {}
175 };
176
nl_sring(struct cmd_context * ctx)177 int nl_sring(struct cmd_context *ctx)
178 {
179 struct nl_context *nlctx = ctx->nlctx;
180 struct nl_msg_buff *msgbuff;
181 struct nl_socket *nlsk;
182 int ret;
183
184 if (netlink_cmd_check(ctx, ETHTOOL_MSG_RINGS_SET, false))
185 return -EOPNOTSUPP;
186
187 nlctx->cmd = "-G";
188 nlctx->argp = ctx->argp;
189 nlctx->argc = ctx->argc;
190 nlctx->devname = ctx->devname;
191 nlsk = nlctx->ethnl_socket;
192 msgbuff = &nlsk->msgbuff;
193
194 ret = msg_init(nlctx, msgbuff, ETHTOOL_MSG_RINGS_SET,
195 NLM_F_REQUEST | NLM_F_ACK);
196 if (ret < 0)
197 return 2;
198 if (ethnla_fill_header(msgbuff, ETHTOOL_A_RINGS_HEADER,
199 ctx->devname, 0))
200 return -EMSGSIZE;
201
202 ret = nl_parser(nlctx, sring_params, NULL, PARSER_GROUP_NONE, NULL);
203 if (ret < 0)
204 return 1;
205
206 ret = nlsock_sendmsg(nlsk, NULL);
207 if (ret < 0)
208 return 81;
209 ret = nlsock_process_reply(nlsk, nomsg_reply_cb, nlctx);
210 if (ret == 0)
211 return 0;
212 else
213 return nlctx->exit_code ?: 81;
214 }
215