这一篇主要围绕网络协议接口层的发送函数的解析



#### int dev_queue_xmit(struct sk_buff *skb) 函数解析

  • 声明:
    /*  include/linux/netdevice.h  */
int dev_queue_xmit(struct sk_buff *skb);
  • 定义:
    /*  net/core/dev.c   */
int dev_queue_xmit(struct sk_buff *skb)
{
return __dev_queue_xmit(skb, NULL);
}
EXPORT_SYMBOL(dev_queue_xmit); /* __dev_queue_xmit() */
/**
* __dev_queue_xmit - transmit a buffer 传输一个缓冲区
* @skb: buffer to transmit 需要传输的缓冲区
* @accel_priv: private data used for L2 forwarding offload 需要顺带一起送过去的个人数据
* 将缓冲区制作成队列传输到一个网络设备,这个函数的使用必须先设置设备和优先级,
* 而且要先创建一个缓冲区在调用它之前,这个函数可以在一个中断中被调用。
* Queue a buffer for transmission to a network device. The caller must
* have set the device and priority and built the buffer before calling
* this function. The function can be called from an interrupt.
* 一个否定的错误码是返回一个错误数字,成功并不保证帧即将传输,
* 他可以因为缓冲向下传输造成堵塞或者流量控制。
* A negative errno code is returned on a failure. A success does not
* guarantee the frame will be transmitted as it may be dropped due
* to congestion or traffic shaping.
*
* -----------------------------------------------------------------------------------
* I notice this method can also return errors from the queue disciplines,
* including NET_XMIT_DROP, which is a positive value. So, errors can also
* be positive.
*
* Regardless of the return value, the skb is consumed, so it is currently
* difficult to retry a send to this method. (You can bump the ref count
* before sending to hold a reference for retry if you are careful.)
*
* When calling this method, interrupts MUST be enabled. This is because
* the BH enable code must have IRQs enabled so that it will not deadlock.
* --BLG
*/ static int __dev_queue_xmit(struct sk_buff *skb, void *accel_priv)
{
struct net_device *dev = skb->dev; // 网络设备结构体
struct netdev_queue *txq; // 网络设备队列结构体
struct Qdisc *q; // 排队准则结构体
int rc = -ENOMEM; skb_reset_mac_header(skb); // 这里是计算了套接字头到数据的这段大小 // 这里告诉cpu 这种概率不是很大,但是有可能是真的,我比较倾向是假的
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_SCHED_TSTAMP))
__skb_tstamp_tx(skb, NULL, skb->sk, SCM_TSTAMP_SCHED); /* Disable soft irqs for various locks below. Also
* stops preemption for RCU.
*/
rcu_read_lock_bh(); skb_update_prio(skb); /* If device/qdisc don't need skb->dst, release it right now while
* its hot in this cpu cache.
*/
/* 检查netdevice的flag 是否要去掉skb DTS相关的信息,一般情况下这个flag是默认被设置的。
* 在alloc_netdev_mqs 的时候,已经被默认设置了。
*/
if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
skb_dst_drop(skb);
else
skb_dst_force(skb); #ifdef CONFIG_NET_SWITCHDEV
/* Don't forward if offload device already forwarded */
if (skb->offload_fwd_mark &&
skb->offload_fwd_mark == dev->offload_fwd_mark) {
consume_skb(skb);
rc = NET_XMIT_SUCCESS;
goto out;
}
#endif
/* 这里是要取出此netdevice的txq和txq的Qdisc, Qdisc主要是用于进行堵塞处理
* 一般情况下,直接将数据包给driver了,如果遇到busy的情况,就需要进行阻塞处理了,就会用到Qdisc
*/
txq = netdev_pick_tx(dev, skb, accel_priv);
q = rcu_dereference_bh(txq->qdisc); #ifdef CONFIG_NET_CLS_ACT
skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_EGRESS);
#endif
trace_net_dev_queue(skb);
/* 检查Qdisc 中是否存在enqueue规则,如果有就会调用__dev_xmit_skb,进入带有阻塞的控制的Flow,
* 注意这个地方,虽然是走阻塞控制的,Flow但是并不一定进行enqueue操作,只有busy的情况下,
* 才会走Qdisc的enqueue 操作进行
*/
if (q->enqueue) {
rc = __dev_xmit_skb(skb, q, dev, txq);
goto out;
} /* The device has no queue. Common case for software devices:
loopback, all the sorts of tunnels... Really, it is unlikely that netif_tx_lock protection is necessary
here. (f.e. loopback and IP tunnels are clean ignoring statistics
counters.)
However, it is possible, that they rely on protection
made by us here. Check this and shot the lock. It is not prone from deadlocks.
Either shot noqueue qdisc, it is even simpler 8)
*/
/* 如果Qdisc 的enqueue 不存在,就会到这里,
* 对于一些loopback/tunnel interface 比较常见,判断设备是不是UP状态
*/
if (dev->flags & IFF_UP) {
int cpu = smp_processor_id(); /* ok because BHs are off */ if (txq->xmit_lock_owner != cpu) { if (__this_cpu_read(xmit_recursion) > RECURSION_LIMIT)
goto recursion_alert; skb = validate_xmit_skb(skb, dev);
if (!skb)
goto drop; HARD_TX_LOCK(dev, txq, cpu);
/* 如果txq 不是stop 状态,那么就会调用dev_hard_start_xmit 函数发送数据 */
if (!netif_xmit_stopped(txq)) {
__this_cpu_inc(xmit_recursion);
skb = dev_hard_start_xmit(skb, dev, txq, &rc);
__this_cpu_dec(xmit_recursion);
if (dev_xmit_complete(rc)) {
HARD_TX_UNLOCK(dev, txq);
goto out;
}
}
HARD_TX_UNLOCK(dev, txq);
net_crit_ratelimited("Virtual device %s asks to queue packet!\n",
dev->name);
} else {
/* Recursion is detected! It is possible,
* unfortunately
*/
recursion_alert:
net_crit_ratelimited("Dead loop on virtual device %s, fix it urgently!\n",
dev->name);
}
} rc = -ENETDOWN;
drop:
rcu_read_unlock_bh(); atomic_long_inc(&dev->tx_dropped);
kfree_skb_list(skb);
return rc;
out:
rcu_read_unlock_bh();
return rc;
}

Linux 网络子系统之网络协议接口层(二)的更多相关文章

  1. Linux 网络子系统之网络协议接口层(一)

    Linux 网络设备驱动之网络协议接口层介绍. 网络协议接口层最主要的功能是给上层协议提供透明的数据包发送和接收接口. 当上层ARP或IP需要发送数据包时,它将调用网络协议接口层的dev_queue_ ...

  2. Linux中断(interrupt)子系统之四:驱动程序接口层 & 中断通用逻辑层【转】

    转自:http://blog.csdn.net/droidphone/article/details/7497787 在本系列文章的第一篇:Linux中断(interrupt)子系统之一:中断系统基本 ...

  3. Linux时间子系统(三) 用户空间接口函数

    一.前言 从应用程序的角度看,内核需要提供的和时间相关的服务有三种: 1.和系统时间相关的服务.例如,在向数据库写入一条记录的时候,需要记录操作时间(何年何月何日何时). 2.让进程睡眠一段时间 3. ...

  4. Linux 网络子系统之结构介绍

    Linux 网络设备驱动程序的体系结构 图片说明如下: 网络协议接口层 网络协议接口层向网络层协议提供统一的数据包收发接口,不论上层协议是ARP还是IP,都通过 dev_queue_xmit() 函数 ...

  5. Linux输入子系统详解

    input输入子系统框架  linux输入子系统(linux input subsystem)从上到下由三层实现,分别为:输入子系统事件处理层(EventHandler).输入子系统核心层(Input ...

  6. Linux网络之设备接口层:发送数据包流程dev_queue_xmit

    转自:http://blog.csdn.net/wdscq1234/article/details/51926808 写在前面 本文主要是分析kernel-3.8的源代码,主要集中在Network的n ...

  7. Linux 网络子系统

    今天记录一下Linux网络子系统相关的东西. 因为感觉对这一块还是有一个很大的空白,这件事情太可怕了. 摘抄多份博客进行总结一下Linux网络子系统的相关东西. 一. Linux网络子系统体系结构 L ...

  8. linux网络子系统内核分析

    1.选择路由 若要将数据包发至PC2,则linux系统通过查询路由表可知168.1.1.10(目的地址)的网关地址为192.168.1.1,此时linux系统选择网卡1发送数据包. 2.邻居子系统(通 ...

  9. Linux内核分析(四)----进程管理|网络子系统|虚拟文件系统|驱动简介

    原文:Linux内核分析(四)----进程管理|网络子系统|虚拟文件系统|驱动简介 Linux内核分析(四) 两天没有更新了,上次博文我们分析了linux的内存管理子系统,本来我不想对接下来的进程管理 ...

随机推荐

  1. 一个Linux下C线程池的实现

    什么时候需要创建线程池呢?简单的说,如果一个应用需要频繁的创建和销毁线程,而任务执行的时间又非常短,这样线程创建和销毁的带来的开销就不容忽视,这时也是线程池该出场的机会了.如果线程创建和销毁时间相比任 ...

  2. Ueditor编辑旧文章,从数据库中取出要修改的内容

    Ueditor编辑旧文章,从数据库中取出要修改的内容然后放置到编辑器中: <script type="text/plain" id="editor"> ...

  3. Web前端开发必备工具推荐

    http://gaohaixian.blog.163.com/blog/static/12326010520114265223489/不管你做前端开发还是网页重构,前端工具都起着非常重要的作用,这里向 ...

  4. 房产地图google map的初步应用点滴.1)(转)

    房产地图google map的初步应用点滴.1)房产地图google map的初步应用点滴.2)房产地图google map的初步应用点滴.3) 房产地图google map的初步应用点滴.4) 以前 ...

  5. Android四款系统架构工具

    开发者若想开发出一款高质量的应用,一款功能强大的开发工具想必是不可或缺的.开发工具简化了应用的开发流程,也能使开发者在应用开发本身投入更多的精力.本文就为大家带来4款实用的Android应用架构工具. ...

  6. 【ASP.NET Web API教程】2.4 创建Web API的帮助页面[转]

    注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. 2.4 Creating a Help Page for a Web API2.4 创建W ...

  7. 深入理解Java:自定义java注解

    要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法. 元注解: 元注解的作用就是负责注解其他注解.Java5. ...

  8. C# 中一些类关系的判定方法 C#中关于增强类功能的几种方式 Asp.Net Core 轻松学-多线程之取消令牌

    1.  IsAssignableFrom实例方法 判断一个类或者接口是否继承自另一个指定的类或者接口. public interface IAnimal { } public interface ID ...

  9. Android利用广播监听设备网络连接(断网)的变化情况

    http://www.open-open.com/lib/view/open1379302453943.html

  10. ios学习之旅--oc对象的关系

    1.匿名对象:就是没有名字对象     1.匿名对象仅用一次     使用场景:     1.当我们仅仅要调用一个对象的某个方法一次的时候能够使用匿名对象 2.匿名对象能够作为函数的实际參数 #imp ...