推荐阅读
本节实验推荐阅读下述内容:
openflow 初学
mininet 使用
mininet 源码分析
mininet 原理
在上一个实验中我们大概明白了 SDN 作用,对其有了一个大概的了解,并且我们选择了 mininet 与 RYU 作为我们接下来学习的工具。
在使用 mininet 之前我们需要对其做一个更深入的了解,以便我们后续的学习。我们将围绕这样的两个话题来学习 mininet:
mininet 是什么?
mininet 是如何实现的?(只分析大概的框架结构)
mininet 是什么
mininet 是一个由 Nick McKeown 研究小组使用 python 开发一个轻量级的网络仿真工具(类似于 GNS3),所谓的仿真就是创造一个几乎与真实环境相同的网络,从拓扑结构到数据通信。
mininet 的便利之处是:
其代码迁移至硬件环境中几乎无差错,便于学习、测试
非常便捷、快速的创建大规模的网络环境
mininet 实现
从上文我们了解到 SDN 主要包含这样的一些层次,且每个层次对应的组件:
既然 mininet 能够做到仿真模拟必然能够尽数包含在内:
在数据层方面有多种选择,即可使用 openvSwitches 也可以使用 openflow switches 并且还可以使用自己 switch;
在控制层方面 mininet 提供、使用 ovsc、pox、nox 等控制器(在 install.sh 脚本中可以看到还有其他控制器的安装),当然也可以使用远程的 controller,也就是其他的 controller;
在业务层方面我们可以通过 mininet 的命令行发送一些指令,还可以运行一些 python 或者 shell 的脚本。
这些组件都存在于同一个架构中,又是如何让它们共存于同一台机器上呢?
mininet 是基于 Linux Container 开发的,而 Linux network namespace 机制可以说是实现这一切的功臣。
Linux Container(简称 LXC)是一种操作系统层虚拟化((Operating system–level virtualization))技术,为Linux内核容器功能的一个用户空间接口。它将应用软件系统打包成一个软件容器(Container),内含应用软件本身的代码,以及所需要的操作系统核心和库。通过统一的名字空间和共用 API 来分配不同软件容器的可用硬件资源,创造出应用程序的独立沙箱运行环境,使得 Linux 用户可以容易的创建和管理系统或应用容器。
在 Linux 内核中,提供了 cgroups 功能,来达成资源的区隔化。它同时也提供了名称空间区隔化的功能,使应用程序看到的操作系统环境被区隔成独立区间,包括进程树,网络,用户id,以及挂载的文件系统。但是 cgroups 并不一定需要引导任何虚拟机。
LXC 利用 cgroups 与名称空间的功能,提供应用软件一个独立的操作系统环境。LXC 不需要 Hypervisor 这个软件层,软件容器(Container)本身极为轻量化,提升了创建虚拟机的速度。(此段来自于 wikipedia)
简单来说:LXC 通过 cgroups 子系统利用 namespace 来实现系统资源使用上的隔离控制,内核支持这样 6 个命名空间:ipc(进程间通信资源命名空间), uts(系统变量命名空间), mount(文件系统挂在命名空间), pid(进程 ID 号命名空间), network(网络命名空间) and user(用户和组的命名空间)。
通过 namespace 的隔离,使得创建出来的每个 controller,switch 都在一个单独的 namespace 中,每个 namespace 中都可以模拟出网卡,并通过创建 veth pair 来连接不同的 namespace,使不同的 namespace 之间相互通信。就像每个都在一个单独的虚拟机中一般,从而便可实现大规模网络的模拟。
所有的组件在系统中类似于这样存在:
mininet 指令
mininet 启动
指令
在明白了 mininet 是什么,主体的实现方式之后我们便来尝试一下 mininet 的使用。
通过这样的命令启动 mininet:
sudo mn
我可以命令行的开头变成了 mininet> 说明我们启动了 mininet 并进入了其命令行,同时我们看到上面显示了一大串信息:
这是因为当我们不添加任何参数的时候,默认会创建一个这样的拓扑结构:
通过显示的信息我们也可以看出其添加了 1 个 controller,2 个 hosts,一个 switch。
注意:若是不想了解源码实现的同学可以跳过这一段
原理
我们可以通过查看源代码明白其中的缘由,进入 mininet 源码的目录:
cd ~/mininet
查看 mn 的源文件:
less bin/mn
查看 52 行左右,或者通过搜索 TOPOS 我们可以看见,当我们不指定 topo 参数的值时,默认为 minimal,而 minimal 对应的值为 MinimalTopo,我们退出该文件,查看 MinimalTopo 定义处:
less mininet/topo.py
查看 321 行左右,或者通过搜索 MinimalTopo 我们可以看见,在使用 MinimalTopo 时会直接调用 SingleSwitchTopo 的 build 方法,在本文中我们在搜索 SingleSwitchTopo,我们会在 293 行左右看到:
通过 addSwitch() 添加了一个名为 s1 的 switch,通过一个循环,循环中使用 addHost() 添加 host,循环的 k 值为 2,所以只会产生两个 host,并通过 addLink() 将 switch 与 host 连接起来。这便是为何默认创建一个 switch 与两个 host 的原因
同样我们在之前查看 TOPOS 的下方,我们可以看到 CONTROLLERS 的默认值为 DefaultController。
我们在终端中 grep -R DefaultController 我们可以看到:
默认使用的是 OVSController 控制器。
就这样我们便创建了这样的一个简单的 topo 结构。
dump 命令
指令
在 mininet 的命令行中,提供了这样的一些命令来辅助我们使用。
我们可以通过 dump 来查看所有节点的相关信息:
通过 dump 我们可以看到节点的类别、名字 、IP 信息、pid。通过 dump 我们也可以看到我们使用的默认 controller 是 OVSController。
原理
之前我们说过其实每个节点都在一个单独的 namespace 里来隔离资源,从而做到虚拟化,实现模拟大规模网络的目的,有一定 LXC 基础的同学会尝试使用 ip netns list,查看一下当前 network namespace 的情况,但是结果回令人失望,没有任何信息的返回。
这是因为 ip netns 只会显示在 /var/run/netns 中有名字的、有挂载的 namespace,而 mininet 中新的 namespace 是通过 PID 来与主机相关联,使用 unshare() 方式来创建出新的 namespace,所以是没有名字的 namespace,以至于我们通过 ip netns list 是无法查看到节点的 namespace。
在 mininet 的 net.py 中 Mininet 类中我们发现 addHost() 方法的定义:
我们可以看到当 cls 为空时,也就是当没有制定的 host 时便使用 mininet 的 host,而 self.host 中的 host 是由 Host 类创建的对象,
通过 grep 我们查看到在 node.py 中 Host 类继承于 Node:
在 Node 类中,inNamespace 默认值为 true,在经过属性的初始化之后会调用 startShell() 方法,下方的 startShell() 中我们看到,当 inNamespace 为 true 会在稍后执行命令参数变量中加 n,而执行的命令便是调用 mnexec,而 mnexec 是位于根目录中一个用 C 写的程序,查看该程序,我们会发现这样的语句:
我们会发现当传入的参数中有 n 时,就会通过 unshare(CLONE_NEWNET | CLONE_NEWNS) 来创建新的网络 namespace 并挂载,而 unshare() 系统调用主要的作用便是在不启动一个新的进程情况下,也就是在当前的进程中执行,将当前进程分离出所在的 namespace 并加入新创建的 namespace,由此我们使用 ip netns list 便看不到该 namesapce 的存在。
就类似于我们使用这样的命令:
sudo unshare --net --mount /bin/bash
我们在新的 namespace 的 shell 中执行 ifconfig,我们会看到没有任何信息,这就是因为我们在新的 namespace 中,并没有创建任何的虚拟网络接口,所以没有任何信息的输出。
若还有兴趣验证的同学通过 /proc/$$/ns 查看两个 shell 的 namespace inode 值,可以发现新创建的 namespace 的 net 与 mnt 的 inode 值与之前的不同。
nodes 命令
指令
通过 dump 我们可以查看所有节点的信息,但是我们若是只是想知道有哪些节点,我们就可以只使用 nodes 命令了:
原理
所有的命令行指令都在 cli.py 中,在该文件中我们可以找到这个函数:
net 命令
通过 nodes 命令我们可以查看到所有的节点,但是只是知道网络的节点还不够,我们还需要知道网络的连接,这种情况我们可以使用 net 命令:
节点执行命令
知道了网络的框架结构,若是我们需要知道某一个节点的具体配置,亦或者是需要让某个节点去做联通测试又该如何呢?
我们可以通过这样的命令来查看 h1 主机的网络配置:
h1 ifconfig
与之前 dump 查看到的信息相同,命令便是 节点名 ifconfig,若我们想做联通行测试,了解 h1 能否与 h2 通信,我们可以这样:
h1 ping -c 4 h2
通过这样两个例子,其实我们很容易明白其实命令结构是这样的 节点名 命令,指定某个节点执行 Linux 中的某个命令。
xterm 命令
若是我们觉得通过指定节点名指定命令来执行很麻烦,我们可以直接为该节点开启一个终端:
xterm h1
当需要启动多个的时候可以是在后方加节点名称,用空格隔开。例如 xterm h1 h2。
目前 mininet 只支持启动两种终端:
xterm
gnome-terminal
若是想使用 gnome-terminal 的话,则使用 gterm h1 命令。
注意:当你的机器中没有这两种终端是输入响应的命令是没有任何反应的,因为系统没有办法调用到,例如需要使用 xterm 的时候,需要提前安装 xterm,在 ubuntu 中使用 sudo apt-get install xterm,若是使用的 ubuntu 的 desktop 版本,则可以直接使用 gnome-terminal。
pingall 命令
上述的方式都是一个节点去 ping 另外一个节点,在小规模的网络是没有问题的,但是当在测试一个大规模的网络的时候我们会发现这样的方式非常的低效,这样的方式太过麻烦,所以有了这个偷懒的命令 `pingall,自动的帮助我们测试所有节点的联通性:
pingall
与之类似的还有 pingallfull,pingpair、pingpairfull。其中 pingpair 的作用是两个节点的互 ping。
link 命令
当我们在一些场景中我们需要做一些局部的测试,我们可能需要关闭一些连接来排除一些因素,已确定我们的一些功能是否成功或者排查问题的出处,这个时候我们便需要使用 link 命令,例如:
link s1 h1 down
通过这样的方式我们便关闭了 switch 与 h1 之间的网络连接,所以此时我们再用 h1 ping h2 是不可达的:
当我们测试完毕,我们需要重新开启该链接的时候我们只需要这样的命令即可:
link s1 h1 up
iperf 命令
在完成网络拓扑的部署之后,我们可能还需要查看网络的性能如何,这个时候我们的第一反应可能会想到使用
iperf
,mininet 中同样对 iperf
提供了支持:
Iperf:是美国伊利诺斯大学(University of Illinois)开发的一种网络性能测试工具。可以用来测试网络节点间TCP或UDP连接的性能,包括带宽、延时抖动(jitter,适用于UDP)以及误码率(适用于UDP)等。若是有对 iperf 源码有兴趣的朋友推荐看该博文
iperf
iperf 可以完成两个节点之间简单的 TCP 测试,若需要 UDP 测试测可以使用 iperfudp 命令。
dpctl 命令
以上我们看到了关于节点的命令,关于链路的相关命令。在 mininet 中还有关于 switch 的命令。
dpctl 是一个 OpenFlow 数据通路的检测和管理工具,它能够显示当前的状态数据通路,功能配置和表中的条目,可以用来对 datapaths 的添加,删除,修改和监控(datapaths 将在后面为大家介绍)。
通过 dpctl show 可以查看交换机的一些基本信息:
还可通过 dpctl dump-flows 查看流表的具体信息,还有 dpctl add-flow 来添加一些表项等等。
命令有很多,我们可以在需要使用的时候通过 dpctl --help 来查看。
执行外部命令
当我们发现 mininet 这些内部命令还是不满足我们的需求,我们还可以使用 py 与 sh 来执行一些 python 的表达式或者 shell 命令来完成我们想要的功能。
例如使用 py locals() 查看相关信息:
例如我们想单独查看 h1 的 IP 地址:
而若是想执行一些 shell 中的命令,只需使用 sh 命令 即可,例如:
help 命令
你可能会说你罗列了这么多的命令根本记不住,平时需要使用的时候忘记命令该怎么办?mininet 贴心的为你提供了 help 命令,查看到命令即可立即唤起你的记忆:
并且在 mininet 中也同样拥有自动补全的功能,只记得半个命令,tab 键会帮你做剩下的事情。
这便是 mininet 命令行中的常用命令。
作业
1.在 mininet 中有很多命令都可以添加在启动参数中,例如 xterm,pingall。请通过 mn --help 查看相关指令,在启动的同时打开所有节点的 xterm 终端。 2.查看推荐阅读的文章,能画出 mininet 构建一个 topo 的流程图。(感兴趣的同学做)