]> git.proxmox.com Git - ovs.git/blame - lib/dpctl.c
dpif-netdev: Add ovs-appctl dpif-netdev/pmd-rxq-rebalance.
[ovs.git] / lib / dpctl.c
CommitLineData
fceef209 1/*
a129fe8c 2 * Copyright (c) 2008-2017 Nicira, Inc.
fceef209
DDP
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <config.h>
18#include <arpa/inet.h>
19#include <errno.h>
20#include <inttypes.h>
21#include <sys/socket.h>
22#include <net/if.h>
23#include <netinet/in.h>
24#include <stdarg.h>
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
28
29#include "command-line.h"
30#include "compiler.h"
dffae65f 31#include "ct-dpif.h"
fceef209
DDP
32#include "dirs.h"
33#include "dpctl.h"
34#include "dpif.h"
3e8a2ad1 35#include "openvswitch/dynamic-string.h"
fceef209 36#include "flow.h"
e29747e4 37#include "openvswitch/match.h"
fceef209 38#include "netdev.h"
abb5943d 39#include "netdev-dpdk.h"
fceef209
DDP
40#include "netlink.h"
41#include "odp-util.h"
64c96779 42#include "openvswitch/ofpbuf.h"
fceef209 43#include "packets.h"
ee89ea7b 44#include "openvswitch/shash.h"
fceef209
DDP
45#include "simap.h"
46#include "smap.h"
47#include "sset.h"
48#include "timeval.h"
49#include "unixctl.h"
50#include "util.h"
7888d2a6 51#include "openvswitch/ofp-parse.h"
d1fd1ea9
BP
52#include "openvswitch/vlog.h"
53VLOG_DEFINE_THIS_MODULE(dpctl);
fceef209 54
56cad666
AW
55typedef int dpctl_command_handler(int argc, const char *argv[],
56 struct dpctl_params *);
57struct dpctl_command {
58 const char *name;
59 const char *usage;
60 int min_args;
61 int max_args;
62 dpctl_command_handler *handler;
1f4a7252 63 enum { DP_RO, DP_RW} mode;
56cad666
AW
64};
65static const struct dpctl_command *get_all_dpctl_commands(void);
7521b9e5
DDP
66static void dpctl_print(struct dpctl_params *dpctl_p, const char *fmt, ...)
67 OVS_PRINTF_FORMAT(2, 3);
68static void dpctl_error(struct dpctl_params* dpctl_p, int err_no,
69 const char *fmt, ...)
70 OVS_PRINTF_FORMAT(3, 4);
56cad666 71
fceef209
DDP
72static void
73dpctl_puts(struct dpctl_params *dpctl_p, bool error, const char *string)
74{
75 dpctl_p->output(dpctl_p->aux, error, string);
76}
77
78static void
79dpctl_print(struct dpctl_params *dpctl_p, const char *fmt, ...)
80{
81 char *string;
82 va_list args;
83
84 va_start(args, fmt);
85 string = xvasprintf(fmt, args);
86 va_end(args);
87
88 dpctl_puts(dpctl_p, false, string);
89 free(string);
90}
91
92static void
93dpctl_error(struct dpctl_params* dpctl_p, int err_no, const char *fmt, ...)
94{
95 const char *subprogram_name = get_subprogram_name();
96 struct ds ds = DS_EMPTY_INITIALIZER;
97 int save_errno = errno;
98 va_list args;
99
100
101 if (subprogram_name[0]) {
102 ds_put_format(&ds, "%s(%s): ", program_name,subprogram_name);
103 } else {
104 ds_put_format(&ds, "%s: ", program_name);
105 }
106
107 va_start(args, fmt);
108 ds_put_format_valist(&ds, fmt, args);
109 va_end(args);
110
111 if (err_no != 0) {
112 ds_put_format(&ds, " (%s)", ovs_retval_to_string(err_no));
113 }
114 ds_put_cstr(&ds, "\n");
115
116 dpctl_puts(dpctl_p, true, ds_cstr(&ds));
117
118 ds_destroy(&ds);
119
120 errno = save_errno;
121}
122\f
123static int dpctl_add_if(int argc, const char *argv[], struct dpctl_params *);
124
125static int
126if_up(struct netdev *netdev)
127{
128 return netdev_turn_flags_on(netdev, NETDEV_UP, NULL);
129}
130
131/* Retrieve the name of the datapath if exactly one exists. The caller
132 * is responsible for freeing the returned string. If there is not one
133 * datapath, aborts with an error message. */
134static char *
135get_one_dp(struct dpctl_params *dpctl_p)
136{
137 struct sset types;
138 const char *type;
139 char *dp_name = NULL;
140 size_t count = 0;
141
142 sset_init(&types);
143 dp_enumerate_types(&types);
144 SSET_FOR_EACH (type, &types) {
145 struct sset names;
146
147 sset_init(&names);
148 if (!dp_enumerate_names(type, &names)) {
149 count += sset_count(&names);
150 if (!dp_name && count == 1) {
151 dp_name = xasprintf("%s@%s", type, SSET_FIRST(&names));
152 }
153 }
154 sset_destroy(&names);
155 }
156 sset_destroy(&types);
157
158 if (!count) {
159 dpctl_error(dpctl_p, 0, "no datapaths exist");
160 } else if (count > 1) {
161 dpctl_error(dpctl_p, 0, "multiple datapaths, specify one");
162 free(dp_name);
163 dp_name = NULL;
164 }
165
166 return dp_name;
167}
168
169static int
170parsed_dpif_open(const char *arg_, bool create, struct dpif **dpifp)
171{
172 int result;
173 char *name, *type;
174
175 dp_parse_name(arg_, &name, &type);
176
177 if (create) {
178 result = dpif_create(name, type, dpifp);
179 } else {
180 result = dpif_open(name, type, dpifp);
181 }
182
183 free(name);
184 free(type);
185 return result;
186}
187
188static int
189dpctl_add_dp(int argc, const char *argv[],
190 struct dpctl_params *dpctl_p)
191{
192 struct dpif *dpif;
193 int error;
194
195 error = parsed_dpif_open(argv[1], true, &dpif);
196 if (error) {
197 dpctl_error(dpctl_p, error, "add_dp");
198 return error;
199 }
200 dpif_close(dpif);
201 if (argc > 2) {
202 error = dpctl_add_if(argc, argv, dpctl_p);
203 }
204 return error;
205}
206
207static int
208dpctl_del_dp(int argc OVS_UNUSED, const char *argv[],
209 struct dpctl_params *dpctl_p)
210{
211 struct dpif *dpif;
212 int error;
213
214 error = parsed_dpif_open(argv[1], false, &dpif);
215 if (error) {
216 dpctl_error(dpctl_p, error, "opening datapath");
217 return error;
218 }
219 error = dpif_delete(dpif);
220 if (error) {
221 dpctl_error(dpctl_p, error, "del_dp");
222 }
223
224 dpif_close(dpif);
225 return error;
226}
227
228static int
229dpctl_add_if(int argc OVS_UNUSED, const char *argv[],
230 struct dpctl_params *dpctl_p)
231{
232 struct dpif *dpif;
233 int i, error, lasterror = 0;
234
235 error = parsed_dpif_open(argv[1], false, &dpif);
236 if (error) {
237 dpctl_error(dpctl_p, error, "opening datapath");
238 return error;
239 }
240 for (i = 2; i < argc; i++) {
241 const char *name, *type;
242 char *save_ptr = NULL, *argcopy;
243 struct netdev *netdev = NULL;
244 struct smap args;
245 odp_port_t port_no = ODPP_NONE;
246 char *option;
247
248 argcopy = xstrdup(argv[i]);
249 name = strtok_r(argcopy, ",", &save_ptr);
250 type = "system";
251
252 if (!name) {
253 dpctl_error(dpctl_p, 0, "%s is not a valid network device name",
254 argv[i]);
255 error = EINVAL;
256 goto next;
257 }
258
259 smap_init(&args);
260 while ((option = strtok_r(NULL, ",", &save_ptr)) != NULL) {
261 char *save_ptr_2 = NULL;
262 char *key, *value;
263
264 key = strtok_r(option, "=", &save_ptr_2);
265 value = strtok_r(NULL, "", &save_ptr_2);
266 if (!value) {
267 value = "";
268 }
269
270 if (!strcmp(key, "type")) {
271 type = value;
272 } else if (!strcmp(key, "port_no")) {
273 port_no = u32_to_odp(atoi(value));
274 } else if (!smap_add_once(&args, key, value)) {
275 dpctl_error(dpctl_p, 0, "duplicate \"%s\" option", key);
276 }
277 }
278
279 error = netdev_open(name, type, &netdev);
280 if (error) {
281 dpctl_error(dpctl_p, error, "%s: failed to open network device",
282 name);
283 goto next_destroy_args;
284 }
285
286 error = netdev_set_config(netdev, &args, NULL);
287 if (error) {
288 goto next_destroy_args;
289 }
290
291 error = dpif_port_add(dpif, netdev, &port_no);
292 if (error) {
293 dpctl_error(dpctl_p, error, "adding %s to %s failed", name,
294 argv[1]);
295 goto next_destroy_args;
296 }
297
298 error = if_up(netdev);
299 if (error) {
300 dpctl_error(dpctl_p, error, "%s: failed bringing interface up",
301 name);
302 }
303
304next_destroy_args:
305 netdev_close(netdev);
306 smap_destroy(&args);
307next:
308 free(argcopy);
309 if (error) {
310 lasterror = error;
311 }
312 }
313 dpif_close(dpif);
314
315 return lasterror;
316}
317
318static int
319dpctl_set_if(int argc, const char *argv[], struct dpctl_params *dpctl_p)
320{
321 struct dpif *dpif;
322 int i, error, lasterror = 0;
323
324 error = parsed_dpif_open(argv[1], false, &dpif);
325 if (error) {
326 dpctl_error(dpctl_p, error, "opening datapath");
327 return error;
328 }
329 for (i = 2; i < argc; i++) {
330 struct netdev *netdev = NULL;
331 struct dpif_port dpif_port;
332 char *save_ptr = NULL;
333 char *type = NULL;
334 char *argcopy;
335 const char *name;
336 struct smap args;
337 odp_port_t port_no;
338 char *option;
71f21279
BP
339
340 error = 0;
fceef209
DDP
341
342 argcopy = xstrdup(argv[i]);
343 name = strtok_r(argcopy, ",", &save_ptr);
344 if (!name) {
345 dpctl_error(dpctl_p, 0, "%s is not a valid network device name",
346 argv[i]);
347 goto next;
348 }
349
350 /* Get the port's type from the datapath. */
351 error = dpif_port_query_by_name(dpif, name, &dpif_port);
352 if (error) {
353 dpctl_error(dpctl_p, error, "%s: failed to query port in %s", name,
354 argv[1]);
355 goto next;
356 }
357 type = xstrdup(dpif_port.type);
358 port_no = dpif_port.port_no;
359 dpif_port_destroy(&dpif_port);
360
361 /* Retrieve its existing configuration. */
362 error = netdev_open(name, type, &netdev);
363 if (error) {
364 dpctl_error(dpctl_p, error, "%s: failed to open network device",
365 name);
366 goto next;
367 }
368
369 smap_init(&args);
370 error = netdev_get_config(netdev, &args);
371 if (error) {
372 dpctl_error(dpctl_p, error, "%s: failed to fetch configuration",
373 name);
374 goto next_destroy_args;
375 }
376
377 /* Parse changes to configuration. */
378 while ((option = strtok_r(NULL, ",", &save_ptr)) != NULL) {
379 char *save_ptr_2 = NULL;
380 char *key, *value;
381
382 key = strtok_r(option, "=", &save_ptr_2);
383 value = strtok_r(NULL, "", &save_ptr_2);
384 if (!value) {
385 value = "";
386 }
387
388 if (!strcmp(key, "type")) {
389 if (strcmp(value, type)) {
390 dpctl_error(dpctl_p, 0,
391 "%s: can't change type from %s to %s",
392 name, type, value);
393 error = EINVAL;
79ae214d 394 goto next_destroy_args;
fceef209
DDP
395 }
396 } else if (!strcmp(key, "port_no")) {
397 if (port_no != u32_to_odp(atoi(value))) {
398 dpctl_error(dpctl_p, 0, "%s: can't change port number from"
399 " %"PRIu32" to %d", name, port_no, atoi(value));
400 error = EINVAL;
79ae214d 401 goto next_destroy_args;
fceef209
DDP
402 }
403 } else if (value[0] == '\0') {
404 smap_remove(&args, key);
405 } else {
406 smap_replace(&args, key, value);
407 }
408 }
409
410 /* Update configuration. */
79ae214d
BP
411 char *err_s = NULL;
412 error = netdev_set_config(netdev, &args, &err_s);
413 if (err_s || error) {
7521b9e5 414 dpctl_error(dpctl_p, error, "%s",
79ae214d
BP
415 err_s ? err_s : "Error updating configuration");
416 free(err_s);
417 }
fceef209
DDP
418 if (error) {
419 goto next_destroy_args;
420 }
421
422next_destroy_args:
423 smap_destroy(&args);
424next:
425 netdev_close(netdev);
426 free(type);
427 free(argcopy);
428 if (error) {
429 lasterror = error;
430 }
431 }
432 dpif_close(dpif);
433
434 return lasterror;
435}
436
437static bool
438get_port_number(struct dpif *dpif, const char *name, odp_port_t *port,
439 struct dpctl_params *dpctl_p)
440{
441 struct dpif_port dpif_port;
442
443 if (!dpif_port_query_by_name(dpif, name, &dpif_port)) {
444 *port = dpif_port.port_no;
445 dpif_port_destroy(&dpif_port);
446 return true;
447 } else {
448 dpctl_error(dpctl_p, 0, "no port named %s", name);
449 return false;
450 }
451}
452
453static int
454dpctl_del_if(int argc, const char *argv[], struct dpctl_params *dpctl_p)
455{
456 struct dpif *dpif;
457 int i, error, lasterror = 0;
458
459 error = parsed_dpif_open(argv[1], false, &dpif);
460 if (error) {
461 dpctl_error(dpctl_p, error, "opening datapath");
462 return error;
463 }
464 for (i = 2; i < argc; i++) {
465 const char *name = argv[i];
466 odp_port_t port;
467
468 if (!name[strspn(name, "0123456789")]) {
469 port = u32_to_odp(atoi(name));
470 } else if (!get_port_number(dpif, name, &port, dpctl_p)) {
471 lasterror = ENOENT;
472 continue;
473 }
474
475 error = dpif_port_del(dpif, port);
476 if (error) {
477 dpctl_error(dpctl_p, error, "deleting port %s from %s failed",
478 name, argv[1]);
479 lasterror = error;
480 }
481 }
482 dpif_close(dpif);
483 return lasterror;
484}
485
486static void
487print_stat(struct dpctl_params *dpctl_p, const char *leader, uint64_t value)
488{
489 dpctl_print(dpctl_p, "%s", leader);
490 if (value != UINT64_MAX) {
491 dpctl_print(dpctl_p, "%"PRIu64, value);
492 } else {
493 dpctl_print(dpctl_p, "?");
494 }
495}
496
497static void
498print_human_size(struct dpctl_params *dpctl_p, uint64_t value)
499{
500 if (value == UINT64_MAX) {
501 /* Nothing to do. */
502 } else if (value >= 1024ULL * 1024 * 1024 * 1024) {
503 dpctl_print(dpctl_p, " (%.1f TiB)",
504 value / (1024.0 * 1024 * 1024 * 1024));
505 } else if (value >= 1024ULL * 1024 * 1024) {
506 dpctl_print(dpctl_p, " (%.1f GiB)", value / (1024.0 * 1024 * 1024));
507 } else if (value >= 1024ULL * 1024) {
508 dpctl_print(dpctl_p, " (%.1f MiB)", value / (1024.0 * 1024));
509 } else if (value >= 1024) {
510 dpctl_print(dpctl_p, " (%.1f KiB)", value / 1024.0);
511 }
512}
513
3ff1613e
JP
514/* qsort comparison function. */
515static int
516compare_port_nos(const void *a_, const void *b_)
517{
518 const odp_port_t *ap = a_;
519 const odp_port_t *bp = b_;
520 uint32_t a = odp_to_u32(*ap);
521 uint32_t b = odp_to_u32(*bp);
522
523 return a < b ? -1 : a > b;
524}
525
fceef209
DDP
526static void
527show_dpif(struct dpif *dpif, struct dpctl_params *dpctl_p)
528{
529 struct dpif_port_dump dump;
530 struct dpif_port dpif_port;
531 struct dpif_dp_stats stats;
532 struct netdev *netdev;
533
534 dpctl_print(dpctl_p, "%s:\n", dpif_name(dpif));
535 if (!dpif_get_dp_stats(dpif, &stats)) {
536 dpctl_print(dpctl_p, "\tlookups: hit:%"PRIu64" missed:%"PRIu64
537 " lost:%"PRIu64"\n\tflows: %"PRIu64"\n",
538 stats.n_hit, stats.n_missed, stats.n_lost, stats.n_flows);
539 if (stats.n_masks != UINT32_MAX) {
540 uint64_t n_pkts = stats.n_hit + stats.n_missed;
541 double avg = n_pkts ? (double) stats.n_mask_hit / n_pkts : 0.0;
542
543 dpctl_print(dpctl_p, "\tmasks: hit:%"PRIu64" total:%"PRIu32
544 " hit/pkt:%.2f\n",
545 stats.n_mask_hit, stats.n_masks, avg);
546 }
547 }
548
3ff1613e
JP
549 odp_port_t *port_nos = NULL;
550 size_t allocated_port_nos = 0, n_port_nos = 0;
fceef209 551 DPIF_PORT_FOR_EACH (&dpif_port, &dump, dpif) {
3ff1613e
JP
552 if (n_port_nos >= allocated_port_nos) {
553 port_nos = x2nrealloc(port_nos, &allocated_port_nos,
554 sizeof *port_nos);
555 }
556
557 port_nos[n_port_nos] = dpif_port.port_no;
558 n_port_nos++;
559 }
560
f77ceea3
BB
561 if (port_nos) {
562 qsort(port_nos, n_port_nos, sizeof *port_nos, compare_port_nos);
563 }
3ff1613e
JP
564
565 for (int i = 0; i < n_port_nos; i++) {
566 if (dpif_port_query_by_number(dpif, port_nos[i], &dpif_port)) {
567 continue;
568 }
569
fceef209
DDP
570 dpctl_print(dpctl_p, "\tport %u: %s",
571 dpif_port.port_no, dpif_port.name);
572
573 if (strcmp(dpif_port.type, "system")) {
574 int error;
575
576 dpctl_print(dpctl_p, " (%s", dpif_port.type);
577
578 error = netdev_open(dpif_port.name, dpif_port.type, &netdev);
579 if (!error) {
580 struct smap config;
581
582 smap_init(&config);
583 error = netdev_get_config(netdev, &config);
584 if (!error) {
270fa6da
JP
585 const struct smap_node **nodes = smap_sort(&config);
586 for (size_t j = 0; j < smap_count(&config); j++) {
587 const struct smap_node *node = nodes[j];
588 dpctl_print(dpctl_p, "%c %s=%s", j ? ',' : ':',
fceef209
DDP
589 node->key, node->value);
590 }
591 free(nodes);
592 } else {
593 dpctl_print(dpctl_p, ", could not retrieve configuration "
594 "(%s)", ovs_strerror(error));
595 }
596 smap_destroy(&config);
597
598 netdev_close(netdev);
599 } else {
600 dpctl_print(dpctl_p, ": open failed (%s)",
601 ovs_strerror(error));
602 }
603 dpctl_print(dpctl_p, ")");
604 }
605 dpctl_print(dpctl_p, "\n");
606
607 if (dpctl_p->print_statistics) {
608 struct netdev_stats s;
609 int error;
610
611 error = netdev_open(dpif_port.name, dpif_port.type, &netdev);
612 if (error) {
613 dpctl_print(dpctl_p, ", open failed (%s)",
614 ovs_strerror(error));
3ff1613e 615 dpif_port_destroy(&dpif_port);
fceef209
DDP
616 continue;
617 }
618 error = netdev_get_stats(netdev, &s);
619 if (!error) {
620 netdev_close(netdev);
621 print_stat(dpctl_p, "\t\tRX packets:", s.rx_packets);
622 print_stat(dpctl_p, " errors:", s.rx_errors);
623 print_stat(dpctl_p, " dropped:", s.rx_dropped);
624 print_stat(dpctl_p, " overruns:", s.rx_over_errors);
625 print_stat(dpctl_p, " frame:", s.rx_frame_errors);
626 dpctl_print(dpctl_p, "\n");
627
628 print_stat(dpctl_p, "\t\tTX packets:", s.tx_packets);
629 print_stat(dpctl_p, " errors:", s.tx_errors);
630 print_stat(dpctl_p, " dropped:", s.tx_dropped);
631 print_stat(dpctl_p, " aborted:", s.tx_aborted_errors);
632 print_stat(dpctl_p, " carrier:", s.tx_carrier_errors);
633 dpctl_print(dpctl_p, "\n");
634
635 print_stat(dpctl_p, "\t\tcollisions:", s.collisions);
636 dpctl_print(dpctl_p, "\n");
637
638 print_stat(dpctl_p, "\t\tRX bytes:", s.rx_bytes);
639 print_human_size(dpctl_p, s.rx_bytes);
640 print_stat(dpctl_p, " TX bytes:", s.tx_bytes);
641 print_human_size(dpctl_p, s.tx_bytes);
642 dpctl_print(dpctl_p, "\n");
643 } else {
644 dpctl_print(dpctl_p, ", could not retrieve stats (%s)",
645 ovs_strerror(error));
646 }
647 }
3ff1613e 648 dpif_port_destroy(&dpif_port);
fceef209 649 }
3ff1613e
JP
650
651 free(port_nos);
1f70f3f0
DDP
652}
653
654typedef void (*dps_for_each_cb)(struct dpif *, struct dpctl_params *);
655
656static int
657dps_for_each(struct dpctl_params *dpctl_p, dps_for_each_cb cb)
658{
659 struct sset dpif_names = SSET_INITIALIZER(&dpif_names),
660 dpif_types = SSET_INITIALIZER(&dpif_types);
88c98bf5 661 int error, openerror = 0, enumerror = 0;
1f70f3f0 662 const char *type, *name;
88c98bf5 663 bool at_least_one = false;
1f70f3f0
DDP
664
665 dp_enumerate_types(&dpif_types);
666
667 SSET_FOR_EACH (type, &dpif_types) {
668 error = dp_enumerate_names(type, &dpif_names);
669 if (error) {
88c98bf5 670 enumerror = error;
1f70f3f0
DDP
671 }
672
673 SSET_FOR_EACH (name, &dpif_names) {
674 struct dpif *dpif;
675
88c98bf5 676 at_least_one = true;
1f70f3f0
DDP
677 error = dpif_open(name, type, &dpif);
678 if (!error) {
679 cb(dpif, dpctl_p);
680 dpif_close(dpif);
681 } else {
88c98bf5 682 openerror = error;
1f70f3f0
DDP
683 dpctl_error(dpctl_p, error, "opening datapath %s failed",
684 name);
685 }
686 }
687 }
688
689 sset_destroy(&dpif_names);
690 sset_destroy(&dpif_types);
691
88c98bf5
DDP
692 /* If there has been an error while opening a datapath it should be
693 * reported. Otherwise, we want to ignore the errors generated by
694 * dp_enumerate_names() if at least one datapath has been discovered,
695 * because they're not interesting for the user. This happens, for
696 * example, if OVS is using a userspace datapath and the kernel module
697 * is not loaded. */
698 if (openerror) {
699 return openerror;
700 } else {
701 return at_least_one ? 0 : enumerror;
702 }
fceef209
DDP
703}
704
705static int
706dpctl_show(int argc, const char *argv[], struct dpctl_params *dpctl_p)
707{
708 int error, lasterror = 0;
709 if (argc > 1) {
710 int i;
711 for (i = 1; i < argc; i++) {
712 const char *name = argv[i];
713 struct dpif *dpif;
714
715 error = parsed_dpif_open(name, false, &dpif);
716 if (!error) {
717 show_dpif(dpif, dpctl_p);
1f70f3f0 718 dpif_close(dpif);
fceef209
DDP
719 } else {
720 dpctl_error(dpctl_p, error, "opening datapath %s failed",
721 name);
722 lasterror = error;
723 }
724 }
725 } else {
1f70f3f0 726 lasterror = dps_for_each(dpctl_p, show_dpif);
fceef209 727 }
1f70f3f0 728
fceef209
DDP
729 return lasterror;
730}
731
1f70f3f0
DDP
732static void
733dump_cb(struct dpif *dpif, struct dpctl_params *dpctl_p)
734{
735 dpctl_print(dpctl_p, "%s\n", dpif_name(dpif));
736}
737
fceef209
DDP
738static int
739dpctl_dump_dps(int argc OVS_UNUSED, const char *argv[] OVS_UNUSED,
740 struct dpctl_params *dpctl_p)
741{
1f70f3f0 742 return dps_for_each(dpctl_p, dump_cb);
fceef209
DDP
743}
744
818650e6
JS
745static void
746format_dpif_flow(struct ds *ds, const struct dpif_flow *f, struct hmap *ports,
4742003c 747 char *type, struct dpctl_params *dpctl_p)
818650e6 748{
fbe794aa
JS
749 if (dpctl_p->verbosity && f->ufid_present) {
750 odp_format_ufid(&f->ufid, ds);
751 ds_put_cstr(ds, ", ");
818650e6
JS
752 }
753 odp_flow_format(f->key, f->key_len, f->mask, f->mask_len, ports, ds,
754 dpctl_p->verbosity);
755 ds_put_cstr(ds, ", ");
756
757 dpif_flow_stats_format(&f->stats, ds);
4742003c
PB
758 if (dpctl_p->verbosity && !type && f->offloaded) {
759 ds_put_cstr(ds, ", offloaded:yes");
760 }
818650e6 761 ds_put_cstr(ds, ", actions:");
0722f341 762 format_odp_actions(ds, f->actions, f->actions_len, ports);
818650e6
JS
763}
764
7e8b7199
PB
765static char *supported_dump_types[] = {
766 "offloaded",
767 "ovs",
768};
769
d1fd1ea9
BP
770static struct hmap *
771dpctl_get_portno_names(struct dpif *dpif, const struct dpctl_params *dpctl_p)
772{
773 if (dpctl_p->names) {
774 struct hmap *portno_names = xmalloc(sizeof *portno_names);
775 hmap_init(portno_names);
776
777 struct dpif_port_dump port_dump;
778 struct dpif_port dpif_port;
779 DPIF_PORT_FOR_EACH (&dpif_port, &port_dump, dpif) {
780 odp_portno_names_set(portno_names, dpif_port.port_no,
781 dpif_port.name);
782 }
783
784 return portno_names;
785 } else {
786 return NULL;
787 }
788}
789
790static void
791dpctl_free_portno_names(struct hmap *portno_names)
792{
793 if (portno_names) {
794 odp_portno_names_destroy(portno_names);
795 hmap_destroy(portno_names);
796 free(portno_names);
797 }
798}
799
fceef209
DDP
800static int
801dpctl_dump_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
802{
803 struct dpif *dpif;
804 struct ds ds;
805 char *name;
806
807 char *filter = NULL;
7e8b7199 808 char *type = NULL;
fceef209
DDP
809 struct flow flow_filter;
810 struct flow_wildcards wc_filter;
811
fceef209
DDP
812 struct dpif_flow_dump_thread *flow_dump_thread;
813 struct dpif_flow_dump *flow_dump;
814 struct dpif_flow f;
1c1e46ed 815 int pmd_id = PMD_ID_NULL;
7e8b7199 816 int lastargc = 0;
fceef209
DDP
817 int error;
818
7e8b7199
PB
819 while (argc > 1 && lastargc != argc) {
820 lastargc = argc;
821 if (!strncmp(argv[argc - 1], "filter=", 7) && !filter) {
822 filter = xstrdup(argv[--argc] + 7);
823 } else if (!strncmp(argv[argc - 1], "type=", 5) && !type) {
824 type = xstrdup(argv[--argc] + 5);
825 }
fceef209 826 }
7e8b7199
PB
827
828 name = (argc > 1) ? xstrdup(argv[1]) : get_one_dp(dpctl_p);
fceef209
DDP
829 if (!name) {
830 error = EINVAL;
7e8b7199 831 goto out_free;
fceef209
DDP
832 }
833
834 error = parsed_dpif_open(name, false, &dpif);
835 free(name);
836 if (error) {
837 dpctl_error(dpctl_p, error, "opening datapath");
7e8b7199 838 goto out_free;
fceef209
DDP
839 }
840
d1fd1ea9 841 struct hmap *portno_names = dpctl_get_portno_names(dpif, dpctl_p);
fceef209
DDP
842
843 if (filter) {
50f96b10
BP
844 struct ofputil_port_map port_map;
845 ofputil_port_map_init(&port_map);
d1fd1ea9
BP
846
847 struct dpif_port_dump port_dump;
848 struct dpif_port dpif_port;
50f96b10
BP
849 DPIF_PORT_FOR_EACH (&dpif_port, &port_dump, dpif) {
850 ofputil_port_map_put(&port_map,
851 u16_to_ofp(odp_to_u32(dpif_port.port_no)),
852 dpif_port.name);
853 }
854 char *err = parse_ofp_exact_flow(&flow_filter, &wc_filter, NULL,
855 filter, &port_map);
856 ofputil_port_map_destroy(&port_map);
fceef209
DDP
857 if (err) {
858 dpctl_error(dpctl_p, 0, "Failed to parse filter (%s)", err);
a129fe8c 859 free(err);
fceef209
DDP
860 error = EINVAL;
861 goto out_dpifclose;
862 }
863 }
864
7e8b7199
PB
865 if (type) {
866 error = EINVAL;
867 for (int i = 0; i < ARRAY_SIZE(supported_dump_types); i++) {
868 if (!strcmp(supported_dump_types[i], type)) {
869 error = 0;
870 break;
871 }
872 }
873 if (error) {
874 dpctl_error(dpctl_p, error, "Failed to parse type (%s)", type);
875 goto out_free;
876 }
877 }
878
d5c199ea
DDP
879 /* Make sure that these values are different. PMD_ID_NULL means that the
880 * pmd is unspecified (e.g. because the datapath doesn't have different
881 * pmd threads), while NON_PMD_CORE_ID refers to every non pmd threads
882 * in the userspace datapath */
883 BUILD_ASSERT(PMD_ID_NULL != NON_PMD_CORE_ID);
884
fceef209 885 ds_init(&ds);
4742003c 886 memset(&f, 0, sizeof f);
7e8b7199 887 flow_dump = dpif_flow_dump_create(dpif, false, (type ? type : "dpctl"));
fceef209
DDP
888 flow_dump_thread = dpif_flow_dump_thread_create(flow_dump);
889 while (dpif_flow_dump_next(flow_dump_thread, &f, 1)) {
890 if (filter) {
891 struct flow flow;
892 struct flow_wildcards wc;
893 struct match match, match_filter;
894 struct minimatch minimatch;
895
896 odp_flow_key_to_flow(f.key, f.key_len, &flow);
8d8ab6c2 897 odp_flow_key_to_mask(f.mask, f.mask_len, &wc, &flow);
fceef209
DDP
898 match_init(&match, &flow, &wc);
899
900 match_init(&match_filter, &flow_filter, &wc);
901 match_init(&match_filter, &match_filter.flow, &wc_filter);
902 minimatch_init(&minimatch, &match_filter);
903
904 if (!minimatch_matches_flow(&minimatch, &match.flow)) {
905 minimatch_destroy(&minimatch);
906 continue;
907 }
908 minimatch_destroy(&minimatch);
909 }
910 ds_clear(&ds);
1c1e46ed
AW
911 /* If 'pmd_id' is specified, overlapping flows could be dumped from
912 * different pmd threads. So, separates dumps from different pmds
913 * by printing a title line. */
914 if (pmd_id != f.pmd_id) {
915 if (f.pmd_id == NON_PMD_CORE_ID) {
916 ds_put_format(&ds, "flow-dump from non-dpdk interfaces:\n");
917 } else {
918 ds_put_format(&ds, "flow-dump from pmd on cpu core: %d\n",
919 f.pmd_id);
920 }
921 pmd_id = f.pmd_id;
922 }
d1fd1ea9 923 format_dpif_flow(&ds, &f, portno_names, type, dpctl_p);
4742003c 924
fceef209
DDP
925 dpctl_print(dpctl_p, "%s\n", ds_cstr(&ds));
926 }
927 dpif_flow_dump_thread_destroy(flow_dump_thread);
928 error = dpif_flow_dump_destroy(flow_dump);
929
930 if (error) {
931 dpctl_error(dpctl_p, error, "Failed to dump flows from datapath");
932 }
933 ds_destroy(&ds);
934
935out_dpifclose:
d1fd1ea9 936 dpctl_free_portno_names(portno_names);
fceef209 937 dpif_close(dpif);
7e8b7199 938out_free:
fceef209 939 free(filter);
7e8b7199 940 free(type);
fceef209
DDP
941 return error;
942}
943
944static int
945dpctl_put_flow(int argc, const char *argv[], enum dpif_flow_put_flags flags,
946 struct dpctl_params *dpctl_p)
947{
948 const char *key_s = argv[argc - 2];
949 const char *actions_s = argv[argc - 1];
950 struct dpif_flow_stats stats;
951 struct dpif_port dpif_port;
952 struct dpif_port_dump port_dump;
953 struct ofpbuf actions;
954 struct ofpbuf key;
955 struct ofpbuf mask;
956 struct dpif *dpif;
534a19b9
JS
957 ovs_u128 ufid;
958 bool ufid_present;
fceef209
DDP
959 char *dp_name;
960 struct simap port_names;
534a19b9 961 int n, error;
fceef209
DDP
962
963 dp_name = argc == 4 ? xstrdup(argv[1]) : get_one_dp(dpctl_p);
964 if (!dp_name) {
965 return EINVAL;
966 }
967 error = parsed_dpif_open(dp_name, false, &dpif);
968 free(dp_name);
969 if (error) {
970 dpctl_error(dpctl_p, error, "opening datapath");
971 return error;
972 }
973
534a19b9
JS
974 ufid_present = false;
975 n = odp_ufid_from_string(key_s, &ufid);
976 if (n < 0) {
977 dpctl_error(dpctl_p, -n, "parsing flow ufid");
978 return -n;
979 } else if (n) {
980 key_s += n;
981 ufid_present = true;
982 }
fceef209
DDP
983
984 simap_init(&port_names);
985 DPIF_PORT_FOR_EACH (&dpif_port, &port_dump, dpif) {
986 simap_put(&port_names, dpif_port.name, odp_to_u32(dpif_port.port_no));
987 }
988
989 ofpbuf_init(&key, 0);
990 ofpbuf_init(&mask, 0);
991 error = odp_flow_from_string(key_s, &port_names, &key, &mask);
992 simap_destroy(&port_names);
993 if (error) {
994 dpctl_error(dpctl_p, error, "parsing flow key");
995 goto out_freekeymask;
996 }
997
998 ofpbuf_init(&actions, 0);
999 error = odp_actions_from_string(actions_s, NULL, &actions);
1000 if (error) {
1001 dpctl_error(dpctl_p, error, "parsing actions");
1002 goto out_freeactions;
1003 }
1c1e46ed 1004
f5d317a1
DDP
1005 /* The flow will be added on all pmds currently in the datapath. */
1006 error = dpif_flow_put(dpif, flags,
1007 key.data, key.size,
1008 mask.size == 0 ? NULL : mask.data,
1009 mask.size, actions.data,
1010 actions.size, ufid_present ? &ufid : NULL,
1011 PMD_ID_NULL,
1012 dpctl_p->print_statistics ? &stats : NULL);
1013
fceef209
DDP
1014 if (error) {
1015 dpctl_error(dpctl_p, error, "updating flow table");
1016 goto out_freeactions;
1017 }
1018
1019 if (dpctl_p->print_statistics) {
1020 struct ds s;
1021
1022 ds_init(&s);
1023 dpif_flow_stats_format(&stats, &s);
1024 dpctl_print(dpctl_p, "%s\n", ds_cstr(&s));
1025 ds_destroy(&s);
1026 }
1027
1028out_freeactions:
1029 ofpbuf_uninit(&actions);
1030out_freekeymask:
1031 ofpbuf_uninit(&mask);
1032 ofpbuf_uninit(&key);
1033 dpif_close(dpif);
1034 return error;
1035}
1036
1037static int
1038dpctl_add_flow(int argc, const char *argv[], struct dpctl_params *dpctl_p)
1039{
1040 return dpctl_put_flow(argc, argv, DPIF_FP_CREATE, dpctl_p);
1041}
1042
1043static int
1044dpctl_mod_flow(int argc, const char *argv[], struct dpctl_params *dpctl_p)
1045{
1046 enum dpif_flow_put_flags flags;
1047
1048 flags = DPIF_FP_MODIFY;
1049 if (dpctl_p->may_create) {
1050 flags |= DPIF_FP_CREATE;
1051 }
1052 if (dpctl_p->zero_statistics) {
1053 flags |= DPIF_FP_ZERO_STATS;
1054 }
1055
1056 return dpctl_put_flow(argc, argv, flags, dpctl_p);
1057}
1058
818650e6
JS
1059static int
1060dpctl_get_flow(int argc, const char *argv[], struct dpctl_params *dpctl_p)
1061{
1062 const char *key_s = argv[argc - 1];
1063 struct dpif_flow flow;
818650e6
JS
1064 struct dpif *dpif;
1065 char *dp_name;
818650e6
JS
1066 ovs_u128 ufid;
1067 struct ofpbuf buf;
1068 uint64_t stub[DPIF_FLOW_BUFSIZE / 8];
1069 struct ds ds;
1070 int n, error;
1071
1072 dp_name = argc == 3 ? xstrdup(argv[1]) : get_one_dp(dpctl_p);
1073 if (!dp_name) {
1074 return EINVAL;
1075 }
1076 error = parsed_dpif_open(dp_name, false, &dpif);
1077 free(dp_name);
1078 if (error) {
1079 dpctl_error(dpctl_p, error, "opening datapath");
1080 return error;
1081 }
1082
1083 ofpbuf_use_stub(&buf, &stub, sizeof stub);
d1fd1ea9
BP
1084
1085 struct hmap *portno_names = dpctl_get_portno_names(dpif, dpctl_p);
818650e6
JS
1086
1087 n = odp_ufid_from_string(key_s, &ufid);
1088 if (n <= 0) {
1089 dpctl_error(dpctl_p, -n, "parsing flow ufid");
1090 goto out;
1091 }
1092
c673049c 1093 /* In case of PMD will be returned flow from first PMD thread with match. */
1c1e46ed 1094 error = dpif_flow_get(dpif, NULL, 0, &ufid, PMD_ID_NULL, &buf, &flow);
818650e6
JS
1095 if (error) {
1096 dpctl_error(dpctl_p, error, "getting flow");
1097 goto out;
1098 }
1099
1100 ds_init(&ds);
d1fd1ea9 1101 format_dpif_flow(&ds, &flow, portno_names, NULL, dpctl_p);
818650e6
JS
1102 dpctl_print(dpctl_p, "%s\n", ds_cstr(&ds));
1103 ds_destroy(&ds);
1104
1105out:
d1fd1ea9 1106 dpctl_free_portno_names(portno_names);
818650e6
JS
1107 ofpbuf_uninit(&buf);
1108 dpif_close(dpif);
1109 return error;
1110}
1111
fceef209
DDP
1112static int
1113dpctl_del_flow(int argc, const char *argv[], struct dpctl_params *dpctl_p)
1114{
1115 const char *key_s = argv[argc - 1];
1116 struct dpif_flow_stats stats;
1117 struct dpif_port dpif_port;
1118 struct dpif_port_dump port_dump;
1119 struct ofpbuf key;
1120 struct ofpbuf mask; /* To be ignored. */
1121 struct dpif *dpif;
534a19b9
JS
1122 ovs_u128 ufid;
1123 bool ufid_present;
fceef209
DDP
1124 char *dp_name;
1125 struct simap port_names;
534a19b9 1126 int n, error;
fceef209
DDP
1127
1128 dp_name = argc == 3 ? xstrdup(argv[1]) : get_one_dp(dpctl_p);
1129 if (!dp_name) {
1130 return EINVAL;
1131 }
1132 error = parsed_dpif_open(dp_name, false, &dpif);
1133 free(dp_name);
1134 if (error) {
1135 dpctl_error(dpctl_p, error, "opening datapath");
1136 return error;
1137 }
1138
534a19b9
JS
1139 ufid_present = false;
1140 n = odp_ufid_from_string(key_s, &ufid);
1141 if (n < 0) {
1142 dpctl_error(dpctl_p, -n, "parsing flow ufid");
1143 return -n;
1144 } else if (n) {
1145 key_s += n;
1146 ufid_present = true;
1147 }
1148
fceef209
DDP
1149 simap_init(&port_names);
1150 DPIF_PORT_FOR_EACH (&dpif_port, &port_dump, dpif) {
1151 simap_put(&port_names, dpif_port.name, odp_to_u32(dpif_port.port_no));
1152 }
1153
1154 ofpbuf_init(&key, 0);
1155 ofpbuf_init(&mask, 0);
1156
1157 error = odp_flow_from_string(key_s, &port_names, &key, &mask);
1158 if (error) {
1159 dpctl_error(dpctl_p, error, "parsing flow key");
1160 goto out;
1161 }
1162
f5d317a1
DDP
1163 /* The flow will be deleted from all pmds currently in the datapath. */
1164 error = dpif_flow_del(dpif, key.data, key.size,
1165 ufid_present ? &ufid : NULL, PMD_ID_NULL,
1166 dpctl_p->print_statistics ? &stats : NULL);
1167
fceef209
DDP
1168 if (error) {
1169 dpctl_error(dpctl_p, error, "deleting flow");
534a19b9
JS
1170 if (error == ENOENT && !ufid_present) {
1171 struct ds s;
1172
1173 ds_init(&s);
1174 ds_put_format(&s, "Perhaps you need to specify a UFID?");
1175 dpctl_print(dpctl_p, "%s\n", ds_cstr(&s));
1176 ds_destroy(&s);
1177 }
fceef209
DDP
1178 goto out;
1179 }
1180
1181 if (dpctl_p->print_statistics) {
1182 struct ds s;
1183
1184 ds_init(&s);
1185 dpif_flow_stats_format(&stats, &s);
1186 dpctl_print(dpctl_p, "%s\n", ds_cstr(&s));
1187 ds_destroy(&s);
1188 }
1189
1190out:
1191 ofpbuf_uninit(&mask);
1192 ofpbuf_uninit(&key);
1193 simap_destroy(&port_names);
1194 dpif_close(dpif);
1195 return error;
1196}
1197
1198static int
1199dpctl_del_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
1200{
1201 struct dpif *dpif;
1202 char *name;
1203 int error;
1204
1205 name = (argc == 2) ? xstrdup(argv[1]) : get_one_dp(dpctl_p);
1206 if (!name) {
1207 return EINVAL;
1208 }
1209 error = parsed_dpif_open(name, false, &dpif);
1210 free(name);
1211 if (error) {
1212 dpctl_error(dpctl_p, error, "opening datapath");
1213 return error;
1214 }
1215
1216 error = dpif_flow_flush(dpif);
1217 if (error) {
1218 dpctl_error(dpctl_p, error, "deleting all flows");
1219 }
1220 dpif_close(dpif);
1221 return error;
1222}
1223
1224static int
1225dpctl_help(int argc OVS_UNUSED, const char *argv[] OVS_UNUSED,
1226 struct dpctl_params *dpctl_p)
1227{
1228 if (dpctl_p->usage) {
1229 dpctl_p->usage(dpctl_p->aux);
1230 }
56cad666
AW
1231
1232 return 0;
1233}
1234
1235static int
1236dpctl_list_commands(int argc OVS_UNUSED, const char *argv[] OVS_UNUSED,
1237 struct dpctl_params *dpctl_p)
1238{
1239 struct ds ds = DS_EMPTY_INITIALIZER;
1240 const struct dpctl_command *commands = get_all_dpctl_commands();
1241
1242 ds_put_cstr(&ds, "The available commands are:\n");
1243 for (; commands->name; commands++) {
1244 const struct dpctl_command *c = commands;
1245
1246 ds_put_format(&ds, " %s%-23s %s\n", dpctl_p->is_appctl ? "dpctl/" : "",
1247 c->name, c->usage);
1248 }
1249 dpctl_puts(dpctl_p, false, ds.string);
1250 ds_destroy(&ds);
1251
fceef209
DDP
1252 return 0;
1253}
dffae65f
DDP
1254
1255static int
1256dpctl_dump_conntrack(int argc, const char *argv[],
1257 struct dpctl_params *dpctl_p)
1258{
1259 struct ct_dpif_dump_state *dump;
1260 struct ct_dpif_entry cte;
1261 uint16_t zone, *pzone = NULL;
ded30c74 1262 int tot_bkts;
dffae65f
DDP
1263 struct dpif *dpif;
1264 char *name;
1265 int error;
1266
1267 if (argc > 1 && ovs_scan(argv[argc - 1], "zone=%"SCNu16, &zone)) {
1268 pzone = &zone;
1269 argc--;
1270 }
1271 name = (argc == 2) ? xstrdup(argv[1]) : get_one_dp(dpctl_p);
1272 if (!name) {
1273 return EINVAL;
1274 }
1275 error = parsed_dpif_open(name, false, &dpif);
1276 free(name);
1277 if (error) {
1278 dpctl_error(dpctl_p, error, "opening datapath");
1279 return error;
1280 }
1281
ded30c74 1282 error = ct_dpif_dump_start(dpif, &dump, pzone, &tot_bkts);
dffae65f
DDP
1283 if (error) {
1284 dpctl_error(dpctl_p, error, "starting conntrack dump");
1285 dpif_close(dpif);
1286 return error;
1287 }
1288
1289 while (!ct_dpif_dump_next(dump, &cte)) {
1290 struct ds s = DS_EMPTY_INITIALIZER;
1291
1292 ct_dpif_format_entry(&cte, &s, dpctl_p->verbosity,
1293 dpctl_p->print_statistics);
1294 ct_dpif_entry_uninit(&cte);
1295
1296 dpctl_print(dpctl_p, "%s\n", ds_cstr(&s));
1297 ds_destroy(&s);
1298 }
1299 ct_dpif_dump_done(dump);
1300 dpif_close(dpif);
1301 return error;
1302}
1303
7f278d1f
DDP
1304static int
1305dpctl_flush_conntrack(int argc, const char *argv[],
1306 struct dpctl_params *dpctl_p)
1307{
1308 struct dpif *dpif;
1309 uint16_t zone, *pzone = NULL;
1310 char *name;
1311 int error;
1312
1313 if (argc > 1 && ovs_scan(argv[argc - 1], "zone=%"SCNu16, &zone)) {
1314 pzone = &zone;
1315 argc--;
1316 }
1317 name = (argc == 2) ? xstrdup(argv[1]) : get_one_dp(dpctl_p);
1318 if (!name) {
1319 return EINVAL;
1320 }
1321 error = parsed_dpif_open(name, false, &dpif);
1322 free(name);
1323 if (error) {
1324 dpctl_error(dpctl_p, error, "opening datapath");
1325 return error;
1326 }
1327
1328 error = ct_dpif_flush(dpif, pzone);
1329
1330 dpif_close(dpif);
1331 return error;
1332}
8a0d9d85
FA
1333
1334static int
1335dpctl_ct_stats_show(int argc, const char *argv[],
1336 struct dpctl_params *dpctl_p)
1337{
1338 struct dpif *dpif;
1339 char *name;
1340
1341 struct ct_dpif_dump_state *dump;
1342 struct ct_dpif_entry cte;
1343 uint16_t zone, *pzone = NULL;
ded30c74 1344 int tot_bkts;
8a0d9d85
FA
1345 bool verbose = false;
1346 int lastargc = 0;
1347
1348 int proto_stats[CT_STATS_MAX];
1349 int tcp_conn_per_states[CT_DPIF_TCPS_MAX_NUM];
1350 int error;
1351
1352 while (argc > 1 && lastargc != argc) {
1353 lastargc = argc;
1354 if (!strncmp(argv[argc - 1], "verbose", 7)) {
1355 verbose = true;
1356 argc--;
1357 } else if (!strncmp(argv[argc - 1], "zone=", 5)) {
1358 if (ovs_scan(argv[argc - 1], "zone=%"SCNu16, &zone)) {
1359 pzone = &zone;
1360 argc--;
1361 }
1362 }
1363 }
1364
1365 name = (argc > 1) ? xstrdup(argv[1]) : get_one_dp(dpctl_p);
1366 if (!name) {
1367 return EINVAL;
1368 }
1369
1370 error = parsed_dpif_open(name, false, &dpif);
1371 free(name);
1372 if (error) {
1373 dpctl_error(dpctl_p, error, "opening datapath");
1374 return error;
1375 }
1376
1377 memset(proto_stats, 0, sizeof(proto_stats));
1378 memset(tcp_conn_per_states, 0, sizeof(tcp_conn_per_states));
ded30c74 1379 error = ct_dpif_dump_start(dpif, &dump, pzone, &tot_bkts);
8a0d9d85
FA
1380 if (error) {
1381 dpctl_error(dpctl_p, error, "starting conntrack dump");
1382 dpif_close(dpif);
1383 return error;
1384 }
1385
1386 int tot_conn = 0;
1387 while (!ct_dpif_dump_next(dump, &cte)) {
1388 ct_dpif_entry_uninit(&cte);
1389 tot_conn++;
1390 switch (cte.tuple_orig.ip_proto) {
1391 case IPPROTO_ICMP:
1392 proto_stats[CT_STATS_ICMP]++;
1393 break;
1394 case IPPROTO_ICMPV6:
1395 proto_stats[CT_STATS_ICMPV6]++;
1396 break;
1397 case IPPROTO_TCP:
1398 proto_stats[CT_STATS_TCP]++;
1399 uint8_t tcp_state;
1400 /* We keep two separate tcp states, but we print just one. The
1401 * Linux kernel connection tracker internally keeps only one state,
1402 * so 'state_orig' and 'state_reply', will be the same. */
1403 tcp_state = MAX(cte.protoinfo.tcp.state_orig,
1404 cte.protoinfo.tcp.state_reply);
1405 tcp_state = ct_dpif_coalesce_tcp_state(tcp_state);
1406 tcp_conn_per_states[tcp_state]++;
1407 break;
1408 case IPPROTO_UDP:
1409 proto_stats[CT_STATS_UDP]++;
1410 break;
1411 case IPPROTO_SCTP:
1412 proto_stats[CT_STATS_SCTP]++;
1413 break;
1414 case IPPROTO_UDPLITE:
1415 proto_stats[CT_STATS_UDPLITE]++;
1416 break;
1417 case IPPROTO_DCCP:
1418 proto_stats[CT_STATS_DCCP]++;
1419 break;
1420 case IPPROTO_IGMP:
1421 proto_stats[CT_STATS_IGMP]++;
1422 break;
1423 default:
1424 proto_stats[CT_STATS_OTHER]++;
1425 break;
1426 }
1427 }
1428
1429 dpctl_print(dpctl_p, "Connections Stats:\n Total: %d\n", tot_conn);
1430 if (proto_stats[CT_STATS_TCP]) {
1431 dpctl_print(dpctl_p, "\tTCP: %d\n", proto_stats[CT_STATS_TCP]);
1432 if (verbose) {
1433 dpctl_print(dpctl_p, "\t Conn per TCP states:\n");
1434 for (int i = 0; i < CT_DPIF_TCPS_MAX_NUM; i++) {
1435 if (tcp_conn_per_states[i]) {
1436 struct ds s = DS_EMPTY_INITIALIZER;
1437 ct_dpif_format_tcp_stat(&s, i, tcp_conn_per_states[i]);
1438 dpctl_print(dpctl_p, "%s\n", ds_cstr(&s));
1439 ds_destroy(&s);
1440 }
1441 }
1442 }
1443 }
1444 if (proto_stats[CT_STATS_UDP]) {
1445 dpctl_print(dpctl_p, "\tUDP: %d\n", proto_stats[CT_STATS_UDP]);
1446 }
1447 if (proto_stats[CT_STATS_UDPLITE]) {
1448 dpctl_print(dpctl_p, "\tUDPLITE: %d\n", proto_stats[CT_STATS_UDPLITE]);
1449 }
1450 if (proto_stats[CT_STATS_SCTP]) {
1451 dpctl_print(dpctl_p, "\tSCTP: %d\n", proto_stats[CT_STATS_SCTP]);
1452 }
1453 if (proto_stats[CT_STATS_ICMP]) {
1454 dpctl_print(dpctl_p, "\tICMP: %d\n", proto_stats[CT_STATS_ICMP]);
1455 }
1456 if (proto_stats[CT_STATS_DCCP]) {
1457 dpctl_print(dpctl_p, "\tDCCP: %d\n", proto_stats[CT_STATS_DCCP]);
1458 }
1459 if (proto_stats[CT_STATS_IGMP]) {
1460 dpctl_print(dpctl_p, "\tIGMP: %d\n", proto_stats[CT_STATS_IGMP]);
1461 }
1462 if (proto_stats[CT_STATS_OTHER]) {
1463 dpctl_print(dpctl_p, "\tOther: %d\n", proto_stats[CT_STATS_OTHER]);
1464 }
1465
1466 ct_dpif_dump_done(dump);
1467 dpif_close(dpif);
1468 return error;
1469}
ded30c74
FA
1470
1471#define CT_BKTS_GT "gt="
1472static int
1473dpctl_ct_bkts(int argc, const char *argv[],
1474 struct dpctl_params *dpctl_p)
1475{
1476 struct dpif *dpif;
1477 char *name;
1478
1479 struct ct_dpif_dump_state *dump;
1480 struct ct_dpif_entry cte;
1481 uint16_t gt = 0; /* Threshold: display value when greater than gt. */
1482 uint16_t *pzone = NULL;
1483 int tot_bkts = 0;
1484 int error;
1485
1486 if (argc > 1 && !strncmp(argv[argc - 1], CT_BKTS_GT, strlen(CT_BKTS_GT))) {
1487 if (ovs_scan(argv[argc - 1], CT_BKTS_GT"%"SCNu16, &gt)) {
1488 argc--;
1489 }
1490 }
1491
1492 name = (argc == 2) ? xstrdup(argv[1]) : get_one_dp(dpctl_p);
1493 if (!name) {
1494 return EINVAL;
1495 }
1496
1497 error = parsed_dpif_open(name, false, &dpif);
1498 free(name);
1499 if (error) {
1500 dpctl_error(dpctl_p, error, "opening datapath");
1501 return error;
1502 }
1503
1504 error = ct_dpif_dump_start(dpif, &dump, pzone, &tot_bkts);
1505 if (error) {
1506 dpctl_error(dpctl_p, error, "starting conntrack dump");
1507 dpif_close(dpif);
1508 return error;
1509 }
1510 if (tot_bkts == -1) {
1511 /* Command not available when called by kernel OvS. */
1512 dpctl_print(dpctl_p,
1513 "Command is available for UserSpace ConnTracker only.\n");
1514 ct_dpif_dump_done(dump);
1515 dpif_close(dpif);
1516 return 0;
1517 }
1518
1519 dpctl_print(dpctl_p, "Total Buckets: %d\n", tot_bkts);
1520
1521 int tot_conn = 0;
1522 uint32_t *conn_per_bkts = xzalloc(tot_bkts * sizeof(uint32_t));
1523
1524 while (!ct_dpif_dump_next(dump, &cte)) {
1525 ct_dpif_entry_uninit(&cte);
1526 tot_conn++;
1527 if (tot_bkts > 0) {
1528 if (cte.bkt < tot_bkts) {
1529 conn_per_bkts[cte.bkt]++;
1530 } else {
1531 dpctl_print(dpctl_p, "Bucket nr out of range: %d >= %d\n",
1532 cte.bkt, tot_bkts);
1533 }
1534 }
1535 }
1536
1537 dpctl_print(dpctl_p, "Current Connections: %d\n", tot_conn);
1538 dpctl_print(dpctl_p, "\n");
1539 if (tot_bkts && tot_conn) {
1540 dpctl_print(dpctl_p, "+-----------+"
1541 "-----------------------------------------+\n");
1542 dpctl_print(dpctl_p, "| Buckets |"
1543 " Connections per Buckets |\n");
1544 dpctl_print(dpctl_p, "+-----------+"
1545 "-----------------------------------------+");
1546#define NUM_BKTS_DIPLAYED_PER_ROW 8
1547 for (int i = 0; i < tot_bkts; i++) {
1548 if (i % NUM_BKTS_DIPLAYED_PER_ROW == 0) {
1549 dpctl_print(dpctl_p, "\n %3d..%3d | ",
1550 i, i + NUM_BKTS_DIPLAYED_PER_ROW - 1);
1551 }
1552 if (conn_per_bkts[i] > gt) {
1553 dpctl_print(dpctl_p, "%5d", conn_per_bkts[i]);
1554 } else {
1555 dpctl_print(dpctl_p, "%5s", ".");
1556 }
1557 }
1558 dpctl_print(dpctl_p, "\n\n");
1559 }
1560
1561 ct_dpif_dump_done(dump);
1562 dpif_close(dpif);
1563 free(conn_per_bkts);
1564 return error;
1565}
fceef209
DDP
1566\f
1567/* Undocumented commands for unit testing. */
1568
1569static int
1570dpctl_parse_actions(int argc, const char *argv[], struct dpctl_params* dpctl_p)
1571{
1572 int i, error = 0;
1573
1574 for (i = 1; i < argc; i++) {
1575 struct ofpbuf actions;
1576 struct ds s;
1577
1578 ofpbuf_init(&actions, 0);
1579 error = odp_actions_from_string(argv[i], NULL, &actions);
1580
1581 if (error) {
1582 ofpbuf_uninit(&actions);
1583 dpctl_error(dpctl_p, error, "odp_actions_from_string");
1584 return error;
1585 }
1586
1587 ds_init(&s);
0722f341 1588 format_odp_actions(&s, actions.data, actions.size, NULL);
fceef209
DDP
1589 dpctl_print(dpctl_p, "%s\n", ds_cstr(&s));
1590 ds_destroy(&s);
1591
1592 ofpbuf_uninit(&actions);
1593 }
1594
1595 return error;
1596}
1597
1598struct actions_for_flow {
1599 struct hmap_node hmap_node;
1600 struct flow flow;
1601 struct ofpbuf actions;
1602};
1603
1604static struct actions_for_flow *
1605get_actions_for_flow(struct hmap *actions_per_flow, const struct flow *flow)
1606{
1607 uint32_t hash = flow_hash(flow, 0);
1608 struct actions_for_flow *af;
1609
1610 HMAP_FOR_EACH_WITH_HASH (af, hmap_node, hash, actions_per_flow) {
1611 if (flow_equal(&af->flow, flow)) {
1612 return af;
1613 }
1614 }
1615
1616 af = xmalloc(sizeof *af);
1617 af->flow = *flow;
1618 ofpbuf_init(&af->actions, 0);
1619 hmap_insert(actions_per_flow, &af->hmap_node, hash);
1620 return af;
1621}
1622
1623static int
1624compare_actions_for_flow(const void *a_, const void *b_)
1625{
1626 struct actions_for_flow *const *a = a_;
1627 struct actions_for_flow *const *b = b_;
1628
1629 return flow_compare_3way(&(*a)->flow, &(*b)->flow);
1630}
1631
1632static int
1633compare_output_actions(const void *a_, const void *b_)
1634{
1635 const struct nlattr *a = a_;
1636 const struct nlattr *b = b_;
1637 uint32_t a_port = nl_attr_get_u32(a);
1638 uint32_t b_port = nl_attr_get_u32(b);
1639
1640 return a_port < b_port ? -1 : a_port > b_port;
1641}
1642
1643static void
1644sort_output_actions__(struct nlattr *first, struct nlattr *end)
1645{
1646 size_t bytes = (uint8_t *) end - (uint8_t *) first;
1647 size_t n = bytes / NL_A_U32_SIZE;
1648
1649 ovs_assert(bytes % NL_A_U32_SIZE == 0);
1650 qsort(first, n, NL_A_U32_SIZE, compare_output_actions);
1651}
1652
1653static void
1654sort_output_actions(struct nlattr *actions, size_t length)
1655{
1656 struct nlattr *first_output = NULL;
1657 struct nlattr *a;
1658 int left;
1659
1660 NL_ATTR_FOR_EACH (a, left, actions, length) {
1661 if (nl_attr_type(a) == OVS_ACTION_ATTR_OUTPUT) {
1662 if (!first_output) {
1663 first_output = a;
1664 }
1665 } else {
1666 if (first_output) {
1667 sort_output_actions__(first_output, a);
1668 first_output = NULL;
1669 }
1670 }
1671 }
1672 if (first_output) {
1673 uint8_t *end = (uint8_t *) actions + length;
1674 sort_output_actions__(first_output,
1675 ALIGNED_CAST(struct nlattr *, end));
1676 }
1677}
1678
1679/* usage: "ovs-dpctl normalize-actions FLOW ACTIONS" where FLOW and ACTIONS
1680 * have the syntax used by "ovs-dpctl dump-flows".
1681 *
1682 * This command prints ACTIONS in a format that shows what happens for each
1683 * VLAN, independent of the order of the ACTIONS. For example, there is more
1684 * than one way to output a packet on VLANs 9 and 11, but this command will
1685 * print the same output for any form.
1686 *
1687 * The idea here generalizes beyond VLANs (e.g. to setting other fields) but
1688 * so far the implementation only covers VLANs. */
1689static int
1690dpctl_normalize_actions(int argc, const char *argv[],
1691 struct dpctl_params *dpctl_p)
1692{
1693 struct simap port_names;
1694 struct ofpbuf keybuf;
1695 struct flow flow;
1696 struct ofpbuf odp_actions;
1697 struct hmap actions_per_flow;
1698 struct actions_for_flow **afs;
1699 struct actions_for_flow *af;
1700 struct nlattr *a;
1701 size_t n_afs;
1702 struct ds s;
1703 int left;
1704 int i, error;
f0fb825a 1705 int encaps = 0;
fceef209
DDP
1706
1707 ds_init(&s);
1708
1709 simap_init(&port_names);
1710 for (i = 3; i < argc; i++) {
1711 char name[16];
1712 int number;
1713
1714 if (ovs_scan(argv[i], "%15[^=]=%d", name, &number)) {
1715 uintptr_t n = number;
1716 simap_put(&port_names, name, n);
1717 } else {
1718 dpctl_error(dpctl_p, 0, "%s: expected NAME=NUMBER", argv[i]);
1719 error = EINVAL;
1720 goto out;
1721 }
1722 }
1723
1724 /* Parse flow key. */
1725 ofpbuf_init(&keybuf, 0);
1726 error = odp_flow_from_string(argv[1], &port_names, &keybuf, NULL);
1727 if (error) {
1728 dpctl_error(dpctl_p, error, "odp_flow_key_from_string");
1729 goto out_freekeybuf;
1730 }
1731
1732 ds_clear(&s);
6fd6ed71 1733 odp_flow_format(keybuf.data, keybuf.size, NULL, 0, NULL,
fceef209
DDP
1734 &s, dpctl_p->verbosity);
1735 dpctl_print(dpctl_p, "input flow: %s\n", ds_cstr(&s));
1736
6fd6ed71 1737 error = odp_flow_key_to_flow(keybuf.data, keybuf.size, &flow);
fceef209
DDP
1738 if (error) {
1739 dpctl_error(dpctl_p, error, "odp_flow_key_to_flow");
1740 goto out_freekeybuf;
1741 }
1742
1743 /* Parse actions. */
1744 ofpbuf_init(&odp_actions, 0);
1745 error = odp_actions_from_string(argv[2], &port_names, &odp_actions);
1746 if (error) {
1747 dpctl_error(dpctl_p, error, "odp_actions_from_string");
1748 goto out_freeactions;
1749 }
1750
1751 if (dpctl_p->verbosity) {
1752 ds_clear(&s);
0722f341 1753 format_odp_actions(&s, odp_actions.data, odp_actions.size, NULL);
fceef209
DDP
1754 dpctl_print(dpctl_p, "input actions: %s\n", ds_cstr(&s));
1755 }
1756
1757 hmap_init(&actions_per_flow);
6fd6ed71 1758 NL_ATTR_FOR_EACH (a, left, odp_actions.data, odp_actions.size) {
fceef209
DDP
1759 const struct ovs_action_push_vlan *push;
1760 switch(nl_attr_type(a)) {
1761 case OVS_ACTION_ATTR_POP_VLAN:
f0fb825a 1762 flow_pop_vlan(&flow, NULL);
fceef209
DDP
1763 continue;
1764
1765 case OVS_ACTION_ATTR_PUSH_VLAN:
f0fb825a 1766 flow_push_vlan_uninit(&flow, NULL);
fceef209 1767 push = nl_attr_get_unspec(a, sizeof *push);
f0fb825a
EG
1768 flow.vlans[0].tpid = push->vlan_tpid;
1769 flow.vlans[0].tci = push->vlan_tci;
fceef209
DDP
1770 continue;
1771 }
1772
1773 af = get_actions_for_flow(&actions_per_flow, &flow);
1774 nl_msg_put_unspec(&af->actions, nl_attr_type(a),
1775 nl_attr_get(a), nl_attr_get_size(a));
1776 }
1777
1778 n_afs = hmap_count(&actions_per_flow);
1779 afs = xmalloc(n_afs * sizeof *afs);
1780 i = 0;
1781 HMAP_FOR_EACH (af, hmap_node, &actions_per_flow) {
1782 afs[i++] = af;
1783 }
1784
1785 ovs_assert(i == n_afs);
1786 hmap_destroy(&actions_per_flow);
1787
1788 qsort(afs, n_afs, sizeof *afs, compare_actions_for_flow);
1789
1790 for (i = 0; i < n_afs; i++) {
71f21279 1791 af = afs[i];
6fd6ed71 1792 sort_output_actions(af->actions.data, af->actions.size);
fceef209 1793
f0fb825a
EG
1794 for (encaps = 0; encaps < FLOW_MAX_VLAN_HEADERS; encaps ++) {
1795 union flow_vlan_hdr *vlan = &af->flow.vlans[encaps];
1796 if (vlan->tci != htons(0)) {
1797 dpctl_print(dpctl_p, "vlan(");
1798 if (vlan->tpid != htons(ETH_TYPE_VLAN)) {
1799 dpctl_print(dpctl_p, "tpid=0x%04"PRIx16",", vlan->tpid);
1800 }
1801 dpctl_print(dpctl_p, "vid=%"PRIu16",pcp=%d): ",
1802 vlan_tci_to_vid(vlan->tci),
1803 vlan_tci_to_pcp(vlan->tci));
1804 } else {
1805 if (encaps == 0) {
1806 dpctl_print(dpctl_p, "no vlan: ");
1807 }
1808 break;
1809 }
fceef209
DDP
1810 }
1811
1812 if (eth_type_mpls(af->flow.dl_type)) {
1813 dpctl_print(dpctl_p, "mpls(label=%"PRIu32",tc=%d,ttl=%d): ",
1814 mpls_lse_to_label(af->flow.mpls_lse[0]),
1815 mpls_lse_to_tc(af->flow.mpls_lse[0]),
1816 mpls_lse_to_ttl(af->flow.mpls_lse[0]));
1817 } else {
1818 dpctl_print(dpctl_p, "no mpls: ");
1819 }
1820
1821 ds_clear(&s);
0722f341 1822 format_odp_actions(&s, af->actions.data, af->actions.size, NULL);
7521b9e5 1823 dpctl_puts(dpctl_p, false, ds_cstr(&s));
fceef209
DDP
1824
1825 ofpbuf_uninit(&af->actions);
1826 free(af);
1827 }
1828 free(afs);
1829
1830
1831out_freeactions:
1832 ofpbuf_uninit(&odp_actions);
1833out_freekeybuf:
1834 ofpbuf_uninit(&keybuf);
1835out:
1836 simap_destroy(&port_names);
1837 ds_destroy(&s);
1838
1839 return error;
1840}
1841\f
fceef209 1842static const struct dpctl_command all_commands[] = {
1ed90a98
BP
1843 { "add-dp", "dp [iface...]", 1, INT_MAX, dpctl_add_dp, DP_RW },
1844 { "del-dp", "dp", 1, 1, dpctl_del_dp, DP_RW },
1845 { "add-if", "dp iface...", 2, INT_MAX, dpctl_add_if, DP_RW },
1846 { "del-if", "dp iface...", 2, INT_MAX, dpctl_del_if, DP_RW },
1847 { "set-if", "dp iface...", 2, INT_MAX, dpctl_set_if, DP_RW },
1f4a7252
RM
1848 { "dump-dps", "", 0, 0, dpctl_dump_dps, DP_RO },
1849 { "show", "[dp...]", 0, INT_MAX, dpctl_show, DP_RO },
1401f6de
FA
1850 { "dump-flows", "[dp] [filter=..] [type=..]",
1851 0, 3, dpctl_dump_flows, DP_RO },
1ed90a98
BP
1852 { "add-flow", "[dp] flow actions", 2, 3, dpctl_add_flow, DP_RW },
1853 { "mod-flow", "[dp] flow actions", 2, 3, dpctl_mod_flow, DP_RW },
1854 { "get-flow", "[dp] ufid", 1, 2, dpctl_get_flow, DP_RO },
1855 { "del-flow", "[dp] flow", 1, 2, dpctl_del_flow, DP_RW },
1f4a7252
RM
1856 { "del-flows", "[dp]", 0, 1, dpctl_del_flows, DP_RW },
1857 { "dump-conntrack", "[dp] [zone=N]", 0, 2, dpctl_dump_conntrack, DP_RO },
1858 { "flush-conntrack", "[dp] [zone=N]", 0, 2, dpctl_flush_conntrack, DP_RW },
8a0d9d85
FA
1859 { "ct-stats-show", "[dp] [zone=N] [verbose]",
1860 0, 3, dpctl_ct_stats_show, DP_RO },
ded30c74 1861 { "ct-bkts", "[dp] [gt=N]", 0, 2, dpctl_ct_bkts, DP_RO },
1f4a7252
RM
1862 { "help", "", 0, INT_MAX, dpctl_help, DP_RO },
1863 { "list-commands", "", 0, INT_MAX, dpctl_list_commands, DP_RO },
fceef209
DDP
1864
1865 /* Undocumented commands for testing. */
1f4a7252 1866 { "parse-actions", "actions", 1, INT_MAX, dpctl_parse_actions, DP_RO },
1401f6de
FA
1867 { "normalize-actions", "actions",
1868 2, INT_MAX, dpctl_normalize_actions, DP_RO },
fceef209 1869
1f4a7252 1870 { NULL, NULL, 0, 0, NULL, DP_RO },
fceef209
DDP
1871};
1872
56cad666
AW
1873static const struct dpctl_command *get_all_dpctl_commands(void)
1874{
1875 return all_commands;
1876}
1877
fceef209
DDP
1878/* Runs the command designated by argv[0] within the command table specified by
1879 * 'commands', which must be terminated by a command whose 'name' member is a
1880 * null pointer. */
1881int
1882dpctl_run_command(int argc, const char *argv[], struct dpctl_params *dpctl_p)
1883{
1884 const struct dpctl_command *p;
fceef209
DDP
1885 if (argc < 1) {
1886 dpctl_error(dpctl_p, 0, "missing command name; use --help for help");
1887 return EINVAL;
1888 }
1889
1890 for (p = all_commands; p->name != NULL; p++) {
1891 if (!strcmp(p->name, argv[0])) {
1892 int n_arg = argc - 1;
1893 if (n_arg < p->min_args) {
1894 dpctl_error(dpctl_p, 0,
1895 "'%s' command requires at least %d arguments",
1896 p->name, p->min_args);
1897 return EINVAL;
1898 } else if (n_arg > p->max_args) {
1899 dpctl_error(dpctl_p, 0,
1900 "'%s' command takes at most %d arguments",
1901 p->name, p->max_args);
1902 return EINVAL;
1903 } else {
1f4a7252
RM
1904 if (p->mode == DP_RW && dpctl_p->read_only) {
1905 dpctl_error(dpctl_p, 0,
1906 "'%s' command does not work in read only mode",
1907 p->name);
1908 return EINVAL;
1909 }
fceef209
DDP
1910 return p->handler(argc, argv, dpctl_p);
1911 }
1912 }
1913 }
1914
1915 dpctl_error(dpctl_p, 0, "unknown command '%s'; use --help for help",
1916 argv[0]);
1917 return EINVAL;
1918}
1919\f
1920static void
1921dpctl_unixctl_print(void *userdata, bool error OVS_UNUSED, const char *msg)
1922{
1923 struct ds *ds = userdata;
1924 ds_put_cstr(ds, msg);
1925}
1926
1927static void
1928dpctl_unixctl_handler(struct unixctl_conn *conn, int argc, const char *argv[],
1929 void *aux)
1930{
1931 struct ds ds = DS_EMPTY_INITIALIZER;
79ae214d 1932 bool error = false;
fceef209 1933
337c4528
BP
1934 struct dpctl_params dpctl_p = {
1935 .is_appctl = true,
1936 .output = dpctl_unixctl_print,
1937 .aux = &ds,
1938 };
fceef209
DDP
1939
1940 /* Parse options (like getopt). Unfortunately it does
1941 * not seem a good idea to call getopt_long() here, since it uses global
1942 * variables */
d1fd1ea9 1943 bool set_names = false;
79ae214d 1944 while (argc > 1 && !error) {
fceef209
DDP
1945 const char *arg = argv[1];
1946 if (!strncmp(arg, "--", 2)) {
1947 /* Long option */
1948 if (!strcmp(arg, "--statistics")) {
1949 dpctl_p.print_statistics = true;
1950 } else if (!strcmp(arg, "--clear")) {
1951 dpctl_p.zero_statistics = true;
1952 } else if (!strcmp(arg, "--may-create")) {
1953 dpctl_p.may_create = true;
1954 } else if (!strcmp(arg, "--more")) {
1955 dpctl_p.verbosity++;
d1fd1ea9
BP
1956 } else if (!strcmp(arg, "--names")) {
1957 dpctl_p.names = true;
1958 set_names = true;
1959 } else if (!strcmp(arg, "--no-names")) {
1960 dpctl_p.names = false;
1961 set_names = true;
fceef209
DDP
1962 } else {
1963 ds_put_format(&ds, "Unrecognized option %s", argv[1]);
79ae214d 1964 error = true;
fceef209
DDP
1965 }
1966 } else if (arg[0] == '-' && arg[1] != '\0') {
1967 /* Short option[s] */
1968 const char *opt = &arg[1];
1969
79ae214d 1970 while (*opt && !error) {
fceef209
DDP
1971 switch (*opt) {
1972 case 'm':
1973 dpctl_p.verbosity++;
1974 break;
1975 case 's':
1976 dpctl_p.print_statistics = true;
1977 break;
1978 default:
1979 ds_put_format(&ds, "Unrecognized option -%c", *opt);
79ae214d 1980 error = true;
fceef209
DDP
1981 break;
1982 }
1983 opt++;
1984 }
1985 } else {
1986 /* Doesn't start with -, not an option */
1987 break;
1988 }
1989
79ae214d 1990 if (error) {
fceef209
DDP
1991 break;
1992 }
1993 argv++;
1994 argc--;
1995 }
d1fd1ea9
BP
1996 if (!set_names) {
1997 dpctl_p.names = dpctl_p.verbosity > 0;
1998 }
1999 VLOG_INFO("set_names=%d verbosity=%d names=%d", set_names,
2000 dpctl_p.verbosity, dpctl_p.names);
fceef209 2001
79ae214d 2002 if (!error) {
337c4528 2003 dpctl_command_handler *handler = (dpctl_command_handler *) aux;
79ae214d 2004 error = handler(argc, argv, &dpctl_p) != 0;
fceef209
DDP
2005 }
2006
79ae214d
BP
2007 if (error) {
2008 unixctl_command_reply_error(conn, ds_cstr(&ds));
2009 } else {
2010 unixctl_command_reply(conn, ds_cstr(&ds));
2011 }
fceef209
DDP
2012
2013 ds_destroy(&ds);
2014}
2015
2016void
2017dpctl_unixctl_register(void)
2018{
2019 const struct dpctl_command *p;
2020
2021 for (p = all_commands; p->name != NULL; p++) {
337c4528
BP
2022 if (strcmp(p->name, "help")) {
2023 char *cmd_name = xasprintf("dpctl/%s", p->name);
c0297846 2024 unixctl_command_register(cmd_name,
2025 p->usage,
2026 p->min_args,
2027 p->max_args,
2028 dpctl_unixctl_handler,
2029 p->handler);
337c4528
BP
2030 free(cmd_name);
2031 }
fceef209
DDP
2032 }
2033}