ImageVerifierCode 换一换
格式:DOC , 页数:29 ,大小:106.50KB ,
资源ID:9009267      下载积分:10 金币
验证码下载
登录下载
邮箱/手机:
图形码:
验证码: 获取验证码
温馨提示:
支付成功后,系统会自动生成账号(用户名为邮箱或者手机号,密码是验证码),方便下次登录下载和查询订单;
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

开通VIP
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.zixin.com.cn/docdown/9009267.html】到电脑端继续下载(重复下载【60天内】不扣币)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

开通VIP折扣优惠下载文档

            查看会员权益                  [ 下载后找不到文档?]

填表反馈(24小时):  下载求助     关注领币    退款申请

开具发票请登录PC端进行申请。


权利声明

1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前可先查看【教您几个在下载文档中可以更好的避免被坑】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时联系平台进行协调解决,联系【微信客服】、【QQ客服】,若有其他问题请点击或扫码反馈【服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【版权申诉】”,意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:4009-655-100;投诉/维权电话:18658249818。

注意事项

本文(在 Linux 下用户空间和内核空间数据交换的方式.doc)为本站上传会员【pc****0】主动上传,咨信网仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知咨信网(发送邮件至1219186828@qq.com、拔打电话4009-655-100或【 微信客服】、【 QQ客服】),核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载【60天内】不扣币。 服务填表

在 Linux 下用户空间和内核空间数据交换的方式.doc

1、 本系列文章包括两篇,他们文周详地地介绍了Linux系统下用户空间和内核空间数据交换的九种方式,包括内核启动参数、模块参数和sysfs、 sysctl、系统调用、netlink、procfs、seq_file、debugfs和relayfs,并给出具体的例子帮助读者掌控这些技术的使 用。 本文是该系列文章的第二篇,他介绍了procfs、seq_file、debugfs和relayfs,并结合给出的例子程式周详地说明了他们怎么使用。 1、内核启动参数 Linux 提供了一种通过 bootloader 向其传输启动参数的功能,内核研发者能通过这种方式来向内核传输数据,从而控制内核启

2、动行为。 通常的使用方式是,定义一个分析参数的函数,而后使用内核提供的宏 __setup把他注册到内核中,该宏定义在 linux/init.h 中,因此要使用他必须包含该头文件: __setup("para_name=", parse_func) para_name 为参数名,parse_func 为分析参数值的函数,他负责把该参数的值转换成相应的内核变量的值并设置那个内核变量。内核为整数参数值的分析提供了函数 get_option 和 get_options,前者用于分析参数值为一个整数的情况,而后者用于分析参数值为逗号分割的一系列整数的情况,对于参数值为字符串的情况,需要研发

3、者自定义相应的分析函数。在原始码包中的内核程式kern-boot-params.c 说明了三种情况的使用。该程式列举了参数为一个整数、逗号分割的整数串及字符串三种情况,读者要想测试该程式,需要把该程式拷贝到要使用的内核的源码目 录树的一个目录下,为了避免和内核其他部分混淆,作者建议在内核源码树的根目录下创建一个新目录,如 examples,然后把该程式拷贝到 examples 目录下并重新命名为 setup_example.c,并且为该目录创建一个 Makefile 文件: obj-y = setup_example.o Makefile 仅许这一行就足够了,然后需要修改源码树的根目

4、录下的 Makefile文件的一行,把下面行 core-y          := usr/ 修改为 core-y          := usr/ examples/ 注意:如果读者创建的新目录和重新命名的文件名和上面不同,需要修改上面所说 Makefile 文件相应的位置。 做完以上工作就能按照内核构建步骤去构建新的内核,在构建好内核并设置好lilo或grub为该内核的启动条目后,就能启动该内核,然后使用lilo或grub的编辑功能为该内核的启动参数行增加如下参数串: setup_example_int=1234 setup_example_int_array=100,200,

5、300,400 setup_example_string=Thisisatest 当然,该参数串也能直接写入到lilo或grub的设置文件中对应于该新内核的内核命令行参数串中。读者能使用其他参数值来测试该功能。 下面是作者系统上使用上面参数行的输出: setup_example_int=1234 setup_example_int_array=100,200,300,400 setup_example_int_array includes 4 intergers setup_example_string=Thisisatest 读者能使用 dmesg | grep setup

6、 来查看该程式的输出。 2、模块参数和sysfs 内核子系统或设备驱动能直接编译到内核,也能编译成模块,如果编译到内核,能使用前一节介绍的方法通过内核启动参数来向他们传递参数,如果编译成模块,则能通过命令行在插入模块时传递参数,或在运行时,通过sysfs来设置或读取模块数据。 Sysfs是个基于内存的文件系统,实际上他基于ramfs,sysfs提供了一种把内核数据结构,他们的属性及属性和数据结构的联系开放给用 户态的方式,他和kobject子系统紧密地结合在一起,因此内核研发者不必直接使用他,而是内核的各个子系统使用他。用户要想使用 sysfs 读取和设置内核参数,仅需装载

7、sysfs 就能通过文件操作应用来读取和设置内核通过 sysfs 开放给用户的各个参数: $ mkdir -p /sysfs $ mount -t sysfs sysfs /sysfs 注意,不要把 sysfs 和 sysctl 混淆,sysctl 是内核的一些控制参数,其目的是方便用户对内核的行为进行控制,而 sysfs 仅仅是把内核的 kobject 对象的层次关系和属性开放给用户查看,因此 sysfs 的绝大部分是只读的,模块作为一个 kobject 也被出口到 sysfs,模块参数则是作为模块属性出口的,内核实现者为模块的使用提供了更灵活的方式,允许用户设置模块参数在 sy

8、sfs 的可见性并允许用户在编写模块时设置这些参数在 sysfs 下的访问权限,然后用户就能通过sysfs 来查看和设置模块参数,从而使得用户能在模块运行时控制模块行为。 对于模块而言,声明为 static 的变量都能通过命令行来设置,但要想在 sysfs下可见,必须通过宏 module_param 来显式声明,该宏有三个参数,第一个为参数名,即已定义的变量名,第二个参数则为变量类型,可用的类型有 byte, short, ushort, int, uint, long, ulong, charp 和 bool 或 invbool,分别对应于 c 类型 char, short, un

9、signed short, int, unsigned int, long, unsigned long, char * 和 int,用户也能自定义类型 XXX(如果用户自己定义了 param_get_XXX,param_set_XXX 和 param_check_XXX)。该宏的第三个参数用于指定访问权限,如果为 0,该参数将不出目前 sysfs 文件系统中,允许的访问权限为 S_IRUSR, S_IWUSR,S_IRGRP,S_IWGRP,S_IROTH 和 S_IWOTH 的组合,他们分别对应于用户读,用户写,用户组读,用户组写,其他用户读和其他用户写,因此用文件的访问权限设置是

10、一致的。 在 原始码包 中的内核模块 module-param-exam.c 是个利用模块参数和sysfs来进行用户态和内核态数据交互的例子。该模块有三个参数能通过命令行设置,下面是作者系统上的运行结果示例: $ insmod ./module-param-exam.ko my_invisible_int=10 my_visible_int=20 mystring="Hello,World" my_invisible_int = 10 my_visible_int = 20 mystring = ’Hello,World’ $ ls /sys/module/module_par

11、am_exam/parameters/ mystring  my_visible_int $ cat /sys/module/module_param_exam/parameters/mystring Hello,World $ cat /sys/module/module_param_exam/parameters/my_visible_int 20 $ echo 2000 > /sys/module/module_param_exam/parameters/my_visible_int $ cat /sys/module/module_param_exam/parameter

12、s/my_visible_int 2000 $ echo "abc" > /sys/module/module_param_exam/parameters/mystring $ cat /sys/module/module_param_exam/parameters/mystring abc $ rmmod module_param_exam my_invisible_int = 10 my_visible_int = 2000 mystring = ’abc’ 3、sysctl Sysctl是一种用户应用来设置和获得运行时内核的设置参数的一种有效方式,通过这种方式

13、用户应用能在内核运行的所有时刻来改动内核的设置参 数,也能在所有时候获得内核的设置参数,通常,内核的这些设置参数也出目前proc文件系统的/proc/sys目录下,用户应用能直接通过这个目录 下的文件来实现内核设置的读写操作,例如,用户能通过 Cat /proc/sys/net/ipv4/ip_forward 来得知内核IP层是否允许转发IP包,用户能通过 echo 1 > /proc/sys/net/ipv4/ip_forward 把内核 IP 层设置为允许转发 IP 包,即把该机器设置成一个路由器或网关。 一般地,所有的 Linux 发布也提供了一个系统工具 sysctl,

14、他能设置和读取内核的设置参数,不过该工具依赖于 proc 文件系统,为了使用该工具,内核必须支持 proc 文件系统。下面是使用 sysctl 工具来获取和设置内核设置参数的例子: $ sysctl net.ipv4.ip_forward net.ipv4.ip_forward = 0 $ sysctl -w net.ipv4.ip_forward=1 net.ipv4.ip_forward = 1 $ sysctl net.ipv4.ip_forward net.ipv4.ip_forward = 1 注意,参数 net.ipv4.ip_forward 实际被转换到对应的 pr

15、oc 文件/proc/sys/net/ipv4/ip_forward,选项 -w 表示设置该内核设置参数,没有选项表示读内核设置参数,用户能使用 sysctl -a 来读取所有的内核设置参数,对应更多的 sysctl 工具的信息,请参考手册页 sysctl(8)。 不过 proc 文件系统对 sysctl 不是必须的,在没有 proc 文件系统的情况下,仍然能,这时需要使用内核提供的系统调用 sysctl 来实现对内核设置参数的设置和读取。 在 原始码包 中 给出了一个实际例子程式,他说明了怎么在内核和用户态使用sysctl。头文件 sysctl-exam.h 定义了 sysct

16、l 条目 ID,用户态应用和内核模块需要这些 ID 来操作和注册 sysctl 条目。内核模块在文件 sysctl-exam-kern.c 中实现,在该内核模块中,每一个 sysctl 条目对应一个 struct ctl_table 结构,该结构定义了要注册的 sysctl 条目的 ID(字段 ctl_name),在 proc 下的名称(字段procname),对应的内核变量(字段data,注意该该字段的赋值必须是指针),条目允许的最大长度(字段maxlen,他主要用于 字符串内核变量,以便在对该条目设置时,对超过该最大长度的字符串截掉后面超长的部分),条目在proc文件系统下的访问

17、权限(字段mode),在通过 proc设置时的处理函数(字段proc_handler,对于整型内核变量,应当设置为&proc_dointvec,而对于字符串内核变量, 则设置为 &proc_dostring),字符串处理策略(字段strategy,一般这是为&sysctl_string)。 Sysctl 条目能是目录,此时 mode 字段应当设置为 0555,否则通过 sysctl 系统调用将无法访问他下面的 sysctl 条目,child 则指向该目录条目下面的所有条目,对于在同一目录下的多个条目,不必一一注册,用户能把他们组织成一个 struct ctl_table 类型的数组,

18、然后一次注册就能,但此时必须把数组的最后一个结构设置为NULL,即 {         .ctl_name = 0 } 注册sysctl条目使用函数register_sysctl_table(struct ctl_table *, int),第一个参数为定义的struct ctl_table结构的sysctl条目或条目数组指针,第二个参数为插入到sysctl条目表中的位置,如果插入到末尾,应当为0,如果插入到开头, 则为非0。内核把所有的sysctl条目都组织成sysctl表。 当模块卸载时,需要使用函数unregister_sysctl_table(struct ctl_ta

19、ble_header *)解注册通过函数register_sysctl_table注册的sysctl条目,函数register_sysctl_table在调用成功时返 回结构struct ctl_table_header,他就是sysctl表的表头,解注册函数使用他来卸载相应的sysctl条目。 用户态应用sysctl-exam-user.c通过sysctl系统调用来查看和设置前面内核模块注册的sysctl条目(当然如果用户的系统内核已 支持proc文件系统,能直接使用文件操作应用如cat, echo等直接查看和设置这些sysctl条目)。 下面是作者运行该模块和应用的输出结果示例:

20、 $ insmod ./sysctl-exam-kern.ko $ cat /proc/sys/mysysctl/myint 0 $ cat /proc/sys/mysysctl/mystring $ ./sysctl-exam-user mysysctl.myint = 0 mysysctl.mystring = "" $ ./sysctl-exam-user 100 "Hello, World" old value: mysysctl.myint = 0 new value: mysysctl.myint = 100 old vale: mysysctl.mystri

21、ng = "" new value: mysysctl.mystring = "Hello, World" $ cat /proc/sys/mysysctl/myint 100 $ cat /proc/sys/mysysctl/mystring Hello, World $ 4、系统调用 系统调用是内核提供给应用程式的接口,应用对底层硬件的操作大部分都是通过调用系统调用来完成的,例如得到和设置系统时间,就需要分别调用 gettimeofday 和 settimeofday 来实现。事实上,所有的系统调用都涉及到内核和应用之间的数据交换,如文件系统操作函数 rea

22、d 和 write,设置和读取网络协议栈的 setsockopt 和 getsockopt。本节并不是讲解怎么增加新的系统调用,而是讲解怎么利用现有系统调用来实现用户的数据传输需求。 一般地,用户能建立一个伪设备来作为应用和内核之间进行数据交换的渠道,最通常的做法是使用伪字符设备,具体实现方法是: 1.定义对字符设备进行操作的必要函数并设置结构 struct file_operations 结构 struct file_operations 非常大,对于一般的数据交换需求,只定义 open, read, write, ioctl, mmap 和 release 函数就足够了,他们实际

23、上对应于用户态的文件系统操作函数 open, read, write, ioctl, mmap 和 close。这些函数的原型示例如下: ssize_t exam_read (struct file * file, char __user * buf, size_t count, loff_t * ppos) { … } ssize_t exam_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos) { … } int exam_ioctl(struct inode *

24、 inode, struct file * file, unsigned int cmd, unsigned long argv) { … } int exam_mmap(struct file *, struct vm_area_struct *) { … } int exam_open(struct inode * inode, struct file * file) { … } int exam_release(struct inode * inode, struct file * file) { … } 在定义了这些操作函数后需要定义并设置结构struc

25、t file_operations struct file_operations exam_file_ops = {         .owner = THIS_MODULE,         .read = exam_read,         .write = exam_write,         .ioctl = exam_ioctl,         .mmap = exam_mmap,         .open = exam_open,         .release = exam_release, }; 2. 注册定义的伪字符设备并把他和上面的 struc

26、t file_operations 关联起来: int exam_char_dev_major; exam_char_dev_major = register_chrdev(0, "exam_char_dev", &exam_file_ops); 注意,函数 register_chrdev 的第一个参数如果为 0,表示由内核来确定该注册伪字符设备的主设备号,这是该函数的返回为实际分配的主设备号,如果返回小于 0,表示注册失败。因此,用户在使用该函数时必须判断返回值以便处理失败情况。为了使用该函数必须包含头文件 linux/fs.h。 在原始码包中给出了一个使用这种方式实现用户态和内

27、核态数据交换的典型例子,他包含了三个文件: 头文件 syscall-exam.h 定义了 ioctl 命令,.c 文件 syscall-exam-user.c为用户态应用,他通过文件系统操作函数 mmap 和 ioctl 来和内核态模块交换数据,.c 文件 syscall-exam-kern.c 为内核模块,他实现了一个伪字符设备,以便和用户态应用进行数据交换。为了正确运行应用程式 syscall-exam-user,需要在插入模块 syscall-exam-kern 后创建该实现的伪字符设备,用户能使用下面命令来正确创建设备: $ mknod /dev/mychrdev c `d

28、mesg | grep "char device mychrdev" | sed ’s/.*major is //g’` 0 然后用户能通过 cat 来读写 /dev/mychrdev,应用程式 syscall-exam-user则使用 mmap 来读数据并使用 ioctl 来得到该字符设备的信息及裁减数据内容,他只是示例怎么使用现有的系统调用来实现用户需要的数据交互操作。 下面是作者运行该模块的结果示例: $ insmod ./syscall-exam-kern.ko char device mychrdev is registered, major is 254 $ mknod

29、/dev/mychrdev c `dmesg | grep "char device mychrdev" | sed ’s/.*major is //g’` 0 $ cat /dev/mychrdev $ echo "abcdefghijklmnopqrstuvwxyz" > /dev/mychrdev $ cat /dev/mychrdev abcdefghijklmnopqrstuvwxyz $ ./syscall-exam-user User process: syscall-exam-us(1433) Available space: 65509 bytes Data

30、len: 27 bytes Offset in physical: cc0 bytes mychrdev content by mmap: abcdefghijklmnopqrstuvwxyz $ cat /dev/mychrdev abcde $ 5、netlink Netlink 是一种特别的 socket,他是 Linux 所特有的,类似于 BSD 中的AF_ROUTE 但又远比他的功能强大,目前在最新的 Linux 内核(2.6.14)中使用netlink 进行应用和内核通信的应用非常多,包括:路由 daemon(NETLINK_ROUTE),1-wire

31、子系统(NETLINK_W1),用户态 socket 协议(NETLINK_USERSOCK),防火墙(NETLINK_FIREWALL),socket 监视(NETLINK_INET_DIAG),netfilter 日志(NETLINK_NFLOG),ipsec 安全策略(NETLINK_XFRM),SELinux 事件通知(NETLINK_SELINUX),iSCSI 子系统(NETLINK_ISCSI),进程审计(NETLINK_AUDIT),转发信息表查询(NETLINK_FIB_LOOKUP), netlink connector(NETLINK_CONNECTOR),ne

32、tfilter 子系统(NETLINK_NETFILTER),IPv6 防火墙(NETLINK_IP6_FW),DECnet 路由信息(NETLINK_DNRTMSG),内核事件向用户态通知(NETLINK_KOBJECT_UEVENT),通用 netlink(NETLINK_GENERIC)。 Netlink 是一种在内核和用户应用间进行双向数据传输的非常好的方式,用户态应用使用标准的 socket API 就能使用 netlink 提供的强大功能,内核态需要使用专门的内核 API 来使用 netlink。 Netlink 相对于系统调用,ioctl 及 /proc 文件系统而言具

33、有以下好处: 1,为了使用 netlink,用户仅需要在 include/linux/netlink.h 中增加一个新类型的 netlink 协议定义即可, 如 #define NETLINK_MYTEST 17 然后,内核和用户态应用就能即时通过 socket API 使用该 netlink 协议类型进行数据交换。但系统调用需要增加新的系统调用,ioctl 则需要增加设备或文件, 那需要不少代码,proc 文件系统则需要在 /proc 下添加新的文件或目录,那将使本来就混乱的 /proc 更加混乱。 2. netlink是一种异步通信机制,在内核和用户态应用之间传递的消息保存

34、在socket缓存队列中,发送消息只是把消息保存在接收者的socket的接 收队列,而不必等待接收者收到消息,但系统调用和 ioctl 则是同步通信机制,如果传递的数据太长,将影响调度粒度。 3.使用 netlink 的内核部分能采用模块的方式实现,使用 netlink 的应用部分和内核部分没有编译时依赖,但系统调用就有依赖,而且新的系统调用的实现必须静态地连接到内核中,他无法在模块中实现,使用新系统调用的应用在编译时需要依赖内核。 4.netlink 支持多播,内核模块或应用能把消息多播给一个netlink组,属于该neilink 组的所有内核模块或应用都能接收到该消息,内核事件向用

35、户态的通知机制就使用了这一特性,所有对内核事件感兴趣的应用都能收到该子系统发送的内核事件,在 后面的文章中将介绍这一机制的使用。 5.内核能使用 netlink 首先发起会话,但系统调用和 ioctl 只能由用户应用发起调用。 6.netlink 使用标准的 socket API,因此非常容易使用,但系统调用和 ioctl则需要专门的培训才能使用。 用户态使用 netlink 用户态应用使用标准的socket APIs, socket(), bind(), sendmsg(), recvmsg() 和 close() 就能非常容易地使用 netlink socket,查询手册页能了

36、解这些函数的使用细节,本文只是讲解使用 netlink 的用户应该怎么使用这些函数。注意,使用 netlink 的应用必须包含头文件 linux/netlink.h。当然 socket 需要的头文件也必不可少,sys/socket.h。 为了创建一个 netlink socket,用户需要使用如下参数调用 socket(): socket(AF_NETLINK, SOCK_RAW, netlink_type) 第一个参数必须是 AF_NETLINK 或 PF_NETLINK,在 Linux 中,他们俩实际为一个东西,他表示要使用netlink,第二个参数必须是SOCK_RAW或SO

37、CK_DGRAM, 第三个参数指定netlink协议类型,如前面讲的用户自定义协议类型NETLINK_MYTEST, NETLINK_GENERIC是个通用的协议类型,他是专门为用户使用的,因此,用户能直接使用他,而不必再添加新的协议类型。内核预定义的协议类 型有: #define NETLINK_ROUTE           0       /* Routing/device hook                          */ #define NETLINK_W1              1       /* 1-wire subsystem          

38、                  */ #define NETLINK_USERSOCK        2       /* Reserved for user mode socket protocols      */ #define NETLINK_FIREWALL        3       /* Firewalling hook                             */ #define NETLINK_INET_DIAG       4       /* INET socket monitoring                       */ #d

39、efine NETLINK_NFLOG           5       /* netfilter/iptables ULOG */ #define NETLINK_XFRM            6       /* ipsec */ #define NETLINK_SELINUX         7       /* SELinux event notifications */ #define NETLINK_ISCSI           8       /* Open-iSCSI */ #define NETLINK_AUDIT           9       /* au

40、diting */ #define NETLINK_FIB_LOOKUP      10 #define NETLINK_CONNECTOR       11 #define NETLINK_NETFILTER       12      /* netfilter subsystem */ #define NETLINK_IP6_FW          13 #define NETLINK_DNRTMSG         14      /* DECnet routing messages */ #define NETLINK_KOBJECT_UEVENT  15      /*

41、Kernel messages to userspace */ #define NETLINK_GENERIC         16 对于每一个netlink协议类型,能有多达 32多播组,每一个多播组用一个位表示,netlink 的多播特性使得发送消息给同一个组仅需要一次系统调用,因而对于需要多拨消息的应用而言,大大地降低了系统调用的次数。 函数 bind() 用于把一个打开的 netlink socket 和 netlink 源 socket 地址绑定在一起。netlink socket 的地址结构如下: struct sockaddr_nl {   sa_family_t 

42、  nl_family;   unsigned short nl_pad;   __u32          nl_pid;   __u32          nl_groups; }; 字段 nl_family 必须设置为 AF_NETLINK 或着 PF_NETLINK,字段 nl_pad 当前没有使用,因此要总是设置为 0,字段 nl_pid 为接收或发送消息的进程的 ID,如果希望内核处理消息或多播消息,就把该字段设置为 0,否则设置为处理消息的进程 ID。字段 nl_groups 用于指定多播组,bind 函数用于把调用进程加入到该字段指定的多播组,如果设置为 0,表

43、示调用者不加入所有多播组。 传递给 bind 函数的地址的 nl_pid 字段应当设置为本进程的进程 ID,这相当于 netlink socket 的本地地址。不过,对于一个进程的多个线程使用 netlink socket 的情况,字段 nl_pid 则能设置为其他的值,如: pthread_self() 因此字段 nl_pid 实际上未必是进程 ID,他只是用于区分不同的接收者或发送者的一个标识,用户能根据自己需要设置该字段。函数  bind 的调用方式如下: bind(fd, (struct sockaddr*)&nladdr, sizeof(struct sockaddr_nl

44、)); fd为前面的 socket 调用返回的文件描述符,参数 nladdr 为 struct sockaddr_nl 类型的地址。 为了发送一个 netlink 消息给内核或其他用户态应用,需要填充目标 netlink socket 地址 ,此时,字段 nl_pid 和 nl_groups 分别表示接收消息者的进程 ID 和多播组。如果字段 nl_pid 设置为 0,表示消息接收者为内核或多播组,如果 nl_groups为 0,表示该消息为单播消息,否则表示多播消息。 使用函数 sendmsg 发送 netlink 消息时还需要引用结构 struct msghdr、struct nl

45、msghdr 和 struct iovec,结构 struct msghdr 需如下设置: struct msghdr msg; memset(&msg, 0, sizeof(msg)); msg.msg_name = (void *)&(nladdr); msg.msg_namelen = sizeof(nladdr); 其中 nladdr 为消息接收者的 netlink 地址。 struct nlmsghdr 为 netlink socket 自己的消息头,这用于多路复用和多路分解 netlink 定义的所有协议类型及其他一些控制,netlink 的内核实现将利用这个消息头

46、来多路复用和多路分解已其他的一些控制,因此他也被称为netlink 控制块。因此,应用在发送 netlink 消息时必须提供该消息头。 struct nlmsghdr {   __u32 nlmsg_len;   /* Length of message */   __u16 nlmsg_type;  /* Message type*/   __u16 nlmsg_flags; /* Additional flags */   __u32 nlmsg_seq;   /* Sequence number */   __u32 nlmsg_pid;   /* Sending pro

47、cess PID */ }; 字段 nlmsg_len 指定消息的总长度,包括紧跟该结构的数据部分长度及该结构的大小,字段 nlmsg_type 用于应用内部定义消息的类型,他对 netlink 内核实现是透明的,因此大部分情况下设置为 0,字段 nlmsg_flags 用于设置消息标志,可用的标志包括: /* Flags values */ #define NLM_F_REQUEST           1       /* It is request message.       */ #define NLM_F_MULTI             2       /* Mu

48、ltipart message, terminated by NLMSG_DONE */ #define NLM_F_ACK               4       /* Reply with ack, with zero or error code */ #define NLM_F_ECHO              8       /* Echo this request            */ /* Modifiers to GET request */ #define NLM_F_ROOT      0x100   /* specify tree root    */

49、 #define NLM_F_MATCH     0x200   /* return all matching  */ #define NLM_F_ATOMIC    0x400   /* atomic GET           */ #define NLM_F_DUMP      (NLM_F_ROOT|NLM_F_MATCH) /* Modifiers to NEW request */ #define NLM_F_REPLACE   0x100   /* Override existing            */ #define NLM_F_EXCL      0x200

50、   /* Do not touch, if it exists   */ #define NLM_F_CREATE    0x400   /* Create, if it does not exist */ #define NLM_F_APPEND    0x800   /* Add to end of list           */ 标志NLM_F_REQUEST用于表示消息是个请求,所有应用首先发起的消息都应设置该标志。 标志NLM_F_MULTI 用于指示该消息是个多部分消息的一部分,后续的消息能通过宏NLMSG_NEXT来获得。 宏NLM_F_ACK表示该消息是前一个请

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:4009-655-100  投诉/维权电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服