Linux数据报文接收发送总结5
2.2 网络子系统初始化
linux内核通过调用subsys_initcall来初始化各个子系统,在源代码目录里你可以grep出许多对这个函数的调用。这里我们要说的是网络子系统的初始化,会执行到net_dev_init函数。
/** Initialize the DEV module. At boot time this walks the device list and* unhooks any devices that fail to initialise (normally hardware not* present) and leaves us with a valid list of present and active devices.**//** This is called single threaded during boot, so no need* to take the rtnl semaphore.*/
static int __init net_dev_init(void)
{int i, rc = -ENOMEM;BUG_ON(!dev_boot_phase);if (dev_proc_init())goto out;if (netdev_kobject_init())goto out;INIT_LIST_HEAD(&ptype_all);for (i = 0; i < PTYPE_HASH_SIZE; i++) // 初始化网络协议hash链表,如ip/ipv6/icmp/arp等协议,用于接收报文协议处理ptype_baseINIT_LIST_HEAD(&ptype_base[i]);INIT_LIST_HEAD(&offload_base);if (register_pernet_subsys(&netdev_net_ops))goto out;/** Initialise the packet receive queues.*/for_each_possible_cpu(i) {struct softnet_data *sd = &per_cpu(softnet_data, i);skb_queue_head_init(&sd->input_pkt_queue);skb_queue_head_init(&sd->process_queue);INIT_LIST_HEAD(&sd->poll_list);sd->output_queue_tailp = &sd->output_queue;
#ifdef CONFIG_RPSsd->csd.func = rps_trigger_softirq;sd->csd.info = sd;sd->cpu = i;
#endifsd->backlog.poll = process_backlog;sd->backlog.weight = weight_p;}dev_boot_phase = 0;/* The loopback device is special if any other network devices* is present in a network namespace the loopback device must* be present. Since we now dynamically allocate and free the* loopback device ensure this invariant is maintained by* keeping the loopback device as the first device on the* list of network devices. Ensuring the loopback devices* is the first device that appears and the last network device* that disappears.*/if (register_pernet_device(&loopback_net_ops))goto out;if (register_pernet_device(&default_device_ops))goto out;open_softirq(NET_TX_SOFTIRQ, net_tx_action);open_softirq(NET_RX_SOFTIRQ, net_rx_action);hotcpu_notifier(dev_cpu_callback, 0);dst_subsys_init();rc = 0;
out:return rc;
}subsys_initcall(net_dev_init);//file : linux/netdevice.h
/** The list of packet types we will receive (as opposed to discard)* and the routines to invoke.** Why 16. Because with 16 the only overlap we get on a hash of the* low nibble of the protocol value is RARP/SNAP/X.25.** NOTE: That is no longer true with the addition of VLAN tags. Not* sure which should go first, but I bet it won't make much* difference if we are running VLANs. The good news is that* this protocol won't be in the list unless compiled in, so* the average user (w/out VLANs) will not be adversely affected.* --BLG** 0800 IP* 8100 802.1Q VLAN* 0001 802.3* 0002 AX.25* 0004 802.2* 8035 RARP* 0005 SNAP* 0805 X.25* 0806 ARP* 8137 IPX* 0009 Localtalk* 86DD IPv6*/
#define PTYPE_HASH_SIZE (16)
#define PTYPE_HASH_MASK (PTYPE_HASH_SIZE - 1)
在这个函数里,会为每个CPU都申请一个softnet_data数据结构,在这个数据结构里的poll_list是等待驱动程序将其poll函数注册进来,稍后网卡驱动初始化的时候我们可以看到这一过程。
另外open_softirq注册了每一种软中断都注册一个处理函数。NET_TX_SOFTIRQ的处理函数为net_tx_action,NET_RX_SOFTIRQ的为net_rx_action。继续跟踪open_softirq后发现这个注册的方式是记录在softirq_vec变量里的。后面ksoftirqd线程收到软中断的时候,也会使用这个变量来找到每一种软中断对应的处理函数。
//file: kernel/softirq.c
void open_softirq(int nr, void (*action)(struct softirq_action *)){softirq_vec[nr].action = action;
}static void run_ksoftirqd(unsigned int cpu)
{local_irq_disable();if (local_softirq_pending()) {/** We can safely run softirq on inline stack, as we are not deep* in the task stack here.*/__do_softirq();local_irq_enable();cond_resched_rcu_qs();return;}local_irq_enable();
}asmlinkage __visible void __do_softirq(void)
{unsigned long end = jiffies + MAX_SOFTIRQ_TIME;unsigned long old_flags = current->flags;int max_restart = MAX_SOFTIRQ_RESTART;struct softirq_action *h;bool in_hardirq;__u32 pending;int softirq_bit;/** Mask out PF_MEMALLOC s current task context is borrowed for the* softirq. A softirq handled such as network RX might set PF_MEMALLOC* again if the socket is related to swap*/current->flags &= ~PF_MEMALLOC;pending = local_softirq_pending();account_irq_enter_time(current);__local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);in_hardirq = lockdep_softirq_start();restart:/* Reset the pending bitmask before enabling irqs */set_softirq_pending(0);local_irq_enable();h = softirq_vec; // 软件中断向量while ((softirq_bit = ffs(pending))) {unsigned int vec_nr;int prev_count;h += softirq_bit - 1;vec_nr = h - softirq_vec;
#ifdef IP_SPEEDUP_DEBUGg_vec_nr[smp_processor_id()] = vec_nr;
#endifprev_count = preempt_count();kstat_incr_softirqs_this_cpu(vec_nr);#ifdef CONFIG_RTK_HOST_SPEEDUPif (isHostSpeedUpEnable())send_delay_ack_timer();
#endiftrace_softirq_entry(vec_nr);h->action(h); // 中断处理函数trace_softirq_exit(vec_nr);if (unlikely(prev_count != preempt_count())) {pr_err("huh, entered softirq %u %s %p with preempt_count %08x, exited with %08x?\n",vec_nr, softirq_to_name[vec_nr], h->action,prev_count, preempt_count());preempt_count_set(prev_count);}h++;pending >>= softirq_bit;}rcu_bh_qs();local_irq_disable();pending = local_softirq_pending();
#ifdef CONFIG_RTK_HOST_SPEEDUPif (isHostSpeedUpEnable()){int unAckSegment;unAckSegment = send_delay_ack_timer();if (unAckSegment){if (pending || time_before(jiffies, end))goto restart;//printk("unAck in softirq!\n");}}
#endifif (pending) {if (time_before(jiffies, end) && !need_resched() &&--max_restart)goto restart;wakeup_softirqd();}lockdep_softirq_end(in_hardirq);account_irq_exit_time(current);__local_bh_enable(SOFTIRQ_OFFSET);WARN_ON_ONCE(in_interrupt());tsk_restore_flags(current, old_flags, PF_MEMALLOC);
}
Linux数据报文接收发送总结5相关推荐
- Linux数据报文接收发送总结1
0. 引 如下简单的一段在代码,我们在Linux上运行:同时再运行一服务端的回显: #include <stdio.h> #include <sys/types.h> #inc ...
- Linux数据报文接收发送总结6
2.3 协议栈注册 内核实现了网络层的ip协议,也实现了传输层的tcp协议和udp协议.这些协议对应的实现函数分别是ip_rcv(),tcp_v4_rcv()和udp_rcv().和我们平时写代码的方 ...
- Linux数据报文接收发送总结4
二.系统初始化 Linux驱动,内核协议栈等等模块在具备接收网卡数据包之前,要做很多的准备工作才行.比如要提前创建好ksoftirqd内核线程,要注册好各个协议对应的处理函数,网络设备子系统要提前初始 ...
- Linux数据报文接收发送总结3
1.3 协议分层 大概了解了网卡驱动.硬中断.软中断和ksoftirqd线程之后,我们在这几个概念的基础上给出一个内核收包的路径示意: 当网卡上收到数据以后,Linux中第一个工作的模块是网络驱动.网 ...
- Linux数据报文接收发送总结2
1. 准备工作 此处重点介绍基础概念,为后面介绍数据包收发打下基础.本次代码层面基于Linux 4.4 Kernel. 1.1 系统调用 Linux的系统运行分为用户态和内核态,内核态控制着系统资源. ...
- Linux数据报文接收发送总结7
2.4 网卡驱动初始化 每一个驱动程序(不仅仅只是网卡驱动)会使用 module_init 向内核注册一个初始化函数,当驱动被加载时,内核会调用这个函数.比如igb网卡驱动的代码位于drivers/n ...
- linux网络报文接收发送浅析_Docker容器网络-基础篇
Docker的技术依赖于Linux内核的虚拟化技术的发展,Docker使用到的网络技术有Network Namespace.Veth设备对.Iptables/Netfilter.网桥.路由等.接下来, ...
- Linux SYN报文接收及发送SYNACK报文
注:本文分析基于3.10.0-693.el7内核版本,即CentOS 7.4 在分析connect()系统调用时,我们已经发送SYN报文,所以服务端就需要作出回应了.我们依然只分析TCP层的操作.SY ...
- linux IPv4报文处理浅析
在<linux网络报文接收发送浅析>一文中介绍了数据链路层关于网络报文的处理. 对于接收到的报文,如果不被丢弃.不被网桥转发,会调用netif_receive_skb()提交给IP层: 而 ...
最新文章
- Windows环境下32位汇编程序设计C版code--第五章(二)
- [渝粤教育] 中国人民解放军陆军工程大学 机械基础 参考 资料
- 一个H3CNE测试的配置
- ckeditor复制html样式丢失,Ckeditor选择html无法正常使用铬浏览器
- 生意倒闭的老板基本死于这两个思维
- linux主机慢的原因,51CTO博客-专业IT技术博客创作平台-技术成就梦想
- 《Android进阶之光》--RxJava实现RxBus
- 常见数通设备镜像制作模板
- 【操作系统安全】_Win7Win8系列提权漏洞
- crx什么意思_CRX文件是什么
- 合肥盛荣乒乓球俱乐部学习感悟
- 新购买的阿里云虚拟机部署项目
- Cython的原理:知其然,知其所以然
- 有时候可用 UIWebView 代替 UITextView,解决行间距问题
- 【iOS】调用百度、高德地图SDK
- 简单实用,聊聊我常用的 4 款 Pandas 自动数据分析神器
- 三人易行PLC编程培训怎么样?
- 【啃书】【阿里云天池大赛赛题解析】目录
- 2021年诺贝尔物理学奖揭晓,复杂科学获得重视
- Panoply安装步骤(for Mac)
热门文章
- java对象的生命周期及回收
- 程序员面试【Brainteasers】
- UA PHYS515A 电磁理论V 电磁波与辐射8 单个粒子的辐射 匀速运动与匀加速运动的情况
- 概率论与数理统计中的算子半群 第一讲 Banach-Steinhaus定理1 Baire‘s Category与Banach-Steinhaus定理的证明
- UA SIE545 优化理论基础4 对偶理论简介5 对偶的几何解释
- win10直接获得文件绝对路径的方法总结
- C# DirectX编程对基本三角形应用平移变换矩阵
- mysql安装和服务相关问题总结
- Gradle修改本地仓库的位置
- 那天有个小孩跟我说LINQ(五)转载