用于ccp的portus实现的python绑定
portus的Python项目详细描述
皮波特斯
该模块为portus ccp实现提供了一个python接口。
设置
要构建和使用python绑定,还需要setuptools\u rust
sudo pip install setuptools_rust
你需要告诉它使用Rust的夜间版本,因为有些功能 仍在实验中:
- 检查包的安装位置:
pip show setuptools_rust
- 编辑
packages/setuptools_rust/build.py
- 搜索包含“rustc”的行(应该是~102),并将参数更改为
["cargo", "+nightly", "rustc", ...
现在,您可以使用
python setup.py develop
根据您的python环境设置,您可能需要使用sudo
运行此命令。
(并确保您的PATH
变量被保留):
sudo env PATH=$PATH python setup.py develop
现在您应该可以像这样导入包:
importportus
编写算法
概述
portus中的算法由python类表示,此类的实例表示单个tcp流。为每个流创建一个新实例。
这个类必须是portus.AlgBase
的子类,并且必须实现两个
以下方法签名:
on_create(self)
on_report(self, r)
r
是一个报表对象,包含数据路径程序中定义的所有字段,以及当前的Cwnd
和Rate
。假设您的程序只定义了一个变量:(def (acked 0))
,其中acked
将自上次报告以来确认的总字节相加。此值可以作为r.acked
访问。类似地,您可以访问cwnd或按r.Cwnd
和r.Rate
(重要的字幕化!).
类的每个实例化将自动在self中有两个字段:
self.datapath
是指向可用于安装的datapath对象的指针 新的数据路径程序。它有两种可用的方法:datapath.install( str )
,它将数据路径程序作为字符串。它编译程序并将其安装在数据路径中。它不返回任何内容,但如果程序无法编译,它可能会引发异常。datapath.update_field(field, val)
,它接受数据路径程序的Report
范围内的变量,并将值设置为val
。例如,要仅更新cwnd,可以使用datapath.update_field("Cwnd", 10000)
(注意:cwnd以字节表示,而不是以数据包表示)。
self.datapath_info
是一个包含来自数据路径的这个特定流的字段的结构(例如,可以在on_create
中使用它来基于数据路径的mss
设置初始cwnd)sock_id
:数据路径中此流的唯一IDinit_cwnd
:此流在设置之前将具有的初始拥塞窗口src_ip
,src_port
,dst_ip
,dst_port
:流的源和目标的IP地址和端口
数据路径程序
数据路径程序用于(1)定义哪些统计信息要发送回您的usespace程序,以及多长时间和(2)设置拥塞窗口和/或速率。数据路径程序是用一种非常简单的类似lisp的方言编写的,它由一个单独的变量定义行和任意数量的when子句组成:
(def ( ... ) ( ... ))
(when (event) (
do_stuff ...
)
(when (other_event) (
do_other_stuff ...
)
注意:以下信息已过期,因为datapath程序api已
已更新
1.报表变量定义
示例:(def (Report.acked 0) (Report.rtt 0) (Report.timeout false))
此行定义report作用域中变量的名称和初始值。在datapath程序中调用(report)
会导致使用这些变量的当前值调用算法的on_report
函数。调用后,这些变量将重置回其初始值。
注意:数据路径程序中的变量被写成{scope}.{name}
。例如,Report
作用域中的acked
变量被写为Report.acked
。因此,此行定义的所有变量必须以Report.
开头,但是,当您在on_report
中访问它们时,只需提供变量名。在上面的例子中,Report.rtt
定义了Report
范围中的变量rtt
。如果我们想在on_report(r)
中访问这个值,我们将使用r.rtt
(即notr.Report.rtt
)。
2。当子句
when子句由布尔表达式和一组指令组成。在每个ack上,数据路径检查布尔表达式,如果其计算结果为true
,则运行一组指令。例如,下面的when子句每rtt发送一次报告(即调用on_report
函数):
(when (> Micros Flow.rtt_sample_us)
(report)
)
总而言之
显示完整API的示例算法定义:
importportus# Class must sublcass portus.AlgBaseclassSampleCCAlg(portus.AlgBase):# Init must take exactly these parametersdef__init__(self,datapath,datapath_info):# Store a copy of the datapath and info for laterself.datapath=datapathself.datapath_info=datapath_info# Internally store an initial cwnd valueself.cwnd=10*self.datapath_info.mss# Install an initial datapath program to keep track of the RTT and report it once per RTT# The first when clause is true on every single ack,# which means the 'Report.rtt' field will always keep the latest rtt sample# The second when clause is true once one rtt's worth of time has passed, # at which point it will trigger on_report, and Micros (and Report.rtt) will be reset to 0self.datapath.install("""\ (def (Report.rtt 0) ) (when true (:= Report.rtt Flow.rtt_sample_us) (fallthrough) ) (when (> Micros Flow.rtt_sample_us) (report) ) """)# This function will be called once per RTT, and the report struct `r` will contain:# "rtt", "Cwnd", and "Rate"defon_report(self,r):# Compute new cwnd internally # If the rtt has decreased, increase the cwnd by 1 packet, else decrease by 1 packetifself.last_rtt<r.rtt:self.cwnd+=self.datapath_info.msselse:self.cwnd-=self.datapath_info.mssself.last_rtt=r.rtt# Send this new value of cwnd to the datapathself.datapath.update_field("Cwnd",self.cwnd)
重要注意事项
- 您应该在
__init__
实现中安装一个初始数据路径程序,否则您将不会收到任何报告,也不会发生任何其他情况。以后处理on_report
时,始终可以安装其他数据路径程序。 - 如果要打印任何内容,应该使用
sys.stderr.write()
(注意,您需要import sys
,并且它不会像print
那样自动为您添加新行)。 - 您必须将对
datapath
的引用存储在名为“datapath”(即self.datapath = datapath
)的self
中,因为库在内部也使用它来访问datapath结构。
启动ccp
ccp入口点是portus.connect(ipc_type, class, debug, blocking)
:
ipc_type (string)
:(netlink unix char)在linux上或(unix)在mac上class
:您的算法类,例如SampleCCAlg
debug (bool)
:如果为true,则ccp将记录ccp和datapath之间传递的所有消息blocking (bool)
:如果为true,则使用阻塞ipc读取,否则使用非阻塞
例如:portus.connect("netlink", SampleCCAlg, debug=True, blocking=True)
。
不管您使用的是阻塞还是非阻塞套接字,connect
都将永远阻塞(要停止ccp,只需发送ctrl+c或终止进程)。
示例
有关定义算法和运行ccp的完整工作示例,请参见./aimd.py
中的简单aimd方案,并尝试运行它:sudo python aimd.py
。