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相关推荐

  1. Linux数据报文接收发送总结1

    0. 引 如下简单的一段在代码,我们在Linux上运行:同时再运行一服务端的回显: #include <stdio.h> #include <sys/types.h> #inc ...

  2. Linux数据报文接收发送总结6

    2.3 协议栈注册 内核实现了网络层的ip协议,也实现了传输层的tcp协议和udp协议.这些协议对应的实现函数分别是ip_rcv(),tcp_v4_rcv()和udp_rcv().和我们平时写代码的方 ...

  3. Linux数据报文接收发送总结4

    二.系统初始化 Linux驱动,内核协议栈等等模块在具备接收网卡数据包之前,要做很多的准备工作才行.比如要提前创建好ksoftirqd内核线程,要注册好各个协议对应的处理函数,网络设备子系统要提前初始 ...

  4. Linux数据报文接收发送总结3

    1.3 协议分层 大概了解了网卡驱动.硬中断.软中断和ksoftirqd线程之后,我们在这几个概念的基础上给出一个内核收包的路径示意: 当网卡上收到数据以后,Linux中第一个工作的模块是网络驱动.网 ...

  5. Linux数据报文接收发送总结2

    1. 准备工作 此处重点介绍基础概念,为后面介绍数据包收发打下基础.本次代码层面基于Linux 4.4 Kernel. 1.1 系统调用 Linux的系统运行分为用户态和内核态,内核态控制着系统资源. ...

  6. Linux数据报文接收发送总结7

    2.4 网卡驱动初始化 每一个驱动程序(不仅仅只是网卡驱动)会使用 module_init 向内核注册一个初始化函数,当驱动被加载时,内核会调用这个函数.比如igb网卡驱动的代码位于drivers/n ...

  7. linux网络报文接收发送浅析_Docker容器网络-基础篇

    Docker的技术依赖于Linux内核的虚拟化技术的发展,Docker使用到的网络技术有Network Namespace.Veth设备对.Iptables/Netfilter.网桥.路由等.接下来, ...

  8. Linux SYN报文接收及发送SYNACK报文

    注:本文分析基于3.10.0-693.el7内核版本,即CentOS 7.4 在分析connect()系统调用时,我们已经发送SYN报文,所以服务端就需要作出回应了.我们依然只分析TCP层的操作.SY ...

  9. linux IPv4报文处理浅析

    在<linux网络报文接收发送浅析>一文中介绍了数据链路层关于网络报文的处理. 对于接收到的报文,如果不被丢弃.不被网桥转发,会调用netif_receive_skb()提交给IP层: 而 ...

最新文章

  1. Windows环境下32位汇编程序设计C版code--第五章(二)
  2. [渝粤教育] 中国人民解放军陆军工程大学 机械基础 参考 资料
  3. 一个H3CNE测试的配置
  4. ckeditor复制html样式丢失,Ckeditor选择html无法正常使用铬浏览器
  5. 生意倒闭的老板基本死于这两个思维
  6. linux主机慢的原因,51CTO博客-专业IT技术博客创作平台-技术成就梦想
  7. 《Android进阶之光》--RxJava实现RxBus
  8. 常见数通设备镜像制作模板
  9. 【操作系统安全】_Win7Win8系列提权漏洞
  10. crx什么意思_CRX文件是什么
  11. 合肥盛荣乒乓球俱乐部学习感悟
  12. 新购买的阿里云虚拟机部署项目
  13. Cython的原理:知其然,知其所以然
  14. 有时候可用 UIWebView 代替 UITextView,解决行间距问题
  15. 【iOS】调用百度、高德地图SDK
  16. 简单实用,聊聊我常用的 4 款 Pandas 自动数据分析神器
  17. 三人易行PLC编程培训怎么样?
  18. 【啃书】【阿里云天池大赛赛题解析】目录
  19. 2021年诺贝尔物理学奖揭晓,复杂科学获得重视
  20. Panoply安装步骤(for Mac)

热门文章

  1. java对象的生命周期及回收
  2. 程序员面试【Brainteasers】
  3. UA PHYS515A 电磁理论V 电磁波与辐射8 单个粒子的辐射 匀速运动与匀加速运动的情况
  4. 概率论与数理统计中的算子半群 第一讲 Banach-Steinhaus定理1 Baire‘s Category与Banach-Steinhaus定理的证明
  5. UA SIE545 优化理论基础4 对偶理论简介5 对偶的几何解释
  6. win10直接获得文件绝对路径的方法总结
  7. C# DirectX编程对基本三角形应用平移变换矩阵
  8. mysql安装和服务相关问题总结
  9. Gradle修改本地仓库的位置
  10. 那天有个小孩跟我说LINQ(五)转载