Generic Netlink(genl)介绍与例子

一、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数据包的结构。数据包的结构如下图所示


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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值