iproute 作为网络接口的设置工具
具备我们大部分需要的功能。

以设置ipv6 地址为例来分析一下它的源码

它的实质其实是与内核建立一个socket通信,通过建立的fd进行网络接口的设置和信息读取。

简单来说,就四步:
建立与内核的连接-> 发送数据到内核 -> 从内核读取数据 -> 关闭连接

  1. 建立与内核的连接
int rtnl_open(struct rtnl_handle *rth, unsigned int subscriptions)
{return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
}
其中rth结构体如下
struct rtnl_handle {int            fd;    // fd是socket 打开的值struct sockaddr_nl    local;  // local 是本地地址struct sockaddr_nl    peer;  // peer 是邻居地址__u32            seq;     // seq 是32位序列号__u32            dump;  // dump 是32位int            proto;  // proto 是协议号FILE               *dump_fp;  // dump_fp 是文件名int            flags; // flags 是 标志字段
};seq:
TCP会话的每一端都包含一个32位(bit)的序列号,该序列号被用来跟踪该端发送的数据量。每一个包中都包含序列号,在接收端则通过确认号用来通知发送端数据成功接收proto:
具体定义:
#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   /* Unused number, formerly ip_queue     */
#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 */
#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 */
#define NETLINK_SMC     22  /* SMC monitoring */#define NETLINK_INET_DIAG   NETLINK_SOCK_DIAG指定要和内核中的哪个子系统进行交互,目前支持:
NETLINK_ROUTE 与路由信息相关,包括查询、设置和删除路由表中的条目等。待会儿我们将以这类family举个实际的例子;
NETLINK_FIREWALL 接收由IPv4防火墙代码发送的包;
NETLINK_ARPD 可以在用户空间进行arp缓存的管理;
NETLINK_ROUTE6 在用户空间发送和接收路由表信息更新;
还有几种虽然没有实现,但已经有了定义,为以后扩展做好了准备。dump 和dump_fd作用还待研究
  1. 发送数据到内核
先总结再细说
struct {struct nlmsghdr n;struct ifaddrmsg  ifa;char            buf[256];
} req
req的基地址(req第一个数据存放的就是struct nlmsghdr    n;传n的地址相当于传req的基地址)传给 iov的iov_base
struct iovec iov = {.iov_base = n,.iov_len = n->nlmsg_len
};
再把iov这个结构体地址传给msg_iov = &iov。
struct msghdr msg = {.msg_name = &nladdr,.msg_namelen = sizeof(nladdr),.msg_iov = &iov,.msg_iovlen = 1,
};
再发送数据给到内核具体分析如下:
static int ipaddr_modify(int cmd, int flags, int argc, char **argv)struct {struct nlmsghdr  n;struct ifaddrmsg  ifa;char            buf[256];} req = {.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),.n.nlmsg_flags = NLM_F_REQUEST | flags,.n.nlmsg_type = cmd,.ifa.ifa_family = preferred_family,};在ipaddr_modify初始化req结构体
struct nlmsghdr
{__u32 nlmsg_len;   /* Length of message */
__u16 nlmsg_type; /* Message type*/
__u16 nlmsg_flags; /* Additional flags */
__u32 nlmsg_seq;   /* Sequence number */
__u32 nlmsg_pid;   /* Sending process PID */
};
字段 nlmsg_len 指定消息的总长度,包括紧跟该结构的数据部分长度以及该结构的大小
#define NLMSG_ALIGNTO   4U
#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
这样返回值在len大于零时,都是以4的倍数对齐(1-4=4;5-8=8;如此类推)struct ifaddrmsg {unsigned char ifa_family;    /* Address type */unsigned char ifa_prefixlen; /* Prefixlength of address */unsigned char ifa_flags;     /* Address flags */unsigned char ifa_scope;     /* Address scope */int           ifa_index;     /* Interface index */};ifa_family: 地址类型(通常为AF_INET or AF_INET6))
ifa_prefixlen: 地址的地址掩码长度,如果改地址定义在这个family
ifa_flags:
ifa_scope: 地址的作用域
ifa_index:  接口索引与接口地址关联
ifa_prefixlen: 就是掩码64,128...
ifa_index: 利用if_nametoindex(name);函数把设备名转换为接口index,这个
值对应的网络设备是固定不变的。.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
初始化是nlmsghdr和ifaddrmsg两个结构体长度24。具体的数据内容是通过addattr_l来添加的
int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,int alen)
{int len = RTA_LENGTH(alen);struct rtattr *rta;if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {fprintf(stderr,"addattr_l ERROR: message exceeded bound of %d\n",maxlen);return -1;}//printf("%s[%d] NLMSG_ALIGN(n->nlmsg_len)[%d]\n",__func__,__LINE__,NLMSG_ALIGN(n->nlmsg_len));rta = NLMSG_TAIL(n);rta->rta_type = type;rta->rta_len = len;if (alen)memcpy(RTA_DATA(rta), data, alen);n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);return 0;
}跳过nlmsg_len,把数据考到req.buf中。
#define NLMSG_TAIL(nmsg) \((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
memcpy(RTA_DATA(rta), data, alen);再更新数据长度
n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
这样下次还有其他数据要加入时,就会在上一个数据末尾加入。
所以想看看自己发的内容对不对,可以查看buf里面的内容。而这个buf分为rta和data;
struct rtattr {unsigned short   rta_len;unsigned short  rta_type;
};
前面存的时rta结构体,接着存的是实际数据
像设置ipv6地址的话就是存一个inet_prefix *addr结构体
inet_pton(AF_INET6, name, addr->data)
将点分文本的IP地址转换为“二进制网络字节序”的IP地址最后利用rtnl_talk -> __rtnl_talk 把数据发送到内核
static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,struct nlmsghdr *answer, size_t maxlen,bool show_rtnl_err, nl_ext_ack_fn_t errfn)
{int status;unsigned int seq;struct nlmsghdr *h;struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };struct iovec iov = {.iov_base = n,.iov_len = n->nlmsg_len};struct msghdr msg = {.msg_name = &nladdr,.msg_namelen = sizeof(nladdr),.msg_iov = &iov,.msg_iovlen = 1,};
...n->nlmsg_seq = seq = ++rtnl->seq;status = sendmsg(rtnl->fd, &msg, 0);if (status < 0) {perror("Cannot talk to rtnetlink");return -1;}发送struct msghdr msg这个结构体到内核中去
struct iovec {                    /* Scatter/gather arrayitems */void *iov_base;              /*Starting address */size_t iov_len;               /* Number of bytes to transfer*/};/* iov_base: iov_base指向数据包缓冲区,即参数buff,iov_len是buff的长度。msghdr中允许一次传递多个buff,以数组的形式组织在 msg_iov中,msg_iovlen就记录数组的长度(即有多少个buff)*/struct msghdr {void         *msg_name;       /* optional address */socklen_t     msg_namelen;    /* size of address */struct iovec *msg_iov;        /* scatter/gather array */size_t        msg_iovlen;     /* # elements in msg_iov */void         *msg_control;    /* ancillary data, see below */size_t        msg_controllen; /* ancillary databuffer len */int           msg_flags;      /* flags on received message */};/* msg_name:数据的目的地址,网络包指向sockaddr_in, netlink则指向sockaddr_nl;msg_namelen: msg_name 所代表的地址长度msg_iov: 指向的是缓冲区数组msg_iovlen: 缓冲区数组长度msg_control: 辅助数据,控制信息(发送任何的控制信息)msg_controllen: 辅助信息长度msg_flags: 消息标识*/
  1. 从内核读取数据
    收数据的话,利用
         iov.iov_base = buf;iov.iov_len = sizeof(buf);status = recvmsg(rtnl->fd, &msg, 0);
for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); )
具体的解析内容就没有分析,可以根据发送来反推。
  1. 关闭连接
    最后利用rth_close来关闭连接的通道。

iproute2 ipv6地址设置源码分析相关推荐

  1. docker ip地址_理解 Docker 网络(番外) -- 《Docker 源码分析》勘误

    前言 本来打算这篇文章是分析 Docker Overlay 网络是如何建立以及如何手动实现 Docker 的跨主机通信的.但是在完成了上一篇文章之后,打算找一些文章或者书籍印证我的文章是否正确.这时看 ...

  2. 【Android 性能优化】应用启动优化 ( 阶段总结 | Trace 文件分析及解决方案 | 源码分析梳理 | 设置主题的方案总结 ) ★

    文章目录 一. 常用的耗时方法优化方案 ( 重要 ) 二. 源码分析梳理 1. 应用启动时间计算相关源码分析 2. Launcher 应用中启动 Android 应用流程 三. 启动白屏解决方案 An ...

  3. JavaFX源码分析实战:如何设置窗体标题小图标和任务栏图标

    JavaFX实战系列 JavaFX源码分析和实战:javaFX线程结构分析 JavaFX源码分析和实战之launcher启动器:两种启动javaFX的方式及launch(args[])参数设置和获取 ...

  4. flink设置watermark以及事件时间字段源码分析

    flink设置watermark以及事件时间字段源码分析 背景 1.1.提取时间戳字段,用于事件时间语义处理数据 1.2.设置水位线(水印)watermark TimestampAssigner 核心 ...

  5. 蓝牙(Bluetooth)---源码目录及设置应用源码分析

    一 Bluetooth 的设置应用 packages\apps\Settings\src\com\android\settings\bluetooth\* 蓝牙设置应用及设置参数,蓝牙状态,蓝牙设备等 ...

  6. Netty4.x: Server端 设置 option 警告 Unknown channel option ‘xxxx‘ for channel 分析及解决 (附源码分析)

    一.问题背景: 最近某springboot项目想嵌入一个用户聊天功能,打算使用 Rabbitmq + Netty4.x + Redis 来开发高性能聊天功能.花费三天时间所有功能都已实现.启动时却警告 ...

  7. Django源码分析2:本地运行runserver分析

    django源码分析 本文环境python3.5.2,django1.10.x系列1.根据上一篇文章分析了,django-admin startproject与startapp的分析流程后,根据dja ...

  8. linux nDPI 协议检测 源码分析

    关于nDPI的基本功能就不在这介绍了,有兴趣了解的读者可以阅读官方的快速入门指南:https://github.com/ntop/nDPI/blob/dev/doc/nDPI_QuickStartGu ...

  9. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

最新文章

  1. Python 捕获警告
  2. 前端笔记——获取url里面的参数值
  3. DataBase project physical design
  4. Qt 原理-MOC(1)Meta Object Compiler
  5. 博士申请 | 美国罗格斯大学王灏助理教授招收机器学习方向博士生
  6. weblogic中ssrf漏洞修复_Weblogic-SSRF漏洞复现
  7. C++ Low level performance optimize 2
  8. 为什么大家越来越重视大数据的发展?
  9. python jieba库的使用
  10. 基于matlab的图像拼接论文,基于MATLAB的图像拼接算法实现研究
  11. APP推广要做哪些?渠道?方案?竞争分析?
  12. ad怎么修改栅格_AD 10怎么设置栅格?
  13. echarts-JSON请求数据
  14. CSU2020期中测试模拟题1 问题E:小帅的字符串
  15. eclipse theia_如何在Ubuntu 18.04上设置Eclipse Theia Cloud IDE平台[快速入门]
  16. springboot+vue+Elementui学生考勤在线请假系统
  17. doom emacs如何安装新插件和自定义快捷键
  18. vscode 修改快捷键 (回到上一处光标位置,下一处光标位置)
  19. IDEA设置Working directory及作用
  20. pd.columns和pd.columns.tolist

热门文章

  1. Android studio小米真机USB调试有图
  2. 大五人格OCEAN模型理论
  3. 【ProtoBuf】1.初识ProtoBuf
  4. NetSarang软件中nssock2.dll模块被植入恶意代码技术分析与防护方案
  5. 下沙的沙子有几粒?(hdu1267)递推
  6. OGRE ANIMATION
  7. 图的应用 | 拓扑排序
  8. CSS修改html单选框radio样式
  9. 威胁建模_现实世界中的威胁建模
  10. 数字逻辑中的德·摩根定理证明