VirtualBox

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

Last change on this file since 28739 was 28449, checked in by vboxsync, 15 years ago

NAT: slirp file headers

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