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.3.4
      9 ## Specifications can be retrieved from https://www.opennetworking.org/
     10 
     11 # scapy.contrib.description = Openflow v1.3
     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 *
     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 = { 0xfffffff8: "IN_PORT",
     30                 0xfffffff9: "TABLE",
     31                 0xfffffffa: "NORMAL",
     32                 0xfffffffb: "FLOOD",
     33                 0xfffffffc: "ALL",
     34                 0xfffffffd: "CONTROLLER",
     35                 0xfffffffe: "LOCAL",
     36                 0xffffffff: "ANY" }
     37 
     38 ofp_group = { 0xffffff00: "MAX",
     39               0xfffffffc: "ALL",
     40               0xffffffff: "ANY" }
     41 
     42 ofp_table = { 0xfe: "MAX",
     43               0xff: "ALL" }
     44 
     45 ofp_queue = { 0xffffffff: "ALL" }
     46 
     47 ofp_meter = { 0xffff0000: "MAX",
     48               0xfffffffd: "SLOWPATH",
     49               0xfffffffe: "CONTROLLER",
     50               0xffffffff: "ALL" }
     51 
     52 ofp_buffer = { 0xffffffff: "NO_BUFFER" }
     53 
     54 ofp_max_len = { 0xffff: "NO_BUFFER" }
     55 
     56 
     57 #####################################################
     58 ################# Common structures #################
     59 #####################################################
     60 
     61 ### The following structures will be used in different types
     62 ### of OpenFlow messages: ports, matches/OXMs, actions,
     63 ### instructions, buckets, queues, meter bands.
     64 
     65 
     66 ################## Hello elements ###################
     67 
     68 class _ofp_hello_elem_header(Packet):
     69     name = "Dummy OpenFlow Hello Elem Header"
     70 
     71     def post_build(self, p, pay):
     72         if self.len is None:
     73             l = len(p)+len(pay)
     74             p = p[:2] + struct.pack("!H", l) + p[4:]
     75         return p + pay
     76 
     77 ofp_hello_elem_types = { 1: "OFPHET_VERSIONBITMAP" }
     78 
     79 class OFPHETVersionBitmap(_ofp_hello_elem_header):
     80     name = "OFPHET_VERSIONBITMAP"
     81     fields_desc = [ ShortEnumField("type", 1, ofp_hello_elem_types),
     82                     ShortField("len", 8),
     83                     FlagsField("bitmap", 0, 32, [ "Type 0",
     84                                                   "OFv1.0",
     85                                                   "OFv1.1",
     86                                                   "OFv1.2",
     87                                                   "OFv1.3",
     88                                                   "OFv1.4" ]) ]
     89 
     90 ofp_hello_elem_cls = { 1: OFPHETVersionBitmap }
     91 
     92 class HelloElemPacketListField(PacketListField):
     93     def m2i(self, pkt, s):
     94         t = struct.unpack("!H", s[:2])[0]
     95         return ofp_hello_elem_cls.get(t, Raw)(s)
     96 
     97     @staticmethod
     98     def _get_hello_elem_length(s):
     99         return struct.unpack("!H", s[2:4])[0]
    100 
    101     def getfield(self, pkt, s):
    102         lst = []
    103         remain = s
    104 
    105         while remain:
    106             l = HelloElemPacketListField._get_hello_elem_length(remain)
    107             current = remain[:l]
    108             remain = remain[l:]
    109             p = self.m2i(pkt, current)
    110             lst.append(p)
    111 
    112         return remain, lst
    113 
    114 
    115 ####################### Ports #######################
    116 
    117 ofp_port_config = [ "PORT_DOWN",
    118                     "NO_STP",        # undefined in v1.3
    119                     "NO_RECV",
    120                     "NO_RECV_STP",   # undefined in v1.3
    121                     "NO_FLOOD",      # undefined in v1.3
    122                     "NO_FWD",
    123                     "NO_PACKET_IN" ]
    124 
    125 ofp_port_state = [ "LINK_DOWN",
    126                    "BLOCKED",
    127                    "LIVE" ]
    128 
    129 ofp_port_features = [ "10MB_HD",
    130                       "10MB_FD",
    131                       "100MB_HD",
    132                       "100MB_FD",
    133                       "1GB_HD",
    134                       "1GB_FD",
    135                       "10GB_FD",
    136                       "40GB_FD",
    137                       "100GB_FD",
    138                       "1TB_FD",
    139                       "OTHER",
    140                       "COPPER",
    141                       "FIBER",
    142                       "AUTONEG",
    143                       "PAUSE",
    144                       "PAUSE_ASYM" ]
    145 
    146 class OFPPort(Packet):
    147     name = "OFP_PHY_PORT"
    148     fields_desc = [ IntEnumField("port_no", 0, ofp_port_no),
    149                     XIntField("pad1", 0),
    150                     MACField("hw_addr", "0"),
    151                     XShortField("pad2", 0),
    152                     StrFixedLenField("port_name", "", 16),
    153                     FlagsField("config", 0, 32, ofp_port_config),
    154                     FlagsField("state", 0, 32, ofp_port_state),
    155                     FlagsField("curr", 0, 32, ofp_port_features),
    156                     FlagsField("advertised", 0, 32, ofp_port_features),
    157                     FlagsField("supported", 0, 32, ofp_port_features),
    158                     FlagsField("peer", 0, 32, ofp_port_features),
    159                     IntField("curr_speed", 0),
    160                     IntField("max_speed", 0) ]
    161 
    162     def extract_padding(self, s):
    163         return "", s
    164     # extract_padding is overridden in order for s not to be considered
    165     # as belonging to the same layer (s usually contains other OFPPorts)
    166 
    167 
    168 ################### Matches & OXMs ##################
    169 
    170 ofp_oxm_classes = {      0: "OFPXMC_NXM_0",
    171                          1: "OFPXMC_NXM_1",
    172                     0x8000: "OFPXMC_OPENFLOW_BASIC",
    173                     0xffff: "OFPXMC_EXPERIMENTER" }
    174 
    175 ofp_oxm_names = {  0: "OFB_IN_PORT",
    176                    1: "OFB_IN_PHY_PORT",
    177                    2: "OFB_METADATA",
    178                    3: "OFB_ETH_DST",
    179                    4: "OFB_ETH_SRC",
    180                    5: "OFB_ETH_TYPE",
    181                    6: "OFB_VLAN_VID",
    182                    7: "OFB_VLAN_PCP",
    183                    8: "OFB_IP_DSCP",
    184                    9: "OFB_IP_ECN",
    185                   10: "OFB_IP_PROTO",
    186                   11: "OFB_IPV4_SRC",
    187                   12: "OFB_IPV4_DST",
    188                   13: "OFB_TCP_SRC",
    189                   14: "OFB_TCP_DST",
    190                   15: "OFB_UDP_SRC",
    191                   16: "OFB_UDP_DST",
    192                   17: "OFB_SCTP_SRC",
    193                   18: "OFB_SCTP_DST",
    194                   19: "OFB_ICMPV4_TYPE",
    195                   20: "OFB_ICMPV4_CODE",
    196                   21: "OFB_ARP_OP",
    197                   22: "OFB_ARP_SPA",
    198                   23: "OFB_ARP_TPA",
    199                   24: "OFB_ARP_SHA",
    200                   25: "OFB_ARP_THA",
    201                   26: "OFB_IPV6_SRC",
    202                   27: "OFB_IPV6_DST",
    203                   28: "OFB_IPV6_FLABEL",
    204                   29: "OFB_ICMPV6_TYPE",
    205                   30: "OFB_ICMPV6_CODE",
    206                   31: "OFB_IPV6_ND_TARGET",
    207                   32: "OFB_IPV6_ND_SLL",
    208                   33: "OFB_IPV6_ND_TLL",
    209                   34: "OFB_MPLS_LABEL",
    210                   35: "OFB_MPLS_TC",
    211                   36: "OFB_MPLS_BOS",
    212                   37: "OFB_PBB_ISID",
    213                   38: "OFB_TUNNEL_ID",
    214                   39: "OFB_IPV6_EXTHDR" }
    215 
    216 ofp_oxm_constr = {  0: ["OFBInPort", "in_port", 4],
    217                     1: ["OFBInPhyPort", "in_phy_port", 4],
    218                     2: ["OFBMetadata", "metadata", 8],
    219                     3: ["OFBEthDst", "eth_dst", 6],
    220                     4: ["OFBEthSrc", "eth_src", 6],
    221                     5: ["OFBEthType", "eth_type", 2],
    222                     6: ["OFBVLANVID", "vlan_vid", 2],
    223                     7: ["OFBVLANPCP", "vlan_pcp", 1],
    224                     8: ["OFBIPDSCP", "ip_dscp", 1],
    225                     9: ["OFBIPECN", "ip_ecn", 1],
    226                    10: ["OFBIPProto", "ip_proto", 1],
    227                    11: ["OFBIPv4Src", "ipv4_src", 4],
    228                    12: ["OFBIPv4Dst", "ipv4_dst", 4],
    229                    13: ["OFBTCPSrc", "tcp_src", 2],
    230                    14: ["OFBTCPDst", "tcp_dst", 2],
    231                    15: ["OFBUDPSrc", "udp_src", 2],
    232                    16: ["OFBUDPDst", "udp_dst", 2],
    233                    17: ["OFBSCTPSrc", "sctp_src", 2],
    234                    18: ["OFBSCTPDst", "sctp_dst", 2],
    235                    19: ["OFBICMPv4Type", "icmpv4_type", 1],    
    236                    20: ["OFBICMPv4Code", "icmpv4_code", 1],    
    237                    21: ["OFBARPOP", "arp_op", 2],    
    238                    22: ["OFBARPSPA", "arp_spa", 4],
    239                    23: ["OFBARPTPA", "arp_tpa", 4],
    240                    24: ["OFBARPSHA", "arp_sha", 6],
    241                    25: ["OFBARPTHA", "arp_tha", 6],
    242                    26: ["OFBIPv6Src", "ipv6_src", 16],
    243                    27: ["OFBIPv6Dst", "ipv6_dst", 16],
    244                    28: ["OFBIPv6FLabel", "ipv6_flabel", 4],
    245                    29: ["OFBICMPv6Type", "icmpv6_type", 1],
    246                    30: ["OFBICMPv6Code", "icmpv6_code", 1],
    247                    31: ["OFBIPv6NDTarget", "ipv6_nd_target", 16],
    248                    32: ["OFBIPv6NDSLL", "ipv6_sll", 6],
    249                    33: ["OFBIPv6NDTLL", "ipv6_tll", 6],
    250                    34: ["OFBMPLSLabel", "mpls_label", 4],
    251                    35: ["OFBMPLSTC", "mpls_tc", 1],
    252                    36: ["OFBMPLSBoS", "mpls_bos", 1],
    253                    37: ["OFBPBBISID", "pbb_isid", 3],
    254                    38: ["OFBTunnelID", "tunnel_id", 8],
    255                    39: ["OFBIPv6ExtHdr", "ipv6_ext_hdr_flags", 2] }
    256 
    257 # the ipv6flags array is useful only to the OFBIPv6ExtHdr class
    258 ipv6flags = [ "NONEXT",
    259               "ESP",
    260               "AUTH",
    261               "DEST",
    262               "FRAG",
    263               "ROUTER",
    264               "HOP",
    265               "UNREP",
    266               "UNSEQ" ]
    267 
    268 ### here we fill ofp_oxm_fields with the fields that will be used
    269 ### to generate the various OXM classes
    270 ### e.g. the call to add_ofp_oxm_fields(0, ["OFBInPort", "in_port", 4])
    271 ### will add {0: [ShortEnumField("class",..), BitEnumField("field",..),..]}
    272 ofp_oxm_fields = {}
    273 def add_ofp_oxm_fields(i, org):
    274     ofp_oxm_fields[i] = [ ShortEnumField("class", "OFPXMC_OPENFLOW_BASIC", ofp_oxm_classes),
    275                           BitEnumField("field", i//2, 7, ofp_oxm_names),
    276                           BitField("hasmask", i%2, 1) ]
    277     ofp_oxm_fields[i].append(ByteField("length", org[2]+org[2]*(i%2)))
    278     if i//2 == 0:           # OFBInPort
    279         ofp_oxm_fields[i].append(IntEnumField(org[1], 0, ofp_port_no))
    280     elif i//2 == 3 or i//2 == 4:          # OFBEthSrc & OFBEthDst
    281         ofp_oxm_fields[i].append(MACField(org[1], None))
    282     elif i//2 == 11 or i//2 == 12:        # OFBIPv4Src & OFBIPv4Dst
    283         ofp_oxm_fields[i].append(IPField(org[1], "0"))
    284     elif i//2 == 39:        # OFBIPv6ExtHdr
    285         ofp_oxm_fields[i].append(FlagsField(org[1], 0, 8*org[2], ipv6flags))
    286     else:
    287         ofp_oxm_fields[i].append(BitField(org[1], 0, 8*org[2]))
    288     if i%2:
    289         ofp_oxm_fields[i].append(BitField(org[1]+"_mask", 0, 8*org[2]))
    290 
    291 # some HM classes are not supported par OFv1.3 but we will create them anyway
    292 for i,cls in ofp_oxm_constr.items():
    293     add_ofp_oxm_fields(2*i, cls)
    294     add_ofp_oxm_fields(2*i+1, cls)
    295 
    296 ### now we create every OXM class with the same call,
    297 ### (except that static variable create_oxm_class.i is each time different)
    298 ### and we fill ofp_oxm_cls with them
    299 ofp_oxm_cls = {}
    300 ofp_oxm_id_cls = {}
    301 def create_oxm_cls():
    302     # static variable initialization
    303     if not hasattr(create_oxm_cls, "i"):
    304         create_oxm_cls.i = 0
    305 
    306     index = create_oxm_cls.i
    307     cls_name = ofp_oxm_constr[index//4][0]
    308     # we create standard OXM then OXM ID then OXM with mask then OXM-hasmask ID
    309     if index % 4 == 2:
    310         cls_name += "HM"
    311     if index % 2:
    312         cls_name += "ID"
    313 
    314     oxm_name = ofp_oxm_names[index//4]
    315     oxm_fields = ofp_oxm_fields[index//2]
    316     # for ID classes we just want the first 4 fields (no payload)
    317     if index % 2:
    318         oxm_fields = oxm_fields[:4]
    319 
    320     cls = type(cls_name, (Packet,), { "name": oxm_name, "fields_desc": oxm_fields })
    321     ### the first call to special function type will create the same class as in
    322     ### class OFBInPort(Packet):
    323     ###     def __init__(self):
    324     ###         self.name = "OFB_IN_PORT"
    325     ###         self.fields_desc = [ ShortEnumField("class", 0x8000, ofp_oxm_classes),
    326     ###                              BitEnumField("field", 0, 7, ofp_oxm_names),
    327     ###                              BitField("hasmask", 0, 1),
    328     ###                              ByteField("length", 4),
    329     ###                              IntEnumField("in_port", 0, ofp_port_no) ]
    330 
    331     if index % 2 == 0:
    332         ofp_oxm_cls[index//2] = cls
    333     else:
    334         ofp_oxm_id_cls[index//2] = cls
    335     create_oxm_cls.i += 1
    336     return cls
    337 
    338 OFBInPort = create_oxm_cls()
    339 OFBInPortID = create_oxm_cls()
    340 OFBInPortHM = create_oxm_cls()
    341 OFBInPortHMID = create_oxm_cls()
    342 OFBInPhyPort = create_oxm_cls()
    343 OFBInPhyPortID = create_oxm_cls()
    344 OFBInPhyPortHM = create_oxm_cls()
    345 OFBInPhyPortHMID = create_oxm_cls()
    346 OFBMetadata = create_oxm_cls()
    347 OFBMetadataID = create_oxm_cls()
    348 OFBMetadataHM = create_oxm_cls()
    349 OFBMetadataHMID = create_oxm_cls()
    350 OFBEthDst = create_oxm_cls()
    351 OFBEthDstID = create_oxm_cls()
    352 OFBEthDstHM = create_oxm_cls()
    353 OFBEthDstHMID = create_oxm_cls()
    354 OFBEthSrc = create_oxm_cls()
    355 OFBEthSrcID = create_oxm_cls()
    356 OFBEthSrcHM = create_oxm_cls()
    357 OFBEthSrcHMID = create_oxm_cls()
    358 OFBEthType = create_oxm_cls()
    359 OFBEthTypeID = create_oxm_cls()
    360 OFBEthTypeHM = create_oxm_cls()
    361 OFBEthTypeHMID = create_oxm_cls()
    362 OFBVLANVID = create_oxm_cls()
    363 OFBVLANVIDID = create_oxm_cls()
    364 OFBVLANVIDHM = create_oxm_cls()
    365 OFBVLANVIDHMID = create_oxm_cls()
    366 OFBVLANPCP = create_oxm_cls()
    367 OFBVLANPCPID = create_oxm_cls()
    368 OFBVLANPCPHM = create_oxm_cls()
    369 OFBVLANPCPHMID = create_oxm_cls()
    370 OFBIPDSCP = create_oxm_cls()
    371 OFBIPDSCPID = create_oxm_cls()
    372 OFBIPDSCPHM = create_oxm_cls()
    373 OFBIPDSCPHMID = create_oxm_cls()
    374 OFBIPECN = create_oxm_cls()
    375 OFBIPECNID = create_oxm_cls()
    376 OFBIPECNHM = create_oxm_cls()
    377 OFBIPECNHMID = create_oxm_cls()
    378 OFBIPProto = create_oxm_cls()
    379 OFBIPProtoID = create_oxm_cls()
    380 OFBIPProtoHM = create_oxm_cls()
    381 OFBIPProtoHMID = create_oxm_cls()
    382 OFBIPv4Src = create_oxm_cls()
    383 OFBIPv4SrcID = create_oxm_cls()
    384 OFBIPv4SrcHM = create_oxm_cls()
    385 OFBIPv4SrcHMID = create_oxm_cls()
    386 OFBIPv4Dst = create_oxm_cls()
    387 OFBIPv4DstID = create_oxm_cls()
    388 OFBIPv4DstHM = create_oxm_cls()
    389 OFBIPv4DstHMID = create_oxm_cls()
    390 OFBTCPSrc = create_oxm_cls()
    391 OFBTCPSrcID = create_oxm_cls()
    392 OFBTCPSrcHM = create_oxm_cls()
    393 OFBTCPSrcHMID = create_oxm_cls()
    394 OFBTCPDst = create_oxm_cls()
    395 OFBTCPDstID = create_oxm_cls()
    396 OFBTCPDstHM = create_oxm_cls()
    397 OFBTCPDstHMID = create_oxm_cls()
    398 OFBUDPSrc = create_oxm_cls()
    399 OFBUDPSrcID = create_oxm_cls()
    400 OFBUDPSrcHM = create_oxm_cls()
    401 OFBUDPSrcHMID = create_oxm_cls()
    402 OFBUDPDst = create_oxm_cls()
    403 OFBUDPDstID = create_oxm_cls()
    404 OFBUDPDstHM = create_oxm_cls()
    405 OFBUDPDstHMID = create_oxm_cls()
    406 OFBSCTPSrc = create_oxm_cls()
    407 OFBSCTPSrcID = create_oxm_cls()
    408 OFBSCTPSrcHM = create_oxm_cls()
    409 OFBSCTPSrcHMID = create_oxm_cls()
    410 OFBSCTPDst = create_oxm_cls()
    411 OFBSCTPDstID = create_oxm_cls()
    412 OFBSCTPDstHM = create_oxm_cls()
    413 OFBSCTPDstHMID = create_oxm_cls()
    414 OFBICMPv4Type = create_oxm_cls()
    415 OFBICMPv4TypeID = create_oxm_cls()
    416 OFBICMPv4TypeHM = create_oxm_cls()
    417 OFBICMPv4TypeHMID = create_oxm_cls()
    418 OFBICMPv4Code = create_oxm_cls()
    419 OFBICMPv4CodeID = create_oxm_cls()
    420 OFBICMPv4CodeHM = create_oxm_cls()
    421 OFBICMPv4CodeHMID = create_oxm_cls()
    422 OFBARPOP = create_oxm_cls()
    423 OFBARPOPID = create_oxm_cls()
    424 OFBARPOPHM = create_oxm_cls()
    425 OFBARPOPHMID = create_oxm_cls()
    426 OFBARPSPA = create_oxm_cls()
    427 OFBARPSPAID = create_oxm_cls()
    428 OFBARPSPAHM = create_oxm_cls()
    429 OFBARPSPAHMID = create_oxm_cls()
    430 OFBARPTPA = create_oxm_cls()
    431 OFBARPTPAID = create_oxm_cls()
    432 OFBARPTPAHM = create_oxm_cls()
    433 OFBARPTPAHMID = create_oxm_cls()
    434 OFBARPSHA = create_oxm_cls()
    435 OFBARPSHAID = create_oxm_cls()
    436 OFBARPSHAHM = create_oxm_cls()
    437 OFBARPSHAHMID = create_oxm_cls()
    438 OFBARPTHA = create_oxm_cls()
    439 OFBARPTHAID = create_oxm_cls()
    440 OFBARPTHAHM = create_oxm_cls()
    441 OFBARPTHAHMID = create_oxm_cls()
    442 OFBIPv6Src = create_oxm_cls()
    443 OFBIPv6SrcID = create_oxm_cls()
    444 OFBIPv6SrcHM = create_oxm_cls()
    445 OFBIPv6SrcHMID = create_oxm_cls()
    446 OFBIPv6Dst = create_oxm_cls()
    447 OFBIPv6DstID = create_oxm_cls()
    448 OFBIPv6DstHM = create_oxm_cls()
    449 OFBIPv6DstHMID = create_oxm_cls()
    450 OFBIPv6FLabel = create_oxm_cls()
    451 OFBIPv6FLabelID = create_oxm_cls()
    452 OFBIPv6FLabelHM = create_oxm_cls()
    453 OFBIPv6FLabelHMID = create_oxm_cls()
    454 OFBICMPv6Type = create_oxm_cls()
    455 OFBICMPv6TypeID = create_oxm_cls()
    456 OFBICMPv6TypeHM = create_oxm_cls()
    457 OFBICMPv6TypeHMID = create_oxm_cls()
    458 OFBICMPv6Code = create_oxm_cls()
    459 OFBICMPv6CodeID = create_oxm_cls()
    460 OFBICMPv6CodeHM = create_oxm_cls()
    461 OFBICMPv6CodeHMID = create_oxm_cls()
    462 OFBIPv6NDTarget = create_oxm_cls()
    463 OFBIPv6NDTargetID = create_oxm_cls()
    464 OFBIPv6NDTargetHM = create_oxm_cls()
    465 OFBIPv6NDTargetHMID = create_oxm_cls()
    466 OFBIPv6NDSLL = create_oxm_cls()
    467 OFBIPv6NDSLLID = create_oxm_cls()
    468 OFBIPv6NDSLLHM = create_oxm_cls()
    469 OFBIPv6NDSLLHMID = create_oxm_cls()
    470 OFBIPv6NDTLL = create_oxm_cls()
    471 OFBIPv6NDTLLID = create_oxm_cls()
    472 OFBIPv6NDTLLHM = create_oxm_cls()
    473 OFBIPv6NDTLLHMID = create_oxm_cls()
    474 OFBMPLSLabel = create_oxm_cls()
    475 OFBMPLSLabelID = create_oxm_cls()
    476 OFBMPLSLabelHM = create_oxm_cls()
    477 OFBMPLSLabelHMID = create_oxm_cls()
    478 OFBMPLSTC = create_oxm_cls()
    479 OFBMPLSTCID = create_oxm_cls()
    480 OFBMPLSTCHM = create_oxm_cls()
    481 OFBMPLSTCHMID = create_oxm_cls()
    482 OFBMPLSBoS = create_oxm_cls()
    483 OFBMPLSBoSID = create_oxm_cls()
    484 OFBMPLSBoSHM = create_oxm_cls()
    485 OFBMPLSBoSHMID = create_oxm_cls()
    486 OFBPBBISID = create_oxm_cls()
    487 OFBPBBISIDID = create_oxm_cls()
    488 OFBPBBISIDHM = create_oxm_cls()
    489 OFBPBBISIDHMID = create_oxm_cls()
    490 OFBTunnelID = create_oxm_cls()
    491 OFBTunnelIDID = create_oxm_cls()
    492 OFBTunnelIDHM = create_oxm_cls()
    493 OFBTunnelIDHMID = create_oxm_cls()
    494 OFBIPv6ExtHdr = create_oxm_cls()
    495 OFBIPv6ExtHdrID = create_oxm_cls()
    496 OFBIPv6ExtHdrHM = create_oxm_cls()
    497 OFBIPv6ExtHdrHMID = create_oxm_cls()
    498 
    499 ### need_prereq holds a list of prerequisites defined in 7.2.3.8 of the specifications
    500 ### e.g. if you want to use an OFBTCPSrc instance (code 26)
    501 ### you first need to declare an OFBIPProto instance (code 20) with value 6,
    502 ### and if you want to use an OFBIPProto instance (still code 20)
    503 ### you first need to declare an OFBEthType instance (code 10) with value 0x0800
    504 ### (0x0800 means IPv4 by default, but you might want to use 0x86dd with IPv6)
    505 ### need_prereq codes are two times higher than previous oxm classes codes,
    506 ### except for 21 which is sort of a proxy for IPv6 (see below)
    507 need_prereq = { 14: [12, 0x1000],
    508                 16: [10, 0x0800],    # could be 0x86dd
    509                 18: [10, 0x0800],    # could be 0x86dd
    510                 20: [10, 0x0800],    # could be 0x86dd
    511                 21: [10, 0x86dd],
    512                 22: [10, 0x0800],
    513                 24: [10, 0x0800],
    514                 26: [20, 6],    
    515                 28: [20, 6],    
    516                 30: [20, 17],    
    517                 32: [20, 17],    
    518                 34: [20, 132],    
    519                 36: [20, 132],    
    520                 38: [20, 1],    
    521                 40: [20, 1],    
    522                 42: [10, 0x0806],
    523                 44: [10, 0x0806],
    524                 46: [10, 0x0806],
    525                 48: [10, 0x0806],
    526                 50: [10, 0x0806],
    527                 52: [10, 0x86dd],
    528                 54: [10, 0x86dd],
    529                 56: [10, 0x86dd],
    530                 58: [21, 58],        ### small trick here, we refer to normally non-
    531                 60: [21, 58],        ### existent field 21 to distinguish ipv6
    532                 62: [58, 135],       # could be 136
    533                 64: [58, 135],
    534                 66: [58, 136],
    535                 68: [10, 0x8847],    # could be 0x8848
    536                 70: [10, 0x8847],    # could be 0x8848
    537                 72: [10, 0x8847],    # could be 0x8848
    538                 74: [10, 0x88e7],
    539                 78: [10, 0x86dd] }
    540 
    541 class OXMPacketListField(PacketListField):
    542 
    543     __slots__ = ["autocomplete", "index"]
    544 
    545     def __init__(self, name, default, cls, length_from=None, autocomplete=prereq_autocomplete):
    546         PacketListField.__init__(self, name, default, cls, length_from=length_from)
    547         self.autocomplete = autocomplete
    548         self.index = []
    549     
    550     def i2m(self, pkt, val):
    551             ### this part makes for a faster writing of specs-compliant matches
    552             ### expect some unwanted behaviour if you try incoherent associations
    553             ### you might want to set autocomplete=False in __init__ method
    554         if self.autocomplete:
    555             # val might be modified during the loop so we need a fixed copy
    556             fix_val = copy.deepcopy(val)
    557             for oxm in fix_val:
    558                 f = 2*oxm.field
    559                 fix_index = list(self.index)
    560                 while f in need_prereq:
    561                 # this loop enables a small recursion
    562                 # e.g. ipv6_nd<--icmpv6<--ip_proto<--eth_type
    563                     prereq = need_prereq[f]
    564                     f = prereq[0]
    565                     f2 = 20 if f == 21 else f       # ipv6 trick...
    566                     if f2 not in fix_index:
    567                         self.index.insert(0, f2)
    568                         prrq = ofp_oxm_cls[f2]()    # never HM
    569                         setattr(prrq, ofp_oxm_constr[f2//2][1], prereq[1])
    570                         val.insert(0, prrq)
    571                     # we could do more complicated stuff to
    572                     # make sure prerequisite order is correct
    573                     # but it works well when presented with any coherent input
    574                     # e.g. you should not mix OFBTCPSrc with OFBICMPv6Code
    575                     # and expect to get coherent results...
    576                     # you can still go manual by setting prereq_autocomplete=False
    577         return val
    578 
    579     def m2i(self, pkt, s):
    580         t = orb(s[2])
    581         nrm_t = t - t%2
    582         if nrm_t not in self.index:
    583             self.index.append(nrm_t)
    584         return ofp_oxm_cls.get(t, Raw)(s)
    585 
    586     @staticmethod
    587     def _get_oxm_length(s):
    588         return orb(s[3])
    589 
    590     def addfield(self, pkt, s, val):
    591         return s + b"".join(raw(x) for x in self.i2m(pkt, val))
    592 
    593     def getfield(self, pkt, s):
    594         lst = []
    595         lim = self.length_from(pkt)
    596         ret = s[lim:]
    597         remain = s[:lim]
    598 
    599         while remain and len(remain) > 4:
    600             l = OXMPacketListField._get_oxm_length(remain) + 4
    601             # this could also be done by parsing oxm_fields (fixed lengths)
    602             if l <= 4 or len(remain) < l:
    603             # no incoherent length
    604                 break
    605             current = remain[:l]
    606             remain = remain[l:]
    607             p = self.m2i(pkt, current)
    608             lst.append(p)
    609 
    610         self.index = []
    611         ### since OXMPacketListField is called only twice (when OFPMatch and OFPSetField
    612         ### classes are created) and not when you want to instantiate an OFPMatch,
    613         ### index needs to be reinitialized, otherwise there will be some conflicts
    614         ### e.g. if you create OFPMatch with OFBTCPSrc and then change to OFBTCPDst,
    615         ### index will already be filled with ethertype and nwproto codes,
    616         ### thus the corresponding fields will not be added to the packet
    617         return remain + ret, lst
    618 
    619 class OXMIDPacketListField(PacketListField):
    620     def m2i(self, pkt, s):
    621         t = orb(s[2])
    622         return ofp_oxm_id_cls.get(t, Raw)(s)
    623 
    624     def getfield(self, pkt, s):
    625         lst = []
    626         lim = self.length_from(pkt)
    627         ret = s[lim:]
    628         remain = s[:lim]
    629 
    630         while remain and len(remain) >= 4:
    631         # all OXM ID are 32-bit long (no experimenter OXM support here)
    632             current = remain[:4]
    633             remain = remain[4:]
    634             p = self.m2i(pkt, current)
    635             lst.append(p)
    636 
    637         return remain + ret, lst
    638 
    639 
    640 class OFPMatch(Packet):
    641     def post_build(self, p, pay):
    642         l = self.length
    643         if l is None:
    644             l = len(p)+len(pay)
    645             p = p[:2] + struct.pack("!H", l) + p[4:]
    646             zero_bytes = (8 - l%8) % 8
    647             p += b"\x00" * zero_bytes
    648         # message with user-defined length will not be automatically padded
    649         return p + pay
    650 
    651     def extract_padding(self, s):
    652         l = self.length
    653         zero_bytes = (8 - l%8) % 8
    654         return s[zero_bytes:], s[:zero_bytes]
    655 
    656     name = "OFP_MATCH"
    657     fields_desc= [ ShortEnumField("type", 1, { 0: "OFPMT_STANDARD",
    658                                                1: "OFPMT_OXM" }),
    659                    ShortField("length", None),
    660                    OXMPacketListField("oxm_fields", [], Packet,
    661                                       length_from=lambda pkt:pkt.length-4) ]
    662 
    663 ### ofp_match is no longer a fixed-length structure in v1.3
    664 ### furthermore it may include variable padding
    665 ### we introduce to that end a subclass of PacketField
    666 class MatchField(PacketField):
    667     def __init__(self, name):
    668         PacketField.__init__(self, name, OFPMatch(), OFPMatch)
    669 
    670     def getfield(self, pkt, s):
    671         i = self.m2i(pkt, s)
    672         ### i can be <OFPMatch> or <OFPMatch <Padding>>
    673         ### or <OFPMatch <Raw>> or <OFPMatch <Raw <Padding>>>
    674         ### and we want to return "", <OFPMatch> or "", <OFPMatch <Padding>>
    675         ### or raw(<Raw>), <OFPMatch> or raw(<Raw>), <OFPMatch <Padding>>
    676         if Raw in i:
    677             r = i[Raw]
    678             if Padding in r:
    679                 p = r[Padding]
    680                 i.payload = p
    681                 del(r.payload)
    682             return r.load, i
    683         else:
    684             return b"", i
    685 
    686 
    687 ###################### Actions ######################
    688 
    689 class _ofp_action_header(Packet):
    690     name = "Dummy OpenFlow Action Header"
    691 
    692     def post_build(self, p, pay):
    693         if self.len is None:
    694             l = len(p)+len(pay)
    695             p = p[:2] + struct.pack("!H", l) + p[4:]
    696         return p + pay
    697 
    698 ofp_action_types = {     0: "OFPAT_OUTPUT",
    699                          1: "OFPAT_SET_VLAN_VID",
    700                          2: "OFPAT_SET_VLAN_PCP",
    701                          3: "OFPAT_STRIP_VLAN",
    702                          4: "OFPAT_SET_DL_SRC",
    703                          5: "OFPAT_SET_DL_DST",
    704                          6: "OFPAT_SET_NW_SRC",
    705                          7: "OFPAT_SET_NW_DST",
    706                          8: "OFPAT_SET_NW_TOS",
    707                          9: "OFPAT_SET_TP_SRC",
    708                         10: "OFPAT_SET_TP_DST",
    709                         #11: "OFPAT_ENQUEUE",
    710                         11: "OFPAT_COPY_TTL_OUT",
    711                         12: "OFPAT_COPY_TTL_IN",
    712                         13: "OFPAT_SET_MPLS_LABEL",
    713                         14: "OFPAT_DEC_MPLS_TC",
    714                         15: "OFPAT_SET_MPLS_TTL",
    715                         16: "OFPAT_DEC_MPLS_TTL",
    716                         17: "OFPAT_PUSH_VLAN",
    717                         18: "OFPAT_POP_VLAN",
    718                         19: "OFPAT_PUSH_MPLS",
    719                         20: "OFPAT_POP_MPLS",
    720                         21: "OFPAT_SET_QUEUE",
    721                         22: "OFPAT_GROUP",
    722                         23: "OFPAT_SET_NW_TTL",
    723                         24: "OFPAT_DEC_NW_TTL",
    724                         25: "OFPAT_SET_FIELD",
    725                         26: "OFPAT_PUSH_PBB",
    726                         27: "OFPAT_POP_PBB",
    727                      65535: "OFPAT_EXPERIMENTER" }
    728 
    729 class OFPATOutput(_ofp_action_header):
    730     name = "OFPAT_OUTPUT"
    731     fields_desc = [ ShortEnumField("type", 0, ofp_action_types),
    732                     ShortField("len", 16),
    733                     IntEnumField("port", 0, ofp_port_no),
    734                     ShortEnumField("max_len", "NO_BUFFER", ofp_max_len),
    735                     XBitField("pad", 0, 48) ]
    736 
    737 # the following actions are not supported by OFv1.3
    738 
    739 class OFPATSetVLANVID(_ofp_action_header):
    740     name = "OFPAT_SET_VLAN_VID"
    741     fields_desc = [ ShortEnumField("type", 1, ofp_action_types),
    742                     ShortField("len", 8),
    743                     ShortField("vlan_vid", 0),
    744                     XShortField("pad", 0) ]
    745 
    746 class OFPATSetVLANPCP(_ofp_action_header):
    747     name = "OFPAT_SET_VLAN_PCP"
    748     fields_desc = [ ShortEnumField("type", 2, ofp_action_types),
    749                     ShortField("len", 8),
    750                     ByteField("vlan_pcp", 0),
    751                     X3BytesField("pad", 0) ]
    752 
    753 class OFPATStripVLAN(_ofp_action_header):
    754     name = "OFPAT_STRIP_VLAN"
    755     fields_desc = [ ShortEnumField("type", 3, ofp_action_types),
    756                     ShortField("len", 8),
    757                     XIntField("pad", 0) ]
    758 
    759 class OFPATSetDlSrc(_ofp_action_header):
    760     name = "OFPAT_SET_DL_SRC"
    761     fields_desc = [ ShortEnumField("type", 4, ofp_action_types),
    762                     ShortField("len", 16),
    763                     MACField("dl_addr", "0"),
    764                     XBitField("pad", 0, 48) ]
    765 
    766 class OFPATSetDlDst(_ofp_action_header):
    767     name = "OFPAT_SET_DL_DST"
    768     fields_desc = [ ShortEnumField("type", 5, ofp_action_types),
    769                     ShortField("len", 16),
    770                     MACField("dl_addr", "0"),
    771                     XBitField("pad", 0, 48) ]
    772 
    773 class OFPATSetNwSrc(_ofp_action_header):
    774     name = "OFPAT_SET_NW_SRC"
    775     fields_desc = [ ShortEnumField("type", 6, ofp_action_types),
    776                     ShortField("len", 8),
    777                     IPField("nw_addr", "0") ]
    778 
    779 class OFPATSetNwDst(_ofp_action_header):
    780     name = "OFPAT_SET_NW_DST"
    781     fields_desc = [ ShortEnumField("type", 7, ofp_action_types),
    782                     ShortField("len", 8),
    783                     IPField("nw_addr", "0") ]
    784 
    785 class OFPATSetNwToS(_ofp_action_header):
    786     name = "OFPAT_SET_TP_TOS"
    787     fields_desc = [ ShortEnumField("type", 8, ofp_action_types),
    788                     ShortField("len", 8),
    789                     ByteField("nw_tos", 0),
    790                     X3BytesField("pad", 0) ]
    791 
    792 class OFPATSetTpSrc(_ofp_action_header):
    793     name = "OFPAT_SET_TP_SRC"
    794     fields_desc = [ ShortEnumField("type", 9, ofp_action_types),
    795                     ShortField("len", 8),
    796                     ShortField("tp_port", 0),
    797                     XShortField("pad", 0) ]
    798 
    799 class OFPATSetTpDst(_ofp_action_header):
    800     name = "OFPAT_SET_TP_DST"
    801     fields_desc = [ ShortEnumField("type", 10, ofp_action_types),
    802                     ShortField("len", 8),
    803                     ShortField("tp_port", 0),
    804                     XShortField("pad", 0) ]
    805 
    806 #class OFPATEnqueue(_ofp_action_header):
    807 #       name = "OFPAT_ENQUEUE"
    808 #       fields_desc = [ ShortEnumField("type", 11, ofp_action_types),
    809 #                       ShortField("len", 16),
    810 #                       ShortField("port", 0),
    811 #                       XBitField("pad", 0, 48),
    812 #                       IntEnumField("queue_id", 0, ofp_queue) ]
    813 
    814 class OFPATSetMPLSLabel(_ofp_action_header):
    815     name = "OFPAT_SET_MPLS_LABEL"
    816     fields_desc = [ ShortEnumField("type", 13, ofp_action_types),
    817                     ShortField("len", 8),
    818                     IntField("mpls_label", 0) ]
    819 
    820 class OFPATSetMPLSTC(_ofp_action_header):
    821     name = "OFPAT_SET_MPLS_TC"
    822     fields_desc = [ ShortEnumField("type", 14, ofp_action_types),
    823                     ShortField("len", 8),
    824                     ByteField("mpls_tc", 0),
    825                     X3BytesField("pad", 0) ]
    826 
    827 # end of unsupported actions
    828 
    829 class OFPATCopyTTLOut(_ofp_action_header):
    830     name = "OFPAT_COPY_TTL_OUT"
    831     fields_desc = [ ShortEnumField("type", 11, ofp_action_types),
    832                     ShortField("len", 8),
    833                     XIntField("pad", 0) ]
    834 
    835 class OFPATCopyTTLIn(_ofp_action_header):
    836     name = "OFPAT_COPY_TTL_IN"
    837     fields_desc = [ ShortEnumField("type", 12, ofp_action_types),
    838                     ShortField("len", 8),
    839                     XIntField("pad", 0) ]
    840 
    841 class OFPATSetMPLSTTL(_ofp_action_header):
    842     name = "OFPAT_SET_MPLS_TTL"
    843     fields_desc = [ ShortEnumField("type", 15, ofp_action_types),
    844                     ShortField("len", 8),
    845                     ByteField("mpls_ttl", 0),
    846                     X3BytesField("pad", 0) ]
    847 
    848 class OFPATDecMPLSTTL(_ofp_action_header):
    849     name = "OFPAT_DEC_MPLS_TTL"
    850     fields_desc = [ ShortEnumField("type", 16, ofp_action_types),
    851                     ShortField("len", 8),
    852                     XIntField("pad", 0) ]
    853 
    854 class OFPATPushVLAN(_ofp_action_header):
    855     name = "OFPAT_PUSH_VLAN"
    856     fields_desc = [ ShortEnumField("type", 17, ofp_action_types),
    857                     ShortField("len", 8),
    858                     ShortField("ethertype", 0x8100),    # or 0x88a8
    859                     XShortField("pad", 0) ]
    860 
    861 class OFPATPopVLAN(_ofp_action_header):
    862     name = "OFPAT_POP_VLAN"
    863     fields_desc = [ ShortEnumField("type", 18, ofp_action_types),
    864                     ShortField("len", 8),
    865                     XIntField("pad", 0) ]
    866 
    867 class OFPATPushMPLS(_ofp_action_header):
    868     name = "OFPAT_PUSH_MPLS"
    869     fields_desc = [ ShortEnumField("type", 19, ofp_action_types),
    870                     ShortField("len", 8),
    871                     ShortField("ethertype", 0x8847),    # or 0x8848
    872                     XShortField("pad", 0) ]
    873 
    874 class OFPATPopMPLS(_ofp_action_header):
    875     name = "OFPAT_POP_MPLS"
    876     fields_desc = [ ShortEnumField("type", 20, ofp_action_types),
    877                     ShortField("len", 8),
    878                     ShortField("ethertype", 0x8847),    # or 0x8848
    879                     XShortField("pad", 0) ]
    880 
    881 class OFPATSetQueue(_ofp_action_header):
    882     name = "OFPAT_SET_QUEUE"
    883     fields_desc = [ ShortEnumField("type", 21, ofp_action_types),
    884                     ShortField("len", 8),
    885                     IntEnumField("queue_id", 0, ofp_queue) ]
    886 
    887 class OFPATGroup(_ofp_action_header):
    888     name = "OFPAT_GROUP"
    889     fields_desc = [ ShortEnumField("type", 22, ofp_action_types),
    890                     ShortField("len", 8),
    891                     IntEnumField("group_id", 0, ofp_group) ]
    892 
    893 class OFPATSetNwTTL(_ofp_action_header):
    894     name = "OFPAT_SET_NW_TTL"
    895     fields_desc = [ ShortEnumField("type", 23, ofp_action_types),
    896                     ShortField("len", 8),
    897                     ByteField("nw_ttl", 0),
    898                     X3BytesField("pad", 0) ]
    899 
    900 class OFPATDecNwTTL(_ofp_action_header):
    901     name = "OFPAT_DEC_NW_TTL"
    902     fields_desc = [ ShortEnumField("type", 24, ofp_action_types),
    903                     ShortField("len", 8),
    904                     XIntField("pad", 0) ]
    905 
    906 class OFPATSetField(_ofp_action_header):
    907 
    908     def post_build(self, p, pay):
    909         l = self.len
    910         zero_bytes = 0
    911         if l is None:
    912             l = len(p)+len(pay)
    913             zero_bytes = (8 - l%8) % 8
    914             l = l + zero_bytes    # add padding length
    915             p = p[:2] + struct.pack("!H", l) + p[4:]
    916         else:
    917             zero_bytes = (8 - l%8) % 8
    918         # every message will be padded correctly
    919         p += b"\x00" * zero_bytes
    920         return p + pay
    921 
    922     def extract_padding(self, s):
    923         return "", s
    924 
    925     name = "OFPAT_SET_FIELD"
    926     fields_desc = [ ShortEnumField("type", 25, ofp_action_types),
    927                     ShortField("len", None),
    928                     # there should not be more than one oxm tlv
    929                     OXMPacketListField("field", [], Packet,
    930                                        length_from=lambda pkt:pkt.len-4,
    931                                        # /!\ contains padding!
    932                                        autocomplete=False) ]
    933 
    934 class OFPATPushPBB(_ofp_action_header):
    935     name = "OFPAT_PUSH_PBB"
    936     fields_desc = [ ShortEnumField("type", 26, ofp_action_types),
    937                     ShortField("len", 8),
    938                     ShortField("ethertype", 0x88e7),
    939                     XShortField("pad", 0) ]
    940 
    941 class OFPATPopPBB(_ofp_action_header):
    942     name = "OFPAT_POP_PBB"
    943     fields_desc = [ ShortEnumField("type", 27, ofp_action_types),
    944                     ShortField("len", 8),
    945                     XIntField("pad", 0) ]
    946 
    947 class OFPATExperimenter(_ofp_action_header):
    948     name = "OFPAT_EXPERIMENTER"
    949     fields_desc = [ ShortEnumField("type", 65535, ofp_action_types),
    950                     ShortField("len", 8),
    951                     IntField("experimenter", 0) ]
    952 
    953 ofp_action_cls = {     0: OFPATOutput,
    954                        1: OFPATSetVLANVID,
    955                        2: OFPATSetVLANPCP,
    956                        3: OFPATStripVLAN,
    957                        4: OFPATSetDlSrc,
    958                        5: OFPATSetDlDst,
    959                        6: OFPATSetNwSrc,
    960                        7: OFPATSetNwDst,
    961                        8: OFPATSetNwToS,
    962                        9: OFPATSetTpSrc,
    963                       10: OFPATSetTpDst,
    964                       #11: OFPATEnqueue,
    965                       11: OFPATCopyTTLOut,
    966                       12: OFPATCopyTTLIn,
    967                       13: OFPATSetMPLSLabel,
    968                       14: OFPATSetMPLSTC,
    969                       15: OFPATSetMPLSTTL,
    970                       16: OFPATDecMPLSTTL,
    971                       17: OFPATPushVLAN,
    972                       18: OFPATPopVLAN,
    973                       19: OFPATPushMPLS,
    974                       20: OFPATPopMPLS,
    975                       21: OFPATSetQueue,
    976                       22: OFPATGroup,
    977                       23: OFPATSetNwTTL,
    978                       24: OFPATDecNwTTL,
    979                       25: OFPATSetField,
    980                       26: OFPATPushPBB,
    981                       27: OFPATPopPBB,
    982                    65535: OFPATExperimenter }
    983 
    984 class ActionPacketListField(PacketListField):
    985     def m2i(self, pkt, s):
    986         t = struct.unpack("!H", s[:2])[0]
    987         return ofp_action_cls.get(t, Raw)(s)
    988 
    989     @staticmethod
    990     def _get_action_length(s):
    991         return struct.unpack("!H", s[2:4])[0]
    992 
    993     def getfield(self, pkt, s):
    994         lst = []
    995         remain = s
    996 
    997         while remain and len(remain)>=4:
    998             l = ActionPacketListField._get_action_length(remain)
    999             if l < 8 or len(remain) < l:
   1000               # length should be at least 8 (non-zero, 64-bit aligned),
   1001               # and no incoherent length
   1002               break
   1003             current = remain[:l]
   1004             remain = remain[l:]
   1005             p = self.m2i(pkt, current)
   1006             lst.append(p)
   1007 
   1008         return remain, lst
   1009 
   1010 
   1011 ##################### Action IDs ####################
   1012 
   1013 # length is computed as in instruction structures,
   1014 # so we reuse _ofp_instruction_header
   1015 
   1016 class OFPATOutputID(_ofp_action_header):
   1017     name = "OFPAT_OUTPUT"
   1018     fields_desc = [ ShortEnumField("type", 0, ofp_action_types),
   1019                     ShortField("len", 4) ]
   1020 
   1021 # the following actions are not supported by OFv1.3
   1022 
   1023 class OFPATSetVLANVIDID(_ofp_action_header):
   1024     name = "OFPAT_SET_VLAN_VID"
   1025     fields_desc = [ ShortEnumField("type", 1, ofp_action_types),
   1026                     ShortField("len", 4) ]
   1027 
   1028 class OFPATSetVLANPCPID(_ofp_action_header):
   1029     name = "OFPAT_SET_VLAN_PCP"
   1030     fields_desc = [ ShortEnumField("type", 2, ofp_action_types),
   1031                     ShortField("len", 4) ]
   1032 
   1033 class OFPATStripVLANID(_ofp_action_header):
   1034     name = "OFPAT_STRIP_VLAN"
   1035     fields_desc = [ ShortEnumField("type", 3, ofp_action_types),
   1036                     ShortField("len", 4) ]
   1037 
   1038 class OFPATSetDlSrcID(_ofp_action_header):
   1039     name = "OFPAT_SET_DL_SRC"
   1040     fields_desc = [ ShortEnumField("type", 4, ofp_action_types),
   1041                     ShortField("len", 4) ]
   1042 
   1043 class OFPATSetDlDstID(_ofp_action_header):
   1044     name = "OFPAT_SET_DL_DST"
   1045     fields_desc = [ ShortEnumField("type", 5, ofp_action_types),
   1046                     ShortField("len", 4) ]
   1047 
   1048 class OFPATSetNwSrcID(_ofp_action_header):
   1049     name = "OFPAT_SET_NW_SRC"
   1050     fields_desc = [ ShortEnumField("type", 6, ofp_action_types),
   1051                     ShortField("len", 4) ]
   1052 
   1053 class OFPATSetNwDstID(_ofp_action_header):
   1054     name = "OFPAT_SET_NW_DST"
   1055     fields_desc = [ ShortEnumField("type", 7, ofp_action_types),
   1056                     ShortField("len", 4) ]
   1057 
   1058 class OFPATSetNwToSID(_ofp_action_header):
   1059     name = "OFPAT_SET_TP_TOS"
   1060     fields_desc = [ ShortEnumField("type", 8, ofp_action_types),
   1061                     ShortField("len", 4) ]
   1062 
   1063 class OFPATSetTpSrcID(_ofp_action_header):
   1064     name = "OFPAT_SET_TP_SRC"
   1065     fields_desc = [ ShortEnumField("type", 9, ofp_action_types),
   1066                     ShortField("len", 4) ]
   1067 
   1068 class OFPATSetTpDstID(_ofp_action_header):
   1069     name = "OFPAT_SET_TP_DST"
   1070     fields_desc = [ ShortEnumField("type", 10, ofp_action_types),
   1071                     ShortField("len", 4) ]
   1072 
   1073 #class OFPATEnqueueID(_ofp_action_header):
   1074 #       name = "OFPAT_ENQUEUE"
   1075 #       fields_desc = [ ShortEnumField("type", 11, ofp_action_types),
   1076 #                       ShortField("len", 4) ]
   1077 
   1078 class OFPATSetMPLSLabelID(_ofp_action_header):
   1079     name = "OFPAT_SET_MPLS_LABEL"
   1080     fields_desc = [ ShortEnumField("type", 13, ofp_action_types),
   1081                     ShortField("len", 4) ]
   1082 
   1083 class OFPATSetMPLSTCID(_ofp_action_header):
   1084     name = "OFPAT_SET_MPLS_TC"
   1085     fields_desc = [ ShortEnumField("type", 14, ofp_action_types),
   1086                     ShortField("len", 4) ]
   1087 
   1088 # end of unsupported actions
   1089 
   1090 class OFPATCopyTTLOutID(_ofp_action_header):
   1091     name = "OFPAT_COPY_TTL_OUT"
   1092     fields_desc = [ ShortEnumField("type", 11, ofp_action_types),
   1093                     ShortField("len", 4) ]
   1094 
   1095 class OFPATCopyTTLInID(_ofp_action_header):
   1096     name = "OFPAT_COPY_TTL_IN"
   1097     fields_desc = [ ShortEnumField("type", 12, ofp_action_types),
   1098                     ShortField("len", 4) ]
   1099 
   1100 class OFPATSetMPLSTTLID(_ofp_action_header):
   1101     name = "OFPAT_SET_MPLS_TTL"
   1102     fields_desc = [ ShortEnumField("type", 15, ofp_action_types),
   1103                     ShortField("len", 4) ]
   1104 
   1105 class OFPATDecMPLSTTLID(_ofp_action_header):
   1106     name = "OFPAT_DEC_MPLS_TTL"
   1107     fields_desc = [ ShortEnumField("type", 16, ofp_action_types),
   1108                     ShortField("len", 4) ]
   1109 
   1110 class OFPATPushVLANID(_ofp_action_header):
   1111     name = "OFPAT_PUSH_VLAN"
   1112     fields_desc = [ ShortEnumField("type", 17, ofp_action_types),
   1113                     ShortField("len", 4) ]
   1114 
   1115 class OFPATPopVLANID(_ofp_action_header):
   1116     name = "OFPAT_POP_VLAN"
   1117     fields_desc = [ ShortEnumField("type", 18, ofp_action_types),
   1118                     ShortField("len", 4) ]
   1119 
   1120 class OFPATPushMPLSID(_ofp_action_header):
   1121     name = "OFPAT_PUSH_MPLS"
   1122     fields_desc = [ ShortEnumField("type", 19, ofp_action_types),
   1123                     ShortField("len", 4) ]
   1124 
   1125 class OFPATPopMPLSID(_ofp_action_header):
   1126     name = "OFPAT_POP_MPLS"
   1127     fields_desc = [ ShortEnumField("type", 20, ofp_action_types),
   1128                     ShortField("len", 4) ]
   1129 
   1130 class OFPATSetQueueID(_ofp_action_header):
   1131     name = "OFPAT_SET_QUEUE"
   1132     fields_desc = [ ShortEnumField("type", 21, ofp_action_types),
   1133                     ShortField("len", 4) ]
   1134 
   1135 class OFPATGroupID(_ofp_action_header):
   1136     name = "OFPAT_GROUP"
   1137     fields_desc = [ ShortEnumField("type", 22, ofp_action_types),
   1138                     ShortField("len", 4) ]
   1139 
   1140 class OFPATSetNwTTLID(_ofp_action_header):
   1141     name = "OFPAT_SET_NW_TTL"
   1142     fields_desc = [ ShortEnumField("type", 23, ofp_action_types),
   1143                     ShortField("len", 4) ]
   1144 
   1145 class OFPATDecNwTTLID(_ofp_action_header):
   1146     name = "OFPAT_DEC_NW_TTL"
   1147     fields_desc = [ ShortEnumField("type", 24, ofp_action_types),
   1148                     ShortField("len", 4) ]
   1149 
   1150 class OFPATSetFieldID(_ofp_action_header):
   1151     name = "OFPAT_SET_FIELD"
   1152     fields_desc = [ ShortEnumField("type", 25, ofp_action_types),
   1153                     ShortField("len", 4) ]
   1154 
   1155 class OFPATPushPBBID(_ofp_action_header):
   1156     name = "OFPAT_PUSH_PBB"
   1157     fields_desc = [ ShortEnumField("type", 26, ofp_action_types),
   1158                     ShortField("len", 4) ]
   1159 
   1160 class OFPATPopPBBID(_ofp_action_header):
   1161     name = "OFPAT_POP_PBB"
   1162     fields_desc = [ ShortEnumField("type", 27, ofp_action_types),
   1163                     ShortField("len", 4) ]
   1164 
   1165 class OFPATExperimenterID(_ofp_action_header):
   1166     name = "OFPAT_EXPERIMENTER"
   1167     fields_desc = [ ShortEnumField("type", 65535, ofp_action_types),
   1168                     ShortField("len", None) ]
   1169 
   1170 ofp_action_id_cls = {     0: OFPATOutputID,
   1171                           1: OFPATSetVLANVIDID,
   1172                           2: OFPATSetVLANPCPID,
   1173                           3: OFPATStripVLANID,
   1174                           4: OFPATSetDlSrcID,
   1175                           5: OFPATSetDlDstID,
   1176                           6: OFPATSetNwSrcID,
   1177                           7: OFPATSetNwDstID,
   1178                           8: OFPATSetNwToSID,
   1179                           9: OFPATSetTpSrcID,
   1180                          10: OFPATSetTpDstID,
   1181                          #11: OFPATEnqueueID,
   1182                          11: OFPATCopyTTLOutID,
   1183                          12: OFPATCopyTTLInID,
   1184                          13: OFPATSetMPLSLabelID,
   1185                          14: OFPATSetMPLSTCID,
   1186                          15: OFPATSetMPLSTTLID,
   1187                          16: OFPATDecMPLSTTLID,
   1188                          17: OFPATPushVLANID,
   1189                          18: OFPATPopVLANID,
   1190                          19: OFPATPushMPLSID,
   1191                          20: OFPATPopMPLSID,
   1192                          21: OFPATSetQueueID,
   1193                          22: OFPATGroupID,
   1194                          23: OFPATSetNwTTLID,
   1195                          24: OFPATDecNwTTLID,
   1196                          25: OFPATSetFieldID,
   1197                          26: OFPATPushPBBID,
   1198                          27: OFPATPopPBBID,
   1199                       65535: OFPATExperimenterID }
   1200 
   1201 class ActionIDPacketListField(PacketListField):
   1202     def m2i(self, pkt, s):
   1203         t = struct.unpack("!H", s[:2])[0]
   1204         return ofp_action_id_cls.get(t, Raw)(s)
   1205 
   1206     @staticmethod
   1207     def _get_action_id_length(s):
   1208         return struct.unpack("!H", s[2:4])[0]
   1209 
   1210     def getfield(self, pkt, s):
   1211         lst = []
   1212         remain = s
   1213 
   1214         while remain and len(remain) >= 4:
   1215             l = ActionIDPacketListField._get_action_id_length(remain)
   1216             if l < 4 or len(remain) < l:
   1217             # length is 4 (may be more for experimenter messages),
   1218             # and no incoherent length
   1219                 break
   1220             current = remain[:l]
   1221             remain = remain[l:]
   1222             p = self.m2i(pkt, current)
   1223             lst.append(p)
   1224 
   1225         return remain, lst
   1226 
   1227 
   1228 #################### Instructions ###################
   1229 
   1230 class _ofp_instruction_header(Packet):
   1231     name = "Dummy OpenFlow Instruction Header"
   1232 
   1233     def post_build(self, p, pay):
   1234         if self.len is None:
   1235             l = len(p)+len(pay)
   1236             p = p[:2] + struct.pack("!H", l) + p[4:]
   1237         return p + pay
   1238 
   1239 ofp_instruction_types = {     1: "OFPIT_GOTO_TABLE",
   1240                               2: "OFPIT_WRITE_METADATA",
   1241                               3: "OFPIT_WRITE_ACTIONS",
   1242                               4: "OFPIT_APPLY_ACTIONS",
   1243                               5: "OFPIT_CLEAR_ACTIONS",
   1244                               6: "OFPIT_METER",
   1245                           65535: "OFPIT_EXPERIMENTER" }
   1246 
   1247 class OFPITGotoTable(_ofp_instruction_header):
   1248     name = "OFPIT_GOTO_TABLE"
   1249     fields_desc = [ ShortEnumField("type", 1, ofp_instruction_types),
   1250                     ShortField("len", 8),
   1251                     ByteEnumField("table_id", 0, ofp_table),
   1252                     X3BytesField("pad", 0) ]
   1253 
   1254 class OFPITWriteMetadata(_ofp_instruction_header):
   1255     name = "OFPIT_WRITE_METADATA"
   1256     fields_desc = [ ShortEnumField("type", 2, ofp_instruction_types),
   1257                     ShortField("len", 24),
   1258                     XIntField("pad", 0),
   1259                     LongField("metadata", 0),
   1260                     LongField("metadata_mask", 0) ]
   1261 
   1262 class OFPITWriteActions(_ofp_instruction_header):
   1263     name = "OFPIT_WRITE_ACTIONS"
   1264     fields_desc = [ ShortEnumField("type", 3, ofp_instruction_types),
   1265                     ShortField("len", None),
   1266                     XIntField("pad", 0),
   1267                     ActionPacketListField("actions", [], Packet,
   1268                                           length_from=lambda pkt:pkt.len-8) ]
   1269 
   1270 class OFPITApplyActions(_ofp_instruction_header):
   1271     name = "OFPIT_APPLY_ACTIONS"
   1272     fields_desc = [ ShortEnumField("type", 4, ofp_instruction_types),
   1273                     ShortField("len", None),
   1274                     XIntField("pad", 0),
   1275                     ActionPacketListField("actions", [], Packet,
   1276                                           length_from=lambda pkt:pkt.len-8) ]
   1277 
   1278 class OFPITClearActions(_ofp_instruction_header):
   1279     name = "OFPIT_CLEAR_ACTIONS"
   1280     fields_desc = [ ShortEnumField("type", 5, ofp_instruction_types),
   1281                     ShortField("len", 8),
   1282                     XIntField("pad", 0) ]
   1283 
   1284 class OFPITMeter(_ofp_instruction_header):
   1285     name = "OFPIT_METER"
   1286     fields_desc = [ ShortEnumField("type", 6, ofp_instruction_types),
   1287                     ShortField("len", 8),
   1288                     IntEnumField("meter_id", 1, ofp_meter) ]
   1289 
   1290 class OFPITExperimenter(_ofp_instruction_header):
   1291     name = "OFPIT_EXPERIMENTER"
   1292     fields_desc = [ ShortEnumField("type", 65535, ofp_instruction_types),
   1293                     ShortField("len", None),
   1294                     IntField("experimenter", 0) ]
   1295 
   1296 ofp_instruction_cls = {     1: OFPITGotoTable,
   1297                             2: OFPITWriteMetadata,
   1298                             3: OFPITWriteActions,
   1299                             4: OFPITApplyActions,
   1300                             5: OFPITClearActions,
   1301                             6: OFPITMeter,
   1302                         65535: OFPITExperimenter }
   1303 
   1304 class InstructionPacketListField(PacketListField):
   1305     def m2i(self, pkt, s):
   1306         t = struct.unpack("!H", s[:2])[0]
   1307         return ofp_instruction_cls.get(t, Raw)(s)
   1308 
   1309     @staticmethod
   1310     def _get_instruction_length(s):
   1311         return struct.unpack("!H", s[2:4])[0]
   1312 
   1313     def getfield(self, pkt, s):
   1314         lst = []
   1315         remain = s
   1316 
   1317         while remain and len(remain) > 4:
   1318             l = InstructionPacketListField._get_instruction_length(remain)
   1319             if l < 8 or len(remain) < l:
   1320             # length should be at least 8 (non-zero, 64-bit aligned),
   1321             # and no incoherent length
   1322                 break
   1323             current = remain[:l]
   1324             remain = remain[l:]
   1325             p = self.m2i(pkt, current)
   1326             lst.append(p)
   1327 
   1328         return remain, lst
   1329 
   1330 
   1331 ################## Instruction IDs ##################
   1332 
   1333 # length is computed as in instruction structures,
   1334 # so we reuse _ofp_instruction_header
   1335 
   1336 class OFPITGotoTableID(_ofp_instruction_header):
   1337     name = "OFPIT_GOTO_TABLE"
   1338     fields_desc = [ ShortEnumField("type", 1, ofp_instruction_types),
   1339                     ShortField("len", 4) ]
   1340 
   1341 class OFPITWriteMetadataID(_ofp_instruction_header):
   1342     name = "OFPIT_WRITE_METADATA"
   1343     fields_desc = [ ShortEnumField("type", 2, ofp_instruction_types),
   1344                     ShortField("len", 4) ]
   1345 
   1346 class OFPITWriteActionsID(_ofp_instruction_header):
   1347     name = "OFPIT_WRITE_ACTIONS"
   1348     fields_desc = [ ShortEnumField("type", 3, ofp_instruction_types),
   1349                     ShortField("len", 4) ]
   1350 
   1351 class OFPITApplyActionsID(_ofp_instruction_header):
   1352     name = "OFPIT_APPLY_ACTIONS"
   1353     fields_desc = [ ShortEnumField("type", 4, ofp_instruction_types),
   1354                     ShortField("len", 4) ]
   1355 
   1356 class OFPITClearActionsID(_ofp_instruction_header):
   1357     name = "OFPIT_CLEAR_ACTIONS"
   1358     fields_desc = [ ShortEnumField("type", 5, ofp_instruction_types),
   1359                     ShortField("len", 4) ]
   1360 
   1361 class OFPITMeterID(_ofp_instruction_header):
   1362     name = "OFPIT_METER"
   1363     fields_desc = [ ShortEnumField("type", 6, ofp_instruction_types),
   1364                     ShortField("len", 4) ]
   1365 
   1366 class OFPITExperimenterID(_ofp_instruction_header):
   1367     name = "OFPIT_EXPERIMENTER"
   1368     fields_desc = [ ShortEnumField("type", 65535, ofp_instruction_types),
   1369                     ShortField("len", None) ]
   1370 
   1371 ofp_instruction_id_cls = {     1: OFPITGotoTableID,
   1372                                2: OFPITWriteMetadataID,
   1373                                3: OFPITWriteActionsID,
   1374                                4: OFPITApplyActionsID,
   1375                                5: OFPITClearActionsID,
   1376                                6: OFPITMeterID,
   1377                            65535: OFPITExperimenterID }
   1378 
   1379 class InstructionIDPacketListField(PacketListField):
   1380     def m2i(self, pkt, s):
   1381         t = struct.unpack("!H", s[:2])[0]
   1382         return ofp_instruction_cls.get(t, Raw)(s)
   1383 
   1384     @staticmethod
   1385     def _get_instruction_id_length(s):
   1386         return struct.unpack("!H", s[2:4])[0]
   1387 
   1388     def getfield(self, pkt, s):
   1389         lst = []
   1390         remain = s
   1391 
   1392         while remain and len(remain) >= 4:
   1393             l = InstructionIDPacketListField._get_instruction_id_length(remain)
   1394             if l < 4 or len(remain) < l:
   1395             # length is 4 (may be more for experimenter messages),
   1396             # and no incoherent length
   1397                 break
   1398             current = remain[:l]
   1399             remain = remain[l:]
   1400             p = self.m2i(pkt, current)
   1401             lst.append(p)
   1402 
   1403         return remain, lst
   1404 
   1405 
   1406 ###################### Buckets ######################
   1407 
   1408 class OFPBucket(Packet):
   1409 
   1410     def extract_padding(self, s):
   1411         return "", s
   1412 
   1413     def post_build(self, p, pay):
   1414         if self.len is None:
   1415             l = len(p)+len(pay)
   1416             p = struct.pack("!H", l) + p[2:]
   1417         return p + pay
   1418 
   1419     name = "OFP_BUCKET"
   1420     fields_desc = [ ShortField("len", None),
   1421                     ShortField("weight", 0),
   1422                     IntEnumField("watch_port", 0, ofp_port_no),
   1423                     IntEnumField("watch_group", 0, ofp_group),
   1424                     XIntField("pad", 0),
   1425                     ActionPacketListField("actions", [], Packet,
   1426                                           length_from=lambda pkt:pkt.len-16) ]
   1427 
   1428 class BucketPacketListField(PacketListField):
   1429 
   1430     @staticmethod
   1431     def _get_bucket_length(s):
   1432         return struct.unpack("!H", s[:2])[0]
   1433 
   1434     def getfield(self, pkt, s):
   1435         lst = []
   1436         remain = s
   1437 
   1438         while remain:
   1439             l = BucketPacketListField._get_bucket_length(remain)
   1440             current = remain[:l]
   1441             remain = remain[l:]
   1442             p = OFPBucket(current)
   1443             lst.append(p)
   1444 
   1445         return remain, lst
   1446 
   1447 
   1448 ####################### Queues ######################
   1449 
   1450 class _ofp_queue_property_header(Packet):
   1451     name = "Dummy OpenFlow Queue Property Header"
   1452 
   1453     def post_build(self, p, pay):
   1454         if self.len is None:
   1455             l = len(p)+len(pay)
   1456             p = p[:2] + struct.pack("!H", l) + p[4:]
   1457         return p + pay
   1458 
   1459 ofp_queue_property_types = { 0: "OFPQT_NONE",
   1460                              1: "OFPQT_MIN_RATE" }
   1461 
   1462 class OFPQTNone(_ofp_queue_property_header):
   1463     name = "OFPQT_NONE"
   1464     fields_desc = [ ShortEnumField("type", 0, ofp_queue_property_types),
   1465                     ShortField("len", 8),
   1466                     XIntField("pad", 0) ]
   1467 
   1468 class OFPQTMinRate(_ofp_queue_property_header):
   1469     name = "OFPQT_MIN_RATE"
   1470     fields_desc = [ ShortEnumField("type", 1, ofp_queue_property_types),
   1471                     ShortField("len", 16),
   1472                     XIntField("pad1", 0),
   1473                     ShortField("rate", 0),
   1474                     XBitField("pad2", 0, 48) ]
   1475 
   1476 ofp_queue_property_cls = { 0: OFPQTNone,
   1477                            1: OFPQTMinRate }
   1478 
   1479 class QueuePropertyPacketListField(PacketListField):
   1480     def m2i(self, pkt, s):
   1481         t = struct.unpack("!H", s[:2])[0]
   1482         return ofp_queue_property_cls.get(t, Raw)(s)
   1483 
   1484     @staticmethod
   1485     def _get_queue_property_length(s):
   1486         return struct.unpack("!H", s[2:4])[0]
   1487 
   1488     def getfield(self, pkt, s):
   1489         lst = []
   1490         remain = s
   1491 
   1492         while remain:
   1493             l = QueuePropertyPacketListField._get_queue_property_length(remain)
   1494             current = remain[:l]
   1495             remain = remain[l:]
   1496             p = self.m2i(pkt, current)
   1497             lst.append(p)
   1498 
   1499         return remain, lst
   1500 
   1501 class OFPPacketQueue(Packet):
   1502 
   1503     def extract_padding(self, s):
   1504         return "", s
   1505 
   1506     def post_build(self, p, pay):
   1507         if self.properties == []:
   1508             p += raw(OFPQTNone())
   1509         if self.len is None:
   1510             l = len(p)+len(pay)
   1511             p = p[:4] + struct.pack("!H", l) + p[6:]
   1512         return p + pay
   1513 
   1514     name = "OFP_PACKET_QUEUE"
   1515     fields_desc = [ IntEnumField("queue_id", 0, ofp_queue),
   1516                     ShortField("len", None),
   1517                     XShortField("pad", 0),
   1518                     QueuePropertyPacketListField("properties", [], Packet,
   1519                                                  length_from=lambda pkt:pkt.len-8) ]
   1520 
   1521 class QueuePacketListField(PacketListField):
   1522 
   1523     @staticmethod
   1524     def _get_queue_length(s):
   1525         return struct.unpack("!H", s[4:6])[0]
   1526 
   1527     def getfield(self, pkt, s):
   1528         lst = []
   1529         remain = s
   1530 
   1531         while remain:
   1532             l = QueuePacketListField._get_queue_length(remain)
   1533             current = remain[:l]
   1534             remain = remain[l:]
   1535             p = OFPPacketQueue(current)
   1536             lst.append(p)
   1537 
   1538         return remain, lst
   1539 
   1540 
   1541 #################### Meter bands ####################
   1542 
   1543 ofp_meter_band_types = {     0: "OFPMBT_DROP",
   1544                              1: "OFPMBT_DSCP_REMARK",
   1545                          65535: "OFPMBT_EXPERIMENTER" }
   1546 
   1547 class OFPMBTDrop(Packet):
   1548     name = "OFPMBT_DROP"
   1549     fields_desc = [ ShortEnumField("type", 0, ofp_queue_property_types),
   1550                     ShortField("len", 16),
   1551                     IntField("rate", 0),
   1552                     IntField("burst_size", 0),
   1553                     XIntField("pad", 0) ]
   1554 
   1555 class OFPMBTDSCPRemark(Packet):
   1556     name = "OFPMBT_DSCP_REMARK"
   1557     fields_desc = [ ShortEnumField("type", 1, ofp_queue_property_types),
   1558                     ShortField("len", 16),
   1559                     IntField("rate", 0),
   1560                     IntField("burst_size", 0),
   1561                     ByteField("prec_level", 0),
   1562                     X3BytesField("pad", 0) ]
   1563 
   1564 class OFPMBTExperimenter(Packet):
   1565     name = "OFPMBT_EXPERIMENTER"
   1566     fields_desc = [ ShortEnumField("type", 65535, ofp_queue_property_types),
   1567                     ShortField("len", 16),
   1568                     IntField("rate", 0),
   1569                     IntField("burst_size", 0),
   1570                     IntField("experimenter", 0) ]
   1571 
   1572 ofp_meter_band_cls = { 0: OFPMBTDrop,
   1573                        1: OFPMBTDSCPRemark,
   1574                        2: OFPMBTExperimenter }
   1575 
   1576 class MeterBandPacketListField(PacketListField):
   1577     def m2i(self, pkt, s):
   1578         t = struct.unpack("!H", s[:2])[0]
   1579         return ofp_meter_band_cls.get(t, Raw)(s)
   1580 
   1581     def getfield(self, pkt, s):
   1582         lst = []
   1583         remain = s
   1584 
   1585         while remain:
   1586             current = remain[:16]
   1587             remain = remain[16:]
   1588             p = self.m2i(pkt, current)
   1589             lst.append(p)
   1590 
   1591         return remain, lst
   1592 
   1593 
   1594 #####################################################
   1595 ############## OpenFlow 1.3 Messages ################
   1596 #####################################################
   1597 
   1598 ofp_version = { 0x01: "OpenFlow 1.0",
   1599                 0x02: "OpenFlow 1.1",
   1600                 0x03: "OpenFlow 1.2",
   1601                 0x04: "OpenFlow 1.3",
   1602                 0x05: "OpenFlow 1.4" }
   1603 
   1604 ofp_type = {  0: "OFPT_HELLO",
   1605               1: "OFPT_ERROR",
   1606               2: "OFPT_ECHO_REQUEST",
   1607               3: "OFPT_ECHO_REPLY",
   1608               4: "OFPT_EXPERIMENTER",
   1609               5: "OFPT_FEATURES_REQUEST",
   1610               6: "OFPT_FEATURES_REPLY",
   1611               7: "OFPT_GET_CONFIG_REQUEST",
   1612               8: "OFPT_GET_CONFIG_REPLY",
   1613               9: "OFPT_SET_CONFIG",
   1614              10: "OFPT_PACKET_IN",
   1615              11: "OFPT_FLOW_REMOVED",
   1616              12: "OFPT_PORT_STATUS",
   1617              13: "OFPT_PACKET_OUT",
   1618              14: "OFPT_FLOW_MOD",
   1619              15: "OFPT_GROUP_MOD",
   1620              16: "OFPT_PORT_MOD",
   1621              17: "OFPT_TABLE_MOD",
   1622              18: "OFPT_MULTIPART_REQUEST",
   1623              19: "OFPT_MULTIPART_REPLY",
   1624              20: "OFPT_BARRIER_REQUEST",
   1625              21: "OFPT_BARRIER_REPLY",
   1626              22: "OFPT_QUEUE_GET_CONFIG_REQUEST",
   1627              23: "OFPT_QUEUE_GET_CONFIG_REPLY",
   1628              24: "OFPT_ROLE_REQUEST",
   1629              25: "OFPT_ROLE_REPLY",
   1630              26: "OFPT_GET_ASYNC_REQUEST",
   1631              27: "OFPT_GET_ASYNC_REPLY",
   1632              28: "OFPT_SET_ASYNC",
   1633              29: "OFPT_METER_MOD" }
   1634 
   1635 class _ofp_header(Packet):
   1636     name = "Dummy OpenFlow Header"
   1637 
   1638     def post_build(self, p, pay):
   1639         if self.len is None:
   1640             l = len(p)+len(pay)
   1641             p = p[:2] + struct.pack("!H", l) + p[4:]
   1642         return p + pay
   1643 
   1644 class OFPTHello(_ofp_header):
   1645     name = "OFPT_HELLO"
   1646     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   1647                     ByteEnumField("type", 0, ofp_type),
   1648                     ShortField("len", None),
   1649                     IntField("xid", 0),
   1650                     HelloElemPacketListField("elements", [], Packet,
   1651                                              length_from=lambda pkt:pkt.len-32) ]
   1652     overload_fields = {TCP: {"sport": 6653}}
   1653 
   1654 #####################################################
   1655 ##################### OFPT_ERROR ####################
   1656 #####################################################
   1657 
   1658 ### this class will be used to display some messages
   1659 ### sent back by the switch after an error
   1660 class OFPacketField(PacketField):
   1661     def getfield(self, pkt, s):
   1662         try:
   1663             l = s[2:4]
   1664             l = struct.unpack("!H", l)[0]
   1665             ofload = s[:l]
   1666             remain = s[l:]
   1667             return remain, OpenFlow(None, ofload)(ofload)
   1668         except:
   1669             return b"", Raw(s)
   1670 
   1671 ofp_error_type = {     0: "OFPET_HELLO_FAILED",
   1672                        1: "OFPET_BAD_REQUEST",
   1673                        2: "OFPET_BAD_ACTION",
   1674                        3: "OFPET_BAD_INSTRUCTION",
   1675                        4: "OFPET_BAD_MATCH",
   1676                        5: "OFPET_FLOW_MOD_FAILED",
   1677                        6: "OFPET_GROUP_MOD_FAILED",
   1678                        7: "OFPET_PORT_MOD_FAILED",
   1679                        8: "OFPET_TABLE_MOD_FAILED",
   1680                        9: "OFPET_QUEUE_OP_FAILED",
   1681                       10: "OFPET_SWITCH_CONFIG_FAILED",
   1682                       11: "OFPET_ROLE_REQUEST_FAILED",
   1683                       12: "OFPET_METER_MOD_FAILED",
   1684                       13: "OFPET_TABLE_FEATURES_FAILED",
   1685                    65535: "OFPET_EXPERIMENTER" }
   1686 
   1687 class OFPETHelloFailed(_ofp_header):
   1688     name = "OFPET_HELLO_FAILED"
   1689     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   1690                     ByteEnumField("type", 1, ofp_type),
   1691                     ShortField("len", None),
   1692                     IntField("xid", 0),
   1693                     ShortEnumField("errtype", 0, ofp_error_type),
   1694                     ShortEnumField("errcode", 0, { 0: "OFPHFC_INCOMPATIBLE",
   1695                                                    1: "OFPHFC_EPERM" }),
   1696                     OFPacketField("data", "", Raw) ]
   1697     overload_fields = {TCP: {"dport": 6653}}
   1698 
   1699 class OFPETBadRequest(_ofp_header):
   1700     name = "OFPET_BAD_REQUEST"
   1701     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   1702                     ByteEnumField("type", 1, ofp_type),
   1703                     ShortField("len", None),
   1704                     IntField("xid", 0),
   1705                     ShortEnumField("errtype", 1, ofp_error_type),
   1706                     ShortEnumField("errcode", 0, {  0: "OFPBRC_BAD_VERSION",
   1707                                                     1: "OFPBRC_BAD_TYPE",
   1708                                                     2: "OFPBRC_BAD_MULTIPART",
   1709                                                     3: "OFPBRC_BAD_EXPERIMENTER",
   1710                                                     4: "OFPBRC_BAD_EXP_TYPE",
   1711                                                     5: "OFPBRC_EPERM",
   1712                                                     6: "OFPBRC_BAD_LEN",
   1713                                                     7: "OFPBRC_BUFFER_EMPTY",
   1714                                                     8: "OFPBRC_BUFFER_UNKNOWN",
   1715                                                     9: "OFPBRC_BAD_TABLE_ID",
   1716                                                    10: "OFPBRC_IS_SLAVE",
   1717                                                    11: "OFPBRC_BAD_PORT",
   1718                                                    12: "OFPBRC_BAD_PACKET",
   1719                                                    13: "OFPBRC_MULTIPART_BUFFER_OVERFLOW" }),
   1720                     OFPacketField("data", "", Raw) ]
   1721     overload_fields = {TCP: {"dport": 6653}}
   1722 
   1723 class OFPETBadAction(_ofp_header):
   1724     name = "OFPET_BAD_ACTION"
   1725     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   1726                     ByteEnumField("type", 1, ofp_type),
   1727                     ShortField("len", None),
   1728                     IntField("xid", 0),
   1729                     ShortEnumField("errtype", 2, ofp_error_type),
   1730                     ShortEnumField("errcode", 0, {  0: "OFPBAC_BAD_TYPE",
   1731                                                     1: "OFPBAC_BAD_LEN",
   1732                                                     2: "OFPBAC_BAD_EXPERIMENTER",
   1733                                                     3: "OFPBAC_BAD_EXP_TYPE",
   1734                                                     4: "OFPBAC_BAD_OUT_PORT",
   1735                                                     5: "OFPBAC_BAD_ARGUMENT",
   1736                                                     6: "OFPBAC_EPERM",
   1737                                                     7: "OFPBAC_TOO_MANY",
   1738                                                     8: "OFPBAC_BAD_QUEUE",
   1739                                                     9: "OFPBAC_BAD_OUT_GROUP",
   1740                                                    10: "OFPBAC_MATCH_INCONSISTENT",
   1741                                                    11: "OFPBAC_UNSUPPORTED_ORDER",
   1742                                                    12: "OFPBAC_BAD_TAG",
   1743                                                    13: "OFPBAC_BAD_SET_TYPE",
   1744                                                    14: "OFPBAC_BAD_SET_LEN",
   1745                                                    15: "OFPBAC_BAD_SET_ARGUMENT" }),
   1746                     OFPacketField("data", "", Raw) ]
   1747     overload_fields = {TCP: {"dport": 6653}}
   1748 
   1749 class OFPETBadInstruction(_ofp_header):
   1750     name = "OFPET_BAD_INSTRUCTION"
   1751     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   1752                     ByteEnumField("type", 1, ofp_type),
   1753                     ShortField("len", None),
   1754                     IntField("xid", 0),
   1755                     ShortEnumField("errtype", 3, ofp_error_type),
   1756                     ShortEnumField("errcode", 0, { 0: "OFPBIC_UNKNOWN_INST",
   1757                                                    1: "OFPBIC_UNSUP_INST",
   1758                                                    2: "OFPBIC_BAD_TABLE_ID",
   1759                                                    3: "OFPBIC_UNSUP_METADATA",
   1760                                                    4: "OFPBIC_UNSUP_METADATA_MASK",
   1761                                                    5: "OFPBIC_BAD_EXPERIMENTER",
   1762                                                    6: "OFPBIC_BAD_EXP_TYPE",
   1763                                                    7: "OFPBIC_BAD_LEN",
   1764                                                    8: "OFPBIC_EPERM" }),
   1765                     OFPacketField("data", "", Raw) ]
   1766     overload_fields = {TCP: {"dport": 6653}}
   1767 
   1768 class OFPETBadMatch(_ofp_header):
   1769     name = "OFPET_BAD_MATCH"
   1770     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   1771                     ByteEnumField("type", 1, ofp_type),
   1772                     ShortField("len", None),
   1773                     IntField("xid", 0),
   1774                     ShortEnumField("errtype", 4, ofp_error_type),
   1775                     ShortEnumField("errcode", 0, {  0: "OFPBMC_BAD_TYPE",
   1776                                                     1: "OFPBMC_BAD_LEN",
   1777                                                     2: "OFPBMC_BAD_TAG",
   1778                                                     3: "OFPBMC_BAD_DL_ADDR_MASK",
   1779                                                     4: "OFPBMC_BAD_NW_ADDR_MASK",
   1780                                                     5: "OFPBMC_BAD_WILDCARDS",
   1781                                                     6: "OFPBMC_BAD_FIELD",
   1782                                                     7: "OFPBMC_BAD_VALUE",
   1783                                                     8: "OFPBMC_BAD_MASK",
   1784                                                     9: "OFPBMC_BAD_PREREQ",
   1785                                                    10: "OFPBMC_DUP_FIELD",
   1786                                                    11: "OFPBMC_EPERM" }),
   1787                     OFPacketField("data", "", Raw) ]
   1788     overload_fields = {TCP: {"dport": 6653}}
   1789 
   1790 class OFPETFlowModFailed(_ofp_header):
   1791     name = "OFPET_FLOW_MOD_FAILED"
   1792     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   1793                     ByteEnumField("type", 1, ofp_type),
   1794                     ShortField("len", None),
   1795                     IntField("xid", 0),
   1796                     ShortEnumField("errtype", 5, ofp_error_type),
   1797                     ShortEnumField("errcode", 0, { 0: "OFPFMFC_UNKNOWN",
   1798                                                    1: "OFPFMFC_TABLE_FULL",
   1799                                                    2: "OFPFMFC_BAD_TABLE_ID",
   1800                                                    3: "OFPFMFC_OVERLAP",
   1801                                                    4: "OFPFMFC_EPERM",
   1802                                                    5: "OFPFMFC_BAD_TIMEOUT",
   1803                                                    6: "OFPFMFC_BAD_COMMAND",
   1804                                                    7: "OFPFMFC_BAD_FLAGS" }),
   1805                     OFPacketField("data", "", Raw) ]
   1806     overload_fields = {TCP: {"dport": 6653}}
   1807 
   1808 class OFPETGroupModFailed(_ofp_header):
   1809     name = "OFPET_GROUP_MOD_FAILED"
   1810     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   1811                     ByteEnumField("type", 1, ofp_type),
   1812                     ShortField("len", None),
   1813                     IntField("xid", 0),
   1814                     ShortEnumField("errtype", 6, ofp_error_type),
   1815                     ShortEnumField("errcode", 0, {  0: "OFPGMFC_GROUP_EXISTS",
   1816                                                     1: "OFPGMFC_INVALID_GROUP",
   1817                                                     2: "OFPGMFC_WEIGHT_UNSUPPORTED",
   1818                                                     3: "OFPGMFC_OUT_OF_GROUPS",
   1819                                                     4: "OFPGMFC_OUT_OF_BUCKETS",
   1820                                                     5: "OFPGMFC_CHAINING_UNSUPPORTED",
   1821                                                     6: "OFPGMFC_WATCH_UNSUPPORTED",
   1822                                                     7: "OFPGMFC_LOOP",
   1823                                                     8: "OFPGMFC_UNKNOWN_GROUP",
   1824                                                     9: "OFPGMFC_CHAINED_GROUP",
   1825                                                    10: "OFPGMFC_BAD_TYPE",
   1826                                                    11: "OFPGMFC_BAD_COMMAND",
   1827                                                    12: "OFPGMFC_BAD_BUCKET",
   1828                                                    13: "OFPGMFC_BAD_WATCH",
   1829                                                    14: "OFPFMFC_EPERM" }),
   1830                     OFPacketField("data", "", Raw) ]
   1831     overload_fields = {TCP: {"dport": 6653}}
   1832 
   1833 class OFPETPortModFailed(_ofp_header):
   1834     name = "OFPET_PORT_MOD_FAILED"
   1835     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   1836                     ByteEnumField("type", 1, ofp_type),
   1837                     ShortField("len", None),
   1838                     IntField("xid", 0),
   1839                     ShortEnumField("errtype", 7, ofp_error_type),
   1840                     ShortEnumField("errcode", 0, { 0: "OFPPMFC_BAD_PORT",
   1841                                                    1: "OFPPMFC_BAD_HW_ADDR",
   1842                                                    2: "OFPPMFC_BAD_CONFIG",
   1843                                                    3: "OFPPMFC_BAD_ADVERTISE",
   1844                                                    4: "OFPPMFC_EPERM" }),
   1845                     OFPacketField("data", "", Raw) ]
   1846     overload_fields = {TCP: {"dport": 6653}}
   1847 
   1848 class OFPETTableModFailed(_ofp_header):
   1849     name = "OFPET_TABLE_MOD_FAILED"
   1850     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   1851                     ByteEnumField("type", 1, ofp_type),
   1852                     ShortField("len", None),
   1853                     IntField("xid", 0),
   1854                     ShortEnumField("errtype", 8, ofp_error_type),
   1855                     ShortEnumField("errcode", 0, { 0: "OFPTMFC_BAD_TABLE",
   1856                                                    1: "OFPTMFC_BAD_CONFIG",
   1857                                                    2: "OFPTMFC_EPERM" }),
   1858                     OFPacketField("data", "", Raw) ]
   1859     overload_fields = {TCP: {"dport": 6653}}
   1860 
   1861 class OFPETQueueOpFailed(_ofp_header):
   1862     name = "OFPET_QUEUE_OP_FAILED"
   1863     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   1864                     ByteEnumField("type", 1, ofp_type),
   1865                     ShortField("len", None),
   1866                     IntField("xid", 0),
   1867                     ShortEnumField("errtype", 9, ofp_error_type),
   1868                     ShortEnumField("errcode", 0, { 0: "OFPQOFC_BAD_PORT",
   1869                                                    1: "OFPQOFC_BAD_QUEUE",
   1870                                                    2: "OFPQOFC_EPERM" }),
   1871                     OFPacketField("data", "", Raw) ]
   1872     overload_fields = {TCP: {"dport": 6653}}
   1873 
   1874 class OFPETSwitchConfigFailed(_ofp_header):
   1875     name = "OFPET_SWITCH_CONFIG_FAILED"
   1876     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   1877                     ByteEnumField("type", 1, ofp_type),
   1878                     ShortField("len", None),
   1879                     IntField("xid", 0),
   1880                     ShortEnumField("errtype", 10, ofp_error_type),
   1881                     ShortEnumField("errcode", 0, { 0: "OFPSCFC_BAD_FLAGS",
   1882                                                    1: "OFPSCFC_BAD_LEN",
   1883                                                    2: "OFPSCFC_EPERM" }),
   1884                     OFPacketField("data", "", Raw) ]
   1885     overload_fields = {TCP: {"dport": 6653}}
   1886 
   1887 class OFPETRoleRequestFailed(_ofp_header):
   1888     name = "OFPET_ROLE_REQUEST_FAILED"
   1889     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   1890                     ByteEnumField("type", 1, ofp_type),
   1891                     ShortField("len", None),
   1892                     IntField("xid", 0),
   1893                     ShortEnumField("errtype", 11, ofp_error_type),
   1894                     ShortEnumField("errcode", 0, { 0: "OFPRRFC_STALE",
   1895                                                    1: "OFPRRFC_UNSUP",
   1896                                                    2: "OFPRRFC_BAD_ROLE" }),
   1897                     OFPacketField("data", "", Raw) ]
   1898     overload_fields = {TCP: {"dport": 6653}}
   1899 
   1900 class OFPETMeterModFailed(_ofp_header):
   1901     name = "OFPET_METER_MOD_FAILED"
   1902     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   1903                     ByteEnumField("type", 1, ofp_type),
   1904                     ShortField("len", None),
   1905                     IntField("xid", 0),
   1906                     ShortEnumField("errtype", 12, ofp_error_type),
   1907                     ShortEnumField("errcode", 0, {  0: "OFPMMFC_UNKNOWN",
   1908                                                     1: "OFPMMFC_METER_EXISTS",
   1909                                                     2: "OFPMMFC_INVALID_METER",
   1910                                                     3: "OFPMMFC_UNKNOWN_METER",
   1911                                                     4: "OFPMMFC_BAD_COMMAND",
   1912                                                     5: "OFPMMFC_BAD_FLAGS",
   1913                                                     6: "OFPMMFC_BAD_RATE",
   1914                                                     7: "OFPMMFC_BAD_BURST",
   1915                                                     8: "OFPMMFC_BAD_BAND",
   1916                                                     9: "OFPMMFC_BAD_BAND_VALUE",
   1917                                                    10: "OFPMMFC_OUT_OF_METERS",
   1918                                                    11: "OFPMMFC_OUT_OF_BANDS" }),
   1919                     OFPacketField("data", "", Raw) ]
   1920     overload_fields = {TCP: {"dport": 6653}}
   1921 
   1922 class OFPETTableFeaturesFailed(_ofp_header):
   1923     name = "OFPET_TABLE_FEATURES_FAILED"
   1924     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   1925                     ByteEnumField("type", 1, ofp_type),
   1926                     ShortField("len", None),
   1927                     IntField("xid", 0),
   1928                     ShortEnumField("errtype", 13, ofp_error_type),
   1929                     ShortEnumField("errcode", 0, { 0: "OFPTFFC_BAD_TABLE",
   1930                                                    1: "OFPTFFC_BAD_METADATA",
   1931                                                    2: "OFPTFFC_BAD_TYPE",
   1932                                                    3: "OFPTFFC_BAD_LEN",
   1933                                                    4: "OFPTFFC_BAD_ARGUMENT",
   1934                                                    5: "OFPTFFC_EPERM" }),
   1935                     OFPacketField("data", "", Raw) ]
   1936     overload_fields = {TCP: {"dport": 6653}}
   1937 
   1938 class OFPETExperimenter(_ofp_header):
   1939     name = "OFPET_EXPERIMENTER"
   1940     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   1941                     ByteEnumField("type", 1, ofp_type),
   1942                     ShortField("len", None),
   1943                     IntField("xid", 0),
   1944                     ShortEnumField("errtype", "OFPET_EXPERIMENTER", ofp_error_type),
   1945                     ShortField("exp_type", None),
   1946                     IntField("experimenter", None),
   1947                     OFPacketField("data", "", Raw) ]
   1948     overload_fields = {TCP: {"dport": 6653}}
   1949 
   1950 # ofp_error_cls allows generic method OpenFlow()
   1951 # to choose the right class for dissection
   1952 ofp_error_cls = {     0: OFPETHelloFailed,
   1953                       1: OFPETBadRequest,
   1954                       2: OFPETBadAction,
   1955                       3: OFPETBadInstruction,
   1956                       4: OFPETBadMatch,
   1957                       5: OFPETFlowModFailed,
   1958                       6: OFPETGroupModFailed,
   1959                       7: OFPETPortModFailed,
   1960                       8: OFPETTableModFailed,
   1961                       9: OFPETQueueOpFailed,
   1962                      10: OFPETSwitchConfigFailed,
   1963                      11: OFPETRoleRequestFailed,
   1964                      12: OFPETMeterModFailed,
   1965                      13: OFPETTableFeaturesFailed,
   1966                   65535: OFPETExperimenter }
   1967 
   1968 ################ end of OFPT_ERRORS #################
   1969 
   1970 class OFPTEchoRequest(_ofp_header):
   1971     name = "OFPT_ECHO_REQUEST"
   1972     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   1973                     ByteEnumField("type", 2, ofp_type),
   1974                     ShortField("len", None),
   1975                     IntField("xid", 0) ]
   1976     overload_fields = {TCP: {"sport": 6653}}
   1977 
   1978 class OFPTEchoReply(_ofp_header):
   1979     name = "OFPT_ECHO_REPLY"
   1980     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   1981                     ByteEnumField("type", 3, ofp_type),
   1982                     ShortField("len", None),
   1983                     IntField("xid", 0) ]
   1984     overload_fields = {TCP: {"sport": 6653}}
   1985 
   1986 class OFPTExperimenter(_ofp_header):
   1987     name = "OFPT_EXPERIMENTER"
   1988     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   1989                     ByteEnumField("type", 4, ofp_type),
   1990                     ShortField("len", None),
   1991                     IntField("xid", 0),
   1992                     IntField("experimenter", 0),
   1993                     IntField("exp_type", 0) ]
   1994     overload_fields = {TCP: {"sport": 6653}}
   1995 
   1996 class OFPTFeaturesRequest(_ofp_header):
   1997     name = "OFPT_FEATURES_REQUEST"
   1998     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   1999                     ByteEnumField("type", 5, ofp_type),
   2000                     ShortField("len", None),
   2001                     IntField("xid", 0) ]
   2002     overload_fields = {TCP: {"sport": 6653}}
   2003 
   2004 class OFPTFeaturesReply(_ofp_header):
   2005     name = "OFPT_FEATURES_REPLY"
   2006     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2007                     ByteEnumField("type", 6, ofp_type),
   2008                     ShortField("len", None),
   2009                     IntField("xid", 0),
   2010                     LongField("datapath_id", 0),
   2011                     IntField("n_buffers", 0),
   2012                     ByteField("n_tables", 1),
   2013                     ByteField("auxiliary_id", 0),
   2014                     XShortField("pad", 0),
   2015                     FlagsField("capabilities", 0, 32, [ "FLOW_STATS",
   2016                                                         "TABLE_STATS",
   2017                                                         "PORT_STATS",
   2018                                                         "GROUP_STATS",
   2019                                                         "RESERVED",       #undefined
   2020                                                         "IP_REASM",
   2021                                                         "QUEUE_STATS",
   2022                                                         "ARP_MATCH_IP",   #undefined
   2023                                                         "PORT_BLOCKED"]),
   2024                     IntField("reserved", 0) ]
   2025     overload_fields = {TCP: {"dport": 6653}}
   2026 
   2027 class OFPTGetConfigRequest(_ofp_header):
   2028     name = "OFPT_GET_CONFIG_REQUEST"
   2029     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2030                     ByteEnumField("type", 7, ofp_type),
   2031                     ShortField("len", None),
   2032                     IntField("xid", 0) ]
   2033     overload_fields = {TCP: {"sport": 6653}}
   2034 
   2035 class OFPTGetConfigReply(_ofp_header):
   2036     name = "OFPT_GET_CONFIG_REPLY"
   2037     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2038                     ByteEnumField("type", 8, ofp_type),
   2039                     ShortField("len", None),
   2040                     IntField("xid", 0),
   2041                     ShortEnumField("flags", 0, { 0: "FRAG_NORMAL",
   2042                                                  1: "FRAG_DROP",
   2043                                                  2: "FRAG_REASM",
   2044                                                  3: "FRAG_MASK" }),
   2045                     ShortField("miss_send_len", 0) ]
   2046     overload_fields = {TCP: {"dport": 6653}}
   2047 
   2048 class OFPTSetConfig(_ofp_header):
   2049     name = "OFPT_SET_CONFIG"
   2050     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2051                     ByteEnumField("type", 9, ofp_type),
   2052                     ShortField("len", None),
   2053                     IntField("xid", 0),
   2054                     ShortEnumField("flags", 0, { 0: "FRAG_NORMAL",
   2055                                                  1: "FRAG_DROP",
   2056                                                  2: "FRAG_REASM",
   2057                                                  3: "FRAG_MASK" }),
   2058                     ShortField("miss_send_len", 128) ]
   2059     overload_fields = {TCP: {"sport": 6653}}
   2060 
   2061 class OFPTPacketIn(_ofp_header):
   2062     name = "OFPT_PACKET_IN"
   2063     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2064                     ByteEnumField("type", 10, ofp_type),
   2065                     ShortField("len", None),
   2066                     IntField("xid", 0),
   2067                     IntEnumField("buffer_id", "NO_BUFFER", ofp_buffer),
   2068                     ShortField("total_len", 0),
   2069                     ByteEnumField("reason", 0, { 0: "OFPR_NO_MATCH",
   2070                                                  1: "OFPR_ACTION",
   2071                                                  2: "OFPR_INVALID_TTL"}),
   2072                     ByteEnumField("table_id", 0, ofp_table),
   2073                     LongField("cookie", 0),
   2074                     MatchField("match"),
   2075                     XShortField("pad", 0),
   2076                     PacketField("data", "", Ether) ]
   2077     overload_fields = {TCP: {"dport": 6653}}
   2078 
   2079 class OFPTFlowRemoved(_ofp_header):
   2080     name = "OFPT_FLOW_REMOVED"
   2081     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2082                     ByteEnumField("type", 11, ofp_type),
   2083                     ShortField("len", None),
   2084                     IntField("xid", 0),
   2085                     LongField("cookie", 0),
   2086                     ShortField("priority", 0),
   2087                     ByteEnumField("reason", 0, { 0: "OFPRR_IDLE_TIMEOUT",
   2088                                                  1: "OFPRR_HARD_TIMEOUT",
   2089                                                  2: "OFPRR_DELETE",
   2090                                                  3: "OFPRR_GROUP_DELETE"}),
   2091                     ByteEnumField("table_id", 0, ofp_table),
   2092                     IntField("duration_sec", 0),
   2093                     IntField("duration_nsec", 0),
   2094                     ShortField("idle_timeout", 0),
   2095                     ShortField("hard_timeout", 0),
   2096                     LongField("packet_count", 0),
   2097                     LongField("byte_count", 0),
   2098                     MatchField("match") ]
   2099     overload_fields = {TCP: {"dport": 6653}}
   2100 
   2101 class OFPTPortStatus(_ofp_header):
   2102     name = "OFPT_PORT_STATUS"
   2103     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2104                     ByteEnumField("type", 12, ofp_type),
   2105                     ShortField("len", None),
   2106                     IntField("xid", 0),
   2107                     ByteEnumField("reason", 0, { 0: "OFPPR_ADD",
   2108                                                  1: "OFPPR_DELETE",
   2109                                                  2: "OFPPR_MODIFY"}),
   2110                     XBitField("pad", 0, 56),
   2111                     PacketField("desc", OFPPort(), OFPPort) ]
   2112     overload_fields = {TCP: {"dport": 6653}}
   2113 
   2114 class OFPTPacketOut(_ofp_header):
   2115     name = "OFPT_PACKET_OUT"
   2116     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2117                     ByteEnumField("type", 13, ofp_type),
   2118                     ShortField("len", None),
   2119                     IntField("xid", 0),
   2120                     IntEnumField("buffer_id", "NO_BUFFER", ofp_buffer),
   2121                     IntEnumField("in_port", "CONTROLLER", ofp_port_no),
   2122                     FieldLenField("actions_len", None, fmt="H", length_of="actions"),
   2123                     XBitField("pad", 0, 48),
   2124                     ActionPacketListField("actions", [], Packet,
   2125                                           length_from=lambda pkt:pkt.actions_len),
   2126                     PacketField("data", "", Ether) ]
   2127     overload_fields = {TCP: {"sport": 6653}}
   2128 
   2129 class OFPTFlowMod(_ofp_header):
   2130     name = "OFPT_FLOW_MOD"
   2131     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2132                     ByteEnumField("type", 14, ofp_type),
   2133                     ShortField("len", None),
   2134                     IntField("xid", 0),
   2135                     LongField("cookie", 0),
   2136                     LongField("cookie_mask", 0),
   2137                     ByteEnumField("table_id", 0, ofp_table),
   2138                     ByteEnumField("cmd", 0, { 0: "OFPFC_ADD",
   2139                                               1: "OFPFC_MODIFY",
   2140                                               2: "OFPFC_MODIFY_STRICT",
   2141                                               3: "OFPFC_DELETE",
   2142                                               4: "OFPFC_DELETE_STRICT" }),
   2143                     ShortField("idle_timeout", 0),
   2144                     ShortField("hard_timeout", 0),
   2145                     ShortField("priority", 0),
   2146                     IntEnumField("buffer_id", "NO_BUFFER", ofp_buffer),
   2147                     IntEnumField("out_port", "ANY", ofp_port_no),
   2148                     IntEnumField("out_group", "ANY", ofp_group),
   2149                     FlagsField("flags", 0, 16, [ "SEND_FLOW_REM",
   2150                                                  "CHECK_OVERLAP",
   2151                                                  "RESET_COUNTS",
   2152                                                  "NO_PKT_COUNTS",
   2153                                                  "NO_BYT_COUNTS" ]),
   2154                     XShortField("pad", 0),
   2155                     MatchField("match"),
   2156                     InstructionPacketListField("instructions", [], Packet,
   2157                                                length_from=lambda pkt:pkt.len-48-(pkt.match.length+(8-pkt.match.length%8)%8)) ]
   2158                                                # include match padding to match.length
   2159     overload_fields = {TCP: {"sport": 6653}}
   2160 
   2161 class OFPTGroupMod(_ofp_header):
   2162     name = "OFPT_GROUP_MOD"
   2163     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2164                     ByteEnumField("type", 15, ofp_type),
   2165                     ShortField("len", None),
   2166                     IntField("xid", 0),
   2167                     ShortEnumField("cmd", 0, { 0: "OFPGC_ADD",
   2168                                                1: "OFPGC_MODIFY",
   2169                                                2: "OFPGC_DELETE" }),
   2170                     ByteEnumField("group_type", 0, { 0: "OFPGT_ALL",
   2171                                                      1: "OFPGT_SELECT",
   2172                                                      2: "OFPGT_INDIRECT",
   2173                                                      3: "OFPGT_FF" }),
   2174                     XByteField("pad", 0),
   2175                     IntEnumField("group_id", 0, ofp_group),
   2176                     BucketPacketListField("buckets", [], Packet,
   2177                                           length_from=lambda pkt:pkt.len-16) ]
   2178     overload_fields = {TCP: {"sport": 6653}}
   2179 
   2180 class OFPTPortMod(_ofp_header):
   2181     name = "OFPT_PORT_MOD"
   2182     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2183                     ByteEnumField("type", 16, ofp_type),
   2184                     ShortField("len", None),
   2185                     IntField("xid", 0),
   2186                     IntEnumField("port_no", 0, ofp_port_no),
   2187                     XIntField("pad1", 0),
   2188                     MACField("hw_addr", "0"),
   2189                     XShortField("pad2", 0),
   2190                     FlagsField("config", 0, 32, ofp_port_config),
   2191                     FlagsField("mask", 0, 32, ofp_port_config),
   2192                     FlagsField("advertise", 0, 32, ofp_port_features),
   2193                     XIntField("pad3", 0) ]
   2194     overload_fields = {TCP: {"sport": 6653}}
   2195 
   2196 class OFPTTableMod(_ofp_header):
   2197     name = "OFPT_TABLE_MOD"
   2198     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2199                     ByteEnumField("type", 17, ofp_type),
   2200                     ShortField("len", None),
   2201                     IntField("xid", 0),
   2202                     ByteEnumField("table_id", 0, ofp_table),
   2203                     X3BytesField("pad", 0),
   2204                     IntEnumField("config", 0, { 3: "OFPTC_DEPRECATED_MASK"}) ]
   2205     overload_fields = {TCP: {"sport": 6653}}
   2206 
   2207 #####################################################
   2208 ################## OFPT_MULTIPART ###################
   2209 #####################################################
   2210 
   2211 ofp_multipart_types = {     0: "OFPMP_DESC",
   2212                             1: "OFPMP_FLOW",
   2213                             2: "OFPMP_AGGREGATE",
   2214                             3: "OFPMP_TABLE",
   2215                             4: "OFPMP_PORT_STATS",
   2216                             5: "OFPMP_QUEUE",
   2217                             6: "OFPMP_GROUP",
   2218                             7: "OFPMP_GROUP_DESC",
   2219                             8: "OFPMP_GROUP_FEATURES",
   2220                             9: "OFPMP_METER",
   2221                            10: "OFPMP_METER_CONFIG",
   2222                            11: "OFPMP_METER_FEATURES",
   2223                            12: "OFPMP_TABLE_FEATURES",
   2224                            13: "OFPMP_PORT_DESC",
   2225                         65535: "OFPST_VENDOR" }
   2226 
   2227 ofpmp_request_flags = [ "REQ_MORE" ]
   2228 
   2229 ofpmp_reply_flags = [ "REPLY_MORE" ]
   2230 
   2231 class OFPMPRequestDesc(_ofp_header):
   2232     name = "OFPMP_REQUEST_DESC"
   2233     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2234                     ByteEnumField("type", 18, ofp_type),
   2235                     ShortField("len", None),
   2236                     IntField("xid", 0),
   2237                     ShortEnumField("mp_type", 0, ofp_multipart_types),
   2238                     FlagsField("flags", 0, 16, ofpmp_request_flags),
   2239                     XIntField("pad", 0) ]
   2240     overload_fields = {TCP: {"sport": 6653}}
   2241 
   2242 class OFPMPReplyDesc(_ofp_header):
   2243     name = "OFPMP_REPLY_DESC"
   2244     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2245                     ByteEnumField("type", 19, ofp_type),
   2246                     ShortField("len", None),
   2247                     IntField("xid", 0),
   2248                     ShortEnumField("mp_type", 0, ofp_multipart_types),
   2249                     FlagsField("flags", 0, 16, ofpmp_reply_flags),
   2250                     XIntField("pad", 0),
   2251                     StrFixedLenField("mfr_desc", "", 256),
   2252                     StrFixedLenField("hw_desc", "", 256),
   2253                     StrFixedLenField("sw_desc", "", 256),
   2254                     StrFixedLenField("serial_num", "", 32),
   2255                     StrFixedLenField("dp_desc", "", 256) ]
   2256     overload_fields = {TCP: {"dport": 6653}}
   2257 
   2258 class OFPMPRequestFlow(_ofp_header):
   2259     name = "OFPMP_REQUEST_FLOW"
   2260     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2261                     ByteEnumField("type", 18, ofp_type),
   2262                     ShortField("len", None),
   2263                     IntField("xid", 0),
   2264                     ShortEnumField("mp_type", 1, ofp_multipart_types),
   2265                     FlagsField("flags", 0, 16, ofpmp_request_flags),
   2266                     XIntField("pad1", 0),
   2267                     ByteEnumField("table_id", "ALL", ofp_table),
   2268                     X3BytesField("pad2", 0),
   2269                     IntEnumField("out_port", "ANY", ofp_port_no),
   2270                     IntEnumField("out_group", "ANY", ofp_group),
   2271                     IntField("pad3", 0),
   2272                     LongField("cookie", 0),
   2273                     LongField("cookie_mask", 0),
   2274                     MatchField("match") ]
   2275     overload_fields = {TCP: {"sport": 6653}}
   2276 
   2277 class OFPFlowStats(Packet):
   2278     def post_build(self, p, pay):
   2279         if self.length is None:
   2280             l = len(p)+len(pay)
   2281             p = struct.pack("!H", l) + p[2:]
   2282         return p + pay
   2283     name = "OFP_FLOW_STATS"
   2284     fields_desc = [ ShortField("length", None),
   2285                     ByteEnumField("table_id", 0, ofp_table),
   2286                     XByteField("pad1", 0),
   2287                     IntField("duration_sec", 0),
   2288                     IntField("duration_nsec", 0),
   2289                     ShortField("priority", 0),
   2290                     ShortField("idle_timeout", 0),
   2291                     ShortField("hard_timeout", 0),
   2292                     FlagsField("flags", 0, 16, [ "SEND_FLOW_REM",
   2293                                                  "CHECK_OVERLAP",
   2294                                                  "RESET_COUNTS",
   2295                                                  "NO_PKT_COUNTS",
   2296                                                  "NO_BYT_COUNTS" ]),
   2297                     IntField("pad2", 0),
   2298                     LongField("cookie", 0),
   2299                     LongField("packet_count", 0),
   2300                     LongField("byte_count", 0),
   2301                     MatchField("match"),
   2302                     InstructionPacketListField("instructions", [], Packet,
   2303                                                length_from=lambda pkt:pkt.length-56-pkt.match.length) ]
   2304 
   2305 class FlowStatsPacketListField(PacketListField):
   2306 
   2307     @staticmethod
   2308     def _get_flow_stats_length(s):
   2309         return struct.unpack("!H", s[:2])[0]
   2310 
   2311     def getfield(self, pkt, s):
   2312         lst = []
   2313         remain = s
   2314 
   2315         while remain:
   2316             l = FlowStatsPacketListField._get_flow_stats_length(remain)
   2317             current = remain[:l]
   2318             remain = remain[l:]
   2319             p = OFPFlowStats(current)
   2320             lst.append(p)
   2321 
   2322         return remain, lst
   2323 
   2324 class OFPMPReplyFlow(_ofp_header):
   2325     name = "OFPMP_REPLY_FLOW"
   2326     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2327                     ByteEnumField("type", 19, ofp_type),
   2328                     ShortField("len", None),
   2329                     IntField("xid", 0),
   2330                     ShortEnumField("mp_type", 1, ofp_multipart_types),
   2331                     FlagsField("flags", 0, 16, ofpmp_reply_flags),
   2332                     XIntField("pad1", 0),
   2333                     FlowStatsPacketListField("flow_stats", [], Packet,
   2334                                              length_from=lambda pkt:pkt.len-16) ]
   2335     overload_fields = {TCP: {"dport": 6653}}
   2336 
   2337 class OFPMPRequestAggregate(_ofp_header):
   2338     name = "OFPMP_REQUEST_AGGREGATE"
   2339     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2340                     ByteEnumField("type", 18, ofp_type),
   2341                     ShortField("len", None),
   2342                     IntField("xid", 0),
   2343                     ShortEnumField("mp_type", 2, ofp_multipart_types),
   2344                     FlagsField("flags", 0, 16, ofpmp_request_flags),
   2345                     XIntField("pad1", 0),
   2346                     ByteEnumField("table_id", "ALL", ofp_table),
   2347                     X3BytesField("pad2", 0),
   2348                     IntEnumField("out_port", "ANY", ofp_port_no),
   2349                     IntEnumField("out_group", "ANY", ofp_group),
   2350                     IntField("pad3", 0),
   2351                     LongField("cookie", 0),
   2352                     LongField("cookie_mask", 0),
   2353                     MatchField("match") ]
   2354     overload_fields = {TCP: {"sport": 6653}}
   2355 
   2356 class OFPMPReplyAggregate(_ofp_header):
   2357     name = "OFPMP_REPLY_AGGREGATE"
   2358     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2359                     ByteEnumField("type", 19, ofp_type),
   2360                     ShortField("len", None),
   2361                     IntField("xid", 0),
   2362                     ShortEnumField("mp_type", 2, ofp_multipart_types),
   2363                     FlagsField("flags", 0, 16, ofpmp_reply_flags),
   2364                     XIntField("pad1", 0),
   2365                     LongField("packet_count", 0),
   2366                     LongField("byte_count", 0),
   2367                     IntField("flow_count", 0),
   2368                     XIntField("pad2", 0) ]
   2369     overload_fields = {TCP: {"dport": 6653}}
   2370 
   2371 class OFPMPRequestTable(_ofp_header):
   2372     name = "OFPMP_REQUEST_TABLE"
   2373     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2374                     ByteEnumField("type", 18, ofp_type),
   2375                     ShortField("len", None),
   2376                     IntField("xid", 0),
   2377                     ShortEnumField("mp_type", 3, ofp_multipart_types),
   2378                     FlagsField("flags", 0, 16, ofpmp_request_flags),
   2379                     XIntField("pad1", 0) ]
   2380     overload_fields = {TCP: {"sport": 6653}}
   2381 
   2382 class OFPTableStats(Packet):
   2383     def extract_padding(self, s):
   2384         return "", s
   2385     name = "OFP_TABLE_STATS"
   2386     fields_desc = [ ByteEnumField("table_id", 0, ofp_table),
   2387                     X3BytesField("pad1", 0),
   2388                     IntField("active_count", 0),
   2389                     LongField("lookup_count", 0),
   2390                     LongField("matched_count", 0) ]
   2391 
   2392 class OFPMPReplyTable(_ofp_header):
   2393     name = "OFPMP_REPLY_TABLE"
   2394     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2395                     ByteEnumField("type", 19, ofp_type),
   2396                     ShortField("len", None),
   2397                     IntField("xid", 0),
   2398                     ShortEnumField("mp_type", 3, ofp_multipart_types),
   2399                     FlagsField("flags", 0, 16, ofpmp_reply_flags),
   2400                     XIntField("pad1", 0),
   2401                     PacketListField("table_stats", None, OFPTableStats,
   2402                                     length_from=lambda pkt:pkt.len-16) ]
   2403     overload_fields = {TCP: {"dport": 6653}}
   2404 
   2405 class OFPMPRequestPortStats(_ofp_header):
   2406     name = "OFPMP_REQUEST_PORT_STATS"
   2407     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2408                     ByteEnumField("type", 18, ofp_type),
   2409                     ShortField("len", None),
   2410                     IntField("xid", 0),
   2411                     ShortEnumField("mp_type", 4, ofp_multipart_types),
   2412                     FlagsField("flags", 0, 16, ofpmp_request_flags),
   2413                     XIntField("pad1", 0),
   2414                     IntEnumField("port_no", "ANY", ofp_port_no),
   2415                     XIntField("pad", 0) ]
   2416     overload_fields = {TCP: {"sport": 6653}}
   2417 
   2418 class OFPPortStats(Packet):
   2419     def extract_padding(self, s):
   2420         return "", s
   2421     name = "OFP_PORT_STATS"
   2422     fields_desc = [ IntEnumField("port_no", 0, ofp_port_no),
   2423                     XIntField("pad", 0),
   2424                     LongField("rx_packets", 0),
   2425                     LongField("tx_packets", 0),
   2426                     LongField("rx_bytes", 0),
   2427                     LongField("tx_bytes", 0),
   2428                     LongField("rx_dropped", 0),
   2429                     LongField("tx_dropped", 0),
   2430                     LongField("rx_errors", 0),
   2431                     LongField("tx_errors", 0),
   2432                     LongField("rx_frame_err", 0),
   2433                     LongField("rx_over_err", 0),
   2434                     LongField("rx_crc_err", 0),
   2435                     LongField("collisions", 0),
   2436                     IntField("duration_sec", 0),
   2437                     IntField("duration_nsec", 0) ]
   2438 
   2439 class OFPMPReplyPortStats(_ofp_header):
   2440     name = "OFPMP_REPLY_PORT_STATS"
   2441     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2442                     ByteEnumField("type", 19, ofp_type),
   2443                     ShortField("len", None),
   2444                     IntField("xid", 0),
   2445                     ShortEnumField("mp_type", 4, ofp_multipart_types),
   2446                     FlagsField("flags", 0, 16, ofpmp_reply_flags),
   2447                     XIntField("pad1", 0),
   2448                     PacketListField("port_stats", None, OFPPortStats,
   2449                                     length_from=lambda pkt:pkt.len-16) ]
   2450     overload_fields = {TCP: {"dport": 6653}}
   2451 
   2452 class OFPMPRequestQueue(_ofp_header):
   2453     name = "OFPMP_REQUEST_QUEUE"
   2454     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2455                     ByteEnumField("type", 18, ofp_type),
   2456                     ShortField("len", None),
   2457                     IntField("xid", 0),
   2458                     ShortEnumField("mp_type", 5, ofp_multipart_types),
   2459                     FlagsField("flags", 0, 16, ofpmp_request_flags),
   2460                     XIntField("pad1", 0),
   2461                     IntEnumField("port_no", "ANY", ofp_port_no),
   2462                     IntEnumField("queue_id", "ALL", ofp_queue) ]
   2463     overload_fields = {TCP: {"sport": 6653}}
   2464 
   2465 class OFPQueueStats(Packet):
   2466     def extract_padding(self, s):
   2467         return "", s
   2468     name = "OFP_QUEUE_STATS"
   2469     fields_desc = [ IntEnumField("port_no", 0, ofp_port_no),
   2470                     IntEnumField("queue_id", 0, ofp_queue),
   2471                     LongField("tx_bytes", 0),
   2472                     LongField("tx_packets", 0),
   2473                     LongField("tx_errors", 0),
   2474                     IntField("duration_sec", 0),
   2475                     IntField("duration_nsec", 0) ]
   2476 
   2477 class OFPMPReplyQueue(_ofp_header):
   2478     name = "OFPMP_REPLY_QUEUE"
   2479     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2480                     ByteEnumField("type", 19, ofp_type),
   2481                     ShortField("len", None),
   2482                     IntField("xid", 0),
   2483                     ShortEnumField("mp_type", 5, ofp_multipart_types),
   2484                     FlagsField("flags", 0, 16, ofpmp_reply_flags),
   2485                     XIntField("pad1", 0),
   2486                     PacketListField("queue_stats", None, OFPQueueStats,
   2487                             length_from=lambda pkt:pkt.len-16) ]
   2488     overload_fields = {TCP: {"dport": 6653}}
   2489 
   2490 class OFPMPRequestGroup(_ofp_header):
   2491     name = "OFPMP_REQUEST_GROUP"
   2492     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2493                     ByteEnumField("type", 18, ofp_type),
   2494                     ShortField("len", None),
   2495                     IntField("xid", 0),
   2496                     ShortEnumField("mp_type", 6, ofp_multipart_types),
   2497                     FlagsField("flags", 0, 16, ofpmp_request_flags),
   2498                     XIntField("pad1", 0),
   2499                     IntEnumField("group_id", "ANY", ofp_group),
   2500                     XIntField("pad2", 0) ]
   2501     overload_fields = {TCP: {"sport": 6653}}
   2502 
   2503 class OFPBucketStats(Packet):
   2504     def extract_padding(self, s):
   2505         return "", s
   2506     name = "OFP_BUCKET_STATS"
   2507     fields_desc = [ LongField("packet_count", 0),
   2508                     LongField("byte_count", 0) ]
   2509 
   2510 class OFPGroupStats(Packet):
   2511     def post_build(self, p, pay):
   2512         if self.length is None:
   2513             l = len(p)+len(pay)
   2514             p = struct.pack("!H", l) + p[2:]
   2515         return p + pay
   2516     name = "OFP_GROUP_STATS"
   2517     fields_desc = [ ShortField("length", None),
   2518                     XShortField("pad1", 0),
   2519                     IntEnumField("group_id", 0, ofp_group),
   2520                     IntField("ref_count", 0),
   2521                     IntField("pad2", 0),
   2522                     LongField("packet_count", 0),
   2523                     LongField("byte_count", 0),
   2524                     IntField("duration_sec", 0),
   2525                     IntField("duration_nsec", 0),
   2526                     PacketListField("bucket_stats", None, OFPBucketStats,
   2527                                     length_from=lambda pkt:pkt.length-40) ]
   2528 
   2529 class GroupStatsPacketListField(PacketListField):
   2530 
   2531     @staticmethod
   2532     def _get_group_stats_length(s):
   2533         return struct.unpack("!H", s[:2])[0]
   2534 
   2535     def getfield(self, pkt, s):
   2536         lst = []
   2537         remain = s
   2538 
   2539         while remain:
   2540             l = GroupStatsPacketListField._get_group_stats_length(remain)
   2541             current = remain[:l]
   2542             remain = remain[l:]
   2543             p = OFPGroupStats(current)
   2544             lst.append(p)
   2545 
   2546         return remain, lst
   2547 
   2548 class OFPMPReplyGroup(_ofp_header):
   2549     name = "OFPMP_REPLY_GROUP"
   2550     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2551                     ByteEnumField("type", 19, ofp_type),
   2552                     ShortField("len", None),
   2553                     IntField("xid", 0),
   2554                     ShortEnumField("mp_type", 6, ofp_multipart_types),
   2555                     FlagsField("flags", 0, 16, ofpmp_reply_flags),
   2556                     XIntField("pad1", 0),
   2557                     GroupStatsPacketListField("group_stats", [], Packet,
   2558                                               length_from=lambda pkt:pkt.len-16) ]
   2559     overload_fields = {TCP: {"dport": 6653}}
   2560 
   2561 class OFPMPRequestGroupDesc(_ofp_header):
   2562     name = "OFPMP_REQUEST_GROUP_DESC"
   2563     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2564                     ByteEnumField("type", 18, ofp_type),
   2565                     ShortField("len", None),
   2566                     IntField("xid", 0),
   2567                     ShortEnumField("mp_type", 7, ofp_multipart_types),
   2568                     FlagsField("flags", 0, 16, ofpmp_request_flags),
   2569                     XIntField("pad1", 0) ]
   2570     overload_fields = {TCP: {"sport": 6653}}
   2571 
   2572 class OFPGroupDesc(Packet):
   2573     def post_build(self, p, pay):
   2574         if self.length is None:
   2575             l = len(p)+len(pay)
   2576             p = struct.pack("!H", l) + p[2:]
   2577         return p + pay
   2578     name = "OFP_GROUP_DESC"
   2579     fields_desc = [ ShortField("length", None),
   2580                     ByteEnumField("type", 0, { 0: "OFPGT_ALL",
   2581                                                1: "OFPGT_SELECT",
   2582                                                2: "OFPGT_INDIRECT",
   2583                                                3: "OFPGT_FF" }),
   2584                     XByteField("pad", 0),
   2585                     IntEnumField("group_id", 0, ofp_group),
   2586                     BucketPacketListField("buckets", None, Packet,
   2587                                           length_from=lambda pkt:pkt.length-8) ]
   2588 
   2589 class GroupDescPacketListField(PacketListField):
   2590 
   2591     @staticmethod
   2592     def _get_group_desc_length(s):
   2593         return struct.unpack("!H", s[:2])[0]
   2594 
   2595     def getfield(self, pkt, s):
   2596         lst = []
   2597         remain = s
   2598 
   2599         while remain:
   2600             l = GroupDescPacketListField._get_group_desc_length(remain)
   2601             current = remain[:l]
   2602             remain = remain[l:]
   2603             p = OFPGroupDesc(current)
   2604             lst.append(p)
   2605 
   2606         return remain, lst
   2607 
   2608 
   2609 class OFPMPReplyGroupDesc(_ofp_header):
   2610     name = "OFPMP_REPLY_GROUP_DESC"
   2611     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2612                     ByteEnumField("type", 19, ofp_type),
   2613                     ShortField("len", None),
   2614                     IntField("xid", 0),
   2615                     ShortEnumField("mp_type", 7, ofp_multipart_types),
   2616                     FlagsField("flags", 0, 16, ofpmp_reply_flags),
   2617                     XIntField("pad1", 0),
   2618                     GroupDescPacketListField("group_descs", [], Packet,
   2619                                              length_from=lambda pkt:pkt.len-16) ]
   2620     overload_fields = {TCP: {"dport": 6653}}
   2621                     
   2622 class OFPMPRequestGroupFeatures(_ofp_header):
   2623     name = "OFPMP_REQUEST_GROUP_FEATURES"
   2624     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2625                     ByteEnumField("type", 18, ofp_type),
   2626                     ShortField("len", None),
   2627                     IntField("xid", 0),
   2628                     ShortEnumField("mp_type", 8, ofp_multipart_types),
   2629                     FlagsField("flags", 0, 16, ofpmp_request_flags),
   2630                     XIntField("pad1", 0) ]
   2631     overload_fields = {TCP: {"sport": 6653}}
   2632 
   2633 ofp_action_types_flags = list(ofp_action_types.values())[:-1]  # no ofpat_experimenter flag
   2634 class OFPMPReplyGroupFeatures(_ofp_header):
   2635     name = "OFPMP_REPLY_GROUP_FEATURES"
   2636     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2637                     ByteEnumField("type", 19, ofp_type),
   2638                     ShortField("len", None),
   2639                     IntField("xid", 0),
   2640                     ShortEnumField("mp_type", 8, ofp_multipart_types),
   2641                     FlagsField("flags", 0, 16, ofpmp_reply_flags),
   2642                     XIntField("pad1", 0),
   2643                     FlagsField("types", 0, 32, [ "ALL",
   2644                                                  "SELECT",
   2645                                                  "INDIRECT",
   2646                                                  "FF" ]),
   2647                     FlagsField("capabilities", 0, 32, [ "SELECT_WEIGHT",
   2648                                                         "SELECT_LIVENESS",
   2649                                                         "CHAINING",
   2650                                                         "CHAINING_CHECKS" ]),
   2651                     IntField("max_group_all", 0),
   2652                     IntField("max_group_select", 0),
   2653                     IntField("max_group_indirect", 0),
   2654                     IntField("max_group_ff", 0),
   2655                     # no ofpat_experimenter flag
   2656                     FlagsField("actions_all", 0, 32, ofp_action_types_flags),
   2657                     FlagsField("actions_select", 0, 32, ofp_action_types_flags),
   2658                     FlagsField("actions_indirect", 0, 32, ofp_action_types_flags),
   2659                     FlagsField("actions_ff", 0, 32, ofp_action_types_flags) ]
   2660     overload_fields = {TCP: {"dport": 6653}}
   2661 
   2662 class OFPMPRequestMeter(_ofp_header):
   2663     name = "OFPMP_REQUEST_METER"
   2664     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2665                     ByteEnumField("type", 18, ofp_type),
   2666                     ShortField("len", None),
   2667                     IntField("xid", 0),
   2668                     ShortEnumField("mp_type", 9, ofp_multipart_types),
   2669                     FlagsField("flags", 0, 16, ofpmp_request_flags),
   2670                     XIntField("pad1", 0),
   2671                     IntEnumField("meter_id", "ALL", ofp_meter),
   2672                     XIntField("pad2", 0) ]
   2673     overload_fields = {TCP: {"sport": 6653}}
   2674 
   2675 class OFPMeterBandStats(Packet):
   2676     def extract_padding(self, s):
   2677         return "", s
   2678     name = "OFP_METER_BAND_STATS"
   2679     fields_desc = [ LongField("packet_band_count", 0),
   2680                     LongField("byte_band_count", 0) ]
   2681 
   2682 class OFPMeterStats(Packet):
   2683     def post_build(self, p, pay):
   2684         if self.len is None:
   2685             l = len(p)+len(pay)
   2686             p = p[:4] + struct.pack("!H", l) + p[6:]
   2687         return p + pay
   2688     name = "OFP_GROUP_STATS"
   2689     fields_desc = [ IntEnumField("meter_id", 1, ofp_meter),
   2690                     ShortField("len", None),
   2691                     XBitField("pad", 0, 48),
   2692                     IntField("flow_count", 0),
   2693                     LongField("packet_in_count", 0),
   2694                     LongField("byte_in_count", 0),
   2695                     IntField("duration_sec", 0),
   2696                     IntField("duration_nsec", 0),
   2697                     PacketListField("band_stats", None, OFPMeterBandStats,
   2698                                     length_from=lambda pkt:pkt.len-40) ]
   2699 
   2700 class MeterStatsPacketListField(PacketListField):
   2701 
   2702     @staticmethod
   2703     def _get_meter_stats_length(s):
   2704         return struct.unpack("!H", s[4:6])[0]
   2705 
   2706     def getfield(self, pkt, s):
   2707         lst = []
   2708         l = 0
   2709         ret = b""
   2710         remain = s
   2711 
   2712         while remain:
   2713             l = MeterStatsPacketListField._get_meter_stats_length(remain)
   2714             current = remain[:l]
   2715             remain = remain[l:]
   2716             p = OFPMeterStats(current)
   2717             lst.append(p)
   2718 
   2719         return remain + ret, lst
   2720 
   2721 class OFPMPReplyMeter(_ofp_header):
   2722     name = "OFPMP_REPLY_METER"
   2723     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2724                     ByteEnumField("type", 19, ofp_type),
   2725                     ShortField("len", None),
   2726                     IntField("xid", 0),
   2727                     ShortEnumField("mp_type", 9, ofp_multipart_types),
   2728                     FlagsField("flags", 0, 16, ofpmp_reply_flags),
   2729                     XIntField("pad1", 0),
   2730                     MeterStatsPacketListField("meter_stats", [], Packet,
   2731                                               length_from=lambda pkt:pkt.len-16) ]
   2732     overload_fields = {TCP: {"dport": 6653}}
   2733 
   2734 class OFPMPRequestMeterConfig(_ofp_header):
   2735     name = "OFPMP_REQUEST_METER_CONFIG"
   2736     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2737                     ByteEnumField("type", 18, ofp_type),
   2738                     ShortField("len", None),
   2739                     IntField("xid", 0),
   2740                     ShortEnumField("mp_type", 10, ofp_multipart_types),
   2741                     FlagsField("flags", 0, 16, ofpmp_request_flags),
   2742                     XIntField("pad1", 0),
   2743                     IntEnumField("meter_id", "ALL", ofp_meter),
   2744                     XIntField("pad2", 0) ]
   2745     overload_fields = {TCP: {"sport": 6653}}
   2746 
   2747 class OFPMeterConfig(Packet):
   2748     def post_build(self, p, pay):
   2749         if self.length is None:
   2750             l = len(p)+len(pay)
   2751             p = struct.pack("!H", l) + p[2:]
   2752         return p + pay
   2753     name = "OFP_METER_CONFIG"
   2754     fields_desc = [ ShortField("length", None),
   2755                     FlagsField("flags", 0, 16, [ "KBPS",
   2756                                                  "PKTPS",
   2757                                                  "BURST",
   2758                                                  "STATS" ]),
   2759                     IntEnumField("meter_id", 1, ofp_meter),
   2760                     MeterBandPacketListField("bands", [], Packet,
   2761                                              length_from=lambda pkt:pkt.len-8) ]
   2762 
   2763 class MeterConfigPacketListField(PacketListField):
   2764 
   2765     @staticmethod
   2766     def _get_meter_config_length(s):
   2767         return struct.unpack("!H", s[:2])[0]
   2768 
   2769     def getfield(self, pkt, s):
   2770         lst = []
   2771         remain = s
   2772 
   2773         while remain:
   2774             l = MeterConfigPacketListField._get_meter_config_length(remain)
   2775             current = remain[:l]
   2776             remain = remain[l:]
   2777             p = OFPMeterConfig(current)
   2778             lst.append(p)
   2779 
   2780         return remain, lst
   2781 
   2782 class OFPMPReplyMeterConfig(_ofp_header):
   2783     name = "OFPMP_REPLY_METER_CONFIG"
   2784     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2785                     ByteEnumField("type", 19, ofp_type),
   2786                     ShortField("len", None),
   2787                     IntField("xid", 0),
   2788                     ShortEnumField("mp_type", 10, ofp_multipart_types),
   2789                     FlagsField("flags", 0, 16, ofpmp_reply_flags),
   2790                     XIntField("pad1", 0),
   2791                     MeterConfigPacketListField("meter_configs", [], Packet,
   2792                                                length_from=lambda pkt:pkt.len-16) ]
   2793     overload_fields = {TCP: {"dport": 6653}}
   2794 
   2795 class OFPMPRequestMeterFeatures(_ofp_header):
   2796     name = "OFPMP_REQUEST_METER_FEATURES"
   2797     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2798                     ByteEnumField("type", 18, ofp_type),
   2799                     ShortField("len", None),
   2800                     IntField("xid", 0),
   2801                     ShortEnumField("mp_type", 11, ofp_multipart_types),
   2802                     FlagsField("flags", 0, 16, ofpmp_request_flags),
   2803                     XIntField("pad1", 0) ]
   2804     overload_fields = {TCP: {"sport": 6653}}
   2805 
   2806 class OFPMPReplyMeterFeatures(_ofp_header):
   2807     name = "OFPMP_REPLY_METER_FEATURES"
   2808     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   2809                     ByteEnumField("type", 19, ofp_type),
   2810                     ShortField("len", None),
   2811                     IntField("xid", 0),
   2812                     ShortEnumField("mp_type", 11, ofp_multipart_types),
   2813                     FlagsField("flags", 0, 16, ofpmp_reply_flags),
   2814                     XIntField("pad1", 0),
   2815                     IntField("max_meter", 0),
   2816                     FlagsField("band_types", 0, 32, [ "DROP",
   2817                                                       "DSCP_REMARK",
   2818                                                       "EXPERIMENTER" ]),
   2819                     FlagsField("capabilities", 0, 32, [ "KPBS",
   2820                                                         "PKTPS",
   2821                                                         "BURST",
   2822                                                         "STATS" ]),
   2823                     ByteField("max_bands", 0),
   2824                     ByteField("max_color", 0),
   2825                     XShortField("pad2", 0) ]
   2826     overload_fields = {TCP: {"dport": 6653}}
   2827 
   2828 ####### table features for multipart messages #######
   2829 
   2830 class _ofp_table_features_prop_header(Packet):
   2831     name = "Dummy OpenFlow Table Features Properties Header"
   2832 
   2833     def post_build(self, p, pay):
   2834         l = self.length
   2835         if l is None:
   2836             l = len(p)+len(pay)
   2837             p = p[:2] + struct.pack("!H", l) + p[4:]
   2838         # every message will be padded correctly
   2839         zero_bytes = (8 - l%8) % 8
   2840         p += b"\x00" * zero_bytes
   2841         return p + pay
   2842 
   2843     def extract_padding(self, s):
   2844         l = self.length
   2845         zero_bytes = (8 - l%8) % 8
   2846         return "", s
   2847 
   2848 
   2849 ofp_table_features_prop_types = {     0: "OFPTFPT_INSTRUCTIONS",
   2850                                       1: "OFPTFPT_INSTRUCTIONS_MISS",
   2851                                       2: "OFPTFPT_NEXT_TABLES",
   2852                                       3: "OFPTFPT_NEXT_TABLES_MISS",
   2853                                       4: "OFPTFPT_WRITE_ACTIONS",
   2854                                       5: "OFPTFPT_WRITE_ACTIONS_MISS",
   2855                                       6: "OFPTFPT_APPLY_ACTIONS",
   2856                                       7: "OFPTFPT_APPLY_ACTIONS_MISS",
   2857                                       8: "OFPTFPT_MATCH",
   2858                                      10: "OFPTFPT_WILDCARDS",
   2859                                      12: "OFPTFPT_WRITE_SETFIELD",
   2860                                      13: "OFPTFPT_WRITE_SETFIELD_MISS",
   2861                                      14: "OFPTFPT_APPLY_SETFIELD",
   2862                                      15: "OFPTFPT_APPLY_SETFIELD_MISS",
   2863                                   65534: "OFPTFPT_EXPERIMENTER",
   2864                                   65535: "OFPTFPT_EXPERIMENTER_MISS" }
   2865 
   2866 class OFPTFPTInstructions(_ofp_table_features_prop_header):
   2867     name = "OFPTFPT_INSTRUCTIONS"
   2868     fields_desc = [ ShortField("type", 0),
   2869                     ShortField("length", None),
   2870                     InstructionIDPacketListField("instruction_ids", [], Packet,
   2871                                                  length_from=lambda pkt:pkt.length-4) ]
   2872 
   2873 class OFPTFPTInstructionsMiss(_ofp_table_features_prop_header):
   2874     name = "OFPTFPT_INSTRUCTIONS_MISS"
   2875     fields_desc = [ ShortField("type", 1),
   2876                     ShortField("length", None),
   2877                     InstructionIDPacketListField("instruction_ids", [], Packet,
   2878                                                  length_from=lambda pkt:pkt.length-4) ]
   2879 
   2880 class OFPTableID(Packet):
   2881     def extract_padding(self, s):
   2882         return "", s
   2883     name = "OFP_TABLE_ID"
   2884     fields_desc = [ ByteEnumField("table_id", 0, ofp_table) ]
   2885 
   2886 class OFPTFPTNextTables(_ofp_table_features_prop_header):
   2887     name = "OFPTFPT_NEXT_TABLES"
   2888     fields_desc = [ ShortField("type", 2),
   2889                     ShortField("length", None),
   2890                     PacketListField("next_table_ids", None, OFPTableID,
   2891                                     length_from=lambda pkt:pkt.length-4) ]
   2892 
   2893 class OFPTFPTNextTablesMiss(_ofp_table_features_prop_header):
   2894     name = "OFPTFPT_NEXT_TABLES_MISS"
   2895     fields_desc = [ ShortField("type", 3),
   2896                     ShortField("length", None),
   2897                     PacketListField("next_table_ids", None, OFPTableID,
   2898                                     length_from=lambda pkt:pkt.length-4) ]
   2899 
   2900 class OFPTFPTWriteActions(_ofp_table_features_prop_header):
   2901     name = "OFPTFPT_WRITE_ACTIONS"
   2902     fields_desc = [ ShortField("type", 4),
   2903                     ShortField("length", None),
   2904                     ActionIDPacketListField("action_ids", [], Packet,
   2905                                             length_from=lambda pkt:pkt.length-4) ]
   2906 
   2907 class OFPTFPTWriteActionsMiss(_ofp_table_features_prop_header):
   2908     name = "OFPTFPT_WRITE_ACTIONS_MISS"
   2909     fields_desc = [ ShortField("type", 5),
   2910                     ShortField("length", None),
   2911                     ActionIDPacketListField("action_ids", [], Packet,
   2912                                             length_from=lambda pkt:pkt.length-4) ]
   2913 
   2914 class OFPTFPTApplyActions(_ofp_table_features_prop_header):
   2915     name = "OFPTFPT_APPLY_ACTIONS"
   2916     fields_desc = [ ShortField("type", 6),
   2917                     ShortField("length", None),
   2918                     ActionIDPacketListField("action_ids", [], Packet,
   2919                                             length_from=lambda pkt:pkt.length-4) ]
   2920 
   2921 class OFPTFPTApplyActionsMiss(_ofp_table_features_prop_header):
   2922     name = "OFPTFPT_APPLY_ACTIONS_MISS"
   2923     fields_desc = [ ShortField("type", 7),
   2924                     ShortField("length", None),
   2925                     ActionIDPacketListField("action_ids", [], Packet,
   2926                                             length_from=lambda pkt:pkt.length-4) ]
   2927 
   2928 class OFPTFPTMatch(_ofp_table_features_prop_header):
   2929     name = "OFPTFPT_MATCH"
   2930     fields_desc = [ ShortField("type", 8),
   2931                     ShortField("length", None),
   2932                     OXMIDPacketListField("oxm_ids", [], Packet,
   2933                                          length_from=lambda pkt:pkt.length-4) ]
   2934 
   2935 class OFPTFPTWildcards(_ofp_table_features_prop_header):
   2936     name = "OFPTFPT_WILDCARDS"
   2937     fields_desc = [ ShortField("type", 10),
   2938                     ShortField("length", None),
   2939                     OXMIDPacketListField("oxm_ids", [], Packet,
   2940                                          length_from=lambda pkt:pkt.length-4) ]
   2941 
   2942 class OFPTFPTWriteSetField(_ofp_table_features_prop_header):
   2943     name = "OFPTFPT_WRITE_SETFIELD"
   2944     fields_desc = [ ShortField("type", 12),
   2945                     ShortField("length", None),
   2946                     OXMIDPacketListField("oxm_ids", [], Packet,
   2947                                          length_from=lambda pkt:pkt.length-4) ]
   2948 
   2949 class OFPTFPTWriteSetFieldMiss(_ofp_table_features_prop_header):
   2950     name = "OFPTFPT_WRITE_SETFIELD_MISS"
   2951     fields_desc = [ ShortField("type", 13),
   2952                     ShortField("length", None),
   2953                     OXMIDPacketListField("oxm_ids", [], Packet,
   2954                                          length_from=lambda pkt:pkt.length-4) ]
   2955 
   2956 class OFPTFPTApplySetField(_ofp_table_features_prop_header):
   2957     name = "OFPTFPT_APPLY_SETFIELD"
   2958     fields_desc = [ ShortField("type", 14),
   2959                     ShortField("length", None),
   2960                     OXMIDPacketListField("oxm_ids", [], Packet,
   2961                                          length_from=lambda pkt:pkt.length-4) ]
   2962 
   2963 class OFPTFPTApplySetFieldMiss(_ofp_table_features_prop_header):
   2964     name = "OFPTFPT_APPLY_SETFIELD_MISS"
   2965     fields_desc = [ ShortField("type", 15),
   2966                     ShortField("length", None),
   2967                     OXMIDPacketListField("oxm_ids", [], Packet,
   2968                                          length_from=lambda pkt:pkt.length-4) ]
   2969 
   2970 class OFPTFPTExperimenter(_ofp_table_features_prop_header):
   2971     name = "OFPTFPT_EXPERIMENTER"
   2972     fields_desc = [ ShortField("type", 65534),
   2973                     ShortField("length", None),
   2974                     IntField("experimenter", 0),
   2975                     IntField("exp_type", 0),
   2976                     PacketField("experimenter_data", None, Raw) ]
   2977 
   2978 class OFPTFPTExperimenterMiss(_ofp_table_features_prop_header):
   2979     name = "OFPTFPT_EXPERIMENTER_MISS"
   2980     fields_desc = [ ShortField("type", 65535),
   2981                     ShortField("length", None),
   2982                     IntField("experimenter", 0),
   2983                     IntField("exp_type", 0),
   2984                     PacketField("experimenter_data", None, Raw) ]
   2985 
   2986 ofp_table_features_prop_cls = {     0: OFPTFPTInstructions,
   2987                                     1: OFPTFPTInstructionsMiss,
   2988                                     2: OFPTFPTNextTables,
   2989                                     3: OFPTFPTNextTablesMiss,
   2990                                     4: OFPTFPTWriteActions,
   2991                                     5: OFPTFPTWriteActionsMiss,
   2992                                     6: OFPTFPTApplyActions,
   2993                                     7: OFPTFPTApplyActionsMiss,
   2994                                     8: OFPTFPTMatch,
   2995                                    10: OFPTFPTWildcards,
   2996                                    12: OFPTFPTWriteSetField,
   2997                                    13: OFPTFPTWriteSetFieldMiss,
   2998                                    14: OFPTFPTApplySetField,
   2999                                    15: OFPTFPTApplySetFieldMiss,
   3000                                 65534: OFPTFPTExperimenter,
   3001                                 65535: OFPTFPTExperimenterMiss }
   3002 
   3003 class TableFeaturesPropPacketListField(PacketListField):
   3004 
   3005     @staticmethod
   3006     def _get_table_features_prop_length(s):
   3007         return struct.unpack("!H", s[2:4])[0]
   3008 
   3009     def m2i(self, pkt, s):
   3010         t = struct.unpack("!H", s[:2])[0]
   3011         return ofp_table_features_prop_cls.get(t, Raw)(s)
   3012 
   3013     def getfield(self, pkt, s):
   3014         lst = []
   3015         remain = s
   3016     
   3017         while remain and len(remain) >= 4:
   3018             l = TableFeaturesPropPacketListField._get_table_features_prop_length(remain)
   3019             # add padding !
   3020             lpad = l + (8 - l%8)%8
   3021             if l < 4 or len(remain) < lpad:
   3022             # no zero length nor incoherent length
   3023                 break
   3024             current = remain[:lpad]
   3025             remain = remain[lpad:]
   3026             p = self.m2i(pkt, current)
   3027             lst.append(p)
   3028 
   3029         return remain, lst
   3030 
   3031 class OFPTableFeatures(Packet):
   3032     def post_build(self, p, pay):
   3033         if self.length is None:
   3034             l = len(p)+len(pay)
   3035             p = struct.pack("!H", l) + p[2:]
   3036         return p + pay
   3037     name = "OFP_TABLE_FEATURES"
   3038     fields_desc = [ ShortField("length", None),
   3039                     ByteEnumField("table_id", 0, ofp_table),
   3040                     XBitField("pad", 0, 40),
   3041                     StrFixedLenField("table_name", "", 32),
   3042                     LongField("metadata_match", 0),
   3043                     LongField("metadata_write", 0),
   3044                     IntEnumField("config", 0, { 0: "OFPTC_NO_MASK",
   3045                                                 3: "OFPTC_DEPRECATED_MASK" }),
   3046                     IntField("max_entries", 0),
   3047                     TableFeaturesPropPacketListField("properties", [], Packet,
   3048                                                      length_from=lambda pkt:pkt.length-64) ]
   3049 
   3050 class TableFeaturesPacketListField(PacketListField):
   3051 
   3052     @staticmethod
   3053     def _get_table_features_length(s):
   3054         return struct.unpack("!H", s[:2])[0]
   3055 
   3056     def getfield(self, pkt, s):
   3057         lst = []
   3058         remain = s
   3059 
   3060         while remain:
   3061             l = TableFeaturesPacketListField._get_table_features_length(remain)
   3062             current = remain[:l]
   3063             remain = remain[l:]
   3064             p = OFPTableFeatures(current)
   3065             lst.append(p)
   3066 
   3067         return remain, lst
   3068 
   3069 class OFPMPRequestTableFeatures(_ofp_header):
   3070     name = "OFPMP_REQUEST_TABLE_FEATURES"
   3071     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   3072                     ByteEnumField("type", 18, ofp_type),
   3073                     ShortField("len", None),
   3074                     IntField("xid", 0),
   3075                     ShortEnumField("mp_type", 12, ofp_multipart_types),
   3076                     FlagsField("flags", 0, 16, ofpmp_request_flags),
   3077                     XIntField("pad1", 0),
   3078                     TableFeaturesPacketListField("table_features", [], Packet,
   3079                                                  length_from=lambda pkt:pkt.len-16) ] 
   3080     overload_fields = {TCP: {"sport": 6653}}
   3081 
   3082 class OFPMPReplyTableFeatures(_ofp_header):
   3083     name = "OFPMP_REPLY_TABLE_FEATURES"
   3084     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   3085                     ByteEnumField("type", 19, ofp_type),
   3086                     ShortField("len", None),
   3087                     IntField("xid", 0),
   3088                     ShortEnumField("mp_type", 12, ofp_multipart_types),
   3089                     FlagsField("flags", 0, 16, ofpmp_reply_flags),
   3090                     XIntField("pad1", 0),
   3091                     TableFeaturesPacketListField("table_features", [], Packet,
   3092                                                  length_from=lambda pkt:pkt.len-16) ]
   3093     overload_fields = {TCP: {"dport": 6653}}
   3094 
   3095 ############### end of table features ###############
   3096 
   3097 class OFPMPRequestPortDesc(_ofp_header):
   3098     name = "OFPMP_REQUEST_PORT_DESC"
   3099     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   3100                     ByteEnumField("type", 18, ofp_type),
   3101                     ShortField("len", None),
   3102                     IntField("xid", 0),
   3103                     ShortEnumField("mp_type", 13, ofp_multipart_types),
   3104                     FlagsField("flags", 0, 16, ofpmp_request_flags),
   3105                     XIntField("pad1", 0),
   3106                     IntEnumField("port_no", 0, ofp_port_no),
   3107                     XIntField("pad", 0) ]
   3108     overload_fields = {TCP: {"sport": 6653}}
   3109 
   3110 class OFPMPReplyPortDesc(_ofp_header):
   3111     name = "OFPMP_REPLY_PORT_DESC"
   3112     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   3113                     ByteEnumField("type", 19, ofp_type),
   3114                     ShortField("len", None),
   3115                     IntField("xid", 0),
   3116                     ShortEnumField("mp_type", 13, ofp_multipart_types),
   3117                     FlagsField("flags", 0, 16, ofpmp_reply_flags),
   3118                     XIntField("pad1", 0),
   3119                     PacketListField("ports", None, OFPPort,
   3120                                     length_from=lambda pkt:pkt.len-16) ]
   3121     overload_fields = {TCP: {"dport": 6653}}
   3122 
   3123 class OFPMPRequestExperimenter(_ofp_header):
   3124     name = "OFPST_REQUEST_EXPERIMENTER"
   3125     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   3126                     ByteEnumField("type", 18, ofp_type),
   3127                     ShortField("len", None),
   3128                     IntField("xid", 0),
   3129                     ShortEnumField("mp_type", 65535, ofp_multipart_types),
   3130                     FlagsField("flags", 0, 16, ofpmp_request_flags),
   3131                     XIntField("pad1", 0),
   3132                     IntField("experimenter", 0),
   3133                     IntField("exp_type", 0) ]
   3134     overload_fields = {TCP: {"sport": 6653}}
   3135 
   3136 class OFPMPReplyExperimenter(_ofp_header):
   3137     name = "OFPST_REPLY_EXPERIMENTER"
   3138     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   3139                     ByteEnumField("type", 19, ofp_type),
   3140                     ShortField("len", None),
   3141                     IntField("xid", 0),
   3142                     ShortEnumField("mp_type", 65535, ofp_multipart_types),
   3143                     FlagsField("flags", 0, 16, ofpmp_reply_flags),
   3144                     XIntField("pad1", 0),
   3145                     IntField("experimenter", 0),
   3146                     IntField("exp_type", 0) ]
   3147     overload_fields = {TCP: {"dport": 6653}}
   3148 
   3149 # ofp_multipart_request/reply_cls allows generic method OpenFlow()
   3150 # to choose the right class for dissection
   3151 ofp_multipart_request_cls = {     0: OFPMPRequestDesc,
   3152                                   1: OFPMPRequestFlow,
   3153                                   2: OFPMPRequestAggregate,
   3154                                   3: OFPMPRequestTable,
   3155                                   4: OFPMPRequestPortStats,
   3156                                   5: OFPMPRequestQueue,
   3157                                   6: OFPMPRequestGroup,
   3158                                   7: OFPMPRequestGroupDesc,
   3159                                   8: OFPMPRequestGroupFeatures,
   3160                                   9: OFPMPRequestMeter,
   3161                                  10: OFPMPRequestMeterConfig,
   3162                                  11: OFPMPRequestMeterFeatures,
   3163                                  12: OFPMPRequestTableFeatures,
   3164                                  13: OFPMPRequestPortDesc,
   3165                               65535: OFPMPRequestExperimenter }
   3166 
   3167 ofp_multipart_reply_cls = {     0: OFPMPReplyDesc,
   3168                                 1: OFPMPReplyFlow,
   3169                                 2: OFPMPReplyAggregate,
   3170                                 3: OFPMPReplyTable,
   3171                                 4: OFPMPReplyPortStats,
   3172                                 5: OFPMPReplyQueue,
   3173                                 6: OFPMPReplyGroup,
   3174                                 7: OFPMPReplyGroupDesc,
   3175                                 8: OFPMPReplyGroupFeatures,
   3176                                 9: OFPMPReplyMeter,
   3177                                10: OFPMPReplyMeterConfig,
   3178                                11: OFPMPReplyMeterFeatures,
   3179                                12: OFPMPReplyTableFeatures,
   3180                                13: OFPMPReplyPortDesc,
   3181                             65535: OFPMPReplyExperimenter }
   3182 
   3183 ############## end of OFPT_MULTIPART ################
   3184 
   3185 class OFPTBarrierRequest(_ofp_header):
   3186     name = "OFPT_BARRIER_REQUEST"
   3187     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   3188                     ByteEnumField("type", 20, ofp_type),
   3189                     ShortField("len", None),
   3190                     IntField("xid", 0) ]
   3191     overload_fields = {TCP: {"sport": 6653}}
   3192 
   3193 class OFPTBarrierReply(_ofp_header):
   3194     name = "OFPT_BARRIER_REPLY"
   3195     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   3196                     ByteEnumField("type", 21, ofp_type),
   3197                     ShortField("len", None),
   3198                     IntField("xid", 0) ]
   3199     overload_fields = {TCP: {"dport": 6653}}
   3200 
   3201 class OFPTQueueGetConfigRequest(_ofp_header):
   3202     name = "OFPT_QUEUE_GET_CONFIG_REQUEST"
   3203     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   3204                     ByteEnumField("type", 22, ofp_type),
   3205                     ShortField("len", None),
   3206                     IntField("xid", 0),
   3207                     IntEnumField("port_no", "ANY", ofp_port_no),
   3208                     XIntField("pad", 0) ]
   3209     overload_fields = {TCP: {"sport": 6653}}
   3210 
   3211 class OFPTQueueGetConfigReply(_ofp_header):
   3212     name = "OFPT_QUEUE_GET_CONFIG_REPLY"
   3213     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   3214                     ByteEnumField("type", 23, ofp_type),
   3215                     ShortField("len", None),
   3216                     IntField("xid", 0),
   3217                     IntEnumField("port", 0, ofp_port_no),
   3218                     XIntField("pad", 0),
   3219                     QueuePacketListField("queues", [], Packet,
   3220                                          length_from=lambda pkt:pkt.len-16) ]
   3221     overload_fields = {TCP: {"dport": 6653}}
   3222 
   3223 class OFPTRoleRequest(_ofp_header):
   3224     name = "OFPT_ROLE_REQUEST"
   3225     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   3226                     ByteEnumField("type", 24, ofp_type),
   3227                     ShortField("len", None),
   3228                     IntField("xid", 0),
   3229                     IntEnumField("role", 0, { 0: "OFPCR_ROLE_NOCHANGE",
   3230                                               1: "OFPCR_ROLE_EQUAL",
   3231                                               2: "OFPCR_ROLE_MASTER",
   3232                                               3: "OFPCR_ROLE_SLAVE" }),
   3233                     XIntField("pad", 0),
   3234                     LongField("generation_id", 0) ]
   3235     overload_fields = {TCP: {"sport": 6653}}
   3236 
   3237 class OFPTRoleReply(_ofp_header):
   3238     name = "OFPT_ROLE_REPLY"
   3239     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   3240                     ByteEnumField("type", 25, ofp_type),
   3241                     ShortField("len", None),
   3242                     IntField("xid", 0),
   3243                     IntEnumField("role", 0, { 0: "OFPCR_ROLE_NOCHANGE",
   3244                                               1: "OFPCR_ROLE_EQUAL",
   3245                                               2: "OFPCR_ROLE_MASTER",
   3246                                               3: "OFPCR_ROLE_SLAVE" }),
   3247                     XIntField("pad", 0),
   3248                     LongField("generation_id", 0) ]
   3249     overload_fields = {TCP: {"dport": 6653}}
   3250 
   3251 class OFPTGetAsyncRequest(_ofp_header):
   3252     name = "OFPT_GET_ASYNC_REQUEST"
   3253     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   3254                     ByteEnumField("type", 26, ofp_type),
   3255                     ShortField("len", 8),
   3256                     IntField("xid", 0) ]
   3257     overload_fields = {TCP: {"sport": 6653}}
   3258 
   3259 ofp_packet_in_reason = [ "NO_MATCH",
   3260                          "ACTION",
   3261                          "INVALID_TTL" ]
   3262 
   3263 ofp_port_reason = [ "ADD",
   3264                     "DELETE",
   3265                     "MODIFY" ]
   3266 
   3267 ofp_flow_removed_reason = [ "IDLE_TIMEOUT",
   3268                             "HARD_TIMEOUT",
   3269                             "DELETE",
   3270                             "GROUP_DELETE" ]
   3271 
   3272 class OFPTGetAsyncReply(_ofp_header):
   3273     name = "OFPT_GET_ASYNC_REPLY"
   3274     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   3275                     ByteEnumField("type", 27, ofp_type),
   3276                     ShortField("len", 32),
   3277                     IntField("xid", 0),
   3278                     FlagsField("packet_in_mask_master", 0, 32, ofp_packet_in_reason),
   3279                     FlagsField("packet_in_mask_slave", 0, 32, ofp_packet_in_reason),
   3280                     FlagsField("port_status_mask_master", 0, 32, ofp_port_reason),
   3281                     FlagsField("port_status_mask_slave", 0, 32, ofp_port_reason),
   3282                     FlagsField("flow_removed_mask_master", 0, 32, ofp_flow_removed_reason),
   3283                     FlagsField("flow_removed_mask_slave", 0, 32, ofp_flow_removed_reason) ]
   3284     overload_fields = {TCP: {"dport": 6653}}
   3285 
   3286 class OFPTSetAsync(_ofp_header):
   3287     name = "OFPT_SET_ASYNC"
   3288     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   3289                     ByteEnumField("type", 28, ofp_type),
   3290                     ShortField("len", 32),
   3291                     IntField("xid", 0),
   3292                     FlagsField("packet_in_mask_master", 0, 32, ofp_packet_in_reason),
   3293                     FlagsField("packet_in_mask_slave", 0, 32, ofp_packet_in_reason),
   3294                     FlagsField("port_status_mask_master", 0, 32, ofp_port_reason),
   3295                     FlagsField("port_status_mask_slave", 0, 32, ofp_port_reason),
   3296                     FlagsField("flow_removed_mask_master", 0, 32, ofp_flow_removed_reason),
   3297                     FlagsField("flow_removed_mask_slave", 0, 32, ofp_flow_removed_reason) ]
   3298     overload_fields = {TCP: {"sport": 6653}}
   3299 
   3300 class OFPTMeterMod(_ofp_header):
   3301     name = "OFPT_METER_MOD"
   3302     fields_desc = [ ByteEnumField("version", 0x04, ofp_version),
   3303                     ByteEnumField("type", 29, ofp_type),
   3304                     ShortField("len", None),
   3305                     IntField("xid", 0),
   3306                     ShortEnumField("cmd", 0, { 0: "OFPMC_ADD",
   3307                                                1: "OFPMC_MODIFY",
   3308                                                2: "OFPMC_DELETE" }),
   3309                     FlagsField("flags", 0, 16, [ "KBPS",
   3310                                                  "PKTPS",
   3311                                                  "BURST",
   3312                                                  "STATS" ]),
   3313                     IntEnumField("meter_id", 1, ofp_meter),
   3314                     MeterBandPacketListField("bands", [], Packet,
   3315                                              length_from=lambda pkt:pkt.len-16) ]
   3316     overload_fields = {TCP: {"sport": 6653}}
   3317 
   3318 # ofpt_cls allows generic method OpenFlow() to choose the right class for dissection
   3319 ofpt_cls = {  0: OFPTHello,
   3320               #1: OFPTError,
   3321               2: OFPTEchoRequest,
   3322               3: OFPTEchoReply,
   3323               4: OFPTExperimenter,
   3324               5: OFPTFeaturesRequest,
   3325               6: OFPTFeaturesReply,
   3326               7: OFPTGetConfigRequest,
   3327               8: OFPTGetConfigReply,
   3328               9: OFPTSetConfig,
   3329              10: OFPTPacketIn,
   3330              11: OFPTFlowRemoved,
   3331              12: OFPTPortStatus,
   3332              13: OFPTPacketOut,
   3333              14: OFPTFlowMod,
   3334              15: OFPTGroupMod,
   3335              16: OFPTPortMod,
   3336              17: OFPTTableMod,
   3337              #18: OFPTMultipartRequest,
   3338              #19: OFPTMultipartReply,
   3339              20: OFPTBarrierRequest,
   3340              21: OFPTBarrierReply,
   3341              22: OFPTQueueGetConfigRequest,
   3342              23: OFPTQueueGetConfigReply,
   3343              24: OFPTRoleRequest,
   3344              25: OFPTRoleReply,
   3345              26: OFPTGetAsyncRequest,
   3346              27: OFPTGetAsyncReply,
   3347              28: OFPTSetAsync,
   3348              29: OFPTMeterMod }
   3349 
   3350 TCP_guess_payload_class_copy = TCP.guess_payload_class
   3351 
   3352 def OpenFlow(self, payload):
   3353     if self is None or self.dport == 6653 or self.dport == 6633 or self.sport == 6653 or self.sport == 6633:
   3354     # port 6653 has been allocated by IANA, port 6633 should no longer be used
   3355     # OpenFlow function may be called with None self in OFPPacketField
   3356         of_type = orb(payload[1])
   3357         if of_type == 1:
   3358             err_type = orb(payload[9])
   3359             # err_type is a short int, but last byte is enough
   3360             if err_type == 255: err_type = 65535
   3361             return ofp_error_cls[err_type]
   3362         elif of_type == 18:
   3363             mp_type = orb(payload[9])
   3364             if mp_type == 255: mp_type = 65535
   3365             return ofp_multipart_request_cls[mp_type]
   3366         elif of_type == 19:
   3367             mp_type = orb(payload[9])
   3368             if mp_type == 255: mp_type = 65535
   3369             return ofp_multipart_reply_cls[mp_type]
   3370         else:
   3371             return ofpt_cls[of_type]
   3372     else:
   3373         return TCP_guess_payload_class_copy(self, payload)
   3374 
   3375 TCP.guess_payload_class = OpenFlow
   3376