`
simohayha
  • 浏览: 1407254 次
  • 性别: Icon_minigender_1
  • 来自: 火星
社区版块
存档分类
最新评论
文章列表
这次主要介绍的是ip层的切片与组包的实现。 首先来看一下分片好的帧的一些概念: 1 第一个帧的offset位非0并且MF位为1 2 所有的在第一个帧和最后一个帧之间的帧都拥有长度大于0的域 3 最后一个帧MF位为0 并且offset位非0。(这样就能判断是否是最后一个帧了). 这里要注意在linux中,ip头的frag_off域包含了 rfcip头的定义中的nf,df,以及offset域,因此我们每次需要按位与来取得相应的域的值,看下面 ip_local_deliver的代码片段就清楚了: ///取出mf位和offset域,从而决定是否要组包。 if (ip_hdr(skb) ...
这次我们来看数据包如何从4层传递到3层。 先看下面的图,这张图表示了4层和3层之间(也就是4层传输给3层)的传输所需要调用的主要的函数: 我们注意到3层最终会把帧用dst_output函数进行输出,而这个函数,我们上一次已经讲过了,他会调用skb->dst->output这个虚函数(他会对包进行3层的处理),而最终会调用一个XX_finish_output的函数,从而将数据传递到neighboring子系统。 这张我们主要聚焦于ip_push_pending_frames,ip_append_data,ip_append_page,ip_queue_xmit这几个函数。 ...
这次主要介绍下forward和local delivery。 上次我们提到当ip_rcv_finish完成后后调用相关的发送函数ip_forward或者ip_local_deliver.这次就主要介绍这两个函数。 先来看forward。 forward一般由下面几部组成: 1 执行ip option 2 确定这个包能被forward 3 减小ttl,当ttl为0时,丢掉这个包 4 如果需要,则将这个包切片 5 发送包到输出网络设备 这里要注意,如果包由于一些原因,不能被forward,则必须发送ICMP消息到发送主机。 int ip_forward(struct sk_buff *s ...
首先来看校验相关的一些结构: 1 net_device结构: 包含一个features的域,这个表示设备的一些特性(比如控制校验),下面的几个flag就是用来控制校验: #define NETIF_F_IP_CSUM 2 /* Can checksum TCP/UDP over IPv4. */ #define NETIF_F_NO_CSUM 4 /* Does no ...
首先来看这个ip层的结构: 这里看到非常多的netfilter hook,这是因为netfilter主要是针对ip层的。 ip层的主要任务有下面5个方面: 1 ip数据包的校验 2 防火墙的处理(也就是netfilter子系统) 3 处理options(这里的options包含了一些可选的信息。比如时间戳或者源路由option). 4 切包和组包(由于mtu的存在,因此我们需要切包和组包). 5 接收,输出和转发操作。 接下来我们来看ip头的结构: struct iphdr { #if defined(__LITTLE_ENDIAN_BITFIELD) _ ...
我们知道netdevice有一个priv域,这个域用来保存设备的私有数据,当这个设备是一个网桥的时候,priv域也就指向一个struct net_bridge. 接下来看net_bridge以及相关的数据结构: struct net_bridge { ///自旋锁 spinlock_t lock; ///网桥所有端口的链表,其中每个元素都是一个net_bridge_port结构。 struct list_head port_list; ///加到这个网桥的物理设备 struct net_device *dev; ///这个锁是用来保护下面的那个hash链表。 ...
Spanning Tree Protocol(STP)主要是用在网桥上,用来避免网络回路,并制造冗余连接(也就是保证网络的可靠性). 这里只是一个大概的介绍,具体的还是要去看IEEE 的 802.1D STP的文档。 先看下面的图: 我们可以看到在stp中,只有一个根节点,然后root port指的是将此网桥和root连接起来的那个端口,而designated port指的是在连接这个lan的端口中,距离root最近的那个port。 这里虚线部分就是没有激活的link,而对应的端口也是关闭的,这些连接其实就是冗余连接,当实线的某些连接不可用时,这些虚线部分的一些就会根据stp的算法 ...
网桥用来连接不同的网段。使不同的网段能够相互通信,看起来很像三层的路由。它能够有多个port,从而能够将数据帧从一个port复制到另一个port。 这里要注意一点,linux下的网桥只能用于以太网。 来看下示意图: 其中一个是bridge,一个是route。 网桥的主要工作是从输入帧学习主机的位置,建立一个地址的表(也就是表明这个主机(mac地址)属于那个网络),然后基于这个表来复制输入帧到正确的位置。 这里虽然bridge只是起一个引导的作用,可是在下面两个情况下,网桥也有可能处理输入帧: 1 将输入帧up到上层协议栈。 比如说这个网桥刚好还是一个router。 2 将帧传 ...
我们知道在tcp/ip模型中,基本每一层都可以处理多重协议类型,那么当一个输入帧到达后,内核的每一层是如何来取得相应的处理函数呢?也就是说当我要把包传递给上层的时候,如何取得相应协议的处理函数。 我们这里先来 ...
首先来看如何打开和关闭一个输出队列。 帧的输出状态是通过device->state设为__LINK_STATE_XOFF来表示的。而打开和关闭队列也就是通过这个状态位来处理。 static inline void netif_start_queue(struct net_device *dev) { netif_tx_start_queue(netdev_get_tx_queue(dev, 0)); } static inline void netif_tx_start_queue(struct netdev_queue *dev_queue) { clear_bi ...
最近刚刚一个项目自己用libevent,因此这几天又把libevent的代码拿出来翻了下,当初看的时候有些似是而非的东西,这次是基本没有了。这篇也算是前面几篇libevent的blog的补充了。 struct event_base { const struct eventop *evsel; void *evbase; int event_count; /* counts number of total events */ int event_count_active; /* counts number of active events */ int event_g ...
我这里描述的只是2层的处理。 首先,我们来看softnet_data这个结构,每个cpu都有这样的一个队列,它主要是用来存储incoming frame。由于他是每个cpu都有一个队列,因此在不同的cpu之间我们就不要任何锁来控制并发的处理这个帧队 ...
首先来看当网络接收帧到达时,设备如何唤醒驱动。 1 轮询 也就是内核不断的监测相应的寄存器,从而得到是否有网络帧到来。 2中断 当有数据时,设备执行一个硬件中断,然后内核调用相应的处理函数。这种处理当网络在高负载的情况时,效率会很低(中断太频繁)。并且会引起receive-livelock.这是因为内核处理输入帧分为了两部分,一部分是驱动复制帧到输入队列,一部分是内核执行相关代码。第一部分的优先级比第二部分高。这时在高负载的情况下会出现输入队列由于队列已满而阻塞,而已复制的帧由于中断太频繁而无法占用cpu。。 3在一个中断执行多个帧 老的处理方法,也就是上面的处理方法,就是每个帧都会产 ...
首先来看如何分配内存给一个网络设备。 内核通过alloc_netdev来分配内存给一个指定的网络设备: #define alloc_netdev(sizeof_priv, name, setup) \ alloc_netdev_mq(sizeof_priv, name, setup, 1) struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, void (*setup)(struct net_device *), unsigned int queue_count) 其中alloc_netd ...
先来看下内核初始化时调用的一些函数: 这里主要的初始化有三类: 1 boot比如grub,u-boot传递给内核的参数,内核的处理。这里是调用parse_args. 2 中断和时钟的初始化。 3 初始化的函数,这里主要是通过do_initcalls标记的驱动初 ...
Global site tag (gtag.js) - Google Analytics