设为首页 加入收藏

TOP

Linux Netlink学习笔记(一)
2023-07-23 13:32:49 】 浏览:59
Tags:Linux Netlink 习笔记

参考链接:https://www.systutorials.com/docs/linux/man/7-netlink/

1. 监听Netlink消息类型示例

Netlink是用户程序与内核通信的socket方法,通过Netlink可以获得修改内核的配置,常见的有获得接口的IP地址列表、更改路由表或邻居表。旧版本的内核提供很多从内核获取信息的方式,至今仍在被广泛使用。
其次,除了可以获取修改内核配置外,还能够监听内核相关配置信息变化的事件,例如:接口状态、接口地址、内核路由表或者内核邻居表项的变更。
下面,我们先列举一个简单的例子:监听接口的状态变化,并打印出出,发生变化的接口信息。

1.1. 监听接口状态变化

咋们直接上代码,然后在详细描述,实现的关键步骤。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include <asm/types.h>
#include <linux/if.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>

#define dprint(format, ...) \
    printf("[%15s:%-4d] " format , __FUNCTION__, __LINE__, ##__VA_ARGS__)

static int gnl_fd;

static void parse_rtattr(struct rtattr **tb, int max, struct rtattr *attr, int len)
{
    for ( ; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
        if (attr->rta_type <= max) {
            tb[attr->rta_type] = attr;
        }
    }
}

static void show_iflink_msg(struct nlmsghdr *nh_msg)
{
    int msg_len;
    /**
     * @brief #define IFLA_MAX (__IFLA_MAX - 1)
     * 头文件:linux/if_link.h
     */
    struct rtattr *tb[IFLA_MAX + 1];
    struct ifinfomsg *ifmsg; /* 6 */

    bzero(tb, sizeof(tb));
    ifmsg = NLMSG_DATA(nh_msg); /* 7 */
    msg_len = nh_msg->nlmsg_len - NLMSG_SPACE(sizeof(*ifmsg));
    parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifmsg), msg_len); /* 8 */

    dprint("  >> if intf_index: %d\n", ifmsg->ifi_index);
    dprint("  >> if intf_name : %s\n", (tb[IFLA_IFNAME] ? RTA_DATA(tb[IFLA_IFNAME]) : " "));
    dprint("  >> if link_type : %s\n", (nh_msg->nlmsg_type == RTM_NEWLINK) ? "NEWLINK" : "DELLINK");
    dprint("  >> if link_state: %s\n\n", (ifmsg->ifi_flags & IFF_UP) ? "up" : "down");
    return;
}

int main(int argc, char **argv)
{
    fd_set rd_set;
    int max_fd = -1;
    int iret, old_iret = -1;
    struct timeva l tmval;
    struct sockaddr_nl sa_nl;
    char sbuff[2048];
    struct nlmsghdr *nh_msg;

    memset(&sa_nl, 0, sizeof(sa_nl));
    sa_nl.nl_family = PF_NETLINK; /* 1 */
    sa_nl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR; /* 2 */

    gnl_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); /* 3 */
    bind(gnl_fd, (struct sockaddr *) &sa_nl, sizeof(sa_nl));

    dprint("begin listen gnl_fd socket ...\n");
    for ( ; ; ) {
        FD_ZERO(&rd_set);
        FD_SET(gnl_fd, &rd_set);

        tmval.tv_sec = 1;
        tmval.tv_usec = 0;
        max_fd = (max_fd > gnl_fd) ? max_fd : gnl_fd;

        iret = select(max_fd + 1, &rd_set, NULL, NULL, &tmval);
        if (old_iret != iret) {
            dprint("select return value %d, errno %d.\n", iret, errno);
            old_iret = iret;
        }

        if (iret == -1 || iret == 0 || !FD_ISSET(gnl_fd, &rd_set)) {
            if (iret == -1 && errno != EINTR)
                break;
            continue;
        }
        
        iret = read(gnl_fd, sbuff, sizeof(sbuff)); 
        dprint("  >> read gnl_fd return value %d.\n", iret);
        if (iret <= 0) {
            continue;
        }

        nh_msg = (struct nlmsghdr *)sbuff;
        for ( ; NLMSG_OK(nh_msg, iret); nh_msg = NLMSG_NEXT(nh_msg, iret)) { /* 4 */
            dprint("  >> recive nh_msg type %u, portid %u.\n", nh_msg->nlmsg_type, nh_msg->nlmsg_pid);

            /**
             * @brief 这里的 nlmsg_type 对应到 linux/rtnetlink.h 中
             * enum { RT
首页 上一页 1 2 3 4 下一页 尾页 1/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Ubuntu20.04 命令行 修改系统IP地.. 下一篇Linux 内存管理 pt.2

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目