- 浏览: 315101 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
JQ_AK47:
...
Linux下直接发送以太包 -
winsen2009:
谢谢分享,如果能再来一个列子就更好了,刚接触看完还是不懂的用
UNPv1_r3读书笔记: SCTP编程
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn
1. 前言 以太头中除了6字节目的MAC地址、6字节源MAC地址外,还有两字节的以太帧类型值,如IPv4为0x0800,ARP为0x0806等,网卡驱动收到以太帧后通过接口函数netif_receive_skb()(netif_rx实际最后也是调用netif_receive_skb)交到上层,而这个接口函数就完成对以太帧类型的区分,交到不同的协议处理程序。如果想自己编写某一以太类型帧的处理程序,需要自己添加相应的 以下Linux内核代码为2.6.17.11。 2. 数据结构 每种协议都要定义一个packet_type结构,引导进入相关的协议数据处理函数,所有节点组成一个链表(HASH链表)。 /* include/linux/netdevice.h */ 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 *); void *af_packet_priv; struct list_head list; }; 参数说明: type:以太帧类型,16位 dev:所附着的网卡设备,如果为NULL则匹配全部网卡 func:协议入口接收处理函数 af_packet_priv:协议私有数据 list:链表扣 一般各协议的packet_type结构都是静态存在,初始化时只提供type和func两个参数就可以了,每个协议在初始化时都要将此结构加入到系统类型链表中。 3. 处理函数 3.1 添加节点 /* net/core/dev.c */ /** * dev_add_pack - add packet handler * @pt: packet type declaration * * Add a protocol handler to the networking stack. The passed &packet_type * is linked into kernel lists and may not be freed until it has been * removed from the kernel lists. * * This call does not sleep therefore it can not * guarantee all CPU's that are in middle of receiving packets * will see the new packet type (until the next received packet). */ void dev_add_pack(struct packet_type *pt) { int hash; spin_lock_bh(&ptype_lock); // 如果类型是全部以太类型,则节点链接到ptype_all链 if (pt->type == htons(ETH_P_ALL)) { netdev_nit++; list_add_rcu(&pt->list, &ptype_all); } else { // 根据协议类型取个HASH,共15个HASH链表 hash = ntohs(pt->type) & 15; // 将节点链接到HASH链表中,list_add_rcu是加了smp_wmb()保护的list_add链表操作 list_add_rcu(&pt->list, &ptype_base[hash]); } spin_unlock_bh(&ptype_lock); } 3.2 删除节点 /** * __dev_remove_pack - remove packet handler * @pt: packet type declaration * * Remove a protocol handler that was previously added to the kernel * protocol handlers by dev_add_pack(). The passed &packet_type is removed * from the kernel lists and can be freed or reused once this function * returns. * * The packet type might still be in use by receivers * and must not be freed until after all the CPU's have gone * through a quiescent state. */ void __dev_remove_pack(struct packet_type *pt) { struct list_head *head; struct packet_type *pt1; spin_lock_bh(&ptype_lock); // 根据协议类型找是在ptype_all表还是某一HASH链表中 if (pt->type == htons(ETH_P_ALL)) { netdev_nit--; head = &ptype_all; } else head = &ptype_base[ntohs(pt->type) & 15]; // 直接用地址比对进行查找,而不是类型,因为同一个类型也可能有多个节点 list_for_each_entry(pt1, head, list) { if (pt == pt1) { list_del_rcu(&pt->list); goto out; } } printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt); out: spin_unlock_bh(&ptype_lock); } /** * dev_remove_pack - remove packet handler * @pt: packet type declaration * * Remove a protocol handler that was previously added to the kernel * protocol handlers by dev_add_pack(). The passed &packet_type is removed * from the kernel lists and can be freed or reused once this function * returns. * * This call sleeps to guarantee that no CPU is looking at the packet * type after return. */ // 只是__dev_remove_pack()的包裹函数 void dev_remove_pack(struct packet_type *pt) { __dev_remove_pack(pt); synchronize_net(); } 4. 实例 4.1 IP /* net/ipv4/af_inet.c */ static struct packet_type ip_packet_type = { .type = __constant_htons(ETH_P_IP), .func = ip_rcv, // IP接收数据的入口点 }; static int __init inet_init(void) { ...... dev_add_pack(&ip_packet_type); ...... 由于IP协议部分不能作为内核模块,所以是没有卸载函数的,没必要调用dev_remove_pack()函数。 4.2 8021q vlan /* net/8021q/vlan.c */ static struct packet_type vlan_packet_type = { .type = __constant_htons(ETH_P_8021Q), .func = vlan_skb_recv, /* VLAN receive method */ }; ...... static int __init vlan_proto_init(void) { ...... dev_add_pack(&vlan_packet_type); ...... static void __exit vlan_cleanup_module(void) { ...... dev_remove_pack(&vlan_packet_type); ...... 由于VLAN可为模块方式存在,所以在模块清除函数中要调用dev_remove_pack()。 5. 网络接收 网卡驱动收到数据包构造出skb后,通过接口函数netif_receive_skb()传递到上层进行协议处理分配。 /* net/core/dev.c */ int netif_receive_skb(struct sk_buff *skb) { ...... // 先查处理所有以太类型的链表各节点 list_for_each_entry_rcu(ptype, &ptype_all, list) { if (!ptype->dev || ptype->dev == skb->dev) { if (pt_prev) ret = deliver_skb(skb, pt_prev, orig_dev); pt_prev = ptype; } } ...... // 再查指定协议的HASH链表 list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type)&15], list) { if (ptype->type == type && (!ptype->dev || ptype->dev == skb->dev)) { if (pt_prev) ret = deliver_skb(skb, pt_prev, orig_dev); pt_prev = ptype; } } ...... // 该函数就是调用个协议的接收函数处理该skb包,进入第三层网络层处理 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); } 6. 结论 通过链表挂接方式,Linux内核可以很容易的添加各种协议的接收处理函数。 数据流程: _____________ | | 网卡驱动--->netif_rx()--->netif_receive_skb()->deliver_skb()->packet_type.func
发表评论
-
Linux内核中流量控制(24)
2011-01-10 16:33 2210本文档的Copyleft归yfydz所 ... -
Linux内核中流量控制(23)
2011-01-10 16:30 1493本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(22)
2011-01-10 16:29 1940本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(21)
2011-01-10 16:28 1357本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(20)
2011-01-10 16:27 1525本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(19)
2011-01-10 16:27 1979本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(18)
2011-01-10 16:26 1572Linux内核中流量控制(18) ... -
Linux内核中流量控制(17)
2011-01-10 16:25 1951本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(16)
2011-01-10 16:25 1808本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(15)
2011-01-10 16:24 1892本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(14)
2011-01-10 16:23 1961本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(13)
2011-01-10 16:22 2638本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(12)
2011-01-10 16:21 2110本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(11)
2011-01-10 16:21 3236本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(10)
2011-01-10 16:20 2007本文档的Copyleft归yfydz所 ... -
Linux内核中流量控制(9)
2011-01-10 16:19 1833本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(8)
2011-01-10 16:18 1498本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(7)
2011-01-10 16:18 2927本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(6)
2011-01-10 16:17 1495本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(5)
2011-01-10 16:16 1730本文档的Copyleft归yfydz所有,使用GPL发布,可以 ...
相关推荐
以太头中除了6字节目的MAC地址、6字节源MAC地址外,还有两字节的以太帧类型值,如IPv4为0x0800,ARP为0x0806等,网卡驱动收到以太帧后通过接口函数netif_...本文将为大家介绍Linux系统内核接收以太帧的处理程序。
linux内核编译2.6.39linux内核编译2.6.39linux内核编译2.6.39linux内核编译2.6.39linux内核编译2.6.39linux内核编译2.6.39linux内核编译2.6.39linux内核编译2.6.39linux内核编译2.6.39linux内核编译2.6.39linux内核...
鉴于此,《Linux内核精髓:精通Linux内核必会的75个绝技》选取了资源管理(CPU、内存、进程等)、文件系统、网络、虚拟化、省电、调试、概要分析、追踪、内核调整等Linux内核的核心主题进行了深入剖析和讲解,总结出...
理解Linux内核最好预备的知识点:懂C语言懂一点操作系统的知识熟悉少量相关算法懂计算机体系结构Linux内核的特点:结合了unix操作系统的一些基础概念Linux内核的任务:1.从技术层面讲,内核是硬件与软
linux内核源代码深度解析linux内核源代码深度解析linux内核源代码深度解析linux内核源代码深度解析linux内核源代码深度解析linux内核源代码深度解析linux内核源代码深度解析linux内核源代码深度解析linux内核源代码...
深入理解Linux内核 + Linux内核设计与实现,绝对完整,我最近也在学,建议先学Linux内核设计与实现,对Linux内核有一个大体的认识,在看深入理解Linux内核,要舍得花时间。
linux内核设计说明,Linux内核设计与实现(第三版中文高清带目录)
linux内核管理linux内核管理linux内核管理linux内核管理linux内核管理
linux内核图解linux内核图解linux内核图解linux内核图解linux内核图解
linux内核源代码情景分析,对于深入学习者有很大帮助
ARM Linux内核源码剖析.pdfARM Linux内核源码剖析.pdfARM Linux内核源码剖析.pdfARM Linux内核源码剖析.pdf 完整书签
LINUX内核经典面试题 ,20) 如何加载、卸载一个模块? 21) 模块和应用程序分别运行在什么空间? 22) Linux中的浮点运算由应用程序实现还是内核实现? 23) 模块程序能否使用可链接的库函数? 24) TLB中缓存的是什么...
linux内核解释 linux内核解释 详解
Linux内核完全注释V3.0,很详细很不错,希望喜欢
深入Linux内核.pdf
如何编译你自己的linux内核.txt如何编译你自己的linux内核.txt如何编译你自己的linux内核.txt如何编译你自己的linux内核.txt如何编译你自己的linux内核.txt如何编译你自己的linux内核.txt如何编译你自己的linux内核....
Linux内核的分析,通过本书学习可以了解到Linux的内核机制。
Linux内核编译与裁剪; Linux内核编译与裁剪; Linux内核编译与裁剪; 欢迎下载
Linux内核设计的艺术 Linux内核设计的艺术 Linux内核设计的艺术
此Linux内核学习资料包中有Linux内核--网络栈实现分析(二)--数据包的传递过程(上).pdf Linux内核--网络栈实现分析(三)--驱动程序层+链路层(上).pdf Linux内核--网络栈实现分析(四)--网络层之IP协议(上)....