VirtualBox

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

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

NAT: BSD mbuf

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

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