POX 控制器 API (一)——基础篇
全网都找不到详尽的 API 介绍,自己试着从各处总结一些。
一种开始构建自己的 POX 模块的常用方法是将现有模块(例如 forwarding/l2_learning.py)复制到 ext 目录(例如 ext/my_component.py)。然后,可以修改新文件并将 POX 调用为 ./pox.py my_component
。
POX 有一个名为 “core” 的对象,它作为 POX 大部分 API 的核心。POX 中的许多模块都会希望访问 core 对象。一般通过导入 core 即可:
from pox.core import core
注册组件
core.register() 接受两个参数。第二个是我们想要在核心上注册的对象,第一个是我们给它起的名字。下例是一个非常简单的组件,它有一个 launch() 函数,注册后就可以通过 core 来调用 thing 里面的 foo 函数了:
class MyComponent (object):
def __init__ (self, an_arg):
self.arg = an_arg
print "MyComponent instance registered with arg:", self.arg
def foo (self):
print "MyComponent with arg:", self.arg
def launch ():
component = MyComponent("spam")
core.register("thing", component)
core.thing.foo() # prints "MyComponent with arg: spam"
处理地址:pox.lib.addresses
POX 中的 IPv4、IPv6 和以太网地址由 pox.lib.addresses 的 IPAddr、IPAddr6 和 EthAddr 类表示。在某些情况下,其他地址格式可能有效(例如,点分四个数字的 IP 地址),但使用地址类应该始终有效。
例如,使用 IP 地址时:
from pox.lib.addresses import IPAddr, IPAddr6, EthAddr
ip = IPAddr("192.168.1.1")
print str(ip) # Prints "192.168.1.1"
print ip.toUnsignedN() # Convert to network-order unsigned integer -- 16885952
print ip.raw # Returns a length-four bytes object (a four byte string, more or less)
ip = IPAddr(16885952, networkOrder=True)
print str(ip) # Also prints "192.168.1.1" !
pox.lib.addresses 还包含各种实用工具函数,用于解析网络掩码、CIDR 表示法、检查IP是否在特定子网内,等等。
处理数据包:pox.lib.packet
POX 中的许多应用程序与数据包交互(例如,你可能希望构造数据包并将其发送出交换机,或者你可以通过 ofp_packet_in OpenFlow 消息从交换机接收数据包)。为此,POX 有一个用于解析和构造数据包的库。该库支持许多不同的数据包类型。
大多数数据包都有某种头部和某种有效载荷。有效载荷通常是另一种类型的包。例如在 POX 中,通常使用以太网数据包,这些数据包通常包含 ipv4 数据包(ipv4 数据包通常又包含 tcp 数据包......)。POX 支持的一些数据包类型是:
- ethernet
- ARP
- IPv4
- ICMP
- TCP
- UDP
- DHCP
- DNS
- LLDP
- VLAN
POX 中的所有数据包类都可以在 pox/lib/packet 中找到。可以简单地通过 import 导入:
import pox.lib.packet as pkt
可以通过两种方式解析封装的数据包:使用数据包对象的 payload 属性,或使用 find()
方法。例如,以下是使用 payload 属性解析 ICMP 消息的方法:
def parse_icmp (eth_packet):
if eth_packet.type == pkt.IP_TYPE:
ip_packet = eth_packet.payload
src_ip = ip_packet.srcip # 源 IP
if ip_packet.protocol == pkt.ICMP_PROTOCOL:
icmp_packet = ip_packet.payload
icmp_code = icmp_packet.code # ICMP sequence number
...
分组对象的 find()
方法可用于通过所需类型名称(例如 “icmp”)或其类(例如 pkt.ICMP)来查找特定的封装分组。如果数据包对象未封装所请求类型的数据包,则返回 None。 例如:
def handle_IP_packet (packet):
ip = packet.find('ipv4')
if ip is None:
# This packet isn't IP!
return
print "Source IP:", ip.srcip
接下来介绍一些支持的数据包类型的一些有用的属性/方法/常量。