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