关于
Mininet是一个用于构建虚拟网络环境的开源软件。它允许用户在单个主机上创建一个全功能的网络拓扑,并模拟网络设备(如交换机、路由器和主机)之间的通信。
Mininet基于Linux命名空间和虚拟化技术,可以在一个主机上创建多个虚拟网络节点,并通过虚拟网络设备将这些节点连接起来。用户可以使用Python编写脚本来定义和配置网络拓扑,并使用Mininet提供的命令行界面来管理和控制虚拟网络。
Mininet的主要用途包括网络研究、网络教育和网络应用开发。通过使用Mininet,用户可以在一个简单的环境中快速搭建和测试各种网络场景,而无需真实的硬件设备。
Mininet支持OpenFlow协议,可以与OpenFlow控制器(如POX、RYU等)配合使用,实现对虚拟网络的控制和管理。此外,Mininet还提供了一些实用工具和函数库,用于网络拓扑的创建、节点的配置和网络性能的测量。
安装
官方提供了三种安装方式:
MininetVM, 通过一个安装一个内置了Mininet及相关组件的Linux发行版虚拟机
Native Installation from Source, 利用源代码安装
Installation from Packages, 在Debian11+或Ubuntu发行版(Ubuntu是Debian的一个常见分支)上使用apt包管理工具下载.
官方的不带桌面环境, 因为github限制了release文件最大2G, 不适合发布大文件.
在已有的Ubuntu最近的发行版上
1 2 3 4 5 apt-get update apt-get install mininet ... mn --version
测试
1 2 service openvswitch-switch start mn --switch ovsbr --test pingall
这个只安装了mininet, 下载用来演示的脚本和额外软件还是要用git = =.
1 2 3 4 5 6 7 apt-get install git git config --global user.name "yourname" git config --global user.email "xx@xx.com" git config --global --list git clone https://www.github.com/mininet/mininet.git mininet/util/install.sh -fw
如果你https connection time out 的话, 一般是网络的问题, 可以配置 ssh 下载
1 ssh-keygen -t ed25519 -C "your_email@example.com"
然后将生成在 ~/.ssh 下的公钥添加到github上, 这个ed25519 是一个基于AES的 数字签名算法,安全性在 RSA 2048 与 RSA 4096 之间,性能却极高. 用传统的RSA也行
直接使用虚拟机
可以在GitHub上下载最新的release https://github.com/mininet/mininet/releases/tag/2.3.0 , 学校给的.ova虚拟机镜像太tm的旧了,看了一下版本–Linux version 3.13.0-24-generic (buildd@batsu) (gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1) ) #47-Ubuntu SMP Fri May 2 23:30:00 UTC 2014 – 内核版本号3.13.0-24-generic应用于2014年4月17日发布的 Ubuntu 14.04 LTS,官方推荐使用最新的 Ubuntu 20.04.1 VM image.
解压完得到两个文件, .ovf 虚拟机配置文件 和 .vmdk 虚拟磁盘文件, 用虚拟机软件打开配置文件就行了。
可以改下root密码登录
1 2 3 4 5 6 sudo passwd root su - root service openvswitch-switch start mn --switch ovsbr --test pingall
一切正常的话:
SDN实验
学校实验课的内容, 按图索骥.
实验一 mininet可视化创建网络拓扑
用可视化工具 miniedit 创建一个网络拓扑,进行相应配置后,保存为 python 脚本,运行 python 脚本重现拓扑;
命令行创建拓扑:
i. 最小的网络拓扑,一个交换机下挂两个主机。
ii. 每个交换机连接一个主机,交换机间相连接。本例:4 个主机,4 个交换机。
iii. 每个主机都连接到同一个交换机上。本例:3 个主机,一个交换机。
交互式界面创建主机、交换机等
对节点间进行 ping 测试
1 python mininet/examples/miniedit.py
不出意外的话, 会出现意外, _tkinter.TclError: no display name and no $DISPLAY environment variable
这是因为没安装GUI, 官方给的镜像就是不带桌面的, 所以python的tkinter模块启动失败。既然实验要求安装使用GUI工具, 给它安个桌面。
Ubuntu22 换源与磁盘扩容
先换个软件源, 用国内镜像源,默认国外的太慢, 顺便把VM内存参数改大点, 这里用的清华的镜像源。
磁盘分区扩容, 这里把VM磁盘空间设置扩展成20G, 之后还要在系统中重新分区与创建FS与挂载
1 2 3 4 5 6 7 8 9 df -Thapt install cloud-guest-utils growpart /dev/sda 2 growpart /dev/sda 5 partprobe resize2fs /dev/sda5 df -h
如果没挂梯子, 建议换下源.
1 2 cp /etc/apt/sources.list /etc/apt/sources.list.backupvi /etc/apt/sources.list
删除原本的内容,这样粘贴, vim 在insert模式, 不要带中文的内容, 不然粘贴不了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse deb http://security.ubuntu.com/ubuntu/ jammy-security main restricted universe multiverse
这样执行会提示 Certification vertification failed 证书验证失败, 解决方法:
重新安装两个证书相关组件
1 apt-get reinstall apt-transport-https ca-certificates
然后执行apt update 就没问题了, 接下来正式安装桌面环境。
安装桌面环境
1 apt update && apt upgrade
下载登录管理器, 原本默认的是GDM3, 下载SDDM,SLiM或LightDM
1 2 3 apt install lightdm apt install tasksel tasksel
tasksel是Debian下提供的一个简单的可以快速安装桌面环境和web服务的工具
方向键移动, 空格选中/取消, 回车确认, tab 移动
如果出现 tasksel: apt-get failed(100), 是firefox snap 安装出现问题
1 2 snap install firefox apt --fix-broken install
如果出现 340.439687 proc: bad value for 'hideid ’
1 apt-get install --reinstall xserver-xorg
切换登录管理器
1 2 dpkg-reconfigure [lightdm/slim/GDM3] service [lightdm/slim/GDM3] restart
打开终端 alt+f2, 输入uxterm 打开终端, 不知道为什么 gnome-terminal 打不开(之后把系统环境改成中文又能打开了, ctrl alt t)
这时候再执行python mininet/examples/miniedit.py
如果出现 $DIPLAY 变量错误是因为还没设置tkinter的输出目标, 将默认的X11显示器设置为输出对象.
1 2 export DISPLAY=:0 sudo python2.7 mininet/examples/miniedit.py
virtualenv 使用python虚拟环境
virtualenv 是一个用于创建隔离的 Python 环境的工具。它可以帮助你在不同的项目中使用不同版本的 Python 和依赖库,从而避免冲突。
1 2 3 4 5 6 7 8 9 10 11 12 13 apt-get install virtualenv virtualenv --python=/usr/bin/python2.7 <path/to/new/virtualenv> source <path/to/new/virtualenv>/bin/activatedeactive rm -rf <path/to/virtualenv>
解决 右上角网络图标不显示的问题
在网上找了一圈, 大部分答案都是让你重装NetworkManager或者让你修改NetworkManager的配置文件, 结果完全没用. 正确的做法是切换Netplan中的renderer, 原本是networkd, 一个系统级别的网络配置和管理工具, 要配置成NetworkManager才能显示在GUI中.https://askubuntu.com/a/1178044/1743772
1 vi /etc/netplan/xxx.yaml
实验
s1
1 sudo python2.7 mininet/examples/miniedit.py
s2
创建网络拓扑
1 2 3 sudo mn --topo single,2 sudo mn --topo linear,4 sudo mn --topo single,3
s3
s4
实验二 python 脚本构建网络拓扑
mininet api
mininet 的 python api
https://mininet.org/api/annotated.html
mn 部分交互式命令
help
查看帮助
help <arg>
查看对应命令帮助
net
显示网络拓扑
nodes
显示所有节点
dump
显示节点配置
iperf
网络性能测试
py
执行python表达式
sh
执行shell命令
exit/quit
退出
dpctl
交换机交互
节点操作
h1 ping h2
ping
h1 ifconfig
网卡信息
gterm/xterm <node>
打开xterm终端
实验
编写 Python 脚本,定义如下拓扑:
i. topo linear,4
ii. topo single,3
iii. topo tree,depth=2,fanout=2
iv. 1 个交换机,2 个主机,并且赋予主机 IP 地址。
编写 Python 脚本,对网络性能进行限制。观察下面给出的脚本文件,addHost()语法可以对主机 cpu 进行设置,以百分数的形式;addLink()语法可以设置带宽 bw、延迟 delay、最大队列的大小 max_queue_size、损耗率 loss。
s1
1 2 3 4 5 6 7 8 9 10 11 12 13 from mininet.net import Mininetfrom mininet.topo import LinearTopofrom mininet.cli import CLIdef create_linear_topology (): topo = LinearTopo(k=4 ) net = Mininet(topo) net.start() CLI(net) net.stop() if __name__ == "__main__" : create_linear_topology()
四个交换机线性连接, 并各自连接一台主机.
1 2 3 4 5 6 7 8 9 10 11 12 13 from mininet.net import Mininetfrom mininet.topo import SingleSwitchTopofrom mininet.cli import CLIdef create_single_topology (): topo = SingleSwitchTopo(k=3 ) net = Mininet(topo) net.start() CLI(net) net.stop() if __name__ == "__main__" : create_single_topology()
一台交换机连接三台主机
1 2 3 4 5 6 7 8 9 10 11 12 13 from mininet.net import Mininetfrom mininet.topolib import TreeTopofrom mininet.cli import CLIdef create_tree_topology (): topo = TreeTopo(depth=2 , fanout=2 ) net = Mininet(topo) net.start() CLI(net) net.stop() if __name__ == "__main__" : create_tree_topology()
树形拓扑, 出度为2.
s2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 from mininet.net import Mininetfrom mininet.node import CPULimitedHostfrom mininet.node import TCIntffrom mininet.link import TCLinkfrom mininet.cli import CLIdef create_network_topology (): net = Mininet() h1 = net.addHost('h1' , cls=CPULimitedHost, cpu=0.2 ) h2 = net.addHost('h2' , cls=CPULimitedHost, cpu=0.2 ) s1 = net.addSwitch('s1' , cls=OVSSwitch, failMode='standalone' ) net.addLink(h1, s1, bw=10 , delay='10ms' , max_queue_size=100 , loss=10 ) net.addLink(h2, s1, bw=10 , delay='10ms' , max_queue_size=100 , loss=10 ) net.start() CLI(net) net.stop() if __name__ == "__main__" : create_network_topology()
会报错 cgroups not mounted on /sys/fs/cgrops, cgroups(Control Groups)是Linux内核中的一个功能,用于对进程组进行资源管理和限制.
参看原码会发现执行了grep cgrop /proc/mount 并做判断是否装载了cgroups文件系统
这里显示的是 cgroup v2, 目前mininet并没有提供对 cgroup v2的支持, 而在Ubuntu 21.10以上和众多发行版中已开始默认使用 cgroup v2https://github.com/opencontainers/runc/blob/main/docs/cgroup-v2.md#cgroup-v2 , 所以需要切换cgroups版本.
在GRUB_CMDLINE_LINUX_DEFAULT 或 GRUB_CMDLINE_LINUX中填入
systemd.unified_cgroup_hierarchy=no, 表示允许使用cgroup-v1
1 2 3 4 sudo update-grub vi /boot/grub/grub.cfg
重启生效
1 grep cgroup /proc/mounts
cgroup-v1 和 v2 并存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 from mininet.net import Mininetfrom mininet.link import TCLinkfrom mininet.cli import CLIfrom mininet.node import *def create_network_topology (): net = Mininet() s1 = net.addSwitch('s1' , cls=OVSSwitch, failMode='standalone' ) h1 = net.addHost('h1' , cls=CPULimitedHost, cpu=0.2 , cores=1 ) h2 = net.addHost('h2' , cls=CPULimitedHost, cpu=0.2 , cores=1 ) net.addLink(h1, s1, cls=TCLink, bw=10 , delay='10ms' , max_queue_size=100 , loss=20 ) net.addLink(h2, s1, cls=TCLink, bw=10 , delay='10ms' , max_queue_size=100 , loss=20 ) net.start() intf1 = s1.intf('s1-eth1' ) intf1.setIP('10.0.0.11/24' ) intf2 = s1.intf('s1-eth2' ) intf2.setIP('10.0.0.22/24' ) intf_h1 = h1.intf('h1-eth0' ) intf_h1.setIP('10.0.0.1/24' ) intf_h2 = h2.intf('h2-eth0' ) intf_h2.setIP('10.0.0.2/24' ) CLI(net) net.stop() if __name__ == "__main__" : create_network_topology()
限制了带宽10M, 对丢包率每条链路20%, h1到h2 应该是36%, 发了20个包丢一半.
实验三 Open vSwitch应用实践
Open vSwitch
Open vSwitch(下面简称为 OVS)是由 Nicira Networks 主导的,运行在虚拟化平台(例如 KVM,Xen)上的虚拟交换机。在虚拟化平台上,OVS 可以为动态变化的端点提供 2 层交换功能,很好的控制虚拟网络中的访问策略、网络隔离、流量监控等等。
OVS 遵循Apache 2.0 许可证, 能同时支持多种标准的管理接口和协议。OVS 也提供了对OpenFlow 协议的支持,用户可以使用任何支持 OpenFlow 协议的控制器对 OVS 进行远程管理控制。
floodlight安装
安装配置jdk8
下载安装 Oracle-jdk8
1 2 3 4 5 6 7 8 9 10 tar -xzf /xxx/jdk-8u391-linux-x64.tar.gz -C /home/dev vi /etc/profile.d/java.sh export JAVA_HOME=/home/dev/jdk-8u391-linux-x64export PATH=
JAVA_HOME/bin:
PATHsource /etc/profile.d/java.shjava -version
编译安装
1 2 3 4 5 6 7 sudo apt-get install ant build-essential maven git clone git@github.com:floodlight/floodlight.git -b v1.2 cd floodlightant java -jar target/floodlight.jar
实验
交换机创建和端口 p0 的配置
创建一个新的 OVS 交换机:
$ ovs-vsctl add-br [名称]
如:sudo ovs-vsctl add-br ovs-switch
创建一端口 p0,设置端口 p0 的 OpenFlow 端口编号为 100,如果在创建端口的时候没
有指定 OpenFlow 端口编号,OVS 会自动生成一个。
$ sudo ovs-vsctl add-port ovs-switch p0
set Interface p0 of port_request=100
设置网络接口设备的类型为“internal”。对于 internal 类型的的网络接口,OVS 会同时
在 Linux 系统中创建一个可以用来收发数据的模拟网络设备。我们可以为这个网络设备
配置 IP 地址、进行数据监听等等。查看结果。
$ sudo ovs-vsctl set Interface p0 type=internal
$ sudo ethtool -i p0
虚拟网络空间的配置
为了避免网络接口上的地址和本机已有网络地址冲突,我们可以创建一个虚拟网络空间
ns0,把 p0 接口移入网络空间 ns0,并配置 IP 地址为 192.168.1.100。
$ sudo ip netns add ns0
$ sudo ip link set p0 netns ns0
$ sudo ip netns exec ns0 ip addr add 192.168.1.100/24 dev p0
$sudo ip netns exec ns0 ifconfig p0 promisc up
查看 OVS 交换机
通过 sudo ovs-vsctl show 命令查看 OVS 交换机的信息。
使用 ovs-ofctl 创建并测试 OpenFlow 命令
查看 Open vSwitch 中的端口信息。从输出结果中,可以获得交换机对应的 datapath ID
(dpid),以及每个端口的 OpenFlow 端口编号,端口名称,当前状态。
①查看交换机中的所有 Table: $ sudo ovs-ofctl dump-tables ovs-switch
②查看交换机中的所有流表项:$sudo ovs-ofctl dump-flows ovs-switch
③查看交换机上的端口信息:$ sudo ovs-ofctl show ovs-switch
④两个端口相互测试:$ sudo ip netns exec ns0 ping 192.168.1.101
任务与要求通过创建拓扑连接 floodlight 控制,通过控制器的图像化界面,编辑交换机流
表规则来控制数据转发。自主完成以下任务。
在虚拟机环境下,打开终端运行 Floodlight;提示:
cd floodlight // 进入 floodlight 文件夹
java -jar target/floodlight.jar //运行 floodlight 控制器
创建 1 个交换机连接 4 台主机的拓扑,并连接控制器。提示:
sudo mn --topo single,4 --controller remote,ip=127.0.0.1,port=6653
打开 floodlight 图像化界面并查看网页中的 topo。提示:
localhost:8080/ui/pages/index.html //在虚拟机的浏览器中访问控制器的 web UI
在 mininet 中执行 pingall 命令,在网页中查看交换机 s1 的流表。
在网页中给交换机中添加一条流表项,使得 h1 不能访问其他所有主机。并在
mininet 中进行 pingall 测试。注意:表的序号是从 0 开始的。
删除之前添加的流表项,在 mininet 中进行 pingall 测试。
s1
交换机创建和端口 eth0 的配置
1 2 3 4 5 6 7 8 ovs-vsctl add-br ovs-switch sudo ovs-vsctl add-port ovs-switch eth0 -- set Interface eth0 ofport_request=100 ovs-vsctl set Interface eth0 type =internal ethtool -i eth0
s2
虚拟网络空间的配置
1 2 3 4 sudo ip netns add ns0 sudo ip link set eth0 netns ns0 sudo ip netns exec ns0 ip addr add 192.168.128.100/24 dev eth0 sudo ip netns exec ns0 ifconfig eth0 promisc up
s3
查看 OVS 交换机
s4
使用 ovs-ofctl 创建并测试 OpenFlow 命令
1 2 3 4 5 6 7 8 sudo ovs-ofctl dump-tables ovs-switch sudo ovs-ofctl dump-tables ovs-switch sudo ovs-ofctl dump-tables ovs-switch sudo ip netns exec ns0 ping 192.168.128.1
进阶
j1
j2
j3
一开始会错误
发现OF协议版本不兼容
floodlight 只支持到1.4, ovs用的是1.6
指定OFv1.0版本
1 sudo mn --topo single,5 --mac --controller remote --switch ovs,protocols=OpenFlow10
进入web面板, http://localhost:8080/ui/index.html
j4
使用floodlight 控制器 北向REST API添加静态流表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import requestsimport jsoncontroller_ip = '127.0.0.1' switch_dpid = '00:00:00:00:00:00:00:01' h1_mac_address = '00:00:00:00:00:01' blocking_port = '1' url = f'http://{controller_ip} :8080/wm/staticflowpusher/json' headers = { 'Content-Type' : 'application/json' } data = { 'switch' : switch_dpid, 'name' : 'block-h1' , 'priority' : '100' , 'in_port' : blocking_port, 'eth-src' : h1_mac_address, 'active' : 'true' , 'actions' : 'drop' } response = requests.post(url, headers=headers, data=json.dumps(data)) if response.status_code == 200 : print ('流表项成功添加,h1 发出的数据包将被阻断.' ) else : print ('无法添加流表项.' ) print (response.text)
1 curl -X DELETE http://127.0.0.1:8080/wm/staticflowpusher/json -d '{"name":"block-h1", "switch":"00:00:00:00:00:00:00:01"}'
h1通信恢复
实验四 OpenFlow协议分析
实验
可视化界面搭建网络拓扑
配置 PC 的 IP 信息
Wireshark 抓包并分析
进阶技能
以前面的基本技能训练为基础, 通过配置远程控制器要求完成一下任务。
对基础技能创建的 lab_3.py 进行修改,将控制器设置为“RemoteController”,
端口号设置为“6653”;
启动抓包软件 wireshark;
启动 RYU 控制器;
运行 lab_3.py;
在 wireshark 中查看控制器与交换机建立连接的过程,画出通信流程图,并对通
信过程中的具体消息进行分析;
在终端查看交换机 s1 的流表,对两台主机相互 ping 测试, 在终端查看交换机
s1 的流表变化并分析;
s1
可视化界面搭建网络拓扑
s2
配置 PC 的 IP 信息
s3
wireshark过滤对应版本的OF协议数据报
可以看到控制器和交换机之间的通信流程:
一开始控制器发送OFPT_HELLO报文, 这是OpenFlow协议的起始消息,用于建立控制器和交换机之间的连接。控制器发送此消息以确认其支持的OpenFlow版本,并与交换机进行握手。
然后OFPT_FEATURES_REQUEST, 控制器向交换机发送的请求消息,用于获取交换机的功能信息。控制器通过此消息了解交换机的特性和能力.
OFPT_FLOW_MOD, 控制器向交换机发送的消息,用于配置交换机的流表项(Flow Entry)。
OFPT_PORT_STATUTS, 交换机向控制器发送的消息,用于通知控制器有关交换机端口状态的变化。
OFPT_FEATURES_REPLY, 这是交换机向控制器发送的响应消息,用于回复控制器的FEATURES_REQUEST消息。此消息中包含了交换机的功能信息,如支持的OpenFlow版本、端口数量、支持的特性等。
周期性发送 OFPT_ECHO_REPLY和OFPT_ECHO_REQUEST, 用于检测控制器和交换机之间连通性
会看到OFPT_PACKET_IN, OFPT_FLOW_MOD, OFPT_PACKET_OUT 消息. 一开始没有流表项, h1 发送给h3 的ICMP报文经过s1 无法匹配转发规则, s1 向控制器发送OFPT_PACKET_IN 请求下发流表; 控制器向交换机发送OFPT_PACKET_OUT消息, 将数据包发送给交换机进行转发, 并发送OFPT_FLOW_MOD, 用于添加或修改流表项.
进阶
安装Ryu
1 2 3 git clone https://github.com/faucetsdn/ryu.git cd ryupip3 install .
运行 ryu-manager 会报错, 因为python版本的问题 #issue169
1 2 3 4 5 6 7 8 9 10 11 sudo add-apt-repository ppa:deadsnakes/ppa sudo apt-get install virtualenv python3.9 python3.9-distutils virtualenv -p /usr/bin/python3.9 ryu-python3.9-venv source ryu-python3.9-venv/bin/activateecho $VIRTUAL_ENV pip install ryu pip uninstall eventlet pip install eventlet==0.30.2 ryu-manager --help
启动ryu控制器
wireshark抓取并查看对应的OF消息
和前面使用OVS-controller通信流程差不多, 多了OFPT_MULTI_PART_REQUEST, OFPMP_PORT_DESC,OFPT_MULTI_PART_REPLY消息
流程图
实验五 OpenFlow流表操作
启动远程控制器Ryu,并在图 2 所示的网络拓扑中,完成相关 IP 配置,随后进行流表的添加与删除等操作,查看流表变化及动作结果,并给出合理解释。
实验
先清除mininet缓存, 防止先前流表干扰
网络拓扑构建
查看节点和连接信息
查看流表
执行pingall
因为默认actions为空, 故丢弃流经交换机数据包
添加流表项测试
一开始添加了单向规则, ICMP报文无法响应, 故任意两个节点之间都ping不通, 添加了双向规则后, h2和h3 之间可正常连接.
删除流表
先用控制器生成所有流表
1 dpctl add-flows in_port=*,actions=output:controller
添加丢弃数据包的流表, 所有交换机的2号端口全部丢弃
命令顺序测试
实验六 POX 控制器编程
使用POX 控制器验证Hub 模块操作
使用POX 控制器验证Switch 模块
进阶:完成二层交换机对于一定MAC地址发送的数据包的过滤
实验
s1
建立拓扑
1 sudo mn --topo=single,3 --mac --controller=remote,ip=127.0.0.1,port=6633 --switch ovsk,protocols=OpenFlow10
debug模式运行hub模块
1 ./pox.py log.level --DEBUG forwarding.hub
xterm h1 h2 h3, 在h2, h3 上使用tcpdump抓包
POX控制器模拟实现了HUB的功能, 在集线器上收到数据包将广播到所有端口.
s2
1 ./pox.py log.level --DEBUG forowarding.l2_learning
POX控制器模拟实现了L2交换机的功能, 经过交换机的数据包基于ARP表转发.
进阶
实现防火墙功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 from pox.core import coreimport pox.openflow.libopenflow_01 as oflog = core.getLogger() class SimpleFirewall (object ): def __init__ (self ): self.blocked_mac = '00:00:00:00:00:01' core.openflow.addListeners(self) def _handle_ConnectionUp (self, event ): log.info("Switch %s connected" , event.connection) def _handle_PacketIn (self, event ): packet = event.parsed if packet.src == self.blocked_mac: log.warning("Blocked packet from MAC %s" , packet.src) msg = of.ofp_packet_out() msg.data = event.ofp msg.actions.append(of.ofp_action_output(port=of.OFPP_NONE)) event.connection.send(msg) else : msg = of.ofp_packet_out() msg.data = event.ofp msg.actions.append(of.ofp_action_output(port=of.OFPP_ALL)) event.connection.send(msg) def launch (): core.registerNew(SimpleFirewall) log.info("SimpleFirewall is running." )
放到pox目录中
1 ./pox.py log.level --DEBUG forowarding.l2_learning fw
实现通过mac地址对h1 数据包的过滤
思考题
在进阶技能中对固定MAC 地址主机发出的数据包进行了限制,那么能否对固定
MAC 位置的固定端口进行数据包的限制。
可以, 记录mac和端口的映射关系, 对同一设备的不同端口进行过滤.
实验七-八 RYU 控制器编程实践
实验
Ryu实现集线器Hub
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 from ryu.base import app_managerfrom ryu.controller import ofp_eventfrom ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHERfrom ryu.controller.handler import set_ev_clsfrom ryu.ofproto import ofproto_v1_3from ryu.lib.packet import packet, ethernetclass SimpleHub (app_manager.RyuApp): OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] def __init__ (self, *args, **kwargs ): super (SimpleHub, self).__init__(*args, **kwargs) @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER ) def switch_features_handler (self, ev ): datapath = ev.msg.datapath ofproto = datapath.ofproto parser = datapath.ofproto_parser match = parser.OFPMatch() actions = [parser.OFPActionOutput(ofproto.OFPP_FLOOD)] self.add_flow(datapath, 0 , match , actions) def add_flow (self, datapath, priority, match , actions, buffer_id=None ): ofproto = datapath.ofproto parser = datapath.ofproto_parser inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)] if buffer_id: mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id, priority=priority, match =match , instructions=inst) else : mod = parser.OFPFlowMod(datapath=datapath, priority=priority, match =match , instructions=inst) datapath.send_msg(mod) @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER ) def packet_in_handler (self, ev ): msg = ev.msg datapath = msg.datapath ofproto = datapath.ofproto parser = datapath.ofproto_parser pkt = packet.Packet(msg.data) eth_pkt = pkt.get_protocol(ethernet.ethernet) if eth_pkt.ethertype == ether_types.ETH_TYPE_IP: pass self.send_packet_out(datapath, msg) def send_packet_out (self, datapath, msg ): ofproto = datapath.ofproto parser = datapath.ofproto_parser actions = [parser.OFPActionOutput(ofproto.OFPP_FLOOD)] out = parser.OFPPacketOut( datapath=datapath, buffer_id=msg.buffer_id, in_port=msg.in_port, actions=actions, data=msg.data ) datapath.send_msg(out) if __name__ == "__main__" : app_manager.main()
放置ryu/ryu/app/下
1 2 ryu-manager ./hub.py --verbose sudo mn --topo single,3 --controller remote,ip=127.0.0.1,port=6633 --switch ovsk
实现了集线器的功能
进阶 Ryu实现Switch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 from ryu.lib.mac import haddr_to_binfrom ryu.base import app_managerfrom ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHERfrom ryu.controller.handler import set_ev_clsfrom ryu.ofproto import ofproto_v1_3from ryu.lib.packet import packet, ethernet, ether_typesfrom ryu.controller import ofp_eventclass SimpleSwitch (app_manager.RyuApp): OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] def __init__ (self, *args, **kwargs ): super (SimpleSwitch, self).__init__(*args, **kwargs) self.mac_to_port = {} @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER ) def switch_features_handler (self, ev ): datapath = ev.msg.datapath ofproto = datapath.ofproto parser = datapath.ofproto_parser match = parser.OFPMatch() actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER)] self.add_flow(datapath, 0 , match , actions) def add_flow (self, datapath, priority, match , actions, buffer_id=None ): ofproto = datapath.ofproto parser = datapath.ofproto_parser inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)] if buffer_id: mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id, priority=priority, match =match , instructions=inst) else : mod = parser.OFPFlowMod(datapath=datapath, priority=priority, match =match , instructions=inst) datapath.send_msg(mod) @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER ) def packet_in_handler (self, ev ): msg = ev.msg datapath = msg.datapath ofproto = datapath.ofproto parser = datapath.ofproto_parser pkt = packet.Packet(msg.data) eth_pkt = pkt.get_protocol(ethernet.ethernet) if eth_pkt.ethertype == ether_types.ETH_TYPE_IP: pass dst = eth_pkt.dst src = eth_pkt.src in_port = msg.match ['in_port' ] self.mac_to_port.setdefault(datapath.id , {}) self.mac_to_port[datapath.id ][src] = in_port if dst in self.mac_to_port[datapath.id ]: out_port = self.mac_to_port[datapath.id ][dst] else : out_port = ofproto.OFPP_FLOOD actions = [parser.OFPActionOutput(out_port)] match = parser.OFPMatch(in_port=in_port, eth_dst=dst) self.add_flow(datapath, 1 , match , actions, msg.buffer_id) self.send_packet_out(datapath, msg, out_port) def send_packet_out (self, datapath, msg, out_port ): ofproto = datapath.ofproto parser = datapath.ofproto_parser actions = [parser.OFPActionOutput(out_port)] out = parser.OFPPacketOut( datapath=datapath, buffer_id=msg.buffer_id, in_port=msg.match ['in_port' ], actions=actions, data=msg.data ) datapath.send_msg(out)
实现了交换机的功能
其他
Ubuntu 部署Samba 文件服务
本来想用VMware选项中自带的共享文件夹功能, 结果发现 win11 不支持. https://docs.vmware.com/cn/VMware-Workstation-Pro/17/com.vmware.ws.using.doc/GUID-7DAD8EC0-0403-4152-86ED-99700F6C02B8.html 也可以用ssh 工具连接虚拟机实现复制粘贴. VMwere对不同的虚拟机镜像支持程度不同, 大多数的linux 的Desktop版安装了VMtools 是可以无缝实现主机与虚拟机的复制粘贴的, 而server版本则完全不行.
部署SMB服务实现在本地局域网文件共享.
1 2 3 4 5 apt-get install samba samba-common mkdir /vmsharechmod -R 777 /vmsharevi /etc/samba/smb.conf
shift G 跳到最后
1 2 3 4 5 6 7 8 9 10 11 12 [share] comment = share folder browseable = yes path = /vmshare create mask = 0755 directory mask = 0755 valid users = slacr force user = slacr force group = slacr public = yes available = yes writable = yes
添加用户, 账号和密码应该为系统中存在的用户
1 2 3 4 5 adduser slacr --home /home/slacr smbpasswd -a slacr systemctl enble --now smbd
MS Word 从超链导入图片
每次传完图床就懒本地保存了, 下载超链的图片一般直接用浏览器或者用curl 或 wget, 比如:
1 2 3 4 5 wget -o test1.png https://cdn.jsdelivr.net/gh/s1acr/PicGoLib@main/2023-9/202311052023840.png curl https://cdn.jsdelivr.net/gh/s1acr/PicGoLib@main/2023-9/202311052023840.png -o test2.png
MSWord 可以直接从超链导入图片, 不用每次下载再插入.
将文件名填成URI
再点插入会自动导入云端图片, 可惜垃圾 WPS 不支持, MSOffice是可以的. 我用的office365, 之前下Viso时候一起安装了KMS破解 .
关于VMware 虚拟机快照
VMware 能创建类似行为树的快照结构, 点击转到会删除当前位置的快照并创建该节点新的分支并不会删除其他子树.
U2FsdGVkX1+r0mmkT4aOMcM7ElMzLjaPrtmEBPXUIxWuAJc8ixW61Jn8k0qvNmj4BFiPYIIKhuaMc3wI5qpKAFSSWPXsQk2fNRh7OjKTkOIWSw0SVQS9uK03Vi35kLmFixBW1jwR7QiaXtSc6GePxHbr5tW+8zluTEUX++6INaWhpA4THIfY8WyPf1PeI+ENFJk4uQNoitiyh1SXnGAVGHS7v3UG3o4fzN5L0wUSW7MorSX7cv99WbNm8/1d1EWPG81gCPAR553mOnHm52jJbbTUCg9gR9KTmo/vvE287T/foa93mWVFY5wuZJFXRL3gCRDiEgQoX2FQS9injb27NUkHy7m/igskgH8ajglNcrq2jEWq2dT/I0SzG7FTdl6Id+zIm4vjLJbog/tRIMgfy0bshhJOBIN/o0/JEC0xF6DjsG6T1u+yiAgeyOIohIqRy19K5k1WrW/TErmlMUV7nBXWcA8888CG9PhXD9O4vt+tmJVqm2VxOj4eX9klKYn042yTiVVsUsyewRh480DaTqu/HHM2u7Rz9phUXY2IBNhu6MlG64oqfl0t1YYtO9QVRs/bn658w2dRhtgbqbyhHQ== 参考
Download/Get Started With Mininet
Mininet VM Setup Notes
获取Debian
清华大学开源镜像站
ubuntu换清华源后错误解决 Certificate verification failed: The certificate is NOT trusted.
Ubuntu安装桌面
Ubuntu部署Samba文件服务
debian开启cgroup memory子系统
在新 Linux 发行版上切换 cgroups 版本
「Floodlight x Mininet」从0开始搭建环境
floodlight-guide
floodlight-REST API
OpenFlow switch v1.5.1 Specification