- 浏览: 1401090 次
- 性别:
- 来自: 火星
文章分类
最新评论
-
aidd:
内核处理time_wait状态详解 -
ahtest:
赞一下~~
一个简单的ruby Metaprogram的例子 -
itiProCareer:
简直胡说八道,误人子弟啊。。。。谁告诉你 Ruby 1.9 ...
ruby中的类变量与类实例变量 -
dear531:
还得补充一句,惊群了之后,数据打印显示,只有一个子线程继续接受 ...
linux已经不存在惊群现象 -
dear531:
我用select试验了,用的ubuntu12.10,内核3.5 ...
linux已经不存在惊群现象
我们知道在tcp/ip模型中,基本每一层都可以处理多重协议类型,那么当一个输入帧到达后,内核的每一层是如何来取得相应的处理函数呢?也就是说当我要把包传递给上层的时候,如何取得相应协议的处理函数。
我们这里先来看从二层如何把把数据传递给三层。
在sk_buff中的protocol字段能够表示输入帧的3层的协议,或者输入帧的mac头。在内核里面,是在函数netif_receive_skb中,通过protocol域来决定在三层的协议,以及处理函数。
如果内核没有找到protocol所对应协议的处理函数,那么这个帧将会被丢掉。而且一个packet也有可能被分发到多个handler,举个例子,当packet sniffer运行的时候,这里的protocol域有时就会为ETH_P_ALL.此时就会放所有的包进入下一层。不过使用ETH_P_ALL一般只是为了监测网络设备或者debug。比如tcpdump。
来看下netif_receive_skb的代码片段:
我们可以看到最终会通过判断protocol来决定调用哪一个ptype,并调用相应的虚函数func,接下来我们就来看packet_type这个结构体,也就是所有的协议handler结构。
首先来看它的整体结构:
这里有一个全局的ptype_base,他是一个hash链表。它表示所有的协议handler结构。当通过dev_add_pack注册协议的时候就插入到相应的hashcode的相应链表。
ptype_all也是一个全局链表,可以看到他完全是和ptype_base独立的。他就表示了ETH_P_ALL协议。
接下来就来看packet_type的结构
type表示了协议的类型,dev表示了那个设备的协议类型,如果是NULL,则表示是所有设备,比如tcpdum就能通过指定设备名来监测某个指定设备。func对应协议的处理函数。af_pack_priv,被PF_PACKET类型的socket所使用(具体看unix网络编程). list链表(也就是hash链表中,相同的桶所处的链表). 中间的两个gso开头的函数,可以自己去看下gso的相关资料。
来看下ip协议的注册,以及初始化:
可以看到在初始化函数中,调用dev_add_pack来上面定义的ip_packet_type加入到全局的hash链表中。
而链路层得到相应的输入包的协议类型是通过eth_type_trans来实现的,可以随便看一下驱动的代码,当驱动调用netif_rx之前,都会先调用这个函数来得到protocol值。
先来看下不同的帧类型的区别:
eth_type_trans有两个作用,一个是设置packet type,一个是设置协议类型。
其中packet type也就是skb->pkt_type字段,表示了链路层的数据类型,他可以为下面几种类型:
这里要注意的是PACKET_OTHERHOST类型,它表示这个帧不属于这个接收接口,可是他并不会立即被扔掉,当传递给高层的时候。它主要用来protocol sniffer.
我们这里先来看从二层如何把把数据传递给三层。
struct sk_buff { .................................... __be16 protocol; ..................................... };
在sk_buff中的protocol字段能够表示输入帧的3层的协议,或者输入帧的mac头。在内核里面,是在函数netif_receive_skb中,通过protocol域来决定在三层的协议,以及处理函数。
如果内核没有找到protocol所对应协议的处理函数,那么这个帧将会被丢掉。而且一个packet也有可能被分发到多个handler,举个例子,当packet sniffer运行的时候,这里的protocol域有时就会为ETH_P_ALL.此时就会放所有的包进入下一层。不过使用ETH_P_ALL一般只是为了监测网络设备或者debug。比如tcpdump。
来看下netif_receive_skb的代码片段:
type = skb->protocol; list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) { if (ptype->type == type && (ptype->dev == null_or_orig || ptype->dev == skb->dev || ptype->dev == orig_dev)) { if (pt_prev) ret = deliver_skb(skb, pt_prev, orig_dev); pt_prev = ptype; } } static inline int deliver_skb(struct sk_buff *skb, struct packet_type *pt_prev, struct net_device *orig_dev) { atomic_inc(&skb->users); return pt_prev->func(skb, skb->dev, pt_prev, orig_dev); }
我们可以看到最终会通过判断protocol来决定调用哪一个ptype,并调用相应的虚函数func,接下来我们就来看packet_type这个结构体,也就是所有的协议handler结构。
首先来看它的整体结构:
static struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;
这里有一个全局的ptype_base,他是一个hash链表。它表示所有的协议handler结构。当通过dev_add_pack注册协议的时候就插入到相应的hashcode的相应链表。
static struct list_head ptype_all __read_mostly; /* Taps */
ptype_all也是一个全局链表,可以看到他完全是和ptype_base独立的。他就表示了ETH_P_ALL协议。
接下来就来看packet_type的结构
struct packet_type { __be16 type; /* This is really htons(ether_type). */ struct net_device *dev; /* NULL is wildcarded here */ int (*func) (struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); struct sk_buff *(*gso_segment)(struct sk_buff *skb, int features); int (*gso_send_check)(struct sk_buff *skb); void *af_packet_priv; struct list_head list; };
type表示了协议的类型,dev表示了那个设备的协议类型,如果是NULL,则表示是所有设备,比如tcpdum就能通过指定设备名来监测某个指定设备。func对应协议的处理函数。af_pack_priv,被PF_PACKET类型的socket所使用(具体看unix网络编程). list链表(也就是hash链表中,相同的桶所处的链表). 中间的两个gso开头的函数,可以自己去看下gso的相关资料。
来看下ip协议的注册,以及初始化:
static struct packet_type ip_packet_type = { .type = __constant_htons(ETH_P_IP), .func = ip_rcv, .gso_send_check = inet_gso_send_check, .gso_segment = inet_gso_segment, }; static int __init inet_init(void) { 。。。。。。。。。。。。。。。。。。。。 dev_add_pack(&ip_packet_type); ......................................... }
可以看到在初始化函数中,调用dev_add_pack来上面定义的ip_packet_type加入到全局的hash链表中。
void dev_add_pack(struct packet_type *pt) { int hash; spin_lock_bh(&ptype_lock); ///判断类型是否为ETH_P_ALL if (pt->type == htons(ETH_P_ALL)) list_add_rcu(&pt->list, &ptype_all); else { ///计算hash值 hash = ntohs(pt->type) & PTYPE_HASH_MASK; ///插入到相应的hash表位置 list_add_rcu(&pt->list, &ptype_base[hash]); } spin_unlock_bh(&ptype_lock); }
而链路层得到相应的输入包的协议类型是通过eth_type_trans来实现的,可以随便看一下驱动的代码,当驱动调用netif_rx之前,都会先调用这个函数来得到protocol值。
先来看下不同的帧类型的区别:
eth_type_trans有两个作用,一个是设置packet type,一个是设置协议类型。
其中packet type也就是skb->pkt_type字段,表示了链路层的数据类型,他可以为下面几种类型:
#define PACKET_HOST 0 /* To us */ #define PACKET_BROADCAST 1 /* To all */ #define PACKET_MULTICAST 2 /* To group */ #define PACKET_OTHERHOST 3 /* To someone else */ #define PACKET_OUTGOING 4 /* Outgoing of any type */
这里要注意的是PACKET_OTHERHOST类型,它表示这个帧不属于这个接收接口,可是他并不会立即被扔掉,当传递给高层的时候。它主要用来protocol sniffer.
/* * This is an Ethernet frame header. */ ///帧头的表示。 struct ethhdr { unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ unsigned char h_source[ETH_ALEN]; /* source ether addr */ __be16 h_proto; /* packet type ID field */ } __attribute__((packed)); __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) { struct ethhdr *eth; unsigned char *rawp; ///一些初始化 skb->dev = dev; skb_reset_mac_header(skb); skb_pull(skb, ETH_HLEN); eth = eth_hdr(skb); if (is_multicast_ether_addr(eth->h_dest)) { ///判断是否为广播。 if (!compare_ether_addr(eth->h_dest, dev->broadcast)) ///数据位广播 skb->pkt_type = PACKET_BROADCAST; else ///多播 skb->pkt_type = PACKET_MULTICAST; } else if (1 /*dev->flags&IFF_PROMISC */ ) { ///主要用来网络的监测。 if (unlikely(compare_ether_addr(eth->h_dest, dev->dev_addr))) skb->pkt_type = PACKET_OTHERHOST; } ///通过上面的图我们知道大于1536为ethernet 类型的帧,因此直接返回h_proto。 if (ntohs(eth->h_proto) >= 1536) return eth->h_proto; rawp = skb->data; ///取数据位来判断是否是802.3的帧。 if (*(unsigned short *)rawp == 0xFFFF) return htons(ETH_P_802_3); /* * Real 802.2 LLC */ return htons(ETH_P_802_2); }
发表评论
-
Receive packet steering patch详解
2010-07-25 16:46 12124Receive packet steering简称rp ... -
内核中拥塞窗口初始值对http性能的影响分析
2010-07-11 00:20 9695这个是google的人提出的 ... -
linux 内核tcp拥塞处理(一)
2010-03-12 16:17 9572这次我们来分析tcp的拥塞控制,我们要知道协议栈都是很保守的, ... -
内核tcp协议栈SACK的处理
2010-01-24 21:13 12154上一篇处理ack的blog中我 ... -
内核tcp的ack的处理
2010-01-17 03:06 11154我们来看tcp输入对于ack,段的处理。 先是ack的处理, ... -
内核处理time_wait状态详解
2010-01-10 17:39 6802这次来详细看内核的time_wait状态的实现,在前面介绍定时 ... -
tcp协议栈处理各种事件的分析
2009-12-30 01:29 13622首先我们来看socket如何将一些状态的变化通知给对应的进程, ... -
linux内核sk_buff的结构分析
2009-12-25 00:42 47900我看的内核版本是2.6.32. 在内核中sk_buff表示一 ... -
tcp的输入段的处理
2009-12-18 00:56 8351tcp是全双工的协议,因此每一端都会有流控。一个tcp段有可能 ... -
内核协议栈tcp层的内存管理
2009-11-28 17:13 12061我们先来看tcp内存管理相关的几个内核参数,这些都能通过pro ... -
linux内核定时器的实现
2009-10-31 01:44 10190由于linux还不是一个实时的操作系统,因此如果需要更高精度, ... -
linux内核中tcp连接的断开处理
2009-10-25 21:47 10313我们这次主要来分析相关的两个断开函数close和shotdow ... -
linux内核tcp的定时器管理(二)
2009-10-05 20:52 5413这次我们来看后面的3个定时器; 首先是keep alive定 ... -
linux内核tcp的定时器管理(一)
2009-10-04 23:29 9824在内核中tcp协议栈有6种 ... -
linux 内核tcp接收数据的实现
2009-09-26 20:24 14509相比于发送数据,接收数据更复杂一些。接收数据这里和3层的接口是 ... -
linux 内核tcp数据发送的实现
2009-09-10 01:41 19767在分析之前先来看下SO_RCVTIMEO和SO_SNDTIME ... -
tcp connection setup的实现(三)
2009-09-03 00:34 5185先来看下accept的实现. 其实accept的作用很简单, ... -
tcp connection setup的实现(二)
2009-09-01 00:46 8426首先来看下内核如何处理3次握手的半连接队列和accept队列( ... -
tcp connection setup的实现(一)
2009-08-23 04:10 5808bind的实现: 先来介绍几个地址结构. struct ... -
linux内核中socket的实现
2009-08-15 04:38 21096首先来看整个与socket相关的操作提供了一个统一的接口sys ...
相关推荐
### 计算机网络数据链路层知识点详解 #### 数据链路层概述 计算机网络中的数据链路层是OSI七层模型中的第二层,主要负责在相邻节点之间提供可靠且透明的数据传输服务。该层的主要任务是通过一系列机制确保数据能够...
数据链路层的主要任务是将网络层交下来的IP数据报封装成帧,在物理层传输的比特流基础上加上帧的起始标志、结束标志和错误检测代码,以确保数据能够正确地从源节点传输到目的节点。这个过程包含了帧的封装、传输、...
总的来说,数据链路层在物理链路层之上提供了一层逻辑控制,使得数据能够在复杂的网络环境中被正确、可靠地传递。它通过定义和执行各种协议,解决了物理层无法处理的错误和冲突,是计算机网络中不可或缺的一环。理解...
在计算机网络中,数据传输的过程可以分为多个层次,这些层次共同构成了网络通信的协议栈,主要包括应用层、传输层、网络层、链路层和物理层。这些层次各自负责不同的功能,确保信息从源主机准确无误地传输到目标主机...
网络层不关心数据的传输质量,而是关注如何最有效地将数据包通过可能存在的多条路径传递到目的地。路由器是网络层的关键设备,它们根据路由表信息决定数据包的下一跳。 链路层则处理物理网络连接,如局域网(LAN)...
### HART有线网络数据链路层服务定义和协议规范 #### 一、概述 HART(Highway Addressable Remote Transducer)协议是一种用于过程自动化领域中的通信协议,旨在为智能现场设备提供一种标准化的数据通信方式。HART...
在广播信道中,数据链路层面临更复杂的任务,如协调多个主机共享信道,这通常涉及到CSMA/CD(Carrier Sense Multiple Access with Collision Detection)协议。CSMA/CD是局域网,尤其是以太网中的冲突检测机制,当多...
数据链路层是计算机网络协议模型中的第二层,它的主要任务是为网络层提供可靠的数据传输服务。在这一层,比特流被组织成帧,并通过物理层进行传输。以下是数据链路层的关键功能: 1. **成帧与帧同步**: 数据链路...
总的来说,以太网链路层是TCP/IP通信的基础,它确保了数据能够在网络中正确、高效地传输。通过ARP协议和交换机的智能转发,主机可以找到正确的路径将数据送达目的地,而交换机则在背后默默维护着网络的正常运行。...
- **成帧**:数据链路层将来自网络层的数据报封装在帧中,添加头尾部信息,便于识别和处理。 - **链路访问**:在共享介质上,如局域网,链路层协议处理多个设备如何公平地共享信道。 - **MAC地址**:帧的头部包含...
异构车联网数据链路层链路调度算法(Heterogeneous Vehicular Networks Link Scheduling Algorithm in LLC,HLSA)应运而生,该算法旨在根据车联网中的交通流密度、数据报文优先级和链路通信状态作为参数对链路进行...
在深入探讨数据链路层与以太网的相关知识点之前,我们需要了解数据链路层在整个网络架构中的作用和重要性。数据链路层位于网络的第二层,其核心功能是确保数据在相邻网络节点间的可靠传输。为了实现这一目标,数据链...
链路层位于网络模型的最底层,负责将网络层的数据包封装成帧,并通过物理介质进行传输。链路层的关键功能包括: - **封装与解封装**:将来自网络层的数据包封装成帧,并在接收端将帧解封装回数据包。 - **差错检测**...
Ethernet帧是数据链路层的传输单位,包含了MAC地址等关键信息。实验要求学生能够通过命令行工具(如IPconfig)查看本机MAC地址,并理解帧结构中的各个字段。例如,Frame字段提供了物理层的数据帧概述,Ethernet II...
局域网的介质访问控制(MAC)层是OSI模型的数据链路层的一部分,负责控制同一物理介质上的多个设备如何共享通信带宽。常见的MAC层协议有: 1. **CSMA/CD (Carrier Sense Multiple Access with Collision Detection)**...
**连接层**,也称为链路层,处理数据帧的传输。帧是数据在网络中传输的基本单元,包含源和目标地址,用于错误检测的校验序列,以及数据负载。以太网和Wi-Fi的连接层协议(如IEEE 802.3和802.11)确保帧正确地在...
数据链路层是计算机网络协议层次中的第二层,主要负责在相邻节点间提供无差错的数据传输,确保数据帧从源节点可靠地传递到目的节点。这一层的任务包括差错检测、媒体访问控制以及在某些情况下实现可靠传输。 首先,...
OSI七层模型是一个标准的网络协议栈,共有七个层次,从上到下分别是应用层、表示层、会话层、传输层、网络层、数据链路层和物理层。每个层次都有其特定的功能和协议。 应用层是最高的一层,负责提供各种网络服务,...
数据链路层的主要任务是为网络层提供可靠的数据传输服务,确保数据在物理链路上的正确传输。这一层的协议包括以太网、802.11无线局域网(Wi-Fi)、令牌环和PPP等。以太网是最常见的局域网标准,其帧结构包含源和目的...