VirtualBox

Changeset 14232 in vbox for trunk/src/VBox/Devices/Network


Ignore:
Timestamp:
Nov 17, 2008 7:25:28 AM (16 years ago)
Author:
vboxsync
Message:

Adapted versions of ip_reass, ip_freef and ip_slowtimo from FreeBSD (compilable on Linux, need some debugging)

Location:
trunk/src/VBox/Devices/Network/slirp
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Network/slirp/ip.h

    r14229 r14232  
    255255        ipasfragp_32 ipq_next,ipq_prev;         /* to ip headers of fragments */
    256256#else /* !VBOX_WITH_BSD_REASS */
     257        u_int8_t        ipq_nfrags;             /* # of fragments in this packet */
    257258        struct mbuf *ipq_frags;                 /* to ip headers of fragments */
    258259#endif /* VBOX_WITH_BSD_REASS */
  • trunk/src/VBox/Devices/Network/slirp/ip_input.c

    r14228 r14232  
    6060        for (i = 0; i < IPREASS_NHASH; ++i)
    6161            TAILQ_INIT(&ipq[i]);
     62        maxnipq = 100; /* ??? */
     63        maxfragsperpacket = 16;
     64        nipq = 0;
    6265#endif /* VBOX_WITH_BSD_REASS */
    6366        ip_currid = tt.tv_sec & 0xffff;
     
    208211                ip->ip_len -= hlen;
    209212#else /* !VBOX_WITH_BSD_REASS */
     213        if (ip->ip_off & (IP_MF | IP_OFFMASK)) {
     214            m = ip_reass(pData, m);
     215            if (m == NULL)
     216                return;
     217            ip = mtod(m, struct ip *);
     218            hlen = ip->ip_len;
     219        }
     220        else
     221                ip->ip_len -= hlen;
    210222#endif /* !VBOX_WITH_BSD_REASS */
    211223
     
    415427struct mbuf *
    416428ip_reass(PNATState pData, struct mbuf* m) {
     429    struct ip *ip;
     430    struct mbuf *p, *q, *nq, *t;
     431    struct ipq_t *fp = NULL;
     432    struct ipqhead *head;
     433    int i, hlen, next;
     434    u_int8_t ecn, ecn0;
     435    u_short hash;
     436
     437    /* If maxnipq or maxfragsperpacket are 0, never accept fragments. */
     438    if (maxnipq == 0
     439        || maxfragsperpacket == 0) {
     440        ipstat.ips_fragments++;
     441        ipstat.ips_fragdropped++;
     442        m_freem(pData, m);
     443        return (NULL);
     444    }
     445
     446    ip = mtod(m, struct ip *);
     447    hlen = ip->ip_hl << 2;
     448
     449    hash = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
     450    head = &ipq[hash];
     451
     452    /*
     453     * Look for queue of fragments
     454     * of this datagram.
     455     */
     456    TAILQ_FOREACH(fp, head, ipq_list)
     457        if (ip->ip_id == fp->ipq_id &&
     458            ip->ip_src.s_addr == fp->ipq_src.s_addr &&
     459            ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
     460            ip->ip_p == fp->ipq_p)
     461            goto found;
     462
     463    fp = NULL;
     464
     465    /*
     466     * Attempt to trim the number of allocated fragment queues if it
     467     * exceeds the administrative limit.
     468     */
     469    if ((nipq > maxnipq) && (maxnipq > 0)) {
     470        /*
     471         * drop something from the tail of the current queue
     472         * before proceeding further
     473         */
     474        struct ipq_t *q = TAILQ_LAST(head, ipqhead);
     475        if (q == NULL) {   /* gak */
     476            for (i = 0; i < IPREASS_NHASH; i++) {
     477                struct ipq_t *r = TAILQ_LAST(&ipq[i], ipqhead);
     478                if (r) {
     479                    ipstat.ips_fragtimeout += r->ipq_nfrags;
     480                    ip_freef(pData, &ipq[i], r);
     481                    break;
     482                }
     483            }
     484        } else {
     485            ipstat.ips_fragtimeout += q->ipq_nfrags;
     486            ip_freef(pData, head, q);
     487        }
     488    }
     489
     490found:
     491    /*
     492     * Adjust ip_len to not reflect header,
     493     * convert offset of this to bytes.
     494     */
     495    ip->ip_len -= hlen;
     496    if (ip->ip_off & IP_MF) {
     497        /*
     498         * Make sure that fragments have a data length
     499         * that's a non-zero multiple of 8 bytes.
     500         */
     501        if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) {
     502            ipstat.ips_toosmall++; /* XXX */
     503            goto dropfrag;
     504        }
     505        m->m_flags |= M_FRAG;
     506    } else
     507        m->m_flags &= ~M_FRAG;
     508    ip->ip_off <<= 3;
     509
     510
     511    /*
     512     * Attempt reassembly; if it succeeds, proceed.
     513     * ip_reass() will return a different mbuf.
     514     */
     515    ipstat.ips_fragments++;
     516    m->m_data = (void *)ip;
     517
     518    /* Previous ip_reass() started here. */
     519    /*
     520     * Presence of header sizes in mbufs
     521     * would confuse code below.
     522     */
     523    m->m_data += hlen;
     524    m->m_len -= hlen;
     525
     526    /*
     527     * If first fragment to arrive, create a reassembly queue.
     528     */
     529    if (fp == NULL) {
     530        fp = malloc(sizeof(struct ipq_t));
     531        if (fp == NULL)
     532            goto dropfrag;
     533        TAILQ_INSERT_HEAD(head, fp, ipq_list);
     534        nipq++;
     535        fp->ipq_nfrags = 1;
     536        fp->ipq_ttl = IPFRAGTTL;
     537        fp->ipq_p = ip->ip_p;
     538        fp->ipq_id = ip->ip_id;
     539        fp->ipq_src = ip->ip_src;
     540        fp->ipq_dst = ip->ip_dst;
     541        fp->ipq_frags = m;
     542        m->m_nextpkt = NULL;
     543        goto done;
     544    } else {
     545        fp->ipq_nfrags++;
     546    }
     547
     548#define GETIP(m)    ((struct ip*)((m)->m_data))
     549
     550
     551    /*
     552     * Find a segment which begins after this one does.
     553     */
     554    for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt)
     555        if (GETIP(q)->ip_off > ip->ip_off)
     556            break;
     557
     558    /*
     559     * If there is a preceding segment, it may provide some of
     560     * our data already.  If so, drop the data from the incoming
     561     * segment.  If it provides all of our data, drop us, otherwise
     562     * stick new segment in the proper place.
     563     *
     564     * If some of the data is dropped from the the preceding
     565     * segment, then it's checksum is invalidated.
     566     */
     567    if (p) {
     568        i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off;
     569        if (i > 0) {
     570            if (i >= ip->ip_len)
     571                goto dropfrag;
     572            m_adj(m, i);
     573            ip->ip_off += i;
     574            ip->ip_len -= i;
     575        }
     576        m->m_nextpkt = p->m_nextpkt;
     577        p->m_nextpkt = m;
     578    } else {
     579        m->m_nextpkt = fp->ipq_frags;
     580        fp->ipq_frags = m;
     581    }
     582
     583    /*
     584     * While we overlap succeeding segments trim them or,
     585     * if they are completely covered, dequeue them.
     586     */
     587    for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off;
     588         q = nq) {
     589        i = (ip->ip_off + ip->ip_len) - GETIP(q)->ip_off;
     590        if (i < GETIP(q)->ip_len) {
     591            GETIP(q)->ip_len -= i;
     592            GETIP(q)->ip_off += i;
     593            m_adj(q, i);
     594            break;
     595        }
     596        nq = q->m_nextpkt;
     597        m->m_nextpkt = nq;
     598        ipstat.ips_fragdropped++;
     599        fp->ipq_nfrags--;
     600        m_freem(pData, q);
     601    }
     602
     603    /*
     604     * Check for complete reassembly and perform frag per packet
     605     * limiting.
     606     *
     607     * Frag limiting is performed here so that the nth frag has
     608     * a chance to complete the packet before we drop the packet.
     609     * As a result, n+1 frags are actually allowed per packet, but
     610     * only n will ever be stored. (n = maxfragsperpacket.)
     611     *
     612     */
     613    next = 0;
     614    for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) {
     615        if (GETIP(q)->ip_off != next) {
     616            if (fp->ipq_nfrags > maxfragsperpacket) {
     617                ipstat.ips_fragdropped += fp->ipq_nfrags;
     618                ip_freef(pData, head, fp);
     619            }
     620            goto done;
     621        }
     622        next += GETIP(q)->ip_len;
     623    }
     624    /* Make sure the last packet didn't have the IP_MF flag */
     625    if (p->m_flags & M_FRAG) {
     626        if (fp->ipq_nfrags > maxfragsperpacket) {
     627            ipstat.ips_fragdropped += fp->ipq_nfrags;
     628            ip_freef(pData, head, fp);
     629        }
     630        goto done;
     631    }
     632
     633    /*
     634     * Reassembly is complete.  Make sure the packet is a sane size.
     635     */
     636    q = fp->ipq_frags;
     637    ip = GETIP(q);
     638    if (next + (ip->ip_hl << 2) > IP_MAXPACKET) {
     639        ipstat.ips_fragdropped += fp->ipq_nfrags;
     640        ip_freef(pData, head, fp);
     641        goto done;
     642    }
     643
     644    /*
     645     * Concatenate fragments.
     646     */
     647    m = q;
     648    t = m->m_next;
     649    m->m_next = NULL;
     650    m_cat(pData, m, t);
     651    nq = q->m_nextpkt;
     652    q->m_nextpkt = NULL;
     653    for (q = nq; q != NULL; q = nq) {
     654        nq = q->m_nextpkt;
     655        q->m_nextpkt = NULL;
     656        m_cat(pData, m, q);
     657    }
     658
     659    /*
     660     * Create header for new ip packet by modifying header of first
     661     * packet;  dequeue and discard fragment reassembly header.
     662     * Make header visible.
     663     */
     664    ip->ip_len = (ip->ip_hl << 2) + next;
     665    ip->ip_src = fp->ipq_src;
     666    ip->ip_dst = fp->ipq_dst;
     667    TAILQ_REMOVE(head, fp, ipq_list);
     668    nipq--;
     669    free(fp);
     670    m->m_len += (ip->ip_hl << 2);
     671    m->m_data -= (ip->ip_hl << 2);
     672    /* some debugging cruft by sklower, below, will go away soon */
     673#if 0
     674    if (m->m_flags & M_PKTHDR)    /* XXX this should be done elsewhere */
     675        m_fixhdr(m);
     676#endif
     677    ipstat.ips_reassembled++;
     678    return (m);
     679
     680dropfrag:
     681    ipstat.ips_fragdropped++;
     682    if (fp != NULL)
     683        fp->ipq_nfrags--;
     684    m_freem(pData, m);
     685done:
    417686    return (NULL);
     687
     688#undef GETIP
    418689}
    419690
    420691void
    421 ip_freef(PNATState pData, struct ipq_t *fp) {
     692ip_freef(PNATState pData, struct ipqhead *fhp, struct ipq_t *fp) {
     693    struct mbuf *q;
     694
     695    while (fp->ipq_frags) {
     696        q = fp->ipq_frags;
     697        fp->ipq_frags = q->m_nextpkt;
     698        m_freem(pData, q);
     699    }
     700    TAILQ_REMOVE(fhp, fp, ipq_list);
     701    free(fp);
     702    nipq--;
    422703}
    423704#endif /* VBOX_WITH_BSD_REASS */
     
    461742        register struct ipq_t *fp;
    462743
     744#ifndef VBOX_WITH_BSD_REASS
    463745        DEBUG_CALL("ip_slowtimo");
    464746
    465 #ifndef VBOX_WITH_BSD_REASS
    466747        fp = u32_to_ptr(pData, ipq.next, struct ipq_t *);
    467748        if (fp == 0)
     
    480761     * additional loop see (see ip_input.c in FreeBSD tree)
    481762     */
     763    int i;
     764    DEBUG_CALL("ip_slowtimo");
     765    for (i = 0; i < IPREASS_NHASH; i++) {
     766        for(fp = TAILQ_FIRST(&ipq[i]); fp;) {
     767            struct ipq_t *fpp;
     768
     769            fpp = fp;
     770            fp = TAILQ_NEXT(fp, ipq_list);
     771            if(--fpp->ipq_ttl == 0) {
     772                ipstat.ips_fragtimeout += fpp->ipq_nfrags;
     773                ip_freef(pData, &ipq[i], fpp);
     774            }
     775        }
     776    }
     777    /*
     778     * If we are over the maximum number of fragments
     779     * (due to the limit being lowered), drain off
     780     * enough to get down to the new limit.
     781     */
     782    if (maxnipq >= 0 && nipq > maxnipq) {
     783        for (i = 0; i < IPREASS_NHASH; i++) {
     784            while (nipq > maxnipq && !TAILQ_EMPTY(&ipq[i])) {
     785                ipstat.ips_fragdropped +=
     786                    TAILQ_FIRST(&ipq[i])->ipq_nfrags;
     787                ip_freef(pData, &ipq[i], TAILQ_FIRST(&ipq[i]));
     788            }
     789        }
     790    }
    482791#endif /* VBOX_WITH_BSD_REASS */
    483792}
  • trunk/src/VBox/Devices/Network/slirp/mbuf.h

    r14227 r14232  
    121121                                         * it rather than putting it on the free list */
    122122#ifdef VBOX_WITH_BSD_REASS
    123 #define M_FRAG                  0x0800  /* packet is a fragment of a larger packet */`
     123#define M_FRAG                  0x0800  /* packet is a fragment of a larger packet */
    124124#define M_FIRSTFRAG             0x1000  /* paket is first fragment */
    125125#define M_LASTFRAG              0x2000  /* paket is last fragment */
  • trunk/src/VBox/Devices/Network/slirp/slirp.c

    r14227 r14232  
    386386    int error;
    387387#endif
     388#ifdef VBOX_WITH_BSD_REASS
     389    int i;
     390#endif /* VBOX_WITH_BSD_REASS */
    388391
    389392    STAM_REL_PROFILE_START(&pData->StatFill, a);
     
    406409     * new macroses
    407410     */
     411                for (i = 0; i < IPREASS_NHASH; i++) {
     412                        if (!TAILQ_EMPTY(&ipq[i])) {
     413                            do_slowtimo = 1;
     414                            break;
     415                        }
     416                }
     417                do_slowtimo |= (tcb.so_next != &tcb);
    408418#endif /* VBOX_WITH_BSD_REASS */
    409419
  • trunk/src/VBox/Devices/Network/slirp/slirp.h

    r14227 r14232  
    335335#ifndef VBOX_WITH_BSD_REASS
    336336struct ip * ip_reass _P((PNATState, register struct ipasfrag *, register struct ipq_t *));
     337void ip_freef _P((PNATState, struct ipq_t *));
    337338#else /* !VBOX_WITH_BSD_REASS */
    338339struct mbuf * ip_reass _P((PNATState, register struct mbuf *));
     340void ip_freef _P((PNATState, struct ipqhead *, struct ipq_t *));
    339341#endif  /* VBOX_WITH_BSD_REASS */
    340 void ip_freef _P((PNATState, struct ipq_t *));
    341342void ip_enq _P((PNATState, register struct ipasfrag *, register struct ipasfrag *));
    342343void ip_deq _P((PNATState, register struct ipasfrag *));
  • trunk/src/VBox/Devices/Network/slirp/slirp_state.h

    r14228 r14232  
    7373#else /* !VBOX_WITH_BSD_REASS */
    7474    struct ipqhead ipq[IPREASS_NHASH];
     75    int maxnipq;    /* Administrative limit on # of reass queues*/
     76    int maxfragsperpacket; /* Maximum number of IPv4 fragments allowed per packet */
     77    int nipq; /* total number of reass queues */
    7578#endif /* VBOX_WITH_BSD_REASS */
    7679    uint16_t ip_currid;
     
    228231#define udp_last_so pData->udp_last_so
    229232
     233#ifdef VBOX_WITH_BSD_REASS
     234#define maxfragsperpacket pData->maxfragsperpacket
     235#define maxnipq pData->maxnipq
     236#define nipq pData->nipq
     237#endif /* VBOX_WITH_BSD_REASS */
     238
    230239
    231240#if SIZEOF_CHAR_P != 4
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette