netlink 0005 -- Generic Netlink详解

通用netlink NETLINK_GENERIC 基本函数 消息格式   int genl_register_family(struct genl_family *family)功能:通用link协议由family来管理,此函数注册一个通用netlink family,其实就是将family表项加入到family_ht表中 family:通用netlink family 返回值:成功返回0 失败返回负数错误码 头文件: #include <n... 阅读详情

netlink socket是一种用于用户态进程和内核态进程之间的通信机制。它通过为内核模块提供一组特殊的API,并为用户程序提供了一组标准的socket接口的方式,实现了全双工的通讯连接。

Netlink的特点: 

  • 双向传输,异步通信
  • 用户空间中使用标准socket API
  • 内核空间中使用专门的API
  • 支持多播
  • 可由内核端发起通信
  • 支持32种协议类型

netlink仅支持32种协议类型,这在实际应用中可能并不足够。因此产生了generic netlink(以下简称为genl)。 
generic netlink支持1023个子协议号,弥补了netlink协议类型较少的缺陷。支持协议号自动分配。它基于netlink,但是在内核中,generic netlink的接口与netlink并不相同。

1. Generic Netlink框架概述

图1表示了Generic Netlink框架。Kernel socket API向用户空间和内核空间分别提供接口。 
Netlink子系统(1)是所有genl通信的基础。Netlink子系统中收到的所有Generic类型的netlink数据都被送到genl总线(2)上;从内核发出的数据也经由genl总线送至netlink子系统,再打包送至用户空间。 
Generic Netlink控制器(4)作为内核的一部分,负责动态地分配genl通道(即genl family id),并管理genl任务。genl控制器是一个特殊的genl内核用户,它负责监听genl bus上的通信通道。genl通信建立在一系列的通信通道的基础上,每个genl family对应多个通道,这些通道由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" |
                   +---------------------+     +---------------------+

图1:generic netlink框架

 

2 Generic Netlink相关结构体 


2.1 genl family 
Generic Netlink是基于客户端-服务端模型的通信机制。服务端注册family(family是对genl服务的各项定义的集合)。控制器和客户端都通过已注册的信息与服务端通信。 
genl family的结构体如下: 

struct genl_family
{
      unsigned int            id;
      unsigned int            hdrsize;
      char                    name[GENL_NAMSIZ];
      unsigned int            version;
      unsigned int            maxattr;
      struct nlattr **        attrbuf;
      struct list_head        ops_list;
      struct list_head        family_list;
};

对此结构体元素具体解释如下: 

* id: family id。当新注册一个family的时候,应该用GENL_ID_GENERATE宏(0x0),表示请控制器自动为family分配的一个id。            0x10保留供genl控制器使用。 
* hdrsize: 用户自定议头部长度。即图2中User Msg的长度。如果没有用户自定义头部,这个值被赋为0。 
* version: 版本号,一般填1即可。 
* name: family名,要求不同的family使用不同的名字。以便控制器进行正确的查找。 
* maxattr:genl使用netlink标准的attr来传输数据。此字段定义了最大attr类型数。(注意:不是一次传输多少个attr,而是一共 有多少种attr,因此,这个值可以被设为0,为0代表不区分所收到的数据的attr type)。在接收数据时,可以根据attr type,获得指定的attr type的数据在整体数据中的位置。 

* struct nlattr **attrbuf 
* struct list_head ops_list 
* struct list_head family_list 
以上的三个字段为私有字段,由系统自动配置,开发者不需要做配置。

图2 genl报文与linux中各变量的对应关系 

图3 genl报文格式 

2.2 genl_ops 结构体 

struct genl_ops
{
      u8                      cmd;
      unsigned int            flags;
      struct nla_policy       *policy;
      int                     (*doit)(struct sk_buff *skb,
                                      struct genl_info *info);
      int                     (*dumpit)(struct sk_buff *skb,
                                          struct netlink_callback *cb);
      struct list_head        ops_list;
};
  •   cmd: 命令名。用于识别各genl_ops
  •   flag: 各种设置属性,以“或”连接。在需要admin特权级别时,使用GENL_ADMIN_PERM
  •   policy:定义了attr规则。如果此指针非空,genl在触发事件处理程序之前,会使用这个字段来对帧中的attr做校验(见  nlmsg_parse函数)。该字段可以为空,表示在触发事件处理程序之前,不做校验。 

   policy是一个struct nla_policy的数组。struct nla_policy结构体表示如下: 

struct nla_policy
{
    u16             type;
    u16             len;
};

其中,type字段表示attr中的数据类型,可被配置为: 
       NLA_UNSPEC--未定义 
       NLA_U8, NLA_U16, NLA_U32, NLA_U64为8bits, 16bits, 32bits, 64bits的无符号整型 
       NLA_STRING--字符串 
       NLA_NUL_STRING--空终止符字符串 
       NLA_NESTED--attr流 

 len字段的意思是:如果在type字段配置的是字符串有关的值,要把len设置为字符串的最大长度(不包含结尾的'\0')。如果type字段未设置或被设置为NLA_UNSPEC,那么这里要设置为attr的payload部分的长度。 
 

  • doit:这是一个回调函数。在generic netlink收到数据时触发,运行在进程上下文。

   doit传入两个参数,skb为触发此回调函数的socket buffer。第二个参数是一个genl_info结构体,定义如下:

struct genl_info
        {
             u32                     snd_seq;
             u32                     snd_pid;
             struct nlmsghdr *       nlhdr;
             struct genlmsghdr *     genlhdr;
             void *                  userhdr;
             struct nlattr **        attrs;
        };

                 * snd_seq:发送序号                 

                 * snd_pid:发送客户端的PID                

                 * nlhdr:netlink header的指针                 

                 * genlmsghdr:genl头部的指针(即family头部)                 

                 * userhdr:用户自定义头部指针                 

                * attrs:attrs,如果定义了genl_ops->policy,这里的attrs是被policy过滤以后的结果。在完成了操作以后,如果 执行正确,返回0;否则,返回一个负数。负数的返回值会触发NLMSG_ERROR消息。当genl_ops的flag标志被添加了 NLMSG_ERROR时,即使doit返回0,也会触发NLMSG_ERROR消息。

  • dumpit

这是一个回调函数,当genl_ops的flag标志被添加了NLM_F_DUMP以后,每次收到genl消息即会回触发这个函数。 dumpit与doit的区别是:dumpit的第一个参数skb不会携带从客户端发来的数据。相反地,开发者应该在skb中填入需要传给客户端的数据, 然后,并skb的数据长度(可以用skb->len)return。skb中携带的数据会被自动送到客户端。只要dumpit的返回值大于 0,dumpit函数就会再次被调用,并被要求在skb中填入数据。当服务端没有数据要传给客户端时,dumpit要返回0。如果函数中出错,要求返回一 个负值。关于doit和dumpit的触发过程,可以查看源码中的genl_rcv_msg函数。

  • ops_list

为私有字段,由系统自动配置,开发者不需要做配置。

3 Generic Netlink服务端(内核)初始化

初始化Generic Netlink的过程分为以下四步:定义family,定义operation,注册family,注册operation。下面通过一个简单例子来说明 如何完成Generic Netlink的初始化。我们首先创建一个genl_family结构体的实例。我们在这里定义一个为"DOC_EXMPL"的family

/* attribute type */
  enum {
        DOC_EXMPL_A_UNSPEC,
        DOC_EXMPL_A_MSG,
        __DOC_EXMPL_A_MAX,
  };
  #define DOC_EXMPL_A_MAX (__DOC_EXMPL_A_MAX - 1)

  /* family definition */
  static struct genl_family doc_exmpl_gnl_family = {
        .id = GENL_ID_GENERATE,
        .hdrsize = 0,
        .name = "DOC_EXMPL",
        .version = 1,
        .maxattr = DOC_EXMPL_A_MAX,

  };

以上,我们定义了一个仅有一种attribuste type的family。.id被配置为GENL_ID_GENERATE,指示genl控制器自动分配一个id。 

第二步为family创建operations。我们至少要创建一个genl_ops结构体的实例。 

/* doit handler */
  int doc_exmpl_echo(struct sk_buff *skb, struct genl_info *info)
  {
        /* message handling code goes here; return 0 on success, negative
         * values on failure */
  }


  /* attribute policy */
  static struct nla_policy doc_exmpl_genl_policy = [DOC_EXMPL_A_MAX + 1] = {
        [DOC_EXMPL_A_MSG] = { .type = NLA_NUL_STRING },
  }

  /* commands */
  enum {
        DOC_EXMPL_C_UNSPEC,
        DOC_EXMPL_C_ECHO,
        __DOC_EXMPL_C_ECHO,
  };
  #define DOC_EXMPL_C_MAX (__DOC_EXMPL_C_MAX - 1)

  /* operation definition */
  struct genl_ops doc_exmpl_gnl_ops_echo = {
        .cmd = DOC_EXMPL_C_ECHO,
        .flags = 0,
        .policy = doc_exmpl_genl_policy,
        .doit = genl_recv_doit,
        .dumpit = NULL,
  }
这里,我们把attribute policy设为NLA_NUL_STRING,表示attr中数据的属性为无NULL结尾的字符串。控制器在收到数据时会自动完成这一类型检查。 

我们定义一个operation,它的id为DOC_EXMPL_C_ECHO,把上述的policy配置给它。一旦本family的genl消息在被总到genl总线上,doit函数(doc_exmpl_echo)会被调用。 

接下来两步是注册family和注册operations。 

genl_register_family(&doc_exmpl_gnl_family); 

genl_register_ops(&doc_exmpl_gnl_family, &doc_exmpl_gnl_ops_echo); 

在完成genl操作后,记对完成对family的注销操作。 

genl_unregister_family(&doc_exmpl_gnl_family); 

4 Generic Netlink客户端(用户空间)初始化 
Generic Netlink在用户空间的初始化和通常的socket通信一致。大致分为两步,创建socket,把socket绑定到地址上(bind)。 
下面也通过一个例子简要说明一下用户空间genl初始化的过程。 
    struct sockaddr_nl saddr;
    int                sock;
    sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);

    if (sock < 0) {
        return -1;
    }

    memset(&saddr, 0, sizeof(saddr));
    saddr.nl_family = AF_NETLINK;
    saddr.nl_pid = getpid();
    if (bind(sock, (struct sockaddr*)&saddr, sizeof(saddr)) < 0) {
        printf("bind fail!\n");
        close(*p_sock);
        return -1;
    }

上述代码中,我们先创建一个socket,注意,第一个参数必须为AF_NETLINK 或 PF_NETLINK,表示创建netlink socket,第二个参数必须是SOCK_RAW或SOCK_DGRAM, 第三个参数指定netlink协议类型,我们要使用generic netlink,那么就要将其设置为:NETLINK_GENERIC。 

接下来,对于genl不可缺少的一步就是获取family id。family id是服务端注册family时,由控制器自动分配的。此时客户端尚不知道family id为多少,因此需要向客户端请求family id。 

下面是一段获取family id的函数 

static int genl_get_family_id(int sd, char *family_name)
{
    msgtemplate_t ans;
    int id, rc;
    struct nlattr *na;
    int rep_len;

    rc = genl_send_msg(sd, GENL_ID_CTRL, 0, CTRL_CMD_GETFAMILY, 1,
                    CTRL_ATTR_FAMILY_NAME, (void *)family_name,
                    strlen(family_name)+1);

    rep_len = recv(sd, &ans, sizeof(ans), 0);
    if (rep_len < 0) {
        return 0;
    }
    if (ans.n.nlmsg_type == NLMSG_ERROR || !NLMSG_OK((&ans.n), rep_len)) {
        return 0;
    }

    na = (struct nlattr *) GENLMSG_DATA(&ans);
    na = (struct nlattr *) ((char *) na + NLA_ALIGN(na->nla_len));
    if (na->nla_type == CTRL_ATTR_FAMILY_ID) {
        id = *(__u16 *) NLA_DATA(na);
    } else {
        id = 0;
    }

    return id;
}


在这个函数中,调用genl_send_msg(这个函数会在下文中介绍并给出源码)发送请求family id的消息,并调用recv接收服务端的反馈消息。这个消息中即包含了family id。 

这个函数的第一个参数是已创建好的socket。第二个参数是family name,注意这里family name需要与服务端注册famile时的name字段一致。该函数返回值即是family id以下是一个调用示例。 
int fid = genl_get_family_id(sock, "DOC_EXMPL"); 

 

5 Generic Netlink通信 
这一节对如何使用Generic Netlink完成内核空间与用户空间的通信做介绍。并把我的示例代码贡献出来。 
示例代码呈现了内核(服务端)和用户空间(客户端)收发数据的过程。 
5.1 内核发送数据 
以下是内核端发送数据的源码。在genl_msg_send_to_user中,调用genl_msg_prepare_usr_msg和 genl_msg_mk_usr_msg来准备socket buffer,为数据加上各种数据头(参考图2)。genlmsg_end把整个数据打包完成,通过genlmsg_unicast完成单播发送。 
 

/** 
* genl_msg_send_to_user - 通过generic netlink发送数据到netlink 
*
* @data: 发送数据缓存
* @len:  数据长度 单位:byte
* @pid:  发送到的客户端pid
*
* return: 
*    0:       成功 
*    -1:      失败
*/
int genl_msg_send_to_user(void *data, int len, pid_t pid)
{
    struct sk_buff *skb;
    size_t size;
    void *head;
    int rc;

    size = nla_total_size(len); /* total length of attribute including padding */

    rc = genl_msg_prepare_usr_msg(DOC_EXMPL_C_ECHO, size, pid, &skb);

    if (rc) {
        return rc;
    }

    rc = genl_msg_mk_usr_msg(skb, DOC_EXMPL_A_MSG, data, len);

    if (rc) {
        kfree_skb(skb);
        return rc;
    }

    head = genlmsg_data(nlmsg_data(nlmsg_hdr(skb)));

    rc = genlmsg_end(skb, head);
    if (rc < 0) {
        kfree_skb(skb);
        return rc;
    }

    rc = genlmsg_unicast(&init_net, skb, pid);
    if (rc < 0) {
        return rc;
    }

    return 0;
}


static inline int genl_msg_mk_usr_msg(struct sk_buff *skb, int type, void *data, int len)
{
    int rc;

    /* add a netlink attribute to a socket buffer */
    if ((rc = nla_put(skb, type, len, data)) != 0) {
        return rc;
    }
    return 0;
}

static inline int genl_msg_prepare_usr_msg(u8 cmd, size_t size, pid_t pid, struct sk_buff **skbp)
{
    struct sk_buff *skb;

    /* create a new netlink msg */
    skb = genlmsg_new(size, GFP_KERNEL);
    if (skb == NULL) {
        return -ENOMEM;
    }

    /* Add a new netlink message to an skb */
    genlmsg_put(skb, pid, 0, &genl_family, 0, cmd);

    *skbp = skb;
    return 0;
}

5.2 用户空间接收数据 
客户端调用通用的recv函数即可完成从内核来的数据的接收。需要注意的是,接收到的数据包含几级的header(图3),我们需要准确地定位到我们所需数据的位置。 

当没有用户自定义头部(即图3中的User Msg,在注册family时把hdrsize置0)时,可以构建这样的数据结构用于接收数据。这样,收到的数据中的netlink header和genl header就被很容易地剥离开来。 
typedef struct msgtemplate {
    struct nlmsghdr n;
    struct genlmsghdr g;
    char data[MAX_MSG_SIZE];
} msgtemplate_t;


下面是客户端接收数据函数的源码: 
 

#define GENLMSG_DATA(glh)       ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
#define NLA_DATA(na)            ((void *)((char *)(na) + NLA_HDRLEN))

void genl_rcv_msg(int fid, int sock, char **string)
{
    int ret;
    struct msgtemplate msg;
    struct nlattr *na;

    ret = recv(sock, &msg, sizeof(msg), 0);
    if (ret < 0) {
        return;
    }
    //printf("received length %d\n", ret);
    if (msg.n.nlmsg_type == NLMSG_ERROR || !NLMSG_OK((&msg.n), ret)) {
        return;
    }
    if (msg.n.nlmsg_type == fid && fid != 0) {
        na = (struct nlattr *) GENLMSG_DATA(&msg);
        *string = (char *)NLA_DATA(na);
    } 
}

以上函数中,第一个参数为family id,第二个参数为socket,第三个参数为待接收数据的buffer。 

5.3 用户空间发送数据 
客户端发送数据简单地说就是调用通用的socket API---sendto来发送数据 

/** 
* genl_send_msg - 通过generic netlink给内核发送数据 
*
* @sd: 客户端socket 
* @nlmsg_type: family_id
* @nlmsg_pid: 客户端pid
* @genl_cmd: 命令类型
* @genl_version: genl版本号
* @nla_type: netlink attr类型
* @nla_data: 发送的数据
* @nla_len: 发送数据长度
*
* return: 
*    0:       成功 
*    -1:      失败
*/
int genl_send_msg(int sd, u_int16_t nlmsg_type, u_int32_t nlmsg_pid,
        u_int8_t genl_cmd, u_int8_t genl_version, u_int16_t nla_type,
        void *nla_data, int nla_len)
{
    struct nlattr *na;
    struct sockaddr_nl nladdr;
    int r, buflen;
    char *buf;
    msgtemplate_t msg;


    if (nlmsg_type == 0) {
        return 0;
    }

    msg.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
    msg.n.nlmsg_type = nlmsg_type;
    msg.n.nlmsg_flags = NLM_F_REQUEST;
    msg.n.nlmsg_seq = 0;
    /*
     * nlmsg_pid是发送进程的端口号。
     * Linux内核不关心这个字段,仅用于跟踪消息。
     */
    msg.n.nlmsg_pid = nlmsg_pid;
    msg.g.cmd = genl_cmd;
    msg.g.version = genl_version;
    na = (struct nlattr *) GENLMSG_DATA(&msg);
    na->nla_type = nla_type;
    na->nla_len = nla_len + 1 + NLA_HDRLEN;
    memcpy(NLA_DATA(na), nla_data, nla_len);
    msg.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);

    buf = (char *) &msg;
    buflen = msg.n.nlmsg_len ;
    memset(&nladdr, 0, sizeof(nladdr));
    nladdr.nl_family = AF_NETLINK;
    while ((r = sendto(sd, buf, buflen, 0, (struct sockaddr *) &nladdr
            , sizeof(nladdr))) < buflen) {
        if (r > 0) {
            buf += r;
            buflen -= r;
        } else if (errno != EAGAIN) {
            return -1;
        }
    }
    return 0;
}

5.4 内核接收数据 
内核端一旦收到generic netlink数据,会触发doit函数运行(上文第3节有提及doit的初始化方法)。 

doit传入两个参数,skb即是接收到的数据,info包含了Genl消息的一些常用指针。这两个结构体字段详见内核源码。 

skb收到的数据还包括了多层的包头,以下程序中的nlmsg_hdr,nlmsg_data,genlmsg_data,nla_data即是把这些包头层层剥开,para->string指向的数据即是用用户空间传来的“纯数据”。 

int genl_recv_doit(struct sk_buff *skb, struct genl_info *info)
{
    /* doit 没有运行在中断上下文 */
    static int          kthread_num = 0; 
    struct nlmsghdr     *nlhdr;
    struct genlmsghdr   *genlhdr;
    struct nlattr       *nlh;
    struct thread_para  *para;              /* 给线程传递参数的结构体 */
    
     nlhdr = nlmsg_hdr(skb);
     genlhdr = nlmsg_data(nlhdr);
     nlh = genlmsg_data(genlhdr);
    /* 配置给新开线程所传的参数 */
    /* para 在线程函数thread_string_proc中释放 */
    para = (struct thread_para  *)kmalloc(sizeof(struct thread_para), GFP_KERNEL);
    para->string = nla_data(nlh);
    para->pid = nlhdr->nlmsg_pid;
    
    /* 每收到一个字符串开辟一个线程 */
    kthread_run(thread_string_proc, (void *)(para), "kthread %d", kthread_num++); 
    
    return 0;
}

 

三、无线信息传递——Generic Netlink(一、初始化) 系列说明  上一篇说明了无线信息的user space至kernel space的大致传递流程,这一主要针对以下3点进行一个顺序的描述: 1、无线驱动信息传递框架:说明无线信息传递的步骤流程以及各程序块之间的联系; 2、generic Netlink信号传递机制:hostapd与无线驱动之间的信息传递机制; 3、以ssid为例说明用户将user space中的ssid配置内容传递至kernel sp 阅读详情

相关推荐

generic netlink 编程快速入门

目录   一、generic netlink 消息结构 二、接口搭建过程 kernel端程序的准备 1、定义想要传送的消息种类 2、定义一组命令 3、为每个命令定义一个响应函数 4、将命令与相应函数关联起来 5、创建一个命令族 6、向内核注册新建的命令族 7、将关联好的命令和响应函数绑定(注册)到命令族上 用户端程序的使用: 1、新建一个套接字,并绑定上 netlink ...

zh_94的博客 2129

GENERIC NETLINK 介绍及使用

之前一篇博文讲述了Netlink如何使用,当时我们是自己定义了一种协议NETLINK_TEST进行用户进程和内核的通信,这篇文章就讲一下如何使用内核为我们提供的NETLINK_GENERIC进行通信。 如果把Netlink协议比作IP层,那么NETLINK_GENERIC可以比作UDP这一层。它们的具体关系如图1。 图中NETLINK_GENERIC协议作为Netlink层的payload,当然NETLINK_GENERIC作为一个上层协议,也拥有自己的头部(图中的Family头部)和pa...

weixin_39094034的博客 5119

内核Generic Netlink通信

内核netlink通信 select函数 Netlink 是一种在内核与用户应用间进行双向数据传输的非常好的方式,用户态应用使用标准的 socket API 就可以使用 netlink 提供的强大功能, 内核态需要使用专门的内核 API 来使用 netlink。 Netlink 相对于系统调用,ioctl 以及 /proc文件系统而言具有以下优点: 1,netlink使用简单,只需要在includ...

wefang的博客 1536

Generic Netlink详解

netlink socket是一种用于用户态进程和内核态进程之间的通信机制。它通过为内核模块提供一组特殊的API,并为用户程序提供了一组标准的socket接口的方式,实现了全双工的通讯连接。 Netlink的特点: 双向传输,异步通信用户空间中使用标准socket API内核空间中使用专门的API支持多播可由内核端发起通信支持32种协议类型 netlink仅支持32种协议类型

工匠重生 3912

linux generic netlink实现机制:注册、创建

目录 1Generic Netlink 概述 2 Generic Netlink相关结构体 2.1 Generic Netlink消息头结构:struct genlmsghdr 2.2 Generic Netlink Family结构:struct genl_family(内核中完成注册) 2.3 Generic Netlink Family命令处理结构:struct genl_ops(内核中完成注册) 2.4 Generic Netlink Family内核接收消息结构:struct gen.

3484

投第一篇SCIE英文期刊(详细步骤)

一个投稿SCIE英文期刊的过程

weixin_48849679的博客 1万+

linux / Generic Netlink

Genetlink 消息是命令驱动式的,即每一条消息的 genlmsghdr 中都指明了当前消息的 cmd 消息命令,这些消息 cmd 命令由用户自行定义。由于 netlink 协议最多支持 32 个协议簇,目前 Linux4.1 的内核中已经使用其中 21 个,对于用户需要定制特殊的协议类型略显不够,而且用户还需自行在 include/linux/netlink.h 中添加簇定义,但有时不方便,为此 Linux 设计了这种通用 Netlink 协议簇,用户可在此之上定义更多类型的子协议。

布袋和尚 1650

PCL1.12.1+VTK9.1+Qt5.14.2实战:解决QVTKOpenGLNativeWidget点云渲染窗口初始化报错问题

本文针对PCL1.12.1、VTK9.1与Qt5.14.2集成开发中,QVTKOpenGLNativeWidget点云渲染窗口初始化时出现的报错与黑屏问题,提供了深度分析与两种实战解决方案。核心在于理解VTK版本升级导致的渲染窗口类型不匹配,并指导开发者通过显式创建vtkGenericOpenGLRenderWindow或利用窗口ID嵌入,正确初始化并绑定可视化组件,从而稳定实现点云渲染。

weixin_29284657的博客 221

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 N...

weixin_42017225的博客 1694

国标Gb28181里Contact和Route的使用

国标Gb28181是基于Sip协议的,因此对Contact和Route的使用,也可以说是Sip里Contact和Route的使用。Contact和Route则是sip协议里的头字段。 现在,在使用国标Gb28181来做项目时,经常会遇到这种情况,国标的下级是在内网里,上级在公网上。如果不做处理,下级到上级会经过nat协议的转换从而导致上级向下级发送请求时(比如获取目录请求)不能到达

wwyyxx26的专栏 5511

CTF全能工具箱ProV2:集成AI与94GB离线资源库,打造无网环境下的智能解题流水线

CTF全能工具箱ProV2是一款专为线下CTF比赛设计的All-in-One离线解决方案。它集成了94GB的庞大离线资源库,涵盖Web、逆向、Pwn等全方向工具链与知识库,并创新性地内置了本地AI大模型,可在断网环境下提供智能解题辅助,实现从信息收集到漏洞利用的智能流水线作业,极大提升比赛效率。

weixin_29240343的博客 421

Generic Netlink内核实现分析(二):通信

前一篇博文中分析了Generic Netlink的消息结构及内核初始化流程,本文中通过一个示例程序来了解Generic Netlink Family的注册初始化以及内核和应用层之间的通信流程。

My Linux Journey 1万+

从仿真到实战:PMOS缓启动与栅极泄放电路的优化设计

本文深入探讨了PMOS缓启动与栅极泄放电路的优化设计,通过立创EDA仿真和实物调试,解决了关断速度慢和耐压问题。文章详细介绍了电路改进方案和低功耗优化技巧,为工程师提供了实用的工程实践建议,帮助提升电源开关电路的性能和可靠性。

weixin_28721917的博客 256

Linux基础 -- Generic Netlink 框架详解与开发实践

在 Linux 内核开发中,内核模块往往需要提供接口供用户空间配置或查询内部状态。ioctl:接口扩展性差、维护成本高;procfssysfs:适合只读状态/参数设置,但不适合复杂命令;Netlink:适合复杂的、结构化的内核通信,但原始 Netlink 使用繁琐,需要自定义协议号与消息调度。u8 cmd;// 命令编号u8 flags;// 权限控制,如 GENL_ADMIN_PERM// 参数校验策略// 处理函数// 列表输出函数doit():处理用户空间发送的一次性命令;

sz66cm 学习随笔 1280

飞行机械臂设计

其后对飞行机械臂系统的机 理模型和基于 ADAMS 的物理模型进行了控制系统的搭建,对于机理模 型,设计了三个输入通道,分别是俯仰力矩,翻滚力矩与偏航力矩,控 制量为翻滚角,俯仰角,偏航角。四旋翼无人机自身具有独特的优势,在无人机上增加机械臂,整个 机体系统相当于一架空中行动自如的空中机器人,可以适应更多的应用场合,能够实现空中抓取,运输载荷,巡航监视等任务。的函数模块如图 4-8 所示,可见输入为 U1,U2,U3,U4,分别对应总力矩,俯仰力矩,翻滚力矩,偏航力矩,控制 量为俯仰角,翻滚角,偏航角。

coldmood77的博客 2914

069、自动曝光(AE)测光策略:全局/中心/点测光与曝光时间增益分配

本文深入探讨了自动曝光(AE)测光策略的技术细节与实际应用。作者通过多个真实案例(手机前置摄像头、车载ADAS、安防监控等)分析了全局测光、中心测光和点测光的优缺点,指出不同场景应采用不同策略。重点剖析了曝光时间与增益分配的"跷跷板效应",提出要根据传感器特性选择最优分配方案。文章强调测光策略应动态调整,并给出5条实用建议:结合场景切换测光模式、关注传感器增益拐点、点测光需防抖处理、全局测光不宜迷信、调试要观察亮度直方图。最后指出AE调试需要结合具体硬件特性进行实测优化,没有通用解决方案。

zzfmlxs的博客 100

Generic Netlink机制

文章目录数据结构genl_familygenl_ops多播组: genl_multicast_groupGeneric Netlink框架Generic Netlink消息消息头部消息API消息的封装消息的解析消息的发送协议初始化family的管理family的注册&去注册family操作集的注册&去注册控制familyfamily查询命令: ctrl_getfamily()消息接收: genl_rcv()genl_rcv_msg()Generic Netlink组播多播组的注册&去

九天小哥的专栏 2211

QT自制TCP服务器

TCP服务器 网络调试助手

大脑曝光 3626

二 generic netlink

一 基础 由于netlink协议最多支持32个协议簇,目前内核中已经使用其中21个,对于用户需要定制特殊的协议类型略显不够,为此Linux设计了这种通用Netlink协议簇,用户可在此之上定义更多类型的子协议。 Generic Netlink是基于客户端-服务端模型的通信机制。服务端(内核)注册family(family是对genl服务的各项定义的集合)。控制器和客户端都通过已注册的信息与服务

clytiejoe的专栏 1997

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

genl_ops结构分析

genl_ops结构分析 struct genl_ops是Generic netlink操作 字段 cmd,命令标识符,就是通过socket发送的命令 doit,标准的命令回调函数 dumpit,dump的回调 定义在genetlink下。 ...

qq_41224661的博客 1056

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

genetlink

转自: http://www.tuicool.com/articles/jE7nim netlink socket是一种用于用户态进程和内核态进程之间的通信机制。它通过为内核模块提供一组特殊的API,并为用户程序提供了一组标准的socket接口的方式,实现了全双工的通讯连接。 Netlink的特点:  双向传输,异步通信 用户空间中使用标准socket API 内核空间中使用专门的API

caoshunxin01的专栏 1169

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

四 libnl库详解

translate from http://www.infradead.org/~tgr/libnl/doc/core.html#core_netlink_fundamentals 1 介绍    libnl核心库提供了通过netlink socket连接所需要的基础函数,用于处理socket的链接和断开、数据收发、消息创建分析,提供用户可定制接收状态机,并提供一种抽象的数据类型框架,

clytiejoe的专栏 1万+

[Linux Kernel] generic_netlink 网络连接

文章目录1. Generic Netlink By Example参考    本文档简要介绍了Generic Netlink,提供了一些有关如何使用它的简单示例,以及一些有关如何充分利用Generic Netlink通信接口的建议。 尽管本文档不需要读者对Netlink是什么以及它如何工作有详细的了解,但是假定读者具有一些Netlink基本知识。 和往常一样,内核源代码是您最好的朋友。    尽管本文档从用户空间的角度简要讨论了Generic Netlink,但其主要重点是内核的Generic Netlin

u012849539的博客 1093

Linux 通用Netlink Howto文档翻译

原地址:https://wiki.linuxfoundation.org/networking/generic_netlink_howto 通用Netlink HOWTO 本文简要介绍了通用Netlink,一些简单的例子说明了如何使用它,并就如何充分利用通用Netlink通信接口提出了一些建议。虽然本文不要求读者详细了解Netlink是什么以及它是如何工作的,但这里假设读者具有一些基本的Netlink知识。和往常一样,内核源代码是您在这里最好的朋友。 虽然本文从用户空间的角度简要讨论了Generic Net

远见望远的博客 693
上一篇: Netlink0004 --- 多播机制的用法
下一篇: netlink 0006 --- genetlink代码例子
废言Pro
博客等级 码龄16年 1092粉丝 142原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值