]> git.proxmox.com Git - mirror_ovs.git/blob - lib/dpctl.c
Revert "dpctl: Expand the flow dump type filter"
[mirror_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;
1313 struct ct_dpif_tuple tuple, *ptuple = NULL;
1314 struct ds ds = DS_EMPTY_INITIALIZER;
1315 uint16_t zone, *pzone = NULL;
1316 char *name;
1317 int error, i = 1;
1318 bool got_dpif = false;
1319
1320 /* Parse datapath name. It is not a mandatory parameter for this command.
1321 * If it is not specified, we retrieve it from the current setup,
1322 * assuming only one exists. */
1323 if (argc >= 2) {
1324 error = parsed_dpif_open(argv[i], false, &dpif);
1325 if (!error) {
1326 got_dpif = true;
1327 i++;
1328 } else if (argc == 4) {
1329 dpctl_error(dpctl_p, error, "invalid datapath");
1330 return error;
1331 }
1332 }
1333 if (!got_dpif) {
1334 name = get_one_dp(dpctl_p);
1335 if (!name) {
1336 return EINVAL;
1337 }
1338 error = parsed_dpif_open(name, false, &dpif);
1339 free(name);
1340 if (error) {
1341 dpctl_error(dpctl_p, error, "opening datapath");
1342 return error;
1343 }
1344 }
1345
1346 /* Parse zone */
1347 if (argc > i && ovs_scan(argv[i], "zone=%"SCNu16, &zone)) {
1348 pzone = &zone;
1349 i++;
1350 }
1351 /* Report error if there are more than one unparsed argument. */
1352 if (argc - i > 1) {
1353 ds_put_cstr(&ds, "invalid zone");
1354 error = EINVAL;
1355 goto error;
1356 }
1357
1358 /* Parse ct tuple */
1359 if (argc > i && ct_dpif_parse_tuple(&tuple, argv[i], &ds)) {
1360 ptuple = &tuple;
1361 i++;
1362 }
1363 /* Report error if there is an unparsed argument. */
1364 if (argc - i) {
1365 error = EINVAL;
1366 goto error;
1367 }
1368
1369 error = ct_dpif_flush(dpif, pzone, ptuple);
1370 if (!error) {
1371 dpif_close(dpif);
1372 return 0;
1373 } else {
1374 ds_put_cstr(&ds, "failed to flush conntrack");
1375 }
1376
1377 error:
1378 dpctl_error(dpctl_p, error, "%s", ds_cstr(&ds));
1379 ds_destroy(&ds);
1380 dpif_close(dpif);
1381 return error;
1382 }
1383
1384 static int
1385 dpctl_ct_stats_show(int argc, const char *argv[],
1386 struct dpctl_params *dpctl_p)
1387 {
1388 struct dpif *dpif;
1389 struct ct_dpif_dump_state *dump;
1390 struct ct_dpif_entry cte;
1391 uint16_t zone, *pzone = NULL;
1392 int tot_bkts;
1393 int lastargc = 0;
1394
1395 int proto_stats[CT_STATS_MAX];
1396 int tcp_conn_per_states[CT_DPIF_TCPS_MAX_NUM];
1397 int error;
1398
1399 bool verbose = dpctl_p->verbosity;
1400
1401 while (argc > 1 && lastargc != argc) {
1402 lastargc = argc;
1403 if (!strncmp(argv[argc - 1], "verbose", 7)) {
1404 /* Support "verbose" argument for backwards compatibility. */
1405 verbose = true;
1406 argc--;
1407 } else if (!strncmp(argv[argc - 1], "zone=", 5)) {
1408 if (ovs_scan(argv[argc - 1], "zone=%"SCNu16, &zone)) {
1409 pzone = &zone;
1410 argc--;
1411 }
1412 }
1413 }
1414
1415 error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif);
1416 if (error) {
1417 return error;
1418 }
1419
1420 memset(proto_stats, 0, sizeof(proto_stats));
1421 memset(tcp_conn_per_states, 0, sizeof(tcp_conn_per_states));
1422 error = ct_dpif_dump_start(dpif, &dump, pzone, &tot_bkts);
1423 if (error) {
1424 dpctl_error(dpctl_p, error, "starting conntrack dump");
1425 dpif_close(dpif);
1426 return error;
1427 }
1428
1429 int tot_conn = 0;
1430 while (!(error = ct_dpif_dump_next(dump, &cte))) {
1431 ct_dpif_entry_uninit(&cte);
1432 tot_conn++;
1433 switch (cte.tuple_orig.ip_proto) {
1434 case IPPROTO_ICMP:
1435 proto_stats[CT_STATS_ICMP]++;
1436 break;
1437 case IPPROTO_ICMPV6:
1438 proto_stats[CT_STATS_ICMPV6]++;
1439 break;
1440 case IPPROTO_TCP:
1441 proto_stats[CT_STATS_TCP]++;
1442 uint8_t tcp_state;
1443 /* We keep two separate tcp states, but we print just one. The
1444 * Linux kernel connection tracker internally keeps only one state,
1445 * so 'state_orig' and 'state_reply', will be the same. */
1446 tcp_state = MAX(cte.protoinfo.tcp.state_orig,
1447 cte.protoinfo.tcp.state_reply);
1448 tcp_state = ct_dpif_coalesce_tcp_state(tcp_state);
1449 tcp_conn_per_states[tcp_state]++;
1450 break;
1451 case IPPROTO_UDP:
1452 proto_stats[CT_STATS_UDP]++;
1453 break;
1454 case IPPROTO_SCTP:
1455 proto_stats[CT_STATS_SCTP]++;
1456 break;
1457 case IPPROTO_UDPLITE:
1458 proto_stats[CT_STATS_UDPLITE]++;
1459 break;
1460 case IPPROTO_DCCP:
1461 proto_stats[CT_STATS_DCCP]++;
1462 break;
1463 case IPPROTO_IGMP:
1464 proto_stats[CT_STATS_IGMP]++;
1465 break;
1466 default:
1467 proto_stats[CT_STATS_OTHER]++;
1468 break;
1469 }
1470 }
1471 if (error == EOF) {
1472 /* All CT entries were dumped with no issue. */
1473 error = 0;
1474 } else if (error) {
1475 dpctl_error(dpctl_p, error, "dumping conntrack entry");
1476 /* Fall through to show any other info we collected. */
1477 }
1478
1479 dpctl_print(dpctl_p, "Connections Stats:\n Total: %d\n", tot_conn);
1480 if (proto_stats[CT_STATS_TCP]) {
1481 dpctl_print(dpctl_p, " TCP: %d\n", proto_stats[CT_STATS_TCP]);
1482 if (verbose) {
1483 dpctl_print(dpctl_p, " Conn per TCP states:\n");
1484 for (int i = 0; i < CT_DPIF_TCPS_MAX_NUM; i++) {
1485 if (tcp_conn_per_states[i]) {
1486 struct ds s = DS_EMPTY_INITIALIZER;
1487 ct_dpif_format_tcp_stat(&s, i, tcp_conn_per_states[i]);
1488 dpctl_print(dpctl_p, "%s\n", ds_cstr(&s));
1489 ds_destroy(&s);
1490 }
1491 }
1492 }
1493 }
1494 if (proto_stats[CT_STATS_UDP]) {
1495 dpctl_print(dpctl_p, " UDP: %d\n", proto_stats[CT_STATS_UDP]);
1496 }
1497 if (proto_stats[CT_STATS_UDPLITE]) {
1498 dpctl_print(dpctl_p, " UDPLITE: %d\n", proto_stats[CT_STATS_UDPLITE]);
1499 }
1500 if (proto_stats[CT_STATS_SCTP]) {
1501 dpctl_print(dpctl_p, " SCTP: %d\n", proto_stats[CT_STATS_SCTP]);
1502 }
1503 if (proto_stats[CT_STATS_ICMP]) {
1504 dpctl_print(dpctl_p, " ICMP: %d\n", proto_stats[CT_STATS_ICMP]);
1505 }
1506 if (proto_stats[CT_STATS_DCCP]) {
1507 dpctl_print(dpctl_p, " DCCP: %d\n", proto_stats[CT_STATS_DCCP]);
1508 }
1509 if (proto_stats[CT_STATS_IGMP]) {
1510 dpctl_print(dpctl_p, " IGMP: %d\n", proto_stats[CT_STATS_IGMP]);
1511 }
1512 if (proto_stats[CT_STATS_OTHER]) {
1513 dpctl_print(dpctl_p, " Other: %d\n", proto_stats[CT_STATS_OTHER]);
1514 }
1515
1516 ct_dpif_dump_done(dump);
1517 dpif_close(dpif);
1518 return error;
1519 }
1520
1521 #define CT_BKTS_GT "gt="
1522 static int
1523 dpctl_ct_bkts(int argc, const char *argv[],
1524 struct dpctl_params *dpctl_p)
1525 {
1526 struct dpif *dpif;
1527 struct ct_dpif_dump_state *dump;
1528 struct ct_dpif_entry cte;
1529 uint16_t gt = 0; /* Threshold: display value when greater than gt. */
1530 uint16_t *pzone = NULL;
1531 int tot_bkts = 0;
1532 int error;
1533
1534 if (argc > 1 && !strncmp(argv[argc - 1], CT_BKTS_GT, strlen(CT_BKTS_GT))) {
1535 if (ovs_scan(argv[argc - 1], CT_BKTS_GT"%"SCNu16, &gt)) {
1536 argc--;
1537 }
1538 }
1539
1540 error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif);
1541 if (error) {
1542 return error;
1543 }
1544
1545 error = ct_dpif_dump_start(dpif, &dump, pzone, &tot_bkts);
1546 if (error) {
1547 dpctl_error(dpctl_p, error, "starting conntrack dump");
1548 dpif_close(dpif);
1549 return error;
1550 }
1551 if (tot_bkts == -1) {
1552 /* Command not available when called by kernel OvS. */
1553 dpctl_print(dpctl_p,
1554 "Command is available for UserSpace ConnTracker only.\n");
1555 ct_dpif_dump_done(dump);
1556 dpif_close(dpif);
1557 return 0;
1558 }
1559
1560 dpctl_print(dpctl_p, "Total Buckets: %d\n", tot_bkts);
1561
1562 int tot_conn = 0;
1563 uint32_t *conn_per_bkts = xzalloc(tot_bkts * sizeof(uint32_t));
1564
1565 while (!(error = ct_dpif_dump_next(dump, &cte))) {
1566 ct_dpif_entry_uninit(&cte);
1567 tot_conn++;
1568 if (tot_bkts > 0) {
1569 if (cte.bkt < tot_bkts) {
1570 conn_per_bkts[cte.bkt]++;
1571 } else {
1572 dpctl_print(dpctl_p, "Bucket nr out of range: %d >= %d\n",
1573 cte.bkt, tot_bkts);
1574 }
1575 }
1576 }
1577 if (error == EOF) {
1578 /* All CT entries were dumped with no issue. */
1579 error = 0;
1580 } else if (error) {
1581 dpctl_error(dpctl_p, error, "dumping conntrack entry");
1582 /* Fall through and display all the collected info. */
1583 }
1584
1585 dpctl_print(dpctl_p, "Current Connections: %d\n", tot_conn);
1586 dpctl_print(dpctl_p, "\n");
1587 if (tot_bkts && tot_conn) {
1588 dpctl_print(dpctl_p, "+-----------+"
1589 "-----------------------------------------+\n");
1590 dpctl_print(dpctl_p, "| Buckets |"
1591 " Connections per Buckets |\n");
1592 dpctl_print(dpctl_p, "+-----------+"
1593 "-----------------------------------------+");
1594 #define NUM_BKTS_DIPLAYED_PER_ROW 8
1595 for (int i = 0; i < tot_bkts; i++) {
1596 if (i % NUM_BKTS_DIPLAYED_PER_ROW == 0) {
1597 dpctl_print(dpctl_p, "\n %3d..%3d | ",
1598 i, i + NUM_BKTS_DIPLAYED_PER_ROW - 1);
1599 }
1600 if (conn_per_bkts[i] > gt) {
1601 dpctl_print(dpctl_p, "%5d", conn_per_bkts[i]);
1602 } else {
1603 dpctl_print(dpctl_p, "%5s", ".");
1604 }
1605 }
1606 dpctl_print(dpctl_p, "\n\n");
1607 }
1608
1609 ct_dpif_dump_done(dump);
1610 dpif_close(dpif);
1611 free(conn_per_bkts);
1612 return error;
1613 }
1614 \f
1615 static int
1616 dpctl_ct_set_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, 3, &dpif);
1621 if (!error) {
1622 uint32_t maxconns;
1623 if (ovs_scan(argv[argc - 1], "%"SCNu32, &maxconns)) {
1624 error = ct_dpif_set_maxconns(dpif, maxconns);
1625
1626 if (!error) {
1627 dpctl_print(dpctl_p, "setting maxconns successful");
1628 } else {
1629 dpctl_error(dpctl_p, error, "ct set maxconns failed");
1630 }
1631 } else {
1632 error = EINVAL;
1633 dpctl_error(dpctl_p, error, "maxconns missing or malformed");
1634 }
1635 dpif_close(dpif);
1636 }
1637
1638 return error;
1639 }
1640
1641 static int
1642 dpctl_ct_get_maxconns(int argc, const char *argv[],
1643 struct dpctl_params *dpctl_p)
1644 {
1645 struct dpif *dpif;
1646 int error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif);
1647 if (!error) {
1648 uint32_t maxconns;
1649 error = ct_dpif_get_maxconns(dpif, &maxconns);
1650
1651 if (!error) {
1652 dpctl_print(dpctl_p, "%u\n", maxconns);
1653 } else {
1654 dpctl_error(dpctl_p, error, "maxconns could not be retrieved");
1655 }
1656 dpif_close(dpif);
1657 }
1658
1659 return error;
1660 }
1661
1662 static int
1663 dpctl_ct_get_nconns(int argc, const char *argv[],
1664 struct dpctl_params *dpctl_p)
1665 {
1666 struct dpif *dpif;
1667 int error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif);
1668 if (!error) {
1669 uint32_t nconns;
1670 error = ct_dpif_get_nconns(dpif, &nconns);
1671
1672 if (!error) {
1673 dpctl_print(dpctl_p, "%u\n", nconns);
1674 } else {
1675 dpctl_error(dpctl_p, error, "nconns could not be retrieved");
1676 }
1677 dpif_close(dpif);
1678 }
1679
1680 return error;
1681 }
1682
1683 /* Undocumented commands for unit testing. */
1684
1685 static int
1686 dpctl_parse_actions(int argc, const char *argv[], struct dpctl_params* dpctl_p)
1687 {
1688 int i, error = 0;
1689
1690 for (i = 1; i < argc; i++) {
1691 struct ofpbuf actions;
1692 struct ds s;
1693
1694 ofpbuf_init(&actions, 0);
1695 error = odp_actions_from_string(argv[i], NULL, &actions);
1696
1697 if (error) {
1698 ofpbuf_uninit(&actions);
1699 dpctl_error(dpctl_p, error, "odp_actions_from_string");
1700 return error;
1701 }
1702
1703 ds_init(&s);
1704 format_odp_actions(&s, actions.data, actions.size, NULL);
1705 dpctl_print(dpctl_p, "%s\n", ds_cstr(&s));
1706 ds_destroy(&s);
1707
1708 ofpbuf_uninit(&actions);
1709 }
1710
1711 return error;
1712 }
1713
1714 struct actions_for_flow {
1715 struct hmap_node hmap_node;
1716 struct flow flow;
1717 struct ofpbuf actions;
1718 };
1719
1720 static struct actions_for_flow *
1721 get_actions_for_flow(struct hmap *actions_per_flow, const struct flow *flow)
1722 {
1723 uint32_t hash = flow_hash(flow, 0);
1724 struct actions_for_flow *af;
1725
1726 HMAP_FOR_EACH_WITH_HASH (af, hmap_node, hash, actions_per_flow) {
1727 if (flow_equal(&af->flow, flow)) {
1728 return af;
1729 }
1730 }
1731
1732 af = xmalloc(sizeof *af);
1733 af->flow = *flow;
1734 ofpbuf_init(&af->actions, 0);
1735 hmap_insert(actions_per_flow, &af->hmap_node, hash);
1736 return af;
1737 }
1738
1739 static int
1740 compare_actions_for_flow(const void *a_, const void *b_)
1741 {
1742 struct actions_for_flow *const *a = a_;
1743 struct actions_for_flow *const *b = b_;
1744
1745 return flow_compare_3way(&(*a)->flow, &(*b)->flow);
1746 }
1747
1748 static int
1749 compare_output_actions(const void *a_, const void *b_)
1750 {
1751 const struct nlattr *a = a_;
1752 const struct nlattr *b = b_;
1753 uint32_t a_port = nl_attr_get_u32(a);
1754 uint32_t b_port = nl_attr_get_u32(b);
1755
1756 return a_port < b_port ? -1 : a_port > b_port;
1757 }
1758
1759 static void
1760 sort_output_actions__(struct nlattr *first, struct nlattr *end)
1761 {
1762 size_t bytes = (uint8_t *) end - (uint8_t *) first;
1763 size_t n = bytes / NL_A_U32_SIZE;
1764
1765 ovs_assert(bytes % NL_A_U32_SIZE == 0);
1766 qsort(first, n, NL_A_U32_SIZE, compare_output_actions);
1767 }
1768
1769 static void
1770 sort_output_actions(struct nlattr *actions, size_t length)
1771 {
1772 struct nlattr *first_output = NULL;
1773 struct nlattr *a;
1774 int left;
1775
1776 NL_ATTR_FOR_EACH (a, left, actions, length) {
1777 if (nl_attr_type(a) == OVS_ACTION_ATTR_OUTPUT) {
1778 if (!first_output) {
1779 first_output = a;
1780 }
1781 } else {
1782 if (first_output) {
1783 sort_output_actions__(first_output, a);
1784 first_output = NULL;
1785 }
1786 }
1787 }
1788 if (first_output) {
1789 uint8_t *end = (uint8_t *) actions + length;
1790 sort_output_actions__(first_output,
1791 ALIGNED_CAST(struct nlattr *, end));
1792 }
1793 }
1794
1795 /* usage: "ovs-dpctl normalize-actions FLOW ACTIONS" where FLOW and ACTIONS
1796 * have the syntax used by "ovs-dpctl dump-flows".
1797 *
1798 * This command prints ACTIONS in a format that shows what happens for each
1799 * VLAN, independent of the order of the ACTIONS. For example, there is more
1800 * than one way to output a packet on VLANs 9 and 11, but this command will
1801 * print the same output for any form.
1802 *
1803 * The idea here generalizes beyond VLANs (e.g. to setting other fields) but
1804 * so far the implementation only covers VLANs. */
1805 static int
1806 dpctl_normalize_actions(int argc, const char *argv[],
1807 struct dpctl_params *dpctl_p)
1808 {
1809 struct simap port_names;
1810 struct ofpbuf keybuf;
1811 struct flow flow;
1812 struct ofpbuf odp_actions;
1813 struct hmap actions_per_flow;
1814 struct actions_for_flow **afs;
1815 struct actions_for_flow *af;
1816 struct nlattr *a;
1817 size_t n_afs;
1818 struct ds s;
1819 int left;
1820 int i, error;
1821 int encaps = 0;
1822
1823 ds_init(&s);
1824
1825 simap_init(&port_names);
1826 for (i = 3; i < argc; i++) {
1827 char name[16];
1828 int number;
1829
1830 if (ovs_scan(argv[i], "%15[^=]=%d", name, &number)) {
1831 uintptr_t n = number;
1832 simap_put(&port_names, name, n);
1833 } else {
1834 dpctl_error(dpctl_p, 0, "%s: expected NAME=NUMBER", argv[i]);
1835 error = EINVAL;
1836 goto out;
1837 }
1838 }
1839
1840 /* Parse flow key. */
1841 ofpbuf_init(&keybuf, 0);
1842 error = odp_flow_from_string(argv[1], &port_names, &keybuf, NULL);
1843 if (error) {
1844 dpctl_error(dpctl_p, error, "odp_flow_key_from_string");
1845 goto out_freekeybuf;
1846 }
1847
1848 ds_clear(&s);
1849 odp_flow_format(keybuf.data, keybuf.size, NULL, 0, NULL,
1850 &s, dpctl_p->verbosity);
1851 dpctl_print(dpctl_p, "input flow: %s\n", ds_cstr(&s));
1852
1853 error = odp_flow_key_to_flow(keybuf.data, keybuf.size, &flow);
1854 if (error) {
1855 dpctl_error(dpctl_p, error, "odp_flow_key_to_flow");
1856 goto out_freekeybuf;
1857 }
1858
1859 /* Parse actions. */
1860 ofpbuf_init(&odp_actions, 0);
1861 error = odp_actions_from_string(argv[2], &port_names, &odp_actions);
1862 if (error) {
1863 dpctl_error(dpctl_p, error, "odp_actions_from_string");
1864 goto out_freeactions;
1865 }
1866
1867 if (dpctl_p->verbosity) {
1868 ds_clear(&s);
1869 format_odp_actions(&s, odp_actions.data, odp_actions.size, NULL);
1870 dpctl_print(dpctl_p, "input actions: %s\n", ds_cstr(&s));
1871 }
1872
1873 hmap_init(&actions_per_flow);
1874 NL_ATTR_FOR_EACH (a, left, odp_actions.data, odp_actions.size) {
1875 const struct ovs_action_push_vlan *push;
1876 switch(nl_attr_type(a)) {
1877 case OVS_ACTION_ATTR_POP_VLAN:
1878 flow_pop_vlan(&flow, NULL);
1879 continue;
1880
1881 case OVS_ACTION_ATTR_PUSH_VLAN:
1882 flow_push_vlan_uninit(&flow, NULL);
1883 push = nl_attr_get_unspec(a, sizeof *push);
1884 flow.vlans[0].tpid = push->vlan_tpid;
1885 flow.vlans[0].tci = push->vlan_tci;
1886 continue;
1887 }
1888
1889 af = get_actions_for_flow(&actions_per_flow, &flow);
1890 nl_msg_put_unspec(&af->actions, nl_attr_type(a),
1891 nl_attr_get(a), nl_attr_get_size(a));
1892 }
1893
1894 n_afs = hmap_count(&actions_per_flow);
1895 afs = xmalloc(n_afs * sizeof *afs);
1896 i = 0;
1897 HMAP_FOR_EACH (af, hmap_node, &actions_per_flow) {
1898 afs[i++] = af;
1899 }
1900
1901 ovs_assert(i == n_afs);
1902 hmap_destroy(&actions_per_flow);
1903
1904 qsort(afs, n_afs, sizeof *afs, compare_actions_for_flow);
1905
1906 for (i = 0; i < n_afs; i++) {
1907 af = afs[i];
1908 sort_output_actions(af->actions.data, af->actions.size);
1909
1910 for (encaps = 0; encaps < FLOW_MAX_VLAN_HEADERS; encaps ++) {
1911 union flow_vlan_hdr *vlan = &af->flow.vlans[encaps];
1912 if (vlan->tci != htons(0)) {
1913 dpctl_print(dpctl_p, "vlan(");
1914 if (vlan->tpid != htons(ETH_TYPE_VLAN)) {
1915 dpctl_print(dpctl_p, "tpid=0x%04"PRIx16",", vlan->tpid);
1916 }
1917 dpctl_print(dpctl_p, "vid=%"PRIu16",pcp=%d): ",
1918 vlan_tci_to_vid(vlan->tci),
1919 vlan_tci_to_pcp(vlan->tci));
1920 } else {
1921 if (encaps == 0) {
1922 dpctl_print(dpctl_p, "no vlan: ");
1923 }
1924 break;
1925 }
1926 }
1927
1928 if (eth_type_mpls(af->flow.dl_type)) {
1929 dpctl_print(dpctl_p, "mpls(label=%"PRIu32",tc=%d,ttl=%d): ",
1930 mpls_lse_to_label(af->flow.mpls_lse[0]),
1931 mpls_lse_to_tc(af->flow.mpls_lse[0]),
1932 mpls_lse_to_ttl(af->flow.mpls_lse[0]));
1933 } else {
1934 dpctl_print(dpctl_p, "no mpls: ");
1935 }
1936
1937 ds_clear(&s);
1938 format_odp_actions(&s, af->actions.data, af->actions.size, NULL);
1939 dpctl_puts(dpctl_p, false, ds_cstr(&s));
1940
1941 ofpbuf_uninit(&af->actions);
1942 free(af);
1943 }
1944 free(afs);
1945
1946
1947 out_freeactions:
1948 ofpbuf_uninit(&odp_actions);
1949 out_freekeybuf:
1950 ofpbuf_uninit(&keybuf);
1951 out:
1952 simap_destroy(&port_names);
1953 ds_destroy(&s);
1954
1955 return error;
1956 }
1957 \f
1958 static const struct dpctl_command all_commands[] = {
1959 { "add-dp", "dp [iface...]", 1, INT_MAX, dpctl_add_dp, DP_RW },
1960 { "del-dp", "dp", 1, 1, dpctl_del_dp, DP_RW },
1961 { "add-if", "dp iface...", 2, INT_MAX, dpctl_add_if, DP_RW },
1962 { "del-if", "dp iface...", 2, INT_MAX, dpctl_del_if, DP_RW },
1963 { "set-if", "dp iface...", 2, INT_MAX, dpctl_set_if, DP_RW },
1964 { "dump-dps", "", 0, 0, dpctl_dump_dps, DP_RO },
1965 { "show", "[dp...]", 0, INT_MAX, dpctl_show, DP_RO },
1966 { "dump-flows", "[dp] [filter=..] [type=..]",
1967 0, 3, dpctl_dump_flows, DP_RO },
1968 { "add-flow", "[dp] flow actions", 2, 3, dpctl_add_flow, DP_RW },
1969 { "mod-flow", "[dp] flow actions", 2, 3, dpctl_mod_flow, DP_RW },
1970 { "get-flow", "[dp] ufid", 1, 2, dpctl_get_flow, DP_RO },
1971 { "del-flow", "[dp] flow", 1, 2, dpctl_del_flow, DP_RW },
1972 { "del-flows", "[dp]", 0, 1, dpctl_del_flows, DP_RW },
1973 { "dump-conntrack", "[dp] [zone=N]", 0, 2, dpctl_dump_conntrack, DP_RO },
1974 { "flush-conntrack", "[dp] [zone=N] [ct-tuple]", 0, 3,
1975 dpctl_flush_conntrack, DP_RW },
1976 { "ct-stats-show", "[dp] [zone=N]",
1977 0, 3, dpctl_ct_stats_show, DP_RO },
1978 { "ct-bkts", "[dp] [gt=N]", 0, 2, dpctl_ct_bkts, DP_RO },
1979 { "ct-set-maxconns", "[dp] maxconns", 1, 2, dpctl_ct_set_maxconns, DP_RW },
1980 { "ct-get-maxconns", "[dp]", 0, 1, dpctl_ct_get_maxconns, DP_RO },
1981 { "ct-get-nconns", "[dp]", 0, 1, dpctl_ct_get_nconns, DP_RO },
1982 { "help", "", 0, INT_MAX, dpctl_help, DP_RO },
1983 { "list-commands", "", 0, INT_MAX, dpctl_list_commands, DP_RO },
1984
1985 /* Undocumented commands for testing. */
1986 { "parse-actions", "actions", 1, INT_MAX, dpctl_parse_actions, DP_RO },
1987 { "normalize-actions", "actions",
1988 2, INT_MAX, dpctl_normalize_actions, DP_RO },
1989
1990 { NULL, NULL, 0, 0, NULL, DP_RO },
1991 };
1992
1993 static const struct dpctl_command *get_all_dpctl_commands(void)
1994 {
1995 return all_commands;
1996 }
1997
1998 /* Runs the command designated by argv[0] within the command table specified by
1999 * 'commands', which must be terminated by a command whose 'name' member is a
2000 * null pointer. */
2001 int
2002 dpctl_run_command(int argc, const char *argv[], struct dpctl_params *dpctl_p)
2003 {
2004 const struct dpctl_command *p;
2005 if (argc < 1) {
2006 dpctl_error(dpctl_p, 0, "missing command name; use --help for help");
2007 return EINVAL;
2008 }
2009
2010 for (p = all_commands; p->name != NULL; p++) {
2011 if (!strcmp(p->name, argv[0])) {
2012 int n_arg = argc - 1;
2013 if (n_arg < p->min_args) {
2014 dpctl_error(dpctl_p, 0,
2015 "'%s' command requires at least %d arguments",
2016 p->name, p->min_args);
2017 return EINVAL;
2018 } else if (n_arg > p->max_args) {
2019 dpctl_error(dpctl_p, 0,
2020 "'%s' command takes at most %d arguments",
2021 p->name, p->max_args);
2022 return EINVAL;
2023 } else {
2024 if (p->mode == DP_RW && dpctl_p->read_only) {
2025 dpctl_error(dpctl_p, 0,
2026 "'%s' command does not work in read only mode",
2027 p->name);
2028 return EINVAL;
2029 }
2030 return p->handler(argc, argv, dpctl_p);
2031 }
2032 }
2033 }
2034
2035 dpctl_error(dpctl_p, 0, "unknown command '%s'; use --help for help",
2036 argv[0]);
2037 return EINVAL;
2038 }
2039 \f
2040 static void
2041 dpctl_unixctl_print(void *userdata, bool error OVS_UNUSED, const char *msg)
2042 {
2043 struct ds *ds = userdata;
2044 ds_put_cstr(ds, msg);
2045 }
2046
2047 static void
2048 dpctl_unixctl_handler(struct unixctl_conn *conn, int argc, const char *argv[],
2049 void *aux)
2050 {
2051 struct ds ds = DS_EMPTY_INITIALIZER;
2052 bool error = false;
2053
2054 struct dpctl_params dpctl_p = {
2055 .is_appctl = true,
2056 .output = dpctl_unixctl_print,
2057 .aux = &ds,
2058 };
2059
2060 /* Parse options (like getopt). Unfortunately it does
2061 * not seem a good idea to call getopt_long() here, since it uses global
2062 * variables */
2063 bool set_names = false;
2064 while (argc > 1 && !error) {
2065 const char *arg = argv[1];
2066 if (!strncmp(arg, "--", 2)) {
2067 /* Long option */
2068 if (!strcmp(arg, "--statistics")) {
2069 dpctl_p.print_statistics = true;
2070 } else if (!strcmp(arg, "--clear")) {
2071 dpctl_p.zero_statistics = true;
2072 } else if (!strcmp(arg, "--may-create")) {
2073 dpctl_p.may_create = true;
2074 } else if (!strcmp(arg, "--more")) {
2075 dpctl_p.verbosity++;
2076 } else if (!strcmp(arg, "--names")) {
2077 dpctl_p.names = true;
2078 set_names = true;
2079 } else if (!strcmp(arg, "--no-names")) {
2080 dpctl_p.names = false;
2081 set_names = true;
2082 } else {
2083 ds_put_format(&ds, "Unrecognized option %s", argv[1]);
2084 error = true;
2085 }
2086 } else if (arg[0] == '-' && arg[1] != '\0') {
2087 /* Short option[s] */
2088 const char *opt = &arg[1];
2089
2090 while (*opt && !error) {
2091 switch (*opt) {
2092 case 'm':
2093 dpctl_p.verbosity++;
2094 break;
2095 case 's':
2096 dpctl_p.print_statistics = true;
2097 break;
2098 default:
2099 ds_put_format(&ds, "Unrecognized option -%c", *opt);
2100 error = true;
2101 break;
2102 }
2103 opt++;
2104 }
2105 } else {
2106 /* Doesn't start with -, not an option */
2107 break;
2108 }
2109
2110 if (error) {
2111 break;
2112 }
2113 argv++;
2114 argc--;
2115 }
2116 if (!set_names) {
2117 dpctl_p.names = dpctl_p.verbosity > 0;
2118 }
2119 VLOG_INFO("set_names=%d verbosity=%d names=%d", set_names,
2120 dpctl_p.verbosity, dpctl_p.names);
2121
2122 if (!error) {
2123 dpctl_command_handler *handler = (dpctl_command_handler *) aux;
2124 error = handler(argc, argv, &dpctl_p) != 0;
2125 }
2126
2127 if (error) {
2128 unixctl_command_reply_error(conn, ds_cstr(&ds));
2129 } else {
2130 unixctl_command_reply(conn, ds_cstr(&ds));
2131 }
2132
2133 ds_destroy(&ds);
2134 }
2135
2136 void
2137 dpctl_unixctl_register(void)
2138 {
2139 const struct dpctl_command *p;
2140
2141 for (p = all_commands; p->name != NULL; p++) {
2142 if (strcmp(p->name, "help")) {
2143 char *cmd_name = xasprintf("dpctl/%s", p->name);
2144 unixctl_command_register(cmd_name,
2145 p->usage,
2146 p->min_args,
2147 p->max_args,
2148 dpctl_unixctl_handler,
2149 p->handler);
2150 free(cmd_name);
2151 }
2152 }
2153 }