linux内核探索--编写一个netlink通信模块

简介: 如何编写一个netlink通信模块

 目录

1,编写内核模块

2,增加相应的生成文件

3,编写用户进程代码

4,测试结果


要求:实现一个网络链路通信模块,用户发送字符串数据后,内核将字符串翻转,然后回复给用户态程序


与系统调用,/ proc,sysfs等类似,netlink也是一种用于用户进程与内核通信的机制,它是基于BSD套接字协议,使用AF_NETLINK地址簇。与系统调用,proc,sysfs文件系统等方式相比,网络链路具有简单,支持双向通信的特点,并支持消息多播机制。

1,编写内核模块

vim netlink_mod.c:

#include <linux/module.h>
#include <net/sock.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#define MY_NETLINK_TYPE 31 //max is 32, see netlink.h
struct sock *my_nl_sock = NULL;
static void hello_nl_recv_msg(struct sk_buff *skb)
{
    struct nlmsghdr *nlh;
    int pid;
    struct sk_buff *skb_out;
    int msg_size;
    char *msg=NULL;
    char *msg_zj=NULL;
    int res;
    int i;
    printk(KERN_INFO "Entering: %s\n", __FUNCTION__);
    //msg_size = strlen(msg);
    nlh = (struct nlmsghdr *)skb->data;//Kernel Space receive message from user
    printk(KERN_INFO "Netlink receive msg: %s\n", (char *)nlmsg_data(nlh));
    msg =nlmsg_data(nlh);
    printk(KERN_INFO "msg:%s\n",msg);    
    msg_size = strlen(msg);
    printk(KERN_INFO "size of msg:%d\n",msg_size);    
    //String inversion
    msg_zj = (char *)kmalloc(msg_size + 1,GFP_KERNEL);
    memset(msg_zj, 0, msg_size + 1);
    for(i = 0; i < msg_size;i++)
    {
  msg_zj[i]=msg[msg_size-i-1];
    }    
    printk(KERN_INFO "msg_zj:%s\n",msg_zj);    
    pid = nlh->nlmsg_pid;
    skb_out = nlmsg_new(msg_size, 0);
    if (!skb_out) {
        printk(KERN_INFO "alloc nlmsg failed\n");
        return;
    }
    nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0);
    NETLINK_CB(skb_out).dst_group = 0;
    //strncpy(nlmsg_data(nlh), msg, msg_size);
    strncpy(nlmsg_data(nlh), msg_zj, msg_size);
    res = nlmsg_unicast(my_nl_sock, skb_out, pid);//Kernel Space send message toUser Space
    if (res < 0)
        printk(KERN_INFO "nlmsg unicast failed\n");
    kfree(msg_zj);
    return;
}
static int __init hello_init(void)
{
    struct netlink_kernel_cfg cfg = {
            .groups = 0,
            .input = hello_nl_recv_msg
    };
    printk("Entering: %s:\n", __FUNCTION__);
    my_nl_sock = netlink_kernel_create(&init_net, MY_NETLINK_TYPE, &cfg);
    if (!my_nl_sock) {
        printk(KERN_ALERT "netlink create sock failed\n");
        return -10;
    }
    return 0;
}
static void __exit hello_exit(void)
{
    printk(KERN_INFO "Exiting hello module\n");
    netlink_kernel_release(my_nl_sock);
    my_nl_sock = NULL;
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

image.gif

2,增加相应的生成文件

vim Makefile:

obj-m += netlink_mod.o
#KVERSION = $(shell uname -r)
#PWD = $(shell pwd)
all:
  make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
  make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

如果觉得文章对你有帮助,欢迎关注微信公众号:小牛呼噜噜

3,编写用户进程代码

用户进程主要使用netlink的socket与内核进行通信,首先向内核发送一条消息,然后再接收内核的消息,代码如下:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#define MY_NETLINK_TYPE 31
#define MAX_PAYLOAD 1024 /* maximum payload size*/
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd;
struct msghdr msg;
int 
main(int argc, char *argv[])
{
    sock_fd = socket(PF_NETLINK, SOCK_DGRAM, MY_NETLINK_TYPE);
    if (sock_fd < 0)
        return -1;
    memset(&src_addr, 0, sizeof(src_addr));
    src_addr.nl_family = AF_NETLINK;
    src_addr.nl_pid = getpid(); /* self pid */
    bind(sock_fd, (struct sockaddr *)&src_addr, sizeof(src_addr));
    memset(&dest_addr, 0, sizeof(dest_addr));
    memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.nl_family = AF_NETLINK;
    dest_addr.nl_pid = 0; /* For Linux Kernel */
    dest_addr.nl_groups = 0; /* unicast */
    nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
    memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
    nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
    nlh->nlmsg_pid = getpid();
    nlh->nlmsg_flags = 0;
    strcpy(NLMSG_DATA(nlh), "Hello");
    iov.iov_base = (void *)nlh;
    iov.iov_len = nlh->nlmsg_len;
    msg.msg_name = (void *)&dest_addr;
    msg.msg_namelen = sizeof(dest_addr);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
    printf("Sending message to kernel<<<%s\n",NLMSG_DATA(nlh));
    sendmsg(sock_fd, &msg, 0);//User Space send message to kernel
    printf("Waiting for message from kernel\n");
    /* Read message from kernel */
    recvmsg(sock_fd, &msg, 0);//User Space receive message from kernel
    printf("Received message payload>>>%s\n", NLMSG_DATA(nlh));
    close(sock_fd);
    return 0;
}

image.gif

4,测试结果

编译模块:

使

image.png

加载该模块:

sudo insmod netlink_mod.ko

image.gif

加载后可用的lsmod查看是否加载成功,然后编译并运行用户进程hello_user

gcc user.c -o user

image.gif

运行

./user

image.gif

可在终端中看到如下结果:

Sending message to kernel<<<Hello
Waiting for message from kernel
Received message payload>>>olleH
上面是用户进程的输出,可用dmesg命令查看内核模块的输出(或者直接查看/var/log/kern).

image.gif

image.png

卸载模块

sudo rmmod netlink_mod

参考:https//yangjin-unique.github.io/ru-he-zai-linuxnei-he-mo-kuai-zhong-jia-ru-netlinktong-xin-jie-kou.html


相关文章
|
1天前
|
算法 Linux 定位技术
Linux内核中的进程调度算法解析####
【10月更文挑战第29天】 本文深入剖析了Linux操作系统的心脏——内核中至关重要的组成部分之一,即进程调度机制。不同于传统的摘要概述,我们将通过一段引人入胜的故事线来揭开进程调度算法的神秘面纱,展现其背后的精妙设计与复杂逻辑,让读者仿佛跟随一位虚拟的“进程侦探”,一步步探索Linux如何高效、公平地管理众多进程,确保系统资源的最优分配与利用。 ####
15 4
|
2天前
|
缓存 负载均衡 算法
Linux内核中的进程调度算法解析####
本文深入探讨了Linux操作系统核心组件之一——进程调度器,着重分析了其采用的CFS(完全公平调度器)算法。不同于传统摘要对研究背景、方法、结果和结论的概述,本文摘要将直接揭示CFS算法的核心优势及其在现代多核处理器环境下如何实现高效、公平的资源分配,同时简要提及该算法如何优化系统响应时间和吞吐量,为读者快速构建对Linux进程调度机制的认知框架。 ####
|
5天前
|
缓存 Linux
揭秘Linux内核:探索CPU拓扑结构
【10月更文挑战第26天】
19 1
|
5天前
|
缓存 运维 Linux
深入探索Linux内核:CPU拓扑结构探测
【10月更文挑战第18天】在现代计算机系统中,CPU的拓扑结构对性能优化和资源管理至关重要。了解CPU的核心、线程、NUMA节点等信息,可以帮助开发者和系统管理员更好地调优应用程序和系统配置。本文将深入探讨如何在Linux内核中探测CPU拓扑结构,介绍相关工具和方法。
8 0
|
2天前
|
缓存 算法 Linux
Linux内核中的内存管理机制深度剖析####
【10月更文挑战第28天】 本文深入探讨了Linux操作系统的心脏——内核,聚焦其内存管理机制的奥秘。不同于传统摘要的概述方式,本文将以一次虚拟的内存分配请求为引子,逐步揭开Linux如何高效、安全地管理着从微小嵌入式设备到庞大数据中心数以千计程序的内存需求。通过这段旅程,读者将直观感受到Linux内存管理的精妙设计与强大能力,以及它是如何在复杂多变的环境中保持系统稳定与性能优化的。 ####
6 0
|
13天前
|
运维 安全 Linux
Linux中传输文件文件夹的10个scp命令
【10月更文挑战第18天】本文详细介绍了10种利用scp命令在Linux系统中进行文件传输的方法,涵盖基础文件传输、使用密钥认证、复制整个目录、从远程主机复制文件、同时传输多个文件和目录、保持文件权限、跨多台远程主机传输、指定端口及显示传输进度等场景,旨在帮助用户在不同情况下高效安全地完成文件传输任务。
104 5
|
13天前
|
Linux
Linux系统之expr命令的基本使用
【10月更文挑战第18天】Linux系统之expr命令的基本使用
48 4
|
3天前
|
Linux Shell 数据安全/隐私保护
|
4天前
|
域名解析 网络协议 安全