VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/mbuf.c@ 28915

Last change on this file since 28915 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.7 KB
Line 
1/* $Id: mbuf.c 28800 2010-04-27 08:22:32Z vboxsync $ */
2/** @file
3 * NAT - mbuf handling.
4 */
5
6/*
7 * Copyright (C) 2006-2010 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 * This code is based on:
20 *
21 * Copyright (c) 1995 Danny Gasparovski
22 *
23 * Please read the file COPYRIGHT for the
24 * terms and conditions of the copyright.
25 */
26
27/*
28 * mbuf's in SLiRP are much simpler than the real mbufs in
29 * FreeBSD. They are fixed size, determined by the MTU,
30 * so that one whole packet can fit. Mbuf's cannot be
31 * chained together. If there's more data than the mbuf
32 * could hold, an external malloced buffer is pointed to
33 * by m_ext (and the data pointers) and M_EXT is set in
34 * the flags
35 */
36#include <slirp.h>
37
38#define MBUF_ZONE_SIZE 100
39static int mbuf_zone_init(PNATState pData)
40{
41 struct mbuf_zone *mzone;
42 int i;
43 struct mbuf *m;
44 uint8_t *zone = RTMemAlloc(msize * MBUF_ZONE_SIZE);
45 if (zone == NULL)
46 {
47 LogRel(("NAT: can't allocate new zone\n"));
48 return -1;
49 }
50 mzone = RTMemAllocZ(sizeof (struct mbuf_zone));
51 if (mzone == NULL)
52 {
53 RTMemFree(zone);
54 LogRel(("NAT: can't allocate zone descriptor\n"));
55 return -1;
56 }
57
58 for (i = 0; i < MBUF_ZONE_SIZE; ++i)
59 {
60 m = (struct mbuf *)((char *)zone + i*msize);
61 memset(m, 0, sizeof(struct mbuf));
62#ifdef M_BUF_DEBUG
63 m->m_hdr.mh_id = pData->mbuf_zone_count * MBUF_ZONE_SIZE + i;
64#endif
65 insque(pData, m, &m_freelist);
66 }
67 mzone->mbuf_zone_base_addr = zone;
68 LIST_INSERT_HEAD(&pData->mbuf_zone_head, mzone, list);
69 pData->mbuf_zone_count++;
70 pData->mbuf_water_line_limit = pData->mbuf_zone_count * MBUF_ZONE_SIZE;
71 return 0;
72}
73
74void m_fini(PNATState pData)
75{
76 struct mbuf_zone *mz;
77 struct mbuf *m;
78 int i;
79 void *zone;
80 while(!LIST_EMPTY(&pData->mbuf_zone_head))
81 {
82 mz = LIST_FIRST(&pData->mbuf_zone_head);
83 zone = mz->mbuf_zone_base_addr;
84 for (i = 0; i < MBUF_ZONE_SIZE; ++i)
85 {
86 m = (struct mbuf *)((char *)zone + i*msize);
87 if ( (m->m_flags & M_EXT)
88 && m->m_ext != NULL)
89 RTMemFree(m->m_ext);
90 }
91 RTMemFree(zone);
92 LIST_REMOVE(mz, list);
93 RTMemFree(mz);
94 }
95}
96
97void
98m_init(PNATState pData)
99{
100 int rc = 0;
101 m_freelist.m_next = m_freelist.m_prev = &m_freelist;
102 m_usedlist.m_next = m_usedlist.m_prev = &m_usedlist;
103 mbuf_alloced = 0;
104 msize_init(pData);
105#if 1
106 rc = RTCritSectInit(&pData->cs_mbuf_zone);
107 AssertRC(rc);
108 rc = mbuf_zone_init(pData);
109 Assert((rc == 0));
110#endif
111}
112
113void
114msize_init(PNATState pData)
115{
116 /*
117 * Find a nice value for msize
118 */
119 msize = (if_mtu>if_mru ? if_mtu : if_mru)
120 + sizeof(struct m_hdr) + sizeof(void *) /*pointer to the backstore*/
121 + if_maxlinkhdr ;
122}
123#ifdef m_get
124# undef m_get
125#endif
126
127#ifdef m_free
128# undef m_free
129#endif
130/*
131 * Get an mbuf from the free list, if there are none
132 * malloc one
133 *
134 * Because fragmentation can occur if we alloc new mbufs and
135 * free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE,
136 * which tells m_free to actually free() it
137 */
138struct mbuf *
139m_get(PNATState pData)
140{
141 register struct mbuf *m;
142 int flags = 0;
143 int rc = 0;
144
145 DEBUG_CALL("m_get");
146
147 rc = RTCritSectEnter(&pData->cs_mbuf_zone);
148 AssertRC(rc);
149
150recheck_zone:
151 if (m_freelist.m_next == &m_freelist)
152 {
153#if 1
154 rc = mbuf_zone_init(pData);
155 if (rc == 0)
156 goto recheck_zone;
157 AssertMsgFailed(("No mbufs on free list\n"));
158 m = NULL;
159 goto end_error;
160#else
161 m = (struct mbuf *)RTMemAlloc(msize);
162 if (m == NULL)
163 goto end_error;
164 mbuf_alloced++;
165 if (mbuf_alloced > mbuf_thresh)
166 flags = M_DOFREE;
167 if (mbuf_alloced > mbuf_max)
168 mbuf_max = mbuf_alloced;
169#endif
170 }
171 else
172 {
173 m = m_freelist.m_next;
174 remque(pData, m);
175 }
176
177 STAM_COUNTER_INC(&pData->StatMBufAllocation);
178 /* Insert it in the used list */
179 mbuf_alloced++;
180#if 0
181 if (mbuf_alloced >= MBUF_ZONE_SIZE/2)
182 {
183 pData->fmbuf_water_line = 1;
184 }
185#endif
186 insque(pData, m, &m_usedlist);
187 m->m_flags = (flags | M_USEDLIST);
188
189 /* Initialise it */
190 m->m_size = msize - sizeof(struct m_hdr);
191 m->m_data = m->m_dat;
192 m->m_len = 0;
193 m->m_nextpkt = 0;
194 m->m_prevpkt = 0;
195 m->m_la = NULL;
196 memset(m->m_data, 0, if_maxlinkhdr); /*initialization of ether area */
197
198end_error:
199 DEBUG_ARG("m = %lx", (long )m);
200 rc = RTCritSectLeave(&pData->cs_mbuf_zone);
201 AssertRC(rc);
202 return m;
203}
204
205void
206m_free(PNATState pData, struct mbuf *m)
207{
208 int rc;
209 DEBUG_CALL("m_free");
210 DEBUG_ARG("m = %lx", (long )m);
211
212 rc = RTCritSectEnter(&pData->cs_mbuf_zone);
213 AssertRC(rc);
214 mbuf_alloced--;
215 if(m)
216 {
217 /* Remove from m_usedlist */
218 if (m->m_flags & M_USEDLIST)
219 remque(pData, m);
220
221 /* If it's M_EXT, free() it */
222 if (m->m_flags & M_EXT)
223 RTMemFree(m->m_ext);
224
225 /*
226 * Either free() it or put it on the free list
227 */
228 if (m->m_flags & M_DOFREE)
229 {
230#if 1
231 if ((m->m_flags & M_EXT) == 0)
232 memset(m->m_dat, 0, if_mtu);
233 insque(pData, m, &m_freelist);
234 m->m_flags = M_FREELIST; /* Clobber other flags */
235#else
236 RTMemFree(m);
237#endif
238 mbuf_alloced--;
239 }
240 else if ((m->m_flags & M_FREELIST) == 0)
241 {
242 insque(pData, m,&m_freelist);
243 m->m_flags = M_FREELIST; /* Clobber other flags */
244 }
245 STAM_COUNTER_INC(&pData->StatMBufAllocation);
246 } /* if(m) */
247 rc = RTCritSectLeave(&pData->cs_mbuf_zone);
248 AssertRC(rc);
249}
250
251/* update macros for m_get/m_free*/
252#undef m_get
253#undef m_free
254#include "mbuf.h"
255
256/*
257 * Copy data from one mbuf to the end of
258 * the other.. if result is too big for one mbuf, malloc()
259 * an M_EXT data segment
260 */
261void
262m_cat(PNATState pData, register struct mbuf *m, register struct mbuf *n)
263{
264 /*
265 * If there's no room, realloc
266 */
267 if (M_FREEROOM(m) < n->m_len)
268 m_inc(m,m->m_size+MINCSIZE);
269
270 memcpy(m->m_data+m->m_len, n->m_data, n->m_len);
271 m->m_len += n->m_len;
272
273 m_free(pData, n);
274}
275
276
277/* make m size bytes large */
278void
279m_inc(struct mbuf *m, int size)
280{
281 int datasize;
282
283 /* some compiles throw up on gotos. This one we can fake. */
284 if (m->m_size > size)
285 return;
286
287 if (m->m_flags & M_EXT)
288 {
289 void *pvNew;
290 datasize = m->m_data - m->m_ext;
291 pvNew = (char *)RTMemRealloc(m->m_ext, size);
292 if (pvNew)
293 return; /** @todo better error reporting. */
294 m->m_ext = (char *)pvNew;
295 m->m_data = m->m_ext + datasize;
296 }
297 else
298 {
299 char *dat;
300 datasize = m->m_data - m->m_dat;
301 dat = (char *)RTMemAlloc(size);
302 if (!dat)
303 return; /** @todo better error reporting. */
304 memcpy(dat, m->m_dat, m->m_size);
305
306 m->m_ext = dat;
307 m->m_data = m->m_ext + datasize;
308 m->m_flags |= M_EXT;
309 }
310
311 m->m_size = size;
312}
313
314
315void
316m_adj(struct mbuf *m, int len)
317{
318 if (m == NULL)
319 return;
320 if (len >= 0)
321 {
322 /* Trim from head */
323 m->m_data += len;
324 m->m_len -= len;
325 }
326 else
327 {
328 /* Trim from tail */
329 len = -len;
330 m->m_len -= len;
331 }
332 Assert(m->m_len >= 0);
333}
334
335
336/*
337 * Copy len bytes from m, starting off bytes into n
338 */
339int
340m_copy(struct mbuf *n, struct mbuf *m, int off, int len)
341{
342 if (len > M_FREEROOM(n))
343 return -1;
344
345 memcpy((n->m_data + n->m_len), (m->m_data + off), len);
346 n->m_len += len;
347 return 0;
348}
349
350
351/*
352 * Given a pointer into an mbuf, return the mbuf
353 * XXX This is a kludge, I should eliminate the need for it
354 * Fortunately, it's not used often
355 */
356struct mbuf *
357dtom(PNATState pData, void *dat)
358{
359 struct mbuf *m;
360
361 DEBUG_CALL("dtom");
362 DEBUG_ARG("dat = %lx", (long )dat);
363
364 /* bug corrected for M_EXT buffers */
365 for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next)
366 {
367 if (m->m_flags & M_EXT)
368 {
369 if ( (char *)dat >= m->m_ext
370 && (char *)dat < (m->m_ext + m->m_size))
371 return m;
372 }
373 else
374 {
375 if ( (char *)dat >= m->m_dat
376 && (char *)dat < (m->m_dat + m->m_size))
377 return m;
378 }
379 }
380
381 DEBUG_ERROR((dfd, "dtom failed"));
382
383 return (struct mbuf *)0;
384}
385
386#ifndef VBOX_WITH_SLIRP_BSD_MBUF
387
388/**
389 * Interface that DrvNAT.cpp uses for allocating a buffer.
390 *
391 * @returns Opaque m_buf pointer.
392 *
393 * @param pData The NAT state.
394 * @param cbMin The minimum buffer size.
395 * @param ppvBuf Where to return the pointer to the start of the data
396 * buffer.
397 * @param pcbBuf Where to return the actual buffer size.
398 */
399struct mbuf *slirp_ext_m_get(PNATState pData, size_t cbMin, void **ppvBuf, size_t *pcbBuf)
400{
401 struct mbuf *m = m_get(pData);
402 if (!m)
403 return NULL;
404 if (cbMin > M_FREEROOM(m))
405 {
406 m_inc(m, cbMin);
407 if (RT_UNLIKELY(cbMin > M_FREEROOM(m)))
408 {
409 m_free(pData, m);
410 return NULL;
411 }
412 }
413
414 *ppvBuf = mtod(m, void *);
415 *pcbBuf = M_FREEROOM(m);
416 return m;
417}
418
419void slirp_ext_m_free(PNATState pData, struct mbuf *m)
420{
421 m_free(pData, m);
422}
423
424#endif /* VBOX_WITH_SLIRP_BSD_MBUF */
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