## 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 struct from scapy.fields import * from scapy.layers.l2 import * from scapy.layers.inet import * from scapy.compat import * ### If prereq_autocomplete is True then match prerequisites will be ### automatically handled. See OFPMatch class. prereq_autocomplete = False ##################################################### ################# 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 ################### class _ofp_hello_elem_header(Packet): name = "Dummy OpenFlow Hello Elem Header" def post_build(self, p, pay): if self.len is None: l = len(p)+len(pay) p = p[:2] + struct.pack("!H", l) + p[4:] return p + pay ofp_hello_elem_types = { 1: "OFPHET_VERSIONBITMAP" } class OFPHETVersionBitmap(_ofp_hello_elem_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" ]) ] ofp_hello_elem_cls = { 1: OFPHETVersionBitmap } class HelloElemPacketListField(PacketListField): def m2i(self, pkt, s): t = struct.unpack("!H", s[:2])[0] return ofp_hello_elem_cls.get(t, Raw)(s) @staticmethod def _get_hello_elem_length(s): return struct.unpack("!H", s[2:4])[0] def getfield(self, pkt, s): lst = [] remain = s while remain: l = HelloElemPacketListField._get_hello_elem_length(remain) current = remain[:l] remain = remain[l:] p = self.m2i(pkt, current) lst.append(p) return remain, lst ####################### 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 "", s # extract_padding is overridden in order for s not to be considered # as belonging to the same layer (s usually contains other OFPPorts) ################### 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), BitEnumField("field", i//2, 7, ofp_oxm_names), BitField("hasmask", i%2, 1) ] ofp_oxm_fields[i].append(ByteField("length", 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 }) ### 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("length", 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 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 ### 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=prereq_autocomplete): PacketListField.__init__(self, name, default, cls, length_from=length_from) 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: # 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 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: l = OXMPacketListField._get_oxm_length(remain) + 4 # this could also be done by parsing oxm_fields (fixed lengths) if l <= 4 or len(remain) < l: # no incoherent length break current = remain[:l] remain = remain[l:] p = self.m2i(pkt, current) lst.append(p) self.index = [] ### since OXMPacketListField is called only twice (when OFPMatch and OFPSetField ### classes are created) and not when you want to instantiate an OFPMatch, ### index needs to be reinitialized, otherwise there will be some conflicts ### e.g. if you create OFPMatch with OFBTCPSrc and then change to OFBTCPDst, ### 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 OXMIDPacketListField(PacketListField): def m2i(self, pkt, s): t = orb(s[2]) return ofp_oxm_id_cls.get(t, Raw)(s) def getfield(self, pkt, s): lst = [] lim = self.length_from(pkt) ret = s[lim:] remain = s[:lim] while remain and len(remain) >= 4: # all OXM ID are 32-bit long (no experimenter OXM support here) current = remain[:4] remain = remain[4:] p = self.m2i(pkt, current) lst.append(p) return remain + ret, lst class OFPMatch(Packet): def post_build(self, p, pay): l = self.length if l is None: l = len(p)+len(pay) p = p[:2] + struct.pack("!H", l) + p[4:] zero_bytes = (8 - l%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): l = self.length zero_bytes = (8 - l%8) % 8 return s[zero_bytes:], s[:zero_bytes] name = "OFP_MATCH" fields_desc= [ ShortEnumField("type", 1, { 0: "OFPMT_STANDARD", 1: "OFPMT_OXM" }), ShortField("length", None), OXMPacketListField("oxm_fields", [], Packet, length_from=lambda pkt:pkt.length-4) ] ### 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 _ofp_action_header(Packet): name = "Dummy OpenFlow Action Header" def post_build(self, p, pay): if self.len is None: l = len(p)+len(pay) p = p[:2] + struct.pack("!H", l) + p[4:] return p + pay 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 OFPATOutput(_ofp_action_header): 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(_ofp_action_header): 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(_ofp_action_header): 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(_ofp_action_header): name = "OFPAT_STRIP_VLAN" fields_desc = [ ShortEnumField("type", 3, ofp_action_types), ShortField("len", 8), XIntField("pad", 0) ] class OFPATSetDlSrc(_ofp_action_header): 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(_ofp_action_header): 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(_ofp_action_header): name = "OFPAT_SET_NW_SRC" fields_desc = [ ShortEnumField("type", 6, ofp_action_types), ShortField("len", 8), IPField("nw_addr", "0") ] class OFPATSetNwDst(_ofp_action_header): name = "OFPAT_SET_NW_DST" fields_desc = [ ShortEnumField("type", 7, ofp_action_types), ShortField("len", 8), IPField("nw_addr", "0") ] class OFPATSetNwToS(_ofp_action_header): 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(_ofp_action_header): 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(_ofp_action_header): 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(_ofp_action_header): # 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(_ofp_action_header): name = "OFPAT_SET_MPLS_LABEL" fields_desc = [ ShortEnumField("type", 13, ofp_action_types), ShortField("len", 8), IntField("mpls_label", 0) ] class OFPATSetMPLSTC(_ofp_action_header): 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(_ofp_action_header): name = "OFPAT_COPY_TTL_OUT" fields_desc = [ ShortEnumField("type", 11, ofp_action_types), ShortField("len", 8), XIntField("pad", 0) ] class OFPATCopyTTLIn(_ofp_action_header): name = "OFPAT_COPY_TTL_IN" fields_desc = [ ShortEnumField("type", 12, ofp_action_types), ShortField("len", 8), XIntField("pad", 0) ] class OFPATSetMPLSTTL(_ofp_action_header): 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(_ofp_action_header): name = "OFPAT_DEC_MPLS_TTL" fields_desc = [ ShortEnumField("type", 16, ofp_action_types), ShortField("len", 8), XIntField("pad", 0) ] class OFPATPushVLAN(_ofp_action_header): 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(_ofp_action_header): name = "OFPAT_POP_VLAN" fields_desc = [ ShortEnumField("type", 18, ofp_action_types), ShortField("len", 8), XIntField("pad", 0) ] class OFPATPushMPLS(_ofp_action_header): 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(_ofp_action_header): 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(_ofp_action_header): name = "OFPAT_SET_QUEUE" fields_desc = [ ShortEnumField("type", 21, ofp_action_types), ShortField("len", 8), IntEnumField("queue_id", 0, ofp_queue) ] class OFPATGroup(_ofp_action_header): name = "OFPAT_GROUP" fields_desc = [ ShortEnumField("type", 22, ofp_action_types), ShortField("len", 8), IntEnumField("group_id", 0, ofp_group) ] class OFPATSetNwTTL(_ofp_action_header): 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(_ofp_action_header): name = "OFPAT_DEC_NW_TTL" fields_desc = [ ShortEnumField("type", 24, ofp_action_types), ShortField("len", 8), XIntField("pad", 0) ] class OFPATSetField(_ofp_action_header): def post_build(self, p, pay): l = self.len zero_bytes = 0 if l is None: l = len(p)+len(pay) zero_bytes = (8 - l%8) % 8 l = l + zero_bytes # add padding length p = p[:2] + struct.pack("!H", l) + p[4:] else: zero_bytes = (8 - l%8) % 8 # every message will be padded correctly p += b"\x00" * zero_bytes return p + pay def extract_padding(self, s): return "", s 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) ] class OFPATPushPBB(_ofp_action_header): name = "OFPAT_PUSH_PBB" fields_desc = [ ShortEnumField("type", 26, ofp_action_types), ShortField("len", 8), ShortField("ethertype", 0x88e7), XShortField("pad", 0) ] class OFPATPopPBB(_ofp_action_header): name = "OFPAT_POP_PBB" fields_desc = [ ShortEnumField("type", 27, ofp_action_types), ShortField("len", 8), XIntField("pad", 0) ] class OFPATExperimenter(_ofp_action_header): 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 } class ActionPacketListField(PacketListField): def m2i(self, pkt, s): t = struct.unpack("!H", s[:2])[0] return ofp_action_cls.get(t, Raw)(s) @staticmethod def _get_action_length(s): return struct.unpack("!H", s[2:4])[0] def getfield(self, pkt, s): lst = [] remain = s while remain and len(remain)>=4: l = ActionPacketListField._get_action_length(remain) if l < 8 or len(remain) < l: # length should be at least 8 (non-zero, 64-bit aligned), # and no incoherent length break current = remain[:l] remain = remain[l:] p = self.m2i(pkt, current) lst.append(p) return remain, lst ##################### Action IDs #################### # length is computed as in instruction structures, # so we reuse _ofp_instruction_header class OFPATOutputID(_ofp_action_header): 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(_ofp_action_header): name = "OFPAT_SET_VLAN_VID" fields_desc = [ ShortEnumField("type", 1, ofp_action_types), ShortField("len", 4) ] class OFPATSetVLANPCPID(_ofp_action_header): name = "OFPAT_SET_VLAN_PCP" fields_desc = [ ShortEnumField("type", 2, ofp_action_types), ShortField("len", 4) ] class OFPATStripVLANID(_ofp_action_header): name = "OFPAT_STRIP_VLAN" fields_desc = [ ShortEnumField("type", 3, ofp_action_types), ShortField("len", 4) ] class OFPATSetDlSrcID(_ofp_action_header): name = "OFPAT_SET_DL_SRC" fields_desc = [ ShortEnumField("type", 4, ofp_action_types), ShortField("len", 4) ] class OFPATSetDlDstID(_ofp_action_header): name = "OFPAT_SET_DL_DST" fields_desc = [ ShortEnumField("type", 5, ofp_action_types), ShortField("len", 4) ] class OFPATSetNwSrcID(_ofp_action_header): name = "OFPAT_SET_NW_SRC" fields_desc = [ ShortEnumField("type", 6, ofp_action_types), ShortField("len", 4) ] class OFPATSetNwDstID(_ofp_action_header): name = "OFPAT_SET_NW_DST" fields_desc = [ ShortEnumField("type", 7, ofp_action_types), ShortField("len", 4) ] class OFPATSetNwToSID(_ofp_action_header): name = "OFPAT_SET_TP_TOS" fields_desc = [ ShortEnumField("type", 8, ofp_action_types), ShortField("len", 4) ] class OFPATSetTpSrcID(_ofp_action_header): name = "OFPAT_SET_TP_SRC" fields_desc = [ ShortEnumField("type", 9, ofp_action_types), ShortField("len", 4) ] class OFPATSetTpDstID(_ofp_action_header): name = "OFPAT_SET_TP_DST" fields_desc = [ ShortEnumField("type", 10, ofp_action_types), ShortField("len", 4) ] #class OFPATEnqueueID(_ofp_action_header): # name = "OFPAT_ENQUEUE" # fields_desc = [ ShortEnumField("type", 11, ofp_action_types), # ShortField("len", 4) ] class OFPATSetMPLSLabelID(_ofp_action_header): name = "OFPAT_SET_MPLS_LABEL" fields_desc = [ ShortEnumField("type", 13, ofp_action_types), ShortField("len", 4) ] class OFPATSetMPLSTCID(_ofp_action_header): name = "OFPAT_SET_MPLS_TC" fields_desc = [ ShortEnumField("type", 14, ofp_action_types), ShortField("len", 4) ] # end of unsupported actions class OFPATCopyTTLOutID(_ofp_action_header): name = "OFPAT_COPY_TTL_OUT" fields_desc = [ ShortEnumField("type", 11, ofp_action_types), ShortField("len", 4) ] class OFPATCopyTTLInID(_ofp_action_header): name = "OFPAT_COPY_TTL_IN" fields_desc = [ ShortEnumField("type", 12, ofp_action_types), ShortField("len", 4) ] class OFPATSetMPLSTTLID(_ofp_action_header): name = "OFPAT_SET_MPLS_TTL" fields_desc = [ ShortEnumField("type", 15, ofp_action_types), ShortField("len", 4) ] class OFPATDecMPLSTTLID(_ofp_action_header): name = "OFPAT_DEC_MPLS_TTL" fields_desc = [ ShortEnumField("type", 16, ofp_action_types), ShortField("len", 4) ] class OFPATPushVLANID(_ofp_action_header): name = "OFPAT_PUSH_VLAN" fields_desc = [ ShortEnumField("type", 17, ofp_action_types), ShortField("len", 4) ] class OFPATPopVLANID(_ofp_action_header): name = "OFPAT_POP_VLAN" fields_desc = [ ShortEnumField("type", 18, ofp_action_types), ShortField("len", 4) ] class OFPATPushMPLSID(_ofp_action_header): name = "OFPAT_PUSH_MPLS" fields_desc = [ ShortEnumField("type", 19, ofp_action_types), ShortField("len", 4) ] class OFPATPopMPLSID(_ofp_action_header): name = "OFPAT_POP_MPLS" fields_desc = [ ShortEnumField("type", 20, ofp_action_types), ShortField("len", 4) ] class OFPATSetQueueID(_ofp_action_header): name = "OFPAT_SET_QUEUE" fields_desc = [ ShortEnumField("type", 21, ofp_action_types), ShortField("len", 4) ] class OFPATGroupID(_ofp_action_header): name = "OFPAT_GROUP" fields_desc = [ ShortEnumField("type", 22, ofp_action_types), ShortField("len", 4) ] class OFPATSetNwTTLID(_ofp_action_header): name = "OFPAT_SET_NW_TTL" fields_desc = [ ShortEnumField("type", 23, ofp_action_types), ShortField("len", 4) ] class OFPATDecNwTTLID(_ofp_action_header): name = "OFPAT_DEC_NW_TTL" fields_desc = [ ShortEnumField("type", 24, ofp_action_types), ShortField("len", 4) ] class OFPATSetFieldID(_ofp_action_header): name = "OFPAT_SET_FIELD" fields_desc = [ ShortEnumField("type", 25, ofp_action_types), ShortField("len", 4) ] class OFPATPushPBBID(_ofp_action_header): name = "OFPAT_PUSH_PBB" fields_desc = [ ShortEnumField("type", 26, ofp_action_types), ShortField("len", 4) ] class OFPATPopPBBID(_ofp_action_header): name = "OFPAT_POP_PBB" fields_desc = [ ShortEnumField("type", 27, ofp_action_types), ShortField("len", 4) ] class OFPATExperimenterID(_ofp_action_header): 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 } class ActionIDPacketListField(PacketListField): def m2i(self, pkt, s): t = struct.unpack("!H", s[:2])[0] return ofp_action_id_cls.get(t, Raw)(s) @staticmethod def _get_action_id_length(s): return struct.unpack("!H", s[2:4])[0] def getfield(self, pkt, s): lst = [] remain = s while remain and len(remain) >= 4: l = ActionIDPacketListField._get_action_id_length(remain) if l < 4 or len(remain) < l: # length is 4 (may be more for experimenter messages), # and no incoherent length break current = remain[:l] remain = remain[l:] p = self.m2i(pkt, current) lst.append(p) return remain, lst #################### Instructions ################### class _ofp_instruction_header(Packet): name = "Dummy OpenFlow Instruction Header" def post_build(self, p, pay): if self.len is None: l = len(p)+len(pay) p = p[:2] + struct.pack("!H", l) + p[4:] return p + pay 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 OFPITGotoTable(_ofp_instruction_header): 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(_ofp_instruction_header): 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(_ofp_instruction_header): name = "OFPIT_WRITE_ACTIONS" fields_desc = [ ShortEnumField("type", 3, ofp_instruction_types), ShortField("len", None), XIntField("pad", 0), ActionPacketListField("actions", [], Packet, length_from=lambda pkt:pkt.len-8) ] class OFPITApplyActions(_ofp_instruction_header): name = "OFPIT_APPLY_ACTIONS" fields_desc = [ ShortEnumField("type", 4, ofp_instruction_types), ShortField("len", None), XIntField("pad", 0), ActionPacketListField("actions", [], Packet, length_from=lambda pkt:pkt.len-8) ] class OFPITClearActions(_ofp_instruction_header): name = "OFPIT_CLEAR_ACTIONS" fields_desc = [ ShortEnumField("type", 5, ofp_instruction_types), ShortField("len", 8), XIntField("pad", 0) ] class OFPITMeter(_ofp_instruction_header): name = "OFPIT_METER" fields_desc = [ ShortEnumField("type", 6, ofp_instruction_types), ShortField("len", 8), IntEnumField("meter_id", 1, ofp_meter) ] class OFPITExperimenter(_ofp_instruction_header): 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 } class InstructionPacketListField(PacketListField): def m2i(self, pkt, s): t = struct.unpack("!H", s[:2])[0] return ofp_instruction_cls.get(t, Raw)(s) @staticmethod def _get_instruction_length(s): return struct.unpack("!H", s[2:4])[0] def getfield(self, pkt, s): lst = [] remain = s while remain and len(remain) > 4: l = InstructionPacketListField._get_instruction_length(remain) if l < 8 or len(remain) < l: # length should be at least 8 (non-zero, 64-bit aligned), # and no incoherent length break current = remain[:l] remain = remain[l:] p = self.m2i(pkt, current) lst.append(p) return remain, lst ################## Instruction IDs ################## # length is computed as in instruction structures, # so we reuse _ofp_instruction_header class OFPITGotoTableID(_ofp_instruction_header): name = "OFPIT_GOTO_TABLE" fields_desc = [ ShortEnumField("type", 1, ofp_instruction_types), ShortField("len", 4) ] class OFPITWriteMetadataID(_ofp_instruction_header): name = "OFPIT_WRITE_METADATA" fields_desc = [ ShortEnumField("type", 2, ofp_instruction_types), ShortField("len", 4) ] class OFPITWriteActionsID(_ofp_instruction_header): name = "OFPIT_WRITE_ACTIONS" fields_desc = [ ShortEnumField("type", 3, ofp_instruction_types), ShortField("len", 4) ] class OFPITApplyActionsID(_ofp_instruction_header): name = "OFPIT_APPLY_ACTIONS" fields_desc = [ ShortEnumField("type", 4, ofp_instruction_types), ShortField("len", 4) ] class OFPITClearActionsID(_ofp_instruction_header): name = "OFPIT_CLEAR_ACTIONS" fields_desc = [ ShortEnumField("type", 5, ofp_instruction_types), ShortField("len", 4) ] class OFPITMeterID(_ofp_instruction_header): name = "OFPIT_METER" fields_desc = [ ShortEnumField("type", 6, ofp_instruction_types), ShortField("len", 4) ] class OFPITExperimenterID(_ofp_instruction_header): 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 } class InstructionIDPacketListField(PacketListField): def m2i(self, pkt, s): t = struct.unpack("!H", s[:2])[0] return ofp_instruction_cls.get(t, Raw)(s) @staticmethod def _get_instruction_id_length(s): return struct.unpack("!H", s[2:4])[0] def getfield(self, pkt, s): lst = [] remain = s while remain and len(remain) >= 4: l = InstructionIDPacketListField._get_instruction_id_length(remain) if l < 4 or len(remain) < l: # length is 4 (may be more for experimenter messages), # and no incoherent length break current = remain[:l] remain = remain[l:] p = self.m2i(pkt, current) lst.append(p) return remain, lst ###################### Buckets ###################### class OFPBucket(Packet): def extract_padding(self, s): return "", s def post_build(self, p, pay): if self.len is None: l = len(p)+len(pay) p = struct.pack("!H", l) + p[2:] return p + pay 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), ActionPacketListField("actions", [], Packet, length_from=lambda pkt:pkt.len-16) ] class BucketPacketListField(PacketListField): @staticmethod def _get_bucket_length(s): return struct.unpack("!H", s[:2])[0] def getfield(self, pkt, s): lst = [] remain = s while remain: l = BucketPacketListField._get_bucket_length(remain) current = remain[:l] remain = remain[l:] p = OFPBucket(current) lst.append(p) return remain, lst ####################### Queues ###################### class _ofp_queue_property_header(Packet): name = "Dummy OpenFlow Queue Property Header" def post_build(self, p, pay): if self.len is None: l = len(p)+len(pay) p = p[:2] + struct.pack("!H", l) + p[4:] return p + pay ofp_queue_property_types = { 0: "OFPQT_NONE", 1: "OFPQT_MIN_RATE" } class OFPQTNone(_ofp_queue_property_header): name = "OFPQT_NONE" fields_desc = [ ShortEnumField("type", 0, ofp_queue_property_types), ShortField("len", 8), XIntField("pad", 0) ] class OFPQTMinRate(_ofp_queue_property_header): 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 QueuePropertyPacketListField(PacketListField): def m2i(self, pkt, s): t = struct.unpack("!H", s[:2])[0] return ofp_queue_property_cls.get(t, Raw)(s) @staticmethod def _get_queue_property_length(s): return struct.unpack("!H", s[2:4])[0] def getfield(self, pkt, s): lst = [] remain = s while remain: l = QueuePropertyPacketListField._get_queue_property_length(remain) current = remain[:l] remain = remain[l:] p = self.m2i(pkt, current) lst.append(p) return remain, lst class OFPPacketQueue(Packet): def extract_padding(self, s): return "", s def post_build(self, p, pay): if self.properties == []: p += raw(OFPQTNone()) if self.len is None: l = len(p)+len(pay) p = p[:4] + struct.pack("!H", l) + p[6:] return p + pay name = "OFP_PACKET_QUEUE" fields_desc = [ IntEnumField("queue_id", 0, ofp_queue), ShortField("len", None), XShortField("pad", 0), QueuePropertyPacketListField("properties", [], Packet, length_from=lambda pkt:pkt.len-8) ] class QueuePacketListField(PacketListField): @staticmethod def _get_queue_length(s): return struct.unpack("!H", s[4:6])[0] def getfield(self, pkt, s): lst = [] remain = s while remain: l = QueuePacketListField._get_queue_length(remain) current = remain[:l] remain = remain[l:] p = OFPPacketQueue(current) lst.append(p) return remain, lst #################### Meter bands #################### ofp_meter_band_types = { 0: "OFPMBT_DROP", 1: "OFPMBT_DSCP_REMARK", 65535: "OFPMBT_EXPERIMENTER" } class OFPMBTDrop(Packet): 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(Packet): 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(Packet): 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 } class MeterBandPacketListField(PacketListField): def m2i(self, pkt, s): t = struct.unpack("!H", s[:2])[0] return ofp_meter_band_cls.get(t, Raw)(s) def getfield(self, pkt, s): lst = [] remain = s while remain: current = remain[:16] remain = remain[16:] p = self.m2i(pkt, current) lst.append(p) return remain, lst ##################################################### ############## 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 _ofp_header(Packet): name = "Dummy OpenFlow Header" def post_build(self, p, pay): if self.len is None: l = len(p)+len(pay) p = p[:2] + struct.pack("!H", l) + p[4:] return p + pay 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), HelloElemPacketListField("elements", [], Packet, length_from=lambda pkt:pkt.len-32) ] overload_fields = {TCP: {"sport": 6653}} ##################################################### ##################### OFPT_ERROR #################### ##################################################### ### this class will be used to display some messages ### sent back by the switch after an error class OFPacketField(PacketField): def getfield(self, pkt, s): try: l = s[2:4] l = struct.unpack("!H", l)[0] ofload = s[:l] remain = s[l:] return remain, OpenFlow(None, ofload)(ofload) except: return b"", Raw(s) 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) ] overload_fields = {TCP: {"dport": 6653}} 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" }), OFPacketField("data", "", Raw) ] overload_fields = {TCP: {"dport": 6653}} 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", 11: "OFPBAC_UNSUPPORTED_ORDER", 12: "OFPBAC_BAD_TAG", 13: "OFPBAC_BAD_SET_TYPE", 14: "OFPBAC_BAD_SET_LEN", 15: "OFPBAC_BAD_SET_ARGUMENT" }), OFPacketField("data", "", Raw) ] overload_fields = {TCP: {"dport": 6653}} 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", 5: "OFPBIC_BAD_EXPERIMENTER", 6: "OFPBIC_BAD_EXP_TYPE", 7: "OFPBIC_BAD_LEN", 8: "OFPBIC_EPERM" }), OFPacketField("data", "", Raw) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"dport": 6653}} 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", 3: "OFPGMFC_OUT_OF_GROUPS", 4: "OFPGMFC_OUT_OF_BUCKETS", 5: "OFPGMFC_CHAINING_UNSUPPORTED", 6: "OFPGMFC_WATCH_UNSUPPORTED", 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) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"dport": 6653}} 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), ShortField("exp_type", None), IntField("experimenter", None), OFPacketField("data", "", Raw) ] overload_fields = {TCP: {"dport": 6653}} # ofp_error_cls allows generic method OpenFlow() # 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) ] overload_fields = {TCP: {"sport": 6653}} 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) ] overload_fields = {TCP: {"sport": 6653}} 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) ] overload_fields = {TCP: {"sport": 6653}} 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) ] overload_fields = {TCP: {"sport": 6653}} 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 "PORT_BLOCKED"]), IntField("reserved", 0) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"sport": 6653}} 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) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"sport": 6653}} 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) ] overload_fields = {TCP: {"dport": 6653}} 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") ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"dport": 6653}} 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"), XBitField("pad", 0, 48), ActionPacketListField("actions", [], Packet, length_from=lambda pkt:pkt.actions_len), PacketField("data", "", Ether) ] overload_fields = {TCP: {"sport": 6653}} 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"), InstructionPacketListField("instructions", [], Packet, length_from=lambda pkt:pkt.len-48-(pkt.match.length+(8-pkt.match.length%8)%8)) ] # include match padding to match.length overload_fields = {TCP: {"sport": 6653}} 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), BucketPacketListField("buckets", [], Packet, length_from=lambda pkt:pkt.len-16) ] overload_fields = {TCP: {"sport": 6653}} 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) ] overload_fields = {TCP: {"sport": 6653}} 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"}) ] overload_fields = {TCP: {"sport": 6653}} ##################################################### ################## 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) ] overload_fields = {TCP: {"sport": 6653}} 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) ] overload_fields = {TCP: {"dport": 6653}} 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") ] overload_fields = {TCP: {"sport": 6653}} class OFPFlowStats(Packet): def post_build(self, p, pay): if self.length is None: l = len(p)+len(pay) p = struct.pack("!H", l) + p[2:] return p + pay name = "OFP_FLOW_STATS" fields_desc = [ ShortField("length", 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"), InstructionPacketListField("instructions", [], Packet, length_from=lambda pkt:pkt.length-56-pkt.match.length) ] class FlowStatsPacketListField(PacketListField): @staticmethod def _get_flow_stats_length(s): return struct.unpack("!H", s[:2])[0] def getfield(self, pkt, s): lst = [] remain = s while remain: l = FlowStatsPacketListField._get_flow_stats_length(remain) current = remain[:l] remain = remain[l:] p = OFPFlowStats(current) lst.append(p) return remain, lst 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), FlowStatsPacketListField("flow_stats", [], Packet, length_from=lambda pkt:pkt.len-16) ] overload_fields = {TCP: {"dport": 6653}} class OFPMPRequestAggregate(_ofp_header): name = "OFPMP_REQUEST_AGGREGATE" fields_desc = [ ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 18, ofp_type), ShortField("len", None), IntField("xid", 0), ShortEnumField("mp_type", 2, 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") ] overload_fields = {TCP: {"sport": 6653}} 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) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"sport": 6653}} class OFPTableStats(Packet): def extract_padding(self, s): return "", s 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) ] 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) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"sport": 6653}} class OFPPortStats(Packet): def extract_padding(self, s): return "", 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) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"sport": 6653}} class OFPQueueStats(Packet): def extract_padding(self, s): return "", s 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) ] 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) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"sport": 6653}} class OFPBucketStats(Packet): def extract_padding(self, s): return "", s name = "OFP_BUCKET_STATS" fields_desc = [ LongField("packet_count", 0), LongField("byte_count", 0) ] class OFPGroupStats(Packet): def post_build(self, p, pay): if self.length is None: l = len(p)+len(pay) p = struct.pack("!H", l) + p[2:] return p + pay name = "OFP_GROUP_STATS" fields_desc = [ ShortField("length", 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.length-40) ] class GroupStatsPacketListField(PacketListField): @staticmethod def _get_group_stats_length(s): return struct.unpack("!H", s[:2])[0] def getfield(self, pkt, s): lst = [] remain = s while remain: l = GroupStatsPacketListField._get_group_stats_length(remain) current = remain[:l] remain = remain[l:] p = OFPGroupStats(current) lst.append(p) return remain, lst 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), GroupStatsPacketListField("group_stats", [], Packet, length_from=lambda pkt:pkt.len-16) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"sport": 6653}} class OFPGroupDesc(Packet): def post_build(self, p, pay): if self.length is None: l = len(p)+len(pay) p = struct.pack("!H", l) + p[2:] return p + pay name = "OFP_GROUP_DESC" fields_desc = [ ShortField("length", 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), BucketPacketListField("buckets", None, Packet, length_from=lambda pkt:pkt.length-8) ] class GroupDescPacketListField(PacketListField): @staticmethod def _get_group_desc_length(s): return struct.unpack("!H", s[:2])[0] def getfield(self, pkt, s): lst = [] remain = s while remain: l = GroupDescPacketListField._get_group_desc_length(remain) current = remain[:l] remain = remain[l:] p = OFPGroupDesc(current) lst.append(p) return remain, lst 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), GroupDescPacketListField("group_descs", [], Packet, length_from=lambda pkt:pkt.len-16) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"sport": 6653}} ofp_action_types_flags = list(ofp_action_types.values())[:-1] # no ofpat_experimenter flag 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), FlagsField("actions_ff", 0, 32, ofp_action_types_flags) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"sport": 6653}} class OFPMeterBandStats(Packet): def extract_padding(self, s): return "", s name = "OFP_METER_BAND_STATS" fields_desc = [ LongField("packet_band_count", 0), LongField("byte_band_count", 0) ] class OFPMeterStats(Packet): def post_build(self, p, pay): if self.len is None: l = len(p)+len(pay) p = p[:4] + struct.pack("!H", l) + p[6:] return p + pay 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) ] class MeterStatsPacketListField(PacketListField): @staticmethod def _get_meter_stats_length(s): return struct.unpack("!H", s[4:6])[0] def getfield(self, pkt, s): lst = [] l = 0 ret = b"" remain = s while remain: l = MeterStatsPacketListField._get_meter_stats_length(remain) current = remain[:l] remain = remain[l:] p = OFPMeterStats(current) lst.append(p) return remain + ret, lst 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), MeterStatsPacketListField("meter_stats", [], Packet, length_from=lambda pkt:pkt.len-16) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"sport": 6653}} class OFPMeterConfig(Packet): def post_build(self, p, pay): if self.length is None: l = len(p)+len(pay) p = struct.pack("!H", l) + p[2:] return p + pay name = "OFP_METER_CONFIG" fields_desc = [ ShortField("length", None), FlagsField("flags", 0, 16, [ "KBPS", "PKTPS", "BURST", "STATS" ]), IntEnumField("meter_id", 1, ofp_meter), MeterBandPacketListField("bands", [], Packet, length_from=lambda pkt:pkt.len-8) ] class MeterConfigPacketListField(PacketListField): @staticmethod def _get_meter_config_length(s): return struct.unpack("!H", s[:2])[0] def getfield(self, pkt, s): lst = [] remain = s while remain: l = MeterConfigPacketListField._get_meter_config_length(remain) current = remain[:l] remain = remain[l:] p = OFPMeterConfig(current) lst.append(p) return remain, lst 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), MeterConfigPacketListField("meter_configs", [], Packet, length_from=lambda pkt:pkt.len-16) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"sport": 6653}} 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) ] overload_fields = {TCP: {"dport": 6653}} ####### table features for multipart messages ####### class _ofp_table_features_prop_header(Packet): name = "Dummy OpenFlow Table Features Properties Header" def post_build(self, p, pay): l = self.length if l is None: l = len(p)+len(pay) p = p[:2] + struct.pack("!H", l) + p[4:] # every message will be padded correctly zero_bytes = (8 - l%8) % 8 p += b"\x00" * zero_bytes return p + pay def extract_padding(self, s): l = self.length zero_bytes = (8 - l%8) % 8 return "", 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(_ofp_table_features_prop_header): name = "OFPTFPT_INSTRUCTIONS" fields_desc = [ ShortField("type", 0), ShortField("length", None), InstructionIDPacketListField("instruction_ids", [], Packet, length_from=lambda pkt:pkt.length-4) ] class OFPTFPTInstructionsMiss(_ofp_table_features_prop_header): name = "OFPTFPT_INSTRUCTIONS_MISS" fields_desc = [ ShortField("type", 1), ShortField("length", None), InstructionIDPacketListField("instruction_ids", [], Packet, length_from=lambda pkt:pkt.length-4) ] class OFPTableID(Packet): def extract_padding(self, s): return "", s name = "OFP_TABLE_ID" fields_desc = [ ByteEnumField("table_id", 0, ofp_table) ] class OFPTFPTNextTables(_ofp_table_features_prop_header): name = "OFPTFPT_NEXT_TABLES" fields_desc = [ ShortField("type", 2), ShortField("length", None), PacketListField("next_table_ids", None, OFPTableID, length_from=lambda pkt:pkt.length-4) ] class OFPTFPTNextTablesMiss(_ofp_table_features_prop_header): name = "OFPTFPT_NEXT_TABLES_MISS" fields_desc = [ ShortField("type", 3), ShortField("length", None), PacketListField("next_table_ids", None, OFPTableID, length_from=lambda pkt:pkt.length-4) ] class OFPTFPTWriteActions(_ofp_table_features_prop_header): name = "OFPTFPT_WRITE_ACTIONS" fields_desc = [ ShortField("type", 4), ShortField("length", None), ActionIDPacketListField("action_ids", [], Packet, length_from=lambda pkt:pkt.length-4) ] class OFPTFPTWriteActionsMiss(_ofp_table_features_prop_header): name = "OFPTFPT_WRITE_ACTIONS_MISS" fields_desc = [ ShortField("type", 5), ShortField("length", None), ActionIDPacketListField("action_ids", [], Packet, length_from=lambda pkt:pkt.length-4) ] class OFPTFPTApplyActions(_ofp_table_features_prop_header): name = "OFPTFPT_APPLY_ACTIONS" fields_desc = [ ShortField("type", 6), ShortField("length", None), ActionIDPacketListField("action_ids", [], Packet, length_from=lambda pkt:pkt.length-4) ] class OFPTFPTApplyActionsMiss(_ofp_table_features_prop_header): name = "OFPTFPT_APPLY_ACTIONS_MISS" fields_desc = [ ShortField("type", 7), ShortField("length", None), ActionIDPacketListField("action_ids", [], Packet, length_from=lambda pkt:pkt.length-4) ] class OFPTFPTMatch(_ofp_table_features_prop_header): name = "OFPTFPT_MATCH" fields_desc = [ ShortField("type", 8), ShortField("length", None), OXMIDPacketListField("oxm_ids", [], Packet, length_from=lambda pkt:pkt.length-4) ] class OFPTFPTWildcards(_ofp_table_features_prop_header): name = "OFPTFPT_WILDCARDS" fields_desc = [ ShortField("type", 10), ShortField("length", None), OXMIDPacketListField("oxm_ids", [], Packet, length_from=lambda pkt:pkt.length-4) ] class OFPTFPTWriteSetField(_ofp_table_features_prop_header): name = "OFPTFPT_WRITE_SETFIELD" fields_desc = [ ShortField("type", 12), ShortField("length", None), OXMIDPacketListField("oxm_ids", [], Packet, length_from=lambda pkt:pkt.length-4) ] class OFPTFPTWriteSetFieldMiss(_ofp_table_features_prop_header): name = "OFPTFPT_WRITE_SETFIELD_MISS" fields_desc = [ ShortField("type", 13), ShortField("length", None), OXMIDPacketListField("oxm_ids", [], Packet, length_from=lambda pkt:pkt.length-4) ] class OFPTFPTApplySetField(_ofp_table_features_prop_header): name = "OFPTFPT_APPLY_SETFIELD" fields_desc = [ ShortField("type", 14), ShortField("length", None), OXMIDPacketListField("oxm_ids", [], Packet, length_from=lambda pkt:pkt.length-4) ] class OFPTFPTApplySetFieldMiss(_ofp_table_features_prop_header): name = "OFPTFPT_APPLY_SETFIELD_MISS" fields_desc = [ ShortField("type", 15), ShortField("length", None), OXMIDPacketListField("oxm_ids", [], Packet, length_from=lambda pkt:pkt.length-4) ] class OFPTFPTExperimenter(_ofp_table_features_prop_header): name = "OFPTFPT_EXPERIMENTER" fields_desc = [ ShortField("type", 65534), ShortField("length", None), IntField("experimenter", 0), IntField("exp_type", 0), PacketField("experimenter_data", None, Raw) ] class OFPTFPTExperimenterMiss(_ofp_table_features_prop_header): name = "OFPTFPT_EXPERIMENTER_MISS" fields_desc = [ ShortField("type", 65535), ShortField("length", None), IntField("experimenter", 0), IntField("exp_type", 0), PacketField("experimenter_data", None, Raw) ] 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 TableFeaturesPropPacketListField(PacketListField): @staticmethod def _get_table_features_prop_length(s): return struct.unpack("!H", s[2:4])[0] def m2i(self, pkt, s): t = struct.unpack("!H", s[:2])[0] return ofp_table_features_prop_cls.get(t, Raw)(s) def getfield(self, pkt, s): lst = [] remain = s while remain and len(remain) >= 4: l = TableFeaturesPropPacketListField._get_table_features_prop_length(remain) # add padding ! lpad = l + (8 - l%8)%8 if l < 4 or len(remain) < lpad: # no zero length nor incoherent length break current = remain[:lpad] remain = remain[lpad:] p = self.m2i(pkt, current) lst.append(p) return remain, lst class OFPTableFeatures(Packet): def post_build(self, p, pay): if self.length is None: l = len(p)+len(pay) p = struct.pack("!H", l) + p[2:] return p + pay name = "OFP_TABLE_FEATURES" fields_desc = [ ShortField("length", 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), TableFeaturesPropPacketListField("properties", [], Packet, length_from=lambda pkt:pkt.length-64) ] class TableFeaturesPacketListField(PacketListField): @staticmethod def _get_table_features_length(s): return struct.unpack("!H", s[:2])[0] def getfield(self, pkt, s): lst = [] remain = s while remain: l = TableFeaturesPacketListField._get_table_features_length(remain) current = remain[:l] remain = remain[l:] p = OFPTableFeatures(current) lst.append(p) return remain, lst 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), TableFeaturesPacketListField("table_features", [], Packet, length_from=lambda pkt:pkt.len-16) ] overload_fields = {TCP: {"sport": 6653}} 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), TableFeaturesPacketListField("table_features", [], Packet, length_from=lambda pkt:pkt.len-16) ] overload_fields = {TCP: {"dport": 6653}} ############### 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) ] overload_fields = {TCP: {"sport": 6653}} 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) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"sport": 6653}} 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) ] overload_fields = {TCP: {"dport": 6653}} # ofp_multipart_request/reply_cls allows generic method OpenFlow() # 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) ] overload_fields = {TCP: {"sport": 6653}} 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) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"sport": 6653}} 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), QueuePacketListField("queues", [], Packet, length_from=lambda pkt:pkt.len-16) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"sport": 6653}} class OFPTRoleReply(_ofp_header): name = "OFPT_ROLE_REPLY" fields_desc = [ ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 25, 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) ] overload_fields = {TCP: {"dport": 6653}} 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) ] overload_fields = {TCP: {"sport": 6653}} 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), FlagsField("packet_in_mask_slave", 0, 32, ofp_packet_in_reason), FlagsField("port_status_mask_master", 0, 32, ofp_port_reason), FlagsField("port_status_mask_slave", 0, 32, ofp_port_reason), FlagsField("flow_removed_mask_master", 0, 32, ofp_flow_removed_reason), FlagsField("flow_removed_mask_slave", 0, 32, ofp_flow_removed_reason) ] overload_fields = {TCP: {"dport": 6653}} class OFPTSetAsync(_ofp_header): name = "OFPT_SET_ASYNC" fields_desc = [ ByteEnumField("version", 0x04, ofp_version), ByteEnumField("type", 28, ofp_type), ShortField("len", 32), IntField("xid", 0), FlagsField("packet_in_mask_master", 0, 32, ofp_packet_in_reason), FlagsField("packet_in_mask_slave", 0, 32, ofp_packet_in_reason), FlagsField("port_status_mask_master", 0, 32, ofp_port_reason), FlagsField("port_status_mask_slave", 0, 32, ofp_port_reason), FlagsField("flow_removed_mask_master", 0, 32, ofp_flow_removed_reason), FlagsField("flow_removed_mask_slave", 0, 32, ofp_flow_removed_reason) ] overload_fields = {TCP: {"sport": 6653}} 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), MeterBandPacketListField("bands", [], Packet, length_from=lambda pkt:pkt.len-16) ] overload_fields = {TCP: {"sport": 6653}} # ofpt_cls allows generic method OpenFlow() to choose the right class for dissection 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 } TCP_guess_payload_class_copy = TCP.guess_payload_class def OpenFlow(self, payload): if self is None or self.dport == 6653 or self.dport == 6633 or self.sport == 6653 or self.sport == 6633: # port 6653 has been allocated by IANA, port 6633 should no longer be used # OpenFlow function may be called with None self in OFPPacketField of_type = orb(payload[1]) if of_type == 1: err_type = orb(payload[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(payload[9]) if mp_type == 255: mp_type = 65535 return ofp_multipart_request_cls[mp_type] elif of_type == 19: mp_type = orb(payload[9]) if mp_type == 255: mp_type = 65535 return ofp_multipart_reply_cls[mp_type] else: return ofpt_cls[of_type] else: return TCP_guess_payload_class_copy(self, payload) TCP.guess_payload_class = OpenFlow