Reimplementation of lxc-device
来源:互联网 发布:写作软件 知乎 编辑:程序博客网 时间:2024/05/20 07:19
最近对lxc比较感兴趣,作为一个new comer to lxc,我希望找一些工作可以作。在mail list中,我找到了一封
关于attach_interface的邮件。
The python3 module does support it (which is why lxc-device supports ittoo) by using the namespace capabilities of the ip command. It'dprobably be nice to re-implement that in C with netlink as add_interfaceand remove_interface so that it's available to all API users (patchesare welcome!).
于是,重写lxc-device就加到了我的TODO.lxc当中。经过几天对lxc的使用了解以及实现的简单熟悉之后。我发出了第一版patch Rewrite lxc-device.
patch通过使用netlink来与kernel交互并完成对netdev的netns的设置,以达到attach和detach的效果。下面分三个章节介绍一下在这个过程中了解到的知识。也是
为自己记录一下吧。
(1)lxc简介。
其实container这个概念在很多地方都会使用到,从kernel到userspace。我这里所说的lxc指的是 https://linuxcontainers.org/。
使用方法: 可以参考 Stgraber的blog: https://www.stgraber.org/2013/12/20/lxc-1-0-blog-post-series/。
代码位置: 现在lxc的代码可以在这个地方找到:https://github.com/lxc/lxc。
编译安装: 和其他项目类似,./autogen && ./configure && make && make install. 我比较喜欢使用(./configure --enable-dependency-tracking --enable-doc --enable-
api-docs --enable-examples --enable-python --enable-bash --enable-tests --enable-configpath-log --prefix=/usr)
代码框架: 进入代码,和大多数项目类似,都有doc,src等目录,主要实现代码都在src下面。进入src,主要是tests。lxc。python-lxc, lua-lxc
tests: 是测试代码, lxc是主要实现代码,python|lua-lxc是语言绑定的代码。
如上所述,lxc-device 现在是通过python调用ip 命令实现的。所以能找到一个叫做lxc-device的python脚本在 src/lxc/lxc-device
如图所试:
/-------------doc
|------config
|-------src/ ----------------tests
|--------include
|--------python-lxc
|---------lua-lxc
|---------lxc/-----------------lxc_start.c
|----------lxc_destroy.c
....
|-----------lxc-device (a python file)
现在的lxc-device主要工作流程如下:
if args.action == "add": if os.path.exists("/sys/class/net/%s/" % args.device): ret = container.add_device_net(args.device, args.name) else: ret = container.add_device_node(args.device, args.name)其中, add_device_net() 是一个只有在python-lxc中实现的interface。所以,在struct lxc_container (src/lxc/lxccontainer.h)中没有这个函数。
也就是说,这种实现知识权宜之计,通过在python里面实现了一个add_device_net的函数,然后通过一个脚本调用这个函数以实现attach interface。
(2)netlink简介
如Stgraber 所说,要实现attach interface 并且不依赖与iprout2,就应该使用netlink在实现。庆幸的是lxc里面已经有了netlink模块。(src/lxc/nl.h|c).
netlink其实是一种userspace与kernelspace交流的一种方式。在kernel中我在这里主要关心几个功能。RTM_NEWLINK, RTM_GETLINK, RTM_DELLINK, RTM_SETLINK.
几个功能的实现在net/core/rtnetlink.c。 使用起来很简单,只需要新建一个socket(AF_NETLINK,...)然后想这个socket sendmsg在recvmsg就可以了。具体可以参考
http://www.linuxjournal.com/article/7356。
(3)lxc-device 的实现。
既然已经对lxc和netlink都有了了解。那么就来看一下要实现lxc-device需要做些什么吧。
1. 为struct lxc_container 添加两个interface,其实就是函数指针的属性。类似于面向对象。(该方法在很多项目中使用,比如kernel.vfs, kernel.scheduler,
kernel.driver). 并且需要使用netlink实现这两个函数。这是最主要的工作。
1.1:为了实现attach_interface(),
首先肯定是需要使用netlink设置device的netns到c->init_pid(c)的netns。简单的查看代码之后发现在lxc已经有了一个函数可以
完成这项工作,(lxc_netdev_move_by_name(const char *ifname, pid_t pid))该函数将指定的netdev move到指定的pid 的netns里面,但是为了方便,我为这个
函数添加了一个参数,const char* newname, 用来指定移动之后的netdev的name。在很多时候,我们移动一个netdev之后并不是原来的name。所以这个参数是
很有实用价值的。其实实现也是很简单的,只需要在发送给kernel的netlink信息里面追加一个条目标记(IFLA_IFNAME, ifname),到了内核里面,会查看因为已经指定
了index所以kernel会直到这是需要rename。
1569 /*1570 * Interface selected by interface index but interface1571 * name provided implies that a name change has been1572 * requested.1573 */1574 if (ifm->ifi_index > 0 && ifname[0]) {1575 err = dev_change_name(dev, ifname);1576 if (err < 0)1577 goto errout;1578 modified = 1;1579 }其次,因为move的时候,如果netdev是up状态,会得到一个busy error。所以需要一个函数用来判断netdev是不是up。然而,现在的lxc里面没有实现
这样的一个函数,所以我添加了两个函数用来的到netdev的状态。
netdev_get_flag(): 用来得到netdev的flag
lxc_netdev_isup(): 调用netdev_get_flag()得到flag之后判断(flag & IFF_UP)至此,attach_interface() 就基本上实现结束了。
+static bool lxcapi_attach_interface(struct lxc_container *c, const char *ifname,+const char *dst_ifname)+{+int ret = 0;++ret = lxc_netdev_isup(ifname);+if (ret < 0)+goto err;++/* netdev of ifname is up. */+if (ret) {+ret = lxc_netdev_down(ifname);+if (ret)+goto err;+}++ret = lxc_netdev_move_by_name(ifname, c->init_pid(c), dst_ifname);+if (ret)+goto err;++return true;+err:+/* -EINVAL means there is no netdev named as ifanme. */+if (ret == -EINVAL) {+ERROR("No network device named as %s.", ifname);+}+return false;+}1.2 为了实现detach_interface()
detach_interface()原理很简单,首先得到当前进程pid,outside_pid, 然后fork()一个子进程,设置子进程的netns为container的netns。以便可以访问到
需要操作的netdev。但是由于pidns还是host的pidns。所以我们可以在子进程中设置netdev的netns到outside_pid的netns。 这样就完成了detach的操作。
+static bool lxcapi_detach_interface(struct lxc_container *c, const char *ifname,+const char *dst_ifname)+{+pid_t pid, pid_outside;++pid_outside = getpid();++pid = fork();+if (pid < 0) {+ERROR("failed to fork task to get interfaces information");+return false;+}++if (pid == 0) { // child+int ret = 0;+if (!enter_to_ns(c)) {+ERROR("failed to enter namespace");+exit(-1);+}++ret = lxc_netdev_isup(ifname);+if (ret < 0)+exit(ret);++/* netdev of ifname is up. */+if (ret) {+ret = lxc_netdev_down(ifname);+if (ret)+exit(ret);+}++ret = lxc_netdev_move_by_name(ifname, pid_outside, dst_ifname);++/* -EINVAL means there is no netdev named as ifanme. */+if (ret == -EINVAL) {+ERROR("No network device named as %s.", ifname);+}+exit(ret);+}++if (wait_for_pid(pid) != 0)+return false;++return true;+}
2. 使用c语言并且使用新加入的两个接口实现lxc_device.c
这个工作基本上就是用 c语言将以前的python脚本重写一遍,不过添加了detach的功能。实现过程简单。需要注意的是修改Makefile文件。需要修改
src/lxc/Makefile.am 删除以前的lxc-device 添加lxc_device.c的编译方法。当然,作为lxc-device,不仅要处理interface,其他的device也是需要处理的,这个时候就设计到怎样分别是不是一个interface设备的问题了。而这其中最重要的
是在detach的时候,怎样进入到container里面判断device是不是一个netdevice。在以前的解决方法中,lxc-device是这样作的,查找/sys/class/net/%s/ 如果存在,则是一个
interface.但是在detach的时候,我们就需要进入到container的mountns 然后查找这个目录。而在现在的方法中,我们只有一个方便的方法可以进入到netns。所以在这个地方
我没有使用这个方法。而是使用了getifaddrs()。 如下。
+static bool is_interface(const char* dev_name, pid_t pid)+{+pid_t p = fork();++if (p == 0) {+struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;++switch_to_newnet(pid);++/* Grab the list of interfaces */+if (getifaddrs(&interfaceArray)) {+ERROR("failed to get interfaces list");+exit(-1);+}++/* Iterate through the interfaces */+for (tempIfAddr = interfaceArray; tempIfAddr != NULL; tempIfAddr = tempIfAddr->ifa_next) {+if (strcmp(tempIfAddr->ifa_name, dev_name) == 0) {+exit(0);+}+}+exit(1);+}++if (wait_for_pid(p) == 0) {+return true;+}+return false;+}
3. 添加这两个接口到python绑定当中,让python里面的Container类也有这两个接口
该工作主要使用 struct PyObject 来实现一个python绑定。没有深入研究,只是简单的按照既定格式完成了绑定工作
至此,我完成了lxc-device的重写工作,当然lua的绑定我没有做,因为我对lua实在是不了解。其实patch已经发出。也得到了一些ACK,但还没有全部apply。这几天的感觉是
lxc不是一个比较活跃的社区。不过只是为了了解一下这个东西。感觉这个项目还是比较有意思。尤其是一些实现比如lxc_attach, 和正在开发中的checkpooint/restore。 下面会继续这些方面的记录。
这是我的第一篇记录文章,总体来起来比较乱。感觉自己学习的过程中探索了很多,有时候会忘了。于是在别人的建议下想用这种方式记录下来。也是为了以后想起来自己做过
些什么。无数次无功而返之后,今天第一次写了些东西,留给自己以后回想。
- Reimplementation of lxc-device
- lxc
- LXC
- LXC
- lxc
- Show memory usage of all docker / lxc containers
- List of device bandwidths
- Example of copying device blocks
- one example of network device
- LXC 学习
- LXC学习
- LXC讲解
- LXC技术研究
- LXC学习
- LXC基础知识
- LXC学习
- LXC容器
- 什么是LXC
- 设计模式 - 代理模式 C++
- error C2065: “IDD_DIALOG1” : 未声明的标识符
- vs2010安装失败 应用程序错误报告
- Android中Parcel的分析以及使用
- Struts2中的ModelDriven机制及其运用
- Reimplementation of lxc-device
- (复习)poj 1952 最长下降子序列—— dp+方案个数
- Android 内存泄漏
- 重写ScrollView实现两个ScrollView的同步滚动显示
- Spring Transactional_Propagation
- Linux 下使用USB 网络
- SQL——索引的创建和撤销
- OA项目之权限设计③
- 华为机试题:回文字符判断