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"
54 #include "openvswitch/vlog.h"
55 VLOG_DEFINE_THIS_MODULE(dpctl
);
57 typedef int dpctl_command_handler(int argc
, const char *argv
[],
58 struct dpctl_params
*);
59 struct dpctl_command
{
64 dpctl_command_handler
*handler
;
65 enum { DP_RO
, DP_RW
} mode
;
67 static const struct dpctl_command
*get_all_dpctl_commands(void);
68 static void dpctl_print(struct dpctl_params
*dpctl_p
, const char *fmt
, ...)
69 OVS_PRINTF_FORMAT(2, 3);
70 static void dpctl_error(struct dpctl_params
* dpctl_p
, int err_no
,
72 OVS_PRINTF_FORMAT(3, 4);
75 dpctl_puts(struct dpctl_params
*dpctl_p
, bool error
, const char *string
)
77 dpctl_p
->output(dpctl_p
->aux
, error
, string
);
81 dpctl_print(struct dpctl_params
*dpctl_p
, const char *fmt
, ...)
87 string
= xvasprintf(fmt
, args
);
90 dpctl_puts(dpctl_p
, false, string
);
95 dpctl_error(struct dpctl_params
* dpctl_p
, int err_no
, const char *fmt
, ...)
97 const char *subprogram_name
= get_subprogram_name();
98 struct ds ds
= DS_EMPTY_INITIALIZER
;
99 int save_errno
= errno
;
103 if (subprogram_name
[0]) {
104 ds_put_format(&ds
, "%s(%s): ", program_name
,subprogram_name
);
106 ds_put_format(&ds
, "%s: ", program_name
);
110 ds_put_format_valist(&ds
, fmt
, args
);
114 ds_put_format(&ds
, " (%s)", ovs_retval_to_string(err_no
));
116 ds_put_cstr(&ds
, "\n");
118 dpctl_puts(dpctl_p
, true, ds_cstr(&ds
));
125 static int dpctl_add_if(int argc
, const char *argv
[], struct dpctl_params
*);
128 if_up(struct netdev
*netdev
)
130 return netdev_turn_flags_on(netdev
, NETDEV_UP
, NULL
);
133 /* Retrieve the name of the datapath if exactly one exists. The caller
134 * is responsible for freeing the returned string. If a single datapath
135 * name cannot be determined, returns NULL. */
137 get_one_dp(struct dpctl_params
*dpctl_p
)
141 char *dp_name
= NULL
;
145 dp_enumerate_types(&types
);
146 SSET_FOR_EACH (type
, &types
) {
150 if (!dp_enumerate_names(type
, &names
)) {
151 count
+= sset_count(&names
);
152 if (!dp_name
&& count
== 1) {
153 dp_name
= xasprintf("%s@%s", type
, SSET_FIRST(&names
));
156 sset_destroy(&names
);
158 sset_destroy(&types
);
161 dpctl_error(dpctl_p
, 0, "no datapaths exist");
162 } else if (count
> 1) {
163 dpctl_error(dpctl_p
, 0, "multiple datapaths, specify one");
172 parsed_dpif_open(const char *arg_
, bool create
, struct dpif
**dpifp
)
177 dp_parse_name(arg_
, &name
, &type
);
180 result
= dpif_create(name
, type
, dpifp
);
182 result
= dpif_open(name
, type
, dpifp
);
191 dp_exists(const char *queried_dp
)
193 char *queried_name
, *queried_type
;
194 dp_parse_name(queried_dp
, &queried_name
, &queried_type
);
195 struct sset dpif_names
= SSET_INITIALIZER(&dpif_names
),
196 dpif_types
= SSET_INITIALIZER(&dpif_types
);
197 dp_enumerate_types(&dpif_types
);
199 bool found
= (sset_contains(&dpif_types
, queried_type
) &&
200 !dp_enumerate_names(queried_type
, &dpif_names
) &&
201 sset_contains(&dpif_names
, queried_name
));
203 sset_destroy(&dpif_names
);
204 sset_destroy(&dpif_types
);
211 dp_arg_exists(int argc
, const char *argv
[])
213 return argc
> 1 && dp_exists(argv
[1]);
216 /* Open a dpif with an optional name argument.
218 * The datapath name is not a mandatory parameter for this command. If it is
219 * not specified, we retrieve it from the current setup, assuming only one
220 * exists. On success stores the opened dpif in '*dpifp'. */
222 opt_dpif_open(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
,
223 int max_args
, struct dpif
**dpifp
)
227 if (dp_arg_exists(argc
, argv
)) {
228 dpname
= xstrdup(argv
[1]);
229 } else if (argc
!= max_args
) {
230 dpname
= get_one_dp(dpctl_p
);
232 /* If the arguments are the maximum possible number and there is no
233 * valid datapath argument, then we fall into the case of dpname is
234 * NULL, since this is an error. */
241 dpctl_error(dpctl_p
, error
, "datapath not found");
243 error
= parsed_dpif_open(dpname
, false, dpifp
);
246 dpctl_error(dpctl_p
, error
, "opening datapath");
253 dpctl_add_dp(int argc
, const char *argv
[],
254 struct dpctl_params
*dpctl_p
)
259 error
= parsed_dpif_open(argv
[1], true, &dpif
);
261 dpctl_error(dpctl_p
, error
, "add_dp");
266 error
= dpctl_add_if(argc
, argv
, dpctl_p
);
272 dpctl_del_dp(int argc OVS_UNUSED
, const char *argv
[],
273 struct dpctl_params
*dpctl_p
)
278 error
= parsed_dpif_open(argv
[1], false, &dpif
);
280 dpctl_error(dpctl_p
, error
, "opening datapath");
283 error
= dpif_delete(dpif
);
285 dpctl_error(dpctl_p
, error
, "del_dp");
293 dpctl_add_if(int argc OVS_UNUSED
, const char *argv
[],
294 struct dpctl_params
*dpctl_p
)
297 int i
, error
, lasterror
= 0;
299 error
= parsed_dpif_open(argv
[1], false, &dpif
);
301 dpctl_error(dpctl_p
, error
, "opening datapath");
304 for (i
= 2; i
< argc
; i
++) {
305 const char *name
, *type
;
306 char *save_ptr
= NULL
, *argcopy
;
307 struct netdev
*netdev
= NULL
;
309 odp_port_t port_no
= ODPP_NONE
;
312 argcopy
= xstrdup(argv
[i
]);
313 name
= strtok_r(argcopy
, ",", &save_ptr
);
317 dpctl_error(dpctl_p
, 0, "%s is not a valid network device name",
324 while ((option
= strtok_r(NULL
, ",", &save_ptr
)) != NULL
) {
325 char *save_ptr_2
= NULL
;
328 key
= strtok_r(option
, "=", &save_ptr_2
);
329 value
= strtok_r(NULL
, "", &save_ptr_2
);
334 if (!strcmp(key
, "type")) {
336 } else if (!strcmp(key
, "port_no")) {
337 port_no
= u32_to_odp(atoi(value
));
338 } else if (!smap_add_once(&args
, key
, value
)) {
339 dpctl_error(dpctl_p
, 0, "duplicate \"%s\" option", key
);
343 error
= netdev_open(name
, type
, &netdev
);
345 dpctl_error(dpctl_p
, error
, "%s: failed to open network device",
347 goto next_destroy_args
;
350 error
= netdev_set_config(netdev
, &args
, NULL
);
352 goto next_destroy_args
;
355 error
= dpif_port_add(dpif
, netdev
, &port_no
);
357 dpctl_error(dpctl_p
, error
, "adding %s to %s failed", name
,
359 goto next_destroy_args
;
362 error
= if_up(netdev
);
364 dpctl_error(dpctl_p
, error
, "%s: failed bringing interface up",
369 netdev_close(netdev
);
383 dpctl_set_if(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
386 int i
, error
, lasterror
= 0;
388 error
= parsed_dpif_open(argv
[1], false, &dpif
);
390 dpctl_error(dpctl_p
, error
, "opening datapath");
393 for (i
= 2; i
< argc
; i
++) {
394 struct netdev
*netdev
= NULL
;
395 struct dpif_port dpif_port
;
396 char *save_ptr
= NULL
;
406 argcopy
= xstrdup(argv
[i
]);
407 name
= strtok_r(argcopy
, ",", &save_ptr
);
409 dpctl_error(dpctl_p
, 0, "%s is not a valid network device name",
414 /* Get the port's type from the datapath. */
415 error
= dpif_port_query_by_name(dpif
, name
, &dpif_port
);
417 dpctl_error(dpctl_p
, error
, "%s: failed to query port in %s", name
,
421 type
= xstrdup(dpif_port
.type
);
422 port_no
= dpif_port
.port_no
;
423 dpif_port_destroy(&dpif_port
);
425 /* Retrieve its existing configuration. */
426 error
= netdev_open(name
, type
, &netdev
);
428 dpctl_error(dpctl_p
, error
, "%s: failed to open network device",
434 error
= netdev_get_config(netdev
, &args
);
436 dpctl_error(dpctl_p
, error
, "%s: failed to fetch configuration",
438 goto next_destroy_args
;
441 /* Parse changes to configuration. */
442 while ((option
= strtok_r(NULL
, ",", &save_ptr
)) != NULL
) {
443 char *save_ptr_2
= NULL
;
446 key
= strtok_r(option
, "=", &save_ptr_2
);
447 value
= strtok_r(NULL
, "", &save_ptr_2
);
452 if (!strcmp(key
, "type")) {
453 if (strcmp(value
, type
)) {
454 dpctl_error(dpctl_p
, 0,
455 "%s: can't change type from %s to %s",
458 goto next_destroy_args
;
460 } else if (!strcmp(key
, "port_no")) {
461 if (port_no
!= u32_to_odp(atoi(value
))) {
462 dpctl_error(dpctl_p
, 0, "%s: can't change port number from"
463 " %"PRIu32
" to %d", name
, port_no
, atoi(value
));
465 goto next_destroy_args
;
467 } else if (value
[0] == '\0') {
468 smap_remove(&args
, key
);
470 smap_replace(&args
, key
, value
);
474 /* Update configuration. */
476 error
= netdev_set_config(netdev
, &args
, &err_s
);
477 if (err_s
|| error
) {
478 dpctl_error(dpctl_p
, error
, "%s",
479 err_s
? err_s
: "Error updating configuration");
483 goto next_destroy_args
;
489 netdev_close(netdev
);
502 get_port_number(struct dpif
*dpif
, const char *name
, odp_port_t
*port
,
503 struct dpctl_params
*dpctl_p
)
505 struct dpif_port dpif_port
;
507 if (!dpif_port_query_by_name(dpif
, name
, &dpif_port
)) {
508 *port
= dpif_port
.port_no
;
509 dpif_port_destroy(&dpif_port
);
512 dpctl_error(dpctl_p
, 0, "no port named %s", name
);
518 dpctl_del_if(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
521 int i
, error
, lasterror
= 0;
523 error
= parsed_dpif_open(argv
[1], false, &dpif
);
525 dpctl_error(dpctl_p
, error
, "opening datapath");
528 for (i
= 2; i
< argc
; i
++) {
529 const char *name
= argv
[i
];
532 if (!name
[strspn(name
, "0123456789")]) {
533 port
= u32_to_odp(atoi(name
));
534 } else if (!get_port_number(dpif
, name
, &port
, dpctl_p
)) {
539 error
= dpif_port_del(dpif
, port
, false);
541 dpctl_error(dpctl_p
, error
, "deleting port %s from %s failed",
551 print_stat(struct dpctl_params
*dpctl_p
, const char *leader
, uint64_t value
)
553 dpctl_print(dpctl_p
, "%s", leader
);
554 if (value
!= UINT64_MAX
) {
555 dpctl_print(dpctl_p
, "%"PRIu64
, value
);
557 dpctl_print(dpctl_p
, "?");
562 print_human_size(struct dpctl_params
*dpctl_p
, uint64_t value
)
564 if (value
== UINT64_MAX
) {
566 } else if (value
>= 1024ULL * 1024 * 1024 * 1024) {
567 dpctl_print(dpctl_p
, " (%.1f TiB)",
568 value
/ (1024.0 * 1024 * 1024 * 1024));
569 } else if (value
>= 1024ULL * 1024 * 1024) {
570 dpctl_print(dpctl_p
, " (%.1f GiB)", value
/ (1024.0 * 1024 * 1024));
571 } else if (value
>= 1024ULL * 1024) {
572 dpctl_print(dpctl_p
, " (%.1f MiB)", value
/ (1024.0 * 1024));
573 } else if (value
>= 1024) {
574 dpctl_print(dpctl_p
, " (%.1f KiB)", value
/ 1024.0);
578 /* qsort comparison function. */
580 compare_port_nos(const void *a_
, const void *b_
)
582 const odp_port_t
*ap
= a_
;
583 const odp_port_t
*bp
= b_
;
584 uint32_t a
= odp_to_u32(*ap
);
585 uint32_t b
= odp_to_u32(*bp
);
587 return a
< b
? -1 : a
> b
;
591 show_dpif(struct dpif
*dpif
, struct dpctl_params
*dpctl_p
)
593 struct dpif_port_dump dump
;
594 struct dpif_port dpif_port
;
595 struct dpif_dp_stats stats
;
596 struct netdev
*netdev
;
598 dpctl_print(dpctl_p
, "%s:\n", dpif_name(dpif
));
599 if (!dpif_get_dp_stats(dpif
, &stats
)) {
600 dpctl_print(dpctl_p
, " lookups: hit:%"PRIu64
" missed:%"PRIu64
601 " lost:%"PRIu64
"\n flows: %"PRIu64
"\n",
602 stats
.n_hit
, stats
.n_missed
, stats
.n_lost
, stats
.n_flows
);
603 if (stats
.n_masks
!= UINT32_MAX
) {
604 uint64_t n_pkts
= stats
.n_hit
+ stats
.n_missed
;
605 double avg
= n_pkts
? (double) stats
.n_mask_hit
/ n_pkts
: 0.0;
607 dpctl_print(dpctl_p
, " masks: hit:%"PRIu64
" total:%"PRIu32
609 stats
.n_mask_hit
, stats
.n_masks
, avg
);
613 odp_port_t
*port_nos
= NULL
;
614 size_t allocated_port_nos
= 0, n_port_nos
= 0;
615 DPIF_PORT_FOR_EACH (&dpif_port
, &dump
, dpif
) {
616 if (n_port_nos
>= allocated_port_nos
) {
617 port_nos
= x2nrealloc(port_nos
, &allocated_port_nos
,
621 port_nos
[n_port_nos
] = dpif_port
.port_no
;
626 qsort(port_nos
, n_port_nos
, sizeof *port_nos
, compare_port_nos
);
629 for (int i
= 0; i
< n_port_nos
; i
++) {
630 if (dpif_port_query_by_number(dpif
, port_nos
[i
], &dpif_port
)) {
634 dpctl_print(dpctl_p
, " port %u: %s",
635 dpif_port
.port_no
, dpif_port
.name
);
637 if (strcmp(dpif_port
.type
, "system")) {
640 dpctl_print(dpctl_p
, " (%s", dpif_port
.type
);
642 error
= netdev_open(dpif_port
.name
, dpif_port
.type
, &netdev
);
647 error
= netdev_get_config(netdev
, &config
);
649 const struct smap_node
**nodes
= smap_sort(&config
);
650 for (size_t j
= 0; j
< smap_count(&config
); j
++) {
651 const struct smap_node
*node
= nodes
[j
];
652 dpctl_print(dpctl_p
, "%c %s=%s", j
? ',' : ':',
653 node
->key
, node
->value
);
657 dpctl_print(dpctl_p
, ", could not retrieve configuration "
658 "(%s)", ovs_strerror(error
));
660 smap_destroy(&config
);
662 netdev_close(netdev
);
664 dpctl_print(dpctl_p
, ": open failed (%s)",
665 ovs_strerror(error
));
667 dpctl_print(dpctl_p
, ")");
669 dpctl_print(dpctl_p
, "\n");
671 if (dpctl_p
->print_statistics
) {
672 struct netdev_stats s
;
675 error
= netdev_open(dpif_port
.name
, dpif_port
.type
, &netdev
);
677 dpctl_print(dpctl_p
, ", open failed (%s)",
678 ovs_strerror(error
));
679 dpif_port_destroy(&dpif_port
);
682 error
= netdev_get_stats(netdev
, &s
);
684 netdev_close(netdev
);
685 print_stat(dpctl_p
, " RX packets:", s
.rx_packets
);
686 print_stat(dpctl_p
, " errors:", s
.rx_errors
);
687 print_stat(dpctl_p
, " dropped:", s
.rx_dropped
);
688 print_stat(dpctl_p
, " overruns:", s
.rx_over_errors
);
689 print_stat(dpctl_p
, " frame:", s
.rx_frame_errors
);
690 dpctl_print(dpctl_p
, "\n");
692 print_stat(dpctl_p
, " TX packets:", s
.tx_packets
);
693 print_stat(dpctl_p
, " errors:", s
.tx_errors
);
694 print_stat(dpctl_p
, " dropped:", s
.tx_dropped
);
695 print_stat(dpctl_p
, " aborted:", s
.tx_aborted_errors
);
696 print_stat(dpctl_p
, " carrier:", s
.tx_carrier_errors
);
697 dpctl_print(dpctl_p
, "\n");
699 print_stat(dpctl_p
, " collisions:", s
.collisions
);
700 dpctl_print(dpctl_p
, "\n");
702 print_stat(dpctl_p
, " RX bytes:", s
.rx_bytes
);
703 print_human_size(dpctl_p
, s
.rx_bytes
);
704 print_stat(dpctl_p
, " TX bytes:", s
.tx_bytes
);
705 print_human_size(dpctl_p
, s
.tx_bytes
);
706 dpctl_print(dpctl_p
, "\n");
708 dpctl_print(dpctl_p
, ", could not retrieve stats (%s)",
709 ovs_strerror(error
));
712 dpif_port_destroy(&dpif_port
);
718 typedef void (*dps_for_each_cb
)(struct dpif
*, struct dpctl_params
*);
721 dps_for_each(struct dpctl_params
*dpctl_p
, dps_for_each_cb cb
)
723 struct sset dpif_names
= SSET_INITIALIZER(&dpif_names
),
724 dpif_types
= SSET_INITIALIZER(&dpif_types
);
725 int error
, openerror
= 0, enumerror
= 0;
726 const char *type
, *name
;
727 bool at_least_one
= false;
729 dp_enumerate_types(&dpif_types
);
731 SSET_FOR_EACH (type
, &dpif_types
) {
732 error
= dp_enumerate_names(type
, &dpif_names
);
737 SSET_FOR_EACH (name
, &dpif_names
) {
741 error
= dpif_open(name
, type
, &dpif
);
747 dpctl_error(dpctl_p
, error
, "opening datapath %s failed",
753 sset_destroy(&dpif_names
);
754 sset_destroy(&dpif_types
);
756 /* If there has been an error while opening a datapath it should be
757 * reported. Otherwise, we want to ignore the errors generated by
758 * dp_enumerate_names() if at least one datapath has been discovered,
759 * because they're not interesting for the user. This happens, for
760 * example, if OVS is using a userspace datapath and the kernel module
765 return at_least_one
? 0 : enumerror
;
770 dpctl_show(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
772 int error
, lasterror
= 0;
775 for (i
= 1; i
< argc
; i
++) {
776 const char *name
= argv
[i
];
779 error
= parsed_dpif_open(name
, false, &dpif
);
781 show_dpif(dpif
, dpctl_p
);
784 dpctl_error(dpctl_p
, error
, "opening datapath %s failed",
790 lasterror
= dps_for_each(dpctl_p
, show_dpif
);
797 dump_cb(struct dpif
*dpif
, struct dpctl_params
*dpctl_p
)
799 dpctl_print(dpctl_p
, "%s\n", dpif_name(dpif
));
803 dpctl_dump_dps(int argc OVS_UNUSED
, const char *argv
[] OVS_UNUSED
,
804 struct dpctl_params
*dpctl_p
)
806 return dps_for_each(dpctl_p
, dump_cb
);
810 format_dpif_flow(struct ds
*ds
, const struct dpif_flow
*f
, struct hmap
*ports
,
811 struct dpctl_params
*dpctl_p
)
813 if (dpctl_p
->verbosity
&& f
->ufid_present
) {
814 odp_format_ufid(&f
->ufid
, ds
);
815 ds_put_cstr(ds
, ", ");
817 odp_flow_format(f
->key
, f
->key_len
, f
->mask
, f
->mask_len
, ports
, ds
,
819 ds_put_cstr(ds
, ", ");
821 dpif_flow_stats_format(&f
->stats
, ds
);
822 if (dpctl_p
->verbosity
&& f
->attrs
.offloaded
) {
823 ds_put_cstr(ds
, ", offloaded:yes");
825 if (dpctl_p
->verbosity
&& f
->attrs
.dp_layer
) {
826 ds_put_format(ds
, ", dp:%s", f
->attrs
.dp_layer
);
828 ds_put_cstr(ds
, ", actions:");
829 format_odp_actions(ds
, f
->actions
, f
->actions_len
, ports
);
840 enable_all_dump_types(struct dump_types
*dump_types
)
842 dump_types
->ovs
= true;
843 dump_types
->tc
= true;
844 dump_types
->offloaded
= true;
845 dump_types
->non_offloaded
= true;
849 populate_dump_types(char *types_list
, struct dump_types
*dump_types
,
850 struct dpctl_params
*dpctl_p
)
853 enable_all_dump_types(dump_types
);
859 while (types_list
&& types_list
[0] != '\0') {
860 current_type
= types_list
;
861 size_t type_len
= strcspn(current_type
, ",");
863 types_list
+= type_len
+ (types_list
[type_len
] != '\0');
864 current_type
[type_len
] = '\0';
866 if (!strcmp(current_type
, "ovs")) {
867 dump_types
->ovs
= true;
868 } else if (!strcmp(current_type
, "tc")) {
869 dump_types
->tc
= true;
870 } else if (!strcmp(current_type
, "offloaded")) {
871 dump_types
->offloaded
= true;
872 } else if (!strcmp(current_type
, "non-offloaded")) {
873 dump_types
->non_offloaded
= true;
874 } else if (!strcmp(current_type
, "all")) {
875 enable_all_dump_types(dump_types
);
877 dpctl_error(dpctl_p
, EINVAL
, "Failed to parse type (%s)",
886 determine_dpif_flow_dump_types(struct dump_types
*dump_types
,
887 struct dpif_flow_dump_types
*dpif_dump_types
)
889 dpif_dump_types
->ovs_flows
= dump_types
->ovs
|| dump_types
->non_offloaded
;
890 dpif_dump_types
->netdev_flows
= dump_types
->tc
|| dump_types
->offloaded
891 || dump_types
->non_offloaded
;
895 flow_passes_type_filter(const struct dpif_flow
*f
,
896 struct dump_types
*dump_types
)
898 if (dump_types
->ovs
&& !strcmp(f
->attrs
.dp_layer
, "ovs")) {
901 if (dump_types
->tc
&& !strcmp(f
->attrs
.dp_layer
, "tc")) {
904 if (dump_types
->offloaded
&& f
->attrs
.offloaded
) {
907 if (dump_types
->non_offloaded
&& !(f
->attrs
.offloaded
)) {
914 dpctl_get_portno_names(struct dpif
*dpif
, const struct dpctl_params
*dpctl_p
)
916 if (dpctl_p
->names
) {
917 struct hmap
*portno_names
= xmalloc(sizeof *portno_names
);
918 hmap_init(portno_names
);
920 struct dpif_port_dump port_dump
;
921 struct dpif_port dpif_port
;
922 DPIF_PORT_FOR_EACH (&dpif_port
, &port_dump
, dpif
) {
923 odp_portno_names_set(portno_names
, dpif_port
.port_no
,
934 dpctl_free_portno_names(struct hmap
*portno_names
)
937 odp_portno_names_destroy(portno_names
);
938 hmap_destroy(portno_names
);
944 dpctl_dump_flows(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
950 struct flow flow_filter
;
951 struct flow_wildcards wc_filter
;
952 char *types_list
= NULL
;
953 struct dump_types dump_types
;
954 struct dpif_flow_dump_types dpif_dump_types
;
956 struct dpif_flow_dump_thread
*flow_dump_thread
;
957 struct dpif_flow_dump
*flow_dump
;
959 int pmd_id
= PMD_ID_NULL
;
963 while (argc
> 1 && lastargc
!= argc
) {
965 if (!strncmp(argv
[argc
- 1], "filter=", 7) && !filter
) {
966 filter
= xstrdup(argv
[--argc
] + 7);
967 } else if (!strncmp(argv
[argc
- 1], "type=", 5) && !types_list
) {
968 types_list
= xstrdup(argv
[--argc
] + 5);
972 error
= opt_dpif_open(argc
, argv
, dpctl_p
, 2, &dpif
);
977 struct hmap
*portno_names
= dpctl_get_portno_names(dpif
, dpctl_p
);
980 struct ofputil_port_map port_map
;
981 ofputil_port_map_init(&port_map
);
983 struct dpif_port_dump port_dump
;
984 struct dpif_port dpif_port
;
985 DPIF_PORT_FOR_EACH (&dpif_port
, &port_dump
, dpif
) {
986 ofputil_port_map_put(&port_map
,
987 u16_to_ofp(odp_to_u32(dpif_port
.port_no
)),
990 char *err
= parse_ofp_exact_flow(&flow_filter
, &wc_filter
, NULL
,
992 ofputil_port_map_destroy(&port_map
);
994 dpctl_error(dpctl_p
, 0, "Failed to parse filter (%s)", err
);
1001 memset(&dump_types
, 0, sizeof dump_types
);
1002 error
= populate_dump_types(types_list
, &dump_types
, dpctl_p
);
1006 determine_dpif_flow_dump_types(&dump_types
, &dpif_dump_types
);
1008 /* Make sure that these values are different. PMD_ID_NULL means that the
1009 * pmd is unspecified (e.g. because the datapath doesn't have different
1010 * pmd threads), while NON_PMD_CORE_ID refers to every non pmd threads
1011 * in the userspace datapath */
1012 BUILD_ASSERT(PMD_ID_NULL
!= NON_PMD_CORE_ID
);
1015 memset(&f
, 0, sizeof f
);
1016 flow_dump
= dpif_flow_dump_create(dpif
, false, &dpif_dump_types
);
1017 flow_dump_thread
= dpif_flow_dump_thread_create(flow_dump
);
1018 while (dpif_flow_dump_next(flow_dump_thread
, &f
, 1)) {
1021 struct flow_wildcards wc
;
1022 struct match match
, match_filter
;
1023 struct minimatch minimatch
;
1025 odp_flow_key_to_flow(f
.key
, f
.key_len
, &flow
, NULL
);
1026 odp_flow_key_to_mask(f
.mask
, f
.mask_len
, &wc
, &flow
, NULL
);
1027 match_init(&match
, &flow
, &wc
);
1029 match_init(&match_filter
, &flow_filter
, &wc
);
1030 match_init(&match_filter
, &match_filter
.flow
, &wc_filter
);
1031 minimatch_init(&minimatch
, &match_filter
);
1033 if (!minimatch_matches_flow(&minimatch
, &match
.flow
)) {
1034 minimatch_destroy(&minimatch
);
1037 minimatch_destroy(&minimatch
);
1040 /* If 'pmd_id' is specified, overlapping flows could be dumped from
1041 * different pmd threads. So, separates dumps from different pmds
1042 * by printing a title line. */
1043 if (pmd_id
!= f
.pmd_id
) {
1044 if (f
.pmd_id
== NON_PMD_CORE_ID
) {
1045 ds_put_format(&ds
, "flow-dump from non-dpdk interfaces:\n");
1047 ds_put_format(&ds
, "flow-dump from pmd on cpu core: %d\n",
1052 if (flow_passes_type_filter(&f
, &dump_types
)) {
1053 format_dpif_flow(&ds
, &f
, portno_names
, dpctl_p
);
1054 dpctl_print(dpctl_p
, "%s\n", ds_cstr(&ds
));
1057 dpif_flow_dump_thread_destroy(flow_dump_thread
);
1058 error
= dpif_flow_dump_destroy(flow_dump
);
1061 dpctl_error(dpctl_p
, error
, "Failed to dump flows from datapath");
1066 dpctl_free_portno_names(portno_names
);
1075 dpctl_put_flow(int argc
, const char *argv
[], enum dpif_flow_put_flags flags
,
1076 struct dpctl_params
*dpctl_p
)
1078 const char *key_s
= argv
[argc
- 2];
1079 const char *actions_s
= argv
[argc
- 1];
1080 struct dpif_flow_stats stats
;
1081 struct dpif_port dpif_port
;
1082 struct dpif_port_dump port_dump
;
1083 struct ofpbuf actions
;
1089 struct simap port_names
;
1092 error
= opt_dpif_open(argc
, argv
, dpctl_p
, 4, &dpif
);
1097 ufid_present
= false;
1098 n
= odp_ufid_from_string(key_s
, &ufid
);
1100 dpctl_error(dpctl_p
, -n
, "parsing flow ufid");
1104 ufid_present
= true;
1107 simap_init(&port_names
);
1108 DPIF_PORT_FOR_EACH (&dpif_port
, &port_dump
, dpif
) {
1109 simap_put(&port_names
, dpif_port
.name
, odp_to_u32(dpif_port
.port_no
));
1112 ofpbuf_init(&key
, 0);
1113 ofpbuf_init(&mask
, 0);
1115 error
= odp_flow_from_string(key_s
, &port_names
, &key
, &mask
, &error_s
);
1116 simap_destroy(&port_names
);
1118 dpctl_error(dpctl_p
, error
, "parsing flow key (%s)", error_s
);
1120 goto out_freekeymask
;
1123 ofpbuf_init(&actions
, 0);
1124 error
= odp_actions_from_string(actions_s
, NULL
, &actions
);
1126 dpctl_error(dpctl_p
, error
, "parsing actions");
1127 goto out_freeactions
;
1130 /* The flow will be added on all pmds currently in the datapath. */
1131 error
= dpif_flow_put(dpif
, flags
,
1133 mask
.size
== 0 ? NULL
: mask
.data
,
1134 mask
.size
, actions
.data
,
1135 actions
.size
, ufid_present
? &ufid
: NULL
,
1137 dpctl_p
->print_statistics
? &stats
: NULL
);
1140 dpctl_error(dpctl_p
, error
, "updating flow table");
1141 goto out_freeactions
;
1144 if (dpctl_p
->print_statistics
) {
1148 dpif_flow_stats_format(&stats
, &s
);
1149 dpctl_print(dpctl_p
, "%s\n", ds_cstr(&s
));
1154 ofpbuf_uninit(&actions
);
1156 ofpbuf_uninit(&mask
);
1157 ofpbuf_uninit(&key
);
1163 dpctl_add_flow(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
1165 return dpctl_put_flow(argc
, argv
, DPIF_FP_CREATE
, dpctl_p
);
1169 dpctl_mod_flow(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
1171 enum dpif_flow_put_flags flags
;
1173 flags
= DPIF_FP_MODIFY
;
1174 if (dpctl_p
->may_create
) {
1175 flags
|= DPIF_FP_CREATE
;
1177 if (dpctl_p
->zero_statistics
) {
1178 flags
|= DPIF_FP_ZERO_STATS
;
1181 return dpctl_put_flow(argc
, argv
, flags
, dpctl_p
);
1185 dpctl_get_flow(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
1187 const char *key_s
= argv
[argc
- 1];
1188 struct dpif_flow flow
;
1192 uint64_t stub
[DPIF_FLOW_BUFSIZE
/ 8];
1196 error
= opt_dpif_open(argc
, argv
, dpctl_p
, 3, &dpif
);
1201 ofpbuf_use_stub(&buf
, &stub
, sizeof stub
);
1203 struct hmap
*portno_names
= dpctl_get_portno_names(dpif
, dpctl_p
);
1205 n
= odp_ufid_from_string(key_s
, &ufid
);
1207 dpctl_error(dpctl_p
, -n
, "parsing flow ufid");
1211 /* In case of PMD will be returned flow from first PMD thread with match. */
1212 error
= dpif_flow_get(dpif
, NULL
, 0, &ufid
, PMD_ID_NULL
, &buf
, &flow
);
1214 dpctl_error(dpctl_p
, error
, "getting flow");
1219 format_dpif_flow(&ds
, &flow
, portno_names
, dpctl_p
);
1220 dpctl_print(dpctl_p
, "%s\n", ds_cstr(&ds
));
1224 dpctl_free_portno_names(portno_names
);
1225 ofpbuf_uninit(&buf
);
1231 dpctl_del_flow(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
1233 const char *key_s
= argv
[argc
- 1];
1234 struct dpif_flow_stats stats
;
1235 struct dpif_port dpif_port
;
1236 struct dpif_port_dump port_dump
;
1238 struct ofpbuf mask
; /* To be ignored. */
1242 struct simap port_names
;
1245 error
= opt_dpif_open(argc
, argv
, dpctl_p
, 3, &dpif
);
1250 ufid_present
= false;
1251 n
= odp_ufid_from_string(key_s
, &ufid
);
1253 dpctl_error(dpctl_p
, -n
, "parsing flow ufid");
1257 ufid_present
= true;
1260 simap_init(&port_names
);
1261 DPIF_PORT_FOR_EACH (&dpif_port
, &port_dump
, dpif
) {
1262 simap_put(&port_names
, dpif_port
.name
, odp_to_u32(dpif_port
.port_no
));
1265 ofpbuf_init(&key
, 0);
1266 ofpbuf_init(&mask
, 0);
1269 error
= odp_flow_from_string(key_s
, &port_names
, &key
, &mask
, &error_s
);
1271 dpctl_error(dpctl_p
, error
, "%s", error_s
);
1276 /* The flow will be deleted from all pmds currently in the datapath. */
1277 error
= dpif_flow_del(dpif
, key
.data
, key
.size
,
1278 ufid_present
? &ufid
: NULL
, PMD_ID_NULL
,
1279 dpctl_p
->print_statistics
? &stats
: NULL
);
1282 dpctl_error(dpctl_p
, error
, "deleting flow");
1283 if (error
== ENOENT
&& !ufid_present
) {
1287 ds_put_format(&s
, "Perhaps you need to specify a UFID?");
1288 dpctl_print(dpctl_p
, "%s\n", ds_cstr(&s
));
1294 if (dpctl_p
->print_statistics
) {
1298 dpif_flow_stats_format(&stats
, &s
);
1299 dpctl_print(dpctl_p
, "%s\n", ds_cstr(&s
));
1304 ofpbuf_uninit(&mask
);
1305 ofpbuf_uninit(&key
);
1306 simap_destroy(&port_names
);
1312 dpctl_del_flows(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
1316 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, 2, &dpif
);
1321 error
= dpif_flow_flush(dpif
);
1323 dpctl_error(dpctl_p
, error
, "deleting all flows");
1330 dpctl_help(int argc OVS_UNUSED
, const char *argv
[] OVS_UNUSED
,
1331 struct dpctl_params
*dpctl_p
)
1333 if (dpctl_p
->usage
) {
1334 dpctl_p
->usage(dpctl_p
->aux
);
1341 dpctl_list_commands(int argc OVS_UNUSED
, const char *argv
[] OVS_UNUSED
,
1342 struct dpctl_params
*dpctl_p
)
1344 struct ds ds
= DS_EMPTY_INITIALIZER
;
1345 const struct dpctl_command
*commands
= get_all_dpctl_commands();
1347 ds_put_cstr(&ds
, "The available commands are:\n");
1348 for (; commands
->name
; commands
++) {
1349 const struct dpctl_command
*c
= commands
;
1351 ds_put_format(&ds
, " %s%-23s %s\n", dpctl_p
->is_appctl
? "dpctl/" : "",
1354 dpctl_puts(dpctl_p
, false, ds
.string
);
1362 dpctl_dump_conntrack(int argc
, const char *argv
[],
1363 struct dpctl_params
*dpctl_p
)
1365 struct ct_dpif_dump_state
*dump
;
1366 struct ct_dpif_entry cte
;
1367 uint16_t zone
, *pzone
= NULL
;
1372 if (argc
> 1 && ovs_scan(argv
[argc
- 1], "zone=%"SCNu16
, &zone
)) {
1377 error
= opt_dpif_open(argc
, argv
, dpctl_p
, 2, &dpif
);
1382 error
= ct_dpif_dump_start(dpif
, &dump
, pzone
, &tot_bkts
);
1384 dpctl_error(dpctl_p
, error
, "starting conntrack dump");
1389 while (!(error
= ct_dpif_dump_next(dump
, &cte
))) {
1390 struct ds s
= DS_EMPTY_INITIALIZER
;
1392 ct_dpif_format_entry(&cte
, &s
, dpctl_p
->verbosity
,
1393 dpctl_p
->print_statistics
);
1394 ct_dpif_entry_uninit(&cte
);
1396 dpctl_print(dpctl_p
, "%s\n", ds_cstr(&s
));
1400 /* Any CT entry was dumped with no issue. */
1403 dpctl_error(dpctl_p
, error
, "dumping conntrack entry");
1406 ct_dpif_dump_done(dump
);
1412 dpctl_flush_conntrack(int argc
, const char *argv
[],
1413 struct dpctl_params
*dpctl_p
)
1415 struct dpif
*dpif
= NULL
;
1416 struct ct_dpif_tuple tuple
, *ptuple
= NULL
;
1417 struct ds ds
= DS_EMPTY_INITIALIZER
;
1418 uint16_t zone
, *pzone
= NULL
;
1420 int args
= argc
- 1;
1422 /* Parse ct tuple */
1423 if (args
&& ct_dpif_parse_tuple(&tuple
, argv
[args
], &ds
)) {
1429 if (args
&& ovs_scan(argv
[args
], "zone=%"SCNu16
, &zone
)) {
1434 /* Report error if there are more than one unparsed argument. */
1436 ds_put_cstr(&ds
, "invalid arguments");
1441 error
= opt_dpif_open(argc
, argv
, dpctl_p
, 4, &dpif
);
1446 error
= ct_dpif_flush(dpif
, pzone
, ptuple
);
1451 ds_put_cstr(&ds
, "failed to flush conntrack");
1455 dpctl_error(dpctl_p
, error
, "%s", ds_cstr(&ds
));
1462 dpctl_ct_stats_show(int argc
, const char *argv
[],
1463 struct dpctl_params
*dpctl_p
)
1466 struct ct_dpif_dump_state
*dump
;
1467 struct ct_dpif_entry cte
;
1468 uint16_t zone
, *pzone
= NULL
;
1472 int proto_stats
[CT_STATS_MAX
];
1473 int tcp_conn_per_states
[CT_DPIF_TCPS_MAX_NUM
];
1476 bool verbose
= dpctl_p
->verbosity
;
1478 while (argc
> 1 && lastargc
!= argc
) {
1480 if (!strncmp(argv
[argc
- 1], "verbose", 7)) {
1481 /* Support "verbose" argument for backwards compatibility. */
1484 } else if (!strncmp(argv
[argc
- 1], "zone=", 5)) {
1485 if (ovs_scan(argv
[argc
- 1], "zone=%"SCNu16
, &zone
)) {
1492 error
= opt_dpif_open(argc
, argv
, dpctl_p
, 2, &dpif
);
1497 memset(proto_stats
, 0, sizeof(proto_stats
));
1498 memset(tcp_conn_per_states
, 0, sizeof(tcp_conn_per_states
));
1499 error
= ct_dpif_dump_start(dpif
, &dump
, pzone
, &tot_bkts
);
1501 dpctl_error(dpctl_p
, error
, "starting conntrack dump");
1507 while (!(error
= ct_dpif_dump_next(dump
, &cte
))) {
1508 ct_dpif_entry_uninit(&cte
);
1510 switch (cte
.tuple_orig
.ip_proto
) {
1512 proto_stats
[CT_STATS_ICMP
]++;
1514 case IPPROTO_ICMPV6
:
1515 proto_stats
[CT_STATS_ICMPV6
]++;
1518 proto_stats
[CT_STATS_TCP
]++;
1520 /* We keep two separate tcp states, but we print just one. The
1521 * Linux kernel connection tracker internally keeps only one state,
1522 * so 'state_orig' and 'state_reply', will be the same. */
1523 tcp_state
= MAX(cte
.protoinfo
.tcp
.state_orig
,
1524 cte
.protoinfo
.tcp
.state_reply
);
1525 tcp_state
= ct_dpif_coalesce_tcp_state(tcp_state
);
1526 tcp_conn_per_states
[tcp_state
]++;
1529 proto_stats
[CT_STATS_UDP
]++;
1532 proto_stats
[CT_STATS_SCTP
]++;
1534 case IPPROTO_UDPLITE
:
1535 proto_stats
[CT_STATS_UDPLITE
]++;
1538 proto_stats
[CT_STATS_DCCP
]++;
1541 proto_stats
[CT_STATS_IGMP
]++;
1544 proto_stats
[CT_STATS_OTHER
]++;
1549 /* All CT entries were dumped with no issue. */
1552 dpctl_error(dpctl_p
, error
, "dumping conntrack entry");
1553 /* Fall through to show any other info we collected. */
1556 dpctl_print(dpctl_p
, "Connections Stats:\n Total: %d\n", tot_conn
);
1557 if (proto_stats
[CT_STATS_TCP
]) {
1558 dpctl_print(dpctl_p
, " TCP: %d\n", proto_stats
[CT_STATS_TCP
]);
1560 dpctl_print(dpctl_p
, " Conn per TCP states:\n");
1561 for (int i
= 0; i
< CT_DPIF_TCPS_MAX_NUM
; i
++) {
1562 if (tcp_conn_per_states
[i
]) {
1563 struct ds s
= DS_EMPTY_INITIALIZER
;
1564 ct_dpif_format_tcp_stat(&s
, i
, tcp_conn_per_states
[i
]);
1565 dpctl_print(dpctl_p
, "%s\n", ds_cstr(&s
));
1571 if (proto_stats
[CT_STATS_UDP
]) {
1572 dpctl_print(dpctl_p
, " UDP: %d\n", proto_stats
[CT_STATS_UDP
]);
1574 if (proto_stats
[CT_STATS_UDPLITE
]) {
1575 dpctl_print(dpctl_p
, " UDPLITE: %d\n", proto_stats
[CT_STATS_UDPLITE
]);
1577 if (proto_stats
[CT_STATS_SCTP
]) {
1578 dpctl_print(dpctl_p
, " SCTP: %d\n", proto_stats
[CT_STATS_SCTP
]);
1580 if (proto_stats
[CT_STATS_ICMP
]) {
1581 dpctl_print(dpctl_p
, " ICMP: %d\n", proto_stats
[CT_STATS_ICMP
]);
1583 if (proto_stats
[CT_STATS_DCCP
]) {
1584 dpctl_print(dpctl_p
, " DCCP: %d\n", proto_stats
[CT_STATS_DCCP
]);
1586 if (proto_stats
[CT_STATS_IGMP
]) {
1587 dpctl_print(dpctl_p
, " IGMP: %d\n", proto_stats
[CT_STATS_IGMP
]);
1589 if (proto_stats
[CT_STATS_OTHER
]) {
1590 dpctl_print(dpctl_p
, " Other: %d\n", proto_stats
[CT_STATS_OTHER
]);
1593 ct_dpif_dump_done(dump
);
1598 #define CT_BKTS_GT "gt="
1600 dpctl_ct_bkts(int argc
, const char *argv
[],
1601 struct dpctl_params
*dpctl_p
)
1604 struct ct_dpif_dump_state
*dump
;
1605 struct ct_dpif_entry cte
;
1606 uint16_t gt
= 0; /* Threshold: display value when greater than gt. */
1607 uint16_t *pzone
= NULL
;
1611 if (argc
> 1 && !strncmp(argv
[argc
- 1], CT_BKTS_GT
, strlen(CT_BKTS_GT
))) {
1612 if (ovs_scan(argv
[argc
- 1], CT_BKTS_GT
"%"SCNu16
, >
)) {
1617 error
= opt_dpif_open(argc
, argv
, dpctl_p
, 2, &dpif
);
1622 error
= ct_dpif_dump_start(dpif
, &dump
, pzone
, &tot_bkts
);
1624 dpctl_error(dpctl_p
, error
, "starting conntrack dump");
1628 if (tot_bkts
== -1) {
1629 /* Command not available when called by kernel OvS. */
1630 dpctl_print(dpctl_p
,
1631 "Command is available for UserSpace ConnTracker only.\n");
1632 ct_dpif_dump_done(dump
);
1637 dpctl_print(dpctl_p
, "Total Buckets: %d\n", tot_bkts
);
1640 uint32_t *conn_per_bkts
= xzalloc(tot_bkts
* sizeof(uint32_t));
1642 while (!(error
= ct_dpif_dump_next(dump
, &cte
))) {
1643 ct_dpif_entry_uninit(&cte
);
1646 if (cte
.bkt
< tot_bkts
) {
1647 conn_per_bkts
[cte
.bkt
]++;
1649 dpctl_print(dpctl_p
, "Bucket nr out of range: %d >= %d\n",
1655 /* All CT entries were dumped with no issue. */
1658 dpctl_error(dpctl_p
, error
, "dumping conntrack entry");
1659 /* Fall through and display all the collected info. */
1662 dpctl_print(dpctl_p
, "Current Connections: %d\n", tot_conn
);
1663 dpctl_print(dpctl_p
, "\n");
1664 if (tot_bkts
&& tot_conn
) {
1665 dpctl_print(dpctl_p
, "+-----------+"
1666 "-----------------------------------------+\n");
1667 dpctl_print(dpctl_p
, "| Buckets |"
1668 " Connections per Buckets |\n");
1669 dpctl_print(dpctl_p
, "+-----------+"
1670 "-----------------------------------------+");
1671 #define NUM_BKTS_DIPLAYED_PER_ROW 8
1672 for (int i
= 0; i
< tot_bkts
; i
++) {
1673 if (i
% NUM_BKTS_DIPLAYED_PER_ROW
== 0) {
1674 dpctl_print(dpctl_p
, "\n %3d..%3d | ",
1675 i
, i
+ NUM_BKTS_DIPLAYED_PER_ROW
- 1);
1677 if (conn_per_bkts
[i
] > gt
) {
1678 dpctl_print(dpctl_p
, "%5d", conn_per_bkts
[i
]);
1680 dpctl_print(dpctl_p
, "%5s", ".");
1683 dpctl_print(dpctl_p
, "\n\n");
1686 ct_dpif_dump_done(dump
);
1688 free(conn_per_bkts
);
1693 dpctl_ct_set_maxconns(int argc
, const char *argv
[],
1694 struct dpctl_params
*dpctl_p
)
1697 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, 3, &dpif
);
1700 if (ovs_scan(argv
[argc
- 1], "%"SCNu32
, &maxconns
)) {
1701 error
= ct_dpif_set_maxconns(dpif
, maxconns
);
1704 dpctl_print(dpctl_p
, "setting maxconns successful");
1706 dpctl_error(dpctl_p
, error
, "ct set maxconns failed");
1710 dpctl_error(dpctl_p
, error
, "maxconns missing or malformed");
1719 dpctl_ct_get_maxconns(int argc
, const char *argv
[],
1720 struct dpctl_params
*dpctl_p
)
1723 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, 2, &dpif
);
1726 error
= ct_dpif_get_maxconns(dpif
, &maxconns
);
1729 dpctl_print(dpctl_p
, "%u\n", maxconns
);
1731 dpctl_error(dpctl_p
, error
, "maxconns could not be retrieved");
1740 dpctl_ct_get_nconns(int argc
, const char *argv
[],
1741 struct dpctl_params
*dpctl_p
)
1744 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, 2, &dpif
);
1747 error
= ct_dpif_get_nconns(dpif
, &nconns
);
1750 dpctl_print(dpctl_p
, "%u\n", nconns
);
1752 dpctl_error(dpctl_p
, error
, "nconns could not be retrieved");
1761 dpctl_ct_set_limits(int argc
, const char *argv
[],
1762 struct dpctl_params
*dpctl_p
)
1765 struct ds ds
= DS_EMPTY_INITIALIZER
;
1766 int i
= dp_arg_exists(argc
, argv
) ? 2 : 1;
1767 uint32_t default_limit
, *p_default_limit
= NULL
;
1768 struct ovs_list zone_limits
= OVS_LIST_INITIALIZER(&zone_limits
);
1770 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, INT_MAX
, &dpif
);
1775 /* Parse default limit */
1776 if (!strncmp(argv
[i
], "default=", 8)) {
1777 if (ovs_scan(argv
[i
], "default=%"SCNu32
, &default_limit
)) {
1778 p_default_limit
= &default_limit
;
1781 ds_put_cstr(&ds
, "invalid default limit");
1787 /* Parse ct zone limit tuples */
1791 if (!ct_dpif_parse_zone_limit_tuple(argv
[i
++], &zone
, &limit
, &ds
)) {
1795 ct_dpif_push_zone_limit(&zone_limits
, zone
, limit
, 0);
1798 error
= ct_dpif_set_limits(dpif
, p_default_limit
, &zone_limits
);
1800 ct_dpif_free_zone_limits(&zone_limits
);
1804 ds_put_cstr(&ds
, "failed to set conntrack limit");
1808 dpctl_error(dpctl_p
, error
, "%s", ds_cstr(&ds
));
1810 ct_dpif_free_zone_limits(&zone_limits
);
1816 parse_ct_limit_zones(const char *argv
, struct ovs_list
*zone_limits
,
1819 char *save_ptr
= NULL
, *argcopy
, *next_zone
;
1822 if (strncmp(argv
, "zone=", 5)) {
1823 ds_put_format(ds
, "invalid argument %s", argv
);
1827 argcopy
= xstrdup(argv
+ 5);
1828 next_zone
= strtok_r(argcopy
, ",", &save_ptr
);
1831 if (ovs_scan(next_zone
, "%"SCNu16
, &zone
)) {
1832 ct_dpif_push_zone_limit(zone_limits
, zone
, 0, 0);
1834 ds_put_cstr(ds
, "invalid zone");
1838 } while ((next_zone
= strtok_r(NULL
, ",", &save_ptr
)) != NULL
);
1845 dpctl_ct_del_limits(int argc
, const char *argv
[],
1846 struct dpctl_params
*dpctl_p
)
1849 struct ds ds
= DS_EMPTY_INITIALIZER
;
1851 int i
= dp_arg_exists(argc
, argv
) ? 2 : 1;
1852 struct ovs_list zone_limits
= OVS_LIST_INITIALIZER(&zone_limits
);
1854 error
= opt_dpif_open(argc
, argv
, dpctl_p
, 3, &dpif
);
1859 error
= parse_ct_limit_zones(argv
[i
], &zone_limits
, &ds
);
1864 error
= ct_dpif_del_limits(dpif
, &zone_limits
);
1868 ds_put_cstr(&ds
, "failed to delete conntrack limit");
1872 dpctl_error(dpctl_p
, error
, "%s", ds_cstr(&ds
));
1875 ct_dpif_free_zone_limits(&zone_limits
);
1881 dpctl_ct_get_limits(int argc
, const char *argv
[],
1882 struct dpctl_params
*dpctl_p
)
1885 struct ds ds
= DS_EMPTY_INITIALIZER
;
1886 uint32_t default_limit
;
1887 int i
= dp_arg_exists(argc
, argv
) ? 2 : 1;
1888 struct ovs_list list_query
= OVS_LIST_INITIALIZER(&list_query
);
1889 struct ovs_list list_reply
= OVS_LIST_INITIALIZER(&list_reply
);
1891 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, 3, &dpif
);
1897 error
= parse_ct_limit_zones(argv
[i
], &list_query
, &ds
);
1903 error
= ct_dpif_get_limits(dpif
, &default_limit
, &list_query
,
1906 ct_dpif_format_zone_limits(default_limit
, &list_reply
, &ds
);
1907 dpctl_print(dpctl_p
, "%s\n", ds_cstr(&ds
));
1910 ds_put_format(&ds
, "failed to get conntrack limit %s",
1911 ovs_strerror(error
));
1915 dpctl_error(dpctl_p
, error
, "%s", ds_cstr(&ds
));
1918 ct_dpif_free_zone_limits(&list_query
);
1919 ct_dpif_free_zone_limits(&list_reply
);
1925 ipf_set_enabled__(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
,
1929 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, 4, &dpif
);
1931 char v4_or_v6
[3] = {0};
1932 if (ovs_scan(argv
[argc
- 1], "%2s", v4_or_v6
) &&
1933 (!strncmp(v4_or_v6
, "v4", 2) || !strncmp(v4_or_v6
, "v6", 2))) {
1934 error
= ct_dpif_ipf_set_enabled(
1935 dpif
, !strncmp(v4_or_v6
, "v6", 2), enabled
);
1937 dpctl_print(dpctl_p
,
1938 "%s fragmentation reassembly successful",
1939 enabled
? "enabling" : "disabling");
1941 dpctl_error(dpctl_p
, error
,
1942 "%s fragmentation reassembly failed",
1943 enabled
? "enabling" : "disabling");
1947 dpctl_error(dpctl_p
, error
,
1948 "parameter missing: 'v4' for IPv4 or 'v6' for IPv6");
1956 dpctl_ipf_set_enabled(int argc
, const char *argv
[],
1957 struct dpctl_params
*dpctl_p
)
1959 return ipf_set_enabled__(argc
, argv
, dpctl_p
, true);
1963 dpctl_ipf_set_disabled(int argc
, const char *argv
[],
1964 struct dpctl_params
*dpctl_p
)
1966 return ipf_set_enabled__(argc
, argv
, dpctl_p
, false);
1970 dpctl_ipf_set_min_frag(int argc
, const char *argv
[],
1971 struct dpctl_params
*dpctl_p
)
1974 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, 4, &dpif
);
1976 char v4_or_v6
[3] = {0};
1977 if (ovs_scan(argv
[argc
- 2], "%2s", v4_or_v6
) &&
1978 (!strncmp(v4_or_v6
, "v4", 2) || !strncmp(v4_or_v6
, "v6", 2))) {
1979 uint32_t min_fragment
;
1980 if (ovs_scan(argv
[argc
- 1], "%"SCNu32
, &min_fragment
)) {
1981 error
= ct_dpif_ipf_set_min_frag(
1982 dpif
, !strncmp(v4_or_v6
, "v6", 2), min_fragment
);
1984 dpctl_print(dpctl_p
,
1985 "setting minimum fragment size successful");
1987 dpctl_error(dpctl_p
, error
,
1988 "requested minimum fragment size too small;"
1989 " see documentation");
1993 dpctl_error(dpctl_p
, error
,
1994 "parameter missing for minimum fragment size");
1998 dpctl_error(dpctl_p
, error
,
1999 "parameter missing: v4 for IPv4 or v6 for IPv6");
2008 dpctl_ipf_set_max_nfrags(int argc
, const char *argv
[],
2009 struct dpctl_params
*dpctl_p
)
2012 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, 3, &dpif
);
2014 uint32_t nfrags_max
;
2015 if (ovs_scan(argv
[argc
- 1], "%"SCNu32
, &nfrags_max
)) {
2016 error
= ct_dpif_ipf_set_max_nfrags(dpif
, nfrags_max
);
2018 dpctl_print(dpctl_p
,
2019 "setting maximum fragments successful");
2021 dpctl_error(dpctl_p
, error
,
2022 "setting maximum fragments failed");
2026 dpctl_error(dpctl_p
, error
,
2027 "parameter missing for maximum fragments");
2036 dpctl_dump_ipf(struct dpif
*dpif
, struct dpctl_params
*dpctl_p
)
2038 struct ipf_dump_ctx
*dump_ctx
;
2041 int error
= ct_dpif_ipf_dump_start(dpif
, &dump_ctx
);
2043 dpctl_error(dpctl_p
, error
, "starting ipf list dump");
2044 /* Nothing to clean up, just return. */
2048 dpctl_print(dpctl_p
, "\n Fragment Lists:\n\n");
2049 while (!(error
= ct_dpif_ipf_dump_next(dpif
, dump_ctx
, &dump
))) {
2050 dpctl_print(dpctl_p
, "%s\n", dump
);
2054 if (error
&& error
!= EOF
) {
2055 dpctl_error(dpctl_p
, error
, "dumping ipf lists failed");
2058 ct_dpif_ipf_dump_done(dpif
, dump_ctx
);
2062 dpctl_ct_ipf_get_status(int argc
, const char *argv
[],
2063 struct dpctl_params
*dpctl_p
)
2066 int error
= opt_dpif_open(argc
, argv
, dpctl_p
, 2, &dpif
);
2069 struct dpif_ipf_status dpif_ipf_status
;
2070 error
= ct_dpif_ipf_get_status(dpif
, &dpif_ipf_status
);
2073 dpctl_print(dpctl_p
, " Fragmentation Module Status\n");
2074 dpctl_print(dpctl_p
, " ---------------------------\n");
2075 dpctl_print(dpctl_p
, " v4 enabled: %u\n",
2076 dpif_ipf_status
.v4
.enabled
);
2077 dpctl_print(dpctl_p
, " v6 enabled: %u\n",
2078 dpif_ipf_status
.v6
.enabled
);
2079 dpctl_print(dpctl_p
, " max num frags (v4/v6): %u\n",
2080 dpif_ipf_status
.nfrag_max
);
2081 dpctl_print(dpctl_p
, " num frag: %u\n",
2082 dpif_ipf_status
.nfrag
);
2083 dpctl_print(dpctl_p
, " min v4 frag size: %u\n",
2084 dpif_ipf_status
.v4
.min_frag_size
);
2085 dpctl_print(dpctl_p
, " v4 frags accepted: %"PRIu64
"\n",
2086 dpif_ipf_status
.v4
.nfrag_accepted
);
2087 dpctl_print(dpctl_p
, " v4 frags completed: %"PRIu64
"\n",
2088 dpif_ipf_status
.v4
.nfrag_completed_sent
);
2089 dpctl_print(dpctl_p
, " v4 frags expired: %"PRIu64
"\n",
2090 dpif_ipf_status
.v4
.nfrag_expired_sent
);
2091 dpctl_print(dpctl_p
, " v4 frags too small: %"PRIu64
"\n",
2092 dpif_ipf_status
.v4
.nfrag_too_small
);
2093 dpctl_print(dpctl_p
, " v4 frags overlapped: %"PRIu64
"\n",
2094 dpif_ipf_status
.v4
.nfrag_overlap
);
2095 dpctl_print(dpctl_p
, " v4 frags purged: %"PRIu64
"\n",
2096 dpif_ipf_status
.v4
.nfrag_purged
);
2098 dpctl_print(dpctl_p
, " min v6 frag size: %u\n",
2099 dpif_ipf_status
.v6
.min_frag_size
);
2100 dpctl_print(dpctl_p
, " v6 frags accepted: %"PRIu64
"\n",
2101 dpif_ipf_status
.v6
.nfrag_accepted
);
2102 dpctl_print(dpctl_p
, " v6 frags completed: %"PRIu64
"\n",
2103 dpif_ipf_status
.v6
.nfrag_completed_sent
);
2104 dpctl_print(dpctl_p
, " v6 frags expired: %"PRIu64
"\n",
2105 dpif_ipf_status
.v6
.nfrag_expired_sent
);
2106 dpctl_print(dpctl_p
, " v6 frags too small: %"PRIu64
"\n",
2107 dpif_ipf_status
.v6
.nfrag_too_small
);
2108 dpctl_print(dpctl_p
, " v6 frags overlapped: %"PRIu64
"\n",
2109 dpif_ipf_status
.v6
.nfrag_overlap
);
2110 dpctl_print(dpctl_p
, " v6 frags purged: %"PRIu64
"\n",
2111 dpif_ipf_status
.v6
.nfrag_purged
);
2113 dpctl_error(dpctl_p
, error
,
2114 "ipf status could not be retrieved");
2118 if (dpctl_p
->verbosity
) {
2119 dpctl_dump_ipf(dpif
, dpctl_p
);
2128 /* Undocumented commands for unit testing. */
2131 dpctl_parse_actions(int argc
, const char *argv
[], struct dpctl_params
* dpctl_p
)
2135 for (i
= 1; i
< argc
; i
++) {
2136 struct ofpbuf actions
;
2139 ofpbuf_init(&actions
, 0);
2140 error
= odp_actions_from_string(argv
[i
], NULL
, &actions
);
2143 ofpbuf_uninit(&actions
);
2144 dpctl_error(dpctl_p
, error
, "odp_actions_from_string");
2149 format_odp_actions(&s
, actions
.data
, actions
.size
, NULL
);
2150 dpctl_print(dpctl_p
, "%s\n", ds_cstr(&s
));
2153 ofpbuf_uninit(&actions
);
2159 struct actions_for_flow
{
2160 struct hmap_node hmap_node
;
2162 struct ofpbuf actions
;
2165 static struct actions_for_flow
*
2166 get_actions_for_flow(struct hmap
*actions_per_flow
, const struct flow
*flow
)
2168 uint32_t hash
= flow_hash(flow
, 0);
2169 struct actions_for_flow
*af
;
2171 HMAP_FOR_EACH_WITH_HASH (af
, hmap_node
, hash
, actions_per_flow
) {
2172 if (flow_equal(&af
->flow
, flow
)) {
2177 af
= xmalloc(sizeof *af
);
2179 ofpbuf_init(&af
->actions
, 0);
2180 hmap_insert(actions_per_flow
, &af
->hmap_node
, hash
);
2185 compare_actions_for_flow(const void *a_
, const void *b_
)
2187 struct actions_for_flow
*const *a
= a_
;
2188 struct actions_for_flow
*const *b
= b_
;
2190 return flow_compare_3way(&(*a
)->flow
, &(*b
)->flow
);
2194 compare_output_actions(const void *a_
, const void *b_
)
2196 const struct nlattr
*a
= a_
;
2197 const struct nlattr
*b
= b_
;
2198 uint32_t a_port
= nl_attr_get_u32(a
);
2199 uint32_t b_port
= nl_attr_get_u32(b
);
2201 return a_port
< b_port
? -1 : a_port
> b_port
;
2205 sort_output_actions__(struct nlattr
*first
, struct nlattr
*end
)
2207 size_t bytes
= (uint8_t *) end
- (uint8_t *) first
;
2208 size_t n
= bytes
/ NL_A_U32_SIZE
;
2210 ovs_assert(bytes
% NL_A_U32_SIZE
== 0);
2211 qsort(first
, n
, NL_A_U32_SIZE
, compare_output_actions
);
2215 sort_output_actions(struct nlattr
*actions
, size_t length
)
2217 struct nlattr
*first_output
= NULL
;
2221 NL_ATTR_FOR_EACH (a
, left
, actions
, length
) {
2222 if (nl_attr_type(a
) == OVS_ACTION_ATTR_OUTPUT
) {
2223 if (!first_output
) {
2228 sort_output_actions__(first_output
, a
);
2229 first_output
= NULL
;
2234 uint8_t *end
= (uint8_t *) actions
+ length
;
2235 sort_output_actions__(first_output
,
2236 ALIGNED_CAST(struct nlattr
*, end
));
2240 /* usage: "ovs-dpctl normalize-actions FLOW ACTIONS" where FLOW and ACTIONS
2241 * have the syntax used by "ovs-dpctl dump-flows".
2243 * This command prints ACTIONS in a format that shows what happens for each
2244 * VLAN, independent of the order of the ACTIONS. For example, there is more
2245 * than one way to output a packet on VLANs 9 and 11, but this command will
2246 * print the same output for any form.
2248 * The idea here generalizes beyond VLANs (e.g. to setting other fields) but
2249 * so far the implementation only covers VLANs. */
2251 dpctl_normalize_actions(int argc
, const char *argv
[],
2252 struct dpctl_params
*dpctl_p
)
2254 struct simap port_names
;
2255 struct ofpbuf keybuf
;
2257 struct ofpbuf odp_actions
;
2258 struct hmap actions_per_flow
;
2259 struct actions_for_flow
**afs
;
2260 struct actions_for_flow
*af
;
2270 simap_init(&port_names
);
2271 for (i
= 3; i
< argc
; i
++) {
2275 if (ovs_scan(argv
[i
], "%15[^=]=%d", name
, &number
)) {
2276 uintptr_t n
= number
;
2277 simap_put(&port_names
, name
, n
);
2279 dpctl_error(dpctl_p
, 0, "%s: expected NAME=NUMBER", argv
[i
]);
2285 /* Parse flow key. */
2286 ofpbuf_init(&keybuf
, 0);
2288 error
= odp_flow_from_string(argv
[1], &port_names
, &keybuf
, NULL
,
2291 dpctl_error(dpctl_p
, error
, "odp_flow_key_from_string (%s)", error_s
);
2293 goto out_freekeybuf
;
2297 odp_flow_format(keybuf
.data
, keybuf
.size
, NULL
, 0, NULL
,
2298 &s
, dpctl_p
->verbosity
);
2299 dpctl_print(dpctl_p
, "input flow: %s\n", ds_cstr(&s
));
2301 error
= odp_flow_key_to_flow(keybuf
.data
, keybuf
.size
, &flow
, &error_s
);
2303 dpctl_error(dpctl_p
, error
, "odp_flow_key_to_flow failed (%s)",
2304 error_s
? error_s
: "reason unknown");
2306 goto out_freekeybuf
;
2309 /* Parse actions. */
2310 ofpbuf_init(&odp_actions
, 0);
2311 error
= odp_actions_from_string(argv
[2], &port_names
, &odp_actions
);
2313 dpctl_error(dpctl_p
, error
, "odp_actions_from_string");
2314 goto out_freeactions
;
2317 if (dpctl_p
->verbosity
) {
2319 format_odp_actions(&s
, odp_actions
.data
, odp_actions
.size
, NULL
);
2320 dpctl_print(dpctl_p
, "input actions: %s\n", ds_cstr(&s
));
2323 hmap_init(&actions_per_flow
);
2324 NL_ATTR_FOR_EACH (a
, left
, odp_actions
.data
, odp_actions
.size
) {
2325 const struct ovs_action_push_vlan
*push
;
2326 switch(nl_attr_type(a
)) {
2327 case OVS_ACTION_ATTR_POP_VLAN
:
2328 flow_pop_vlan(&flow
, NULL
);
2331 case OVS_ACTION_ATTR_PUSH_VLAN
:
2332 flow_push_vlan_uninit(&flow
, NULL
);
2333 push
= nl_attr_get_unspec(a
, sizeof *push
);
2334 flow
.vlans
[0].tpid
= push
->vlan_tpid
;
2335 flow
.vlans
[0].tci
= push
->vlan_tci
;
2339 af
= get_actions_for_flow(&actions_per_flow
, &flow
);
2340 nl_msg_put_unspec(&af
->actions
, nl_attr_type(a
),
2341 nl_attr_get(a
), nl_attr_get_size(a
));
2344 n_afs
= hmap_count(&actions_per_flow
);
2345 afs
= xmalloc(n_afs
* sizeof *afs
);
2347 HMAP_FOR_EACH (af
, hmap_node
, &actions_per_flow
) {
2351 ovs_assert(i
== n_afs
);
2352 hmap_destroy(&actions_per_flow
);
2354 qsort(afs
, n_afs
, sizeof *afs
, compare_actions_for_flow
);
2356 for (i
= 0; i
< n_afs
; i
++) {
2358 sort_output_actions(af
->actions
.data
, af
->actions
.size
);
2360 for (encaps
= 0; encaps
< FLOW_MAX_VLAN_HEADERS
; encaps
++) {
2361 union flow_vlan_hdr
*vlan
= &af
->flow
.vlans
[encaps
];
2362 if (vlan
->tci
!= htons(0)) {
2363 dpctl_print(dpctl_p
, "vlan(");
2364 if (vlan
->tpid
!= htons(ETH_TYPE_VLAN
)) {
2365 dpctl_print(dpctl_p
, "tpid=0x%04"PRIx16
",", vlan
->tpid
);
2367 dpctl_print(dpctl_p
, "vid=%"PRIu16
",pcp=%d): ",
2368 vlan_tci_to_vid(vlan
->tci
),
2369 vlan_tci_to_pcp(vlan
->tci
));
2372 dpctl_print(dpctl_p
, "no vlan: ");
2378 if (eth_type_mpls(af
->flow
.dl_type
)) {
2379 dpctl_print(dpctl_p
, "mpls(label=%"PRIu32
",tc=%d,ttl=%d): ",
2380 mpls_lse_to_label(af
->flow
.mpls_lse
[0]),
2381 mpls_lse_to_tc(af
->flow
.mpls_lse
[0]),
2382 mpls_lse_to_ttl(af
->flow
.mpls_lse
[0]));
2384 dpctl_print(dpctl_p
, "no mpls: ");
2388 format_odp_actions(&s
, af
->actions
.data
, af
->actions
.size
, NULL
);
2389 dpctl_puts(dpctl_p
, false, ds_cstr(&s
));
2391 ofpbuf_uninit(&af
->actions
);
2398 ofpbuf_uninit(&odp_actions
);
2400 ofpbuf_uninit(&keybuf
);
2402 simap_destroy(&port_names
);
2408 static const struct dpctl_command all_commands
[] = {
2409 { "add-dp", "dp [iface...]", 1, INT_MAX
, dpctl_add_dp
, DP_RW
},
2410 { "del-dp", "dp", 1, 1, dpctl_del_dp
, DP_RW
},
2411 { "add-if", "dp iface...", 2, INT_MAX
, dpctl_add_if
, DP_RW
},
2412 { "del-if", "dp iface...", 2, INT_MAX
, dpctl_del_if
, DP_RW
},
2413 { "set-if", "dp iface...", 2, INT_MAX
, dpctl_set_if
, DP_RW
},
2414 { "dump-dps", "", 0, 0, dpctl_dump_dps
, DP_RO
},
2415 { "show", "[dp...]", 0, INT_MAX
, dpctl_show
, DP_RO
},
2416 { "dump-flows", "[dp] [filter=..] [type=..]",
2417 0, 3, dpctl_dump_flows
, DP_RO
},
2418 { "add-flow", "[dp] flow actions", 2, 3, dpctl_add_flow
, DP_RW
},
2419 { "mod-flow", "[dp] flow actions", 2, 3, dpctl_mod_flow
, DP_RW
},
2420 { "get-flow", "[dp] ufid", 1, 2, dpctl_get_flow
, DP_RO
},
2421 { "del-flow", "[dp] flow", 1, 2, dpctl_del_flow
, DP_RW
},
2422 { "del-flows", "[dp]", 0, 1, dpctl_del_flows
, DP_RW
},
2423 { "dump-conntrack", "[dp] [zone=N]", 0, 2, dpctl_dump_conntrack
, DP_RO
},
2424 { "flush-conntrack", "[dp] [zone=N] [ct-tuple]", 0, 3,
2425 dpctl_flush_conntrack
, DP_RW
},
2426 { "ct-stats-show", "[dp] [zone=N]",
2427 0, 3, dpctl_ct_stats_show
, DP_RO
},
2428 { "ct-bkts", "[dp] [gt=N]", 0, 2, dpctl_ct_bkts
, DP_RO
},
2429 { "ct-set-maxconns", "[dp] maxconns", 1, 2, dpctl_ct_set_maxconns
, DP_RW
},
2430 { "ct-get-maxconns", "[dp]", 0, 1, dpctl_ct_get_maxconns
, DP_RO
},
2431 { "ct-get-nconns", "[dp]", 0, 1, dpctl_ct_get_nconns
, DP_RO
},
2432 { "ct-set-limits", "[dp] [default=L] [zone=N,limit=L]...", 1, INT_MAX
,
2433 dpctl_ct_set_limits
, DP_RO
},
2434 { "ct-del-limits", "[dp] zone=N1[,N2]...", 1, 2, dpctl_ct_del_limits
,
2436 { "ct-get-limits", "[dp] [zone=N1[,N2]...]", 0, 2, dpctl_ct_get_limits
,
2438 { "ipf-set-enabled", "[dp] v4|v6", 1, 2, dpctl_ipf_set_enabled
, DP_RW
},
2439 { "ipf-set-disabled", "[dp] v4|v6", 1, 2, dpctl_ipf_set_disabled
, DP_RW
},
2440 { "ipf-set-min-frag", "[dp] v4|v6 minfragment", 2, 3,
2441 dpctl_ipf_set_min_frag
, DP_RW
},
2442 { "ipf-set-max-nfrags", "[dp] maxfrags", 1, 2,
2443 dpctl_ipf_set_max_nfrags
, DP_RW
},
2444 { "ipf-get-status", "[dp]", 0, 1, dpctl_ct_ipf_get_status
,
2446 { "help", "", 0, INT_MAX
, dpctl_help
, DP_RO
},
2447 { "list-commands", "", 0, INT_MAX
, dpctl_list_commands
, DP_RO
},
2449 /* Undocumented commands for testing. */
2450 { "parse-actions", "actions", 1, INT_MAX
, dpctl_parse_actions
, DP_RO
},
2451 { "normalize-actions", "actions",
2452 2, INT_MAX
, dpctl_normalize_actions
, DP_RO
},
2454 { NULL
, NULL
, 0, 0, NULL
, DP_RO
},
2457 static const struct dpctl_command
*get_all_dpctl_commands(void)
2459 return all_commands
;
2462 /* Runs the command designated by argv[0] within the command table specified by
2463 * 'commands', which must be terminated by a command whose 'name' member is a
2466 dpctl_run_command(int argc
, const char *argv
[], struct dpctl_params
*dpctl_p
)
2468 const struct dpctl_command
*p
;
2470 dpctl_error(dpctl_p
, 0, "missing command name; use --help for help");
2474 for (p
= all_commands
; p
->name
!= NULL
; p
++) {
2475 if (!strcmp(p
->name
, argv
[0])) {
2476 int n_arg
= argc
- 1;
2477 if (n_arg
< p
->min_args
) {
2478 dpctl_error(dpctl_p
, 0,
2479 "'%s' command requires at least %d arguments",
2480 p
->name
, p
->min_args
);
2482 } else if (n_arg
> p
->max_args
) {
2483 dpctl_error(dpctl_p
, 0,
2484 "'%s' command takes at most %d arguments",
2485 p
->name
, p
->max_args
);
2488 if (p
->mode
== DP_RW
&& dpctl_p
->read_only
) {
2489 dpctl_error(dpctl_p
, 0,
2490 "'%s' command does not work in read only mode",
2494 return p
->handler(argc
, argv
, dpctl_p
);
2499 dpctl_error(dpctl_p
, 0, "unknown command '%s'; use --help for help",
2505 dpctl_unixctl_print(void *userdata
, bool error OVS_UNUSED
, const char *msg
)
2507 struct ds
*ds
= userdata
;
2508 ds_put_cstr(ds
, msg
);
2512 dpctl_unixctl_handler(struct unixctl_conn
*conn
, int argc
, const char *argv
[],
2515 struct ds ds
= DS_EMPTY_INITIALIZER
;
2518 struct dpctl_params dpctl_p
= {
2520 .output
= dpctl_unixctl_print
,
2524 /* Parse options (like getopt). Unfortunately it does
2525 * not seem a good idea to call getopt_long() here, since it uses global
2527 bool set_names
= false;
2528 while (argc
> 1 && !error
) {
2529 const char *arg
= argv
[1];
2530 if (!strncmp(arg
, "--", 2)) {
2532 if (!strcmp(arg
, "--statistics")) {
2533 dpctl_p
.print_statistics
= true;
2534 } else if (!strcmp(arg
, "--clear")) {
2535 dpctl_p
.zero_statistics
= true;
2536 } else if (!strcmp(arg
, "--may-create")) {
2537 dpctl_p
.may_create
= true;
2538 } else if (!strcmp(arg
, "--more")) {
2539 dpctl_p
.verbosity
++;
2540 } else if (!strcmp(arg
, "--names")) {
2541 dpctl_p
.names
= true;
2543 } else if (!strcmp(arg
, "--no-names")) {
2544 dpctl_p
.names
= false;
2547 ds_put_format(&ds
, "Unrecognized option %s", argv
[1]);
2550 } else if (arg
[0] == '-' && arg
[1] != '\0') {
2551 /* Short option[s] */
2552 const char *opt
= &arg
[1];
2554 while (*opt
&& !error
) {
2557 dpctl_p
.verbosity
++;
2560 dpctl_p
.print_statistics
= true;
2563 ds_put_format(&ds
, "Unrecognized option -%c", *opt
);
2570 /* Doesn't start with -, not an option */
2581 dpctl_p
.names
= dpctl_p
.verbosity
> 0;
2583 VLOG_INFO("set_names=%d verbosity=%d names=%d", set_names
,
2584 dpctl_p
.verbosity
, dpctl_p
.names
);
2587 dpctl_command_handler
*handler
= (dpctl_command_handler
*) aux
;
2588 error
= handler(argc
, argv
, &dpctl_p
) != 0;
2592 unixctl_command_reply_error(conn
, ds_cstr(&ds
));
2594 unixctl_command_reply(conn
, ds_cstr(&ds
));
2601 dpctl_unixctl_register(void)
2603 const struct dpctl_command
*p
;
2605 for (p
= all_commands
; p
->name
!= NULL
; p
++) {
2606 if (strcmp(p
->name
, "help")) {
2607 char *cmd_name
= xasprintf("dpctl/%s", p
->name
);
2608 unixctl_command_register(cmd_name
,
2612 dpctl_unixctl_handler
,