blob: 844c6292aaf11930f6077d2816cff3d3174d7c8a [file] [log] [blame]
## 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