libnl教程(2):发送请求

news2024/9/19 16:44:10

文章目录

    • 前言
    • 示例
      • 示例代码
      • 构造请求
      • 创建套接字
      • 发送请求
    • 简化示例

前言

前置阅读要求:libnl教程(1):订阅内核的netlink广播通知

本文介绍,libnl如何向内核发送请求。这包含三个部分:构建请求;创建套接字;发送请求。

同样,本文使用示例说明libnl的API该如何组合使用。

本文使用的示例是,发送netlink请求,以创建一张dummy网卡。


示例

示例代码

运行该示例代码,即可创建一个dummy类型的网卡。网卡名为dummy0

代码参考自:https://github.com/FDio/vpp/blob/master/src/vnet/devices/netlink.c

上面的参考代码很好,完整的显示了构建请求-创建套接字-发送请求-接收回复的过程。

但是上面参考代码的路子有点野。因为它很少调用libnl的API。它作为参考是好的。但是日常编程中,还是尽量调用libnl的API。

下面的示例代码中,我在展示逻辑结构的基础上,尽量调用了libnl的API。

#include <linux/rtnetlink.h>
#include <netlink/msg.h>
#include <netlink/netlink.h>
#include <netlink/route/link.h>
#include <netlink/socket.h>

int netlink_add(const char *iftype, const char *ifname) {
  int ret = 0;
  struct nl_msg *msg = NULL;
  struct nl_sock *sk = NULL;

  // 构建请求
  msg = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK |
                                            NLM_F_CREATE | NLM_F_EXCL);

  struct ifinfomsg ifi = {};
  ifi.ifi_family = AF_UNSPEC;

  ret = nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO);
  if (ret < 0) {
    printf("%s", nl_geterror(ret));
    goto end;
  }

#if 0
  ret = nla_put_string(msg, IFLA_INFO_KIND, iftype);
  if (ret < 0) {
    goto end;
  }
#endif

  struct nlattr *info = nla_nest_start(msg, IFLA_LINKINFO);
  ret = nla_put_string(msg, IFLA_INFO_KIND, iftype);
  if (ret < 0) {
    printf("%s", nl_geterror(ret));
    goto end;
  }
  nla_nest_end(msg, info);

  ret = nla_put_string(msg, IFLA_IFNAME, ifname);
  if (ret < 0) {
    printf("%s", nl_geterror(ret));
    goto end;
  }

  // 创建套接字
  sk = nl_socket_alloc();

  nl_connect(sk, NETLINK_ROUTE);

  // 发送请求
  ret = nl_send_auto(sk, msg);
  if (ret < 0) {
    printf("%s", nl_geterror(ret));
    goto end;
  }

  // 接收回复
  ret = nl_recvmsgs_default(sk);
  if (ret < 0) {
    printf("%s", nl_geterror(ret));
    goto end;
  }

end:
  nlmsg_free(msg);
  nl_socket_free(sk);
  return 0;
}

int main(int argc, char *argv[]) { netlink_add("dummy", "dummy0"); }

构造请求

一个Link请求包含三部分:

  • netlink header(struct nlmsghdr): netlink消息本身的头。其余部分都是netlink消息的负载。整个消息都遵循TLV(Type–length–value)。消息头中记录着消息的整体长度。后面的负载中的属性也遵循TLV。
  • netlink link messages header(struct ifinfomsg): Link请求的消息头。
  • netlink attributes(struct nlattr): 一个属性的类型和长度,后面要跟着具体的属性。

请求的整体格式如下。

在这里插入图片描述

在内存中,有对齐要求,格式如下。

在这里插入图片描述

接下来介绍,该如何填充这些内容。

  • struct nlmsghdr的填充:可以使用 nlmsg_alloc_simple(int nlmsg_type, int flags)函数填充。调用这些API的好处是,可以屏蔽 sequence numbers、port等细节。代码中的消息类型是RTM_NEWLINK表示创建网卡。标志的含义表示,这是一个请求,需要回复,请求创建一张网卡,如果网卡已经存在,则不在创建。
  • struct ifinfomsg的填充:示例代码没有填充任何内容。因为是创建网卡。如果是查询/修改网卡等操作,需要根据不同情况填充不同内容。
  • struct nlattr的填充:示例追加了两个属性,分别用来设置网卡类型和网卡名称。为什么网卡类型使用嵌套属性。因为我们用户层是发起请求,这个是内核路由部分的要求。我是咋知道的呢?因为我去看来libnl中rtnl_link_add()函数的源码知道的。

创建套接字

使用libnl的接口创建套接字。当然,我们也可以跳过libnl的API,直接使用socket创建套接字,但是没必要。

sk = nl_socket_alloc();
nl_connect(sk, NETLINK_ROUTE);

发送请求

通过netlink套接字,发送netlink消息的标准方法是,使用nl_send_auto()函数。它将自动补充netlink消息头中丢失的内容信息,然后将消息传递给nl_send()


简化示例

上面示例中,最麻烦的一步是构造请求。

其实,我们想一想,构造请求基本都是固定的,只有很少的字段需要用户指定。

再想一想,其实请求和回复也基本是固定的。

这些都可以按照目的进行封装,形成更高层的接口。

下面,我们使用libnl的接口,可以更简单的实现我们的目标。(因为这个完全失去了请求的细节,所以我构造了上面的示例。)

#include <linux/rtnetlink.h>
#include <netlink/msg.h>
#include <netlink/netlink.h>
#include <netlink/route/link.h>
#include <netlink/socket.h>

int netlink_add(const char *iftype, const char *ifname) {
  struct rtnl_link *link = rtnl_link_alloc();
  rtnl_link_set_type(link, iftype);
  rtnl_link_set_name(link, ifname);

  struct nl_sock *sk = nl_socket_alloc();
  nl_connect(sk, NETLINK_ROUTE);

  rtnl_link_add(sk, link, NLM_F_CREATE | NLM_F_EXCL);
  return 0;
}

int main(int argc, char *argv[]) { netlink_add("dummy", "dummy0"); }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2039880.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

milvus helm k8s开启监控

https://milvus.io/docs/monitor.md 文章写的很清晰 &#xff0c;我这边做一下个人补充&#xff0c;初版可能只是配置&#xff0c;具体的grafana 监控报表后期补一下。 架构如下&#xff1a; values.yaml 配置 enabled: true 改为true metrics:enabled: trueserviceMonitor:…

F.Enchanted

https://codeforces.com/gym/105139/problem/F24湖北省赛F 看了一下前面两种操作&#xff0c;做法不是很明显 后面两种操作&#xff0c;一看就是可持久化线段树&#xff0c;单点修改&#xff0c;版本复制 接下来解决前面的两种操作 第一个操作 两个相同的合成一个新的(33-&…

Linux基础-磁盘管理

基于Ubuntu 20.04环境测试验证。 一、磁盘空间查看 1.1 磁盘分区管理 - fdisk fdisk通常被用来查看系统磁盘的分区信息&#xff0c;同时fdisk也支持对磁盘空间进行分区&#xff08;下一章节介绍&#xff09;。 命令参数&#xff1a; Usage:fdisk [options] <disk> …

科普----Linux的前世今生

提到电脑的操作系统 相信大多数人会脱口而出&#xff1a;Windows&#xff01;MacOS&#xff01; 没错&#xff0c;这确实是目前市场上主流的两款操作系统。 但对于从事IT相关工作的人们来说&#xff0c;还有一种系统也必须拥有姓名 那就是Linux 看到这个词&#xff0c;大家…

unity游戏开发003:深入理解Unity中的坐标系

Unity游戏开发 “好读书&#xff0c;不求甚解&#xff1b;每有会意&#xff0c;便欣然忘食。” 本文目录&#xff1a; Unity游戏开发 Unity游戏开发深入理解Unity中的坐标系前言1. 坐标轴2. 左手坐标系3. 世界坐标系 vs. 局部坐标系4. 坐标变换5. 注意事项 总结 深入理解Unity中…

虚幻5|简单装备武器

一&#xff0c;首先我们要创建一个actor蓝图类 打开组件添加一个静态网格体&#xff0c;点击该组件&#xff0c;右侧细节找到网格体资产&#xff0c;选择需要的武器 三&#xff0c;打开角色的骨骼网格体&#xff0c;添加武器插槽 这个有些动作包里的骨骼网格体是加了骨骼&…

10 - Linux系统安全及应用

目录 一、账号安全控制 1.系统账号清理 2.密码安全控制 3.命令历史限制 4.终端自动注销 二、用户切换和用户提权 1. su 命令 - 切换用户 1.1 su 命令的用途及用法 1.2 限制使用su 命令的用户 1.3 查看su操作记录 2. sudo 命令 - 用户提权 2.1 sudo 命令的用途及用法…

Unity转Unreal5从入门到精通之如何实现一个简单的AI寻路

前言 我们今天使用最基础的引擎知识&#xff0c;来给大家创建一个简单的AI&#xff0c;可以追踪目标&#xff0c;攻击目标。 使用Unity类比的话&#xff0c;就是一个怪物预制体&#xff0c;放到了寻路上&#xff0c;当他视野看到目标后&#xff0c;就一直追踪目标&#xff0c;…

转账记录是怎样使用ZK实现证明的

目录 转账记录是怎样使用ZK实现证明的 1. 准备阶段 2. 生成证明 3. 转账记录的验证过程 4. 隐私保护 5. 应用场景 结论 转账记录是怎样使用ZK实现证明的 转账记录使用ZK(零知识证明)实现证明的过程,主要依赖于零知识证明技术中的协议,如ZK-SNARKs(Zero-Knowledge S…

72、docker资源管理

一、docker数据卷 容器和宿主机之间数据共享-----------挂载卷------------容器内的目录和宿主机的目录进行挂载。实现数据文件共享。 容器的生命周期是有限的&#xff0c;一旦重启所有对容器内部文件数据的修改以及保存的数据会被初始化&#xff0c;所以为了防止数据丢失&am…

Java语言程序设计基础篇_编程练习题16.22(播放、循环播放和停止播放一个音频剪辑)

题目&#xff1a;16.22&#xff08;播放、循环播放和停止播放一个音频剪辑&#xff09; 编写一个满足下面要求的程序&#xff1a; 使用AudioClip获取一个音频文件&#xff0c;该文件存放在类目录下。放置三个标记为Play、Loop和Stop的按钮&#xff0c;如图16-46a所示。单击Pla…

什么是调度中心控制台,它在现代运营管理中扮演什么角色?

在现代复杂多变的运营环境中&#xff0c;调度中心控制台作为企业内部信息管理的核心枢纽&#xff0c;扮演着至关重要的角色。它不仅是一个技术平台&#xff0c;更是企业高效运营和智能决策的重要支撑。接下来就给大家科普一下关于调度中心控制台知识点&#xff0c;及在现代运营…

HarmonyOS笔记4:从云数据库获取数据

移动应用获取数据的方式主要有&#xff1a; 1.从网络中获取数据接口API。 2.从华为云数据库获取云数据库的资源。 3.从移动终端直接获取本地的数据 在HarmonyOS笔记3中已经完成了方式一从网络中获取数据接口API的方式。在本篇笔记中&#xff0c;将讨论从云数据库中获取数据。 因…

极狐GitLab CI/CD 如何构建镜像并推送到 azure 镜像仓库?

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门面向中国程序员和企业提供企业级一体化 DevOps 平台&#xff0c;用来帮助用户实现需求管理、源代码托管、CI/CD、安全合规&#xff0c;而且所有的操作都是在一个平台上进行&#xff0c;省事省心省钱。可以一键安装极狐GitL…

远程访问安全:rsync、ProFTPD、OpenSSH和VNC漏洞分析

文章目录 rsync未授权访问概念复现个别工具检测批量工具检测 proftpd远程命令介绍CVE-2015-3306复现 openssh信息泄露介绍复现 libssh身份绕过介绍条件危害复现 向日葵远程RCE介绍条件靶场&#xff1a; VNC配置不当介绍复现 在当今高度互联的数字时代&#xff0c;远程访问工具已…

[Qt][Qt 事件][上]详细讲解

目录 1.事件介绍2.事件的处理3.鼠标事件4.按键事件5.moveEvent6.resizeEvent 1.事件介绍 事件是应⽤程序内部或者外部产⽣的事情或者动作的统称 在Qt中使⽤⼀个对象来表⽰⼀个事件&#xff0c;所有的Qt事件均继承于抽象类QEvent 事件是由系统或者Qt平台本⾝在不同的时刻发出的…

深入理解C#中的yield关键字:提升迭代性能与效率

文章目录 前言一、yield return二、yield break总结 前言 在C#中&#xff0c;yield 关键字是特别用于迭代器块和方法中的&#xff0c;它允许你逐个返回序列中的元素&#xff0c;而不是一次性返回整个集合。使用 yield 可以显著提高处理大数据集或进行复杂迭代时的性能和内存效率…

【数据结构初阶】队列经典习题两道

hello&#xff01; 我是云边有个稻草人 目录 一、用队列实现栈 二、用栈实现队列 Relaxing Time &#xff01; 正文开始—— 一、用队列实现栈 225. 用队列实现栈 - 力扣&#xff08;LeetCode&#xff09; 根据题目要求&#xff0c;我们要用两个队列来实现栈的相关功能&…

虚拟机上使用Ubuntu1804上编译qt5.12.9部署到jetson nano上

开发qt界面&#xff0c;基于Qt5.12.9&#xff0c;开发环境使用虚拟机加载Ubuntu1804&#xff0c;开发完成后的qt程序最后部署到jetson nano上&#xff0c;使用的通用编译器是gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu 安装编译器 本文中直接将gcc-linaro-7.5.0-2019.…

汇昌联信做拼多多店铺如何运营?

汇昌联信如何在拼多多上运营店铺&#xff0c;是许多电商新手和希望扩展市场的商家所关注的问题。在这个快速发展的电商平台上&#xff0c;掌握正确的运营策略&#xff0c;对于提升店铺销量、增强品牌影响力至关重要。接下来&#xff0c;我们将详细探讨如何有效运营拼多多店铺。…