Annotation of qemu/slirp/if.c, revision 1.1.1.5

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

unix.superglobalmegacorp.com