VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/PDMAllNetShaper.cpp@ 93633

Last change on this file since 93633 was 93633, checked in by vboxsync, 2 years ago

VMM/PDMNetShaper: Statistics. bugref:5582

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.2 KB
Line 
1/* $Id: PDMAllNetShaper.cpp 93633 2022-02-07 01:27:28Z vboxsync $ */
2/** @file
3 * PDM Network Shaper - Limit network traffic according to bandwidth group settings.
4 */
5
6/*
7 * Copyright (C) 2011-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_NET_SHAPER
23#include <VBox/vmm/pdmnetshaper.h>
24#include "PDMInternal.h"
25#include <VBox/vmm/vmcc.h>
26
27#include <VBox/log.h>
28#include <iprt/time.h>
29#include <iprt/asm-math.h>
30
31
32/**
33 * Obtain bandwidth in a bandwidth group.
34 *
35 * @returns True if bandwidth was allocated, false if not.
36 * @param pVM The cross context VM structure.
37 * @param pFilter Pointer to the filter that allocates bandwidth.
38 * @param cbTransfer Number of bytes to allocate.
39 */
40VMM_INT_DECL(bool) PDMNetShaperAllocateBandwidth(PVMCC pVM, PPDMNSFILTER pFilter, size_t cbTransfer)
41{
42 AssertPtrReturn(pFilter, true);
43
44 /*
45 * If we haven't got a valid bandwidth group, we always allow the traffic.
46 */
47 bool fAllowed = true;
48 uint32_t iGroup = ASMAtomicUoReadU32(&pFilter->iGroup);
49 if (iGroup != 0)
50 {
51 if (iGroup <= RT_MIN(pVM->pdm.s.cNsGroups, RT_ELEMENTS(pVM->pdm.s.aNsGroups)))
52 {
53 PPDMNSBWGROUP pGroup = &pVM->pdm.s.aNsGroups[iGroup - 1];
54 int rc = PDMCritSectEnter(pVM, &pGroup->Lock, VINF_TRY_AGAIN);
55 if (rc == VINF_SUCCESS)
56 {
57 uint64_t const cbPerSecMax = pGroup->cbPerSecMax;
58 if (cbPerSecMax > 0)
59 {
60 /*
61 * Re-fill the bucket first
62 *
63 * Note! We limit the cTokensAdded calculation to 1 second, since it's really
64 * pointless to calculate much beyond PDM_NETSHAPER_MAX_LATENCY (100ms)
65 * let alone 1 sec. This makes it possible to use ASMMultU64ByU32DivByU32
66 * as the cNsDelta is less than 30 bits wide now, which means we don't get
67 * into overflow issues when multiplying two 64-bit values.
68 */
69 uint64_t const nsNow = RTTimeSystemNanoTS();
70 uint64_t const cNsDelta = nsNow - pGroup->tsUpdatedLast;
71 uint64_t const cTokensAdded = cNsDelta < RT_NS_1SEC
72 ? ASMMultU64ByU32DivByU32(cbPerSecMax, (uint32_t)cNsDelta, RT_NS_1SEC)
73 : cbPerSecMax;
74 uint32_t const cbBucket = pGroup->cbBucket;
75 uint32_t const cbTokensLast = pGroup->cbTokensLast;
76 uint32_t const cTokens = (uint32_t)RT_MIN(cbBucket, cTokensAdded + cbTokensLast);
77
78 /*
79 * Allowed?
80 */
81 if (cbTransfer <= cTokens)
82 {
83 pGroup->cbTokensLast = cTokens - (uint32_t)cbTransfer;
84 pGroup->tsUpdatedLast = nsNow;
85 Log2(("pdmNsAllocateBandwidth/%s: allowed - cbTransfer=%#zx cTokens=%#x cTokensAdded=%#x\n",
86 pGroup->szName, cbTransfer, cTokens, cTokensAdded));
87 }
88 else
89 {
90 /*
91 * No, we're choked. Arm the unchoke timer for the next period.
92 * Just do this on a simple PDM_NETSHAPER_MAX_LATENCY clock granularity.
93 * ASSUMES the timer uses millisecond resolution clock.
94 */
95 ASMAtomicWriteBool(&pFilter->fChoked, true);
96 if (ASMAtomicCmpXchgBool(&pVM->pdm.s.fNsUnchokeTimerArmed, true, false))
97 {
98 Assert(TMTimerGetFreq(pVM, pVM->pdm.s.hNsUnchokeTimer) == RT_MS_1SEC);
99 uint64_t const msNow = TMTimerGet(pVM, pVM->pdm.s.hNsUnchokeTimer);
100 uint64_t const msExpire = (msNow / PDM_NETSHAPER_MAX_LATENCY + 1) * PDM_NETSHAPER_MAX_LATENCY;
101 rc = TMTimerSet(pVM, pVM->pdm.s.hNsUnchokeTimer, msExpire);
102 AssertRC(rc);
103
104 Log2(("pdmNsAllocateBandwidth/%s: refused - cbTransfer=%#zx cTokens=%#x cTokensAdded=%#x cMsExpire=%u\n",
105 pGroup->szName, cbTransfer, cTokens, cTokensAdded, msExpire - msNow));
106 }
107 else
108 Log2(("pdmNsAllocateBandwidth/%s: refused - cbTransfer=%#zx cTokens=%#x cTokensAdded=%#x\n",
109 pGroup->szName, cbTransfer, cTokens, cTokensAdded));
110 ASMAtomicIncU64(&pGroup->cTotalChokings);
111 fAllowed = false;
112 }
113 }
114 else
115 Log2(("pdmNsAllocateBandwidth/%s: disabled\n", pGroup->szName));
116
117 rc = PDMCritSectLeave(pVM, &pGroup->Lock);
118 AssertRCSuccess(rc);
119 }
120 else if (rc == VINF_TRY_AGAIN) /* (accounted for by the critsect stats) */
121 Log2(("pdmNsAllocateBandwidth/%s: allowed - lock contention\n", pGroup->szName));
122 else
123 PDM_CRITSECT_RELEASE_ASSERT_RC(pVM, &pGroup->Lock, rc);
124 }
125 else
126 AssertMsgFailed(("Invalid iGroup=%d\n", iGroup));
127 }
128 return fAllowed;
129}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use