// 调用路径: // 1.NAPI设备的poll函数->netif_receive_skb // 2.积压设备的process_backlog函数->netif_receive_skb // 参数: // skb,驱动程序已经去掉了以太帧最后的四字节crc32,skb->mac.raw指向mac头,skb->data,skb->nh指向l3帧头 // 函数主要任务: // 1.处理netpoll衔接点 // 2.更新时间戳,dev的统计信息 // 3.处理bonding衔接点 // 4.向ETH_P_ALL类型的l3协议传递skb // 5.处理bridge衔接点 // 6.通过数据帧标示的l3协议,传递skb到正确的l3协议 1.1 int netif_receive_skb(struct sk_buff *skb) { struct packet_type *ptype, *pt_prev; int ret = NET_RX_DROP; unsigned short type; #ifdef CONFIG_NETPOLL //netpoll机制 if (skb->dev->netpoll_rx && skb->dev->poll && netpoll_rx(skb)) { //返回1,说明netpoll处理了这个skb,则释放skb,并返回 kfree_skb(skb); return NET_RX_DROP; } #endif //设置skb的时间戳 if (!skb->stamp.tv_sec) net_timestamp(&skb->stamp); //处理bonding //在3.x的版本中,虚拟dev会注册一个handler,处理bonding skb_bond(skb); //更新本cpu接收到的数据包个数 __get_cpu_var(netdev_rx_stat).total++; //将l4,l3报头对应的指针,指向skb->data skb->h.raw = skb->nh.raw = skb->data; skb->mac_len = skb->nh.raw - skb->mac.raw; pt_prev = NULL; rcu_read_lock(); ... //向所有ETH_P_ALL类型的l3协议,传递一份skb list_for_each_entry_rcu(ptype, &ptype_all, list) { //如果对应的l3协议没有指定dev,或者l3指定的dev就是接收到本skb的dev if (!ptype->dev || ptype->dev == skb->dev) { if (pt_prev) //向对应l3传递skb ret = deliver_skb(skb, pt_prev); pt_prev = ptype; } } //处理分流器 handle_diverter(skb); //处理桥接 if (handle_bridge(&skb, &pt_prev, &ret)) goto out; //获取skb的l3协议 type = skb->protocol; //hash到l3协议对应的链表,会存在协议号相同的l3协议,向所有协议号相同的处理函数传递一份skb。 list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type)&15], list) { if (ptype->type == type && (!ptype->dev || ptype->dev == skb->dev)) { if (pt_prev) //将skb传递给对应的l3协议 ret = deliver_skb(skb, pt_prev); pt_prev = ptype; } } //处理遍历过程中最后一个l3协议 if (pt_prev) { ret = pt_prev->func(skb, skb->dev, pt_prev); } else { kfree_skb(skb); ret = NET_RX_DROP; } out: rcu_read_unlock(); return ret; } // 调用路径: // 1.邻居子系统邻居项output->dev_queue_xmit // 2.l2帧头缓存output->dev_queue_xmit // 3.其他l3协议 // 参数: // skb,已经填充好mac头,l3,l4协议头,skb->data指向l2帧头 // 函数主要任务: // 1.处理skb与驱动能力不匹配的情况 // 1.1 skb->frag_list分片,驱动不能处理frag_list, // 1.2 skb->frags分散聚集内存,驱动不能处理分散内存 // 1.3 重新分配sk_buff,拷贝所有数据到sk->data中 // 2.处理上层协议与驱动能力不匹配的情况 // 2.1 上层要求硬件计算校验和,驱动不能提供此能力 // 2.2 由软件计算校验和 // 3.关中断,禁止下半部 // 4.传输 // 4.1 驱动程序使用队列规则 // 4.1.1 获取dev->queue_lock // 4.1.2 入队skb // 4.1.3 通过qdisc_run启动队列进行传输 // 4.1.4 释放dev->queue_lock // 4.2 驱动程序没有使用队列规则 // 4.2.1 获取xmit_lock锁 // 4.2.2 通过hard_start_xmit进行传输 // 4.2.3 释放xmit_lock锁 2.1 int dev_queue_xmit(struct sk_buff *skb) { struct net_device *dev = skb->dev; struct Qdisc *q; int rc = -ENOMEM; //1.如果,skb被分片,设备不能处理skb->frag_list,重新分配sk_buff, //将skb_shinfo(skb)->frag_list中的数据拷贝到新skb->data if (skb_shinfo(skb)->frag_list && !(dev->features & NETIF_F_FRAGLIST) && __skb_linearize(skb, GFP_ATOMIC)) goto out_kfree_skb; //2.如果,skb使用分散聚集内存,设备不支持分散聚集IO,或者skb处于高端dma内存, //重新分配skb_buff,将skb_shinfo(skb)->frags中的数据拷贝到skb->data if (skb_shinfo(skb)->nr_frags && (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) && __skb_linearize(skb, GFP_ATOMIC)) goto out_kfree_skb; //在1,2中,只要有一个成立,就会通过__skb_linearize将skb_shinfo(skb)->frags, //skb_shinfo(skb)->frag_list中的数据拷贝新分配的sk_buff //3.l4协议要求使用硬件计算校验和,但是设备驱动没有提供校验和功能, //通过软件方式完成校验和 if (skb->ip_summed == CHECKSUM_HW && (!(dev->features & (NETIF_F_HW_CSUM | NETIF_F_NO_CSUM)) && (!(dev->features & NETIF_F_IP_CSUM) || skb->protocol != htons(ETH_P_IP)))) if (skb_checksum_help(skb, 0)) goto out_kfree_skb; //1.设备驱动使用规则队列,通过队列规则完成数据传输 //关软中断,获取dev的队列规则 local_bh_disable(); q = rcu_dereference(dev->qdisc); //队列规则具有入队功能 if (q->enqueue) { //获取队列锁 spin_lock(&dev->queue_lock); rc = q->enqueue(skb, q); //在获取设备队列锁之后,启动规则队列的数据传输 qdisc_run(dev); spin_unlock(&dev->queue_lock); rc = rc == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : rc; goto out; } //设备没有使用队列规则,直接通过驱动程序完成传输 if (dev->flags & IFF_UP) { int cpu = smp_processor_id(); if (dev->xmit_lock_owner != cpu) { //获取xmit_lock HARD_TX_LOCK(dev, cpu); //如果设备传输队列没有被关闭 if (!netif_queue_stopped(dev)) { //向ETH_P_ALL类型的l3协议传递一份skb if (netdev_nit)//netdev_nit表示ETH_P_ALL类型l3协议的个数 dev_queue_xmit_nit(skb, dev); rc = 0; //通过驱动程序完成传输 if (!dev->hard_start_xmit(skb, dev)) { HARD_TX_UNLOCK(dev); goto out; } } //对xmit_lock解锁 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); } } rc = -ENETDOWN; local_bh_enable(); out_kfree_skb: kfree_skb(skb); return rc; out: local_bh_enable(); return rc; }
时间: 2024-11-02 15:23:13