女人被狂躁到高潮视频免费无遮挡,内射人妻骚骚骚,免费人成小说在线观看网站,九九影院午夜理论片少妇,免费av永久免费网址

當(dāng)前位置:首頁(yè) > > 充電吧
[導(dǎo)讀]內(nèi)核態(tài)與用戶態(tài)通信方式 Linux下內(nèi)核空間與用戶空間進(jìn)行通信的方式主要有system call、sysctl、procfs、模塊參數(shù)、debugfs、relayfs、sysfs和netlink等。

內(nèi)核態(tài)與用戶態(tài)通信方式

Linux下內(nèi)核空間與用戶空間進(jìn)行通信的方式主要有system call、sysctl、procfs、模塊參數(shù)、debugfs、relayfs、sysfs和netlink等。

Why NetlinK full-duplex

模塊參數(shù)、sysfs、procfs、debugfs和relayfs都是基于文件系統(tǒng),用于內(nèi)核向用戶發(fā)送消息;sysctl和system call是用戶向內(nèi)核發(fā)送消息。它們都是單工通信方式。netlink是一種特殊的通信方式,用于在內(nèi)核空間和用戶空間傳遞消息,是一種雙工通信方式。使用地址協(xié)議簇AF_NETLINK,使用頭文件include/linux/netlink.h。

simple to add
為新特性添加system call、sysctl或者procfs是一件復(fù)雜的工作,它們會(huì)污染kernel,破壞系統(tǒng)的穩(wěn)定性,這是非常危險(xiǎn)的。Netlink的添加,對(duì)內(nèi)核的影響僅在于向netlink.h中添加一個(gè)固定的協(xié)議類型,然后內(nèi)核模塊和應(yīng)用層的通信使用一套標(biāo)準(zhǔn)的API。 Netlink Socket APIs 用戶空間 創(chuàng)建
int socket(int doamin, int type, int protocal);

domain填A(yù)F_NETLINK,type為SOCK_RAW或者SOCK_DGRAM。protocal可選NETLINK_ROUTE、NETLINK_FIREWALL、NETLINK_ARPD、NETLINK_ROUTE6和NETLINK_IP6_FW,或者傳入自定義協(xié)議類型。

綁定
int bind(int fd, (struct sockaddr *)&nladdr, sizeof(nladdr));

netlink地址結(jié)構(gòu)如下

struct sockaddr_nl{
    sa_family_t     nl_family;      //AF_NETLINK
    unsigned short  nl_pad;         //0
    __u32           nl_pid;         //進(jìn)程pid
    __u32           nl_groups;      //多播組掩碼
}

如果進(jìn)程僅僅使用一個(gè)netlink,nl_pid可以傳入該進(jìn)程的pid,

my_pid = getpid();

如果一個(gè)進(jìn)程的多個(gè)線程需要不同的netlink,使用如下方法獲得nl_pid:

pthread_self << 16 | gitpid();
發(fā)送
int sendmsg(fd, &msg, 0);

struct nlmsghdr msg為netlink發(fā)送消息結(jié)構(gòu),

struct msghdr{
    void            *msg_name;      //socket name
    int             msg_namelen;    //len of name
    struct iovec    *msg_iov;       //data block
    __kernel_size_t msg_iovlen;     //num of block
    void            *msg_control;   //per protocol magic
    __kernel_size_t msg_controllen; //len of cmsg list
    unsigned        msg_flags;

}

其中需要填充的是msg_iov和msg_oivlen。
msg與其他結(jié)構(gòu)體的關(guān)系如圖所示

nlmsghdr結(jié)構(gòu)體為消息頭信息

struct nlmsghdr{
    __u32 nlmsg_len;    //len of msg
    __u16 nlmsg_type;   //msg type
    __u16 nlmsg_flags;  //additional flags
    __u32 nlmsg_seq;    //sequence num
    __u32 nlmsg_pid;    //send process pid
}

nlmsg_len是整個(gè)消息的長(zhǎng)度,包含頭;
nlmsg_type對(duì)內(nèi)核不透明;
nlmsg_flag被用于對(duì)消息的附加控制;
nlmsg_seq和nlmsg_pid被用于跟蹤消息,對(duì)內(nèi)核不透明。

要將地址結(jié)構(gòu)體傳入消息頭部:

struct msghdr msg;
msg.msg_name = (void *)&nladdr;
msg.msg_namelen = sizeof(nladdr);

發(fā)送地址同樣使用sockaddr_nl結(jié)構(gòu)體,如果目的是內(nèi)核,nl_pid和nl_groups都為0;如果消息為單播,目的為另一個(gè)進(jìn)程,nl_pid是目的進(jìn)程pid,nl_groups為0;如果消息為多播,目的是一個(gè)或多個(gè)多播組,nl_groups域中需填寫所有目的多播組的掩碼和。

結(jié)構(gòu)體iovce結(jié)構(gòu)如下

struct iovec iov;
iov.iov_base = (void *)nlh;
iov.iov_len = nlh->nlmsg_len;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
接收

接收時(shí)需要?jiǎng)?chuàng)建足夠的buf,

struct sockadddr_nl nladdr;
struct msghdr msg;
struct iovec iov;

iov.iov_base = (void *)nlh;
iov.iov_len = MAX_NL_MSG_LEN;
msg.msg_name = (void *)&nladdr;
msg.msg_namelen = sizeof(nladdr);

msg.msg_iov = &iov;
msg.msg_iovlen = 1;
recvmsg(fd, &msg, 0);
內(nèi)核空間

內(nèi)核空間的API由net/core/af_netlink.c支持。
可以在netlink.h中添加自定義協(xié)議類型:

#define NETLINK_TEST    17
創(chuàng)建
struct sock *netlink_kernel_create(int unit, 
        void (*input)(struct sock *sk, int len));

unit是netlink.h中定義的協(xié)議類型,*input是一個(gè)回調(diào)函數(shù)指針,接收到消息會(huì)觸發(fā)這個(gè)函數(shù)。

發(fā)送

發(fā)送消息使用struct sk_buff *skb。
用以下方式設(shè)置本地地址:

NETLINK_CB(skb).groups = local_groups;
NETLINK_CB(skb).pid = 0;

因?yàn)槭窃趦?nèi)核,pid = 0

用以下方式設(shè)置目的地址:

NETLINK_CB(skb).dst_groups = dst_groups;
NETLINK_CB(skb).dst_pid = dst_pid;

發(fā)送單播函數(shù)為

int netlink_unicast(struct sock *sk, struct sk_buff *skb, u32 pid, int nonblock);

*sk為netlink_kernel_create()返回的結(jié)構(gòu)體指針;
skb->data指向消息;
pid為應(yīng)用程序的pid;
block表明如果當(dāng)接收緩沖非法時(shí)數(shù)據(jù)分塊還是返回錯(cuò)誤值。

發(fā)送多播函數(shù)為

void netlink_broadcast(struct sock *sk, struct sk_buff *skb, u32 pid, u32 group, int allocation);

group是所有需要接收多播消息的組掩碼和;
allocation是內(nèi)核內(nèi)存分配標(biāo)志,中斷上下文中使用GFP_ATOMIC,其他情況使用GFP_KERNEL。

銷毀
sock_release(nl_sk->socket);
example user-space 初始化
#define MAX_NLMSG_PAYLOAD_LEN       128
#define NETLINK_GROUP_MASK(group)   (1 << group)

int usr_netlink_init(int netlink_type, int *fd, int group)
{
    struct nlmsghdr *nlh = NULL;
    struct sockaddr_nl addr;

    memset((void *)&addr, 0x0, sizeof(addr));

    if ((*fd = socket(PF_NETLINK, SOCK_RAW, netlink_type)) < 0)
    {
        /* error process*/
        return -1;
    }

    addr.nl_family = AF_NETLINK;
    addr.nl_pid = getpid();
    addr.nl_groups = NETLINK_GROUP_MASK(group);

    if (bind(*fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        /* error process */
        close(*fd);
        *fd = -1;
        return -2;
    }

    /* send pid to kernel */
    if (us_netlink_send(*fd, 0, NULL, 0) < 0)
    {
        /* error process */
        close(*fd);
        *fd = -1;
        return -3;
    }

    return 0;
}
發(fā)送
int usr_netlink_send(int fd, uint16 msg_type, char *data, int data_len)
{
    struct nlmsghdr *nlh;
    struct msghdr msg;
    struct iovec iov;
    int msg_len;

    if (data && (msg_len > MAX_NLMSG_PAYLOAD_LEN))
    {
        return -1;
    }

    memset((void*)&iov, 0x0, sizeof(iov));
    memset((void*)&msg, 0x0, sizeof(msg));        
    msg_len = NLMSG_SPACE(data_len);

    nlh = (struct nlmsghdr *)malloc(msg_len);
    if (NULL = nlh)
    {
        return -2;
    }

    /* fill nlmsghdr */
    memset(nlh, 0x0, msg_len);
    nlh->nlmsg_len = msg_len;
    nlh->nlmsg_pid = getpid();
    nlh->nlmsg_type = msg_type;
    nlh->nlmsg_flags = 0;

    if (data)
    {
        memcpy(NLMSG_DATA(nlh), data, msg_len);
    }

    /* fill iovec */
    iov.iov_base = (void *)nlh;
    iov.iov_len = nlh->nlmsg_len;
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    if (sendmsg(fd, &msg, 0) < 0)
    {
        /* error process */
        free(nlh);
        return -3;
    }

    free(nlh);
    return 0;
}
接收
int usr_netlink_recv(int fd, char *buf, int len)
{
    struct iovec iov = {buf, len};
    struct sockaddr_nl nl_src_addr;
    struct msghdr msg;
    int recv_len;

    memset(&msg, 0x0, sizeof(struct msghdr));
    memset(&nl_src_addr, 0x0, sizeof(struct sockaddr_nl));

    msg.msg_name = (void *)&nl_src_addr;
    msg.msg_namelen = sizeof(nl_src_addr);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    recv_len = recvmsg(fd, &msg, 0);
    if (recv_len < 0)
    {
        /* recv error */
    }
    else if (recv_len == 0)
    {
        /* recv EOF */
    }

    return recv_len;
}
kernel 初始化
static struct sock *sg_knl_xxx_sk = NULL;
static int sg_knl_xxx_pid = -1;

void knl_netlink_init()
{   
    struct net init_net;

    sg_knl_xxx_sk = netlink_kernel_create(&init_net, NETLINK_TEST, 0, knl_neklink_recv, NULL, THIS_MODULE);
}
接收
void knl_netlink_recv(struct sock *skb)
{
    struct nlmsghdr *nlh = nlmsg_hdr(skb);
    sg_knl_xxx_pid = nlh->nlmsg_pid;
}
發(fā)送
int group_mask(int group)
{
    return (1 << group);
}

void knl_netlink_send(int msg_type, char *data, int data_len, int group)
{
    struct sk_buff *skb = NULL;
    struct nlmsghdr *nlh = NULL;
    unsigned int msg_len = NLMSG_SPACE(data_len);

    if(data && (data_len > MAX_PAYLOAD_LEN))
    {
        /* error process */
        return;
    } 

    skb = alloc_skb(msg_len, GFP_KERNEL);
    if (!skb)
    {
        /* erro process */
        return;
    }

    memset((void *)skb, 0x0, msg_len);
    nlh = nlmsg_put(skb, 0, 0, msg_type, msg_len, 0);

    if(data)
    {
        memcpy(NLMSG_DATA(nlh), data, data_len);
    } 

    NETLINK_CB(skb).pid = 0; /*from kernel */
    NETLINK_CB(skb).dst_group = group_mask(group); 

    /* if unicast */
    netlink_unicast(sg_knl_xxx_sk, skb, sg_knl_xxx_pid, MSG_DONTWAIT);
    /* if mulicast */
    //nlmsg_multicast(sg_knl_xxx_sk, skb, 0, group_mask(group), 0);
}
本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動(dòng)電源

在工業(yè)自動(dòng)化蓬勃發(fā)展的當(dāng)下,工業(yè)電機(jī)作為核心動(dòng)力設(shè)備,其驅(qū)動(dòng)電源的性能直接關(guān)系到整個(gè)系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動(dòng)勢(shì)抑制與過(guò)流保護(hù)是驅(qū)動(dòng)電源設(shè)計(jì)中至關(guān)重要的兩個(gè)環(huán)節(jié),集成化方案的設(shè)計(jì)成為提升電機(jī)驅(qū)動(dòng)性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機(jī) 驅(qū)動(dòng)電源

LED 驅(qū)動(dòng)電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個(gè)照明設(shè)備的使用壽命。然而,在實(shí)際應(yīng)用中,LED 驅(qū)動(dòng)電源易損壞的問題卻十分常見,不僅增加了維護(hù)成本,還影響了用戶體驗(yàn)。要解決這一問題,需從設(shè)計(jì)、生...

關(guān)鍵字: 驅(qū)動(dòng)電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動(dòng)電源的公式,電感內(nèi)電流波動(dòng)大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計(jì) 驅(qū)動(dòng)電源

電動(dòng)汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動(dòng)汽車的核心技術(shù)之一是電機(jī)驅(qū)動(dòng)控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機(jī)驅(qū)動(dòng)系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動(dòng)汽車的動(dòng)力性能和...

關(guān)鍵字: 電動(dòng)汽車 新能源 驅(qū)動(dòng)電源

在現(xiàn)代城市建設(shè)中,街道及停車場(chǎng)照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進(jìn)步,高亮度白光發(fā)光二極管(LED)因其獨(dú)特的優(yōu)勢(shì)逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動(dòng)電源 LED

LED通用照明設(shè)計(jì)工程師會(huì)遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動(dòng)電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動(dòng)電源的電磁干擾(EMI)問題成為了一個(gè)不可忽視的挑戰(zhàn)。電磁干擾不僅會(huì)影響LED燈具的正常工作,還可能對(duì)周圍電子設(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來(lái)解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動(dòng)電源

開關(guān)電源具有效率高的特性,而且開關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機(jī)重量也有所下降,所以,現(xiàn)在的LED驅(qū)動(dòng)電源

關(guān)鍵字: LED 驅(qū)動(dòng)電源 開關(guān)電源

LED驅(qū)動(dòng)電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動(dòng)LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動(dòng)電源
關(guān)閉