免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2342 | 回复: 0
打印 上一主题 下一主题

关于ip_finish_output2的一点分析 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-04-19 15:08 |只看该作者 |倒序浏览

                                               
[color="#000000"]首先声明,因为刚开始看linux内核协议栈,所以肯定有许多不正确的地方,如果大家发现不对的地方请帮我指正。在此先谢过了。
[color="#000000"]ip_finish_output2函数在文件“net/ipv4/ip_output.c”[color="#000000"]中定义,如下:
static inline 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);
    } else if (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;
}
[color="#000000"]对于“hh->hh_output(skb);[color="#000000"]”,这里hh_output的赋值,在google上没找到,粗略看了一下代码,估计是在函数neigh_hh_init中赋值的([color="#ff0000"]我也不能确定,还需要以后更熟悉协议栈代码后,如有错再更正[color="#000000"]),此[color="#000000"]函数在文件“net/core/neighbour.c”[color="#000000"]中定义,如下[color="#000000"]
static void 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;
    }
}
[color="#000000"]我们可以知道赋值为n->ops->hh_output或n->ops->output, n是结构体struct neighbour指针[color="#000000"].  这里的
[color="#000000"]n->ops和ip_finish_output2函数中的“return dst->neighbour->output(skb); ”[color="#000000"]里的output函数指针应该是在文件"net/ipv4/arp.c" 中的arp_constructor函数中赋值的,下面是代码:
static int 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, because this 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, useless in 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;
}
[color="#000000"]这个netgh->ops赋值为函数arp_generic_ops[color="#0000ff"]或者arp_hh_ops[color="#000000"]或者arp_broken_ops或者arp_direct_ops的地址, 这四个结构体变量的具体定义在“net/ipv4/arp.c”中找到,代码如下:
               
               
                static struct 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。
       
               
               
               
               
               
               
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/88019/showart_1903875.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP