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