]>
Commit | Line | Data |
---|---|---|
064af421 | 1 | /* |
1ba530f4 | 2 | * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks. |
064af421 | 3 | * |
a14bc59f BP |
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: | |
064af421 | 7 | * |
a14bc59f BP |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
064af421 BP |
15 | */ |
16 | ||
17 | #include <config.h> | |
18 | #include <arpa/inet.h> | |
19 | #include <errno.h> | |
20 | #include <getopt.h> | |
21 | #include <inttypes.h> | |
9d82ec47 | 22 | #include <sys/socket.h> |
064af421 BP |
23 | #include <net/if.h> |
24 | #include <netinet/in.h> | |
25 | #include <signal.h> | |
26 | #include <stdarg.h> | |
27 | #include <stdlib.h> | |
28 | #include <string.h> | |
29 | #include <unistd.h> | |
30 | #include <sys/stat.h> | |
31 | #include <sys/time.h> | |
32 | ||
33 | #include "command-line.h" | |
34 | #include "compiler.h" | |
35 | #include "dirs.h" | |
36 | #include "dpif.h" | |
37 | #include "dynamic-string.h" | |
38 | #include "netdev.h" | |
39 | #include "odp-util.h" | |
c3827f61 | 40 | #include "shash.h" |
d0c23a1a | 41 | #include "sset.h" |
064af421 BP |
42 | #include "timeval.h" |
43 | #include "util.h" | |
064af421 | 44 | #include "vlog.h" |
5136ce49 | 45 | |
d98e6007 | 46 | VLOG_DEFINE_THIS_MODULE(dpctl); |
064af421 | 47 | |
032aa6a3 | 48 | /* -s, --statistics: Print port statistics? */ |
d3d8f1f7 | 49 | static bool print_statistics; |
032aa6a3 | 50 | |
675febfa | 51 | static const struct command all_commands[]; |
064af421 BP |
52 | |
53 | static void usage(void) NO_RETURN; | |
54 | static void parse_options(int argc, char *argv[]); | |
55 | ||
675febfa BP |
56 | int |
57 | main(int argc, char *argv[]) | |
064af421 | 58 | { |
064af421 | 59 | set_program_name(argv[0]); |
064af421 BP |
60 | parse_options(argc, argv); |
61 | signal(SIGPIPE, SIG_IGN); | |
675febfa | 62 | run_command(argc - optind, argv + optind, all_commands); |
064af421 BP |
63 | return 0; |
64 | } | |
65 | ||
66 | static void | |
67 | parse_options(int argc, char *argv[]) | |
68 | { | |
87c84891 JP |
69 | enum { |
70 | OPT_DUMMY = UCHAR_MAX + 1, | |
71 | VLOG_OPTION_ENUMS | |
72 | }; | |
064af421 | 73 | static struct option long_options[] = { |
e3c17733 BP |
74 | {"statistics", no_argument, NULL, 's'}, |
75 | {"timeout", required_argument, NULL, 't'}, | |
76 | {"help", no_argument, NULL, 'h'}, | |
77 | {"version", no_argument, NULL, 'V'}, | |
87c84891 | 78 | VLOG_LONG_OPTIONS, |
e3c17733 | 79 | {NULL, 0, NULL, 0}, |
064af421 BP |
80 | }; |
81 | char *short_options = long_options_to_short_options(long_options); | |
82 | ||
83 | for (;;) { | |
84 | unsigned long int timeout; | |
85 | int c; | |
86 | ||
87 | c = getopt_long(argc, argv, short_options, long_options, NULL); | |
88 | if (c == -1) { | |
89 | break; | |
90 | } | |
91 | ||
92 | switch (c) { | |
032aa6a3 BP |
93 | case 's': |
94 | print_statistics = true; | |
95 | break; | |
96 | ||
064af421 BP |
97 | case 't': |
98 | timeout = strtoul(optarg, NULL, 10); | |
99 | if (timeout <= 0) { | |
100 | ovs_fatal(0, "value %s on -t or --timeout is not at least 1", | |
101 | optarg); | |
102 | } else { | |
103 | time_alarm(timeout); | |
104 | } | |
105 | break; | |
106 | ||
107 | case 'h': | |
108 | usage(); | |
109 | ||
110 | case 'V': | |
55d5bb44 | 111 | ovs_print_version(0, 0); |
064af421 BP |
112 | exit(EXIT_SUCCESS); |
113 | ||
87c84891 | 114 | VLOG_OPTION_HANDLERS |
064af421 BP |
115 | |
116 | case '?': | |
117 | exit(EXIT_FAILURE); | |
118 | ||
119 | default: | |
120 | abort(); | |
121 | } | |
122 | } | |
123 | free(short_options); | |
124 | } | |
125 | ||
126 | static void | |
127 | usage(void) | |
128 | { | |
129 | printf("%s: Open vSwitch datapath management utility\n" | |
130 | "usage: %s [OPTIONS] COMMAND [ARG...]\n" | |
131 | " add-dp DP [IFACE...] add new datapath DP (with IFACEs)\n" | |
132 | " del-dp DP delete local datapath DP\n" | |
133 | " add-if DP IFACE... add each IFACE as a port on DP\n" | |
134 | " del-if DP IFACE... delete each IFACE from DP\n" | |
b566902b | 135 | " dump-dps display names of all datapaths\n" |
064af421 BP |
136 | " show show basic info on all datapaths\n" |
137 | " show DP... show basic info on each DP\n" | |
138 | " dump-flows DP display flows in DP\n" | |
f1588b1f | 139 | " del-flows DP delete all flows from DP\n", |
064af421 BP |
140 | program_name, program_name); |
141 | vlog_usage(); | |
142 | printf("\nOther options:\n" | |
143 | " -t, --timeout=SECS give up after SECS seconds\n" | |
144 | " -h, --help display this help message\n" | |
145 | " -V, --version display version information\n"); | |
146 | exit(EXIT_SUCCESS); | |
147 | } | |
148 | ||
149 | static void run(int retval, const char *message, ...) | |
150 | PRINTF_FORMAT(2, 3); | |
151 | ||
152 | static void run(int retval, const char *message, ...) | |
153 | { | |
154 | if (retval) { | |
155 | va_list args; | |
156 | ||
064af421 | 157 | va_start(args, message); |
fcaddd4d | 158 | ovs_fatal_valist(retval, message, args); |
064af421 BP |
159 | } |
160 | } | |
161 | \f | |
162 | static void do_add_if(int argc, char *argv[]); | |
163 | ||
164 | static int if_up(const char *netdev_name) | |
165 | { | |
166 | struct netdev *netdev; | |
167 | int retval; | |
168 | ||
18812dff | 169 | retval = netdev_open(netdev_name, "system", &netdev); |
064af421 BP |
170 | if (!retval) { |
171 | retval = netdev_turn_flags_on(netdev, NETDEV_UP, true); | |
172 | netdev_close(netdev); | |
173 | } | |
174 | return retval; | |
175 | } | |
176 | ||
1a6f1e2a JG |
177 | static int |
178 | parsed_dpif_open(const char *arg_, bool create, struct dpif **dpifp) | |
179 | { | |
180 | int result; | |
181 | char *name, *type; | |
182 | ||
183 | dp_parse_name(arg_, &name, &type); | |
184 | ||
185 | if (create) { | |
186 | result = dpif_create(name, type, dpifp); | |
187 | } else { | |
188 | result = dpif_open(name, type, dpifp); | |
189 | } | |
190 | ||
191 | free(name); | |
192 | free(type); | |
193 | return result; | |
194 | } | |
195 | ||
064af421 | 196 | static void |
67a4917b | 197 | do_add_dp(int argc OVS_UNUSED, char *argv[]) |
064af421 | 198 | { |
c228a364 | 199 | struct dpif *dpif; |
1a6f1e2a | 200 | run(parsed_dpif_open(argv[1], true, &dpif), "add_dp"); |
c228a364 | 201 | dpif_close(dpif); |
064af421 BP |
202 | if (argc > 2) { |
203 | do_add_if(argc, argv); | |
204 | } | |
205 | } | |
206 | ||
207 | static void | |
67a4917b | 208 | do_del_dp(int argc OVS_UNUSED, char *argv[]) |
064af421 | 209 | { |
c228a364 | 210 | struct dpif *dpif; |
1a6f1e2a | 211 | run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath"); |
c228a364 BP |
212 | run(dpif_delete(dpif), "del_dp"); |
213 | dpif_close(dpif); | |
064af421 BP |
214 | } |
215 | ||
064af421 | 216 | static void |
67a4917b | 217 | do_add_if(int argc OVS_UNUSED, char *argv[]) |
064af421 BP |
218 | { |
219 | bool failure = false; | |
c228a364 | 220 | struct dpif *dpif; |
064af421 BP |
221 | int i; |
222 | ||
1a6f1e2a | 223 | run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath"); |
064af421 | 224 | for (i = 2; i < argc; i++) { |
18812dff | 225 | const char *name, *type; |
064af421 | 226 | char *save_ptr = NULL; |
de5cdb90 | 227 | struct netdev *netdev = NULL; |
c3827f61 BP |
228 | struct shash args; |
229 | char *option; | |
064af421 BP |
230 | int error; |
231 | ||
18812dff BP |
232 | name = strtok_r(argv[i], ",", &save_ptr); |
233 | type = "system"; | |
c3827f61 | 234 | |
18812dff | 235 | if (!name) { |
064af421 BP |
236 | ovs_error(0, "%s is not a valid network device name", argv[i]); |
237 | continue; | |
238 | } | |
239 | ||
c3827f61 | 240 | shash_init(&args); |
25608d97 | 241 | while ((option = strtok_r(NULL, ",", &save_ptr)) != NULL) { |
c3827f61 BP |
242 | char *save_ptr_2 = NULL; |
243 | char *key, *value; | |
244 | ||
245 | key = strtok_r(option, "=", &save_ptr_2); | |
246 | value = strtok_r(NULL, "", &save_ptr_2); | |
247 | if (!value) { | |
248 | value = ""; | |
249 | } | |
250 | ||
251 | if (!strcmp(key, "type")) { | |
18812dff | 252 | type = value; |
c3827f61 BP |
253 | } else if (!shash_add_once(&args, key, value)) { |
254 | ovs_error(0, "duplicate \"%s\" option", key); | |
064af421 BP |
255 | } |
256 | } | |
064af421 | 257 | |
18812dff | 258 | error = netdev_open(name, type, &netdev); |
c3827f61 | 259 | if (error) { |
18812dff | 260 | ovs_error(error, "%s: failed to open network device", name); |
de5cdb90 BP |
261 | goto next; |
262 | } | |
263 | ||
264 | error = netdev_set_config(netdev, &args); | |
265 | if (error) { | |
18812dff | 266 | ovs_error(error, "%s: failed to configure network device", name); |
de5cdb90 | 267 | goto next; |
c3827f61 | 268 | } |
de5cdb90 BP |
269 | |
270 | error = dpif_port_add(dpif, netdev, NULL); | |
271 | if (error) { | |
18812dff | 272 | ovs_error(error, "adding %s to %s failed", name, argv[1]); |
de5cdb90 BP |
273 | goto next; |
274 | } | |
275 | ||
18812dff | 276 | error = if_up(name); |
de5cdb90 BP |
277 | |
278 | next: | |
279 | netdev_close(netdev); | |
064af421 | 280 | if (error) { |
064af421 BP |
281 | failure = true; |
282 | } | |
283 | } | |
c228a364 | 284 | dpif_close(dpif); |
064af421 BP |
285 | if (failure) { |
286 | exit(EXIT_FAILURE); | |
287 | } | |
288 | } | |
289 | ||
290 | static bool | |
291 | get_port_number(struct dpif *dpif, const char *name, uint16_t *port) | |
292 | { | |
4c738a8d | 293 | struct dpif_port dpif_port; |
0a54c658 | 294 | |
4c738a8d BP |
295 | if (!dpif_port_query_by_name(dpif, name, &dpif_port)) { |
296 | *port = dpif_port.port_no; | |
297 | dpif_port_destroy(&dpif_port); | |
0a54c658 BP |
298 | return true; |
299 | } else { | |
300 | ovs_error(0, "no port named %s", name); | |
301 | return false; | |
064af421 | 302 | } |
064af421 BP |
303 | } |
304 | ||
305 | static void | |
67a4917b | 306 | do_del_if(int argc OVS_UNUSED, char *argv[]) |
064af421 BP |
307 | { |
308 | bool failure = false; | |
c228a364 | 309 | struct dpif *dpif; |
064af421 BP |
310 | int i; |
311 | ||
1a6f1e2a | 312 | run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath"); |
064af421 BP |
313 | for (i = 2; i < argc; i++) { |
314 | const char *name = argv[i]; | |
315 | uint16_t port; | |
316 | int error; | |
317 | ||
318 | if (!name[strspn(name, "0123456789")]) { | |
319 | port = atoi(name); | |
c228a364 | 320 | } else if (!get_port_number(dpif, name, &port)) { |
064af421 BP |
321 | failure = true; |
322 | continue; | |
323 | } | |
324 | ||
c228a364 | 325 | error = dpif_port_del(dpif, port); |
064af421 BP |
326 | if (error) { |
327 | ovs_error(error, "deleting port %s from %s failed", name, argv[1]); | |
328 | failure = true; | |
329 | } | |
330 | } | |
c228a364 | 331 | dpif_close(dpif); |
064af421 BP |
332 | if (failure) { |
333 | exit(EXIT_FAILURE); | |
334 | } | |
335 | } | |
336 | ||
032aa6a3 BP |
337 | static void |
338 | print_stat(const char *leader, uint64_t value) | |
339 | { | |
340 | fputs(leader, stdout); | |
341 | if (value != UINT64_MAX) { | |
342 | printf("%"PRIu64, value); | |
343 | } else { | |
344 | putchar('?'); | |
345 | } | |
346 | } | |
347 | ||
348 | static void | |
349 | print_human_size(uint64_t value) | |
350 | { | |
351 | if (value == UINT64_MAX) { | |
352 | /* Nothing to do. */ | |
353 | } else if (value >= 1024ULL * 1024 * 1024 * 1024) { | |
354 | printf(" (%.1f TiB)", value / (1024.0 * 1024 * 1024 * 1024)); | |
355 | } else if (value >= 1024ULL * 1024 * 1024) { | |
356 | printf(" (%.1f GiB)", value / (1024.0 * 1024 * 1024)); | |
357 | } else if (value >= 1024ULL * 1024) { | |
358 | printf(" (%.1f MiB)", value / (1024.0 * 1024)); | |
359 | } else if (value >= 1024) { | |
360 | printf(" (%.1f KiB)", value / 1024.0); | |
361 | } | |
362 | } | |
363 | ||
064af421 BP |
364 | static void |
365 | show_dpif(struct dpif *dpif) | |
366 | { | |
b0ec0f27 | 367 | struct dpif_port_dump dump; |
4c738a8d | 368 | struct dpif_port dpif_port; |
a8d9304d | 369 | struct dpif_dp_stats stats; |
f613a0d7 | 370 | struct netdev *netdev; |
064af421 | 371 | |
b29ba128 | 372 | printf("%s:\n", dpif_name(dpif)); |
064af421 | 373 | if (!dpif_get_dp_stats(dpif, &stats)) { |
7257b535 BP |
374 | printf("\tlookups: hit:%"PRIu64" missed:%"PRIu64" lost:%"PRIu64"\n" |
375 | "\tflows: %"PRIu64"\n", | |
376 | stats.n_hit, stats.n_missed, stats.n_lost, stats.n_flows); | |
064af421 | 377 | } |
4c738a8d BP |
378 | DPIF_PORT_FOR_EACH (&dpif_port, &dump, dpif) { |
379 | printf("\tport %u: %s", dpif_port.port_no, dpif_port.name); | |
0ae60917 | 380 | |
4c738a8d | 381 | if (strcmp(dpif_port.type, "system")) { |
ffeda91a BP |
382 | int error; |
383 | ||
4c738a8d | 384 | printf (" (%s", dpif_port.type); |
ffeda91a | 385 | |
18812dff | 386 | error = netdev_open(dpif_port.name, dpif_port.type, &netdev); |
ffeda91a | 387 | if (!error) { |
de5cdb90 BP |
388 | struct shash config; |
389 | ||
390 | shash_init(&config); | |
391 | error = netdev_get_config(netdev, &config); | |
392 | if (!error) { | |
393 | const struct shash_node **nodes; | |
394 | size_t i; | |
395 | ||
396 | nodes = shash_sort(&config); | |
397 | for (i = 0; i < shash_count(&config); i++) { | |
398 | const struct shash_node *node = nodes[i]; | |
399 | printf("%c %s=%s", i ? ',' : ':', | |
400 | node->name, (char *) node->data); | |
401 | } | |
402 | free(nodes); | |
403 | } else { | |
404 | printf(", could not retrieve configuration (%s)", | |
405 | strerror(error)); | |
ffeda91a | 406 | } |
de5cdb90 | 407 | shash_destroy_free_data(&config); |
ffeda91a BP |
408 | |
409 | netdev_close(netdev); | |
410 | } else { | |
411 | printf(": open failed (%s)", strerror(error)); | |
412 | } | |
413 | putchar(')'); | |
414 | } | |
415 | putchar('\n'); | |
032aa6a3 BP |
416 | |
417 | if (print_statistics) { | |
f613a0d7 PS |
418 | struct netdev_stats s; |
419 | int error; | |
420 | ||
421 | error = netdev_open(dpif_port.name, dpif_port.type, &netdev); | |
422 | if (error) { | |
423 | printf(", open failed (%s)", strerror(error)); | |
424 | continue; | |
425 | } | |
426 | error = netdev_get_stats(netdev, &s); | |
427 | if (error) { | |
428 | printf(", could not retrieve stats (%s)", strerror(error)); | |
429 | continue; | |
430 | } | |
032aa6a3 | 431 | |
f613a0d7 PS |
432 | netdev_close(netdev); |
433 | print_stat("\t\tRX packets:", s.rx_packets); | |
434 | print_stat(" errors:", s.rx_errors); | |
435 | print_stat(" dropped:", s.rx_dropped); | |
436 | print_stat(" overruns:", s.rx_over_errors); | |
437 | print_stat(" frame:", s.rx_frame_errors); | |
032aa6a3 BP |
438 | printf("\n"); |
439 | ||
f613a0d7 PS |
440 | print_stat("\t\tTX packets:", s.tx_packets); |
441 | print_stat(" errors:", s.tx_errors); | |
442 | print_stat(" dropped:", s.tx_dropped); | |
443 | print_stat(" aborted:", s.tx_aborted_errors); | |
444 | print_stat(" carrier:", s.tx_carrier_errors); | |
032aa6a3 BP |
445 | printf("\n"); |
446 | ||
f613a0d7 | 447 | print_stat("\t\tcollisions:", s.collisions); |
032aa6a3 BP |
448 | printf("\n"); |
449 | ||
f613a0d7 PS |
450 | print_stat("\t\tRX bytes:", s.rx_bytes); |
451 | print_human_size(s.rx_bytes); | |
452 | print_stat(" TX bytes:", s.tx_bytes); | |
453 | print_human_size(s.tx_bytes); | |
032aa6a3 BP |
454 | printf("\n"); |
455 | } | |
064af421 | 456 | } |
064af421 BP |
457 | dpif_close(dpif); |
458 | } | |
459 | ||
460 | static void | |
c4fca56a | 461 | do_show(int argc, char *argv[]) |
064af421 BP |
462 | { |
463 | bool failure = false; | |
464 | if (argc > 1) { | |
465 | int i; | |
466 | for (i = 1; i < argc; i++) { | |
467 | const char *name = argv[i]; | |
c228a364 | 468 | struct dpif *dpif; |
064af421 BP |
469 | int error; |
470 | ||
1a6f1e2a | 471 | error = parsed_dpif_open(name, false, &dpif); |
064af421 | 472 | if (!error) { |
c228a364 | 473 | show_dpif(dpif); |
064af421 BP |
474 | } else { |
475 | ovs_error(error, "opening datapath %s failed", name); | |
476 | failure = true; | |
477 | } | |
478 | } | |
479 | } else { | |
d0c23a1a | 480 | struct sset types; |
17dddfc9 | 481 | const char *type; |
17dddfc9 | 482 | |
d0c23a1a | 483 | sset_init(&types); |
17dddfc9 | 484 | dp_enumerate_types(&types); |
d0c23a1a BP |
485 | SSET_FOR_EACH (type, &types) { |
486 | struct sset names; | |
17dddfc9 | 487 | const char *name; |
17dddfc9 | 488 | |
d0c23a1a | 489 | sset_init(&names); |
17dddfc9 | 490 | if (dp_enumerate_names(type, &names)) { |
064af421 | 491 | failure = true; |
17dddfc9 BP |
492 | continue; |
493 | } | |
d0c23a1a | 494 | SSET_FOR_EACH (name, &names) { |
17dddfc9 BP |
495 | struct dpif *dpif; |
496 | int error; | |
497 | ||
498 | error = dpif_open(name, type, &dpif); | |
499 | if (!error) { | |
500 | show_dpif(dpif); | |
501 | } else { | |
502 | ovs_error(error, "opening datapath %s failed", name); | |
503 | failure = true; | |
504 | } | |
064af421 | 505 | } |
d0c23a1a | 506 | sset_destroy(&names); |
064af421 | 507 | } |
d0c23a1a | 508 | sset_destroy(&types); |
064af421 BP |
509 | } |
510 | if (failure) { | |
511 | exit(EXIT_FAILURE); | |
512 | } | |
513 | } | |
514 | ||
b566902b | 515 | static void |
67a4917b | 516 | do_dump_dps(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) |
b566902b | 517 | { |
d0c23a1a BP |
518 | struct sset dpif_names, dpif_types; |
519 | const char *type; | |
1a6f1e2a | 520 | int error = 0; |
b566902b | 521 | |
d0c23a1a BP |
522 | sset_init(&dpif_names); |
523 | sset_init(&dpif_types); | |
1a6f1e2a | 524 | dp_enumerate_types(&dpif_types); |
b566902b | 525 | |
d0c23a1a BP |
526 | SSET_FOR_EACH (type, &dpif_types) { |
527 | const char *name; | |
1a6f1e2a JG |
528 | int retval; |
529 | ||
d0c23a1a | 530 | retval = dp_enumerate_names(type, &dpif_names); |
1a6f1e2a JG |
531 | if (retval) { |
532 | error = retval; | |
533 | } | |
534 | ||
d0c23a1a | 535 | SSET_FOR_EACH (name, &dpif_names) { |
1a6f1e2a | 536 | struct dpif *dpif; |
d0c23a1a | 537 | if (!dpif_open(name, type, &dpif)) { |
1a6f1e2a JG |
538 | printf("%s\n", dpif_name(dpif)); |
539 | dpif_close(dpif); | |
540 | } | |
b566902b | 541 | } |
b566902b JP |
542 | } |
543 | ||
d0c23a1a BP |
544 | sset_destroy(&dpif_names); |
545 | sset_destroy(&dpif_types); | |
b566902b JP |
546 | if (error) { |
547 | exit(EXIT_FAILURE); | |
548 | } | |
549 | } | |
550 | ||
064af421 | 551 | static void |
67a4917b | 552 | do_dump_flows(int argc OVS_UNUSED, char *argv[]) |
064af421 | 553 | { |
c97fb132 | 554 | const struct dpif_flow_stats *stats; |
feebdea2 | 555 | const struct nlattr *actions; |
704a1e09 | 556 | struct dpif_flow_dump dump; |
feebdea2 BP |
557 | const struct nlattr *key; |
558 | size_t actions_len; | |
c228a364 | 559 | struct dpif *dpif; |
feebdea2 | 560 | size_t key_len; |
064af421 | 561 | struct ds ds; |
064af421 | 562 | |
1a6f1e2a | 563 | run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath"); |
064af421 BP |
564 | |
565 | ds_init(&ds); | |
704a1e09 | 566 | dpif_flow_dump_start(&dump, dpif); |
feebdea2 BP |
567 | while (dpif_flow_dump_next(&dump, &key, &key_len, |
568 | &actions, &actions_len, &stats)) { | |
704a1e09 | 569 | ds_clear(&ds); |
feebdea2 BP |
570 | odp_flow_key_format(key, key_len, &ds); |
571 | ds_put_cstr(&ds, ", "); | |
c97fb132 | 572 | dpif_flow_stats_format(stats, &ds); |
feebdea2 BP |
573 | ds_put_cstr(&ds, ", actions:"); |
574 | format_odp_actions(&ds, actions, actions_len); | |
704a1e09 | 575 | printf("%s\n", ds_cstr(&ds)); |
064af421 | 576 | } |
704a1e09 | 577 | dpif_flow_dump_done(&dump); |
064af421 | 578 | ds_destroy(&ds); |
c228a364 | 579 | dpif_close(dpif); |
064af421 BP |
580 | } |
581 | ||
582 | static void | |
67a4917b | 583 | do_del_flows(int argc OVS_UNUSED, char *argv[]) |
064af421 | 584 | { |
c228a364 | 585 | struct dpif *dpif; |
064af421 | 586 | |
1a6f1e2a | 587 | run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath"); |
c228a364 BP |
588 | run(dpif_flow_flush(dpif), "deleting all flows"); |
589 | dpif_close(dpif); | |
064af421 BP |
590 | } |
591 | ||
064af421 | 592 | static void |
67a4917b | 593 | do_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) |
064af421 BP |
594 | { |
595 | usage(); | |
596 | } | |
597 | ||
675febfa | 598 | static const struct command all_commands[] = { |
064af421 BP |
599 | { "add-dp", 1, INT_MAX, do_add_dp }, |
600 | { "del-dp", 1, 1, do_del_dp }, | |
601 | { "add-if", 2, INT_MAX, do_add_if }, | |
602 | { "del-if", 2, INT_MAX, do_del_if }, | |
b566902b | 603 | { "dump-dps", 0, 0, do_dump_dps }, |
064af421 BP |
604 | { "show", 0, INT_MAX, do_show }, |
605 | { "dump-flows", 1, 1, do_dump_flows }, | |
606 | { "del-flows", 1, 1, do_del_flows }, | |
064af421 BP |
607 | { "help", 0, INT_MAX, do_help }, |
608 | { NULL, 0, 0, NULL }, | |
609 | }; |