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