]> git.proxmox.com Git - mirror_ovs.git/blob - ofproto/ofproto-dpif-trace.c
userspace: Switching of L3 packets in L2 pipeline
[mirror_ovs.git] / ofproto / ofproto-dpif-trace.c
1 /*
2 * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 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
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
26 static 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 *);
30 static 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'. */
35 struct oftrace_node *
36 oftrace_report(struct ovs_list *super, enum oftrace_node_type type,
37 const char *text)
38 {
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);
44
45 return node;
46 }
47
48 static bool
49 oftrace_node_type_is_terminal(enum oftrace_node_type type)
50 {
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;
62 }
63
64 OVS_NOT_REACHED();
65 }
66
67 static void
68 oftrace_node_list_destroy(struct ovs_list *nodes)
69 {
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 }
76 }
77 }
78
79 static void
80 oftrace_node_destroy(struct oftrace_node *node)
81 {
82 if (node) {
83 oftrace_node_list_destroy(&node->subs);
84 free(node->text);
85 free(node);
86 }
87 }
88
89 static void
90 oftrace_node_print_details(struct ds *output,
91 const struct ovs_list *nodes, int level)
92 {
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 }
98
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;
124 }
125
126 oftrace_node_print_details(output, &sub->subs, level + more + more);
127 }
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. */
138 static char * OVS_WARN_UNUSED_RESULT
139 parse_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 struct ofputil_port_map map = OFPUTIL_PORT_MAP_INITIALIZER(&map);
257 const struct ofport *ofport;
258 HMAP_FOR_EACH (ofport, hmap_node, &(*ofprotop)->up.ports) {
259 ofputil_port_map_put(&map, ofport->ofp_port,
260 netdev_get_name(ofport->netdev));
261 }
262 err = parse_ofp_exact_flow(flow, NULL,
263 ofproto_get_tun_tab(&(*ofprotop)->up),
264 argv[argc - 1], &map);
265 ofputil_port_map_destroy(&map);
266 if (err) {
267 m_err = xasprintf("Bad openflow flow syntax: %s", err);
268 free(err);
269 goto exit;
270 }
271 }
272
273 /* Generate a packet, if requested. */
274 if (packet) {
275 if (!dp_packet_size(packet)) {
276 flow_compose(packet, flow);
277 } else {
278 /* Use the metadata from the flow and the packet argument
279 * to reconstruct the flow. */
280 pkt_metadata_from_flow(&packet->md, flow);
281 flow_extract(packet, flow);
282 }
283 }
284
285 exit:
286 if (error && !m_err) {
287 m_err = xstrdup(error);
288 }
289 if (m_err) {
290 dp_packet_delete(packet);
291 packet = NULL;
292 }
293 *packetp = packet;
294 ofpbuf_uninit(&odp_key);
295 ofpbuf_uninit(&odp_mask);
296 simap_destroy(&port_names);
297 return m_err;
298 }
299
300 static void
301 ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
302 void *aux OVS_UNUSED)
303 {
304 struct ofproto_dpif *ofproto;
305 struct dp_packet *packet;
306 char *error;
307 struct flow flow;
308
309 error = parse_flow_and_packet(argc, argv, &ofproto, &flow, &packet);
310 if (!error) {
311 struct ds result;
312
313 ds_init(&result);
314 ofproto_trace(ofproto, &flow, packet, NULL, 0, &result);
315 unixctl_command_reply(conn, ds_cstr(&result));
316 ds_destroy(&result);
317 dp_packet_delete(packet);
318 } else {
319 unixctl_command_reply_error(conn, error);
320 free(error);
321 }
322 }
323
324 static void
325 ofproto_unixctl_trace_actions(struct unixctl_conn *conn, int argc,
326 const char *argv[], void *aux OVS_UNUSED)
327 {
328 enum ofputil_protocol usable_protocols;
329 struct ofproto_dpif *ofproto;
330 bool enforce_consistency;
331 struct ofpbuf ofpacts;
332 struct dp_packet *packet;
333 struct ds result;
334 struct match match;
335 uint16_t in_port;
336
337 /* Three kinds of error return values! */
338 enum ofperr retval;
339 char *error;
340
341 packet = NULL;
342 ds_init(&result);
343 ofpbuf_init(&ofpacts, 0);
344
345 /* Parse actions. */
346 error = ofpacts_parse_actions(argv[--argc], NULL,
347 &ofpacts, &usable_protocols);
348 if (error) {
349 unixctl_command_reply_error(conn, error);
350 free(error);
351 goto exit;
352 }
353
354 /* OpenFlow 1.1 and later suggest that the switch enforces certain forms of
355 * consistency between the flow and the actions. With -consistent, we
356 * enforce consistency even for a flow supported in OpenFlow 1.0. */
357 if (!strcmp(argv[1], "-consistent")) {
358 enforce_consistency = true;
359 argv++;
360 argc--;
361 } else {
362 enforce_consistency = false;
363 }
364
365 error = parse_flow_and_packet(argc, argv, &ofproto, &match.flow, &packet);
366 if (error) {
367 unixctl_command_reply_error(conn, error);
368 free(error);
369 goto exit;
370 }
371 match_wc_init(&match, &match.flow);
372
373 /* Do the same checks as handle_packet_out() in ofproto.c.
374 *
375 * We pass a 'table_id' of 0 to ofpacts_check(), which isn't
376 * strictly correct because these actions aren't in any table, but it's OK
377 * because it 'table_id' is used only to check goto_table instructions, but
378 * packet-outs take a list of actions and therefore it can't include
379 * instructions.
380 *
381 * We skip the "meter" check here because meter is an instruction, not an
382 * action, and thus cannot appear in ofpacts. */
383 in_port = ofp_to_u16(match.flow.in_port.ofp_port);
384 if (in_port >= ofproto->up.max_ports && in_port < ofp_to_u16(OFPP_MAX)) {
385 unixctl_command_reply_error(conn, "invalid in_port");
386 goto exit;
387 }
388 if (enforce_consistency) {
389 retval = ofpacts_check_consistency(ofpacts.data, ofpacts.size, &match,
390 u16_to_ofp(ofproto->up.max_ports),
391 0, ofproto->up.n_tables,
392 usable_protocols);
393 } else {
394 retval = ofpacts_check(ofpacts.data, ofpacts.size, &match,
395 u16_to_ofp(ofproto->up.max_ports), 0,
396 ofproto->up.n_tables, &usable_protocols);
397 }
398 if (!retval) {
399 ovs_mutex_lock(&ofproto_mutex);
400 retval = ofproto_check_ofpacts(&ofproto->up, ofpacts.data,
401 ofpacts.size);
402 ovs_mutex_unlock(&ofproto_mutex);
403 }
404
405 if (retval) {
406 ds_clear(&result);
407 ds_put_format(&result, "Bad actions: %s", ofperr_to_string(retval));
408 unixctl_command_reply_error(conn, ds_cstr(&result));
409 goto exit;
410 }
411
412 ofproto_trace(ofproto, &match.flow, packet,
413 ofpacts.data, ofpacts.size, &result);
414 unixctl_command_reply(conn, ds_cstr(&result));
415
416 exit:
417 ds_destroy(&result);
418 dp_packet_delete(packet);
419 ofpbuf_uninit(&ofpacts);
420 }
421
422 /* Implements a "trace" through 'ofproto''s flow table, appending a textual
423 * description of the results to 'output'.
424 *
425 * The trace follows a packet with the specified 'flow' through the flow
426 * table. 'packet' may be nonnull to trace an actual packet, with consequent
427 * side effects (if it is nonnull then its flow must be 'flow').
428 *
429 * If 'ofpacts' is nonnull then its 'ofpacts_len' bytes specify the actions to
430 * trace, otherwise the actions are determined by a flow table lookup. */
431 static void
432 ofproto_trace(struct ofproto_dpif *ofproto, struct flow *flow,
433 const struct dp_packet *packet,
434 const struct ofpact ofpacts[], size_t ofpacts_len,
435 struct ds *output)
436 {
437 struct ofpbuf odp_actions;
438 ofpbuf_init(&odp_actions, 0);
439
440 struct xlate_in xin;
441 struct flow_wildcards wc;
442 struct ovs_list trace = OVS_LIST_INITIALIZER(&trace);
443 xlate_in_init(&xin, ofproto,
444 ofproto_dpif_get_tables_version(ofproto), flow,
445 flow->in_port.ofp_port, NULL, ntohs(flow->tcp_flags),
446 packet, &wc, &odp_actions);
447 xin.ofpacts = ofpacts;
448 xin.ofpacts_len = ofpacts_len;
449 xin.trace = &trace;
450
451 /* Copy initial flow out of xin.flow. It differs from '*flow' because
452 * xlate_in_init() initializes actset_output to OFPP_UNSET. */
453 struct flow initial_flow = xin.flow;
454 ds_put_cstr(output, "Flow: ");
455 flow_format(output, &initial_flow, NULL);
456 ds_put_char(output, '\n');
457
458 struct xlate_out xout;
459 enum xlate_error error = xlate_actions(&xin, &xout);
460
461 oftrace_node_print_details(output, &trace, 0);
462
463 ds_put_cstr(output, "\nFinal flow: ");
464 if (flow_equal(&initial_flow, &xin.flow)) {
465 ds_put_cstr(output, "unchanged");
466 } else {
467 flow_format(output, &xin.flow, NULL);
468 }
469 ds_put_char(output, '\n');
470
471 ds_put_cstr(output, "Megaflow: ");
472 struct match match;
473 match_init(&match, flow, &wc);
474 match_format(&match, NULL, output, OFP_DEFAULT_PRIORITY);
475 ds_put_char(output, '\n');
476
477 ds_put_cstr(output, "Datapath actions: ");
478 format_odp_actions(output, odp_actions.data, odp_actions.size);
479
480 if (error != XLATE_OK) {
481 ds_put_format(output,
482 "\nTranslation failed (%s), packet is dropped.\n",
483 xlate_strerror(error));
484 } else if (xout.slow) {
485 enum slow_path_reason slow;
486
487 ds_put_cstr(output, "\nThis flow is handled by the userspace "
488 "slow path because it:");
489
490 slow = xout.slow;
491 while (slow) {
492 enum slow_path_reason bit = rightmost_1bit(slow);
493
494 ds_put_format(output, "\n\t- %s.",
495 slow_path_reason_to_explanation(bit));
496
497 slow &= ~bit;
498 }
499 }
500
501 xlate_out_uninit(&xout);
502 ofpbuf_uninit(&odp_actions);
503 oftrace_node_list_destroy(&trace);
504 }
505
506 void
507 ofproto_dpif_trace_init(void)
508 {
509 static bool registered;
510 if (registered) {
511 return;
512 }
513 registered = true;
514
515 unixctl_command_register(
516 "ofproto/trace",
517 "{[dp_name] odp_flow | bridge br_flow} [-generate|packet]",
518 1, 3, ofproto_unixctl_trace, NULL);
519 unixctl_command_register(
520 "ofproto/trace-packet-out",
521 "[-consistent] {[dp_name] odp_flow | bridge br_flow} [-generate|packet] actions",
522 2, 6, ofproto_unixctl_trace_actions, NULL);
523 }