VirtualBox

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

Last change on this file since 27467 was 23462, checked in by vboxsync, 15 years ago

NAT: Big changeset:

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