VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette