netdev-dummy: New appctl command netdev-dummy/set-admin-state.
[sliver-openvswitch.git] / utilities / ovs-dpctl.c
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18 #include <arpa/inet.h>
19 #include <assert.h>
20 #include <errno.h>
21 #include <getopt.h>
22 #include <inttypes.h>
23 #include <sys/socket.h>
24 #include <net/if.h>
25 #include <netinet/in.h>
26 #include <signal.h>
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <sys/stat.h>
32 #include <sys/time.h>
33
34 #include "command-line.h"
35 #include "compiler.h"
36 #include "dirs.h"
37 #include "dpif.h"
38 #include "dynamic-string.h"
39 #include "flow.h"
40 #include "netdev.h"
41 #include "netlink.h"
42 #include "odp-util.h"
43 #include "ofpbuf.h"
44 #include "packets.h"
45 #include "shash.h"
46 #include "simap.h"
47 #include "smap.h"
48 #include "sset.h"
49 #include "timeval.h"
50 #include "util.h"
51 #include "vlog.h"
52
53 VLOG_DEFINE_THIS_MODULE(dpctl);
54
55 /* -s, --statistics: Print port statistics? */
56 static bool print_statistics;
57
58 /* -m, --more: Output verbosity.
59  *
60  * So far only undocumented commands honor this option, so we don't document
61  * the option itself. */
62 static int verbosity;
63
64 static const struct command all_commands[];
65
66 static void usage(void) NO_RETURN;
67 static void parse_options(int argc, char *argv[]);
68
69 int
70 main(int argc, char *argv[])
71 {
72     set_program_name(argv[0]);
73     parse_options(argc, argv);
74     signal(SIGPIPE, SIG_IGN);
75     run_command(argc - optind, argv + optind, all_commands);
76     return 0;
77 }
78
79 static void
80 parse_options(int argc, char *argv[])
81 {
82     enum {
83         OPT_DUMMY = UCHAR_MAX + 1,
84         VLOG_OPTION_ENUMS
85     };
86     static struct option long_options[] = {
87         {"statistics", no_argument, NULL, 's'},
88         {"more", no_argument, NULL, 'm'},
89         {"timeout", required_argument, NULL, 't'},
90         {"help", no_argument, NULL, 'h'},
91         {"version", no_argument, NULL, 'V'},
92         VLOG_LONG_OPTIONS,
93         {NULL, 0, NULL, 0},
94     };
95     char *short_options = long_options_to_short_options(long_options);
96
97     for (;;) {
98         unsigned long int timeout;
99         int c;
100
101         c = getopt_long(argc, argv, short_options, long_options, NULL);
102         if (c == -1) {
103             break;
104         }
105
106         switch (c) {
107         case 's':
108             print_statistics = true;
109             break;
110
111         case 'm':
112             verbosity++;
113             break;
114
115         case 't':
116             timeout = strtoul(optarg, NULL, 10);
117             if (timeout <= 0) {
118                 ovs_fatal(0, "value %s on -t or --timeout is not at least 1",
119                           optarg);
120             } else {
121                 time_alarm(timeout);
122             }
123             break;
124
125         case 'h':
126             usage();
127
128         case 'V':
129             ovs_print_version(0, 0);
130             exit(EXIT_SUCCESS);
131
132         VLOG_OPTION_HANDLERS
133
134         case '?':
135             exit(EXIT_FAILURE);
136
137         default:
138             abort();
139         }
140     }
141     free(short_options);
142 }
143
144 static void
145 usage(void)
146 {
147     printf("%s: Open vSwitch datapath management utility\n"
148            "usage: %s [OPTIONS] COMMAND [ARG...]\n"
149            "  add-dp DP [IFACE...]     add new datapath DP (with IFACEs)\n"
150            "  del-dp DP                delete local datapath DP\n"
151            "  add-if DP IFACE...       add each IFACE as a port on DP\n"
152            "  set-if DP IFACE...       reconfigure each IFACE within DP\n"
153            "  del-if DP IFACE...       delete each IFACE from DP\n"
154            "  dump-dps                 display names of all datapaths\n"
155            "  show                     show basic info on all datapaths\n"
156            "  show DP...               show basic info on each DP\n"
157            "  dump-flows DP            display flows in DP\n"
158            "  del-flows DP             delete all flows from DP\n"
159            "Each IFACE on add-dp, add-if, and set-if may be followed by\n"
160            "comma-separated options.  See ovs-dpctl(8) for syntax, or the\n"
161            "Interface table in ovs-vswitchd.conf.db(5) for an options list.\n",
162            program_name, program_name);
163     vlog_usage();
164     printf("\nOther options:\n"
165            "  -t, --timeout=SECS          give up after SECS seconds\n"
166            "  -h, --help                  display this help message\n"
167            "  -V, --version               display version information\n");
168     exit(EXIT_SUCCESS);
169 }
170
171 static void run(int retval, const char *message, ...)
172     PRINTF_FORMAT(2, 3);
173
174 static void run(int retval, const char *message, ...)
175 {
176     if (retval) {
177         va_list args;
178
179         va_start(args, message);
180         ovs_fatal_valist(retval, message, args);
181     }
182 }
183 \f
184 static void dpctl_add_if(int argc, char *argv[]);
185
186 static int if_up(const char *netdev_name)
187 {
188     struct netdev *netdev;
189     int retval;
190
191     retval = netdev_open(netdev_name, "system", &netdev);
192     if (!retval) {
193         retval = netdev_turn_flags_on(netdev, NETDEV_UP, true);
194         netdev_close(netdev);
195     }
196     return retval;
197 }
198
199 static int
200 parsed_dpif_open(const char *arg_, bool create, struct dpif **dpifp)
201 {
202     int result;
203     char *name, *type;
204
205     dp_parse_name(arg_, &name, &type);
206
207     if (create) {
208         result = dpif_create(name, type, dpifp);
209     } else {
210         result = dpif_open(name, type, dpifp);
211     }
212
213     free(name);
214     free(type);
215     return result;
216 }
217
218 static void
219 dpctl_add_dp(int argc OVS_UNUSED, char *argv[])
220 {
221     struct dpif *dpif;
222     run(parsed_dpif_open(argv[1], true, &dpif), "add_dp");
223     dpif_close(dpif);
224     if (argc > 2) {
225         dpctl_add_if(argc, argv);
226     }
227 }
228
229 static void
230 dpctl_del_dp(int argc OVS_UNUSED, char *argv[])
231 {
232     struct dpif *dpif;
233     run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
234     run(dpif_delete(dpif), "del_dp");
235     dpif_close(dpif);
236 }
237
238 static void
239 dpctl_add_if(int argc OVS_UNUSED, char *argv[])
240 {
241     bool failure = false;
242     struct dpif *dpif;
243     int i;
244
245     run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
246     for (i = 2; i < argc; i++) {
247         const char *name, *type;
248         char *save_ptr = NULL;
249         struct netdev *netdev = NULL;
250         struct smap args;
251         uint16_t port_no = UINT16_MAX;
252         char *option;
253         int error;
254
255         name = strtok_r(argv[i], ",", &save_ptr);
256         type = "system";
257
258         if (!name) {
259             ovs_error(0, "%s is not a valid network device name", argv[i]);
260             failure = true;
261             continue;
262         }
263
264         smap_init(&args);
265         while ((option = strtok_r(NULL, ",", &save_ptr)) != NULL) {
266             char *save_ptr_2 = NULL;
267             char *key, *value;
268
269             key = strtok_r(option, "=", &save_ptr_2);
270             value = strtok_r(NULL, "", &save_ptr_2);
271             if (!value) {
272                 value = "";
273             }
274
275             if (!strcmp(key, "type")) {
276                 type = value;
277             } else if (!strcmp(key, "port_no")) {
278                 port_no = atoi(value);
279             } else if (!smap_add_once(&args, key, value)) {
280                 ovs_error(0, "duplicate \"%s\" option", key);
281             }
282         }
283
284         error = netdev_open(name, type, &netdev);
285         if (error) {
286             ovs_error(error, "%s: failed to open network device", name);
287             goto next;
288         }
289
290         error = netdev_set_config(netdev, &args);
291         if (error) {
292             ovs_error(error, "%s: failed to configure network device", name);
293             goto next;
294         }
295
296         error = dpif_port_add(dpif, netdev, &port_no);
297         if (error) {
298             ovs_error(error, "adding %s to %s failed", name, argv[1]);
299             goto next;
300         }
301
302         error = if_up(name);
303
304 next:
305         netdev_close(netdev);
306         if (error) {
307             failure = true;
308         }
309     }
310     dpif_close(dpif);
311     if (failure) {
312         exit(EXIT_FAILURE);
313     }
314 }
315
316 static void
317 dpctl_set_if(int argc, char *argv[])
318 {
319     bool failure = false;
320     struct dpif *dpif;
321     int i;
322
323     run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
324     for (i = 2; i < argc; i++) {
325         struct netdev *netdev = NULL;
326         struct dpif_port dpif_port;
327         char *save_ptr = NULL;
328         char *type = NULL;
329         const char *name;
330         struct smap args;
331         uint32_t port_no;
332         char *option;
333         int error;
334
335         name = strtok_r(argv[i], ",", &save_ptr);
336         if (!name) {
337             ovs_error(0, "%s is not a valid network device name", argv[i]);
338             failure = true;
339             continue;
340         }
341
342         /* Get the port's type from the datapath. */
343         error = dpif_port_query_by_name(dpif, name, &dpif_port);
344         if (error) {
345             ovs_error(error, "%s: failed to query port in %s", name, argv[1]);
346             goto next;
347         }
348         type = xstrdup(dpif_port.type);
349         port_no = dpif_port.port_no;
350         dpif_port_destroy(&dpif_port);
351
352         /* Retrieve its existing configuration. */
353         error = netdev_open(name, type, &netdev);
354         if (error) {
355             ovs_error(error, "%s: failed to open network device", name);
356             goto next;
357         }
358
359         smap_init(&args);
360         error = netdev_get_config(netdev, &args);
361         if (error) {
362             ovs_error(error, "%s: failed to fetch configuration", name);
363             goto next;
364         }
365
366         /* Parse changes to configuration. */
367         while ((option = strtok_r(NULL, ",", &save_ptr)) != NULL) {
368             char *save_ptr_2 = NULL;
369             char *key, *value;
370
371             key = strtok_r(option, "=", &save_ptr_2);
372             value = strtok_r(NULL, "", &save_ptr_2);
373             if (!value) {
374                 value = "";
375             }
376
377             if (!strcmp(key, "type")) {
378                 if (strcmp(value, type)) {
379                     ovs_error(0, "%s: can't change type from %s to %s",
380                               name, type, value);
381                     failure = true;
382                 }
383             } else if (!strcmp(key, "port_no")) {
384                 if (port_no != atoi(value)) {
385                     ovs_error(0, "%s: can't change port number from "
386                               "%"PRIu32" to %d",
387                               name, port_no, atoi(value));
388                     failure = true;
389                 }
390             } else if (value[0] == '\0') {
391                 smap_remove(&args, key);
392             } else {
393                 smap_replace(&args, key, value);
394             }
395         }
396
397         /* Update configuration. */
398         error = netdev_set_config(netdev, &args);
399         smap_destroy(&args);
400         if (error) {
401             ovs_error(error, "%s: failed to configure network device", name);
402             goto next;
403         }
404
405 next:
406         free(type);
407         netdev_close(netdev);
408         if (error) {
409             failure = true;
410         }
411     }
412     dpif_close(dpif);
413     if (failure) {
414         exit(EXIT_FAILURE);
415     }
416 }
417
418 static bool
419 get_port_number(struct dpif *dpif, const char *name, uint16_t *port)
420 {
421     struct dpif_port dpif_port;
422
423     if (!dpif_port_query_by_name(dpif, name, &dpif_port)) {
424         *port = dpif_port.port_no;
425         dpif_port_destroy(&dpif_port);
426         return true;
427     } else {
428         ovs_error(0, "no port named %s", name);
429         return false;
430     }
431 }
432
433 static void
434 dpctl_del_if(int argc OVS_UNUSED, char *argv[])
435 {
436     bool failure = false;
437     struct dpif *dpif;
438     int i;
439
440     run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
441     for (i = 2; i < argc; i++) {
442         const char *name = argv[i];
443         uint16_t port;
444         int error;
445
446         if (!name[strspn(name, "0123456789")]) {
447             port = atoi(name);
448         } else if (!get_port_number(dpif, name, &port)) {
449             failure = true;
450             continue;
451         }
452
453         error = dpif_port_del(dpif, port);
454         if (error) {
455             ovs_error(error, "deleting port %s from %s failed", name, argv[1]);
456             failure = true;
457         }
458     }
459     dpif_close(dpif);
460     if (failure) {
461         exit(EXIT_FAILURE);
462     }
463 }
464
465 static void
466 print_stat(const char *leader, uint64_t value)
467 {
468     fputs(leader, stdout);
469     if (value != UINT64_MAX) {
470         printf("%"PRIu64, value);
471     } else {
472         putchar('?');
473     }
474 }
475
476 static void
477 print_human_size(uint64_t value)
478 {
479     if (value == UINT64_MAX) {
480         /* Nothing to do. */
481     } else if (value >= 1024ULL * 1024 * 1024 * 1024) {
482         printf(" (%.1f TiB)", value / (1024.0 * 1024 * 1024 * 1024));
483     } else if (value >= 1024ULL * 1024 * 1024) {
484         printf(" (%.1f GiB)", value / (1024.0 * 1024 * 1024));
485     } else if (value >= 1024ULL * 1024) {
486         printf(" (%.1f MiB)", value / (1024.0 * 1024));
487     } else if (value >= 1024) {
488         printf(" (%.1f KiB)", value / 1024.0);
489     }
490 }
491
492 static void
493 show_dpif(struct dpif *dpif)
494 {
495     struct dpif_port_dump dump;
496     struct dpif_port dpif_port;
497     struct dpif_dp_stats stats;
498     struct netdev *netdev;
499
500     printf("%s:\n", dpif_name(dpif));
501     if (!dpif_get_dp_stats(dpif, &stats)) {
502         printf("\tlookups: hit:%"PRIu64" missed:%"PRIu64" lost:%"PRIu64"\n"
503                "\tflows: %"PRIu64"\n",
504                stats.n_hit, stats.n_missed, stats.n_lost, stats.n_flows);
505     }
506     DPIF_PORT_FOR_EACH (&dpif_port, &dump, dpif) {
507         printf("\tport %u: %s", dpif_port.port_no, dpif_port.name);
508
509         if (strcmp(dpif_port.type, "system")) {
510             int error;
511
512             printf (" (%s", dpif_port.type);
513
514             error = netdev_open(dpif_port.name, dpif_port.type, &netdev);
515             if (!error) {
516                 struct smap config;
517
518                 smap_init(&config);
519                 error = netdev_get_config(netdev, &config);
520                 if (!error) {
521                     const struct smap_node **nodes;
522                     size_t i;
523
524                     nodes = smap_sort(&config);
525                     for (i = 0; i < smap_count(&config); i++) {
526                         const struct smap_node *node = nodes[i];
527                         printf("%c %s=%s", i ? ',' : ':', node->key,
528                                node->value);
529                     }
530                     free(nodes);
531                 } else {
532                     printf(", could not retrieve configuration (%s)",
533                            strerror(error));
534                 }
535                 smap_destroy(&config);
536
537                 netdev_close(netdev);
538             } else {
539                 printf(": open failed (%s)", strerror(error));
540             }
541             putchar(')');
542         }
543         putchar('\n');
544
545         if (print_statistics) {
546             struct netdev_stats s;
547             int error;
548
549             error = netdev_open(dpif_port.name, dpif_port.type, &netdev);
550             if (error) {
551                 printf(", open failed (%s)", strerror(error));
552                 continue;
553             }
554             error = netdev_get_stats(netdev, &s);
555             if (error) {
556                 printf(", could not retrieve stats (%s)", strerror(error));
557                 continue;
558             }
559
560             netdev_close(netdev);
561             print_stat("\t\tRX packets:", s.rx_packets);
562             print_stat(" errors:", s.rx_errors);
563             print_stat(" dropped:", s.rx_dropped);
564             print_stat(" overruns:", s.rx_over_errors);
565             print_stat(" frame:", s.rx_frame_errors);
566             printf("\n");
567
568             print_stat("\t\tTX packets:", s.tx_packets);
569             print_stat(" errors:", s.tx_errors);
570             print_stat(" dropped:", s.tx_dropped);
571             print_stat(" aborted:", s.tx_aborted_errors);
572             print_stat(" carrier:", s.tx_carrier_errors);
573             printf("\n");
574
575             print_stat("\t\tcollisions:", s.collisions);
576             printf("\n");
577
578             print_stat("\t\tRX bytes:", s.rx_bytes);
579             print_human_size(s.rx_bytes);
580             print_stat("  TX bytes:", s.tx_bytes);
581             print_human_size(s.tx_bytes);
582             printf("\n");
583         }
584     }
585     dpif_close(dpif);
586 }
587
588 static void
589 dpctl_show(int argc, char *argv[])
590 {
591     bool failure = false;
592     if (argc > 1) {
593         int i;
594         for (i = 1; i < argc; i++) {
595             const char *name = argv[i];
596             struct dpif *dpif;
597             int error;
598
599             error = parsed_dpif_open(name, false, &dpif);
600             if (!error) {
601                 show_dpif(dpif);
602             } else {
603                 ovs_error(error, "opening datapath %s failed", name);
604                 failure = true;
605             }
606         }
607     } else {
608         struct sset types;
609         const char *type;
610
611         sset_init(&types);
612         dp_enumerate_types(&types);
613         SSET_FOR_EACH (type, &types) {
614             struct sset names;
615             const char *name;
616
617             sset_init(&names);
618             if (dp_enumerate_names(type, &names)) {
619                 failure = true;
620                 continue;
621             }
622             SSET_FOR_EACH (name, &names) {
623                 struct dpif *dpif;
624                 int error;
625
626                 error = dpif_open(name, type, &dpif);
627                 if (!error) {
628                     show_dpif(dpif);
629                 } else {
630                     ovs_error(error, "opening datapath %s failed", name);
631                     failure = true;
632                 }
633             }
634             sset_destroy(&names);
635         }
636         sset_destroy(&types);
637     }
638     if (failure) {
639         exit(EXIT_FAILURE);
640     }
641 }
642
643 static void
644 dpctl_dump_dps(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
645 {
646     struct sset dpif_names, dpif_types;
647     const char *type;
648     int error = 0;
649
650     sset_init(&dpif_names);
651     sset_init(&dpif_types);
652     dp_enumerate_types(&dpif_types);
653
654     SSET_FOR_EACH (type, &dpif_types) {
655         const char *name;
656         int retval;
657
658         retval = dp_enumerate_names(type, &dpif_names);
659         if (retval) {
660             error = retval;
661         }
662
663         SSET_FOR_EACH (name, &dpif_names) {
664             struct dpif *dpif;
665             if (!dpif_open(name, type, &dpif)) {
666                 printf("%s\n", dpif_name(dpif));
667                 dpif_close(dpif);
668             }
669         }
670     }
671
672     sset_destroy(&dpif_names);
673     sset_destroy(&dpif_types);
674     if (error) {
675         exit(EXIT_FAILURE);
676     }
677 }
678
679 static void
680 dpctl_dump_flows(int argc OVS_UNUSED, char *argv[])
681 {
682     const struct dpif_flow_stats *stats;
683     const struct nlattr *actions;
684     struct dpif_flow_dump dump;
685     const struct nlattr *key;
686     size_t actions_len;
687     struct dpif *dpif;
688     size_t key_len;
689     struct ds ds;
690
691     run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
692
693     ds_init(&ds);
694     dpif_flow_dump_start(&dump, dpif);
695     while (dpif_flow_dump_next(&dump, &key, &key_len,
696                                &actions, &actions_len, &stats)) {
697         ds_clear(&ds);
698         odp_flow_key_format(key, key_len, &ds);
699         ds_put_cstr(&ds, ", ");
700         dpif_flow_stats_format(stats, &ds);
701         ds_put_cstr(&ds, ", actions:");
702         format_odp_actions(&ds, actions, actions_len);
703         printf("%s\n", ds_cstr(&ds));
704     }
705     dpif_flow_dump_done(&dump);
706     ds_destroy(&ds);
707     dpif_close(dpif);
708 }
709
710 static void
711 dpctl_del_flows(int argc OVS_UNUSED, char *argv[])
712 {
713     struct dpif *dpif;
714
715     run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
716     run(dpif_flow_flush(dpif), "deleting all flows");
717     dpif_close(dpif);
718 }
719
720 static void
721 dpctl_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
722 {
723     usage();
724 }
725 \f
726 /* Undocumented commands for unit testing. */
727
728 static void
729 dpctl_parse_actions(int argc, char *argv[])
730 {
731     int i;
732
733     for (i = 1; i < argc; i++) {
734         struct ofpbuf actions;
735         struct ds s;
736
737         ofpbuf_init(&actions, 0);
738         run(odp_actions_from_string(argv[i], NULL, &actions),
739             "odp_actions_from_string");
740
741         ds_init(&s);
742         format_odp_actions(&s, actions.data, actions.size);
743         puts(ds_cstr(&s));
744         ds_destroy(&s);
745
746         ofpbuf_uninit(&actions);
747     }
748 }
749
750 struct actions_for_flow {
751     struct hmap_node hmap_node;
752     struct flow flow;
753     struct ofpbuf actions;
754 };
755
756 static struct actions_for_flow *
757 get_actions_for_flow(struct hmap *actions_per_flow, const struct flow *flow)
758 {
759     uint32_t hash = flow_hash(flow, 0);
760     struct actions_for_flow *af;
761
762     HMAP_FOR_EACH_WITH_HASH (af, hmap_node, hash, actions_per_flow) {
763         if (flow_equal(&af->flow, flow)) {
764             return af;
765         }
766     }
767
768     af = xmalloc(sizeof *af);
769     af->flow = *flow;
770     ofpbuf_init(&af->actions, 0);
771     hmap_insert(actions_per_flow, &af->hmap_node, hash);
772     return af;
773 }
774
775 static int
776 compare_actions_for_flow(const void *a_, const void *b_)
777 {
778     struct actions_for_flow *const *a = a_;
779     struct actions_for_flow *const *b = b_;
780
781     return flow_compare_3way(&(*a)->flow, &(*b)->flow);
782 }
783
784 static int
785 compare_output_actions(const void *a_, const void *b_)
786 {
787     const struct nlattr *a = a_;
788     const struct nlattr *b = b_;
789     uint32_t a_port = nl_attr_get_u32(a);
790     uint32_t b_port = nl_attr_get_u32(b);
791
792     return a_port < b_port ? -1 : a_port > b_port;
793 }
794
795 static void
796 sort_output_actions__(struct nlattr *first, struct nlattr *end)
797 {
798     size_t bytes = (uint8_t *) end - (uint8_t *) first;
799     size_t n = bytes / NL_A_U32_SIZE;
800
801     assert(bytes % NL_A_U32_SIZE == 0);
802     qsort(first, n, NL_A_U32_SIZE, compare_output_actions);
803 }
804
805 static void
806 sort_output_actions(struct nlattr *actions, size_t length)
807 {
808     struct nlattr *first_output = NULL;
809     struct nlattr *a;
810     int left;
811
812     NL_ATTR_FOR_EACH (a, left, actions, length) {
813         if (nl_attr_type(a) == OVS_ACTION_ATTR_OUTPUT) {
814             if (!first_output) {
815                 first_output = a;
816             }
817         } else {
818             if (first_output) {
819                 sort_output_actions__(first_output, a);
820                 first_output = NULL;
821             }
822         }
823     }
824     if (first_output) {
825         uint8_t *end = (uint8_t *) actions + length;
826         sort_output_actions__(first_output, (struct nlattr *) end);
827     }
828 }
829
830 /* usage: "ovs-dpctl normalize-actions FLOW ACTIONS" where FLOW and ACTIONS
831  * have the syntax used by "ovs-dpctl dump-flows".
832  *
833  * This command prints ACTIONS in a format that shows what happens for each
834  * VLAN, independent of the order of the ACTIONS.  For example, there is more
835  * than one way to output a packet on VLANs 9 and 11, but this command will
836  * print the same output for any form.
837  *
838  * The idea here generalizes beyond VLANs (e.g. to setting other fields) but
839  * so far the implementation only covers VLANs. */
840 static void
841 dpctl_normalize_actions(int argc, char *argv[])
842 {
843     struct simap port_names;
844     struct ofpbuf keybuf;
845     struct flow flow;
846     struct ofpbuf odp_actions;
847     struct hmap actions_per_flow;
848     struct actions_for_flow **afs;
849     struct actions_for_flow *af;
850     struct nlattr *a;
851     size_t n_afs;
852     struct ds s;
853     int left;
854     int i;
855
856     ds_init(&s);
857
858     simap_init(&port_names);
859     for (i = 3; i < argc; i++) {
860         char name[16];
861         int number;
862         int n = -1;
863
864         if (sscanf(argv[i], "%15[^=]=%d%n", name, &number, &n) > 0 && n > 0) {
865             uintptr_t n = number;
866             simap_put(&port_names, name, n);
867         } else {
868             ovs_fatal(0, "%s: expected NAME=NUMBER", argv[i]);
869         }
870     }
871
872     /* Parse flow key. */
873     ofpbuf_init(&keybuf, 0);
874     run(odp_flow_key_from_string(argv[1], &port_names, &keybuf),
875         "odp_flow_key_from_string");
876
877     ds_clear(&s);
878     odp_flow_key_format(keybuf.data, keybuf.size, &s);
879     printf("input flow: %s\n", ds_cstr(&s));
880
881     run(odp_flow_key_to_flow(keybuf.data, keybuf.size, &flow),
882         "odp_flow_key_to_flow");
883     ofpbuf_uninit(&keybuf);
884
885     /* Parse actions. */
886     ofpbuf_init(&odp_actions, 0);
887     run(odp_actions_from_string(argv[2], &port_names, &odp_actions),
888         "odp_actions_from_string");
889
890     if (verbosity) {
891         ds_clear(&s);
892         format_odp_actions(&s, odp_actions.data, odp_actions.size);
893         printf("input actions: %s\n", ds_cstr(&s));
894     }
895
896     hmap_init(&actions_per_flow);
897     NL_ATTR_FOR_EACH (a, left, odp_actions.data, odp_actions.size) {
898         if (nl_attr_type(a) == OVS_ACTION_ATTR_POP_VLAN) {
899             flow.vlan_tci = htons(0);
900             continue;
901         }
902
903         if (nl_attr_type(a) == OVS_ACTION_ATTR_PUSH_VLAN) {
904             const struct ovs_action_push_vlan *push;
905
906             push = nl_attr_get_unspec(a, sizeof *push);
907             flow.vlan_tci = push->vlan_tci;
908             continue;
909         }
910
911         af = get_actions_for_flow(&actions_per_flow, &flow);
912         nl_msg_put_unspec(&af->actions, nl_attr_type(a),
913                           nl_attr_get(a), nl_attr_get_size(a));
914     }
915
916     n_afs = hmap_count(&actions_per_flow);
917     afs = xmalloc(n_afs * sizeof *afs);
918     i = 0;
919     HMAP_FOR_EACH (af, hmap_node, &actions_per_flow) {
920         afs[i++] = af;
921     }
922     assert(i == n_afs);
923
924     qsort(afs, n_afs, sizeof *afs, compare_actions_for_flow);
925
926     for (i = 0; i < n_afs; i++) {
927         const struct actions_for_flow *af = afs[i];
928
929         sort_output_actions(af->actions.data, af->actions.size);
930
931         if (af->flow.vlan_tci != htons(0)) {
932             printf("vlan(vid=%"PRIu16",pcp=%d): ",
933                    vlan_tci_to_vid(af->flow.vlan_tci),
934                    vlan_tci_to_pcp(af->flow.vlan_tci));
935         } else {
936             printf("no vlan: ");
937         }
938
939         ds_clear(&s);
940         format_odp_actions(&s, af->actions.data, af->actions.size);
941         puts(ds_cstr(&s));
942     }
943     ds_destroy(&s);
944 }
945
946 static const struct command all_commands[] = {
947     { "add-dp", 1, INT_MAX, dpctl_add_dp },
948     { "del-dp", 1, 1, dpctl_del_dp },
949     { "add-if", 2, INT_MAX, dpctl_add_if },
950     { "del-if", 2, INT_MAX, dpctl_del_if },
951     { "set-if", 2, INT_MAX, dpctl_set_if },
952     { "dump-dps", 0, 0, dpctl_dump_dps },
953     { "show", 0, INT_MAX, dpctl_show },
954     { "dump-flows", 1, 1, dpctl_dump_flows },
955     { "del-flows", 1, 1, dpctl_del_flows },
956     { "help", 0, INT_MAX, dpctl_help },
957
958     /* Undocumented commands for testing. */
959     { "parse-actions", 1, INT_MAX, dpctl_parse_actions },
960     { "normalize-actions", 2, INT_MAX, dpctl_normalize_actions },
961
962     { NULL, 0, 0, NULL },
963 };