# This file is part of Scapy # See http://www.secdev.org/projects/scapy for more information # Copyright (C) Philippe Biondi # This program is published under a GPLv2 license # Copyright (C) 2014 Maxence Tury # OpenFlow is an open standard used in SDN deployments. # Based on OpenFlow v1.3.4 # Specifications can be retrieved from https://www.opennetworking.org/ # scapy.contrib.description = OpenFlow v1.3 # scapy.contrib.status = loads from __future__ import absolute_import import copy import struct from scapy.compat import orb, raw from scapy.config import conf from scapy.fields import BitEnumField, BitField, ByteEnumField, ByteField, \ FieldLenField, FlagsField, IntEnumField, IntField, IPField, \ LongField, MACField, PacketField, PacketListField, ShortEnumField, \ ShortField, StrFixedLenField, X3BytesField, XBitField, XByteField, \ XIntField, XShortField, PacketLenField from scapy.layers.l2 import Ether from scapy.packet import Packet, Padding, Raw from scapy.modules import six from scapy.contrib.openflow import _ofp_header, _ofp_header_item, \ OFPacketField, OpenFlow, _UnknownOpenFlow ##################################################### # Predefined values # ##################################################### ofp_port_no = {0xfffffff8: "IN_PORT", 0xfffffff9: "TABLE", 0xfffffffa: "NORMAL", 0xfffffffb: "FLOOD", 0xfffffffc: "ALL", 0xfffffffd: "CONTROLLER", 0xfffffffe: "LOCAL", 0xffffffff: "ANY"} ofp_group = {0xffffff00: "MAX", 0xfffffffc: "ALL", 0xffffffff: "ANY"} ofp_table = {0xfe: "MAX", 0xff: "ALL"} ofp_queue = {0xffffffff: "ALL"} ofp_meter = {0xffff0000: "MAX", 0xfffffffd: "SLOWPATH", 0xfffffffe: "CONTROLLER", 0xffffffff: "ALL"} ofp_buffer = {0xffffffff: "NO_BUFFER"} ofp_max_len = {0xffff: "NO_BUFFER"} ##################################################### # Common structures # ##################################################### # The following structures will be used in different types # of OpenFlow messages: ports, matches/OXMs, actions, # instructions, buckets, queues, meter bands. # Hello elements # ofp_hello_elem_types = {1: "OFPHET_VERSIONBITMAP"} class OFPHET(_ofp_header): @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and len(_pkt) >= 2: t = struct.unpack("!H", _pkt[:2])[0] return ofp_hello_elem_cls.get(t, Raw) return Raw def extract_padding(self, s): return b"", s class OFPHETVersionBitmap(_ofp_header): name = "OFPHET_VERSIONBITMAP" fields_desc = [ShortEnumField("type", 1, ofp_hello_elem_types), ShortField("len", 8), FlagsField("bitmap", 0, 32, ["Type 0", "OFv1.0", "OFv1.1", "OFv1.2", "OFv1.3", "OFv1.4", "OFv1.5"])] ofp_hello_elem_cls = {1: OFPHETVersionBitmap} # Ports # ofp_port_config = ["PORT_DOWN", "NO_STP", # undefined in v1.3 "NO_RECV", "NO_RECV_STP", # undefined in v1.3 "NO_FLOOD", # undefined in v1.3 "NO_FWD", "NO_PACKET_IN"] ofp_port_state = ["LINK_DOWN", "BLOCKED", "LIVE"] ofp_port_features = ["10MB_HD", "10MB_FD", "100MB_HD", "100MB_FD", "1GB_HD", "1GB_FD", "10GB_FD", "40GB_FD", "100GB_FD", "1TB_FD", "OTHER", "COPPER", "FIBER", "AUTONEG", "PAUSE", "PAUSE_ASYM"] class OFPPort(Packet): name = "OFP_PHY_PORT" fields_desc = [IntEnumField("port_no", 0, ofp_port_no), XIntField("pad1", 0), MACField("hw_addr", "0"), XShortField("pad2", 0), StrFixedLenField("port_name", "", 16), FlagsField("config", 0, 32, ofp_port_config), FlagsField("state", 0, 32, ofp_port_state), FlagsField("curr", 0, 32, ofp_port_features), FlagsField("advertised", 0, 32, ofp_port_features), FlagsField("supported", 0, 32, ofp_port_features), FlagsField("peer", 0, 32, ofp_port_features), IntField("curr_speed", 0), IntField("max_speed", 0)] def extract_padding(self, s): return b"", s # Matches & OXMs # ofp_oxm_classes = {0: "OFPXMC_NXM_0", 1: "OFPXMC_NXM_1", 0x8000: "OFPXMC_OPENFLOW_BASIC", 0xffff: "OFPXMC_EXPERIMENTER"} ofp_oxm_names = {0: "OFB_IN_PORT", 1: "OFB_IN_PHY_PORT", 2: "OFB_METADATA", 3: "OFB_ETH_DST", 4: "OFB_ETH_SRC", 5: "OFB_ETH_TYPE", 6: "OFB_VLAN_VID", 7: "OFB_VLAN_PCP", 8: "OFB_IP_DSCP", 9: "OFB_IP_ECN", 10: "OFB_IP_PROTO", 11: "OFB_IPV4_SRC", 12: "OFB_IPV4_DST", 13: "OFB_TCP_SRC", 14: "OFB_TCP_DST", 15: "OFB_UDP_SRC", 16: "OFB_UDP_DST", 17: "OFB_SCTP_SRC", 18: "OFB_SCTP_DST", 19: "OFB_ICMPV4_TYPE", 20: "OFB_ICMPV4_CODE", 21: "OFB_ARP_OP", 22: "OFB_ARP_SPA", 23: "OFB_ARP_TPA", 24: "OFB_ARP_SHA", 25: "OFB_ARP_THA", 26: "OFB_IPV6_SRC", 27: "OFB_IPV6_DST", 28: "OFB_IPV6_FLABEL", 29: "OFB_ICMPV6_TYPE", 30: "OFB_ICMPV6_CODE", 31: "OFB_IPV6_ND_TARGET", 32: "OFB_IPV6_ND_SLL", 33: "OFB_IPV6_ND_TLL", 34: "OFB_MPLS_LABEL", 35: "OFB_MPLS_TC", 36: "OFB_MPLS_BOS", 37: "OFB_PBB_ISID", 38: "OFB_TUNNEL_ID", 39: "OFB_IPV6_EXTHDR"} ofp_oxm_constr = {0: ["OFBInPort", "in_port", 4], 1: ["OFBInPhyPort", "in_phy_port", 4], 2: ["OFBMetadata", "metadata", 8], 3: ["OFBEthDst", "eth_dst", 6], 4: ["OFBEthSrc", "eth_src", 6], 5: ["OFBEthType", "eth_type", 2], 6: ["OFBVLANVID", "vlan_vid", 2], 7: ["OFBVLANPCP", "vlan_pcp", 1], 8: ["OFBIPDSCP", "ip_dscp", 1], 9: ["OFBIPECN", "ip_ecn", 1], 10: ["OFBIPProto", "ip_proto", 1], 11: ["OFBIPv4Src", "ipv4_src", 4], 12: ["OFBIPv4Dst", "ipv4_dst", 4], 13: ["OFBTCPSrc", "tcp_src", 2], 14: ["OFBTCPDst", "tcp_dst", 2], 15: ["OFBUDPSrc", "udp_src", 2], 16: ["OFBUDPDst", "udp_dst", 2], 17: ["OFBSCTPSrc", "sctp_src", 2], 18: ["OFBSCTPDst", "sctp_dst", 2], 19: ["OFBICMPv4Type", "icmpv4_type", 1], 20: ["OFBICMPv4Code", "icmpv4_code", 1], 21: ["OFBARPOP", "arp_op", 2], 22: ["OFBARPSPA", "arp_spa", 4], 23: ["OFBARPTPA", "arp_tpa", 4], 24: ["OFBARPSHA", "arp_sha", 6], 25: ["OFBARPTHA", "arp_tha", 6], 26: ["OFBIPv6Src", "ipv6_src", 16], 27: ["OFBIPv6Dst", "ipv6_dst", 16], 28: ["OFBIPv6FLabel", "ipv6_flabel", 4], 29: ["OFBICMPv6Type", "icmpv6_type", 1], 30: ["OFBICMPv6Code", "icmpv6_code", 1], 31: ["OFBIPv6NDTarget", "ipv6_nd_target", 16], 32: ["OFBIPv6NDSLL", "ipv6_sll", 6], 33: ["OFBIPv6NDTLL", "ipv6_tll", 6], 34: ["OFBMPLSLabel", "mpls_label", 4], 35: ["OFBMPLSTC", "mpls_tc", 1], 36: ["OFBMPLSBoS", "mpls_bos", 1], 37: ["OFBPBBISID", "pbb_isid", 3], 38: ["OFBTunnelID", "tunnel_id", 8], 39: ["OFBIPv6ExtHdr", "ipv6_ext_hdr_flags", 2]} # the ipv6flags array is useful only to the OFBIPv6ExtHdr class ipv6flags = ["NONEXT", "ESP", "AUTH", "DEST", "FRAG", "ROUTER", "HOP", "UNREP", "UNSEQ"] # here we fill ofp_oxm_fields with the fields that will be used # to generate the various OXM classes # e.g. the call to add_ofp_oxm_fields(0, ["OFBInPort", "in_port", 4]) # will add {0: [ShortEnumField("class",..), BitEnumField("field",..),..]} ofp_oxm_fields = {} def add_ofp_oxm_fields(i, org): ofp_oxm_fields[i] = [ShortEnumField("class", "OFPXMC_OPENFLOW_BASIC", ofp_oxm_classes), # noqa: E501 BitEnumField("field", i // 2, 7, ofp_oxm_names), BitField("hasmask", i % 2, 1)] ofp_oxm_fields[i].append(ByteField("len", org[2] + org[2] * (i % 2))) if i // 2 == 0: # OFBInPort ofp_oxm_fields[i].append(IntEnumField(org[1], 0, ofp_port_no)) elif i // 2 == 3 or i // 2 == 4: # OFBEthSrc & OFBEthDst ofp_oxm_fields[i].append(MACField(org[1], None)) elif i // 2 == 11 or i // 2 == 12: # OFBIPv4Src & OFBIPv4Dst ofp_oxm_fields[i].append(IPField(org[1], "0")) elif i // 2 == 39: # OFBIPv6ExtHdr ofp_oxm_fields[i].append(FlagsField(org[1], 0, 8 * org[2], ipv6flags)) else: ofp_oxm_fields[i].append(BitField(org[1], 0, 8 * org[2])) if i % 2: ofp_oxm_fields[i].append(BitField(org[1] + "_mask", 0, 8 * org[2])) # some HM classes are not supported par OFv1.3 but we will create them anyway for i, cls in ofp_oxm_constr.items(): add_ofp_oxm_fields(2 * i, cls) add_ofp_oxm_fields(2 * i + 1, cls) # now we create every OXM class with the same call, # (except that static variable create_oxm_class.i is each time different) # and we fill ofp_oxm_cls with them ofp_oxm_cls = {} ofp_oxm_id_cls = {} def _create_oxm_cls(): # static variable initialization if not hasattr(_create_oxm_cls, "i"): _create_oxm_cls.i = 0 index = _create_oxm_cls.i cls_name = ofp_oxm_constr[index // 4][0] # we create standard OXM then OXM ID then OXM with mask then OXM-hasmask ID if index % 4 == 2: cls_name += "HM" if index % 2: cls_name += "ID" oxm_name = ofp_oxm_names[index // 4] oxm_fields = ofp_oxm_fields[index // 2] # for ID classes we just want the first 4 fields (no payload) if index % 2: oxm_fields = oxm_fields[:4] cls = type(cls_name, (Packet,), {"name": oxm_name, "fields_desc": oxm_fields}) # noqa: E501 # the first call to special function type will create the same class as in # class OFBInPort(Packet): # def __init__(self): # self.name = "OFB_IN_PORT" # self.fields_desc = [ ShortEnumField("class", 0x8000, ofp_oxm_classes), # BitEnumField("field", 0, 7, ofp_oxm_names), # BitField("hasmask", 0, 1), # ByteField("len", 4), # IntEnumField("in_port", 0, ofp_port_no) ] if index % 2 == 0: ofp_oxm_cls[index // 2] = cls else: ofp_oxm_id_cls[index // 2] = cls _create_oxm_cls.i += 1 cls.extract_padding = lambda self, s: (b"", s) return cls OFBInPort = _create_oxm_cls() OFBInPortID = _create_oxm_cls() OFBInPortHM = _create_oxm_cls() OFBInPortHMID = _create_oxm_cls() OFBInPhyPort = _create_oxm_cls() OFBInPhyPortID = _create_oxm_cls() OFBInPhyPortHM = _create_oxm_cls() OFBInPhyPortHMID = _create_oxm_cls() OFBMetadata = _create_oxm_cls() OFBMetadataID = _create_oxm_cls() OFBMetadataHM = _create_oxm_cls() OFBMetadataHMID = _create_oxm_cls() OFBEthDst = _create_oxm_cls() OFBEthDstID = _create_oxm_cls() OFBEthDstHM = _create_oxm_cls() OFBEthDstHMID = _create_oxm_cls() OFBEthSrc = _create_oxm_cls() OFBEthSrcID = _create_oxm_cls() OFBEthSrcHM = _create_oxm_cls() OFBEthSrcHMID = _create_oxm_cls() OFBEthType = _create_oxm_cls() OFBEthTypeID = _create_oxm_cls() OFBEthTypeHM = _create_oxm_cls() OFBEthTypeHMID = _create_oxm_cls() OFBVLANVID = _create_oxm_cls() OFBVLANVIDID = _create_oxm_cls() OFBVLANVIDHM = _create_oxm_cls() OFBVLANVIDHMID = _create_oxm_cls() OFBVLANPCP = _create_oxm_cls() OFBVLANPCPID = _create_oxm_cls() OFBVLANPCPHM = _create_oxm_cls() OFBVLANPCPHMID = _create_oxm_cls() OFBIPDSCP = _create_oxm_cls() OFBIPDSCPID = _create_oxm_cls() OFBIPDSCPHM = _create_oxm_cls() OFBIPDSCPHMID = _create_oxm_cls() OFBIPECN = _create_oxm_cls() OFBIPECNID = _create_oxm_cls() OFBIPECNHM = _create_oxm_cls() OFBIPECNHMID = _create_oxm_cls() OFBIPProto = _create_oxm_cls() OFBIPProtoID = _create_oxm_cls() OFBIPProtoHM = _create_oxm_cls() OFBIPProtoHMID = _create_oxm_cls() OFBIPv4Src = _create_oxm_cls() OFBIPv4SrcID = _create_oxm_cls() OFBIPv4SrcHM = _create_oxm_cls() OFBIPv4SrcHMID = _create_oxm_cls() OFBIPv4Dst = _create_oxm_cls() OFBIPv4DstID = _create_oxm_cls() OFBIPv4DstHM = _create_oxm_cls() OFBIPv4DstHMID = _create_oxm_cls() OFBTCPSrc = _create_oxm_cls() OFBTCPSrcID = _create_oxm_cls() OFBTCPSrcHM = _create_oxm_cls() OFBTCPSrcHMID = _create_oxm_cls() OFBTCPDst = _create_oxm_cls() OFBTCPDstID = _create_oxm_cls() OFBTCPDstHM = _create_oxm_cls() OFBTCPDstHMID = _create_oxm_cls() OFBUDPSrc = _create_oxm_cls() OFBUDPSrcID = _create_oxm_cls() OFBUDPSrcHM = _create_oxm_cls() OFBUDPSrcHMID = _create_oxm_cls() OFBUDPDst = _create_oxm_cls() OFBUDPDstID = _create_oxm_cls() OFBUDPDstHM = _create_oxm_cls() OFBUDPDstHMID = _create_oxm_cls() OFBSCTPSrc = _create_oxm_cls() OFBSCTPSrcID = _create_oxm_cls() OFBSCTPSrcHM = _create_oxm_cls() OFBSCTPSrcHMID = _create_oxm_cls() OFBSCTPDst = _create_oxm_cls() OFBSCTPDstID = _create_oxm_cls() OFBSCTPDstHM = _create_oxm_cls() OFBSCTPDstHMID = _create_oxm_cls() OFBICMPv4Type = _create_oxm_cls() OFBICMPv4TypeID = _create_oxm_cls() OFBICMPv4TypeHM = _create_oxm_cls() OFBICMPv4TypeHMID = _create_oxm_cls() OFBICMPv4Code = _create_oxm_cls() OFBICMPv4CodeID = _create_oxm_cls() OFBICMPv4CodeHM = _create_oxm_cls() OFBICMPv4CodeHMID = _create_oxm_cls() OFBARPOP = _create_oxm_cls() OFBARPOPID = _create_oxm_cls() OFBARPOPHM = _create_oxm_cls() OFBARPOPHMID = _create_oxm_cls() OFBARPSPA = _create_oxm_cls() OFBARPSPAID = _create_oxm_cls() OFBARPSPAHM = _create_oxm_cls() OFBARPSPAHMID = _create_oxm_cls() OFBARPTPA = _create_oxm_cls() OFBARPTPAID = _create_oxm_cls() OFBARPTPAHM = _create_oxm_cls() OFBARPTPAHMID = _create_oxm_cls() OFBARPSHA = _create_oxm_cls() OFBARPSHAID = _create_oxm_cls() OFBARPSHAHM = _create_oxm_cls() OFBARPSHAHMID = _create_oxm_cls() OFBARPTHA = _create_oxm_cls() OFBARPTHAID = _create_oxm_cls() OFBARPTHAHM = _create_oxm_cls() OFBARPTHAHMID = _create_oxm_cls() OFBIPv6Src = _create_oxm_cls() OFBIPv6SrcID = _create_oxm_cls() OFBIPv6SrcHM = _create_oxm_cls() OFBIPv6SrcHMID = _create_oxm_cls() OFBIPv6Dst = _create_oxm_cls() OFBIPv6DstID = _create_oxm_cls() OFBIPv6DstHM = _create_oxm_cls() OFBIPv6DstHMID = _create_oxm_cls() OFBIPv6FLabel = _create_oxm_cls() OFBIPv6FLabelID = _create_oxm_cls() OFBIPv6FLabelHM = _create_oxm_cls() OFBIPv6FLabelHMID = _create_oxm_cls() OFBICMPv6Type = _create_oxm_cls() OFBICMPv6TypeID = _create_oxm_cls() OFBICMPv6TypeHM = _create_oxm_cls() OFBICMPv6TypeHMID = _create_oxm_cls() OFBICMPv6Code = _create_oxm_cls() OFBICMPv6CodeID = _create_oxm_cls() OFBICMPv6CodeHM = _create_oxm_cls() OFBICMPv6CodeHMID = _create_oxm_cls() OFBIPv6NDTarget = _create_oxm_cls() OFBIPv6NDTargetID = _create_oxm_cls() OFBIPv6NDTargetHM = _create_oxm_cls() OFBIPv6NDTargetHMID = _create_oxm_cls() OFBIPv6NDSLL = _create_oxm_cls() OFBIPv6NDSLLID = _create_oxm_cls() OFBIPv6NDSLLHM = _create_oxm_cls() OFBIPv6NDSLLHMID = _create_oxm_cls() OFBIPv6NDTLL = _create_oxm_cls() OFBIPv6NDTLLID = _create_oxm_cls() OFBIPv6NDTLLHM = _create_oxm_cls() OFBIPv6NDTLLHMID = _create_oxm_cls() OFBMPLSLabel = _create_oxm_cls() OFBMPLSLabelID = _create_oxm_cls() OFBMPLSLabelHM = _create_oxm_cls() OFBMPLSLabelHMID = _create_oxm_cls() OFBMPLSTC = _create_oxm_cls() OFBMPLSTCID = _create_oxm_cls() OFBMPLSTCHM = _create_oxm_cls() OFBMPLSTCHMID = _create_oxm_cls() OFBMPLSBoS = _create_oxm_cls() OFBMPLSBoSID = _create_oxm_cls() OFBMPLSBoSHM = _create_oxm_cls() OFBMPLSBoSHMID = _create_oxm_cls() OFBPBBISID = _create_oxm_cls() OFBPBBISIDID = _create_oxm_cls() OFBPBBISIDHM = _create_oxm_cls() OFBPBBISIDHMID = _create_oxm_cls() OFBTunnelID = _create_oxm_cls() OFBTunnelIDID = _create_oxm_cls() OFBTunnelIDHM = _create_oxm_cls() OFBTunnelIDHMID = _create_oxm_cls() OFBIPv6ExtHdr = _create_oxm_cls() OFBIPv6ExtHdrID = _create_oxm_cls() OFBIPv6ExtHdrHM = _create_oxm_cls() OFBIPv6ExtHdrHMID = _create_oxm_cls() # need_prereq holds a list of prerequisites defined in 7.2.3.8 of the specifications # noqa: E501 # e.g. if you want to use an OFBTCPSrc instance (code 26) # you first need to declare an OFBIPProto instance (code 20) with value 6, # and if you want to use an OFBIPProto instance (still code 20) # you first need to declare an OFBEthType instance (code 10) with value 0x0800 # (0x0800 means IPv4 by default, but you might want to use 0x86dd with IPv6) # need_prereq codes are two times higher than previous oxm classes codes, # except for 21 which is sort of a proxy for IPv6 (see below) need_prereq = {14: [12, 0x1000], 16: [10, 0x0800], # could be 0x86dd 18: [10, 0x0800], # could be 0x86dd 20: [10, 0x0800], # could be 0x86dd 21: [10, 0x86dd], 22: [10, 0x0800], 24: [10, 0x0800], 26: [20, 6], 28: [20, 6], 30: [20, 17], 32: [20, 17], 34: [20, 132], 36: [20, 132], 38: [20, 1], 40: [20, 1], 42: [10, 0x0806], 44: [10, 0x0806], 46: [10, 0x0806], 48: [10, 0x0806], 50: [10, 0x0806], 52: [10, 0x86dd], 54: [10, 0x86dd], 56: [10, 0x86dd], 58: [21, 58], # small trick here, we refer to normally non- 60: [21, 58], # existent field 21 to distinguish ipv6 62: [58, 135], # could be 136 64: [58, 135], 66: [58, 136], 68: [10, 0x8847], # could be 0x8848 70: [10, 0x8847], # could be 0x8848 72: [10, 0x8847], # could be 0x8848 74: [10, 0x88e7], 78: [10, 0x86dd]} class OXMPacketListField(PacketListField): __slots__ = ["autocomplete", "index"] def __init__(self, name, default, cls, length_from=None, autocomplete=False): # noqa: E501 PacketListField.__init__(self, name, default, cls, length_from=length_from) # noqa: E501 self.autocomplete = autocomplete self.index = [] def i2m(self, pkt, val): # this part makes for a faster writing of specs-compliant matches # expect some unwanted behaviour if you try incoherent associations # you might want to set autocomplete=False in __init__ method if self.autocomplete or conf.contribs['OPENFLOW']['prereq_autocomplete']: # noqa: E501 # val might be modified during the loop so we need a fixed copy fix_val = copy.deepcopy(val) for oxm in fix_val: f = 2 * oxm.field fix_index = list(self.index) while f in need_prereq: # this loop enables a small recursion # e.g. ipv6_nd<--icmpv6<--ip_proto<--eth_type prereq = need_prereq[f] f = prereq[0] f2 = 20 if f == 21 else f # ipv6 trick... if f2 not in fix_index: self.index.insert(0, f2) prrq = ofp_oxm_cls[f2]() # never HM setattr(prrq, ofp_oxm_constr[f2 // 2][1], prereq[1]) val.insert(0, prrq) # we could do more complicated stuff to # make sure prerequisite order is correct # but it works well when presented with any coherent input # e.g. you should not mix OFBTCPSrc with OFBICMPv6Code # and expect to get coherent results... # you can still go manual by setting prereq_autocomplete=False # noqa: E501 return val def m2i(self, pkt, s): t = orb(s[2]) nrm_t = t - t % 2 if nrm_t not in self.index: self.index.append(nrm_t) return ofp_oxm_cls.get(t, Raw)(s) @staticmethod def _get_oxm_length(s): return orb(s[3]) def addfield(self, pkt, s, val): return s + b"".join(raw(x) for x in self.i2m(pkt, val)) def getfield(self, pkt, s): lst = [] lim = self.length_from(pkt) ret = s[lim:] remain = s[:lim] while remain and len(remain) > 4: tmp_len = OXMPacketListField._get_oxm_length(remain) + 4 # this could also be done by parsing oxm_fields (fixed lengths) if tmp_len <= 4 or len(remain) < tmp_len: # no incoherent length break current = remain[:tmp_len] remain = remain[tmp_len:] p = self.m2i(pkt, current) lst.append(p) self.index = [] # since OXMPacketListField is called only twice (when OFPMatch and OFPSetField # noqa: E501 # classes are created) and not when you want to instantiate an OFPMatch, # noqa: E501 # index needs to be reinitialized, otherwise there will be some conflicts # noqa: E501 # e.g. if you create OFPMatch with OFBTCPSrc and then change to OFBTCPDst, # noqa: E501 # index will already be filled with ethertype and nwproto codes, # thus the corresponding fields will not be added to the packet return remain + ret, lst class OXMID(Packet): @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and len(_pkt) >= 2: t = orb(_pkt[2]) return ofp_oxm_id_cls.get(t, Raw) return Raw def extract_padding(self, s): return b"", s class OFPMatch(Packet): name = "OFP_MATCH" fields_desc = [ShortEnumField("type", 1, {0: "OFPMT_STANDARD", 1: "OFPMT_OXM"}), ShortField("len", None), OXMPacketListField("oxm_fields", [], Packet, length_from=lambda pkt:pkt.len - 4)] def post_build(self, p, pay): tmp_len = self.len if tmp_len is None: tmp_len = len(p) + len(pay) p = p[:2] + struct.pack("!H", tmp_len) + p[4:] zero_bytes = (8 - tmp_len % 8) % 8 p += b"\x00" * zero_bytes # message with user-defined length will not be automatically padded return p + pay def extract_padding(self, s): tmp_len = self.len zero_bytes = (8 - tmp_len % 8) % 8 return s[zero_bytes:], s[:zero_bytes] # ofp_match is no longer a fixed-length structure in v1.3 # furthermore it may include variable padding # we introduce to that end a subclass of PacketField class MatchField(PacketField): def __init__(self, name): PacketField.__init__(self, name, OFPMatch(), OFPMatch) def getfield(self, pkt, s): i = self.m2i(pkt, s) # i can be or > # or > or >> # and we want to return "", or "", > # or raw(), or raw(), > if Raw in i: r = i[Raw] if Padding in r: p = r[Padding] i.payload = p del(r.payload) return r.load, i else: return b"", i # Actions # class OpenFlow3(OpenFlow): name = "OpenFlow v1.3 dissector" @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and len(_pkt) >= 2: # port 6653 has been allocated by IANA, port 6633 should no # longer be used # OpenFlow3 function may be called with None self in OFPPacketField of_type = orb(_pkt[1]) if of_type == 1: err_type = orb(_pkt[9]) # err_type is a short int, but last byte is enough if err_type == 255: err_type = 65535 return ofp_error_cls[err_type] elif of_type == 18: mp_type = orb(_pkt[9]) if mp_type == 255: mp_type = 65535 return ofp_multipart_request_cls[mp_type] elif of_type == 19: mp_type = orb(_pkt[9]) if mp_type == 255: mp_type = 65535 return ofp_multipart_reply_cls[mp_type] else: return ofpt_cls[of_type] return _UnknownOpenFlow ofp_action_types = {0: "OFPAT_OUTPUT", 1: "OFPAT_SET_VLAN_VID", 2: "OFPAT_SET_VLAN_PCP", 3: "OFPAT_STRIP_VLAN", 4: "OFPAT_SET_DL_SRC", 5: "OFPAT_SET_DL_DST", 6: "OFPAT_SET_NW_SRC", 7: "OFPAT_SET_NW_DST", 8: "OFPAT_SET_NW_TOS", 9: "OFPAT_SET_TP_SRC", 10: "OFPAT_SET_TP_DST", # 11: "OFPAT_ENQUEUE", 11: "OFPAT_COPY_TTL_OUT", 12: "OFPAT_COPY_TTL_IN", 13: "OFPAT_SET_MPLS_LABEL", 14: "OFPAT_DEC_MPLS_TC", 15: "OFPAT_SET_MPLS_TTL", 16: "OFPAT_DEC_MPLS_TTL", 17: "OFPAT_PUSH_VLAN", 18: "OFPAT_POP_VLAN", 19: "OFPAT_PUSH_MPLS", 20: "OFPAT_POP_MPLS", 21: "OFPAT_SET_QUEUE", 22: "OFPAT_GROUP", 23: "OFPAT_SET_NW_TTL", 24: "OFPAT_DEC_NW_TTL", 25: "OFPAT_SET_FIELD", 26: "OFPAT_PUSH_PBB", 27: "OFPAT_POP_PBB", 65535: "OFPAT_EXPERIMENTER"} class OFPAT(_ofp_header): @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and len(_pkt) >= 2: t = struct.unpack("!H", _pkt[:2])[0] return ofp_action_cls.get(t, Raw) return Raw def extract_padding(self, s): return b"", s class OFPATOutput(OFPAT): name = "OFPAT_OUTPUT" fields_desc = [ShortEnumField("type", 0, ofp_action_types), ShortField("len", 16), IntEnumField("port", 0, ofp_port_no), ShortEnumField("max_len", "NO_BUFFER", ofp_max_len), XBitField("pad", 0, 48)] # the following actions are not supported by OFv1.3 class OFPATSetVLANVID(OFPAT): name = "OFPAT_SET_VLAN_VID" fields_desc = [ShortEnumField("type", 1, ofp_action_types), ShortField("len", 8), ShortField("vlan_vid", 0), XShortField("pad", 0)] class OFPATSetVLANPCP(OFPAT): name = "OFPAT_SET_VLAN_PCP" fields_desc = [ShortEnumField("type", 2, ofp_action_types), ShortField("len", 8), ByteField("vlan_pcp", 0), X3BytesField("pad", 0)] class OFPATStripVLAN(OFPAT): name = "OFPAT_STRIP_VLAN" fields_desc = [ShortEnumField("type", 3, ofp_action_types), ShortField("len", 8), XIntField("pad", 0)] class OFPATSetDlSrc(OFPAT): name = "OFPAT_SET_DL_SRC" fields_desc = [ShortEnumField("type", 4, ofp_action_types), ShortField("len", 16), MACField("dl_addr", "0"), XBitField("pad", 0, 48)] class OFPATSetDlDst(OFPAT): name = "OFPAT_SET_DL_DST" fields_desc = [ShortEnumField("type", 5, ofp_action_types), ShortField("len", 16), MACField("dl_addr", "0"), XBitField("pad", 0, 48)] class OFPATSetNwSrc(OFPAT): name = "OFPAT_SET_NW_SRC" fields_desc = [ShortEnumField("type", 6, ofp_action_types), ShortField("len", 8), IPField("nw_addr", "0")] class OFPATSetNwDst(OFPAT): name = "OFPAT_SET_NW_DST" fields_desc = [ShortEnumField("type", 7, ofp_action_types), ShortField("len", 8), IPField("nw_addr", "0")] class OFPATSetNwToS(OFPAT): name = "OFPAT_SET_TP_TOS" fields_desc = [ShortEnumField("type", 8, ofp_action_types), ShortField("len", 8), ByteField("nw_tos", 0), X3BytesField("pad", 0)] class OFPATSetTpSrc(OFPAT): name = "OFPAT_SET_TP_SRC" fields_desc = [ShortEnumField("type", 9, ofp_action_types), ShortField("len", 8), ShortField("tp_port", 0), XShortField("pad", 0)] class OFPATSetTpDst(OFPAT): name = "OFPAT_SET_TP_DST" fields_desc = [ShortEnumField("type", 10, ofp_action_types), ShortField("len", 8), ShortField("tp_port", 0), XShortField("pad", 0)] # class OFPATEnqueue(OFPAT): # name = "OFPAT_ENQUEUE" # fields_desc = [ ShortEnumField("type", 11, ofp_action_types), # ShortField("len", 16), # ShortField("port", 0), # XBitField("pad", 0, 48), # IntEnumField("queue_id", 0, ofp_queue) ] class OFPATSetMPLSLabel(OFPAT): name = "OFPAT_SET_MPLS_LABEL" fields_desc = [ShortEnumField("type", 13, ofp_action_types), ShortField("len", 8), IntField("mpls_label", 0)] class OFPATSetMPLSTC(OFPAT): name = "OFPAT_SET_MPLS_TC" fields_desc = [ShortEnumField("type", 14, ofp_action_types), ShortField("len", 8), ByteField("mpls_tc", 0), X3BytesField("pad", 0)] # end of unsupported actions class OFPATCopyTTLOut(OFPAT): name = "OFPAT_COPY_TTL_OUT" fields_desc = [ShortEnumField("type", 11, ofp_action_types), ShortField("len", 8), XIntField("pad", 0)] class OFPATCopyTTLIn(OFPAT): name = "OFPAT_COPY_TTL_IN" fields_desc = [ShortEnumField("type", 12, ofp_action_types), ShortField("len", 8), XIntField("pad", 0)] class OFPATSetMPLSTTL(OFPAT): name = "OFPAT_SET_MPLS_TTL" fields_desc = [ShortEnumField("type", 15, ofp_action_types), ShortField("len", 8), ByteField("mpls_ttl", 0), X3BytesField("pad", 0)] class OFPATDecMPLSTTL(OFPAT): name = "OFPAT_DEC_MPLS_TTL" fields_desc = [ShortEnumField("type", 16, ofp_action_types), ShortField("len", 8), XIntField("pad", 0)] class OFPATPushVLAN(OFPAT): name = "OFPAT_PUSH_VLAN" fields_desc = [ShortEnumField("type", 17, ofp_action_types), ShortField("len", 8), ShortField("ethertype", 0x8100), # or 0x88a8 XShortField("pad", 0)] class OFPATPopVLAN(OFPAT): name = "OFPAT_POP_VLAN" fields_desc = [ShortEnumField("type", 18, ofp_action_types), ShortField("len", 8), XIntField("pad", 0)] class OFPATPushMPLS(OFPAT): name = "OFPAT_PUSH_MPLS" fields_desc = [ShortEnumField("type", 19, ofp_action_types), ShortField("len", 8), ShortField("ethertype", 0x8847), # or 0x8848 XShortField("pad", 0)] class OFPATPopMPLS(OFPAT): name = "OFPAT_POP_MPLS" fields_desc = [ShortEnumField("type", 20, ofp_action_types), ShortField("len", 8), ShortField("ethertype", 0x8847), # or 0x8848 XShortField("pad", 0)] class OFPATSetQueue(OFPAT): name = "OFPAT_SET_QUEUE" fields_desc = [ShortEnumField("type", 21, ofp_action_types), ShortField("len", 8), IntEnumField("queue_id", 0, ofp_queue)] class OFPATGroup(OFPAT): name = "OFPAT_GROUP" fields_desc = [ShortEnumField("type", 22, ofp_action_types), ShortField("len", 8), IntEnumField("group_id", 0, ofp_group)] class OFPATSetNwTTL(OFPAT): name = "OFPAT_SET_NW_TTL" fields_desc = [ShortEnumField("type", 23, ofp_action_types), ShortField("len", 8), ByteField("nw_ttl", 0), X3BytesField("pad", 0)] class OFPATDecNwTTL(OFPAT): name = "OFPAT_DEC_NW_TTL" fields_desc = [ShortEnumField("type", 24, ofp_action_types), ShortField("len", 8), XIntField("pad", 0)] class OFPATSetField(OFPAT): name = "OFPAT_SET_FIELD" fields_desc = [ShortEnumField("type", 25, ofp_action_types), ShortField("len", None), # there should not be more than one oxm tlv OXMPacketListField("field", [], Packet, length_from=lambda pkt:pkt.len - 4, # /!\ contains padding! autocomplete=False)] def post_build(self, p, pay): tmp_len = self.len zero_bytes = 0 if tmp_len is None: tmp_len = len(p) + len(pay) zero_bytes = (8 - tmp_len % 8) % 8 tmp_len = tmp_len + zero_bytes # add padding length p = p[:2] + struct.pack("!H", tmp_len) + p[4:] else: zero_bytes = (8 - tmp_len % 8) % 8 # every message will be padded correctly p += b"\x00" * zero_bytes return p + pay def extract_padding(self, s): return b"", s class OFPATPushPBB(OFPAT): name = "OFPAT_PUSH_PBB" fields_desc = [ShortEnumField("type", 26, ofp_action_types), ShortField("len", 8), ShortField("ethertype", 0x88e7), XShortField("pad", 0)] class OFPATPopPBB(OFPAT): name = "OFPAT_POP_PBB" fields_desc = [ShortEnumField("type", 27, ofp_action_types), ShortField("len", 8), XIntField("pad", 0)] class OFPATExperimenter(OFPAT): name = "OFPAT_EXPERIMENTER" fields_desc = [ShortEnumField("type", 65535, ofp_action_types), ShortField("len", 8), IntField("experimenter", 0)] ofp_action_cls = {0: OFPATOutput, 1: OFPATSetVLANVID, 2: OFPATSetVLANPCP, 3: OFPATStripVLAN, 4: OFPATSetDlSrc, 5: OFPATSetDlDst, 6: OFPATSetNwSrc, 7: OFPATSetNwDst, 8: OFPATSetNwToS, 9: OFPATSetTpSrc, 10: OFPATSetTpDst, # 11: OFPATEnqueue, 11: OFPATCopyTTLOut, 12: OFPATCopyTTLIn, 13: OFPATSetMPLSLabel, 14: OFPATSetMPLSTC, 15: OFPATSetMPLSTTL, 16: OFPATDecMPLSTTL, 17: OFPATPushVLAN, 18: OFPATPopVLAN, 19: OFPATPushMPLS, 20: OFPATPopMPLS, 21: OFPATSetQueue, 22: OFPATGroup, 23: OFPATSetNwTTL, 24: OFPATDecNwTTL, 25: OFPATSetField, 26: OFPATPushPBB, 27: OFPATPopPBB, 65535: OFPATExperimenter} # Action IDs # class OFPATID(_ofp_header): @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and len(_pkt) >= 2: t = struct.unpack("!H", _pkt[:2])[0] return ofp_action_id_cls.get(t, Raw) return Raw def extract_padding(self, s): return b"", s # length is computed as in instruction structures, # so we reuse _ofp_header class OFPATOutputID(OFPATID): name = "OFPAT_OUTPUT" fields_desc = [ShortEnumField("type", 0, ofp_action_types), ShortField("len", 4)] # the following actions are not supported by OFv1.3 class OFPATSetVLANVIDID(OFPATID): name = "OFPAT_SET_VLAN_VID" fields_desc = [ShortEnumField("type", 1, ofp_action_types), ShortField("len", 4)] class OFPATSetVLANPCPID(OFPATID): name = "OFPAT_SET_VLAN_PCP" fields_desc = [ShortEnumField("type", 2, ofp_action_types), ShortField("len", 4)] class OFPATStripVLANID(OFPATID): name = "OFPAT_STRIP_VLAN" fields_desc = [ShortEnumField("type", 3, ofp_action_types), ShortField("len", 4)] class OFPATSetDlSrcID(OFPATID): name = "OFPAT_SET_DL_SRC" fields_desc = [ShortEnumField("type", 4, ofp_action_types), ShortField("len", 4)] class OFPATSetDlDstID(OFPATID): name = "OFPAT_SET_DL_DST" fields_desc = [ShortEnumField("type", 5, ofp_action_types), ShortField("len", 4)] class OFPATSetNwSrcID(OFPATID): name = "OFPAT_SET_NW_SRC" fields_desc = [ShortEnumField("type", 6, ofp_action_types), ShortField("len", 4)] class OFPATSetNwDstID(OFPATID): name = "OFPAT_SET_NW_DST" fields_desc = [ShortEnumField("type", 7, ofp_action_types), ShortField("len", 4)] class OFPATSetNwToSID(OFPATID): name = "OFPAT_SET_TP_TOS" fields_desc = [ShortEnumField("type", 8, ofp_action_types), ShortField("len", 4)] class OFPATSetTpSrcID(OFPATID): name = "OFPAT_SET_TP_SRC" fields_desc = [ShortEnumField("type", 9, ofp_action_types), ShortField("len", 4)] class OFPATSetTpDstID(OFPATID): name = "OFPAT_SET_TP_DST" fields_desc = [ShortEnumField("type", 10, ofp_action_types), ShortField("len", 4)] # class OFPATEnqueueID(OFPAT): # name = "OFPAT_ENQUEUE" # fields_desc = [ ShortEnumField("type", 11, ofp_action_types), # ShortField("len", 4) ] class OFPATSetMPLSLabelID(OFPATID): name = "OFPAT_SET_MPLS_LABEL" fields_desc = [ShortEnumField("type", 13, ofp_action_types), ShortField("len", 4)] class OFPATSetMPLSTCID(OFPATID): name = "OFPAT_SET_MPLS_TC" fields_desc = [ShortEnumField("type", 14, ofp_action_types), ShortField("len", 4)] # end of unsupported actions class OFPATCopyTTLOutID(OFPATID): name = "OFPAT_COPY_TTL_OUT" fields_desc = [ShortEnumField("type", 11, ofp_action_types), ShortField("len", 4)] class OFPATCopyTTLInID(OFPATID): name = "OFPAT_COPY_TTL_IN" fields_desc = [ShortEnumField("type", 12, ofp_action_types), ShortField("len", 4)] class OFPATSetMPLSTTLID(OFPATID): name = "OFPAT_SET_MPLS_TTL" fields_desc = [ShortEnumField("type", 15, ofp_action_types), ShortField("len", 4)] class OFPATDecMPLSTTLID(OFPATID): name = "OFPAT_DEC_MPLS_TTL" fields_desc = [ShortEnumField("type", 16, ofp_action_types), ShortField("len", 4)] class OFPATPushVLANID(OFPATID): name = "OFPAT_PUSH_VLAN" fields_desc = [ShortEnumField("type", 17, ofp_action_types), ShortField("len", 4)] class OFPATPopVLANID(OFPATID): name = "OFPAT_POP_VLAN" fields_desc = [ShortEnumField("type", 18, ofp_action_types), ShortField("len", 4)] class OFPATPushMPLSID(OFPATID): name = "OFPAT_PUSH_MPLS" fields_desc = [ShortEnumField("type", 19, ofp_action_types), ShortField("len", 4)] class OFPATPopMPLSID(OFPATID): name = "OFPAT_POP_MPLS" fields_desc = [ShortEnumField("type", 20, ofp_action_types), ShortField("len", 4)] class OFPATSetQueueID(OFPATID): name = "OFPAT_SET_QUEUE" fields_desc = [ShortEnumField("type", 21, ofp_action_types), ShortField("len", 4)] class OFPATGroupID(OFPATID): name = "OFPAT_GROUP" fields_desc = [ShortEnumField("type", 22, ofp_action_types), ShortField("len", 4)] class OFPATSetNwTTLID(OFPATID): name = "OFPAT_SET_NW_TTL" fields_desc = [ShortEnumField("type", 23, ofp_action_types), ShortField("len", 4)] class OFPATDecNwTTLID(OFPATID): name = "OFPAT_DEC_NW_TTL" fields_desc = [ShortEnumField("type", 24, ofp_action_types), ShortField("len", 4)] class OFPATSetFieldID(OFPATID): name = "OFPAT_SET_FIELD" fields_desc = [ShortEnumField("type", 25, ofp_action_types), ShortField("len", 4)] class OFPATPushPBBID(OFPATID): name = "OFPAT_PUSH_PBB" fields_desc = [ShortEnumField("type", 26, ofp_action_types), ShortField("len", 4)] class OFPATPopPBBID(OFPATID): name = "OFPAT_POP_PBB" fields_desc = [ShortEnumField("type", 27, ofp_action_types), ShortField("len", 4)] class OFPATExperimenterID(OFPATID): name = "OFPAT_EXPERIMENTER" fields_desc = [ShortEnumField("type", 65535, ofp_action_types), ShortField("len", None)] ofp_action_id_cls = {0: OFPATOutputID, 1: OFPATSetVLANVIDID, 2: OFPATSetVLANPCPID, 3: OFPATStripVLANID, 4: OFPATSetDlSrcID, 5: OFPATSetDlDstID, 6: OFPATSetNwSrcID, 7: OFPATSetNwDstID, 8: OFPATSetNwToSID, 9: OFPATSetTpSrcID, 10: OFPATSetTpDstID, # 11: OFPATEnqueueID, 11: OFPATCopyTTLOutID, 12: OFPATCopyTTLInID, 13: OFPATSetMPLSLabelID, 14: OFPATSetMPLSTCID, 15: OFPATSetMPLSTTLID, 16: OFPATDecMPLSTTLID, 17: OFPATPushVLANID, 18: OFPATPopVLANID, 19: OFPATPushMPLSID, 20: OFPATPopMPLSID, 21: OFPATSetQueueID, 22: OFPATGroupID, 23: OFPATSetNwTTLID, 24: OFPATDecNwTTLID, 25: OFPATSetFieldID, 26: OFPATPushPBBID, 27: OFPATPopPBBID, 65535: OFPATExperimenterID} # Instructions # ofp_instruction_types = {1: "OFPIT_GOTO_TABLE", 2: "OFPIT_WRITE_METADATA", 3: "OFPIT_WRITE_ACTIONS", 4: "OFPIT_APPLY_ACTIONS", 5: "OFPIT_CLEAR_ACTIONS", 6: "OFPIT_METER", 65535: "OFPIT_EXPERIMENTER"} class OFPIT(_ofp_header): @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and len(_pkt) >= 2: t = struct.unpack("!H", _pkt[:2])[0] return ofp_instruction_cls.get(t, Raw) return Raw def extract_padding(self, s): return b"", s class OFPITGotoTable(OFPIT): name = "OFPIT_GOTO_TABLE" fields_desc = [ShortEnumField("type", 1, ofp_instruction_types), ShortField("len", 8), ByteEnumField("table_id", 0, ofp_table), X3BytesField("pad", 0)] class OFPITWriteMetadata(OFPIT): name = "OFPIT_WRITE_METADATA" fields_desc = [ShortEnumField("type", 2, ofp_instruction_types), ShortField("len", 24), XIntField("pad", 0), LongField("metadata", 0), LongField("metadata_mask", 0)] class OFPITWriteActions(OFPIT): name = "OFPIT_WRITE_ACTIONS" fields_desc = [ShortEnumField("type", 3, ofp_instruction_types), ShortField("len", None), XIntField("pad", 0), PacketListField("actions", [], OFPAT, length_from=lambda pkt:pkt.len - 8)] class OFPITApplyActions(OFPIT): name = "OFPIT_APPLY_ACTIONS" fields_desc = [ShortEnumField("type", 4, ofp_instruction_types), ShortField("len", None), XIntField("pad", 0), PacketListField("actions", [], OFPAT, length_from=lambda pkt:pkt.len - 8)] class OFPITClearActions(OFPIT): name = "OFPIT_CLEAR_ACTIONS" fields_desc = [ShortEnumField("type", 5, ofp_instruction_types), ShortField("len", 8), XIntField("pad", 0)] class OFPITMeter(OFPIT): name = "OFPIT_METER" fields_desc = [ShortEnumField("type", 6, ofp_instruction_types), ShortField("len", 8), IntEnumField("meter_id", 1, ofp_meter)] class OFPITExperimenter(OFPIT): name = "OFPIT_EXPERIMENTER" fields_desc = [ShortEnumField("type", 65535, ofp_instruction_types), ShortField("len", None), IntField("experimenter", 0)] ofp_instruction_cls = {1: OFPITGotoTable, 2: OFPITWriteMetadata, 3: OFPITWriteActions, 4: OFPITApplyActions, 5: OFPITClearActions, 6: OFPITMeter, 65535: OFPITExperimenter} # Instruction IDs # # length is computed as in instruction structures, # so we reuse _ofp_header class OFPITID(_ofp_header): @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and len(_pkt) >= 2: t = struct.unpack("!H", _pkt[:2])[0] return ofp_instruction_id_cls.get(t, Raw) return Raw def extract_padding(self, s): return b"", s class OFPITGotoTableID(OFPITID): name = "OFPIT_GOTO_TABLE" fields_desc = [ShortEnumField("type", 1, ofp_instruction_types), ShortField("len", 4)] class OFPITWriteMetadataID(OFPITID): name = "OFPIT_WRITE_METADATA" fields_desc = [ShortEnumField("type", 2, ofp_instruction_types), ShortField("len", 4)] class OFPITWriteActionsID(OFPITID): name = "OFPIT_WRITE_ACTIONS" fields_desc = [ShortEnumField("type", 3, ofp_instruction_types), ShortField("len", 4)] class OFPITApplyActionsID(OFPITID): name = "OFPIT_APPLY_ACTIONS" fields_desc = [ShortEnumField("type", 4, ofp_instruction_types), ShortField("len", 4)] class OFPITClearActionsID(OFPITID): name = "OFPIT_CLEAR_ACTIONS" fields_desc = [ShortEnumField("type", 5, ofp_instruction_types), ShortField("len", 4)] class OFPITMeterID(OFPITID): name = "OFPIT_METER" fields_desc = [ShortEnumField("type", 6, ofp_instruction_types), ShortField("len", 4)] class OFPITExperimenterID(OFPITID): name = "OFPIT_EXPERIMENTER" fields_desc = [ShortEnumField("type", 65535, ofp_instruction_types), ShortField("len", None)] ofp_instruction_id_cls = {1: OFPITGotoTableID, 2: OFPITWriteMetadataID, 3: OFPITWriteActionsID, 4: OFPITApplyActionsID, 5: OFPITClearActionsID, 6: OFPITMeterID, 65535: OFPITExperimenterID} # Buckets # class OFPBucket(_ofp_header_item): name = "OFP_BUCKET" fields_desc = [ShortField("len", None), ShortField("weight", 0), IntEnumField("watch_port", 0, ofp_port_no), IntEnumField("watch_group", 0, ofp_group), XIntField("pad", 0), PacketListField("actions", [], OFPAT, length_from=lambda pkt:pkt.len - 16)] def extract_padding(self, s): return b"", s # Queues # ofp_queue_property_types = {0: "OFPQT_NONE", 1: "OFPQT_MIN_RATE"} class OFPQT(_ofp_header): @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and len(_pkt) >= 2: t = struct.unpack("!H", _pkt[:2])[0] return ofp_queue_property_cls.get(t, Raw) return Raw def extract_padding(self, s): return b"", s class OFPQTNone(OFPQT): name = "OFPQT_NONE" fields_desc = [ShortEnumField("type", 0, ofp_queue_property_types), ShortField("len", 8), XIntField("pad", 0)] class OFPQTMinRate(OFPQT): name = "OFPQT_MIN_RATE" fields_desc = [ShortEnumField("type", 1, ofp_queue_property_types), ShortField("len", 16), XIntField("pad1", 0), ShortField("rate", 0), XBitField("pad2", 0, 48)] ofp_queue_property_cls = {0: OFPQTNone, 1: OFPQTMinRate} class OFPPacketQueue(Packet): name = "OFP_PACKET_QUEUE" fields_desc = [IntEnumField("queue_id", 0, ofp_queue), ShortField("len", None), XShortField("pad", 0), PacketListField("properties", [], OFPQT, length_from=lambda pkt:pkt.len - 8)] # noqa: E501 def extract_padding(self, s): return b"", s def post_build(self, p, pay): if self.properties == []: p += raw(OFPQTNone()) if self.len is None: tmp_len = len(p) + len(pay) p = p[:4] + struct.pack("!H", tmp_len) + p[6:] return p + pay # Meter bands # ofp_meter_band_types = {0: "OFPMBT_DROP", 1: "OFPMBT_DSCP_REMARK", 65535: "OFPMBT_EXPERIMENTER"} class OFPMBT(_ofp_header): @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and len(_pkt) >= 2: t = struct.unpack("!H", _pkt[:2])[0] return ofp_meter_band_cls.get(t, Raw) return Raw def extract_padding(self, s): return b"", s class OFPMBTDrop(OFPMBT): name = "OFPMBT_DROP" fields_desc = [ShortEnumField("type", 0, ofp_queue_property_types), ShortField("len", 16), IntField("rate", 0), IntField("burst_size", 0), XIntField("pad", 0)] class OFPMBTDSCPRemark(OFPMBT): name = "OFPMBT_DSCP_REMARK" fields_desc = [ShortEnumField("type", 1, ofp_queue_property_types), ShortField("len", 16), IntField("rate", 0), IntField("burst_size", 0), ByteField("prec_level", 0), X3BytesField("pad", 0)] class OFPMBTExperimenter(OFPMBT): name = "OFPMBT_EXPERIMENTER" fields_desc = [ShortEnumField("type", 65535, ofp_queue_property_types), ShortField("len", 16), IntField("rate", 0), IntField("burst_size", 0), IntField("experimenter", 0)] ofp_meter_band_cls = {0: OFPMBTDrop, 1: OFPMBTDSCPRemark, 2: OFPMBTExperimenter} ##################################################### # OpenFlow 1.3 Messages # ##################################################### ofp_version = {0x01: "OpenFlow 1.0", 0x02: "OpenFlow 1.1", 0x03: "OpenFlow 1.2", 0x04: "OpenFlow 1.3", 0x05: "OpenFlow 1.4"} ofp_type = {0: "OFPT_HELLO", 1: "OFPT_ERROR", 2: "OFPT_ECHO_REQUEST", 3: "OFPT_ECHO_REPLY", 4: "OFPT_EXPERIMENTER", 5: "OFPT_FEATURES_REQUEST", 6: "OFPT_FEATURES_REPLY", 7: "OFPT_GET_CONFIG_REQUEST", 8: "OFPT_GET_CONFIG_REPLY", 9: "OFPT_SET_CONFIG", 10: "OFPT_PACKET_IN", 11: "OFPT_FLOW_REMOVED", 12: "OFPT_PORT_STATUS", 13: "OFPT_PACKET_OUT", 14: "OFPT_FLOW_MOD", 15: "OFPT_GROUP_MOD", 16: "OFPT_PORT_MOD", 17: "OFPT_TABLE_MOD", 18: "OFPT_MULTIPART_REQUEST", 19: "OFPT_MULTIPART_REPLY", 20: "OFPT_BARRIER_REQUEST", 21: "OFPT_BARRIER_REPLY", 22: "OFPT_QUEUE_GET_CONFIG_REQUEST", 23: "OFPT_QUEUE_GET_CONFIG_REPLY", 24: "OFPT_ROLE_REQUEST", 25: "OFPT_ROLE_REPLY", 26: "OFPT_GET_ASYNC_REQUEST", 27: "OFPT_GET_ASYNC_REPLY", 28: "OFPT_SET_ASYNC", 29: "OFPT_METER_MOD"} class OFPTHello(_ofp_header): name = "OFPT_HELLO" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 0, ofp_type), ShortField("len", None), IntField("xid", 0), PacketListField("elements", [], OFPHET, length_from=lambda pkt: pkt.len - 8)] ##################################################### # OFPT_ERROR # ##################################################### ofp_error_type = {0: "OFPET_HELLO_FAILED", 1: "OFPET_BAD_REQUEST", 2: "OFPET_BAD_ACTION", 3: "OFPET_BAD_INSTRUCTION", 4: "OFPET_BAD_MATCH", 5: "OFPET_FLOW_MOD_FAILED", 6: "OFPET_GROUP_MOD_FAILED", 7: "OFPET_PORT_MOD_FAILED", 8: "OFPET_TABLE_MOD_FAILED", 9: "OFPET_QUEUE_OP_FAILED", 10: "OFPET_SWITCH_CONFIG_FAILED", 11: "OFPET_ROLE_REQUEST_FAILED", 12: "OFPET_METER_MOD_FAILED", 13: "OFPET_TABLE_FEATURES_FAILED", 65535: "OFPET_EXPERIMENTER"} class OFPETHelloFailed(_ofp_header): name = "OFPET_HELLO_FAILED" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 1, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("errtype", 0, ofp_error_type), ShortEnumField("errcode", 0, {0: "OFPHFC_INCOMPATIBLE", 1: "OFPHFC_EPERM"}), OFPacketField("data", "", Raw)] class OFPETBadRequest(_ofp_header): name = "OFPET_BAD_REQUEST" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 1, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("errtype", 1, ofp_error_type), ShortEnumField("errcode", 0, {0: "OFPBRC_BAD_VERSION", 1: "OFPBRC_BAD_TYPE", 2: "OFPBRC_BAD_MULTIPART", 3: "OFPBRC_BAD_EXPERIMENTER", 4: "OFPBRC_BAD_EXP_TYPE", 5: "OFPBRC_EPERM", 6: "OFPBRC_BAD_LEN", 7: "OFPBRC_BUFFER_EMPTY", 8: "OFPBRC_BUFFER_UNKNOWN", 9: "OFPBRC_BAD_TABLE_ID", 10: "OFPBRC_IS_SLAVE", 11: "OFPBRC_BAD_PORT", 12: "OFPBRC_BAD_PACKET", 13: "OFPBRC_MULTIPART_BUFFER_OVERFLOW"}), # noqa: E501 OFPacketField("data", "", Raw)] class OFPETBadAction(_ofp_header): name = "OFPET_BAD_ACTION" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 1, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("errtype", 2, ofp_error_type), ShortEnumField("errcode", 0, {0: "OFPBAC_BAD_TYPE", 1: "OFPBAC_BAD_LEN", 2: "OFPBAC_BAD_EXPERIMENTER", 3: "OFPBAC_BAD_EXP_TYPE", 4: "OFPBAC_BAD_OUT_PORT", 5: "OFPBAC_BAD_ARGUMENT", 6: "OFPBAC_EPERM", 7: "OFPBAC_TOO_MANY", 8: "OFPBAC_BAD_QUEUE", 9: "OFPBAC_BAD_OUT_GROUP", 10: "OFPBAC_MATCH_INCONSISTENT", # noqa: E501 11: "OFPBAC_UNSUPPORTED_ORDER", # noqa: E501 12: "OFPBAC_BAD_TAG", 13: "OFPBAC_BAD_SET_TYPE", 14: "OFPBAC_BAD_SET_LEN", 15: "OFPBAC_BAD_SET_ARGUMENT"}), # noqa: E501 OFPacketField("data", "", Raw)] class OFPETBadInstruction(_ofp_header): name = "OFPET_BAD_INSTRUCTION" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 1, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("errtype", 3, ofp_error_type), ShortEnumField("errcode", 0, {0: "OFPBIC_UNKNOWN_INST", 1: "OFPBIC_UNSUP_INST", 2: "OFPBIC_BAD_TABLE_ID", 3: "OFPBIC_UNSUP_METADATA", 4: "OFPBIC_UNSUP_METADATA_MASK", # noqa: E501 5: "OFPBIC_BAD_EXPERIMENTER", 6: "OFPBIC_BAD_EXP_TYPE", 7: "OFPBIC_BAD_LEN", 8: "OFPBIC_EPERM"}), OFPacketField("data", "", Raw)] class OFPETBadMatch(_ofp_header): name = "OFPET_BAD_MATCH" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 1, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("errtype", 4, ofp_error_type), ShortEnumField("errcode", 0, {0: "OFPBMC_BAD_TYPE", 1: "OFPBMC_BAD_LEN", 2: "OFPBMC_BAD_TAG", 3: "OFPBMC_BAD_DL_ADDR_MASK", 4: "OFPBMC_BAD_NW_ADDR_MASK", 5: "OFPBMC_BAD_WILDCARDS", 6: "OFPBMC_BAD_FIELD", 7: "OFPBMC_BAD_VALUE", 8: "OFPBMC_BAD_MASK", 9: "OFPBMC_BAD_PREREQ", 10: "OFPBMC_DUP_FIELD", 11: "OFPBMC_EPERM"}), OFPacketField("data", "", Raw)] class OFPETFlowModFailed(_ofp_header): name = "OFPET_FLOW_MOD_FAILED" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 1, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("errtype", 5, ofp_error_type), ShortEnumField("errcode", 0, {0: "OFPFMFC_UNKNOWN", 1: "OFPFMFC_TABLE_FULL", 2: "OFPFMFC_BAD_TABLE_ID", 3: "OFPFMFC_OVERLAP", 4: "OFPFMFC_EPERM", 5: "OFPFMFC_BAD_TIMEOUT", 6: "OFPFMFC_BAD_COMMAND", 7: "OFPFMFC_BAD_FLAGS"}), OFPacketField("data", "", Raw)] class OFPETGroupModFailed(_ofp_header): name = "OFPET_GROUP_MOD_FAILED" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 1, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("errtype", 6, ofp_error_type), ShortEnumField("errcode", 0, {0: "OFPGMFC_GROUP_EXISTS", 1: "OFPGMFC_INVALID_GROUP", 2: "OFPGMFC_WEIGHT_UNSUPPORTED", # noqa: E501 3: "OFPGMFC_OUT_OF_GROUPS", 4: "OFPGMFC_OUT_OF_BUCKETS", 5: "OFPGMFC_CHAINING_UNSUPPORTED", # noqa: E501 6: "OFPGMFC_WATCH_UNSUPPORTED", # noqa: E501 7: "OFPGMFC_LOOP", 8: "OFPGMFC_UNKNOWN_GROUP", 9: "OFPGMFC_CHAINED_GROUP", 10: "OFPGMFC_BAD_TYPE", 11: "OFPGMFC_BAD_COMMAND", 12: "OFPGMFC_BAD_BUCKET", 13: "OFPGMFC_BAD_WATCH", 14: "OFPFMFC_EPERM"}), OFPacketField("data", "", Raw)] class OFPETPortModFailed(_ofp_header): name = "OFPET_PORT_MOD_FAILED" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 1, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("errtype", 7, ofp_error_type), ShortEnumField("errcode", 0, {0: "OFPPMFC_BAD_PORT", 1: "OFPPMFC_BAD_HW_ADDR", 2: "OFPPMFC_BAD_CONFIG", 3: "OFPPMFC_BAD_ADVERTISE", 4: "OFPPMFC_EPERM"}), OFPacketField("data", "", Raw)] class OFPETTableModFailed(_ofp_header): name = "OFPET_TABLE_MOD_FAILED" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 1, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("errtype", 8, ofp_error_type), ShortEnumField("errcode", 0, {0: "OFPTMFC_BAD_TABLE", 1: "OFPTMFC_BAD_CONFIG", 2: "OFPTMFC_EPERM"}), OFPacketField("data", "", Raw)] class OFPETQueueOpFailed(_ofp_header): name = "OFPET_QUEUE_OP_FAILED" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 1, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("errtype", 9, ofp_error_type), ShortEnumField("errcode", 0, {0: "OFPQOFC_BAD_PORT", 1: "OFPQOFC_BAD_QUEUE", 2: "OFPQOFC_EPERM"}), OFPacketField("data", "", Raw)] class OFPETSwitchConfigFailed(_ofp_header): name = "OFPET_SWITCH_CONFIG_FAILED" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 1, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("errtype", 10, ofp_error_type), ShortEnumField("errcode", 0, {0: "OFPSCFC_BAD_FLAGS", 1: "OFPSCFC_BAD_LEN", 2: "OFPSCFC_EPERM"}), OFPacketField("data", "", Raw)] class OFPETRoleRequestFailed(_ofp_header): name = "OFPET_ROLE_REQUEST_FAILED" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 1, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("errtype", 11, ofp_error_type), ShortEnumField("errcode", 0, {0: "OFPRRFC_STALE", 1: "OFPRRFC_UNSUP", 2: "OFPRRFC_BAD_ROLE"}), OFPacketField("data", "", Raw)] class OFPETMeterModFailed(_ofp_header): name = "OFPET_METER_MOD_FAILED" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 1, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("errtype", 12, ofp_error_type), ShortEnumField("errcode", 0, {0: "OFPMMFC_UNKNOWN", 1: "OFPMMFC_METER_EXISTS", 2: "OFPMMFC_INVALID_METER", 3: "OFPMMFC_UNKNOWN_METER", 4: "OFPMMFC_BAD_COMMAND", 5: "OFPMMFC_BAD_FLAGS", 6: "OFPMMFC_BAD_RATE", 7: "OFPMMFC_BAD_BURST", 8: "OFPMMFC_BAD_BAND", 9: "OFPMMFC_BAD_BAND_VALUE", 10: "OFPMMFC_OUT_OF_METERS", 11: "OFPMMFC_OUT_OF_BANDS"}), OFPacketField("data", "", Raw)] class OFPETTableFeaturesFailed(_ofp_header): name = "OFPET_TABLE_FEATURES_FAILED" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 1, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("errtype", 13, ofp_error_type), ShortEnumField("errcode", 0, {0: "OFPTFFC_BAD_TABLE", 1: "OFPTFFC_BAD_METADATA", 2: "OFPTFFC_BAD_TYPE", 3: "OFPTFFC_BAD_LEN", 4: "OFPTFFC_BAD_ARGUMENT", 5: "OFPTFFC_EPERM"}), OFPacketField("data", "", Raw)] class OFPETExperimenter(_ofp_header): name = "OFPET_EXPERIMENTER" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 1, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("errtype", "OFPET_EXPERIMENTER", ofp_error_type), # noqa: E501 ShortField("exp_type", None), IntField("experimenter", None), OFPacketField("data", "", Raw)] # ofp_error_cls allows generic method OpenFlow3() # to choose the right class for dissection ofp_error_cls = {0: OFPETHelloFailed, 1: OFPETBadRequest, 2: OFPETBadAction, 3: OFPETBadInstruction, 4: OFPETBadMatch, 5: OFPETFlowModFailed, 6: OFPETGroupModFailed, 7: OFPETPortModFailed, 8: OFPETTableModFailed, 9: OFPETQueueOpFailed, 10: OFPETSwitchConfigFailed, 11: OFPETRoleRequestFailed, 12: OFPETMeterModFailed, 13: OFPETTableFeaturesFailed, 65535: OFPETExperimenter} # end of OFPT_ERRORS # class OFPTEchoRequest(_ofp_header): name = "OFPT_ECHO_REQUEST" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 2, ofp_type), ShortField("len", None), IntField("xid", 0)] class OFPTEchoReply(_ofp_header): name = "OFPT_ECHO_REPLY" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 3, ofp_type), ShortField("len", None), IntField("xid", 0)] class OFPTExperimenter(_ofp_header): name = "OFPT_EXPERIMENTER" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 4, ofp_type), ShortField("len", None), IntField("xid", 0), IntField("experimenter", 0), IntField("exp_type", 0)] class OFPTFeaturesRequest(_ofp_header): name = "OFPT_FEATURES_REQUEST" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 5, ofp_type), ShortField("len", None), IntField("xid", 0)] class OFPTFeaturesReply(_ofp_header): name = "OFPT_FEATURES_REPLY" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 6, ofp_type), ShortField("len", None), IntField("xid", 0), LongField("datapath_id", 0), IntField("n_buffers", 0), ByteField("n_tables", 1), ByteField("auxiliary_id", 0), XShortField("pad", 0), FlagsField("capabilities", 0, 32, ["FLOW_STATS", "TABLE_STATS", "PORT_STATS", "GROUP_STATS", "RESERVED", # undefined "IP_REASM", "QUEUE_STATS", "ARP_MATCH_IP", # undefined # noqa: E501 "PORT_BLOCKED"]), IntField("reserved", 0)] class OFPTGetConfigRequest(_ofp_header): name = "OFPT_GET_CONFIG_REQUEST" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 7, ofp_type), ShortField("len", None), IntField("xid", 0)] class OFPTGetConfigReply(_ofp_header): name = "OFPT_GET_CONFIG_REPLY" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 8, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("flags", 0, {0: "FRAG_NORMAL", 1: "FRAG_DROP", 2: "FRAG_REASM", 3: "FRAG_MASK"}), ShortField("miss_send_len", 0)] class OFPTSetConfig(_ofp_header): name = "OFPT_SET_CONFIG" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 9, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("flags", 0, {0: "FRAG_NORMAL", 1: "FRAG_DROP", 2: "FRAG_REASM", 3: "FRAG_MASK"}), ShortField("miss_send_len", 128)] class OFPTPacketIn(_ofp_header): name = "OFPT_PACKET_IN" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 10, ofp_type), ShortField("len", None), IntField("xid", 0), IntEnumField("buffer_id", "NO_BUFFER", ofp_buffer), ShortField("total_len", 0), ByteEnumField("reason", 0, {0: "OFPR_NO_MATCH", 1: "OFPR_ACTION", 2: "OFPR_INVALID_TTL"}), ByteEnumField("table_id", 0, ofp_table), LongField("cookie", 0), MatchField("match"), XShortField("pad", 0), PacketField("data", "", Ether)] class OFPTFlowRemoved(_ofp_header): name = "OFPT_FLOW_REMOVED" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 11, ofp_type), ShortField("len", None), IntField("xid", 0), LongField("cookie", 0), ShortField("priority", 0), ByteEnumField("reason", 0, {0: "OFPRR_IDLE_TIMEOUT", 1: "OFPRR_HARD_TIMEOUT", 2: "OFPRR_DELETE", 3: "OFPRR_GROUP_DELETE"}), ByteEnumField("table_id", 0, ofp_table), IntField("duration_sec", 0), IntField("duration_nsec", 0), ShortField("idle_timeout", 0), ShortField("hard_timeout", 0), LongField("packet_count", 0), LongField("byte_count", 0), MatchField("match")] class OFPTPortStatus(_ofp_header): name = "OFPT_PORT_STATUS" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 12, ofp_type), ShortField("len", None), IntField("xid", 0), ByteEnumField("reason", 0, {0: "OFPPR_ADD", 1: "OFPPR_DELETE", 2: "OFPPR_MODIFY"}), XBitField("pad", 0, 56), PacketField("desc", OFPPort(), OFPPort)] class OFPTPacketOut(_ofp_header): name = "OFPT_PACKET_OUT" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 13, ofp_type), ShortField("len", None), IntField("xid", 0), IntEnumField("buffer_id", "NO_BUFFER", ofp_buffer), IntEnumField("in_port", "CONTROLLER", ofp_port_no), FieldLenField("actions_len", None, fmt="H", length_of="actions"), # noqa: E501 XBitField("pad", 0, 48), PacketListField("actions", [], OFPAT, OFPAT, length_from=lambda pkt:pkt.actions_len), PacketField("data", "", Ether)] class OFPTFlowMod(_ofp_header): name = "OFPT_FLOW_MOD" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 14, ofp_type), ShortField("len", None), IntField("xid", 0), LongField("cookie", 0), LongField("cookie_mask", 0), ByteEnumField("table_id", 0, ofp_table), ByteEnumField("cmd", 0, {0: "OFPFC_ADD", 1: "OFPFC_MODIFY", 2: "OFPFC_MODIFY_STRICT", 3: "OFPFC_DELETE", 4: "OFPFC_DELETE_STRICT"}), ShortField("idle_timeout", 0), ShortField("hard_timeout", 0), ShortField("priority", 0), IntEnumField("buffer_id", "NO_BUFFER", ofp_buffer), IntEnumField("out_port", "ANY", ofp_port_no), IntEnumField("out_group", "ANY", ofp_group), FlagsField("flags", 0, 16, ["SEND_FLOW_REM", "CHECK_OVERLAP", "RESET_COUNTS", "NO_PKT_COUNTS", "NO_BYT_COUNTS"]), XShortField("pad", 0), MatchField("match"), PacketListField("instructions", [], OFPIT, length_from=lambda pkt:pkt.len - 48 - (pkt.match.len + (8 - pkt.match.len % 8) % 8))] # noqa: E501 # include match padding to match.len class OFPTGroupMod(_ofp_header): name = "OFPT_GROUP_MOD" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 15, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("cmd", 0, {0: "OFPGC_ADD", 1: "OFPGC_MODIFY", 2: "OFPGC_DELETE"}), ByteEnumField("group_type", 0, {0: "OFPGT_ALL", 1: "OFPGT_SELECT", 2: "OFPGT_INDIRECT", 3: "OFPGT_FF"}), XByteField("pad", 0), IntEnumField("group_id", 0, ofp_group), PacketListField("buckets", [], OFPBucket, length_from=lambda pkt:pkt.len - 16)] class OFPTPortMod(_ofp_header): name = "OFPT_PORT_MOD" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 16, ofp_type), ShortField("len", None), IntField("xid", 0), IntEnumField("port_no", 0, ofp_port_no), XIntField("pad1", 0), MACField("hw_addr", "0"), XShortField("pad2", 0), FlagsField("config", 0, 32, ofp_port_config), FlagsField("mask", 0, 32, ofp_port_config), FlagsField("advertise", 0, 32, ofp_port_features), XIntField("pad3", 0)] class OFPTTableMod(_ofp_header): name = "OFPT_TABLE_MOD" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 17, ofp_type), ShortField("len", None), IntField("xid", 0), ByteEnumField("table_id", 0, ofp_table), X3BytesField("pad", 0), IntEnumField("config", 0, {3: "OFPTC_DEPRECATED_MASK"})] ##################################################### # OFPT_MULTIPART # ##################################################### ofp_multipart_types = {0: "OFPMP_DESC", 1: "OFPMP_FLOW", 2: "OFPMP_AGGREGATE", 3: "OFPMP_TABLE", 4: "OFPMP_PORT_STATS", 5: "OFPMP_QUEUE", 6: "OFPMP_GROUP", 7: "OFPMP_GROUP_DESC", 8: "OFPMP_GROUP_FEATURES", 9: "OFPMP_METER", 10: "OFPMP_METER_CONFIG", 11: "OFPMP_METER_FEATURES", 12: "OFPMP_TABLE_FEATURES", 13: "OFPMP_PORT_DESC", 65535: "OFPST_VENDOR"} ofpmp_request_flags = ["REQ_MORE"] ofpmp_reply_flags = ["REPLY_MORE"] class OFPMPRequestDesc(_ofp_header): name = "OFPMP_REQUEST_DESC" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 18, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 0, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_request_flags), XIntField("pad", 0)] class OFPMPReplyDesc(_ofp_header): name = "OFPMP_REPLY_DESC" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 19, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 0, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_reply_flags), XIntField("pad", 0), StrFixedLenField("mfr_desc", "", 256), StrFixedLenField("hw_desc", "", 256), StrFixedLenField("sw_desc", "", 256), StrFixedLenField("serial_num", "", 32), StrFixedLenField("dp_desc", "", 256)] class OFPMPRequestFlow(_ofp_header): name = "OFPMP_REQUEST_FLOW" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 18, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 1, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_request_flags), XIntField("pad1", 0), ByteEnumField("table_id", "ALL", ofp_table), X3BytesField("pad2", 0), IntEnumField("out_port", "ANY", ofp_port_no), IntEnumField("out_group", "ANY", ofp_group), IntField("pad3", 0), LongField("cookie", 0), LongField("cookie_mask", 0), MatchField("match")] class OFPFlowStats(_ofp_header_item): name = "OFP_FLOW_STATS" fields_desc = [ShortField("len", None), ByteEnumField("table_id", 0, ofp_table), XByteField("pad1", 0), IntField("duration_sec", 0), IntField("duration_nsec", 0), ShortField("priority", 0), ShortField("idle_timeout", 0), ShortField("hard_timeout", 0), FlagsField("flags", 0, 16, ["SEND_FLOW_REM", "CHECK_OVERLAP", "RESET_COUNTS", "NO_PKT_COUNTS", "NO_BYT_COUNTS"]), IntField("pad2", 0), LongField("cookie", 0), LongField("packet_count", 0), LongField("byte_count", 0), MatchField("match"), PacketListField("instructions", [], OFPIT, length_from=lambda pkt:pkt.len - 56 - pkt.match.len)] # noqa: E501 def extract_padding(self, s): return b"", s class OFPMPReplyFlow(_ofp_header): name = "OFPMP_REPLY_FLOW" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 19, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 1, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_reply_flags), XIntField("pad1", 0), PacketListField("flow_stats", [], OFPFlowStats, length_from=lambda pkt:pkt.len - 16)] class OFPMPRequestAggregate(OFPMPRequestFlow): name = "OFPMP_REQUEST_AGGREGATE" mp_type = 2 class OFPMPReplyAggregate(_ofp_header): name = "OFPMP_REPLY_AGGREGATE" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 19, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 2, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_reply_flags), XIntField("pad1", 0), LongField("packet_count", 0), LongField("byte_count", 0), IntField("flow_count", 0), XIntField("pad2", 0)] class OFPMPRequestTable(_ofp_header): name = "OFPMP_REQUEST_TABLE" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 18, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 3, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_request_flags), XIntField("pad1", 0)] class OFPTableStats(Packet): name = "OFP_TABLE_STATS" fields_desc = [ByteEnumField("table_id", 0, ofp_table), X3BytesField("pad1", 0), IntField("active_count", 0), LongField("lookup_count", 0), LongField("matched_count", 0)] def extract_padding(self, s): return b"", s class OFPMPReplyTable(_ofp_header): name = "OFPMP_REPLY_TABLE" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 19, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 3, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_reply_flags), XIntField("pad1", 0), PacketListField("table_stats", None, OFPTableStats, length_from=lambda pkt:pkt.len - 16)] class OFPMPRequestPortStats(_ofp_header): name = "OFPMP_REQUEST_PORT_STATS" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 18, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 4, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_request_flags), XIntField("pad1", 0), IntEnumField("port_no", "ANY", ofp_port_no), XIntField("pad", 0)] class OFPPortStats(Packet): def extract_padding(self, s): return b"", s name = "OFP_PORT_STATS" fields_desc = [IntEnumField("port_no", 0, ofp_port_no), XIntField("pad", 0), LongField("rx_packets", 0), LongField("tx_packets", 0), LongField("rx_bytes", 0), LongField("tx_bytes", 0), LongField("rx_dropped", 0), LongField("tx_dropped", 0), LongField("rx_errors", 0), LongField("tx_errors", 0), LongField("rx_frame_err", 0), LongField("rx_over_err", 0), LongField("rx_crc_err", 0), LongField("collisions", 0), IntField("duration_sec", 0), IntField("duration_nsec", 0)] class OFPMPReplyPortStats(_ofp_header): name = "OFPMP_REPLY_PORT_STATS" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 19, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 4, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_reply_flags), XIntField("pad1", 0), PacketListField("port_stats", None, OFPPortStats, length_from=lambda pkt:pkt.len - 16)] class OFPMPRequestQueue(_ofp_header): name = "OFPMP_REQUEST_QUEUE" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 18, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 5, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_request_flags), XIntField("pad1", 0), IntEnumField("port_no", "ANY", ofp_port_no), IntEnumField("queue_id", "ALL", ofp_queue)] class OFPQueueStats(Packet): name = "OFP_QUEUE_STATS" fields_desc = [IntEnumField("port_no", 0, ofp_port_no), IntEnumField("queue_id", 0, ofp_queue), LongField("tx_bytes", 0), LongField("tx_packets", 0), LongField("tx_errors", 0), IntField("duration_sec", 0), IntField("duration_nsec", 0)] def extract_padding(self, s): return b"", s class OFPMPReplyQueue(_ofp_header): name = "OFPMP_REPLY_QUEUE" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 19, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 5, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_reply_flags), XIntField("pad1", 0), PacketListField("queue_stats", None, OFPQueueStats, length_from=lambda pkt:pkt.len - 16)] class OFPMPRequestGroup(_ofp_header): name = "OFPMP_REQUEST_GROUP" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 18, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 6, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_request_flags), XIntField("pad1", 0), IntEnumField("group_id", "ANY", ofp_group), XIntField("pad2", 0)] class OFPBucketStats(Packet): name = "OFP_BUCKET_STATS" fields_desc = [LongField("packet_count", 0), LongField("byte_count", 0)] def extract_padding(self, s): return b"", s class OFPGroupStats(_ofp_header_item): name = "OFP_GROUP_STATS" fields_desc = [ShortField("len", None), XShortField("pad1", 0), IntEnumField("group_id", 0, ofp_group), IntField("ref_count", 0), IntField("pad2", 0), LongField("packet_count", 0), LongField("byte_count", 0), IntField("duration_sec", 0), IntField("duration_nsec", 0), PacketListField("bucket_stats", None, OFPBucketStats, length_from=lambda pkt:pkt.len - 40)] def extract_padding(self, s): return b"", s class OFPMPReplyGroup(_ofp_header): name = "OFPMP_REPLY_GROUP" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 19, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 6, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_reply_flags), XIntField("pad1", 0), PacketListField("group_stats", [], OFPGroupStats, length_from=lambda pkt:pkt.len - 16)] class OFPMPRequestGroupDesc(_ofp_header): name = "OFPMP_REQUEST_GROUP_DESC" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 18, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 7, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_request_flags), XIntField("pad1", 0)] class OFPGroupDesc(_ofp_header_item): name = "OFP_GROUP_DESC" fields_desc = [ShortField("len", None), ByteEnumField("type", 0, {0: "OFPGT_ALL", 1: "OFPGT_SELECT", 2: "OFPGT_INDIRECT", 3: "OFPGT_FF"}), XByteField("pad", 0), IntEnumField("group_id", 0, ofp_group), PacketListField("buckets", None, OFPBucket, length_from=lambda pkt: pkt.len - 8)] def extract_padding(self, s): return b"", s class OFPMPReplyGroupDesc(_ofp_header): name = "OFPMP_REPLY_GROUP_DESC" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 19, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 7, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_reply_flags), XIntField("pad1", 0), PacketListField("group_descs", [], OFPGroupDesc, length_from=lambda pkt:pkt.len - 16)] class OFPMPRequestGroupFeatures(_ofp_header): name = "OFPMP_REQUEST_GROUP_FEATURES" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 18, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 8, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_request_flags), XIntField("pad1", 0)] ofp_action_types_flags = [v for v in six.itervalues(ofp_action_types) if v != 'OFPAT_EXPERIMENTER'] class OFPMPReplyGroupFeatures(_ofp_header): name = "OFPMP_REPLY_GROUP_FEATURES" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 19, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 8, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_reply_flags), XIntField("pad1", 0), FlagsField("types", 0, 32, ["ALL", "SELECT", "INDIRECT", "FF"]), FlagsField("capabilities", 0, 32, ["SELECT_WEIGHT", "SELECT_LIVENESS", "CHAINING", "CHAINING_CHECKS"]), IntField("max_group_all", 0), IntField("max_group_select", 0), IntField("max_group_indirect", 0), IntField("max_group_ff", 0), # no ofpat_experimenter flag FlagsField("actions_all", 0, 32, ofp_action_types_flags), FlagsField("actions_select", 0, 32, ofp_action_types_flags), FlagsField("actions_indirect", 0, 32, ofp_action_types_flags), # noqa: E501 FlagsField("actions_ff", 0, 32, ofp_action_types_flags)] class OFPMPRequestMeter(_ofp_header): name = "OFPMP_REQUEST_METER" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 18, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 9, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_request_flags), XIntField("pad1", 0), IntEnumField("meter_id", "ALL", ofp_meter), XIntField("pad2", 0)] class OFPMeterBandStats(Packet): name = "OFP_METER_BAND_STATS" fields_desc = [LongField("packet_band_count", 0), LongField("byte_band_count", 0)] def extract_padding(self, s): return b"", s class OFPMeterStats(Packet): name = "OFP_GROUP_STATS" fields_desc = [IntEnumField("meter_id", 1, ofp_meter), ShortField("len", None), XBitField("pad", 0, 48), IntField("flow_count", 0), LongField("packet_in_count", 0), LongField("byte_in_count", 0), IntField("duration_sec", 0), IntField("duration_nsec", 0), PacketListField("band_stats", None, OFPMeterBandStats, length_from=lambda pkt:pkt.len - 40)] def post_build(self, p, pay): if self.len is None: tmp_len = len(p) + len(pay) p = p[:4] + struct.pack("!H", tmp_len) + p[6:] return p + pay def extract_padding(self, s): return b"", s class OFPMPReplyMeter(_ofp_header): name = "OFPMP_REPLY_METER" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 19, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 9, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_reply_flags), XIntField("pad1", 0), PacketListField("meter_stats", [], OFPMeterStats, length_from=lambda pkt:pkt.len - 16)] class OFPMPRequestMeterConfig(_ofp_header): name = "OFPMP_REQUEST_METER_CONFIG" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 18, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 10, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_request_flags), XIntField("pad1", 0), IntEnumField("meter_id", "ALL", ofp_meter), XIntField("pad2", 0)] class OFPMeterConfig(_ofp_header_item): name = "OFP_METER_CONFIG" fields_desc = [ShortField("len", None), FlagsField("flags", 0, 16, ["KBPS", "PKTPS", "BURST", "STATS"]), IntEnumField("meter_id", 1, ofp_meter), PacketListField("bands", [], OFPMBT, length_from=lambda pkt:pkt.len - 8)] def extract_padding(self, s): return b"", s class OFPMPReplyMeterConfig(_ofp_header): name = "OFPMP_REPLY_METER_CONFIG" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 19, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 10, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_reply_flags), XIntField("pad1", 0), PacketListField("meter_configs", [], OFPMeterConfig, length_from=lambda pkt:pkt.len - 16)] class OFPMPRequestMeterFeatures(_ofp_header): name = "OFPMP_REQUEST_METER_FEATURES" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 18, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 11, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_request_flags), XIntField("pad1", 0)] class OFPMPReplyMeterFeatures(_ofp_header): name = "OFPMP_REPLY_METER_FEATURES" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 19, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 11, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_reply_flags), XIntField("pad1", 0), IntField("max_meter", 0), FlagsField("band_types", 0, 32, ["DROP", "DSCP_REMARK", "EXPERIMENTER"]), FlagsField("capabilities", 0, 32, ["KPBS", "PKTPS", "BURST", "STATS"]), ByteField("max_bands", 0), ByteField("max_color", 0), XShortField("pad2", 0)] # table features for multipart messages # class OFPTFPT(Packet): name = "Dummy OpenFlow3 Table Features Properties Header" @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and len(_pkt) >= 2: t = struct.unpack("!H", _pkt[:2])[0] return ofp_table_features_prop_cls.get(t, Raw) return Raw def post_build(self, p, pay): tmp_len = self.len if tmp_len is None: tmp_len = len(p) + len(pay) p = p[:2] + struct.pack("!H", tmp_len) + p[4:] # every message will be padded correctly zero_bytes = (8 - tmp_len % 8) % 8 p += b"\x00" * zero_bytes return p + pay def extract_padding(self, s): return b"", s ofp_table_features_prop_types = {0: "OFPTFPT_INSTRUCTIONS", 1: "OFPTFPT_INSTRUCTIONS_MISS", 2: "OFPTFPT_NEXT_TABLES", 3: "OFPTFPT_NEXT_TABLES_MISS", 4: "OFPTFPT_WRITE_ACTIONS", 5: "OFPTFPT_WRITE_ACTIONS_MISS", 6: "OFPTFPT_APPLY_ACTIONS", 7: "OFPTFPT_APPLY_ACTIONS_MISS", 8: "OFPTFPT_MATCH", 10: "OFPTFPT_WILDCARDS", 12: "OFPTFPT_WRITE_SETFIELD", 13: "OFPTFPT_WRITE_SETFIELD_MISS", 14: "OFPTFPT_APPLY_SETFIELD", 15: "OFPTFPT_APPLY_SETFIELD_MISS", 65534: "OFPTFPT_EXPERIMENTER", 65535: "OFPTFPT_EXPERIMENTER_MISS"} class OFPTFPTInstructions(OFPTFPT): name = "OFPTFPT_INSTRUCTIONS" fields_desc = [ShortField("type", 0), ShortField("len", None), PacketListField("instruction_ids", [], OFPITID, length_from=lambda pkt:pkt.len - 4)] class OFPTFPTInstructionsMiss(OFPTFPT): name = "OFPTFPT_INSTRUCTIONS_MISS" fields_desc = [ShortField("type", 1), ShortField("len", None), PacketListField("instruction_ids", [], OFPITID, length_from=lambda pkt:pkt.len - 4)] class OFPTableID(Packet): name = "OFP_TABLE_ID" fields_desc = [ByteEnumField("table_id", 0, ofp_table)] def extract_padding(self, s): return b"", s class OFPTFPTNextTables(OFPTFPT): name = "OFPTFPT_NEXT_TABLES" fields_desc = [ShortField("type", 2), ShortField("len", None), PacketListField("next_table_ids", None, OFPTableID, length_from=lambda pkt:pkt.len - 4)] class OFPTFPTNextTablesMiss(OFPTFPT): name = "OFPTFPT_NEXT_TABLES_MISS" fields_desc = [ShortField("type", 3), ShortField("len", None), PacketListField("next_table_ids", None, OFPTableID, length_from=lambda pkt:pkt.len - 4)] class OFPTFPTWriteActions(OFPTFPT): name = "OFPTFPT_WRITE_ACTIONS" fields_desc = [ShortField("type", 4), ShortField("len", None), PacketListField("action_ids", [], OFPATID, length_from=lambda pkt:pkt.len - 4)] class OFPTFPTWriteActionsMiss(OFPTFPT): name = "OFPTFPT_WRITE_ACTIONS_MISS" fields_desc = [ShortField("type", 5), ShortField("len", None), PacketListField("action_ids", [], OFPATID, length_from=lambda pkt:pkt.len - 4)] class OFPTFPTApplyActions(OFPTFPT): name = "OFPTFPT_APPLY_ACTIONS" fields_desc = [ShortField("type", 6), ShortField("len", None), PacketListField("action_ids", [], OFPATID, length_from=lambda pkt:pkt.len - 4)] class OFPTFPTApplyActionsMiss(OFPTFPT): name = "OFPTFPT_APPLY_ACTIONS_MISS" fields_desc = [ShortField("type", 7), ShortField("len", None), PacketListField("action_ids", [], OFPATID, length_from=lambda pkt:pkt.len - 4)] class OFPTFPTMatch(OFPTFPT): name = "OFPTFPT_MATCH" fields_desc = [ShortField("type", 8), ShortField("len", None), PacketListField("oxm_ids", [], OXMID, length_from=lambda pkt:pkt.len - 4)] class OFPTFPTWildcards(OFPTFPT): name = "OFPTFPT_WILDCARDS" fields_desc = [ShortField("type", 10), ShortField("len", None), PacketListField("oxm_ids", [], OXMID, length_from=lambda pkt:pkt.len - 4)] class OFPTFPTWriteSetField(OFPTFPT): name = "OFPTFPT_WRITE_SETFIELD" fields_desc = [ShortField("type", 12), ShortField("len", None), PacketListField("oxm_ids", [], OXMID, length_from=lambda pkt:pkt.len - 4)] class OFPTFPTWriteSetFieldMiss(OFPTFPT): name = "OFPTFPT_WRITE_SETFIELD_MISS" fields_desc = [ShortField("type", 13), ShortField("len", None), PacketListField("oxm_ids", [], OXMID, length_from=lambda pkt:pkt.len - 4)] class OFPTFPTApplySetField(OFPTFPT): name = "OFPTFPT_APPLY_SETFIELD" fields_desc = [ShortField("type", 14), ShortField("len", None), PacketListField("oxm_ids", [], OXMID, length_from=lambda pkt:pkt.len - 4)] class OFPTFPTApplySetFieldMiss(OFPTFPT): name = "OFPTFPT_APPLY_SETFIELD_MISS" fields_desc = [ShortField("type", 15), ShortField("len", None), PacketListField("oxm_ids", [], OXMID, length_from=lambda pkt:pkt.len - 4)] class OFPTFPTExperimenter(OFPTFPT): name = "OFPTFPT_EXPERIMENTER" fields_desc = [ShortField("type", 65534), ShortField("len", None), IntField("experimenter", 0), IntField("exp_type", 0), PacketLenField("experimenter_data", None, Raw, length_from=lambda pkt: pkt.len - 12)] class OFPTFPTExperimenterMiss(OFPTFPT): name = "OFPTFPT_EXPERIMENTER_MISS" fields_desc = [ShortField("type", 65535), ShortField("len", None), IntField("experimenter", 0), IntField("exp_type", 0), PacketLenField("experimenter_data", None, Raw, length_from=lambda pkt: pkt.len - 12)] ofp_table_features_prop_cls = {0: OFPTFPTInstructions, 1: OFPTFPTInstructionsMiss, 2: OFPTFPTNextTables, 3: OFPTFPTNextTablesMiss, 4: OFPTFPTWriteActions, 5: OFPTFPTWriteActionsMiss, 6: OFPTFPTApplyActions, 7: OFPTFPTApplyActionsMiss, 8: OFPTFPTMatch, 10: OFPTFPTWildcards, 12: OFPTFPTWriteSetField, 13: OFPTFPTWriteSetFieldMiss, 14: OFPTFPTApplySetField, 15: OFPTFPTApplySetFieldMiss, 65534: OFPTFPTExperimenter, 65535: OFPTFPTExperimenterMiss} class OFPTableFeatures(_ofp_header_item): name = "OFP_TABLE_FEATURES" fields_desc = [ShortField("len", None), ByteEnumField("table_id", 0, ofp_table), XBitField("pad", 0, 40), StrFixedLenField("table_name", "", 32), LongField("metadata_match", 0), LongField("metadata_write", 0), IntEnumField("config", 0, {0: "OFPTC_NO_MASK", 3: "OFPTC_DEPRECATED_MASK"}), IntField("max_entries", 0), PacketListField("properties", [], OFPTFPT, length_from=lambda pkt:pkt.len - 64)] def extract_padding(self, s): return b"", s class OFPMPRequestTableFeatures(_ofp_header): name = "OFPMP_REQUEST_TABLE_FEATURES" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 18, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 12, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_request_flags), XIntField("pad1", 0), PacketListField("table_features", [], OFPTableFeatures, length_from=lambda pkt:pkt.len - 16)] class OFPMPReplyTableFeatures(_ofp_header): name = "OFPMP_REPLY_TABLE_FEATURES" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 19, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 12, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_reply_flags), XIntField("pad1", 0), PacketListField("table_features", [], OFPTableFeatures, length_from=lambda pkt:pkt.len - 16)] # end of table features # class OFPMPRequestPortDesc(_ofp_header): name = "OFPMP_REQUEST_PORT_DESC" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 18, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 13, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_request_flags), XIntField("pad1", 0), IntEnumField("port_no", 0, ofp_port_no), XIntField("pad", 0)] class OFPMPReplyPortDesc(_ofp_header): name = "OFPMP_REPLY_PORT_DESC" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 19, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 13, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_reply_flags), XIntField("pad1", 0), PacketListField("ports", None, OFPPort, length_from=lambda pkt:pkt.len - 16)] class OFPMPRequestExperimenter(_ofp_header): name = "OFPST_REQUEST_EXPERIMENTER" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 18, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 65535, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_request_flags), XIntField("pad1", 0), IntField("experimenter", 0), IntField("exp_type", 0)] class OFPMPReplyExperimenter(_ofp_header): name = "OFPST_REPLY_EXPERIMENTER" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 19, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 65535, ofp_multipart_types), FlagsField("flags", 0, 16, ofpmp_reply_flags), XIntField("pad1", 0), IntField("experimenter", 0), IntField("exp_type", 0)] # ofp_multipart_request/reply_cls allows generic method OpenFlow3() # to choose the right class for dissection ofp_multipart_request_cls = {0: OFPMPRequestDesc, 1: OFPMPRequestFlow, 2: OFPMPRequestAggregate, 3: OFPMPRequestTable, 4: OFPMPRequestPortStats, 5: OFPMPRequestQueue, 6: OFPMPRequestGroup, 7: OFPMPRequestGroupDesc, 8: OFPMPRequestGroupFeatures, 9: OFPMPRequestMeter, 10: OFPMPRequestMeterConfig, 11: OFPMPRequestMeterFeatures, 12: OFPMPRequestTableFeatures, 13: OFPMPRequestPortDesc, 65535: OFPMPRequestExperimenter} ofp_multipart_reply_cls = {0: OFPMPReplyDesc, 1: OFPMPReplyFlow, 2: OFPMPReplyAggregate, 3: OFPMPReplyTable, 4: OFPMPReplyPortStats, 5: OFPMPReplyQueue, 6: OFPMPReplyGroup, 7: OFPMPReplyGroupDesc, 8: OFPMPReplyGroupFeatures, 9: OFPMPReplyMeter, 10: OFPMPReplyMeterConfig, 11: OFPMPReplyMeterFeatures, 12: OFPMPReplyTableFeatures, 13: OFPMPReplyPortDesc, 65535: OFPMPReplyExperimenter} # end of OFPT_MULTIPART # class OFPTBarrierRequest(_ofp_header): name = "OFPT_BARRIER_REQUEST" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 20, ofp_type), ShortField("len", None), IntField("xid", 0)] class OFPTBarrierReply(_ofp_header): name = "OFPT_BARRIER_REPLY" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 21, ofp_type), ShortField("len", None), IntField("xid", 0)] class OFPTQueueGetConfigRequest(_ofp_header): name = "OFPT_QUEUE_GET_CONFIG_REQUEST" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 22, ofp_type), ShortField("len", None), IntField("xid", 0), IntEnumField("port_no", "ANY", ofp_port_no), XIntField("pad", 0)] class OFPTQueueGetConfigReply(_ofp_header): name = "OFPT_QUEUE_GET_CONFIG_REPLY" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 23, ofp_type), ShortField("len", None), IntField("xid", 0), IntEnumField("port", 0, ofp_port_no), XIntField("pad", 0), PacketListField("queues", [], OFPPacketQueue, length_from=lambda pkt:pkt.len - 16)] class OFPTRoleRequest(_ofp_header): name = "OFPT_ROLE_REQUEST" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 24, ofp_type), ShortField("len", None), IntField("xid", 0), IntEnumField("role", 0, {0: "OFPCR_ROLE_NOCHANGE", 1: "OFPCR_ROLE_EQUAL", 2: "OFPCR_ROLE_MASTER", 3: "OFPCR_ROLE_SLAVE"}), XIntField("pad", 0), LongField("generation_id", 0)] class OFPTRoleReply(OFPTRoleRequest): name = "OFPT_ROLE_REPLY" type = 25 class OFPTGetAsyncRequest(_ofp_header): name = "OFPT_GET_ASYNC_REQUEST" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 26, ofp_type), ShortField("len", 8), IntField("xid", 0)] ofp_packet_in_reason = ["NO_MATCH", "ACTION", "INVALID_TTL"] ofp_port_reason = ["ADD", "DELETE", "MODIFY"] ofp_flow_removed_reason = ["IDLE_TIMEOUT", "HARD_TIMEOUT", "DELETE", "GROUP_DELETE"] class OFPTGetAsyncReply(_ofp_header): name = "OFPT_GET_ASYNC_REPLY" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 27, ofp_type), ShortField("len", 32), IntField("xid", 0), FlagsField("packet_in_mask_master", 0, 32, ofp_packet_in_reason), # noqa: E501 FlagsField("packet_in_mask_slave", 0, 32, ofp_packet_in_reason), # noqa: E501 FlagsField("port_status_mask_master", 0, 32, ofp_port_reason), # noqa: E501 FlagsField("port_status_mask_slave", 0, 32, ofp_port_reason), # noqa: E501 FlagsField("flow_removed_mask_master", 0, 32, ofp_flow_removed_reason), # noqa: E501 FlagsField("flow_removed_mask_slave", 0, 32, ofp_flow_removed_reason)] # noqa: E501 class OFPTSetAsync(OFPTGetAsyncReply): name = "OFPT_SET_ASYNC" type = 28 class OFPTMeterMod(_ofp_header): name = "OFPT_METER_MOD" fields_desc = [ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 29, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("cmd", 0, {0: "OFPMC_ADD", 1: "OFPMC_MODIFY", 2: "OFPMC_DELETE"}), FlagsField("flags", 0, 16, ["KBPS", "PKTPS", "BURST", "STATS"]), IntEnumField("meter_id", 1, ofp_meter), PacketListField("bands", [], OFPMBT, length_from=lambda pkt:pkt.len - 16)] # ofpt_cls allows generic method OpenFlow3() to choose the right class for dissection # noqa: E501 ofpt_cls = {0: OFPTHello, # 1: OFPTError, 2: OFPTEchoRequest, 3: OFPTEchoReply, 4: OFPTExperimenter, 5: OFPTFeaturesRequest, 6: OFPTFeaturesReply, 7: OFPTGetConfigRequest, 8: OFPTGetConfigReply, 9: OFPTSetConfig, 10: OFPTPacketIn, 11: OFPTFlowRemoved, 12: OFPTPortStatus, 13: OFPTPacketOut, 14: OFPTFlowMod, 15: OFPTGroupMod, 16: OFPTPortMod, 17: OFPTTableMod, # 18: OFPTMultipartRequest, # 19: OFPTMultipartReply, 20: OFPTBarrierRequest, 21: OFPTBarrierReply, 22: OFPTQueueGetConfigRequest, 23: OFPTQueueGetConfigReply, 24: OFPTRoleRequest, 25: OFPTRoleReply, 26: OFPTGetAsyncRequest, 27: OFPTGetAsyncReply, 28: OFPTSetAsync, 29: OFPTMeterMod}