xref: /dpdk/examples/ethtool/ethtool-app/ethapp.c (revision a997a33b2a0145ad3e6320ea1fc7df8d51a2fcdf)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2015 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <cmdline_parse.h>
35 #include <cmdline_parse_num.h>
36 #include <cmdline_parse_string.h>
37 #include <cmdline_parse_etheraddr.h>
38 #include <cmdline_socket.h>
39 #include <cmdline.h>
40 
41 #include "rte_ethtool.h"
42 #include "ethapp.h"
43 
44 #define EEPROM_DUMP_CHUNKSIZE 1024
45 
46 
47 struct pcmd_get_params {
48 	cmdline_fixed_string_t cmd;
49 };
50 struct pcmd_int_params {
51 	cmdline_fixed_string_t cmd;
52 	uint16_t port;
53 };
54 struct pcmd_intstr_params {
55 	cmdline_fixed_string_t cmd;
56 	uint16_t port;
57 	cmdline_fixed_string_t opt;
58 };
59 struct pcmd_intmac_params {
60 	cmdline_fixed_string_t cmd;
61 	uint16_t port;
62 	struct ether_addr mac;
63 };
64 struct pcmd_str_params {
65 	cmdline_fixed_string_t cmd;
66 	cmdline_fixed_string_t opt;
67 };
68 struct pcmd_vlan_params {
69 	cmdline_fixed_string_t cmd;
70 	uint16_t port;
71 	cmdline_fixed_string_t mode;
72 	uint16_t vid;
73 };
74 struct pcmd_intintint_params {
75 	cmdline_fixed_string_t cmd;
76 	uint16_t port;
77 	uint16_t tx;
78 	uint16_t rx;
79 };
80 
81 
82 /* Parameter-less commands */
83 cmdline_parse_token_string_t pcmd_quit_token_cmd =
84 	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "quit");
85 cmdline_parse_token_string_t pcmd_stats_token_cmd =
86 	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "stats");
87 cmdline_parse_token_string_t pcmd_drvinfo_token_cmd =
88 	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "drvinfo");
89 cmdline_parse_token_string_t pcmd_link_token_cmd =
90 	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "link");
91 
92 /* Commands taking just port id */
93 cmdline_parse_token_string_t pcmd_open_token_cmd =
94 	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "open");
95 cmdline_parse_token_string_t pcmd_stop_token_cmd =
96 	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "stop");
97 cmdline_parse_token_string_t pcmd_rxmode_token_cmd =
98 	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "rxmode");
99 cmdline_parse_token_string_t pcmd_portstats_token_cmd =
100 	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "portstats");
101 cmdline_parse_token_num_t pcmd_int_token_port =
102 	TOKEN_NUM_INITIALIZER(struct pcmd_int_params, port, UINT16);
103 
104 /* Commands taking port id and string */
105 cmdline_parse_token_string_t pcmd_eeprom_token_cmd =
106 	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "eeprom");
107 cmdline_parse_token_string_t pcmd_mtu_token_cmd =
108 	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "mtu");
109 cmdline_parse_token_string_t pcmd_regs_token_cmd =
110 	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "regs");
111 
112 cmdline_parse_token_num_t pcmd_intstr_token_port =
113 	TOKEN_NUM_INITIALIZER(struct pcmd_intstr_params, port, UINT16);
114 cmdline_parse_token_string_t pcmd_intstr_token_opt =
115 	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, opt, NULL);
116 
117 /* Commands taking port id and a MAC address string */
118 cmdline_parse_token_string_t pcmd_macaddr_token_cmd =
119 	TOKEN_STRING_INITIALIZER(struct pcmd_intmac_params, cmd, "macaddr");
120 cmdline_parse_token_num_t pcmd_intmac_token_port =
121 	TOKEN_NUM_INITIALIZER(struct pcmd_intmac_params, port, UINT16);
122 cmdline_parse_token_etheraddr_t pcmd_intmac_token_mac =
123 	TOKEN_ETHERADDR_INITIALIZER(struct pcmd_intmac_params, mac);
124 
125 /* Command taking just a MAC address */
126 cmdline_parse_token_string_t pcmd_validate_token_cmd =
127 	TOKEN_STRING_INITIALIZER(struct pcmd_intmac_params, cmd, "validate");
128 
129 
130 /* Commands taking port id and two integers */
131 cmdline_parse_token_string_t pcmd_ringparam_token_cmd =
132 	TOKEN_STRING_INITIALIZER(struct pcmd_intintint_params, cmd,
133 		"ringparam");
134 cmdline_parse_token_num_t pcmd_intintint_token_port =
135 	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, port, UINT16);
136 cmdline_parse_token_num_t pcmd_intintint_token_tx =
137 	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, tx, UINT16);
138 cmdline_parse_token_num_t pcmd_intintint_token_rx =
139 	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, rx, UINT16);
140 
141 
142 /* Pause commands */
143 cmdline_parse_token_string_t pcmd_pause_token_cmd =
144 	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "pause");
145 cmdline_parse_token_num_t pcmd_pause_token_port =
146 	TOKEN_NUM_INITIALIZER(struct pcmd_intstr_params, port, UINT16);
147 cmdline_parse_token_string_t pcmd_pause_token_opt =
148 	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params,
149 		opt, "all#tx#rx#none");
150 
151 /* VLAN commands */
152 cmdline_parse_token_string_t pcmd_vlan_token_cmd =
153 	TOKEN_STRING_INITIALIZER(struct pcmd_vlan_params, cmd, "vlan");
154 cmdline_parse_token_num_t pcmd_vlan_token_port =
155 	TOKEN_NUM_INITIALIZER(struct pcmd_vlan_params, port, UINT16);
156 cmdline_parse_token_string_t pcmd_vlan_token_mode =
157 	TOKEN_STRING_INITIALIZER(struct pcmd_vlan_params, mode, "add#del");
158 cmdline_parse_token_num_t pcmd_vlan_token_vid =
159 	TOKEN_NUM_INITIALIZER(struct pcmd_vlan_params, vid, UINT16);
160 
161 
162 static void
163 pcmd_quit_callback(__rte_unused void *ptr_params,
164 	struct cmdline *ctx,
165 	__rte_unused void *ptr_data)
166 {
167 	cmdline_quit(ctx);
168 }
169 
170 
171 static void
172 pcmd_drvinfo_callback(__rte_unused void *ptr_params,
173 	__rte_unused struct cmdline *ctx,
174 	__rte_unused void *ptr_data)
175 {
176 	struct ethtool_drvinfo info;
177 	int id_port;
178 
179 	for (id_port = 0; id_port < rte_eth_dev_count(); id_port++) {
180 		memset(&info, 0, sizeof(info));
181 		if (rte_ethtool_get_drvinfo(id_port, &info)) {
182 			printf("Error getting info for port %i\n", id_port);
183 			return;
184 		}
185 		printf("Port %i driver: %s (ver: %s)\n",
186 			id_port, info.driver, info.version
187 		      );
188 	}
189 }
190 
191 
192 static void
193 pcmd_link_callback(__rte_unused void *ptr_params,
194 	__rte_unused struct cmdline *ctx,
195 	__rte_unused void *ptr_data)
196 {
197 	int num_ports = rte_eth_dev_count();
198 	int id_port, stat_port;
199 
200 	for (id_port = 0; id_port < num_ports; id_port++) {
201 		if (!rte_eth_dev_is_valid_port(id_port))
202 			continue;
203 		stat_port = rte_ethtool_get_link(id_port);
204 		switch (stat_port) {
205 		case 0:
206 			printf("Port %i: Down\n", id_port);
207 			break;
208 		case 1:
209 			printf("Port %i: Up\n", id_port);
210 			break;
211 		default:
212 			printf("Port %i: Error getting link status\n",
213 				id_port
214 				);
215 			break;
216 		}
217 	}
218 	printf("\n");
219 }
220 
221 
222 static void
223 pcmd_regs_callback(void *ptr_params,
224 	__rte_unused struct cmdline *ctx,
225 	__rte_unused void *ptr_data)
226 {
227 	struct pcmd_intstr_params *params = ptr_params;
228 	int len_regs;
229 	struct ethtool_regs regs;
230 	unsigned char *buf_data;
231 	FILE *fp_regs;
232 
233 	if (!rte_eth_dev_is_valid_port(params->port)) {
234 		printf("Error: Invalid port number %i\n", params->port);
235 		return;
236 	}
237 	len_regs = rte_ethtool_get_regs_len(params->port);
238 	if (len_regs > 0) {
239 		printf("Port %i: %i bytes\n", params->port, len_regs);
240 		buf_data = malloc(len_regs);
241 		if (buf_data == NULL) {
242 			printf("Error allocating %i bytes for buffer\n",
243 				len_regs);
244 			return;
245 		}
246 		if (!rte_ethtool_get_regs(params->port, &regs, buf_data)) {
247 			fp_regs = fopen(params->opt, "wb");
248 			if (fp_regs == NULL) {
249 				printf("Error opening '%s' for writing\n",
250 					params->opt);
251 			} else {
252 				if ((int)fwrite(buf_data,
253 						1, len_regs,
254 						fp_regs) != len_regs)
255 					printf("Error writing '%s'\n",
256 						params->opt);
257 				fclose(fp_regs);
258 			}
259 		}
260 		free(buf_data);
261 	} else if (len_regs == -ENOTSUP)
262 		printf("Port %i: Operation not supported\n", params->port);
263 	else
264 		printf("Port %i: Error getting registers\n", params->port);
265 }
266 
267 
268 static void
269 pcmd_eeprom_callback(void *ptr_params,
270 	__rte_unused struct cmdline *ctx,
271 	__rte_unused void *ptr_data)
272 {
273 	struct pcmd_intstr_params *params = ptr_params;
274 	struct ethtool_eeprom info_eeprom;
275 	int len_eeprom;
276 	int pos_eeprom;
277 	int stat;
278 	unsigned char bytes_eeprom[EEPROM_DUMP_CHUNKSIZE];
279 	FILE *fp_eeprom;
280 
281 	if (!rte_eth_dev_is_valid_port(params->port)) {
282 		printf("Error: Invalid port number %i\n", params->port);
283 		return;
284 	}
285 	len_eeprom = rte_ethtool_get_eeprom_len(params->port);
286 	if (len_eeprom > 0) {
287 		fp_eeprom = fopen(params->opt, "wb");
288 		if (fp_eeprom == NULL) {
289 			printf("Error opening '%s' for writing\n",
290 				params->opt);
291 			return;
292 		}
293 		printf("Total EEPROM length: %i bytes\n", len_eeprom);
294 		info_eeprom.len = EEPROM_DUMP_CHUNKSIZE;
295 		for (pos_eeprom = 0;
296 				pos_eeprom < len_eeprom;
297 				pos_eeprom += EEPROM_DUMP_CHUNKSIZE) {
298 			info_eeprom.offset = pos_eeprom;
299 			if (pos_eeprom + EEPROM_DUMP_CHUNKSIZE > len_eeprom)
300 				info_eeprom.len = len_eeprom - pos_eeprom;
301 			else
302 				info_eeprom.len = EEPROM_DUMP_CHUNKSIZE;
303 			stat = rte_ethtool_get_eeprom(
304 				params->port, &info_eeprom, bytes_eeprom
305 				);
306 			if (stat != 0) {
307 				printf("EEPROM read error %i\n", stat);
308 				break;
309 			}
310 			if (fwrite(bytes_eeprom,
311 					1, info_eeprom.len,
312 					fp_eeprom) != info_eeprom.len) {
313 				printf("Error writing '%s'\n", params->opt);
314 				break;
315 			}
316 		}
317 		fclose(fp_eeprom);
318 	} else if (len_eeprom == 0)
319 		printf("Port %i: Device does not have EEPROM\n", params->port);
320 	else if (len_eeprom == -ENOTSUP)
321 		printf("Port %i: Operation not supported\n", params->port);
322 	else
323 		printf("Port %i: Error getting EEPROM\n", params->port);
324 }
325 
326 
327 static void
328 pcmd_pause_callback(void *ptr_params,
329 	__rte_unused struct cmdline *ctx,
330 	void *ptr_data)
331 {
332 	struct pcmd_intstr_params *params = ptr_params;
333 	struct ethtool_pauseparam info;
334 	int stat;
335 
336 	if (!rte_eth_dev_is_valid_port(params->port)) {
337 		printf("Error: Invalid port number %i\n", params->port);
338 		return;
339 	}
340 	if (ptr_data != NULL) {
341 		stat = rte_ethtool_get_pauseparam(params->port, &info);
342 	} else {
343 		memset(&info, 0, sizeof(info));
344 		if (strcasecmp("all", params->opt) == 0) {
345 			info.tx_pause = 1;
346 			info.rx_pause = 1;
347 		} else if (strcasecmp("tx", params->opt) == 0) {
348 			info.tx_pause = 1;
349 			info.rx_pause = 0;
350 		} else if (strcasecmp("rx", params->opt) == 0) {
351 			info.tx_pause = 0;
352 			info.rx_pause = 1;
353 		} else {
354 			info.tx_pause = 0;
355 			info.rx_pause = 0;
356 		}
357 		/* Assume auto-negotiation wanted */
358 		info.autoneg = 1;
359 		stat = rte_ethtool_set_pauseparam(params->port, &info);
360 	}
361 	if (stat == 0) {
362 		if (info.rx_pause && info.tx_pause)
363 			printf("Port %i: Tx & Rx Paused\n", params->port);
364 		else if (info.rx_pause)
365 			printf("Port %i: Rx Paused\n", params->port);
366 		else if (info.tx_pause)
367 			printf("Port %i: Tx Paused\n", params->port);
368 		else
369 			printf("Port %i: Tx & Rx not paused\n", params->port);
370 	} else if (stat == -ENOTSUP)
371 		printf("Port %i: Operation not supported\n", params->port);
372 	else
373 		printf("Port %i: Error %i\n", params->port, stat);
374 }
375 
376 
377 static void
378 pcmd_open_callback(__rte_unused void *ptr_params,
379 	__rte_unused struct cmdline *ctx,
380 	__rte_unused void *ptr_data)
381 {
382 	struct pcmd_int_params *params = ptr_params;
383 	int stat;
384 
385 	if (!rte_eth_dev_is_valid_port(params->port)) {
386 		printf("Error: Invalid port number %i\n", params->port);
387 		return;
388 	}
389 	lock_port(params->port);
390 	stat = rte_ethtool_net_open(params->port);
391 	mark_port_active(params->port);
392 	unlock_port(params->port);
393 	if (stat == 0)
394 		return;
395 	else if (stat == -ENOTSUP)
396 		printf("Port %i: Operation not supported\n", params->port);
397 	else
398 		printf("Port %i: Error opening device\n", params->port);
399 }
400 
401 static void
402 pcmd_stop_callback(__rte_unused void *ptr_params,
403 	__rte_unused struct cmdline *ctx,
404 	__rte_unused void *ptr_data)
405 {
406 	struct pcmd_int_params *params = ptr_params;
407 	int stat;
408 
409 	if (!rte_eth_dev_is_valid_port(params->port)) {
410 		printf("Error: Invalid port number %i\n", params->port);
411 		return;
412 	}
413 	lock_port(params->port);
414 	stat = rte_ethtool_net_stop(params->port);
415 	mark_port_inactive(params->port);
416 	unlock_port(params->port);
417 	if (stat == 0)
418 		return;
419 	else if (stat == -ENOTSUP)
420 		printf("Port %i: Operation not supported\n", params->port);
421 	else
422 		printf("Port %i: Error stopping device\n", params->port);
423 }
424 
425 
426 static void
427 pcmd_rxmode_callback(void *ptr_params,
428 	__rte_unused struct cmdline *ctx,
429 	__rte_unused void *ptr_data)
430 {
431 	struct pcmd_intstr_params *params = ptr_params;
432 	int stat;
433 
434 	if (!rte_eth_dev_is_valid_port(params->port)) {
435 		printf("Error: Invalid port number %i\n", params->port);
436 		return;
437 	}
438 	stat = rte_ethtool_net_set_rx_mode(params->port);
439 	if (stat == 0)
440 		return;
441 	else if (stat == -ENOTSUP)
442 		printf("Port %i: Operation not supported\n", params->port);
443 	else
444 		printf("Port %i: Error setting rx mode\n", params->port);
445 }
446 
447 
448 static void
449 pcmd_macaddr_callback(void *ptr_params,
450 	__rte_unused struct cmdline *ctx,
451 	void *ptr_data)
452 {
453 	struct pcmd_intmac_params *params = ptr_params;
454 	struct ether_addr mac_addr;
455 	int stat;
456 
457 	stat = 0;
458 	if (!rte_eth_dev_is_valid_port(params->port)) {
459 		printf("Error: Invalid port number %i\n", params->port);
460 		return;
461 	}
462 	if (ptr_data != NULL) {
463 		lock_port(params->port);
464 		stat = rte_ethtool_net_set_mac_addr(params->port,
465 			&params->mac);
466 		mark_port_newmac(params->port);
467 		unlock_port(params->port);
468 		if (stat == 0) {
469 			printf("MAC address changed\n");
470 			return;
471 		}
472 	} else {
473 		stat = rte_ethtool_net_get_mac_addr(params->port, &mac_addr);
474 		if (stat == 0) {
475 			printf(
476 				"Port %i MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
477 				params->port,
478 				mac_addr.addr_bytes[0],
479 				mac_addr.addr_bytes[1],
480 				mac_addr.addr_bytes[2],
481 				mac_addr.addr_bytes[3],
482 				mac_addr.addr_bytes[4],
483 				mac_addr.addr_bytes[5]);
484 			return;
485 		}
486 	}
487 
488 	printf("Port %i: Error %s\n", params->port,
489 	       strerror(-stat));
490 }
491 
492 static void
493 pcmd_mtu_callback(void *ptr_params,
494 	__rte_unused struct cmdline *ctx,
495 	__rte_unused void *ptr_data)
496 {
497 	struct pcmd_intstr_params *params = ptr_params;
498 	int stat;
499 	int new_mtu;
500 	char *ptr_parse_end;
501 
502 	if (!rte_eth_dev_is_valid_port(params->port)) {
503 		printf("Error: Invalid port number %i\n", params->port);
504 		return;
505 	}
506 	new_mtu = atoi(params->opt);
507 	new_mtu = strtoul(params->opt, &ptr_parse_end, 10);
508 	if (*ptr_parse_end != '\0' ||
509 			new_mtu < ETHER_MIN_MTU ||
510 			new_mtu > ETHER_MAX_JUMBO_FRAME_LEN) {
511 		printf("Port %i: Invalid MTU value\n", params->port);
512 		return;
513 	}
514 	stat = rte_ethtool_net_change_mtu(params->port, new_mtu);
515 	if (stat == 0)
516 		printf("Port %i: MTU set to %i\n", params->port, new_mtu);
517 	else if (stat == -ENOTSUP)
518 		printf("Port %i: Operation not supported\n", params->port);
519 	else
520 		printf("Port %i: Error setting MTU\n", params->port);
521 }
522 
523 
524 
525 static void pcmd_portstats_callback(__rte_unused void *ptr_params,
526 	__rte_unused struct cmdline *ctx,
527 	__rte_unused void *ptr_data)
528 {
529 	struct pcmd_int_params *params = ptr_params;
530 	struct rte_eth_stats stat_info;
531 	int stat;
532 
533 	if (!rte_eth_dev_is_valid_port(params->port)) {
534 		printf("Error: Invalid port number %i\n", params->port);
535 		return;
536 	}
537 	stat = rte_ethtool_net_get_stats64(params->port, &stat_info);
538 	if (stat == 0) {
539 		printf("Port %i stats\n", params->port);
540 		printf("   In: %" PRIu64 " (%" PRIu64 " bytes)\n"
541 			"  Out: %"PRIu64" (%"PRIu64 " bytes)\n"
542 			"  Err: %"PRIu64"\n",
543 			stat_info.ipackets,
544 			stat_info.ibytes,
545 			stat_info.opackets,
546 			stat_info.obytes,
547 			stat_info.ierrors+stat_info.oerrors
548 		      );
549 	} else if (stat == -ENOTSUP)
550 		printf("Port %i: Operation not supported\n", params->port);
551 	else
552 		printf("Port %i: Error fetching statistics\n", params->port);
553 }
554 
555 static void pcmd_ringparam_callback(__rte_unused void *ptr_params,
556 	__rte_unused struct cmdline *ctx,
557 	void *ptr_data)
558 {
559 	struct pcmd_intintint_params *params = ptr_params;
560 	struct ethtool_ringparam ring_data;
561 	struct ethtool_ringparam ring_params;
562 	int stat;
563 
564 	if (!rte_eth_dev_is_valid_port(params->port)) {
565 		printf("Error: Invalid port number %i\n", params->port);
566 		return;
567 	}
568 	if (ptr_data == NULL) {
569 		stat = rte_ethtool_get_ringparam(params->port, &ring_data);
570 		if (stat == 0) {
571 			printf("Port %i ring parameters\n"
572 				"  Rx Pending: %i (%i max)\n"
573 				"  Tx Pending: %i (%i max)\n",
574 				params->port,
575 				ring_data.rx_pending,
576 				ring_data.rx_max_pending,
577 				ring_data.tx_pending,
578 				ring_data.tx_max_pending);
579 		}
580 	} else {
581 		if (params->tx < 1 || params->rx < 1) {
582 			printf("Error: Invalid parameters\n");
583 			return;
584 		}
585 		memset(&ring_params, 0, sizeof(struct ethtool_ringparam));
586 		ring_params.tx_pending = params->tx;
587 		ring_params.rx_pending = params->rx;
588 		lock_port(params->port);
589 		stat = rte_ethtool_set_ringparam(params->port, &ring_params);
590 		unlock_port(params->port);
591 	}
592 	if (stat == 0)
593 		return;
594 	else if (stat == -ENOTSUP)
595 		printf("Port %i: Operation not supported\n", params->port);
596 	else
597 		printf("Port %i: Error fetching statistics\n", params->port);
598 }
599 
600 static void pcmd_validate_callback(void *ptr_params,
601 	__rte_unused struct cmdline *ctx,
602 	__rte_unused void *ptr_data)
603 {
604 	struct pcmd_intmac_params *params = ptr_params;
605 
606 	if (rte_ethtool_net_validate_addr(0, &params->mac))
607 		printf("Address is unicast\n");
608 	else
609 		printf("Address is not unicast\n");
610 }
611 
612 
613 static void pcmd_vlan_callback(__rte_unused void *ptr_params,
614 	__rte_unused struct cmdline *ctx,
615 	__rte_unused void *ptr_data)
616 {
617 	struct pcmd_vlan_params *params = ptr_params;
618 	int stat;
619 
620 	if (!rte_eth_dev_is_valid_port(params->port)) {
621 		printf("Error: Invalid port number %i\n", params->port);
622 		return;
623 	}
624 	stat = 0;
625 
626 	if (strcasecmp("add", params->mode) == 0) {
627 		stat = rte_ethtool_net_vlan_rx_add_vid(
628 			params->port, params->vid
629 			);
630 		if (stat == 0)
631 			printf("VLAN vid %i added\n", params->vid);
632 
633 	} else if (strcasecmp("del", params->mode) == 0) {
634 		stat = rte_ethtool_net_vlan_rx_kill_vid(
635 			params->port, params->vid
636 			);
637 		if (stat == 0)
638 			printf("VLAN vid %i removed\n", params->vid);
639 	} else {
640 		/* Should not happen! */
641 		printf("Error: Bad mode %s\n", params->mode);
642 	}
643 	if (stat == -ENOTSUP)
644 		printf("Port %i: Operation not supported\n", params->port);
645 	else if (stat == -ENOSYS)
646 		printf("Port %i: VLAN filtering disabled\n", params->port);
647 	else if (stat != 0)
648 		printf("Port %i: Error changing VLAN setup (code %i)\n",
649 			params->port, -stat);
650 }
651 
652 
653 cmdline_parse_inst_t pcmd_quit = {
654 	.f = pcmd_quit_callback,
655 	.data = NULL,
656 	.help_str = "quit\n     Exit program",
657 	.tokens = {(void *)&pcmd_quit_token_cmd, NULL},
658 };
659 cmdline_parse_inst_t pcmd_drvinfo = {
660 	.f = pcmd_drvinfo_callback,
661 	.data = NULL,
662 	.help_str = "drvinfo\n     Print driver info",
663 	.tokens = {(void *)&pcmd_drvinfo_token_cmd, NULL},
664 };
665 cmdline_parse_inst_t pcmd_link = {
666 	.f = pcmd_link_callback,
667 	.data = NULL,
668 	.help_str = "link\n     Print port link states",
669 	.tokens = {(void *)&pcmd_link_token_cmd, NULL},
670 };
671 cmdline_parse_inst_t pcmd_regs = {
672 	.f = pcmd_regs_callback,
673 	.data = NULL,
674 	.help_str = "regs <port_id> <filename>\n"
675 		"     Dump port register(s) to file",
676 	.tokens = {
677 		(void *)&pcmd_regs_token_cmd,
678 		(void *)&pcmd_intstr_token_port,
679 		(void *)&pcmd_intstr_token_opt,
680 		NULL
681 	},
682 };
683 cmdline_parse_inst_t pcmd_eeprom = {
684 	.f = pcmd_eeprom_callback,
685 	.data = NULL,
686 	.help_str = "eeprom <port_id> <filename>\n    Dump EEPROM to file",
687 	.tokens = {
688 		(void *)&pcmd_eeprom_token_cmd,
689 		(void *)&pcmd_intstr_token_port,
690 		(void *)&pcmd_intstr_token_opt,
691 		NULL
692 	},
693 };
694 cmdline_parse_inst_t pcmd_pause_noopt = {
695 	.f = pcmd_pause_callback,
696 	.data = (void *)0x01,
697 	.help_str = "pause <port_id>\n     Print port pause state",
698 	.tokens = {
699 		(void *)&pcmd_pause_token_cmd,
700 		(void *)&pcmd_pause_token_port,
701 		NULL
702 	},
703 };
704 cmdline_parse_inst_t pcmd_pause = {
705 	.f = pcmd_pause_callback,
706 	.data = NULL,
707 	.help_str =
708 		"pause <port_id> <all|tx|rx|none>\n     Pause/unpause port",
709 	.tokens = {
710 		(void *)&pcmd_pause_token_cmd,
711 		(void *)&pcmd_pause_token_port,
712 		(void *)&pcmd_pause_token_opt,
713 		NULL
714 	},
715 };
716 cmdline_parse_inst_t pcmd_open = {
717 	.f = pcmd_open_callback,
718 	.data = NULL,
719 	.help_str = "open <port_id>\n     Open port",
720 	.tokens = {
721 		(void *)&pcmd_open_token_cmd,
722 		(void *)&pcmd_int_token_port,
723 		NULL
724 	},
725 };
726 cmdline_parse_inst_t pcmd_stop = {
727 	.f = pcmd_stop_callback,
728 	.data = NULL,
729 	.help_str = "stop <port_id>\n     Stop port",
730 	.tokens = {
731 		(void *)&pcmd_stop_token_cmd,
732 		(void *)&pcmd_int_token_port,
733 		NULL
734 	},
735 };
736 cmdline_parse_inst_t pcmd_rxmode = {
737 	.f = pcmd_rxmode_callback,
738 	.data = NULL,
739 	.help_str = "rxmode <port_id>\n     Toggle port Rx mode",
740 	.tokens = {
741 		(void *)&pcmd_rxmode_token_cmd,
742 		(void *)&pcmd_int_token_port,
743 		NULL
744 	},
745 };
746 cmdline_parse_inst_t pcmd_macaddr_get = {
747 	.f = pcmd_macaddr_callback,
748 	.data = NULL,
749 	.help_str = "macaddr <port_id>\n"
750 		"     Get MAC address",
751 	.tokens = {
752 		(void *)&pcmd_macaddr_token_cmd,
753 		(void *)&pcmd_intstr_token_port,
754 		NULL
755 	},
756 };
757 cmdline_parse_inst_t pcmd_macaddr = {
758 	.f = pcmd_macaddr_callback,
759 	.data = (void *)0x01,
760 	.help_str =
761 		"macaddr <port_id> <mac_addr>\n"
762 		"     Set MAC address",
763 	.tokens = {
764 		(void *)&pcmd_macaddr_token_cmd,
765 		(void *)&pcmd_intmac_token_port,
766 		(void *)&pcmd_intmac_token_mac,
767 		NULL
768 	},
769 };
770 cmdline_parse_inst_t pcmd_mtu = {
771 	.f = pcmd_mtu_callback,
772 	.data = NULL,
773 	.help_str = "mtu <port_id> <mtu_value>\n"
774 		"     Change MTU",
775 	.tokens = {
776 		(void *)&pcmd_mtu_token_cmd,
777 		(void *)&pcmd_intstr_token_port,
778 		(void *)&pcmd_intstr_token_opt,
779 		NULL
780 	},
781 };
782 cmdline_parse_inst_t pcmd_portstats = {
783 	.f = pcmd_portstats_callback,
784 	.data = NULL,
785 	.help_str = "portstats <port_id>\n"
786 		"     Print port eth statistics",
787 	.tokens = {
788 		(void *)&pcmd_portstats_token_cmd,
789 		(void *)&pcmd_int_token_port,
790 		NULL
791 	},
792 };
793 cmdline_parse_inst_t pcmd_ringparam = {
794 	.f = pcmd_ringparam_callback,
795 	.data = NULL,
796 	.help_str = "ringparam <port_id>\n"
797 		"     Print ring parameters",
798 	.tokens = {
799 		(void *)&pcmd_ringparam_token_cmd,
800 		(void *)&pcmd_intintint_token_port,
801 		NULL
802 	},
803 };
804 cmdline_parse_inst_t pcmd_ringparam_set = {
805 	.f = pcmd_ringparam_callback,
806 	.data = (void *)1,
807 	.help_str = "ringparam <port_id> <tx_param> <rx_param>\n"
808 		"     Set ring parameters",
809 	.tokens = {
810 		(void *)&pcmd_ringparam_token_cmd,
811 		(void *)&pcmd_intintint_token_port,
812 		(void *)&pcmd_intintint_token_tx,
813 		(void *)&pcmd_intintint_token_rx,
814 		NULL
815 	},
816 };
817 cmdline_parse_inst_t pcmd_validate = {
818 	.f = pcmd_validate_callback,
819 	.data = NULL,
820 	.help_str = "validate <mac_addr>\n"
821 		"     Check that MAC address is valid unicast address",
822 	.tokens = {
823 		(void *)&pcmd_validate_token_cmd,
824 		(void *)&pcmd_intmac_token_mac,
825 		NULL
826 	},
827 };
828 cmdline_parse_inst_t pcmd_vlan = {
829 	.f = pcmd_vlan_callback,
830 	.data = NULL,
831 	.help_str = "vlan <port_id> <add|del> <vlan_id>\n"
832 		"     Add/remove VLAN id",
833 	.tokens = {
834 		(void *)&pcmd_vlan_token_cmd,
835 		(void *)&pcmd_vlan_token_port,
836 		(void *)&pcmd_vlan_token_mode,
837 		(void *)&pcmd_vlan_token_vid,
838 		NULL
839 	},
840 };
841 
842 
843 cmdline_parse_ctx_t list_prompt_commands[] = {
844 	(cmdline_parse_inst_t *)&pcmd_drvinfo,
845 	(cmdline_parse_inst_t *)&pcmd_eeprom,
846 	(cmdline_parse_inst_t *)&pcmd_link,
847 	(cmdline_parse_inst_t *)&pcmd_macaddr_get,
848 	(cmdline_parse_inst_t *)&pcmd_macaddr,
849 	(cmdline_parse_inst_t *)&pcmd_mtu,
850 	(cmdline_parse_inst_t *)&pcmd_open,
851 	(cmdline_parse_inst_t *)&pcmd_pause_noopt,
852 	(cmdline_parse_inst_t *)&pcmd_pause,
853 	(cmdline_parse_inst_t *)&pcmd_portstats,
854 	(cmdline_parse_inst_t *)&pcmd_regs,
855 	(cmdline_parse_inst_t *)&pcmd_ringparam,
856 	(cmdline_parse_inst_t *)&pcmd_ringparam_set,
857 	(cmdline_parse_inst_t *)&pcmd_rxmode,
858 	(cmdline_parse_inst_t *)&pcmd_stop,
859 	(cmdline_parse_inst_t *)&pcmd_validate,
860 	(cmdline_parse_inst_t *)&pcmd_vlan,
861 	(cmdline_parse_inst_t *)&pcmd_quit,
862 	NULL
863 };
864 
865 
866 void ethapp_main(void)
867 {
868 	struct cmdline *ctx_cmdline;
869 
870 	ctx_cmdline = cmdline_stdin_new(list_prompt_commands, "EthApp> ");
871 	cmdline_interact(ctx_cmdline);
872 	cmdline_stdin_exit(ctx_cmdline);
873 }
874