2 * Copyright (c) 2008-2019 Nicira, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <sys/types.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
23 #include <sys/socket.h>
30 #include "command-line.h"
36 #include "dpif-provider.h"
37 #include "openvswitch/dynamic-string.h"
39 #include "openvswitch/match.h"
43 #include "openvswitch/ofpbuf.h"
45 #include "openvswitch/shash.h"
52 #include "openvswitch/ofp-flow.h"
53 #include "openvswitch/ofp-port.h"
61 typedef int dpctl_command_handler(int argc
, const char *argv
[],
62 struct dpctl_params
*);
63 struct dpctl_command
{
68 dpctl_command_handler
*handler
;
69 enum { DP_RO
, DP_RW
} mode
;
71 static const struct dpctl_command
*get_all_dpctl_commands(void);
72 static void dpctl_print(struct dpctl_params
*dpctl_p
, const char *fmt
, ...)
73 OVS_PRINTF_FORMAT(2, 3);
74 static void dpctl_error(struct dpctl_params
* dpctl_p
, int err_no
,
76 OVS_PRINTF_FORMAT(3, 4);
79 dpctl_puts(struct dpctl_params
*dpctl_p
, bool error
, const char *string
)
81 dpctl_p
->output(dpctl_p
->aux
, error
, string
);
85 dpctl_print(struct dpctl_params
*dpctl_p
, const char *fmt
, ...)
91 string
= xvasprintf(fmt
, args
);
94 dpctl_puts(dpctl_p
, false, string
);
99 dpctl_error(struct dpctl_params
* dpctl_p
, int err_no
, const char *fmt
, ...)
101 const char *subprogram_name
= get_subprogram_name();
102 struct ds ds
= DS_EMPTY_INITIALIZER
;
103 int save_errno
= errno
;
107 if (subprogram_name
[0]) {
108 ds_put_format(&ds
, "%s(%s): ", program_name
,subprogram_name
);
110 ds_put_format(&ds
, "%s: ", program_name
);
114 ds_put_format_valist(&ds
, fmt
, args
);
118 ds_put_format(&ds
, " (%s)", ovs_retval_to_string(err_no
));
120 ds_put_cstr(&ds
, "\n");
122 dpctl_puts(dpctl_p
, true, ds_cstr(&ds
));
129 static int dpctl_add_if(int argc
, const char *argv
[], struct dpctl_params
*);
132 if_up(struct netdev
*netdev
)
134 return netdev_turn_flags_on(netdev
, NETDEV_UP
, NULL
);
137 /* Retrieve the name of the datapath if exactly one exists. The caller
138 * is responsible for freeing the returned string. If a single datapath
139 * name cannot be determined, returns NULL. */
141 get_one_dp(struct dpctl_params
*dpctl_p
)
145 char *dp_name
= NULL
;
149 dp_enumerate_types(&types
);
150 SSET_FOR_EACH (type
, &types
) {
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
));
160 sset_destroy(&names
);
162 sset_destroy(&types
);
165 dpctl_error(dpctl_p
, 0, "no datapaths exist");
166 } else if (count
> 1) {
167 dpctl_error(dpctl_p
, 0, "multiple datapaths, specify one");
176 parsed_dpif_open(const char *arg_
, bool create
, struct dpif
**dpifp
)
181 dp_parse_name(arg_
, &name
, &type
);
184 result
= dpif_create(name
, type
, dpifp
);
186 result
= dpif_open(name
, type
, dpifp
);
195 dp_exists(const char *queried_dp
)
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
);
203 bool found
= (sset_contains(&dpif_types
, queried_type
) &&
204 !dp_enumerate_names(queried_type
, &dpif_names
) &&
205 sset_contains(&dpif_names
, queried_name
));
207 sset_destroy(&dpif_names
);
208 sset_destroy(&dpif_types
);
215 dp_arg_exists(int argc
, const char *argv
[])
217 return argc
> 1 && dp_exists(argv
[1]);
220 /* Open a dpif with an optional name argument.
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
224 * exists. On success stores the opened dpif in '*dpifp'. */
226 opt_dpif_open(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
,
227 int max_args
, struct dpif
**dpifp
)
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
);
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. */
245 dpctl_error(dpctl_p
, error
, "datapath not found");
247 error
= parsed_dpif_open(dpname
, false, dpifp
);
250 dpctl_error(dpctl_p
, error
, "opening datapath");
257 dpctl_add_dp(int argc
, const char *argv
[],
258 struct dpctl_params
*dpctl_p
)
263 error
= parsed_dpif_open(argv
[1], true, &dpif
);
265 dpctl_error(dpctl_p
, error
, "add_dp");
270 error
= dpctl_add_if(argc
, argv
, dpctl_p
);
276 dpctl_del_dp(int argc OVS_UNUSED
, const char *argv
[],
277 struct dpctl_params
*dpctl_p
)
282 error
= parsed_dpif_open(argv
[1], false, &dpif
);
284 dpctl_error(dpctl_p
, error
, "opening datapath");
287 error
= dpif_delete(dpif
);
289 dpctl_error(dpctl_p
, error
, "del_dp");
297 dpctl_add_if(int argc OVS_UNUSED
, const char *argv
[],
298 struct dpctl_params
*dpctl_p
)
301 int i
, error
, lasterror
= 0;
303 error
= parsed_dpif_open(argv
[1], false, &dpif
);
305 dpctl_error(dpctl_p
, error
, "opening datapath");
308 for (i
= 2; i
< argc
; i
++) {
309 const char *name
, *type
;
310 char *save_ptr
= NULL
, *argcopy
;
311 struct netdev
*netdev
= NULL
;
313 odp_port_t port_no
= ODPP_NONE
;
316 argcopy
= xstrdup(argv
[i
]);
317 name
= strtok_r(argcopy
, ",", &save_ptr
);
321 dpctl_error(dpctl_p
, 0, "%s is not a valid network device name",
328 while ((option
= strtok_r(NULL
, ",", &save_ptr
)) != NULL
) {
329 char *save_ptr_2
= NULL
;
332 key
= strtok_r(option
, "=", &save_ptr_2
);
333 value
= strtok_r(NULL
, "", &save_ptr_2
);
338 if (!strcmp(key
, "type")) {
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
);
347 error
= netdev_open(name
, type
, &netdev
);
349 dpctl_error(dpctl_p
, error
, "%s: failed to open network device",
351 goto next_destroy_args
;
354 error
= netdev_set_config(netdev
, &args
, NULL
);
356 goto next_destroy_args
;
359 error
= dpif_port_add(dpif
, netdev
, &port_no
);
361 dpctl_error(dpctl_p
, error
, "adding %s to %s failed", name
,
363 goto next_destroy_args
;
366 error
= if_up(netdev
);
368 dpctl_error(dpctl_p
, error
, "%s: failed bringing interface up",
373 netdev_close(netdev
);
387 dpctl_set_if(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
390 int i
, error
, lasterror
= 0;
392 error
= parsed_dpif_open(argv
[1], false, &dpif
);
394 dpctl_error(dpctl_p
, error
, "opening datapath");
397 for (i
= 2; i
< argc
; i
++) {
398 struct netdev
*netdev
= NULL
;
399 struct dpif_port dpif_port
;
400 char *save_ptr
= NULL
;
410 argcopy
= xstrdup(argv
[i
]);
411 name
= strtok_r(argcopy
, ",", &save_ptr
);
413 dpctl_error(dpctl_p
, 0, "%s is not a valid network device name",
418 /* Get the port's type from the datapath. */
419 error
= dpif_port_query_by_name(dpif
, name
, &dpif_port
);
421 dpctl_error(dpctl_p
, error
, "%s: failed to query port in %s", name
,
425 type
= xstrdup(dpif_port
.type
);
426 port_no
= dpif_port
.port_no
;
427 dpif_port_destroy(&dpif_port
);
429 /* Retrieve its existing configuration. */
430 error
= netdev_open(name
, type
, &netdev
);
432 dpctl_error(dpctl_p
, error
, "%s: failed to open network device",
438 error
= netdev_get_config(netdev
, &args
);
440 dpctl_error(dpctl_p
, error
, "%s: failed to fetch configuration",
442 goto next_destroy_args
;
445 /* Parse changes to configuration. */
446 while ((option
= strtok_r(NULL
, ",", &save_ptr
)) != NULL
) {
447 char *save_ptr_2
= NULL
;
450 key
= strtok_r(option
, "=", &save_ptr_2
);
451 value
= strtok_r(NULL
, "", &save_ptr_2
);
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",
462 goto next_destroy_args
;
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
));
469 goto next_destroy_args
;
471 } else if (value
[0] == '\0') {
472 smap_remove(&args
, key
);
474 smap_replace(&args
, key
, value
);
478 /* Update configuration. */
480 error
= netdev_set_config(netdev
, &args
, &err_s
);
481 if (err_s
|| error
) {
482 dpctl_error(dpctl_p
, error
, "%s",
483 err_s
? err_s
: "Error updating configuration");
487 goto next_destroy_args
;
493 netdev_close(netdev
);
506 get_port_number(struct dpif
*dpif
, const char *name
, odp_port_t
*port
,
507 struct dpctl_params
*dpctl_p
)
509 struct dpif_port dpif_port
;
511 if (!dpif_port_query_by_name(dpif
, name
, &dpif_port
)) {
512 *port
= dpif_port
.port_no
;
513 dpif_port_destroy(&dpif_port
);
516 dpctl_error(dpctl_p
, 0, "no port named %s", name
);
522 dpctl_del_if(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
525 int i
, error
, lasterror
= 0;
527 error
= parsed_dpif_open(argv
[1], false, &dpif
);
529 dpctl_error(dpctl_p
, error
, "opening datapath");
532 for (i
= 2; i
< argc
; i
++) {
533 const char *name
= argv
[i
];
536 if (!name
[strspn(name
, "0123456789")]) {
537 port
= u32_to_odp(atoi(name
));
538 } else if (!get_port_number(dpif
, name
, &port
, dpctl_p
)) {
543 error
= dpif_port_del(dpif
, port
, false);
545 dpctl_error(dpctl_p
, error
, "deleting port %s from %s failed",
555 print_stat(struct dpctl_params
*dpctl_p
, const char *leader
, uint64_t value
)
557 dpctl_print(dpctl_p
, "%s", leader
);
558 if (value
!= UINT64_MAX
) {
559 dpctl_print(dpctl_p
, "%"PRIu64
, value
);
561 dpctl_print(dpctl_p
, "?");
566 print_human_size(struct dpctl_params
*dpctl_p
, uint64_t value
)
568 if (value
== UINT64_MAX
) {
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);
582 /* qsort comparison function. */
584 compare_port_nos(const void *a_
, const void *b_
)
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
);
591 return a
< b
? -1 : a
> b
;
595 show_dpif(struct dpif
*dpif
, struct dpctl_params
*dpctl_p
)
597 struct dpif_port_dump dump
;
598 struct dpif_port dpif_port
;
599 struct dpif_dp_stats stats
;
600 struct netdev
*netdev
;
602 dpctl_print(dpctl_p
, "%s:\n", dpif_name(dpif
));
603 if (!dpif_get_dp_stats(dpif
, &stats
)) {
604 dpctl_print(dpctl_p
, " lookups: hit:%"PRIu64
" missed:%"PRIu64
605 " lost:%"PRIu64
"\n flows: %"PRIu64
"\n",
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;
611 dpctl_print(dpctl_p
, " masks: hit:%"PRIu64
" total:%"PRIu32
613 stats
.n_mask_hit
, stats
.n_masks
, avg
);
617 odp_port_t
*port_nos
= NULL
;
618 size_t allocated_port_nos
= 0, n_port_nos
= 0;
619 DPIF_PORT_FOR_EACH (&dpif_port
, &dump
, dpif
) {
620 if (n_port_nos
>= allocated_port_nos
) {
621 port_nos
= x2nrealloc(port_nos
, &allocated_port_nos
,
625 port_nos
[n_port_nos
] = dpif_port
.port_no
;
630 qsort(port_nos
, n_port_nos
, sizeof *port_nos
, compare_port_nos
);
633 for (int i
= 0; i
< n_port_nos
; i
++) {
634 if (dpif_port_query_by_number(dpif
, port_nos
[i
], &dpif_port
)) {
638 dpctl_print(dpctl_p
, " port %u: %s",
639 dpif_port
.port_no
, dpif_port
.name
);
641 if (strcmp(dpif_port
.type
, "system")) {
644 dpctl_print(dpctl_p
, " (%s", dpif_port
.type
);
646 error
= netdev_open(dpif_port
.name
, dpif_port
.type
, &netdev
);
651 error
= netdev_get_config(netdev
, &config
);
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
? ',' : ':',
657 node
->key
, node
->value
);
661 dpctl_print(dpctl_p
, ", could not retrieve configuration "
662 "(%s)", ovs_strerror(error
));
664 smap_destroy(&config
);
666 netdev_close(netdev
);
668 dpctl_print(dpctl_p
, ": open failed (%s)",
669 ovs_strerror(error
));
671 dpctl_print(dpctl_p
, ")");
673 dpctl_print(dpctl_p
, "\n");
675 if (dpctl_p
->print_statistics
) {
676 struct netdev_stats s
;
679 error
= netdev_open(dpif_port
.name
, dpif_port
.type
, &netdev
);
681 dpctl_print(dpctl_p
, ", open failed (%s)",
682 ovs_strerror(error
));
683 dpif_port_destroy(&dpif_port
);
686 error
= netdev_get_stats(netdev
, &s
);
688 netdev_close(netdev
);
689 print_stat(dpctl_p
, " RX packets:", s
.rx_packets
);
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");
696 print_stat(dpctl_p
, " TX packets:", s
.tx_packets
);
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");
703 print_stat(dpctl_p
, " collisions:", s
.collisions
);
704 dpctl_print(dpctl_p
, "\n");
706 print_stat(dpctl_p
, " RX bytes:", s
.rx_bytes
);
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");
712 dpctl_print(dpctl_p
, ", could not retrieve stats (%s)",
713 ovs_strerror(error
));
716 dpif_port_destroy(&dpif_port
);
722 typedef void (*dps_for_each_cb
)(struct dpif
*, struct dpctl_params
*);
725 dps_for_each(struct dpctl_params
*dpctl_p
, dps_for_each_cb cb
)
727 struct sset dpif_names
= SSET_INITIALIZER(&dpif_names
),
728 dpif_types
= SSET_INITIALIZER(&dpif_types
);
729 int error
, openerror
= 0, enumerror
= 0;
730 const char *type
, *name
;
731 bool at_least_one
= false;
733 dp_enumerate_types(&dpif_types
);
735 SSET_FOR_EACH (type
, &dpif_types
) {
736 error
= dp_enumerate_names(type
, &dpif_names
);
741 SSET_FOR_EACH (name
, &dpif_names
) {
745 error
= dpif_open(name
, type
, &dpif
);
751 dpctl_error(dpctl_p
, error
, "opening datapath %s failed",
757 sset_destroy(&dpif_names
);
758 sset_destroy(&dpif_types
);
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
769 return at_least_one
? 0 : enumerror
;
774 dpctl_show(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
776 int error
, lasterror
= 0;
779 for (i
= 1; i
< argc
; i
++) {
780 const char *name
= argv
[i
];
783 error
= parsed_dpif_open(name
, false, &dpif
);
785 show_dpif(dpif
, dpctl_p
);
788 dpctl_error(dpctl_p
, error
, "opening datapath %s failed",
794 lasterror
= dps_for_each(dpctl_p
, show_dpif
);
801 dump_cb(struct dpif
*dpif
, struct dpctl_params
*dpctl_p
)
803 dpctl_print(dpctl_p
, "%s\n", dpif_name(dpif
));
807 dpctl_dump_dps(int argc OVS_UNUSED
, const char *argv
[] OVS_UNUSED
,
808 struct dpctl_params
*dpctl_p
)
810 return dps_for_each(dpctl_p
, dump_cb
);
814 format_dpif_flow(struct ds
*ds
, const struct dpif_flow
*f
, struct hmap
*ports
,
815 struct dpctl_params
*dpctl_p
)
817 if (dpctl_p
->verbosity
&& f
->ufid_present
) {
818 odp_format_ufid(&f
->ufid
, ds
);
819 ds_put_cstr(ds
, ", ");
821 odp_flow_format(f
->key
, f
->key_len
, f
->mask
, f
->mask_len
, ports
, ds
,
823 ds_put_cstr(ds
, ", ");
825 dpif_flow_stats_format(&f
->stats
, ds
);
826 if (dpctl_p
->verbosity
&& f
->attrs
.offloaded
) {
827 if (f
->attrs
.dp_layer
&& !strcmp(f
->attrs
.dp_layer
, "ovs")) {
828 ds_put_cstr(ds
, ", offloaded:partial");
830 ds_put_cstr(ds
, ", offloaded:yes");
833 if (dpctl_p
->verbosity
&& f
->attrs
.dp_layer
) {
834 ds_put_format(ds
, ", dp:%s", f
->attrs
.dp_layer
);
836 ds_put_cstr(ds
, ", actions:");
837 format_odp_actions(ds
, f
->actions
, f
->actions_len
, ports
);
838 if (dpctl_p
->verbosity
&& f
->attrs
.dp_extra_info
) {
839 ds_put_format(ds
, ", dp-extra-info:%s", f
->attrs
.dp_extra_info
);
849 bool partially_offloaded
;
853 enable_all_dump_types(struct dump_types
*dump_types
)
855 dump_types
->ovs
= true;
856 dump_types
->tc
= true;
857 dump_types
->dpdk
= true;
858 dump_types
->offloaded
= true;
859 dump_types
->non_offloaded
= true;
860 dump_types
->partially_offloaded
= true;
864 populate_dump_types(char *types_list
, struct dump_types
*dump_types
,
865 struct dpctl_params
*dpctl_p
)
868 enable_all_dump_types(dump_types
);
874 while (types_list
&& types_list
[0] != '\0') {
875 current_type
= types_list
;
876 size_t type_len
= strcspn(current_type
, ",");
878 types_list
+= type_len
+ (types_list
[type_len
] != '\0');
879 current_type
[type_len
] = '\0';
881 if (!strcmp(current_type
, "ovs")) {
882 dump_types
->ovs
= true;
883 } else if (!strcmp(current_type
, "tc")) {
884 dump_types
->tc
= true;
885 } else if (!strcmp(current_type
, "dpdk")) {
886 dump_types
->dpdk
= true;
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;
891 } else if (!strcmp(current_type
, "partially-offloaded")) {
892 dump_types
->partially_offloaded
= true;
893 } else if (!strcmp(current_type
, "all")) {
894 enable_all_dump_types(dump_types
);
896 dpctl_error(dpctl_p
, EINVAL
, "Failed to parse type (%s)",
905 determine_dpif_flow_dump_types(struct dump_types
*dump_types
,
906 struct dpif_flow_dump_types
*dpif_dump_types
)
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
910 || dump_types
->non_offloaded
912 || dump_types
->partially_offloaded
;
916 flow_passes_type_filter(const struct dpif_flow
*f
,
917 struct dump_types
*dump_types
)
919 if (dump_types
->ovs
&& !strcmp(f
->attrs
.dp_layer
, "ovs")) {
922 if (dump_types
->tc
&& !strcmp(f
->attrs
.dp_layer
, "tc")) {
925 if (dump_types
->dpdk
&& !strcmp(f
->attrs
.dp_layer
, "dpdk")) {
928 if (dump_types
->offloaded
&& f
->attrs
.offloaded
&&
929 strcmp(f
->attrs
.dp_layer
, "ovs")) {
932 if (dump_types
->partially_offloaded
&& f
->attrs
.offloaded
&&
933 !strcmp(f
->attrs
.dp_layer
, "ovs")) {
936 if (dump_types
->non_offloaded
&& !(f
->attrs
.offloaded
)) {
943 dpctl_get_portno_names(struct dpif
*dpif
, const struct dpctl_params
*dpctl_p
)
945 if (dpctl_p
->names
) {
946 struct hmap
*portno_names
= xmalloc(sizeof *portno_names
);
947 hmap_init(portno_names
);
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
,
963 dpctl_free_portno_names(struct hmap
*portno_names
)
966 odp_portno_names_destroy(portno_names
);
967 hmap_destroy(portno_names
);
973 dpctl_dump_flows(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
979 struct flow flow_filter
;
980 struct flow_wildcards wc_filter
;
981 char *types_list
= NULL
;
982 struct dump_types dump_types
;
983 struct dpif_flow_dump_types dpif_dump_types
;
985 struct dpif_flow_dump_thread
*flow_dump_thread
;
986 struct dpif_flow_dump
*flow_dump
;
988 int pmd_id
= PMD_ID_NULL
;
989 bool pmd_id_filter
= false;
993 while (argc
> 1 && lastargc
!= argc
) {
995 if (!strncmp(argv
[argc
- 1], "filter=", 7) && !filter
) {
996 filter
= xstrdup(argv
[--argc
] + 7);
997 } else if (!strncmp(argv
[argc
- 1], "type=", 5) && !types_list
) {
998 if (!dpctl_p
->is_appctl
) {
999 dpctl_error(dpctl_p
, 0,
1000 "Invalid argument 'type'. "
1001 "Use 'ovs-appctl dpctl/dump-flows' instead.");
1005 types_list
= xstrdup(argv
[--argc
] + 5);
1006 } else if (!strncmp(argv
[argc
- 1], "pmd=", 4)) {
1007 if (!ovs_scan(argv
[--argc
], "pmd=%d", &pmd_id
)) {
1013 pmd_id
= NON_PMD_CORE_ID
;
1015 pmd_id_filter
= true;
1019 error
= opt_dpif_open(argc
, argv
, dpctl_p
, 2, &dpif
);
1024 struct hmap
*portno_names
= dpctl_get_portno_names(dpif
, dpctl_p
);
1027 struct ofputil_port_map port_map
;
1028 ofputil_port_map_init(&port_map
);
1030 struct dpif_port_dump port_dump
;
1031 struct dpif_port dpif_port
;
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
)),
1037 char *err
= parse_ofp_exact_flow(&flow_filter
, &wc_filter
, NULL
,
1039 ofputil_port_map_destroy(&port_map
);
1041 dpctl_error(dpctl_p
, 0, "Failed to parse filter (%s)", err
);
1048 memset(&dump_types
, 0, sizeof dump_types
);
1049 error
= populate_dump_types(types_list
, &dump_types
, dpctl_p
);
1053 determine_dpif_flow_dump_types(&dump_types
, &dpif_dump_types
);
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
);
1062 memset(&f
, 0, sizeof f
);
1063 flow_dump
= dpif_flow_dump_create(dpif
, false, &dpif_dump_types
);
1064 flow_dump_thread
= dpif_flow_dump_thread_create(flow_dump
);
1065 while (dpif_flow_dump_next(flow_dump_thread
, &f
, 1)) {
1068 struct flow_wildcards wc
;
1069 struct match match
, match_filter
;
1070 struct minimatch minimatch
;
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
);
1074 match_init(&match
, &flow
, &wc
);
1076 match_init(&match_filter
, &flow_filter
, &wc
);
1077 match_init(&match_filter
, &match_filter
.flow
, &wc_filter
);
1078 minimatch_init(&minimatch
, &match_filter
);
1080 if (!minimatch_matches_flow(&minimatch
, &match
.flow
)) {
1081 minimatch_destroy(&minimatch
);
1084 minimatch_destroy(&minimatch
);
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. */
1090 if (!pmd_id_filter
&& pmd_id
!= f
.pmd_id
) {
1091 if (f
.pmd_id
== NON_PMD_CORE_ID
) {
1092 ds_put_format(&ds
, "flow-dump from the main thread:\n");
1094 ds_put_format(&ds
, "flow-dump from pmd on cpu core: %d\n",
1099 if (pmd_id
== f
.pmd_id
&&
1100 flow_passes_type_filter(&f
, &dump_types
)) {
1101 format_dpif_flow(&ds
, &f
, portno_names
, dpctl_p
);
1102 dpctl_print(dpctl_p
, "%s\n", ds_cstr(&ds
));
1105 dpif_flow_dump_thread_destroy(flow_dump_thread
);
1106 error
= dpif_flow_dump_destroy(flow_dump
);
1109 dpctl_error(dpctl_p
, error
, "Failed to dump flows from datapath");
1114 dpctl_free_portno_names(portno_names
);
1123 dpctl_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
)
1128 struct dpif_flow_stats stats
;
1129 struct dpif_port dpif_port
;
1130 struct dpif_port_dump port_dump
;
1131 struct ofpbuf actions
;
1136 struct simap port_names
;
1139 ufid_present
= false;
1140 n
= odp_ufid_from_string(key_s
, &ufid
);
1142 dpctl_error(dpctl_p
, -n
, "parsing flow ufid");
1146 ufid_present
= true;
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
));
1154 ofpbuf_init(&key
, 0);
1155 ofpbuf_init(&mask
, 0);
1157 error
= odp_flow_from_string(key_s
, &port_names
, &key
, &mask
, &error_s
);
1158 simap_destroy(&port_names
);
1160 dpctl_error(dpctl_p
, error
, "parsing flow key (%s)", error_s
);
1162 goto out_freekeymask
;
1165 ofpbuf_init(&actions
, 0);
1166 error
= odp_actions_from_string(actions_s
, NULL
, &actions
);
1168 dpctl_error(dpctl_p
, error
, "parsing actions");
1169 goto out_freeactions
;
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;
1182 /* The flow will be added on all pmds currently in the datapath. */
1183 error
= dpif_flow_put(dpif
, flags
,
1185 mask
.size
== 0 ? NULL
: mask
.data
,
1186 mask
.size
, actions
.data
,
1187 actions
.size
, ufid_present
? &ufid
: NULL
,
1189 dpctl_p
->print_statistics
? &stats
: NULL
);
1192 dpctl_error(dpctl_p
, error
, "updating flow table");
1193 goto out_freeactions
;
1196 if (dpctl_p
->print_statistics
) {
1200 dpif_flow_stats_format(&stats
, &s
);
1201 dpctl_print(dpctl_p
, "%s\n", ds_cstr(&s
));
1206 ofpbuf_uninit(&actions
);
1208 ofpbuf_uninit(&mask
);
1209 ofpbuf_uninit(&key
);
1214 dpctl_put_flow(int argc
, const char *argv
[], enum dpif_flow_put_flags flags
,
1215 struct dpctl_params
*dpctl_p
)
1220 error
= opt_dpif_open(argc
, argv
, dpctl_p
, 4, &dpif
);
1225 error
= dpctl_put_flow_dpif(dpif
, argv
[argc
- 2], argv
[argc
- 1], flags
,
1233 dpctl_add_flow(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
1235 return dpctl_put_flow(argc
, argv
, DPIF_FP_CREATE
, dpctl_p
);
1239 dpctl_mod_flow(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
1241 enum dpif_flow_put_flags flags
;
1243 flags
= DPIF_FP_MODIFY
;
1244 if (dpctl_p
->may_create
) {
1245 flags
|= DPIF_FP_CREATE
;
1247 if (dpctl_p
->zero_statistics
) {
1248 flags
|= DPIF_FP_ZERO_STATS
;
1251 return dpctl_put_flow(argc
, argv
, flags
, dpctl_p
);
1255 dpctl_get_flow(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
1257 const char *key_s
= argv
[argc
- 1];
1258 struct dpif_flow flow
;
1262 uint64_t stub
[DPIF_FLOW_BUFSIZE
/ 8];
1266 error
= opt_dpif_open(argc
, argv
, dpctl_p
, 3, &dpif
);
1271 ofpbuf_use_stub(&buf
, &stub
, sizeof stub
);
1273 struct hmap
*portno_names
= dpctl_get_portno_names(dpif
, dpctl_p
);
1275 n
= odp_ufid_from_string(key_s
, &ufid
);
1277 dpctl_error(dpctl_p
, -n
, "parsing flow ufid");
1281 /* In case of PMD will be returned flow from first PMD thread with match. */
1282 error
= dpif_flow_get(dpif
, NULL
, 0, &ufid
, PMD_ID_NULL
, &buf
, &flow
);
1284 dpctl_error(dpctl_p
, error
, "getting flow");
1289 format_dpif_flow(&ds
, &flow
, portno_names
, dpctl_p
);
1290 dpctl_print(dpctl_p
, "%s\n", ds_cstr(&ds
));
1294 dpctl_free_portno_names(portno_names
);
1295 ofpbuf_uninit(&buf
);
1301 dpctl_del_flow_dpif(struct dpif
*dpif
, const char *key_s
,
1302 struct dpctl_params
*dpctl_p
)
1304 struct dpif_flow_stats stats
;
1305 struct dpif_port dpif_port
;
1306 struct dpif_port_dump port_dump
;
1308 struct ofpbuf mask
; /* To be ignored. */
1311 bool ufid_generated
;
1313 struct simap port_names
;
1316 ufid_present
= false;
1317 n
= odp_ufid_from_string(key_s
, &ufid
);
1319 dpctl_error(dpctl_p
, -n
, "parsing flow ufid");
1323 ufid_present
= true;
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
));
1331 ofpbuf_init(&key
, 0);
1332 ofpbuf_init(&mask
, 0);
1335 error
= odp_flow_from_string(key_s
, &port_names
, &key
, &mask
, &error_s
);
1337 dpctl_error(dpctl_p
, error
, "%s", error_s
);
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;
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
);
1356 dpctl_error(dpctl_p
, error
, "deleting flow");
1357 if (error
== ENOENT
&& (!ufid_present
|| ufid_generated
)) {
1361 ds_put_format(&s
, "Perhaps you need to specify a UFID?");
1362 dpctl_print(dpctl_p
, "%s\n", ds_cstr(&s
));
1368 if (dpctl_p
->print_statistics
) {
1372 dpif_flow_stats_format(&stats
, &s
);
1373 dpctl_print(dpctl_p
, "%s\n", ds_cstr(&s
));
1378 ofpbuf_uninit(&mask
);
1379 ofpbuf_uninit(&key
);
1380 simap_destroy(&port_names
);
1385 dpctl_del_flow(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
1387 const char *key_s
= argv
[argc
- 1];
1391 error
= opt_dpif_open(argc
, argv
, dpctl_p
, 3, &dpif
);
1396 error
= dpctl_del_flow_dpif(dpif
, key_s
, dpctl_p
);
1403 dpctl_parse_flow_line(int command
, struct ds
*s
, char **flow
, char **action
)
1405 const char *line
= ds_cstr(s
);
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");
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
;
1423 /* Isolate flow and action (for add/modify). */
1424 line
+= strspn(line
, " \t\r\n");
1425 len
= strcspn(line
, " \t\r\n");
1433 *flow
= xzalloc(len
+ 1);
1434 ovs_strlcpy(*flow
, line
, len
+ 1);
1437 line
+= strspn(line
, " \t\r\n");
1439 *action
= xstrdup(line
);
1448 dpctl_process_flows(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
1450 const char *file_name
= argv
[argc
- 1];
1451 int line_number
= 0;
1456 int def_cmd
= DPCTL_FLOWS_ADD
;
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
;
1464 error
= opt_dpif_open(argc
, argv
, dpctl_p
, 4, &dpif
);
1469 stream
= !strcmp(file_name
, "-") ? stdin
: fopen(file_name
, "r");
1472 dpctl_error(dpctl_p
, error
, "Opening file \"%s\" failed", file_name
);
1473 goto out_close_dpif
;
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.
1483 char *action
= NULL
;
1484 int cmd
= dpctl_parse_flow_line(def_cmd
, &line
, &flow
, &action
);
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!",
1494 case DPCTL_FLOWS_ADD
:
1495 dpctl_put_flow_dpif(dpif
, flow
, action
,
1496 DPIF_FP_CREATE
, dpctl_p
);
1498 case DPCTL_FLOWS_MOD
:
1499 dpctl_put_flow_dpif(dpif
, flow
, action
,
1500 DPIF_FP_MODIFY
, dpctl_p
);
1502 case DPCTL_FLOWS_DEL
:
1503 dpctl_del_flow_dpif(dpif
, flow
, dpctl_p
);
1513 if (stream
!= stdin
) {
1522 dpctl_del_flows(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
1527 if ((!dp_arg_exists(argc
, argv
) && argc
== 2) || argc
> 2) {
1528 return dpctl_process_flows(argc
, argv
, dpctl_p
);
1531 error
= opt_dpif_open(argc
, argv
, dpctl_p
, 2, &dpif
);
1536 error
= dpif_flow_flush(dpif
);
1538 dpctl_error(dpctl_p
, error
, "deleting all flows");
1545 dpctl_help(int argc OVS_UNUSED
, const char *argv
[] OVS_UNUSED
,
1546 struct dpctl_params
*dpctl_p
)
1548 if (dpctl_p
->usage
) {
1549 dpctl_p
->usage(dpctl_p
->aux
);
1556 dpctl_list_commands(int argc OVS_UNUSED
, const char *argv
[] OVS_UNUSED
,
1557 struct dpctl_params
*dpctl_p
)
1559 struct ds ds
= DS_EMPTY_INITIALIZER
;
1560 const struct dpctl_command
*commands
= get_all_dpctl_commands();
1562 ds_put_cstr(&ds
, "The available commands are:\n");
1563 for (; commands
->name
; commands
++) {
1564 const struct dpctl_command
*c
= commands
;
1566 if (dpctl_p
->is_appctl
&& !strcmp(c
->name
, "help")) {
1570 ds_put_format(&ds
, " %s%-23s %s\n", dpctl_p
->is_appctl
? "dpctl/" : "",
1573 dpctl_puts(dpctl_p
, false, ds
.string
);
1581 dpctl_dump_conntrack(int argc
, const char *argv
[],
1582 struct dpctl_params
*dpctl_p
)
1584 struct ct_dpif_dump_state
*dump
;
1585 struct ct_dpif_entry cte
;
1586 uint16_t zone
, *pzone
= NULL
;
1591 if (argc
> 1 && ovs_scan(argv
[argc
- 1], "zone=%"SCNu16
, &zone
)) {
1596 error
= opt_dpif_open(argc
, argv
, dpctl_p
, 2, &dpif
);
1601 error
= ct_dpif_dump_start(dpif
, &dump
, pzone
, &tot_bkts
);
1603 dpctl_error(dpctl_p
, error
, "starting conntrack dump");
1608 while (!(error
= ct_dpif_dump_next(dump
, &cte
))) {
1609 struct ds s
= DS_EMPTY_INITIALIZER
;
1611 ct_dpif_format_entry(&cte
, &s
, dpctl_p
->verbosity
,
1612 dpctl_p
->print_statistics
);
1613 ct_dpif_entry_uninit(&cte
);
1615 dpctl_print(dpctl_p
, "%s\n", ds_cstr(&s
));
1619 /* Any CT entry was dumped with no issue. */
1622 dpctl_error(dpctl_p
, error
, "dumping conntrack entry");
1625 ct_dpif_dump_done(dump
);
1631 dpctl_flush_conntrack(int argc
, const char *argv
[],
1632 struct dpctl_params
*dpctl_p
)
1634 struct dpif
*dpif
= NULL
;
1635 struct ct_dpif_tuple tuple
, *ptuple
= NULL
;
1636 struct ds ds
= DS_EMPTY_INITIALIZER
;
1637 uint16_t zone
, *pzone
= NULL
;
1639 int args
= argc
- 1;
1641 /* Parse ct tuple */
1642 if (args
&& ct_dpif_parse_tuple(&tuple
, argv
[args
], &ds
)) {
1648 if (args
&& ovs_scan(argv
[args
], "zone=%"SCNu16
, &zone
)) {
1653 /* Report error if there are more than one unparsed argument. */
1655 ds_put_cstr(&ds
, "invalid arguments");
1660 error
= opt_dpif_open(argc
, argv
, dpctl_p
, 4, &dpif
);
1665 error
= ct_dpif_flush(dpif
, pzone
, ptuple
);
1670 ds_put_cstr(&ds
, "failed to flush conntrack");
1674 dpctl_error(dpctl_p
, error
, "%s", ds_cstr(&ds
));
1681 dpctl_ct_stats_show(int argc
, const char *argv
[],
1682 struct dpctl_params
*dpctl_p
)
1685 struct ct_dpif_dump_state
*dump
;
1686 struct ct_dpif_entry cte
;
1687 uint16_t zone
, *pzone
= NULL
;
1691 int proto_stats
[CT_STATS_MAX
];
1692 int tcp_conn_per_states
[CT_DPIF_TCPS_MAX_NUM
];
1695 bool verbose
= dpctl_p
->verbosity
;
1697 while (argc
> 1 && lastargc
!= argc
) {
1699 if (!strncmp(argv
[argc
- 1], "verbose", 7)) {
1700 /* Support "verbose" argument for backwards compatibility. */
1703 } else if (!strncmp(argv
[argc
- 1], "zone=", 5)) {
1704 if (ovs_scan(argv
[argc
- 1], "zone=%"SCNu16
, &zone
)) {
1711 error
= opt_dpif_open(argc
, argv
, dpctl_p
, 2, &dpif
);
1716 memset(proto_stats
, 0, sizeof(proto_stats
));
1717 memset(tcp_conn_per_states
, 0, sizeof(tcp_conn_per_states
));
1718 error
= ct_dpif_dump_start(dpif
, &dump
, pzone
, &tot_bkts
);
1720 dpctl_error(dpctl_p
, error
, "starting conntrack dump");
1726 while (!(error
= ct_dpif_dump_next(dump
, &cte
))) {
1727 ct_dpif_entry_uninit(&cte
);
1729 switch (cte
.tuple_orig
.ip_proto
) {
1731 proto_stats
[CT_STATS_ICMP
]++;
1733 case IPPROTO_ICMPV6
:
1734 proto_stats
[CT_STATS_ICMPV6
]++;
1737 proto_stats
[CT_STATS_TCP
]++;
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
]++;
1748 proto_stats
[CT_STATS_UDP
]++;
1751 proto_stats
[CT_STATS_SCTP
]++;
1753 case IPPROTO_UDPLITE
:
1754 proto_stats
[CT_STATS_UDPLITE
]++;
1757 proto_stats
[CT_STATS_DCCP
]++;
1760 proto_stats
[CT_STATS_IGMP
]++;
1763 proto_stats
[CT_STATS_OTHER
]++;
1768 /* All CT entries were dumped with no issue. */
1771 dpctl_error(dpctl_p
, error
, "dumping conntrack entry");
1772 /* Fall through to show any other info we collected. */
1775 dpctl_print(dpctl_p
, "Connections Stats:\n Total: %d\n", tot_conn
);
1776 if (proto_stats
[CT_STATS_TCP
]) {
1777 dpctl_print(dpctl_p
, " TCP: %d\n", proto_stats
[CT_STATS_TCP
]);
1779 dpctl_print(dpctl_p
, " Conn per TCP states:\n");
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
));
1790 if (proto_stats
[CT_STATS_UDP
]) {
1791 dpctl_print(dpctl_p
, " UDP: %d\n", proto_stats
[CT_STATS_UDP
]);
1793 if (proto_stats
[CT_STATS_UDPLITE
]) {
1794 dpctl_print(dpctl_p
, " UDPLITE: %d\n", proto_stats
[CT_STATS_UDPLITE
]);
1796 if (proto_stats
[CT_STATS_SCTP
]) {
1797 dpctl_print(dpctl_p
, " SCTP: %d\n", proto_stats
[CT_STATS_SCTP
]);
1799 if (proto_stats
[CT_STATS_ICMP
]) {
1800 dpctl_print(dpctl_p
, " ICMP: %d\n", proto_stats
[CT_STATS_ICMP
]);
1802 if (proto_stats
[CT_STATS_DCCP
]) {
1803 dpctl_print(dpctl_p
, " DCCP: %d\n", proto_stats
[CT_STATS_DCCP
]);
1805 if (proto_stats
[CT_STATS_IGMP
]) {
1806 dpctl_print(dpctl_p
, " IGMP: %d\n", proto_stats
[CT_STATS_IGMP
]);
1808 if (proto_stats
[CT_STATS_OTHER
]) {
1809 dpctl_print(dpctl_p
, " Other: %d\n", proto_stats
[CT_STATS_OTHER
]);
1812 ct_dpif_dump_done(dump
);
1817 #define CT_BKTS_GT "gt="
1819 dpctl_ct_bkts(int argc
, const char *argv
[],
1820 struct dpctl_params
*dpctl_p
)
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
;
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
, >
)) {
1836 error
= opt_dpif_open(argc
, argv
, dpctl_p
, 2, &dpif
);
1841 error
= ct_dpif_dump_start(dpif
, &dump
, pzone
, &tot_bkts
);
1843 dpctl_error(dpctl_p
, error
, "starting conntrack dump");
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
);
1856 dpctl_print(dpctl_p
, "Total Buckets: %d\n", tot_bkts
);
1859 uint32_t *conn_per_bkts
= xzalloc(tot_bkts
* sizeof(uint32_t));
1861 while (!(error
= ct_dpif_dump_next(dump
, &cte
))) {
1862 ct_dpif_entry_uninit(&cte
);
1865 if (cte
.bkt
< tot_bkts
) {
1866 conn_per_bkts
[cte
.bkt
]++;
1868 dpctl_print(dpctl_p
, "Bucket nr out of range: %d >= %d\n",
1874 /* All CT entries were dumped with no issue. */
1877 dpctl_error(dpctl_p
, error
, "dumping conntrack entry");
1878 /* Fall through and display all the collected info. */
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);
1896 if (conn_per_bkts
[i
] > gt
) {
1897 dpctl_print(dpctl_p
, "%5d", conn_per_bkts
[i
]);
1899 dpctl_print(dpctl_p
, "%5s", ".");
1902 dpctl_print(dpctl_p
, "\n\n");
1905 ct_dpif_dump_done(dump
);
1907 free(conn_per_bkts
);
1912 dpctl_ct_set_maxconns(int argc
, const char *argv
[],
1913 struct dpctl_params
*dpctl_p
)
1916 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, 3, &dpif
);
1919 if (ovs_scan(argv
[argc
- 1], "%"SCNu32
, &maxconns
)) {
1920 error
= ct_dpif_set_maxconns(dpif
, maxconns
);
1923 dpctl_print(dpctl_p
, "setting maxconns successful");
1925 dpctl_error(dpctl_p
, error
, "ct set maxconns failed");
1929 dpctl_error(dpctl_p
, error
, "maxconns missing or malformed");
1938 dpctl_ct_get_maxconns(int argc
, const char *argv
[],
1939 struct dpctl_params
*dpctl_p
)
1942 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, 2, &dpif
);
1945 error
= ct_dpif_get_maxconns(dpif
, &maxconns
);
1948 dpctl_print(dpctl_p
, "%u\n", maxconns
);
1950 dpctl_error(dpctl_p
, error
, "maxconns could not be retrieved");
1959 dpctl_ct_get_nconns(int argc
, const char *argv
[],
1960 struct dpctl_params
*dpctl_p
)
1963 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, 2, &dpif
);
1966 error
= ct_dpif_get_nconns(dpif
, &nconns
);
1969 dpctl_print(dpctl_p
, "%u\n", nconns
);
1971 dpctl_error(dpctl_p
, error
, "nconns could not be retrieved");
1980 dpctl_ct_set_tcp_seq_chk__(int argc
, const char *argv
[],
1981 struct dpctl_params
*dpctl_p
, bool enabled
)
1984 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, 3, &dpif
);
1986 error
= ct_dpif_set_tcp_seq_chk(dpif
, enabled
);
1988 dpctl_print(dpctl_p
,
1989 "%s TCP sequence checking successful",
1990 enabled
? "enabling" : "disabling");
1992 dpctl_error(dpctl_p
, error
,
1993 "%s TCP sequence checking failed",
1994 enabled
? "enabling" : "disabling");
2002 dpctl_ct_enable_tcp_seq_chk(int argc
, const char *argv
[],
2003 struct dpctl_params
*dpctl_p
)
2005 return dpctl_ct_set_tcp_seq_chk__(argc
, argv
, dpctl_p
, true);
2009 dpctl_ct_disable_tcp_seq_chk(int argc
, const char *argv
[],
2010 struct dpctl_params
*dpctl_p
)
2012 return dpctl_ct_set_tcp_seq_chk__(argc
, argv
, dpctl_p
, false);
2016 dpctl_ct_get_tcp_seq_chk(int argc
, const char *argv
[],
2017 struct dpctl_params
*dpctl_p
)
2020 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, 2, &dpif
);
2023 error
= ct_dpif_get_tcp_seq_chk(dpif
, &enabled
);
2025 dpctl_print(dpctl_p
, "TCP sequence checking: %s\n",
2026 enabled
? "enabled" : "disabled");
2028 dpctl_error(dpctl_p
, error
, "TCP sequence checking query failed");
2036 dpctl_ct_set_limits(int argc
, const char *argv
[],
2037 struct dpctl_params
*dpctl_p
)
2040 struct ds ds
= DS_EMPTY_INITIALIZER
;
2041 int i
= dp_arg_exists(argc
, argv
) ? 2 : 1;
2042 uint32_t default_limit
, *p_default_limit
= NULL
;
2043 struct ovs_list zone_limits
= OVS_LIST_INITIALIZER(&zone_limits
);
2045 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, INT_MAX
, &dpif
);
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
;
2056 ds_put_cstr(&ds
, "invalid default limit");
2062 /* Parse ct zone limit tuples */
2066 if (!ct_dpif_parse_zone_limit_tuple(argv
[i
++], &zone
, &limit
, &ds
)) {
2070 ct_dpif_push_zone_limit(&zone_limits
, zone
, limit
, 0);
2073 error
= ct_dpif_set_limits(dpif
, p_default_limit
, &zone_limits
);
2075 ct_dpif_free_zone_limits(&zone_limits
);
2079 ds_put_cstr(&ds
, "failed to set conntrack limit");
2083 dpctl_error(dpctl_p
, error
, "%s", ds_cstr(&ds
));
2085 ct_dpif_free_zone_limits(&zone_limits
);
2091 parse_ct_limit_zones(const char *argv
, struct ovs_list
*zone_limits
,
2094 char *save_ptr
= NULL
, *argcopy
, *next_zone
;
2097 if (strncmp(argv
, "zone=", 5)) {
2098 ds_put_format(ds
, "invalid argument %s", argv
);
2102 argcopy
= xstrdup(argv
+ 5);
2103 next_zone
= strtok_r(argcopy
, ",", &save_ptr
);
2106 if (ovs_scan(next_zone
, "%"SCNu16
, &zone
)) {
2107 ct_dpif_push_zone_limit(zone_limits
, zone
, 0, 0);
2109 ds_put_cstr(ds
, "invalid zone");
2113 } while ((next_zone
= strtok_r(NULL
, ",", &save_ptr
)) != NULL
);
2120 dpctl_ct_del_limits(int argc
, const char *argv
[],
2121 struct dpctl_params
*dpctl_p
)
2124 struct ds ds
= DS_EMPTY_INITIALIZER
;
2126 int i
= dp_arg_exists(argc
, argv
) ? 2 : 1;
2127 struct ovs_list zone_limits
= OVS_LIST_INITIALIZER(&zone_limits
);
2129 error
= opt_dpif_open(argc
, argv
, dpctl_p
, 3, &dpif
);
2134 error
= parse_ct_limit_zones(argv
[i
], &zone_limits
, &ds
);
2139 error
= ct_dpif_del_limits(dpif
, &zone_limits
);
2143 ds_put_cstr(&ds
, "failed to delete conntrack limit");
2147 dpctl_error(dpctl_p
, error
, "%s", ds_cstr(&ds
));
2150 ct_dpif_free_zone_limits(&zone_limits
);
2156 dpctl_ct_get_limits(int argc
, const char *argv
[],
2157 struct dpctl_params
*dpctl_p
)
2160 struct ds ds
= DS_EMPTY_INITIALIZER
;
2161 uint32_t default_limit
;
2162 int i
= dp_arg_exists(argc
, argv
) ? 2 : 1;
2163 struct ovs_list list_query
= OVS_LIST_INITIALIZER(&list_query
);
2164 struct ovs_list list_reply
= OVS_LIST_INITIALIZER(&list_reply
);
2166 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, 3, &dpif
);
2172 error
= parse_ct_limit_zones(argv
[i
], &list_query
, &ds
);
2178 error
= ct_dpif_get_limits(dpif
, &default_limit
, &list_query
,
2181 ct_dpif_format_zone_limits(default_limit
, &list_reply
, &ds
);
2182 dpctl_print(dpctl_p
, "%s\n", ds_cstr(&ds
));
2185 ds_put_format(&ds
, "failed to get conntrack limit %s",
2186 ovs_strerror(error
));
2190 dpctl_error(dpctl_p
, error
, "%s", ds_cstr(&ds
));
2193 ct_dpif_free_zone_limits(&list_query
);
2194 ct_dpif_free_zone_limits(&list_reply
);
2200 ipf_set_enabled__(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
,
2204 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, 4, &dpif
);
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
);
2212 dpctl_print(dpctl_p
,
2213 "%s fragmentation reassembly successful",
2214 enabled
? "enabling" : "disabling");
2216 dpctl_error(dpctl_p
, error
,
2217 "%s fragmentation reassembly failed",
2218 enabled
? "enabling" : "disabling");
2222 dpctl_error(dpctl_p
, error
,
2223 "parameter missing: 'v4' for IPv4 or 'v6' for IPv6");
2231 dpctl_ipf_set_enabled(int argc
, const char *argv
[],
2232 struct dpctl_params
*dpctl_p
)
2234 return ipf_set_enabled__(argc
, argv
, dpctl_p
, true);
2238 dpctl_ipf_set_disabled(int argc
, const char *argv
[],
2239 struct dpctl_params
*dpctl_p
)
2241 return ipf_set_enabled__(argc
, argv
, dpctl_p
, false);
2245 dpctl_ipf_set_min_frag(int argc
, const char *argv
[],
2246 struct dpctl_params
*dpctl_p
)
2249 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, 4, &dpif
);
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
);
2259 dpctl_print(dpctl_p
,
2260 "setting minimum fragment size successful");
2262 dpctl_error(dpctl_p
, error
,
2263 "requested minimum fragment size too small;"
2264 " see documentation");
2268 dpctl_error(dpctl_p
, error
,
2269 "parameter missing for minimum fragment size");
2273 dpctl_error(dpctl_p
, error
,
2274 "parameter missing: v4 for IPv4 or v6 for IPv6");
2283 dpctl_ipf_set_max_nfrags(int argc
, const char *argv
[],
2284 struct dpctl_params
*dpctl_p
)
2287 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, 3, &dpif
);
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
);
2293 dpctl_print(dpctl_p
,
2294 "setting maximum fragments successful");
2296 dpctl_error(dpctl_p
, error
,
2297 "setting maximum fragments failed");
2301 dpctl_error(dpctl_p
, error
,
2302 "parameter missing for maximum fragments");
2311 dpctl_dump_ipf(struct dpif
*dpif
, struct dpctl_params
*dpctl_p
)
2313 struct ipf_dump_ctx
*dump_ctx
;
2316 int error
= ct_dpif_ipf_dump_start(dpif
, &dump_ctx
);
2318 dpctl_error(dpctl_p
, error
, "starting ipf list dump");
2319 /* Nothing to clean up, just return. */
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
);
2329 if (error
&& error
!= EOF
) {
2330 dpctl_error(dpctl_p
, error
, "dumping ipf lists failed");
2333 ct_dpif_ipf_dump_done(dpif
, dump_ctx
);
2337 dpctl_ct_ipf_get_status(int argc
, const char *argv
[],
2338 struct dpctl_params
*dpctl_p
)
2341 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, 2, &dpif
);
2344 struct dpif_ipf_status dpif_ipf_status
;
2345 error
= ct_dpif_ipf_get_status(dpif
, &dpif_ipf_status
);
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
);
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
);
2388 dpctl_error(dpctl_p
, error
,
2389 "ipf status could not be retrieved");
2393 if (dpctl_p
->verbosity
) {
2394 dpctl_dump_ipf(dpif
, dpctl_p
);
2403 /* Undocumented commands for unit testing. */
2406 dpctl_parse_actions(int argc
, const char *argv
[], struct dpctl_params
* dpctl_p
)
2410 for (i
= 1; i
< argc
; i
++) {
2411 struct ofpbuf actions
;
2414 ofpbuf_init(&actions
, 0);
2415 error
= odp_actions_from_string(argv
[i
], NULL
, &actions
);
2418 ofpbuf_uninit(&actions
);
2419 dpctl_error(dpctl_p
, error
, "odp_actions_from_string");
2424 format_odp_actions(&s
, actions
.data
, actions
.size
, NULL
);
2425 dpctl_print(dpctl_p
, "%s\n", ds_cstr(&s
));
2428 ofpbuf_uninit(&actions
);
2434 struct actions_for_flow
{
2435 struct hmap_node hmap_node
;
2437 struct ofpbuf actions
;
2440 static struct actions_for_flow
*
2441 get_actions_for_flow(struct hmap
*actions_per_flow
, const struct flow
*flow
)
2443 uint32_t hash
= flow_hash(flow
, 0);
2444 struct actions_for_flow
*af
;
2446 HMAP_FOR_EACH_WITH_HASH (af
, hmap_node
, hash
, actions_per_flow
) {
2447 if (flow_equal(&af
->flow
, flow
)) {
2452 af
= xmalloc(sizeof *af
);
2454 ofpbuf_init(&af
->actions
, 0);
2455 hmap_insert(actions_per_flow
, &af
->hmap_node
, hash
);
2460 compare_actions_for_flow(const void *a_
, const void *b_
)
2462 struct actions_for_flow
*const *a
= a_
;
2463 struct actions_for_flow
*const *b
= b_
;
2465 return flow_compare_3way(&(*a
)->flow
, &(*b
)->flow
);
2469 compare_output_actions(const void *a_
, const void *b_
)
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
);
2476 return a_port
< b_port
? -1 : a_port
> b_port
;
2480 sort_output_actions__(struct nlattr
*first
, struct nlattr
*end
)
2482 size_t bytes
= (uint8_t *) end
- (uint8_t *) first
;
2483 size_t n
= bytes
/ NL_A_U32_SIZE
;
2485 ovs_assert(bytes
% NL_A_U32_SIZE
== 0);
2486 qsort(first
, n
, NL_A_U32_SIZE
, compare_output_actions
);
2490 sort_output_actions(struct nlattr
*actions
, size_t length
)
2492 struct nlattr
*first_output
= NULL
;
2496 NL_ATTR_FOR_EACH (a
, left
, actions
, length
) {
2497 if (nl_attr_type(a
) == OVS_ACTION_ATTR_OUTPUT
) {
2498 if (!first_output
) {
2503 sort_output_actions__(first_output
, a
);
2504 first_output
= NULL
;
2509 uint8_t *end
= (uint8_t *) actions
+ length
;
2510 sort_output_actions__(first_output
,
2511 ALIGNED_CAST(struct nlattr
*, end
));
2515 /* usage: "ovs-dpctl normalize-actions FLOW ACTIONS" where FLOW and ACTIONS
2516 * have the syntax used by "ovs-dpctl dump-flows".
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.
2523 * The idea here generalizes beyond VLANs (e.g. to setting other fields) but
2524 * so far the implementation only covers VLANs. */
2526 dpctl_normalize_actions(int argc
, const char *argv
[],
2527 struct dpctl_params
*dpctl_p
)
2529 struct simap port_names
;
2530 struct ofpbuf keybuf
;
2532 struct ofpbuf odp_actions
;
2533 struct hmap actions_per_flow
;
2534 struct actions_for_flow
**afs
;
2535 struct actions_for_flow
*af
;
2545 simap_init(&port_names
);
2546 for (i
= 3; i
< argc
; i
++) {
2550 if (ovs_scan(argv
[i
], "%15[^=]=%d", name
, &number
)) {
2551 uintptr_t n
= number
;
2552 simap_put(&port_names
, name
, n
);
2554 dpctl_error(dpctl_p
, 0, "%s: expected NAME=NUMBER", argv
[i
]);
2560 /* Parse flow key. */
2561 ofpbuf_init(&keybuf
, 0);
2563 error
= odp_flow_from_string(argv
[1], &port_names
, &keybuf
, NULL
,
2566 dpctl_error(dpctl_p
, error
, "odp_flow_key_from_string (%s)", error_s
);
2568 goto out_freekeybuf
;
2572 odp_flow_format(keybuf
.data
, keybuf
.size
, NULL
, 0, NULL
,
2573 &s
, dpctl_p
->verbosity
);
2574 dpctl_print(dpctl_p
, "input flow: %s\n", ds_cstr(&s
));
2576 error
= odp_flow_key_to_flow(keybuf
.data
, keybuf
.size
, &flow
, &error_s
);
2578 dpctl_error(dpctl_p
, error
, "odp_flow_key_to_flow failed (%s)",
2579 error_s
? error_s
: "reason unknown");
2581 goto out_freekeybuf
;
2584 /* Parse actions. */
2585 ofpbuf_init(&odp_actions
, 0);
2586 error
= odp_actions_from_string(argv
[2], &port_names
, &odp_actions
);
2588 dpctl_error(dpctl_p
, error
, "odp_actions_from_string");
2589 goto out_freeactions
;
2592 if (dpctl_p
->verbosity
) {
2594 format_odp_actions(&s
, odp_actions
.data
, odp_actions
.size
, NULL
);
2595 dpctl_print(dpctl_p
, "input actions: %s\n", ds_cstr(&s
));
2598 hmap_init(&actions_per_flow
);
2599 NL_ATTR_FOR_EACH (a
, left
, odp_actions
.data
, odp_actions
.size
) {
2600 const struct ovs_action_push_vlan
*push
;
2601 switch(nl_attr_type(a
)) {
2602 case OVS_ACTION_ATTR_POP_VLAN
:
2603 flow_pop_vlan(&flow
, NULL
);
2606 case OVS_ACTION_ATTR_PUSH_VLAN
:
2607 flow_push_vlan_uninit(&flow
, NULL
);
2608 push
= nl_attr_get_unspec(a
, sizeof *push
);
2609 flow
.vlans
[0].tpid
= push
->vlan_tpid
;
2610 flow
.vlans
[0].tci
= push
->vlan_tci
;
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
));
2619 n_afs
= hmap_count(&actions_per_flow
);
2620 afs
= xmalloc(n_afs
* sizeof *afs
);
2622 HMAP_FOR_EACH (af
, hmap_node
, &actions_per_flow
) {
2626 ovs_assert(i
== n_afs
);
2627 hmap_destroy(&actions_per_flow
);
2629 qsort(afs
, n_afs
, sizeof *afs
, compare_actions_for_flow
);
2631 for (i
= 0; i
< n_afs
; i
++) {
2633 sort_output_actions(af
->actions
.data
, af
->actions
.size
);
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
);
2642 dpctl_print(dpctl_p
, "vid=%"PRIu16
",pcp=%d): ",
2643 vlan_tci_to_vid(vlan
->tci
),
2644 vlan_tci_to_pcp(vlan
->tci
));
2647 dpctl_print(dpctl_p
, "no vlan: ");
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]));
2659 dpctl_print(dpctl_p
, "no mpls: ");
2663 format_odp_actions(&s
, af
->actions
.data
, af
->actions
.size
, NULL
);
2664 dpctl_puts(dpctl_p
, false, ds_cstr(&s
));
2666 ofpbuf_uninit(&af
->actions
);
2673 ofpbuf_uninit(&odp_actions
);
2675 ofpbuf_uninit(&keybuf
);
2677 simap_destroy(&port_names
);
2683 static const struct dpctl_command all_commands
[] = {
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
},
2689 { "dump-dps", "", 0, 0, dpctl_dump_dps
, DP_RO
},
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
},
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
},
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
},
2700 { "dump-conntrack", "[-m] [-s] [dp] [zone=N]",
2701 0, 4, dpctl_dump_conntrack
, DP_RO
},
2702 { "flush-conntrack", "[dp] [zone=N] [ct-tuple]", 0, 3,
2703 dpctl_flush_conntrack
, DP_RW
},
2704 { "ct-stats-show", "[dp] [zone=N]",
2705 0, 3, dpctl_ct_stats_show
, DP_RO
},
2706 { "ct-bkts", "[dp] [gt=N]", 0, 2, dpctl_ct_bkts
, DP_RO
},
2707 { "ct-set-maxconns", "[dp] maxconns", 1, 2, dpctl_ct_set_maxconns
,
2709 { "ct-get-maxconns", "[dp]", 0, 1, dpctl_ct_get_maxconns
, DP_RO
},
2710 { "ct-get-nconns", "[dp]", 0, 1, dpctl_ct_get_nconns
, DP_RO
},
2711 { "ct-enable-tcp-seq-chk", "[dp]", 0, 1, dpctl_ct_enable_tcp_seq_chk
,
2713 { "ct-disable-tcp-seq-chk", "[dp]", 0, 1, dpctl_ct_disable_tcp_seq_chk
,
2715 { "ct-get-tcp-seq-chk", "[dp]", 0, 1, dpctl_ct_get_tcp_seq_chk
, DP_RO
},
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
,
2720 { "ct-get-limits", "[dp] [zone=N1[,N2]...]", 0, 2, dpctl_ct_get_limits
,
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
,
2730 { "help", "", 0, INT_MAX
, dpctl_help
, DP_RO
},
2731 { "list-commands", "", 0, INT_MAX
, dpctl_list_commands
, DP_RO
},
2733 /* Undocumented commands for testing. */
2734 { "parse-actions", "actions", 1, INT_MAX
, dpctl_parse_actions
, DP_RO
},
2735 { "normalize-actions", "actions",
2736 2, INT_MAX
, dpctl_normalize_actions
, DP_RO
},
2738 { NULL
, NULL
, 0, 0, NULL
, DP_RO
},
2741 static const struct dpctl_command
*get_all_dpctl_commands(void)
2743 return all_commands
;
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
2750 dpctl_run_command(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
2752 const struct dpctl_command
*p
;
2754 dpctl_error(dpctl_p
, 0, "missing command name; use --help for help");
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
);
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
);
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",
2778 return p
->handler(argc
, argv
, dpctl_p
);
2783 dpctl_error(dpctl_p
, 0, "unknown command '%s'; use --help for help",
2789 dpctl_unixctl_print(void *userdata
, bool error OVS_UNUSED
, const char *msg
)
2791 struct ds
*ds
= userdata
;
2792 ds_put_cstr(ds
, msg
);
2796 dpctl_unixctl_handler(struct unixctl_conn
*conn
, int argc
, const char *argv
[],
2799 struct ds ds
= DS_EMPTY_INITIALIZER
;
2802 struct dpctl_params dpctl_p
= {
2804 .output
= dpctl_unixctl_print
,
2808 /* Parse options (like getopt). Unfortunately it does
2809 * not seem a good idea to call getopt_long() here, since it uses global
2811 bool set_names
= false;
2812 while (argc
> 1 && !error
) {
2813 const char *arg
= argv
[1];
2814 if (!strncmp(arg
, "--", 2)) {
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
++;
2824 } else if (!strcmp(arg
, "--names")) {
2825 dpctl_p
.names
= true;
2827 } else if (!strcmp(arg
, "--no-names")) {
2828 dpctl_p
.names
= false;
2831 ds_put_format(&ds
, "Unrecognized option %s", argv
[1]);
2834 } else if (arg
[0] == '-' && arg
[1] != '\0') {
2835 /* Short option[s] */
2836 const char *opt
= &arg
[1];
2838 while (*opt
&& !error
) {
2841 dpctl_p
.verbosity
++;
2844 dpctl_p
.print_statistics
= true;
2847 ds_put_format(&ds
, "Unrecognized option -%c", *opt
);
2854 /* Doesn't start with -, not an option */
2865 dpctl_p
.names
= dpctl_p
.verbosity
> 0;
2869 dpctl_command_handler
*handler
= (dpctl_command_handler
*) aux
;
2870 error
= handler(argc
, argv
, &dpctl_p
) != 0;
2874 unixctl_command_reply_error(conn
, ds_cstr(&ds
));
2876 unixctl_command_reply(conn
, ds_cstr(&ds
));
2883 dpctl_unixctl_register(void)
2885 const struct dpctl_command
*p
;
2887 for (p
= all_commands
; p
->name
!= NULL
; p
++) {
2888 if (strcmp(p
->name
, "help")) {
2889 char *cmd_name
= xasprintf("dpctl/%s", p
->name
);
2890 unixctl_command_register(cmd_name
,
2894 dpctl_unixctl_handler
,