最近研究学习linux内核对IP分片的重组处理这块,有些地方不太明白,想请教熟悉的dx。问题如下,这个函数内部对LINUX的分片last_in设置为COMPLETE标识。请结合场景流程解析下,谢谢!本来COMPLETE是用来标识所有的分片到齐的,我就是一直没明白如何判断一个分组的所有分片到齐。FIRST_IN、LAST_IN都容易理解,唯独这个COMPLETE没看懂。static struct ipq *ip_frag_intern(unsigned int hash, struct ipq *qp_in)
{
struct ipq *qp; write_lock(&ipfrag_lock);
#ifdef CONFIG_SMP
/* With SMP race we have to recheck hash table, because
 * such entry could be created on other cpu, while we
 * promoted read lock to write lock.
 */
for(qp = ipq_hash[hash]; qp; qp = qp->next) {
if(qp->id == qp_in->id &&
   qp->saddr == qp_in->saddr &&
   qp->daddr == qp_in->daddr &&
   qp->protocol == qp_in->protocol) {
atomic_inc(&qp->refcnt);
write_unlock(&ipfrag_lock);
qp_in->last_in |= COMPLETE;// 这里设置COMPLETE,如何理解?
ipq_put(qp_in);
return qp;
}
}
#endif
qp = qp_in; if (!mod_timer(&qp->timer, jiffies + sysctl_ipfrag_time))
atomic_inc(&qp->refcnt); atomic_inc(&qp->refcnt);
if((qp->next = ipq_hash[hash]) != NULL)
qp->next->pprev = &qp->next;
ipq_hash[hash] = qp;
qp->pprev = &ipq_hash[hash];
INIT_LIST_HEAD(&qp->lru_list);
list_add_tail(&qp->lru_list, &ipq_lru_list);
ip_frag_nqueues++;
write_unlock(&ipfrag_lock);
return qp;
}

解决方案 »

  1.   

    忘记说了,这个是LINUX kernel 2.4.26 -- linux-2.4.26\linux-2.4.26\net\ipv4\IP_fragment.c源文件代码。
      

  2.   

    在CSDN问这样的问题好像不是地方啊!应该到linux论坛里去问啊!
      

  3.   

    ... ... 没办法,研究这个的linux论坛也很冷清,csdn强人多!
      

  4.   

        off = 0;
        while (pep=(struct ep *)seeq(iq->ipf_q)) {    //取数据报
            pip = (struct ip *)pep->ep_data;
            packoff = (pip->ip_fragoff & IP_FRAGOFF)<<3;
            if (off < packoff) {    //只要一个不满足,说明分片还没有到全
                while(seeq(iq->ipf_q))
                    /*empty*/;
                return 0;
            }
            off = packoff + pip->ip_len - IP_HLEN(pip);    //最后总数据报长度(没有头部)
        }这里不是有判断完整的代码吗?
      

  5.   

    查看几个相关的函数你会发现有几处判断if (last_in&COMPLETE) ,但是没有发现对于last_in的赋值为COMPLETE语句,本来的设计意图是如果last_in状态标识COMPLETE那么后续的分片为无效数据了。这里是个非常关键的判断,至于后续的确定数据片到齐比如说FIRST_IN/LAST_IN都容易理解了。
      

  6.   

    比如:
    /*
    // 如果节点状态为COMPLETE,所有分片已经到齐,后续分片为无效数据
    if (qp->last_in & COMPLETE)
    goto err;
    */
    /* Add new segment to existing queue. */
    static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
    {
    struct sk_buff *prev, *next;
    int flags, offset;
    int ihl, end; // 如果节点状态为COMPLETE,所有分片已经到齐,后续分片为无效数据
    if (qp->last_in & COMPLETE)
    goto err;  offset = ntohs(skb->nh.iph->frag_off);
    flags = offset & ~IP_OFFSET;
    offset &= IP_OFFSET;
    offset <<= 3; /* offset is in 8-byte chunks */
      ihl = skb->nh.iph->ihl * 4; /* Determine the position of this fragment. */
      end = offset + skb->len - ihl; /* Is this the final fragment? */
    if ((flags & IP_MF) == 0) 
    {
    /* If we already have some bits beyond end
     * or have different end, the segment is corrrupted.
     */
    if (end < qp->len ||
        ((qp->last_in & LAST_IN) && end != qp->len))
    goto err;
    qp->last_in |= LAST_IN;
    qp->len = end;

    else 
    {
    if (end&7) {
    end &= ~7;
    if (skb->ip_summed != CHECKSUM_UNNECESSARY)
    skb->ip_summed = CHECKSUM_NONE;
    }
    if (end > qp->len) {
    /* Some bits beyond end -> corruption. */
    if (qp->last_in & LAST_IN)
    goto err;
    qp->len = end;
    }
    }
    if (end == offset)
    goto err; if (pskb_pull(skb, ihl) == NULL)
    goto err;
    if (pskb_trim(skb, end-offset))
    goto err; /* Find out which fragments are in front and at the back of us
     * in the chain of fragments so far.  We must know where to put
     * this fragment, right?
     */
    prev = NULL;
    for(next = qp->fragments; next != NULL; next = next->next) 
    {
    if (FRAG_CB(next)->offset >= offset)
    break; /* bingo! */
    prev = next;
    } /* We found where to put this one.  Check for overlap with
     * preceding fragment, and, if needed, align things so that
     * any overlaps are eliminated.
     */
    if (prev) {
    int i = (FRAG_CB(prev)->offset + prev->len) - offset; if (i > 0) {
    offset += i;
    if (end <= offset)
    goto err;
    if (!pskb_pull(skb, i))
    goto err;
    if (skb->ip_summed != CHECKSUM_UNNECESSARY)
    skb->ip_summed = CHECKSUM_NONE;
    }
    } while (next && FRAG_CB(next)->offset < end) {
    int i = end - FRAG_CB(next)->offset; /* overlap is 'i' bytes */ if (i < next->len) {
    /* Eat head of the next overlapped fragment
     * and leave the loop. The next ones cannot overlap.
     */
    if (!pskb_pull(next, i))
    goto err;
    FRAG_CB(next)->offset += i;
    qp->meat -= i;
    if (next->ip_summed != CHECKSUM_UNNECESSARY)
    next->ip_summed = CHECKSUM_NONE;
    break;
    } else {
    struct sk_buff *free_it = next; /* Old fragmnet is completely overridden with
     * new one drop it.
     */
    next = next->next; if (prev)
    prev->next = next;
    else
    qp->fragments = next; qp->meat -= free_it->len;
    frag_kfree_skb(free_it);
    }
    } FRAG_CB(skb)->offset = offset; /* Insert this fragment in the chain of fragments. */
    skb->next = next;
    if (prev)
    prev->next = skb;
    else
    qp->fragments = skb;  if (skb->dev)
      qp->iif = skb->dev->ifindex;
    skb->dev = NULL;
    qp->stamp = skb->stamp;
    qp->meat += skb->len;
    atomic_add(skb->truesize, &ip_frag_mem);
    if (offset == 0)
    qp->last_in |= FIRST_IN; write_lock(&ipfrag_lock);
    list_move_tail(&qp->lru_list, &ipq_lru_list);
    write_unlock(&ipfrag_lock); return;err:
    kfree_skb(skb);
    }