## This file is part of Scapy
|
## See http://www.secdev.org/projects/scapy for more information
|
## Copyright (C) Philippe Biondi <phil@secdev.org>
|
## This program is published under a GPLv2 license
|
|
## Copyright (C) 2014 Maxence Tury <maxence.tury@ssi.gouv.fr>
|
## OpenFlow is an open standard used in SDN deployments.
|
## Based on OpenFlow v1.0.1
|
## Specifications can be retrieved from https://www.opennetworking.org/
|
|
# scapy.contrib.description = Openflow v1.0
|
# scapy.contrib.status = loads
|
|
from __future__ import absolute_import
|
import struct
|
from scapy.fields import *
|
from scapy.layers.l2 import *
|
from scapy.layers.inet import *
|
from scapy.compat import orb
|
|
### If prereq_autocomplete is True then match prerequisites will be
|
### automatically handled. See OFPMatch class.
|
prereq_autocomplete = False
|
|
#####################################################
|
################# Predefined values #################
|
#####################################################
|
|
ofp_port_no = { 0xfff8: "IN_PORT",
|
0xfff9: "TABLE",
|
0xfffa: "NORMAL",
|
0xfffb: "FLOOD",
|
0xfffc: "ALL",
|
0xfffd: "CONTROLLER",
|
0xfffe: "LOCAL",
|
0xffff: "NONE" }
|
|
ofp_table = { 0xff: "ALL" }
|
|
ofp_queue = { 0xffffffff: "ALL" }
|
|
ofp_buffer = { 0xffffffff: "NO_BUFFER" }
|
|
ofp_max_len = { 0xffff: "NO_BUFFER" }
|
|
#####################################################
|
################# Common structures #################
|
#####################################################
|
|
### The following structures will be used in different types
|
### of OpenFlow messages: ports, matches, actions, queues.
|
|
|
##################### Ports #####################
|
|
ofp_port_config = [ "PORT_DOWN",
|
"NO_STP",
|
"NO_RECV",
|
"NO_RECV_STP",
|
"NO_FLOOD",
|
"NO_FWD",
|
"NO_PACKET_IN" ]
|
|
ofp_port_state = [ "LINK_DOWN" ]
|
|
ofp_port_state_stp = { 0: "OFPPS_STP_LISTEN",
|
1: "OFPPS_STP_LEARN",
|
2: "OFPPS_STP_FORWARD",
|
3: "OFPPS_STP_BLOCK" }
|
|
ofp_port_features = [ "10MB_HD",
|
"10MB_FD",
|
"100MB_HD",
|
"100MB_FD",
|
"1GB_HD",
|
"1GB_FD",
|
"10GB_FD",
|
"COPPER",
|
"FIBER",
|
"AUTONEG",
|
"PAUSE",
|
"PAUSE_ASYM" ]
|
|
class OFPPhyPort(Packet):
|
name = "OFP_PHY_PORT"
|
fields_desc = [ ShortEnumField("port_no", 0, ofp_port_no),
|
MACField("hw_addr", "0"),
|
StrFixedLenField("port_name", "", 16),
|
FlagsField("config", 0, 32, ofp_port_config),
|
BitEnumField("stp_state", 0, 24, ofp_port_state),
|
FlagsField("state", 0, 8, ofp_port_state),
|
FlagsField("curr", 0, 32, ofp_port_features),
|
FlagsField("advertised", 0, 32, ofp_port_features),
|
FlagsField("supported", 0, 32, ofp_port_features),
|
FlagsField("peer", 0, 32, ofp_port_features) ]
|
|
def extract_padding(self, s):
|
return "", s
|
|
class OFPMatch(Packet):
|
name = "OFP_MATCH"
|
fields_desc= [ FlagsField("wildcards1", None, 12, [ "DL_VLAN_PCP",
|
"NW_TOS" ]),
|
BitField("nw_dst_mask", None, 6),
|
BitField("nw_src_mask", None, 6),
|
FlagsField("wildcards2", None, 8, [ "IN_PORT",
|
"DL_VLAN",
|
"DL_SRC",
|
"DL_DST",
|
"DL_TYPE",
|
"NW_PROTO",
|
"TP_SRC",
|
"TP_DST" ]),
|
ShortEnumField("in_port", None, ofp_port_no),
|
MACField("dl_src", None),
|
MACField("dl_dst", None),
|
ShortField("dl_vlan", None),
|
ByteField("dl_vlan_pcp", None),
|
XByteField("pad1", None),
|
ShortField("dl_type", None),
|
ByteField("nw_tos", None),
|
ByteField("nw_proto", None),
|
XShortField("pad2", None),
|
IPField("nw_src", "0"),
|
IPField("nw_dst", "0"),
|
ShortField("tp_src", None),
|
ShortField("tp_dst", None) ]
|
|
def extract_padding(self, s):
|
return "", s
|
|
### with post_build we create the wildcards field bit by bit
|
def post_build(self, p, pay):
|
# first 10 bits of an ofp_match are always set to 0
|
l = "0"*10
|
|
# when one field has not been declared, it is assumed to be wildcarded
|
if self.wildcards1 is None:
|
if self.nw_tos is None: l+="1"
|
else: l+="0"
|
if self.dl_vlan_pcp is None: l+="1"
|
else: l+="0"
|
else:
|
w1 = binrepr(self.wildcards1)
|
l+="0"*(2-len(w1))
|
l+=w1
|
|
# ip masks use 6 bits each
|
if self.nw_dst_mask is None:
|
if self.nw_dst is "0": l+="111111"
|
# 0x100000 would be ok too (32-bit IP mask)
|
else: l+="0"*6
|
else:
|
m1 = binrepr(self.nw_dst_mask)
|
l+="0"*(6-len(m1))
|
l+=m1
|
if self.nw_src_mask is None:
|
if self.nw_src is "0": l+="111111"
|
else: l+="0"*6
|
else:
|
m2 = binrepr(self.nw_src_mask)
|
l+="0"*(6-len(m2))
|
l+=m2
|
|
# wildcards2 works the same way as wildcards1
|
if self.wildcards2 is None:
|
if self.tp_dst is None: l+="1"
|
else: l+="0"
|
if self.tp_src is None: l+="1"
|
else: l+="0"
|
if self.nw_proto is None: l+="1"
|
else: l+="0"
|
if self.dl_type is None: l+="1"
|
else: l+="0"
|
if self.dl_dst is None: l+="1"
|
else: l+="0"
|
if self.dl_src is None: l+="1"
|
else: l+="0"
|
if self.dl_vlan is None: l+="1"
|
else: l+="0"
|
if self.in_port is None: l+="1"
|
else: l+="0"
|
else:
|
w2 = binrepr(self.wildcards2)
|
l+="0"*(8-len(w2))
|
l+=w2
|
|
### In order to write OFPMatch compliant with the specifications,
|
### if prereq_autocomplete has been set to True
|
### we assume ethertype=IP or nwproto=TCP when appropriate subfields are provided.
|
if prereq_autocomplete:
|
if self.dl_type is None:
|
if self.nw_src is not "0" or self.nw_dst is not "0" or self.nw_proto is not None or self.nw_tos is not None:
|
p = p[:22] + struct.pack("!H", 0x0800) + p[24:]
|
l = l[:-5] + "0" + l[-4:]
|
if self.nw_proto is None:
|
if self.tp_src is not None or self.tp_dst is not None:
|
p = p[:22] + struct.pack("!H", 0x0800) + p[24:]
|
l = l[:-5] + "0" + l[-4:]
|
p = p[:25] + struct.pack("!B", 0x06) + p[26:]
|
l = l[:-6] + "0" + l[-5:]
|
|
ins = b"".join(chb(int("".join(x),2)) for x in zip(*[iter(l)]*8))
|
p = ins + p[4:]
|
return p + pay
|
|
|
###################### Actions ######################
|
|
class _ofp_action_header(Packet):
|
name = "Dummy OpenFlow Action Header"
|
|
def post_build(self, p, pay):
|
if self.len is None:
|
l = len(p)+len(pay)
|
p = p[:2] + struct.pack("!H", l) + p[4:]
|
return p + pay
|
|
ofp_action_types = { 0: "OFPAT_OUTPUT",
|
1: "OFPAT_SET_VLAN_VID",
|
2: "OFPAT_SET_VLAN_PCP",
|
3: "OFPAT_STRIP_VLAN",
|
4: "OFPAT_SET_DL_SRC",
|
5: "OFPAT_SET_DL_DST",
|
6: "OFPAT_SET_NW_SRC",
|
7: "OFPAT_SET_NW_DST",
|
8: "OFPAT_SET_NW_TOS",
|
9: "OFPAT_SET_TP_SRC",
|
10: "OFPAT_SET_TP_DST",
|
11: "OFPAT_ENQUEUE",
|
65535: "OFPAT_VENDOR" }
|
|
class OFPATOutput(_ofp_action_header):
|
name = "OFPAT_OUTPUT"
|
fields_desc = [ ShortEnumField("type", 0, ofp_action_types),
|
ShortField("len", 8),
|
ShortEnumField("port", 0, ofp_port_no),
|
ShortEnumField("max_len", "NO_BUFFER", ofp_max_len) ]
|
|
class OFPATSetVLANVID(_ofp_action_header):
|
name = "OFPAT_SET_VLAN_VID"
|
fields_desc = [ ShortEnumField("type", 1, ofp_action_types),
|
ShortField("len", 8),
|
ShortField("vlan_vid", 0),
|
XShortField("pad", 0) ]
|
|
class OFPATSetVLANPCP(_ofp_action_header):
|
name = "OFPAT_SET_VLAN_PCP"
|
fields_desc = [ ShortEnumField("type", 2, ofp_action_types),
|
ShortField("len", 8),
|
ByteField("vlan_pcp", 0),
|
X3BytesField("pad", 0) ]
|
|
class OFPATStripVLAN(_ofp_action_header):
|
name = "OFPAT_STRIP_VLAN"
|
fields_desc = [ ShortEnumField("type", 3, ofp_action_types),
|
ShortField("len", 8),
|
XIntField("pad", 0) ]
|
|
class OFPATSetDlSrc(_ofp_action_header):
|
name = "OFPAT_SET_DL_SRC"
|
fields_desc = [ ShortEnumField("type", 4, ofp_action_types),
|
ShortField("len", 16),
|
MACField("dl_addr", "0"),
|
XBitField("pad", 0, 48) ]
|
|
class OFPATSetDlDst(_ofp_action_header):
|
name = "OFPAT_SET_DL_DST"
|
fields_desc = [ ShortEnumField("type", 5, ofp_action_types),
|
ShortField("len", 16),
|
MACField("dl_addr", "0"),
|
XBitField("pad", 0, 48) ]
|
|
class OFPATSetNwSrc(_ofp_action_header):
|
name = "OFPAT_SET_NW_SRC"
|
fields_desc = [ ShortEnumField("type", 6, ofp_action_types),
|
ShortField("len", 8),
|
IPField("nw_addr", "0") ]
|
|
class OFPATSetNwDst(_ofp_action_header):
|
name = "OFPAT_SET_NW_DST"
|
fields_desc = [ ShortEnumField("type", 7, ofp_action_types),
|
ShortField("len", 8),
|
IPField("nw_addr", "0") ]
|
|
class OFPATSetNwToS(_ofp_action_header):
|
name = "OFPAT_SET_TP_TOS"
|
fields_desc = [ ShortEnumField("type", 8, ofp_action_types),
|
ShortField("len", 8),
|
ByteField("nw_tos", 0),
|
X3BytesField("pad", 0) ]
|
|
class OFPATSetTpSrc(_ofp_action_header):
|
name = "OFPAT_SET_TP_SRC"
|
fields_desc = [ ShortEnumField("type", 9, ofp_action_types),
|
ShortField("len", 8),
|
ShortField("tp_port", 0),
|
XShortField("pad", 0) ]
|
|
class OFPATSetTpDst(_ofp_action_header):
|
name = "OFPAT_SET_TP_DST"
|
fields_desc = [ ShortEnumField("type", 10, ofp_action_types),
|
ShortField("len", 8),
|
ShortField("tp_port", 0),
|
XShortField("pad", 0) ]
|
|
class OFPATEnqueue(_ofp_action_header):
|
name = "OFPAT_ENQUEUE"
|
fields_desc = [ ShortEnumField("type", 11, ofp_action_types),
|
ShortField("len", 16),
|
ShortEnumField("port", 0, ofp_port_no),
|
XBitField("pad", 0, 48),
|
IntField("queue_id", 0) ]
|
|
class OFPATVendor(_ofp_action_header):
|
name = "OFPAT_VENDOR"
|
fields_desc = [ ShortEnumField("type", 65535, ofp_action_types),
|
ShortField("len", 8),
|
IntField("vendor", 0) ]
|
|
ofp_action_cls = { 0: OFPATOutput,
|
1: OFPATSetVLANVID,
|
2: OFPATSetVLANPCP,
|
3: OFPATStripVLAN,
|
4: OFPATSetDlSrc,
|
5: OFPATSetDlDst,
|
6: OFPATSetNwSrc,
|
7: OFPATSetNwDst,
|
8: OFPATSetNwToS,
|
9: OFPATSetTpSrc,
|
10: OFPATSetTpDst,
|
11: OFPATEnqueue,
|
65535: OFPATVendor }
|
|
class ActionPacketListField(PacketListField):
|
def m2i(self, pkt, s):
|
t = struct.unpack("!H", s[:2])[0]
|
return ofp_action_cls.get(t, Raw)(s)
|
|
@staticmethod
|
def _get_action_length(s):
|
return struct.unpack("!H", s[2:4])[0]
|
|
def getfield(self, pkt, s):
|
lst = []
|
remain = s
|
|
while remain:
|
l = ActionPacketListField._get_action_length(remain)
|
current = remain[:l]
|
remain = remain[l:]
|
p = self.m2i(pkt, current)
|
lst.append(p)
|
|
return remain, lst
|
|
|
####################### Queues ######################
|
|
class _ofp_queue_property_header(Packet):
|
name = "Dummy OpenFlow Queue Property Header"
|
|
def post_build(self, p, pay):
|
if self.len is None:
|
l = len(p)+len(pay)
|
p = p[:2] + struct.pack("!H", l) + p[4:]
|
return p + pay
|
|
ofp_queue_property_types = { 0: "OFPQT_NONE",
|
1: "OFPQT_MIN_RATE" }
|
|
class OFPQTNone(_ofp_queue_property_header):
|
name = "OFPQT_NONE"
|
fields_desc = [ ShortEnumField("type", 0, ofp_queue_property_types),
|
ShortField("len", 8),
|
XIntField("pad", 0) ]
|
|
class OFPQTMinRate(_ofp_queue_property_header):
|
name = "OFPQT_MIN_RATE"
|
fields_desc = [ ShortEnumField("type", 1, ofp_queue_property_types),
|
ShortField("len", 16),
|
XIntField("pad", 0),
|
ShortField("rate", 0),
|
XBitField("pad2", 0, 48) ]
|
|
ofp_queue_property_cls = { 0: OFPQTNone,
|
1: OFPQTMinRate }
|
|
class QueuePropertyPacketListField(PacketListField):
|
def m2i(self, pkt, s):
|
t = struct.unpack("!H", s[:2])[0]
|
return ofp_queue_property_cls.get(t, Raw)(s)
|
|
@staticmethod
|
def _get_queue_property_length(s):
|
return struct.unpack("!H", s[2:4])[0]
|
|
def getfield(self, pkt, s):
|
lst = []
|
l = 0
|
ret = ""
|
remain = s
|
|
while remain:
|
l = QueuePropertyPacketListField._get_queue_property_length(remain)
|
current = remain[:l]
|
remain = remain[l:]
|
p = self.m2i(pkt, current)
|
lst.append(p)
|
|
return remain + ret, lst
|
|
class OFPPacketQueue(Packet):
|
|
def extract_padding(self, s):
|
return "", s
|
|
def post_build(self, p, pay):
|
if self.properties == []:
|
p += str(OFPQTNone())
|
if self.len is None:
|
l = len(p)+len(pay)
|
p = p[:4] + struct.pack("!H", l) + p[6:]
|
return p + pay
|
|
name = "OFP_PACKET_QUEUE"
|
fields_desc = [ IntField("queue_id", 0),
|
ShortField("len", None),
|
XShortField("pad", 0),
|
QueuePropertyPacketListField("properties", [], Packet,
|
length_from=lambda pkt:pkt.len-8) ]
|
|
class QueuePacketListField(PacketListField):
|
|
@staticmethod
|
def _get_queue_length(s):
|
return struct.unpack("!H", s[4:6])[0]
|
|
def getfield(self, pkt, s):
|
lst = []
|
l = 0
|
ret = ""
|
remain = s
|
|
while remain:
|
l = QueuePacketListField._get_queue_length(remain)
|
current = remain[:l]
|
remain = remain[l:]
|
p = OFPPacketQueue(current)
|
lst.append(p)
|
|
return remain + ret, lst
|
|
|
#####################################################
|
############## OpenFlow 1.0 Messages ################
|
#####################################################
|
|
class _ofp_header(Packet):
|
name = "Dummy OpenFlow Header"
|
|
def post_build(self, p, pay):
|
if self.len is None:
|
l = len(p)+len(pay)
|
p = p[:2] + struct.pack("!H", l) + p[4:]
|
return p + pay
|
|
ofp_version = { 0x01: "OpenFlow 1.0",
|
0x02: "OpenFlow 1.1",
|
0x03: "OpenFlow 1.2",
|
0x04: "OpenFlow 1.3",
|
0x05: "OpenFlow 1.4" }
|
|
ofp_type = { 0: "OFPT_HELLO",
|
1: "OFPT_ERROR",
|
2: "OFPT_ECHO_REQUEST",
|
3: "OFPT_ECHO_REPLY",
|
4: "OFPT_VENDOR",
|
5: "OFPT_FEATURES_REQUEST",
|
6: "OFPT_FEATURES_REPLY",
|
7: "OFPT_GET_CONFIG_REQUEST",
|
8: "OFPT_GET_CONFIG_REPLY",
|
9: "OFPT_SET_CONFIG",
|
10: "OFPT_PACKET_IN",
|
11: "OFPT_FLOW_REMOVED",
|
12: "OFPT_PORT_STATUS",
|
13: "OFPT_PACKET_OUT",
|
14: "OFPT_FLOW_MOD",
|
15: "OFPT_PORT_MOD",
|
16: "OFPT_STATS_REQUEST",
|
17: "OFPT_STATS_REPLY",
|
18: "OFPT_BARRIER_REQUEST",
|
19: "OFPT_BARRIER_REPLY",
|
20: "OFPT_QUEUE_GET_CONFIG_REQUEST",
|
21: "OFPT_QUEUE_GET_CONFIG_REPLY" }
|
|
class OFPTHello(_ofp_header):
|
name = "OFPT_HELLO"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 0, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0) ]
|
overload_fields = {TCP: {"sport": 6653}}
|
|
#####################################################
|
#################### OFPT_ERROR #####################
|
#####################################################
|
|
### this class will be used to display some messages
|
### sent back by the switch after an error
|
class OFPacketField(PacketField):
|
def getfield(self, pkt, s):
|
try:
|
l = s[2:4]
|
l = struct.unpack("!H", l)[0]
|
ofload = s[:l]
|
remain = s[l:]
|
return remain, OpenFlow(None, ofload)(ofload)
|
except:
|
return "", Raw(s)
|
|
ofp_error_type = { 0: "OFPET_HELLO_FAILED",
|
1: "OFPET_BAD_REQUEST",
|
2: "OFPET_BAD_ACTION",
|
3: "OFPET_FLOW_MOD_FAILED",
|
4: "OFPET_PORT_MOD_FAILED",
|
5: "OFPET_QUEUE_OP_FAILED" }
|
|
class OFPETHelloFailed(_ofp_header):
|
name = "OFPET_HELLO_FAILED"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 1, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("errtype", 0, ofp_error_type),
|
ShortEnumField("errcode", 0, { 0: "OFPHFC_INCOMPATIBLE",
|
1: "OFPHFC_EPERM" }),
|
OFPacketField("data", "", Raw) ]
|
overload_fields = {TCP: {"dport": 6653}}
|
|
class OFPETBadRequest(_ofp_header):
|
name = "OFPET_BAD_REQUEST"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 1, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("errtype", 1, ofp_error_type),
|
ShortEnumField("errcode", 0, { 0: "OFPBRC_BAD_VERSION",
|
1: "OFPBRC_BAD_TYPE",
|
2: "OFPBRC_BAD_STAT",
|
3: "OFPBRC_BAD_VENDOR",
|
4: "OFPBRC_BAD_SUBTYPE",
|
5: "OFPBRC_EPERM",
|
6: "OFPBRC_BAD_LEN",
|
7: "OFPBRC_BUFFER_EMPTY",
|
8: "OFPBRC_BUFFER_UNKNOWN" }),
|
OFPacketField("data", "", Raw) ]
|
overload_fields = {TCP: {"dport": 6653}}
|
|
class OFPETBadAction(_ofp_header):
|
name = "OFPET_BAD_ACTION"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 1, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("errtype", 2, ofp_error_type),
|
ShortEnumField("errcode", 0, { 0: "OFPBAC_BAD_TYPE",
|
1: "OFPBAC_BAD_LEN",
|
2: "OFPBAC_BAD_VENDOR",
|
3: "OFPBAC_BAD_VENDOR_TYPE",
|
4: "OFPBAC_BAD_OUT_PORT",
|
5: "OFPBAC_BAD_ARGUMENT",
|
6: "OFPBAC_EPERM",
|
7: "OFPBAC_TOO_MANY",
|
8: "OFPBAC_BAD_QUEUE" }),
|
OFPacketField("data", "", Raw) ]
|
overload_fields = {TCP: {"dport": 6653}}
|
|
class OFPETFlowModFailed(_ofp_header):
|
name = "OFPET_FLOW_MOD_FAILED"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 1, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("errtype", 3, ofp_error_type),
|
ShortEnumField("errcode", 0, { 0: "OFPFMFC_ALL_TABLES_FULL",
|
1: "OFPFMFC_OVERLAP",
|
2: "OFPFMFC_EPERM",
|
3: "OFPFMFC_BAD_EMERG_TIMEOUT",
|
4: "OFPFMFC_BAD_COMMAND",
|
5: "OFPFMFC_UNSUPPORTED" }),
|
OFPacketField("data", "", Raw) ]
|
overload_fields = {TCP: {"dport": 6653}}
|
|
class OFPETPortModFailed(_ofp_header):
|
name = "OFPET_PORT_MOD_FAILED"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 1, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("errtype", 4, ofp_error_type),
|
ShortEnumField("errcode", 0, { 0: "OFPPMFC_BAD_PORT",
|
1: "OFPPMFC_BAD_HW_ADDR" }),
|
OFPacketField("data", "", Raw) ]
|
overload_fields = {TCP: {"dport": 6653}}
|
|
class OFPETQueueOpFailed(_ofp_header):
|
name = "OFPET_QUEUE_OP_FAILED"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 1, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("errtype", 5, ofp_error_type),
|
ShortEnumField("errcode", 0, { 0: "OFPQOFC_BAD_PORT",
|
1: "OFPQOFC_BAD_QUEUE",
|
2: "OFPQOFC_EPERM" }),
|
OFPacketField("data", "", Raw) ]
|
overload_fields = {TCP: {"dport": 6653}}
|
|
# ofp_error_cls allows generic method OpenFlow() to choose the right class for dissection
|
ofp_error_cls = { 0: OFPETHelloFailed,
|
1: OFPETBadRequest,
|
2: OFPETBadAction,
|
3: OFPETFlowModFailed,
|
4: OFPETPortModFailed,
|
5: OFPETQueueOpFailed }
|
|
################ end of OFPT_ERRORS #################
|
|
class OFPTEchoRequest(_ofp_header):
|
name = "OFPT_ECHO_REQUEST"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 2, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0) ]
|
overload_fields = {TCP: {"sport": 6653}}
|
|
class OFPTEchoReply(_ofp_header):
|
name = "OFPT_ECHO_REPLY"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 3, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0) ]
|
overload_fields = {TCP: {"sport": 6653}}
|
|
class OFPTVendor(_ofp_header):
|
name = "OFPT_VENDOR"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 4, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
IntField("vendor", 0) ]
|
overload_fields = {TCP: {"sport": 6653}}
|
|
class OFPTFeaturesRequest(_ofp_header):
|
name = "OFPT_FEATURES_REQUEST"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 5, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0) ]
|
overload_fields = {TCP: {"sport": 6653}}
|
|
ofp_action_types_flags = list(ofp_action_types.values())[:-1] # no ofpat_vendor flag
|
|
class OFPTFeaturesReply(_ofp_header):
|
name = "OFPT_FEATURES_REPLY"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 6, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
LongField("datapath_id", 0),
|
IntField("n_buffers", 0),
|
ByteField("n_tables", 1),
|
X3BytesField("pad", 0),
|
FlagsField("capabilities", 0, 32, [ "FLOW_STATS",
|
"TABLE_STATS",
|
"PORT_STATS",
|
"STP",
|
"RESERVED",
|
"IP_REASM",
|
"QUEUE_STATS",
|
"ARP_MATCH_IP" ]),
|
FlagsField("actions", 0, 32, ofp_action_types_flags),
|
PacketListField("ports", None, OFPPhyPort,
|
length_from=lambda pkt:pkt.len-32) ]
|
overload_fields = {TCP: {"dport": 6653}}
|
|
class OFPTGetConfigRequest(_ofp_header):
|
name = "OFPT_GET_CONFIG_REQUEST"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 7, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0) ]
|
overload_fields = {TCP: {"sport": 6653}}
|
|
class OFPTGetConfigReply(_ofp_header):
|
name = "OFPT_GET_CONFIG_REPLY"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 8, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("flags", 0, { 0: "FRAG_NORMAL",
|
1: "FRAG_DROP",
|
2: "FRAG_REASM",
|
3: "FRAG_MASK" }),
|
ShortField("miss_send_len", 0) ]
|
overload_fields = {TCP: {"dport": 6653}}
|
|
class OFPTSetConfig(_ofp_header):
|
name = "OFPT_SET_CONFIG"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 9, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("flags", 0, { 0: "FRAG_NORMAL",
|
1: "FRAG_DROP",
|
2: "FRAG_REASM",
|
3: "FRAG_MASK" }),
|
ShortField("miss_send_len", 128) ]
|
overload_fields = {TCP: {"sport": 6653}}
|
|
class OFPTPacketIn(_ofp_header):
|
name = "OFPT_PACKET_IN"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 10, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
IntEnumField("buffer_id", "NO_BUFFER", ofp_buffer),
|
ShortField("total_len", 0),
|
ShortEnumField("in_port", 0, ofp_port_no),
|
ByteEnumField("reason", 0, { 0: "OFPR_NO_MATCH",
|
1: "OFPR_ACTION" }),
|
XByteField("pad", 0),
|
PacketField("data", None, Ether) ]
|
overload_fields = {TCP: {"dport": 6653}}
|
|
class OFPTFlowRemoved(_ofp_header):
|
name = "OFPT_FLOW_REMOVED"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 11, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
PacketField("match", OFPMatch(), OFPMatch),
|
LongField("cookie", 0),
|
ShortField("priority", 0),
|
ByteEnumField("reason", 0, { 0: "OFPRR_IDLE_TIMEOUT",
|
1: "OFPRR_HARD_TIMEOUT",
|
2: "OFPRR_DELETE" }),
|
XByteField("pad1", 0),
|
IntField("duration_sec", 0),
|
IntField("duration_nsec", 0),
|
ShortField("idle_timeout", 0),
|
XShortField("pad2", 0),
|
LongField("packet_count", 0),
|
LongField("byte_count", 0) ]
|
overload_fields = {TCP: {"dport": 6653}}
|
|
class OFPTPortStatus(_ofp_header):
|
name = "OFPT_PORT_STATUS"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 12, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ByteEnumField("reason", 0, { 0: "OFPPR_ADD",
|
1: "OFPPR_DELETE",
|
2: "OFPPR_MODIFY" }),
|
XBitField("pad", 0, 56),
|
PacketField("desc", OFPPhyPort(), OFPPhyPort) ]
|
overload_fields = {TCP: {"dport": 6653}}
|
|
class OFPTPacketOut(_ofp_header):
|
name = "OFPT_PACKET_OUT"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 13, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
IntEnumField("buffer_id", "NO_BUFFER", ofp_buffer),
|
ShortEnumField("in_port", "NONE", ofp_port_no),
|
FieldLenField("actions_len", None, fmt="H", length_of="actions"),
|
ActionPacketListField("actions", [], Packet,
|
length_from=lambda pkt:pkt.actions_len),
|
PacketField("data", None, Ether) ]
|
overload_fields = {TCP: {"sport": 6653}}
|
|
class OFPTFlowMod(_ofp_header):
|
name = "OFPT_FLOW_MOD"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 14, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
PacketField("match", OFPMatch(), OFPMatch),
|
LongField("cookie", 0),
|
ShortEnumField("cmd", 0, { 0: "OFPFC_ADD",
|
1: "OFPFC_MODIFY",
|
2: "OFPFC_MODIFY_STRICT",
|
3: "OFPFC_DELETE",
|
4: "OFPFC_DELETE_STRICT" }),
|
ShortField("idle_timeout", 0),
|
ShortField("hard_timeout", 0),
|
ShortField("priority", 0),
|
IntEnumField("buffer_id", "NO_BUFFER", ofp_buffer),
|
ShortEnumField("out_port", "NONE", ofp_port_no),
|
FlagsField("flags", 0, 16, [ "SEND_FLOW_REM",
|
"CHECK_OVERLAP",
|
"EMERG" ]),
|
ActionPacketListField("actions", [], Packet,
|
length_from=lambda pkt:pkt.len-72) ]
|
overload_fields = {TCP: {"sport": 6653}}
|
|
class OFPTPortMod(_ofp_header):
|
name = "OFPT_PORT_MOD"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 15, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("port_no", 0, ofp_port_no),
|
MACField("hw_addr", "0"),
|
FlagsField("config", 0, 32, ofp_port_config),
|
FlagsField("mask", 0, 32, ofp_port_config),
|
FlagsField("advertise", 0, 32, ofp_port_features),
|
IntField("pad", 0) ]
|
overload_fields = {TCP: {"sport": 6653}}
|
|
#####################################################
|
##################### OFPT_STATS ####################
|
#####################################################
|
|
ofp_stats_types = { 0: "OFPST_DESC",
|
1: "OFPST_FLOW",
|
2: "OFPST_AGGREGATE",
|
3: "OFPST_TABLE",
|
4: "OFPST_PORT",
|
5: "OFPST_QUEUE",
|
65535: "OFPST_VENDOR" }
|
|
class OFPTStatsRequestDesc(_ofp_header):
|
name = "OFPST_STATS_REQUEST_DESC"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 16, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("stats_type", 0, ofp_stats_types),
|
FlagsField("flags", 0, 16, []) ]
|
overload_fields = {TCP: {"sport": 6653}}
|
|
class OFPTStatsReplyDesc(_ofp_header):
|
name = "OFPST_STATS_REPLY_DESC"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 17, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("stats_type", 0, ofp_stats_types),
|
FlagsField("flags", 0, 16, []),
|
StrFixedLenField("mfr_desc", "", 256),
|
StrFixedLenField("hw_desc", "", 256),
|
StrFixedLenField("sw_desc", "", 256),
|
StrFixedLenField("serial_num", "", 32),
|
StrFixedLenField("dp_desc", "", 256) ]
|
overload_fields = {TCP: {"dport": 6653}}
|
|
class OFPTStatsRequestFlow(_ofp_header):
|
name = "OFPST_STATS_REQUEST_FLOW"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 16, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("stats_type", 1, ofp_stats_types),
|
FlagsField("flags", 0, 16, []),
|
PacketField("match", OFPMatch(), OFPMatch),
|
ByteEnumField("table_id", "ALL", ofp_table),
|
ByteField("pad", 0),
|
ShortEnumField("out_port", "NONE", ofp_port_no) ]
|
overload_fields = {TCP: {"sport": 6653}}
|
|
class OFPFlowStats(Packet):
|
|
def post_build(self, p, pay):
|
if self.length is None:
|
l = len(p)+len(pay)
|
p = struct.pack("!H", l) + p[2:]
|
return p + pay
|
|
name = "OFP_FLOW_STATS"
|
fields_desc = [ ShortField("length", None),
|
ByteField("table_id", 0),
|
XByteField("pad1", 0),
|
PacketField("match", OFPMatch(), OFPMatch),
|
IntField("duration_sec", 0),
|
IntField("duration_nsec", 0),
|
ShortField("priority", 0),
|
ShortField("idle_timeout", 0),
|
ShortField("hard_timeout", 0),
|
XBitField("pad2", 0, 48),
|
LongField("cookie", 0),
|
LongField("packet_count", 0),
|
LongField("byte_count", 0),
|
ActionPacketListField("actions", [], Packet,
|
length_from=lambda pkt:pkt.length-88) ]
|
|
class FlowStatsPacketListField(PacketListField):
|
|
@staticmethod
|
def _get_flow_stats_length(s):
|
return struct.unpack("!H", s[:2])[0]
|
|
def getfield(self, pkt, s):
|
lst = []
|
remain = s
|
|
while remain:
|
l = FlowStatsPacketListField._get_flow_stats_length(remain)
|
current = remain[:l]
|
remain = remain[l:]
|
p = OFPFlowStats(current)
|
lst.append(p)
|
|
return remain, lst
|
|
class OFPTStatsReplyFlow(_ofp_header):
|
name = "OFPST_STATS_REPLY_FLOW"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 17, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("stats_type", 1, ofp_stats_types),
|
FlagsField("flags", 0, 16, []),
|
FlowStatsPacketListField("flow_stats", [], Packet,
|
length_from=lambda pkt:pkt.len-12) ]
|
overload_fields = {TCP: {"dport": 6653}}
|
|
class OFPTStatsRequestAggregate(_ofp_header):
|
name = "OFPST_STATS_REQUEST_AGGREGATE"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 16, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("stats_type", 2, ofp_stats_types),
|
FlagsField("flags", 0, 16, []),
|
PacketField("match", OFPMatch(), OFPMatch),
|
ByteEnumField("table_id", "ALL", ofp_table),
|
ByteField("pad", 0),
|
ShortEnumField("out_port", "NONE", ofp_port_no) ]
|
overload_fields = {TCP: {"sport": 6653}}
|
|
class OFPTStatsReplyAggregate(_ofp_header):
|
name = "OFPST_STATS_REPLY_AGGREGATE"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 17, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("stats_type", 2, ofp_stats_types),
|
FlagsField("flags", 0, 16, []),
|
LongField("packet_count", 0),
|
LongField("byte_count", 0),
|
IntField("flow_count", 0),
|
XIntField("pad", 0) ]
|
overload_fields = {TCP: {"dport": 6653}}
|
|
class OFPTStatsRequestTable(_ofp_header):
|
name = "OFPST_STATS_REQUEST_TABLE"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 16, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("stats_type", 3, ofp_stats_types),
|
FlagsField("flags", 0, 16, []) ]
|
overload_fields = {TCP: {"sport": 6653}}
|
|
class OFPTableStats(Packet):
|
|
def extract_padding(self, s):
|
return "", s
|
|
name = "OFP_TABLE_STATS"
|
fields_desc = [ ByteField("table_id", 0),
|
X3BytesField("pad", 0),
|
StrFixedLenField("name", "", 32),
|
FlagsField("wildcards1", 0x003, 12, [ "DL_VLAN_PCP",
|
"NW_TOS" ]),
|
BitField("nw_dst_mask", 63, 6), # 32 would be enough
|
BitField("nw_src_mask", 63, 6),
|
FlagsField("wildcards2", 0xff, 8, [ "IN_PORT",
|
"DL_VLAN",
|
"DL_SRC",
|
"DL_DST",
|
"DL_TYPE",
|
"NW_PROTO",
|
"TP_SRC",
|
"TP_DST" ]),
|
IntField("max_entries", 0),
|
IntField("active_count", 0),
|
LongField("lookup_count", 0),
|
LongField("matched_count", 0) ]
|
|
class OFPTStatsReplyTable(_ofp_header):
|
name = "OFPST_STATS_REPLY_TABLE"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 17, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("stats_type", 3, ofp_stats_types),
|
FlagsField("flags", 0, 16, []),
|
PacketListField("table_stats", None, OFPTableStats,
|
length_from=lambda pkt:pkt.len-12) ]
|
overload_fields = {TCP: {"dport": 6653}}
|
|
class OFPTStatsRequestPort(_ofp_header):
|
name = "OFPST_STATS_REQUEST_PORT"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 16, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("stats_type", 4, ofp_stats_types),
|
FlagsField("flags", 0, 16, []),
|
ShortEnumField("port_no", "NONE", ofp_port_no),
|
XBitField("pad", 0, 48) ]
|
overload_fields = {TCP: {"sport": 6653}}
|
|
class OFPPortStats(Packet):
|
|
def extract_padding(self, s):
|
return "", s
|
|
name = "OFP_PORT_STATS"
|
fields_desc = [ ShortEnumField("port_no", 0, ofp_port_no),
|
XBitField("pad", 0, 48),
|
LongField("rx_packets", 0),
|
LongField("tx_packets", 0),
|
LongField("rx_bytes", 0),
|
LongField("tx_bytes", 0),
|
LongField("rx_dropped", 0),
|
LongField("tx_dropped", 0),
|
LongField("rx_errors", 0),
|
LongField("tx_errors", 0),
|
LongField("rx_frame_err", 0),
|
LongField("rx_over_err", 0),
|
LongField("rx_crc_err", 0),
|
LongField("collisions", 0) ]
|
|
class OFPTStatsReplyPort(_ofp_header):
|
name = "OFPST_STATS_REPLY_TABLE"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 17, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("stats_type", 4, ofp_stats_types),
|
FlagsField("flags", 0, 16, []),
|
PacketListField("port_stats", None, OFPPortStats,
|
length_from=lambda pkt:pkt.len-12) ]
|
overload_fields = {TCP: {"dport": 6653}}
|
|
class OFPTStatsRequestQueue(_ofp_header):
|
name = "OFPST_STATS_REQUEST_QUEUE"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 16, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("stats_type", 5, ofp_stats_types),
|
FlagsField("flags", 0, 16, []),
|
ShortEnumField("port_no", "NONE", ofp_port_no),
|
XShortField("pad", 0),
|
IntEnumField("queue_id", "ALL", ofp_queue) ]
|
overload_fields = {TCP: {"sport": 6653}}
|
|
class OFPTStatsReplyQueue(_ofp_header):
|
name = "OFPST_STATS_REPLY_QUEUE"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 17, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("stats_type", 5, ofp_stats_types),
|
FlagsField("flags", 0, 16, []),
|
ShortEnumField("port_no", "NONE", ofp_port_no),
|
XShortField("pad", 0),
|
IntEnumField("queue_id", "ALL", ofp_queue),
|
LongField("tx_bytes", 0),
|
LongField("tx_packets", 0),
|
LongField("tx_errors", 0) ]
|
overload_fields = {TCP: {"dport": 6653}}
|
|
class OFPTStatsRequestVendor(_ofp_header):
|
name = "OFPST_STATS_REQUEST_VENDOR"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 16, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("stats_type", 6, ofp_stats_types),
|
FlagsField("flags", 0, 16, []),
|
IntField("vendor", 0) ]
|
overload_fields = {TCP: {"sport": 6653}}
|
|
class OFPTStatsReplyVendor(_ofp_header):
|
name = "OFPST_STATS_REPLY_VENDOR"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 17, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("stats_type", 6, ofp_stats_types),
|
FlagsField("flags", 0, 16, []),
|
IntField("vendor", 0) ]
|
overload_fields = {TCP: {"dport": 6653}}
|
|
# ofp_stats_request/reply_cls allows generic method OpenFlow() (end of script)
|
# to choose the right class for dissection
|
ofp_stats_request_cls = { 0: OFPTStatsRequestDesc,
|
1: OFPTStatsRequestFlow,
|
2: OFPTStatsRequestAggregate,
|
3: OFPTStatsRequestTable,
|
4: OFPTStatsRequestPort,
|
5: OFPTStatsRequestQueue,
|
65535: OFPTStatsRequestVendor }
|
|
ofp_stats_reply_cls = { 0: OFPTStatsReplyDesc,
|
1: OFPTStatsReplyFlow,
|
2: OFPTStatsReplyAggregate,
|
3: OFPTStatsReplyTable,
|
4: OFPTStatsReplyPort,
|
5: OFPTStatsReplyQueue,
|
65535: OFPTStatsReplyVendor }
|
|
################ end of OFPT_STATS ##################
|
|
class OFPTBarrierRequest(_ofp_header):
|
name = "OFPT_BARRIER_REQUEST"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 18, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0) ]
|
overload_fields = {TCP: {"sport": 6653}}
|
|
class OFPTBarrierReply(_ofp_header):
|
name = "OFPT_BARRIER_REPLY"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 19, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0) ]
|
overload_fields = {TCP: {"dport": 6653}}
|
|
class OFPTQueueGetConfigRequest(_ofp_header):
|
name = "OFPT_QUEUE_GET_CONFIG_REQUEST"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 20, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("port", 0, ofp_port_no),
|
XShortField("pad", 0) ]
|
overload_fields = {TCP: {"sport": 6653}}
|
|
class OFPTQueueGetConfigReply(_ofp_header):
|
name = "OFPT_QUEUE_GET_CONFIG_REPLY"
|
fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
|
ByteEnumField("type", 21, ofp_type),
|
ShortField("len", None),
|
IntField("xid", 0),
|
ShortEnumField("port", 0, ofp_port_no),
|
XBitField("pad", 0, 48),
|
QueuePacketListField("queues", [], Packet,
|
length_from=lambda pkt:pkt.len-16) ]
|
overload_fields = {TCP: {"dport": 6653}}
|
|
# ofpt_cls allows generic method OpenFlow() to choose the right class for dissection
|
ofpt_cls = { 0: OFPTHello,
|
#1: OFPTError,
|
2: OFPTEchoRequest,
|
3: OFPTEchoReply,
|
4: OFPTVendor,
|
5: OFPTFeaturesRequest,
|
6: OFPTFeaturesReply,
|
7: OFPTGetConfigRequest,
|
8: OFPTGetConfigReply,
|
9: OFPTSetConfig,
|
10: OFPTPacketIn,
|
11: OFPTFlowRemoved,
|
12: OFPTPortStatus,
|
13: OFPTPacketOut,
|
14: OFPTFlowMod,
|
15: OFPTPortMod,
|
#16: OFPTStatsRequest,
|
#17: OFPTStatsReply,
|
18: OFPTBarrierRequest,
|
19: OFPTBarrierReply,
|
20: OFPTQueueGetConfigRequest,
|
21: OFPTQueueGetConfigReply }
|
|
TCP_guess_payload_class_copy = TCP.guess_payload_class
|
|
def OpenFlow(self, payload):
|
if self is None or self.dport == 6653 or self.dport == 6633 or self.sport == 6653 or self.sport == 6633:
|
# port 6653 has been allocated by IANA, port 6633 should no longer be used
|
# OpenFlow function may be called with None self in OFPPacketField
|
of_type = orb(payload[1])
|
if of_type == 1:
|
err_type = orb(payload[9])
|
# err_type is a short int, but last byte is enough
|
if err_type == 255: err_type = 65535
|
return ofp_error_cls[err_type]
|
elif of_type == 16:
|
mp_type = orb(payload[9])
|
if mp_type == 255: mp_type = 65535
|
return ofp_stats_request_cls[mp_type]
|
elif of_type == 17:
|
mp_type = orb(payload[9])
|
if mp_type == 255: mp_type = 65535
|
return ofp_stats_reply_cls[mp_type]
|
else:
|
return ofpt_cls[of_type]
|
else:
|
return TCP_guess_payload_class_copy(self, payload)
|
|
TCP.guess_payload_class = OpenFlow
|