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

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

unix.superglobalmegacorp.com