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