| ## This file is part of Scapy |
| ## See http://www.secdev.org/projects/scapy for more information |
| ## Copyright (C) Philippe Biondi <phil@secdev.org> |
| ## This program is published under a GPLv2 license |
| |
| ## Copyright (C) 2014 Maxence Tury <maxence.tury@ssi.gouv.fr> |
| ## 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 <OFPMatch> or <OFPMatch <Padding>> |
| ### or <OFPMatch <Raw>> or <OFPMatch <Raw <Padding>>> |
| ### and we want to return "", <OFPMatch> or "", <OFPMatch <Padding>> |
| ### or raw(<Raw>), <OFPMatch> or raw(<Raw>), <OFPMatch <Padding>> |
| 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 |