cyliu
论坛版主
论坛版主
  • 注册日期2003-06-13
  • 最后登录2014-04-11
  • 粉丝5
  • 关注0
  • 积分1238分
  • 威望2531点
  • 贡献值0点
  • 好评度577点
  • 原创分14分
  • 专家分10分
阅读:1743回复:0

网络设备发送过程

楼主#
更多 发布于:2008-01-16 20:41
int dev_queue_xmit(struct sk_buff *skb)
{
    struct net_device *dev = skb->dev;
    struct Qdisc *q;
    int rc = -ENOMEM;

    /* 处理GSO 数据包. */
    if (netif_needs_gso(dev, skb))
        goto gso;

    /*如果设备不支持sg,并且数据是分片的;数据包分片中至少有一个数据在高端内存位置,并且设备不支持dma
     * 作线性华处理
    */
    if (skb_shinfo(skb)->frag_list &&
        !(dev->features & NETIF_F_FRAGLIST) &&
        __skb_linearize(skb))
        goto out_kfree_skb;
        
    if (skb_shinfo(skb)->nr_frags &&
        (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) &&
        __skb_linearize(skb))
        goto out_kfree_skb;

    /* 如果数据包为作校验和,并且设备对该协议不支持校验和计算,则在此处计算校验
     */
    if (skb->ip_summed == CHECKSUM_PARTIAL) {
        skb_set_transport_header(skb, skb->csum_start -
                          skb_headroom(skb));

        if (!(dev->features & NETIF_F_GEN_CSUM) &&
            !((dev->features & NETIF_F_IP_CSUM) &&
              skb->protocol == htons(ETH_P_IP)) &&
            !((dev->features & NETIF_F_IPV6_CSUM) &&
              skb->protocol == htons(ETH_P_IPV6)))
            if (skb_checksum_help(skb))
                goto out_kfree_skb;
    }

gso:
    spin_lock_prefetch(&dev->queue_lock);

    .....
    
    /* 设备支持队列,则数据包入队列操作:如保序计算等*/
    if (q->enqueue) {
        /* Grab device queue */
        spin_lock(&dev->queue_lock);
        q = dev->qdisc;
        if (q->enqueue) {
            /* reset queue_mapping to zero */
            skb->queue_mapping = 0;
            rc = q->enqueue(skb, q);
            qdisc_run(dev);
            spin_unlock(&dev->queue_lock);

            rc = rc == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : rc;
            goto out;
        }
        spin_unlock(&dev->queue_lock);
    }

    /* 设备无队列*/
    if (dev->flags & IFF_UP) {
        int cpu = smp_processor_id(); /* ok because BHs are off */

        /* 防止数据包循环处理 */
        if (dev->xmit_lock_owner != cpu) {

            HARD_TX_LOCK(dev, cpu);

            if (!netif_queue_stopped(dev) &&
                !netif_subqueue_stopped(dev, skb->queue_mapping)) {
                rc = 0;
                
                /* 发送数据*/
                if (!dev_hard_start_xmit(skb, dev)) {
                    HARD_TX_UNLOCK(dev);
                    goto out;
                }
            }
            HARD_TX_UNLOCK(dev);
            if (net_ratelimit())
                printk(KERN_CRIT "Virtual device %s asks to "
                       "queue packet!\n", dev->name);
        } else {            
            if (net_ratelimit())
                printk(KERN_CRIT "Dead loop on virtual device "
                       "%s, fix it urgently!\n", dev->name);
        }
    }
 ....
}

int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
    if (likely(!skb->next)) {
        ..............
                                          /* 调用设备的发送函数接口*/
        return dev->hard_start_xmit(skb, dev);
    }

out_kfree_skb:
    kfree_skb(skb);
    return 0;
}

/* 这里借用了gre设备来掩饰设备发送接口的*/

static void ipgre_tunnel_setup(struct net_device *dev)
{
    SET_MODULE_OWNER(dev);
    dev->uninit        = ipgre_tunnel_uninit;
    dev->destructor     = free_netdev;
    dev->hard_start_xmit    = ipgre_tunnel_xmit;    
                      dev->get_stats        = ipgre_tunnel_get_stats;
    dev->do_ioctl        = ipgre_tunnel_ioctl;
    dev->change_mtu        = ipgre_tunnel_change_mtu;

    dev->type        = ARPHRD_IPGRE;
    dev->hard_header_len     = LL_MAX_HEADER + sizeof(struct iphdr) + 4;
    dev->mtu        = ETH_DATA_LEN - sizeof(struct iphdr) - 4;
    dev->flags        = IFF_NOARP;
    dev->iflink        = 0;
    dev->addr_len        = 4;
}
走走看看开源好 Solaris vs Linux
游客

返回顶部