关于ip_finish_output2的一点分析

来源:互联网 发布:兴业信用卡淘宝卡年费 编辑:程序博客网 时间:2024/05/17 03:48

             关于ip_finish_output2的一点分析(转) 2009-10-22 07:33:55

分类: LINUX

   

首先声明,因为刚开始看linux内核协议栈,所以肯定有许多不正确的地方,如果大家发现不对的地方请帮我指正。在此先谢过了。

ip_finish_output2函数在文件“net/ipv4/ip_output.c”中定义,如下:

staticinline int ip_finish_output2(struct sk_buff*skb)
{
    struct dst_entry *dst = skb->dst;
    struct hh_cache *hh = dst->hh;
    struct net_device *dev = dst->dev;
    int hh_len = LL_RESERVED_SPACE(dev);

    /* Be paranoid, rather than too clever. */
    if (unlikely(skb_headroom(skb)< hh_len && dev->hard_header)){
        struct sk_buff *skb2;

        skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
        if (skb2 ==NULL){
            kfree_skb(skb);
            return -ENOMEM;
        }
        if (skb->sk)
            skb_set_owner_w(skb2, skb->sk);
        kfree_skb(skb);
        skb = skb2;
    }

    if (hh){
        int hh_alen;

        read_lock_bh(&hh->hh_lock);
        hh_alen = HH_DATA_ALIGN(hh->hh_len);
          memcpy(skb->data- hh_alen, hh->hh_data, hh_alen);
        read_unlock_bh(&hh->hh_lock);
     skb_push(skb, hh->hh_len);
        return hh->hh_output(skb);
    } elseif (dst->neighbour)
        return dst->neighbour->output(skb);

    if (net_ratelimit())
        printk(KERN_DEBUG "ip_finish_output2: No header cache and no neighbour!\n");
    kfree_skb(skb);
    return -EINVAL;
}

对于“hh->hh_output(skb);”,这里hh_output的赋值,在google上没找到,粗略看了一下代码,估计是在函数neigh_hh_init中赋值的(我也不能确定,还需要以后更熟悉协议栈代码后,如有错再更正),此函数在文件“net/core/neighbour.c”中定义,如下

staticvoid neigh_hh_init(struct neighbour*n,struct dst_entry *dst, u16 protocol)
{
    struct hh_cache    *hh;
    struct net_device *dev = dst->dev;

    for (hh = n->hh; hh; hh= hh->hh_next)
        if (hh->hh_type== protocol)
            break;

    if (!hh&&(hh = kmalloc(sizeof(*hh), GFP_ATOMIC))!=NULL){
        memset(hh, 0,sizeof(struct hh_cache));
        rwlock_init(&hh->hh_lock);
        hh->hh_type= protocol;
        atomic_set(&hh->hh_refcnt, 0);
        hh->hh_next= NULL;
        if (dev->hard_header_cache(n, hh)){
            kfree(hh);
            hh = NULL;
        } else {
            atomic_inc(&hh->hh_refcnt);
            hh->hh_next= n->hh;
            n->hh    = hh;
            if (n->nud_state& NUD_CONNECTED)
                hh->hh_output= n->ops->hh_output;
            else
                hh->hh_output= n->ops->output;
        }
    }
    if (hh)    {
        atomic_inc(&hh->hh_refcnt);
        dst->hh= hh;
    }
}

我们可以知道赋值为n->ops->hh_output或n->ops->output, n是结构体struct neighbour指针.  这里的

n->ops和ip_finish_output2函数中的return dst->neighbour->output(skb); ”里的output函数指针应该是在文件"net/ipv4/arp.c"中的arp_constructor函数中赋值的,下面是代码:

staticint arp_constructor(struct neighbour*neigh)
{
    u32 addr = *(u32*)neigh->primary_key;
    struct net_device *dev = neigh->dev;
    struct in_device *in_dev;
    struct neigh_parms *parms;

    neigh->type= inet_addr_type(addr);

    rcu_read_lock();
    in_dev = __in_dev_get_rcu(dev);
    if (in_dev== NULL) {
        rcu_read_unlock();
        return -EINVAL;
    }

    parms = in_dev->arp_parms;
    __neigh_parms_put(neigh->parms);
    neigh->parms= neigh_parms_clone(parms);
    rcu_read_unlock();

    if (dev->hard_header== NULL) {
        neigh->nud_state= NUD_NOARP;
        neigh->ops= &arp_direct_ops;
        neigh->output= neigh->ops->queue_xmit;
    } else {
        /* Good devices (checked by reading texts, but only Ethernet is
         tested)

         ARPHRD_ETHER: (ethernet, apfddi)
         ARPHRD_FDDI: (fddi)
         ARPHRD_IEEE802: (tr)
         ARPHRD_METRICOM: (strip)
         ARPHRD_ARCNET:
         etc. etc. etc.

         ARPHRD_IPDDP will also work, if author repairs it.
         I did not it, becausethis driver does not work even
         in old paradigm.
         */

#if 1
        /* So... these"amateur" devices are hopeless.
         The only thing, that I can say now:
         It is very sad that we need to keep ugly obsolete
         code to make them happy.

         They should be moved to more reasonable state, now
         they use rebuild_header INSTEAD OF
         Besides that, they are sort of out of date
         (a lot of redundant clones/copies, uselessin 2.1),
         I wonder why people believe that they work.
         */
        switch (dev->type) {
        default:
            break;
        case ARPHRD_ROSE:    
#if defined(CONFIG_AX25)|| defined(CONFIG_AX25_MODULE)
        case ARPHRD_AX25:
#if defined(CONFIG_NETROM)|| defined(CONFIG_NETROM_MODULE)
        case ARPHRD_NETROM:
#endif
            neigh->ops= &arp_broken_ops;
            neigh->output= neigh->ops->output;
            return 0;
#endif
        ;}
#endif
        if (neigh->type== RTN_MULTICAST) {
            neigh->nud_state= NUD_NOARP;
            arp_mc_map(addr, neigh->ha, dev, 1);
        } else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
            neigh->nud_state= NUD_NOARP;
            memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
        } else if (neigh->type== RTN_BROADCAST|| dev->flags&IFF_POINTOPOINT) {
            neigh->nud_state= NUD_NOARP;
            memcpy(neigh->ha, dev->broadcast, dev->addr_len);
        }
        if (dev->hard_header_cache)
            neigh->ops= &arp_hh_ops;
        else
            neigh->ops= &arp_generic_ops;
        if (neigh->nud_state&NUD_VALID)
            neigh->output= neigh->ops->connected_output;
        else
            neigh->output= neigh->ops->output;
    }
    return 0;
}

这个netgh->ops赋值为函数arp_generic_ops或者arp_hh_ops或者arp_broken_ops或者arp_direct_ops的地址, 这四个结构体变量的具体定义在“net/ipv4/arp.c”中找到,代码如下:

staticstruct neigh_ops arp_generic_ops = {
    .family =        AF_INET,
    .solicit =        arp_solicit,
    .error_report =        arp_error_report,
    .output =        neigh_resolve_output,
    .connected_output =    neigh_connected_output,
    .hh_output =        dev_queue_xmit,
    .queue_xmit =        dev_queue_xmit,
};

static struct neigh_ops arp_hh_ops= {
    .family =        AF_INET,
    .solicit =        arp_solicit,
    .error_report =        arp_error_report,
    .output =        neigh_resolve_output,
    .connected_output =    neigh_resolve_output,
    .hh_output =        dev_queue_xmit,
    .queue_xmit =        dev_queue_xmit,
};

static struct neigh_ops arp_direct_ops= {
    .family =        AF_INET,
    .output =        dev_queue_xmit,
    .connected_output =    dev_queue_xmit,
    .hh_output =        dev_queue_xmit,
    .queue_xmit =        dev_queue_xmit,
};

struct neigh_ops arp_broken_ops = {
    .family =        AF_INET,
    .solicit =        arp_solicit,
    .error_report =        arp_error_report,
    .output =        neigh_compat_output,
    .connected_output =    neigh_compat_output,
    .hh_output =        dev_queue_xmit,
    .queue_xmit =        dev_queue_xmit,
};

一般情况下指向arp_generic_ops,所以hh->hh_output对应的函数应该是dev_queue_xmit,

neigh->ops->output对应的就是函数neigh_resolve_output。

0 0
原创粉丝点击