netlink怎么读_ovs源码阅读--netlink使用
netlink
netlink socket是一種用于用戶態(tài)進程和內(nèi)核態(tài)進程之間的通信機制。它通過為內(nèi)核模塊提供一組特殊的API,并為用戶程序提供了一組標準的socket接口的方式,實現(xiàn)了全雙工的通訊連接。
特點:
雙向傳輸,異步通信
用戶空間中使用標準socket API
內(nèi)核空間中使用專門的API
支持多播
可由內(nèi)核端發(fā)起通信
支持32種協(xié)議類型
netlink僅支持32種協(xié)議類型,這在實際應用中可能并不足夠,因此產(chǎn)生了generic netlink(以下簡稱為genl),
generic netlink支持1023個子協(xié)議號,彌補了netlink協(xié)議類型較少的缺陷。
通信架構(gòu)
Netlink子系統(tǒng):所有g(shù)enl通信的基礎,Netlink子系統(tǒng)中收到的所有Generic類型的netlink數(shù)據(jù)都被送到genl總線上;從內(nèi)核發(fā)出的數(shù)據(jù)也經(jīng)由genl總線送至netlink子系統(tǒng),再打包送至用戶空間
Generic Netlink控制器:作為內(nèi)核的一部分,負責動態(tài)地分配genl通道(即genl family id),并管理genl任務,genl控制器是一個特殊的genl內(nèi)核用戶,它負責監(jiān)聽genl bus上的通信通道
genl通信建立在一系列的通信通道的基礎上,每個genl family對應多個通道,這些通道由genl控制器動態(tài)分配
相關(guān)結(jié)構(gòu)體
genl family
Generic Netlink是基于客戶端-服務端模型的通信機制,服務端注冊family(family是對genl服務的各項定義的集合),控制器和客戶端都通過已注冊的信息與服務端通信。
//genl_family主要字段
struct genl_family
{
unsigned intid;//family id
unsigned int hdrsize; //用戶自定議頭部長度
char name[GENL_NAMSIZ]; //family名,要求不同的family使用不同的名字
unsigned int version;//版本
unsigned int maxattr;//最大attr類型數(shù),使用netlink標準的attr來傳輸數(shù)據(jù)
genl_ops *ops;// 操作集合
};
genl_ops
定義了netlink family相關(guān)的操作
// genl_ops主要字段
struct genl_ops
{
u8 cmd;//命令名,用于識別genl_ops
unsigned int flags;//設置屬性
struct nla_policy *policy; //定義了attr規(guī)則,genl在觸發(fā)事件處理程序之前,會用其進行attr校驗
int (*doit)(struct sk_buff *skb, struct genl_info *info);
int (*dumpit)(struct sk_buff *skb, struct netlink_callback *cb);
};
doit:回調(diào)函數(shù),在generic netlink收到數(shù)據(jù)時觸發(fā),運行在進程上下文
dumpit:回調(diào)函數(shù),當genl_ops的flag標志被添加了NLM_F_DUMP以后,每次收到genl消息即會回觸發(fā)這個函數(shù)
dumpit與doit的區(qū)別是:dumpit的第一個參數(shù)skb不會攜帶從客戶端發(fā)來的數(shù)據(jù)。相反地,開發(fā)者應該在skb中填入需要傳給客戶端的數(shù)據(jù),skb中攜帶的數(shù)據(jù)會被自動送到客戶端。只要dumpit的返回值大于0,dumpit函數(shù)就會再次被調(diào)用,并被要求在skb中填入數(shù)據(jù)。當服務端沒有數(shù)據(jù)要傳給客戶端時,dumpit要返回0。如果函數(shù)中出錯,要求返回一個負值。
nal_policy
定義了attr規(guī)則
struct nla_policy
{
u16 type;//attr中的數(shù)據(jù)類型
u16 len;//如果在type字段配置的是字符串有關(guān)的值,要把len設置為字符串的最大長度
};
genl_info
內(nèi)核在接收到用戶的genetlink消息后,會對消息解析并封裝成genl_info結(jié)構(gòu)
struct genl_info
{
u32 snd_seq; //發(fā)送序號
u32 snd_pid; //發(fā)送客戶端的PID
struct nlmsghdr * nlhdr; //netlink header的指針
struct genlmsghdr * genlhdr; //genl頭部的指針(即family頭部)
void * userhdr; //用戶自定義頭部指針
struct nlattr ** attrs; //如果定義了genl_ops->policy,保存被policy過濾以后的結(jié)果
};
Generic Netlink服務端(內(nèi)核)初始化
這里以OVS中packet的處理為例:
1. 定義family
//定義packet family
static struct genl_family dp_packet_genl_family __ro_after_init = {
.hdrsize = sizeof(struct ovs_header),
.name = OVS_PACKET_FAMILY,
.version = OVS_PACKET_VERSION,
.maxattr = OVS_PACKET_ATTR_MAX,
.netnsok = true,
.parallel_ops = true,
.ops = dp_packet_genl_ops, //操作集合
.n_ops = ARRAY_SIZE(dp_packet_genl_ops),
.module = THIS_MODULE,
};
2. 定義operation
// 定義packet family 的操作 --- packet類型的操作只支持OVS_PACKET_CMD_EXECUTE
static struct genl_ops dp_packet_genl_ops[] = {
{ .cmd = OVS_PACKET_CMD_EXECUTE,
.flags = GENL_UNS_ADMIN_PERM,
.policy = packet_policy,
.doit = ovs_packet_cmd_execute //接受數(shù)據(jù)包時,調(diào)用ovs_packet_cmd_execute進行處理
}
};
// 定義packet family 的過濾規(guī)則
static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = {
[OVS_PACKET_ATTR_PACKET] = { .len = ETH_HLEN },
[OVS_PACKET_ATTR_KEY] = { .type = NLA_NESTED },
[OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED },
[OVS_PACKET_ATTR_PROBE] = { .type = NLA_FLAG },
[OVS_PACKET_ATTR_MRU] = { .type = NLA_U16 },
};
3. 注冊family
genl_register_family(&dp_packet_genl_family);
Generic Netlink客戶端(用戶空間)初始化
struct sockaddr_nl saddr;
int sock;
sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); //創(chuàng)建一個netlink類型的socket
if (sock < 0) {
return -1;
}
memset(&saddr, 0, sizeof(saddr));
saddr.nl_family = AF_NETLINK;
saddr.nl_pid = getpid();//獲取family id
if (bind(sock, (struct sockaddr*)&saddr, sizeof(saddr)) < 0) {//綁定
printf("bind fail!\n");
close(*p_sock);
return -1;
}
內(nèi)核空間接受發(fā)送數(shù)據(jù)
接受數(shù)據(jù):內(nèi)核端一旦收到generic netlink數(shù)據(jù),會觸發(fā)doit函數(shù)運行,通過回調(diào)函數(shù)進行處理
發(fā)送數(shù)據(jù):將數(shù)據(jù)打包好之后,可通過單播(genlmsg_unicast)或多播()的形式進行發(fā)送
用戶空間接受發(fā)送數(shù)據(jù)
接受數(shù)據(jù):調(diào)用recv函數(shù)即可完成從內(nèi)核來的數(shù)據(jù)的接收
發(fā)送數(shù)據(jù):調(diào)用sendto來發(fā)送數(shù)據(jù)
netlink收發(fā)數(shù)據(jù)—以ovs中packet為例
參考內(nèi)容
與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的netlink怎么读_ovs源码阅读--netlink使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux系统sql语句报错_如果数据库
- 下一篇: mllib调参 spark_从Spark