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