VirtualBox

source: vbox/trunk/include/VBox/intnetinline.h@ 28065

Last change on this file since 28065 was 28037, checked in by vboxsync, 15 years ago

DevE1000,GSO: coding.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.9 KB
Line 
1/* $Id: intnetinline.h 28037 2010-04-07 09:56:45Z vboxsync $ */
2/** @file
3 * INTNET - Internal Networking, Inlined Code. (DEV,++)
4 *
5 * This is all inlined because it's too tedious to create 2-3 libraries to
6 * contain it all. Large parts of this header is only accessible from C++
7 * sources because of mixed code and variables.
8 */
9
10/*
11 * Copyright (C) 2006-2010 Sun Microsystems, Inc.
12 *
13 * This file is part of VirtualBox Open Source Edition (OSE), as
14 * available from http://www.virtualbox.org. This file is free software;
15 * you can redistribute it and/or modify it under the terms of the GNU
16 * General Public License (GPL) as published by the Free Software
17 * Foundation, in version 2 as it comes in the "COPYING" file of the
18 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
19 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20 *
21 * The contents of this file may alternatively be used under the terms
22 * of the Common Development and Distribution License Version 1.0
23 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
24 * VirtualBox OSE distribution, in which case the provisions of the
25 * CDDL are applicable instead of those of the GPL.
26 *
27 * You may elect to license modified versions of this file under the
28 * terms and conditions of either the GPL or the CDDL or both.
29 *
30 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
31 * Clara, CA 95054 USA or visit http://www.sun.com if you need
32 * additional information or have any questions.
33 */
34
35#ifndef ___VBox_intnetinline_h
36#define ___VBox_intnetinline_h
37
38#include <VBox/intnet.h>
39#include <iprt/string.h>
40#include <iprt/assert.h>
41#include <iprt/err.h>
42#include <VBox/log.h>
43
44
45
46/**
47 * Valid internal networking frame type.
48 *
49 * @returns true / false.
50 * @param u16Type The frame type to check.
51 */
52DECLINLINE(bool) INETNETIsValidFrameType(uint16_t u16Type)
53{
54 if (RT_LIKELY( u16Type == INTNETHDR_TYPE_FRAME
55 || u16Type == INTNETHDR_TYPE_GSO
56 || u16Type == INTNETHDR_TYPE_PADDING))
57 return true;
58 return false;
59}
60
61
62/**
63 * Partly initializes a scatter / gather buffer, leaving the segments to the
64 * caller.
65 *
66 * @returns Pointer to the start of the frame.
67 * @param pSG Pointer to the scatter / gather structure.
68 * @param cbTotal The total size.
69 * @param cSegs The number of segments.
70 * @param cSegsUsed The number of used segments.
71 */
72DECLINLINE(void) INTNETSgInitTempSegs(PINTNETSG pSG, uint32_t cbTotal, unsigned cSegs, unsigned cSegsUsed)
73{
74 pSG->pvOwnerData = NULL;
75 pSG->pvUserData = NULL;
76 pSG->pvUserData2 = NULL;
77 pSG->cbTotal = cbTotal;
78 pSG->cUsers = 1;
79 pSG->fFlags = INTNETSG_FLAGS_TEMP;
80 pSG->GsoCtx.u8Type = (uint8_t)PDMNETWORKGSOTYPE_INVALID;
81 pSG->GsoCtx.cbHdrs = 0;
82 pSG->GsoCtx.cbMaxSeg= 0;
83 pSG->GsoCtx.offHdr1 = 0;
84 pSG->GsoCtx.offHdr2 = 0;
85 pSG->GsoCtx.au8Unused[0] = 0;
86 pSG->GsoCtx.au8Unused[1] = 0;
87#if ARCH_BITS == 64
88 pSG->uPadding = 0;
89#endif
90 pSG->cSegsAlloc = (uint16_t)cSegs;
91 Assert(pSG->cSegsAlloc == cSegs);
92 pSG->cSegsUsed = (uint16_t)cSegsUsed;
93 Assert(pSG->cSegsUsed == cSegsUsed);
94 Assert(cSegs >= cSegsUsed);
95}
96
97
98/**
99 * Partly initializes a scatter / gather buffer w/ GSO, leaving the segments to
100 * the caller.
101 *
102 * @returns Pointer to the start of the frame.
103 * @param pSG Pointer to the scatter / gather structure.
104 * @param cbTotal The total size.
105 * @param cSegs The number of segments.
106 * @param cSegsUsed The number of used segments.
107 * @param pGso The GSO context.
108 */
109DECLINLINE(void) INTNETSgInitTempSegsGso(PINTNETSG pSG, uint32_t cbTotal, unsigned cSegs,
110 unsigned cSegsUsed, PCPDMNETWORKGSO pGso)
111{
112 pSG->pvOwnerData = NULL;
113 pSG->pvUserData = NULL;
114 pSG->pvUserData2 = NULL;
115 pSG->cbTotal = cbTotal;
116 pSG->cUsers = 1;
117 pSG->fFlags = INTNETSG_FLAGS_TEMP;
118 pSG->GsoCtx.u8Type = pGso->u8Type;
119 pSG->GsoCtx.cbHdrs = pGso->cbHdrs;
120 pSG->GsoCtx.cbMaxSeg= pGso->cbMaxSeg;
121 pSG->GsoCtx.offHdr1 = pGso->offHdr1;
122 pSG->GsoCtx.offHdr2 = pGso->offHdr2;
123 pSG->GsoCtx.au8Unused[0] = 0;
124 pSG->GsoCtx.au8Unused[1] = 0;
125#if ARCH_BITS == 64
126 pSG->uPadding = 0;
127#endif
128 pSG->cSegsAlloc = (uint16_t)cSegs;
129 Assert(pSG->cSegsAlloc == cSegs);
130 pSG->cSegsUsed = (uint16_t)cSegsUsed;
131 Assert(pSG->cSegsUsed == cSegsUsed);
132 Assert(cSegs >= cSegsUsed);
133}
134
135
136
137/**
138 * Initializes a scatter / gather buffer describing a simple linear buffer.
139 *
140 * @returns Pointer to the start of the frame.
141 * @param pSG Pointer to the scatter / gather structure.
142 * @param pvFrame Pointer to the frame
143 * @param cbFrame The size of the frame.
144 */
145DECLINLINE(void) INTNETSgInitTemp(PINTNETSG pSG, void *pvFrame, uint32_t cbFrame)
146{
147 INTNETSgInitTempSegs(pSG, cbFrame, 1, 1);
148 pSG->aSegs[0].Phys = NIL_RTHCPHYS;
149 pSG->aSegs[0].pv = pvFrame;
150 pSG->aSegs[0].cb = cbFrame;
151}
152
153/**
154 * Initializes a scatter / gather buffer describing a simple linear buffer.
155 *
156 * @returns Pointer to the start of the frame.
157 * @param pSG Pointer to the scatter / gather structure.
158 * @param pvFrame Pointer to the frame
159 * @param cbFrame The size of the frame.
160 * @param pGso The GSO context.
161 */
162DECLINLINE(void) INTNETSgInitTempGso(PINTNETSG pSG, void *pvFrame, uint32_t cbFrame, PCPDMNETWORKGSO pGso)
163{
164 INTNETSgInitTempSegsGso(pSG, cbFrame, 1, 1, pGso);
165 pSG->aSegs[0].Phys = NIL_RTHCPHYS;
166 pSG->aSegs[0].pv = pvFrame;
167 pSG->aSegs[0].cb = cbFrame;
168}
169
170#ifdef __cplusplus
171
172/**
173 * Get the amount of space available for writing.
174 *
175 * @returns Number of available bytes.
176 * @param pRingBuf The ring buffer.
177 */
178DECLINLINE(uint32_t) INTNETRingGetWritable(PINTNETRINGBUF pRingBuf)
179{
180 uint32_t const offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX);
181 uint32_t const offWriteInt = ASMAtomicUoReadU32(&pRingBuf->offWriteInt);
182 return offRead <= offWriteInt
183 ? pRingBuf->offEnd - offWriteInt + offRead - pRingBuf->offStart - 1
184 : offRead - offWriteInt - 1;
185}
186
187
188/**
189 * Checks if the ring has more for us to read.
190 *
191 * @returns Number of ready bytes.
192 * @param pRingBuf The ring buffer.
193 */
194DECLINLINE(bool) INTNETRingHasMoreToRead(PINTNETRINGBUF pRingBuf)
195{
196 uint32_t const offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX);
197 uint32_t const offWriteCom = ASMAtomicUoReadU32(&pRingBuf->offWriteCom);
198 return offRead != offWriteCom;
199}
200
201
202/**
203 * Gets the next frame to read.
204 *
205 * @returns Pointer to the next frame. NULL if done.
206 * @param pRingBuf The ring buffer.
207 */
208DECLINLINE(PINTNETHDR) INTNETRingGetNextFrameToRead(PINTNETRINGBUF pRingBuf)
209{
210 uint32_t const offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX);
211 uint32_t const offWriteCom = ASMAtomicUoReadU32(&pRingBuf->offWriteCom);
212 if (offRead == offWriteCom)
213 return NULL;
214 return (PINTNETHDR)((uint8_t *)pRingBuf + offRead);
215}
216
217
218/**
219 * Get the amount of data ready for reading.
220 *
221 * @returns Number of ready bytes.
222 * @param pRingBuf The ring buffer.
223 */
224DECLINLINE(uint32_t) INTNETRingGetReadable(PINTNETRINGBUF pRingBuf)
225{
226 uint32_t const offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX);
227 uint32_t const offWriteCom = ASMAtomicUoReadU32(&pRingBuf->offWriteCom);
228 return offRead <= offWriteCom
229 ? offWriteCom - offRead
230 : pRingBuf->offEnd - offRead + offWriteCom - pRingBuf->offStart;
231}
232
233
234/**
235 * Calculates the pointer to the frame.
236 *
237 * @returns Pointer to the start of the frame.
238 * @param pHdr Pointer to the packet header
239 * @param pBuf The buffer the header is within. Only used in strict builds.
240 */
241DECLINLINE(void *) INTNETHdrGetFramePtr(PCINTNETHDR pHdr, PCINTNETBUF pBuf)
242{
243 uint8_t *pu8 = (uint8_t *)pHdr + pHdr->offFrame;
244#ifdef VBOX_STRICT
245 const uintptr_t off = (uintptr_t)pu8 - (uintptr_t)pBuf;
246 Assert(INETNETIsValidFrameType(pHdr->u16Type));
247 Assert(off < pBuf->cbBuf);
248 Assert(off + pHdr->cbFrame <= pBuf->cbBuf);
249#endif
250 NOREF(pBuf);
251 return pu8;
252}
253
254
255/**
256 * Calculates the pointer to the GSO context.
257 *
258 * ASSUMES the frame is a GSO frame.
259 *
260 * The GSO context is immediately followed by the headers and payload. The size
261 * is INTNETBUF::cbFrame - sizeof(PDMNETWORKGSO).
262 *
263 * @returns Pointer to the GSO context.
264 * @param pHdr Pointer to the packet header
265 * @param pBuf The buffer the header is within. Only used in strict builds.
266 */
267DECLINLINE(PPDMNETWORKGSO) INTNETHdrGetGsoContext(PCINTNETHDR pHdr, PCINTNETBUF pBuf)
268{
269 PPDMNETWORKGSO pGso = (PPDMNETWORKGSO)((uint8_t *)pHdr + pHdr->offFrame);
270#ifdef VBOX_STRICT
271 const uintptr_t off = (uintptr_t)pGso - (uintptr_t)pBuf;
272 Assert(pHdr->u16Type == INTNETHDR_TYPE_GSO);
273 Assert(off < pBuf->cbBuf);
274 Assert(off + pHdr->cbFrame <= pBuf->cbBuf);
275#endif
276 NOREF(pBuf);
277 return pGso;
278}
279
280
281/**
282 * Skips to the next (read) frame in the buffer.
283 *
284 * @param pRingBuf The ring buffer in question.
285 */
286DECLINLINE(void) INTNETRingSkipFrame(PINTNETRINGBUF pRingBuf)
287{
288 uint32_t const offReadOld = ASMAtomicUoReadU32(&pRingBuf->offReadX);
289 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offReadOld);
290 Assert(offReadOld >= pRingBuf->offStart);
291 Assert(offReadOld < pRingBuf->offEnd);
292 Assert(RT_ALIGN_PT(pHdr, INTNETHDR_ALIGNMENT, INTNETHDR *) == pHdr);
293 Assert(INETNETIsValidFrameType(pHdr->u16Type));
294
295 /* skip the frame */
296 uint32_t offReadNew = offReadOld + pHdr->offFrame + pHdr->cbFrame;
297 offReadNew = RT_ALIGN_32(offReadNew, INTNETHDR_ALIGNMENT);
298 Assert(offReadNew <= pRingBuf->offEnd && offReadNew >= pRingBuf->offStart);
299 if (offReadNew >= pRingBuf->offEnd)
300 offReadNew = pRingBuf->offStart;
301 Log2(("INTNETRingSkipFrame: offReadX: %#x -> %#x (1)\n", offReadOld, offReadNew));
302#ifdef INTNET_POISON_READ_FRAMES
303 memset((uint8_t *)pHdr + pHdr->offFrame, 0xfe, RT_ALIGN_32(pHdr->cbFrame, INTNETHDR_ALIGNMENT));
304 memset(pHdr, 0xef, sizeof(*pHdr));
305#endif
306 ASMAtomicWriteU32(&pRingBuf->offReadX, offReadNew);
307}
308
309
310/**
311 * Allocates a frame in the specified ring.
312 *
313 * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW.
314 * @param pRingBuf The ring buffer.
315 * @param cbFrame The frame size.
316 * @param ppHdr Where to return the frame header.
317 * Don't touch this!
318 * @param ppvFrame Where to return the frame pointer.
319 */
320DECLINLINE(int) intnetRingAllocateFrameInternal(PINTNETRINGBUF pRingBuf, uint32_t cbFrame, uint16_t u16Type,
321 PINTNETHDR *ppHdr, void **ppvFrame)
322{
323 /*
324 * Validate input and adjust the input.
325 */
326 INTNETRINGBUF_ASSERT_SANITY(pRingBuf);
327 Assert(cbFrame >= sizeof(RTMAC) * 2);
328
329 const uint32_t cb = RT_ALIGN_32(cbFrame, INTNETHDR_ALIGNMENT);
330 uint32_t offWriteInt = ASMAtomicUoReadU32(&pRingBuf->offWriteInt);
331 uint32_t offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX);
332 if (offRead <= offWriteInt)
333 {
334 /*
335 * Try fit it all before the end of the buffer.
336 */
337 if (pRingBuf->offEnd - offWriteInt >= cb + sizeof(INTNETHDR))
338 {
339 uint32_t offNew = offWriteInt + cb + sizeof(INTNETHDR);
340 if (offNew >= pRingBuf->offEnd)
341 offNew = pRingBuf->offStart;
342 if (RT_UNLIKELY(!ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt)))
343 return VERR_WRONG_ORDER; /* race */
344 Log2(("INTNETRingAllocateFrame: offWriteInt: %#x -> %#x (1) (offRead=%#x)\n", offWriteInt, offNew, offRead));
345
346 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt);
347 pHdr->u16Type = u16Type;
348 pHdr->cbFrame = (uint16_t)cbFrame; Assert(pHdr->cbFrame == cbFrame);
349 pHdr->offFrame = sizeof(INTNETHDR);
350
351 *ppHdr = pHdr;
352 *ppvFrame = pHdr + 1;
353 return VINF_SUCCESS;
354 }
355 /*
356 * Try fit the frame at the start of the buffer.
357 * (The header fits before the end of the buffer because of alignment.)
358 */
359 AssertMsg(pRingBuf->offEnd - offWriteInt >= sizeof(INTNETHDR), ("offEnd=%x offWriteInt=%x\n", pRingBuf->offEnd, offWriteInt));
360 if (offRead - pRingBuf->offStart > cb) /* not >= ! */
361 {
362 uint32_t offNew = pRingBuf->offStart + cb;
363 if (RT_UNLIKELY(!ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt)))
364 return VERR_WRONG_ORDER; /* race */
365 Log2(("INTNETRingAllocateFrame: offWriteInt: %#x -> %#x (2) (offRead=%#x)\n", offWriteInt, offNew, offRead));
366
367 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt);
368 pHdr->u16Type = u16Type;
369 pHdr->cbFrame = (uint16_t)cbFrame; Assert(pHdr->cbFrame == cbFrame);
370 pHdr->offFrame = pRingBuf->offStart - offWriteInt;
371
372 *ppHdr = pHdr;
373 *ppvFrame = (uint8_t *)pRingBuf + pRingBuf->offStart;
374 return VINF_SUCCESS;
375 }
376 }
377 /*
378 * The reader is ahead of the writer, try fit it into that space.
379 */
380 else if (offRead - offWriteInt > cb + sizeof(INTNETHDR)) /* not >= ! */
381 {
382 uint32_t offNew = offWriteInt + cb + sizeof(INTNETHDR);
383 if (RT_UNLIKELY(!ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt)))
384 return VERR_WRONG_ORDER; /* race */
385 Log2(("INTNETRingAllocateFrame: offWriteInt: %#x -> %#x (3) (offRead=%#x)\n", offWriteInt, offNew, offRead));
386
387 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt);
388 pHdr->u16Type = u16Type;
389 pHdr->cbFrame = (uint16_t)cbFrame; Assert(pHdr->cbFrame == cbFrame);
390 pHdr->offFrame = sizeof(INTNETHDR);
391
392 *ppHdr = pHdr;
393 *ppvFrame = pHdr + 1;
394 return VINF_SUCCESS;
395 }
396
397 /* (it didn't fit) */
398 STAM_REL_COUNTER_INC(&pRingBuf->cOverflows);
399 return VERR_BUFFER_OVERFLOW;
400}
401
402
403/**
404 * Allocates a normal frame in the specified ring.
405 *
406 * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW.
407 * @param pRingBuf The ring buffer.
408 * @param cbFrame The frame size.
409 * @param ppHdr Where to return the frame header.
410 * Don't touch this!
411 * @param ppvFrame Where to return the frame pointer.
412 */
413DECLINLINE(int) INTNETRingAllocateFrame(PINTNETRINGBUF pRingBuf, uint32_t cbFrame, PINTNETHDR *ppHdr, void **ppvFrame)
414{
415 return intnetRingAllocateFrameInternal(pRingBuf, cbFrame, INTNETHDR_TYPE_FRAME, ppHdr, ppvFrame);
416}
417
418
419/**
420 * Allocates a GSO frame in the specified ring.
421 *
422 * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW.
423 * @param pRingBuf The ring buffer.
424 * @param cbFrame The frame size.
425 * @param pGso Pointer to the GSO context.
426 * @param ppHdr Where to return the frame header.
427 * Don't touch this!
428 * @param ppvFrame Where to return the frame pointer.
429 */
430DECLINLINE(int) INTNETRingAllocateGsoFrame(PINTNETRINGBUF pRingBuf, uint32_t cbFrame, PCPDMNETWORKGSO pGso,
431 PINTNETHDR *ppHdr, void **ppvFrame)
432{
433 void *pvFrame = NULL; /* gcc maybe used uninitialized */
434 int rc = intnetRingAllocateFrameInternal(pRingBuf, cbFrame + sizeof(*pGso), INTNETHDR_TYPE_GSO, ppHdr, &pvFrame);
435 if (RT_SUCCESS(rc))
436 {
437 PPDMNETWORKGSO pGsoCopy = (PPDMNETWORKGSO)pvFrame;
438 *pGsoCopy = *pGso;
439 *ppvFrame = pGsoCopy + 1;
440 }
441 return rc;
442}
443
444
445/**
446 * Commits a frame.
447 *
448 * Make sure to commit the frames in the order they've been allocated!
449 *
450 * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW.
451 * @param pRingBuf The ring buffer.
452 * @param pHdr The frame header returned by
453 * INTNETRingAllocateFrame.
454 */
455DECLINLINE(void) INTNETRingCommitFrame(PINTNETRINGBUF pRingBuf, PINTNETHDR pHdr)
456{
457 /*
458 * Validate input and commit order.
459 */
460 INTNETRINGBUF_ASSERT_SANITY(pRingBuf);
461 INTNETHDR_ASSERT_SANITY(pHdr, pRingBuf);
462 Assert(pRingBuf->offWriteCom == ((uintptr_t)pHdr - (uintptr_t)pRingBuf));
463
464 /*
465 * Figure out the offWriteCom for this packet and update the ring.
466 */
467 const uint32_t cbFrame = pHdr->cbFrame;
468 const uint32_t cb = RT_ALIGN_32(cbFrame, INTNETHDR_ALIGNMENT);
469 uint32_t offWriteCom = (uint32_t)((uintptr_t)pHdr - (uintptr_t)pRingBuf)
470 + pHdr->offFrame
471 + cb;
472 if (offWriteCom >= pRingBuf->offEnd)
473 {
474 Assert(offWriteCom == pRingBuf->offEnd);
475 offWriteCom = pRingBuf->offStart;
476 }
477 Log2(("INTNETRingCommitFrame: offWriteCom: %#x -> %#x (offRead=%#x)\n", pRingBuf->offWriteCom, offWriteCom, pRingBuf->offReadX));
478 ASMAtomicWriteU32(&pRingBuf->offWriteCom, offWriteCom);
479 STAM_REL_COUNTER_ADD(&pRingBuf->cbStatWritten, cbFrame);
480 STAM_REL_COUNTER_INC(&pRingBuf->cStatFrames);
481}
482
483
484/**
485 * Commits a frame and injects a filler frame if not all of the buffer was used.
486 *
487 * Make sure to commit the frames in the order they've been allocated!
488 *
489 * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW.
490 * @param pRingBuf The ring buffer.
491 * @param pHdr The frame header returned by
492 * INTNETRingAllocateFrame.
493 * @param cbUsed The amount of space actually used.
494 */
495DECLINLINE(void) INTNETRingCommitFrameEx(PINTNETRINGBUF pRingBuf, PINTNETHDR pHdr, size_t cbUsed)
496{
497 /*
498 * Validate input and commit order.
499 */
500 INTNETRINGBUF_ASSERT_SANITY(pRingBuf);
501 INTNETHDR_ASSERT_SANITY(pHdr, pRingBuf);
502 Assert(pRingBuf->offWriteCom == ((uintptr_t)pHdr - (uintptr_t)pRingBuf));
503
504 /*
505 * Calc the new write commit offset.
506 */
507 const uint32_t cbAlignedFrame = RT_ALIGN_32(pHdr->cbFrame, INTNETHDR_ALIGNMENT);
508 const uint32_t cbAlignedUsed = RT_ALIGN_32(cbUsed, INTNETHDR_ALIGNMENT);
509 uint32_t offWriteCom = (uint32_t)((uintptr_t)pHdr - (uintptr_t)pRingBuf)
510 + pHdr->offFrame
511 + cbAlignedFrame;
512 if (offWriteCom >= pRingBuf->offEnd)
513 {
514 Assert(offWriteCom == pRingBuf->offEnd);
515 offWriteCom = pRingBuf->offStart;
516 }
517
518 /*
519 * Insert a dummy frame to pad any unused space.
520 */
521 if (cbAlignedFrame != cbAlignedUsed)
522 {
523 /** @todo Later: Try unallocate the extra memory. */
524 PINTNETHDR pHdrPadding = (PINTNETHDR)((uint8_t *)pHdr + pHdr->offFrame + cbAlignedUsed);
525 pHdrPadding->u16Type = INTNETHDR_TYPE_PADDING;
526 pHdrPadding->cbFrame = (uint16_t)(cbAlignedFrame - cbAlignedUsed - sizeof(INTNETHDR));
527 pHdrPadding->offFrame = sizeof(INTNETHDR);
528 pHdr->cbFrame = (uint16_t)cbUsed;
529 }
530
531 Log2(("INTNETRingCommitFrame: offWriteCom: %#x -> %#x (offRead=%#x)\n", pRingBuf->offWriteCom, offWriteCom, pRingBuf->offReadX));
532 ASMAtomicWriteU32(&pRingBuf->offWriteCom, offWriteCom);
533 STAM_REL_COUNTER_ADD(&pRingBuf->cbStatWritten, cbUsed);
534 STAM_REL_COUNTER_INC(&pRingBuf->cStatFrames);
535}
536
537
538/**
539 * Writes a frame to the specified ring.
540 *
541 * Make sure you don't have any uncommitted frames when calling this function!
542 *
543 * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW.
544 * @param pRingBuf The ring buffer.
545 * @param pvFrame The bits to write.
546 * @param cbFrame How much to write.
547 */
548DECLINLINE(int) INTNETRingWriteFrame(PINTNETRINGBUF pRingBuf, const void *pvFrame, size_t cbFrame)
549{
550 /*
551 * Validate input.
552 */
553 INTNETRINGBUF_ASSERT_SANITY(pRingBuf);
554 Assert(cbFrame >= sizeof(RTMAC) * 2);
555
556 /*
557 * Align the size and read the volatile ring buffer variables.
558 */
559 const uint32_t cb = RT_ALIGN_32(cbFrame, INTNETHDR_ALIGNMENT);
560 uint32_t offWriteInt = ASMAtomicUoReadU32(&pRingBuf->offWriteInt);
561 uint32_t offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX);
562 if (offRead <= offWriteInt)
563 {
564 /*
565 * Try fit it all before the end of the buffer.
566 */
567 if (pRingBuf->offEnd - offWriteInt >= cb + sizeof(INTNETHDR))
568 {
569 uint32_t offNew = offWriteInt + cb + sizeof(INTNETHDR);
570 if (offNew >= pRingBuf->offEnd)
571 offNew = pRingBuf->offStart;
572 if (RT_UNLIKELY(!ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt)))
573 return VERR_WRONG_ORDER; /* race */
574 Log2(("INTNETRingWriteFrame: offWriteInt: %#x -> %#x (1)\n", offWriteInt, offNew));
575
576 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt);
577 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
578 pHdr->cbFrame = (uint16_t)cbFrame; Assert(pHdr->cbFrame == cbFrame);
579 pHdr->offFrame = sizeof(INTNETHDR);
580
581 memcpy(pHdr + 1, pvFrame, cbFrame);
582
583 Log2(("INTNETRingWriteFrame: offWriteCom: %#x -> %#x (1)\n", pRingBuf->offWriteCom, offNew));
584 ASMAtomicWriteU32(&pRingBuf->offWriteCom, offNew);
585 STAM_REL_COUNTER_ADD(&pRingBuf->cbStatWritten, cbFrame);
586 STAM_REL_COUNTER_INC(&pRingBuf->cStatFrames);
587 return VINF_SUCCESS;
588 }
589 /*
590 * Try fit the frame at the start of the buffer.
591 * (The header fits before the end of the buffer because of alignment.)
592 */
593 AssertMsg(pRingBuf->offEnd - offWriteInt >= sizeof(INTNETHDR), ("offEnd=%x offWriteInt=%x\n", pRingBuf->offEnd, offWriteInt));
594 if (offRead - pRingBuf->offStart > cb) /* not >= ! */
595 {
596 uint32_t offNew = pRingBuf->offStart + cb;
597 if (RT_UNLIKELY(!ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt)))
598 return VERR_WRONG_ORDER; /* race */
599 Log2(("INTNETRingWriteFrame: offWriteInt: %#x -> %#x (2)\n", offWriteInt, offNew));
600
601 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt);
602 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
603 pHdr->cbFrame = (uint16_t)cbFrame; Assert(pHdr->cbFrame == cbFrame);
604 pHdr->offFrame = pRingBuf->offStart - offWriteInt;
605
606 memcpy((uint8_t *)pRingBuf + pRingBuf->offStart, pvFrame, cbFrame);
607
608 Log2(("INTNETRingWriteFrame: offWriteCom: %#x -> %#x (2)\n", pRingBuf->offWriteCom, offNew));
609 ASMAtomicWriteU32(&pRingBuf->offWriteCom, offNew);
610 STAM_REL_COUNTER_ADD(&pRingBuf->cbStatWritten, cbFrame);
611 STAM_REL_COUNTER_INC(&pRingBuf->cStatFrames);
612 return VINF_SUCCESS;
613 }
614 }
615 /*
616 * The reader is ahead of the writer, try fit it into that space.
617 */
618 else if (offRead - offWriteInt > cb + sizeof(INTNETHDR)) /* not >= ! */
619 {
620 uint32_t offNew = offWriteInt + cb + sizeof(INTNETHDR);
621 if (RT_UNLIKELY(!ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt)))
622 return VERR_WRONG_ORDER; /* race */
623 Log2(("INTNETRingWriteFrame: offWriteInt: %#x -> %#x (3)\n", offWriteInt, offNew));
624
625 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt);
626 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
627 pHdr->cbFrame = (uint16_t)cbFrame; Assert(pHdr->cbFrame == cbFrame);
628 pHdr->offFrame = sizeof(INTNETHDR);
629
630 memcpy(pHdr + 1, pvFrame, cbFrame);
631
632 Log2(("INTNETRingWriteFrame: offWriteCom: %#x -> %#x (3)\n", pRingBuf->offWriteCom, offNew));
633 ASMAtomicWriteU32(&pRingBuf->offWriteCom, offNew);
634 STAM_REL_COUNTER_ADD(&pRingBuf->cbStatWritten, cbFrame);
635 STAM_REL_COUNTER_INC(&pRingBuf->cStatFrames);
636 return VINF_SUCCESS;
637 }
638
639 /* (it didn't fit) */
640 STAM_REL_COUNTER_INC(&pRingBuf->cOverflows);
641 return VERR_BUFFER_OVERFLOW;
642}
643
644
645/**
646 * Reads the next frame in the buffer and moves the read cursor past it.
647 *
648 * @returns Size of the frame in bytes. 0 is returned if nothing in the buffer.
649 * @param pRingBuff The ring buffer to read from.
650 * @param pvFrameDst Where to put the frame. The caller is responsible for
651 * ensuring that there is sufficient space for the frame.
652 *
653 * @deprecated Bad interface, do NOT use it! Only for tstIntNetR0.
654 */
655DECLINLINE(uint32_t) INTNETRingReadAndSkipFrame(PINTNETRINGBUF pRingBuf, void *pvFrameDst)
656{
657 INTNETRINGBUF_ASSERT_SANITY(pRingBuf);
658
659 uint32_t offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX);
660 uint32_t const offWriteCom = ASMAtomicUoReadU32(&pRingBuf->offWriteCom);
661 if (offRead == offWriteCom)
662 return 0;
663
664 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offRead);
665 INTNETHDR_ASSERT_SANITY(pHdr, pRingBuf);
666
667 uint32_t const cbFrame = pHdr->cbFrame;
668 int32_t const offFrame = pHdr->offFrame;
669 const void *pvFrameSrc = (uint8_t *)pHdr + offFrame;
670 memcpy(pvFrameDst, pvFrameSrc, cbFrame);
671#ifdef INTNET_POISON_READ_FRAMES
672 memset((void *)pvFrameSrc, 0xfe, RT_ALIGN_32(cbFrame, INTNETHDR_ALIGNMENT));
673 memset(pHdr, 0xef, sizeof(*pHdr));
674#endif
675
676 /* skip the frame */
677 offRead += offFrame + cbFrame;
678 offRead = RT_ALIGN_32(offRead, INTNETHDR_ALIGNMENT);
679 Assert(offRead <= pRingBuf->offEnd && offRead >= pRingBuf->offStart);
680 if (offRead >= pRingBuf->offEnd)
681 offRead = pRingBuf->offStart;
682 ASMAtomicWriteU32(&pRingBuf->offReadX, offRead);
683 return cbFrame;
684}
685
686
687/**
688 * Initializes a buffer structure.
689 *
690 * @param pIntBuf The internal networking interface buffer. This
691 * expected to be cleared prior to calling this
692 * function.
693 * @param cbBuf The size of the whole buffer.
694 * @param cbRecv The receive size.
695 * @param cbSend The send size.
696 */
697DECLINLINE(void) INTNETBufInit(PINTNETBUF pIntBuf, uint32_t cbBuf, uint32_t cbRecv, uint32_t cbSend)
698{
699 AssertCompileSizeAlignment(INTNETBUF, INTNETHDR_ALIGNMENT);
700 AssertCompileSizeAlignment(INTNETBUF, INTNETRINGBUF_ALIGNMENT);
701 Assert(cbBuf >= sizeof(INTNETBUF) + cbRecv + cbSend);
702 Assert(RT_ALIGN_32(cbRecv, INTNETRINGBUF_ALIGNMENT) == cbRecv);
703 Assert(RT_ALIGN_32(cbSend, INTNETRINGBUF_ALIGNMENT) == cbSend);
704 Assert(ASMMemIsAll8(pIntBuf, cbBuf, '\0') == NULL);
705
706 pIntBuf->u32Magic = INTNETBUF_MAGIC;
707 pIntBuf->cbBuf = cbBuf;
708 pIntBuf->cbRecv = cbRecv;
709 pIntBuf->cbSend = cbSend;
710
711 /* receive ring buffer. */
712 uint32_t offBuf = RT_ALIGN_32(sizeof(INTNETBUF), INTNETRINGBUF_ALIGNMENT) - RT_OFFSETOF(INTNETBUF, Recv);
713 pIntBuf->Recv.offStart = offBuf;
714 pIntBuf->Recv.offReadX = offBuf;
715 pIntBuf->Recv.offWriteInt = offBuf;
716 pIntBuf->Recv.offWriteCom = offBuf;
717 pIntBuf->Recv.offEnd = offBuf + cbRecv;
718
719 /* send ring buffer. */
720 offBuf += cbRecv + RT_OFFSETOF(INTNETBUF, Recv) - RT_OFFSETOF(INTNETBUF, Send);
721 pIntBuf->Send.offStart = offBuf;
722 pIntBuf->Send.offReadX = offBuf;
723 pIntBuf->Send.offWriteCom = offBuf;
724 pIntBuf->Send.offWriteInt = offBuf;
725 pIntBuf->Send.offEnd = offBuf + cbSend;
726 Assert(cbBuf >= offBuf + cbSend);
727}
728
729#endif /* __cplusplus */
730
731#endif
732
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