Mininet学习记录之源码分析

2 篇文章 0 订阅


主要参考
linkSDN 网络系统之 Mininet 与 API 详解
link mininet_book
link这个很适合回顾总结,初学的时候一开始还是应该从documentation
按照这个顺序找手册就挺好的~

sudo apt-get install方式装的mininet文件夹默认在/usr/bin下面

link
OpenFlow 是 OpenFlow 协议的主页,里面提供了 OpenFlow 协议的白皮书以及 OpenFlow 交换机的实现规范。

Mininet基础知识点包含:

通过本文的阐述及实践,我们了解 Mininet 以及 OpenFlow 的基本概念。通过 Mininet 网络系统去仿真网络拓扑和自定义参数网络拓扑的实现,并且采用 dpctl 命令实现 OpenFlow 协议修改了流表项及其他常用的操作,最后对 Mininet 网络系统几个重要的执行文件进行了代码分析。

这么几大块,回头的时候就用这个逻辑去介绍~

没有找到我的mininet目录在哪,只有子目录??

init.py

python 代码导入控制文件

from mininet.topo import Topo
mininet.topo
from mininet.util import (方法)
这些方法都可以在mininet目录下util.py文件里找到~ 引用的库文件都是这里哒

util.py

link.py

描述链路相关的接口和连接。

  • 不同种类的links
    • simple veth pairs
    • tunneled links
    • patchable links (which can be disconnected and reconnected via a patchbay)
    • link simulators (e.g. wireless)
  • 分工
    • Nodes: know how to execute commands
      *Intfs: know how to configure themselves
      *Links: know how to connect nodes together
  • Intf : basic interface object that can configure itself
  • TCIntf: interface with bandwidth limiting and delay via tc
  • Link: basic link class for creating veth pairs
link.Intf

表示基本的网络接口,比如 h1-eth0 表示 host 1 上的 eth0 接口。 属性包括所在的节点,名称,所接的 link,mac/ip 信息等。 构造的时候会传入节点、端口等属性,并绑定接口到对应的节点的端口上。

def __init__( self, name, node=None, port=None, link=None, **params ):
        """name: interface name (e.g. h1-eth0)
           node: owning node (where this intf most likely lives)
           link: parent link if we're part of a link
           other arguments are passed to config()"""
        self.node = node
        self.name = name
        self.link = link
        self.mac, self.ip, self.prefixLen = None, None, None
        # Add to node (and move ourselves if necessary )
        node.addIntf( self, port=port )
        # Save params for future reference
        self.params = params
        self.config( **params )

所支持的方法包括配置 mac/ip 等配置方法,大都是通过 ifconfig 命令在对应节点上调用cmd方法来实现。 此外,还提供了 config() 方法来一次性配置所有的属性。

link.Link

表示基本的一条链路,最基本的链路在 mininet 中其实就是一对 veth 接口对。

def __init__( self, node1, node2, port1=None, port2=None,
                  intfName1=None, intfName2=None,
                  intf=Intf, cls1=None, cls2=None, params1=None,
                  params2=None ):
        """Create veth link to another node, making two new interfaces.
           node1: first node
           node2: second node
           port1: node1 port number (optional)
           port2: node2 port number (optional)
           intf: default interface class/constructor
           cls1, cls2: optional interface-specific constructors
           intfName1: node1 interface name (optional)
           intfName2: node2  interface name (optional)
           params1: parameters for interface 1
           params2: parameters for interface 2"""
        # This is a bit awkward; it seems that having everything in
        # params would be more orthogonal, but being able to specify
        # in-line arguments is more convenient!
        if port1 is None:
            port1 = node1.newPort()
        if port2 is None:
            port2 = node2.newPort()
        if not intfName1:
            intfName1 = self.intfName( node1, port1 )
        if not intfName2:
            intfName2 = self.intfName( node2, port2 )

        **self.makeIntfPair( intfName1, intfName2 )**

        if not cls1:
            cls1 = intf
        if not cls2:
            cls2 = intf
        if not params1:
            params1 = {}
        if not params2:
            params2 = {}

        intf1 = cls1( name=intfName1, node=node1, port=port1,
                      link=self, **params1  )
        intf2 = cls2( name=intfName2, node=node2, port=port2,
                      link=self, **params2 )

        # All we are is dust in the wind, and our two interfaces
        self.intf1, self.intf2 = intf1, intf2

创建链路时,需要在两个节点上分别生成两个端口,利用节点和端口,获取对应的两个网络接口的名称,例如 s1-eth0 和 h1-eth0,然后调用 makeIntfPair() 方法,最终调用 util.py 中的 makeIntfPair() 方法,调用系统中的 ip link 命令来创造一对 veth pair。

link.TCIntf

被 TC(Linux 下的 traffic control 的工具)自定义的接口,可以配置包括带宽、延迟、丢包率、最大队列长度等参数

link.TCLink

表示一对对称的 TC 接口连接到一起。都是看不懂的代码了233

Cli.py

定义 CLI 类,在 mn 运行后提供简单的命令行接口,解析用户键入的各项命令

  • 每个节点都有个独立的控制台,比如可以在mininet环境下运行h27 ifconfig runs ‘ifconfig’ on host h27.

  • list all nodes (‘nodes’)

  • print out the network topology(‘net’)

  • check connectivity (‘pingall’, ‘pingpair’)

  • check bandwidth (‘iperf’.)

link 真心没想到在百度知道里面能找到有用的答案

topo.py

提供了建拓扑结构需要用的过程以及一些拓扑类

topo.Topo

拓扑基类,默认的拓扑图被 multigraph 类维护,此外还包括节点、连接信息等。主要的方法就是添加节点、连接等。 Topo 中一个 node 实际上就是图结构中的一个节点,一个 port 是全局维护增长的源和目的 node 所对应的序号。

init
addNode

添加节点方法被添加主机 addHost、交换机 addSwitch、控制器 addController 等方法使用。

该方法在图上添加一个节点,然后添加对应的节点信息到拓扑的参数上。

addPort

addPort 会同时创建源和目标节点上的端口号信息。 拓扑中所有的 port 都被 self.ports 结构维护,其中 ports[src][dst] 表示在 src 节点上的 port,该 port 所在 link 连接到 dst 节点。 添加一个 port 就是更新了这些信息。

addLink

添加一条连接实际上就是添加对应的两个 port,并在图上添加上边。

  • SingleSwithTopo :一个交换机上连K个主机
  • SingleSwitchReversedTopo: 小号主机连大号端口,验证自定义端口号
  • MinimalTopo:一台交换机两台主机
  • LinearTopo:k个交换机,每个交换机上挂n个主机
  • MultiGraph: 表示一个图结构。 类似于networkx中的图G(V,E)的概念。主要维护节点、边信息。 在MultiGraph中,节点就是一个序号,边则通过节点和节点所对应的连接列表中元素来表示。节点和节点的连接列表的对应关系通过字典结构来维护。图结构最主要的功能就是维护一个字典。Key 是节点,value 是该节点所连接的所有的其他节点的列表。添加一条边,实际上就是添加两个节点,然后将连接信息放到 data 字典中(需要注意的是一条边的信息仅被保存了一次,即放到序号较小的节点对应的 list 中)。

topolib.py

  • TreeTopo: 给定深度和扇出,建树
  • TorusTopo:没兴趣2333

自定义的拓扑类可以定义在topolib模块下也可定义在topo模块下,拓扑类的__init__方法中可添加构建拓扑所需要的参数,Mininet在调用拓扑类时会将从命令行接收的topo选项之后的参数*args和关键字参数**kwargs传递到该拓扑类的__init__方法中初始化该拓扑类的对象。

自定义的拓扑类需要导入mn中,然后在存放拓扑参数的字典TOPOS中加入对应的键值,就可以在mn命令中使用自定义的拓扑了

from mininet.topolib import FatTreeTopo
  TOPOS = { 'linear': LinearTopo,
  'single': SingleSwitchTopo,
  'tree': TreeTopo,
  'fattree': FatTreeTopo }
  启动8叉胖树自定义拓扑的Mininet拓扑环境:
  $ sudo mn --topo=fattree, k=8

net.py

主要包括 Mininet 和 MininetWithControlNet 两个类。
mn 网络平台的主类。完成包括节点管理、基本测试等功能。

net.Mininet

模拟一个 Mininet 中的网络,包括拓扑、交换机、主机、控制器、链路、接口等。 其中最主要的部分是 build() 函数,依次执行:根据拓扑创建网络,配置网络名字空间,配置主机的 IP、MAC 等信息,检查是否启动 xterm,是否配置自动静态 arp 等。

net.MininetWithControlNet

继承自 Mininet 类,主要用于在使用用户态 datapath 的时候模拟一个控制器网络,即连接用户态的交换机和用户态的控制器。

模拟主机是在不同网络空间的进程
每个主机都有:

  • 虚拟的控制台(pipes to a shell)
  • 虚拟接口(half of a veth pair)
  • 父控制台,可能会有一些子进程
    主机网络接口由ifconfig/iplink.etc配置

This version supports both the kernel and user space datapaths
from the OpenFlow reference implementation (openflowswitch.org)
as well as OpenVSwitch (openvswitch.org.)
link

模式
kernel datapath mode:
switch 和 controller是root空间的进程
veth pair 一端连着KernelOpenFlow datapaths,一端连着主机命名空间。switch和controller通过回环接口连接

user datapath mode
switch 和 controller在自己网络的名称空间,有管理、接口和IP地址。host和主机之间也有veth pair

veth-pair 就是一对的虚拟设备接口,veth-pair 就是一对的虚拟设备接口,正因为有这个特性,它常常充当着一个桥梁,连接着各种虚拟网络设备,典型的例子像“两个 namespace 之间的连接”,“Bridge、OVS 之间的连接”,“Docker 容器之间的连接” 等等,以此构建出非常复杂的虚拟网络结构
link.

命名规则:

  • Host nodes are named h1-hN
  • Switch nodes are named s1-sN
  • Controller nodes are named c0-cN
  • Interfaces are named {nodename}-eth0 … {nodename}-ethN

用mininet.topo创建网络的命名和IP地址:

  • If the network topology is created using mininet.topo, then
    node numbers are unique among hosts and switches (e.g. we have
    h1…hN and SN…SN+M) and also correspond to their default IP addresses of 10.x.y.z/8 where x.y.z is the base-256 representation of N for hN. This mapping allows easy determination of a node’s IP
    address from its name, e.g. h1 -> 10.0.0.1, h257 -> 10.0.1.1.(256一进位)

  • 10.0.0.1 can often be written as 10.1 for short

实现了什么:

Currently we wrap the entire network in a ‘mininet’ object, which
constructs

  • a simulated network based on a network topology created
    using a topology object (e.g. LinearTopo) from mininet.topo or
    mininet.topolib

  • a Controller which the switches will connect to.

  • Several configuration options are provided for functions

    • automatically setting MAC addresses,
    • populating the ARP table,
    • running a set of terminals to allow direct interaction with nodes.
  • After the network is created, it can be started using start(), and a
    variety of useful tasks maybe performed, including :

    • basic connectivity
    • bandwidth tests
    • running the mininet CLI.
  • Once the network is up and running, test code can easily get access
    to host and switch objects which can then be used for arbitrary
    experiments, typically involving running a series of commands on the
    hosts.

  • After all desired tests or activities have been completed, the stop()
    method may be called to shut down the network.

node.py

实现网络节点功能的几个类
每个主机默认在一个单独的名字空间中,交换机和控制器都在 root 名字空间中

node.Node(基类)

实现上其实就是在网络名字空间中的一个shell进程,可以通过各种管道进行通信。该类是模块中其他类的根本,其它类都是直接或间接继承。节点包括名称、是否在网络名字空间、接口、端口等可能的属性。

node.Controller(控制器类)

控制器基类。默认的控制器是一个参考的实现,controller。

表示一个控制器节点。包括 IP 地址、端口等。

主要方法包括启动和停止一个控制器。

node.Host(主机类)

表示一个主机节点,目前跟 Node 类定义相同。 在主机类上执行命令可以通过 Cmd() 或者 sendCmd() 方法,前者会等待命令的输出结果,后者会直接返回,并允许使用后续的 monitor() 来进行监视跟踪。

node.Switch(交换机类)

表示一个交换机的基类。

运行在 root 名字空间。主要包括 dpid、listenport 等属性。

类的继承关系如下图:
在这里插入图片描述

  • Node: 本地的节点都是在一个或多个进程
  • Host:默认是一个shell,命令通过Cmd或sendCmd()实现,默认共享root空间
  • CPULimitedHost:被RT或CFS限制CPU带宽的主机
  • Switch
  • KernelSwitch:内核空间的交换机,仅能在 root 名字空间中执行。
  • OVSLegacyKernelSwith:内核兼容模式交换机,仅能 root 名字空间中执行。传统的 openvswitch 交换机,基于 ovs-openflowd。不推荐。(代码中没有提到)
  • UserSwitch:用户空间的交换机。a switch using the user-space switch from the OpenFlow reference implementation用户态的 openflow 参考交换机,即 ofdatapath。不推荐。
  • OVSKernelSwitch:Open vSwitch 的内核空间交换机,仅能在 root 名字空间中执行。基于 ovs-vsctl 进行操作。目前所谓的 OVSKernelSwitch 实际上就是 OVSSwitch
  • IVSSwitch: Indigo Virtual Switch.(代码里没有提到这个)
  • Controller
  • NOX:NOX 控制器。
  • RemoteController:mininet 外的控制,通过指定 IP 地址等进行连接。可以是任意与OpenFlow兼容的controller
  • OVSController: Open vSwitch的测试控制.
  • RyuController

此外还有OVSBridge:是用Open vSwitch实现的以太网桥。支持STP协议((生成树协议)逻辑上断开环路,防止二层网络的广播风暴的产生)

/usr/bin/mn

mn是Mininet执行的解释器,负责解析参数,定义了MininetRunner类用来构建、配置并运行整个Mininet平台。
用 sudo mn -h可以看到这些选项

TOPODEF = 'minimal'
TOPOS = { 'minimal': MinimalTopo,
          'linear': LinearTopo,
          'reversed': SingleSwitchReversedTopo,
          'single': SingleSwitchTopo,
          'tree': TreeTopo,
          'torus': TorusTopo }

SWITCHDEF = 'default'
SWITCHES = { 'user': UserSwitch,
             'ovs': OVSSwitch,
             'ovsbr' : OVSBridge,
             # Keep ovsk for compatibility with 2.0
             'ovsk': OVSSwitch,
             'ivs': IVSSwitch,
             'lxbr': LinuxBridge,
             'default': OVSSwitch }

HOSTDEF = 'proc'
HOSTS = { 'proc': Host,
          'rt': specialClass( CPULimitedHost, defaults=dict( sched='rt' ) ),
          'cfs': specialClass( CPULimitedHost, defaults=dict( sched='cfs' ) ) }

CONTROLLERDEF = 'default'
CONTROLLERS = { 'ref': Controller,
                'ovsc': OVSController,
                'nox': NOX,
                'remote': RemoteController,
                'ryu': Ryu,
                'default': DefaultController,  # Note: overridden below
                'none': NullController }

LINKDEF = 'default'
LINKS = { 'default': Link,  # Note: overridden below
          'tc': TCLink,
          'tcu': TCULink,
          'ovs': OVSLink }

MininetRunner类,为整个测试创建基础平台,主要执行三大步骤:
1.parseArgs() :解析参数
2.Setup(): 调用 mininet.net.init()
3. Begin(): 执行执行给定参数,包括创建拓扑、地址分配等;调用 mininet.net.Mininet()创建网络平台 mn;调用 mininet.cli.CLI()创建 CLI 对象;调用 mn.start()启动网络;执行指定的测试命令,默认为 cli,即调用 CLI(mn)进入交互环境;执行结束后调用 mn.stop()退出
mnexec 文件 完成一些 python 代码执行起来比较慢或者难以实现的功能,包括关闭文件描述、使用 setsid 从控制 tty 剥离、在网络空间运行、打印 pid 等。
在这里插入图片描述

其它

custom/ 目录

可以放一些用户自定义的 Python 文件,比如自定义的拓扑类等。

test/ 目录

是一些测试的例子。

util/

目录下是一些辅助文件,包括安装脚本、文档辅助生成等,重要的文件包括:

  • m bash 脚本提供用户直接在 host 执行命令的接口。例如
    m host cmd args…
  • m 通过调用 mnexec 来实现对 Mininet 中的元素执行相应的命令。
    mnexec C 程序,通过参数绑定到某个名字空间,并执行给定的命令。

运行相关

  • bin/mn 主运行文件,安装后执行 mn 即调用的本程序,是 Python 程序。
  • mnexec.c 执行一些快速命令,比如关闭文件描述符等,是 C 程序,编译后生成二进制文件 mnexec 被 Python 库调用。

clean 模块

提供对执行 Mininet 后的清理工作,主要包括 cleanup() 函数,该函数实际上调用了 sh() 函数。

cleanup() 函数主要包括清除僵尸进程,临时文件,X11 tunnel,额外的内核态 datapath,ovs datapath,ip link 等。

实现过程主要是通过调用 subprocess 模块(主要用于执行外部命令和程序)中的 Popen 类中方法来对进程发送指令。

操作总结

cmd常用命令总结
  • help 默认列出所有命令文档,后面加命令名将介绍该命令用法
  • dump 打印节点信息
  • gterm 给定节点上开启 gnome-terminal。注:可能导致 Mininet 崩溃
  • xterm 给定节点上开启 xterm
  • intfs 列出所有的网络接口
  • iperf 两个节点之间进行简单的 iperf TCP测试
  • iperfudp 两个节点之间用指定带宽 udp 进行测试
  • net 显示网络链接情况
  • noecho 运行交互式窗口,关闭回应(echoing)
  • pingpair 在前两个主机之间互 ping 测试
  • source 从外部文件中读入命令
  • dpctl 在所有交换机上用 dptcl 执行相关命令,本地为 tcp 127.0.0.1:6634
  • link 禁用或启用两个节点之间的链路
  • nodes 列出所有的节点信息
  • pingall 所有 host 节点之间互 ping
  • py 执行 Python 表达式
  • sh 运行外部 shell 命令
  • quit/exit 退出
link

在 Mininet cli 中,使用 link 命令,禁用或启用某条链路,格式为link node1 node2 up/down

友好的Mac地址

–mac

namespace

主机节点有用独立的名字空间(namespace),而控制节点跟交换节点都在根名字空间(root namespace)中。

如果想要让所有节点拥有各自的名字空间,需要添加 --innamespace 参数,即启动方式为 sudo mn --innamespace
注意:为了方便测试,在默认情况下,所有节点使用同一进程空间,因此,在 h2 跟 h3 或者 s1 上使用 ps 查看进程得到的结果是一致的,都是根名字空间中的进程信息。

启用参数总结
  • -h, --help 打印帮助信息
  • –switch=SWITCH 交换机类型,包括 [kernel user ovsk]
  • –host=HOST 模拟主机类型,包括 [process]
  • –controller=CONTROLLER 控制器类型,包括 [nox_dump none ref remote nox_pysw]
  • –topo=TOPO,arg1,arg2,…argN 指定自带拓扑,包括 [tree reversed single linear minimal]
  • -c, --clean清理环境
  • –custom=CUSTOM 使用自定义拓扑和节点参数
  • –test=TEST 测试命令,包括 [cli build pingall pingpair iperf all iperfudp none]
  • -x, --xterms 在每个节点上打开 xterm
  • –mac 让MAC 地址跟 DP ID 相同
  • –arp 配置所有 ARP 项
  • -v VERBOSITY, --verbosity=VERBOSITY [info warning critical error debug output] 输出日志级别
  • –ip=IP 远端控制器的IP地址
  • –port=PORT 远端控制器监听端口
  • –innamespace 在独立的名字空间内
  • –listenport=LISTENPORT 被动监听的起始端口
  • –nolistenport 不使用被动监听端口
  • –pre=PRE 测试前运行的 CLI 脚本
  • –post=POST 测试后运行的 CLI 脚本
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值