Home | History | Annotate | Download | only in contrib
      1 ## This file is part of Scapy
      2 ## See http://www.secdev.org/projects/scapy for more information
      3 ## Copyright (C) Philippe Biondi <phil (at] secdev.org>
      4 ## This program is published under a GPLv2 license
      5 
      6 ## Copyright (C) 2014 Maxence Tury <maxence.tury (at] ssi.gouv.fr>
      7 ## OpenFlow is an open standard used in SDN deployments.
      8 ## Based on OpenFlow v1.0.1
      9 ## Specifications can be retrieved from https://www.opennetworking.org/
     10 
     11 # scapy.contrib.description = Openflow v1.0
     12 # scapy.contrib.status = loads
     13 
     14 from __future__ import absolute_import
     15 import struct
     16 from scapy.fields import *
     17 from scapy.layers.l2 import *
     18 from scapy.layers.inet import *
     19 from scapy.compat import orb
     20 
     21 ### If prereq_autocomplete is True then match prerequisites will be
     22 ### automatically handled. See OFPMatch class.
     23 prereq_autocomplete = False
     24 
     25 #####################################################
     26 ################# Predefined values #################
     27 #####################################################
     28 
     29 ofp_port_no = { 0xfff8: "IN_PORT",
     30                 0xfff9: "TABLE",
     31                 0xfffa: "NORMAL",
     32                 0xfffb: "FLOOD",
     33                 0xfffc: "ALL",
     34                 0xfffd: "CONTROLLER",
     35                 0xfffe: "LOCAL",
     36                 0xffff: "NONE" }
     37 
     38 ofp_table = { 0xff: "ALL" }
     39 
     40 ofp_queue = { 0xffffffff: "ALL" }
     41 
     42 ofp_buffer = { 0xffffffff: "NO_BUFFER" }
     43 
     44 ofp_max_len = { 0xffff: "NO_BUFFER" }
     45 
     46 #####################################################
     47 ################# Common structures #################
     48 #####################################################
     49 
     50 ### The following structures will be used in different types
     51 ### of OpenFlow messages: ports, matches, actions, queues.
     52 
     53 
     54 ##################### Ports #####################
     55 
     56 ofp_port_config = [ "PORT_DOWN",
     57                     "NO_STP",
     58                     "NO_RECV",
     59                     "NO_RECV_STP",
     60                     "NO_FLOOD",
     61                     "NO_FWD",
     62                     "NO_PACKET_IN" ]
     63 
     64 ofp_port_state = [ "LINK_DOWN" ]
     65 
     66 ofp_port_state_stp = { 0: "OFPPS_STP_LISTEN",
     67                        1: "OFPPS_STP_LEARN",
     68                        2: "OFPPS_STP_FORWARD",
     69                        3: "OFPPS_STP_BLOCK" }
     70 
     71 ofp_port_features = [ "10MB_HD",
     72                       "10MB_FD",
     73                       "100MB_HD",
     74                       "100MB_FD",
     75                       "1GB_HD",
     76                       "1GB_FD",
     77                       "10GB_FD",
     78                       "COPPER",
     79                       "FIBER",
     80                       "AUTONEG",
     81                       "PAUSE",
     82                       "PAUSE_ASYM" ]
     83 
     84 class OFPPhyPort(Packet):
     85     name = "OFP_PHY_PORT"
     86     fields_desc = [ ShortEnumField("port_no", 0, ofp_port_no),
     87                     MACField("hw_addr", "0"),
     88                     StrFixedLenField("port_name", "", 16),
     89                     FlagsField("config", 0, 32, ofp_port_config),
     90                     BitEnumField("stp_state", 0, 24, ofp_port_state),
     91                     FlagsField("state", 0, 8, ofp_port_state),
     92                     FlagsField("curr", 0, 32, ofp_port_features),
     93                     FlagsField("advertised", 0, 32, ofp_port_features),
     94                     FlagsField("supported", 0, 32, ofp_port_features),
     95                     FlagsField("peer", 0, 32, ofp_port_features) ]
     96 
     97     def extract_padding(self, s):
     98         return "", s
     99 
    100 class OFPMatch(Packet):
    101     name = "OFP_MATCH"
    102     fields_desc= [ FlagsField("wildcards1", None, 12, [ "DL_VLAN_PCP",
    103                                                         "NW_TOS" ]),
    104                    BitField("nw_dst_mask", None, 6),
    105                    BitField("nw_src_mask", None, 6),
    106                    FlagsField("wildcards2", None, 8, [ "IN_PORT",
    107                                                        "DL_VLAN",
    108                                                        "DL_SRC",
    109                                                        "DL_DST",
    110                                                        "DL_TYPE",
    111                                                        "NW_PROTO",
    112                                                        "TP_SRC",
    113                                                        "TP_DST" ]),
    114                    ShortEnumField("in_port", None, ofp_port_no),
    115                    MACField("dl_src", None),
    116                    MACField("dl_dst", None),
    117                    ShortField("dl_vlan", None),
    118                    ByteField("dl_vlan_pcp", None),
    119                    XByteField("pad1", None),
    120                    ShortField("dl_type", None),
    121                    ByteField("nw_tos", None),
    122                    ByteField("nw_proto", None),
    123                    XShortField("pad2", None),
    124                    IPField("nw_src", "0"),
    125                    IPField("nw_dst", "0"),
    126                    ShortField("tp_src", None),
    127                    ShortField("tp_dst", None) ]
    128 
    129     def extract_padding(self, s):
    130         return "", s
    131 
    132     ### with post_build we create the wildcards field bit by bit
    133     def post_build(self, p, pay):
    134         # first 10 bits of an ofp_match are always set to 0
    135         l = "0"*10
    136 
    137         # when one field has not been declared, it is assumed to be wildcarded
    138         if self.wildcards1 is None:
    139             if self.nw_tos is None: l+="1"
    140             else: l+="0"
    141             if self.dl_vlan_pcp is None: l+="1"
    142             else: l+="0"
    143         else:
    144             w1 = binrepr(self.wildcards1)
    145             l+="0"*(2-len(w1))
    146             l+=w1
    147                     
    148         # ip masks use 6 bits each
    149         if self.nw_dst_mask is None:
    150             if self.nw_dst is "0": l+="111111"
    151             # 0x100000 would be ok too (32-bit IP mask)
    152             else: l+="0"*6
    153         else:
    154             m1 = binrepr(self.nw_dst_mask)
    155             l+="0"*(6-len(m1))
    156             l+=m1
    157         if self.nw_src_mask is None:
    158             if self.nw_src is "0": l+="111111"
    159             else: l+="0"*6
    160         else:
    161             m2 = binrepr(self.nw_src_mask)
    162             l+="0"*(6-len(m2))
    163             l+=m2
    164 
    165         # wildcards2 works the same way as wildcards1
    166         if self.wildcards2 is None:
    167             if self.tp_dst is None: l+="1"
    168             else: l+="0"
    169             if self.tp_src is None: l+="1"
    170             else: l+="0"
    171             if self.nw_proto is None: l+="1"
    172             else: l+="0"
    173             if self.dl_type is None: l+="1"
    174             else: l+="0"
    175             if self.dl_dst is None: l+="1"
    176             else: l+="0"
    177             if self.dl_src is None: l+="1"
    178             else: l+="0"
    179             if self.dl_vlan is None: l+="1"
    180             else: l+="0"
    181             if self.in_port is None: l+="1"
    182             else: l+="0"
    183         else:
    184             w2 = binrepr(self.wildcards2)
    185             l+="0"*(8-len(w2))
    186             l+=w2
    187 
    188         ### In order to write OFPMatch compliant with the specifications,
    189         ### if prereq_autocomplete has been set to True
    190         ### we assume ethertype=IP or nwproto=TCP when appropriate subfields are provided.
    191         if prereq_autocomplete:
    192             if self.dl_type is None:
    193                 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:
    194                     p = p[:22] + struct.pack("!H", 0x0800) + p[24:]
    195                     l = l[:-5] + "0" + l[-4:]
    196             if self.nw_proto is None:
    197                 if self.tp_src is not None or self.tp_dst is not None:
    198                     p = p[:22] + struct.pack("!H", 0x0800) + p[24:]
    199                     l = l[:-5] + "0" + l[-4:]
    200                     p = p[:25] + struct.pack("!B", 0x06) + p[26:]
    201                     l = l[:-6] + "0" + l[-5:]
    202 
    203         ins = b"".join(chb(int("".join(x),2)) for x in zip(*[iter(l)]*8))
    204         p = ins + p[4:]
    205         return p + pay
    206 
    207 
    208 ###################### Actions ######################
    209 
    210 class _ofp_action_header(Packet):
    211     name = "Dummy OpenFlow Action Header"
    212 
    213     def post_build(self, p, pay):
    214         if self.len is None:
    215             l = len(p)+len(pay)
    216             p = p[:2] + struct.pack("!H", l) + p[4:]
    217         return p + pay
    218 
    219 ofp_action_types = {     0: "OFPAT_OUTPUT",
    220                          1: "OFPAT_SET_VLAN_VID",
    221                          2: "OFPAT_SET_VLAN_PCP",
    222                          3: "OFPAT_STRIP_VLAN",
    223                          4: "OFPAT_SET_DL_SRC",
    224                          5: "OFPAT_SET_DL_DST",
    225                          6: "OFPAT_SET_NW_SRC",
    226                          7: "OFPAT_SET_NW_DST",
    227                          8: "OFPAT_SET_NW_TOS",
    228                          9: "OFPAT_SET_TP_SRC",
    229                         10: "OFPAT_SET_TP_DST",
    230                         11: "OFPAT_ENQUEUE",
    231                      65535: "OFPAT_VENDOR" }
    232 
    233 class OFPATOutput(_ofp_action_header):
    234     name = "OFPAT_OUTPUT"
    235     fields_desc = [ ShortEnumField("type", 0, ofp_action_types),
    236                     ShortField("len", 8),
    237                     ShortEnumField("port", 0, ofp_port_no),
    238                     ShortEnumField("max_len", "NO_BUFFER", ofp_max_len) ]
    239 
    240 class OFPATSetVLANVID(_ofp_action_header):
    241     name = "OFPAT_SET_VLAN_VID"
    242     fields_desc = [ ShortEnumField("type", 1, ofp_action_types),
    243                     ShortField("len", 8),
    244                     ShortField("vlan_vid", 0),
    245                     XShortField("pad", 0) ]
    246 
    247 class OFPATSetVLANPCP(_ofp_action_header):
    248     name = "OFPAT_SET_VLAN_PCP"
    249     fields_desc = [ ShortEnumField("type", 2, ofp_action_types),
    250                     ShortField("len", 8),
    251                     ByteField("vlan_pcp", 0),
    252                     X3BytesField("pad", 0) ]
    253 
    254 class OFPATStripVLAN(_ofp_action_header):
    255     name = "OFPAT_STRIP_VLAN"
    256     fields_desc = [ ShortEnumField("type", 3, ofp_action_types),
    257                     ShortField("len", 8),
    258                     XIntField("pad", 0) ]
    259 
    260 class OFPATSetDlSrc(_ofp_action_header):
    261     name = "OFPAT_SET_DL_SRC"
    262     fields_desc = [ ShortEnumField("type", 4, ofp_action_types),
    263                     ShortField("len", 16),
    264                     MACField("dl_addr", "0"),
    265                     XBitField("pad", 0, 48) ]
    266 
    267 class OFPATSetDlDst(_ofp_action_header):
    268     name = "OFPAT_SET_DL_DST"
    269     fields_desc = [ ShortEnumField("type", 5, ofp_action_types),
    270                     ShortField("len", 16),
    271                     MACField("dl_addr", "0"),
    272                     XBitField("pad", 0, 48) ]
    273 
    274 class OFPATSetNwSrc(_ofp_action_header):
    275     name = "OFPAT_SET_NW_SRC"
    276     fields_desc = [ ShortEnumField("type", 6, ofp_action_types),
    277                     ShortField("len", 8),
    278                     IPField("nw_addr", "0") ]
    279 
    280 class OFPATSetNwDst(_ofp_action_header):
    281     name = "OFPAT_SET_NW_DST"
    282     fields_desc = [ ShortEnumField("type", 7, ofp_action_types),
    283                     ShortField("len", 8),
    284                     IPField("nw_addr", "0") ]
    285 
    286 class OFPATSetNwToS(_ofp_action_header):
    287     name = "OFPAT_SET_TP_TOS"
    288     fields_desc = [ ShortEnumField("type", 8, ofp_action_types),
    289                     ShortField("len", 8),
    290                     ByteField("nw_tos", 0),
    291                     X3BytesField("pad", 0) ]
    292 
    293 class OFPATSetTpSrc(_ofp_action_header):
    294     name = "OFPAT_SET_TP_SRC"
    295     fields_desc = [ ShortEnumField("type", 9, ofp_action_types),
    296                     ShortField("len", 8),
    297                     ShortField("tp_port", 0),
    298                     XShortField("pad", 0) ]
    299 
    300 class OFPATSetTpDst(_ofp_action_header):
    301     name = "OFPAT_SET_TP_DST"
    302     fields_desc = [ ShortEnumField("type", 10, ofp_action_types),
    303                     ShortField("len", 8),
    304                     ShortField("tp_port", 0),
    305                     XShortField("pad", 0) ]
    306 
    307 class OFPATEnqueue(_ofp_action_header):
    308     name = "OFPAT_ENQUEUE"
    309     fields_desc = [ ShortEnumField("type", 11, ofp_action_types),
    310                     ShortField("len", 16),
    311                     ShortEnumField("port", 0, ofp_port_no),
    312                     XBitField("pad", 0, 48),
    313                     IntField("queue_id", 0) ]
    314 
    315 class OFPATVendor(_ofp_action_header):
    316     name = "OFPAT_VENDOR"
    317     fields_desc = [ ShortEnumField("type", 65535, ofp_action_types),
    318                     ShortField("len", 8),
    319                     IntField("vendor", 0) ]
    320 
    321 ofp_action_cls = {     0: OFPATOutput,
    322                        1: OFPATSetVLANVID,
    323                        2: OFPATSetVLANPCP,
    324                        3: OFPATStripVLAN,
    325                        4: OFPATSetDlSrc,
    326                        5: OFPATSetDlDst,
    327                        6: OFPATSetNwSrc,
    328                        7: OFPATSetNwDst,
    329                        8: OFPATSetNwToS,
    330                        9: OFPATSetTpSrc,
    331                       10: OFPATSetTpDst,
    332                       11: OFPATEnqueue,
    333                    65535: OFPATVendor }
    334 
    335 class ActionPacketListField(PacketListField):
    336     def m2i(self, pkt, s):
    337         t = struct.unpack("!H", s[:2])[0]
    338         return ofp_action_cls.get(t, Raw)(s)
    339 
    340     @staticmethod
    341     def _get_action_length(s):
    342         return struct.unpack("!H", s[2:4])[0]
    343 
    344     def getfield(self, pkt, s):
    345         lst = []
    346         remain = s
    347 
    348         while remain:
    349             l = ActionPacketListField._get_action_length(remain)
    350             current = remain[:l]
    351             remain = remain[l:]
    352             p = self.m2i(pkt, current)
    353             lst.append(p)
    354 
    355         return remain, lst
    356 
    357 
    358 ####################### Queues ######################
    359 
    360 class _ofp_queue_property_header(Packet):
    361     name = "Dummy OpenFlow Queue Property Header"
    362 
    363     def post_build(self, p, pay):
    364         if self.len is None:
    365             l = len(p)+len(pay)
    366             p = p[:2] + struct.pack("!H", l) + p[4:]
    367         return p + pay
    368 
    369 ofp_queue_property_types = { 0: "OFPQT_NONE",
    370                              1: "OFPQT_MIN_RATE" }
    371 
    372 class OFPQTNone(_ofp_queue_property_header):
    373     name = "OFPQT_NONE"
    374     fields_desc = [ ShortEnumField("type", 0, ofp_queue_property_types),
    375                     ShortField("len", 8),
    376                     XIntField("pad", 0) ]
    377 
    378 class OFPQTMinRate(_ofp_queue_property_header):
    379     name = "OFPQT_MIN_RATE"
    380     fields_desc = [ ShortEnumField("type", 1, ofp_queue_property_types),
    381                     ShortField("len", 16),
    382                     XIntField("pad", 0),
    383                     ShortField("rate", 0),
    384                     XBitField("pad2", 0, 48) ]
    385 
    386 ofp_queue_property_cls = { 0: OFPQTNone,
    387                            1: OFPQTMinRate }
    388 
    389 class QueuePropertyPacketListField(PacketListField):
    390     def m2i(self, pkt, s):
    391         t = struct.unpack("!H", s[:2])[0]
    392         return ofp_queue_property_cls.get(t, Raw)(s)
    393 
    394     @staticmethod
    395     def _get_queue_property_length(s):
    396         return struct.unpack("!H", s[2:4])[0]
    397 
    398     def getfield(self, pkt, s):
    399         lst = []
    400         l = 0
    401         ret = ""
    402         remain = s
    403 
    404         while remain:
    405             l = QueuePropertyPacketListField._get_queue_property_length(remain)
    406             current = remain[:l]
    407             remain = remain[l:]
    408             p = self.m2i(pkt, current)
    409             lst.append(p)
    410 
    411         return remain + ret, lst
    412 
    413 class OFPPacketQueue(Packet):
    414 
    415     def extract_padding(self, s):
    416         return "", s
    417 
    418     def post_build(self, p, pay):
    419         if self.properties == []:
    420             p += str(OFPQTNone())
    421         if self.len is None:
    422             l = len(p)+len(pay)
    423             p = p[:4] + struct.pack("!H", l) + p[6:]
    424         return p + pay
    425 
    426     name = "OFP_PACKET_QUEUE"
    427     fields_desc = [ IntField("queue_id", 0),
    428                     ShortField("len", None),
    429                     XShortField("pad", 0),
    430                     QueuePropertyPacketListField("properties", [], Packet,
    431                                                  length_from=lambda pkt:pkt.len-8) ]
    432 
    433 class QueuePacketListField(PacketListField):
    434 
    435     @staticmethod
    436     def _get_queue_length(s):
    437         return struct.unpack("!H", s[4:6])[0]
    438 
    439     def getfield(self, pkt, s):
    440         lst = []
    441         l = 0
    442         ret = ""
    443         remain = s
    444 
    445         while remain:
    446             l = QueuePacketListField._get_queue_length(remain)
    447             current = remain[:l]
    448             remain = remain[l:]
    449             p = OFPPacketQueue(current)
    450             lst.append(p)
    451 
    452         return remain + ret, lst
    453 
    454 
    455 #####################################################
    456 ############## OpenFlow 1.0 Messages ################
    457 #####################################################
    458 
    459 class _ofp_header(Packet):
    460     name = "Dummy OpenFlow Header"
    461 
    462     def post_build(self, p, pay):
    463         if self.len is None:
    464             l = len(p)+len(pay)
    465             p = p[:2] + struct.pack("!H", l) + p[4:]
    466         return p + pay
    467 
    468 ofp_version = { 0x01: "OpenFlow 1.0",
    469                 0x02: "OpenFlow 1.1",
    470                 0x03: "OpenFlow 1.2",
    471                 0x04: "OpenFlow 1.3",
    472                 0x05: "OpenFlow 1.4" }
    473 
    474 ofp_type = {  0: "OFPT_HELLO",
    475               1: "OFPT_ERROR",
    476               2: "OFPT_ECHO_REQUEST",
    477               3: "OFPT_ECHO_REPLY",
    478               4: "OFPT_VENDOR",
    479               5: "OFPT_FEATURES_REQUEST",
    480               6: "OFPT_FEATURES_REPLY",
    481               7: "OFPT_GET_CONFIG_REQUEST",
    482               8: "OFPT_GET_CONFIG_REPLY",
    483               9: "OFPT_SET_CONFIG",
    484              10: "OFPT_PACKET_IN",
    485              11: "OFPT_FLOW_REMOVED",
    486              12: "OFPT_PORT_STATUS",
    487              13: "OFPT_PACKET_OUT",
    488              14: "OFPT_FLOW_MOD",
    489              15: "OFPT_PORT_MOD",
    490              16: "OFPT_STATS_REQUEST",
    491              17: "OFPT_STATS_REPLY",
    492              18: "OFPT_BARRIER_REQUEST",
    493              19: "OFPT_BARRIER_REPLY",
    494              20: "OFPT_QUEUE_GET_CONFIG_REQUEST",
    495              21: "OFPT_QUEUE_GET_CONFIG_REPLY" }
    496 
    497 class OFPTHello(_ofp_header):
    498     name = "OFPT_HELLO"
    499     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    500                     ByteEnumField("type", 0, ofp_type),
    501                     ShortField("len", None),
    502                     IntField("xid", 0) ]
    503     overload_fields = {TCP: {"sport": 6653}}
    504 
    505 #####################################################
    506 #################### OFPT_ERROR #####################
    507 #####################################################
    508 
    509 ### this class will be used to display some messages
    510 ### sent back by the switch after an error
    511 class OFPacketField(PacketField):
    512     def getfield(self, pkt, s):
    513         try:
    514             l = s[2:4]
    515             l = struct.unpack("!H", l)[0]
    516             ofload = s[:l]
    517             remain = s[l:]
    518             return remain, OpenFlow(None, ofload)(ofload)
    519         except:
    520             return "", Raw(s)
    521 
    522 ofp_error_type = { 0: "OFPET_HELLO_FAILED",
    523                    1: "OFPET_BAD_REQUEST",
    524                    2: "OFPET_BAD_ACTION",
    525                    3: "OFPET_FLOW_MOD_FAILED",
    526                    4: "OFPET_PORT_MOD_FAILED",
    527                    5: "OFPET_QUEUE_OP_FAILED" }
    528 
    529 class OFPETHelloFailed(_ofp_header):
    530     name = "OFPET_HELLO_FAILED"
    531     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    532                     ByteEnumField("type", 1, ofp_type),
    533                     ShortField("len", None),
    534                     IntField("xid", 0),
    535                     ShortEnumField("errtype", 0, ofp_error_type),
    536                     ShortEnumField("errcode", 0, { 0: "OFPHFC_INCOMPATIBLE",
    537                                                    1: "OFPHFC_EPERM" }),
    538                     OFPacketField("data", "", Raw) ]
    539     overload_fields = {TCP: {"dport": 6653}}
    540 
    541 class OFPETBadRequest(_ofp_header):
    542     name = "OFPET_BAD_REQUEST"
    543     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    544                     ByteEnumField("type", 1, ofp_type),
    545                     ShortField("len", None),
    546                     IntField("xid", 0),
    547                     ShortEnumField("errtype", 1, ofp_error_type),
    548                     ShortEnumField("errcode", 0, { 0: "OFPBRC_BAD_VERSION",
    549                                                    1: "OFPBRC_BAD_TYPE",
    550                                                    2: "OFPBRC_BAD_STAT",
    551                                                    3: "OFPBRC_BAD_VENDOR",
    552                                                    4: "OFPBRC_BAD_SUBTYPE",
    553                                                    5: "OFPBRC_EPERM",
    554                                                    6: "OFPBRC_BAD_LEN",
    555                                                    7: "OFPBRC_BUFFER_EMPTY",
    556                                                    8: "OFPBRC_BUFFER_UNKNOWN" }),
    557                     OFPacketField("data", "", Raw) ]
    558     overload_fields = {TCP: {"dport": 6653}}
    559 
    560 class OFPETBadAction(_ofp_header):
    561     name = "OFPET_BAD_ACTION"
    562     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    563                     ByteEnumField("type", 1, ofp_type),
    564                     ShortField("len", None),
    565                     IntField("xid", 0),
    566                     ShortEnumField("errtype", 2, ofp_error_type),
    567                     ShortEnumField("errcode", 0, { 0: "OFPBAC_BAD_TYPE",
    568                                                    1: "OFPBAC_BAD_LEN",
    569                                                    2: "OFPBAC_BAD_VENDOR",
    570                                                    3: "OFPBAC_BAD_VENDOR_TYPE",
    571                                                    4: "OFPBAC_BAD_OUT_PORT",
    572                                                    5: "OFPBAC_BAD_ARGUMENT",
    573                                                    6: "OFPBAC_EPERM",
    574                                                    7: "OFPBAC_TOO_MANY",
    575                                                    8: "OFPBAC_BAD_QUEUE" }),
    576                     OFPacketField("data", "", Raw) ]
    577     overload_fields = {TCP: {"dport": 6653}}
    578 
    579 class OFPETFlowModFailed(_ofp_header):
    580     name = "OFPET_FLOW_MOD_FAILED"
    581     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    582                     ByteEnumField("type", 1, ofp_type),
    583                     ShortField("len", None),
    584                     IntField("xid", 0),
    585                     ShortEnumField("errtype", 3, ofp_error_type),
    586                     ShortEnumField("errcode", 0, { 0: "OFPFMFC_ALL_TABLES_FULL",
    587                                                    1: "OFPFMFC_OVERLAP",
    588                                                    2: "OFPFMFC_EPERM",
    589                                                    3: "OFPFMFC_BAD_EMERG_TIMEOUT",
    590                                                    4: "OFPFMFC_BAD_COMMAND",
    591                                                    5: "OFPFMFC_UNSUPPORTED" }),
    592                     OFPacketField("data", "", Raw) ]
    593     overload_fields = {TCP: {"dport": 6653}}
    594 
    595 class OFPETPortModFailed(_ofp_header):
    596     name = "OFPET_PORT_MOD_FAILED"
    597     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    598                     ByteEnumField("type", 1, ofp_type),
    599                     ShortField("len", None),
    600                     IntField("xid", 0),
    601                     ShortEnumField("errtype", 4, ofp_error_type),
    602                     ShortEnumField("errcode", 0, { 0: "OFPPMFC_BAD_PORT",
    603                                                    1: "OFPPMFC_BAD_HW_ADDR" }),
    604                     OFPacketField("data", "", Raw) ]
    605     overload_fields = {TCP: {"dport": 6653}}
    606 
    607 class OFPETQueueOpFailed(_ofp_header):
    608     name = "OFPET_QUEUE_OP_FAILED"
    609     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    610                     ByteEnumField("type", 1, ofp_type),
    611                     ShortField("len", None),
    612                     IntField("xid", 0),
    613                     ShortEnumField("errtype", 5, ofp_error_type),
    614                     ShortEnumField("errcode", 0, { 0: "OFPQOFC_BAD_PORT",
    615                                                    1: "OFPQOFC_BAD_QUEUE",
    616                                                    2: "OFPQOFC_EPERM" }),
    617                     OFPacketField("data", "", Raw) ]
    618     overload_fields = {TCP: {"dport": 6653}}
    619 
    620 # ofp_error_cls allows generic method OpenFlow() to choose the right class for dissection
    621 ofp_error_cls = { 0: OFPETHelloFailed,
    622                   1: OFPETBadRequest,
    623                   2: OFPETBadAction,
    624                   3: OFPETFlowModFailed,
    625                   4: OFPETPortModFailed,
    626                   5: OFPETQueueOpFailed }
    627 
    628 ################ end of OFPT_ERRORS #################
    629 
    630 class OFPTEchoRequest(_ofp_header):
    631     name = "OFPT_ECHO_REQUEST"
    632     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    633                     ByteEnumField("type", 2, ofp_type),
    634                     ShortField("len", None),
    635                     IntField("xid", 0) ]
    636     overload_fields = {TCP: {"sport": 6653}}
    637 
    638 class OFPTEchoReply(_ofp_header):
    639     name = "OFPT_ECHO_REPLY"
    640     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    641                     ByteEnumField("type", 3, ofp_type),
    642                     ShortField("len", None),
    643                     IntField("xid", 0) ]
    644     overload_fields = {TCP: {"sport": 6653}}
    645 
    646 class OFPTVendor(_ofp_header):
    647     name = "OFPT_VENDOR"
    648     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    649                     ByteEnumField("type", 4, ofp_type),
    650                     ShortField("len", None),
    651                     IntField("xid", 0),
    652                     IntField("vendor", 0) ]
    653     overload_fields = {TCP: {"sport": 6653}}
    654 
    655 class OFPTFeaturesRequest(_ofp_header):
    656     name = "OFPT_FEATURES_REQUEST"
    657     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    658                     ByteEnumField("type", 5, ofp_type),
    659                     ShortField("len", None),
    660                     IntField("xid", 0) ]
    661     overload_fields = {TCP: {"sport": 6653}}
    662 
    663 ofp_action_types_flags = list(ofp_action_types.values())[:-1]  # no ofpat_vendor flag
    664 
    665 class OFPTFeaturesReply(_ofp_header):
    666     name = "OFPT_FEATURES_REPLY"
    667     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    668                     ByteEnumField("type", 6, ofp_type),
    669                     ShortField("len", None),
    670                     IntField("xid", 0),
    671                     LongField("datapath_id", 0),
    672                     IntField("n_buffers", 0),
    673                     ByteField("n_tables", 1),
    674                     X3BytesField("pad", 0),
    675                     FlagsField("capabilities", 0, 32, [ "FLOW_STATS",
    676                                                         "TABLE_STATS",
    677                                                         "PORT_STATS",
    678                                                         "STP",
    679                                                         "RESERVED",
    680                                                         "IP_REASM",
    681                                                         "QUEUE_STATS",
    682                                                         "ARP_MATCH_IP" ]),
    683                     FlagsField("actions", 0, 32, ofp_action_types_flags),
    684                     PacketListField("ports", None, OFPPhyPort,
    685                                     length_from=lambda pkt:pkt.len-32) ]
    686     overload_fields = {TCP: {"dport": 6653}}
    687 
    688 class OFPTGetConfigRequest(_ofp_header):
    689     name = "OFPT_GET_CONFIG_REQUEST"
    690     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    691                     ByteEnumField("type", 7, ofp_type),
    692                     ShortField("len", None),
    693                     IntField("xid", 0) ]
    694     overload_fields = {TCP: {"sport": 6653}}
    695 
    696 class OFPTGetConfigReply(_ofp_header):
    697     name = "OFPT_GET_CONFIG_REPLY"
    698     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    699                     ByteEnumField("type", 8, ofp_type),
    700                     ShortField("len", None),
    701                     IntField("xid", 0),
    702                     ShortEnumField("flags", 0, { 0: "FRAG_NORMAL",
    703                                                  1: "FRAG_DROP",
    704                                                  2: "FRAG_REASM",
    705                                                  3: "FRAG_MASK" }),
    706                     ShortField("miss_send_len", 0) ]
    707     overload_fields = {TCP: {"dport": 6653}}
    708 
    709 class OFPTSetConfig(_ofp_header):
    710     name = "OFPT_SET_CONFIG"
    711     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    712                     ByteEnumField("type", 9, ofp_type),
    713                     ShortField("len", None),
    714                     IntField("xid", 0),
    715                     ShortEnumField("flags", 0, { 0: "FRAG_NORMAL",
    716                                                  1: "FRAG_DROP",
    717                                                  2: "FRAG_REASM",
    718                                                  3: "FRAG_MASK" }),
    719                     ShortField("miss_send_len", 128) ]
    720     overload_fields = {TCP: {"sport": 6653}}
    721 
    722 class OFPTPacketIn(_ofp_header):
    723     name = "OFPT_PACKET_IN"
    724     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    725                     ByteEnumField("type", 10, ofp_type),
    726                     ShortField("len", None),
    727                     IntField("xid", 0),
    728                     IntEnumField("buffer_id", "NO_BUFFER", ofp_buffer),
    729                     ShortField("total_len", 0),
    730                     ShortEnumField("in_port", 0, ofp_port_no),
    731                     ByteEnumField("reason", 0, { 0: "OFPR_NO_MATCH",
    732                                                  1: "OFPR_ACTION" }),
    733                     XByteField("pad", 0),
    734                     PacketField("data", None, Ether) ]
    735     overload_fields = {TCP: {"dport": 6653}}
    736 
    737 class OFPTFlowRemoved(_ofp_header):
    738     name = "OFPT_FLOW_REMOVED"
    739     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    740                     ByteEnumField("type", 11, ofp_type),
    741                     ShortField("len", None),
    742                     IntField("xid", 0),
    743                     PacketField("match", OFPMatch(), OFPMatch),
    744                     LongField("cookie", 0),
    745                     ShortField("priority", 0),
    746                     ByteEnumField("reason", 0, { 0: "OFPRR_IDLE_TIMEOUT",
    747                                                  1: "OFPRR_HARD_TIMEOUT",
    748                                                  2: "OFPRR_DELETE" }),
    749                     XByteField("pad1", 0),
    750                     IntField("duration_sec", 0),
    751                     IntField("duration_nsec", 0),
    752                     ShortField("idle_timeout", 0),
    753                     XShortField("pad2", 0),
    754                     LongField("packet_count", 0),
    755                     LongField("byte_count", 0) ]
    756     overload_fields = {TCP: {"dport": 6653}}
    757 
    758 class OFPTPortStatus(_ofp_header):
    759     name = "OFPT_PORT_STATUS"
    760     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    761                     ByteEnumField("type", 12, ofp_type),
    762                     ShortField("len", None),
    763                     IntField("xid", 0),
    764                     ByteEnumField("reason", 0, { 0: "OFPPR_ADD",
    765                                                  1: "OFPPR_DELETE",
    766                                                  2: "OFPPR_MODIFY" }),
    767                     XBitField("pad", 0, 56),
    768                     PacketField("desc", OFPPhyPort(), OFPPhyPort) ]
    769     overload_fields = {TCP: {"dport": 6653}}
    770 
    771 class OFPTPacketOut(_ofp_header):
    772     name = "OFPT_PACKET_OUT"
    773     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    774                     ByteEnumField("type", 13, ofp_type),
    775                     ShortField("len", None),
    776                     IntField("xid", 0),
    777                     IntEnumField("buffer_id", "NO_BUFFER", ofp_buffer),
    778                     ShortEnumField("in_port", "NONE", ofp_port_no),
    779                     FieldLenField("actions_len", None, fmt="H", length_of="actions"),
    780                     ActionPacketListField("actions", [], Packet,
    781                                           length_from=lambda pkt:pkt.actions_len),
    782                     PacketField("data", None, Ether) ]
    783     overload_fields = {TCP: {"sport": 6653}}
    784 
    785 class OFPTFlowMod(_ofp_header):
    786     name = "OFPT_FLOW_MOD"
    787     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    788                     ByteEnumField("type", 14, ofp_type),
    789                     ShortField("len", None),
    790                     IntField("xid", 0),
    791                     PacketField("match", OFPMatch(), OFPMatch),
    792                     LongField("cookie", 0),
    793                     ShortEnumField("cmd", 0, { 0: "OFPFC_ADD",
    794                                                1: "OFPFC_MODIFY",
    795                                                2: "OFPFC_MODIFY_STRICT",
    796                                                3: "OFPFC_DELETE",
    797                                                4: "OFPFC_DELETE_STRICT" }),
    798                     ShortField("idle_timeout", 0),
    799                     ShortField("hard_timeout", 0),
    800                     ShortField("priority", 0),
    801                     IntEnumField("buffer_id", "NO_BUFFER", ofp_buffer),
    802                     ShortEnumField("out_port", "NONE", ofp_port_no),
    803                     FlagsField("flags", 0, 16, [ "SEND_FLOW_REM",
    804                                                  "CHECK_OVERLAP",
    805                                                  "EMERG" ]),
    806                     ActionPacketListField("actions", [], Packet,
    807                                           length_from=lambda pkt:pkt.len-72) ]
    808     overload_fields = {TCP: {"sport": 6653}}
    809 
    810 class OFPTPortMod(_ofp_header):
    811     name = "OFPT_PORT_MOD"
    812     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    813                     ByteEnumField("type", 15, ofp_type),
    814                     ShortField("len", None),
    815                     IntField("xid", 0),
    816                     ShortEnumField("port_no", 0, ofp_port_no),
    817                     MACField("hw_addr", "0"),
    818                     FlagsField("config", 0, 32, ofp_port_config),
    819                     FlagsField("mask", 0, 32, ofp_port_config),
    820                     FlagsField("advertise", 0, 32, ofp_port_features),
    821                     IntField("pad", 0) ]
    822     overload_fields = {TCP: {"sport": 6653}}
    823 
    824 #####################################################
    825 ##################### OFPT_STATS ####################
    826 #####################################################
    827 
    828 ofp_stats_types = {     0: "OFPST_DESC",
    829                         1: "OFPST_FLOW",
    830                         2: "OFPST_AGGREGATE",
    831                         3: "OFPST_TABLE",
    832                         4: "OFPST_PORT",
    833                         5: "OFPST_QUEUE",
    834                     65535: "OFPST_VENDOR" }
    835 
    836 class OFPTStatsRequestDesc(_ofp_header):
    837     name = "OFPST_STATS_REQUEST_DESC"
    838     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    839                     ByteEnumField("type", 16, ofp_type),
    840                     ShortField("len", None),
    841                     IntField("xid", 0),
    842                     ShortEnumField("stats_type", 0, ofp_stats_types),
    843                     FlagsField("flags", 0, 16, []) ]
    844     overload_fields = {TCP: {"sport": 6653}}
    845 
    846 class OFPTStatsReplyDesc(_ofp_header):
    847     name = "OFPST_STATS_REPLY_DESC"
    848     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    849                     ByteEnumField("type", 17, ofp_type),
    850                     ShortField("len", None),
    851                     IntField("xid", 0),
    852                     ShortEnumField("stats_type", 0, ofp_stats_types),
    853                     FlagsField("flags", 0, 16, []),
    854                     StrFixedLenField("mfr_desc", "", 256),
    855                     StrFixedLenField("hw_desc", "", 256),
    856                     StrFixedLenField("sw_desc", "", 256),
    857                     StrFixedLenField("serial_num", "", 32),
    858                     StrFixedLenField("dp_desc", "", 256) ]
    859     overload_fields = {TCP: {"dport": 6653}}
    860 
    861 class OFPTStatsRequestFlow(_ofp_header):
    862     name = "OFPST_STATS_REQUEST_FLOW"
    863     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    864                     ByteEnumField("type", 16, ofp_type),
    865                     ShortField("len", None),
    866                     IntField("xid", 0),
    867                     ShortEnumField("stats_type", 1, ofp_stats_types),
    868                     FlagsField("flags", 0, 16, []),
    869                     PacketField("match", OFPMatch(), OFPMatch),
    870                     ByteEnumField("table_id", "ALL", ofp_table),
    871                     ByteField("pad", 0),
    872                     ShortEnumField("out_port", "NONE", ofp_port_no) ]
    873     overload_fields = {TCP: {"sport": 6653}}
    874 
    875 class OFPFlowStats(Packet):
    876 
    877     def post_build(self, p, pay):
    878         if self.length is None:
    879             l = len(p)+len(pay)
    880             p = struct.pack("!H", l) + p[2:]
    881         return p + pay
    882 
    883     name = "OFP_FLOW_STATS"
    884     fields_desc = [ ShortField("length", None),
    885                     ByteField("table_id", 0),
    886                     XByteField("pad1", 0),
    887                     PacketField("match", OFPMatch(), OFPMatch),
    888                     IntField("duration_sec", 0),
    889                     IntField("duration_nsec", 0),
    890                     ShortField("priority", 0),
    891                     ShortField("idle_timeout", 0),
    892                     ShortField("hard_timeout", 0),
    893                     XBitField("pad2", 0, 48),
    894                     LongField("cookie", 0),
    895                     LongField("packet_count", 0),
    896                     LongField("byte_count", 0),
    897                     ActionPacketListField("actions", [], Packet,
    898                                           length_from=lambda pkt:pkt.length-88) ]
    899 
    900 class FlowStatsPacketListField(PacketListField):
    901 
    902     @staticmethod
    903     def _get_flow_stats_length(s):
    904         return struct.unpack("!H", s[:2])[0]
    905 
    906     def getfield(self, pkt, s):
    907         lst = []
    908         remain = s
    909 
    910         while remain:
    911             l = FlowStatsPacketListField._get_flow_stats_length(remain)
    912             current = remain[:l]
    913             remain = remain[l:]
    914             p = OFPFlowStats(current)
    915             lst.append(p)
    916 
    917         return remain, lst
    918 
    919 class OFPTStatsReplyFlow(_ofp_header):
    920     name = "OFPST_STATS_REPLY_FLOW"
    921     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    922                     ByteEnumField("type", 17, ofp_type),
    923                     ShortField("len", None),
    924                     IntField("xid", 0),
    925                     ShortEnumField("stats_type", 1, ofp_stats_types),
    926                     FlagsField("flags", 0, 16, []),
    927                     FlowStatsPacketListField("flow_stats", [], Packet,
    928                                              length_from=lambda pkt:pkt.len-12) ]
    929     overload_fields = {TCP: {"dport": 6653}}
    930 
    931 class OFPTStatsRequestAggregate(_ofp_header):
    932     name = "OFPST_STATS_REQUEST_AGGREGATE"
    933     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    934                     ByteEnumField("type", 16, ofp_type),
    935                     ShortField("len", None),
    936                     IntField("xid", 0),
    937                     ShortEnumField("stats_type", 2, ofp_stats_types),
    938                     FlagsField("flags", 0, 16, []),
    939                     PacketField("match", OFPMatch(), OFPMatch),
    940                     ByteEnumField("table_id", "ALL", ofp_table),
    941                     ByteField("pad", 0),
    942                     ShortEnumField("out_port", "NONE", ofp_port_no) ]
    943     overload_fields = {TCP: {"sport": 6653}}
    944 
    945 class OFPTStatsReplyAggregate(_ofp_header):
    946     name = "OFPST_STATS_REPLY_AGGREGATE"
    947     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    948                     ByteEnumField("type", 17, ofp_type),
    949                     ShortField("len", None),
    950                     IntField("xid", 0),
    951                     ShortEnumField("stats_type", 2, ofp_stats_types),
    952                     FlagsField("flags", 0, 16, []),
    953                     LongField("packet_count", 0),
    954                     LongField("byte_count", 0),
    955                     IntField("flow_count", 0),
    956                     XIntField("pad", 0) ]
    957     overload_fields = {TCP: {"dport": 6653}}
    958 
    959 class OFPTStatsRequestTable(_ofp_header):
    960     name = "OFPST_STATS_REQUEST_TABLE"
    961     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    962                     ByteEnumField("type", 16, ofp_type),
    963                     ShortField("len", None),
    964                     IntField("xid", 0),
    965                     ShortEnumField("stats_type", 3, ofp_stats_types),
    966                     FlagsField("flags", 0, 16, []) ]
    967     overload_fields = {TCP: {"sport": 6653}}
    968 
    969 class OFPTableStats(Packet):
    970 
    971     def extract_padding(self, s):
    972         return "", s
    973 
    974     name = "OFP_TABLE_STATS"
    975     fields_desc = [ ByteField("table_id", 0),
    976                     X3BytesField("pad", 0),
    977                     StrFixedLenField("name", "", 32),
    978                     FlagsField("wildcards1", 0x003, 12, [ "DL_VLAN_PCP",
    979                                                           "NW_TOS" ]),
    980                     BitField("nw_dst_mask", 63, 6),        # 32 would be enough
    981                     BitField("nw_src_mask", 63, 6),
    982                     FlagsField("wildcards2", 0xff, 8, [ "IN_PORT",
    983                                                         "DL_VLAN",
    984                                                         "DL_SRC",
    985                                                         "DL_DST",
    986                                                         "DL_TYPE",
    987                                                         "NW_PROTO",
    988                                                         "TP_SRC",
    989                                                         "TP_DST" ]),
    990                     IntField("max_entries", 0),
    991                     IntField("active_count", 0),
    992                     LongField("lookup_count", 0),
    993                     LongField("matched_count", 0) ]
    994 
    995 class OFPTStatsReplyTable(_ofp_header):
    996     name = "OFPST_STATS_REPLY_TABLE"
    997     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
    998                     ByteEnumField("type", 17, ofp_type),
    999                     ShortField("len", None),
   1000                     IntField("xid", 0),
   1001                     ShortEnumField("stats_type", 3, ofp_stats_types),
   1002                     FlagsField("flags", 0, 16, []),
   1003                     PacketListField("table_stats", None, OFPTableStats,
   1004                                     length_from=lambda pkt:pkt.len-12) ]
   1005     overload_fields = {TCP: {"dport": 6653}}
   1006 
   1007 class OFPTStatsRequestPort(_ofp_header):
   1008     name = "OFPST_STATS_REQUEST_PORT"
   1009     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
   1010                     ByteEnumField("type", 16, ofp_type),
   1011                     ShortField("len", None),
   1012                     IntField("xid", 0),
   1013                     ShortEnumField("stats_type", 4, ofp_stats_types),
   1014                     FlagsField("flags", 0, 16, []),
   1015                     ShortEnumField("port_no", "NONE", ofp_port_no),
   1016                     XBitField("pad", 0, 48) ]
   1017     overload_fields = {TCP: {"sport": 6653}}
   1018 
   1019 class OFPPortStats(Packet):
   1020 
   1021     def extract_padding(self, s):
   1022         return "", s
   1023 
   1024     name = "OFP_PORT_STATS"
   1025     fields_desc = [ ShortEnumField("port_no", 0, ofp_port_no),
   1026                     XBitField("pad", 0, 48),
   1027                     LongField("rx_packets", 0),
   1028                     LongField("tx_packets", 0),
   1029                     LongField("rx_bytes", 0),
   1030                     LongField("tx_bytes", 0),
   1031                     LongField("rx_dropped", 0),
   1032                     LongField("tx_dropped", 0),
   1033                     LongField("rx_errors", 0),
   1034                     LongField("tx_errors", 0),
   1035                     LongField("rx_frame_err", 0),
   1036                     LongField("rx_over_err", 0),
   1037                     LongField("rx_crc_err", 0),
   1038                     LongField("collisions", 0) ]
   1039 
   1040 class OFPTStatsReplyPort(_ofp_header):
   1041     name = "OFPST_STATS_REPLY_TABLE"
   1042     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
   1043                     ByteEnumField("type", 17, ofp_type),
   1044                     ShortField("len", None),
   1045                     IntField("xid", 0),
   1046                     ShortEnumField("stats_type", 4, ofp_stats_types),
   1047                     FlagsField("flags", 0, 16, []),
   1048                     PacketListField("port_stats", None, OFPPortStats,
   1049                                     length_from=lambda pkt:pkt.len-12) ]
   1050     overload_fields = {TCP: {"dport": 6653}}
   1051 
   1052 class OFPTStatsRequestQueue(_ofp_header):
   1053     name = "OFPST_STATS_REQUEST_QUEUE"
   1054     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
   1055                     ByteEnumField("type", 16, ofp_type),
   1056                     ShortField("len", None),
   1057                     IntField("xid", 0),
   1058                     ShortEnumField("stats_type", 5, ofp_stats_types),
   1059                     FlagsField("flags", 0, 16, []),
   1060                     ShortEnumField("port_no", "NONE", ofp_port_no),
   1061                     XShortField("pad", 0),
   1062                     IntEnumField("queue_id", "ALL", ofp_queue) ]
   1063     overload_fields = {TCP: {"sport": 6653}}
   1064 
   1065 class OFPTStatsReplyQueue(_ofp_header):
   1066     name = "OFPST_STATS_REPLY_QUEUE"
   1067     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
   1068                     ByteEnumField("type", 17, ofp_type),
   1069                     ShortField("len", None),
   1070                     IntField("xid", 0),
   1071                     ShortEnumField("stats_type", 5, ofp_stats_types),
   1072                     FlagsField("flags", 0, 16, []),
   1073                     ShortEnumField("port_no", "NONE", ofp_port_no),
   1074                     XShortField("pad", 0),
   1075                     IntEnumField("queue_id", "ALL", ofp_queue),
   1076                     LongField("tx_bytes", 0),
   1077                     LongField("tx_packets", 0),
   1078                     LongField("tx_errors", 0) ]
   1079     overload_fields = {TCP: {"dport": 6653}}
   1080 
   1081 class OFPTStatsRequestVendor(_ofp_header):
   1082     name = "OFPST_STATS_REQUEST_VENDOR"
   1083     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
   1084                     ByteEnumField("type", 16, ofp_type),
   1085                     ShortField("len", None),
   1086                     IntField("xid", 0),
   1087                     ShortEnumField("stats_type", 6, ofp_stats_types),
   1088                     FlagsField("flags", 0, 16, []),
   1089                     IntField("vendor", 0) ]
   1090     overload_fields = {TCP: {"sport": 6653}}
   1091 
   1092 class OFPTStatsReplyVendor(_ofp_header):
   1093     name = "OFPST_STATS_REPLY_VENDOR"
   1094     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
   1095                     ByteEnumField("type", 17, ofp_type),
   1096                     ShortField("len", None),
   1097                     IntField("xid", 0),
   1098                     ShortEnumField("stats_type", 6, ofp_stats_types),
   1099                     FlagsField("flags", 0, 16, []),
   1100                     IntField("vendor", 0) ]
   1101     overload_fields = {TCP: {"dport": 6653}}
   1102 
   1103 # ofp_stats_request/reply_cls allows generic method OpenFlow() (end of script)
   1104 # to choose the right class for dissection
   1105 ofp_stats_request_cls = {     0: OFPTStatsRequestDesc,
   1106                               1: OFPTStatsRequestFlow,
   1107                               2: OFPTStatsRequestAggregate,
   1108                               3: OFPTStatsRequestTable,
   1109                               4: OFPTStatsRequestPort,
   1110                               5: OFPTStatsRequestQueue,
   1111                           65535: OFPTStatsRequestVendor }
   1112 
   1113 ofp_stats_reply_cls = {     0: OFPTStatsReplyDesc,
   1114                             1: OFPTStatsReplyFlow,
   1115                             2: OFPTStatsReplyAggregate,
   1116                             3: OFPTStatsReplyTable,
   1117                             4: OFPTStatsReplyPort,
   1118                             5: OFPTStatsReplyQueue,
   1119                         65535: OFPTStatsReplyVendor }
   1120 
   1121 ################ end of OFPT_STATS ##################
   1122 
   1123 class OFPTBarrierRequest(_ofp_header):
   1124     name = "OFPT_BARRIER_REQUEST"
   1125     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
   1126                     ByteEnumField("type", 18, ofp_type),
   1127                     ShortField("len", None),
   1128                     IntField("xid", 0) ]
   1129     overload_fields = {TCP: {"sport": 6653}}
   1130 
   1131 class OFPTBarrierReply(_ofp_header):
   1132     name = "OFPT_BARRIER_REPLY"
   1133     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
   1134                     ByteEnumField("type", 19, ofp_type),
   1135                     ShortField("len", None),
   1136                     IntField("xid", 0) ]
   1137     overload_fields = {TCP: {"dport": 6653}}
   1138 
   1139 class OFPTQueueGetConfigRequest(_ofp_header):
   1140     name = "OFPT_QUEUE_GET_CONFIG_REQUEST"
   1141     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
   1142                     ByteEnumField("type", 20, ofp_type),
   1143                     ShortField("len", None),
   1144                     IntField("xid", 0),
   1145                     ShortEnumField("port", 0, ofp_port_no),
   1146                     XShortField("pad", 0) ]
   1147     overload_fields = {TCP: {"sport": 6653}}
   1148 
   1149 class OFPTQueueGetConfigReply(_ofp_header):
   1150     name = "OFPT_QUEUE_GET_CONFIG_REPLY"
   1151     fields_desc = [ ByteEnumField("version", 0x01, ofp_version),
   1152                     ByteEnumField("type", 21, ofp_type),
   1153                     ShortField("len", None),
   1154                     IntField("xid", 0),
   1155                     ShortEnumField("port", 0, ofp_port_no),
   1156                     XBitField("pad", 0, 48),
   1157                     QueuePacketListField("queues", [], Packet,
   1158                                          length_from=lambda pkt:pkt.len-16) ]
   1159     overload_fields = {TCP: {"dport": 6653}}
   1160 
   1161 # ofpt_cls allows generic method OpenFlow() to choose the right class for dissection
   1162 ofpt_cls = {  0: OFPTHello,
   1163               #1: OFPTError,
   1164               2: OFPTEchoRequest,
   1165               3: OFPTEchoReply,
   1166               4: OFPTVendor,
   1167               5: OFPTFeaturesRequest,
   1168               6: OFPTFeaturesReply,
   1169               7: OFPTGetConfigRequest,
   1170               8: OFPTGetConfigReply,
   1171               9: OFPTSetConfig,
   1172              10: OFPTPacketIn,
   1173              11: OFPTFlowRemoved,
   1174              12: OFPTPortStatus,
   1175              13: OFPTPacketOut,
   1176              14: OFPTFlowMod,
   1177              15: OFPTPortMod,
   1178              #16: OFPTStatsRequest,
   1179              #17: OFPTStatsReply,
   1180              18: OFPTBarrierRequest,
   1181              19: OFPTBarrierReply,
   1182              20: OFPTQueueGetConfigRequest,
   1183              21: OFPTQueueGetConfigReply }
   1184 
   1185 TCP_guess_payload_class_copy = TCP.guess_payload_class
   1186 
   1187 def OpenFlow(self, payload):
   1188     if self is None or self.dport == 6653 or self.dport == 6633 or self.sport == 6653 or self.sport == 6633:
   1189     # port 6653 has been allocated by IANA, port 6633 should no longer be used
   1190     # OpenFlow function may be called with None self in OFPPacketField
   1191         of_type = orb(payload[1])
   1192         if of_type == 1:
   1193             err_type = orb(payload[9])
   1194             # err_type is a short int, but last byte is enough
   1195             if err_type == 255: err_type = 65535
   1196             return ofp_error_cls[err_type]
   1197         elif of_type == 16:
   1198             mp_type = orb(payload[9])
   1199             if mp_type == 255: mp_type = 65535
   1200             return ofp_stats_request_cls[mp_type]
   1201         elif of_type == 17:
   1202             mp_type = orb(payload[9])
   1203             if mp_type == 255: mp_type = 65535
   1204             return ofp_stats_reply_cls[mp_type]
   1205         else:
   1206             return ofpt_cls[of_type]
   1207     else:
   1208         return TCP_guess_payload_class_copy(self, payload)
   1209 
   1210 TCP.guess_payload_class = OpenFlow
   1211