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



#### 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. PHP-FastCGI详解

    一.什么是 FastCGI FastCGI是一个可伸缩地.高速地在HTTP server和动态脚本语言间通信的接口.多数流行的HTTP server都支持FastCGI,包括Apache.Nginx和 ...

  2. PHP-深入学习Smarty

    本文中的边界标签分别为"<{"和"}>" start-12, 都是静态模板中的内容, 即使函数也只是模板中的标签或者变量调解器; 13-end, 都 ...

  3. HDUOJ----4502吉哥系列故事——临时工计划

    吉哥系列故事——临时工计划 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tot ...

  4. HDUOJ---What Are You Talking About

    What Are You Talking About Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/204800 K ...

  5. hduoj---Tempter of the Bone

    Tempter of the Bone Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Othe ...

  6. Chrome禁用缓存

    Chrome默认对JS和CSS等静态资源进行缓存,对HTML不启用缓存. 在开发阶段,我们想要更改之后马上看到效果,那就必须禁用JS和CSS. 快捷键是F12+F1,F12相当于打开dev-tool, ...

  7. 【C++】关于带const的指针问题

    区分const出现在*前还是*后 前: 例如const int *p,这种表示情况下,p本身可以改变,即p可以指向不同的地址, 但是p指向的内容不可改变. 就像你喜欢看书,图书馆规定你可以任意借阅及更 ...

  8. 【LeetCode】19. Remove Nth Node From End of List (2 solutions)

    Remove Nth Node From End of List Given a linked list, remove the nth node from the end of list and r ...

  9. Eclipse 调试器:零距离接触实战技巧

    http://my.oschina.net/willSoft/blog/37784调试的方法虽然千千万万,但归根结底,就是找到引发错误的代码.Eclipse调试器的目标是让程序员能对本地或远程程序进行 ...

  10. hello oc

    printf("Hello C\n"); //OC可以采用C语言的输出方式 printf("The number is %d\n",100);//%d 输出数字 ...