没有合适的资源?快使用搜索试试~ 我知道了~
Linux内核中netlink协议族的实现
需积分: 16 18 下载量 187 浏览量
2010-08-27
21:14:20
上传
评论 1
收藏 678KB PDF 举报
温馨提示
试读
26页
介绍linux内核中netlink协议族的实现,主要是用户态与内核的通信。
资源推荐
资源详情
资源评论
内部公开 Internal Use Only▲
<以上所有信息均为中兴通讯股份有限公司所有,不得外传>
All Rights reserved, No Spreading abroad without Permission of ZTE
第 1 页
Linux 内核中 netlink 协议族的实现
1. 前言
netlink 协议族是 Linux 内核网络部分的一个固定部分, 一旦在内核配置中选了网络支持就自
动带了而不能单独去掉。
netlink 的实现源码在 net/netlink 目录下,主要是 net/netlink/af_netlink.c 文件。
以下内核代码版本为 2.6.19.2, 如无特别说明代码取自 net/netlink/af_netlink.c。
2. 数据结构
netlink 套接口结构:
/* net/netlink/af_netlink.c */
struct netlink_sock {
/* struct sock has to be the first member of netlink_sock */
struct sock sk;
u32 pid; // 自己的 pid, 通常是 0
u32 dst_pid; // 对方的 pid
u32 dst_group; // 对方的组
u32 flags;
u32 subscriptions;
u32 ngroups; // 多播组数量
unsigned long *groups; // 多播组号
unsigned long state;
wait_queue_head_t wait; // 等待队列,用于处理接收发送包时的 top half
struct netlink_callback *cb; // 回调结构,包含回调函数
spinlock_t cb_lock;
void (*data_ready)(struct sock *sk, int bytes); // 数据到达时
//的操作, netlink 可有不同类型, 如 ROUTE,
FIREWALL, ARPD 等,
//每种类型都自己定义的 data_ready 处理
struct module *module;
};
这个结构先是包含一个标准的 struct sock 结构,后面又跟和 netlink 相关的特有相关数据,内核
中其他协议的 sock 也是类似定义的, 注意 sock 结构必须放在第一位,这是为了可以直接将
sock 的指针转为 netlink_sock 的指针。
netlink sock 的表
:
struct netlink_table {
struct nl_pid_hash hash; // 根据 pid 进行 HASH 的 netlink sock 链表, 相当于客户端链表
struct hlist_head mc_list; // 多播的 sock 链表
unsigned long *listeners; // 监听者标志
内部公开 Internal Use Only▲
<以上所有信息均为中兴通讯股份有限公司所有,不得外传>
All Rights reserved, No Spreading abroad without Permission of ZTE
第 2 页
unsigned int nl_nonroot;
unsigned int groups; // 每个 netlink 的协议类型可以定义多个组, 8 的倍数,最小是 32
struct module *module;
int registered;
};
最大可有 MAX_LINKS(32)个表,处理不同协议类型的 netlink 套接口, 注意由于是自身的通
信, 本机同时作为服务器和客户端, 服务端需要一个套接口对应, 每个客户端也要有一个套
接口对应, 多个客户端的套接口形成一个链表.
struct nl_pid_hash {
struct hlist_head *table; // 链表节点
unsigned long rehash_time; // 重新计算 HASH 的时间间隔
unsigned int mask;
unsigned int shift;
unsigned int entries; // 链表节点数
unsigned int max_shift; // 最大幂值
u32 rnd; // 随机数
};
其他和 netlink 数据相关的数据结构在 include/linux/netlink.h 中定义, 不过这些结构更多用在
各具体的 netlink 对象的实现中, 在基本 netlink 套接口中到是用得不多。
3. af_netlink 协议初始化
static int __init netlink_proto_init(void)
{
struct sk_buff *dummy_skb;
int i;
unsigned long max;
unsigned int order;
// 登记 netlink_proto 结构, 该结构定义如下:
// static struct proto netlink_proto = {
// .name = "NETLINK",
// .owner = THIS_MODULE,
// .obj_size = sizeof(struct netlink_sock),
// };
// 最后一个参数为 0, 表示不进行 slab 的分配, 只是简单的将 netlink_proto 结构
// 挂接到系统的网络协议链表中,这个结构最主要是告知了 netlink sock 结构的大小
int err = proto_register(&netlink_proto, 0);
if (err != 0)
goto out;
BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > sizeof(dummy_skb->cb));
// 分配 MAX_LINKS 个 netlink 表结构
nl_table = kcalloc(MAX_LINKS, sizeof(*nl_table), GFP_KERNEL);
if (!nl_table)
goto panic;
内部公开 Internal Use Only▲
<以上所有信息均为中兴通讯股份有限公司所有,不得外传>
All Rights reserved, No Spreading abroad without Permission of ZTE
第 3 页
// 以下根据系统内存大小计算最大链表元素个数
// PAGE_SHIFT 是每页大小的 2 的幂,对 i386 是 12,即每页是 4K,2^12
// 对于 128M 内存的机器,max 计算值是(128*1024) >> (21-12) = 256
// 对于 64M 内存的机器,max 计算值是(64*1024) >> (23-12) = 32
if (num_physpages >= (128 * 1024))
max = num_physpages >> (21 - PAGE_SHIFT);
else
max = num_physpages >> (23 - PAGE_SHIFT);
// 根据 max 再和 PAGE_SHIFT 计算总内存空间相应的幂值 order
order = get_bitmask_order(max) - 1 + PAGE_SHIFT;
// max 是最大节点数
max = (1UL << order) / sizeof(struct hlist_head);
// order 是 max 对于 2 的幂数
order = get_bitmask_order(max > UINT_MAX ? UINT_MAX : max) - 1;
for (i = 0; i < MAX_LINKS; i++) {
struct nl_pid_hash *hash = &nl_table[i].hash;
// 为 netlink 的每个协议类型分配 HASH 表链表头
hash->table = nl_pid_hash_alloc(1 * sizeof(*hash->table));
if (!hash->table) {
while (i-- > 0)
nl_pid_hash_free(nl_table[i].hash.table,
1 * sizeof(*hash->table));
kfree(nl_table);
goto panic;
}
// 初始化 HASH 表参数
memset(hash->table, 0, 1 * sizeof(*hash->table));
// 最大幂数
hash->max_shift = order;
hash->shift = 0;
hash->mask = 0;
hash->rehash_time = jiffies;
}
// 登记 netlink 协议族的的操作结构
sock_register(&netlink_family_ops);
#ifdef CONFIG_PROC_FS
proc_net_fops_create("netlink", 0, &netlink_seq_fops);
#endif
/* The netlink device handler may be needed early. */
// 初始化路由 netlink
rtnetlink_init();
out:
return err;
panic:
内部公开 Internal Use Only▲
<以上所有信息均为中兴通讯股份有限公司所有,不得外传>
All Rights reserved, No Spreading abroad without Permission of ZTE
第 4 页
panic("netlink_init: Cannot allocate nl_table\n");
}
core_initcall(netlink_proto_init);
4. 建立 netlink 套接口
4.1 建立对应客户端的套接口
// netlink 协议族操作, 在用户程序使用 socket 打开 netlink 类型的 socket 时调用,
// 相应的 create 函数在__sock_create(net/socket.c)函数中调用:
static struct net_proto_family netlink_family_ops = {
.family = PF_NETLINK,
.create = netlink_create,
.owner = THIS_MODULE, /* for consistency 8) */
};
// 在用户空间每次打开 netlink socket 时都会调用此函数:
static int netlink_create(struct socket *sock, int protocol)
{
struct module *module = NULL;
struct netlink_sock *nlk;
unsigned int groups;
int err = 0;
// sock 状态初始化
sock->state = SS_UNCONNECTED;
// 对 netlink sock 的类型和协议(实际是 netlink_family 类型)限制检查
if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM)
return -ESOCKTNOSUPPORT;
if (protocol<0 || protocol >= MAX_LINKS)
return -EPROTONOSUPPORT;
netlink_lock_table();
#ifdef CONFIG_KMOD
// 如果相应的 netlink 协议是模块又没有加载的话先加载该模块
if (!nl_table[protocol].registered) {
netlink_unlock_table();
request_module("net-pf-%d-proto-%d", PF_NETLINK, protocol);
netlink_lock_table();
}
#endif
if (nl_table[protocol].registered &&
try_module_get(nl_table[protocol].module))
module = nl_table[protocol].module;
// groups 这个值在函数后面也没见用上, 这句没意义
groups = nl_table[protocol].groups;
netlink_unlock_table();
内部公开 Internal Use Only▲
<以上所有信息均为中兴通讯股份有限公司所有,不得外传>
All Rights reserved, No Spreading abroad without Permission of ZTE
第 5 页
// 真正的建立 netlink sock 的函数
if ((err = __netlink_create(sock, protocol)) < 0)
goto out_module;
nlk = nlk_sk(sock->sk);
nlk->module = module;
out:
return err;
out_module:
module_put(module);
goto out;
}
// 基本函数
static int __netlink_create(struct socket *sock, int protocol)
{
struct sock *sk;
struct netlink_sock *nlk;
// netlink sock 的基本操作
sock->ops = &netlink_ops;
// 分配 sock 结构, 通过 netlink_proto 中的 obj_size 指出了 netlink sock 的大小
sk = sk_alloc(PF_NETLINK, GFP_KERNEL, &netlink_proto, 1);
if (!sk)
return -ENOMEM;
// 初始化 sock 基本数据, 将 sock 和 socket 关联起来
sock_init_data(sock, sk);
// 将普通 sock 转为 netlink sock,实际只是重新定义的一下指针类型,指针本身值不变
nlk = nlk_sk(sk);
// 初始化 sock 的锁
spin_lock_init(&nlk->cb_lock);
// 初始化等待队列
init_waitqueue_head(&nlk->wait);
// sock 的析构函数,释放接收队列中的 skb 数据包
sk->sk_destruct = netlink_sock_destruct;
sk->sk_protocol = protocol;
// 注意这里没有重新定义 sk 的 sk_data_ready 函数
// 在 sock_init_data()函数中将 sk_data_ready 定义为 sock_def_readable()函数
return 0;
}
用户空间使用 socket(2)系统调用打开 netlink 类型的套接口时, 在内核中会调用 sys_sock()函
数 , 然后是调用__sock_create()函数, 在其中调用 netlink 协议族的 create()函数, 即
netlink_create()函数.
4.2 建立服务器端的套接口
剩余25页未读,继续阅读
资源评论
cly4968812
- 粉丝: 1
- 资源: 20
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- YOLOV4-TINY权重文件
- 以下是一个使用贪心算法解决多机调度问题的基本步骤0.txt
- 基于大数据的房产估价是近年来随着技术的发展而兴起的一种新型估价方法.txt
- 企业供应链管理系统v3.rar
- 富芮坤FR8016HA蓝牙开发板使用手册+硬件PCB图+封装库+DEMO演示软件源代码.zip
- 基于YOLOv7的芯片表面缺陷检测系统
- 京东物流 数字化供应链综合研究报告2018.rar
- 基于YOLOv7的植物虫害识别&防治系统
- 2000.1-2023.8中国经济政策不确定性指数月度数据.xlsx
- Screenshot_2024-04-21-20-42-15-443_com.tencent.mm.jpg
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功