]> git.proxmox.com Git - ovs.git/blame - ofproto/ofproto-dpif-trace.c
dpif: Meter framework.
[ovs.git] / ofproto / ofproto-dpif-trace.c
CommitLineData
d13ee228 1/*
2d9b49dd 2 * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc.
d13ee228
BP
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
19#include "ofproto-dpif-trace.h"
20
21#include "dpif.h"
22#include "ofproto-dpif-xlate.h"
23#include "openvswitch/ofp-parse.h"
24#include "unixctl.h"
25
d13ee228
BP
26static void ofproto_trace(struct ofproto_dpif *, struct flow *,
27 const struct dp_packet *packet,
28 const struct ofpact[], size_t ofpacts_len,
29 struct ds *);
2d9b49dd
BP
30static void oftrace_node_destroy(struct oftrace_node *);
31
32/* Creates a new oftrace_node, populates it with the given 'type' and a copy of
33 * 'text', and appends it to list 'super'. The caller retains ownership of
34 * 'text'. */
35struct oftrace_node *
36oftrace_report(struct ovs_list *super, enum oftrace_node_type type,
37 const char *text)
d13ee228 38{
2d9b49dd
BP
39 struct oftrace_node *node = xmalloc(sizeof *node);
40 ovs_list_push_back(super, &node->node);
41 node->type = type;
42 node->text = xstrdup(text);
43 ovs_list_init(&node->subs);
d13ee228 44
2d9b49dd 45 return node;
d13ee228
BP
46}
47
2d9b49dd
BP
48static bool
49oftrace_node_type_is_terminal(enum oftrace_node_type type)
d13ee228 50{
2d9b49dd
BP
51 switch (type) {
52 case OFT_ACTION:
53 case OFT_DETAIL:
54 case OFT_WARN:
55 case OFT_ERROR:
56 return true;
57
58 case OFT_BRIDGE:
59 case OFT_TABLE:
60 case OFT_THAW:
61 return false;
d13ee228 62 }
2d9b49dd
BP
63
64 OVS_NOT_REACHED();
d13ee228
BP
65}
66
67static void
2d9b49dd 68oftrace_node_list_destroy(struct ovs_list *nodes)
d13ee228 69{
2d9b49dd
BP
70 if (nodes) {
71 struct oftrace_node *node, *next;
72 LIST_FOR_EACH_SAFE (node, next, node, nodes) {
73 ovs_list_remove(&node->node);
74 oftrace_node_destroy(node);
75 }
d13ee228 76 }
d13ee228
BP
77}
78
79static void
2d9b49dd 80oftrace_node_destroy(struct oftrace_node *node)
d13ee228 81{
2d9b49dd
BP
82 if (node) {
83 oftrace_node_list_destroy(&node->subs);
84 free(node->text);
85 free(node);
86 }
d13ee228
BP
87}
88
89static void
2d9b49dd
BP
90oftrace_node_print_details(struct ds *output,
91 const struct ovs_list *nodes, int level)
d13ee228 92{
2d9b49dd
BP
93 const struct oftrace_node *sub;
94 LIST_FOR_EACH (sub, node, nodes) {
95 if (sub->type == OFT_BRIDGE) {
96 ds_put_char(output, '\n');
97 }
d13ee228 98
2d9b49dd
BP
99 bool more = (sub->node.next != nodes
100 || oftrace_node_type_is_terminal(sub->type));
101
102 ds_put_char_multiple(output, ' ', (level + more) * 4);
103 switch (sub->type) {
104 case OFT_DETAIL:
105 ds_put_format(output, " -> %s\n", sub->text);
106 break;
107 case OFT_WARN:
108 ds_put_format(output, " >> %s\n", sub->text);
109 break;
110 case OFT_ERROR:
111 ds_put_format(output, " >>>> %s <<<<\n", sub->text);
112 break;
113 case OFT_BRIDGE:
114 ds_put_format(output, "%s\n", sub->text);
115 ds_put_char_multiple(output, ' ', (level + more) * 4);
116 ds_put_char_multiple(output, '-', strlen(sub->text));
117 ds_put_char(output, '\n');
118 break;
119 case OFT_TABLE:
120 case OFT_THAW:
121 case OFT_ACTION:
122 ds_put_format(output, "%s\n", sub->text);
123 break;
d13ee228 124 }
d13ee228 125
2d9b49dd 126 oftrace_node_print_details(output, &sub->subs, level + more + more);
d13ee228 127 }
d13ee228
BP
128}
129
130/* Parses the 'argc' elements of 'argv', ignoring argv[0]. The following
131 * forms are supported:
132 *
133 * - [dpname] odp_flow [-generate | packet]
134 * - bridge br_flow [-generate | packet]
135 *
136 * On success, initializes '*ofprotop' and 'flow' and returns NULL. On failure
137 * returns a nonnull malloced error message. */
138static char * OVS_WARN_UNUSED_RESULT
139parse_flow_and_packet(int argc, const char *argv[],
140 struct ofproto_dpif **ofprotop, struct flow *flow,
141 struct dp_packet **packetp)
142{
143 const struct dpif_backer *backer = NULL;
144 const char *error = NULL;
145 char *m_err = NULL;
146 struct simap port_names = SIMAP_INITIALIZER(&port_names);
147 struct dp_packet *packet;
148 struct ofpbuf odp_key;
149 struct ofpbuf odp_mask;
150
151 ofpbuf_init(&odp_key, 0);
152 ofpbuf_init(&odp_mask, 0);
153
154 /* Handle "-generate" or a hex string as the last argument. */
155 if (!strcmp(argv[argc - 1], "-generate")) {
156 packet = dp_packet_new(0);
157 argc--;
158 } else {
159 error = eth_from_hex(argv[argc - 1], &packet);
160 if (!error) {
161 argc--;
162 } else if (argc == 4) {
163 /* The 3-argument form must end in "-generate' or a hex string. */
164 goto exit;
165 }
166 error = NULL;
167 }
168
169 /* odp_flow can have its in_port specified as a name instead of port no.
170 * We do not yet know whether a given flow is a odp_flow or a br_flow.
171 * But, to know whether a flow is odp_flow through odp_flow_from_string(),
172 * we need to create a simap of name to port no. */
173 if (argc == 3) {
174 const char *dp_type;
175 if (!strncmp(argv[1], "ovs-", 4)) {
176 dp_type = argv[1] + 4;
177 } else {
178 dp_type = argv[1];
179 }
180 backer = shash_find_data(&all_dpif_backers, dp_type);
181 } else if (argc == 2) {
182 struct shash_node *node;
183 if (shash_count(&all_dpif_backers) == 1) {
184 node = shash_first(&all_dpif_backers);
185 backer = node->data;
186 }
187 } else {
188 error = "Syntax error";
189 goto exit;
190 }
191 if (backer && backer->dpif) {
192 struct dpif_port dpif_port;
193 struct dpif_port_dump port_dump;
194 DPIF_PORT_FOR_EACH (&dpif_port, &port_dump, backer->dpif) {
195 simap_put(&port_names, dpif_port.name,
196 odp_to_u32(dpif_port.port_no));
197 }
198 }
199
200 /* Parse the flow and determine whether a datapath or
201 * bridge is specified. If function odp_flow_key_from_string()
202 * returns 0, the flow is a odp_flow. If function
203 * parse_ofp_exact_flow() returns NULL, the flow is a br_flow. */
204 if (!odp_flow_from_string(argv[argc - 1], &port_names,
205 &odp_key, &odp_mask)) {
206 if (!backer) {
207 error = "Cannot find the datapath";
208 goto exit;
209 }
210
211 if (odp_flow_key_to_flow(odp_key.data, odp_key.size, flow) == ODP_FIT_ERROR) {
212 error = "Failed to parse datapath flow key";
213 goto exit;
214 }
215
216 *ofprotop = xlate_lookup_ofproto(backer, flow,
217 &flow->in_port.ofp_port);
218 if (*ofprotop == NULL) {
219 error = "Invalid datapath flow";
220 goto exit;
221 }
222
223 flow->tunnel.metadata.tab = ofproto_get_tun_tab(&(*ofprotop)->up);
224
225 /* Convert Geneve options to OpenFlow format now. This isn't actually
226 * required in order to get the right results since the ofproto xlate
227 * actions will handle this for us. However, converting now ensures
228 * that our formatting code will always be able to consistently print
229 * in OpenFlow format, which is what we use here. */
230 if (flow->tunnel.flags & FLOW_TNL_F_UDPIF) {
231 struct flow_tnl tnl;
232 int err;
233
234 memcpy(&tnl, &flow->tunnel, sizeof tnl);
235 err = tun_metadata_from_geneve_udpif(flow->tunnel.metadata.tab,
236 &tnl, &tnl, &flow->tunnel);
237 if (err) {
238 error = "Failed to parse Geneve options";
239 goto exit;
240 }
241 }
242 } else {
243 char *err;
244
245 if (argc != 3) {
246 error = "Must specify bridge name";
247 goto exit;
248 }
249
250 *ofprotop = ofproto_dpif_lookup(argv[1]);
251 if (!*ofprotop) {
252 error = "Unknown bridge name";
253 goto exit;
254 }
255
256 err = parse_ofp_exact_flow(flow, NULL,
257 ofproto_get_tun_tab(&(*ofprotop)->up),
258 argv[argc - 1], NULL);
259 if (err) {
260 m_err = xasprintf("Bad openflow flow syntax: %s", err);
261 free(err);
262 goto exit;
263 }
264 }
265
266 /* Generate a packet, if requested. */
267 if (packet) {
268 if (!dp_packet_size(packet)) {
269 flow_compose(packet, flow);
270 } else {
271 /* Use the metadata from the flow and the packet argument
272 * to reconstruct the flow. */
273 pkt_metadata_from_flow(&packet->md, flow);
274 flow_extract(packet, flow);
275 }
276 }
277
278exit:
279 if (error && !m_err) {
280 m_err = xstrdup(error);
281 }
282 if (m_err) {
283 dp_packet_delete(packet);
284 packet = NULL;
285 }
286 *packetp = packet;
287 ofpbuf_uninit(&odp_key);
288 ofpbuf_uninit(&odp_mask);
289 simap_destroy(&port_names);
290 return m_err;
291}
292
293static void
294ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
295 void *aux OVS_UNUSED)
296{
297 struct ofproto_dpif *ofproto;
298 struct dp_packet *packet;
299 char *error;
300 struct flow flow;
301
302 error = parse_flow_and_packet(argc, argv, &ofproto, &flow, &packet);
303 if (!error) {
304 struct ds result;
305
306 ds_init(&result);
307 ofproto_trace(ofproto, &flow, packet, NULL, 0, &result);
308 unixctl_command_reply(conn, ds_cstr(&result));
309 ds_destroy(&result);
310 dp_packet_delete(packet);
311 } else {
312 unixctl_command_reply_error(conn, error);
313 free(error);
314 }
315}
316
317static void
318ofproto_unixctl_trace_actions(struct unixctl_conn *conn, int argc,
319 const char *argv[], void *aux OVS_UNUSED)
320{
321 enum ofputil_protocol usable_protocols;
322 struct ofproto_dpif *ofproto;
323 bool enforce_consistency;
324 struct ofpbuf ofpacts;
325 struct dp_packet *packet;
326 struct ds result;
327 struct flow flow;
328 uint16_t in_port;
329
330 /* Three kinds of error return values! */
331 enum ofperr retval;
332 char *error;
333
334 packet = NULL;
335 ds_init(&result);
336 ofpbuf_init(&ofpacts, 0);
337
338 /* Parse actions. */
339 error = ofpacts_parse_actions(argv[--argc], &ofpacts, &usable_protocols);
340 if (error) {
341 unixctl_command_reply_error(conn, error);
342 free(error);
343 goto exit;
344 }
345
346 /* OpenFlow 1.1 and later suggest that the switch enforces certain forms of
347 * consistency between the flow and the actions. With -consistent, we
348 * enforce consistency even for a flow supported in OpenFlow 1.0. */
349 if (!strcmp(argv[1], "-consistent")) {
350 enforce_consistency = true;
351 argv++;
352 argc--;
353 } else {
354 enforce_consistency = false;
355 }
356
357 error = parse_flow_and_packet(argc, argv, &ofproto, &flow, &packet);
358 if (error) {
359 unixctl_command_reply_error(conn, error);
360 free(error);
361 goto exit;
362 }
363
364 /* Do the same checks as handle_packet_out() in ofproto.c.
365 *
366 * We pass a 'table_id' of 0 to ofpacts_check(), which isn't
367 * strictly correct because these actions aren't in any table, but it's OK
368 * because it 'table_id' is used only to check goto_table instructions, but
369 * packet-outs take a list of actions and therefore it can't include
370 * instructions.
371 *
372 * We skip the "meter" check here because meter is an instruction, not an
373 * action, and thus cannot appear in ofpacts. */
374 in_port = ofp_to_u16(flow.in_port.ofp_port);
375 if (in_port >= ofproto->up.max_ports && in_port < ofp_to_u16(OFPP_MAX)) {
376 unixctl_command_reply_error(conn, "invalid in_port");
377 goto exit;
378 }
379 if (enforce_consistency) {
380 retval = ofpacts_check_consistency(ofpacts.data, ofpacts.size, &flow,
381 u16_to_ofp(ofproto->up.max_ports),
382 0, ofproto->up.n_tables,
383 usable_protocols);
384 } else {
385 retval = ofpacts_check(ofpacts.data, ofpacts.size, &flow,
386 u16_to_ofp(ofproto->up.max_ports), 0,
387 ofproto->up.n_tables, &usable_protocols);
388 }
389 if (!retval) {
390 retval = ofproto_check_ofpacts(&ofproto->up, ofpacts.data,
391 ofpacts.size);
392 }
393
394 if (retval) {
395 ds_clear(&result);
396 ds_put_format(&result, "Bad actions: %s", ofperr_to_string(retval));
397 unixctl_command_reply_error(conn, ds_cstr(&result));
398 goto exit;
399 }
400
401 ofproto_trace(ofproto, &flow, packet,
402 ofpacts.data, ofpacts.size, &result);
403 unixctl_command_reply(conn, ds_cstr(&result));
404
405exit:
406 ds_destroy(&result);
407 dp_packet_delete(packet);
408 ofpbuf_uninit(&ofpacts);
409}
410
411/* Implements a "trace" through 'ofproto''s flow table, appending a textual
2d9b49dd 412 * description of the results to 'output'.
d13ee228
BP
413 *
414 * The trace follows a packet with the specified 'flow' through the flow
415 * table. 'packet' may be nonnull to trace an actual packet, with consequent
416 * side effects (if it is nonnull then its flow must be 'flow').
417 *
418 * If 'ofpacts' is nonnull then its 'ofpacts_len' bytes specify the actions to
419 * trace, otherwise the actions are determined by a flow table lookup. */
420static void
421ofproto_trace(struct ofproto_dpif *ofproto, struct flow *flow,
422 const struct dp_packet *packet,
423 const struct ofpact ofpacts[], size_t ofpacts_len,
2d9b49dd 424 struct ds *output)
d13ee228 425{
2d9b49dd
BP
426 struct ofpbuf odp_actions;
427 ofpbuf_init(&odp_actions, 0);
d13ee228 428
2d9b49dd
BP
429 struct xlate_in xin;
430 struct flow_wildcards wc;
431 struct ovs_list trace = OVS_LIST_INITIALIZER(&trace);
432 xlate_in_init(&xin, ofproto,
d13ee228
BP
433 ofproto_dpif_get_tables_version(ofproto), flow,
434 flow->in_port.ofp_port, NULL, ntohs(flow->tcp_flags),
2d9b49dd
BP
435 packet, &wc, &odp_actions);
436 xin.ofpacts = ofpacts;
437 xin.ofpacts_len = ofpacts_len;
438 xin.trace = &trace;
439
440 /* Copy initial flow out of xin.flow. It differs from '*flow' because
441 * xlate_in_init() initializes actset_output to OFPP_UNSET. */
442 struct flow initial_flow = xin.flow;
443 ds_put_cstr(output, "Flow: ");
444 flow_format(output, &initial_flow);
445 ds_put_char(output, '\n');
446
447 struct xlate_out xout;
448 enum xlate_error error = xlate_actions(&xin, &xout);
449
450 oftrace_node_print_details(output, &trace, 0);
451
452 ds_put_cstr(output, "\nFinal flow: ");
453 if (flow_equal(&initial_flow, &xin.flow)) {
454 ds_put_cstr(output, "unchanged");
455 } else {
456 flow_format(output, &xin.flow);
457 }
458 ds_put_char(output, '\n');
d13ee228 459
2d9b49dd
BP
460 ds_put_cstr(output, "Megaflow: ");
461 struct match match;
462 match_init(&match, flow, &wc);
463 match_format(&match, output, OFP_DEFAULT_PRIORITY);
464 ds_put_char(output, '\n');
d13ee228 465
2d9b49dd
BP
466 ds_put_cstr(output, "Datapath actions: ");
467 format_odp_actions(output, odp_actions.data, odp_actions.size);
d13ee228
BP
468
469 if (error != XLATE_OK) {
2d9b49dd
BP
470 ds_put_format(output,
471 "\nTranslation failed (%s), packet is dropped.\n",
d13ee228 472 xlate_strerror(error));
2d9b49dd 473 } else if (xout.slow) {
d13ee228
BP
474 enum slow_path_reason slow;
475
2d9b49dd 476 ds_put_cstr(output, "\nThis flow is handled by the userspace "
d13ee228
BP
477 "slow path because it:");
478
2d9b49dd 479 slow = xout.slow;
d13ee228
BP
480 while (slow) {
481 enum slow_path_reason bit = rightmost_1bit(slow);
482
2d9b49dd 483 ds_put_format(output, "\n\t- %s.",
d13ee228
BP
484 slow_path_reason_to_explanation(bit));
485
486 slow &= ~bit;
487 }
488 }
489
2d9b49dd
BP
490 xlate_out_uninit(&xout);
491 ofpbuf_uninit(&odp_actions);
492 oftrace_node_list_destroy(&trace);
d13ee228
BP
493}
494
495void
496ofproto_dpif_trace_init(void)
497{
498 static bool registered;
499 if (registered) {
500 return;
501 }
502 registered = true;
503
504 unixctl_command_register(
505 "ofproto/trace",
506 "{[dp_name] odp_flow | bridge br_flow} [-generate|packet]",
507 1, 3, ofproto_unixctl_trace, NULL);
508 unixctl_command_register(
509 "ofproto/trace-packet-out",
510 "[-consistent] {[dp_name] odp_flow | bridge br_flow} [-generate|packet] actions",
511 2, 6, ofproto_unixctl_trace_actions, NULL);
512}