VirtualBox

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

Last change on this file since 16450 was 15890, checked in by vboxsync, 16 years ago

NAT: 1. wo sync enhancement branch is still functional (was corrupted with using ICMP file handler in select(1))

  1. after sending send queue doesn't need to synchronize with NAT thread to free mbuf instead NAT queue used to call freeing slirp routine.
  2. no more copying on slirp to guest sent.


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