From patchwork Thu Aug 18 11:11:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wilson Peng X-Patchwork-Id: 1667644 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=vmware.com header.i=@vmware.com header.a=rsa-sha256 header.s=selector2 header.b=PwEyV3IA; dkim-atps=neutral Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4M7hz82zF9z1yg3 for ; Thu, 18 Aug 2022 21:11:32 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id D1ACE41186; Thu, 18 Aug 2022 11:11:29 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org D1ACE41186 Authentication-Results: smtp2.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key, unprotected) header.d=vmware.com header.i=@vmware.com header.a=rsa-sha256 header.s=selector2 header.b=PwEyV3IA X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id VuKqwFCO3Hq5; Thu, 18 Aug 2022 11:11:28 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTPS id EB462405F4; Thu, 18 Aug 2022 11:11:26 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org EB462405F4 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id A6531C0070; Thu, 18 Aug 2022 11:11:26 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 37753C002D for ; Thu, 18 Aug 2022 11:11:25 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id F19876116C for ; Thu, 18 Aug 2022 11:11:24 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org F19876116C Authentication-Results: smtp3.osuosl.org; dkim=pass (1024-bit key, unprotected) header.d=vmware.com header.i=@vmware.com header.a=rsa-sha256 header.s=selector2 header.b=PwEyV3IA X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ilBqcUmwY9Yh for ; Thu, 18 Aug 2022 11:11:22 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org A81D36116B Received: from NAM11-DM6-obe.outbound.protection.outlook.com (mail-dm6nam11on2045.outbound.protection.outlook.com [40.107.223.45]) by smtp3.osuosl.org (Postfix) with ESMTPS id A81D36116B for ; Thu, 18 Aug 2022 11:11:22 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=cjsH3xmqXNmP+HaUcCLBkv3oI76MIH7evV3iietdv4rMCBaQIHApWeph1MK07JcF7ZxeaoIqM0sAw4MEW0tnZUushz6983wfIvpqUKtisLEEVzGFYtmm2s0jaiZE7J9Xn2XufuJNcwbbf+vFiJiIBfsaAkX6XqSxte8b5h0bMZoOF0XLr/urN8icWDFsmpHvZ0JpxOAy3hQSYJpa6y0Qm7cqQuc3U1Ft1CWQN4EnG5s9nHfZ2P83UOqesGvOSq0+DgKH43cRIcGSDg7lYAH/HPqDaLCUHyA8RANaGLxuOnqtZTXkID35SiScf1tW3AwfomdZ5PgiIQXCj33s4/JwXw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=diGgxxTOultlJvL7ERqO5CJozKy/MWD4fw6k5DwyW6g=; b=Ow9vQYL9YTLnz3Est07XM7jN5Cyn6E2gN9uxcPuzMqBsfQGwz7Np+j7Ly8zuUR/bbXw4/BFvog+Tf6+Un34Wzt8DwJ+i1vc5exQKXo0ko7a8Pc/HSzxFcPHBNpwjqFrudIvmUL0AttRZmNamkHG74lEfm8jlBTmWDN71hyOVzARH5Ag0x1ax8XTDpz/31rHHUQFf1GJSdT6qG5l2V48HGKDzJi7KQyO4AWHHSmy9jaTqvqlO0uzx6l2Hyiq/XgwC4DIa0WdfuCSvDpztFo8vFWddCn69lbTKYUWyLyVCqv2mLSs2OTumDQY5ei1F7M53NKYqftUQyBQ3y09Vu6C2mg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=vmware.com; dmarc=pass action=none header.from=vmware.com; dkim=pass header.d=vmware.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=vmware.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=diGgxxTOultlJvL7ERqO5CJozKy/MWD4fw6k5DwyW6g=; b=PwEyV3IAUnRq1C2IZ151pl7EvZkXV3gkW9jce9xneAZZm/TyKx1u28+lifj/bbWEsTC7I7WfHx6SAYR2V6OtzAT+Ek7GF66buhS8lfL7PrVtdWscX8S73Vs6g71Fr0TjwJfB+7wd7yAJzWnUhrzHe6Kt54/ZK05GSnNmqn0xuKs= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=vmware.com; Received: from SN6PR05MB5935.namprd05.prod.outlook.com (2603:10b6:805:100::18) by DM6PR05MB4971.namprd05.prod.outlook.com (2603:10b6:5:76::14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5546.14; Thu, 18 Aug 2022 11:11:19 +0000 Received: from SN6PR05MB5935.namprd05.prod.outlook.com ([fe80::a0ab:9fa6:8753:3c37]) by SN6PR05MB5935.namprd05.prod.outlook.com ([fe80::a0ab:9fa6:8753:3c37%3]) with mapi id 15.20.5546.014; Thu, 18 Aug 2022 11:11:19 +0000 To: dev@openvswitch.org Date: Thu, 18 Aug 2022 19:11:00 +0800 Message-Id: <20220818111100.75351-1-svc.ovs-community@vmware.com> X-Mailer: git-send-email 2.30.1 (Apple Git-130) X-ClientProxiedBy: MA1P287CA0014.INDP287.PROD.OUTLOOK.COM (2603:1096:a00:35::31) To SN6PR05MB5935.namprd05.prod.outlook.com (2603:10b6:805:100::18) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 4e7a16c5-2055-43d6-e4b1-08da810a6006 X-MS-TrafficTypeDiagnostic: DM6PR05MB4971:EE_ X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: N+s6hTKOTFVlZaFK7R1/Ii/v37MMdvaHBhkvEEJz+ROJ8mzIS6tcy1X4nYqpZ7wH1T3MyYo5myuLck2Ro3NyeI0tNIolCGU6QoI+ZrKuo1DyTrSUo5CvVAutGJFe3ngbUcrRKNLB/RxZNEAW60y0DJlhJ84BUnSApoKsgJKvIF/Bnjs5BhuCozfKAiUpEDUo1yxAOuttjnadTMEywNtSXiX3G/J7Yh8iL3ASmxXF4QzqvB9qqsuCOqC6d1vU3qWjh4bU7bhV2MbsF4J+rWd3t9O47QMRiWk1YpAwiVeAb/alHtc5N9gBEMfR4CxhBe4nSU338L+A178wYlgAZ2I121k3f/iK8XA/74elEac/wFwX2K91upfTfDEjjKyb47owc5lmx2u9Qi+bA+dR9GMOMAlbfFK/i6FCybLgTPx+HtsuPvYZVIlDDxKD9IWTgD1MPvjnI8kPIaxkbK2f5URV8tYwCooDygnyoRtKVIMC0uFLj2SafxI0VEC+C8y7sCi98v97eaiElm9vqNiky8LXxhtM9PIc6Y27bhcJjaf9Mq/1HkD/eG/JIGEASaeGhGweL06MSVKktnd/uh5VSTLB6d7avA5p2ax2QWOK/FxHF0pC+6HShoORtjIburJ7tsKJNVIQ5sEWOlgYPFd8EZOgcDrWFGn4yf7MT9T8xqGBT1qDLKaOlbKqtj/3ZeVRcF2cbLrg8rqEXa+zduB8h6r5spebQENmqSWF2Dq4ME/18Eo9qH4m0WyfP3wmsI6reTcvxT8w7YKSQg8U2QdDTrSJelQKwgdpEmdgLp2NDsHg3btb31ymuaImul4JLKmxVXamzx7JBwuvg4j+BukoMWMSIqHXtMlrSHp6ef+ybcDVwj/4IGcC29tO9xZswpNiv7wzYV3stubSs7AGO9ALkkKA6cYktwAEvFaf+PhXYqwCqhU= X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:SN6PR05MB5935.namprd05.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230016)(4636009)(376002)(366004)(39860400002)(346002)(396003)(136003)(2616005)(38100700002)(6512007)(26005)(83380400001)(86362001)(5660300002)(8936002)(107886003)(186003)(30864003)(38350700002)(1076003)(52116002)(66476007)(8676002)(4326008)(66556008)(66946007)(36756003)(6486002)(41300700001)(2906002)(966005)(6506007)(6916009)(6666004)(478600001)(316002)(43062005); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: QRDxp5S077P540/LYYmgbcxScZ5uNSqFD3tV/GEiZ8hzW+4D/BJib5BSZZJz+P3jaJr2KzsAkpqwbiW66YKm0UAbGeGMWVgi/8lrA9ysBm+kbRRAJ/lZBCOrL9DRb//nHIu9zKpDSjHuHroCbDwqq72xr73lgvyvvtYWs4VaQtTDTKLtwKOTTdiWae6+8GSzdDKtUExqU+KBBVLu/XSMBaAwmGcTN8R8I3QWOw2o5rJfbPd+2/jeWnWqRHqDYoP7trMq9X26wSF0hzlY9qsx3QwsCcTFats3mWLYBc1S79VtSwPHCHPFdrNumv8HvqIq6PWujUyW8H+lmJtOwUyn3JCD9hkX67r7irLadcfGwQpdbavGxLFfG27XYs0zmde8Piu8bri2cPwe6lwlAuW07EVtUCMJ3o+hCavL/7YLnWVWDK+B5V7hn1PoyKpR/FrxXC8GwK0JzA9UKXm57mO3nTkvu8CY3km5m1V+S6p4d6URx46nB861bjVEA7Bo9aX/5uw+D2zHTQ6FrDMvl3Vu1lQw3Xklhn8MQCd+3psCzrVKHJReZlMYQ6ojDJIsTSYV6mbfFQ2fUKCNRddWFycThqhsTQWxHKpMgsKjMw1bCsFQAtdlWuXYj92DksFl9k1Ikssp0mN49Htf+97pfKzVDNcNDwD640BRyR3uiGcTq5Ylg6HSzUJGnNebmkr+xlOC27DGBz2ovorSC6BrLx5857RFhsqU+a/i5BfwExc6TdFOn4O/vLGVWlQyGR7fG5be16IkXysPypHyqUYcxodX5TVOzkGGf21R/9UAIIk38rQXMLcgam4EJXylNmSDK9P3X+EfGvP1Z0bwQGBmlaBCePS9DiCGaSfslU9524BPGOjK/Eo8yybO8/eFl4F0iOX6HcIPON93u6XadgVp9Cj5j8Ol2LZVb0+CNcZPS0u9hi9/oFKeR13AEJg7pycT43UaqMOdbqmQUVEHY04r+U+SA4D1RYd1EOuh9kCbNH3ecT/68JTkVSqHYGmyK+mfHvB9bkEUlOLGDzHz+rZfdwcRMBsngYa8Ek8AMtl3t6K5NBxEuNTfZ7VNuiSgoJKucrf9qYc5Ck+vF/LY0JuFC81B7f1iknC8e6VT/Q8w82fQDGB+WNYa74mxN39UjwkZd+oC3qQcQSA/GUi2jbGrbuiMc10qOXiPMCC86yJPp4ukeUvbgld18q26V1E1+fygdLdlqARlR07hsNDftURZL2EjUuV6E8YRoXBxYpInnnaf2uT38qYN5lUz1Xi5MyQwd1CPl+P+npUlzzOIhM/zRo5gvc+m74pIRn09CVHRsL33VrN5WeLoh2/6oKj4R/4VZvasPT/Pe8P5hJaKT/KEkrAdQnX/ZmVyxYJWcvPekUoNDHKTaMWPpIjfi5n75wHcNf5fay3c60D+TCBF1bzqe/8PLGCV0gg1LQqdr/XJYPCPXskhQbwcpmgB6ZHQw8FqQ+8DcgsQ8PPPEQL7zCqyV3+4bykzuqb6cC9qpALbl2TqRz4+RWpRtKwVRlT3Lr8QCQ9pStQoR3NgQ20tqZKGGRSF+ER155fOCn33HGhhcDteoacQqE6mpySeEmQoMqDrriR1mScO91SQNzsMqQXoPaVSWQ== X-OriginatorOrg: vmware.com X-MS-Exchange-CrossTenant-Network-Message-Id: 4e7a16c5-2055-43d6-e4b1-08da810a6006 X-MS-Exchange-CrossTenant-AuthSource: SN6PR05MB5935.namprd05.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Aug 2022 11:11:19.1285 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: b39138ca-3cee-4b4a-a4d6-cd83d9dd62f0 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: Ni+CBpf1ZnJ1B+1RN9Gx8RztfORZeMYb9ws2EFymP03atNaKJntxxk41FH9E+sU5dsm079Oy9LWJhSoXsuUBeQWg1fJy32v6CSmsQ0Ga+uQ= X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM6PR05MB4971 Cc: ldejing Subject: [ovs-dev] [PATCH v2 1/1] datapath-windows: support meter action initial version 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: , X-Patchwork-Original-From: ldejing via dev From: Wilson Peng Reply-To: ldejing Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: ldejing This patch implemented meter action, currently, meter only support drop method and only support one band. The overall implementation is, when a packet comes in, it will first lookup meter according to the meter id, then get the band->rates and delta time since last access the same meter from the meter struct. Add the multiply result(band->rates * delta_time) to bucket, finally bucket minus the packet size, if the result larger than zero, allow the packet go through, otherwise deny the packet go through. Test case: 1. Setting the size meter size 3M, then the bandwidth was limit around 3M; ovs-ofctl -O OpenFlow13 add-meter br-test meter=2,kbps,\ band=type=drop,rate=3000 ovs-ofctl add-flow br-test "table=0,priority=1,ip \ actions=meter:2,normal" -O OpenFlow13 2. Setting the meter size 8M, then the bandwidth was limit around 8M; ovs-ofctl -O OpenFlow13 add-meter br-test meter=2,\ kbps,band=type=drop,rate=8000 ovs-ofctl add-flow br-test "table=0,priority=1,ip\ actions=meter:2,normal" -O OpenFlow13 Signed-off-by: ldejing Signed-off-by: ldejing --- datapath-windows/automake.mk | 2 + datapath-windows/include/OvsDpInterfaceExt.h | 3 + datapath-windows/ovsext/Actions.c | 10 + datapath-windows/ovsext/Datapath.c | 46 +- datapath-windows/ovsext/Meter.c | 540 +++++++++++++++++++ datapath-windows/ovsext/Meter.h | 68 +++ datapath-windows/ovsext/Switch.c | 8 + datapath-windows/ovsext/Util.h | 1 + datapath-windows/ovsext/ovsext.vcxproj | 2 + lib/netlink-socket.c | 5 + 10 files changed, 684 insertions(+), 1 deletion(-) create mode 100644 datapath-windows/ovsext/Meter.c create mode 100644 datapath-windows/ovsext/Meter.h diff --git a/datapath-windows/automake.mk b/datapath-windows/automake.mk index 60b3d6033..2d9f9a40d 100644 --- a/datapath-windows/automake.mk +++ b/datapath-windows/automake.mk @@ -42,6 +42,8 @@ EXTRA_DIST += \ datapath-windows/ovsext/Jhash.c \ datapath-windows/ovsext/Jhash.h \ datapath-windows/ovsext/Mpls.h \ + datapath-windows/ovsext/Meter.c \ + datapath-windows/ovsext/Meter.h \ datapath-windows/ovsext/NetProto.h \ datapath-windows/ovsext/Netlink/Netlink.c \ datapath-windows/ovsext/Netlink/Netlink.h \ diff --git a/datapath-windows/include/OvsDpInterfaceExt.h b/datapath-windows/include/OvsDpInterfaceExt.h index 5fd8000d1..045e4cbd6 100644 --- a/datapath-windows/include/OvsDpInterfaceExt.h +++ b/datapath-windows/include/OvsDpInterfaceExt.h @@ -74,6 +74,9 @@ #define OVS_WIN_NL_CT_FAMILY_ID (NLMSG_MIN_TYPE + 7) #define OVS_WIN_NL_CTLIMIT_FAMILY_ID (NLMSG_MIN_TYPE + 8) +/* Meter Family */ +#define OVS_WIN_NL_METER_FAMILY_ID (NLMSG_MIN_TYPE + 9) + #define OVS_WIN_NL_INVALID_MCGRP_ID 0 #define OVS_WIN_NL_MCGRP_START_ID 100 #define OVS_WIN_NL_VPORT_MCGRP_ID (OVS_WIN_NL_MCGRP_START_ID + 1) diff --git a/datapath-windows/ovsext/Actions.c b/datapath-windows/ovsext/Actions.c index 20de4db4c..63ee574c5 100644 --- a/datapath-windows/ovsext/Actions.c +++ b/datapath-windows/ovsext/Actions.c @@ -23,6 +23,7 @@ #include "Flow.h" #include "Gre.h" #include "Jhash.h" +#include "Meter.h" #include "Mpls.h" #include "NetProto.h" #include "Offload.h" @@ -2502,6 +2503,15 @@ OvsDoExecuteActions(POVS_SWITCH_CONTEXT switchContext, } break; } + case OVS_ACTION_ATTR_METER: { + if (OvsMeterExecute(&ovsFwdCtx, NlAttrGetU32(a))) { + OVS_LOG_INFO("Drop packet"); + dropReason = L"Ovs-meter exceed max rate"; + goto dropit; + } + + break; + } case OVS_ACTION_ATTR_SAMPLE: { if (ovsFwdCtx.destPortsSizeOut > 0 || ovsFwdCtx.tunnelTxNic != NULL diff --git a/datapath-windows/ovsext/Datapath.c b/datapath-windows/ovsext/Datapath.c index fa994840a..37db5bd17 100644 --- a/datapath-windows/ovsext/Datapath.c +++ b/datapath-windows/ovsext/Datapath.c @@ -100,7 +100,11 @@ NetlinkCmdHandler OvsGetNetdevCmdHandler, OvsReadPacketCmdHandler, OvsCtDeleteCmdHandler, OvsCtDumpCmdHandler, - OvsCtLimitHandler; + OvsCtLimitHandler, + OvsMeterFeatureProbe, + OvsNewMeterCmdHandler, + OvsMeterDestroy, + OvsMeterGet; static NTSTATUS HandleGetDpTransaction(POVS_USER_PARAMS_CONTEXT usrParamsCtx, UINT32 *replyLen); @@ -307,6 +311,43 @@ NETLINK_FAMILY nlCtFamilyOps = { .opsCount = ARRAY_SIZE(nlCtFamilyCmdOps) }; +/* Netlink Meter family */ +NETLINK_CMD nlMeterFamilyCmdOps[] = { + { .cmd = OVS_METER_CMD_FEATURES, + .handler = OvsMeterFeatureProbe, + .supportedDevOp = OVS_TRANSACTION_DEV_OP | + OVS_WRITE_DEV_OP | OVS_READ_DEV_OP, + .validateDpIndex = FALSE + }, + { .cmd = OVS_METER_CMD_SET, + .handler = OvsNewMeterCmdHandler, + .supportedDevOp = OVS_TRANSACTION_DEV_OP | + OVS_WRITE_DEV_OP | OVS_READ_DEV_OP, + .validateDpIndex = FALSE + }, + { .cmd = OVS_METER_CMD_GET, + .handler = OvsMeterGet, + .supportedDevOp = OVS_TRANSACTION_DEV_OP | + OVS_WRITE_DEV_OP | OVS_READ_DEV_OP, + .validateDpIndex = FALSE + }, + { .cmd = OVS_METER_CMD_DEL, + .handler = OvsMeterDestroy, + .supportedDevOp = OVS_TRANSACTION_DEV_OP | + OVS_WRITE_DEV_OP | OVS_READ_DEV_OP, + .validateDpIndex = FALSE + }, +}; + +NETLINK_FAMILY nlMeterFamilyOps = { + .name = OVS_METER_FAMILY, + .id = OVS_WIN_NL_METER_FAMILY_ID, + .version = OVS_METER_VERSION, + .maxAttr = __OVS_METER_ATTR_MAX, + .cmds = nlMeterFamilyCmdOps, + .opsCount = ARRAY_SIZE(nlMeterFamilyCmdOps) +}; + /* Netlink netdev family. */ NETLINK_CMD nlNetdevFamilyCmdOps[] = { { .cmd = OVS_WIN_NETDEV_CMD_GET, @@ -952,6 +993,9 @@ OvsDeviceControl(PDEVICE_OBJECT deviceObject, case NFNL_TYPE_CT_DEL: nlFamilyOps = &nlCtFamilyOps; break; + case OVS_WIN_NL_METER_FAMILY_ID: + nlFamilyOps = &nlMeterFamilyOps; + break; case OVS_WIN_NL_CTRL_FAMILY_ID: nlFamilyOps = &nlControlFamilyOps; break; diff --git a/datapath-windows/ovsext/Meter.c b/datapath-windows/ovsext/Meter.c new file mode 100644 index 000000000..a896f999d --- /dev/null +++ b/datapath-windows/ovsext/Meter.c @@ -0,0 +1,540 @@ +/* + * Copyright (c) 2022 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Meter.h" +#include "precomp.h" +#include "Switch.h" +#include "User.h" +#include "Datapath.h" +#include "Event.h" +#include "NetProto.h" +#include "Flow.h" +#include "PacketParser.h" +#include "util.h" + +static PNDIS_RW_LOCK_EX meterGlobalTableLock; +PLIST_ENTRY meterGlobalTable; + +const NL_POLICY nlMeterPolicy[OVS_METER_ATTR_MAX + 1] = { + [OVS_METER_ATTR_ID] = { .type = NL_A_U32, }, + [OVS_METER_ATTR_KBPS] = { .type = NL_A_FLAG, .optional = TRUE }, + [OVS_METER_ATTR_STATS] = { .minLen = sizeof(struct ovs_flow_stats), + .maxLen = sizeof(struct ovs_flow_stats), + .optional = TRUE }, + [OVS_METER_ATTR_BANDS] = { .type = NL_A_NESTED, .optional = TRUE }, + [OVS_METER_ATTR_USED] = { .type = NL_A_U64, .optional = TRUE }, + [OVS_METER_ATTR_CLEAR] = { .type = NL_A_FLAG, .optional = TRUE }, + [OVS_METER_ATTR_MAX_METERS] = { .type = NL_A_U32, .optional = TRUE }, + [OVS_METER_ATTR_MAX_BANDS] = { .type = NL_A_U32, .optional = TRUE }, +}; + +const NL_POLICY bandPolicy[OVS_BAND_ATTR_MAX + 1] = { + [OVS_BAND_ATTR_TYPE] = { .type = NL_A_U32, .optional = FALSE }, + [OVS_BAND_ATTR_RATE] = { .type = NL_A_U32, .optional = TRUE }, + [OVS_BAND_ATTR_BURST] = { .type = NL_A_U32, .optional = TRUE }, + [OVS_BAND_ATTR_STATS] = { .minLen = sizeof(struct ovs_flow_stats), + .maxLen = sizeof(struct ovs_flow_stats), + .optional = TRUE }, +}; + +NTSTATUS +OvsInitMeter(POVS_SWITCH_CONTEXT context) +{ + UINT32 maxEntry = METER_HASH_BUCKET_MAX; + + meterGlobalTableLock = NdisAllocateRWLock(context->NdisFilterHandle); + if (meterGlobalTableLock == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + meterGlobalTable = OvsAllocateMemoryWithTag(sizeof(LIST_ENTRY) * maxEntry, + OVS_METER_TAG); + if (!meterGlobalTable) { + NdisFreeRWLock(meterGlobalTableLock); + return NDIS_STATUS_RESOURCES; + } + + for (UINT32 index = 0; index < maxEntry; index++) { + InitializeListHead(&meterGlobalTable[index]); + } + + return NDIS_STATUS_SUCCESS; +} + +NDIS_STATUS +FillBandIntoMeter(PNL_ATTR meterAttrs[], DpMeter *meter, PNL_MSG_HDR nlMsgHdr) +{ + PNL_ATTR a = NULL; + INT rem = 0; + UINT32 bandMaxDelta = 0; + UINT32 attrOffset = 0; + DpMeterBand *band = NULL; + PNL_ATTR bandAttrs[OVS_BAND_ATTR_MAX + 1]; + UINT16 nBands = 0; + + band = meter->bands; + NL_ATTR_FOR_EACH(a, rem, NlAttrData(meterAttrs[OVS_METER_ATTR_BANDS]), + NlAttrGetSize(meterAttrs[OVS_METER_ATTR_BANDS])) { + RtlZeroMemory(bandAttrs, sizeof(bandAttrs)); + attrOffset = (UINT32)((PCHAR)NlAttrData(a) - (PCHAR)nlMsgHdr); + if (!NlAttrParse(nlMsgHdr, + attrOffset, + NlAttrGetSize(a), + bandPolicy, ARRAY_SIZE(bandPolicy), + bandAttrs, ARRAY_SIZE(bandAttrs))) { + return STATUS_INVALID_PARAMETER; + } + + if (bandAttrs[OVS_BAND_ATTR_TYPE]) { + band->type = NlAttrGetU32(bandAttrs[OVS_BAND_ATTR_TYPE]); + } + + if (bandAttrs[OVS_BAND_ATTR_RATE]) { + band->rate = NlAttrGetU32(bandAttrs[OVS_BAND_ATTR_RATE]); + } + + if (bandAttrs[OVS_BAND_ATTR_BURST]) { + band->burst_size = NlAttrGetU32(bandAttrs[OVS_BAND_ATTR_BURST]); + } + + band->bucket = (band->burst_size + band->rate) * 1000; + bandMaxDelta = (UINT32)((band->bucket / band->rate) / 10); + if (bandMaxDelta > meter->maxDelta) { + meter->maxDelta = bandMaxDelta; + } + + nBands++; + band++; + } + + meter->nBands = nBands; + return NDIS_STATUS_SUCCESS; +} + +NDIS_STATUS +OvsNewMeterCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx, + UINT32 *replyLen) +{ + DpMeter *meter = NULL; + POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer; + PNL_MSG_HDR nlMsgHdr = &(msgIn->nlMsg); + PGENL_MSG_HDR genlMsgHdr = &(msgIn->genlMsg); + POVS_HDR ovsHdr = &(msgIn->ovsHdr); + LOCK_STATE_EX lockState; + PNL_ATTR meterAttrs[ARRAY_SIZE(nlMeterPolicy)]; + ASSERT(usrParamsCtx->inputBuffer != NULL); + PNL_MSG_HDR nlMsgOutHdr = NULL; + NL_BUFFER nlBuf; + NL_ERROR nlError = NL_ERROR_SUCCESS; + + if (!NlAttrParse((PNL_MSG_HDR)msgIn, + NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN, + NlMsgAttrsLen((PNL_MSG_HDR)msgIn), + nlMeterPolicy, ARRAY_SIZE(nlMeterPolicy), + meterAttrs, ARRAY_SIZE(meterAttrs))) { + nlError = NL_ERROR_NOMSG; + goto Done; + } + + meter = OvsAllocateMemoryWithTag(sizeof(*meter), OVS_METER_TAG); + if (!meter) { + nlError = NL_ERROR_NOMEM; + goto Done; + } + + RtlZeroMemory(meter, sizeof(*meter)); + meter->id = NlAttrGetU32(meterAttrs[OVS_METER_ATTR_ID]); + meter->kbps = meterAttrs[OVS_METER_ATTR_KBPS] ? 1 : 0; + meter->keepStatus = meterAttrs[OVS_METER_ATTR_CLEAR] ? 1 : 0; + if (meter->keepStatus && meterAttrs[OVS_METER_ATTR_STATS]) { + meter->stats = *(struct ovs_flow_stats *)NlAttrData( + meterAttrs[OVS_METER_ATTR_STATS]); + } + + if (FillBandIntoMeter(meterAttrs, meter, nlMsgHdr) != NDIS_STATUS_SUCCESS) { + nlError = NL_ERROR_NOMSG; + OvsFreeMemoryWithTag(meter, OVS_METER_TAG); + goto Done; + } + + NdisAcquireRWLockWrite(meterGlobalTableLock, &lockState, 0); + InsertHeadList(&meterGlobalTable[meter->id & (METER_HASH_BUCKET_MAX - 1)], + &(meter->link)); + NdisReleaseRWLock(meterGlobalTableLock, &lockState); + + NlBufInit(&nlBuf, usrParamsCtx->outputBuffer, usrParamsCtx->outputLength); + nlMsgOutHdr = (PNL_MSG_HDR)(NlBufAt(&nlBuf, 0, 0)); + if (!NlFillOvsMsg(&nlBuf, nlMsgHdr->nlmsgType, 0, + nlMsgHdr->nlmsgSeq, nlMsgHdr->nlmsgPid, + genlMsgHdr->cmd, OVS_METER_CMD_GET, + ovsHdr->dp_ifindex)) { + nlError = NL_ERROR_NOMSG; + goto Done; + } + + if (!buildOvsMeterReplyMsg(&nlBuf, meter)) { + nlError = NL_ERROR_NOMEM; + goto Done; + } + + NlMsgSetSize(nlMsgOutHdr, NlBufSize(&nlBuf)); + NlMsgAlignSize(nlMsgOutHdr); + *replyLen += NlMsgSize(nlMsgOutHdr); + +Done: + if (nlError != NL_ERROR_SUCCESS) { + POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR) + usrParamsCtx->outputBuffer; + + ASSERT(msgError); + NlBuildErrorMsg(msgIn, msgError, nlError, replyLen); + ASSERT(*replyLen != 0); + } + + return NDIS_STATUS_SUCCESS; +} + +NDIS_STATUS OvsMeterFeatureProbe(POVS_USER_PARAMS_CONTEXT usrParamsCtx, + UINT32 *replyLen) +{ + POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer; + PNL_MSG_HDR nlMsgHdr = &(msgIn->nlMsg); + POVS_HDR ovsHdr = &(msgIn->ovsHdr); + PNL_MSG_HDR nlMsgOutHdr = NULL; + BOOLEAN ok = FALSE; + PGENL_MSG_HDR genlMsgHdr = &(msgIn->genlMsg); + NL_BUFFER nlBuf; + NL_ERROR nlError = NL_ERROR_SUCCESS; + UINT32 bandsOffset = 0; + UINT32 bandAttrOffset = 0; + + NlBufInit(&nlBuf, usrParamsCtx->outputBuffer, usrParamsCtx->outputLength); + nlMsgOutHdr = (PNL_MSG_HDR)(NlBufAt(&nlBuf, 0, 0)); + ok = NlFillOvsMsg(&nlBuf, nlMsgHdr->nlmsgType, 0, + nlMsgHdr->nlmsgSeq, nlMsgHdr->nlmsgPid, + genlMsgHdr->cmd, OVS_METER_CMD_FEATURES, + ovsHdr->dp_ifindex); + if (!ok) { + nlError = NL_ERROR_NOMSG; + goto Done; + } + + if (!NlMsgPutTailU32(&nlBuf, OVS_METER_ATTR_MAX_METERS, UINT32_MAX)) { + nlError = NL_ERROR_NOMSG; + goto Done; + } + + if (!NlMsgPutTailU32(&nlBuf, OVS_METER_ATTR_MAX_BANDS, OVS_MAX_BANDS)) { + nlError = NL_ERROR_NOMSG; + goto Done; + } + + bandsOffset = NlMsgStartNested(&nlBuf, OVS_METER_ATTR_BANDS); + bandAttrOffset = NlMsgStartNested(&nlBuf, OVS_METER_ATTR_UNSPEC); + if (!NlMsgPutTailU32(&nlBuf, OVS_BAND_ATTR_TYPE, + OVS_METER_BAND_TYPE_DROP)) { + nlError = NL_ERROR_NOMSG; + goto Done; + + } + NlMsgEndNested(&nlBuf, bandAttrOffset); + NlMsgEndNested(&nlBuf, bandsOffset); + + NlMsgSetSize(nlMsgOutHdr, NlBufSize(&nlBuf)); + NlMsgAlignSize(nlMsgOutHdr); + *replyLen += NlMsgSize(nlMsgOutHdr); + +Done: + if (nlError != NL_ERROR_SUCCESS) { + POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR) + usrParamsCtx->outputBuffer; + + ASSERT(msgError); + NlBuildErrorMsg(msgIn, msgError, nlError, replyLen); + ASSERT(*replyLen != 0); + } + + return STATUS_SUCCESS; +} + +BOOLEAN +buildOvsMeterReplyMsg(NL_BUFFER *nlBuf, DpMeter *dpMeter) +{ + BOOLEAN ok = FALSE; + UINT32 bandAttrOffset; + UINT32 bandsOffset; + + /* Add meter element. */ + ok = NlMsgPutTailU32(nlBuf, OVS_METER_ATTR_ID, dpMeter->id); + if (!ok) { + OVS_LOG_ERROR("Could not add meter id %d.", dpMeter->id); + return ok; + } + + ok = NlMsgPutTailUnspec(nlBuf, OVS_METER_ATTR_STATS, + (PCHAR)&(dpMeter->stats), + sizeof(dpMeter->stats)); + if (!ok) { + OVS_LOG_ERROR("Could not add ovs meter stats."); + return ok; + } + + bandsOffset = NlMsgStartNested(nlBuf, OVS_METER_ATTR_BANDS); + for (int index = 0; index < dpMeter->nBands; index++) { + bandAttrOffset = NlMsgStartNested(nlBuf, OVS_BAND_ATTR_UNSPEC); + ok = NlMsgPutTailUnspec(nlBuf, OVS_BAND_ATTR_STATS, + (PCHAR)&(dpMeter->bands[index].stats), + sizeof(dpMeter->bands[index].stats)); + NlMsgEndNested(nlBuf, bandAttrOffset); + if (!ok) { + break; + } + } + + NlMsgEndNested(nlBuf, bandsOffset); + return ok; +} + +NDIS_STATUS +OvsMeterGet(POVS_USER_PARAMS_CONTEXT usrParamsCtx, + UINT32 *replyLen) +{ + POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer; + PNL_MSG_HDR nlMsgHdr = &(msgIn->nlMsg); + POVS_HDR ovsHdr = &(msgIn->ovsHdr); + PNL_MSG_HDR nlMsgOutHdr = NULL; + PNL_ATTR meterAttrs[ARRAY_SIZE(nlMeterPolicy)]; + UINT32 meterId = 0; + DpMeter *dpMeter = NULL; + BOOLEAN ok = FALSE; + PGENL_MSG_HDR genlMsgHdr = &(msgIn->genlMsg); + NL_BUFFER nlBuf; + NL_ERROR nlError = NL_ERROR_SUCCESS; + LOCK_STATE_EX lockState; + + if (!NlAttrParse((PNL_MSG_HDR)msgIn, + NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN, + NlMsgAttrsLen((PNL_MSG_HDR)msgIn), + nlMeterPolicy, ARRAY_SIZE(nlMeterPolicy), + meterAttrs, ARRAY_SIZE(meterAttrs))) { + nlError = NL_ERROR_NOMSG; + goto Done; + } + + NlBufInit(&nlBuf, usrParamsCtx->outputBuffer, usrParamsCtx->outputLength); + meterId = NlAttrGetU32(meterAttrs[OVS_METER_ATTR_ID]); + + /* Reply message header */ + nlMsgOutHdr = (PNL_MSG_HDR)(NlBufAt(&nlBuf, 0, 0)); + ok = NlFillOvsMsg(&nlBuf, nlMsgHdr->nlmsgType, 0, + nlMsgHdr->nlmsgSeq, nlMsgHdr->nlmsgPid, + genlMsgHdr->cmd, OVS_METER_CMD_GET, + ovsHdr->dp_ifindex); + if (!ok) { + nlError = NL_ERROR_NOMSG; + goto Done; + } + + NdisAcquireRWLockRead(meterGlobalTableLock, &lockState, 0); + dpMeter = OvsMeterLookup(meterId); + if (!dpMeter) { + OVS_LOG_WARN("Has not find %d associated meter", meterId); + nlError = NL_ERROR_EXIST; + NdisReleaseRWLock(meterGlobalTableLock, &lockState); + goto Done; + } + + if (!buildOvsMeterReplyMsg(&nlBuf, dpMeter)) { + nlError = NL_ERROR_NOMEM; + OVS_LOG_ERROR("Could not build ovs meter reply msg."); + NdisReleaseRWLock(meterGlobalTableLock, &lockState); + goto Done; + } + + NdisReleaseRWLock(meterGlobalTableLock, &lockState); + NlMsgSetSize(nlMsgOutHdr, NlBufSize(&nlBuf)); + NlMsgAlignSize(nlMsgOutHdr); + *replyLen += NlMsgSize(nlMsgOutHdr); + +Done: + if (nlError != NL_ERROR_SUCCESS) { + POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR) + usrParamsCtx->outputBuffer; + + ASSERT(msgError); + NlBuildErrorMsg(msgIn, msgError, nlError, replyLen); + ASSERT(*replyLen != 0); + } + + return NDIS_STATUS_SUCCESS; +} + +NDIS_STATUS +OvsMeterDestroy(POVS_USER_PARAMS_CONTEXT usrParamsCtx, + UINT32 *replyLen) +{ + POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer; + PNL_MSG_HDR nlMsgHdr = &(msgIn->nlMsg); + POVS_HDR ovsHdr = &(msgIn->ovsHdr); + PNL_MSG_HDR nlMsgOutHdr = NULL; + PNL_ATTR meterAttrs[ARRAY_SIZE(nlMeterPolicy)]; + PGENL_MSG_HDR genlMsgHdr = &(msgIn->genlMsg); + LOCK_STATE_EX lockState; + UINT32 meterId = 0; + BOOLEAN ok; + NL_BUFFER nlBuf; + NL_ERROR nlError = NL_ERROR_SUCCESS; + + if (!NlAttrParse((PNL_MSG_HDR)msgIn, + NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN, + NlMsgAttrsLen((PNL_MSG_HDR)msgIn), + nlMeterPolicy, ARRAY_SIZE(nlMeterPolicy), + meterAttrs, ARRAY_SIZE(meterAttrs))) { + return STATUS_INVALID_PARAMETER; + } + + NlBufInit(&nlBuf, usrParamsCtx->outputBuffer, usrParamsCtx->outputLength); + + meterId = NlAttrGetU32(meterAttrs[OVS_METER_ATTR_ID]); + nlMsgOutHdr = (PNL_MSG_HDR)(NlBufAt(&nlBuf, 0, 0)); + ok = NlFillOvsMsg(&nlBuf, nlMsgHdr->nlmsgType, 0, + nlMsgHdr->nlmsgSeq, nlMsgHdr->nlmsgPid, + genlMsgHdr->cmd, OVS_METER_CMD_DEL, + ovsHdr->dp_ifindex); + if (!ok) { + nlError = NL_ERROR_NOMEM; + goto Done; + } + + NdisAcquireRWLockWrite(meterGlobalTableLock, &lockState, 0); + PLIST_ENTRY head = &meterGlobalTable[meterId & (METER_HASH_BUCKET_MAX - 1)]; + PLIST_ENTRY link, next; + DpMeter *entry = NULL; + + LIST_FORALL_SAFE(head, link, next) { + entry = CONTAINING_RECORD(link, DpMeter, link); + if (entry->id == meterId) { + if (!buildOvsMeterReplyMsg(&nlBuf, entry)) { + nlError = NL_ERROR_NOMEM; + NdisReleaseRWLock(meterGlobalTableLock, &lockState); + goto Done; + } + RemoveEntryList(&entry->link); + OvsFreeMemoryWithTag(entry, OVS_METER_TAG); + break; + } + } + + NdisReleaseRWLock(meterGlobalTableLock, &lockState); + NlMsgSetSize(nlMsgOutHdr, NlBufSize(&nlBuf)); + NlMsgAlignSize(nlMsgOutHdr); + *replyLen += NlMsgSize(nlMsgOutHdr); + +Done: + if (nlError != NL_ERROR_SUCCESS) { + POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR) + usrParamsCtx->outputBuffer; + + ASSERT(msgError); + NlBuildErrorMsg(msgIn, msgError, nlError, replyLen); + ASSERT(*replyLen != 0); + } + + return NDIS_STATUS_SUCCESS; +} + + + +DpMeter* +OvsMeterLookup(UINT32 meterId) +{ + PLIST_ENTRY head = &meterGlobalTable[meterId & (METER_HASH_BUCKET_MAX - 1)]; + PLIST_ENTRY link, next; + DpMeter *entry = NULL; + + LIST_FORALL_SAFE(head, link, next) { + entry = CONTAINING_RECORD(link, DpMeter, link); + if (entry->id == meterId) { + return entry; + } + } + + return NULL; +} + +BOOLEAN +OvsMeterExecute(OvsForwardingContext *fwdCtx, UINT32 meterId) +{ + DpMeter *dpMeter; + DpMeterBand *band; + UINT32 longDeltaMs; + UINT32 deltaMs; + UINT64 currentTime; + LOCK_STATE_EX lockState; + UINT32 cost; + UINT32 bandExceededRate = 0; + INT32 bandExceedIndex = -1; + UINT64 maxBucketSize = 0; + + NdisAcquireRWLockRead(meterGlobalTableLock, &lockState, 0); + dpMeter = OvsMeterLookup(meterId); + if (!dpMeter) { + OVS_LOG_ERROR("Not found meter id %d associated meter.", meterId); + NdisReleaseRWLock(meterGlobalTableLock, &lockState); + return FALSE; + } + + NdisGetCurrentSystemTime((LARGE_INTEGER *)¤tTime); + /* currentTime represent count of 100-nanosecond intervals, to convert it to + * ms, we need to divide 10000. */ + longDeltaMs = (UINT32)((currentTime - dpMeter->used) / 10000); + deltaMs = longDeltaMs > dpMeter->maxDelta ? dpMeter->maxDelta : + longDeltaMs; + dpMeter->used = currentTime; + dpMeter->stats.n_packets += 1; + dpMeter->stats.n_bytes += OvsPacketLenNBL(fwdCtx->curNbl); + cost = dpMeter->kbps ? OvsPacketLenNBL(fwdCtx->curNbl) * 8 : 1000; + for (int index = 0; index < dpMeter->nBands; index++) { + band = &(dpMeter->bands[index]); + maxBucketSize = (band->burst_size + band->rate) * 1000LL; + band->bucket += deltaMs * band->rate; + if (band->bucket > maxBucketSize) { + band->bucket = maxBucketSize; + } + + if (band->bucket >= cost) { + band->bucket -= cost; + band->stats.n_packets += 1; + band->stats.n_bytes += OvsPacketLenNBL(fwdCtx->curNbl); + } else if (band->rate > bandExceededRate) { + bandExceededRate = band->rate; + bandExceedIndex = index; + } + } + + if (bandExceedIndex >= 0) { + band = &(dpMeter->bands[bandExceedIndex]); + band->stats.n_packets += 1; + band->stats.n_bytes += OvsPacketLenNBL(fwdCtx->curNbl); + if (band->type == OVS_METER_BAND_TYPE_DROP) { + NdisReleaseRWLock(meterGlobalTableLock, &lockState); + return TRUE; + } + } + + NdisReleaseRWLock(meterGlobalTableLock, &lockState); + return FALSE; +} diff --git a/datapath-windows/ovsext/Meter.h b/datapath-windows/ovsext/Meter.h new file mode 100644 index 000000000..bc94489a5 --- /dev/null +++ b/datapath-windows/ovsext/Meter.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2022 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OVS_METER_H +#define OVS_METER_H + +#include "precomp.h" +#include "Switch.h" +#include "User.h" +#include "Datapath.h" +#include "Event.h" +#include "NetProto.h" +#include "Netlink/Netlink.h" +#include "Flow.h" + +#define OVS_MAX_BANDS 1 +#define OVS_MAX_METERS 32 +#define METER_HASH_BUCKET_MAX 1024 + +typedef struct _DpMeterBand { + UINT32 type; + UINT32 rate; + UINT32 burst_size; + UINT64 bucket; + struct ovs_flow_stats stats; +} DpMeterBand; + +typedef struct _DpMeter { + LIST_ENTRY link; + UINT32 id; + UINT16 kbps:1; + UINT16 keepStatus:1; + UINT16 nBands; + UINT32 maxDelta; + UINT64 used; + struct ovs_flow_stats stats; + DpMeterBand bands[OVS_MAX_BANDS]; +} DpMeter; + +NTSTATUS OvsInitMeter(POVS_SWITCH_CONTEXT context); +NDIS_STATUS OvsNewMeterCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx, + UINT32 *replyLen); +NDIS_STATUS OvsMeterFeatureProbe(POVS_USER_PARAMS_CONTEXT usrParamsCtx, +UINT32 *replyLen); + +NDIS_STATUS OvsMeterDestroy(POVS_USER_PARAMS_CONTEXT usrParamsCtx, + UINT32 *replyLen); +DpMeter* OvsMeterLookup(UINT32 meterId); +BOOLEAN +OvsMeterExecute(OvsForwardingContext *fwdCtx, UINT32 meterId); +BOOLEAN +buildOvsMeterReplyMsg(NL_BUFFER *nlBuf, DpMeter *dpMeter); + + +#endif //OVS_METER_H diff --git a/datapath-windows/ovsext/Switch.c b/datapath-windows/ovsext/Switch.c index 1ac4fa77c..088aee21a 100644 --- a/datapath-windows/ovsext/Switch.c +++ b/datapath-windows/ovsext/Switch.c @@ -24,6 +24,7 @@ #include "Switch.h" #include "Vport.h" #include "Event.h" +#include "Meter.h" #include "Flow.h" #include "IpHelper.h" #include "Oid.h" @@ -239,6 +240,13 @@ OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle, goto create_switch_done; } + status = OvsInitMeter(switchContext); + if (status != STATUS_SUCCESS) { + OvsUninitSwitchContext(switchContext); + OVS_LOG_ERROR("Exit: Failed to initialize Ovs meter."); + goto create_switch_done; + } + *switchContextOut = switchContext; create_switch_done: diff --git a/datapath-windows/ovsext/Util.h b/datapath-windows/ovsext/Util.h index f63a885a9..16903ed46 100644 --- a/datapath-windows/ovsext/Util.h +++ b/datapath-windows/ovsext/Util.h @@ -38,6 +38,7 @@ #define OVS_TUNFLT_POOL_TAG 'WSVO' #define OVS_RECIRC_POOL_TAG 'CSVO' #define OVS_CT_POOL_TAG 'CTVO' +#define OVS_METER_TAG 'MEVO' #define OVS_GENEVE_POOL_TAG 'GNVO' #define OVS_IPFRAG_POOL_TAG 'FGVO' diff --git a/datapath-windows/ovsext/ovsext.vcxproj b/datapath-windows/ovsext/ovsext.vcxproj index 7a2cbd2de..6e54b71f9 100644 --- a/datapath-windows/ovsext/ovsext.vcxproj +++ b/datapath-windows/ovsext/ovsext.vcxproj @@ -164,6 +164,7 @@ + @@ -408,6 +409,7 @@ + diff --git a/lib/netlink-socket.c b/lib/netlink-socket.c index 93c1fa561..80da20d9f 100644 --- a/lib/netlink-socket.c +++ b/lib/netlink-socket.c @@ -1574,6 +1574,11 @@ do_lookup_genl_family(const char *name, struct nlattr **attrs, family_name = OVS_FLOW_FAMILY; family_version = OVS_FLOW_VERSION; family_attrmax = OVS_FLOW_ATTR_MAX; + } else if (!strcmp(name, OVS_METER_FAMILY)) { + family_id = OVS_WIN_NL_METER_FAMILY_ID; + family_name = OVS_METER_FAMILY; + family_version = OVS_METER_VERSION; + family_attrmax = __OVS_METER_ATTR_MAX; } else if (!strcmp(name, OVS_WIN_NETDEV_FAMILY)) { family_id = OVS_WIN_NL_NETDEV_FAMILY_ID; family_name = OVS_WIN_NETDEV_FAMILY;