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 		if (rte_ethtool_get_drvinfo(id_port, &info)) {
181 			printf("Error getting info for port %i\n", id_port);
182 			return;
183 		}
184 		printf("Port %i driver: %s (ver: %s)\n",
185 			id_port, info.driver, info.version
186 		      );
187 	}
188 }
189 
190 
191 static void
192 pcmd_link_callback(__rte_unused void *ptr_params,
193 	__rte_unused struct cmdline *ctx,
194 	__rte_unused void *ptr_data)
195 {
196 	int num_ports = rte_eth_dev_count();
197 	int id_port, stat_port;
198 
199 	for (id_port = 0; id_port < num_ports; id_port++) {
200 		if (!rte_eth_dev_is_valid_port(id_port))
201 			continue;
202 		stat_port = rte_ethtool_get_link(id_port);
203 		switch (stat_port) {
204 		case 0:
205 			printf("Port %i: Down\n", id_port);
206 			break;
207 		case 1:
208 			printf("Port %i: Up\n", id_port);
209 			break;
210 		default:
211 			printf("Port %i: Error getting link status\n",
212 				id_port
213 				);
214 			break;
215 		}
216 	}
217 	printf("\n");
218 }
219 
220 
221 static void
222 pcmd_regs_callback(void *ptr_params,
223 	__rte_unused struct cmdline *ctx,
224 	__rte_unused void *ptr_data)
225 {
226 	struct pcmd_intstr_params *params = ptr_params;
227 	int len_regs;
228 	struct ethtool_regs regs;
229 	unsigned char *buf_data;
230 	FILE *fp_regs;
231 
232 	if (!rte_eth_dev_is_valid_port(params->port)) {
233 		printf("Error: Invalid port number %i\n", params->port);
234 		return;
235 	}
236 	len_regs = rte_ethtool_get_regs_len(params->port);
237 	if (len_regs > 0) {
238 		printf("Port %i: %i bytes\n", params->port, len_regs);
239 		buf_data = malloc(len_regs);
240 		if (buf_data == NULL) {
241 			printf("Error allocating %i bytes for buffer\n",
242 				len_regs);
243 			return;
244 		}
245 		if (!rte_ethtool_get_regs(params->port, &regs, buf_data)) {
246 			fp_regs = fopen(params->opt, "wb");
247 			if (fp_regs == NULL) {
248 				printf("Error opening '%s' for writing\n",
249 					params->opt);
250 			} else {
251 				if ((int)fwrite(buf_data,
252 						1, len_regs,
253 						fp_regs) != len_regs)
254 					printf("Error writing '%s'\n",
255 						params->opt);
256 				fclose(fp_regs);
257 			}
258 		}
259 		free(buf_data);
260 	} else if (len_regs == -ENOTSUP)
261 		printf("Port %i: Operation not supported\n", params->port);
262 	else
263 		printf("Port %i: Error getting registers\n", params->port);
264 }
265 
266 
267 static void
268 pcmd_eeprom_callback(void *ptr_params,
269 	__rte_unused struct cmdline *ctx,
270 	__rte_unused void *ptr_data)
271 {
272 	struct pcmd_intstr_params *params = ptr_params;
273 	struct ethtool_eeprom info_eeprom;
274 	int len_eeprom;
275 	int pos_eeprom;
276 	int stat;
277 	unsigned char bytes_eeprom[EEPROM_DUMP_CHUNKSIZE];
278 	FILE *fp_eeprom;
279 
280 	if (!rte_eth_dev_is_valid_port(params->port)) {
281 		printf("Error: Invalid port number %i\n", params->port);
282 		return;
283 	}
284 	len_eeprom = rte_ethtool_get_eeprom_len(params->port);
285 	if (len_eeprom > 0) {
286 		fp_eeprom = fopen(params->opt, "wb");
287 		if (fp_eeprom == NULL) {
288 			printf("Error opening '%s' for writing\n",
289 				params->opt);
290 			return;
291 		}
292 		printf("Total EEPROM length: %i bytes\n", len_eeprom);
293 		info_eeprom.len = EEPROM_DUMP_CHUNKSIZE;
294 		for (pos_eeprom = 0;
295 				pos_eeprom < len_eeprom;
296 				pos_eeprom += EEPROM_DUMP_CHUNKSIZE) {
297 			info_eeprom.offset = pos_eeprom;
298 			if (pos_eeprom + EEPROM_DUMP_CHUNKSIZE > len_eeprom)
299 				info_eeprom.len = len_eeprom - pos_eeprom;
300 			else
301 				info_eeprom.len = EEPROM_DUMP_CHUNKSIZE;
302 			stat = rte_ethtool_get_eeprom(
303 				params->port, &info_eeprom, bytes_eeprom
304 				);
305 			if (stat != 0) {
306 				printf("EEPROM read error %i\n", stat);
307 				break;
308 			}
309 			if (fwrite(bytes_eeprom,
310 					1, info_eeprom.len,
311 					fp_eeprom) != info_eeprom.len) {
312 				printf("Error writing '%s'\n", params->opt);
313 				break;
314 			}
315 		}
316 		fclose(fp_eeprom);
317 	} else if (len_eeprom == 0)
318 		printf("Port %i: Device does not have EEPROM\n", params->port);
319 	else if (len_eeprom == -ENOTSUP)
320 		printf("Port %i: Operation not supported\n", params->port);
321 	else
322 		printf("Port %i: Error getting EEPROM\n", params->port);
323 }
324 
325 
326 static void
327 pcmd_pause_callback(void *ptr_params,
328 	__rte_unused struct cmdline *ctx,
329 	void *ptr_data)
330 {
331 	struct pcmd_intstr_params *params = ptr_params;
332 	struct ethtool_pauseparam info;
333 	int stat;
334 
335 	if (!rte_eth_dev_is_valid_port(params->port)) {
336 		printf("Error: Invalid port number %i\n", params->port);
337 		return;
338 	}
339 	if (ptr_data != NULL) {
340 		stat = rte_ethtool_get_pauseparam(params->port, &info);
341 	} else {
342 		memset(&info, 0, sizeof(info));
343 		if (strcasecmp("all", params->opt) == 0) {
344 			info.tx_pause = 1;
345 			info.rx_pause = 1;
346 		} else if (strcasecmp("tx", params->opt) == 0) {
347 			info.tx_pause = 1;
348 			info.rx_pause = 0;
349 		} else if (strcasecmp("rx", params->opt) == 0) {
350 			info.tx_pause = 0;
351 			info.rx_pause = 1;
352 		} else {
353 			info.tx_pause = 0;
354 			info.rx_pause = 0;
355 		}
356 		/* Assume auto-negotiation wanted */
357 		info.autoneg = 1;
358 		stat = rte_ethtool_set_pauseparam(params->port, &info);
359 	}
360 	if (stat == 0) {
361 		if (info.rx_pause && info.tx_pause)
362 			printf("Port %i: Tx & Rx Paused\n", params->port);
363 		else if (info.rx_pause)
364 			printf("Port %i: Rx Paused\n", params->port);
365 		else if (info.tx_pause)
366 			printf("Port %i: Tx Paused\n", params->port);
367 		else
368 			printf("Port %i: Tx & Rx not paused\n", params->port);
369 	} else if (stat == -ENOTSUP)
370 		printf("Port %i: Operation not supported\n", params->port);
371 	else
372 		printf("Port %i: Error %i\n", params->port, stat);
373 }
374 
375 
376 static void
377 pcmd_open_callback(__rte_unused void *ptr_params,
378 	__rte_unused struct cmdline *ctx,
379 	__rte_unused void *ptr_data)
380 {
381 	struct pcmd_int_params *params = ptr_params;
382 	int stat;
383 
384 	if (!rte_eth_dev_is_valid_port(params->port)) {
385 		printf("Error: Invalid port number %i\n", params->port);
386 		return;
387 	}
388 	lock_port(params->port);
389 	stat = rte_ethtool_net_open(params->port);
390 	mark_port_active(params->port);
391 	unlock_port(params->port);
392 	if (stat == 0)
393 		return;
394 	else if (stat == -ENOTSUP)
395 		printf("Port %i: Operation not supported\n", params->port);
396 	else
397 		printf("Port %i: Error opening device\n", params->port);
398 }
399 
400 static void
401 pcmd_stop_callback(__rte_unused void *ptr_params,
402 	__rte_unused struct cmdline *ctx,
403 	__rte_unused void *ptr_data)
404 {
405 	struct pcmd_int_params *params = ptr_params;
406 	int stat;
407 
408 	if (!rte_eth_dev_is_valid_port(params->port)) {
409 		printf("Error: Invalid port number %i\n", params->port);
410 		return;
411 	}
412 	lock_port(params->port);
413 	stat = rte_ethtool_net_stop(params->port);
414 	mark_port_inactive(params->port);
415 	unlock_port(params->port);
416 	if (stat == 0)
417 		return;
418 	else if (stat == -ENOTSUP)
419 		printf("Port %i: Operation not supported\n", params->port);
420 	else
421 		printf("Port %i: Error stopping device\n", params->port);
422 }
423 
424 
425 static void
426 pcmd_rxmode_callback(void *ptr_params,
427 	__rte_unused struct cmdline *ctx,
428 	__rte_unused void *ptr_data)
429 {
430 	struct pcmd_intstr_params *params = ptr_params;
431 	int stat;
432 
433 	if (!rte_eth_dev_is_valid_port(params->port)) {
434 		printf("Error: Invalid port number %i\n", params->port);
435 		return;
436 	}
437 	stat = rte_ethtool_net_set_rx_mode(params->port);
438 	if (stat == 0)
439 		return;
440 	else if (stat == -ENOTSUP)
441 		printf("Port %i: Operation not supported\n", params->port);
442 	else
443 		printf("Port %i: Error setting rx mode\n", params->port);
444 }
445 
446 
447 static void
448 pcmd_macaddr_callback(void *ptr_params,
449 	__rte_unused struct cmdline *ctx,
450 	void *ptr_data)
451 {
452 	struct pcmd_intmac_params *params = ptr_params;
453 	struct ether_addr mac_addr;
454 	int stat;
455 
456 	stat = 0;
457 	if (!rte_eth_dev_is_valid_port(params->port)) {
458 		printf("Error: Invalid port number %i\n", params->port);
459 		return;
460 	}
461 	if (ptr_data != NULL) {
462 		lock_port(params->port);
463 		stat = rte_ethtool_net_set_mac_addr(params->port,
464 			&params->mac);
465 		mark_port_newmac(params->port);
466 		unlock_port(params->port);
467 		if (stat == 0) {
468 			printf("MAC address changed\n");
469 			return;
470 		}
471 	} else {
472 		stat = rte_ethtool_net_get_mac_addr(params->port, &mac_addr);
473 		if (stat == 0) {
474 			printf(
475 				"Port %i MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
476 				params->port,
477 				mac_addr.addr_bytes[0],
478 				mac_addr.addr_bytes[1],
479 				mac_addr.addr_bytes[2],
480 				mac_addr.addr_bytes[3],
481 				mac_addr.addr_bytes[4],
482 				mac_addr.addr_bytes[5]);
483 			return;
484 		}
485 	}
486 
487 	printf("Port %i: Error %s\n", params->port,
488 	       strerror(-stat));
489 }
490 
491 static void
492 pcmd_mtu_callback(void *ptr_params,
493 	__rte_unused struct cmdline *ctx,
494 	__rte_unused void *ptr_data)
495 {
496 	struct pcmd_intstr_params *params = ptr_params;
497 	int stat;
498 	int new_mtu;
499 	char *ptr_parse_end;
500 
501 	if (!rte_eth_dev_is_valid_port(params->port)) {
502 		printf("Error: Invalid port number %i\n", params->port);
503 		return;
504 	}
505 	new_mtu = atoi(params->opt);
506 	new_mtu = strtoul(params->opt, &ptr_parse_end, 10);
507 	if (*ptr_parse_end != '\0' ||
508 			new_mtu < ETHER_MIN_MTU ||
509 			new_mtu > ETHER_MAX_JUMBO_FRAME_LEN) {
510 		printf("Port %i: Invalid MTU value\n", params->port);
511 		return;
512 	}
513 	stat = rte_ethtool_net_change_mtu(params->port, new_mtu);
514 	if (stat == 0)
515 		printf("Port %i: MTU set to %i\n", params->port, new_mtu);
516 	else if (stat == -ENOTSUP)
517 		printf("Port %i: Operation not supported\n", params->port);
518 	else
519 		printf("Port %i: Error setting MTU\n", params->port);
520 }
521 
522 
523 
524 static void pcmd_portstats_callback(__rte_unused void *ptr_params,
525 	__rte_unused struct cmdline *ctx,
526 	__rte_unused void *ptr_data)
527 {
528 	struct pcmd_int_params *params = ptr_params;
529 	struct rte_eth_stats stat_info;
530 	int stat;
531 
532 	if (!rte_eth_dev_is_valid_port(params->port)) {
533 		printf("Error: Invalid port number %i\n", params->port);
534 		return;
535 	}
536 	stat = rte_ethtool_net_get_stats64(params->port, &stat_info);
537 	if (stat == 0) {
538 		printf("Port %i stats\n", params->port);
539 		printf("   In: %" PRIu64 " (%" PRIu64 " bytes)\n"
540 			"  Out: %"PRIu64" (%"PRIu64 " bytes)\n"
541 			"  Err: %"PRIu64"\n",
542 			stat_info.ipackets,
543 			stat_info.ibytes,
544 			stat_info.opackets,
545 			stat_info.obytes,
546 			stat_info.ierrors+stat_info.oerrors
547 		      );
548 	} else if (stat == -ENOTSUP)
549 		printf("Port %i: Operation not supported\n", params->port);
550 	else
551 		printf("Port %i: Error fetching statistics\n", params->port);
552 }
553 
554 static void pcmd_ringparam_callback(__rte_unused void *ptr_params,
555 	__rte_unused struct cmdline *ctx,
556 	void *ptr_data)
557 {
558 	struct pcmd_intintint_params *params = ptr_params;
559 	struct ethtool_ringparam ring_data;
560 	struct ethtool_ringparam ring_params;
561 	int stat;
562 
563 	if (!rte_eth_dev_is_valid_port(params->port)) {
564 		printf("Error: Invalid port number %i\n", params->port);
565 		return;
566 	}
567 	if (ptr_data == NULL) {
568 		stat = rte_ethtool_get_ringparam(params->port, &ring_data);
569 		if (stat == 0) {
570 			printf("Port %i ring parameters\n"
571 				"  Rx Pending: %i (%i max)\n"
572 				"  Tx Pending: %i (%i max)\n",
573 				params->port,
574 				ring_data.rx_pending,
575 				ring_data.rx_max_pending,
576 				ring_data.tx_pending,
577 				ring_data.tx_max_pending);
578 		}
579 	} else {
580 		if (params->tx < 1 || params->rx < 1) {
581 			printf("Error: Invalid parameters\n");
582 			return;
583 		}
584 		memset(&ring_params, 0, sizeof(struct ethtool_ringparam));
585 		ring_params.tx_pending = params->tx;
586 		ring_params.rx_pending = params->rx;
587 		lock_port(params->port);
588 		stat = rte_ethtool_set_ringparam(params->port, &ring_params);
589 		unlock_port(params->port);
590 	}
591 	if (stat == 0)
592 		return;
593 	else if (stat == -ENOTSUP)
594 		printf("Port %i: Operation not supported\n", params->port);
595 	else
596 		printf("Port %i: Error fetching statistics\n", params->port);
597 }
598 
599 static void pcmd_validate_callback(void *ptr_params,
600 	__rte_unused struct cmdline *ctx,
601 	__rte_unused void *ptr_data)
602 {
603 	struct pcmd_intmac_params *params = ptr_params;
604 
605 	if (rte_ethtool_net_validate_addr(0, &params->mac))
606 		printf("Address is unicast\n");
607 	else
608 		printf("Address is not unicast\n");
609 }
610 
611 
612 static void pcmd_vlan_callback(__rte_unused void *ptr_params,
613 	__rte_unused struct cmdline *ctx,
614 	__rte_unused void *ptr_data)
615 {
616 	struct pcmd_vlan_params *params = ptr_params;
617 	int stat;
618 
619 	if (!rte_eth_dev_is_valid_port(params->port)) {
620 		printf("Error: Invalid port number %i\n", params->port);
621 		return;
622 	}
623 	stat = 0;
624 
625 	if (strcasecmp("add", params->mode) == 0) {
626 		stat = rte_ethtool_net_vlan_rx_add_vid(
627 			params->port, params->vid
628 			);
629 		if (stat == 0)
630 			printf("VLAN vid %i added\n", params->vid);
631 
632 	} else if (strcasecmp("del", params->mode) == 0) {
633 		stat = rte_ethtool_net_vlan_rx_kill_vid(
634 			params->port, params->vid
635 			);
636 		if (stat == 0)
637 			printf("VLAN vid %i removed\n", params->vid);
638 	} else {
639 		/* Should not happen! */
640 		printf("Error: Bad mode %s\n", params->mode);
641 	}
642 	if (stat == -ENOTSUP)
643 		printf("Port %i: Operation not supported\n", params->port);
644 	else if (stat == -ENOSYS)
645 		printf("Port %i: VLAN filtering disabled\n", params->port);
646 	else if (stat != 0)
647 		printf("Port %i: Error changing VLAN setup (code %i)\n",
648 			params->port, -stat);
649 }
650 
651 
652 cmdline_parse_inst_t pcmd_quit = {
653 	.f = pcmd_quit_callback,
654 	.data = NULL,
655 	.help_str = "quit\n     Exit program",
656 	.tokens = {(void *)&pcmd_quit_token_cmd, NULL},
657 };
658 cmdline_parse_inst_t pcmd_drvinfo = {
659 	.f = pcmd_drvinfo_callback,
660 	.data = NULL,
661 	.help_str = "drvinfo\n     Print driver info",
662 	.tokens = {(void *)&pcmd_drvinfo_token_cmd, NULL},
663 };
664 cmdline_parse_inst_t pcmd_link = {
665 	.f = pcmd_link_callback,
666 	.data = NULL,
667 	.help_str = "link\n     Print port link states",
668 	.tokens = {(void *)&pcmd_link_token_cmd, NULL},
669 };
670 cmdline_parse_inst_t pcmd_regs = {
671 	.f = pcmd_regs_callback,
672 	.data = NULL,
673 	.help_str = "regs <port_id> <filename>\n"
674 		"     Dump port register(s) to file",
675 	.tokens = {
676 		(void *)&pcmd_regs_token_cmd,
677 		(void *)&pcmd_intstr_token_port,
678 		(void *)&pcmd_intstr_token_opt,
679 		NULL
680 	},
681 };
682 cmdline_parse_inst_t pcmd_eeprom = {
683 	.f = pcmd_eeprom_callback,
684 	.data = NULL,
685 	.help_str = "eeprom <port_id> <filename>\n    Dump EEPROM to file",
686 	.tokens = {
687 		(void *)&pcmd_eeprom_token_cmd,
688 		(void *)&pcmd_intstr_token_port,
689 		(void *)&pcmd_intstr_token_opt,
690 		NULL
691 	},
692 };
693 cmdline_parse_inst_t pcmd_pause_noopt = {
694 	.f = pcmd_pause_callback,
695 	.data = (void *)0x01,
696 	.help_str = "pause <port_id>\n     Print port pause state",
697 	.tokens = {
698 		(void *)&pcmd_pause_token_cmd,
699 		(void *)&pcmd_pause_token_port,
700 		NULL
701 	},
702 };
703 cmdline_parse_inst_t pcmd_pause = {
704 	.f = pcmd_pause_callback,
705 	.data = NULL,
706 	.help_str =
707 		"pause <port_id> <all|tx|rx|none>\n     Pause/unpause port",
708 	.tokens = {
709 		(void *)&pcmd_pause_token_cmd,
710 		(void *)&pcmd_pause_token_port,
711 		(void *)&pcmd_pause_token_opt,
712 		NULL
713 	},
714 };
715 cmdline_parse_inst_t pcmd_open = {
716 	.f = pcmd_open_callback,
717 	.data = NULL,
718 	.help_str = "open <port_id>\n     Open port",
719 	.tokens = {
720 		(void *)&pcmd_open_token_cmd,
721 		(void *)&pcmd_int_token_port,
722 		NULL
723 	},
724 };
725 cmdline_parse_inst_t pcmd_stop = {
726 	.f = pcmd_stop_callback,
727 	.data = NULL,
728 	.help_str = "stop <port_id>\n     Stop port",
729 	.tokens = {
730 		(void *)&pcmd_stop_token_cmd,
731 		(void *)&pcmd_int_token_port,
732 		NULL
733 	},
734 };
735 cmdline_parse_inst_t pcmd_rxmode = {
736 	.f = pcmd_rxmode_callback,
737 	.data = NULL,
738 	.help_str = "rxmode <port_id>\n     Toggle port Rx mode",
739 	.tokens = {
740 		(void *)&pcmd_rxmode_token_cmd,
741 		(void *)&pcmd_int_token_port,
742 		NULL
743 	},
744 };
745 cmdline_parse_inst_t pcmd_macaddr_get = {
746 	.f = pcmd_macaddr_callback,
747 	.data = NULL,
748 	.help_str = "macaddr <port_id>\n"
749 		"     Get MAC address",
750 	.tokens = {
751 		(void *)&pcmd_macaddr_token_cmd,
752 		(void *)&pcmd_intstr_token_port,
753 		NULL
754 	},
755 };
756 cmdline_parse_inst_t pcmd_macaddr = {
757 	.f = pcmd_macaddr_callback,
758 	.data = (void *)0x01,
759 	.help_str =
760 		"macaddr <port_id> <mac_addr>\n"
761 		"     Set MAC address",
762 	.tokens = {
763 		(void *)&pcmd_macaddr_token_cmd,
764 		(void *)&pcmd_intmac_token_port,
765 		(void *)&pcmd_intmac_token_mac,
766 		NULL
767 	},
768 };
769 cmdline_parse_inst_t pcmd_mtu = {
770 	.f = pcmd_mtu_callback,
771 	.data = NULL,
772 	.help_str = "mtu <port_id> <mtu_value>\n"
773 		"     Change MTU",
774 	.tokens = {
775 		(void *)&pcmd_mtu_token_cmd,
776 		(void *)&pcmd_intstr_token_port,
777 		(void *)&pcmd_intstr_token_opt,
778 		NULL
779 	},
780 };
781 cmdline_parse_inst_t pcmd_portstats = {
782 	.f = pcmd_portstats_callback,
783 	.data = NULL,
784 	.help_str = "portstats <port_id>\n"
785 		"     Print port eth statistics",
786 	.tokens = {
787 		(void *)&pcmd_portstats_token_cmd,
788 		(void *)&pcmd_int_token_port,
789 		NULL
790 	},
791 };
792 cmdline_parse_inst_t pcmd_ringparam = {
793 	.f = pcmd_ringparam_callback,
794 	.data = NULL,
795 	.help_str = "ringparam <port_id>\n"
796 		"     Print ring parameters",
797 	.tokens = {
798 		(void *)&pcmd_ringparam_token_cmd,
799 		(void *)&pcmd_intintint_token_port,
800 		NULL
801 	},
802 };
803 cmdline_parse_inst_t pcmd_ringparam_set = {
804 	.f = pcmd_ringparam_callback,
805 	.data = (void *)1,
806 	.help_str = "ringparam <port_id> <tx_param> <rx_param>\n"
807 		"     Set ring parameters",
808 	.tokens = {
809 		(void *)&pcmd_ringparam_token_cmd,
810 		(void *)&pcmd_intintint_token_port,
811 		(void *)&pcmd_intintint_token_tx,
812 		(void *)&pcmd_intintint_token_rx,
813 		NULL
814 	},
815 };
816 cmdline_parse_inst_t pcmd_validate = {
817 	.f = pcmd_validate_callback,
818 	.data = NULL,
819 	.help_str = "validate <mac_addr>\n"
820 		"     Check that MAC address is valid unicast address",
821 	.tokens = {
822 		(void *)&pcmd_validate_token_cmd,
823 		(void *)&pcmd_intmac_token_mac,
824 		NULL
825 	},
826 };
827 cmdline_parse_inst_t pcmd_vlan = {
828 	.f = pcmd_vlan_callback,
829 	.data = NULL,
830 	.help_str = "vlan <port_id> <add|del> <vlan_id>\n"
831 		"     Add/remove VLAN id",
832 	.tokens = {
833 		(void *)&pcmd_vlan_token_cmd,
834 		(void *)&pcmd_vlan_token_port,
835 		(void *)&pcmd_vlan_token_mode,
836 		(void *)&pcmd_vlan_token_vid,
837 		NULL
838 	},
839 };
840 
841 
842 cmdline_parse_ctx_t list_prompt_commands[] = {
843 	(cmdline_parse_inst_t *)&pcmd_drvinfo,
844 	(cmdline_parse_inst_t *)&pcmd_eeprom,
845 	(cmdline_parse_inst_t *)&pcmd_link,
846 	(cmdline_parse_inst_t *)&pcmd_macaddr_get,
847 	(cmdline_parse_inst_t *)&pcmd_macaddr,
848 	(cmdline_parse_inst_t *)&pcmd_mtu,
849 	(cmdline_parse_inst_t *)&pcmd_open,
850 	(cmdline_parse_inst_t *)&pcmd_pause_noopt,
851 	(cmdline_parse_inst_t *)&pcmd_pause,
852 	(cmdline_parse_inst_t *)&pcmd_portstats,
853 	(cmdline_parse_inst_t *)&pcmd_regs,
854 	(cmdline_parse_inst_t *)&pcmd_ringparam,
855 	(cmdline_parse_inst_t *)&pcmd_ringparam_set,
856 	(cmdline_parse_inst_t *)&pcmd_rxmode,
857 	(cmdline_parse_inst_t *)&pcmd_stop,
858 	(cmdline_parse_inst_t *)&pcmd_validate,
859 	(cmdline_parse_inst_t *)&pcmd_vlan,
860 	(cmdline_parse_inst_t *)&pcmd_quit,
861 	NULL
862 };
863 
864 
865 void ethapp_main(void)
866 {
867 	struct cmdline *ctx_cmdline;
868 
869 	ctx_cmdline = cmdline_stdin_new(list_prompt_commands, "EthApp> ");
870 	cmdline_interact(ctx_cmdline);
871 	cmdline_stdin_exit(ctx_cmdline);
872 }
873