Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License");
5 : : * you may not use this file except in compliance with the License.
6 : : * You may obtain a copy of the License at:
7 : : *
8 : : * http://www.apache.org/licenses/LICENSE-2.0
9 : : *
10 : : * Unless required by applicable law or agreed to in writing, software
11 : : * distributed under the License is distributed on an "AS IS" BASIS,
12 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : : * See the License for the specific language governing permissions and
14 : : * limitations under the License.
15 : : */
16 : :
17 : : #include <config.h>
18 : : #include <ctype.h>
19 : : #include <errno.h>
20 : : #include <getopt.h>
21 : : #include <inttypes.h>
22 : : #include <sys/socket.h>
23 : : #include <net/if.h>
24 : : #include <signal.h>
25 : : #include <stdlib.h>
26 : : #include <string.h>
27 : : #include <unistd.h>
28 : : #include <fcntl.h>
29 : : #include <sys/stat.h>
30 : : #include <sys/time.h>
31 : :
32 : : #include "byte-order.h"
33 : : #include "classifier.h"
34 : : #include "command-line.h"
35 : : #include "daemon.h"
36 : : #include "colors.h"
37 : : #include "compiler.h"
38 : : #include "dirs.h"
39 : : #include "dp-packet.h"
40 : : #include "fatal-signal.h"
41 : : #include "nx-match.h"
42 : : #include "odp-util.h"
43 : : #include "ofp-version-opt.h"
44 : : #include "ofproto/ofproto.h"
45 : : #include "openflow/nicira-ext.h"
46 : : #include "openflow/openflow.h"
47 : : #include "openvswitch/dynamic-string.h"
48 : : #include "openvswitch/meta-flow.h"
49 : : #include "openvswitch/ofp-actions.h"
50 : : #include "openvswitch/ofp-errors.h"
51 : : #include "openvswitch/ofp-msgs.h"
52 : : #include "openvswitch/ofp-print.h"
53 : : #include "openvswitch/ofp-util.h"
54 : : #include "openvswitch/ofp-parse.h"
55 : : #include "openvswitch/ofpbuf.h"
56 : : #include "openvswitch/vconn.h"
57 : : #include "openvswitch/vlog.h"
58 : : #include "packets.h"
59 : : #include "pcap-file.h"
60 : : #include "poll-loop.h"
61 : : #include "random.h"
62 : : #include "sort.h"
63 : : #include "stream-ssl.h"
64 : : #include "socket-util.h"
65 : : #include "timeval.h"
66 : : #include "unixctl.h"
67 : : #include "util.h"
68 : :
69 : 7780 : VLOG_DEFINE_THIS_MODULE(ofctl);
70 : :
71 : : /* --bundle: Use OpenFlow 1.3+ bundle for making the flow table change atomic.
72 : : * NOTE: If OpenFlow 1.3 or higher is not selected with the '-O' option,
73 : : * OpenFlow 1.4 will be implicitly selected. Also the flow mod will use
74 : : * OpenFlow 1.4, so the semantics may be different (see the comment in
75 : : * parse_options() for details).
76 : : */
77 : : static bool bundle = false;
78 : :
79 : : /* --color: Use color markers. */
80 : : static bool enable_color;
81 : :
82 : : /* --read-only: Do not execute read only commands. */
83 : : static bool read_only;
84 : :
85 : : /* --strict: Use strict matching for flow mod commands? Additionally governs
86 : : * use of nx_pull_match() instead of nx_pull_match_loose() in parse-nx-match.
87 : : */
88 : : static bool strict;
89 : :
90 : : /* --may-create: If true, the mod-group command creates a group that does not
91 : : * yet exist; otherwise, such a command has no effect. */
92 : : static bool may_create;
93 : :
94 : : /* --readd: If true, on replace-flows, re-add even flows that have not changed
95 : : * (to reset flow counters). */
96 : : static bool readd;
97 : :
98 : : /* -F, --flow-format: Allowed protocols. By default, any protocol is
99 : : * allowed. */
100 : : static enum ofputil_protocol allowed_protocols = OFPUTIL_P_ANY;
101 : :
102 : : /* -P, --packet-in-format: Packet IN format to use in monitor and snoop
103 : : * commands. Either one of NXPIF_* to force a particular packet_in format, or
104 : : * -1 to let ovs-ofctl choose the default. */
105 : : static int preferred_packet_in_format = -1;
106 : :
107 : : /* -m, --more: Additional verbosity for ofp-print functions. */
108 : : static int verbosity;
109 : :
110 : : /* --timestamp: Print a timestamp before each received packet on "monitor" and
111 : : * "snoop" command? */
112 : : static bool timestamp;
113 : :
114 : : /* --unixctl-path: Path to use for unixctl server, for "monitor" and "snoop"
115 : : commands. */
116 : : static char *unixctl_path;
117 : :
118 : : /* --sort, --rsort: Sort order. */
119 : : enum sort_order { SORT_ASC, SORT_DESC };
120 : : struct sort_criterion {
121 : : const struct mf_field *field; /* NULL means to sort by priority. */
122 : : enum sort_order order;
123 : : };
124 : : static struct sort_criterion *criteria;
125 : : static size_t n_criteria, allocated_criteria;
126 : :
127 : : static const struct ovs_cmdl_command *get_all_commands(void);
128 : :
129 : : OVS_NO_RETURN static void usage(void);
130 : : static void parse_options(int argc, char *argv[]);
131 : :
132 : : static bool recv_flow_stats_reply(struct vconn *, ovs_be32 send_xid,
133 : : struct ofpbuf **replyp,
134 : : struct ofputil_flow_stats *,
135 : : struct ofpbuf *ofpacts);
136 : : int
137 : 3890 : main(int argc, char *argv[])
138 : : {
139 : 3890 : struct ovs_cmdl_context ctx = { .argc = 0, };
140 : 3890 : set_program_name(argv[0]);
141 : 3890 : service_start(&argc, &argv);
142 : 3890 : parse_options(argc, argv);
143 : 3885 : fatal_ignore_sigpipe();
144 : 3885 : ctx.argc = argc - optind;
145 : 3885 : ctx.argv = argv + optind;
146 : :
147 : 3885 : daemon_become_new_user(false);
148 [ - + ]: 3885 : if (read_only) {
149 : 0 : ovs_cmdl_run_command_read_only(&ctx, get_all_commands());
150 : : } else {
151 : 3885 : ovs_cmdl_run_command(&ctx, get_all_commands());
152 : : }
153 : 3699 : return 0;
154 : : }
155 : :
156 : : static void
157 : 14 : add_sort_criterion(enum sort_order order, const char *field)
158 : : {
159 : : struct sort_criterion *sc;
160 : :
161 [ + + ]: 14 : if (n_criteria >= allocated_criteria) {
162 : 13 : criteria = x2nrealloc(criteria, &allocated_criteria, sizeof *criteria);
163 : : }
164 : :
165 : 14 : sc = &criteria[n_criteria++];
166 [ + + ][ + + ]: 14 : if (!field || !strcasecmp(field, "priority")) {
167 : 8 : sc->field = NULL;
168 : : } else {
169 : 6 : sc->field = mf_from_name(field);
170 [ - + ]: 6 : if (!sc->field) {
171 : 0 : ovs_fatal(0, "%s: unknown field name", field);
172 : : }
173 : : }
174 : 14 : sc->order = order;
175 : 14 : }
176 : :
177 : : static void
178 : 3890 : parse_options(int argc, char *argv[])
179 : : {
180 : : enum {
181 : : OPT_STRICT = UCHAR_MAX + 1,
182 : : OPT_READD,
183 : : OPT_TIMESTAMP,
184 : : OPT_SORT,
185 : : OPT_RSORT,
186 : : OPT_UNIXCTL,
187 : : OPT_BUNDLE,
188 : : OPT_COLOR,
189 : : OPT_MAY_CREATE,
190 : : OPT_READ_ONLY,
191 : : DAEMON_OPTION_ENUMS,
192 : : OFP_VERSION_OPTION_ENUMS,
193 : : VLOG_OPTION_ENUMS
194 : : };
195 : : static const struct option long_options[] = {
196 : : {"timeout", required_argument, NULL, 't'},
197 : : {"strict", no_argument, NULL, OPT_STRICT},
198 : : {"readd", no_argument, NULL, OPT_READD},
199 : : {"flow-format", required_argument, NULL, 'F'},
200 : : {"packet-in-format", required_argument, NULL, 'P'},
201 : : {"more", no_argument, NULL, 'm'},
202 : : {"timestamp", no_argument, NULL, OPT_TIMESTAMP},
203 : : {"sort", optional_argument, NULL, OPT_SORT},
204 : : {"rsort", optional_argument, NULL, OPT_RSORT},
205 : : {"unixctl", required_argument, NULL, OPT_UNIXCTL},
206 : : {"help", no_argument, NULL, 'h'},
207 : : {"option", no_argument, NULL, 'o'},
208 : : {"bundle", no_argument, NULL, OPT_BUNDLE},
209 : : {"color", optional_argument, NULL, OPT_COLOR},
210 : : {"may-create", no_argument, NULL, OPT_MAY_CREATE},
211 : : {"read-only", no_argument, NULL, OPT_READ_ONLY},
212 : : DAEMON_LONG_OPTIONS,
213 : : OFP_VERSION_LONG_OPTIONS,
214 : : VLOG_LONG_OPTIONS,
215 : : STREAM_SSL_LONG_OPTIONS,
216 : : {NULL, 0, NULL, 0},
217 : : };
218 : 3890 : char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
219 : : uint32_t versions;
220 : : enum ofputil_protocol version_protocols;
221 : :
222 : : /* For now, ovs-ofctl only enables OpenFlow 1.0 by default. This is
223 : : * because ovs-ofctl implements command such as "add-flow" as raw OpenFlow
224 : : * requests, but those requests have subtly different semantics in
225 : : * different OpenFlow versions. For example:
226 : : *
227 : : * - In OpenFlow 1.0, a "mod-flow" operation that does not find any
228 : : * existing flow to modify adds a new flow.
229 : : *
230 : : * - In OpenFlow 1.1, a "mod-flow" operation that does not find any
231 : : * existing flow to modify adds a new flow, but only if the mod-flow
232 : : * did not match on the flow cookie.
233 : : *
234 : : * - In OpenFlow 1.2 and a later, a "mod-flow" operation never adds a
235 : : * new flow.
236 : : */
237 : 3890 : set_allowed_ofp_versions("OpenFlow10");
238 : :
239 : : for (;;) {
240 : : unsigned long int timeout;
241 : : int c;
242 : :
243 : 6055 : c = getopt_long(argc, argv, short_options, long_options, NULL);
244 [ + + ]: 6055 : if (c == -1) {
245 : 3888 : break;
246 : : }
247 : :
248 [ - + + + : 2167 : switch (c) {
- + + + -
- - + + +
- + + - +
+ - - - -
+ + - - -
- - - -
- ]
249 : : case 't':
250 : 0 : timeout = strtoul(optarg, NULL, 10);
251 [ # # ]: 0 : if (timeout <= 0) {
252 : 0 : ovs_fatal(0, "value %s on -t or --timeout is not at least 1",
253 : : optarg);
254 : : } else {
255 : 0 : time_alarm(timeout);
256 : : }
257 : 0 : break;
258 : :
259 : : case 'F':
260 : 61 : allowed_protocols = ofputil_protocols_from_string(optarg);
261 [ - + ]: 61 : if (!allowed_protocols) {
262 : 0 : ovs_fatal(0, "%s: invalid flow format(s)", optarg);
263 : : }
264 : 61 : break;
265 : :
266 : : case 'P':
267 : 113 : preferred_packet_in_format =
268 : 113 : ofputil_packet_in_format_from_string(optarg);
269 [ - + ]: 113 : if (preferred_packet_in_format < 0) {
270 : 0 : ovs_fatal(0, "unknown packet-in format `%s'", optarg);
271 : : }
272 : 113 : break;
273 : :
274 : : case 'm':
275 : 18 : verbosity++;
276 : 18 : break;
277 : :
278 : : case 'h':
279 : 0 : usage();
280 : :
281 : : case 'o':
282 : 2 : ovs_cmdl_print_options(long_options);
283 : 2 : exit(EXIT_SUCCESS);
284 : :
285 : : case OPT_BUNDLE:
286 : 122 : bundle = true;
287 : 122 : break;
288 : :
289 : : case OPT_STRICT:
290 : 47 : strict = true;
291 : 47 : break;
292 : :
293 : : case OPT_READ_ONLY:
294 : 0 : read_only = true;
295 : 0 : break;
296 : :
297 : : case OPT_READD:
298 : 0 : readd = true;
299 : 0 : break;
300 : :
301 : : case OPT_TIMESTAMP:
302 : 0 : timestamp = true;
303 : 0 : break;
304 : :
305 : : case OPT_SORT:
306 : 6 : add_sort_criterion(SORT_ASC, optarg);
307 : 6 : break;
308 : :
309 : : case OPT_RSORT:
310 : 2 : add_sort_criterion(SORT_DESC, optarg);
311 : 2 : break;
312 : :
313 : : case OPT_UNIXCTL:
314 : 7 : unixctl_path = optarg;
315 : 7 : break;
316 : :
317 : : case OPT_COLOR:
318 [ # # ]: 0 : if (optarg) {
319 [ # # ]: 0 : if (!strcasecmp(optarg, "always")
320 [ # # ]: 0 : || !strcasecmp(optarg, "yes")
321 [ # # ]: 0 : || !strcasecmp(optarg, "force")) {
322 : 0 : enable_color = true;
323 [ # # ]: 0 : } else if (!strcasecmp(optarg, "never")
324 [ # # ]: 0 : || !strcasecmp(optarg, "no")
325 [ # # ]: 0 : || !strcasecmp(optarg, "none")) {
326 : 0 : enable_color = false;
327 [ # # ]: 0 : } else if (!strcasecmp(optarg, "auto")
328 [ # # ]: 0 : || !strcasecmp(optarg, "tty")
329 [ # # ]: 0 : || !strcasecmp(optarg, "if-tty")) {
330 : : /* Determine whether we need colors, i.e. whether standard
331 : : * output is a tty. */
332 : 0 : enable_color = is_stdout_a_tty();
333 : : } else {
334 : 0 : ovs_fatal(0, "incorrect value `%s' for --color", optarg);
335 : : }
336 : : } else {
337 : 0 : enable_color = is_stdout_a_tty();
338 : : }
339 : 0 : break;
340 : :
341 : : case OPT_MAY_CREATE:
342 : 4 : may_create = true;
343 : 4 : break;
344 : :
345 : 443 : DAEMON_OPTION_HANDLERS
346 : 898 : OFP_VERSION_OPTION_HANDLERS
347 : 444 : VLOG_OPTION_HANDLERS
348 : 0 : STREAM_SSL_OPTION_HANDLERS
349 : :
350 : : case '?':
351 : 0 : exit(EXIT_FAILURE);
352 : :
353 : : default:
354 : 0 : abort();
355 : : }
356 : 2165 : }
357 : :
358 [ + + ]: 3888 : if (n_criteria) {
359 : : /* Always do a final sort pass based on priority. */
360 : 6 : add_sort_criterion(SORT_DESC, "priority");
361 : : }
362 : :
363 : 3888 : free(short_options);
364 : :
365 : : /* Implicit OpenFlow 1.4 with the '--bundle' option. */
366 [ + + ][ + + ]: 4010 : if (bundle && !(get_allowed_ofp_versions() &
367 : 122 : ofputil_protocols_to_version_bitmap(OFPUTIL_P_OF13_UP))) {
368 : : /* Add implicit allowance for OpenFlow 1.4. */
369 : 89 : add_allowed_ofp_versions(ofputil_protocols_to_version_bitmap(
370 : : OFPUTIL_P_OF14_OXM));
371 : : /* Remove all versions that do not support bundles. */
372 : 89 : mask_allowed_ofp_versions(ofputil_protocols_to_version_bitmap(
373 : : OFPUTIL_P_OF13_UP));
374 : : }
375 : 3888 : versions = get_allowed_ofp_versions();
376 : 3888 : version_protocols = ofputil_protocols_from_version_bitmap(versions);
377 [ + + ]: 3888 : if (!(allowed_protocols & version_protocols)) {
378 : 3 : char *protocols = ofputil_protocols_to_string(allowed_protocols);
379 : 3 : struct ds version_s = DS_EMPTY_INITIALIZER;
380 : :
381 : 3 : ofputil_format_version_bitmap_names(&version_s, versions);
382 : 3 : ovs_fatal(0, "None of the enabled OpenFlow versions (%s) supports "
383 : : "any of the enabled flow formats (%s). (Use -O to enable "
384 : : "additional OpenFlow versions or -F to enable additional "
385 : : "flow formats.)", ds_cstr(&version_s), protocols);
386 : : }
387 : 3885 : allowed_protocols &= version_protocols;
388 : 3885 : mask_allowed_ofp_versions(ofputil_protocols_to_version_bitmap(
389 : : allowed_protocols));
390 : :
391 : 3885 : colors_init(enable_color);
392 : 3885 : }
393 : :
394 : : static void
395 : 0 : usage(void)
396 : : {
397 : 0 : printf("%s: OpenFlow switch management utility\n"
398 : : "usage: %s [OPTIONS] COMMAND [ARG...]\n"
399 : : "\nFor OpenFlow switches:\n"
400 : : " show SWITCH show OpenFlow information\n"
401 : : " dump-desc SWITCH print switch description\n"
402 : : " dump-tables SWITCH print table stats\n"
403 : : " dump-table-features SWITCH print table features\n"
404 : : " dump-table-desc SWITCH print table description (OF1.4+)\n"
405 : : " mod-port SWITCH IFACE ACT modify port behavior\n"
406 : : " mod-table SWITCH MOD modify flow table behavior\n"
407 : : " OF1.1/1.2 MOD: controller, continue, drop\n"
408 : : " OF1.4+ MOD: evict, noevict, vacancy:low,high, novacancy\n"
409 : : " get-frags SWITCH print fragment handling behavior\n"
410 : : " set-frags SWITCH FRAG_MODE set fragment handling behavior\n"
411 : : " FRAG_MODE: normal, drop, reassemble, nx-match\n"
412 : : " dump-ports SWITCH [PORT] print port statistics\n"
413 : : " dump-ports-desc SWITCH [PORT] print port descriptions\n"
414 : : " dump-flows SWITCH print all flow entries\n"
415 : : " dump-flows SWITCH FLOW print matching FLOWs\n"
416 : : " dump-aggregate SWITCH print aggregate flow statistics\n"
417 : : " dump-aggregate SWITCH FLOW print aggregate stats for FLOWs\n"
418 : : " queue-stats SWITCH [PORT [QUEUE]] dump queue stats\n"
419 : : " add-flow SWITCH FLOW add flow described by FLOW\n"
420 : : " add-flows SWITCH FILE add flows from FILE\n"
421 : : " mod-flows SWITCH FLOW modify actions of matching FLOWs\n"
422 : : " del-flows SWITCH [FLOW] delete matching FLOWs\n"
423 : : " replace-flows SWITCH FILE replace flows with those in FILE\n"
424 : : " diff-flows SOURCE1 SOURCE2 compare flows from two sources\n"
425 : : " packet-out SWITCH IN_PORT ACTIONS PACKET...\n"
426 : : " execute ACTIONS on PACKET\n"
427 : : " monitor SWITCH [MISSLEN] [invalid_ttl] [watch:[...]]\n"
428 : : " print packets received from SWITCH\n"
429 : : " snoop SWITCH snoop on SWITCH and its controller\n"
430 : : " add-group SWITCH GROUP add group described by GROUP\n"
431 : : " add-groups SWITCH FILE add group from FILE\n"
432 : : " [--may-create] mod-group SWITCH GROUP modify specific group\n"
433 : : " del-groups SWITCH [GROUP] delete matching GROUPs\n"
434 : : " insert-buckets SWITCH [GROUP] add buckets to GROUP\n"
435 : : " remove-buckets SWITCH [GROUP] remove buckets from GROUP\n"
436 : : " dump-group-features SWITCH print group features\n"
437 : : " dump-groups SWITCH [GROUP] print group description\n"
438 : : " dump-group-stats SWITCH [GROUP] print group statistics\n"
439 : : " queue-get-config SWITCH [PORT] print queue config for PORT\n"
440 : : " add-meter SWITCH METER add meter described by METER\n"
441 : : " mod-meter SWITCH METER modify specific METER\n"
442 : : " del-meter SWITCH METER delete METER\n"
443 : : " del-meters SWITCH delete all meters\n"
444 : : " dump-meter SWITCH METER print METER configuration\n"
445 : : " dump-meters SWITCH print all meter configuration\n"
446 : : " meter-stats SWITCH [METER] print meter statistics\n"
447 : : " meter-features SWITCH print meter features\n"
448 : : " add-tlv-map SWITCH MAP add TLV option MAPpings\n"
449 : : " del-tlv-map SWITCH [MAP] delete TLV option MAPpings\n"
450 : : " dump-tlv-map SWITCH print TLV option mappings\n"
451 : : " dump-ipfix-bridge SWITCH print ipfix stats of bridge\n"
452 : : " dump-ipfix-flow SWITCH print flow ipfix of a bridge\n"
453 : : "\nFor OpenFlow switches and controllers:\n"
454 : : " probe TARGET probe whether TARGET is up\n"
455 : : " ping TARGET [N] latency of N-byte echos\n"
456 : : " benchmark TARGET N COUNT bandwidth of COUNT N-byte echos\n"
457 : : "SWITCH or TARGET is an active OpenFlow connection method.\n"
458 : : "\nOther commands:\n"
459 : : " ofp-parse FILE print messages read from FILE\n"
460 : : " ofp-parse-pcap PCAP print OpenFlow read from PCAP\n",
461 : : program_name, program_name);
462 : 0 : vconn_usage(true, false, false);
463 : 0 : daemon_usage();
464 : 0 : ofp_version_usage();
465 : 0 : vlog_usage();
466 : 0 : printf("\nOther options:\n"
467 : : " --strict use strict match for flow commands\n"
468 : : " --read-only do not execute read/write commands\n"
469 : : " --readd replace flows that haven't changed\n"
470 : : " -F, --flow-format=FORMAT force particular flow format\n"
471 : : " -P, --packet-in-format=FRMT force particular packet in format\n"
472 : : " -m, --more be more verbose printing OpenFlow\n"
473 : : " --timestamp (monitor, snoop) print timestamps\n"
474 : : " -t, --timeout=SECS give up after SECS seconds\n"
475 : : " --sort[=field] sort in ascending order\n"
476 : : " --rsort[=field] sort in descending order\n"
477 : : " --unixctl=SOCKET set control socket name\n"
478 : : " --color[=always|never|auto] control use of color in output\n"
479 : : " -h, --help display this help message\n"
480 : : " -V, --version display version information\n");
481 : 0 : exit(EXIT_SUCCESS);
482 : : }
483 : :
484 : : static void
485 : 143 : ofctl_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
486 : : const char *argv[] OVS_UNUSED, void *exiting_)
487 : : {
488 : 143 : bool *exiting = exiting_;
489 : 143 : *exiting = true;
490 : 143 : unixctl_command_reply(conn, NULL);
491 : 143 : }
492 : :
493 : : static void run(int retval, const char *message, ...)
494 : : OVS_PRINTF_FORMAT(2, 3);
495 : :
496 : : static void
497 : 18540 : run(int retval, const char *message, ...)
498 : : {
499 [ + + ]: 18540 : if (retval) {
500 : : va_list args;
501 : :
502 : 23 : va_start(args, message);
503 : 23 : ovs_fatal_valist(retval, message, args);
504 : : }
505 : 18517 : }
506 : :
507 : : /* Generic commands. */
508 : :
509 : : static int
510 : 6771 : open_vconn_socket(const char *name, struct vconn **vconnp)
511 : : {
512 : 6771 : char *vconn_name = xasprintf("unix:%s", name);
513 : : int error;
514 : :
515 : 6771 : error = vconn_open(vconn_name, get_allowed_ofp_versions(), DSCP_DEFAULT,
516 : : vconnp);
517 [ + + ][ - + ]: 6771 : if (error && error != ENOENT) {
518 : 0 : ovs_fatal(0, "%s: failed to open socket (%s)", name,
519 : : ovs_strerror(error));
520 : : }
521 : 6771 : free(vconn_name);
522 : :
523 : 6771 : return error;
524 : : }
525 : :
526 : : enum open_target { MGMT, SNOOP };
527 : :
528 : : static enum ofputil_protocol
529 : 3385 : open_vconn__(const char *name, enum open_target target,
530 : : struct vconn **vconnp)
531 : : {
532 [ + - ]: 3385 : const char *suffix = target == MGMT ? "mgmt" : "snoop";
533 : : char *datapath_name, *datapath_type, *socket_name;
534 : : enum ofputil_protocol protocol;
535 : : char *bridge_path;
536 : : int ofp_version;
537 : : int error;
538 : :
539 : 3385 : bridge_path = xasprintf("%s/%s.%s", ovs_rundir(), name, suffix);
540 : :
541 : 3385 : ofproto_parse_name(name, &datapath_name, &datapath_type);
542 : 3385 : socket_name = xasprintf("%s/%s.%s", ovs_rundir(), datapath_name, suffix);
543 : 3385 : free(datapath_name);
544 : 3385 : free(datapath_type);
545 : :
546 [ + + ]: 3385 : if (strchr(name, ':')) {
547 : 1 : run(vconn_open(name, get_allowed_ofp_versions(), DSCP_DEFAULT, vconnp),
548 : : "connecting to %s", name);
549 [ + - ]: 3384 : } else if (!open_vconn_socket(name, vconnp)) {
550 : : /* Fall Through. */
551 [ + + ]: 3384 : } else if (!open_vconn_socket(bridge_path, vconnp)) {
552 : : /* Fall Through. */
553 [ + - ]: 3 : } else if (!open_vconn_socket(socket_name, vconnp)) {
554 : : /* Fall Through. */
555 : : } else {
556 : 3 : ovs_fatal(0, "%s is not a bridge or a socket", name);
557 : : }
558 : :
559 [ - + ]: 3382 : if (target == SNOOP) {
560 : 0 : vconn_set_recv_any_version(*vconnp);
561 : : }
562 : :
563 : 3382 : free(bridge_path);
564 : 3382 : free(socket_name);
565 : :
566 [ + + ]: 3382 : VLOG_DBG("connecting to %s", vconn_get_name(*vconnp));
567 : 3382 : error = vconn_connect_block(*vconnp);
568 [ - + ]: 3382 : if (error) {
569 : 0 : ovs_fatal(0, "%s: failed to connect to socket (%s)", name,
570 : : ovs_strerror(error));
571 : : }
572 : :
573 : 3382 : ofp_version = vconn_get_version(*vconnp);
574 : 3382 : protocol = ofputil_protocol_from_ofp_version(ofp_version);
575 [ - + ]: 3382 : if (!protocol) {
576 : 0 : ovs_fatal(0, "%s: unsupported OpenFlow version 0x%02x",
577 : : name, ofp_version);
578 : : }
579 : 3382 : return protocol;
580 : : }
581 : :
582 : : static enum ofputil_protocol
583 : 3385 : open_vconn(const char *name, struct vconn **vconnp)
584 : : {
585 : 3385 : return open_vconn__(name, MGMT, vconnp);
586 : : }
587 : :
588 : : static void
589 : 596 : send_openflow_buffer(struct vconn *vconn, struct ofpbuf *buffer)
590 : : {
591 : 596 : run(vconn_send_block(vconn, buffer), "failed to send packet to switch");
592 : 596 : }
593 : :
594 : : static void
595 : 601 : dump_transaction(struct vconn *vconn, struct ofpbuf *request)
596 : : {
597 : 601 : const struct ofp_header *oh = request->data;
598 [ + + ]: 601 : if (ofpmsg_is_stat_request(oh)) {
599 : 547 : ovs_be32 send_xid = oh->xid;
600 : : enum ofpraw request_raw;
601 : : enum ofpraw reply_raw;
602 : 547 : bool done = false;
603 : :
604 : 547 : ofpraw_decode_partial(&request_raw, request->data, request->size);
605 : 547 : reply_raw = ofpraw_stats_request_to_reply(request_raw, oh->version);
606 : :
607 : 547 : send_openflow_buffer(vconn, request);
608 [ + + ]: 1095 : while (!done) {
609 : : ovs_be32 recv_xid;
610 : : struct ofpbuf *reply;
611 : :
612 : 548 : run(vconn_recv_block(vconn, &reply),
613 : : "OpenFlow packet receive failed");
614 : 548 : recv_xid = ((struct ofp_header *) reply->data)->xid;
615 [ + - ]: 548 : if (send_xid == recv_xid) {
616 : : enum ofpraw raw;
617 : :
618 : 548 : ofp_print(stdout, reply->data, reply->size, verbosity + 1);
619 : :
620 : 548 : ofpraw_decode(&raw, reply->data);
621 [ + + ]: 548 : if (ofptype_from_ofpraw(raw) == OFPTYPE_ERROR) {
622 : 21 : done = true;
623 [ + - ]: 527 : } else if (raw == reply_raw) {
624 : 527 : done = !ofpmp_more(reply->data);
625 : : } else {
626 : 548 : ovs_fatal(0, "received bad reply: %s",
627 : 0 : ofp_to_string(reply->data, reply->size,
628 : : verbosity + 1));
629 : : }
630 : : } else {
631 [ # # ]: 0 : VLOG_DBG("received reply with xid %08"PRIx32" "
632 : : "!= expected %08"PRIx32, recv_xid, send_xid);
633 : : }
634 : 548 : ofpbuf_delete(reply);
635 : : }
636 : : } else {
637 : : struct ofpbuf *reply;
638 : :
639 : 54 : run(vconn_transact(vconn, request, &reply), "talking to %s",
640 : : vconn_get_name(vconn));
641 : 54 : ofp_print(stdout, reply->data, reply->size, verbosity + 1);
642 : 54 : ofpbuf_delete(reply);
643 : : }
644 : 601 : }
645 : :
646 : : static void
647 : 61 : dump_trivial_transaction(const char *vconn_name, enum ofpraw raw)
648 : : {
649 : : struct ofpbuf *request;
650 : : struct vconn *vconn;
651 : :
652 : 61 : open_vconn(vconn_name, &vconn);
653 : 61 : request = ofpraw_alloc(raw, vconn_get_version(vconn), 0);
654 : 61 : dump_transaction(vconn, request);
655 : 61 : vconn_close(vconn);
656 : 61 : }
657 : :
658 : : /* Sends all of the 'requests', which should be requests that only have replies
659 : : * if an error occurs, and waits for them to succeed or fail. If an error does
660 : : * occur, prints it and exits with an error.
661 : : *
662 : : * Destroys all of the 'requests'. */
663 : : static void
664 : 13028 : transact_multiple_noreply(struct vconn *vconn, struct ovs_list *requests)
665 : : {
666 : : struct ofpbuf *reply;
667 : :
668 : 13028 : run(vconn_transact_multiple_noreply(vconn, requests, &reply),
669 : : "talking to %s", vconn_get_name(vconn));
670 [ + + ]: 13028 : if (reply) {
671 : 13 : ofp_print(stderr, reply->data, reply->size, verbosity + 2);
672 : 13 : exit(1);
673 : : }
674 : 13015 : ofpbuf_delete(reply);
675 : 13015 : }
676 : :
677 : : /* Frees the error messages as they are printed. */
678 : : static void
679 : 119 : bundle_print_errors(struct ovs_list *errors, struct ovs_list *requests)
680 : : {
681 : : struct vconn_bundle_error *error, *next;
682 : : struct ofpbuf *bmsg;
683 : :
684 : 119 : INIT_CONTAINER(bmsg, requests, list_node);
685 : :
686 [ + + ][ + + ]: 132 : LIST_FOR_EACH_SAFE (error, next, list_node, errors) {
687 : : enum ofperr ofperr;
688 : : struct ofpbuf payload;
689 : :
690 : 13 : ofperr = ofperr_decode_msg(&error->ofp_msg, &payload);
691 [ - + ]: 13 : if (!ofperr) {
692 : 0 : fprintf(stderr, "***decode error***");
693 : : } else {
694 : : /* Default to the likely truncated message. */
695 : 13 : const struct ofp_header *ofp_msg = payload.data;
696 : 13 : size_t msg_len = payload.size;
697 : :
698 : : /* Find the failing message from the requests list to be able to
699 : : * dump the whole message. We assume the errors are returned in
700 : : * the same order as in which the messages are sent to get O(n)
701 : : * rather than O(n^2) processing here. If this heuristics fails we
702 : : * may print the truncated hexdumps instead. */
703 [ + + ]: 35 : LIST_FOR_EACH_CONTINUE (bmsg, list_node, requests) {
704 : 30 : const struct ofp_header *oh = bmsg->data;
705 : :
706 [ + + ]: 30 : if (oh->xid == error->ofp_msg.xid) {
707 : 8 : ofp_msg = oh;
708 : 8 : msg_len = bmsg->size;
709 : 8 : break;
710 : : }
711 : : }
712 : 13 : fprintf(stderr, "Error %s for: ", ofperr_get_name(ofperr));
713 : 13 : ofp_print(stderr, ofp_msg, msg_len, verbosity + 1);
714 : : }
715 : 13 : free(error);
716 : : }
717 : 119 : fflush(stderr);
718 : 119 : }
719 : :
720 : : static void
721 : 119 : bundle_transact(struct vconn *vconn, struct ovs_list *requests, uint16_t flags)
722 : : {
723 : : struct ovs_list errors;
724 : 119 : int retval = vconn_bundle_transact(vconn, requests, flags, &errors);
725 : :
726 : 119 : bundle_print_errors(&errors, requests);
727 : :
728 [ + + ]: 119 : if (retval) {
729 : 8 : ovs_fatal(retval, "talking to %s", vconn_get_name(vconn));
730 : : }
731 : 111 : }
732 : :
733 : : /* Sends 'request', which should be a request that only has a reply if an error
734 : : * occurs, and waits for it to succeed or fail. If an error does occur, prints
735 : : * it and exits with an error.
736 : : *
737 : : * Destroys 'request'. */
738 : : static void
739 : 13024 : transact_noreply(struct vconn *vconn, struct ofpbuf *request)
740 : : {
741 : : struct ovs_list requests;
742 : :
743 : 13024 : ovs_list_init(&requests);
744 : 13024 : ovs_list_push_back(&requests, &request->list_node);
745 : 13024 : transact_multiple_noreply(vconn, &requests);
746 : 13011 : }
747 : :
748 : : static void
749 : 194 : fetch_switch_config(struct vconn *vconn, struct ofputil_switch_config *config)
750 : : {
751 : : struct ofpbuf *request;
752 : : struct ofpbuf *reply;
753 : : enum ofptype type;
754 : :
755 : 194 : request = ofpraw_alloc(OFPRAW_OFPT_GET_CONFIG_REQUEST,
756 : 194 : vconn_get_version(vconn), 0);
757 : 194 : run(vconn_transact(vconn, request, &reply),
758 : : "talking to %s", vconn_get_name(vconn));
759 : :
760 [ + - ]: 194 : if (ofptype_decode(&type, reply->data)
761 [ - + ]: 194 : || type != OFPTYPE_GET_CONFIG_REPLY) {
762 : 0 : ovs_fatal(0, "%s: bad reply to config request", vconn_get_name(vconn));
763 : : }
764 : 194 : ofputil_decode_get_config_reply(reply->data, config);
765 : 194 : ofpbuf_delete(reply);
766 : 194 : }
767 : :
768 : : static void
769 : 156 : set_switch_config(struct vconn *vconn,
770 : : const struct ofputil_switch_config *config)
771 : : {
772 : 156 : enum ofp_version version = vconn_get_version(vconn);
773 : 156 : transact_noreply(vconn, ofputil_encode_set_config(config, version));
774 : 156 : }
775 : :
776 : : static void
777 : 46 : ofctl_show(struct ovs_cmdl_context *ctx)
778 : : {
779 : 46 : const char *vconn_name = ctx->argv[1];
780 : : enum ofp_version version;
781 : : struct vconn *vconn;
782 : : struct ofpbuf *request;
783 : : struct ofpbuf *reply;
784 : : bool has_ports;
785 : :
786 : 46 : open_vconn(vconn_name, &vconn);
787 : 45 : version = vconn_get_version(vconn);
788 : 45 : request = ofpraw_alloc(OFPRAW_OFPT_FEATURES_REQUEST, version, 0);
789 : 45 : run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
790 : :
791 : 45 : has_ports = ofputil_switch_features_has_ports(reply);
792 : 45 : ofp_print(stdout, reply->data, reply->size, verbosity + 1);
793 : 45 : ofpbuf_delete(reply);
794 : :
795 [ + + ]: 45 : if (!has_ports) {
796 : 15 : request = ofputil_encode_port_desc_stats_request(version, OFPP_ANY);
797 : 15 : dump_transaction(vconn, request);
798 : : }
799 : 45 : dump_trivial_transaction(vconn_name, OFPRAW_OFPT_GET_CONFIG_REQUEST);
800 : 45 : vconn_close(vconn);
801 : 45 : }
802 : :
803 : : static void
804 : 0 : ofctl_dump_desc(struct ovs_cmdl_context *ctx)
805 : : {
806 : 0 : dump_trivial_transaction(ctx->argv[1], OFPRAW_OFPST_DESC_REQUEST);
807 : 0 : }
808 : :
809 : : static void
810 : 10 : ofctl_dump_tables(struct ovs_cmdl_context *ctx)
811 : : {
812 : 10 : dump_trivial_transaction(ctx->argv[1], OFPRAW_OFPST_TABLE_REQUEST);
813 : 10 : }
814 : :
815 : : static void
816 : 2 : ofctl_dump_table_features(struct ovs_cmdl_context *ctx)
817 : : {
818 : : struct ofpbuf *request;
819 : : struct vconn *vconn;
820 : :
821 : 2 : open_vconn(ctx->argv[1], &vconn);
822 : 2 : request = ofputil_encode_table_features_request(vconn_get_version(vconn));
823 : :
824 : : /* The following is similar to dump_trivial_transaction(), but it
825 : : * maintains the previous 'ofputil_table_features' from one stats reply
826 : : * message to the next, which allows duplication to be eliminated in the
827 : : * output across messages. Otherwise the output is much larger and harder
828 : : * to read, because only 17 or so ofputil_table_features elements fit in a
829 : : * single 64 kB OpenFlow message and therefore you get a ton of repetition
830 : : * (every 17th element is printed in full instead of abbreviated). */
831 : :
832 : 2 : const struct ofp_header *request_oh = request->data;
833 : 2 : ovs_be32 send_xid = request_oh->xid;
834 : 2 : bool done = false;
835 : :
836 : : struct ofputil_table_features prev;
837 : 2 : int n = 0;
838 : :
839 : 2 : send_openflow_buffer(vconn, request);
840 [ + + ]: 36 : while (!done) {
841 : : ovs_be32 recv_xid;
842 : : struct ofpbuf *reply;
843 : :
844 : 34 : run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed");
845 : 34 : recv_xid = ((struct ofp_header *) reply->data)->xid;
846 [ + - ]: 34 : if (send_xid == recv_xid) {
847 : : enum ofptype type;
848 : : enum ofperr error;
849 : 34 : error = ofptype_decode(&type, reply->data);
850 [ - + ]: 34 : if (error) {
851 : 0 : ovs_fatal(0, "decode error: %s", ofperr_get_name(error));
852 [ - + ]: 34 : } else if (type == OFPTYPE_ERROR) {
853 : 0 : ofp_print(stdout, reply->data, reply->size, verbosity + 1);
854 : 0 : done = true;
855 [ + - ]: 34 : } else if (type == OFPTYPE_TABLE_FEATURES_STATS_REPLY) {
856 : 34 : done = !ofpmp_more(reply->data);
857 : : for (;;) {
858 : : struct ofputil_table_features tf;
859 : : int retval;
860 : :
861 : 542 : retval = ofputil_decode_table_features(reply, &tf, true);
862 [ + + ]: 542 : if (retval) {
863 [ - + ]: 34 : if (retval != EOF) {
864 : 0 : ovs_fatal(0, "decode error: %s",
865 : : ofperr_get_name(retval));
866 : : }
867 : 34 : break;
868 : : }
869 : :
870 : 508 : struct ds s = DS_EMPTY_INITIALIZER;
871 [ + + ]: 508 : ofp_print_table_features(&s, &tf, n ? &prev : NULL,
872 : : NULL, NULL);
873 : 508 : puts(ds_cstr(&s));
874 : 508 : ds_destroy(&s);
875 : :
876 : 508 : prev = tf;
877 : 508 : n++;
878 : 508 : }
879 : : } else {
880 : 34 : ovs_fatal(0, "received bad reply: %s",
881 : 0 : ofp_to_string(reply->data, reply->size,
882 : : verbosity + 1));
883 : : }
884 : : } else {
885 [ # # ]: 0 : VLOG_DBG("received reply with xid %08"PRIx32" "
886 : : "!= expected %08"PRIx32, recv_xid, send_xid);
887 : : }
888 : 34 : ofpbuf_delete(reply);
889 : : }
890 : :
891 : 2 : vconn_close(vconn);
892 : 2 : }
893 : :
894 : : static void
895 : 3 : ofctl_dump_table_desc(struct ovs_cmdl_context *ctx)
896 : : {
897 : : struct ofpbuf *request;
898 : : struct vconn *vconn;
899 : :
900 : 3 : open_vconn(ctx->argv[1], &vconn);
901 : 3 : request = ofputil_encode_table_desc_request(vconn_get_version(vconn));
902 [ + - ]: 3 : if (request) {
903 : 3 : dump_transaction(vconn, request);
904 : : }
905 : :
906 : 3 : vconn_close(vconn);
907 : 3 : }
908 : :
909 : :
910 : : static bool
911 : 41 : str_to_ofp(const char *s, ofp_port_t *ofp_port)
912 : : {
913 : : bool ret;
914 : : uint32_t port_;
915 : :
916 : 41 : ret = str_to_uint(s, 10, &port_);
917 : 41 : *ofp_port = u16_to_ofp(port_);
918 : 41 : return ret;
919 : : }
920 : :
921 : : struct port_iterator {
922 : : struct vconn *vconn;
923 : :
924 : : enum { PI_FEATURES, PI_PORT_DESC } variant;
925 : : struct ofpbuf *reply;
926 : : ovs_be32 send_xid;
927 : : bool more;
928 : : };
929 : :
930 : : static void
931 : 17 : port_iterator_fetch_port_desc(struct port_iterator *pi)
932 : : {
933 : 17 : pi->variant = PI_PORT_DESC;
934 : 17 : pi->more = true;
935 : :
936 : 17 : struct ofpbuf *rq = ofputil_encode_port_desc_stats_request(
937 : 17 : vconn_get_version(pi->vconn), OFPP_ANY);
938 : 17 : pi->send_xid = ((struct ofp_header *) rq->data)->xid;
939 : 17 : send_openflow_buffer(pi->vconn, rq);
940 : 17 : }
941 : :
942 : : static void
943 : 25 : port_iterator_fetch_features(struct port_iterator *pi)
944 : : {
945 : 25 : pi->variant = PI_FEATURES;
946 : :
947 : : /* Fetch the switch's ofp_switch_features. */
948 : 25 : enum ofp_version version = vconn_get_version(pi->vconn);
949 : 25 : struct ofpbuf *rq = ofpraw_alloc(OFPRAW_OFPT_FEATURES_REQUEST, version, 0);
950 : 25 : run(vconn_transact(pi->vconn, rq, &pi->reply),
951 : 25 : "talking to %s", vconn_get_name(pi->vconn));
952 : :
953 : : enum ofptype type;
954 [ + - ]: 25 : if (ofptype_decode(&type, pi->reply->data)
955 [ - + ]: 25 : || type != OFPTYPE_FEATURES_REPLY) {
956 : 0 : ovs_fatal(0, "%s: received bad features reply",
957 : 0 : vconn_get_name(pi->vconn));
958 : : }
959 [ - + ]: 25 : if (!ofputil_switch_features_has_ports(pi->reply)) {
960 : : /* The switch features reply does not contain a complete list of ports.
961 : : * Probably, there are more ports than will fit into a single 64 kB
962 : : * OpenFlow message. Use OFPST_PORT_DESC to get a complete list of
963 : : * ports. */
964 : 0 : ofpbuf_delete(pi->reply);
965 : 0 : pi->reply = NULL;
966 : 0 : port_iterator_fetch_port_desc(pi);
967 : 0 : return;
968 : : }
969 : :
970 : : struct ofputil_switch_features features;
971 : 25 : enum ofperr error = ofputil_pull_switch_features(pi->reply, &features);
972 [ - + ]: 25 : if (error) {
973 : 25 : ovs_fatal(0, "%s: failed to decode features reply (%s)",
974 : 0 : vconn_get_name(pi->vconn), ofperr_to_string(error));
975 : : }
976 : : }
977 : :
978 : : /* Initializes 'pi' to prepare for iterating through all of the ports on the
979 : : * OpenFlow switch to which 'vconn' is connected.
980 : : *
981 : : * During iteration, the client should not make other use of 'vconn', because
982 : : * that can cause other messages to be interleaved with the replies used by the
983 : : * iterator and thus some ports may be missed or a hang can occur. */
984 : : static void
985 : 42 : port_iterator_init(struct port_iterator *pi, struct vconn *vconn)
986 : : {
987 : 42 : memset(pi, 0, sizeof *pi);
988 : 42 : pi->vconn = vconn;
989 [ + + ]: 42 : if (vconn_get_version(vconn) < OFP13_VERSION) {
990 : 25 : port_iterator_fetch_features(pi);
991 : : } else {
992 : 17 : port_iterator_fetch_port_desc(pi);
993 : : }
994 : 42 : }
995 : :
996 : : /* Obtains the next port from 'pi'. On success, initializes '*pp' with the
997 : : * port's details and returns true, otherwise (if all the ports have already
998 : : * been seen), returns false. */
999 : : static bool
1000 : 55 : port_iterator_next(struct port_iterator *pi, struct ofputil_phy_port *pp)
1001 : : {
1002 : : for (;;) {
1003 [ + + ]: 72 : if (pi->reply) {
1004 : 55 : int retval = ofputil_pull_phy_port(vconn_get_version(pi->vconn),
1005 : : pi->reply, pp);
1006 [ + + ]: 55 : if (!retval) {
1007 : 55 : return true;
1008 [ - + ]: 1 : } else if (retval != EOF) {
1009 : 0 : ovs_fatal(0, "received bad reply: %s",
1010 : 0 : ofp_to_string(pi->reply->data, pi->reply->size,
1011 : : verbosity + 1));
1012 : : }
1013 : : }
1014 : :
1015 [ + + ][ - + ]: 18 : if (pi->variant == PI_FEATURES || !pi->more) {
1016 : 1 : return false;
1017 : : }
1018 : :
1019 : : ovs_be32 recv_xid;
1020 : : do {
1021 : 17 : ofpbuf_delete(pi->reply);
1022 : 17 : run(vconn_recv_block(pi->vconn, &pi->reply),
1023 : : "OpenFlow receive failed");
1024 : 17 : recv_xid = ((struct ofp_header *) pi->reply->data)->xid;
1025 [ - + ]: 17 : } while (pi->send_xid != recv_xid);
1026 : :
1027 : 17 : struct ofp_header *oh = pi->reply->data;
1028 : : enum ofptype type;
1029 [ + - ]: 17 : if (ofptype_pull(&type, pi->reply)
1030 [ - + ]: 17 : || type != OFPTYPE_PORT_DESC_STATS_REPLY) {
1031 : 0 : ovs_fatal(0, "received bad reply: %s",
1032 : 0 : ofp_to_string(pi->reply->data, pi->reply->size,
1033 : : verbosity + 1));
1034 : : }
1035 : :
1036 : 17 : pi->more = (ofpmp_flags(oh) & OFPSF_REPLY_MORE) != 0;
1037 : 17 : }
1038 : : }
1039 : :
1040 : : /* Destroys iterator 'pi'. */
1041 : : static void
1042 : 42 : port_iterator_destroy(struct port_iterator *pi)
1043 : : {
1044 [ + - ]: 42 : if (pi) {
1045 [ + + ][ - + ]: 42 : while (pi->variant == PI_PORT_DESC && pi->more) {
1046 : : /* Drain vconn's queue of any other replies for this request. */
1047 : : struct ofputil_phy_port pp;
1048 : 0 : port_iterator_next(pi, &pp);
1049 : : }
1050 : :
1051 : 42 : ofpbuf_delete(pi->reply);
1052 : : }
1053 : 42 : }
1054 : :
1055 : : /* Opens a connection to 'vconn_name', fetches the port structure for
1056 : : * 'port_name' (which may be a port name or number), and copies it into
1057 : : * '*pp'. */
1058 : : static void
1059 : 41 : fetch_ofputil_phy_port(const char *vconn_name, const char *port_name,
1060 : : struct ofputil_phy_port *pp)
1061 : : {
1062 : : struct vconn *vconn;
1063 : : ofp_port_t port_no;
1064 : 41 : bool found = false;
1065 : :
1066 : : /* Try to interpret the argument as a port number. */
1067 [ + + ]: 41 : if (!str_to_ofp(port_name, &port_no)) {
1068 : 39 : port_no = OFPP_NONE;
1069 : : }
1070 : :
1071 : : /* OpenFlow 1.0, 1.1, and 1.2 put the list of ports in the
1072 : : * OFPT_FEATURES_REPLY message. OpenFlow 1.3 and later versions put it
1073 : : * into the OFPST_PORT_DESC reply. Try it the correct way. */
1074 : 41 : open_vconn(vconn_name, &vconn);
1075 : : struct port_iterator pi;
1076 [ + - ]: 51 : for (port_iterator_init(&pi, vconn); port_iterator_next(&pi, pp); ) {
1077 [ + + ][ + + ]: 51 : if (port_no != OFPP_NONE
1078 : 5 : ? port_no == pp->port_no
1079 : 46 : : !strcmp(pp->name, port_name)) {
1080 : 41 : found = true;
1081 : 41 : break;
1082 : : }
1083 : : }
1084 : 41 : port_iterator_destroy(&pi);
1085 : 41 : vconn_close(vconn);
1086 : :
1087 [ - + ]: 41 : if (!found) {
1088 : 0 : ovs_fatal(0, "%s: couldn't find port `%s'", vconn_name, port_name);
1089 : : }
1090 : 41 : }
1091 : :
1092 : : /* Returns the port number corresponding to 'port_name' (which may be a port
1093 : : * name or number) within the switch 'vconn_name'. */
1094 : : static ofp_port_t
1095 : 1393 : str_to_port_no(const char *vconn_name, const char *port_name)
1096 : : {
1097 : : ofp_port_t port_no;
1098 : :
1099 [ + + ]: 1393 : if (ofputil_port_from_string(port_name, &port_no)) {
1100 : 1391 : return port_no;
1101 : : } else {
1102 : : struct ofputil_phy_port pp;
1103 : :
1104 : 2 : fetch_ofputil_phy_port(vconn_name, port_name, &pp);
1105 : 1393 : return pp.port_no;
1106 : : }
1107 : : }
1108 : :
1109 : : static bool
1110 : 559 : try_set_protocol(struct vconn *vconn, enum ofputil_protocol want,
1111 : : enum ofputil_protocol *cur)
1112 : : {
1113 : : for (;;) {
1114 : : struct ofpbuf *request, *reply;
1115 : : enum ofputil_protocol next;
1116 : :
1117 : 1006 : request = ofputil_encode_set_protocol(*cur, want, &next);
1118 [ + + ]: 1006 : if (!request) {
1119 : 559 : return *cur == want;
1120 : : }
1121 : :
1122 : 447 : run(vconn_transact_noreply(vconn, request, &reply),
1123 : : "talking to %s", vconn_get_name(vconn));
1124 [ - + ]: 447 : if (reply) {
1125 : 0 : char *s = ofp_to_string(reply->data, reply->size, 2);
1126 [ # # ]: 0 : VLOG_DBG("%s: failed to set protocol, switch replied: %s",
1127 : : vconn_get_name(vconn), s);
1128 : 0 : free(s);
1129 : 0 : ofpbuf_delete(reply);
1130 : 0 : return false;
1131 : : }
1132 : :
1133 : 447 : *cur = next;
1134 : 447 : }
1135 : : }
1136 : :
1137 : : static enum ofputil_protocol
1138 : 408 : set_protocol_for_flow_dump(struct vconn *vconn,
1139 : : enum ofputil_protocol cur_protocol,
1140 : : enum ofputil_protocol usable_protocols)
1141 : : {
1142 : : char *usable_s;
1143 : : int i;
1144 : :
1145 [ + + ]: 2559 : for (i = 0; i < ofputil_n_flow_dump_protocols; i++) {
1146 : 2558 : enum ofputil_protocol f = ofputil_flow_dump_protocols[i];
1147 [ + + ]: 2558 : if (f & usable_protocols & allowed_protocols
1148 [ + - ]: 407 : && try_set_protocol(vconn, f, &cur_protocol)) {
1149 : 407 : return f;
1150 : : }
1151 : : }
1152 : :
1153 : 1 : usable_s = ofputil_protocols_to_string(usable_protocols);
1154 [ - + ]: 1 : if (usable_protocols & allowed_protocols) {
1155 : 0 : ovs_fatal(0, "switch does not support any of the usable flow "
1156 : : "formats (%s)", usable_s);
1157 : : } else {
1158 : 1 : char *allowed_s = ofputil_protocols_to_string(allowed_protocols);
1159 : 1 : ovs_fatal(0, "none of the usable flow formats (%s) is among the "
1160 : : "allowed flow formats (%s)", usable_s, allowed_s);
1161 : : }
1162 : : }
1163 : :
1164 : : static struct vconn *
1165 : 393 : prepare_dump_flows(int argc, char *argv[], bool aggregate,
1166 : : struct ofpbuf **requestp)
1167 : : {
1168 : : enum ofputil_protocol usable_protocols, protocol;
1169 : : struct ofputil_flow_stats_request fsr;
1170 : : struct vconn *vconn;
1171 : : char *error;
1172 : :
1173 [ + + ]: 393 : error = parse_ofp_flow_stats_request_str(&fsr, aggregate,
1174 : : argc > 2 ? argv[2] : "",
1175 : : &usable_protocols);
1176 [ - + ]: 393 : if (error) {
1177 : 0 : ovs_fatal(0, "%s", error);
1178 : : }
1179 : :
1180 : 393 : protocol = open_vconn(argv[1], &vconn);
1181 : 391 : protocol = set_protocol_for_flow_dump(vconn, protocol, usable_protocols);
1182 : 390 : *requestp = ofputil_encode_flow_stats_request(&fsr, protocol);
1183 : 390 : return vconn;
1184 : : }
1185 : :
1186 : : static void
1187 : 387 : ofctl_dump_flows__(int argc, char *argv[], bool aggregate)
1188 : : {
1189 : : struct ofpbuf *request;
1190 : : struct vconn *vconn;
1191 : :
1192 : 387 : vconn = prepare_dump_flows(argc, argv, aggregate, &request);
1193 : 384 : dump_transaction(vconn, request);
1194 : 384 : vconn_close(vconn);
1195 : 384 : }
1196 : :
1197 : : static void
1198 : 154 : get_match_field(const struct mf_field *field, const struct match *match,
1199 : : union mf_value *value)
1200 : : {
1201 [ + + ][ + - ]: 154 : if (!match->tun_md.valid || (field->id < MFF_TUN_METADATA0 ||
[ + + ]
1202 : 22 : field->id >= MFF_TUN_METADATA0 +
1203 : : TUN_METADATA_NUM_OPTS)) {
1204 : 152 : mf_get_value(field, &match->flow, value);
1205 : : } else {
1206 : 2 : const struct tun_metadata_loc *loc = &match->tun_md.entry[field->id -
1207 : : MFF_TUN_METADATA0].loc;
1208 : :
1209 : : /* Since we don't have a tunnel mapping table, extract the value
1210 : : * from the locally allocated location in the match. */
1211 : 2 : memset(value, 0, field->n_bytes - loc->len);
1212 : 2 : memcpy(value->tun_metadata + field->n_bytes - loc->len,
1213 : 6 : match->flow.tunnel.metadata.opts.u8 + loc->c.offset, loc->len);
1214 : : }
1215 : 154 : }
1216 : :
1217 : : static int
1218 : 140 : compare_flows(const void *afs_, const void *bfs_)
1219 : : {
1220 : 140 : const struct ofputil_flow_stats *afs = afs_;
1221 : 140 : const struct ofputil_flow_stats *bfs = bfs_;
1222 : 140 : const struct match *a = &afs->match;
1223 : 140 : const struct match *b = &bfs->match;
1224 : : const struct sort_criterion *sc;
1225 : :
1226 [ + - ]: 177 : for (sc = criteria; sc < &criteria[n_criteria]; sc++) {
1227 : 177 : const struct mf_field *f = sc->field;
1228 : : int ret;
1229 : :
1230 [ + + ]: 177 : if (!f) {
1231 : 78 : int a_pri = afs->priority;
1232 : 78 : int b_pri = bfs->priority;
1233 [ + + ]: 78 : ret = a_pri < b_pri ? -1 : a_pri > b_pri;
1234 : : } else {
1235 : : bool ina, inb;
1236 : :
1237 : 99 : ina = mf_are_prereqs_ok(f, &a->flow, NULL)
1238 [ + + ][ + + ]: 99 : && !mf_is_all_wild(f, &a->wc);
1239 : 99 : inb = mf_are_prereqs_ok(f, &b->flow, NULL)
1240 [ + + ][ + + ]: 99 : && !mf_is_all_wild(f, &b->wc);
1241 [ + + ]: 99 : if (ina != inb) {
1242 : : /* Skip the test for sc->order, so that missing fields always
1243 : : * sort to the end whether we're sorting in ascending or
1244 : : * descending order. */
1245 [ + + ]: 22 : return ina ? -1 : 1;
1246 : : } else {
1247 : : union mf_value aval, bval;
1248 : :
1249 : 77 : get_match_field(f, a, &aval);
1250 : 77 : get_match_field(f, b, &bval);
1251 : 77 : ret = memcmp(&aval, &bval, f->n_bytes);
1252 : : }
1253 : : }
1254 : :
1255 [ + + ]: 155 : if (ret) {
1256 [ + + ]: 118 : return sc->order == SORT_ASC ? ret : -ret;
1257 : : }
1258 : : }
1259 : :
1260 : 0 : return 0;
1261 : : }
1262 : :
1263 : : static void
1264 : 388 : ofctl_dump_flows(struct ovs_cmdl_context *ctx)
1265 : : {
1266 [ + + ]: 388 : if (!n_criteria) {
1267 : 382 : ofctl_dump_flows__(ctx->argc, ctx->argv, false);
1268 : 379 : return;
1269 : : } else {
1270 : : struct ofputil_flow_stats *fses;
1271 : : size_t n_fses, allocated_fses;
1272 : : struct ofpbuf *request;
1273 : : struct ofpbuf ofpacts;
1274 : : struct ofpbuf *reply;
1275 : : struct vconn *vconn;
1276 : : ovs_be32 send_xid;
1277 : : struct ds s;
1278 : : size_t i;
1279 : :
1280 : 6 : vconn = prepare_dump_flows(ctx->argc, ctx->argv, false, &request);
1281 : 6 : send_xid = ((struct ofp_header *) request->data)->xid;
1282 : 6 : send_openflow_buffer(vconn, request);
1283 : :
1284 : 6 : fses = NULL;
1285 : 6 : n_fses = allocated_fses = 0;
1286 : 6 : reply = NULL;
1287 : 6 : ofpbuf_init(&ofpacts, 0);
1288 : : for (;;) {
1289 : : struct ofputil_flow_stats *fs;
1290 : :
1291 [ + + ]: 72 : if (n_fses >= allocated_fses) {
1292 : 30 : fses = x2nrealloc(fses, &allocated_fses, sizeof *fses);
1293 : : }
1294 : :
1295 : 72 : fs = &fses[n_fses];
1296 [ + + ]: 72 : if (!recv_flow_stats_reply(vconn, send_xid, &reply, fs,
1297 : : &ofpacts)) {
1298 : 6 : break;
1299 : : }
1300 : 66 : fs->ofpacts = xmemdup(fs->ofpacts, fs->ofpacts_len);
1301 : 66 : n_fses++;
1302 : 66 : }
1303 : 6 : ofpbuf_uninit(&ofpacts);
1304 : :
1305 : 6 : qsort(fses, n_fses, sizeof *fses, compare_flows);
1306 : :
1307 : 6 : ds_init(&s);
1308 [ + + ]: 72 : for (i = 0; i < n_fses; i++) {
1309 : 66 : ds_clear(&s);
1310 : 66 : ofp_print_flow_stats(&s, &fses[i]);
1311 : 66 : puts(ds_cstr(&s));
1312 : : }
1313 : 6 : ds_destroy(&s);
1314 : :
1315 [ + + ]: 72 : for (i = 0; i < n_fses; i++) {
1316 : 66 : free(CONST_CAST(struct ofpact *, fses[i].ofpacts));
1317 : : }
1318 : 6 : free(fses);
1319 : :
1320 : 6 : vconn_close(vconn);
1321 : : }
1322 : : }
1323 : :
1324 : : static void
1325 : 5 : ofctl_dump_aggregate(struct ovs_cmdl_context *ctx)
1326 : : {
1327 : 5 : ofctl_dump_flows__(ctx->argc, ctx->argv, true);
1328 : 5 : }
1329 : :
1330 : : static void
1331 : 35 : ofctl_queue_stats(struct ovs_cmdl_context *ctx)
1332 : : {
1333 : : struct ofpbuf *request;
1334 : : struct vconn *vconn;
1335 : : struct ofputil_queue_stats_request oqs;
1336 : :
1337 : 35 : open_vconn(ctx->argv[1], &vconn);
1338 : :
1339 [ + + ][ + - ]: 35 : if (ctx->argc > 2 && ctx->argv[2][0] && strcasecmp(ctx->argv[2], "all")) {
[ + - ]
1340 : 30 : oqs.port_no = str_to_port_no(ctx->argv[1], ctx->argv[2]);
1341 : : } else {
1342 : 5 : oqs.port_no = OFPP_ANY;
1343 : : }
1344 [ + + ][ + - ]: 35 : if (ctx->argc > 3 && ctx->argv[3][0] && strcasecmp(ctx->argv[3], "all")) {
[ + - ]
1345 : 20 : oqs.queue_id = atoi(ctx->argv[3]);
1346 : : } else {
1347 : 15 : oqs.queue_id = OFPQ_ALL;
1348 : : }
1349 : :
1350 : 35 : request = ofputil_encode_queue_stats_request(vconn_get_version(vconn), &oqs);
1351 : 35 : dump_transaction(vconn, request);
1352 : 35 : vconn_close(vconn);
1353 : 35 : }
1354 : :
1355 : : static void
1356 : 12 : ofctl_queue_get_config(struct ovs_cmdl_context *ctx)
1357 : : {
1358 : 12 : const char *vconn_name = ctx->argv[1];
1359 [ + + ]: 12 : const char *port_name = ctx->argc > 2 ? ctx->argv[2] : "any";
1360 : 12 : ofp_port_t port = str_to_port_no(vconn_name, port_name);
1361 [ + + ]: 12 : const char *queue_name = ctx->argc > 3 ? ctx->argv[3] : "all";
1362 : 24 : uint32_t queue = (!strcasecmp(queue_name, "all")
1363 : : ? OFPQ_ALL
1364 [ + + ]: 12 : : atoi(queue_name));
1365 : : struct vconn *vconn;
1366 : :
1367 : 12 : enum ofputil_protocol protocol = open_vconn(vconn_name, &vconn);
1368 : 12 : enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
1369 [ + + ][ + + ]: 13 : if (port == OFPP_ANY && version == OFP10_VERSION) {
1370 : : /* The user requested all queues on all ports. OpenFlow 1.0 only
1371 : : * supports getting queues for an individual port, so to implement the
1372 : : * user's request we have to get a list of all the ports.
1373 : : *
1374 : : * We use a second vconn to avoid having to accumulate a list of all of
1375 : : * the ports. */
1376 : : struct vconn *vconn2;
1377 : 1 : enum ofputil_protocol protocol2 = open_vconn(vconn_name, &vconn2);
1378 : 1 : enum ofp_version version2 = ofputil_protocol_to_ofp_version(protocol2);
1379 : :
1380 : : struct port_iterator pi;
1381 : : struct ofputil_phy_port pp;
1382 [ + + ]: 4 : for (port_iterator_init(&pi, vconn); port_iterator_next(&pi, &pp); ) {
1383 [ + + ]: 3 : if (ofp_to_u16(pp.port_no) < ofp_to_u16(OFPP_MAX)) {
1384 : 2 : dump_transaction(vconn2,
1385 : : ofputil_encode_queue_get_config_request(
1386 : : version2, pp.port_no, queue));
1387 : : }
1388 : : }
1389 : 1 : port_iterator_destroy(&pi);
1390 : 1 : vconn_close(vconn2);
1391 : : } else {
1392 : 11 : dump_transaction(vconn, ofputil_encode_queue_get_config_request(
1393 : : version, port, queue));
1394 : : }
1395 : 12 : vconn_close(vconn);
1396 : 12 : }
1397 : :
1398 : : static enum ofputil_protocol
1399 : 1122 : open_vconn_for_flow_mod(const char *remote, struct vconn **vconnp,
1400 : : enum ofputil_protocol usable_protocols)
1401 : : {
1402 : : enum ofputil_protocol cur_protocol;
1403 : : char *usable_s;
1404 : : int i;
1405 : :
1406 [ + + ]: 1122 : if (!(usable_protocols & allowed_protocols)) {
1407 : 6 : char *allowed_s = ofputil_protocols_to_string(allowed_protocols);
1408 : 6 : usable_s = ofputil_protocols_to_string(usable_protocols);
1409 : 6 : ovs_fatal(0, "none of the usable flow formats (%s) is among the "
1410 : : "allowed flow formats (%s)", usable_s, allowed_s);
1411 : : }
1412 : :
1413 : : /* If the initial flow format is allowed and usable, keep it. */
1414 : 1116 : cur_protocol = open_vconn(remote, vconnp);
1415 [ + + ]: 1116 : if (usable_protocols & allowed_protocols & cur_protocol) {
1416 : 964 : return cur_protocol;
1417 : : }
1418 : :
1419 : : /* Otherwise try each flow format in turn. */
1420 [ + - ]: 414 : for (i = 0; i < sizeof(enum ofputil_protocol) * CHAR_BIT; i++) {
1421 : 414 : enum ofputil_protocol f = 1 << i;
1422 : :
1423 [ + + ]: 414 : if (f != cur_protocol
1424 [ + + ]: 262 : && f & usable_protocols & allowed_protocols
1425 [ + - ]: 152 : && try_set_protocol(*vconnp, f, &cur_protocol)) {
1426 : 152 : return f;
1427 : : }
1428 : : }
1429 : :
1430 : 0 : usable_s = ofputil_protocols_to_string(usable_protocols);
1431 : 1116 : ovs_fatal(0, "switch does not support any of the usable flow "
1432 : : "formats (%s)", usable_s);
1433 : : }
1434 : :
1435 : : static void
1436 : 77 : bundle_flow_mod__(const char *remote, struct ofputil_flow_mod *fms,
1437 : : size_t n_fms, enum ofputil_protocol usable_protocols)
1438 : : {
1439 : : enum ofputil_protocol protocol;
1440 : : struct vconn *vconn;
1441 : : struct ovs_list requests;
1442 : : size_t i;
1443 : :
1444 : 77 : ovs_list_init(&requests);
1445 : :
1446 : : /* Bundles need OpenFlow 1.3+. */
1447 : 77 : usable_protocols &= OFPUTIL_P_OF13_UP;
1448 : 77 : protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols);
1449 : :
1450 [ + + ]: 726 : for (i = 0; i < n_fms; i++) {
1451 : 649 : struct ofputil_flow_mod *fm = &fms[i];
1452 : 649 : struct ofpbuf *request = ofputil_encode_flow_mod(fm, protocol);
1453 : :
1454 : 649 : ovs_list_push_back(&requests, &request->list_node);
1455 : 649 : free(CONST_CAST(struct ofpact *, fm->ofpacts));
1456 : : }
1457 : :
1458 : 77 : bundle_transact(vconn, &requests, OFPBF_ORDERED | OFPBF_ATOMIC);
1459 : 74 : ofpbuf_list_delete(&requests);
1460 : 74 : vconn_close(vconn);
1461 : 74 : }
1462 : :
1463 : : static void
1464 : 972 : ofctl_flow_mod__(const char *remote, struct ofputil_flow_mod *fms,
1465 : : size_t n_fms, enum ofputil_protocol usable_protocols)
1466 : : {
1467 : : enum ofputil_protocol protocol;
1468 : : struct vconn *vconn;
1469 : : size_t i;
1470 : :
1471 [ + + ]: 972 : if (bundle) {
1472 : 77 : bundle_flow_mod__(remote, fms, n_fms, usable_protocols);
1473 : 74 : return;
1474 : : }
1475 : :
1476 : 895 : protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols);
1477 : :
1478 [ + + ]: 12126 : for (i = 0; i < n_fms; i++) {
1479 : 11243 : struct ofputil_flow_mod *fm = &fms[i];
1480 : :
1481 : 11243 : transact_noreply(vconn, ofputil_encode_flow_mod(fm, protocol));
1482 : 11235 : free(CONST_CAST(struct ofpact *, fm->ofpacts));
1483 : : }
1484 : 883 : vconn_close(vconn);
1485 : : }
1486 : :
1487 : : static void
1488 : 297 : ofctl_flow_mod_file(int argc OVS_UNUSED, char *argv[], int command)
1489 : : {
1490 : : enum ofputil_protocol usable_protocols;
1491 : 297 : struct ofputil_flow_mod *fms = NULL;
1492 : 297 : size_t n_fms = 0;
1493 : : char *error;
1494 : :
1495 [ + + ]: 297 : if (command == OFPFC_ADD) {
1496 : : /* Allow the file to specify a mix of commands. If none specified at
1497 : : * the beginning of any given line, then the default is OFPFC_ADD, so
1498 : : * this is backwards compatible. */
1499 : 296 : command = -2;
1500 : : }
1501 : 297 : error = parse_ofp_flow_mod_file(argv[2], command, &fms, &n_fms,
1502 : : &usable_protocols);
1503 [ - + ]: 297 : if (error) {
1504 : 0 : ovs_fatal(0, "%s", error);
1505 : : }
1506 : 297 : ofctl_flow_mod__(argv[1], fms, n_fms, usable_protocols);
1507 : 294 : free(fms);
1508 : 294 : }
1509 : :
1510 : : static void
1511 : 695 : ofctl_flow_mod(int argc, char *argv[], uint16_t command)
1512 : : {
1513 [ + + ][ + + ]: 695 : if (argc > 2 && !strcmp(argv[2], "-")) {
1514 : 1 : ofctl_flow_mod_file(argc, argv, command);
1515 : : } else {
1516 : : struct ofputil_flow_mod fm;
1517 : : char *error;
1518 : : enum ofputil_protocol usable_protocols;
1519 : :
1520 [ + + ]: 694 : error = parse_ofp_flow_mod_str(&fm, argc > 2 ? argv[2] : "", command,
1521 : : &usable_protocols);
1522 [ + + ]: 694 : if (error) {
1523 : 19 : ovs_fatal(0, "%s", error);
1524 : : }
1525 : 675 : ofctl_flow_mod__(argv[1], &fm, 1, usable_protocols);
1526 : : }
1527 : 664 : }
1528 : :
1529 : : static void
1530 : 462 : ofctl_add_flow(struct ovs_cmdl_context *ctx)
1531 : : {
1532 : 462 : ofctl_flow_mod(ctx->argc, ctx->argv, OFPFC_ADD);
1533 : 436 : }
1534 : :
1535 : : static void
1536 : 296 : ofctl_add_flows(struct ovs_cmdl_context *ctx)
1537 : : {
1538 : 296 : ofctl_flow_mod_file(ctx->argc, ctx->argv, OFPFC_ADD);
1539 : 293 : }
1540 : :
1541 : : static void
1542 : 35 : ofctl_mod_flows(struct ovs_cmdl_context *ctx)
1543 : : {
1544 [ - + ]: 35 : ofctl_flow_mod(ctx->argc, ctx->argv, strict ? OFPFC_MODIFY_STRICT : OFPFC_MODIFY);
1545 : 33 : }
1546 : :
1547 : : static void
1548 : 198 : ofctl_del_flows(struct ovs_cmdl_context *ctx)
1549 : : {
1550 [ + + ]: 198 : ofctl_flow_mod(ctx->argc, ctx->argv, strict ? OFPFC_DELETE_STRICT : OFPFC_DELETE);
1551 : 195 : }
1552 : :
1553 : : static bool
1554 : 166 : set_packet_in_format(struct vconn *vconn,
1555 : : enum nx_packet_in_format packet_in_format,
1556 : : bool must_succeed)
1557 : : {
1558 : : struct ofpbuf *spif;
1559 : :
1560 : 166 : spif = ofputil_make_set_packet_in_format(vconn_get_version(vconn),
1561 : : packet_in_format);
1562 [ + + ]: 166 : if (must_succeed) {
1563 : 113 : transact_noreply(vconn, spif);
1564 : : } else {
1565 : : struct ofpbuf *reply;
1566 : :
1567 : 53 : run(vconn_transact_noreply(vconn, spif, &reply),
1568 : : "talking to %s", vconn_get_name(vconn));
1569 [ - + ]: 53 : if (reply) {
1570 : 0 : char *s = ofp_to_string(reply->data, reply->size, 2);
1571 [ # # ]: 0 : VLOG_DBG("%s: failed to set packet in format to nx_packet_in, "
1572 : : "controller replied: %s.",
1573 : : vconn_get_name(vconn), s);
1574 : 0 : free(s);
1575 : 0 : ofpbuf_delete(reply);
1576 : :
1577 : 0 : return false;
1578 : : } else {
1579 [ - + ]: 53 : VLOG_DBG("%s: using user-specified packet in format %s",
1580 : : vconn_get_name(vconn),
1581 : : ofputil_packet_in_format_to_string(packet_in_format));
1582 : : }
1583 : : }
1584 : 166 : return true;
1585 : : }
1586 : :
1587 : : static int
1588 : 29 : monitor_set_invalid_ttl_to_controller(struct vconn *vconn)
1589 : : {
1590 : : struct ofputil_switch_config config;
1591 : :
1592 : 29 : fetch_switch_config(vconn, &config);
1593 [ + - ]: 29 : if (!config.invalid_ttl_to_controller) {
1594 : 29 : config.invalid_ttl_to_controller = 1;
1595 : 29 : set_switch_config(vconn, &config);
1596 : :
1597 : : /* Then retrieve the configuration to see if it really took. OpenFlow
1598 : : * has ill-defined error reporting for bad flags, so this is about the
1599 : : * best we can do. */
1600 : 29 : fetch_switch_config(vconn, &config);
1601 [ - + ]: 29 : if (!config.invalid_ttl_to_controller) {
1602 : 0 : ovs_fatal(0, "setting invalid_ttl_to_controller failed (this "
1603 : : "switch probably doesn't support this flag)");
1604 : : }
1605 : : }
1606 : 29 : return 0;
1607 : : }
1608 : :
1609 : : /* Converts hex digits in 'hex' to an OpenFlow message in '*msgp'. The
1610 : : * caller must free '*msgp'. On success, returns NULL. On failure, returns
1611 : : * an error message and stores NULL in '*msgp'. */
1612 : : static const char *
1613 : 87 : openflow_from_hex(const char *hex, struct ofpbuf **msgp)
1614 : : {
1615 : : struct ofp_header *oh;
1616 : : struct ofpbuf *msg;
1617 : :
1618 : 87 : msg = ofpbuf_new(strlen(hex) / 2);
1619 : 87 : *msgp = NULL;
1620 : :
1621 [ - + ]: 87 : if (ofpbuf_put_hex(msg, hex, NULL)[0] != '\0') {
1622 : 0 : ofpbuf_delete(msg);
1623 : 0 : return "Trailing garbage in hex data";
1624 : : }
1625 : :
1626 [ - + ]: 87 : if (msg->size < sizeof(struct ofp_header)) {
1627 : 0 : ofpbuf_delete(msg);
1628 : 0 : return "Message too short for OpenFlow";
1629 : : }
1630 : :
1631 : 87 : oh = msg->data;
1632 [ - + ]: 87 : if (msg->size != ntohs(oh->length)) {
1633 : 0 : ofpbuf_delete(msg);
1634 : 0 : return "Message size does not match length in OpenFlow header";
1635 : : }
1636 : :
1637 : 87 : *msgp = msg;
1638 : 87 : return NULL;
1639 : : }
1640 : :
1641 : : static void
1642 : 87 : ofctl_send(struct unixctl_conn *conn, int argc,
1643 : : const char *argv[], void *vconn_)
1644 : : {
1645 : 87 : struct vconn *vconn = vconn_;
1646 : : struct ds reply;
1647 : : bool ok;
1648 : : int i;
1649 : :
1650 : 87 : ok = true;
1651 : 87 : ds_init(&reply);
1652 [ + + ]: 174 : for (i = 1; i < argc; i++) {
1653 : : const char *error_msg;
1654 : : struct ofpbuf *msg;
1655 : : int error;
1656 : :
1657 : 87 : error_msg = openflow_from_hex(argv[i], &msg);
1658 [ - + ]: 87 : if (error_msg) {
1659 : 0 : ds_put_format(&reply, "%s\n", error_msg);
1660 : 0 : ok = false;
1661 : 0 : continue;
1662 : : }
1663 : :
1664 : 87 : fprintf(stderr, "send: ");
1665 : 87 : ofp_print(stderr, msg->data, msg->size, verbosity);
1666 : :
1667 : 87 : error = vconn_send_block(vconn, msg);
1668 [ - + ]: 87 : if (error) {
1669 : 0 : ofpbuf_delete(msg);
1670 : 0 : ds_put_format(&reply, "%s\n", ovs_strerror(error));
1671 : 0 : ok = false;
1672 : : } else {
1673 : 87 : ds_put_cstr(&reply, "sent\n");
1674 : : }
1675 : : }
1676 : :
1677 [ + - ]: 87 : if (ok) {
1678 : 87 : unixctl_command_reply(conn, ds_cstr(&reply));
1679 : : } else {
1680 : 0 : unixctl_command_reply_error(conn, ds_cstr(&reply));
1681 : : }
1682 : 87 : ds_destroy(&reply);
1683 : 87 : }
1684 : :
1685 : : struct barrier_aux {
1686 : : struct vconn *vconn; /* OpenFlow connection for sending barrier. */
1687 : : struct unixctl_conn *conn; /* Connection waiting for barrier response. */
1688 : : };
1689 : :
1690 : : static void
1691 : 118 : ofctl_barrier(struct unixctl_conn *conn, int argc OVS_UNUSED,
1692 : : const char *argv[] OVS_UNUSED, void *aux_)
1693 : : {
1694 : 118 : struct barrier_aux *aux = aux_;
1695 : : struct ofpbuf *msg;
1696 : : int error;
1697 : :
1698 [ - + ]: 118 : if (aux->conn) {
1699 : 0 : unixctl_command_reply_error(conn, "already waiting for barrier reply");
1700 : 0 : return;
1701 : : }
1702 : :
1703 : 118 : msg = ofputil_encode_barrier_request(vconn_get_version(aux->vconn));
1704 : 118 : error = vconn_send_block(aux->vconn, msg);
1705 [ - + ]: 118 : if (error) {
1706 : 0 : ofpbuf_delete(msg);
1707 : 0 : unixctl_command_reply_error(conn, ovs_strerror(error));
1708 : : } else {
1709 : 118 : aux->conn = conn;
1710 : : }
1711 : : }
1712 : :
1713 : : static void
1714 : 47 : ofctl_set_output_file(struct unixctl_conn *conn, int argc OVS_UNUSED,
1715 : : const char *argv[], void *aux OVS_UNUSED)
1716 : : {
1717 : : int fd;
1718 : :
1719 : 47 : fd = open(argv[1], O_CREAT | O_TRUNC | O_WRONLY, 0666);
1720 [ - + ]: 47 : if (fd < 0) {
1721 : 0 : unixctl_command_reply_error(conn, ovs_strerror(errno));
1722 : 0 : return;
1723 : : }
1724 : :
1725 : 47 : fflush(stderr);
1726 : 47 : dup2(fd, STDERR_FILENO);
1727 : 47 : close(fd);
1728 : 47 : unixctl_command_reply(conn, NULL);
1729 : : }
1730 : :
1731 : : static void
1732 : 1 : ofctl_block(struct unixctl_conn *conn, int argc OVS_UNUSED,
1733 : : const char *argv[] OVS_UNUSED, void *blocked_)
1734 : : {
1735 : 1 : bool *blocked = blocked_;
1736 : :
1737 [ + - ]: 1 : if (!*blocked) {
1738 : 1 : *blocked = true;
1739 : 1 : unixctl_command_reply(conn, NULL);
1740 : : } else {
1741 : 0 : unixctl_command_reply(conn, "already blocking");
1742 : : }
1743 : 1 : }
1744 : :
1745 : : static void
1746 : 1 : ofctl_unblock(struct unixctl_conn *conn, int argc OVS_UNUSED,
1747 : : const char *argv[] OVS_UNUSED, void *blocked_)
1748 : : {
1749 : 1 : bool *blocked = blocked_;
1750 : :
1751 [ + - ]: 1 : if (*blocked) {
1752 : 1 : *blocked = false;
1753 : 1 : unixctl_command_reply(conn, NULL);
1754 : : } else {
1755 : 0 : unixctl_command_reply(conn, "already unblocked");
1756 : : }
1757 : 1 : }
1758 : :
1759 : : /* Prints to stdout all of the messages received on 'vconn'.
1760 : : *
1761 : : * Iff 'reply_to_echo_requests' is true, sends a reply to any echo request
1762 : : * received on 'vconn'.
1763 : : *
1764 : : * If 'resume_continuations' is true, sends an NXT_RESUME in reply to any
1765 : : * NXT_PACKET_IN2 that includes a continuation. */
1766 : : static void
1767 : 166 : monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests,
1768 : : bool resume_continuations)
1769 : : {
1770 : 166 : struct barrier_aux barrier_aux = { vconn, NULL };
1771 : : struct unixctl_server *server;
1772 : 166 : bool exiting = false;
1773 : 166 : bool blocked = false;
1774 : : int error;
1775 : :
1776 : 166 : daemon_save_fd(STDERR_FILENO);
1777 : 166 : daemonize_start(false);
1778 : 166 : error = unixctl_server_create(unixctl_path, &server);
1779 [ - + ]: 166 : if (error) {
1780 : 0 : ovs_fatal(error, "failed to create unixctl server");
1781 : : }
1782 : 166 : unixctl_command_register("exit", "", 0, 0, ofctl_exit, &exiting);
1783 : 166 : unixctl_command_register("ofctl/send", "OFMSG...", 1, INT_MAX,
1784 : : ofctl_send, vconn);
1785 : 166 : unixctl_command_register("ofctl/barrier", "", 0, 0,
1786 : : ofctl_barrier, &barrier_aux);
1787 : 166 : unixctl_command_register("ofctl/set-output-file", "FILE", 1, 1,
1788 : : ofctl_set_output_file, NULL);
1789 : :
1790 : 166 : unixctl_command_register("ofctl/block", "", 0, 0, ofctl_block, &blocked);
1791 : 166 : unixctl_command_register("ofctl/unblock", "", 0, 0, ofctl_unblock,
1792 : : &blocked);
1793 : :
1794 : 166 : daemonize_complete();
1795 : :
1796 : 166 : enum ofp_version version = vconn_get_version(vconn);
1797 : 166 : enum ofputil_protocol protocol
1798 : : = ofputil_protocol_from_ofp_version(version);
1799 : :
1800 : : for (;;) {
1801 : : struct ofpbuf *b;
1802 : : int retval;
1803 : :
1804 : 1994 : unixctl_server_run(server);
1805 : :
1806 [ + + ]: 5432 : while (!blocked) {
1807 : : enum ofptype type;
1808 : :
1809 : 5429 : retval = vconn_recv(vconn, &b);
1810 [ + + ]: 5429 : if (retval == EAGAIN) {
1811 : 1968 : break;
1812 : : }
1813 : 3461 : run(retval, "vconn_recv");
1814 : :
1815 [ - + ]: 3438 : if (timestamp) {
1816 : 0 : char *s = xastrftime_msec("%Y-%m-%d %H:%M:%S.###: ",
1817 : : time_wall_msec(), true);
1818 : 0 : fputs(s, stderr);
1819 : 0 : free(s);
1820 : : }
1821 : :
1822 : 3438 : ofptype_decode(&type, b->data);
1823 : 3438 : ofp_print(stderr, b->data, b->size, verbosity + 2);
1824 : 3438 : fflush(stderr);
1825 : :
1826 [ + + + + ]: 3438 : switch ((int) type) {
1827 : : case OFPTYPE_BARRIER_REPLY:
1828 [ + - ]: 118 : if (barrier_aux.conn) {
1829 : 118 : unixctl_command_reply(barrier_aux.conn, NULL);
1830 : 118 : barrier_aux.conn = NULL;
1831 : : }
1832 : 118 : break;
1833 : :
1834 : : case OFPTYPE_ECHO_REQUEST:
1835 [ + - ]: 1 : if (reply_to_echo_requests) {
1836 : : struct ofpbuf *reply;
1837 : :
1838 : 1 : reply = make_echo_reply(b->data);
1839 : 1 : retval = vconn_send_block(vconn, reply);
1840 [ - + ]: 1 : if (retval) {
1841 : 0 : ovs_fatal(retval, "failed to send echo reply");
1842 : : }
1843 : : }
1844 : 1 : break;
1845 : :
1846 : : case OFPTYPE_PACKET_IN:
1847 [ + + ]: 538 : if (resume_continuations) {
1848 : : struct ofputil_packet_in pin;
1849 : : struct ofpbuf continuation;
1850 : :
1851 : 194 : error = ofputil_decode_packet_in(b->data, true, &pin,
1852 : : NULL, NULL,
1853 : : &continuation);
1854 [ - + ]: 194 : if (error) {
1855 : 0 : fprintf(stderr, "decoding packet-in failed: %s",
1856 : : ofperr_to_string(error));
1857 [ + - ]: 194 : } else if (continuation.size) {
1858 : : struct ofpbuf *reply;
1859 : :
1860 : 194 : reply = ofputil_encode_resume(&pin, &continuation,
1861 : : protocol);
1862 : :
1863 : 194 : fprintf(stderr, "send: ");
1864 : 194 : ofp_print(stderr, reply->data, reply->size,
1865 : : verbosity + 2);
1866 : 194 : fflush(stderr);
1867 : :
1868 : 194 : retval = vconn_send_block(vconn, reply);
1869 [ - + ]: 194 : if (retval) {
1870 : 194 : ovs_fatal(retval, "failed to send NXT_RESUME");
1871 : : }
1872 : : }
1873 : : }
1874 : 538 : break;
1875 : : }
1876 : 3438 : ofpbuf_delete(b);
1877 : : }
1878 : :
1879 [ + + ]: 1971 : if (exiting) {
1880 : 143 : break;
1881 : : }
1882 : :
1883 : 1828 : vconn_run(vconn);
1884 : 1828 : vconn_run_wait(vconn);
1885 [ + + ]: 1828 : if (!blocked) {
1886 : 1825 : vconn_recv_wait(vconn);
1887 : : }
1888 : 1828 : unixctl_server_wait(server);
1889 : 1828 : poll_block();
1890 : 1828 : }
1891 : 143 : vconn_close(vconn);
1892 : 143 : unixctl_server_destroy(server);
1893 : 143 : }
1894 : :
1895 : : static void
1896 : 166 : ofctl_monitor(struct ovs_cmdl_context *ctx)
1897 : : {
1898 : : struct vconn *vconn;
1899 : : int i;
1900 : : enum ofputil_protocol usable_protocols;
1901 : :
1902 : : /* If the user wants the invalid_ttl_to_controller feature, limit the
1903 : : * OpenFlow versions to those that support that feature. (Support in
1904 : : * OpenFlow 1.0 is an Open vSwitch extension.) */
1905 [ + + ]: 293 : for (i = 2; i < ctx->argc; i++) {
1906 [ + + ]: 156 : if (!strcmp(ctx->argv[i], "invalid_ttl")) {
1907 : 29 : uint32_t usable_versions = ((1u << OFP10_VERSION) |
1908 : : (1u << OFP11_VERSION) |
1909 : : (1u << OFP12_VERSION));
1910 : 29 : uint32_t allowed_versions = get_allowed_ofp_versions();
1911 [ - + ]: 29 : if (!(allowed_versions & usable_versions)) {
1912 : 0 : struct ds versions = DS_EMPTY_INITIALIZER;
1913 : 0 : ofputil_format_version_bitmap_names(&versions,
1914 : : usable_versions);
1915 : 0 : ovs_fatal(0, "invalid_ttl requires one of the OpenFlow "
1916 : : "versions %s but none is enabled (use -O)",
1917 : : ds_cstr(&versions));
1918 : : }
1919 : 29 : mask_allowed_ofp_versions(usable_versions);
1920 : 29 : break;
1921 : : }
1922 : : }
1923 : :
1924 : 166 : open_vconn(ctx->argv[1], &vconn);
1925 : 166 : bool resume_continuations = false;
1926 [ + + ]: 322 : for (i = 2; i < ctx->argc; i++) {
1927 : 156 : const char *arg = ctx->argv[i];
1928 : :
1929 [ + + ]: 156 : if (isdigit((unsigned char) *arg)) {
1930 : : struct ofputil_switch_config config;
1931 : :
1932 : 113 : fetch_switch_config(vconn, &config);
1933 : 113 : config.miss_send_len = atoi(arg);
1934 : 113 : set_switch_config(vconn, &config);
1935 [ + + ]: 43 : } else if (!strcmp(arg, "invalid_ttl")) {
1936 : 29 : monitor_set_invalid_ttl_to_controller(vconn);
1937 [ + + ]: 14 : } else if (!strncmp(arg, "watch:", 6)) {
1938 : : struct ofputil_flow_monitor_request fmr;
1939 : : struct ofpbuf *msg;
1940 : : char *error;
1941 : :
1942 : 4 : error = parse_flow_monitor_request(&fmr, arg + 6,
1943 : : &usable_protocols);
1944 [ - + ]: 4 : if (error) {
1945 : 0 : ovs_fatal(0, "%s", error);
1946 : : }
1947 : :
1948 : 4 : msg = ofpbuf_new(0);
1949 : 4 : ofputil_append_flow_monitor_request(&fmr, msg);
1950 : 4 : dump_transaction(vconn, msg);
1951 : 4 : fflush(stdout);
1952 [ + - ]: 10 : } else if (!strcmp(arg, "resume")) {
1953 : : /* This option is intentionally undocumented because it is meant
1954 : : * only for testing. */
1955 : 10 : resume_continuations = true;
1956 : :
1957 : : /* Set miss_send_len to ensure that we get packet-ins. */
1958 : : struct ofputil_switch_config config;
1959 : 10 : fetch_switch_config(vconn, &config);
1960 : 10 : config.miss_send_len = UINT16_MAX;
1961 : 10 : set_switch_config(vconn, &config);
1962 : : } else {
1963 : 0 : ovs_fatal(0, "%s: unsupported \"monitor\" argument", arg);
1964 : : }
1965 : : }
1966 : :
1967 [ + + ]: 166 : if (preferred_packet_in_format >= 0) {
1968 : : /* A particular packet-in format was requested, so we must set it. */
1969 : 113 : set_packet_in_format(vconn, preferred_packet_in_format, true);
1970 : : } else {
1971 : : /* Otherwise, we always prefer NXT_PACKET_IN2. */
1972 [ - + ]: 53 : if (!set_packet_in_format(vconn, NXPIF_NXT_PACKET_IN2, false)) {
1973 : : /* We can't get NXT_PACKET_IN2. For OpenFlow 1.0 only, request
1974 : : * NXT_PACKET_IN. (Before 2.6, Open vSwitch will accept a request
1975 : : * for NXT_PACKET_IN with OF1.1+, but even after that it still
1976 : : * sends packet-ins in the OpenFlow native format.) */
1977 [ # # ]: 0 : if (vconn_get_version(vconn) == OFP10_VERSION) {
1978 : 0 : set_packet_in_format(vconn, NXPIF_NXT_PACKET_IN, false);
1979 : : }
1980 : : }
1981 : : }
1982 : :
1983 : 166 : monitor_vconn(vconn, true, resume_continuations);
1984 : 143 : }
1985 : :
1986 : : static void
1987 : 0 : ofctl_snoop(struct ovs_cmdl_context *ctx)
1988 : : {
1989 : : struct vconn *vconn;
1990 : :
1991 : 0 : open_vconn__(ctx->argv[1], SNOOP, &vconn);
1992 : 0 : monitor_vconn(vconn, false, false);
1993 : 0 : }
1994 : :
1995 : : static void
1996 : 19 : ofctl_dump_ports(struct ovs_cmdl_context *ctx)
1997 : : {
1998 : : struct ofpbuf *request;
1999 : : struct vconn *vconn;
2000 : : ofp_port_t port;
2001 : :
2002 : 19 : open_vconn(ctx->argv[1], &vconn);
2003 [ + + ]: 19 : port = ctx->argc > 2 ? str_to_port_no(ctx->argv[1], ctx->argv[2]) : OFPP_ANY;
2004 : 19 : request = ofputil_encode_dump_ports_request(vconn_get_version(vconn), port);
2005 : 19 : dump_transaction(vconn, request);
2006 : 19 : vconn_close(vconn);
2007 : 19 : }
2008 : :
2009 : : static void
2010 : 4 : ofctl_dump_ports_desc(struct ovs_cmdl_context *ctx)
2011 : : {
2012 : : struct ofpbuf *request;
2013 : : struct vconn *vconn;
2014 : : ofp_port_t port;
2015 : :
2016 : 4 : open_vconn(ctx->argv[1], &vconn);
2017 [ + + ]: 4 : port = ctx->argc > 2 ? str_to_port_no(ctx->argv[1], ctx->argv[2]) : OFPP_ANY;
2018 : 4 : request = ofputil_encode_port_desc_stats_request(vconn_get_version(vconn),
2019 : : port);
2020 : 4 : dump_transaction(vconn, request);
2021 : 4 : vconn_close(vconn);
2022 : 4 : }
2023 : :
2024 : : static void
2025 : 1 : ofctl_probe(struct ovs_cmdl_context *ctx)
2026 : : {
2027 : : struct ofpbuf *request;
2028 : : struct vconn *vconn;
2029 : : struct ofpbuf *reply;
2030 : :
2031 : 1 : open_vconn(ctx->argv[1], &vconn);
2032 : 1 : request = make_echo_request(vconn_get_version(vconn));
2033 : 1 : run(vconn_transact(vconn, request, &reply), "talking to %s", ctx->argv[1]);
2034 [ - + ]: 1 : if (reply->size != sizeof(struct ofp_header)) {
2035 : 0 : ovs_fatal(0, "reply does not match request");
2036 : : }
2037 : 1 : ofpbuf_delete(reply);
2038 : 1 : vconn_close(vconn);
2039 : 1 : }
2040 : :
2041 : : static void
2042 : 1342 : ofctl_packet_out(struct ovs_cmdl_context *ctx)
2043 : : {
2044 : : enum ofputil_protocol protocol;
2045 : : struct ofputil_packet_out po;
2046 : : struct ofpbuf ofpacts;
2047 : : struct vconn *vconn;
2048 : : char *error;
2049 : : int i;
2050 : : enum ofputil_protocol usable_protocols; /* XXX: Use in proto selection */
2051 : :
2052 : 1342 : ofpbuf_init(&ofpacts, 64);
2053 : 1342 : error = ofpacts_parse_actions(ctx->argv[3], &ofpacts, &usable_protocols);
2054 [ - + ]: 1342 : if (error) {
2055 : 0 : ovs_fatal(0, "%s", error);
2056 : : }
2057 : :
2058 : 1342 : po.buffer_id = UINT32_MAX;
2059 : 1342 : po.in_port = str_to_port_no(ctx->argv[1], ctx->argv[2]);
2060 : 1342 : po.ofpacts = ofpacts.data;
2061 : 1342 : po.ofpacts_len = ofpacts.size;
2062 : :
2063 : 1342 : protocol = open_vconn(ctx->argv[1], &vconn);
2064 [ + + ]: 2684 : for (i = 4; i < ctx->argc; i++) {
2065 : : struct dp_packet *packet;
2066 : : struct ofpbuf *opo;
2067 : : const char *error_msg;
2068 : :
2069 : 1342 : error_msg = eth_from_hex(ctx->argv[i], &packet);
2070 [ - + ]: 1342 : if (error_msg) {
2071 : 0 : ovs_fatal(0, "%s", error_msg);
2072 : : }
2073 : :
2074 : 1342 : po.packet = dp_packet_data(packet);
2075 : 1342 : po.packet_len = dp_packet_size(packet);
2076 : 1342 : opo = ofputil_encode_packet_out(&po, protocol);
2077 : 1342 : transact_noreply(vconn, opo);
2078 : 1342 : dp_packet_delete(packet);
2079 : : }
2080 : 1342 : vconn_close(vconn);
2081 : 1342 : ofpbuf_uninit(&ofpacts);
2082 : 1342 : }
2083 : :
2084 : : static void
2085 : 39 : ofctl_mod_port(struct ovs_cmdl_context *ctx)
2086 : : {
2087 : : struct ofp_config_flag {
2088 : : const char *name; /* The flag's name. */
2089 : : enum ofputil_port_config bit; /* Bit to turn on or off. */
2090 : : bool on; /* Value to set the bit to. */
2091 : : };
2092 : : static const struct ofp_config_flag flags[] = {
2093 : : { "up", OFPUTIL_PC_PORT_DOWN, false },
2094 : : { "down", OFPUTIL_PC_PORT_DOWN, true },
2095 : : { "stp", OFPUTIL_PC_NO_STP, false },
2096 : : { "receive", OFPUTIL_PC_NO_RECV, false },
2097 : : { "receive-stp", OFPUTIL_PC_NO_RECV_STP, false },
2098 : : { "flood", OFPUTIL_PC_NO_FLOOD, false },
2099 : : { "forward", OFPUTIL_PC_NO_FWD, false },
2100 : : { "packet-in", OFPUTIL_PC_NO_PACKET_IN, false },
2101 : : };
2102 : :
2103 : : const struct ofp_config_flag *flag;
2104 : : enum ofputil_protocol protocol;
2105 : : struct ofputil_port_mod pm;
2106 : : struct ofputil_phy_port pp;
2107 : : struct vconn *vconn;
2108 : : const char *command;
2109 : : bool not;
2110 : :
2111 : 39 : fetch_ofputil_phy_port(ctx->argv[1], ctx->argv[2], &pp);
2112 : :
2113 : 39 : pm.port_no = pp.port_no;
2114 : 39 : pm.hw_addr = pp.hw_addr;
2115 : 39 : pm.config = 0;
2116 : 39 : pm.mask = 0;
2117 : 39 : pm.advertise = 0;
2118 : :
2119 [ + + ]: 39 : if (!strncasecmp(ctx->argv[3], "no-", 3)) {
2120 : 9 : command = ctx->argv[3] + 3;
2121 : 9 : not = true;
2122 [ + + ]: 30 : } else if (!strncasecmp(ctx->argv[3], "no", 2)) {
2123 : 3 : command = ctx->argv[3] + 2;
2124 : 3 : not = true;
2125 : : } else {
2126 : 27 : command = ctx->argv[3];
2127 : 27 : not = false;
2128 : : }
2129 [ + - ]: 159 : for (flag = flags; flag < &flags[ARRAY_SIZE(flags)]; flag++) {
2130 [ + + ]: 159 : if (!strcasecmp(command, flag->name)) {
2131 : 39 : pm.mask = flag->bit;
2132 [ + + ]: 39 : pm.config = flag->on ^ not ? flag->bit : 0;
2133 : 39 : goto found;
2134 : : }
2135 : : }
2136 : 0 : ovs_fatal(0, "unknown mod-port command '%s'", ctx->argv[3]);
2137 : :
2138 : : found:
2139 : 39 : protocol = open_vconn(ctx->argv[1], &vconn);
2140 : 39 : transact_noreply(vconn, ofputil_encode_port_mod(&pm, protocol));
2141 : 39 : vconn_close(vconn);
2142 : 39 : }
2143 : :
2144 : : /* This function uses OFPMP14_TABLE_DESC request to get the current
2145 : : * table configuration from switch. The function then modifies
2146 : : * only that table-config property, which has been requested. */
2147 : : static void
2148 : 7 : fetch_table_desc(struct vconn *vconn, struct ofputil_table_mod *tm,
2149 : : struct ofputil_table_desc *td)
2150 : : {
2151 : : struct ofpbuf *request;
2152 : : ovs_be32 send_xid;
2153 : 7 : bool done = false;
2154 : 7 : bool found = false;
2155 : :
2156 : 7 : request = ofputil_encode_table_desc_request(vconn_get_version(vconn));
2157 : 7 : send_xid = ((struct ofp_header *) request->data)->xid;
2158 : 7 : send_openflow_buffer(vconn, request);
2159 [ + + ]: 14 : while (!done) {
2160 : : ovs_be32 recv_xid;
2161 : : struct ofpbuf *reply;
2162 : :
2163 : 7 : run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed");
2164 : 7 : recv_xid = ((struct ofp_header *) reply->data)->xid;
2165 [ + - ]: 7 : if (send_xid == recv_xid) {
2166 : 7 : struct ofp_header *oh = reply->data;
2167 : 7 : struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
2168 : :
2169 : : enum ofptype type;
2170 [ + - ]: 7 : if (ofptype_pull(&type, &b)
2171 [ - + ]: 7 : || type != OFPTYPE_TABLE_DESC_REPLY) {
2172 : 0 : ovs_fatal(0, "received bad reply: %s",
2173 : 0 : ofp_to_string(reply->data, reply->size,
2174 : : verbosity + 1));
2175 : : }
2176 : 7 : uint16_t flags = ofpmp_flags(oh);
2177 : 7 : done = !(flags & OFPSF_REPLY_MORE);
2178 [ - + ]: 7 : if (found) {
2179 : : /* We've already found the table desc consisting of current
2180 : : * table configuration, but we need to drain the queue of
2181 : : * any other replies for this request. */
2182 : 0 : continue;
2183 : : }
2184 [ + - ]: 17 : while (!ofputil_decode_table_desc(&b, td, oh->version)) {
2185 [ + + ]: 10 : if (td->table_id == tm->table_id) {
2186 : 7 : found = true;
2187 : 7 : break;
2188 : : }
2189 : : }
2190 : : } else {
2191 [ # # ]: 0 : VLOG_DBG("received reply with xid %08"PRIx32" "
2192 : : "!= expected %08"PRIx32, recv_xid, send_xid);
2193 : : }
2194 : 7 : ofpbuf_delete(reply);
2195 : : }
2196 [ + + ]: 7 : if (tm->eviction != OFPUTIL_TABLE_EVICTION_DEFAULT) {
2197 : 3 : tm->vacancy = td->vacancy;
2198 : 3 : tm->table_vacancy.vacancy_down = td->table_vacancy.vacancy_down;
2199 : 3 : tm->table_vacancy.vacancy_up = td->table_vacancy.vacancy_up;
2200 [ + - ]: 4 : } else if (tm->vacancy != OFPUTIL_TABLE_VACANCY_DEFAULT) {
2201 : 4 : tm->eviction = td->eviction;
2202 : 4 : tm->eviction_flags = td->eviction_flags;
2203 : : }
2204 : 7 : }
2205 : :
2206 : : static void
2207 : 14 : ofctl_mod_table(struct ovs_cmdl_context *ctx)
2208 : : {
2209 : : uint32_t usable_versions;
2210 : : struct ofputil_table_mod tm;
2211 : : struct vconn *vconn;
2212 : : char *error;
2213 : : int i;
2214 : :
2215 : 14 : error = parse_ofp_table_mod(&tm, ctx->argv[2], ctx->argv[3],
2216 : : &usable_versions);
2217 [ - + ]: 14 : if (error) {
2218 : 0 : ovs_fatal(0, "%s", error);
2219 : : }
2220 : :
2221 : 14 : uint32_t allowed_versions = get_allowed_ofp_versions();
2222 [ - + ]: 14 : if (!(allowed_versions & usable_versions)) {
2223 : 0 : struct ds versions = DS_EMPTY_INITIALIZER;
2224 : 0 : ofputil_format_version_bitmap_names(&versions, usable_versions);
2225 : 0 : ovs_fatal(0, "table_mod '%s' requires one of the OpenFlow "
2226 : : "versions %s",
2227 : 0 : ctx->argv[3], ds_cstr(&versions));
2228 : : }
2229 : 14 : mask_allowed_ofp_versions(usable_versions);
2230 : 14 : enum ofputil_protocol protocol = open_vconn(ctx->argv[1], &vconn);
2231 : :
2232 : : /* For OpenFlow 1.4+, ovs-ofctl mod-table should not affect table-config
2233 : : * properties that the user didn't ask to change, so it is necessary to
2234 : : * restore the current configuration of table-config parameters using
2235 : : * OFPMP14_TABLE_DESC request. */
2236 [ + + ][ - + ]: 14 : if ((allowed_versions & (1u << OFP14_VERSION)) ||
2237 : 7 : (allowed_versions & (1u << OFP15_VERSION))) {
2238 : : struct ofputil_table_desc td;
2239 : :
2240 [ - + ]: 7 : if (tm.table_id == OFPTT_ALL) {
2241 [ # # ]: 0 : for (i = 0; i < OFPTT_MAX; i++) {
2242 : 0 : tm.table_id = i;
2243 : 0 : fetch_table_desc(vconn, &tm, &td);
2244 : 0 : transact_noreply(vconn,
2245 : : ofputil_encode_table_mod(&tm, protocol));
2246 : : }
2247 : : } else {
2248 : 7 : fetch_table_desc(vconn, &tm, &td);
2249 : 7 : transact_noreply(vconn, ofputil_encode_table_mod(&tm, protocol));
2250 : : }
2251 : : } else {
2252 : 7 : transact_noreply(vconn, ofputil_encode_table_mod(&tm, protocol));
2253 : : }
2254 : 14 : vconn_close(vconn);
2255 : 14 : }
2256 : :
2257 : : static void
2258 : 0 : ofctl_get_frags(struct ovs_cmdl_context *ctx)
2259 : : {
2260 : : struct ofputil_switch_config config;
2261 : : struct vconn *vconn;
2262 : :
2263 : 0 : open_vconn(ctx->argv[1], &vconn);
2264 : 0 : fetch_switch_config(vconn, &config);
2265 : 0 : puts(ofputil_frag_handling_to_string(config.frag));
2266 : 0 : vconn_close(vconn);
2267 : 0 : }
2268 : :
2269 : : static void
2270 : 9 : ofctl_set_frags(struct ovs_cmdl_context *ctx)
2271 : : {
2272 : : struct ofputil_switch_config config;
2273 : : enum ofputil_frag_handling frag;
2274 : : struct vconn *vconn;
2275 : :
2276 [ - + ]: 9 : if (!ofputil_frag_handling_from_string(ctx->argv[2], &frag)) {
2277 : 0 : ovs_fatal(0, "%s: unknown fragment handling mode", ctx->argv[2]);
2278 : : }
2279 : :
2280 : 9 : open_vconn(ctx->argv[1], &vconn);
2281 : 9 : fetch_switch_config(vconn, &config);
2282 [ + + ]: 9 : if (frag != config.frag) {
2283 : : /* Set the configuration. */
2284 : 4 : config.frag = frag;
2285 : 4 : set_switch_config(vconn, &config);
2286 : :
2287 : : /* Then retrieve the configuration to see if it really took. OpenFlow
2288 : : * has ill-defined error reporting for bad flags, so this is about the
2289 : : * best we can do. */
2290 : 4 : fetch_switch_config(vconn, &config);
2291 [ - + ]: 4 : if (frag != config.frag) {
2292 : 0 : ovs_fatal(0, "%s: setting fragment handling mode failed (this "
2293 : : "switch probably doesn't support mode \"%s\")",
2294 : 0 : ctx->argv[1], ofputil_frag_handling_to_string(frag));
2295 : : }
2296 : : }
2297 : 9 : vconn_close(vconn);
2298 : 9 : }
2299 : :
2300 : : static void
2301 : 2 : ofctl_ofp_parse(struct ovs_cmdl_context *ctx)
2302 : : {
2303 : 2 : const char *filename = ctx->argv[1];
2304 : : struct ofpbuf b;
2305 : : FILE *file;
2306 : :
2307 [ + + ]: 2 : file = !strcmp(filename, "-") ? stdin : fopen(filename, "r");
2308 [ - + ]: 2 : if (file == NULL) {
2309 : 0 : ovs_fatal(errno, "%s: open", filename);
2310 : : }
2311 : :
2312 : 2 : ofpbuf_init(&b, 65536);
2313 : : for (;;) {
2314 : : struct ofp_header *oh;
2315 : : size_t length, tail_len;
2316 : : void *tail;
2317 : : size_t n;
2318 : :
2319 : 5 : ofpbuf_clear(&b);
2320 : 5 : oh = ofpbuf_put_uninit(&b, sizeof *oh);
2321 : 5 : n = fread(oh, 1, sizeof *oh, file);
2322 [ + + ]: 5 : if (n == 0) {
2323 : 2 : break;
2324 [ - + ]: 3 : } else if (n < sizeof *oh) {
2325 : 0 : ovs_fatal(0, "%s: unexpected end of file mid-message", filename);
2326 : : }
2327 : :
2328 : 3 : length = ntohs(oh->length);
2329 [ - + ]: 3 : if (length < sizeof *oh) {
2330 : 0 : ovs_fatal(0, "%s: %"PRIuSIZE"-byte message is too short for OpenFlow",
2331 : : filename, length);
2332 : : }
2333 : :
2334 : 3 : tail_len = length - sizeof *oh;
2335 : 3 : tail = ofpbuf_put_uninit(&b, tail_len);
2336 : 3 : n = fread(tail, 1, tail_len, file);
2337 [ - + ]: 3 : if (n < tail_len) {
2338 : 0 : ovs_fatal(0, "%s: unexpected end of file mid-message", filename);
2339 : : }
2340 : :
2341 : 3 : ofp_print(stdout, b.data, b.size, verbosity + 2);
2342 : 3 : }
2343 : 2 : ofpbuf_uninit(&b);
2344 : :
2345 [ + + ]: 2 : if (file != stdin) {
2346 : 1 : fclose(file);
2347 : : }
2348 : 2 : }
2349 : :
2350 : : static bool
2351 : 0 : is_openflow_port(ovs_be16 port_, char *ports[])
2352 : : {
2353 : 0 : uint16_t port = ntohs(port_);
2354 [ # # ]: 0 : if (ports[0]) {
2355 : : int i;
2356 : :
2357 [ # # ]: 0 : for (i = 0; ports[i]; i++) {
2358 [ # # ]: 0 : if (port == atoi(ports[i])) {
2359 : 0 : return true;
2360 : : }
2361 : : }
2362 : 0 : return false;
2363 : : } else {
2364 [ # # ][ # # ]: 0 : return port == OFP_PORT || port == OFP_OLD_PORT;
2365 : : }
2366 : : }
2367 : :
2368 : : static void
2369 : 0 : ofctl_ofp_parse_pcap(struct ovs_cmdl_context *ctx)
2370 : : {
2371 : : struct tcp_reader *reader;
2372 : : FILE *file;
2373 : : int error;
2374 : : bool first;
2375 : :
2376 : 0 : file = ovs_pcap_open(ctx->argv[1], "rb");
2377 [ # # ]: 0 : if (!file) {
2378 : 0 : ovs_fatal(errno, "%s: open failed", ctx->argv[1]);
2379 : : }
2380 : :
2381 : 0 : reader = tcp_reader_open();
2382 : 0 : first = true;
2383 : : for (;;) {
2384 : : struct dp_packet *packet;
2385 : : long long int when;
2386 : : struct flow flow;
2387 : :
2388 : 0 : error = ovs_pcap_read(file, &packet, &when);
2389 [ # # ]: 0 : if (error) {
2390 : 0 : break;
2391 : : }
2392 : 0 : pkt_metadata_init(&packet->md, ODPP_NONE);
2393 : 0 : flow_extract(packet, &flow);
2394 [ # # ]: 0 : if (flow.dl_type == htons(ETH_TYPE_IP)
2395 [ # # ]: 0 : && flow.nw_proto == IPPROTO_TCP
2396 [ # # # # ]: 0 : && (is_openflow_port(flow.tp_src, ctx->argv + 2) ||
2397 : 0 : is_openflow_port(flow.tp_dst, ctx->argv + 2))) {
2398 : 0 : struct dp_packet *payload = tcp_reader_run(reader, &flow, packet);
2399 [ # # ]: 0 : if (payload) {
2400 [ # # ]: 0 : while (dp_packet_size(payload) >= sizeof(struct ofp_header)) {
2401 : : const struct ofp_header *oh;
2402 : 0 : void *data = dp_packet_data(payload);
2403 : : int length;
2404 : :
2405 : : /* Align OpenFlow on 8-byte boundary for safe access. */
2406 : 0 : dp_packet_shift(payload, -((intptr_t) data & 7));
2407 : :
2408 : 0 : oh = dp_packet_data(payload);
2409 : 0 : length = ntohs(oh->length);
2410 [ # # ]: 0 : if (dp_packet_size(payload) < length) {
2411 : 0 : break;
2412 : : }
2413 : :
2414 [ # # ]: 0 : if (!first) {
2415 : 0 : putchar('\n');
2416 : : }
2417 : 0 : first = false;
2418 : :
2419 [ # # ]: 0 : if (timestamp) {
2420 : 0 : char *s = xastrftime_msec("%H:%M:%S.### ", when, true);
2421 : 0 : fputs(s, stdout);
2422 : 0 : free(s);
2423 : : }
2424 : :
2425 : 0 : printf(IP_FMT".%"PRIu16" > "IP_FMT".%"PRIu16":\n",
2426 : 0 : IP_ARGS(flow.nw_src), ntohs(flow.tp_src),
2427 : 0 : IP_ARGS(flow.nw_dst), ntohs(flow.tp_dst));
2428 : 0 : ofp_print(stdout, dp_packet_data(payload), length, verbosity + 1);
2429 : 0 : dp_packet_pull(payload, length);
2430 : : }
2431 : : }
2432 : : }
2433 : 0 : dp_packet_delete(packet);
2434 : 0 : }
2435 : 0 : tcp_reader_close(reader);
2436 : 0 : }
2437 : :
2438 : : static void
2439 : 0 : ofctl_ping(struct ovs_cmdl_context *ctx)
2440 : : {
2441 : 0 : size_t max_payload = 65535 - sizeof(struct ofp_header);
2442 : : unsigned int payload;
2443 : : struct vconn *vconn;
2444 : : int i;
2445 : :
2446 [ # # ]: 0 : payload = ctx->argc > 2 ? atoi(ctx->argv[2]) : 64;
2447 [ # # ]: 0 : if (payload > max_payload) {
2448 : 0 : ovs_fatal(0, "payload must be between 0 and %"PRIuSIZE" bytes", max_payload);
2449 : : }
2450 : :
2451 : 0 : open_vconn(ctx->argv[1], &vconn);
2452 [ # # ]: 0 : for (i = 0; i < 10; i++) {
2453 : : struct timeval start, end;
2454 : : struct ofpbuf *request, *reply;
2455 : : const struct ofp_header *rpy_hdr;
2456 : : enum ofptype type;
2457 : :
2458 : 0 : request = ofpraw_alloc(OFPRAW_OFPT_ECHO_REQUEST,
2459 : 0 : vconn_get_version(vconn), payload);
2460 : 0 : random_bytes(ofpbuf_put_uninit(request, payload), payload);
2461 : :
2462 : 0 : xgettimeofday(&start);
2463 : 0 : run(vconn_transact(vconn, ofpbuf_clone(request), &reply), "transact");
2464 : 0 : xgettimeofday(&end);
2465 : :
2466 : 0 : rpy_hdr = reply->data;
2467 [ # # ]: 0 : if (ofptype_pull(&type, reply)
2468 [ # # ]: 0 : || type != OFPTYPE_ECHO_REPLY
2469 [ # # ]: 0 : || reply->size != payload
2470 [ # # ]: 0 : || memcmp(request->msg, reply->msg, payload)) {
2471 : 0 : printf("Reply does not match request. Request:\n");
2472 : 0 : ofp_print(stdout, request, request->size, verbosity + 2);
2473 : 0 : printf("Reply:\n");
2474 : 0 : ofp_print(stdout, reply, reply->size, verbosity + 2);
2475 : : }
2476 : 0 : printf("%"PRIu32" bytes from %s: xid=%08"PRIx32" time=%.1f ms\n",
2477 : 0 : reply->size, ctx->argv[1], ntohl(rpy_hdr->xid),
2478 : 0 : (1000*(double)(end.tv_sec - start.tv_sec))
2479 : 0 : + (.001*(end.tv_usec - start.tv_usec)));
2480 : 0 : ofpbuf_delete(request);
2481 : 0 : ofpbuf_delete(reply);
2482 : : }
2483 : 0 : vconn_close(vconn);
2484 : 0 : }
2485 : :
2486 : : static void
2487 : 0 : ofctl_benchmark(struct ovs_cmdl_context *ctx)
2488 : : {
2489 : 0 : size_t max_payload = 65535 - sizeof(struct ofp_header);
2490 : : struct timeval start, end;
2491 : : unsigned int payload_size, message_size;
2492 : : struct vconn *vconn;
2493 : : double duration;
2494 : : int count;
2495 : : int i;
2496 : :
2497 : 0 : payload_size = atoi(ctx->argv[2]);
2498 [ # # ]: 0 : if (payload_size > max_payload) {
2499 : 0 : ovs_fatal(0, "payload must be between 0 and %"PRIuSIZE" bytes", max_payload);
2500 : : }
2501 : 0 : message_size = sizeof(struct ofp_header) + payload_size;
2502 : :
2503 : 0 : count = atoi(ctx->argv[3]);
2504 : :
2505 : 0 : printf("Sending %d packets * %u bytes (with header) = %u bytes total\n",
2506 : : count, message_size, count * message_size);
2507 : :
2508 : 0 : open_vconn(ctx->argv[1], &vconn);
2509 : 0 : xgettimeofday(&start);
2510 [ # # ]: 0 : for (i = 0; i < count; i++) {
2511 : : struct ofpbuf *request, *reply;
2512 : :
2513 : 0 : request = ofpraw_alloc(OFPRAW_OFPT_ECHO_REQUEST,
2514 : 0 : vconn_get_version(vconn), payload_size);
2515 : 0 : ofpbuf_put_zeros(request, payload_size);
2516 : 0 : run(vconn_transact(vconn, request, &reply), "transact");
2517 : 0 : ofpbuf_delete(reply);
2518 : : }
2519 : 0 : xgettimeofday(&end);
2520 : 0 : vconn_close(vconn);
2521 : :
2522 : 0 : duration = ((1000*(double)(end.tv_sec - start.tv_sec))
2523 : 0 : + (.001*(end.tv_usec - start.tv_usec)));
2524 : 0 : printf("Finished in %.1f ms (%.0f packets/s) (%.0f bytes/s)\n",
2525 : 0 : duration, count / (duration / 1000.0),
2526 : 0 : count * message_size / (duration / 1000.0));
2527 : 0 : }
2528 : :
2529 : : static void
2530 : 3 : ofctl_dump_ipfix_bridge(struct ovs_cmdl_context *ctx)
2531 : : {
2532 : 3 : dump_trivial_transaction(ctx->argv[1], OFPRAW_NXST_IPFIX_BRIDGE_REQUEST);
2533 : 3 : }
2534 : :
2535 : : static void
2536 : 3 : ofctl_dump_ipfix_flow(struct ovs_cmdl_context *ctx)
2537 : : {
2538 : 3 : dump_trivial_transaction(ctx->argv[1], OFPRAW_NXST_IPFIX_FLOW_REQUEST);
2539 : 3 : }
2540 : :
2541 : : static void
2542 : 37 : bundle_group_mod__(const char *remote, struct ofputil_group_mod *gms,
2543 : : size_t n_gms, enum ofputil_protocol usable_protocols)
2544 : : {
2545 : : enum ofputil_protocol protocol;
2546 : : enum ofp_version version;
2547 : : struct vconn *vconn;
2548 : : struct ovs_list requests;
2549 : : size_t i;
2550 : :
2551 : 37 : ovs_list_init(&requests);
2552 : :
2553 : : /* Bundles need OpenFlow 1.3+. */
2554 : 37 : usable_protocols &= OFPUTIL_P_OF13_UP;
2555 : 37 : protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols);
2556 : 37 : version = ofputil_protocol_to_ofp_version(protocol);
2557 : :
2558 [ + + ]: 78 : for (i = 0; i < n_gms; i++) {
2559 : 43 : struct ofputil_group_mod *gm = &gms[i];
2560 : 43 : struct ofpbuf *request = ofputil_encode_group_mod(version, gm);
2561 : :
2562 : 41 : ovs_list_push_back(&requests, &request->list_node);
2563 : 41 : ofputil_uninit_group_mod(gm);
2564 : : }
2565 : :
2566 : 35 : bundle_transact(vconn, &requests, OFPBF_ORDERED | OFPBF_ATOMIC);
2567 : 31 : ofpbuf_list_delete(&requests);
2568 : 31 : vconn_close(vconn);
2569 : 31 : }
2570 : :
2571 : : static void
2572 : 135 : ofctl_group_mod__(const char *remote, struct ofputil_group_mod *gms,
2573 : : size_t n_gms, enum ofputil_protocol usable_protocols)
2574 : : {
2575 : : enum ofputil_protocol protocol;
2576 : : struct ofputil_group_mod *gm;
2577 : : enum ofp_version version;
2578 : : struct ofpbuf *request;
2579 : :
2580 : : struct vconn *vconn;
2581 : : size_t i;
2582 : :
2583 [ + + ]: 135 : if (bundle) {
2584 : 37 : bundle_group_mod__(remote, gms, n_gms, usable_protocols);
2585 : 31 : return;
2586 : : }
2587 : :
2588 : 98 : protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols);
2589 : 96 : version = ofputil_protocol_to_ofp_version(protocol);
2590 : :
2591 [ + + ]: 196 : for (i = 0; i < n_gms; i++) {
2592 : 107 : gm = &gms[i];
2593 : 107 : request = ofputil_encode_group_mod(version, gm);
2594 : 104 : transact_noreply(vconn, request);
2595 : 100 : ofputil_uninit_group_mod(gm);
2596 : : }
2597 : :
2598 : 89 : vconn_close(vconn);
2599 : : }
2600 : :
2601 : : static void
2602 : 21 : ofctl_group_mod_file(int argc OVS_UNUSED, char *argv[], int command)
2603 : : {
2604 : 21 : struct ofputil_group_mod *gms = NULL;
2605 : : enum ofputil_protocol usable_protocols;
2606 : 21 : size_t n_gms = 0;
2607 : : char *error;
2608 : :
2609 [ + + ]: 21 : if (command == OFPGC11_ADD) {
2610 : : /* Allow the file to specify a mix of commands. If none specified at
2611 : : * the beginning of any given line, then the default is OFPGC11_ADD, so
2612 : : * this is backwards compatible. */
2613 : 17 : command = -2;
2614 : : }
2615 : 21 : error = parse_ofp_group_mod_file(argv[2], command, &gms, &n_gms,
2616 : : &usable_protocols);
2617 [ - + ]: 21 : if (error) {
2618 : 0 : ovs_fatal(0, "%s", error);
2619 : : }
2620 : 21 : ofctl_group_mod__(argv[1], gms, n_gms, usable_protocols);
2621 : 20 : free(gms);
2622 : 20 : }
2623 : :
2624 : : static void
2625 : 124 : ofctl_group_mod(int argc, char *argv[], uint16_t command)
2626 : : {
2627 [ + + ][ + + ]: 124 : if (argc > 2 && !strcmp(argv[2], "-")) {
2628 : 4 : ofctl_group_mod_file(argc, argv, command);
2629 : : } else {
2630 : : enum ofputil_protocol usable_protocols;
2631 : : struct ofputil_group_mod gm;
2632 : : char *error;
2633 : :
2634 [ + + ]: 120 : error = parse_ofp_group_mod_str(&gm, command, argc > 2 ? argv[2] : "",
2635 : : &usable_protocols);
2636 [ + + ]: 120 : if (error) {
2637 : 6 : ovs_fatal(0, "%s", error);
2638 : : }
2639 : 114 : ofctl_group_mod__(argv[1], &gm, 1, usable_protocols);
2640 : : }
2641 : 104 : }
2642 : :
2643 : : static void
2644 : 46 : ofctl_add_group(struct ovs_cmdl_context *ctx)
2645 : : {
2646 : 46 : ofctl_group_mod(ctx->argc, ctx->argv, OFPGC11_ADD);
2647 : 42 : }
2648 : :
2649 : : static void
2650 : 17 : ofctl_add_groups(struct ovs_cmdl_context *ctx)
2651 : : {
2652 : 17 : ofctl_group_mod_file(ctx->argc, ctx->argv, OFPGC11_ADD);
2653 : 16 : }
2654 : :
2655 : : static void
2656 : 7 : ofctl_mod_group(struct ovs_cmdl_context *ctx)
2657 : : {
2658 [ + + ]: 7 : ofctl_group_mod(ctx->argc, ctx->argv,
2659 : : may_create ? OFPGC11_ADD_OR_MOD : OFPGC11_MODIFY);
2660 : 4 : }
2661 : :
2662 : : static void
2663 : 34 : ofctl_del_groups(struct ovs_cmdl_context *ctx)
2664 : : {
2665 : 34 : ofctl_group_mod(ctx->argc, ctx->argv, OFPGC11_DELETE);
2666 : 31 : }
2667 : :
2668 : : static void
2669 : 19 : ofctl_insert_bucket(struct ovs_cmdl_context *ctx)
2670 : : {
2671 : 19 : ofctl_group_mod(ctx->argc, ctx->argv, OFPGC15_INSERT_BUCKET);
2672 : 13 : }
2673 : :
2674 : : static void
2675 : 18 : ofctl_remove_bucket(struct ovs_cmdl_context *ctx)
2676 : : {
2677 : 18 : ofctl_group_mod(ctx->argc, ctx->argv, OFPGC15_REMOVE_BUCKET);
2678 : 14 : }
2679 : :
2680 : : static void
2681 : 10 : ofctl_dump_group_stats(struct ovs_cmdl_context *ctx)
2682 : : {
2683 : : enum ofputil_protocol usable_protocols;
2684 : : struct ofputil_group_mod gm;
2685 : : struct ofpbuf *request;
2686 : : struct vconn *vconn;
2687 : : uint32_t group_id;
2688 : : char *error;
2689 : :
2690 : 10 : memset(&gm, 0, sizeof gm);
2691 : :
2692 [ + + ]: 10 : error = parse_ofp_group_mod_str(&gm, OFPGC11_DELETE,
2693 : 13 : ctx->argc > 2 ? ctx->argv[2] : "",
2694 : : &usable_protocols);
2695 [ - + ]: 10 : if (error) {
2696 : 0 : ovs_fatal(0, "%s", error);
2697 : : }
2698 : :
2699 : 10 : group_id = gm.group_id;
2700 : :
2701 : 10 : open_vconn(ctx->argv[1], &vconn);
2702 : 10 : request = ofputil_encode_group_stats_request(vconn_get_version(vconn),
2703 : : group_id);
2704 [ + - ]: 10 : if (request) {
2705 : 10 : dump_transaction(vconn, request);
2706 : : }
2707 : :
2708 : 10 : vconn_close(vconn);
2709 : 10 : }
2710 : :
2711 : : static void
2712 : 53 : ofctl_dump_group_desc(struct ovs_cmdl_context *ctx)
2713 : : {
2714 : : struct ofpbuf *request;
2715 : : struct vconn *vconn;
2716 : : uint32_t group_id;
2717 : :
2718 : 53 : open_vconn(ctx->argv[1], &vconn);
2719 : :
2720 [ + + ][ - + ]: 53 : if (ctx->argc < 3 || !ofputil_group_from_string(ctx->argv[2], &group_id)) {
2721 : 43 : group_id = OFPG_ALL;
2722 : : }
2723 : :
2724 : 53 : request = ofputil_encode_group_desc_request(vconn_get_version(vconn),
2725 : : group_id);
2726 [ + - ]: 52 : if (request) {
2727 : 52 : dump_transaction(vconn, request);
2728 : : }
2729 : :
2730 : 52 : vconn_close(vconn);
2731 : 52 : }
2732 : :
2733 : : static void
2734 : 1 : ofctl_dump_group_features(struct ovs_cmdl_context *ctx)
2735 : : {
2736 : : struct ofpbuf *request;
2737 : : struct vconn *vconn;
2738 : :
2739 : 1 : open_vconn(ctx->argv[1], &vconn);
2740 : 1 : request = ofputil_encode_group_features_request(vconn_get_version(vconn));
2741 [ + - ]: 1 : if (request) {
2742 : 1 : dump_transaction(vconn, request);
2743 : : }
2744 : :
2745 : 1 : vconn_close(vconn);
2746 : 1 : }
2747 : :
2748 : : static void
2749 : 2 : ofctl_bundle(struct ovs_cmdl_context *ctx)
2750 : : {
2751 : : enum ofputil_protocol protocol, usable_protocols;
2752 : : struct ofputil_bundle_msg *bms;
2753 : : struct ovs_list requests;
2754 : : struct vconn *vconn;
2755 : : size_t n_bms;
2756 : : char *error;
2757 : :
2758 : 2 : error = parse_ofp_bundle_file(ctx->argv[2], &bms, &n_bms,
2759 : : &usable_protocols);
2760 [ - + ]: 2 : if (error) {
2761 : 0 : ovs_fatal(0, "%s", error);
2762 : : }
2763 : :
2764 : : /* Implicit OpenFlow 1.4. */
2765 [ + - ]: 4 : if (!(get_allowed_ofp_versions() &
2766 : 2 : ofputil_protocols_to_version_bitmap(OFPUTIL_P_OF13_UP))) {
2767 : :
2768 : : /* Add implicit allowance for OpenFlow 1.4. */
2769 : 2 : add_allowed_ofp_versions(ofputil_protocols_to_version_bitmap(
2770 : : OFPUTIL_P_OF14_OXM));
2771 : : /* Remove all versions that do not support bundles. */
2772 : 2 : mask_allowed_ofp_versions(ofputil_protocols_to_version_bitmap(
2773 : : OFPUTIL_P_OF13_UP));
2774 : 2 : allowed_protocols = ofputil_protocols_from_version_bitmap(
2775 : : get_allowed_ofp_versions());
2776 : : }
2777 : :
2778 : : /* Bundles need OpenFlow 1.3+. */
2779 : 2 : usable_protocols &= OFPUTIL_P_OF13_UP;
2780 : 2 : protocol = open_vconn_for_flow_mod(ctx->argv[1], &vconn, usable_protocols);
2781 : :
2782 : 2 : ovs_list_init(&requests);
2783 : 2 : ofputil_encode_bundle_msgs(bms, n_bms, &requests, protocol);
2784 : 2 : bundle_transact(vconn, &requests, OFPBF_ORDERED | OFPBF_ATOMIC);
2785 : 1 : ofpbuf_list_delete(&requests);
2786 : :
2787 : 1 : vconn_close(vconn);
2788 : 1 : }
2789 : :
2790 : : static void
2791 : 13 : ofctl_tlv_mod(struct ovs_cmdl_context *ctx, uint16_t command)
2792 : : {
2793 : : enum ofputil_protocol usable_protocols;
2794 : : enum ofputil_protocol protocol;
2795 : : struct ofputil_tlv_table_mod ttm;
2796 : : char *error;
2797 : : enum ofp_version version;
2798 : : struct ofpbuf *request;
2799 : : struct vconn *vconn;
2800 : :
2801 [ + + ]: 13 : error = parse_ofp_tlv_table_mod_str(&ttm, command, ctx->argc > 2 ?
2802 : 12 : ctx->argv[2] : "",
2803 : : &usable_protocols);
2804 [ - + ]: 13 : if (error) {
2805 : 0 : ovs_fatal(0, "%s", error);
2806 : : }
2807 : :
2808 : 13 : protocol = open_vconn_for_flow_mod(ctx->argv[1], &vconn, usable_protocols);
2809 : 13 : version = ofputil_protocol_to_ofp_version(protocol);
2810 : :
2811 : 13 : request = ofputil_encode_tlv_table_mod(version, &ttm);
2812 [ + - ]: 13 : if (request) {
2813 : 13 : transact_noreply(vconn, request);
2814 : : }
2815 : :
2816 : 12 : vconn_close(vconn);
2817 : 12 : ofputil_uninit_tlv_table(&ttm.mappings);
2818 : 12 : }
2819 : :
2820 : : static void
2821 : 11 : ofctl_add_tlv_map(struct ovs_cmdl_context *ctx)
2822 : : {
2823 : 11 : ofctl_tlv_mod(ctx, NXTTMC_ADD);
2824 : 10 : }
2825 : :
2826 : : static void
2827 : 2 : ofctl_del_tlv_map(struct ovs_cmdl_context *ctx)
2828 : : {
2829 [ + + ]: 2 : ofctl_tlv_mod(ctx, ctx->argc > 2 ? NXTTMC_DELETE : NXTTMC_CLEAR);
2830 : 2 : }
2831 : :
2832 : : static void
2833 : 0 : ofctl_dump_tlv_map(struct ovs_cmdl_context *ctx)
2834 : : {
2835 : 0 : dump_trivial_transaction(ctx->argv[1], OFPRAW_NXT_TLV_TABLE_REQUEST);
2836 : 0 : }
2837 : :
2838 : : static void
2839 : 0 : ofctl_help(struct ovs_cmdl_context *ctx OVS_UNUSED)
2840 : : {
2841 : 0 : usage();
2842 : : }
2843 : :
2844 : : static void
2845 : 2 : ofctl_list_commands(struct ovs_cmdl_context *ctx OVS_UNUSED)
2846 : : {
2847 : 2 : ovs_cmdl_print_commands(get_all_commands());
2848 : 2 : }
2849 : :
2850 : : /* replace-flows and diff-flows commands. */
2851 : :
2852 : : struct flow_tables {
2853 : : struct classifier tables[OFPTT_MAX + 1];
2854 : : };
2855 : :
2856 : : #define FOR_EACH_TABLE(CLS, TABLES) \
2857 : : for ((CLS) = (TABLES)->tables; \
2858 : : (CLS) < &(TABLES)->tables[ARRAY_SIZE((TABLES)->tables)]; \
2859 : : (CLS)++)
2860 : :
2861 : : static void
2862 : 17 : flow_tables_init(struct flow_tables *tables)
2863 : : {
2864 : : struct classifier *cls;
2865 : :
2866 [ + + ]: 4352 : FOR_EACH_TABLE (cls, tables) {
2867 : 4335 : classifier_init(cls, NULL);
2868 : : }
2869 : 17 : }
2870 : :
2871 : : static void
2872 : 17 : flow_tables_defer(struct flow_tables *tables)
2873 : : {
2874 : : struct classifier *cls;
2875 : :
2876 [ + + ]: 4352 : FOR_EACH_TABLE (cls, tables) {
2877 : 4335 : classifier_defer(cls);
2878 : : }
2879 : 17 : }
2880 : :
2881 : : static void
2882 : 17 : flow_tables_publish(struct flow_tables *tables)
2883 : : {
2884 : : struct classifier *cls;
2885 : :
2886 [ + + ]: 4352 : FOR_EACH_TABLE (cls, tables) {
2887 : 4335 : classifier_publish(cls);
2888 : : }
2889 : 17 : }
2890 : :
2891 : : /* A flow table entry, possibly with two different versions. */
2892 : : struct fte {
2893 : : struct cls_rule rule; /* Within a "struct classifier". */
2894 : : struct fte_version *versions[2];
2895 : : };
2896 : :
2897 : : /* One version of a Flow Table Entry. */
2898 : : struct fte_version {
2899 : : ovs_be64 cookie;
2900 : : uint16_t idle_timeout;
2901 : : uint16_t hard_timeout;
2902 : : uint16_t importance;
2903 : : uint16_t flags;
2904 : : struct ofpact *ofpacts;
2905 : : size_t ofpacts_len;
2906 : : uint8_t table_id;
2907 : : };
2908 : :
2909 : : /* Frees 'version' and the data that it owns. */
2910 : : static void
2911 : 28 : fte_version_free(struct fte_version *version)
2912 : : {
2913 [ - + ]: 28 : if (version) {
2914 : 0 : free(CONST_CAST(struct ofpact *, version->ofpacts));
2915 : 0 : free(version);
2916 : : }
2917 : 28 : }
2918 : :
2919 : : /* Returns true if 'a' and 'b' are the same, false if they differ.
2920 : : *
2921 : : * Ignores differences in 'flags' because there's no way to retrieve flags from
2922 : : * an OpenFlow switch. We have to assume that they are the same. */
2923 : : static bool
2924 : 9236 : fte_version_equals(const struct fte_version *a, const struct fte_version *b)
2925 : : {
2926 : 9236 : return (a->cookie == b->cookie
2927 [ + - ]: 9236 : && a->idle_timeout == b->idle_timeout
2928 [ + - ]: 9236 : && a->hard_timeout == b->hard_timeout
2929 [ + + ]: 9236 : && a->importance == b->importance
2930 [ + - ]: 9228 : && a->table_id == b->table_id
2931 [ + - ][ + + ]: 18472 : && ofpacts_equal(a->ofpacts, a->ofpacts_len,
2932 : 9228 : b->ofpacts, b->ofpacts_len));
2933 : : }
2934 : :
2935 : : /* Clears 's', then if 's' has a version 'index', formats 'fte' and version
2936 : : * 'index' into 's', followed by a new-line. */
2937 : : static void
2938 : 2060 : fte_version_format(const struct fte *fte, int index, struct ds *s)
2939 : : {
2940 : 2060 : const struct fte_version *version = fte->versions[index];
2941 : :
2942 : 2060 : ds_clear(s);
2943 [ + + ]: 2060 : if (!version) {
2944 : 1027 : return;
2945 : : }
2946 : :
2947 [ - + ]: 1033 : if (version->table_id) {
2948 : 0 : ds_put_format(s, "table=%"PRIu8" ", version->table_id);
2949 : : }
2950 : 1033 : cls_rule_format(&fte->rule, s);
2951 [ + + ]: 1033 : if (version->cookie != htonll(0)) {
2952 : 1 : ds_put_format(s, " cookie=0x%"PRIx64, ntohll(version->cookie));
2953 : : }
2954 [ + + ]: 1033 : if (version->idle_timeout != OFP_FLOW_PERMANENT) {
2955 : 1 : ds_put_format(s, " idle_timeout=%"PRIu16, version->idle_timeout);
2956 : : }
2957 [ + + ]: 1033 : if (version->hard_timeout != OFP_FLOW_PERMANENT) {
2958 : 1 : ds_put_format(s, " hard_timeout=%"PRIu16, version->hard_timeout);
2959 : : }
2960 [ - + ]: 1033 : if (version->importance != 0) {
2961 : 0 : ds_put_format(s, " importance=%"PRIu16, version->importance);
2962 : : }
2963 : :
2964 : 1033 : ds_put_cstr(s, " actions=");
2965 : 1033 : ofpacts_format(version->ofpacts, version->ofpacts_len, s);
2966 : :
2967 : 1033 : ds_put_char(s, '\n');
2968 : : }
2969 : :
2970 : : static struct fte *
2971 : 19542 : fte_from_cls_rule(const struct cls_rule *cls_rule)
2972 : : {
2973 : 19542 : return cls_rule ? CONTAINER_OF(cls_rule, struct fte, rule) : NULL;
2974 : : }
2975 : :
2976 : : /* Frees 'fte' and its versions. */
2977 : : static void
2978 : 14 : fte_free(struct fte *fte)
2979 : : {
2980 [ + - ]: 14 : if (fte) {
2981 : 14 : fte_version_free(fte->versions[0]);
2982 : 14 : fte_version_free(fte->versions[1]);
2983 : 14 : cls_rule_destroy(&fte->rule);
2984 : 14 : free(fte);
2985 : : }
2986 : 14 : }
2987 : :
2988 : : /* Frees all of the FTEs within 'tables'. */
2989 : : static void
2990 : 17 : fte_free_all(struct flow_tables *tables)
2991 : : {
2992 : : struct classifier *cls;
2993 : :
2994 [ + + ]: 4352 : FOR_EACH_TABLE (cls, tables) {
2995 : : struct fte *fte;
2996 : :
2997 : 4335 : classifier_defer(cls);
2998 [ + + ][ + + ]: 14641 : CLS_FOR_EACH (fte, rule, cls) {
2999 : 10306 : classifier_remove(cls, &fte->rule);
3000 : 10306 : ovsrcu_postpone(fte_free, fte);
3001 : : }
3002 : 4335 : classifier_destroy(cls);
3003 : : }
3004 : 17 : }
3005 : :
3006 : : /* Searches 'tables' for an FTE matching 'rule', inserting a new one if
3007 : : * necessary. Sets 'version' as the version of that rule with the given
3008 : : * 'index', replacing any existing version, if any.
3009 : : *
3010 : : * Takes ownership of 'version'. */
3011 : : static void
3012 : 19542 : fte_insert(struct flow_tables *tables, const struct match *match,
3013 : : int priority, struct fte_version *version, int index)
3014 : : {
3015 : 19542 : struct classifier *cls = &tables->tables[version->table_id];
3016 : : struct fte *old, *fte;
3017 : :
3018 : 19542 : fte = xzalloc(sizeof *fte);
3019 : 19542 : cls_rule_init(&fte->rule, match, priority);
3020 : 19542 : fte->versions[index] = version;
3021 : :
3022 : 19542 : old = fte_from_cls_rule(classifier_replace(cls, &fte->rule,
3023 : : OVS_VERSION_MIN, NULL, 0));
3024 [ + + ]: 19542 : if (old) {
3025 : 9236 : fte->versions[!index] = old->versions[!index];
3026 : 9236 : old->versions[!index] = NULL;
3027 : :
3028 : 9236 : ovsrcu_postpone(fte_free, old);
3029 : : }
3030 : 19542 : }
3031 : :
3032 : : /* A FTE entry that has been queued for later insertion after all
3033 : : * flows have been scanned to correctly allocation tunnel metadata. */
3034 : : struct fte_pending {
3035 : : struct match *match;
3036 : : int priority;
3037 : : struct fte_version *version;
3038 : : int index;
3039 : :
3040 : : struct ovs_list list_node;
3041 : : };
3042 : :
3043 : : /* Processing state during two stage processing of flow table entries.
3044 : : * Tracks the maximum size seen for each tunnel metadata entry as well
3045 : : * as a list of the pending FTE entries. */
3046 : : struct fte_state {
3047 : : int tun_metadata_size[TUN_METADATA_NUM_OPTS];
3048 : : struct ovs_list fte_pending_list;
3049 : : };
3050 : :
3051 : : /* Given a list of the field sizes for each tunnel metadata entry, install
3052 : : * a mapping table for later operations. */
3053 : : static void
3054 : 17 : generate_tun_metadata(struct fte_state *state)
3055 : : {
3056 : : struct ofputil_tlv_table_mod ttm;
3057 : : int i;
3058 : :
3059 : 17 : ttm.command = NXTTMC_ADD;
3060 : 17 : ovs_list_init(&ttm.mappings);
3061 : :
3062 [ + + ]: 1105 : for (i = 0; i < TUN_METADATA_NUM_OPTS; i++) {
3063 [ + + ]: 1088 : if (state->tun_metadata_size[i] != -1) {
3064 : 2 : struct ofputil_tlv_map *map = xmalloc(sizeof *map);
3065 : :
3066 : 2 : ovs_list_push_back(&ttm.mappings, &map->list_node);
3067 : :
3068 : : /* We don't care about the actual option class and type since there
3069 : : * won't be any lookup. We just need to make them unique. */
3070 : 2 : map->option_class = i / UINT8_MAX;
3071 : 2 : map->option_type = i;
3072 : 2 : map->option_len = ROUND_UP(state->tun_metadata_size[i], 4);
3073 : 2 : map->index = i;
3074 : : }
3075 : : }
3076 : :
3077 : 17 : tun_metadata_table_mod(&ttm);
3078 : 17 : ofputil_uninit_tlv_table(&ttm.mappings);
3079 : 17 : }
3080 : :
3081 : : /* Once we have created a tunnel mapping table with a consistent overall
3082 : : * allocation, we need to remap each flow to use this table from its own
3083 : : * allocation. Since the mapping table has already been installed, we
3084 : : * can just read the data from the match and rewrite it. On rewrite, it
3085 : : * will use the new table. */
3086 : : static void
3087 : 19542 : remap_match(struct match *match)
3088 : : {
3089 : : int i;
3090 : :
3091 [ + + ]: 19542 : if (!match->tun_md.valid) {
3092 : 19537 : return;
3093 : : }
3094 : :
3095 : 5 : struct tun_metadata flow = match->flow.tunnel.metadata;
3096 : 5 : struct tun_metadata flow_mask = match->wc.masks.tunnel.metadata;
3097 : 5 : memset(&match->flow.tunnel.metadata, 0, sizeof match->flow.tunnel.metadata);
3098 : 5 : memset(&match->wc.masks.tunnel.metadata, 0,
3099 : : sizeof match->wc.masks.tunnel.metadata);
3100 : 5 : match->tun_md.valid = false;
3101 : :
3102 [ + + ]: 11 : ULLONG_FOR_EACH_1 (i, flow_mask.present.map) {
3103 : 6 : const struct mf_field *field = mf_from_id(MFF_TUN_METADATA0 + i);
3104 : 6 : int offset = match->tun_md.entry[i].loc.c.offset;
3105 : 6 : int len = match->tun_md.entry[i].loc.len;
3106 : : union mf_value value, mask;
3107 : :
3108 : 6 : memset(&value, 0, field->n_bytes - len);
3109 [ + + ]: 6 : memset(&mask, match->tun_md.entry[i].masked ? 0 : 0xff,
3110 : 6 : field->n_bytes - len);
3111 : :
3112 : 12 : memcpy(value.tun_metadata + field->n_bytes - len,
3113 : 6 : flow.opts.u8 + offset, len);
3114 : 12 : memcpy(mask.tun_metadata + field->n_bytes - len,
3115 : 6 : flow_mask.opts.u8 + offset, len);
3116 : 6 : mf_set(field, &value, &mask, match, NULL);
3117 : : }
3118 : : }
3119 : :
3120 : : /* In order to correctly handle tunnel metadata, we need to have
3121 : : * two passes over the flows. This happens because tunnel metadata
3122 : : * doesn't have fixed locations in a flow entry but is instead dynamically
3123 : : * allocated space. In the case of flows coming from a file, we don't
3124 : : * even know the size of each field when we need to do the allocation.
3125 : : * When the flows come in, each flow has an individual allocation based
3126 : : * on its own fields. However, this allocation is not the same across
3127 : : * different flows and therefore fields are not directly comparable.
3128 : : *
3129 : : * In the first pass, we record the maximum size of each tunnel metadata
3130 : : * field as well as queue FTE entries for later processing.
3131 : : *
3132 : : * In the second pass, we use the metadata size information to create a
3133 : : * tunnel mapping table and set that through the tunnel metadata processing
3134 : : * code. We then remap all individual flows to use this common allocation
3135 : : * scheme. Finally, we load the queued entries into the classifier for
3136 : : * comparison.
3137 : : *
3138 : : * fte_state_init() should be called before processing any flows. */
3139 : : static void
3140 : 17 : fte_state_init(struct fte_state *state)
3141 : : {
3142 : : int i;
3143 : :
3144 [ + + ]: 1105 : for (i = 0; i < TUN_METADATA_NUM_OPTS; i++) {
3145 : 1088 : state->tun_metadata_size[i] = -1;
3146 : : }
3147 : :
3148 : 17 : ovs_list_init(&state->fte_pending_list);
3149 : 17 : }
3150 : :
3151 : : /* The first pass of the processing described in the comment about
3152 : : * fte_state_init(). fte_queue() is the first pass to be called as each
3153 : : * flow is read from its source. */
3154 : : static void
3155 : 19542 : fte_queue(struct fte_state *state, const struct match *match,
3156 : : int priority, struct fte_version *version, int index)
3157 : : {
3158 : 19542 : struct fte_pending *pending = xmalloc(sizeof *pending);
3159 : : int i;
3160 : :
3161 : 19542 : pending->match = xmemdup(match, sizeof *match);
3162 : 19542 : pending->priority = priority;
3163 : 19542 : pending->version = version;
3164 : 19542 : pending->index = index;
3165 : 19542 : ovs_list_push_back(&state->fte_pending_list, &pending->list_node);
3166 : :
3167 [ + + ]: 19542 : if (!match->tun_md.valid) {
3168 : 19537 : return;
3169 : : }
3170 : :
3171 [ + + ]: 11 : ULLONG_FOR_EACH_1 (i, match->wc.masks.tunnel.metadata.present.map) {
3172 [ + + ]: 6 : if (match->tun_md.entry[i].loc.len > state->tun_metadata_size[i]) {
3173 : 3 : state->tun_metadata_size[i] = match->tun_md.entry[i].loc.len;
3174 : : }
3175 : : }
3176 : : }
3177 : :
3178 : : /* The second pass of the processing described in the comment about
3179 : : * fte_state_init(). This should be called once all flows (from both
3180 : : * sides of the comparison) have been added through fte_queue(). */
3181 : : static void
3182 : 17 : fte_fill(struct fte_state *state, struct flow_tables *tables)
3183 : : {
3184 : : struct fte_pending *pending;
3185 : :
3186 : 17 : generate_tun_metadata(state);
3187 : :
3188 : 17 : flow_tables_init(tables);
3189 : 17 : flow_tables_defer(tables);
3190 : :
3191 [ + + ]: 19559 : LIST_FOR_EACH_POP(pending, list_node, &state->fte_pending_list) {
3192 : 19542 : remap_match(pending->match);
3193 : 19542 : fte_insert(tables, pending->match, pending->priority, pending->version,
3194 : : pending->index);
3195 : 19542 : free(pending->match);
3196 : 19542 : free(pending);
3197 : : }
3198 : :
3199 : 17 : flow_tables_publish(tables);
3200 : 17 : }
3201 : :
3202 : : /* Reads the flows in 'filename' as flow table entries in 'tables' for the
3203 : : * version with the specified 'index'. Returns the flow formats able to
3204 : : * represent the flows that were read. */
3205 : : static enum ofputil_protocol
3206 : 17 : read_flows_from_file(const char *filename, struct fte_state *state, int index)
3207 : : {
3208 : : enum ofputil_protocol usable_protocols;
3209 : : int line_number;
3210 : : struct ds s;
3211 : : FILE *file;
3212 : :
3213 [ + - ]: 17 : file = !strcmp(filename, "-") ? stdin : fopen(filename, "r");
3214 [ - + ]: 17 : if (file == NULL) {
3215 : 0 : ovs_fatal(errno, "%s: open", filename);
3216 : : }
3217 : :
3218 : 17 : ds_init(&s);
3219 : 17 : usable_protocols = OFPUTIL_P_ANY;
3220 : 17 : line_number = 0;
3221 [ + + ]: 10311 : while (!ds_get_preprocessed_line(&s, file, &line_number)) {
3222 : : struct fte_version *version;
3223 : : struct ofputil_flow_mod fm;
3224 : : char *error;
3225 : : enum ofputil_protocol usable;
3226 : :
3227 : 10294 : error = parse_ofp_str(&fm, OFPFC_ADD, ds_cstr(&s), &usable);
3228 [ - + ]: 10294 : if (error) {
3229 : 0 : ovs_fatal(0, "%s:%d: %s", filename, line_number, error);
3230 : : }
3231 : 10294 : usable_protocols &= usable;
3232 : :
3233 : 10294 : version = xmalloc(sizeof *version);
3234 : 10294 : version->cookie = fm.new_cookie;
3235 : 10294 : version->idle_timeout = fm.idle_timeout;
3236 : 10294 : version->hard_timeout = fm.hard_timeout;
3237 : 10294 : version->importance = fm.importance;
3238 : 10294 : version->flags = fm.flags & (OFPUTIL_FF_SEND_FLOW_REM
3239 : : | OFPUTIL_FF_EMERG);
3240 : 10294 : version->ofpacts = fm.ofpacts;
3241 : 10294 : version->ofpacts_len = fm.ofpacts_len;
3242 [ + + ]: 10294 : version->table_id = fm.table_id != OFPTT_ALL ? fm.table_id : 0;
3243 : :
3244 : 10294 : fte_queue(state, &fm.match, fm.priority, version, index);
3245 : : }
3246 : 17 : ds_destroy(&s);
3247 : :
3248 [ + - ]: 17 : if (file != stdin) {
3249 : 17 : fclose(file);
3250 : : }
3251 : :
3252 : 17 : return usable_protocols;
3253 : : }
3254 : :
3255 : : static bool
3256 : 9337 : recv_flow_stats_reply(struct vconn *vconn, ovs_be32 send_xid,
3257 : : struct ofpbuf **replyp,
3258 : : struct ofputil_flow_stats *fs, struct ofpbuf *ofpacts)
3259 : : {
3260 : 9337 : struct ofpbuf *reply = *replyp;
3261 : :
3262 : : for (;;) {
3263 : : int retval;
3264 : : bool more;
3265 : :
3266 : : /* Get a flow stats reply message, if we don't already have one. */
3267 [ + + ]: 9343 : if (!reply) {
3268 : : enum ofptype type;
3269 : : enum ofperr error;
3270 : :
3271 : : do {
3272 : 29 : run(vconn_recv_block(vconn, &reply),
3273 : : "OpenFlow packet receive failed");
3274 [ - + ]: 29 : } while (((struct ofp_header *) reply->data)->xid != send_xid);
3275 : :
3276 : 29 : error = ofptype_decode(&type, reply->data);
3277 [ + - ][ - + ]: 29 : if (error || type != OFPTYPE_FLOW_STATS_REPLY) {
3278 : 29 : ovs_fatal(0, "received bad reply: %s",
3279 : 0 : ofp_to_string(reply->data, reply->size,
3280 : : verbosity + 1));
3281 : : }
3282 : : }
3283 : :
3284 : : /* Pull an individual flow stats reply out of the message. */
3285 : 9343 : retval = ofputil_decode_flow_stats_reply(fs, reply, false, ofpacts);
3286 [ + + - ]: 9343 : switch (retval) {
3287 : : case 0:
3288 : 9314 : *replyp = reply;
3289 : 9314 : return true;
3290 : :
3291 : : case EOF:
3292 : 29 : more = ofpmp_more(reply->header);
3293 : 29 : ofpbuf_delete(reply);
3294 : 29 : reply = NULL;
3295 [ + + ]: 29 : if (!more) {
3296 : 23 : *replyp = NULL;
3297 : 23 : return false;
3298 : : }
3299 : 6 : break;
3300 : :
3301 : : default:
3302 : 0 : ovs_fatal(0, "parse error in reply (%s)",
3303 : : ofperr_to_string(retval));
3304 : : }
3305 : 9343 : }
3306 : : }
3307 : :
3308 : : /* Reads the OpenFlow flow table from 'vconn', which has currently active flow
3309 : : * format 'protocol', and adds them as flow table entries in 'tables' for the
3310 : : * version with the specified 'index'. */
3311 : : static void
3312 : 17 : read_flows_from_switch(struct vconn *vconn,
3313 : : enum ofputil_protocol protocol,
3314 : : struct fte_state *state, int index)
3315 : : {
3316 : : struct ofputil_flow_stats_request fsr;
3317 : : struct ofputil_flow_stats fs;
3318 : : struct ofpbuf *request;
3319 : : struct ofpbuf ofpacts;
3320 : : struct ofpbuf *reply;
3321 : : ovs_be32 send_xid;
3322 : :
3323 : 17 : fsr.aggregate = false;
3324 : 17 : match_init_catchall(&fsr.match);
3325 : 17 : fsr.out_port = OFPP_ANY;
3326 : 17 : fsr.out_group = OFPG_ANY;
3327 : 17 : fsr.table_id = 0xff;
3328 : 17 : fsr.cookie = fsr.cookie_mask = htonll(0);
3329 : 17 : request = ofputil_encode_flow_stats_request(&fsr, protocol);
3330 : 17 : send_xid = ((struct ofp_header *) request->data)->xid;
3331 : 17 : send_openflow_buffer(vconn, request);
3332 : :
3333 : 17 : reply = NULL;
3334 : 17 : ofpbuf_init(&ofpacts, 0);
3335 [ + + ]: 9265 : while (recv_flow_stats_reply(vconn, send_xid, &reply, &fs, &ofpacts)) {
3336 : : struct fte_version *version;
3337 : :
3338 : 9248 : version = xmalloc(sizeof *version);
3339 : 9248 : version->cookie = fs.cookie;
3340 : 9248 : version->idle_timeout = fs.idle_timeout;
3341 : 9248 : version->hard_timeout = fs.hard_timeout;
3342 : 9248 : version->importance = fs.importance;
3343 : 9248 : version->flags = 0;
3344 : 9248 : version->ofpacts_len = fs.ofpacts_len;
3345 : 9248 : version->ofpacts = xmemdup(fs.ofpacts, fs.ofpacts_len);
3346 : 9248 : version->table_id = fs.table_id;
3347 : :
3348 : 9248 : fte_queue(state, &fs.match, fs.priority, version, index);
3349 : : }
3350 : 17 : ofpbuf_uninit(&ofpacts);
3351 : 17 : }
3352 : :
3353 : : static void
3354 : 52 : fte_make_flow_mod(const struct fte *fte, int index, uint16_t command,
3355 : : enum ofputil_protocol protocol, struct ovs_list *packets)
3356 : : {
3357 : 52 : const struct fte_version *version = fte->versions[index];
3358 : : struct ofpbuf *ofm;
3359 : :
3360 : 416 : struct ofputil_flow_mod fm = {
3361 : 52 : .priority = fte->rule.priority,
3362 : 52 : .new_cookie = version->cookie,
3363 : : .modify_cookie = true,
3364 : 52 : .table_id = version->table_id,
3365 : : .command = command,
3366 : 52 : .idle_timeout = version->idle_timeout,
3367 : 52 : .hard_timeout = version->hard_timeout,
3368 : 52 : .importance = version->importance,
3369 : : .buffer_id = UINT32_MAX,
3370 : : .out_port = OFPP_ANY,
3371 : : .out_group = OFPG_ANY,
3372 : 52 : .flags = version->flags,
3373 : : };
3374 : 52 : minimatch_expand(&fte->rule.match, &fm.match);
3375 [ + + ][ + - ]: 52 : if (command == OFPFC_ADD || command == OFPFC_MODIFY ||
[ - + ]
3376 : : command == OFPFC_MODIFY_STRICT) {
3377 : 43 : fm.ofpacts = version->ofpacts;
3378 : 43 : fm.ofpacts_len = version->ofpacts_len;
3379 : : } else {
3380 : 9 : fm.ofpacts = NULL;
3381 : 9 : fm.ofpacts_len = 0;
3382 : : }
3383 : :
3384 : 52 : ofm = ofputil_encode_flow_mod(&fm, protocol);
3385 : 52 : ovs_list_push_back(packets, &ofm->list_node);
3386 : 52 : }
3387 : :
3388 : : static void
3389 : 9 : ofctl_replace_flows(struct ovs_cmdl_context *ctx)
3390 : : {
3391 : : enum { FILE_IDX = 0, SWITCH_IDX = 1 };
3392 : : enum ofputil_protocol usable_protocols, protocol;
3393 : : struct fte_state fte_state;
3394 : : struct flow_tables tables;
3395 : : struct classifier *cls;
3396 : : struct ovs_list requests;
3397 : : struct vconn *vconn;
3398 : : struct fte *fte;
3399 : :
3400 : 9 : fte_state_init(&fte_state);
3401 : 9 : usable_protocols = read_flows_from_file(ctx->argv[2], &fte_state, FILE_IDX);
3402 : :
3403 : 9 : protocol = open_vconn(ctx->argv[1], &vconn);
3404 : 9 : protocol = set_protocol_for_flow_dump(vconn, protocol, usable_protocols);
3405 : :
3406 : 9 : read_flows_from_switch(vconn, protocol, &fte_state, SWITCH_IDX);
3407 : :
3408 : 9 : fte_fill(&fte_state, &tables);
3409 : :
3410 : 9 : ovs_list_init(&requests);
3411 : :
3412 [ + + ]: 2304 : FOR_EACH_TABLE (cls, &tables) {
3413 : : /* Delete flows that exist on the switch but not in the file. */
3414 [ + + ][ + + ]: 2352 : CLS_FOR_EACH (fte, rule, cls) {
3415 : 57 : struct fte_version *file_ver = fte->versions[FILE_IDX];
3416 : 57 : struct fte_version *sw_ver = fte->versions[SWITCH_IDX];
3417 : :
3418 [ + + ][ + + ]: 57 : if (sw_ver && !file_ver) {
3419 : 9 : fte_make_flow_mod(fte, SWITCH_IDX, OFPFC_DELETE_STRICT,
3420 : : protocol, &requests);
3421 : : }
3422 : : }
3423 : :
3424 : : /* Add flows that exist in the file but not on the switch.
3425 : : * Update flows that exist in both places but differ. */
3426 [ + + ][ + + ]: 2352 : CLS_FOR_EACH (fte, rule, cls) {
3427 : 57 : struct fte_version *file_ver = fte->versions[FILE_IDX];
3428 : 57 : struct fte_version *sw_ver = fte->versions[SWITCH_IDX];
3429 : :
3430 [ + + ][ + - ]: 57 : if (file_ver &&
3431 [ + + ][ + + ]: 48 : (readd || !sw_ver || !fte_version_equals(sw_ver, file_ver))) {
3432 : 43 : fte_make_flow_mod(fte, FILE_IDX, OFPFC_ADD, protocol,
3433 : : &requests);
3434 : : }
3435 : : }
3436 : : }
3437 [ + + ]: 9 : if (bundle) {
3438 : 5 : bundle_transact(vconn, &requests, OFPBF_ORDERED | OFPBF_ATOMIC);
3439 : : } else {
3440 : 4 : transact_multiple_noreply(vconn, &requests);
3441 : : }
3442 : :
3443 : 9 : ofpbuf_list_delete(&requests);
3444 : 9 : vconn_close(vconn);
3445 : :
3446 : 9 : fte_free_all(&tables);
3447 : 9 : }
3448 : :
3449 : : static void
3450 : 16 : read_flows_from_source(const char *source, struct fte_state *state, int index)
3451 : : {
3452 : : struct stat s;
3453 : :
3454 [ + - ][ + - ]: 16 : if (source[0] == '/' || source[0] == '.'
3455 [ + - ][ + + ]: 16 : || (!strchr(source, ':') && !stat(source, &s))) {
3456 : 8 : read_flows_from_file(source, state, index);
3457 : : } else {
3458 : : enum ofputil_protocol protocol;
3459 : : struct vconn *vconn;
3460 : :
3461 : 8 : protocol = open_vconn(source, &vconn);
3462 : 8 : protocol = set_protocol_for_flow_dump(vconn, protocol, OFPUTIL_P_ANY);
3463 : 8 : read_flows_from_switch(vconn, protocol, state, index);
3464 : 8 : vconn_close(vconn);
3465 : : }
3466 : 16 : }
3467 : :
3468 : : static void
3469 : 8 : ofctl_diff_flows(struct ovs_cmdl_context *ctx)
3470 : : {
3471 : 8 : bool differences = false;
3472 : : struct fte_state fte_state;
3473 : : struct flow_tables tables;
3474 : : struct classifier *cls;
3475 : : struct ds a_s, b_s;
3476 : : struct fte *fte;
3477 : :
3478 : 8 : fte_state_init(&fte_state);
3479 : 8 : read_flows_from_source(ctx->argv[1], &fte_state, 0);
3480 : 8 : read_flows_from_source(ctx->argv[2], &fte_state, 1);
3481 : 8 : fte_fill(&fte_state, &tables);
3482 : :
3483 : 8 : ds_init(&a_s);
3484 : 8 : ds_init(&b_s);
3485 : :
3486 [ + + ]: 2048 : FOR_EACH_TABLE (cls, &tables) {
3487 [ + + ][ + + ]: 12289 : CLS_FOR_EACH (fte, rule, cls) {
3488 : 10249 : struct fte_version *a = fte->versions[0];
3489 : 10249 : struct fte_version *b = fte->versions[1];
3490 : :
3491 [ + + ][ + + ]: 10249 : if (!a || !b || !fte_version_equals(a, b)) {
[ + + ]
3492 : 1030 : fte_version_format(fte, 0, &a_s);
3493 : 1030 : fte_version_format(fte, 1, &b_s);
3494 [ + + ]: 1030 : if (strcmp(ds_cstr(&a_s), ds_cstr(&b_s))) {
3495 [ + + ]: 1027 : if (a_s.length) {
3496 : 514 : printf("-%s", ds_cstr(&a_s));
3497 : : }
3498 [ + + ]: 1027 : if (b_s.length) {
3499 : 513 : printf("+%s", ds_cstr(&b_s));
3500 : : }
3501 : 1027 : differences = true;
3502 : : }
3503 : : }
3504 : : }
3505 : : }
3506 : :
3507 : 8 : ds_destroy(&a_s);
3508 : 8 : ds_destroy(&b_s);
3509 : :
3510 : 8 : fte_free_all(&tables);
3511 : :
3512 [ + + ]: 8 : if (differences) {
3513 : 5 : exit(2);
3514 : : }
3515 : 3 : }
3516 : :
3517 : : static void
3518 : 0 : ofctl_meter_mod__(const char *bridge, const char *str, int command)
3519 : : {
3520 : : struct ofputil_meter_mod mm;
3521 : : struct vconn *vconn;
3522 : : enum ofputil_protocol protocol;
3523 : : enum ofputil_protocol usable_protocols;
3524 : : enum ofp_version version;
3525 : :
3526 [ # # ]: 0 : if (str) {
3527 : : char *error;
3528 : 0 : error = parse_ofp_meter_mod_str(&mm, str, command, &usable_protocols);
3529 [ # # ]: 0 : if (error) {
3530 : 0 : ovs_fatal(0, "%s", error);
3531 : : }
3532 : : } else {
3533 : 0 : usable_protocols = OFPUTIL_P_OF13_UP;
3534 : 0 : mm.command = command;
3535 : 0 : mm.meter.meter_id = OFPM13_ALL;
3536 : : }
3537 : :
3538 : 0 : protocol = open_vconn_for_flow_mod(bridge, &vconn, usable_protocols);
3539 : 0 : version = ofputil_protocol_to_ofp_version(protocol);
3540 : 0 : transact_noreply(vconn, ofputil_encode_meter_mod(version, &mm));
3541 : 0 : vconn_close(vconn);
3542 : 0 : }
3543 : :
3544 : : static void
3545 : 0 : ofctl_meter_request__(const char *bridge, const char *str,
3546 : : enum ofputil_meter_request_type type)
3547 : : {
3548 : : struct ofputil_meter_mod mm;
3549 : : struct vconn *vconn;
3550 : : enum ofputil_protocol usable_protocols;
3551 : : enum ofputil_protocol protocol;
3552 : : enum ofp_version version;
3553 : :
3554 [ # # ]: 0 : if (str) {
3555 : : char *error;
3556 : 0 : error = parse_ofp_meter_mod_str(&mm, str, -1, &usable_protocols);
3557 [ # # ]: 0 : if (error) {
3558 : 0 : ovs_fatal(0, "%s", error);
3559 : : }
3560 : : } else {
3561 : 0 : usable_protocols = OFPUTIL_P_OF13_UP;
3562 : 0 : mm.meter.meter_id = OFPM13_ALL;
3563 : : }
3564 : :
3565 : 0 : protocol = open_vconn_for_flow_mod(bridge, &vconn, usable_protocols);
3566 : 0 : version = ofputil_protocol_to_ofp_version(protocol);
3567 : 0 : dump_transaction(vconn, ofputil_encode_meter_request(version, type,
3568 : : mm.meter.meter_id));
3569 : 0 : vconn_close(vconn);
3570 : 0 : }
3571 : :
3572 : :
3573 : : static void
3574 : 0 : ofctl_add_meter(struct ovs_cmdl_context *ctx)
3575 : : {
3576 : 0 : ofctl_meter_mod__(ctx->argv[1], ctx->argv[2], OFPMC13_ADD);
3577 : 0 : }
3578 : :
3579 : : static void
3580 : 0 : ofctl_mod_meter(struct ovs_cmdl_context *ctx)
3581 : : {
3582 : 0 : ofctl_meter_mod__(ctx->argv[1], ctx->argv[2], OFPMC13_MODIFY);
3583 : 0 : }
3584 : :
3585 : : static void
3586 : 0 : ofctl_del_meters(struct ovs_cmdl_context *ctx)
3587 : : {
3588 [ # # ]: 0 : ofctl_meter_mod__(ctx->argv[1], ctx->argc > 2 ? ctx->argv[2] : NULL, OFPMC13_DELETE);
3589 : 0 : }
3590 : :
3591 : : static void
3592 : 0 : ofctl_dump_meters(struct ovs_cmdl_context *ctx)
3593 : : {
3594 [ # # ]: 0 : ofctl_meter_request__(ctx->argv[1], ctx->argc > 2 ? ctx->argv[2] : NULL,
3595 : : OFPUTIL_METER_CONFIG);
3596 : 0 : }
3597 : :
3598 : : static void
3599 : 0 : ofctl_meter_stats(struct ovs_cmdl_context *ctx)
3600 : : {
3601 [ # # ]: 0 : ofctl_meter_request__(ctx->argv[1], ctx->argc > 2 ? ctx->argv[2] : NULL,
3602 : : OFPUTIL_METER_STATS);
3603 : 0 : }
3604 : :
3605 : : static void
3606 : 0 : ofctl_meter_features(struct ovs_cmdl_context *ctx)
3607 : : {
3608 : 0 : ofctl_meter_request__(ctx->argv[1], NULL, OFPUTIL_METER_FEATURES);
3609 : 0 : }
3610 : :
3611 : :
3612 : : /* Undocumented commands for unit testing. */
3613 : :
3614 : : static void
3615 : 164 : ofctl_parse_flows__(struct ofputil_flow_mod *fms, size_t n_fms,
3616 : : enum ofputil_protocol usable_protocols)
3617 : : {
3618 : 164 : enum ofputil_protocol protocol = 0;
3619 : : char *usable_s;
3620 : : size_t i;
3621 : :
3622 : 164 : usable_s = ofputil_protocols_to_string(usable_protocols);
3623 : 164 : printf("usable protocols: %s\n", usable_s);
3624 : 164 : free(usable_s);
3625 : :
3626 [ - + ]: 164 : if (!(usable_protocols & allowed_protocols)) {
3627 : 0 : ovs_fatal(0, "no usable protocol");
3628 : : }
3629 [ + - ]: 428 : for (i = 0; i < sizeof(enum ofputil_protocol) * CHAR_BIT; i++) {
3630 : 428 : protocol = 1 << i;
3631 [ + + ]: 428 : if (protocol & usable_protocols & allowed_protocols) {
3632 : 164 : break;
3633 : : }
3634 : : }
3635 [ - + ]: 164 : ovs_assert(is_pow2(protocol));
3636 : :
3637 : 164 : printf("chosen protocol: %s\n", ofputil_protocol_to_string(protocol));
3638 : :
3639 [ + + ]: 491 : for (i = 0; i < n_fms; i++) {
3640 : 327 : struct ofputil_flow_mod *fm = &fms[i];
3641 : : struct ofpbuf *msg;
3642 : :
3643 : 327 : msg = ofputil_encode_flow_mod(fm, protocol);
3644 : 327 : ofp_print(stdout, msg->data, msg->size, verbosity);
3645 : 327 : ofpbuf_delete(msg);
3646 : :
3647 : 327 : free(CONST_CAST(struct ofpact *, fm->ofpacts));
3648 : : }
3649 : 164 : }
3650 : :
3651 : : /* "parse-flow FLOW": parses the argument as a flow (like add-flow) and prints
3652 : : * it back to stdout. */
3653 : : static void
3654 : 196 : ofctl_parse_flow(struct ovs_cmdl_context *ctx)
3655 : : {
3656 : : enum ofputil_protocol usable_protocols;
3657 : : struct ofputil_flow_mod fm;
3658 : : char *error;
3659 : :
3660 : 196 : error = parse_ofp_flow_mod_str(&fm, ctx->argv[1], OFPFC_ADD, &usable_protocols);
3661 [ + + ]: 196 : if (error) {
3662 : 42 : ovs_fatal(0, "%s", error);
3663 : : }
3664 : 154 : ofctl_parse_flows__(&fm, 1, usable_protocols);
3665 : 154 : }
3666 : :
3667 : : /* "parse-flows FILENAME": reads the named file as a sequence of flows (like
3668 : : * add-flows) and prints each of the flows back to stdout. */
3669 : : static void
3670 : 11 : ofctl_parse_flows(struct ovs_cmdl_context *ctx)
3671 : : {
3672 : : enum ofputil_protocol usable_protocols;
3673 : 11 : struct ofputil_flow_mod *fms = NULL;
3674 : 11 : size_t n_fms = 0;
3675 : : char *error;
3676 : :
3677 : 11 : error = parse_ofp_flow_mod_file(ctx->argv[1], OFPFC_ADD, &fms, &n_fms,
3678 : : &usable_protocols);
3679 [ + + ]: 11 : if (error) {
3680 : 1 : ovs_fatal(0, "%s", error);
3681 : : }
3682 : 10 : ofctl_parse_flows__(fms, n_fms, usable_protocols);
3683 : 10 : free(fms);
3684 : 10 : }
3685 : :
3686 : : static void
3687 : 15 : ofctl_parse_nxm__(bool oxm, enum ofp_version version)
3688 : : {
3689 : : struct ds in;
3690 : :
3691 : 15 : ds_init(&in);
3692 [ + + ]: 444 : while (!ds_get_test_line(&in, stdin)) {
3693 : : struct ofpbuf nx_match;
3694 : : struct match match;
3695 : : ovs_be64 cookie, cookie_mask;
3696 : : enum ofperr error;
3697 : : int match_len;
3698 : :
3699 : : /* Convert string to nx_match. */
3700 : 429 : ofpbuf_init(&nx_match, 0);
3701 [ + + ]: 429 : if (oxm) {
3702 : 217 : match_len = oxm_match_from_string(ds_cstr(&in), &nx_match);
3703 : : } else {
3704 : 212 : match_len = nx_match_from_string(ds_cstr(&in), &nx_match);
3705 : : }
3706 : :
3707 : : /* Convert nx_match to match. */
3708 [ + + ]: 429 : if (strict) {
3709 [ + + ]: 418 : if (oxm) {
3710 : 210 : error = oxm_pull_match(&nx_match, &match);
3711 : : } else {
3712 : 418 : error = nx_pull_match(&nx_match, match_len, &match,
3713 : : &cookie, &cookie_mask);
3714 : : }
3715 : : } else {
3716 [ + + ]: 11 : if (oxm) {
3717 : 7 : error = oxm_pull_match_loose(&nx_match, &match);
3718 : : } else {
3719 : 4 : error = nx_pull_match_loose(&nx_match, match_len, &match,
3720 : : &cookie, &cookie_mask);
3721 : : }
3722 : : }
3723 : :
3724 : :
3725 [ + + ]: 429 : if (!error) {
3726 : : char *out;
3727 : :
3728 : : /* Convert match back to nx_match. */
3729 : 283 : ofpbuf_uninit(&nx_match);
3730 : 283 : ofpbuf_init(&nx_match, 0);
3731 [ + + ]: 283 : if (oxm) {
3732 : 158 : match_len = oxm_put_match(&nx_match, &match, version);
3733 : 158 : out = oxm_match_to_string(&nx_match, match_len);
3734 : : } else {
3735 : 125 : match_len = nx_put_match(&nx_match, &match,
3736 : : cookie, cookie_mask);
3737 : 125 : out = nx_match_to_string(nx_match.data, match_len);
3738 : : }
3739 : :
3740 : 283 : puts(out);
3741 : 283 : free(out);
3742 : :
3743 [ + + ]: 283 : if (verbosity > 0) {
3744 : 283 : ovs_hex_dump(stdout, nx_match.data, nx_match.size, 0, false);
3745 : : }
3746 : : } else {
3747 : 146 : printf("nx_pull_match() returned error %s\n",
3748 : : ofperr_get_name(error));
3749 : : }
3750 : :
3751 : 429 : ofpbuf_uninit(&nx_match);
3752 : : }
3753 : 15 : ds_destroy(&in);
3754 : 15 : }
3755 : :
3756 : : /* "parse-nxm": reads a series of NXM nx_match specifications as strings from
3757 : : * stdin, does some internal fussing with them, and then prints them back as
3758 : : * strings on stdout. */
3759 : : static void
3760 : 4 : ofctl_parse_nxm(struct ovs_cmdl_context *ctx OVS_UNUSED)
3761 : : {
3762 : 4 : ofctl_parse_nxm__(false, 0);
3763 : 4 : }
3764 : :
3765 : : /* "parse-oxm VERSION": reads a series of OXM nx_match specifications as
3766 : : * strings from stdin, does some internal fussing with them, and then prints
3767 : : * them back as strings on stdout. VERSION must specify an OpenFlow version,
3768 : : * e.g. "OpenFlow12". */
3769 : : static void
3770 : 11 : ofctl_parse_oxm(struct ovs_cmdl_context *ctx)
3771 : : {
3772 : 11 : enum ofp_version version = ofputil_version_from_string(ctx->argv[1]);
3773 [ - + ]: 11 : if (version < OFP12_VERSION) {
3774 : 0 : ovs_fatal(0, "%s: not a valid version for OXM", ctx->argv[1]);
3775 : : }
3776 : :
3777 : 11 : ofctl_parse_nxm__(true, version);
3778 : 11 : }
3779 : :
3780 : : static void
3781 : 229 : print_differences(const char *prefix,
3782 : : const void *a_, size_t a_len,
3783 : : const void *b_, size_t b_len)
3784 : : {
3785 : 229 : const uint8_t *a = a_;
3786 : 229 : const uint8_t *b = b_;
3787 : : size_t i;
3788 : :
3789 [ + + ]: 9357 : for (i = 0; i < MIN(a_len, b_len); i++) {
3790 [ + + ]: 9128 : if (a[i] != b[i]) {
3791 : 105 : printf("%s%2"PRIuSIZE": %02"PRIx8" -> %02"PRIx8"\n",
3792 : 210 : prefix, i, a[i], b[i]);
3793 : : }
3794 : : }
3795 [ - + ]: 229 : for (i = a_len; i < b_len; i++) {
3796 : 0 : printf("%s%2"PRIuSIZE": (none) -> %02"PRIx8"\n", prefix, i, b[i]);
3797 : : }
3798 [ + + ]: 277 : for (i = b_len; i < a_len; i++) {
3799 : 48 : printf("%s%2"PRIuSIZE": %02"PRIx8" -> (none)\n", prefix, i, a[i]);
3800 : : }
3801 : 229 : }
3802 : :
3803 : : static void
3804 : 7 : ofctl_parse_actions__(const char *version_s, bool instructions)
3805 : : {
3806 : : enum ofp_version version;
3807 : : struct ds in;
3808 : :
3809 : 7 : version = ofputil_version_from_string(version_s);
3810 [ - + ]: 7 : if (!version) {
3811 : 0 : ovs_fatal(0, "%s: not a valid OpenFlow version", version_s);
3812 : : }
3813 : :
3814 : 7 : ds_init(&in);
3815 [ + + ]: 150 : while (!ds_get_preprocessed_line(&in, stdin, NULL)) {
3816 : : struct ofpbuf of_out;
3817 : : struct ofpbuf of_in;
3818 : : struct ofpbuf ofpacts;
3819 : : const char *table_id;
3820 : : char *actions;
3821 : : enum ofperr error;
3822 : : size_t size;
3823 : : struct ds s;
3824 : :
3825 : : /* Parse table_id separated with the follow-up actions by ",", if
3826 : : * any. */
3827 : 143 : actions = ds_cstr(&in);
3828 : 143 : table_id = NULL;
3829 [ + + ]: 143 : if (strstr(actions, ",")) {
3830 : 1 : table_id = strsep(&actions, ",");
3831 : : }
3832 : :
3833 : : /* Parse hex bytes. */
3834 : 143 : ofpbuf_init(&of_in, 0);
3835 [ - + ]: 143 : if (ofpbuf_put_hex(&of_in, actions, NULL)[0] != '\0') {
3836 : 0 : ovs_fatal(0, "Trailing garbage in hex data");
3837 : : }
3838 : :
3839 : : /* Convert to ofpacts. */
3840 : 143 : ofpbuf_init(&ofpacts, 0);
3841 : 143 : size = of_in.size;
3842 : 143 : error = (instructions
3843 : : ? ofpacts_pull_openflow_instructions
3844 [ + + ]: 143 : : ofpacts_pull_openflow_actions)(
3845 : : &of_in, of_in.size, version, &ofpacts);
3846 [ + + ][ + + ]: 143 : if (!error && instructions) {
3847 : : /* Verify actions, enforce consistency. */
3848 : : enum ofputil_protocol protocol;
3849 : : struct flow flow;
3850 : :
3851 : 19 : memset(&flow, 0, sizeof flow);
3852 : 19 : protocol = ofputil_protocols_from_ofp_version(version);
3853 [ + + ]: 20 : error = ofpacts_check_consistency(ofpacts.data, ofpacts.size,
3854 : : &flow, OFPP_MAX,
3855 : 1 : table_id ? atoi(table_id) : 0,
3856 : : OFPTT_MAX + 1, protocol);
3857 : : }
3858 [ + + ]: 143 : if (error) {
3859 [ + + ]: 28 : printf("bad %s %s: %s\n\n",
3860 : : version_s, instructions ? "instructions" : "actions",
3861 : : ofperr_get_name(error));
3862 : 28 : ofpbuf_uninit(&ofpacts);
3863 : 28 : ofpbuf_uninit(&of_in);
3864 : 28 : continue;
3865 : : }
3866 : 115 : ofpbuf_push_uninit(&of_in, size);
3867 : :
3868 : : /* Print cls_rule. */
3869 : 115 : ds_init(&s);
3870 : 115 : ds_put_cstr(&s, "actions=");
3871 : 115 : ofpacts_format(ofpacts.data, ofpacts.size, &s);
3872 : 115 : puts(ds_cstr(&s));
3873 : 115 : ds_destroy(&s);
3874 : :
3875 : : /* Convert back to ofp10 actions and print differences from input. */
3876 : 115 : ofpbuf_init(&of_out, 0);
3877 [ + + ]: 115 : if (instructions) {
3878 : 18 : ofpacts_put_openflow_instructions(ofpacts.data, ofpacts.size,
3879 : : &of_out, version);
3880 : : } else {
3881 : 97 : ofpacts_put_openflow_actions(ofpacts.data, ofpacts.size,
3882 : : &of_out, version);
3883 : : }
3884 : :
3885 : 115 : print_differences("", of_in.data, of_in.size,
3886 : 230 : of_out.data, of_out.size);
3887 : 115 : putchar('\n');
3888 : :
3889 : 115 : ofpbuf_uninit(&ofpacts);
3890 : 115 : ofpbuf_uninit(&of_in);
3891 : 115 : ofpbuf_uninit(&of_out);
3892 : : }
3893 : 7 : ds_destroy(&in);
3894 : 7 : }
3895 : :
3896 : : /* "parse-actions VERSION": reads a series of action specifications for the
3897 : : * given OpenFlow VERSION as hex bytes from stdin, converts them to ofpacts,
3898 : : * prints them as strings on stdout, and then converts them back to hex bytes
3899 : : * and prints any differences from the input. */
3900 : : static void
3901 : 5 : ofctl_parse_actions(struct ovs_cmdl_context *ctx)
3902 : : {
3903 : 5 : ofctl_parse_actions__(ctx->argv[1], false);
3904 : 5 : }
3905 : :
3906 : : /* "parse-actions VERSION": reads a series of instruction specifications for
3907 : : * the given OpenFlow VERSION as hex bytes from stdin, converts them to
3908 : : * ofpacts, prints them as strings on stdout, and then converts them back to
3909 : : * hex bytes and prints any differences from the input. */
3910 : : static void
3911 : 2 : ofctl_parse_instructions(struct ovs_cmdl_context *ctx)
3912 : : {
3913 : 2 : ofctl_parse_actions__(ctx->argv[1], true);
3914 : 2 : }
3915 : :
3916 : : /* "parse-ofp10-match": reads a series of ofp10_match specifications as hex
3917 : : * bytes from stdin, converts them to cls_rules, prints them as strings on
3918 : : * stdout, and then converts them back to hex bytes and prints any differences
3919 : : * from the input.
3920 : : *
3921 : : * The input hex bytes may contain "x"s to represent "don't-cares", bytes whose
3922 : : * values are ignored in the input and will be set to zero when OVS converts
3923 : : * them back to hex bytes. ovs-ofctl actually sets "x"s to random bits when
3924 : : * it does the conversion to hex, to ensure that in fact they are ignored. */
3925 : : static void
3926 : 1 : ofctl_parse_ofp10_match(struct ovs_cmdl_context *ctx OVS_UNUSED)
3927 : : {
3928 : : struct ds expout;
3929 : : struct ds in;
3930 : :
3931 : 1 : ds_init(&in);
3932 : 1 : ds_init(&expout);
3933 [ + + ]: 37 : while (!ds_get_preprocessed_line(&in, stdin, NULL)) {
3934 : : struct ofpbuf match_in, match_expout;
3935 : : struct ofp10_match match_out;
3936 : : struct ofp10_match match_normal;
3937 : : struct match match;
3938 : : char *p;
3939 : :
3940 : : /* Parse hex bytes to use for expected output. */
3941 : 36 : ds_clear(&expout);
3942 : 36 : ds_put_cstr(&expout, ds_cstr(&in));
3943 [ + + ]: 3420 : for (p = ds_cstr(&expout); *p; p++) {
3944 [ + + ]: 3384 : if (*p == 'x') {
3945 : 2276 : *p = '0';
3946 : : }
3947 : : }
3948 : 36 : ofpbuf_init(&match_expout, 0);
3949 [ - + ]: 36 : if (ofpbuf_put_hex(&match_expout, ds_cstr(&expout), NULL)[0] != '\0') {
3950 : 0 : ovs_fatal(0, "Trailing garbage in hex data");
3951 : : }
3952 [ - + ]: 36 : if (match_expout.size != sizeof(struct ofp10_match)) {
3953 : 0 : ovs_fatal(0, "Input is %"PRIu32" bytes, expected %"PRIuSIZE,
3954 : : match_expout.size, sizeof(struct ofp10_match));
3955 : : }
3956 : :
3957 : : /* Parse hex bytes for input. */
3958 [ + + ]: 3420 : for (p = ds_cstr(&in); *p; p++) {
3959 [ + + ]: 3384 : if (*p == 'x') {
3960 : 2276 : *p = "0123456789abcdef"[random_uint32() & 0xf];
3961 : : }
3962 : : }
3963 : 36 : ofpbuf_init(&match_in, 0);
3964 [ - + ]: 36 : if (ofpbuf_put_hex(&match_in, ds_cstr(&in), NULL)[0] != '\0') {
3965 : 0 : ovs_fatal(0, "Trailing garbage in hex data");
3966 : : }
3967 [ - + ]: 36 : if (match_in.size != sizeof(struct ofp10_match)) {
3968 : 0 : ovs_fatal(0, "Input is %"PRIu32" bytes, expected %"PRIuSIZE,
3969 : : match_in.size, sizeof(struct ofp10_match));
3970 : : }
3971 : :
3972 : : /* Convert to cls_rule and print. */
3973 : 36 : ofputil_match_from_ofp10_match(match_in.data, &match);
3974 : 36 : match_print(&match);
3975 : :
3976 : : /* Convert back to ofp10_match and print differences from input. */
3977 : 36 : ofputil_match_to_ofp10_match(&match, &match_out);
3978 : 36 : print_differences("", match_expout.data, match_expout.size,
3979 : : &match_out, sizeof match_out);
3980 : :
3981 : : /* Normalize, then convert and compare again. */
3982 : 36 : ofputil_normalize_match(&match);
3983 : 36 : ofputil_match_to_ofp10_match(&match, &match_normal);
3984 : 36 : print_differences("normal: ", &match_out, sizeof match_out,
3985 : : &match_normal, sizeof match_normal);
3986 : 36 : putchar('\n');
3987 : :
3988 : 36 : ofpbuf_uninit(&match_in);
3989 : 36 : ofpbuf_uninit(&match_expout);
3990 : : }
3991 : 1 : ds_destroy(&in);
3992 : 1 : ds_destroy(&expout);
3993 : 1 : }
3994 : :
3995 : : /* "parse-ofp11-match": reads a series of ofp11_match specifications as hex
3996 : : * bytes from stdin, converts them to "struct match"es, prints them as strings
3997 : : * on stdout, and then converts them back to hex bytes and prints any
3998 : : * differences from the input. */
3999 : : static void
4000 : 1 : ofctl_parse_ofp11_match(struct ovs_cmdl_context *ctx OVS_UNUSED)
4001 : : {
4002 : : struct ds in;
4003 : :
4004 : 1 : ds_init(&in);
4005 [ + + ]: 46 : while (!ds_get_preprocessed_line(&in, stdin, NULL)) {
4006 : : struct ofpbuf match_in;
4007 : : struct ofp11_match match_out;
4008 : : struct match match;
4009 : : enum ofperr error;
4010 : :
4011 : : /* Parse hex bytes. */
4012 : 45 : ofpbuf_init(&match_in, 0);
4013 [ - + ]: 45 : if (ofpbuf_put_hex(&match_in, ds_cstr(&in), NULL)[0] != '\0') {
4014 : 0 : ovs_fatal(0, "Trailing garbage in hex data");
4015 : : }
4016 [ - + ]: 45 : if (match_in.size != sizeof(struct ofp11_match)) {
4017 : 0 : ovs_fatal(0, "Input is %"PRIu32" bytes, expected %"PRIuSIZE,
4018 : : match_in.size, sizeof(struct ofp11_match));
4019 : : }
4020 : :
4021 : : /* Convert to match. */
4022 : 45 : error = ofputil_match_from_ofp11_match(match_in.data, &match);
4023 [ + + ]: 45 : if (error) {
4024 : 3 : printf("bad ofp11_match: %s\n\n", ofperr_get_name(error));
4025 : 3 : ofpbuf_uninit(&match_in);
4026 : 3 : continue;
4027 : : }
4028 : :
4029 : : /* Print match. */
4030 : 42 : match_print(&match);
4031 : :
4032 : : /* Convert back to ofp11_match and print differences from input. */
4033 : 42 : ofputil_match_to_ofp11_match(&match, &match_out);
4034 : :
4035 : 42 : print_differences("", match_in.data, match_in.size,
4036 : : &match_out, sizeof match_out);
4037 : 42 : putchar('\n');
4038 : :
4039 : 42 : ofpbuf_uninit(&match_in);
4040 : : }
4041 : 1 : ds_destroy(&in);
4042 : 1 : }
4043 : :
4044 : : /* "parse-pcap PCAP...": read packets from each PCAP file and print their
4045 : : * flows. */
4046 : : static void
4047 : 49 : ofctl_parse_pcap(struct ovs_cmdl_context *ctx)
4048 : : {
4049 : 49 : int error = 0;
4050 [ + + ]: 359 : for (int i = 1; i < ctx->argc; i++) {
4051 : 310 : const char *filename = ctx->argv[i];
4052 : 310 : FILE *pcap = ovs_pcap_open(filename, "rb");
4053 [ - + ]: 310 : if (!pcap) {
4054 : 0 : error = errno;
4055 : 0 : ovs_error(error, "%s: open failed", filename);
4056 : 0 : continue;
4057 : : }
4058 : :
4059 : : for (;;) {
4060 : : struct dp_packet *packet;
4061 : : struct flow flow;
4062 : : int retval;
4063 : :
4064 : 1893 : retval = ovs_pcap_read(pcap, &packet, NULL);
4065 [ + + ]: 1893 : if (retval == EOF) {
4066 : 310 : break;
4067 [ - + ]: 1583 : } else if (retval) {
4068 : 0 : error = retval;
4069 : 0 : ovs_error(error, "%s: read failed", filename);
4070 : : }
4071 : :
4072 : 1583 : pkt_metadata_init(&packet->md, u32_to_odp(ofp_to_u16(OFPP_ANY)));
4073 : 1583 : flow_extract(packet, &flow);
4074 : 1583 : flow_print(stdout, &flow);
4075 : 1583 : putchar('\n');
4076 : 1583 : dp_packet_delete(packet);
4077 : 1583 : }
4078 : 310 : fclose(pcap);
4079 : : }
4080 : 49 : exit(error);
4081 : : }
4082 : :
4083 : : /* "check-vlan VLAN_TCI VLAN_TCI_MASK": converts the specified vlan_tci and
4084 : : * mask values to and from various formats and prints the results. */
4085 : : static void
4086 : 10 : ofctl_check_vlan(struct ovs_cmdl_context *ctx)
4087 : : {
4088 : : struct match match;
4089 : :
4090 : : char *string_s;
4091 : : struct ofputil_flow_mod fm;
4092 : :
4093 : : struct ofpbuf nxm;
4094 : : struct match nxm_match;
4095 : : int nxm_match_len;
4096 : : char *nxm_s;
4097 : :
4098 : : struct ofp10_match of10_raw;
4099 : : struct match of10_match;
4100 : :
4101 : : struct ofp11_match of11_raw;
4102 : : struct match of11_match;
4103 : :
4104 : : enum ofperr error;
4105 : : char *error_s;
4106 : :
4107 : : enum ofputil_protocol usable_protocols; /* Unused for now. */
4108 : :
4109 : 10 : match_init_catchall(&match);
4110 : 10 : match.flow.vlan_tci = htons(strtoul(ctx->argv[1], NULL, 16));
4111 : 10 : match.wc.masks.vlan_tci = htons(strtoul(ctx->argv[2], NULL, 16));
4112 : :
4113 : : /* Convert to and from string. */
4114 : 10 : string_s = match_to_string(&match, OFP_DEFAULT_PRIORITY);
4115 : 10 : printf("%s -> ", string_s);
4116 : 10 : fflush(stdout);
4117 : 10 : error_s = parse_ofp_str(&fm, -1, string_s, &usable_protocols);
4118 [ - + ]: 10 : if (error_s) {
4119 : 0 : ovs_fatal(0, "%s", error_s);
4120 : : }
4121 : 10 : printf("%04"PRIx16"/%04"PRIx16"\n",
4122 : 10 : ntohs(fm.match.flow.vlan_tci),
4123 : 10 : ntohs(fm.match.wc.masks.vlan_tci));
4124 : 10 : free(string_s);
4125 : :
4126 : : /* Convert to and from NXM. */
4127 : 10 : ofpbuf_init(&nxm, 0);
4128 : 10 : nxm_match_len = nx_put_match(&nxm, &match, htonll(0), htonll(0));
4129 : 10 : nxm_s = nx_match_to_string(nxm.data, nxm_match_len);
4130 : 10 : error = nx_pull_match(&nxm, nxm_match_len, &nxm_match, NULL, NULL);
4131 : 10 : printf("NXM: %s -> ", nxm_s);
4132 [ - + ]: 10 : if (error) {
4133 : 0 : printf("%s\n", ofperr_to_string(error));
4134 : : } else {
4135 : 10 : printf("%04"PRIx16"/%04"PRIx16"\n",
4136 : 10 : ntohs(nxm_match.flow.vlan_tci),
4137 : 10 : ntohs(nxm_match.wc.masks.vlan_tci));
4138 : : }
4139 : 10 : free(nxm_s);
4140 : 10 : ofpbuf_uninit(&nxm);
4141 : :
4142 : : /* Convert to and from OXM. */
4143 : 10 : ofpbuf_init(&nxm, 0);
4144 : 10 : nxm_match_len = oxm_put_match(&nxm, &match, OFP12_VERSION);
4145 : 10 : nxm_s = oxm_match_to_string(&nxm, nxm_match_len);
4146 : 10 : error = oxm_pull_match(&nxm, &nxm_match);
4147 : 10 : printf("OXM: %s -> ", nxm_s);
4148 [ - + ]: 10 : if (error) {
4149 : 0 : printf("%s\n", ofperr_to_string(error));
4150 : : } else {
4151 : 10 : uint16_t vid = ntohs(nxm_match.flow.vlan_tci) &
4152 : : (VLAN_VID_MASK | VLAN_CFI);
4153 : 10 : uint16_t mask = ntohs(nxm_match.wc.masks.vlan_tci) &
4154 : : (VLAN_VID_MASK | VLAN_CFI);
4155 : :
4156 : 10 : printf("%04"PRIx16"/%04"PRIx16",", vid, mask);
4157 [ + + ][ + + ]: 10 : if (vid && vlan_tci_to_pcp(nxm_match.wc.masks.vlan_tci)) {
4158 : 3 : printf("%02"PRIx8"\n", vlan_tci_to_pcp(nxm_match.flow.vlan_tci));
4159 : : } else {
4160 : 7 : printf("--\n");
4161 : : }
4162 : : }
4163 : 10 : free(nxm_s);
4164 : 10 : ofpbuf_uninit(&nxm);
4165 : :
4166 : : /* Convert to and from OpenFlow 1.0. */
4167 : 10 : ofputil_match_to_ofp10_match(&match, &of10_raw);
4168 : 10 : ofputil_match_from_ofp10_match(&of10_raw, &of10_match);
4169 : 10 : printf("OF1.0: %04"PRIx16"/%d,%02"PRIx8"/%d -> %04"PRIx16"/%04"PRIx16"\n",
4170 : 10 : ntohs(of10_raw.dl_vlan),
4171 : 10 : (of10_raw.wildcards & htonl(OFPFW10_DL_VLAN)) != 0,
4172 : 10 : of10_raw.dl_vlan_pcp,
4173 : 10 : (of10_raw.wildcards & htonl(OFPFW10_DL_VLAN_PCP)) != 0,
4174 : 10 : ntohs(of10_match.flow.vlan_tci),
4175 : 10 : ntohs(of10_match.wc.masks.vlan_tci));
4176 : :
4177 : : /* Convert to and from OpenFlow 1.1. */
4178 : 10 : ofputil_match_to_ofp11_match(&match, &of11_raw);
4179 : 10 : ofputil_match_from_ofp11_match(&of11_raw, &of11_match);
4180 : 10 : printf("OF1.1: %04"PRIx16"/%d,%02"PRIx8"/%d -> %04"PRIx16"/%04"PRIx16"\n",
4181 : 10 : ntohs(of11_raw.dl_vlan),
4182 : 10 : (of11_raw.wildcards & htonl(OFPFW11_DL_VLAN)) != 0,
4183 : 10 : of11_raw.dl_vlan_pcp,
4184 : 10 : (of11_raw.wildcards & htonl(OFPFW11_DL_VLAN_PCP)) != 0,
4185 : 10 : ntohs(of11_match.flow.vlan_tci),
4186 : 10 : ntohs(of11_match.wc.masks.vlan_tci));
4187 : 10 : }
4188 : :
4189 : : /* "print-error ENUM": Prints the type and code of ENUM for every OpenFlow
4190 : : * version. */
4191 : : static void
4192 : 2 : ofctl_print_error(struct ovs_cmdl_context *ctx)
4193 : : {
4194 : : enum ofperr error;
4195 : : int version;
4196 : :
4197 : 2 : error = ofperr_from_name(ctx->argv[1]);
4198 [ - + ]: 2 : if (!error) {
4199 : 0 : ovs_fatal(0, "unknown error \"%s\"", ctx->argv[1]);
4200 : : }
4201 : :
4202 [ + + ]: 514 : for (version = 0; version <= UINT8_MAX; version++) {
4203 : 512 : const char *name = ofperr_domain_get_name(version);
4204 [ + + ]: 512 : if (name) {
4205 : 14 : int vendor = ofperr_get_vendor(error, version);
4206 : 14 : int type = ofperr_get_type(error, version);
4207 : 14 : int code = ofperr_get_code(error, version);
4208 : :
4209 [ + + ][ + - ]: 14 : if (vendor != -1 || type != -1 || code != -1) {
[ - + ]
4210 : 12 : printf("%s: vendor %#x, type %d, code %d\n",
4211 : : name, vendor, type, code);
4212 : : }
4213 : : }
4214 : : }
4215 : 2 : }
4216 : :
4217 : : /* "encode-error-reply ENUM REQUEST": Encodes an error reply to REQUEST for the
4218 : : * error named ENUM and prints the error reply in hex. */
4219 : : static void
4220 : 11 : ofctl_encode_error_reply(struct ovs_cmdl_context *ctx)
4221 : : {
4222 : : const struct ofp_header *oh;
4223 : : struct ofpbuf request, *reply;
4224 : : enum ofperr error;
4225 : :
4226 : 11 : error = ofperr_from_name(ctx->argv[1]);
4227 [ - + ]: 11 : if (!error) {
4228 : 0 : ovs_fatal(0, "unknown error \"%s\"", ctx->argv[1]);
4229 : : }
4230 : :
4231 : 11 : ofpbuf_init(&request, 0);
4232 [ - + ]: 11 : if (ofpbuf_put_hex(&request, ctx->argv[2], NULL)[0] != '\0') {
4233 : 0 : ovs_fatal(0, "Trailing garbage in hex data");
4234 : : }
4235 [ - + ]: 11 : if (request.size < sizeof(struct ofp_header)) {
4236 : 0 : ovs_fatal(0, "Request too short");
4237 : : }
4238 : :
4239 : 11 : oh = request.data;
4240 [ - + ]: 11 : if (request.size != ntohs(oh->length)) {
4241 : 0 : ovs_fatal(0, "Request size inconsistent");
4242 : : }
4243 : :
4244 : 11 : reply = ofperr_encode_reply(error, request.data);
4245 : 11 : ofpbuf_uninit(&request);
4246 : :
4247 : 11 : ovs_hex_dump(stdout, reply->data, reply->size, 0, false);
4248 : 11 : ofpbuf_delete(reply);
4249 : 11 : }
4250 : :
4251 : : /* "ofp-print HEXSTRING [VERBOSITY]": Converts the hex digits in HEXSTRING into
4252 : : * binary data, interpreting them as an OpenFlow message, and prints the
4253 : : * OpenFlow message on stdout, at VERBOSITY (level 2 by default).
4254 : : *
4255 : : * Alternative usage: "ofp-print [VERBOSITY] - < HEXSTRING_FILE", where
4256 : : * HEXSTRING_FILE contains the HEXSTRING. */
4257 : : static void
4258 : 231 : ofctl_ofp_print(struct ovs_cmdl_context *ctx)
4259 : : {
4260 : : struct ofpbuf packet;
4261 : : char *buffer;
4262 : 231 : int verbosity = 2;
4263 : : struct ds line;
4264 : :
4265 : 231 : ds_init(&line);
4266 : :
4267 [ + + ]: 231 : if (!strcmp(ctx->argv[ctx->argc-1], "-")) {
4268 [ - + ]: 1 : if (ds_get_line(&line, stdin)) {
4269 : 0 : VLOG_FATAL("Failed to read stdin");
4270 : : }
4271 : :
4272 : 1 : buffer = line.string;
4273 [ - + ]: 1 : verbosity = ctx->argc > 2 ? atoi(ctx->argv[1]) : verbosity;
4274 [ + + ]: 230 : } else if (ctx->argc > 2) {
4275 : 32 : buffer = ctx->argv[1];
4276 : 32 : verbosity = atoi(ctx->argv[2]);
4277 : : } else {
4278 : 198 : buffer = ctx->argv[1];
4279 : : }
4280 : :
4281 : 231 : ofpbuf_init(&packet, strlen(buffer) / 2);
4282 [ - + ]: 231 : if (ofpbuf_put_hex(&packet, buffer, NULL)[0] != '\0') {
4283 : 0 : ovs_fatal(0, "trailing garbage following hex bytes");
4284 : : }
4285 : 231 : ofp_print(stdout, packet.data, packet.size, verbosity);
4286 : 231 : ofpbuf_uninit(&packet);
4287 : 231 : ds_destroy(&line);
4288 : 231 : }
4289 : :
4290 : : /* "encode-hello BITMAP...": Encodes each BITMAP as an OpenFlow hello message
4291 : : * and dumps each message in hex. */
4292 : : static void
4293 : 9 : ofctl_encode_hello(struct ovs_cmdl_context *ctx)
4294 : : {
4295 : 9 : uint32_t bitmap = strtol(ctx->argv[1], NULL, 0);
4296 : : struct ofpbuf *hello;
4297 : :
4298 : 9 : hello = ofputil_encode_hello(bitmap);
4299 : 9 : ovs_hex_dump(stdout, hello->data, hello->size, 0, false);
4300 : 9 : ofp_print(stdout, hello->data, hello->size, verbosity);
4301 : 9 : ofpbuf_delete(hello);
4302 : 9 : }
4303 : :
4304 : : static void
4305 : 5 : ofctl_parse_key_value(struct ovs_cmdl_context *ctx)
4306 : : {
4307 [ + + ]: 25 : for (size_t i = 1; i < ctx->argc; i++) {
4308 : 20 : char *s = ctx->argv[i];
4309 : : char *key, *value;
4310 : 20 : int j = 0;
4311 [ + + ]: 50 : while (ofputil_parse_key_value(&s, &key, &value)) {
4312 [ + + ]: 30 : if (j++) {
4313 : 10 : fputs(", ", stdout);
4314 : : }
4315 : 30 : fputs(key, stdout);
4316 [ + + ]: 30 : if (value[0]) {
4317 : 14 : printf("=%s", value);
4318 : : }
4319 : : }
4320 : 20 : putchar('\n');
4321 : : }
4322 : 5 : }
4323 : :
4324 : : static const struct ovs_cmdl_command all_commands[] = {
4325 : : { "show", "switch",
4326 : : 1, 1, ofctl_show, OVS_RO },
4327 : : { "monitor", "switch [misslen] [invalid_ttl] [watch:[...]]",
4328 : : 1, 3, ofctl_monitor, OVS_RO },
4329 : : { "snoop", "switch",
4330 : : 1, 1, ofctl_snoop, OVS_RO },
4331 : : { "dump-desc", "switch",
4332 : : 1, 1, ofctl_dump_desc, OVS_RO },
4333 : : { "dump-tables", "switch",
4334 : : 1, 1, ofctl_dump_tables, OVS_RO },
4335 : : { "dump-table-features", "switch",
4336 : : 1, 1, ofctl_dump_table_features, OVS_RO },
4337 : : { "dump-table-desc", "switch",
4338 : : 1, 1, ofctl_dump_table_desc, OVS_RO },
4339 : : { "dump-flows", "switch",
4340 : : 1, 2, ofctl_dump_flows, OVS_RO },
4341 : : { "dump-aggregate", "switch",
4342 : : 1, 2, ofctl_dump_aggregate, OVS_RO },
4343 : : { "queue-stats", "switch [port [queue]]",
4344 : : 1, 3, ofctl_queue_stats, OVS_RO },
4345 : : { "queue-get-config", "switch [port [queue]]",
4346 : : 1, 3, ofctl_queue_get_config, OVS_RO },
4347 : : { "add-flow", "switch flow",
4348 : : 2, 2, ofctl_add_flow, OVS_RW },
4349 : : { "add-flows", "switch file",
4350 : : 2, 2, ofctl_add_flows, OVS_RW },
4351 : : { "mod-flows", "switch flow",
4352 : : 2, 2, ofctl_mod_flows, OVS_RW },
4353 : : { "del-flows", "switch [flow]",
4354 : : 1, 2, ofctl_del_flows, OVS_RW },
4355 : : { "replace-flows", "switch file",
4356 : : 2, 2, ofctl_replace_flows, OVS_RW },
4357 : : { "diff-flows", "source1 source2",
4358 : : 2, 2, ofctl_diff_flows, OVS_RW },
4359 : : { "add-meter", "switch meter",
4360 : : 2, 2, ofctl_add_meter, OVS_RW },
4361 : : { "mod-meter", "switch meter",
4362 : : 2, 2, ofctl_mod_meter, OVS_RW },
4363 : : { "del-meter", "switch meter",
4364 : : 2, 2, ofctl_del_meters, OVS_RW },
4365 : : { "del-meters", "switch",
4366 : : 1, 1, ofctl_del_meters, OVS_RW },
4367 : : { "dump-meter", "switch meter",
4368 : : 2, 2, ofctl_dump_meters, OVS_RO },
4369 : : { "dump-meters", "switch",
4370 : : 1, 1, ofctl_dump_meters, OVS_RO },
4371 : : { "meter-stats", "switch [meter]",
4372 : : 1, 2, ofctl_meter_stats, OVS_RO },
4373 : : { "meter-features", "switch",
4374 : : 1, 1, ofctl_meter_features, OVS_RO },
4375 : : { "packet-out", "switch in_port actions packet...",
4376 : : 4, INT_MAX, ofctl_packet_out, OVS_RW },
4377 : : { "dump-ports", "switch [port]",
4378 : : 1, 2, ofctl_dump_ports, OVS_RO },
4379 : : { "dump-ports-desc", "switch [port]",
4380 : : 1, 2, ofctl_dump_ports_desc, OVS_RO },
4381 : : { "mod-port", "switch iface act",
4382 : : 3, 3, ofctl_mod_port, OVS_RW },
4383 : : { "mod-table", "switch mod",
4384 : : 3, 3, ofctl_mod_table, OVS_RW },
4385 : : { "get-frags", "switch",
4386 : : 1, 1, ofctl_get_frags, OVS_RO },
4387 : : { "set-frags", "switch frag_mode",
4388 : : 2, 2, ofctl_set_frags, OVS_RW },
4389 : : { "probe", "target",
4390 : : 1, 1, ofctl_probe, OVS_RO },
4391 : : { "ping", "target [n]",
4392 : : 1, 2, ofctl_ping, OVS_RO },
4393 : : { "benchmark", "target n count",
4394 : : 3, 3, ofctl_benchmark, OVS_RO },
4395 : :
4396 : : { "dump-ipfix-bridge", "switch",
4397 : : 1, 1, ofctl_dump_ipfix_bridge, OVS_RO },
4398 : : { "dump-ipfix-flow", "switch",
4399 : : 1, 1, ofctl_dump_ipfix_flow, OVS_RO },
4400 : :
4401 : : { "ofp-parse", "file",
4402 : : 1, 1, ofctl_ofp_parse, OVS_RW },
4403 : : { "ofp-parse-pcap", "pcap",
4404 : : 1, INT_MAX, ofctl_ofp_parse_pcap, OVS_RW },
4405 : :
4406 : : { "add-group", "switch group",
4407 : : 1, 2, ofctl_add_group, OVS_RW },
4408 : : { "add-groups", "switch file",
4409 : : 1, 2, ofctl_add_groups, OVS_RW },
4410 : : { "mod-group", "switch group",
4411 : : 1, 2, ofctl_mod_group, OVS_RW },
4412 : : { "del-groups", "switch [group]",
4413 : : 1, 2, ofctl_del_groups, OVS_RW },
4414 : : { "insert-buckets", "switch [group]",
4415 : : 1, 2, ofctl_insert_bucket, OVS_RW },
4416 : : { "remove-buckets", "switch [group]",
4417 : : 1, 2, ofctl_remove_bucket, OVS_RW },
4418 : : { "dump-groups", "switch [group]",
4419 : : 1, 2, ofctl_dump_group_desc, OVS_RO },
4420 : : { "dump-group-stats", "switch [group]",
4421 : : 1, 2, ofctl_dump_group_stats, OVS_RO },
4422 : : { "dump-group-features", "switch",
4423 : : 1, 1, ofctl_dump_group_features, OVS_RO },
4424 : :
4425 : : { "bundle", "switch file",
4426 : : 2, 2, ofctl_bundle, OVS_RW },
4427 : :
4428 : : { "add-tlv-map", "switch map",
4429 : : 2, 2, ofctl_add_tlv_map, OVS_RO },
4430 : : { "del-tlv-map", "switch [map]",
4431 : : 1, 2, ofctl_del_tlv_map, OVS_RO },
4432 : : { "dump-tlv-map", "switch",
4433 : : 1, 1, ofctl_dump_tlv_map, OVS_RO },
4434 : : { "help", NULL, 0, INT_MAX, ofctl_help, OVS_RO },
4435 : : { "list-commands", NULL, 0, INT_MAX, ofctl_list_commands, OVS_RO },
4436 : :
4437 : : /* Undocumented commands for testing. */
4438 : : { "parse-flow", NULL, 1, 1, ofctl_parse_flow, OVS_RW },
4439 : : { "parse-flows", NULL, 1, 1, ofctl_parse_flows, OVS_RW },
4440 : : { "parse-nx-match", NULL, 0, 0, ofctl_parse_nxm, OVS_RW },
4441 : : { "parse-nxm", NULL, 0, 0, ofctl_parse_nxm, OVS_RW },
4442 : : { "parse-oxm", NULL, 1, 1, ofctl_parse_oxm, OVS_RW },
4443 : : { "parse-actions", NULL, 1, 1, ofctl_parse_actions, OVS_RW },
4444 : : { "parse-instructions", NULL, 1, 1, ofctl_parse_instructions, OVS_RW },
4445 : : { "parse-ofp10-match", NULL, 0, 0, ofctl_parse_ofp10_match, OVS_RW },
4446 : : { "parse-ofp11-match", NULL, 0, 0, ofctl_parse_ofp11_match, OVS_RW },
4447 : : { "parse-pcap", NULL, 1, INT_MAX, ofctl_parse_pcap, OVS_RW },
4448 : : { "check-vlan", NULL, 2, 2, ofctl_check_vlan, OVS_RW },
4449 : : { "print-error", NULL, 1, 1, ofctl_print_error, OVS_RW },
4450 : : { "encode-error-reply", NULL, 2, 2, ofctl_encode_error_reply, OVS_RW },
4451 : : { "ofp-print", NULL, 1, 2, ofctl_ofp_print, OVS_RW },
4452 : : { "encode-hello", NULL, 1, 1, ofctl_encode_hello, OVS_RW },
4453 : : { "parse-key-value", NULL, 1, INT_MAX, ofctl_parse_key_value, OVS_RW },
4454 : :
4455 : : { NULL, NULL, 0, 0, NULL, OVS_RO },
4456 : : };
4457 : :
4458 : 3887 : static const struct ovs_cmdl_command *get_all_commands(void)
4459 : : {
4460 : 3887 : return all_commands;
4461 : : }
|