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