1## This file is part of Scapy
2## See http://www.secdev.org/projects/scapy for more information
3## Copyright (C) Philippe Biondi <phil@secdev.org>
4## This program is published under a GPLv2 license
5
6## Copyright (C) 2014 Maxence Tury <maxence.tury@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
14from __future__ import absolute_import
15import struct
16from scapy.fields import *
17from scapy.layers.l2 import *
18from scapy.layers.inet import *
19from scapy.compat import *
20
21### If prereq_autocomplete is True then match prerequisites will be
22### automatically handled. See OFPMatch class.
23prereq_autocomplete = False
24
25#####################################################
26################# Predefined values #################
27#####################################################
28
29ofp_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
38ofp_group = { 0xffffff00: "MAX",
39              0xfffffffc: "ALL",
40              0xffffffff: "ANY" }
41
42ofp_table = { 0xfe: "MAX",
43              0xff: "ALL" }
44
45ofp_queue = { 0xffffffff: "ALL" }
46
47ofp_meter = { 0xffff0000: "MAX",
48              0xfffffffd: "SLOWPATH",
49              0xfffffffe: "CONTROLLER",
50              0xffffffff: "ALL" }
51
52ofp_buffer = { 0xffffffff: "NO_BUFFER" }
53
54ofp_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
68class _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
77ofp_hello_elem_types = { 1: "OFPHET_VERSIONBITMAP" }
78
79class 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
90ofp_hello_elem_cls = { 1: OFPHETVersionBitmap }
91
92class 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
117ofp_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
125ofp_port_state = [ "LINK_DOWN",
126                   "BLOCKED",
127                   "LIVE" ]
128
129ofp_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
146class 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
170ofp_oxm_classes = {      0: "OFPXMC_NXM_0",
171                         1: "OFPXMC_NXM_1",
172                    0x8000: "OFPXMC_OPENFLOW_BASIC",
173                    0xffff: "OFPXMC_EXPERIMENTER" }
174
175ofp_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
216ofp_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
258ipv6flags = [ "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",..),..]}
272ofp_oxm_fields = {}
273def 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
292for 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
299ofp_oxm_cls = {}
300ofp_oxm_id_cls = {}
301def 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
338OFBInPort = create_oxm_cls()
339OFBInPortID = create_oxm_cls()
340OFBInPortHM = create_oxm_cls()
341OFBInPortHMID = create_oxm_cls()
342OFBInPhyPort = create_oxm_cls()
343OFBInPhyPortID = create_oxm_cls()
344OFBInPhyPortHM = create_oxm_cls()
345OFBInPhyPortHMID = create_oxm_cls()
346OFBMetadata = create_oxm_cls()
347OFBMetadataID = create_oxm_cls()
348OFBMetadataHM = create_oxm_cls()
349OFBMetadataHMID = create_oxm_cls()
350OFBEthDst = create_oxm_cls()
351OFBEthDstID = create_oxm_cls()
352OFBEthDstHM = create_oxm_cls()
353OFBEthDstHMID = create_oxm_cls()
354OFBEthSrc = create_oxm_cls()
355OFBEthSrcID = create_oxm_cls()
356OFBEthSrcHM = create_oxm_cls()
357OFBEthSrcHMID = create_oxm_cls()
358OFBEthType = create_oxm_cls()
359OFBEthTypeID = create_oxm_cls()
360OFBEthTypeHM = create_oxm_cls()
361OFBEthTypeHMID = create_oxm_cls()
362OFBVLANVID = create_oxm_cls()
363OFBVLANVIDID = create_oxm_cls()
364OFBVLANVIDHM = create_oxm_cls()
365OFBVLANVIDHMID = create_oxm_cls()
366OFBVLANPCP = create_oxm_cls()
367OFBVLANPCPID = create_oxm_cls()
368OFBVLANPCPHM = create_oxm_cls()
369OFBVLANPCPHMID = create_oxm_cls()
370OFBIPDSCP = create_oxm_cls()
371OFBIPDSCPID = create_oxm_cls()
372OFBIPDSCPHM = create_oxm_cls()
373OFBIPDSCPHMID = create_oxm_cls()
374OFBIPECN = create_oxm_cls()
375OFBIPECNID = create_oxm_cls()
376OFBIPECNHM = create_oxm_cls()
377OFBIPECNHMID = create_oxm_cls()
378OFBIPProto = create_oxm_cls()
379OFBIPProtoID = create_oxm_cls()
380OFBIPProtoHM = create_oxm_cls()
381OFBIPProtoHMID = create_oxm_cls()
382OFBIPv4Src = create_oxm_cls()
383OFBIPv4SrcID = create_oxm_cls()
384OFBIPv4SrcHM = create_oxm_cls()
385OFBIPv4SrcHMID = create_oxm_cls()
386OFBIPv4Dst = create_oxm_cls()
387OFBIPv4DstID = create_oxm_cls()
388OFBIPv4DstHM = create_oxm_cls()
389OFBIPv4DstHMID = create_oxm_cls()
390OFBTCPSrc = create_oxm_cls()
391OFBTCPSrcID = create_oxm_cls()
392OFBTCPSrcHM = create_oxm_cls()
393OFBTCPSrcHMID = create_oxm_cls()
394OFBTCPDst = create_oxm_cls()
395OFBTCPDstID = create_oxm_cls()
396OFBTCPDstHM = create_oxm_cls()
397OFBTCPDstHMID = create_oxm_cls()
398OFBUDPSrc = create_oxm_cls()
399OFBUDPSrcID = create_oxm_cls()
400OFBUDPSrcHM = create_oxm_cls()
401OFBUDPSrcHMID = create_oxm_cls()
402OFBUDPDst = create_oxm_cls()
403OFBUDPDstID = create_oxm_cls()
404OFBUDPDstHM = create_oxm_cls()
405OFBUDPDstHMID = create_oxm_cls()
406OFBSCTPSrc = create_oxm_cls()
407OFBSCTPSrcID = create_oxm_cls()
408OFBSCTPSrcHM = create_oxm_cls()
409OFBSCTPSrcHMID = create_oxm_cls()
410OFBSCTPDst = create_oxm_cls()
411OFBSCTPDstID = create_oxm_cls()
412OFBSCTPDstHM = create_oxm_cls()
413OFBSCTPDstHMID = create_oxm_cls()
414OFBICMPv4Type = create_oxm_cls()
415OFBICMPv4TypeID = create_oxm_cls()
416OFBICMPv4TypeHM = create_oxm_cls()
417OFBICMPv4TypeHMID = create_oxm_cls()
418OFBICMPv4Code = create_oxm_cls()
419OFBICMPv4CodeID = create_oxm_cls()
420OFBICMPv4CodeHM = create_oxm_cls()
421OFBICMPv4CodeHMID = create_oxm_cls()
422OFBARPOP = create_oxm_cls()
423OFBARPOPID = create_oxm_cls()
424OFBARPOPHM = create_oxm_cls()
425OFBARPOPHMID = create_oxm_cls()
426OFBARPSPA = create_oxm_cls()
427OFBARPSPAID = create_oxm_cls()
428OFBARPSPAHM = create_oxm_cls()
429OFBARPSPAHMID = create_oxm_cls()
430OFBARPTPA = create_oxm_cls()
431OFBARPTPAID = create_oxm_cls()
432OFBARPTPAHM = create_oxm_cls()
433OFBARPTPAHMID = create_oxm_cls()
434OFBARPSHA = create_oxm_cls()
435OFBARPSHAID = create_oxm_cls()
436OFBARPSHAHM = create_oxm_cls()
437OFBARPSHAHMID = create_oxm_cls()
438OFBARPTHA = create_oxm_cls()
439OFBARPTHAID = create_oxm_cls()
440OFBARPTHAHM = create_oxm_cls()
441OFBARPTHAHMID = create_oxm_cls()
442OFBIPv6Src = create_oxm_cls()
443OFBIPv6SrcID = create_oxm_cls()
444OFBIPv6SrcHM = create_oxm_cls()
445OFBIPv6SrcHMID = create_oxm_cls()
446OFBIPv6Dst = create_oxm_cls()
447OFBIPv6DstID = create_oxm_cls()
448OFBIPv6DstHM = create_oxm_cls()
449OFBIPv6DstHMID = create_oxm_cls()
450OFBIPv6FLabel = create_oxm_cls()
451OFBIPv6FLabelID = create_oxm_cls()
452OFBIPv6FLabelHM = create_oxm_cls()
453OFBIPv6FLabelHMID = create_oxm_cls()
454OFBICMPv6Type = create_oxm_cls()
455OFBICMPv6TypeID = create_oxm_cls()
456OFBICMPv6TypeHM = create_oxm_cls()
457OFBICMPv6TypeHMID = create_oxm_cls()
458OFBICMPv6Code = create_oxm_cls()
459OFBICMPv6CodeID = create_oxm_cls()
460OFBICMPv6CodeHM = create_oxm_cls()
461OFBICMPv6CodeHMID = create_oxm_cls()
462OFBIPv6NDTarget = create_oxm_cls()
463OFBIPv6NDTargetID = create_oxm_cls()
464OFBIPv6NDTargetHM = create_oxm_cls()
465OFBIPv6NDTargetHMID = create_oxm_cls()
466OFBIPv6NDSLL = create_oxm_cls()
467OFBIPv6NDSLLID = create_oxm_cls()
468OFBIPv6NDSLLHM = create_oxm_cls()
469OFBIPv6NDSLLHMID = create_oxm_cls()
470OFBIPv6NDTLL = create_oxm_cls()
471OFBIPv6NDTLLID = create_oxm_cls()
472OFBIPv6NDTLLHM = create_oxm_cls()
473OFBIPv6NDTLLHMID = create_oxm_cls()
474OFBMPLSLabel = create_oxm_cls()
475OFBMPLSLabelID = create_oxm_cls()
476OFBMPLSLabelHM = create_oxm_cls()
477OFBMPLSLabelHMID = create_oxm_cls()
478OFBMPLSTC = create_oxm_cls()
479OFBMPLSTCID = create_oxm_cls()
480OFBMPLSTCHM = create_oxm_cls()
481OFBMPLSTCHMID = create_oxm_cls()
482OFBMPLSBoS = create_oxm_cls()
483OFBMPLSBoSID = create_oxm_cls()
484OFBMPLSBoSHM = create_oxm_cls()
485OFBMPLSBoSHMID = create_oxm_cls()
486OFBPBBISID = create_oxm_cls()
487OFBPBBISIDID = create_oxm_cls()
488OFBPBBISIDHM = create_oxm_cls()
489OFBPBBISIDHMID = create_oxm_cls()
490OFBTunnelID = create_oxm_cls()
491OFBTunnelIDID = create_oxm_cls()
492OFBTunnelIDHM = create_oxm_cls()
493OFBTunnelIDHMID = create_oxm_cls()
494OFBIPv6ExtHdr = create_oxm_cls()
495OFBIPv6ExtHdrID = create_oxm_cls()
496OFBIPv6ExtHdrHM = create_oxm_cls()
497OFBIPv6ExtHdrHMID = 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)
507need_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
541class 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
619class 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
640class 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
666class 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
689class _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
698ofp_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
729class 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
739class 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
746class 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
753class 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
759class 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
766class 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
773class 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
779class 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
785class 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
792class 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
799class 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
814class 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
820class 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
829class 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
835class 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
841class 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
848class 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
854class 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
861class 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
867class 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
874class 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
881class 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
887class 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
893class 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
900class 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
906class 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
934class 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
941class 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
947class 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
953ofp_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
984class 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
1016class 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
1023class OFPATSetVLANVIDID(_ofp_action_header):
1024    name = "OFPAT_SET_VLAN_VID"
1025    fields_desc = [ ShortEnumField("type", 1, ofp_action_types),
1026                    ShortField("len", 4) ]
1027
1028class OFPATSetVLANPCPID(_ofp_action_header):
1029    name = "OFPAT_SET_VLAN_PCP"
1030    fields_desc = [ ShortEnumField("type", 2, ofp_action_types),
1031                    ShortField("len", 4) ]
1032
1033class OFPATStripVLANID(_ofp_action_header):
1034    name = "OFPAT_STRIP_VLAN"
1035    fields_desc = [ ShortEnumField("type", 3, ofp_action_types),
1036                    ShortField("len", 4) ]
1037
1038class OFPATSetDlSrcID(_ofp_action_header):
1039    name = "OFPAT_SET_DL_SRC"
1040    fields_desc = [ ShortEnumField("type", 4, ofp_action_types),
1041                    ShortField("len", 4) ]
1042
1043class OFPATSetDlDstID(_ofp_action_header):
1044    name = "OFPAT_SET_DL_DST"
1045    fields_desc = [ ShortEnumField("type", 5, ofp_action_types),
1046                    ShortField("len", 4) ]
1047
1048class OFPATSetNwSrcID(_ofp_action_header):
1049    name = "OFPAT_SET_NW_SRC"
1050    fields_desc = [ ShortEnumField("type", 6, ofp_action_types),
1051                    ShortField("len", 4) ]
1052
1053class OFPATSetNwDstID(_ofp_action_header):
1054    name = "OFPAT_SET_NW_DST"
1055    fields_desc = [ ShortEnumField("type", 7, ofp_action_types),
1056                    ShortField("len", 4) ]
1057
1058class OFPATSetNwToSID(_ofp_action_header):
1059    name = "OFPAT_SET_TP_TOS"
1060    fields_desc = [ ShortEnumField("type", 8, ofp_action_types),
1061                    ShortField("len", 4) ]
1062
1063class OFPATSetTpSrcID(_ofp_action_header):
1064    name = "OFPAT_SET_TP_SRC"
1065    fields_desc = [ ShortEnumField("type", 9, ofp_action_types),
1066                    ShortField("len", 4) ]
1067
1068class 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
1078class OFPATSetMPLSLabelID(_ofp_action_header):
1079    name = "OFPAT_SET_MPLS_LABEL"
1080    fields_desc = [ ShortEnumField("type", 13, ofp_action_types),
1081                    ShortField("len", 4) ]
1082
1083class 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
1090class OFPATCopyTTLOutID(_ofp_action_header):
1091    name = "OFPAT_COPY_TTL_OUT"
1092    fields_desc = [ ShortEnumField("type", 11, ofp_action_types),
1093                    ShortField("len", 4) ]
1094
1095class OFPATCopyTTLInID(_ofp_action_header):
1096    name = "OFPAT_COPY_TTL_IN"
1097    fields_desc = [ ShortEnumField("type", 12, ofp_action_types),
1098                    ShortField("len", 4) ]
1099
1100class OFPATSetMPLSTTLID(_ofp_action_header):
1101    name = "OFPAT_SET_MPLS_TTL"
1102    fields_desc = [ ShortEnumField("type", 15, ofp_action_types),
1103                    ShortField("len", 4) ]
1104
1105class OFPATDecMPLSTTLID(_ofp_action_header):
1106    name = "OFPAT_DEC_MPLS_TTL"
1107    fields_desc = [ ShortEnumField("type", 16, ofp_action_types),
1108                    ShortField("len", 4) ]
1109
1110class OFPATPushVLANID(_ofp_action_header):
1111    name = "OFPAT_PUSH_VLAN"
1112    fields_desc = [ ShortEnumField("type", 17, ofp_action_types),
1113                    ShortField("len", 4) ]
1114
1115class OFPATPopVLANID(_ofp_action_header):
1116    name = "OFPAT_POP_VLAN"
1117    fields_desc = [ ShortEnumField("type", 18, ofp_action_types),
1118                    ShortField("len", 4) ]
1119
1120class OFPATPushMPLSID(_ofp_action_header):
1121    name = "OFPAT_PUSH_MPLS"
1122    fields_desc = [ ShortEnumField("type", 19, ofp_action_types),
1123                    ShortField("len", 4) ]
1124
1125class OFPATPopMPLSID(_ofp_action_header):
1126    name = "OFPAT_POP_MPLS"
1127    fields_desc = [ ShortEnumField("type", 20, ofp_action_types),
1128                    ShortField("len", 4) ]
1129
1130class OFPATSetQueueID(_ofp_action_header):
1131    name = "OFPAT_SET_QUEUE"
1132    fields_desc = [ ShortEnumField("type", 21, ofp_action_types),
1133                    ShortField("len", 4) ]
1134
1135class OFPATGroupID(_ofp_action_header):
1136    name = "OFPAT_GROUP"
1137    fields_desc = [ ShortEnumField("type", 22, ofp_action_types),
1138                    ShortField("len", 4) ]
1139
1140class OFPATSetNwTTLID(_ofp_action_header):
1141    name = "OFPAT_SET_NW_TTL"
1142    fields_desc = [ ShortEnumField("type", 23, ofp_action_types),
1143                    ShortField("len", 4) ]
1144
1145class OFPATDecNwTTLID(_ofp_action_header):
1146    name = "OFPAT_DEC_NW_TTL"
1147    fields_desc = [ ShortEnumField("type", 24, ofp_action_types),
1148                    ShortField("len", 4) ]
1149
1150class OFPATSetFieldID(_ofp_action_header):
1151    name = "OFPAT_SET_FIELD"
1152    fields_desc = [ ShortEnumField("type", 25, ofp_action_types),
1153                    ShortField("len", 4) ]
1154
1155class OFPATPushPBBID(_ofp_action_header):
1156    name = "OFPAT_PUSH_PBB"
1157    fields_desc = [ ShortEnumField("type", 26, ofp_action_types),
1158                    ShortField("len", 4) ]
1159
1160class OFPATPopPBBID(_ofp_action_header):
1161    name = "OFPAT_POP_PBB"
1162    fields_desc = [ ShortEnumField("type", 27, ofp_action_types),
1163                    ShortField("len", 4) ]
1164
1165class OFPATExperimenterID(_ofp_action_header):
1166    name = "OFPAT_EXPERIMENTER"
1167    fields_desc = [ ShortEnumField("type", 65535, ofp_action_types),
1168                    ShortField("len", None) ]
1169
1170ofp_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
1201class 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
1230class _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
1239ofp_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
1247class 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
1254class 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
1262class 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
1270class 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
1278class 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
1284class 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
1290class 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
1296ofp_instruction_cls = {     1: OFPITGotoTable,
1297                            2: OFPITWriteMetadata,
1298                            3: OFPITWriteActions,
1299                            4: OFPITApplyActions,
1300                            5: OFPITClearActions,
1301                            6: OFPITMeter,
1302                        65535: OFPITExperimenter }
1303
1304class 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
1336class OFPITGotoTableID(_ofp_instruction_header):
1337    name = "OFPIT_GOTO_TABLE"
1338    fields_desc = [ ShortEnumField("type", 1, ofp_instruction_types),
1339                    ShortField("len", 4) ]
1340
1341class OFPITWriteMetadataID(_ofp_instruction_header):
1342    name = "OFPIT_WRITE_METADATA"
1343    fields_desc = [ ShortEnumField("type", 2, ofp_instruction_types),
1344                    ShortField("len", 4) ]
1345
1346class OFPITWriteActionsID(_ofp_instruction_header):
1347    name = "OFPIT_WRITE_ACTIONS"
1348    fields_desc = [ ShortEnumField("type", 3, ofp_instruction_types),
1349                    ShortField("len", 4) ]
1350
1351class OFPITApplyActionsID(_ofp_instruction_header):
1352    name = "OFPIT_APPLY_ACTIONS"
1353    fields_desc = [ ShortEnumField("type", 4, ofp_instruction_types),
1354                    ShortField("len", 4) ]
1355
1356class OFPITClearActionsID(_ofp_instruction_header):
1357    name = "OFPIT_CLEAR_ACTIONS"
1358    fields_desc = [ ShortEnumField("type", 5, ofp_instruction_types),
1359                    ShortField("len", 4) ]
1360
1361class OFPITMeterID(_ofp_instruction_header):
1362    name = "OFPIT_METER"
1363    fields_desc = [ ShortEnumField("type", 6, ofp_instruction_types),
1364                    ShortField("len", 4) ]
1365
1366class OFPITExperimenterID(_ofp_instruction_header):
1367    name = "OFPIT_EXPERIMENTER"
1368    fields_desc = [ ShortEnumField("type", 65535, ofp_instruction_types),
1369                    ShortField("len", None) ]
1370
1371ofp_instruction_id_cls = {     1: OFPITGotoTableID,
1372                               2: OFPITWriteMetadataID,
1373                               3: OFPITWriteActionsID,
1374                               4: OFPITApplyActionsID,
1375                               5: OFPITClearActionsID,
1376                               6: OFPITMeterID,
1377                           65535: OFPITExperimenterID }
1378
1379class 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
1408class 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
1428class 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
1450class _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
1459ofp_queue_property_types = { 0: "OFPQT_NONE",
1460                             1: "OFPQT_MIN_RATE" }
1461
1462class 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
1468class 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
1476ofp_queue_property_cls = { 0: OFPQTNone,
1477                           1: OFPQTMinRate }
1478
1479class 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
1501class 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
1521class 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
1543ofp_meter_band_types = {     0: "OFPMBT_DROP",
1544                             1: "OFPMBT_DSCP_REMARK",
1545                         65535: "OFPMBT_EXPERIMENTER" }
1546
1547class 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
1555class 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
1564class 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
1572ofp_meter_band_cls = { 0: OFPMBTDrop,
1573                       1: OFPMBTDSCPRemark,
1574                       2: OFPMBTExperimenter }
1575
1576class 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
1598ofp_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
1604ofp_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
1635class _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
1644class 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
1660class 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
1671ofp_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
1687class 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
1699class 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
1723class 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
1749class 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
1768class 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
1790class 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
1808class 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
1833class 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
1848class 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
1861class 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
1874class 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
1887class 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
1900class 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
1922class 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
1938class 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
1952ofp_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
1970class 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
1978class 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
1986class 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
1996class 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
2004class 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
2027class 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
2035class 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
2048class 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
2061class 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
2079class 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
2101class 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
2114class 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
2129class 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
2161class 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
2180class 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
2196class 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
2211ofp_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
2227ofpmp_request_flags = [ "REQ_MORE" ]
2228
2229ofpmp_reply_flags = [ "REPLY_MORE" ]
2230
2231class 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
2242class 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
2258class 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
2277class 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
2305class 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
2324class 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
2337class 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
2356class 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
2371class 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
2382class 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
2392class 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
2405class 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
2418class 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
2439class 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
2452class 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
2465class 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
2477class 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
2490class 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
2503class 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
2510class 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
2529class 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
2548class 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
2561class 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
2572class 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
2589class 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
2609class 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
2622class 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
2633ofp_action_types_flags = list(ofp_action_types.values())[:-1]  # no ofpat_experimenter flag
2634class 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
2662class 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
2675class 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
2682class 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
2700class 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
2721class 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
2734class 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
2747class 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
2763class 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
2782class 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
2795class 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
2806class 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
2830class _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
2849ofp_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
2866class 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
2873class 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
2880class 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
2886class 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
2893class 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
2900class 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
2907class 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
2914class 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
2921class 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
2928class 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
2935class 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
2942class 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
2949class 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
2956class 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
2963class 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
2970class 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
2978class 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
2986ofp_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
3003class 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
3031class 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
3050class 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
3069class 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
3082class 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
3097class 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
3110class 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
3123class 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
3136class 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
3151ofp_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
3167ofp_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
3185class 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
3193class 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
3201class 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
3211class 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
3223class 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
3237class 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
3251class 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
3259ofp_packet_in_reason = [ "NO_MATCH",
3260                         "ACTION",
3261                         "INVALID_TTL" ]
3262
3263ofp_port_reason = [ "ADD",
3264                    "DELETE",
3265                    "MODIFY" ]
3266
3267ofp_flow_removed_reason = [ "IDLE_TIMEOUT",
3268                            "HARD_TIMEOUT",
3269                            "DELETE",
3270                            "GROUP_DELETE" ]
3271
3272class 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
3286class 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
3300class 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
3319ofpt_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
3350TCP_guess_payload_class_copy = TCP.guess_payload_class
3351
3352def 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
3375TCP.guess_payload_class = OpenFlow
3376