VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/NetLib/IntNetIf.cpp@ 97071

Last change on this file since 97071 was 97071, checked in by vboxsync, 3 years ago

NetworkServices: Implement support for communicating over the R3 internal network service in driverless mode, bugref:10297

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.9 KB
Line 
1/* $Id: IntNetIf.cpp 97071 2022-10-10 16:30:56Z vboxsync $ */
2/** @file
3 * IntNetIf - Convenience class implementing an IntNet connection.
4 */
5
6/*
7 * Copyright (C) 2009-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.215389.xyz.
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#include "IntNetIf.h"
29
30#include <iprt/path.h>
31
32#include <VBox/intnetinline.h>
33#include <VBox/vmm/pdmnetinline.h>
34
35IntNetIf::IntNetIf()
36 : m_hIf(NULL),
37 m_pIfBuf(NULL),
38 m_pfnInput(NULL),
39 m_pvUser(NULL),
40 m_pfnInputGSO(NULL),
41 m_pvUserGSO(NULL)
42{
43 return;
44}
45
46
47IntNetIf::~IntNetIf()
48{
49 uninit();
50}
51
52
53/*
54 * Wrappers for VMM ioctl requests and low-level intnet operations.
55 */
56
57/**
58 * Open the specified internal network.
59 * Perform VMMR0_DO_INTNET_OPEN.
60 *
61 * @param strNetwork The name of the network.
62 * @param enmTrunkType The trunk type.
63 * @param strTrunk The trunk name, its meaning is specific to the type.
64 * @return iprt status code.
65 */
66int
67IntNetIf::ifOpen(const RTCString &strNetwork,
68 INTNETTRUNKTYPE enmTrunkType,
69 const RTCString &strTrunk)
70{
71 AssertReturn(m_hIf == NULL, VERR_GENERAL_FAILURE);
72
73 if (enmTrunkType == kIntNetTrunkType_Invalid)
74 enmTrunkType = kIntNetTrunkType_WhateverNone;
75
76 return IntNetR3IfCtxCreate(&m_hIf, strNetwork.c_str(), enmTrunkType,
77 strTrunk.c_str(), _128K /*cbSend*/, _256K /*cbRecv*/,
78 0 /*fFlags*/);
79}
80
81
82/**
83 * Set promiscuous mode on the interface.
84 */
85int
86IntNetIf::ifSetPromiscuous(bool fPromiscuous)
87{
88 AssertReturn(m_hIf != NULL, VERR_GENERAL_FAILURE);
89
90 return IntNetR3IfCtxSetPromiscuous(m_hIf, fPromiscuous);
91}
92
93
94/**
95 * Obtain R3 send/receive ring buffers for the internal network.
96 * Performs VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS.
97 * @return iprt status code.
98 */
99int
100IntNetIf::ifGetBuf()
101{
102 AssertReturn(m_hIf != NULL, VERR_GENERAL_FAILURE);
103 AssertReturn(m_pIfBuf == NULL, VERR_GENERAL_FAILURE);
104
105 return IntNetR3IfCtxQueryBufferPtr(m_hIf, &m_pIfBuf);
106}
107
108
109/**
110 * Activate the network interface.
111 * Performs VMMR0_DO_INTNET_IF_SET_ACTIVE.
112 * @return iprt status code.
113 */
114int
115IntNetIf::ifActivate()
116{
117 AssertReturn(m_hIf != NULL, VERR_GENERAL_FAILURE);
118 AssertReturn(m_pIfBuf != NULL, VERR_GENERAL_FAILURE);
119
120 return IntNetR3IfCtxSetActive(m_hIf, true /*fActive*/);
121}
122
123
124/**
125 * Wait for input frame(s) to become available in the receive ring
126 * buffer. Performs VMMR0_DO_INTNET_IF_WAIT.
127 *
128 * @param cMillies Timeout, defaults to RT_INDEFINITE_WAIT.
129 * @return iprt status code.
130 */
131int
132IntNetIf::ifWait(uint32_t cMillies)
133{
134 AssertReturn(m_hIf != NULL, VERR_GENERAL_FAILURE);
135
136 return IntNetR3IfWait(m_hIf, cMillies);
137}
138
139
140/**
141 * Abort pending ifWait(), prevent any further attempts to wait.
142 */
143int
144IntNetIf::ifAbort()
145{
146 AssertReturn(m_hIf != NULL, VERR_GENERAL_FAILURE);
147
148 return IntNetR3IfWaitAbort(m_hIf);
149}
150
151
152/**
153 * Process input available in the receive ring buffer.
154 * Feeds input frames to the user callback.
155 * @return iprt status code.
156 */
157int
158IntNetIf::ifProcessInput()
159{
160 AssertReturn(m_hIf != INTNET_HANDLE_INVALID, VERR_GENERAL_FAILURE);
161 AssertReturn(m_pIfBuf != NULL, VERR_GENERAL_FAILURE);
162 AssertReturn(m_pfnInput != NULL, VERR_GENERAL_FAILURE);
163
164 PCINTNETHDR pHdr = IntNetRingGetNextFrameToRead(&m_pIfBuf->Recv);
165 while (pHdr)
166 {
167 const uint8_t u8Type = pHdr->u8Type;
168 void *pvSegFrame;
169 uint32_t cbSegFrame;
170
171 if (u8Type == INTNETHDR_TYPE_FRAME)
172 {
173 pvSegFrame = IntNetHdrGetFramePtr(pHdr, m_pIfBuf);
174 cbSegFrame = pHdr->cbFrame;
175
176 /* pass the frame to the user callback */
177 (*m_pfnInput)(m_pvUser, pvSegFrame, cbSegFrame);
178 }
179 else if (u8Type == INTNETHDR_TYPE_GSO)
180 {
181 size_t cbGso = pHdr->cbFrame;
182 size_t cbFrame = cbGso - sizeof(PDMNETWORKGSO);
183
184 PCPDMNETWORKGSO pcGso = IntNetHdrGetGsoContext(pHdr, m_pIfBuf);
185 if (PDMNetGsoIsValid(pcGso, cbGso, cbFrame))
186 {
187 if (m_pfnInputGSO != NULL)
188 {
189 /* pass the frame to the user GSO input callback if set */
190 (*m_pfnInputGSO)(m_pvUserGSO, pcGso, (uint32_t)cbFrame);
191 }
192 else
193 {
194 const uint32_t cSegs = PDMNetGsoCalcSegmentCount(pcGso, cbFrame);
195 for (uint32_t i = 0; i < cSegs; ++i)
196 {
197 uint8_t abHdrScratch[256];
198 pvSegFrame = PDMNetGsoCarveSegmentQD(pcGso, (uint8_t *)(pcGso + 1), cbFrame,
199 abHdrScratch,
200 i, cSegs,
201 &cbSegFrame);
202
203 /* pass carved frames to the user input callback */
204 (*m_pfnInput)(m_pvUser, pvSegFrame, (uint32_t)cbSegFrame);
205 }
206 }
207 }
208 }
209
210 /* advance to the next input frame */
211 IntNetRingSkipFrame(&m_pIfBuf->Recv);
212 pHdr = IntNetRingGetNextFrameToRead(&m_pIfBuf->Recv);
213 }
214
215 return VINF_SUCCESS;
216}
217
218
219/**
220 * Flush output frames from the send ring buffer to the network.
221 * Performs VMMR0_DO_INTNET_IF_SEND.
222 */
223int
224IntNetIf::ifFlush()
225{
226 AssertReturn(m_hIf != NULL, VERR_GENERAL_FAILURE);
227
228 return IntNetR3IfSend(m_hIf);
229}
230
231
232/**
233 * Close the connection to the network.
234 * Performs VMMR0_DO_INTNET_IF_CLOSE.
235 */
236int
237IntNetIf::ifClose()
238{
239 if (m_hIf == NULL)
240 return VINF_SUCCESS;
241
242 int rc = IntNetR3IfCtxDestroy(m_hIf);
243 m_hIf = NULL;
244 return rc;
245}
246
247
248
249/*
250 * Public high-level user interface.
251 */
252
253/**
254 * Connect to the specified internal network.
255 *
256 * @param strNetwork The name of the network.
257 * @param enmTrunkType The trunk type. Defaults to kIntNetTrunkType_WhateverNone.
258 * @param strTrunk The trunk name, its meaning is specific to the type.
259 * Defaults to an empty string.
260 * @return iprt status code.
261 */
262int
263IntNetIf::init(const RTCString &strNetwork,
264 INTNETTRUNKTYPE enmTrunkType,
265 const RTCString &strTrunk)
266{
267 int rc = ifOpen(strNetwork, enmTrunkType, strTrunk);
268 if (RT_FAILURE(rc))
269 return rc;
270
271 rc = ifGetBuf();
272 if (RT_FAILURE(rc))
273 return rc;
274
275 rc = ifActivate();
276 if (RT_FAILURE(rc))
277 return rc;
278
279 return VINF_SUCCESS;
280}
281
282
283void
284IntNetIf::uninit()
285{
286 ifClose();
287}
288
289
290/**
291 * Set the user input callback function.
292 *
293 * @param pfnInput User input callback.
294 * @param pvUser The user specified argument to the callback.
295 * @return iprt status code.
296 */
297int
298IntNetIf::setInputCallback(PFNINPUT pfnInput, void *pvUser)
299{
300 AssertReturn(pfnInput != NULL, VERR_INVALID_STATE);
301
302 m_pfnInput = pfnInput;
303 m_pvUser = pvUser;
304 return VINF_SUCCESS;
305}
306
307
308/**
309 * Set the user GSO input callback function.
310 *
311 * @param pfnInputGSO User input callback.
312 * @param pvUserGSO The user specified argument to the callback.
313 * @return iprt status code.
314 */
315int
316IntNetIf::setInputGSOCallback(PFNINPUTGSO pfnInputGSO, void *pvUserGSO)
317{
318 AssertReturn(pfnInputGSO != NULL, VERR_INVALID_STATE);
319
320 m_pfnInputGSO = pfnInputGSO;
321 m_pvUserGSO = pvUserGSO;
322 return VINF_SUCCESS;
323}
324
325
326/**
327 * Process incoming packets forever.
328 *
329 * User call this method on its receive thread. The packets are
330 * passed to the user inpiut callbacks. If the GSO input callback is
331 * not registered, a GSO input frame is carved into normal frames and
332 * those frames are passed to the normal input callback.
333 */
334int
335IntNetIf::ifPump()
336{
337 AssertReturn(m_pfnInput != NULL, VERR_GENERAL_FAILURE);
338
339 int rc;
340 for (;;)
341 {
342 rc = ifWait();
343 if (RT_SUCCESS(rc) || rc == VERR_INTERRUPTED || rc == VERR_TIMEOUT)
344 ifProcessInput();
345 else
346 break;
347 }
348 return rc;
349}
350
351
352int
353IntNetIf::getOutputFrame(IntNetIf::Frame &rFrame, size_t cbFrame)
354{
355 int rc;
356
357 rc = IntNetRingAllocateFrame(&m_pIfBuf->Send, (uint32_t)cbFrame,
358 &rFrame.pHdr, &rFrame.pvFrame);
359 return rc;
360}
361
362
363int
364IntNetIf::ifOutput(IntNetIf::Frame &rFrame)
365{
366 int rc;
367
368 IntNetRingCommitFrame(&m_pIfBuf->Send, rFrame.pHdr);
369
370 rc = ifFlush();
371 return rc;
372}
Note: See TracBrowser for help on using the repository browser.

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