链路仿真工具 - Mahimahi使用教程
Mahimahi网址
http://mahimahi.mit.edu/
Mahimahi安装流程
$ sudo add-apt-repository ppa:keithw/mahimahi
$ sudo apt-get update
$ sudo apt-get install mahimahi
Mahimahi使用流程
Mahimahi针对模拟链路主要分为三个部分:
- mm-delay:模拟链路固定传播时延
- mm-loss:模拟链路随机丢包率
- mm-link:模拟联络动态带宽(后面需要跟上行和下行带宽的文件路径)
一共有两种使用方法
(1)直接在shell中输入
在命令行窗口中输入之后启动命令吼,该窗口会被包装成一个单独的容器,在这个窗口里运行的程序都会在mahimahi容器中运行,从而实现网络仿真。该容器会有单独的ip地址(一般是10.0.0.x)
1.mm-delay:`mm-delay 10` (单位ms)
2.mm-loss:`mm-loss uplink 0.05`
3.mm-link:`mm-link --meter-all uplink_trace downlink_trace`
典型使用案例(–meter-all 代表实时展现带宽的可视化折线图):
mm-delay 20 mm-link --meter-all /usr/share/mahimahi/traces/Verizon-LTE-short.up /usr/share/mahimahi/traces/Verizon-LTE-short.down
(2)集成在程序中使用(比较常用)
使用案例:将server.py放在mahimahi容器中运行,可以进行网络链路的自定义
BASE_DELAY = 20
TRACE = './traces/10mbps_01.log'
server_comds = 'python server.py'
start_server = ['mm-delay', str(BASE_DELAY),
'mm-link', TRACE, TRACE,
'--uplink-queue=droptail --uplink-queue-args=packets=2048',
'-- sh -c', f"'{server_comds}'"]
start_server = ' '.join(start_server)
server = Popen(start_server, shell=True)
附:关于容器级连问题
在mahimahi中,mm-delay / mm-loss / mm-link都会产生单独的容器,如果同时使用多个,多个容器之间会级连在一起,也就是会产生多个ip,例如如果同时使用mm-delay和mm-link:
容器外部运行ifconfig:
delay-6100: flags=81<UP,POINTOPOINT,RUNNING> mtu 1500
inet 100.64.0.1 netmask 255.255.255.255 destination 100.64.0.2
容器内部运行ifconfig:
ingress: flags=81<UP,POINTOPOINT,RUNNING> mtu 1500
inet 100.64.0.4 netmask 255.255.255.255 destination 100.64.0.3
容器内(100.64.0.4) 发送UDP包到容器外时,容器外解析出来的packet address是 100.64.0.2,中间经过了一层转发。
正常我们都是把server端包装在mahimahi容器中,然后给client发送数据,其中server->client是没问题的,而client->server需要使用server发过来数据的源端口,例如下面的就是server端被放在mahimahi容器中时,双方的网络通信。
server端:
server_send_proxy=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
server_send_proxy.connect(("172.26.254.98", 10000))
packet = 'hello'.encode()
server_send_proxy.send(packet)
ack = server.recv(1500)
client端:
recv_proxy = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
recv_proxy.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
recv_proxy.bind(("172.26.254.98", 10000))
data, addr = recv_proxy.recvfrom(2000)
ack = 'feedback info'.encode()
recv_proxy.sendto(ack, addr)