网络子系统7_l2、l3接口

来源:互联网 发布:两个移动硬盘对拷数据 编辑:程序博客网 时间:2024/05/18 15:28
//调用路径://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,处理bondingskb_bond(skb);//更新本cpu接收到的数据包个数__get_cpu_var(netdev_rx_stat).total++;//将l4,l3报头对应的指针,指向skb->dataskb->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协议,传递一份skblist_for_each_entry_rcu(ptype, &ptype_all, list) {//如果对应的l3协议没有指定dev,或者l3指定的dev就是接收到本skb的devif (!ptype->dev || ptype->dev == skb->dev) {if (pt_prev) //向对应l3传递skbret = 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->dataif (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->dataif (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_lockHARD_TX_LOCK(dev, cpu);//如果设备传输队列没有被关闭if (!netif_queue_stopped(dev)) {//向ETH_P_ALL类型的l3协议传递一份skbif (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;}