| ## 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 |