多平台统一管理软件接口,如何实现多平台统一管理软件接口
463
2022-10-12
Linux内核中VLAN的实现过程(3)-proc文件系统(Linux vlan)
Linux内核中VLAN的实现过程(3)
本节主要关注和解析vlan模块proc文件系统接口功能实现,代码位于net/8021q/vlanproc.c文件中。
接口原型
// 在proc文件系统中创建vlan条目(/proc/net/vlan) int vlan_proc_init(struct net *net); // 移除vlan设备节点 void vlan_proc_rem_dev(struct net_device *vlandev); // 添加vlan设备节点 int vlan_proc_add_dev(struct net_device *vlandev); // 从proc文件系统中删除vlan条目(/proc/net/vlan) void vlan_proc_cleanup(struct net *net);
创建vlan条目
例如,在我的设备上创建两个vlan设备后,查看vlan目录和各个文件内容如下:
root@penyforever-pc:~# vconfig add docker0 1 root@penyforever-pc:~# vconfig add enp2s0 1 root@penyforever-pc:~# cd /proc/net/vlan root@penyforever-pc:/proc/net/vlan# ls config docker0.1 enp2s0.1 root@penyforever-pc:/proc/net/vlan# cat config VLAN Dev name | VLAN ID Name-Type: VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD enp2s0.1 | 1 | enp2s0 docker0.1 | 1 | docker0 root@penyforever-pc:/proc/net/vlan# cat docker0.1 docker0.1 VID: 1 REORDER_HDR: 1 dev->priv_flags: 1001 total frames received 0 total bytes received 0 Broadcast/Multicast Rcvd 0 total frames transmitted 0 total bytes transmitted 0 Device: docker0 INGRESS priority mappings: 0:0 1:0 2:0 3:0 4:0 5:0 6:0 7:0 EGRESS priority mappings: root@penyforever-pc:/proc/net/vlan# cat enp2s0.1 enp2s0.1 VID: 1 REORDER_HDR: 1 dev->priv_flags: 1021 total frames received 0 total bytes received 0 Broadcast/Multicast Rcvd 0 total frames transmitted 0 total bytes transmitted 0 Device: enp2s0 INGRESS priority mappings: 0:0 1:0 2:0 3:0 4:0 5:0 6:0 7:0 EGRESS priority mappings:
/* * Create /proc/net/vlan entries */ int __net_init vlan_proc_init(struct net *net) { // 根据vlan命名空间id获取vlan proc文件系统信息 struct vlan_net *vn = net_generic(net, vlan_net_id); // 在/proc/net/下创建vlan目录 vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net); if (!vn->proc_vlan_dir) goto err; // 在/proc/net/vlan/下创建config文件,并设置文件权限和文件(seq fie)操作函数 vn->proc_vlan_conf = proc_create_net(name_conf, S_IFREG | 0600, vn->proc_vlan_dir, &vlan_seq_ops, sizeof(struct seq_net_private)); if (!vn->proc_vlan_conf) goto err; return 0; err: pr_err("can't create entry in proc filesystem!\n"); 从proc文件系统中删除vlan条目(/proc/net/vlan) vlan_proc_cleanup(net); return -ENOBUFS; }
删除vlan条目
/* * Clean up /proc/net/vlan entries */ void vlan_proc_cleanup(struct net *net) { // 根据vlan命名空间id获取vlan proc文件系统信息 struct vlan_net *vn = net_generic(net, vlan_net_id); // 删除config文件 if (vn->proc_vlan_conf) remove_proc_entry(name_conf, vn->proc_vlan_dir); // 删除vlan目录 if (vn->proc_vlan_dir) remove_proc_entry(name_root, net->proc_net); /* Dynamically added entries should be cleaned up as their vlan_device * is removed, so we should not have to take care of it here... */ }
添加设备节点
/* * Add directory entry for VLAN device. */ int vlan_proc_add_dev(struct net_device *vlandev) { // 获取vlan设备私有信息 struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev); // 根据vlan命名空间id获取vlan proc文件系统信息 struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id); // 校验,vlan设备名字不能是“config” if (!strcmp(vlandev->name, name_conf)) return -EINVAL; // 在/proc/vlan/下创建设备节点文件,用来保存vlan设备信息,并设置文件权限和文件(seq file)操作函数 vlan->dent = proc_create_single_data(vlandev->name, S_IFREG | 0600, vn->proc_vlan_dir, vlandev_seq_show, vlandev); if (!vlan->dent) return -ENOBUFS; return 0; }
移除设备节点
/* * Delete directory entry for VLAN device. */ void vlan_proc_rem_dev(struct net_device *vlandev) { // 从/proc/net/vlan/移除vlan设备信息文件 /** NOTE: This will consume the memory pointed to by dent, it seems. */ proc_remove(vlan_dev_priv(vlandev)->dent); // vlan设备私有信息置为空 vlan_dev_priv(vlandev)->dent = NULL; }
seq文件操作函数
一般地,内核通过在procfs文件系统下建立文件来向用户空间提供输出信息,用户空间可以通过任何文本阅读应用查看该文件信息,但是procfs有一个缺陷,如果输出内容大于1个内存页,需要多次读,因此处理起来很难,另外,如果输出太大,速度比较慢,有时会出现一些意想不到的情况,Alexander Viro实现了一套新的功能,使得内核输出大文件信息更容易,该功能出现在2.4.15(包括2.4.15)以后的所有2.4内核以及2.6内核中,尤其是在2.6内核中,已经大量地使用了该功能。
要想使用seq_file功能,开发者需要包含头文件linux/seq_file.h,并定义与设置一个seq_operations结构(类似于file_operations结构),seq_file必须实现四个操作函数:start(), next(), show(), stop()。
/****** Proc filesystem entry points ****************************************/
/*
* The following few functions build the content of /proc/net/vlan/config
*/
// 主要实现初始化工作,在遍历一个链接对象开始时调用,返回一个链接对象的偏移或者SEQ_START_TOKEN(表征这是所有循环的开始)
/* start read of /proc/net/vlan/config */
static void *vlan_seq_start(struct seq_file *seq, loff_t *pos)
__acquires(rcu)
{
struct net_device *dev;
struct net *net = seq_file_net(seq);
loff_t i = 1;
// 加rcu读锁
rcu_read_lock();
if (*pos == 0)
return SEQ_START_TOKEN;
// 遍历网络命名空间下的所有设备,找到偏移pos指向的vlan设备
for_each_netdev_rcu(net, dev) {
if (!is_vlan_dev(dev))
continue;
if (i++ == *pos)
return dev;
}
return NULL;
}
// 用来在遍历中寻找下一个链接对象,返回下一个链接对象或者NULL(遍历结束)
static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
struct net_device *dev;
struct net *net = seq_file_net(seq);
++*pos;
// 找到下一个vlan设备
dev = v;
if (v == SEQ_START_TOKEN)
dev = net_device_entry(&net->dev_base_head);
for_each_netdev_continue_rcu(net, dev) {
if (!is_vlan_dev(dev))
continue;
return dev;
}
return NULL;
}
// 当所有链接对象遍历结束时调用,主要完成一些清理工作
static void vlan_seq_stop(struct seq_file *seq, void *v)
__releases(rcu)
{
// 释放rcu读锁
rcu_read_unlock();
}
// 对遍历对象进行查看操作的函数,主要是调用seq_printf(), seq_puts()之类的函数,打印出这个对象节点的信息
static int vlandev_seq_show(struct seq_file *seq, void *offset)
{
// 获取vlan设备信息
struct net_device *vlandev = (struct net_device *) seq->private;
// 获取vlan设备私有信息
const struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
struct rtnl_link_stats64 temp;
const struct rtnl_link_stats64 *stats;
static const char fmt64[] = "%30s %12llu\n";
int i;
if (!is_vlan_dev(vlandev))
return 0;
// 获取vlan设备接口统计信息
stats = dev_get_stats(vlandev, &temp);
// 输出设备设备名称,vlan id,网络设备接口的标识符(其状态类型被定义在
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~