VirtualBox

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

最後變更 在這個檔案從26594是 26574,由 vboxsync 提交於 15 年 前

Networking: Preparing to make the driver return a send buffer to the device emulation.

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

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