From patchwork Thu Jun 17 16:27:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kumar Amber X-Patchwork-Id: 1493740 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4G5SVj5n12z9sRf for ; Fri, 18 Jun 2021 02:41:17 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id A0926421E9; Thu, 17 Jun 2021 16:41:14 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id RUA62W_ozXWe; Thu, 17 Jun 2021 16:41:13 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp4.osuosl.org (Postfix) with ESMTPS id E2DEC421EE; Thu, 17 Jun 2021 16:41:11 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id B69D9C000F; Thu, 17 Jun 2021 16:41:11 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id B2811C000D for ; Thu, 17 Jun 2021 16:41:10 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 7F57783ED0 for ; Thu, 17 Jun 2021 16:41:10 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id WD5ncmAJaIki for ; Thu, 17 Jun 2021 16:41:09 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by smtp1.osuosl.org (Postfix) with ESMTPS id 8007983EC2 for ; Thu, 17 Jun 2021 16:41:09 +0000 (UTC) IronPort-SDR: xwNj/jRuXzXsrGPjS74bW7sZWA4RRzF4aBEHsK7BTuEfYTjxzjjA8qRFS1KjdNYm2h6gyGTJ1/ sp3di+Wt41SQ== X-IronPort-AV: E=McAfee;i="6200,9189,10018"; a="193719915" X-IronPort-AV: E=Sophos;i="5.83,281,1616482800"; d="scan'208";a="193719915" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jun 2021 09:41:09 -0700 IronPort-SDR: VsMzTXXm28Hxm1Td/1dKqj6Wc9IiIwgFu+J5vD0bZM///aYo/O4Xrp9mslJrtZzPvmAn+zkFrY CsSWzDFtXzww== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.83,281,1616482800"; d="scan'208";a="555252874" Received: from bmca4bf01706bbf.iind.intel.com (HELO localhost.localdomain) ([10.190.213.111]) by fmsmga001.fm.intel.com with ESMTP; 17 Jun 2021 09:41:06 -0700 From: Kumar Amber To: dev@openvswitch.org Date: Thu, 17 Jun 2021 21:57:44 +0530 Message-Id: <20210617162754.2028048-3-kumar.amber@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210617162754.2028048-1-kumar.amber@intel.com> References: <20210517135708.685517-1-kumar.amber@intel.com> <20210617162754.2028048-1-kumar.amber@intel.com> MIME-Version: 1.0 Cc: Kumar Amber , i.maximets@ovn.org Subject: [ovs-dev] [v4 02/12] dpif-netdev: Add auto validation function for miniflow extract X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" This patch introduced the auto-validation function which allows users to compare the batch of packets obtained from different miniflow implementations against the linear miniflow extract and return a hitmask. The autovaidator function can be triggered at runtime using the following command: $ ovs-appctl dpif-netdev/miniflow-parser-set autovalidator Signed-off-by: Kumar Amber Co-authored-by: Harry van Haaren Signed-off-by: Harry van Haaren Signed-off-by: Kumar Amber > Signed-off-by: Harry van Haaren > Signed-off-by: Kumar Amber > Signed-off-by: Harry van Haaren > Signed-off-by: Kumar Amber > Signed-off-by: Harry van Haaren > --- lib/dpif-netdev-private-extract.c | 141 ++++++++++++++++++++++++++++++ lib/dpif-netdev-private-extract.h | 15 ++++ lib/dpif-netdev.c | 2 +- 3 files changed, 157 insertions(+), 1 deletion(-) diff --git a/lib/dpif-netdev-private-extract.c b/lib/dpif-netdev-private-extract.c index fcc56ef26..0741c19f9 100644 --- a/lib/dpif-netdev-private-extract.c +++ b/lib/dpif-netdev-private-extract.c @@ -32,6 +32,11 @@ VLOG_DEFINE_THIS_MODULE(dpif_netdev_extract); /* Implementations of available extract options. */ static struct dpif_miniflow_extract_impl mfex_impls[] = { + { + .probe = NULL, + .extract_func = dpif_miniflow_extract_autovalidator, + .name = "autovalidator", + }, { .probe = NULL, .extract_func = NULL, @@ -84,3 +89,139 @@ dpif_miniflow_extract_info_get(struct dpif_miniflow_extract_impl **out_ptr) *out_ptr = mfex_impls; return ARRAY_SIZE(mfex_impls); } + +uint32_t +dpif_miniflow_extract_autovalidator(struct dp_packet_batch *packets, + struct netdev_flow_key *keys, + uint32_t keys_size, odp_port_t in_port, + void *pmd_handle) +{ + const size_t cnt = dp_packet_batch_size(packets); + uint16_t good_l2_5_ofs[NETDEV_MAX_BURST]; + uint16_t good_l3_ofs[NETDEV_MAX_BURST]; + uint16_t good_l4_ofs[NETDEV_MAX_BURST]; + uint16_t good_l2_pad_size[NETDEV_MAX_BURST]; + struct dp_packet *packet; + struct dp_netdev_pmd_thread *pmd = pmd_handle; + struct dpif_miniflow_extract_impl *miniflow_funcs; + + int32_t mfunc_count = dpif_miniflow_extract_info_get(&miniflow_funcs); + if (mfunc_count < 0) { + pmd->miniflow_extract_opt = NULL; + VLOG_ERR("failed to get miniflow extract function implementations\n"); + return 0; + } + ovs_assert(keys_size >= cnt); + struct netdev_flow_key test_keys[NETDEV_MAX_BURST]; + + /* Run scalar miniflow_extract to get default result. */ + DP_PACKET_BATCH_FOR_EACH (i, packet, packets) { + pkt_metadata_init(&packet->md, in_port); + miniflow_extract(packet, &keys[i].mf); + + /* Store known good metadata to compare with optimized metadata. */ + good_l2_5_ofs[i] = packet->l2_5_ofs; + good_l3_ofs[i] = packet->l3_ofs; + good_l4_ofs[i] = packet->l4_ofs; + good_l2_pad_size[i] = packet->l2_pad_size; + } + + /* Iterate through each version of miniflow implementations. */ + for (int j = MFEX_IMPL_START_IDX; j < ARRAY_SIZE(mfex_impls); j++) { + if (!mfex_impls[j].available) { + continue; + } + + /* Reset keys and offsets before each implementation. */ + memset(test_keys, 0, keys_size * sizeof(struct netdev_flow_key)); + DP_PACKET_BATCH_FOR_EACH (i, packet, packets) { + dp_packet_reset_offsets(packet); + } + /* Call optimized miniflow for each batch of packet. */ + uint32_t hit_mask = mfex_impls[j].extract_func(packets, test_keys, + keys_size, in_port, pmd_handle); + + /* Do a miniflow compare for bits, blocks and offsets for all the + * classified packets in the hitmask marked by set bits. */ + while (hit_mask) { + /* Index for the set bit. */ + uint32_t i = __builtin_ctz(hit_mask); + /* Set the index in hitmask to Zero. */ + hit_mask &= (hit_mask - 1); + + uint32_t failed = 0; + + /* Check miniflow bits are equal. */ + if ((keys[i].mf.map.bits[0] != test_keys[i].mf.map.bits[0]) || + (keys[i].mf.map.bits[1] != test_keys[i].mf.map.bits[1])) { + VLOG_ERR("Good 0x%llx 0x%llx\tTest 0x%llx 0x%llx\n", + keys[i].mf.map.bits[0], keys[i].mf.map.bits[1], + test_keys[i].mf.map.bits[0], + test_keys[i].mf.map.bits[1]); + failed = 1; + } + + if (!miniflow_equal(&keys[i].mf, &test_keys[i].mf)) { + uint32_t block_cnt = miniflow_n_values(&keys[i].mf); + VLOG_ERR("Autovalidation blocks failed for %s pkt %d", + mfex_impls[j].name, i); + VLOG_ERR(" Good hexdump:\n"); + uint64_t *good_block_ptr = (uint64_t *)&keys[i].buf; + uint64_t *test_block_ptr = (uint64_t *)&test_keys[i].buf; + for (uint32_t b = 0; b < block_cnt; b++) { + VLOG_ERR(" %"PRIx64"\n", good_block_ptr[b]); + } + VLOG_ERR(" Test hexdump:\n"); + for (uint32_t b = 0; b < block_cnt; b++) { + VLOG_ERR(" %"PRIx64"\n", test_block_ptr[b]); + } + failed = 1; + } + + if ((packets->packets[i]->l2_pad_size != good_l2_pad_size[i]) || + (packets->packets[i]->l2_5_ofs != good_l2_5_ofs[i]) || + (packets->packets[i]->l3_ofs != good_l3_ofs[i]) || + (packets->packets[i]->l4_ofs != good_l4_ofs[i])) { + VLOG_ERR("Autovalidation packet offsets failed for %s pkt %d", + mfex_impls[j].name, i); + VLOG_ERR(" Good offsets: l2_pad_size %u, l2_5_ofs : %u" + " l3_ofs %u, l4_ofs %u\n", + good_l2_pad_size[i], good_l2_5_ofs[i], + good_l3_ofs[i], good_l4_ofs[i]); + VLOG_ERR(" Test offsets: l2_pad_size %u, l2_5_ofs : %u" + " l3_ofs %u, l4_ofs %u\n", + packets->packets[i]->l2_pad_size, + packets->packets[i]->l2_5_ofs, + packets->packets[i]->l3_ofs, + packets->packets[i]->l4_ofs); + failed = 1; + } + + if (failed) { + /* Having dumped the debug info, disable autovalidator. */ + VLOG_ERR("Autovalidation failed in %s pkt %d, disabling.\n", + mfex_impls[j].name, i); + /* Halt OVS here on debug builds. */ + ovs_assert(0); + pmd->miniflow_extract_opt = NULL; + break; + } + } + } + + /* preserve packet correctness by storing back the good offsets in + * packets back. */ + DP_PACKET_BATCH_FOR_EACH (i, packet, packets) { + packet->l2_5_ofs = good_l2_5_ofs[i]; + packet->l3_ofs = good_l3_ofs[i]; + packet->l4_ofs = good_l4_ofs[i]; + packet->l2_pad_size = good_l2_pad_size[i]; + } + + /* Returning zero implies no packets were hit by autovalidation. This + * simplifies unit-tests as changing --enable-mfex-default-autovalidator + * would pass/fail. By always returning zero, autovalidator is a little + * slower, but we gain consistency in testing. + */ + return 0; +} diff --git a/lib/dpif-netdev-private-extract.h b/lib/dpif-netdev-private-extract.h index b7b0b2be4..455a7b590 100644 --- a/lib/dpif-netdev-private-extract.h +++ b/lib/dpif-netdev-private-extract.h @@ -24,6 +24,11 @@ /* Max size of dpif_miniflow_extract_impl array. */ #define MFEX_IMPLS_MAX_SIZE (16) +/* Skip the autovalidator study and null when iterating all available + * miniflow implementations. + */ +#define MFEX_IMPL_START_IDX (1) + /* Forward declarations. */ struct dp_packet; struct miniflow; @@ -90,5 +95,15 @@ dpif_miniflow_extract_init(void); int32_t dpif_miniflow_extract_info_get(struct dpif_miniflow_extract_impl **out_ptr); +/* Retrieve the hitmask of the batch of pakcets which is obtained by comparing + * different miniflow implementations with linear miniflow extract. + * On error, returns a zero. + * On success, returns the number of packets in the batch compared. + */ +uint32_t +dpif_miniflow_extract_autovalidator(struct dp_packet_batch *batch, + struct netdev_flow_key *keys, + uint32_t keys_size, odp_port_t in_port, + void *pmd_handle); #endif /* DPIF_NETDEV_AVX512_EXTRACT */ diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 567ebd952..4f4ab2790 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -1181,8 +1181,8 @@ dpif_miniflow_extract_impl_set(struct unixctl_conn *conn, int argc, struct ds reply = DS_EMPTY_INITIALIZER; ds_put_format(&reply, "Miniflow implementation set to %s.\n", mfex_name); const char *reply_str = ds_cstr(&reply); - unixctl_command_reply(conn, reply_str); VLOG_INFO("%s", reply_str); + unixctl_command_reply(conn, reply_str); ds_destroy(&reply); }