SDN学习笔记

记录一点学习过程。

0x00 Open vSwitch

网桥ovs-vsctl 基本命令:

命令 含义
init 初始化数据库(前提数据分组为空)
show 打印数据库信息摘要
add-br BRIDGE 添加新的网桥
del-br BRIDGE 删除网桥
list-br 打印网桥摘要信息
list-ports BRIDGE 打印网桥中所有port摘要信息
add-port BRIDGE PORT 向网桥中添加端口
del-port [BRIDGE] PORT 删除网桥上的端口
get-controller BRIDGE 获取网桥的控制器信息
del-controller BRIDGE 删除网桥的控制器信息
set-controller BRIDGE TARGET 向网桥添加控制器

流表 ovs-ofctl 基本命令:

ovs-ofctl是Open vSwitch提供的命令行工具。在没有配置OpenFlow控制器的模式下,用户可以使用ovs-ofctl命令通过OpenFlow协议连接Open vSwitch来创建、修改或删除Open vSwitch中的流表项,并对Open vSwitch的运行状况进行动态监控。

命令 含义
show SWITCH 输出OpenFlow信息
dump-ports SWITCH PORT 输出端口统计信息
dump-ports-desc SWITCH 输出端口描述信息
dump-flows SWITCH 输出交换机中所有的流表项
dump-flows SWITCH FLOW 输出交换机中匹配的流表项
add-flow SWITCH FLOW 向交换机中添加流表项
add-flows SWITCH FILE 在文件中向交换机添加流表项
mod-flows SWITCH FLOW 修改交换机流表项
del-flows SWITCH FLOW 删除交换机流表项

对于add-flow、add-flows和mod-flows这3个命令,还需要指定要执行的动作actions=[target],[target]…,一个流规则中可能有多个动作,按照指定的先后顺序执行。

常见流表操作如下:

操作 说明
output:port 输出数据包到指定端口,port是指端口的 OpenFlow端口编号
mod_vlan_vid 修改数据包中的VLANtag
strip_vlan 移除数据包中的VLANtag
mod_dl_src/mod_dl_dest 修改源或者目标的MAC地址信息
mod_nw_src/mod_nw_dst 修改源或者目标的IPv4地址信息
resubmit:port 替换流表的in_port字段,并重新进行匹配
load:value->dst[start…end] 写数据到指定字段

支持OpenFlow协议的交换机应该包括一个或多个流表,流表中的条目包含:数据包头的信息、匹配成功后要执行的指令和统计信息。

当数据包进入OVS后,会将数据包和流表中的流表项进行匹配,如果发现了匹配的流表项,则执行该流表项中的指令集。相反,如果数据包在流表中没有发现任何匹配,OVS会通过控制通道把数据包发到OpenFlow控制器中。

在OVS中,流表项作为ovs-ofctl的参数,采用如下的格式:字段=值,如果有多个字段,可以用逗号或空格分开,一些常用的字段列举如下表所示。

字段名称 说明
in_port=port 传递数据包端口的OpenFlow端口编号
dl_vlan=vlan 数据包中的VLANtag值,范围是0-4095,0xffff代表不含VLANtag
dl_src= dl_dst= 匹配源或者目标的MAC地址。广播地址01:00:00:00:00:00/01:00:00:00:00:00,单播地址:00:00:00:00:00:00/01:00:00:00:00:00
dl_type=ethertype 匹配以太网协议类型, 0x0800代表IPv4,0x086dd代表IPv6,0x0806代表ARP
nw_src=ip[/netmask] nw_dst=ip[/netmask] 当dl_type=0x0800时,匹配IPv4地址,可以使用IPv4地址或域名
nw_proto=proto 和dl_type字段协同使用。匹配IP编号或者IPv6编号
table=number 指定要使用的流表编号,范围0-254,默认值为0。通过使用流表编号,可以创建或者修改多个Table中的Flow
reg=value[/mask] 交换机中寄存器的值。当一个数据包进入交换机时,所有的寄存器都被清零,用户可以通过Action指令来修改寄存器中的值

示例:

1
2
3
4
5
//添加一条流表项,设置流表项生命周期为1000s,优先级为17,入端口为3,动作是output:2。
# ovs-ofctl add-flow br0 idle_timeout=1000,priority=17,in_port=3,actions=output:2
//删除入端口为3的的流表项
# ovs-ofctl del-flows br0 in_port=3
# ovs-ofctl dump-flows br0

端口映射:

端口镜像(port Mirroring)是把交换机一个或多个端口(VLAN)的数据镜像到一个或多个端口的方法。在一些交换机中,我们可以通过对交换机的配置来实现将某个端口上的数据包,拷贝一份到另外一个端口上,这个过程就是端口镜像

1
2
3
4
//获得端口信息
# ovs-vsctl list port |more
//eth1端口接收的,eth2端口发出的=>eth3,均用uuid
# ovs-vsctl -- set bridge br-sw mirrors=@m -- --id=@m create mirror name=mymirror select-dst-port=2e9edacd-f52a-4855-83b8-3839891b546c select-src-port=dff77057-e7a8-43ff-95f7-8c6e3308fd87 output-port=679aefab-88ba-44da-a1f7-0324a5790759

QoS:

首先,根据预先设置的匹配规则来对报文进行分类,如果是没有规定流量特性的报文,就直接继续发送,并不需要经过令牌桶的处理;如果是需要进行流量控制的报文,则会进入令牌桶中进行处理。如果令牌桶中有足够的令牌可以用来发送报文,则允许报文通过,报文可以被继续发送下去。如果令牌桶中的令牌不满足报文的发送条件,则报文被丢弃。这样,就可以对某类报文的流量进行控制。

ovs-vsctl set interface vif1.0 ingress_policing_rate=10000
ovs-vsctl set interface vif1.0 ingress_policing_burst=8000

上面两行命令,把虚拟端口vif1.0的最大接收速率设置为10000kbps,桶大小设置为8000kb,突发接收速率为(10000+8000)kbps

接口和端口是两个比较容易混淆的概念。一般是物理上的概念,主机后面的就是接口,有KVM接口、以太网接口、同步串口等,也可以是逻辑上的概念比如VLAN的interface。端口是TCP/UDP协议的一个概念,用来区分某种应用,例如telnet的端口是23、而www的端口是80等。Open vSwitch既可以针对网络接口,也可以针对端口设置QoS

测试两个主机之间的吞吐量:

1
2
3
4
5
6
7
8
9
10
//主机1
# ps -ef|grep ovs
# ovs-vsctl add-br br0
# ovs-vsctl add-port br0 eth0
//云主机将IP赋给br0
# ifconfig eth0 0 up
# ifconfig br0 30.0.1.8/24 up
# ifconfig
//启动服务
#netserver -p 9991
1
2
//主机2
# netperf -t UDP_STREAM -H 30.0.1.8 -p 9991
1
2
3
4
//主机1 设置QoS参数
# ovs-vsctl set interface eth0 ingress_policing_rate=100000
# ovs-vsctl set interface eth0 ingress_policing_burst=50000
//在主机2进行测试

0x01 Mininet

  • 网络构建参数

1.网络拓扑:–topo

–topo用于指定网络拓扑,Mininet支持创建的网络拓扑为:minimal、single、linear和tree。

(1) minimal:创建一个交换机和两个主机相连的简单拓扑。默认无–topo参数的情况下就是这样。其内部实现就是调用了single,2对应的函数。

(2) single,n:设置一个交换机和n个主机相连的拓扑。

(3) linear,n:创建n个交换机,每个交换机只连接一个主机,并且所有交换机成线型排列。

(4) tree,depth=n,fanout=m:创建深度为n,每层树枝为m的树型拓扑。因此形成的拓扑的交换机个数为(mn-1)/(m-1),主机个数为mn。

–custom:在上述已有拓扑的基础上,Mininet支持自定义的拓扑,使用一个简单的Python API即可。–custom需和–topo一起使用,如mn --custom file.py --topo mytopo。

2.设置交换机:–switch

用于选择交换机的种类,主要包括user、ovsbr、ovsk、ivs和lxbr等,无–switch参数的时候,默认就是ovsk即OpenvSwitch交换机。

3.设置控制器:–controller

定义要使用的控制器,主要包括:nox、ryu、ovsc和虚拟机之外的远端控制器。如果没有指定则使用Mininet中默认的控制器。

4.设置MAC地址:–mac

设置MAC地址的作用是增强设备MAC地址的易读性,即将交换机和主机的MAC地址设置为一个较小的、唯一的、易读的ID,以便在后续工作中减少对设备识别的难度。

  • 内部交互命令

参数 作用
-h, —help show this help message and exit
–switch=SWITCH [kernel user ovsk]
–host=HOST [process]
–controller=CONTROLLER [nox_dump none ref remote nox_pysw]
–topo=TOPO [tree reversed single linear minimal],arg1,arg2,…argN
-c, —clean clean and exit
–custom=CUSTOM read custom topo and node params from .py file
–test=TEST [cli build pingall pingpair iperf all iperfudp none]
-x, —xterms spawn xterms for each node
–mac set MACs equal to DPIDs
–arp set all-pairs ARP entries
-v VERBOSITY, —verbosity=VERBOSITY [info warning critical error debug output]
–ip=IP [ip address as a dotted decimal string for aremote controller]
–port=PORT [port integer for a listening remote controller]
–innamespace sw and ctrl in namespace?
–listenport=LISTENPORT [base port for passive switch listening controller]
–nolistenport don’t use passive listening port
–pre=PRE [CLI script to run before tests]
–post=POST [CLI script to run after tests]

Mininet 常用命令

命令 作用
help 默认列出所有命令文档,后面加命令名将介绍该命令用法 dump打印节点信息
gterm 给定节点上开启gnome-terminal 注:可能导致mn崩溃
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 所有主机节点之间互Ping
py 执行Python表达式
sh 运行外部shell命令
quit/exit 退出

简单python脚本示例1:

1
2
3
4
5
6
7
from mininet.net import Mininet
from mininet.topo import LinearTopo #此处为linear拓扑
Linear1 = LinearTopo(k=5) #五个交换机,分别下挂一个主机
net = Mininet(topo=Linear1)
net.start()
net.pingAll()
net.stop()

简单python脚本示例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from mininet.net import Mininet
net = Mininet()
# Creating nodes in the network.
c0 = net.addController()
h0 = net.addHost('h0')
s0 = net.addSwitch('s0')
h1 = net.addHost('h1')
# Creating links between nodes in network
net.addLink(h0, s0)
net.addLink(h1, s0)
# Configuration of IP addresses in interfaces
h0.setIP('192.168.1.1', 24)
h1.setIP('192.168.1.2', 24)
net.start()
net.pingAll()
net.stop()

简单python脚本示例3:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from mininet.net import Mininet
from mininet.node import CPULimitedHost
from mininet.link import TCLink
net = Mininet(host=CPULimitedHost, link=TCLink)
c0 = net.addController()
s0 = net.addSwitch('s0')
h0 = net.addHost('h0')
h1 = net.addHost('h1', cpu=0.5)
h2 = net.addHost('h1', cpu=0.5)
net.addLink(s0, h0, bw=10, delay='5ms',
max_queue_size=1000, loss=10, use_htb=True)
net.addLink(s0, h1)
net.addLink(s0, h2)
net.start()
net.pingAll()
net.stop()
  • 交互式界面创建主机、交换机

    1
    2
    3
    4
    > py net.addHost(‘h3’)
    > py net.addLink(s1,net.get(‘h3’))
    > py s1.attach(‘s1-eth3’)
    > py s1.attach(‘s1-eth3’)

    测试网络

    1
    2
    3
    > px from mininet.util import dumpNodeConnections
    > py dumpNodeConnections(net.hosts)
    > py net.pingAll()

    外部运行参数

    -c:清除配置信息

    -h:帮助

0x02 OpenDaylight

理论知识:

YANG:一种建模语言,有固定模板,为了快速进行网络配置

MD-SAL:模型驱动-业务抽象层,提供统一的北向接口

DataStore:树形存储,内存数据库,包括config(配置信息)、operational(运行状态信息)两种数据,通过JAVA API读写。

RESTCONF:北向接口,监听端口8181

实践部分:(需要JAVA环境)

需要Java环境

登录$ ./client -u karaf

列出feature opendaylight-user@root> feature:list

列出界面 opendaylight-user@root> feature:list -i |grep dlux

0x03 Ryu