欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Generic Netlink(genl)介绍与例子

程序员文章站 2024-03-23 13:24:28
...

一、Generic Netlink介绍

介绍Generic Netlink之前,不得不说Netlink。Netlink是一种灵活的并且健壮的通讯方式,可以用于kernel to user、user to kernel、kernel to kernel甚至user to user的通讯。Netlink的通道是通过Family来组织的,但随着使用越来越多,Family ID已经不够分配了,所以才有了Generic Netlink。

所以,Generic Netlink其实是对Netlink报文中的数据进行了再次封装。


二、genl架构

    +---------------------+      +---------------------+
     | (3) application "A" |      | (3) application "B" |
     +------+--------------+      +--------------+------+
            |                                    |
            \                                    /
             \                                  /
              |                                |
      +-------+--------------------------------+-------+
      |        :                               :       |   user-space
 =====+        :   (5)  kernel socket API      :       +================
      |        :                               :       |   kernel-space
      +--------+-------------------------------+-------+
               |                               |
         +-----+-------------------------------+----+
         |        (1)  Netlink subsystem            |
         +---------------------+--------------------+
                               |
         +---------------------+--------------------+
         |       (2) Generic Netlink bus            |
         +--+--------------------------+-------+----+
            |                          |       |
    +-------+---------+                |       |
    |  (4) controller |               /         \
    +-----------------+              /           \
                                     |           |
                  +------------------+--+     +--+------------------+
                  | (3) kernel user "X" |     | (3) kernel user "Y" |
                  +---------------------+     +---------------------+
genl架构图,https://wiki.linuxfoundation.org/networking/generic_netlink_howto#architectural-overview


三、genl数据包结构

要理解genl的程序,必须先了解genl数据包的结构。数据包的结构如下图所示

Generic Netlink(genl)介绍与例子

genl机制的数据包分了4层,用户的实际数据封装在attribute里,一个或多个attribute可以被封装在用户自定义的一个family报文里,一个family报文又被封装在genlmsg里,最后genlmsg被封装在nlmsg里,总共4层。


四、流程说明

1. 对于从user to kernel的通讯,driver必须先向内核注册一个struct genl_family,并且注册一些cmd的处理函数。这些cmd是跟某个family关联起来的。注册family的时候我们可以让内核自动为这个family分配一个ID。每个family都有一个唯一的ID,其中ID号0x10是被内核的nlctrl family所使用。当注册成功以后,如果user program向某个family发送cmd,那么内核就会回调对应cmd的处理函数。对于user program,使用前,除了要创建一个socket并绑定地址以外,还需要先通过family的名字获取family的ID。获取方法,就是向nlctrl这个family查询。详细的方法可以看后面的例子。有了family的ID以后,才能向该family发送cmd。


2.对于从kernel to user的通讯,采用的是广播的形式,只要user program监听了,都能收到。但是同样的,user program在监听前,也必须先查询到family的ID。


五、示例

网上很多例子都不是很完整,这里贴一个完整的例子源码供参考。

例子1:user到kernel,user program通过发送一个命令到内核,内核相应的模块接收到命令以后,执行对应的回调函数

kernel端:


   
  1. #include <net/netlink.h>
  2. #include <net/genetlink.h>
  3. #include <linux/version.h>
  4. #define TEST_GENL_MSG_FROM_KERNEL "Hello from kernel space!!!"
  5. /* handler
  6. * message handling code goes here; return 0 on success, negative
  7. * values on failure
  8. */
  9. static int doc_exmpl_echo(struct sk_buff *skb, struct genl_info *info);
  10. /* netlink attributes */
  11. enum {
  12. DOC_EXMPL_A_UNSPEC,
  13. DOC_EXMPL_A_MSG,
  14. __DOC_EXMPL_A_MAX,
  15. };
  16. #define DOC_EXMPL_A_MAX (__DOC_EXMPL_A_MAX - 1)
  17. /* attribute policy */
  18. static struct nla_policy doc_exmpl_genl_policy[DOC_EXMPL_A_MAX + 1] = {
  19. [DOC_EXMPL_A_MSG] = { .type = NLA_NUL_STRING },
  20. };
  21. /* commands 定义命令类型,用户空间以此来表明需要执行的命令 */
  22. enum {
  23. DOC_EXMPL_C_UNSPEC,
  24. DOC_EXMPL_C_ECHO,
  25. __DOC_EXMPL_C_MAX,
  26. };
  27. #define DOC_EXMPL_C_MAX (__DOC_EXMPL_C_MAX - 1)
  28. /* family definition */
  29. static struct genl_family doc_exmpl_genl_family = {
  30. .id = GENL_ID_GENERATE, //这里不指定family ID,由内核进行分配
  31. .hdrsize = 0, //自定义的头部长度,参考genl数据包结构
  32. .name = "DOC_EXMPL", //这里定义family的名称,user program需要根据这个名字来找到对应的family ID。
  33. .version = 1,
  34. .maxattr = DOC_EXMPL_A_MAX,
  35. };
  36. /* operation definition 将命令command echo和具体的handler对应起来 */
  37. static struct genl_ops doc_exmpl_genl_ops_echo = {
  38. .cmd = DOC_EXMPL_C_ECHO,
  39. .flags = 0,
  40. .policy = doc_exmpl_genl_policy,
  41. .doit = doc_exmpl_echo,
  42. .dumpit = NULL,
  43. };
  44. static struct genl_multicast_group doc_exmpl_genl_mcgrp = {
  45. .name = "DOC_EXMPL_GRP",
  46. };
  47. static inline int genl_msg_prepare_usr_msg(u8 cmd, size_t size, pid_t pid, struct sk_buff **skbp)
  48. {
  49.     struct sk_buff *skb;
  50.     /* create a new netlink msg */
  51.     skb = genlmsg_new(size, GFP_KERNEL);
  52.     if (skb == NULL) {
  53.         return -ENOMEM;
  54.     }
  55.     /* Add a new netlink message to an skb */
  56.     genlmsg_put(skb, pid, 0, &doc_exmpl_genl_family, 0, cmd);
  57.     *skbp = skb;
  58.     return 0;
  59. }
  60. static inline int genl_msg_mk_usr_msg(struct sk_buff *skb, int type, void *data, int len)
  61. {
  62.     int rc;
  63.     /* add a netlink attribute to a socket buffer */
  64.     if ((rc = nla_put(skb, type, len, data)) != 0) {
  65.         return rc;
  66.     }
  67.     return 0;
  68. }
  69. /**
  70. * genl_msg_send_to_user - 通过generic netlink发送数据到netlink
  71. *
  72. * @data: 发送数据缓存
  73. * @len:  数据长度 单位:byte
  74. * @pid:  发送到的客户端pid
  75. *
  76. * return:
  77. *    0:       成功
  78. *    -1:      失败
  79. */
  80. int genl_msg_send_to_user(void *data, int len, pid_t pid)
  81. {
  82.     struct sk_buff *skb;
  83.     size_t size;
  84.     void *head;
  85.     int rc;
  86.     size = nla_total_size(len); /* total length of attribute including padding */
  87.     rc = genl_msg_prepare_usr_msg(DOC_EXMPL_C_ECHO, size, pid, &skb);
  88.     if (rc) {
  89.         return rc;
  90.     }
  91.     rc = genl_msg_mk_usr_msg(skb, DOC_EXMPL_A_MSG, data, len);
  92.     if (rc) {
  93.         kfree_skb(skb);
  94.         return rc;
  95.     }
  96.     head = genlmsg_data(nlmsg_data(nlmsg_hdr(skb)));
  97.     rc = genlmsg_end(skb, head);
  98.     if (rc < 0) {
  99.         kfree_skb(skb);
  100.         return rc;
  101.     }
  102.     rc = genlmsg_unicast(&init_net, skb, pid);
  103.     if (rc < 0) {
  104.         return rc;
  105.     }
  106.     return 0;
  107. }
  108. //echo command handler, 命令处理函数,当接收到user program发出的命令后,这个函数会被内核调用
  109. static int doc_exmpl_echo(struct sk_buff *skb, struct genl_info *info)
  110. {
  111. /* message handling code goes here; return 0 on success, negative values on failure */
  112. struct nlmsghdr *nlhdr;
  113. struct genlmsghdr *genlhdr;
  114. struct nlattr *nlh;
  115. char *str;
  116. int ret;
  117. nlhdr = nlmsg_hdr(skb);
  118. genlhdr = nlmsg_data(nlhdr);
  119. nlh = genlmsg_data(genlhdr);
  120. str = nla_data(nlh);
  121. printk( "doc_exmpl_echo get: %s\n", str);
  122. ret = genl_msg_send_to_user(TEST_GENL_MSG_FROM_KERNEL,
  123. strlen(TEST_GENL_MSG_FROM_KERNEL) + 1, nlhdr->nlmsg_pid);
  124. return ret;
  125. }
  126. static int genetlink_init(void)
  127. {
  128. int rc;
  129. /**
  130. * 1. Registering A Family
  131. * This function doesn't exist past linux 3.12
  132. */
  133. rc = genl_register_family(&doc_exmpl_genl_family);
  134. if (rc != 0)
  135. goto err_out1;
  136. rc = genl_register_ops(&doc_exmpl_genl_family, &doc_exmpl_genl_ops_echo);
  137. if (rc != 0)
  138. goto err_out2;
  139. /*
  140. * for multicast
  141. */
  142. rc = genl_register_mc_group(&doc_exmpl_genl_family, &doc_exmpl_genl_mcgrp);
  143. if (rc != 0)
  144. goto err_out3;
  145. LOGC( "doc_exmpl_genl_mcgrp.id=%d", doc_exmpl_genl_mcgrp.id);
  146. LOGC( "genetlink_init OK");
  147. return 0;
  148. err_out3:
  149. genl_unregister_ops(&doc_exmpl_genl_family, &doc_exmpl_genl_ops_echo);
  150. err_out2:
  151. genl_unregister_family(&doc_exmpl_genl_family);
  152. err_out1:
  153. LOGC( "Error occured while inserting generic netlink example module\n");
  154. return rc;
  155. }
  156. static void genetlink_exit(void)
  157. {
  158. LOGC( "Generic Netlink Example Module unloaded.");
  159. genl_unregister_mc_group(&doc_exmpl_genl_family, &doc_exmpl_genl_mcgrp);
  160. genl_unregister_ops(&doc_exmpl_genl_family, &doc_exmpl_genl_ops_echo);
  161. genl_unregister_family(&doc_exmpl_genl_family);
  162. }

user program


   
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <errno.h>
  4. #include <unistd.h>
  5. #include <poll.h>
  6. #include <string.h>
  7. #include <fcntl.h>
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <sys/socket.h>
  11. #include <sys/types.h>
  12. #include <signal.h>
  13. #include <linux/genetlink.h>
  14. #define GENLMSG_DATA(glh) ((void*)(((char*)glh) + GENL_HDRLEN))
  15. #define NLA_DATA(nla) ((void *)((char*)(nla) + NLA_HDRLEN))
  16. #define NLA_NEXT(nla,len) ((len) -= NLA_ALIGN((nla)->nla_len), \
  17. (struct nlattr*)(((char*)(nla)) + NLA_ALIGN((nla)->nla_len)))
  18. #define NLA_OK(nla,len) ((len) >= (int)sizeof(struct nlattr) && \
  19. (nla)->nla_len >= sizeof(struct nlattr) && \
  20. (nla)->nla_len <= (len))
  21. //copy from kernel driver genl_ops's cmd
  22. enum {
  23. DOC_EXMPL_C_UNSPEC,
  24. DOC_EXMPL_C_ECHO,
  25. __DOC_EXMPL_C_MAX,
  26. };
  27. //copy from kernel driver netlink attribute
  28. enum {
  29. DOC_EXMPL_A_UNSPEC,
  30. DOC_EXMPL_A_MSG,
  31. __DOC_EXMPL_A_MAX,
  32. };
  33. #define MESSAGE_TO_KERNEL "Hello World from user space!"
  34. /**
  35. * nla_attr_size - length of attribute size, NOT including padding
  36. * @param payload length of payload
  37. * @return
  38. */
  39. static inline int nla_attr_size(int payload)
  40. {
  41. return NLA_HDRLEN + payload;
  42. }
  43. /**
  44. * nla_total_size - total length of attribute including padding
  45. * @param payload length of payload, NOT including NLA_HDR
  46. */
  47. static inline int nla_total_size(int payload)
  48. {
  49. return NLA_ALIGN(nla_attr_size(payload));
  50. }
  51. static int genlmsg_open(void)
  52. {
  53. int sockfd;
  54. struct sockaddr_nl nladdr;
  55. int ret;
  56. sockfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
  57. if (sockfd < 0)
  58. {
  59. LOGC( "socket: %m");
  60. return -1;
  61. }
  62. memset(&nladdr, 0, sizeof(nladdr));
  63. nladdr.nl_family = AF_NETLINK;
  64. nladdr.nl_pid = getpid();
  65. nladdr.nl_groups = 0xffffffff; //这个是mask值,如果family ID & nl_groups为0,
  66. //则这个family的广播就接收不到,所以这里设为0xffffffff就可以接收所有的family消息
  67. ret = bind(sockfd, (struct sockaddr *)&nladdr, sizeof(nladdr));
  68. if (ret < 0)
  69. {
  70. LOGC( "bind: %m");
  71. ret = -1;
  72. goto err_out;
  73. }
  74. return sockfd;
  75. err_out:
  76. close(sockfd);
  77. return ret;
  78. }
  79. static void *genlmsg_alloc(int *size)
  80. {
  81. unsigned char *buf;
  82. int len;
  83. /*
  84. * attribute len
  85. * attr len = (nla_hdr + pad) + (payload(user data) + pad)
  86. */
  87. len = nla_total_size(*size);
  88. /*
  89. * family msg len,
  90. * but actually we have NOT custom family header
  91. * family msg len = family_hdr + payload(attribute)
  92. */
  93. len += 0;
  94. /*
  95. * generic netlink msg len
  96. * genlmsg len = (genlhdr + pad) + payload(family msg)
  97. */
  98. len += GENL_HDRLEN;
  99. /*
  100. * netlink msg len
  101. * nlmsg len = (nlmsghdr + pad) + (payload(genlmsg) + pad)
  102. */
  103. len = NLMSG_SPACE(len);
  104. buf = malloc(len);
  105. if (!buf)
  106. return NULL;
  107. memset(buf, 0, len);
  108. *size = len;
  109. return buf;
  110. }
  111. static void genlmsg_free(void *buf)
  112. {
  113. if (buf)
  114. free(buf);
  115. }
  116. static int genlmsg_send(int sockfd, unsigned short nlmsg_type, unsigned int nlmsg_pid,
  117. unsigned char genl_cmd, unsigned char genl_version,
  118. unsigned short nla_type, const void *nla_data, unsigned int nla_len)
  119. {
  120. struct nlmsghdr *nlh; //netlink message header
  121. struct genlmsghdr *glh; //generic netlink message header
  122. struct nlattr *nla; //netlink attribute header
  123. struct sockaddr_nl nladdr;
  124. unsigned char *buf;
  125. int len;
  126. int count;
  127. int ret;
  128. if ((nlmsg_type == 0) || (!nla_data) || (nla_len <= 0))
  129. {
  130. return -1;
  131. }
  132. len = nla_len;
  133. buf = genlmsg_alloc(&len);
  134. if (!buf)
  135. return -1;
  136. nlh = (struct nlmsghdr *)buf;
  137. nlh->nlmsg_len = len;
  138. nlh->nlmsg_type = nlmsg_type;
  139. nlh->nlmsg_flags = NLM_F_REQUEST;
  140. nlh->nlmsg_seq = 0;
  141. nlh->nlmsg_pid = nlmsg_pid;
  142. glh = (struct genlmsghdr *)NLMSG_DATA(nlh);
  143. glh->cmd = genl_cmd;
  144. glh->version = genl_version;
  145. nla = (struct nlattr *)GENLMSG_DATA(glh);
  146. nla->nla_type = nla_type;
  147. nla->nla_len = nla_attr_size(nla_len);
  148. memcpy(NLA_DATA(nla), nla_data, nla_len);
  149. memset(&nladdr, 0, sizeof(nladdr));
  150. nladdr.nl_family = AF_NETLINK;
  151. count = 0;
  152. ret = 0;
  153. do {
  154. ret = sendto(sockfd, &buf[count], len - count, 0,
  155. (struct sockaddr *)&nladdr, sizeof(nladdr));
  156. if (ret < 0)
  157. {
  158. if (errno != EAGAIN)
  159. {
  160. count = -1;
  161. goto out;
  162. }
  163. }
  164. else
  165. {
  166. count += ret;
  167. }
  168. } while (count < len);
  169. out:
  170. genlmsg_free(buf);
  171. LOGC( "send return %d", count);
  172. return count;
  173. }
  174. /**
  175. *
  176. * @param sockfd generic netlink socket fd
  177. * @param buf the 'buf' is including the struct nlmsghdr,
  178. * struct genlmsghdr and struct nlattr
  179. * @param len size of 'buf'
  180. * @return >0 size of genlmsg
  181. * <0 error occur
  182. */
  183. static int genlmsg_recv(int sockfd, unsigned char *buf, unsigned int len)
  184. {
  185. struct sockaddr_nl nladdr;
  186. struct msghdr msg;
  187. struct iovec iov;
  188. int ret;
  189. nladdr.nl_family = AF_NETLINK;
  190. nladdr.nl_pid = getpid();
  191. nladdr.nl_groups = 0xffffffff;
  192. iov.iov_base = buf;
  193. iov.iov_len = len;
  194. msg.msg_name = ( void *)&nladdr;
  195. msg.msg_namelen = sizeof(nladdr);
  196. msg.msg_iov = &iov;
  197. msg.msg_iovlen = 1;
  198. msg.msg_control = NULL;
  199. msg.msg_controllen = 0;
  200. msg.msg_flags = 0;
  201. ret = recvmsg(sockfd, &msg, 0);
  202. ret = ret > 0 ? ret : -1;
  203. LOGC( "recv return %d", ret);
  204. return ret;
  205. }
  206. static int genlmsg_dispatch(struct nlmsghdr *nlmsghdr, unsigned int nlh_len,
  207. int nlmsg_type, int nla_type, unsigned char *buf, int *len)
  208. {
  209. struct nlmsghdr *nlh;
  210. struct genlmsghdr *glh;
  211. struct nlattr *nla;
  212. int nla_len;
  213. int l;
  214. int i;
  215. int ret = -1;
  216. if (!nlmsghdr || !buf || !len)
  217. return -1;
  218. LOGC( "nlmsg_type = %d", nlmsghdr->nlmsg_type);
  219. if (nlmsg_type && (nlmsghdr->nlmsg_type != nlmsg_type))
  220. return -1;
  221. //读取到的数据流里面,可能会包含多条nlmsg
  222. for (nlh = nlmsghdr; NLMSG_OK(nlh, nlh_len); nlh = NLMSG_NEXT(nlh, nlh_len))
  223. {
  224. /* The end of multipart message. */
  225. if (nlh->nlmsg_type == NLMSG_DONE)
  226. {
  227. LOGC( "get NLMSG_DONE");
  228. ret = 0;
  229. break;
  230. }
  231. if (nlh->nlmsg_type == NLMSG_ERROR)
  232. {
  233. LOGC( "get NLMSG_ERROR");
  234. ret = -1;
  235. break;
  236. }
  237. glh = (struct genlmsghdr *)NLMSG_DATA(nlh);
  238. nla = (struct nlattr *)GENLMSG_DATA(glh); //the first attribute
  239. nla_len = nlh->nlmsg_len - GENL_HDRLEN; //len of attributes
  240. for (i = 0; NLA_OK(nla, nla_len); nla = NLA_NEXT(nla, nla_len), ++i)
  241. {
  242. //一条nlmsg里面,可能会包含多个attr
  243. LOGC( "%d. nla->nla_type = %d", i, nla->nla_type);
  244. /* Match the family ID, copy the data to user */
  245. if (nla_type == nla->nla_type)
  246. {
  247. l = nla->nla_len - NLA_HDRLEN; //attribute里的payload就是内核返回给用户的实际数据
  248. *len = *len > l ? l : *len;
  249. memcpy(buf, NLA_DATA(nla), *len);
  250. ret = 0;
  251. break;
  252. }
  253. }
  254. }
  255. return ret;
  256. }
  257. static int genlmsg_get_family_id(int sockfd, const char *family_name)
  258. {
  259. void *buf;
  260. int len;
  261. __u16 id;
  262. int l;
  263. int ret;
  264. ret = genlmsg_send(sockfd, GENL_ID_CTRL, 0, CTRL_CMD_GETFAMILY, 1,
  265. CTRL_ATTR_FAMILY_NAME, family_name, strlen(family_name) + 1);
  266. if (ret < 0)
  267. return -1;
  268. len = 256;
  269. buf = genlmsg_alloc(&len);
  270. if (!buf)
  271. return -1;
  272. len = genlmsg_recv(sockfd, buf, len);
  273. if (len < 0)
  274. return len;
  275. id = 0;
  276. l = sizeof(id);
  277. genlmsg_dispatch((struct nlmsghdr *)buf, len, 0, CTRL_ATTR_FAMILY_ID, ( unsigned char *)&id, &l);
  278. genlmsg_free(buf);
  279. return id > 0 ? id : -1;
  280. }
  281. static void genlmsg_close(int sockfd)
  282. {
  283. if (sockfd >= 0)
  284. close(sockfd);
  285. }
  286. #define BUF_SIZE 256
  287. static int test_netlink_unicast(void)
  288. {
  289. struct nlmsghdr *nlh = NULL;
  290. int sockfd = -1;
  291. unsigned char buf[BUF_SIZE];
  292. int len;
  293. int id;
  294. pid_t pid;
  295. int ret;
  296. len = BUF_SIZE;
  297. nlh = genlmsg_alloc(&len);
  298. if (!nlh)
  299. return -1;
  300. sockfd = genlmsg_open();
  301. if (sockfd < 0)
  302. return -1;
  303. id = genlmsg_get_family_id(sockfd, "DOC_EXMPL"); //这里必须先通过family的名字获取到family ID,名字需要与驱动里的一致
  304. LOGC( "get family ID[%d]", id);
  305. if (id <= 0)
  306. {
  307. ret = -1;
  308. goto out;
  309. }
  310. pid = getpid();
  311. ret = genlmsg_send(sockfd, id, pid, DOC_EXMPL_C_ECHO, 1,
  312. DOC_EXMPL_A_MSG, MESSAGE_TO_KERNEL, strlen(MESSAGE_TO_KERNEL) + 1); //向内核发送genl消息
  313. if (ret < 0)
  314. {
  315. goto out;
  316. }
  317. ret = genlmsg_recv(sockfd, ( unsigned char *)nlh, len); //等待内核的回复
  318. if (ret > 0)
  319. {
  320. memset(buf, 0, sizeof(buf));
  321. len = sizeof(buf);
  322. ret = genlmsg_dispatch(nlh, ret, id, DOC_EXMPL_A_MSG, buf, &len);
  323. if (ret == 0)
  324. {
  325. printf( "get: %s\n", buf);
  326. }
  327. }
  328. out:
  329. genlmsg_close(sockfd);
  330. genlmsg_free(nlh);
  331. return ret;
  332. }
  333. int main(int argc, char *argv[])
  334. {
  335. /*
  336. * test netlink unicast
  337. */
  338. test_netlink_unicast();
  339. return 0;
  340. }


例子2:kernel到user,user program先创建一个socket并监听,内核发生某个事件以后,就可以发送一个广播,通知user program

kernel端:


   
  1. #include <net/netlink.h>
  2. #include <net/genetlink.h>
  3. #include <linux/version.h>
  4. #define TEST_GENL_FAMILY_NAME "my-test-family"
  5. #define TEST_GENL_MCAST_GROUP_NAME "my-test-group"
  6. #define TEST_GENL_MSG_FROM_KERNEL "Hello from kernel space!!!"
  7. /* handler
  8. * message handling code goes here; return 0 on success, negative
  9. * values on failure
  10. */
  11. static int doc_exmpl_echo(struct sk_buff *skb, struct genl_info *info);
  12. /* netlink attributes 可以通过枚举索引找到对应的类型,用户空间应用程序要传递这样的信息 */
  13. enum {
  14. DOC_EXMPL_A_UNSPEC,
  15. DOC_EXMPL_A_MSG,
  16. __DOC_EXMPL_A_MAX,
  17. };
  18. #define DOC_EXMPL_A_MAX (__DOC_EXMPL_A_MAX - 1)
  19. /* attribute policy */
  20. static struct nla_policy doc_exmpl_genl_policy[DOC_EXMPL_A_MAX + 1] = {
  21. [DOC_EXMPL_A_MSG] = { .type = NLA_NUL_STRING },
  22. };
  23. /* commands 定义命令类型,用户空间以此来表明需要执行的命令 */
  24. enum {
  25. DOC_EXMPL_C_UNSPEC,
  26. DOC_EXMPL_C_ECHO,
  27. __DOC_EXMPL_C_MAX,
  28. };
  29. #define DOC_EXMPL_C_MAX (__DOC_EXMPL_C_MAX - 1)
  30. #if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)
  31. /* family definition */
  32. static struct genl_family doc_exmpl_genl_family = {
  33. .id = GENL_ID_GENERATE, //request a new channel number, assigned by kernel, NOT driver specific
  34. .hdrsize = 0,
  35. .name = "DOC_EXMPL",
  36. .version = 1,
  37. .maxattr = DOC_EXMPL_A_MAX,
  38. };
  39. /* operation definition 将命令command echo和具体的handler对应起来 */
  40. static struct genl_ops doc_exmpl_genl_ops_echo = {
  41. .cmd = DOC_EXMPL_C_ECHO,
  42. .flags = 0,
  43. .policy = doc_exmpl_genl_policy,
  44. .doit = doc_exmpl_echo,
  45. .dumpit = NULL,
  46. };
  47. static struct genl_multicast_group doc_exmpl_genl_mcgrp = {
  48. .name = "DOC_EXMPL_GRP",
  49. };
  50. //需要在其他地方主动调用这个函数发送广播
  51. static int test_netlink_send(void)
  52. {
  53. struct sk_buff *skb = NULL;
  54. void *msg_header = NULL;
  55. int size;
  56. int rc;
  57. /* allocate memory */
  58. size = nla_total_size( strlen(TEST_GENL_MSG_FROM_KERNEL) + 1) + nla_total_size( 0);
  59. skb = genlmsg_new(size, GFP_KERNEL);
  60. if (!skb)
  61. return -ENOMEM;
  62. /* add the genetlink message header */
  63. msg_header = genlmsg_put(skb, 0, 0,
  64. &doc_exmpl_genl_family, 0, DOC_EXMPL_C_ECHO);
  65. if (!msg_header)
  66. {
  67. rc = -ENOMEM;
  68. goto err_out;
  69. }
  70. /* add a DOC_EXMPL_A_MSG attribute */
  71. rc = nla_put_string(skb, DOC_EXMPL_A_MSG, TEST_GENL_MSG_FROM_KERNEL);
  72. if (rc != 0)
  73. goto err_out;
  74. /* finalize the message */
  75. genlmsg_end(skb, msg_header);
  76. //multicast is send a message to a logical group
  77. rc = genlmsg_multicast(skb, 0, doc_exmpl_genl_mcgrp.id, GFP_KERNEL);
  78. if (rc != 0 && rc != -ESRCH)
  79. {
  80. /* if NO one is waitting the message in user space,
  81. * genlmsg_multicast return -ESRCH
  82. */
  83. LOGC( "genlmsg_multicast to user failed, return %d", rc);
  84. /*
  85. * attention:
  86. * If you NOT call genlmsg_unicast/genlmsg_multicast and error occurs,
  87. * call nlmsg_free(skb).
  88. * But if you call genlmsg_unicast/genlmsg_multicast, NO need to call
  89. * nlmsg_free(skb). If NOT, kernel crash.
  90. */
  91. return rc;
  92. }
  93. LOGC( "genlmsg_multicast Success");
  94. /*
  95. * Attention:
  96. * Should NOT call nlmsg_free(skb) here. If NOT, kernel crash!!!
  97. */
  98. return 0;
  99. err_out:
  100. if (skb)
  101. nlmsg_free(skb);
  102. return rc;
  103. }
  104. static int genetlink_init(struct my_module_priv *ctx)
  105. {
  106. int rc;
  107. /**
  108. * 1. Registering A Family
  109. * This function doesn't exist past linux 3.12
  110. */
  111. rc = genl_register_family(&doc_exmpl_genl_family);
  112. if (rc != 0)
  113. goto err_out1;
  114. rc = genl_register_ops(&doc_exmpl_genl_family, &doc_exmpl_genl_ops_echo);
  115. if (rc != 0)
  116. goto err_out2;
  117. /*
  118. * for multicast
  119. */
  120. rc = genl_register_mc_group(&doc_exmpl_genl_family, &doc_exmpl_genl_mcgrp);
  121. if (rc != 0)
  122. goto err_out3;
  123. LOGC( "doc_exmpl_genl_mcgrp.id=%d", doc_exmpl_genl_mcgrp.id);
  124. LOGC( "genetlink_init OK");
  125. return 0;
  126. err_out3:
  127. genl_unregister_ops(&doc_exmpl_genl_family, &doc_exmpl_genl_ops_echo);
  128. err_out2:
  129. genl_unregister_family(&doc_exmpl_genl_family);
  130. err_out1:
  131. LOGC( "Error occured while inserting generic netlink example module\n");
  132. return rc;
  133. }
  134. static void genetlink_exit(struct my_module_priv *ctx)
  135. {
  136. LOGC( "Generic Netlink Example Module unloaded.");
  137. genl_unregister_mc_group(&doc_exmpl_genl_family, &doc_exmpl_genl_mcgrp);
  138. genl_unregister_ops(&doc_exmpl_genl_family, &doc_exmpl_genl_ops_echo);
  139. genl_unregister_family(&doc_exmpl_genl_family);
  140. }
  141. static struct my_module_work g_my_module_work = {
  142. .do_test_probe = genetlink_init,
  143. .do_test_remove = genetlink_exit,
  144. };

user program


   
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <errno.h>
  4. #include <unistd.h>
  5. #include <poll.h>
  6. #include <string.h>
  7. #include <fcntl.h>
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <sys/socket.h>
  11. #include <sys/types.h>
  12. #include <signal.h>
  13. #include <linux/genetlink.h>
  14. #define GENLMSG_DATA(glh) ((void*)(((char*)glh) + GENL_HDRLEN))
  15. #define NLA_DATA(nla) ((void *)((char*)(nla) + NLA_HDRLEN))
  16. #define NLA_NEXT(nla,len) ((len) -= NLA_ALIGN((nla)->nla_len), \
  17. (struct nlattr*)(((char*)(nla)) + NLA_ALIGN((nla)->nla_len)))
  18. #define NLA_OK(nla,len) ((len) >= (int)sizeof(struct nlattr) && \
  19. (nla)->nla_len >= sizeof(struct nlattr) && \
  20. (nla)->nla_len <= (len))
  21. //copy from kernel driver genl_ops's cmd
  22. enum {
  23. DOC_EXMPL_C_UNSPEC,
  24. DOC_EXMPL_C_ECHO,
  25. __DOC_EXMPL_C_MAX,
  26. };
  27. //copy from kernel driver netlink attribute
  28. enum {
  29. DOC_EXMPL_A_UNSPEC,
  30. DOC_EXMPL_A_MSG,
  31. __DOC_EXMPL_A_MAX,
  32. };
  33. #define MESSAGE_TO_KERNEL "Hello World from user space!"
  34. /**
  35. * nla_attr_size - length of attribute size, NOT including padding
  36. * @param payload length of payload
  37. * @return
  38. */
  39. static inline int nla_attr_size(int payload)
  40. {
  41. return NLA_HDRLEN + payload;
  42. }
  43. /**
  44. * nla_total_size - total length of attribute including padding
  45. * @param payload length of payload, NOT including NLA_HDR
  46. */
  47. static inline int nla_total_size(int payload)
  48. {
  49. return NLA_ALIGN(nla_attr_size(payload));
  50. }
  51. static int genlmsg_open(void)
  52. {
  53. int sockfd;
  54. struct sockaddr_nl nladdr;
  55. int ret;
  56. sockfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
  57. if (sockfd < 0)
  58. {
  59. LOGC( "socket: %m");
  60. return -1;
  61. }
  62. memset(&nladdr, 0, sizeof(nladdr));
  63. nladdr.nl_family = AF_NETLINK;
  64. nladdr.nl_pid = getpid();
  65. nladdr.nl_groups = 0xffffffff;
  66. ret = bind(sockfd, (struct sockaddr *)&nladdr, sizeof(nladdr));
  67. if (ret < 0)
  68. {
  69. LOGC( "bind: %m");
  70. ret = -1;
  71. goto err_out;
  72. }
  73. return sockfd;
  74. err_out:
  75. close(sockfd);
  76. return ret;
  77. }
  78. static void *genlmsg_alloc(int *size)
  79. {
  80. unsigned char *buf;
  81. int len;
  82. /*
  83. * attribute len
  84. * attr len = (nla_hdr + pad) + (payload(user data) + pad)
  85. */
  86. len = nla_total_size(*size);
  87. /*
  88. * family msg len,
  89. * but actually we have NOT custom family header
  90. * family msg len = family_hdr + payload(attribute)
  91. */
  92. len += 0;
  93. /*
  94. * generic netlink msg len
  95. * genlmsg len = (genlhdr + pad) + payload(family msg)
  96. */
  97. len += GENL_HDRLEN;
  98. /*
  99. * netlink msg len
  100. * nlmsg len = (nlmsghdr + pad) + (payload(genlmsg) + pad)
  101. */
  102. len = NLMSG_SPACE(len);
  103. buf = malloc(len);
  104. if (!buf)
  105. return NULL;
  106. memset(buf, 0, len);
  107. *size = len;
  108. return buf;
  109. }
  110. static void genlmsg_free(void *buf)
  111. {
  112. if (buf)
  113. free(buf);
  114. }
  115. static int genlmsg_send(int sockfd, unsigned short nlmsg_type, unsigned int nlmsg_pid,
  116. unsigned char genl_cmd, unsigned char genl_version,
  117. unsigned short nla_type, const void *nla_data, unsigned int nla_len)
  118. {
  119. struct nlmsghdr *nlh; //netlink message header
  120. struct genlmsghdr *glh; //generic netlink message header
  121. struct nlattr *nla; //netlink attribute header
  122. struct sockaddr_nl nladdr;
  123. unsigned char *buf;
  124. int len;
  125. int count;
  126. int ret;
  127. if ((nlmsg_type == 0) || (!nla_data) || (nla_len <= 0))
  128. {
  129. return -1;
  130. }
  131. len = nla_len;
  132. buf = genlmsg_alloc(&len);
  133. if (!buf)
  134. return -1;
  135. nlh = (struct nlmsghdr *)buf;
  136. nlh->nlmsg_len = len;
  137. nlh->nlmsg_type = nlmsg_type;
  138. nlh->nlmsg_flags = NLM_F_REQUEST;
  139. nlh->nlmsg_seq = 0;
  140. nlh->nlmsg_pid = nlmsg_pid;
  141. glh = (struct genlmsghdr *)NLMSG_DATA(nlh);
  142. glh->cmd = genl_cmd;
  143. glh->version = genl_version;
  144. nla = (struct nlattr *)GENLMSG_DATA(glh);
  145. nla->nla_type = nla_type;
  146. nla->nla_len = nla_attr_size(nla_len);
  147. memcpy(NLA_DATA(nla), nla_data, nla_len);
  148. memset(&nladdr, 0, sizeof(nladdr));
  149. nladdr.nl_family = AF_NETLINK;
  150. count = 0;
  151. ret = 0;
  152. do {
  153. ret = sendto(sockfd, &buf[count], len - count, 0,
  154. (struct sockaddr *)&nladdr, sizeof(nladdr));
  155. if (ret < 0)
  156. {
  157. if (errno != EAGAIN)
  158. {
  159. count = -1;
  160. goto out;
  161. }
  162. }
  163. else
  164. {
  165. count += ret;
  166. }
  167. } while (count < len);
  168. out:
  169. genlmsg_free(buf);
  170. LOGC( "send return %d", count);
  171. return count;
  172. }
  173. /**
  174. *
  175. * @param sockfd generic netlink socket fd
  176. * @param buf the 'buf' is including the struct nlmsghdr,
  177. * struct genlmsghdr and struct nlattr
  178. * @param len size of 'buf'
  179. * @return >0 size of genlmsg
  180. * <0 error occur
  181. */
  182. static int genlmsg_recv(int sockfd, unsigned char *buf, unsigned int len)
  183. {
  184. struct sockaddr_nl nladdr;
  185. struct msghdr msg;
  186. struct iovec iov;
  187. int ret;
  188. nladdr.nl_family = AF_NETLINK;
  189. nladdr.nl_pid = getpid();
  190. nladdr.nl_groups = 0xffffffff;
  191. iov.iov_base = buf;
  192. iov.iov_len = len;
  193. msg.msg_name = ( void *)&nladdr;
  194. msg.msg_namelen = sizeof(nladdr);
  195. msg.msg_iov = &iov;
  196. msg.msg_iovlen = 1;
  197. msg.msg_control = NULL;
  198. msg.msg_controllen = 0;
  199. msg.msg_flags = 0;
  200. ret = recvmsg(sockfd, &msg, 0);
  201. ret = ret > 0 ? ret : -1;
  202. LOGC( "recv return %d", ret);
  203. return ret;
  204. }
  205. static int genlmsg_dispatch(struct nlmsghdr *nlmsghdr, unsigned int nlh_len,
  206. int nlmsg_type, int nla_type, unsigned char *buf, int *len)
  207. {
  208. struct nlmsghdr *nlh;
  209. struct genlmsghdr *glh;
  210. struct nlattr *nla;
  211. int nla_len;
  212. int l;
  213. int i;
  214. int ret = -1;
  215. if (!nlmsghdr || !buf || !len)
  216. return -1;
  217. LOGC( "nlmsg_type = %d", nlmsghdr->nlmsg_type);
相关标签: linux kernel