From 284689f84894eab8be5451a156cdc7efd48cb3e3 Mon Sep 17 00:00:00 2001 From: gatieme Date: Mon, 5 Sep 2016 23:53:01 +0800 Subject: [PATCH] ... --- .../01-net_device/README.md | 0 .../02-receive/README.md | 85 ++++++++++++- .../04-net/04-网络访问层/03-send/README.md | 30 +++++ .../{04- => 04-网络访问层}/images/napi.png | Bin .../images/net_rx_action.png | Bin .../04-网络访问层/images/net_rx_action2.png | Bin 0 -> 49205 bytes .../images/receive_kernel_route.png | Bin study/kernel/04-net/05-网络层/README.md | 119 ++++++++++++++++++ 8 files changed, 232 insertions(+), 2 deletions(-) rename study/kernel/04-net/{04- => 04-网络访问层}/01-net_device/README.md (100%) rename study/kernel/04-net/{04- => 04-网络访问层}/02-receive/README.md (80%) create mode 100644 study/kernel/04-net/04-网络访问层/03-send/README.md rename study/kernel/04-net/{04- => 04-网络访问层}/images/napi.png (100%) rename study/kernel/04-net/{04- => 04-网络访问层}/images/net_rx_action.png (100%) create mode 100644 study/kernel/04-net/04-网络访问层/images/net_rx_action2.png rename study/kernel/04-net/{04- => 04-网络访问层}/images/receive_kernel_route.png (100%) create mode 100644 study/kernel/04-net/05-网络层/README.md diff --git a/study/kernel/04-net/04-/01-net_device/README.md b/study/kernel/04-net/04-网络访问层/01-net_device/README.md similarity index 100% rename from study/kernel/04-net/04-/01-net_device/README.md rename to study/kernel/04-net/04-网络访问层/01-net_device/README.md diff --git a/study/kernel/04-net/04-/02-receive/README.md b/study/kernel/04-net/04-网络访问层/02-receive/README.md similarity index 80% rename from study/kernel/04-net/04-/02-receive/README.md rename to study/kernel/04-net/04-网络访问层/02-receive/README.md index 90a7e2b..0f11a3c 100644 --- a/study/kernel/04-net/04-/02-receive/README.md +++ b/study/kernel/04-net/04-网络访问层/02-receive/README.md @@ -173,7 +173,8 @@ struct packet_type { NAPI的另一个优点是可以高效地丢弃分组. 如果内核确信因为有很多其他工作需要处理, 而导致无法处理任何新的分组,那么网络适配器可以直接丢弃分组,无须复制到内核. -只有设备满足如下两个条件时,才能实现NAPI方法。 + +只有设备满足如下两个条件时,才能实现NAPI方法. 1. 设备必须能够保留多个接收的分组,例如保存到DMA环形缓冲区中. 下文将该缓冲区称为Rx缓冲区. @@ -188,9 +189,11 @@ NAPI的另一个优点是可以高效地丢弃分组. 如果内核确信因为 内核以循环方式处理链表上的所有设备 : 内核依次轮询各个设备, 如果已经花费了一定的时间来处理某个设备, 则选择下一个设备进行处理. 此外, 某个设备都带有一个相对权重, 表示与轮询表中其他设备相比, 该设备的相对重要性. 较快的设备权重较大,较慢的设备权重较小. 由于权重指定了在一个轮询的循环中处理多少分组, 这确保了内核将更多地注意速度较快的设备. + ###2.2.2 napi机制的实现细节 ------- + 现在我们已经弄清楚了NAPI的基本原理, 接下来将讨论其实现细节. 与旧的API相比, 关键性的变化在于, 支持NAPI的设备必须提供一个 poll函数. 该方法是特定于设备的, 在用`netif_napi_add`注册网卡时指定. 调用该函数注册, 表明设备可以且必须用新方法处理. ```CPP @@ -292,7 +295,85 @@ static int hyper_card_poll(struct napi_struct *napi, int budget) * 已经完全用掉了预算,但仍然有更多的分组需要处理。设备仍然留在轮询表上,不启用中断. + ###2.2.4 实现IRQ处理程序 ------- -NAPI也需要对网络设备的IRQ处理程序做一些改动. 这里仍然不求助于任何具体的硬件, 而介绍针对虚构设备的代码: \ No newline at end of file +NAPI也需要对网络设备的IRQ处理程序做一些改动. 这里仍然不求助于任何具体的硬件, 而介绍针对虚构设备的代码: + + +```cpp +static irqreturn_t e100_intr(int irq, void *dev_id) +{ + struct net_device *netdev = dev_id; + struct nic *nic = netdev_priv(netdev); + u8 stat_ack = ioread8(&nic->csr->scb.stat_ack); + + netif_printk(nic, intr, KERN_DEBUG, nic->netdev, + "stat_ack = 0x%02X\n", stat_ack); + + if (stat_ack == stat_ack_not_ours || /* Not our interrupt */ + stat_ack == stat_ack_not_present) /* Hardware is ejected */ + return IRQ_NONE; + + /* Ack interrupt(s) */ + iowrite8(stat_ack, &nic->csr->scb.stat_ack); + + /* We hit Receive No Resource (RNR); restart RU after cleaning */ + if (stat_ack & stat_ack_rnr) + nic->ru_running = RU_SUSPENDED; + + if (likely(napi_schedule_prep(&nic->napi))) { + e100_disable_irq(nic); + __napi_schedule(&nic->napi); + } + + return IRQ_HANDLED; +} +``` + + +假定特定于接口的数据保存在`net_device->private`中, 这是大多数网卡驱动程序使用的方法. + +使用辅助函数`netdev_priv`访问该字段. + +现在需要通知内核有新的分组可用. 这需要如下二阶段的方法. + +1. `netif_rx_schedule_prep`准备将设备放置到轮询表上. 本质上, 这会安置`napi_struct->flags`中的`NAPI_STATE_SCHED`标志. + +2. 如果设置该标志成功(仅当NAPI已经处于活跃状态时, 才会失败), 驱动程序必须用特定于设备的适当方法来禁用相应的IRQ. 调用`__netif_rx_schedule`将设备的`napi_struct`添加到轮询表, 并引发软中断`NET_RX_SOFTIRQ`. 这通知内核在`net_rx_action`中开始轮询. + + +###2.2.5 处理Rx软中断 +------- + +在讨论了为支持NAPI驱动程序需要做哪些改动之后, 我们来考察一下内核需要承担的职责. + +`net_rx_action`依旧是软中断`NET_RX_SOFTIRQ`的处理程序. 在前一节给出了该函数的一个简化版本. + +随着有关NAPI的更多细节尘埃落定, 现在可以讨论该函数的所有细节了. + +![图12-13给出了其代码流程图](../images/net_rx_action.png) + + +本质上, 内核通过依次调用各个设备特定的poll方法, 处理轮询表上当前的所有设备. 设备的权重用作该设备本身的预算, 即轮询的一步中可能处理的分组数目. + +必须确保在这个软中断的处理程序中, 不会花费过多时间. 如果如下两个条件成立, 则放弃处理. + +1. 处理程序已经花费了超出一个jiffie的时间. + +2. 所处理分组的总数, 已经超过了`netdev_budget`指定的预算总值. 通常, 总值设置为300, 但可以通过`/proc/sys/net/core/netdev_budget`修改. + +这个预算不能与各个网络设备本身的预算混淆! 在每个轮询步之后, 都从全局预算中减去处理的分组数目, 如果该预算值下降到0, 则退出软中断处理程序. + +在轮询了一个设备之后, 内核会检查所处理的分组数目, 与该设备的预算是否相等. + +如果相等, 那么尚未获得该设备上所有等待的分组, 即代码流程图中`work == weight`所表示的情况. 内核接下来将该设备移动到轮询表末尾, 在链表中所有其他设备都处理过之后, 继续轮询该设备. 显然, 这实现了网络设备之间的循环调度. + +###2.2.6 在NAPI之上实现旧式API +------- + + +最后, 请注意旧的API是如何在NAPI上实现的. 内核的常规行为, 由一个与`softnet`队列关联的伪网络设备控制, `net/core/dev.c`中的`process_backlog`标准函数用作poll方法. 如果没有网络适配器将其自身添加到该队列的轮询表, 其中只包含这个伪适配器, 那么net_rx_action的行为就是通过对`process_backlog`的单一调用来处理队列中的分组, 而不管分组的来源设备. + + diff --git a/study/kernel/04-net/04-网络访问层/03-send/README.md b/study/kernel/04-net/04-网络访问层/03-send/README.md new file mode 100644 index 0000000..ef69fee --- /dev/null +++ b/study/kernel/04-net/04-网络访问层/03-send/README.md @@ -0,0 +1,30 @@ +进程虚拟地址空间 +======= + +| 日期 | 内核版本 | 架构| 作者 | GitHub| CSDN | +| ------- |:-------:|:-------:|:-------:|:-------:|:-------:| +| 2016-06-14 | [Linux-4.7](http://lxr.free-electrons.com/source/?v=4.7) | X86 & arm | [gatieme](http://blog.csdn.net/gatieme) | [LinuxDeviceDrivers](https://github.com/gatieme/LDD-LinuxDeviceDrivers) | [Linux内存管理](http://blog.csdn.net/gatieme/article/category/6225543) | + + +#3 发送分组 +------- + +在网络层中特定于协议的函数通知网络访问层处理由套接字缓冲区定义的一个分组时, 将发送完成的分组. + + +当信息从计算机发送出去时, 必须注意哪些事项? 除了特定协议需要完成的首部和校验和, 以及由高层协议实例生成的数据之外, 分组的路由是最重要的.(即使计算机只有一个网卡, 内核仍然需要区分发送到外部目标的分组和针对环回接口的分组.) + + +因为该问题只能由更高层的协议实例决定(特别是, 如果可以选择到预期目标的路由时), 所以设备驱动程序假定高层协议已经做出了决策. + + +在分组可以发送到下一个正确的计算机之前(通常不同于目标计算机,因为除非存在直接的硬件链路, 否则IP分组通常通过网关发送), 必须确定接收方网卡的硬件地址. + +这是一个复杂的过程, 将在12.8.5节详细讲述. 此时, 我们假定已经知道接收方的MAC地址. 网络访问层的所需的另一个首部, 通常由特定于协议的函数产生. + + +`net/core/dev.c`中的`dev_queue_xmit`用于将分组放置到发出分组的队列上. + +这里将忽略这个特定于设备的队列的实现, 因为它并没有揭示什么网络层的运作机制. 只要知道, 在分组放置到等待队列上一定的时间之后, 分组将发出即可. + +这是通过特定于适配器的函数`hard_start_xmit`完成的, 在每个net_device结构中都以函数指针的形式出现, 由硬件设备驱动程序实现. \ No newline at end of file diff --git a/study/kernel/04-net/04-/images/napi.png b/study/kernel/04-net/04-网络访问层/images/napi.png similarity index 100% rename from study/kernel/04-net/04-/images/napi.png rename to study/kernel/04-net/04-网络访问层/images/napi.png diff --git a/study/kernel/04-net/04-/images/net_rx_action.png b/study/kernel/04-net/04-网络访问层/images/net_rx_action.png similarity index 100% rename from study/kernel/04-net/04-/images/net_rx_action.png rename to study/kernel/04-net/04-网络访问层/images/net_rx_action.png diff --git a/study/kernel/04-net/04-网络访问层/images/net_rx_action2.png b/study/kernel/04-net/04-网络访问层/images/net_rx_action2.png new file mode 100644 index 0000000000000000000000000000000000000000..d70103e3f81e0a4b205f0fd742c83b7705239c24 GIT binary patch literal 49205 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 of Service(服务类型) | 用于更复杂的协议选项,我们在这里无须关注 | +| Length(长度) | 指定了分组的总长度,即首部加数据的长度 | +| fragment ID(分片标识) | 标识了一个分片的IP分组的各个部分。分片方法将同一分片ID指定到同一原始分组的各个数据片,使之可标识为同一分组的成员。各个部分的相对位置由fragment offset(分片偏移量)字段定义。偏移量的单位是64 bit | + + +第三个标志位"保留供未来使用", 但考虑到IPv6的存在, 这是不太可能的. + + +| 字段 | 描述 | +|:-----:|:-----:| +| TTL意为"Time to Live" | 指定了从发送者到接收者的传输路径上中间站点的最大数目(或跳数) | +| Protocol | 标识了IP分组承载的高层协议(传输层)。例如,TCP和UDP协议都有对应的唯一值 | +| Checksum | 包含了一个校验和,根据首部和数据的内容计算。如果指定的校验和与接收方计算的值不一致,那么可能发生了传输错误,应该丢弃该分组 | +| src和dest | 指定了源和目标的32位IP地址 | +| options | 用于扩展IP选项 | +| data | 保存了分组数据(净荷) | + + +IP首部中所有的数值都以网络字节序存储(大端序). + +在内核源代码中, 该首部由iphdr数据结构实现, 定义在[include/uapi/linux/ip.h?v=4.7, line 85](http://lxr.free-electrons.com/source/include/uapi/linux/ip.h?v=4.7#L85) + +```cpp +struct iphdr { +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 ihl:4, + version:4; +#elif defined (__BIG_ENDIAN_BITFIELD) + __u8 version:4, + ihl:4; +#else +#error "Please fix " +#endif + __u8 tos; + __be16 tot_len; + __be16 id; + __be16 frag_off; + __u8 ttl; + __u8 protocol; + __sum16 check; + __be32 saddr; + __be32 daddr; + /*The options start here. */ +}; +``` + + +`ip_rcv`函数是网络层的入口点. 分组向上穿过内核的路线如下图所示 + +![图12-15 分组穿过互联网络层的路线](../images/) + + + +发送和接收操作的程序流程并不总是分离的, 如果分组只通过当前计算机转发, 那么发送和接收操作是交织的. 这种分组不会传递到更高的协议层(或应用程序), 而是立即离开计算机, 发往新的目的地. + + + +#3 接收分组 +------- + + +在分组(以及对应的套接字缓冲区,其中的指针已经设置了适当的值)转发到ip_rcv之后, 必须检查接收到的信息, 确保它是正确的。 主要检查计算的校验和与首部中存储的校验和是否一致. + +其他的检查包括分组是否达到了IP首部的最小长度,分组的协议是否确实是IPv4(IPv6的接收例程是另一个). + +在进行了这些检查之后, 内核并不立即继续对分组的处理, 而是调用一个`netfilter`挂钩, 使得用户空间可以对分组数据进行操作. + +`netfilter`挂钩插入到内核源代码中定义好的各个位置, 使得分组能够被 +外部动态操作. 挂钩存在于网络子系统的各个位置, 每种挂钩都有一个特别的标记, 例如NF_IP_POST_ROUTING. + +在内核到达一个挂钩位置时, 将在用户空间调用对该标记支持的例程. 接下来, 在另一个内核函数中继续内核端的处理(分组可能被修改过). + +12.8.6节讨论了netfilter机制的实现。 +在下一步中,接收到的分组到达一个十字路口,此时需要判断该分组的目的地是本地系统还是远 +程计算机。根据对分组目的地的判断,需要将分组转发到更高层,或转到互联网络层的输出路径上(这 +里不打算讨论第三种选项,即通过多播将分组发送到一组计算机)。 +ip_route_input负责选择路由。这个相对复杂的决策过程在12.8.5节详细讨论。判断路由的结果 +是,选择一个函数,进行进一步的分组处理。可用的函数是ip_local_deliver和ip_forward。具体 +选择哪个函数,取决于分组是交付到本地计算机下一个更高协议层的例程,还是转发到网络中的另一 \ No newline at end of file