From patchwork Thu Jan 18 22:45:15 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 863201 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3zMzbD4tnNz9sBd for ; Fri, 19 Jan 2018 09:46:32 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 2C982F80; Thu, 18 Jan 2018 22:45:31 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id EB2C7E6E for ; Thu, 18 Jan 2018 22:45:28 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net [217.70.183.198]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 65E2E47C for ; Thu, 18 Jan 2018 22:45:28 +0000 (UTC) X-Originating-IP: 208.91.3.26 Received: from sigabrt.benpfaff.org (unknown [208.91.3.26]) (Authenticated sender: blp@ovn.org) by relay6-d.mail.gandi.net (Postfix) with ESMTPSA id 70713FB88B; Thu, 18 Jan 2018 23:45:26 +0100 (CET) From: Ben Pfaff To: dev@openvswitch.org Date: Thu, 18 Jan 2018 14:45:15 -0800 Message-Id: <20180118224515.4208-4-blp@ovn.org> X-Mailer: git-send-email 2.10.2 In-Reply-To: <20180118224515.4208-1-blp@ovn.org> References: <20180118224515.4208-1-blp@ovn.org> X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: Ben Pfaff Subject: [ovs-dev] [PATCH 4/4] ovs-ofctl: Add "compose-packet" command for testing flow_compose(). X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org I don't feel obligated to add a bunch of automatic tests for flow_compose(), but this is handy for manual testing or for simple packet generation. Signed-off-by: Ben Pfaff --- utilities/ovs-ofctl.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 953184da4d19..94bd9abd6dc1 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -138,6 +138,9 @@ static bool should_show_ports(void); /* --stats, --no-stats: Show statistics in flow dumps? */ static int show_stats = 1; +/* --pcap: Makes "compose-packet" print a pcap on stdout. */ +static int print_pcap = 0; + static const struct ovs_cmdl_command *get_all_commands(void); OVS_NO_RETURN static void usage(void); @@ -223,6 +226,7 @@ parse_options(int argc, char *argv[]) {"bundle", no_argument, NULL, OPT_BUNDLE}, {"color", optional_argument, NULL, OPT_COLOR}, {"may-create", no_argument, NULL, OPT_MAY_CREATE}, + {"pcap", no_argument, &print_pcap, 1}, {"read-only", no_argument, NULL, OPT_READ_ONLY}, DAEMON_LONG_OPTIONS, OFP_VERSION_LONG_OPTIONS, @@ -4492,6 +4496,73 @@ ofctl_parse_key_value(struct ovs_cmdl_context *ctx) } } +/* "compose-packet [--pcap] FLOW [L7]": Converts the OpenFlow flow + * specification FLOW to a packet with flow_compose() and prints the hex bytes + * in the packet on stdout. Also verifies that the flow extracted from that + * packet matches the original FLOW. + * + * With --pcap, prints the packet to stdout instead as a pcap file, so that you + * can do something like "ovs-ofctl compose-packet udp | tcpdump -vvvv -r-" to + * use another tool to dump the packet contents. + * + * If L7 is specified, draws the L7 payload data from it, otherwise defaults to + * 64 bytes of payload. */ +static void +ofctl_compose_packet(struct ovs_cmdl_context *ctx) +{ + if (print_pcap && isatty(STDOUT_FILENO)) { + ovs_fatal(1, "not writing pcap data to stdout; redirect to a file " + "or pipe to tcpdump instead"); + } + + struct flow flow1; + char *error = parse_ofp_exact_flow(&flow1, NULL, NULL, ctx->argv[1], NULL); + if (error) { + ovs_fatal(0, "%s", error); + } + + struct dp_packet p; + memset(&p, 0, sizeof p); + dp_packet_init(&p, 0); + + void *l7 = NULL; + size_t l7_len = 64; + if (ctx->argc > 2) { + struct dp_packet payload; + memset(&payload, 0, sizeof payload); + dp_packet_init(&payload, 0); + if (dp_packet_put_hex(&payload, ctx->argv[2], NULL)[0] != '\0') { + ovs_fatal(0, "%s: trailing garbage in packet data", ctx->argv[2]); + } + l7_len = dp_packet_size(&payload); + l7 = dp_packet_steal_data(&payload); + } + flow_compose(&p, &flow1, l7, l7_len); + free(l7); + + if (print_pcap) { + ovs_pcap_write_header(stdout); + ovs_pcap_write(stdout, &p); + } else { + ovs_hex_dump(stdout, dp_packet_data(&p), dp_packet_size(&p), 0, false); + } + + struct flow flow2; + flow_extract(&p, &flow2); + flow2.in_port.ofp_port = OFPP_ANY; + + dp_packet_uninit(&p); + + if (!flow_equal(&flow1, &flow2)) { + fprintf(stderr, "specified and extracted flows differ:\n"); + fputs("specified: ", stderr); + flow_print(stderr, &flow1, NULL); + fputs("\nextracted: ", stderr); + flow_print(stderr, &flow2, NULL); + exit(1); + } +} + static const struct ovs_cmdl_command all_commands[] = { { "show", "switch", 1, 1, ofctl_show, OVS_RO }, @@ -4625,6 +4696,7 @@ static const struct ovs_cmdl_command all_commands[] = { { "ofp-print", NULL, 1, 2, ofctl_ofp_print, OVS_RW }, { "encode-hello", NULL, 1, 1, ofctl_encode_hello, OVS_RW }, { "parse-key-value", NULL, 1, INT_MAX, ofctl_parse_key_value, OVS_RW }, + { "compose-packet", NULL, 1, 2, ofctl_compose_packet, OVS_RO }, { NULL, NULL, 0, 0, NULL, OVS_RO }, };