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

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: }

unix.superglobalmegacorp.com