VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/if.c@ 28800

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