美文网首页
netlink内核态和用户态使用

netlink内核态和用户态使用

作者: gbmaotai | 来源:发表于2018-11-05 10:23 被阅读0次

vold进程:

1.管理和控制Android平台外部存储设备,包括SD插拨、挂载、卸载、格式化

2.3G 4G 模块支持
G3Dev.cpp ----- usb_modeswitch -W -I ....

clipboard.png

netlink

Netlink是一种在内核与用户应用间进行双向数据传输的非常好的方式,用户态应用使用标准的socketAPI就可以使用netlink提供的强大功能,内核态需要使用专门的内核API来使用netlink。

netd vold 都在使用这个。

Netlink的优点:
1. 使用简便

为了使用netlink,用户仅需要在include/linux/netlink.h中增加一个新类型的netlink协议定义即可,如#defineNETLINK_MYTEST17,然后,内核和用户态应用就可以立即通过socketAPI使用该netlink协议类型进行数据交换。但系统调用需要增加新的系统调用,ioctl则需要增加设备或文件,那需要不少代码,proc文件系统则需要在/proc下添加新的文件或目录,那将使本来就混乱的/proc更加混乱。

2.异步通信

netlink是一种异步通信机制,在内核与用户态应用之间传递的消息保存在socket缓存队列中,但系统调用与ioctl则是同步通信机制。

3.模块机制

使用netlink的内核部分可以采用模块的方式实现,使用netlink的应用部分和内核部分没有编译时依赖,但系统调用就有依赖,而且新的系统调用的实现必须静态地连接到内核中,它无法在模块中实现,使用新系统调用的应用在编译时需要依赖内核。

4.支持多播

内核模块或应用可以把消息多播给一个netlink组,属于该neilink组的任何内核模块或应用都能接收到该消息,内核事件向用户态的通知机制就使用了这一特性,任何对内核事件感兴趣的应用都能收到该子系统发送的内核事件。

#define NETLINK_ROUTE    0  /* Routing/device hook   */
#define NETLINK_UNUSED   1  /* Unused number     */
#define NETLINK_USERSOCK    2   /* Reserved for user mode socket protocols  */
#define NETLINK_FIREWALL    3   /* Firewalling hook  */
#define NETLINK_SOCK_DIAG   4   /* socket monitoring     */
#define NETLINK_NFLOG    5  /* netfilter/iptables ULOG */
#define NETLINK_XFRM     6  /* ipsec */
#define NETLINK_SELINUX  7  /* SELinux event notifications */
#define NETLINK_ISCSI    8  /* Open-iSCSI */
#define NETLINK_AUDIT    9  /* auditing */
#define NETLINK_FIB_LOOKUP  10
#define NETLINK_CONNECTOR   11
#define NETLINK_NETFILTER   12  /* netfilter subsystem */
#define NETLINK_IP6_FW   13
#define NETLINK_DNRTMSG  14 /* DECnet routing messages */
#define NETLINK_KOBJECT_UEVENT  15  /* Kernel messages to userspace */
</span>#define NETLINK_GENERIC   16
/* leave room for NETLINK_DM (DM Events) */
#define NETLINK_SCSITRANSPORT   18  /* SCSI Transports */
#define NETLINK_ECRYPTFS    19
#define NETLINK_RDMA     20
#define NETLINK_CRYPTO   21 /* Crypto layer */

用户态如何使用netlink

1.创建一个netlinksocket
socket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
2.设置socket的选项(可选)
setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
3.bind

使用bind()把创建的netlinksocket与netlinksocket地址绑定在一起

bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr));

其中,nladdr是sockaddr_nl结构体:

struct sockaddr_nl
{
  sa_family_t    nl_family;
  unsigned short    nl_pad;
  __u32          nl_pid;
  __u32          nl_groups;
};

字段nl_family必须设置为AF_NETLINK或着PF_NETLINK,字段nl_pad当前没有使用,因此要总是设置为0,字段nl_pid为接收或发送消息的进程的ID,如果希望内核处理消息或多播消息,就把该字段设置为0,否则设置为处理消息的进程ID。字段nl_groups用于指定多播组,bind函数用于把调用进程加入到该字段指定的多播组,如果设置为0,表示调用者不加入任何多播组。

struct sockaddr_nl nladdr;
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = getpid();
nladdr.nl_groups = 0xffffffff;
4.创建一个listener监听该socket

创建一个listener监听该socket,重写listener的onEvent函数,来完成对监听到的数据进行筛选/分类/处理。

mHandler = new NetlinkHandler(mSock);

内核态如何使用netlink

1.创建netlinksocket。
ue_sk->sk = netlink_kernel_create(net, NETLINK_KOBJECT_UEVENT,
  1, NULL, NULL, THIS_MODULE);

其中第四个参数为接收用户态消息的函数指针,为null说明为单向的,即内核不处理用户态发来的消息,只是向用户态通知内核事件。

NETLINK_KOBJECT_UEVENT是表示的接收内核uevent信息

3.向用户态上报消息

当有事件发生的时候,调用 kobject_uevent()函数,实际上最终是调用
netlink_broadcast_filtered
完成广播任务。

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

其中,参数sk为函数netlink_kernel_create()返回的socket,参数skb存放消息,参数pid为接收消息进程的pid,参数group为接收消息的多播组。

NETD

内核检测打到网络的变化 ,向用户态通知。
比如interface add /remove, link up/down.

int NetlinkManager::start() {
    if ((mUeventHandler = setupSocket(&mUeventSock, NETLINK_KOBJECT_UEVENT,
         0xffffffff, NetlinkListener::NETLINK_FORMAT_ASCII)) == NULL) {
        return -1;
    }
    ...
}
 
NetlinkHandler *NetlinkManager::setupSocket(int *sock, int netlinkFamily,
    int groups, int format) {
    struct sockaddr_nl nladdr;
    int sz = 64 * 1024;
    int on = 1;
    memset(&nladdr, 0, sizeof(nladdr));
    nladdr.nl_family = AF_NETLINK;
    nladdr.nl_pid = getpid();
    nladdr.nl_groups = groups;
 
    if ((*sock = socket(PF_NETLINK, SOCK_DGRAM, netlinkFamily)) < 0) {
    ...}
 
    if (setsockopt(*sock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
    ...}
 
    if (setsockopt(*sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
    ...}
 
    if (bind(*sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
    ...}
 
    NetlinkHandler *handler = new NetlinkHandler(this, *sock, format);
    if (handler->start()) {
    ...}
    return handler;
}
 
int NetlinkManager::stop() {
    ...
    if (mUeventHandler->stop()) {
    ...}
 
    delete mUeventHandler;
    mUeventHandler = NULL;
 
    close(mUeventSock);
    mUeventSock = -1;
...
}

int NetlinkHandler::start() {
    return this->startListener();
}
 
int NetlinkHandler::stop() {
    return this->stopListener();
}
 
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
const char *subsys = evt->getSubsystem();
     ...
if (!strcmp(subsys, "net")) {
        int action = evt->getAction();
        const char *iface = evt->findParam("INTERFACE");
 
        if (action == evt->NlActionAdd) {
            notifyInterfaceAdded(iface);
        } else if (action == evt->NlActionRemove) {
            notifyInterfaceRemoved(iface);
        } else if (action == evt->NlActionChange) {
            evt->dump();
            notifyInterfaceChanged("nana", true);
        } else if (action == evt->NlActionLinkUp) {
            notifyInterfaceLinkChanged(iface, true);
        } else if (action == evt->NlActionLinkDown) {
            notifyInterfaceLinkChanged(iface, false);
        } else if (action == evt->NlActionAddressUpdated ||
                   action == evt->NlActionAddressRemoved) {
            const char *address = evt->findParam("ADDRESS");
            const char *flags = evt->findParam("FLAGS");
            const char *scope = evt->findParam("SCOPE");
            if (iface && flags && scope) {
                notifyAddressChanged(action, address, iface, flags, scope);
            ...}
        ...}
    ...}
}

相关文章

  • netlink内核态和用户态使用

    vold进程: 1.管理和控制Android平台外部存储设备,包括SD插拨、挂载、卸载、格式化 2.3G 4G 模...

  • 内核态和用户态、

    内核态和用户态的区别 内核态切换用户态耗时的原因

  • 内核态和用户态

    内核态和用户态是操作系统的两种运行级别,内核态权限高,用户态权限低。 用户程序从用户态切换到内核态:系统调用(软中...

  • 深入理解goroutine调度 2023-01-03

    内核态vs用户态 操作系统运行时使用的ram存储资源叫内核态用户(上层软件)运行时使用的ram存储资源叫用户态 对...

  • 【笔记】Linux内核简介

    用户态与内核态 用户态下,程序不能访问内核地址空间(数据和代码),内核态下则没有此限制。 激活内核例程的方法: 系...

  • Linux内核——用户堆栈和内核堆栈

    定义 每个进程都有用户堆栈和内核堆栈两个堆栈。进程在用户态时使用用户堆栈,陷入到内核态时便使用内核堆栈。 切换过程...

  • 进程内存布局

    ARM64内核的内存布局 进程有用户态和内核态,同样进程的地址空间包括用户地址空间和内核地址空间,用户态访问用户地...

  • 用户态与内核态

    什么是用户态、内核态一般的操作系统对执行权限进行分级,分别为用保护态和内核态。用户态相较于内核态有较低的执行权限,...

  • 用户态与内核态

    内核态与用户态 正如标题,本文主要讨论用户态与内核态。文章主要从什么是用户态与内核态,这两个名词是对谁而言的;并且...

  • 用户态和内核态

    操作系统会将内存分配为内核空间和用户空间 内核空间是由所有进程共享,每个进程通过系统调用进入内核用户空间中各个进程...

网友评论

      本文标题:netlink内核态和用户态使用

      本文链接:https://www.haomeiwen.com/subject/jrwjxqtx.html