- tun_id_s = strtok_r(NULL, " ", &save_ptr);
- in_port_s = strtok_r(NULL, " ", &save_ptr);
- packet_s = strtok_r(NULL, "", &save_ptr); /* Get entire rest of line. */
- if (!dpname || !in_port_s || !packet_s) {
+ arg1 = strtok_r(NULL, " ", &save_ptr);
+ arg2 = strtok_r(NULL, " ", &save_ptr);
+ arg3 = strtok_r(NULL, "", &save_ptr); /* Get entire rest of line. */
+ if (dpname && arg1 && !arg2 && !arg3) {
+ /* ofproto/trace dpname flow */
+ int error;
+
+ /* Convert string to datapath key. */
+ ofpbuf_init(&odp_key, 0);
+ error = odp_flow_key_from_string(arg1, &odp_key);
+ if (error) {
+ unixctl_command_reply(conn, 501, "Bad flow syntax");
+ goto exit;
+ }
+
+ /* Convert odp_key to flow. */
+ error = odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
+ if (error) {
+ unixctl_command_reply(conn, 501, "Invalid flow");
+ goto exit;
+ }
+ } else if (dpname && arg1 && arg2 && arg3) {
+ /* ofproto/trace dpname tun_id in_port packet */
+ uint16_t in_port;
+ ovs_be64 tun_id;
+
+ tun_id = htonll(strtoull(arg1, NULL, 0));
+ in_port = ofp_port_to_odp_port(atoi(arg2));
+
+ packet = ofpbuf_new(strlen(args) / 2);
+ arg3 = ofpbuf_put_hex(packet, arg3, NULL);
+ arg3 += strspn(arg3, " ");
+ if (*arg3 != '\0') {
+ unixctl_command_reply(conn, 501, "Trailing garbage in command");
+ goto exit;
+ }
+ if (packet->size < ETH_HEADER_LEN) {
+ unixctl_command_reply(conn, 501,
+ "Packet data too short for Ethernet");
+ goto exit;
+ }
+
+ ds_put_cstr(&result, "Packet: ");
+ s = ofp_packet_to_string(packet->data, packet->size, packet->size);
+ ds_put_cstr(&result, s);
+ free(s);
+
+ flow_extract(packet, tun_id, in_port, &flow);
+ } else {