VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/misc.c@ 40204

Last change on this file since 40204 was 40204, checked in by vboxsync, 13 years ago

NAT: logging: VBOX_NAT_MEM_DEBUG control adding NAT's "uma" emulation operation into the log.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.4 KB
Line 
1/* $Id: misc.c 40204 2012-02-22 02:02:10Z vboxsync $ */
2/** @file
3 * NAT - helpers.
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#define WANT_SYS_IOCTL_H
28#include <slirp.h>
29#include "zone.h"
30
31#ifndef HAVE_INET_ATON
32int
33inet_aton(const char *cp, struct in_addr *ia)
34{
35 u_int32_t addr = inet_addr(cp);
36 if (addr == 0xffffffff)
37 return 0;
38 ia->s_addr = addr;
39 return 1;
40}
41#endif
42
43/*
44 * Get our IP address and put it in our_addr
45 */
46void
47getouraddr(PNATState pData)
48{
49 our_addr.s_addr = loopback_addr.s_addr;
50}
51
52struct quehead
53{
54 struct quehead *qh_link;
55 struct quehead *qh_rlink;
56};
57
58void
59insque(PNATState pData, void *a, void *b)
60{
61 register struct quehead *element = (struct quehead *) a;
62 register struct quehead *head = (struct quehead *) b;
63 NOREF(pData);
64 element->qh_link = head->qh_link;
65 head->qh_link = (struct quehead *)element;
66 element->qh_rlink = (struct quehead *)head;
67 ((struct quehead *)(element->qh_link))->qh_rlink = (struct quehead *)element;
68}
69
70void
71remque(PNATState pData, void *a)
72{
73 register struct quehead *element = (struct quehead *) a;
74 NOREF(pData);
75 ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink;
76 ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link;
77 element->qh_rlink = NULL;
78 /* element->qh_link = NULL; TCP FIN1 crashes if you do this. Why ? */
79}
80
81
82/*
83 * Set fd blocking and non-blocking
84 */
85void
86fd_nonblock(int fd)
87{
88#ifdef FIONBIO
89 int opt = 1;
90
91 ioctlsocket(fd, FIONBIO, &opt);
92#else
93 int opt;
94
95 opt = fcntl(fd, F_GETFL, 0);
96 opt |= O_NONBLOCK;
97 fcntl(fd, F_SETFL, opt);
98#endif
99}
100
101#if !defined(VBOX_NAT_MEM_DEBUG) && defined(LOG_ENABLED)
102# undef LogFlowFunc
103# define LogFlowFunc(x)
104
105# undef LogFlowFuncEnter
106# define LogFlowFuncEnter()
107
108# undef LogFlowFuncLeave
109# define LogFlowFuncLeave()
110
111# undef Log2
112# define Log2(x)
113#else
114# define NAT_MEM_LOG_ENABLED
115#endif
116
117
118/**
119 * Called when memory becomes available, works pfnXmitPending.
120 *
121 * @note This will LEAVE the critical section of the zone and RE-ENTER it
122 * again. Changes to the zone data should be expected across calls to
123 * this function!
124 *
125 * @param zone The zone.
126 */
127DECLINLINE(void) slirp_zone_check_and_send_pending(uma_zone_t zone)
128{
129 LogFlowFunc(("ENTER: zone:%R[mzone]\n", zone));
130 if ( zone->fDoXmitPending
131 && zone->master_zone == NULL)
132 {
133 int rc2;
134 zone->fDoXmitPending = false;
135 rc2 = RTCritSectLeave(&zone->csZone); AssertRC(rc2);
136
137 slirp_output_pending(zone->pData->pvUser);
138
139 rc2 = RTCritSectEnter(&zone->csZone); AssertRC(rc2);
140 }
141 LogFlowFuncLeave();
142}
143
144static void *slirp_uma_alloc(uma_zone_t zone,
145 int size, uint8_t *pflags, int fWait)
146{
147 struct item *it;
148 uint8_t *sub_area;
149 void *ret = NULL;
150 int rc;
151
152 LogFlowFunc(("ENTER: %R[mzone], size:%d, pflags:%p, %RTbool\n", zone, size, pflags, fWait));
153#ifndef NAT_MEM_LOG_ENABLED
154 NOREF(size);
155 NOREF(pflags);
156 NOREF(fWait);
157#endif
158 RTCritSectEnter(&zone->csZone);
159 for (;;)
160 {
161 if (!LIST_EMPTY(&zone->free_items))
162 {
163 it = LIST_FIRST(&zone->free_items);
164 Assert(it->magic == ITEM_MAGIC);
165 rc = 0;
166 if (zone->pfInit)
167 rc = zone->pfInit(zone->pData, (void *)&it[1], zone->size, M_DONTWAIT);
168 if (rc == 0)
169 {
170 zone->cur_items++;
171 LIST_REMOVE(it, list);
172 LIST_INSERT_HEAD(&zone->used_items, it, list);
173 slirp_zone_check_and_send_pending(zone); /* may exit+enter the cs! */
174 ret = (void *)&it[1];
175 }
176 else
177 {
178 AssertMsgFailed(("NAT: item initialization failed for zone %s\n", zone->name));
179 ret = NULL;
180 }
181 break;
182 }
183
184 if (!zone->master_zone)
185 {
186 /* We're on the master zone and we can't allocate more. */
187 Log2(("NAT: no room on %s zone\n", zone->name));
188 /* AssertMsgFailed(("NAT: OOM!")); */
189 zone->fDoXmitPending = true;
190 break;
191 }
192
193 /* we're on a sub-zone, we need get a chunk from the master zone and split
194 * it into sub-zone conforming chunks.
195 */
196 sub_area = slirp_uma_alloc(zone->master_zone, zone->master_zone->size, NULL, 0);
197 if (!sub_area)
198 {
199 /* No room on master */
200 Log2(("NAT: no room on %s zone for %s zone\n", zone->master_zone->name, zone->name));
201 break;
202 }
203 zone->max_items++;
204 it = &((struct item *)sub_area)[-1];
205 /* It's the chunk descriptor of the master zone, we should remove it
206 * from the master list first.
207 */
208 Assert((it->zone && it->zone->magic == ZONE_MAGIC));
209 RTCritSectEnter(&it->zone->csZone);
210 /** @todo should we alter count of master counters? */
211 LIST_REMOVE(it, list);
212 RTCritSectLeave(&it->zone->csZone);
213
214 /** @todo '+ zone->size' should be depend on flag */
215 memset(it, 0, sizeof(struct item));
216 it->zone = zone;
217 it->magic = ITEM_MAGIC;
218 LIST_INSERT_HEAD(&zone->free_items, it, list);
219 if (zone->cur_items >= zone->max_items)
220 LogRel(("NAT: zone(%s) has reached it maximum\n", zone->name));
221 }
222 RTCritSectLeave(&zone->csZone);
223 LogFlowFunc(("LEAVE: %p\n", ret));
224 return ret;
225}
226
227static void slirp_uma_free(void *item, int size, uint8_t flags)
228{
229 struct item *it;
230 uma_zone_t zone;
231#ifndef NAT_MEM_LOG_ENABLED
232 NOREF(size);
233 NOREF(flags);
234#endif
235
236 Assert(item);
237 it = &((struct item *)item)[-1];
238 LogFlowFunc(("ENTER: item:%p(%R[mzoneitem]), size:%d, flags:%RX8\n", item, it, size, flags));
239 Assert(it->magic == ITEM_MAGIC);
240 zone = it->zone;
241 /* check border magic */
242 Assert((*(uint32_t *)(((uint8_t *)&it[1]) + zone->size) == 0xabadbabe));
243
244 RTCritSectEnter(&zone->csZone);
245 Assert(zone->magic == ZONE_MAGIC);
246 LIST_REMOVE(it, list);
247 if (zone->pfFini)
248 {
249 zone->pfFini(zone->pData, item, zone->size);
250 }
251 if (zone->pfDtor)
252 {
253 zone->pfDtor(zone->pData, item, zone->size, NULL);
254 }
255 LIST_INSERT_HEAD(&zone->free_items, it, list);
256 zone->cur_items--;
257 slirp_zone_check_and_send_pending(zone); /* may exit+enter the cs! */
258 RTCritSectLeave(&zone->csZone);
259 LogFlowFuncLeave();
260}
261
262uma_zone_t uma_zcreate(PNATState pData, char *name, size_t size,
263 ctor_t ctor, dtor_t dtor, zinit_t init, zfini_t fini, int flags1, int flags2)
264{
265 uma_zone_t zone = NULL;
266#ifndef NAT_MEM_LOG_ENABLED
267 NOREF(flags1);
268 NOREF(flags2);
269#endif
270 LogFlowFunc(("ENTER: name:%s size:%d, ctor:%p, dtor:%p, init:%p, fini:%p, flags1:%RX32, flags2:%RX32\n",
271 name, ctor, dtor, init, fini, flags1, flags2));
272 zone = RTMemAllocZ(sizeof(struct uma_zone));
273 Assert((pData));
274 zone->magic = ZONE_MAGIC;
275 zone->pData = pData;
276 zone->name = name;
277 zone->size = size;
278 zone->pfCtor = ctor;
279 zone->pfDtor = dtor;
280 zone->pfInit = init;
281 zone->pfFini = fini;
282 zone->pfAlloc = slirp_uma_alloc;
283 zone->pfFree = slirp_uma_free;
284 RTCritSectInit(&zone->csZone);
285 LogFlowFunc(("LEAVE: %R[mzone]\n", zone));
286 return zone;
287
288}
289uma_zone_t uma_zsecond_create(char *name, ctor_t ctor,
290 dtor_t dtor, zinit_t init, zfini_t fini, uma_zone_t master)
291{
292 uma_zone_t zone;
293 Assert(master);
294 LogFlowFunc(("ENTER: name:%s ctor:%p, dtor:%p, init:%p, fini:%p, master:%R[mzone]\n",
295 name, ctor, dtor, init, fini, master));
296 zone = RTMemAllocZ(sizeof(struct uma_zone));
297 if (zone == NULL)
298 {
299 LogFlowFunc(("LEAVE: %R[mzone]\n", NULL));
300 return NULL;
301 }
302
303 Assert((master && master->pData));
304 zone->magic = ZONE_MAGIC;
305 zone->pData = master->pData;
306 zone->name = name;
307 zone->pfCtor = ctor;
308 zone->pfDtor = dtor;
309 zone->pfInit = init;
310 zone->pfFini = fini;
311 zone->pfAlloc = slirp_uma_alloc;
312 zone->pfFree = slirp_uma_free;
313 zone->size = master->size;
314 zone->master_zone = master;
315 RTCritSectInit(&zone->csZone);
316 LogFlowFunc(("LEAVE: %R[mzone]\n", zone));
317 return zone;
318}
319
320void uma_zone_set_max(uma_zone_t zone, int max)
321{
322 int i = 0;
323 struct item *it;
324 LogFlowFunc(("ENTER: zone:%R[mzone], max:%d\n", zone, max));
325 zone->max_items = max;
326 zone->area = RTMemAllocZ(max * (sizeof(struct item) + zone->size + sizeof(uint32_t)));
327 for (; i < max; ++i)
328 {
329 it = (struct item *)(((uint8_t *)zone->area) + i*(sizeof(struct item) + zone->size + sizeof(uint32_t)));
330 it->magic = ITEM_MAGIC;
331 it->zone = zone;
332 *(uint32_t *)(((uint8_t *)&it[1]) + zone->size) = 0xabadbabe;
333 LIST_INSERT_HEAD(&zone->free_items, it, list);
334 }
335 LogFlowFuncLeave();
336}
337
338void uma_zone_set_allocf(uma_zone_t zone, uma_alloc_t pfAlloc)
339{
340 LogFlowFunc(("ENTER: zone:%R[mzone], pfAlloc:%Rfn\n", zone, pfAlloc));
341 zone->pfAlloc = pfAlloc;
342 LogFlowFuncLeave();
343}
344
345void uma_zone_set_freef(uma_zone_t zone, uma_free_t pfFree)
346{
347 LogFlowFunc(("ENTER: zone:%R[mzone], pfAlloc:%Rfn\n", zone, pfFree));
348 zone->pfFree = pfFree;
349 LogFlowFuncLeave();
350}
351
352uint32_t *uma_find_refcnt(uma_zone_t zone, void *mem)
353{
354 /** @todo (vvl) this function supposed to work with special zone storing
355 reference counters */
356 struct item *it = NULL;
357#ifndef NAT_MEM_LOG_ENABLED
358 NOREF(zone);
359#endif
360 LogFlowFunc(("ENTER: zone:%R[mzone], mem:%p\n", zone, mem));
361 it = (struct item *)mem; /* 1st element */
362 Assert(mem != NULL);
363 Assert(zone->magic == ZONE_MAGIC);
364 /* for returning pointer to counter we need get 0 elemnt */
365 Assert(it[-1].magic == ITEM_MAGIC);
366 LogFlowFunc(("LEAVE: %p\n", &it[-1].ref_count));
367 return &it[-1].ref_count;
368}
369
370void *uma_zalloc_arg(uma_zone_t zone, void *args, int how)
371{
372 void *mem;
373#ifndef NAT_MEM_LOG_ENABLED
374 NOREF(how);
375#endif
376 Assert(zone->magic == ZONE_MAGIC);
377 LogFlowFunc(("ENTER: zone:%R[mzone], args:%p, how:%RX32\n", zone, args, how));
378 if (zone->pfAlloc == NULL)
379 {
380 LogFlowFunc(("LEAVE: NULL\n"));
381 return NULL;
382 }
383 RTCritSectEnter(&zone->csZone);
384 mem = zone->pfAlloc(zone, zone->size, NULL, 0);
385 if (mem != NULL)
386 {
387 if (zone->pfCtor)
388 zone->pfCtor(zone->pData, mem, zone->size, args, M_DONTWAIT);
389 }
390 RTCritSectLeave(&zone->csZone);
391 LogFlowFunc(("LEAVE: %p\n", mem));
392 return mem;
393}
394
395void uma_zfree(uma_zone_t zone, void *item)
396{
397 LogFlowFunc(("ENTER: zone:%R[mzone], item:%p\n", zone, item));
398 uma_zfree_arg(zone, item, NULL);
399 LogFlowFuncLeave();
400}
401
402void uma_zfree_arg(uma_zone_t zone, void *mem, void *flags)
403{
404 struct item *it;
405 Assert(zone->magic == ZONE_MAGIC);
406 Assert((zone->pfFree));
407 Assert((mem));
408 LogFlowFunc(("ENTER: zone:%R[mzone], mem:%p, flags:%p\n", zone, mem, flags));
409#ifndef NAT_MEM_LOG_ENABLED
410 NOREF(flags);
411#endif
412
413 RTCritSectEnter(&zone->csZone);
414 it = &((struct item *)mem)[-1];
415 Assert((it->magic == ITEM_MAGIC));
416 Assert((zone->magic == ZONE_MAGIC && zone == it->zone));
417
418 zone->pfFree(mem, 0, 0);
419 RTCritSectLeave(&zone->csZone);
420 LogFlowFuncLeave();
421}
422
423int uma_zone_exhausted_nolock(uma_zone_t zone)
424{
425 int fExhausted;
426 LogFlowFunc(("ENTER: zone:%R[mzone]\n", zone));
427 RTCritSectEnter(&zone->csZone);
428 fExhausted = (zone->cur_items == zone->max_items);
429 RTCritSectLeave(&zone->csZone);
430 LogFlowFunc(("LEAVE: %RTbool\n", fExhausted));
431 return fExhausted;
432}
433
434void zone_drain(uma_zone_t zone)
435{
436 struct item *it;
437 uma_zone_t master_zone;
438
439 /* vvl: Huh? What to do with zone which hasn't got backstore ? */
440 Assert((zone->master_zone));
441 LogFlowFunc(("ENTER: zone:%R[mzone]\n", zone));
442 master_zone = zone->master_zone;
443 while (!LIST_EMPTY(&zone->free_items))
444 {
445 it = LIST_FIRST(&zone->free_items);
446 Assert((it->magic == ITEM_MAGIC));
447
448 RTCritSectEnter(&zone->csZone);
449 LIST_REMOVE(it, list);
450 zone->max_items--;
451 RTCritSectLeave(&zone->csZone);
452
453 it->zone = master_zone;
454
455 RTCritSectEnter(&master_zone->csZone);
456 LIST_INSERT_HEAD(&master_zone->free_items, it, list);
457 master_zone->cur_items--;
458 slirp_zone_check_and_send_pending(master_zone); /* may exit+enter the cs! */
459 RTCritSectLeave(&master_zone->csZone);
460 }
461 LogFlowFuncLeave();
462}
463
464void slirp_null_arg_free(void *mem, void *arg)
465{
466 /** @todo (vvl) make it wiser */
467 LogFlowFunc(("ENTER: mem:%p, arg:%p\n", mem, arg));
468 Assert(mem);
469#ifndef NAT_MEM_LOG_ENABLED
470 NOREF(arg);
471#endif
472 RTMemFree(mem);
473 LogFlowFuncLeave();
474}
475
476void *uma_zalloc(uma_zone_t zone, int len)
477{
478#ifndef NAT_MEM_LOG_ENABLED
479 NOREF(zone);
480 NOREF(len);
481#endif
482 LogFlowFunc(("ENTER: zone:%R[mzone], len:%d\n", zone, len));
483 LogFlowFunc(("LEAVE: NULL"));
484 return NULL;
485}
486
487struct mbuf *slirp_ext_m_get(PNATState pData, size_t cbMin, void **ppvBuf, size_t *pcbBuf)
488{
489 struct mbuf *m;
490 size_t size = MCLBYTES;
491 LogFlowFunc(("ENTER: cbMin:%d, ppvBuf:%p, pcbBuf:%p\n", cbMin, ppvBuf, pcbBuf));
492 if (cbMin < MSIZE)
493 size = MCLBYTES;
494 else if (cbMin < MCLBYTES)
495 size = MCLBYTES;
496 else if (cbMin < MJUM9BYTES)
497 size = MJUM9BYTES;
498 else if (cbMin < MJUM16BYTES)
499 size = MJUM16BYTES;
500 else
501 AssertMsgFailed(("Unsupported size"));
502
503 m = m_getjcl(pData, M_NOWAIT, MT_HEADER, M_PKTHDR, size);
504 if (m == NULL)
505 {
506 *ppvBuf = NULL;
507 *pcbBuf = 0;
508 LogFlowFunc(("LEAVE: NULL\n"));
509 return NULL;
510 }
511 m->m_len = size;
512 *ppvBuf = mtod(m, void *);
513 *pcbBuf = size;
514 LogFlowFunc(("LEAVE: %p\n", m));
515 return m;
516}
517
518void slirp_ext_m_free(PNATState pData, struct mbuf *m, uint8_t *pu8Buf)
519{
520
521 LogFlowFunc(("ENTER: m:%p, pu8Buf:%p\n", m, pu8Buf));
522 if ( !pu8Buf
523 && pu8Buf != mtod(m, uint8_t *))
524 RTMemFree(pu8Buf); /* This buffer was allocated on heap */
525 m_freem(pData, m);
526 LogFlowFuncLeave();
527}
528
529static void zone_destroy(uma_zone_t zone)
530{
531 RTCritSectEnter(&zone->csZone);
532 LogFlowFunc(("ENTER: zone:%R[mzone]\n", zone));
533 LogRel(("NAT: zone(nm:%s, used:%d)\n", zone->name, zone->cur_items));
534 if (zone->master_zone)
535 RTMemFree(zone->area);
536 RTCritSectLeave(&zone->csZone);
537 RTCritSectDelete(&zone->csZone);
538 RTMemFree(zone);
539 LogFlowFuncLeave();
540}
541
542void m_fini(PNATState pData)
543{
544 LogFlowFuncEnter();
545#define ZONE_DESTROY(zone) do { zone_destroy((zone)); (zone) = NULL;} while (0)
546 ZONE_DESTROY(pData->zone_clust);
547 ZONE_DESTROY(pData->zone_pack);
548 ZONE_DESTROY(pData->zone_mbuf);
549 ZONE_DESTROY(pData->zone_jumbop);
550 ZONE_DESTROY(pData->zone_jumbo9);
551 ZONE_DESTROY(pData->zone_jumbo16);
552#undef ZONE_DESTROY
553 /** @todo do finalize here.*/
554 LogFlowFuncLeave();
555}
556
557void
558if_init(PNATState pData)
559{
560 /* 14 for ethernet */
561 if_maxlinkhdr = 14;
562 if_comp = IF_AUTOCOMP;
563 if_mtu = 1500;
564 if_mru = 1500;
565}
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