一. 概述
在routing进程所使用的配置文件中,存在如下配置项目:
{"unicast" : "192.168.56.101",..."service-discovery" :{"enable" : "true","multicast" : "224.244.224.245",...}
}
其中有 “unicast” : "192.168.56.101"和 “multicast” : “224.244.224.245” 两个通信地址,这两个地址一个是用于vsomeip用于对外通信的单播地址,另一个配置的是service-discovery功能依赖的组播的地址。
作为routingmanager的进程需要监听这个单播地址和组播地址所在的网卡的状态,这部分功能主要在netlink_connector中实现,routing_manager_imp依赖netlink_connector来监听网卡状态,并且在网卡状态ready的情况下才会启动routing。
netlink_connector中使用到了linux平台的netlink协议用于监听内核上网卡相关事件。
二. netlink protocol
netlink是linux平台上第一种IPC机制,主要用于用户态进程与内核进程通信,此外还可以用于用户态进程之间通信(这个使用unix domain socket)也可以做到。
netlink和传统的和内核通信的机制(ioctl,sysfs属性)等不同,netlink是支持全双工的通信的,也就是可以异步通信的,而其他几种传统的内核通信的机制只支持半双工同步通信的方式。在这种情况下,内核甚至支持主动发起通信,而不是由应用发起通信。
此外,netlink支持组播的方式,以组播的方式将消息发给多个进程(根据groupid)。
netlink的通信方式使用的是socket API,创建NETLINK socket的时候,需要指定NETLINK socket的协议类型类型()
sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); // NETLINK_ROUTE是协议类型
目前的linxu系统中支持32中协议类型,个人认为这个协议类型就是事件组(网卡/路由/安全/审计/SCSI设备…等等)。
#define NETLINK_ROUTE 0 /* 用于设置和查询路由表等网络核心模块*/
#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 */
...
...
NETLINK socket需要做bind操作绑定NETLINK的地址,NETLINK地址结构如下:
struct sockaddr_nl {__kernel_sa_family_t nl_family; /* 协议族 AF_NETLINK */unsigned short nl_pad; /* 固定填写0 zero */__u32 nl_pid; /* 端口ID,内核填0,应用进程填PID port ID */__u32 nl_groups; /* 广播组 multicast groups mask */
};
除了nl_pad固定为0以外,其他参数需要填写
struct sockaddr_nl addr;
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK; // 协议族
// RTMGRP_LINK: 网卡UP/DOWN
// RTMGRP_IPV4_IFADDR: ip地址变化
addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR; // 广播组(事件组中的具体事件)
设置好NETLINK地址后,将其绑定到socket上面
bind(sock, (struct sockaddr *)&addr, sizeof(addr);
接着,就可以使用该socket和内核进行netlink通信了,通过标准recv接口从内核接收消息
while (running && (len = recv(sock, buffer, 4096, 0)) > 0) {nlh = (struct nlmsghdr *)buffer;while (NLMSG_OK(nlh, len) && (nlh->nlmsg_type != NLMSG_DONE)) {// 解析不同类型的NetLink消息...// 下一条消息nlh = NLMSG_NEXT(nlh, len);}
}
close(sock);
三. netlink_connector的作用