# 10. Mininet

Mininet是一个由Stanford大学Nick研究小组开发的网络虚拟化平台，可以用来方便的测试、验证和研究OpenFlow和SDN网络。

Mininet使用Linux Network Namespaces来创建虚拟节点，默认情况下，Mininet会为每一个host创建一个新的网络命名空间，同时在root Namespace（根进程命名空间）运行交换机和控制器的进程，因此这两个进程就共享host网络命名空间。由于每个主机都有各自独立的网络命名空间，我们就可以进行个性化的网络配置和网络程序部署。

Mininet提供了命令行工具`mn`和Python API，用来构建网络拓扑。

## 安装Mininet

在Ubuntu系统上可以使用通过下面的命令来安装mininet：

```bash
sudo apt-get install -y mininet openvswitch-testcontroller
sudo /usr/bin/ovs-testcontroller /usr/bin/ovs-controller
sudo service openvswitch-switch start
```

然后运行下面的命令验证安装是否正常

```bash
sudo mn --test pingall
```

其他系统上，可以参考[这里](https://github.com/mininet/mininet/wiki/Mininet-VM-Images)下载预置mininet的虚拟机镜像。

## mn命令行

直接运行mn命令可以进入mininet控制台，默认创建一个`minimal`拓扑，即一个控制器、一台OpenFlow交换机并连着两台host。

```bash
$ sudo mn
mininet> nodes
available nodes are:
h1 h2 s1
mininet> dump
<Host h1: h1-eth0:10.0.0.1 pid=21291>
<Host h2: h2-eth0:10.0.0.2 pid=21293>
<OVSBridge s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None pid=21298>
```

以节点名字开始的命令在节点内运行

```bash
mininet> h1 ifconfig -a
h1-eth0   Link encap:Ethernet  HWaddr aa:7d:6a:7f:b5:52
          inet addr:10.0.0.1  Bcast:10.255.255.255  Mask:255.0.0.0
          inet6 addr: fe80::a87d:6aff:fe7f:b552/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:15 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:1206 (1.2 KB)  TX bytes:648 (648.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

mininet> h1 ping -c1 h2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.040 ms

--- 10.0.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.040/0.040/0.040/0.000 ms
```

### 命令和选项

命令列表

* py：执行python命令，如`py h1.IP()`
* dump：查看各节点的信息
* nodes：查看所有节点
* net：查看链路信息
* links：查看网络接口连接拓扑
* link：开启或关闭网络接口，如`link s1 h1 up`
* xterm：开启终端
* dpctl：操作OpenFlow流表
* pingall：自动ping测试

选项列表

* `--topo`：自定义拓扑，如`linear|minimal|reversed|single|torus|tree`
* `--link`：自定义网络参数，如`default|ovs|tc`
* `--switch`：自定义虚拟交换机，如`default|ivs|lxbr|ovs|ovsbr|ovsk|user`
* `--controller`：自定义控制器，如`default|none|nox|ovsc|ref|remote|ryu`
* `--nat`：自动设置NAT
* `--cluster`：集群模式，将网络拓扑运行在多台机器上
* `--mac`：自动设置主机mac
* `--arp`：自动设置arp表项

### 自定义网络拓扑

默认的`minimal`拓扑比较简单，可以使用`--topo`选项设置网络拓扑。

```bash
$ sudo mn --topo single,3
mininet> dump
<Host h1: h1-eth0:10.0.0.1 pid=22193>
<Host h2: h2-eth0:10.0.0.2 pid=22195>
<Host h3: h3-eth0:10.0.0.3 pid=22197>
<OVSBridge s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None,s1-eth3:None pid=22202>
```

### 自定义网络参数

可以使用`--link`选项设置网络参数。

```bash
$ sudo mn --link tc,bw=10,delay=10ms
mininet> iperf
*** Iperf: testing TCP bandwidth between h1 and h2
*** Results: ['9.50 Mbits/sec', '12.0 Mbits/sec']
```

### 自定义独立命名空间

默认情况下，host在独立的netns中，而switch和controller都还是使用host netns，可以使用`--innamespace`选项将它们也放到独立的netns中。

```bash
$ sudo mn --innamespace --switch user
```

## Python API

对于复杂的网络，需要使用[Python API](http://mininet.org/api/annotated.html)来构建。

比如，使用python API构造一个单switch接4台虚拟节点的示例

```python
#!/usr/bin/python
from mininet.topo import Topo
from mininet.net import Mininet
from mininet.util import dumpNodeConnections
from mininet.log import setLogLevel
from mininet.node import OVSController

class SingleSwitchTopo(Topo):
    "Single switch connected to n hosts."
    def build(self, n=2):
        switch = self.addSwitch('s1')
        # Python's range(N) generates 0..N-1
        for h in range(n):
            host = self.addHost('h%s' % (h + 1))
            self.addLink(host, switch)

def simpleTest():
    "Create and test a simple network"
    topo = SingleSwitchTopo(n=4)
    net = Mininet(topo=topo, controller = OVSController)
    net.start()
    print "Dumping host connections"
    dumpNodeConnections(net.hosts)
    print "Testing network connectivity"
    net.pingAll()
    net.stop()

topos = {"mytopo": SingleSwitchTopo}

if __name__ == '__main__':
    # Tell mininet to print useful information
    setLogLevel('info')
    simpleTest()
```

这个脚本可以直接运行，也可以使用mn命令启动

```bash
$ sudo mn --custom a.py --topo mytopo,3 --test pingall
```

Mininet v2.2.0+还提供了一个miniedit的可视化界面，更直观的编辑和查看网络拓扑。miniedit实际上是一个python脚本，存放在mininet安装目录的examples中，如`/usr/lib/python2.7/dist-packages/mininet/examples/miniedit.py`。

## 参考文档

* [Mininet官方网站](http://mininet.org/)
* [Mininet Github](https://github.com/mininet/mininet)
* [REPRODUCING NETWORK RESEARCH](https://reproducingnetworkresearch.wordpress.com/)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://sdn.feisky.xyz/sdn-shi-jian/index.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
