netlink.docx
《netlink.docx》由会员分享,可在线阅读,更多相关《netlink.docx(109页珍藏版)》请在冰豆网上搜索。
netlink
netlink学习笔记
(一)
Linux——Netlink
最好的参考资料:
1.师从互联网。
2.Linuxman命令:
man netlink,manrtnetlink。
3.UNPv1第18章 。
4.
http:
//en.wikipedia.org/wiki/Netlink
第一条:
概述。
简单说来,linux通过Netlink机制与内核中相应的模块进行通信来掌控设备(网络方面的居多)。
man手册如是说:
Netlink is used totransferinformationbetweenkernelanduserspace processes. Itconsists of a standard sockets-based interface for userspaceprocessesandaninternalkernelAPIforkernelmodules. The internalkernelinterfaceisnotdocumentedinthismanualpage. There is also an obsoletenetlinkinterfacevianetlinkcharacterdevices;thisinterfaceisnotdocumentedhereandisonly provided for backwardscompatibility.
我翻译的:
Netlink用于在内核和用户空间的进程之间通信。
Netlink机制由在用户空间的SocketAPI和内核模块的系统调用组成。
手册不提及内核的系统调用接口。
至于,Netlink字符设备的接口API也没说,Netlink字符设备的接口API是为了向后兼容。
另外:
UNPv1第18章的路由Socket不适用于Linux,linux使用netlink机制全面代替BSD的路由套接口机制。
#define PF_ROUTEPF_NETLINK
题外话:
什么是套接字?
即IP地址和端口的组合。
第二条:
Netlink套接字描述符
intsockfd=socket(AF_NETLINK,sock_type,netlink_faimly);
1.sock_type:
man手册中说:
Netlink is adatagram-orientedservice。
netlink机制是面向数据报的服务,故可以使用SOCK_RAW和SOCK_DGRAM,不能使用SOCK_STREAM。
手册中也提到:
netlink机制不区分数据报(datagram)套接字和原始(raw)套接字。
link_faimly:
指定与哪个内核模块进行通信的协议,如下:
NETLINK_ROUTE:
路由daemon
Receivesroutingandlinkupdatesandmaybeusedtomodify the routing tables(bothIPv4andIPv6),IPaddresses,link parameters,neighborsetups,queueingdisciplines,trafficclassesand packetclassifiers(seertnetlink(7)).
NETLINK_W1:
1-wire子系统
Messagesfrom1-wiresubsystem.
NETLINK_USERSOCK:
用户态socket协议
Reservedforuser-modesocketprotocols.
NETLINK_FIREWALL:
防火墙
Transport IPv4 packets from netfiltertouserspace. Usedby ip_queuekernelmodule.
NETLINK_INET_DIAG:
socket监视
INETsocketmonitoring.
NETLINK_NFLOG:
netfilter日志
Netfilter/iptablesULOG.
NETLINK_XFRM:
ipsec安全策略
IPsec.
NETLINK_SELINUX:
SELinux事件通知
SELinuxeventnotifications.
NETLINK_ISCSI:
iSCSI子系统
Open-iSCSI.
NETLINK_AUDIT:
进程审计
Auditing.
NETLINK_FIB_LOOKUP:
转发信息表查询
AccesstoFIBlookupfromuserspace.
NETLINK_CONNECTOR:
netlinkconnector
Kernelconnector. SeeDocumentation/connector
unsignedshortnl_pad;
__u32nl_pid;
__u32nl_groups;
};
nl_pid:
1.当作为bind函数的参数时,就是给没有名字的socketfd赋上一个名字,只有一个要求在有多个Netlinksocketfd时要保证唯一性,方式一:
由用户保证唯一性:
一个进程只有一个Netlinksocketfd时可以指定nl_pid为任意整数,getpid()是个不错的选择。
但是一个进程有多个Netlinksocketfd时就不能都指定为getpid(),必须加以区别。
方式二:
man手册指出当把nl_pid赋为0,无论一个进程内有几个 Netlinksocketfd,内核将保证他们唯一性。
2.作为sendto等函数的参数:
是用来指定发送数据目的地,当目的地是其他的进程,就赋上那个进程的pid就可,这个几乎用不到。
当放送到内核,直接赋为0.
nl_groups:
对于Netlink的每个协议,都有一个容纳32个多播组的集合。
nl_groups的一个二进制位代表一个组,共有32个。
1.作为bind函数的参数,用于把调用进程加入到该nl_groups指定的多播组(是否可以同时被添加进多个组,就是nl_groups多位为1,未验证),如果设置为0,表示调用者不加入任何多播组。
2.作为sendto等函数的参数时。
若nl_groups为0,配合nl_pid发送单播数据,当nl_groups不为0,配合nl_pid发送多播。
第四条:
Netlink消息。
Netlink与内核通信的消息有两部分:
首部和数据。
首先,Netlinksocket和TCP协议中接收放送数据一样,也需要首部。
主要用于多路复用和多路分解,以及其它的一些控制。
structnlmsghdr{//这个结构就是用于表示首部(头部)。
__u32nlmsg_len;
__u16nlmsg_type;
__u16nlmsg_flags;
__u32nlmsg_seq;
__u32nlmsg_pid;
};
nlmsg_seq和nlmsg_pid用于应用追踪消息,前者表示顺序号,后者为消息来源进程ID。
如果一个消息是由多个数据报组成,也就是说这个消息有多个首部,当然每个首部后面跟着数据部分。
那么除了最后数据报,每个部分的首部都要在nlmsg_flags设置NLM_F_MULTI,最后数据报的首部nlmsg_type设置为NLMSG_DONE。
这种情况多是由内核向用户空间造成的,所以这些标志一般都是由内核赋值的我们不需要赋值,只在接收消息检测这些标志位。
nlmsg_type:
取值如下:
以下四个值一般由内核设置,用于我们接收数据后,检测。
1.NLMSG_NOOP:
message is tobeignored;这个消息类型表示数据内容为空,应用可以忽略该报文
2.NLMSG_ERROR:
messagesignalsanerrorandthepayload containsannlmsgerrstructure 这个消息类型表示数据部分是一个错误信息,数据部分的结构如下
structnlmsgerr {
int
error;
struct
nlmsghdrmsg;
};
3.NLMSG_DONE:
messageterminatesa multipartmessage.在我们接收或者发送消息给内核的时候,可能一次发送多个报文,这个消息类型标志最后一个报文。
4.NLMSG_OVERRUN :
Datalost。
以下是由程序员设置的,这里的是NETLINK_ROUTE协议支持的类型,至于其他协议的有待研究,每种类型对应着后面数据部分的不同承载结构。
使用NETLINK_ROUTE协议时候支持的类型如下,他们都定义在linux/rtnetlink.h中:
1.LinkLayer:
创建,删除、获取、设置网络设备的信息:
RTM_NEWLINK,RTM_DELLINK,RTM_GETLINK,RTM_SETLINK
对应数据部分数据结构:
在linux/rtnetlink.h中
structifinfomsg{
unsignedchar ifi_family;
unsignedchar __ifi_pad;
unsignedshort ifi_type;
int ifi_index;
unsigned ifi_flags;
unsigned ifi_change;
};
2.AddressSettings:
创建,删除、获取网络设备的IP信息:
RTM_NEWADDR,RTM_DELADDR,RTM_GETADDR
对应数据部分数据结构:
在linux/if_addr.h中
structifaddrmsg{
__u8 ifa_family;
__u8 ifa_prefixlen;
__u8 ifa_flags;
__u8 ifa_scope;
__u32 ifa_index;
};
3.RoutingTables:
创建,删除、获取网络设备的路由信息:
RTM_NEWROUTE,RTM_DELROUTE,RTM_GETROUTE
对应数据部分数据结构:
在linux/rtnetlink.h中
structrtmsg{//Definitionsusedinroutingtableadministration.
unsignedchar rtm_family;
unsignedchar rtm_dst_len;
unsignedchar rtm_src_len;
unsignedchar rtm_tos;
unsignedchar rtm_table;
unsignedchar rtm_protocol;
unsignedchar rtm_scope;
unsignedchar rtm_type;
unsigned rtm_flags;
};
4.NeighborCache:
创建,删除、获取网络设备的相邻信息:
RTM_NEWNEIGH,RTM_DELNEIGH,RTM_GETNEIGH
对应数据部分数据结构:
在linux/neighbour.h中
structndmsg{
__u8 ndm_family;
__u8 ndm_pad1;
__u16 ndm_pad2;
__s32 ndm_ifindex;
__u16 ndm_state;
__u8 ndm_flags;
__u8 ndm_type;
};
structnda_cacheinfo{
__u32 ndm_confirmed;
__u32 ndm_used;
__u32 ndm_updated;
__u32 ndm_refcnt;
};
5.RoutingRules:
创建,删除、获取路由规则信息:
RTM_NEWRULE,RTM_DELRULE,RTM_GETRULE
对应数据部分数据结构:
在linux/rtnetlink.h中structrtmsg
6.QueuingDisciplineSettings:
创建,删除、获取队列的原则:
RTM_NEWQDISC,RTM_DELQDISC,RTM_GETQDISC
对应数据部分数据结构:
在linux/rtnetlink.h中
structtcmsg{//Trafficcontrolmessages.
unsignedchar tcm_family;
unsignedchar tcm__pad1;
unsignedshort tcm__pad2;
int tcm_ifindex;
__u32 tcm_handle;
__u32 tcm_parent;
__u32 tcm_info;
};
7.TrafficClassesusedwithQueues:
创建,删除、获取流量的类别:
RTM_NEWTCLASS,RTM_DELTCLASS,RTM_GETTCLASS
对应数据部分数据结构:
linux/rtnetlink.h中structtcmsg
8.Trafficfilters:
创建,删除、获取流量的过虑:
RTM_NEWTFILTER,RTM_DELTFILTER,RTM_GETTFILTER
对应数据部分数据结构:
linux/rtnetlink.h中structtcmsg
9.Others:
RTM_NEWACTION, RTM_DELACTION, RTM_GETACTION, RTM_NEWPREFIX, RTM_GETPREFIX, RTM_GETMULTICAST,
RTM_GETANYCAST,RTM_NEWNEIGHTBL,RTM_GETNEIGHTBL, RTM_SETNEIGHTBL
nlmsg_flags:
这个成员用于控制和表示消息,值如下:
1.Standardflagbitsinnlmsg_flags
NLM_F_REQUEST Mustbesetonallrequestmessages.表示消息是一个请求,所有应用首先发起的消息都应设置该标志。
,这个标志可以和以下的一个标志组合
∙NLM_F_ROOT 被许多netlink协议的各种数据获取操作使用,该标志指示被请求的数据表应当整体返回用户应用,而不是一个条目一个条目地返回。
有该标志的请求通常导致响应消息设置NLM_F_MULTI标志。
注意,当设置了该标志时,请求是协议特定的,因此,需要在字段nlmsg_type中指定协议类型。
∙NLM_F_MATCH 表示该协议特定的请求只需要一个数据子集,数据子集由指定的协议特定的过滤器来匹配。
∙NLM_F_ATOMIC返回对象表的快照
∙NLM_F_DUMP被定义为NLM_F_ROOT|NLM_F_MATCH
∙NLM_F_REPLACE 用于取代在数据表中的现有条目。
∙NLM_F_EXCL 用于和CREATE和APPEND配合使用,如果条目已经存在,将失败。
∙NLM_F_CREAT 指示应当在指定的表中创建一个条目。
∙NLM_F_APPEND 指示在表末尾添加新的条目。
NLM_F_MULTI The message ispartofamultipartmessageterminatedbyNLMSG_DONE. 用于指示该消息是一个多部分消息的一部分,后续的消息可以通过宏NLMSG_NEXT来获得。
NLM_F_ACK Requestforanacknowledgmentonsuccess.表示该消息是前一个请求消息的响应,顺序号与进程ID可以把请求与响应关联起来。
NLM_F_ECHO Echothisrequest.表示该消息是相关的一个包的回传。
2.AdditionalflagbitsforGETrequests
NLM_F_ROOT Returnthecompletetableinsteadofasingleentry.
NLM_F_MATCH Returnallentriesmatching criteria(标准,要求) passed in message content. Notimplementedyet.
NLM_F_ATOMIC Returnanatomicsnapshotofthetable.
NLM_F_DUMP Conveniencemacro;equivalentto(NLM_F_ROOT|NLM_F_MATCH).
Note that NLM_F_ATOMIC requires the CAP_NET_ADMINcapabilityoran effectiveUIDof0.
3.AdditionalflagbitsforNEWrequests
NLM_F_REPLACE Replaceexistingmatchingobject.
NLM_F_EXCL Don'treplaceiftheobjectalreadyexists.
NLM_F_CREATE Createobjectifitdoesn'talreadyexist.
NLM_F_APPEND Addtotheendoftheobjectlist.
第五条Netlink与内核通信
Linux定义了多个宏,来辅助我们发送和接收Netlink消息,与内核进行通信。
#include
#include
1.intNLMSG_ALIGN(size_tlen);
#defineNLMSG_ALIGNTO4
#defineNLMSG_ALIGN(len)(((len)+NLMSG_ALIGNTO-1)&~(NLMSG_ALIGNTO-1))
//宏NLMSG_ALIGN(len)用于得到不小于len且字节对齐的最小数值。
2.#defineNLMSG_HDRLEN ((int)NLMSG_ALIGN(sizeof(structnlmsghdr)))
//头部长度
3.intNLMSG_LENGTH(size_tlen);
#defineNLMSG_LENGTH(len)((len)+NLMSG_ALIGN(NLMSG_HDRLEN))
//宏NLMSG_LENGTH(len)用于计算数据部分长度为len时实际的消息长度。
它一般用于分配消息缓存。
4.intNLMSG_SPACE(size_tlen);
#defineNLMSG_SPACE(len)NLMSG_ALIGN(NLMSG_LENGTH(len))
//宏NLMSG_SPACE(len)返回不小于NLMSG_LENGTH(len)且字节对齐的最小数值,它也用于分配消息缓存。
5.void*NLMSG_DATA(structnlmsghdr*nlh);
#defineNLMSG_DATA(nlh) ((void*)(((char*)nlh)+NLMSG_LENGTH(0)))
//宏NLMSG_DATA(nlh)用于取得消息的数据部分的首地址,设置和读取消息数据部分时需要使用该宏。
6.structnlmsghdr*NLMSG_NEXT(structnlmsghdr*nlh,intlen);
#defineNLMSG_NEXT(nlh,len)((len)-=NLMSG_ALIGN((nlh)->nlmsg_len), (structnlmsghdr*)(((char*)(nlh))+NLMSG_ALIGN((nlh)->nlmsg_len)))
//宏NLMSG_NEXT(nlh,len)用于得到下一个消息的首地址,同时len也减少为剩余消息的总长度,该宏一般在一个消息被分成几个部分发送或接收时使用。
7.intNLMSG_OK(structnlmsghdr*nlh,intlen);
#defineNLMSG_OK(nlh,len)((len)>=(int)sizeof(structnlmsghdr)&& (nlh)->nlmsg_len>=sizeof(structnlmsghdr)&& (nlh)->nlmsg_len<=(len))
//宏NLMSG_OK(nlh,len)用于判断消息是否有len这么长。
8.intNLMSG_PAYL