CORE网络仿真软件分析

CORE采用LXC(Linux namespace Container)技术和Bridge技术实现虚拟主机和虚拟网络的仿真模拟。LXC利用cgroups子系统中的进程组资源管理框架将虚拟主机实现为同一个组相对独立的进程。LXC已加入到内核2.6.28版本,CORE对虚拟主机创建和管理,通过的C语言系统调用来的实现,具体代码实现在core/daemon/src文件夹下。

文件列表


文件名称


功能说明


vnoded_main.c


创建LXC容器运行的守护进程vnoded(PID 1)


vcmd_main.c


tool, 指定LXC容器运行命令


netns_main.c


tool, 创建LXC容器中运行指定程序


netns.h, netns.c


提供LXC容器管理操作


netnsmodule.c


提供LXC容器管理操作的Python库


vnode_server.h, .c


vnode_client.h, .c


vnode_cmd.h, .c


vnode_msg.h, .c


vnode_io.h, .c


提供了io基本操作


vnode_chnl.h, .c


提供了针对vnoded进程的连接管理操作

LXC容器(netns.h, netns.c)

Linux下通过进程克隆(syscall调用)来创建LXC容器。每个LXC容器PID、IPC、Network等系统资源不再是全局的,而是属于特定的Namespace,每个Namespace中的资源相对其它Namespace是透明的。

pid = syscall(SYS_clone, flags | NSCLONEFLGS, NULL, NULL, NULL, NULL)

在创建新的LXC容器时需要指定相应的flag。

#define NSCLONEFLGS                      \           //netns.c

(                                      \

SIGCHLD       |                       \

CLONE_NEWNS   |                        \

CLONE_NEWUTS  |                       \

CLONE_NEWIPC  |                        \

CLONE_NEWPID       |                          \

CLONE_NEWNET                                  \

)

l        SIGCHLD表示创建进程退出后向父进程发送SIGCHLD信号

l        CLONE_NEWNS表示创建进程设置独立的文件层次视图

l        CLONE_NEWUTS表示创建进程设置独立的主机名称

l        CLONE_NEWIPC表示创建进程设置独立的IPC环境

l        CLONE_NEWPID表示创建进程设置独立的PID环境

l        CLONE_NEWNET表示创建进程独立的网络环境

以上flags可以组合使用,根据需要进行创建LXC容器。

vnoded进程(vnoded_main.c)

vnoded进程是虚拟主机创建后运行的第一个进程(pid=1),它由pycore调用/usr/sbin/vnoded命令来创建,命令执行时需要提供的参数有newnetns, ctrlchnlname, logfilename, pidfilename等。vnoded进程是一个守护进程,执行时会进入消息循环,直至退出。

ev_loop(vnodeserver->loop, 0);

vnoded进程相当于LXC容器内运行的操作系统,因此它提供了简易操作系统功能:文件管理,用户访问,进程管理三个基本功能。vnoded进程执行分为三个步骤:

Step1. 创建用户访问ctrlchnl

CORE虚拟出来的节点需要通过ctrlchnl进行访问,ctrlchnl其实是SOCK_SEQPACKET 类型的Socket进程间通讯机制。ctrlchnl建立位于进程克隆之前,这样克隆出来的进程(子进程)自然可以访问该Socket句柄。

fd = socket(AF_UNIX, SOCK_SEQPACKET, 0)

bind(fd, (struct sockaddr *)&addr, sizeof(addr))

Step2. 创建容器(namespace)。

pid = nsfork(0);

子进程:

关闭父进程打开的所有文件;设置输入/输出。

for (i = 3; i < openmax; i++)

if (i != ctrlfd) close(i);

DUPFILE("/dev/null", O_RDONLY, STDIN_FILENO);

setvbuf(stdout, NULL, _IOLBF, 0);

setvbuf(stderr, NULL, _IOLBF, 0);

父进程:

退出等待。

_exit(0);     /* nothing else for the parent to do */

Step3. 建立监听消息循环。

vnoded进程(运行在容器中)建立两个消息循环,一个是Ctrlchnl消息循环,接收用户命令。另一个是子进程消息,接收子进程信息。这两个消息循环的实现采用了libev库,封装在vnode_server_t结构体中来完成。

server = vnode_newserver(ev_default_loop(0), ctrlfd, ctrlchnlname);

vcmd命令(vcmd_main.c)

vcmd命令用于指定容器里运行程序,确切地说是向vnoded进程发送消息,让它clone出一个新的进程。关于网卡和链路的配置都需要通过vcmd命令进行。。为了指定LXC容器,vcmd执行时需要指定容器的ctrlchnl

Linux下的程序需要标准输入输出和出错输出,可以是管道(Pipe),也可以是终端(Pty),统称为I/O。用vcmd命令执行另一个程序,需要为该程序指定I/O,通过参数-I, -i, -q等。vmd定义了三种输入输出I/O类型:文件、管道、终端,V4.5版本中仅仅实现终端类型,即VCMD_IO_PTY。

typedef enum {

VCMD_IO_NONE = 0,

VCMD_IO_FD,

VCMD_IO_PIPE,

VCMD_IO_PTY,

} vnode_client_cmdiotype_t;

Vcmd命令执行分为以下四个步骤。

Step1. 初始化输入输出

根据命令参数,对终端、管道进行初始化。

vcmd.cmdio = vnode_open_clientcmdio(iotype);

Step2. 建立容器访问客户端。

       容器访问客户端封装在vnode_client_t结构体中。vcmd命令会创建vnode_client_t结构体,并通过它与服务器进程(vnoded)访问。

vcmd.client = vnode_client(ev_default_loop(0), ctrlchnlname,

vcmd_ioerrorcb, &vcmd);

Step3. 建立命令回复响应消息循环。

vcmd命令进程在执行时,接收用户输入,并将输入传递给容器中的进程,同时也将容器中的进程执行回复显示在用户终端,因此vcmd需要建立两个消息循环:自身I/O消息循环和容器中的进程的I/O消息循环。

vcmd->stdin_fwdfd = vcmd->cmdio->stdiopty.masterfd;

vcmd->stdin_watcher.data = &vcmd->stdin_fwdfd;

ev_io_init(&vcmd->stdin_watcher, vcmd_rwcb,

STDIN_FILENO, EV_READ);

ev_io_start(loop, &vcmd->stdin_watcher);

vcmd->ptymaster_fwdfd = STDOUT_FILENO;

vcmd->ptymaster_watcher.data = &vcmd->ptymaster_fwdfd;

ev_io_init(&vcmd->ptymaster_watcher, vcmd_rwcb,

vcmd->cmdio->stdiopty.masterfd, EV_READ);

ev_io_start(loop, &vcmd->ptymaster_watcher);

Step4. 发送命令消息。

vcmd通过argc, argv获得用户想要在容器中执行程序的名称和参数,然后通过ctrlchnl发送给vnoded进程,然后由vnoded进程通过forkexec来执行。为了编程方便,vcmd作为如下层次抽象。

图1  vcmd消息传递机制

命令层cmd交给用户客户端vnode_client,用户客户端交给消息层msg,然后通过Socket发送给Vnode进程的消息层msg,上传给服务客户端,然后由命令层cmd解包获得命令参数进行执行。此外,Vcmd还与子进程建立了标准输入输出。

vnode_server_t结构体(vnoded_server.h, .c)

vnoded进程启动的系统服务功能为接收用户请求连接,根据用户命令,在容器中执行(forkexec)相应程序,并将程序结果返回给用户。由于用户可能有多个,执行的程序也会有多个,vnode_server_t结构体用队列clientlist,cmdlist来存储。serverfd用于存储用户连接绑定的contrlchnl建立的Socket。fdwatcher和childwatcher分别是建立两个消息观察器,前者观察用户连接消息,后都观察子进程执行消息。

typedef struct {

TAILQ_HEAD(clientlist, cliententry) clientlisthead;

TAILQ_HEAD(cmdlist, cmdentry) cmdlisthead;

struct ev_loop *loop;

char ctrlchnlname[PATH_MAX];

char pidfilename[PATH_MAX];

int serverfd;

ev_io fdwatcher;

ev_child childwatcher;

} vnode_server_t;

用户连接消息循环

用户连接消息由回调函数vnode_server_cb处理。

static void vnode_server_cb(struct ev_loop *loop, ev_io *w, int revents)

该函数将生成vnode_client对象,加入到clientlist队列中,并启动vnode_client对象的msgio消息循环,之后该client对象与server的io处理交给msgio消息循环处理。

vnode_msgiostart(&client->msgio, server->loop, client->clientfd, client, client_ioerror, msghandler)

子进程消息循环

子进程消息由回调函数vnode_child_cb处理。

static void vnode_child_cb(struct ev_loop *loop, ev_child *w, int revents)

该函数根据子进程执行返回的状态,向用户发送状态信息。

vnode_send_cmdstatus(client->clientfd, cmd->cmdid, w->rstatus)

之后,从cmdlist中将相应的cmd移除。

TAILQ_REMOVE(&server->cmdlisthead, cmd, entries);

vnode_client_t结构体(vnoded_client.h, .c)

vnode_client_t结构体用于创建用户客户端实体,对应于vnoded进程中一个vnode_cliententry_t表项。vnode_client_t接收用户命令vcmd_t,并将用户命令封装在vnode_msgio结构体中,并vnode_msgiostart启动该消息循环。

typedef struct vnode_client {

TAILQ_HEAD(cmdlist, cmdentry) cmdlisthead;

struct ev_loop *loop;

int serverfd;

struct vnode_msgio msgio;

void *data;

vnode_clientcb_t ioerrorcb;

int32_t cmdid;

} vnode_client_t;

cmdlist用于存储vcmd_t,但理解上一条命令对应一个用户客户端,不需要用列表来存储,检查代码后发现没有往该列表中插入任何对象,vcmd_t存在data中。serverfd用于存储vnoded进程ctrlchnl。msgio存储msg消息层结构体vnode_msgio。Ioerrorcb用于存储服务器端io出错回调函数。cmdid用于存储子进程id号。

用户客户端向服务客户端发送消息,应该向消息层指定消息响应回调。程序定义了四种消息类型。

typedef enum {

VNODE_MSG_NONE = 0,

VNODE_MSG_CMDREQ,

VNODE_MSG_CMDREQACK,

VNODE_MSG_CMDSTATUS,

VNODE_MSG_CMDSIGNAL,

VNODE_MSG_MAX,

} vnode_msgtype_t;

但实际只指定了两个类型的回调。

static const vnode_msghandler_t msghandler[VNODE_MSG_MAX] = {

[VNODE_MSG_CMDREQACK] = vnode_clientrecv_cmdreqack,

[VNODE_MSG_CMDSTATUS] = vnode_clientrecv_cmdstatus,

};

vnode_msgio_t结构体(vnoded_msg.h, .c)

vnode_msgio_t负责收发消息,它维护的重点是fd的处理,但不负责fd的初始化,且msghandler也是由client为它指定。

typedef struct vnode_msgio {

struct ev_loop *loop;

int fd;

ev_io fdwatcher;

vnode_msgbuf_t msgbuf;

void *data;

vnode_msghandler_t ioerror;

vnode_msghandler_t msghandler[VNODE_MSG_MAX];

} vnode_msgio_t;

vnode_msgio_t最关键的两个函数是收发消息函数。

ssize_t vnode_sendmsg(int fd, vnode_msgbuf_t *msgbuf);

ssize_t vnode_recvmsg(vnode_msgio_t *msgio);

vnode_sendmsg可由外部调用,收消息vnode_recvmsg由fdwatcher在消息触发时在vnode_msg_cb回调函数中调用,读取消息后根据消息类型,选择不同的msghandler处理。

msghandlefn = msgio->msghandler[msgio->msgbuf.msg->hdr.type];

msghandlefn(msgio);

vnode_cmd.h, .c, vcmdmodule.c

定义了结构体vnode_cmdentry_t,但没有引用(可见代码是在其它代码上修改而来)。定义了命令层次收发函数。主要是发送命令请求vnode_send_cmdreq,接收命令请求vnode_recv_cmdreq,发送命令状态vnode_send_cmdstatus,发送命令信号vnode_send_cmdsignal,接收命令信号vnode_recv_cmdsignal。

void vnode_recv_cmdreq(vnode_msgio_t *msgio);

int vnode_send_cmdreq(int fd, int32_t cmdid, char *argv[], int infd, int outfd, int errfd);

int vnode_send_cmdstatus(int fd, int32_t cmdid, int32_t status);

int vnode_send_cmdsignal(int fd, int32_t cmdid, int32_t signum);

void vnode_recv_cmdsignal(vnode_msgio_t *msgio);

部分函数只有定义,并没有调用,估计在完善中,例如vnode_send_cmdstatus和

vnode_recv_cmdsignal。

时间: 2024-10-09 22:19:36

CORE网络仿真软件分析的相关文章

Linux下电骡aMule Kademlia网络构建分析3

将本节点加入Kademlia网络 连接请求的发起 aMule在启动的时候,会起一些定时器,以便于定期的执行一些任务.其中比较重要的就是core_timer,相关code如下(amule-2.3.1/src/amule-gui.cpp): // Create the Core timer core_timer = new CTimer(this,ID_CORE_TIMER_EVENT); if (!core_timer) { AddLogLineCS(_("Fatal Error: Failed

【转】几款网络仿真软件的比较

转自: 网络仿真技术是一种通过建立网络设备和网络链路的统计模型, 并模拟网络流量的传输, 从而获取网络设计或优化所需要的网络性能数据的仿真技术.由于仿真不是基于数学计算, 而是基于统计模型,因此,统计复用的随机性被精确地再现.网络仿真技术具有以下特点:一, 全新的模拟实验机理使其具有在高度复杂的网络环境下得到高可信度结果的特点.二, 网络仿真的预测功能是其他任何方法都无法比拟的:三,使用范围广, 既可以用于现有网络的优化和扩容,也可以用于新网络的设计,而且特别适用于中大型网络的设计和优化:四,初

CORE网络数据包接收传递过程分析

能够接收实际网络流量是CORE的一个显著优点,这使得已有的系统能方便地接入虚拟网络进行模拟.CORE对网络设备的虚拟是通过LXC技术来实现的,而对网络的虚拟则是通过虚拟网卡(veth).网桥(Bridge).Quagga来实现的.本文档主要通过分析CORE中网络数据传递过程,来理解CORE网络模拟. 拓扑结构 为了方便描述,以如图1所示拓扑结构为例子,分析数据流从网卡eth0到虚拟节点n2的过程. 图1 示例拓扑 虚拟网络创建由CORE后台根据前台的拓扑结构和配置,执行相应的命令进行实现,如下:

Ns3网络仿真软件简单介绍

Ns3网络仿真软件简单介绍 1. 什么是NS-3? NS是一个开源离散事件驱动网络模拟器.官方定义:(fromhttp://www.nsnam.org/) ns-3 is a discrete-event network simulatorfor Internet systems, targeted primarily for research and educational use. ns-3is free software, licensed under the GNU GPLv2 lice

linux 网络协议分析---3

本章节主要介绍linxu网络模型.以及常用的网络协议分析以太网协议.IP协议.TCP协议.UDP协议 一.网络模型 TCP/IP分层模型的四个协议层分别完成以下的功能: 第一层 网络接口层 网络接口层包括用于协作IP数据在已有网络介质上传输的协议.实际上TCP/IP标准并不定义与ISO数据链路层和物理层相对应的功能.相反,它定义像 地址解析协议(Address Resolution Protocol,ARP)这样的协议,提供TCP/IP协议的数据结构和实际物理硬件之间的接口. 第二层 网间层 网

spark core源码分析6 Spark job的提交

本节主要讲解SparkContext的逻辑 首先看一个spark自带的最简单的例子: object SparkPi { def main(args: Array[String]) { val conf = new SparkConf().setAppName("Spark Pi") val spark = new SparkContext(conf) val slices = if (args.length > 0) args(0).toInt else 2 val n = ma

Linux下电骡aMule Kademlia网络构建分析5 —— 资源的发布

资源发布请求消息的发送 在aMule中,主要用CSharedFileList class来管理共享给其它节点的文件.如我们前面在 Linux下电骡aMule Kademlia网络构建分析3 一文中分析的那样,aMule在启动的时候,会起一些定时器,以便于定期的执行一些任务.CamuleApp::OnCoreTimer()是其中之一,在这个函数中,我们可以看到这样的几行: // Publish files to server if needed. sharedfiles->Process(); 由

TFTP网络协议分析

TFTP网络协议分析 周学伟 文档说明:所有函数都依托与两个出口,发送和接收. 1:作为发送时,要完成基于TFTP协议下的文件传输,但前提是知道木的PC机的MAC地址,因为当发送TFTP请求包时必须提供目的主机的MAC地址.则提供串口srcureCRT控制台,首先进行ARP请求包的发送,收到来自客户端的ARP应答包时,提取出目的主机的MAC地址,然后在发送TFTP请求包,等到目的主机返回数据报文后,文件传输即可开始,此过程,可用wireshark抓包工具进行检测. 2:作为接收时,可在DM900

《Unix/Linux网络日志分析与流量监控》获2015年度最受读者喜爱的IT图书奖

<Unix/Linux网络日志分析与流量监控>获2015年度最受读者喜爱的IT图书奖.刊登在<中华读书报>( 2015年01月28日 19 版) 我的2015年新作刊登在<中华读书报>( 2015年01月28日 19 版) 原文下载:http://epaper.gmw.cn/zhdsb/images/2015-01/28/19/2015012819_pdf.pdf 这3本原创Linux图书,全部收录于中国科学院图书馆.国图以及211.985高校图书馆,广获读者好评,在当