数据包库

介绍

OS-Ken 数据包库帮助您解析和构建各种协议数据包。dpkt 是用于相同目的的流行库,但是它并非设计用于处理交错协议;vlan、mpls、gre 等。因此,我们实现了我们自己的数据包库。

网络地址

除非另有说明,否则此库中的 MAC/IPv4/IPv6 地址使用人类可读的字符串指定。例如,'08:60:6e:7f:74:e7'、'192.0.2.1'、'fe80::a60:6eff:fe7f:74e7'。

解析数据包

首先,让我们看看如何使用该库来解析 OFPPacketIn 消息的处理程序中接收到的数据包。

from os_ken.lib.packet import packet

@handler.set_ev_cls(ofp_event.EventOFPPacketIn, handler.MAIN_DISPATCHER)
def packet_in_handler(self, ev):
    pkt = packet.Packet(array.array('B', ev.msg.data))
    for p in pkt.protocols:
        print p

您可以使用接收到的原始数据创建一个 Packet 类实例。然后,数据包库将解析数据并创建包含数据的协议类实例。数据包类的 'protocols' 属性包含协议类实例。

如果收到 TCP 数据包,将打印如下内容

<os_ken.lib.packet.ethernet.ethernet object at 0x107a5d790>
<os_ken.lib.packet.vlan.vlan object at 0x107a5d7d0>
<os_ken.lib.packet.ipv4.ipv4 object at 0x107a5d810>
<os_ken.lib.packet.tcp.tcp object at 0x107a5d850>

如果未使用 VLAN,您将看到如下内容

<os_ken.lib.packet.ethernet.ethernet object at 0x107a5d790>
<os_ken.lib.packet.ipv4.ipv4 object at 0x107a5d810>
<os_ken.lib.packet.tcp.tcp object at 0x107a5d850>

您可以使用数据包类迭代器访问特定的协议类实例。让我们尝试检查是否使用了 VLAN,如果是,则检查 VLAN ID

from os_ken.lib.packet import packet

@handler.set_ev_cls(ofp_event.EventOFPPacketIn, handler.MAIN_DISPATCHER)
def packet_in_handler(self, ev):
    pkt = packet.Packet(array.array('B', ev.msg.data))
    for p in pkt:
        print p.protocol_name, p
        if p.protocol_name == 'vlan':
            print 'vid = ', p.vid

您将看到如下内容

ethernet <os_ken.lib.packet.ethernet.ethernet object at 0x107a5d790>
vlan <os_ken.lib.packet.vlan.vlan object at 0x107a5d7d0>
vid = 10
ipv4 <os_ken.lib.packet.ipv4.ipv4 object at 0x107a5d810>
tcp <os_ken.lib.packet.tcp.tcp object at 0x107a5d850>

构建数据包

您需要创建要发送的协议类实例,通过 add_protocol 方法将其添加到数据包类实例,然后调用 serialize 方法。您将获得要发送的原始数据。以下示例是构建一个 ARP 数据包。

from os_ken.ofproto import ether
from os_ken.lib.packet import ethernet, arp, packet

e = ethernet.ethernet(dst='ff:ff:ff:ff:ff:ff',
                      src='08:60:6e:7f:74:e7',
                      ethertype=ether.ETH_TYPE_ARP)
a = arp.arp(hwtype=1, proto=0x0800, hlen=6, plen=4, opcode=2,
            src_mac='08:60:6e:7f:74:e7', src_ip='192.0.2.1',
            dst_mac='00:00:00:00:00:00', dst_ip='192.0.2.2')
p = packet.Packet()
p.add_protocol(e)
p.add_protocol(a)
p.serialize()
print repr(p.data)  # the on-wire packet