当前位置: 首页 > news >正文

libnl教程(2):发送请求

文章目录

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

前言

前置阅读要求: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 0ret = nla_put_string(msg, IFLA_INFO_KIND, iftype);if (ret < 0) {goto end;}
#endifstruct 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"); }

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • sp-eric靶机
  • 【区块链+金融服务】农业大宗供应链线上融资平台 | FISCO BCOS应用案例
  • PDF转换器推荐:轻松将图片批量转为PDF
  • 系列:水果甜度个人手持设备检测-- 行业现状小结
  • Spring @Transactional事务传播行为详解
  • Datawhale AI 夏令营第四期 大模型技术-微调 task3 数据增强与评分
  • 汽车4S店管理系统-计算机毕设Java|springboot实战项目
  • 【Linux基础】对Linux权限的理解与管理
  • 解决方案上新了丨趋动科技推出基于银河麒麟操作系统的异构算力池化解决方案
  • 统一响应结果封装,Result类的实现【后端 06】
  • 鸿蒙开发APP应用UX体验标准
  • 【应用】 Flask 和 WebSockets 开发实时聊天应用程序
  • 【论文笔记】:YOLOv8-QSD 自动驾驶场景小目标检测算法
  • skywalking架构
  • Qt QPushButton::clicked和QPushButton::click的区别
  • 【剑指offer】让抽象问题具体化
  • 3.7、@ResponseBody 和 @RestController
  • Angularjs之国际化
  • Cookie 在前端中的实践
  • php ci框架整合银盛支付
  • 试着探索高并发下的系统架构面貌
  • 小程序开发中的那些坑
  • 一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
  • 用jQuery怎么做到前后端分离
  • 《天龙八部3D》Unity技术方案揭秘
  • HanLP分词命名实体提取详解
  • "无招胜有招"nbsp;史上最全的互…
  • #HarmonyOS:Web组件的使用
  • #NOIP 2014#day.2 T1 无限网络发射器选址
  • (3)(3.5) 遥测无线电区域条例
  • (C语言)求出1,2,5三个数不同个数组合为100的组合个数
  • (Matlab)使用竞争神经网络实现数据聚类
  • (八)光盘的挂载与解挂、挂载CentOS镜像、rpm安装软件详细学习笔记
  • (二)测试工具
  • (附源码)ssm学生管理系统 毕业设计 141543
  • (含react-draggable库以及相关BUG如何解决)固定在左上方某盒子内(如按钮)添加可拖动功能,使用react hook语法实现
  • (免费分享)基于springboot,vue疗养中心管理系统
  • (十六)一篇文章学会Java的常用API
  • (转)shell中括号的特殊用法 linux if多条件判断
  • (转)菜鸟学数据库(三)——存储过程
  • (转载)OpenStack Hacker养成指南
  • *Algs4-1.5.25随机网格的倍率测试-(未读懂题)
  • .NET MVC第五章、模型绑定获取表单数据
  • .NET 的程序集加载上下文
  • .Net下的签名与混淆
  • .NET中GET与SET的用法
  • .Net中wcf服务生成及调用
  • @transaction 提交事务_【读源码】剖析TCCTransaction事务提交实现细节
  • [ABC294Ex] K-Coloring
  • [Android] Upload package to device fails #2720
  • [C/C++]关于C++11中的std::move和std::forward
  • [C++] 小游戏 斗破苍穹 2.11.6 版本 zty出品
  • [CareerCup] 17.8 Contiguous Sequence with Largest Sum 连续子序列之和最大
  • [EFI]Acer Aspire A515-54g电脑 Hackintosh 黑苹果efi引导文件
  • [flutter]一键将YAPI生成的api.json文件转为需要的Dart Model类的脚本