Linux 网络子系统之网络协议接口层(二)
这一篇主要围绕网络协议接口层的发送函数的解析
#### 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 网络子系统之网络协议接口层(二)的更多相关文章
- Linux 网络子系统之网络协议接口层(一)
Linux 网络设备驱动之网络协议接口层介绍. 网络协议接口层最主要的功能是给上层协议提供透明的数据包发送和接收接口. 当上层ARP或IP需要发送数据包时,它将调用网络协议接口层的dev_queue_ ...
- Linux中断(interrupt)子系统之四:驱动程序接口层 & 中断通用逻辑层【转】
转自:http://blog.csdn.net/droidphone/article/details/7497787 在本系列文章的第一篇:Linux中断(interrupt)子系统之一:中断系统基本 ...
- Linux时间子系统(三) 用户空间接口函数
一.前言 从应用程序的角度看,内核需要提供的和时间相关的服务有三种: 1.和系统时间相关的服务.例如,在向数据库写入一条记录的时候,需要记录操作时间(何年何月何日何时). 2.让进程睡眠一段时间 3. ...
- Linux 网络子系统之结构介绍
Linux 网络设备驱动程序的体系结构 图片说明如下: 网络协议接口层 网络协议接口层向网络层协议提供统一的数据包收发接口,不论上层协议是ARP还是IP,都通过 dev_queue_xmit() 函数 ...
- Linux输入子系统详解
input输入子系统框架 linux输入子系统(linux input subsystem)从上到下由三层实现,分别为:输入子系统事件处理层(EventHandler).输入子系统核心层(Input ...
- Linux网络之设备接口层:发送数据包流程dev_queue_xmit
转自:http://blog.csdn.net/wdscq1234/article/details/51926808 写在前面 本文主要是分析kernel-3.8的源代码,主要集中在Network的n ...
- Linux 网络子系统
今天记录一下Linux网络子系统相关的东西. 因为感觉对这一块还是有一个很大的空白,这件事情太可怕了. 摘抄多份博客进行总结一下Linux网络子系统的相关东西. 一. Linux网络子系统体系结构 L ...
- linux网络子系统内核分析
1.选择路由 若要将数据包发至PC2,则linux系统通过查询路由表可知168.1.1.10(目的地址)的网关地址为192.168.1.1,此时linux系统选择网卡1发送数据包. 2.邻居子系统(通 ...
- Linux内核分析(四)----进程管理|网络子系统|虚拟文件系统|驱动简介
原文:Linux内核分析(四)----进程管理|网络子系统|虚拟文件系统|驱动简介 Linux内核分析(四) 两天没有更新了,上次博文我们分析了linux的内存管理子系统,本来我不想对接下来的进程管理 ...
随机推荐
- Swift和Objective-C混编的注意啦
文/仁伯安(授权) 原文链接:http://www.jianshu.com/p/2ed48b954612 前言 Swift已推出数年,与Objective-C相比Swift的语言机制及使用简易程度上更 ...
- PLSQL_统计信息系列08_统计信息生成和还原
2015-02-01 Created By BaoXinjian
- IDLE经常使用快捷键汇总
IDLE(An Integrated DeveLopment Environment for Python)是Python自带的编译器,在刚開始学习的人,或写小程序,或用于验证的时候,经经常使用到!假 ...
- Oracle 11gR2数据库使用
1很奇怪,不太懂原理 一.Oracle 12c创建用户是出现“ORA-65096: invalid common user or role name”的错误 - CalvinR http://www. ...
- 清理linux 某个文件夹下面所有的log文件
#!/bin/sh #目标文件夹下面所有问题 target_dir="/app/" #删除2天前新建的后缀为log的文件 -name "*.log" -exec ...
- Flume入门
1.Flume是什么? ○ Flume是由cloudera开发的实时日志收集系统 ○ 核心概念是由一个叫做Agent(代理节点)的java进程运行在日志收集节点 ○ Flume在0.94. ...
- JBoss DataGrid的集群部署与訪问
集群部署 JDG的缓存模式包含本地(Local)模式和集群(Clustered)模式.本项目採用多节点的Clustered模式部署.数据在多个节点的子集间进行复制.而不是同步拷贝到全部的节点. 使用子 ...
- VS中批量删除注释
批量删除: 按ctrl+H 选上正则表达式 Find what: //.* Replace with: (空) 点replace all就行了
- Python 计算两个IP段之间的有效IP地址
Can anyone think of an algorithm to put all of the addresses between two others and put them in a li ...
- coreos 创建使用密钥登陆的ubuntu 基础镜像
下载官方镜像 core@localhost ~ $ docker pull ubuntu:14.04 #假设官方下载较慢,可到www.dockerpool.com下载标准镜像 core@localho ...