VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/if.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: 8.3 KB
Line 
1/* $Id: if.c 28449 2010-04-19 09:52:59Z vboxsync $ */
2/** @file
3 * NAT - if_*.
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#include <slirp.h>
32
33
34#ifndef VBOX_WITH_SLIRP_BSD_MBUF
35# define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm))
36
37static void ifs_insque(struct mbuf *ifm, struct mbuf *ifmhead)
38{
39 ifm->ifs_next = ifmhead->ifs_next;
40 ifmhead->ifs_next = ifm;
41 ifm->ifs_prev = ifmhead;
42 ifm->ifs_next->ifs_prev = ifm;
43}
44
45static void ifs_remque(struct mbuf *ifm)
46{
47 ifm->ifs_prev->ifs_next = ifm->ifs_next;
48 ifm->ifs_next->ifs_prev = ifm->ifs_prev;
49}
50#else
51#endif
52
53void
54if_init(PNATState pData)
55{
56 /* 14 for ethernet */
57 if_maxlinkhdr = 14;
58 if_queued = 0;
59 if_thresh = 10;
60 if_comp = IF_AUTOCOMP;
61 if_mtu = 1500;
62 if_mru = 1500;
63#ifndef VBOX_WITH_SLIRP_BSD_MBUF
64 if_fastq.ifq_next = if_fastq.ifq_prev = &if_fastq;
65 if_batchq.ifq_next = if_batchq.ifq_prev = &if_batchq;
66/* sl_compress_init(&comp_s); */
67 next_m = &if_batchq;
68#else
69 TAILQ_INIT(&if_fastq);
70 TAILQ_INIT(&if_batchq);
71 next_m = TAILQ_FIRST(&if_fastq);
72#endif
73}
74
75/*
76 * if_output: Queue packet into an output queue.
77 * There are 2 output queue's, if_fastq and if_batchq.
78 * Each output queue is a doubly linked list of double linked lists
79 * of mbufs, each list belonging to one "session" (socket). This
80 * way, we can output packets fairly by sending one packet from each
81 * session, instead of all the packets from one session, then all packets
82 * from the next session, etc. Packets on the if_fastq get absolute
83 * priority, but if one session hogs the link, it gets "downgraded"
84 * to the batchq until it runs out of packets, then it'll return
85 * to the fastq (eg. if the user does an ls -alR in a telnet session,
86 * it'll temporarily get downgraded to the batchq)
87 */
88void
89if_output(PNATState pData, struct socket *so, struct mbuf *ifm)
90{
91 struct mbuf *ifq;
92 int on_fastq = 1;
93
94 DEBUG_CALL("if_output");
95 DEBUG_ARG("so = %lx", (long)so);
96 DEBUG_ARG("ifm = %lx", (long)ifm);
97
98#ifndef VBOX_WITH_SLIRP_BSD_MBUF
99 /*
100 * First remove the mbuf from m_usedlist,
101 * since we're gonna use m_next and m_prev ourselves
102 * XXX Shouldn't need this, gotta change dtom() etc.
103 */
104 if (ifm->m_flags & M_USEDLIST)
105 {
106 remque(pData, ifm);
107 ifm->m_flags &= ~M_USEDLIST;
108 }
109#endif
110
111 /*
112 * See if there's already a batchq list for this session.
113 * This can include an interactive session, which should go on fastq,
114 * but gets too greedy... hence it'll be downgraded from fastq to batchq.
115 * We mustn't put this packet back on the fastq (or we'll send it out of order)
116 * XXX add cache here?
117 */
118#ifndef VBOX_WITH_SLIRP_BSD_MBUF
119 for (ifq = if_batchq.ifq_prev; ifq != &if_batchq; ifq = ifq->ifq_prev)
120#else
121 TAILQ_FOREACH_REVERSE(ifq, &if_batchq, if_queue, m_ifq)
122#endif
123 {
124 if (so == ifq->ifq_so)
125 {
126 /* A match! */
127 ifm->ifq_so = so;
128#ifndef VBOX_WITH_SLIRP_BSD_MBUF
129 ifs_insque(ifm, ifq->ifs_prev);
130#endif
131 goto diddit;
132 }
133 }
134
135 /* No match, check which queue to put it on */
136 if (so && (so->so_iptos & IPTOS_LOWDELAY))
137 {
138#ifndef VBOX_WITH_SLIRP_BSD_MBUF
139 ifq = if_fastq.ifq_prev;
140#else
141 ifq = TAILQ_LAST(&if_fastq, if_queue);
142#endif
143 on_fastq = 1;
144 /*
145 * Check if this packet is a part of the last
146 * packet's session
147 */
148 if (ifq->ifq_so == so)
149 {
150 ifm->ifq_so = so;
151#ifndef VBOX_WITH_SLIRP_BSD_MBUF
152 ifs_insque(ifm, ifq->ifs_prev);
153#endif
154 goto diddit;
155 }
156 }
157#ifndef VBOX_WITH_SLIRP_BSD_MBUF
158 else
159 ifq = if_batchq.ifq_prev;
160
161 /* Create a new doubly linked list for this session */
162 ifm->ifq_so = so;
163 ifs_init(ifm);
164 insque(pData, ifm, ifq);
165#else
166 else
167 {
168 TAILQ_INSERT_TAIL(&if_batchq, ifm, m_ifq);
169 ifq = TAILQ_LAST(&if_batchq, if_queue);
170 }
171
172 /* queue already created */
173#endif
174
175diddit:
176 ++if_queued;
177
178 if (so)
179 {
180 /* Update *_queued */
181 so->so_queued++;
182 so->so_nqueued++;
183 /*
184 * Check if the interactive session should be downgraded to
185 * the batchq. A session is downgraded if it has queued 6
186 * packets without pausing, and at least 3 of those packets
187 * have been sent over the link
188 * (XXX These are arbitrary numbers, probably not optimal..)
189 */
190 if (on_fastq
191 && so->so_nqueued >= 6
192 && (so->so_nqueued - so->so_queued) >= 3)
193 {
194#ifndef VBOX_WITH_SLIRP_BSD_MBUF
195 /* Remove from current queue... */
196 remque(pData, ifm->ifs_next);
197
198 /* ...And insert in the new. That'll teach ya! */
199 insque(pData, ifm->ifs_next, &if_batchq);
200#endif
201 }
202 }
203
204#ifndef FULL_BOLT
205 /*
206 * This prevents us from malloc()ing too many mbufs
207 */
208 if (link_up)
209 {
210 /* if_start will check towrite */
211 if_start(pData);
212 }
213#endif
214}
215
216/*
217 * Send a packet
218 * We choose a packet based on it's position in the output queues;
219 * If there are packets on the fastq, they are sent FIFO, before
220 * everything else. Otherwise we choose the first packet from the
221 * batchq and send it. the next packet chosen will be from the session
222 * after this one, then the session after that one, and so on.. So,
223 * for example, if there are 3 ftp session's fighting for bandwidth,
224 * one packet will be sent from the first session, then one packet
225 * from the second session, then one packet from the third, then back
226 * to the first, etc. etc.
227 */
228void
229if_start(PNATState pData)
230{
231 struct mbuf *ifm, *ifqt;
232#ifdef VBOX_WITH_SLIRP_BSD_MBUF
233 struct if_queue *pqueue = NULL;
234 ifm = NULL;
235 ifqt = NULL;
236#endif
237
238 DEBUG_CALL("if_start");
239
240 if (!if_queued)
241 return; /* Nothing to do */
242
243 for (;;)
244 {
245 /* check if we can really output */
246 if (!slirp_can_output(pData->pvUser))
247 {
248 Log(("if_start: can't send\n"));
249 return;
250 }
251
252#ifndef VBOX_WITH_SLIRP_BSD_MBUF
253 /*
254 * See which queue to get next packet from
255 * If there's something in the fastq, select it immediately
256 */
257 if (if_fastq.ifq_next != &if_fastq)
258 ifm = if_fastq.ifq_next;
259 else
260 {
261 /* Nothing on fastq, see if next_m is valid */
262 if (next_m != &if_batchq)
263 ifm = next_m;
264 else
265 ifm = if_batchq.ifq_next;
266
267 /* Set which packet to send on next iteration */
268 next_m = ifm->ifq_next;
269 }
270 /* Remove it from the queue */
271 ifqt = ifm->ifq_prev;
272 remque(pData, ifm);
273 --if_queued;
274
275 /* If there are more packets for this session, re-queue them */
276 if (ifm->ifs_next != /* ifm->ifs_prev != */ ifm)
277 {
278 insque(pData, ifm->ifs_next, ifqt);
279 ifs_remque(ifm);
280 }
281#else
282 if (!TAILQ_EMPTY(&if_fastq))
283 {
284 pqueue = &if_fastq;
285 }
286 else if (!TAILQ_EMPTY(&if_batchq))
287 {
288 pqueue = &if_batchq;
289 }
290 if (pqueue != NULL) {
291 ifm = TAILQ_FIRST(pqueue);
292 TAILQ_REMOVE(pqueue, ifm, m_ifq);
293 --if_queued;
294 }
295#endif
296
297 /* Update so_queued */
298 if (ifm->ifq_so)
299 {
300 if (--ifm->ifq_so->so_queued == 0)
301 /* If there's no more queued, reset nqueued */
302 ifm->ifq_so->so_nqueued = 0;
303 }
304
305 if_encap(pData, ETH_P_IP, ifm, 0);
306
307 if (!if_queued)
308 {
309 return;
310 }
311 }
312}
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