esp32_bluetooth_classic_sni.../libs/scapy/contrib/openflow.py

1231 lines
48 KiB
Python
Raw Normal View History

# 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.compat import chb, orb, raw
from scapy.config import conf
from scapy.error import warning
from scapy.fields import BitEnumField, BitField, ByteEnumField, ByteField, FieldLenField, FlagsField, IntEnumField, IntField, IPField, LongField, MACField, PacketField, PacketListField, ShortEnumField, ShortField, StrFixedLenField, X3BytesField, XBitField, XByteField, XIntField, XShortField # noqa: E501
from scapy.layers.l2 import Ether
from scapy.layers.inet import TCP
from scapy.packet import Packet, Raw, bind_bottom_up, bind_top_down
from scapy.utils import binrepr
from scapy.modules import six
# If prereq_autocomplete is True then match prerequisites will be
# automatically handled. See OFPMatch class.
conf.contribs['OPENFLOW'] = {'prereq_autocomplete': True}
#####################################################
# 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 b"", 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 b"", 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
lst_bits = "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:
lst_bits += "1"
else:
lst_bits += "0"
if self.dl_vlan_pcp is None:
lst_bits += "1"
else:
lst_bits += "0"
else:
w1 = binrepr(self.wildcards1)
lst_bits += "0" * (2 - len(w1))
lst_bits += w1
# ip masks use 6 bits each
if self.nw_dst_mask is None:
if self.nw_dst == "0":
lst_bits += "111111"
# 0x100000 would be ok too (32-bit IP mask)
else:
lst_bits += "0" * 6
else:
m1 = binrepr(self.nw_dst_mask)
lst_bits += "0" * (6 - len(m1))
lst_bits += m1
if self.nw_src_mask is None:
if self.nw_src == "0":
lst_bits += "111111"
else:
lst_bits += "0" * 6
else:
m2 = binrepr(self.nw_src_mask)
lst_bits += "0" * (6 - len(m2))
lst_bits += m2
# wildcards2 works the same way as wildcards1
if self.wildcards2 is None:
if self.tp_dst is None:
lst_bits += "1"
else:
lst_bits += "0"
if self.tp_src is None:
lst_bits += "1"
else:
lst_bits += "0"
if self.nw_proto is None:
lst_bits += "1"
else:
lst_bits += "0"
if self.dl_type is None:
lst_bits += "1"
else:
lst_bits += "0"
if self.dl_dst is None:
lst_bits += "1"
else:
lst_bits += "0"
if self.dl_src is None:
lst_bits += "1"
else:
lst_bits += "0"
if self.dl_vlan is None:
lst_bits += "1"
else:
lst_bits += "0"
if self.in_port is None:
lst_bits += "1"
else:
lst_bits += "0"
else:
w2 = binrepr(self.wildcards2)
lst_bits += "0" * (8 - len(w2))
lst_bits += 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. # noqa: E501
if conf.contribs['OPENFLOW']['prereq_autocomplete']:
if self.dl_type is None:
if self.nw_src != "0" or self.nw_dst != "0" or \
self.nw_proto is not None or self.nw_tos is not None:
p = p[:22] + struct.pack("!H", 0x0800) + p[24:]
lst_bits = lst_bits[:-5] + "0" + lst_bits[-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:]
lst_bits = lst_bits[:-5] + "0" + lst_bits[-4:]
p = p[:25] + struct.pack("!B", 0x06) + p[26:]
lst_bits = lst_bits[:-6] + "0" + lst_bits[-5:]
ins = b"".join(chb(int("".join(x), 2)) for x in zip(*[iter(lst_bits)] * 8)) # noqa: E501
p = ins + p[4:]
return p + pay
class _ofp_header(Packet):
name = "Dummy OpenFlow Header for some lower layers"
def post_build(self, p, pay):
if self.len is None:
tmp_len = len(p) + len(pay)
p = p[:2] + struct.pack("!H", tmp_len) + p[4:]
return p + pay
class _ofp_header_item(Packet):
name = "Dummy OpenFlow Header for items layers"
def post_build(self, p, pay):
if self.len is None:
tmp_len = len(p) + len(pay)
p = struct.pack("!H", tmp_len) + p[2:]
return p + pay
# Actions #
class _UnknownOpenFlow(Raw):
name = "Unknown OpenFlow packet"
class OpenFlow(_ofp_header):
name = "OpenFlow dissector"
@classmethod
def dispatch_hook(cls, _pkt=None, *args, **kargs):
if _pkt and len(_pkt) >= 2:
version = orb(_pkt[0])
if version == 0x04: # OpenFlow 1.3
from scapy.contrib.openflow3 import OpenFlow3
return OpenFlow3.dispatch_hook(_pkt, *args, **kargs)
elif version == 0x01: # OpenFlow 1.0
# port 6653 has been allocated by IANA, port 6633 should no
# longer be used
# OpenFlow function may be called with a None
# self in OFPPacketField
of_type = orb(_pkt[1])
if of_type == 1:
err_type = orb(_pkt[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(_pkt[9])
if mp_type == 255:
mp_type = 65535
return ofp_stats_request_cls[mp_type]
elif of_type == 17:
mp_type = orb(_pkt[9])
if mp_type == 255:
mp_type = 65535
return ofp_stats_reply_cls[mp_type]
else:
return ofpt_cls[of_type]
else:
warning("Unknown OpenFlow packet")
return _UnknownOpenFlow
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(OpenFlow):
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(OpenFlow):
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(OpenFlow):
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(OpenFlow):
name = "OFPAT_STRIP_VLAN"
fields_desc = [ShortEnumField("type", 3, ofp_action_types),
ShortField("len", 8),
XIntField("pad", 0)]
class OFPATSetDlSrc(OpenFlow):
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(OpenFlow):
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(OpenFlow):
name = "OFPAT_SET_NW_SRC"
fields_desc = [ShortEnumField("type", 6, ofp_action_types),
ShortField("len", 8),
IPField("nw_addr", "0")]
class OFPATSetNwDst(OpenFlow):
name = "OFPAT_SET_NW_DST"
fields_desc = [ShortEnumField("type", 7, ofp_action_types),
ShortField("len", 8),
IPField("nw_addr", "0")]
class OFPATSetNwToS(OpenFlow):
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(OpenFlow):
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(OpenFlow):
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(OpenFlow):
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(OpenFlow):
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 OFPAT(Packet):
@classmethod
def dispatch_hook(cls, _pkt=None, *args, **kargs):
if _pkt and len(_pkt) >= 2:
t = struct.unpack("!H", _pkt[:2])[0]
return ofp_action_cls.get(t, Raw)
return Raw
def extract_padding(self, s):
return b"", s
# Queues #
ofp_queue_property_types = {0: "OFPQT_NONE",
1: "OFPQT_MIN_RATE"}
class OFPQTNone(_ofp_header):
name = "OFPQT_NONE"
fields_desc = [ShortEnumField("type", 0, ofp_queue_property_types),
ShortField("len", 8),
XIntField("pad", 0)]
class OFPQTMinRate(_ofp_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 OFPQT(Packet):
@classmethod
def dispatch_hook(cls, _pkt=None, *args, **kargs):
if _pkt and len(_pkt) >= 2:
t = struct.unpack("!H", _pkt[:2])[0]
return ofp_queue_property_cls.get(t, Raw)
return Raw
def extract_padding(self, s):
return b"", s
class OFPPacketQueue(Packet):
name = "OFP_PACKET_QUEUE"
fields_desc = [IntField("queue_id", 0),
ShortField("len", None),
XShortField("pad", 0),
PacketListField("properties", [], OFPQT,
length_from=lambda pkt:pkt.len - 8)] # noqa: E501
def extract_padding(self, s):
return b"", s
def post_build(self, p, pay):
if self.properties == []:
p += raw(OFPQTNone())
if self.len is None:
tmp_len = len(p) + len(pay)
p = p[:4] + struct.pack("!H", tmp_len) + p[6:]
return p + pay
#####################################################
# OpenFlow 1.0 Messages #
#####################################################
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)]
#####################################################
# 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:
tmp_len = s[2:4]
tmp_len = struct.unpack("!H", tmp_len)[0]
ofload = s[:tmp_len]
remain = s[tmp_len:]
return remain, OpenFlow(ofload)
except Exception:
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)]
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)]
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)]
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", # noqa: E501
4: "OFPFMFC_BAD_COMMAND",
5: "OFPFMFC_UNSUPPORTED"}),
OFPacketField("data", "", Raw)]
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)]
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)]
# ofp_error_cls allows generic method OpenFlow() to choose the right class for dissection # noqa: E501
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)]
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)]
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)]
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)]
ofp_action_types_flags = [v for v in six.itervalues(ofp_action_types)
if v != 'OFPAT_VENDOR']
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", [], OFPPhyPort,
length_from=lambda pkt:pkt.len - 32)]
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)]
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)]
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)]
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)]
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)]
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)]
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"), # noqa: E501
PacketListField("actions", [], OFPAT,
ofp_action_cls,
length_from=lambda pkt:pkt.actions_len), # noqa: E501
PacketField("data", None, Ether)]
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"]),
PacketListField("actions", [], OFPAT,
ofp_action_cls,
length_from=lambda pkt:pkt.len - 72)]
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)]
#####################################################
# 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, [])]
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)]
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)]
class OFPFlowStats(Packet):
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),
PacketListField("actions", [], OFPAT,
ofp_action_cls,
length_from=lambda pkt:pkt.length - 88)]
def post_build(self, p, pay):
if self.length is None:
tmp_len = len(p) + len(pay)
p = struct.pack("!H", tmp_len) + p[2:]
return p + pay
def extract_padding(self, s):
return b"", s
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, []),
PacketListField("flow_stats", [], OFPFlowStats,
length_from=lambda pkt:pkt.len - 12)] # noqa: E501
class OFPTStatsRequestAggregate(OFPTStatsRequestFlow):
name = "OFPST_STATS_REQUEST_AGGREGATE"
stats_type = 2
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)]
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, [])]
class OFPTableStats(Packet):
def extract_padding(self, s):
return b"", 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", [], OFPTableStats,
length_from=lambda pkt:pkt.len - 12)]
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)]
class OFPPortStats(Packet):
def extract_padding(self, s):
return b"", 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", [], OFPPortStats,
length_from=lambda pkt:pkt.len - 12)]
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)]
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)]
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)]
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)]
# 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)]
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)]
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)]
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),
PacketListField("queues", [], OFPPacketQueue,
length_from=lambda pkt:pkt.len - 16)]
# ofpt_cls allows generic method OpenFlow() to choose the right class for dissection # noqa: E501
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}
bind_bottom_up(TCP, OpenFlow, dport=6653)
bind_bottom_up(TCP, OpenFlow, sport=6653)
bind_bottom_up(TCP, OpenFlow, dport=6633)
bind_bottom_up(TCP, OpenFlow, sport=6633)
bind_top_down(TCP, _ofp_header, sport=6653, dport=6653)