class StatsRequest(GenericMessage): """Request statistics to switch.""" #: OpenFlow :class:`~pyof.v0x01.common.header.Header` header = Header(message_type=Type.OFPT_STATS_REQUEST) body_type = UBInt16(enum_ref=StatsType) flags = UBInt16() body = BinaryData() def __init__(self, xid=None, body_type=None, flags=0, body=b''): """Create a StatsRequest with the optional parameters below. Args: xid (int): xid to be used on the message header. body_type (StatsType): One of the OFPST_* constants. flags (int): OFPSF_REQ_* flags (none yet defined). body (BinaryData): Body of the request. """ super().__init__(xid) self.body_type = body_type self.flags = flags self.body = body def pack(self, value=None): """Pack according to :attr:`body_type`. Make `body` a binary pack before packing this object. Then, restore body. """ backup = self.body if not value: value = self.body if hasattr(value, 'pack'): self.body = value.pack() stats_request_packed = super().pack() self.body = backup return stats_request_packed def unpack(self, buff, offset=0): """Unpack according to :attr:`body_type`.""" super().unpack(buff) class_name = self._get_body_class() buff = self.body.value self.body = FixedTypeList(pyof_class=class_name) self.body.unpack(buff) def _get_body_class(self): if isinstance(self.body_type, (int, UBInt16)): self.body_type = self.body_type.enum_ref(self.body_type.value) module = import_module('pyof.v0x01.controller2switch.common') body_name = self.body_type.name.replace('OFPST_', '').title() for class_name in module.__all__: if 'Request' in class_name and body_name in class_name: return getattr(module, class_name) return None
class StatsRequest(GenericMessage): """Request statistics to switch.""" #: OpenFlow :class:`~pyof.v0x01.common.header.Header` header = Header(message_type=Type.OFPT_STATS_REQUEST) body_type = UBInt16(enum_ref=StatsTypes) flags = UBInt16() body = BinaryData() def __init__(self, xid=None, body_type=None, flags=0, body=b''): """Create a StatsRequest with the optional parameters below. Args: xid (int): xid to be used on the message header. body_type (StatsTypes): One of the OFPST_* constants. flags (int): OFPSF_REQ_* flags (none yet defined). body (BinaryData): Body of the request. """ super().__init__(xid) self.body_type = body_type self.flags = flags self.body = body def pack(self, value=None): """Pack according to :attr:`body_type`. Make `body` a binary pack before packing this object. Then, restore body. """ backup = self.body if not value: value = self.body if hasattr(value, 'pack'): self.body = value.pack() stats_request_packed = super().pack() self.body = backup return stats_request_packed def unpack(self, buff, offset=0): """Unpack according to :attr:`body_type`.""" super().unpack(buff) class_name = self._get_body_class() buff = self.body.value self.body = FixedTypeList(pyof_class=class_name) self.body.unpack(buff) def _get_body_class(self): if isinstance(self.body_type, (int, UBInt16)): self.body_type = self.body_type.enum_ref(self.body_type.value) module = import_module('pyof.v0x01.controller2switch.common') body_name = self.body_type.name.replace('OFPST_', '').title() for class_name in module.__all__: if 'Request' in class_name and body_name in class_name: return getattr(module, class_name) return None
def unpack(self, buff, offset=0): """Unpack according to :attr:`body_type`.""" super().unpack(buff) class_name = self._get_body_class() buff = self.body.value self.body = FixedTypeList(pyof_class=class_name) self.body.unpack(buff)
class GroupDescStats(GenericStruct): """Body of reply to OFPMP_GROUP_DESC request.""" length = UBInt16() group_type = UBInt8() #: Pad to 64 bits. pad = Pad(1) group_id = UBInt32() buckets = FixedTypeList(Bucket) def __init__(self, length=None, group_type=None, group_id=None, buckets=None): """Create a GroupDescStats with the optional parameters below. Args: length (int): Length of this entry. group_type (|GroupType_v0x05|): One of OFPGT_*. group_id (int): Group identifier. buckets (|ListOfBuckets_v0x05|): List of buckets in group. """ super().__init__() self.length = length self.group_type = group_type self.group_id = group_id self.buckets = buckets
def _get_body_instance(self): """Return the body instance.""" exp_header = ExperimenterMultipartHeader simple_body = {MultipartType.OFPMP_DESC: Desc, MultipartType.OFPMP_GROUP_FEATURES: GroupFeatures, MultipartType.OFPMP_METER_FEATURES: MeterFeatures, MultipartType.OFPMP_EXPERIMENTER: exp_header} array_of_bodies = {MultipartType.OFPMP_FLOW: FlowStats, MultipartType.OFPMP_AGGREGATE: AggregateStatsReply, MultipartType.OFPMP_TABLE: TableStats, MultipartType.OFPMP_PORT_STATS: PortStats, MultipartType.OFPMP_QUEUE: QueueStats, MultipartType.OFPMP_GROUP: GroupStats, MultipartType.OFPMP_GROUP_DESC: GroupDescStats, MultipartType.OFPMP_METER: MeterStats, MultipartType.OFPMP_METER_CONFIG: MeterConfig, MultipartType.OFPMP_TABLE_FEATURES: TableFeatures, MultipartType.OFPMP_PORT_DESC: Port} if isinstance(self.multipart_type, UBInt16): self.multipart_type = self.multipart_type.enum_ref( self.multipart_type.value) pyof_class = simple_body.get(self.multipart_type, None) if pyof_class: return pyof_class() array_of_class = array_of_bodies.get(self.multipart_type, None) if array_of_class: return FixedTypeList(pyof_class=array_of_class) return BinaryData(b'')
class TableMod(GenericMessage): """Configure/Modify behavior of a flow table.""" #: class:`~pyof.v0x05.common.action.ActionHeader`: OpenFlow Header header = Header(message_type=Type.OFPT_TABLE_MOD) #: ID of the table, OFPTT_ALL indicates all tables table_id = UBInt8() #: Pad to 32 bits pad = Pad(3) #: Bitmap of OFPTC_* flags config = UBInt32() #: Table Mod Property list properties = FixedTypeList(TableModPropHeader) def __init__(self, xid=None, table_id=Table.OFPTT_ALL, config=3, properties=None): """Assing parameters to object attributes. Args: xid (int): :class:`~pyof.v0x05.common.header.Header`'s xid. Defaults to random. table_id (int): ID of the table, OFPTT_ALL indicates all tables. config (int): Bitmap of OFPTC_* flags """ super().__init__(xid) self.table_id = table_id # This is reserved for future used. The default value is the only valid # one from the Enum. self.config = config self.properties = properties
def _get_body_instance(self): """Return the body instance.""" simple_body = { MultipartTypes.OFPMP_FLOW: FlowStatsRequest, MultipartTypes.OFPMP_AGGREGATE: AggregateStatsRequest, MultipartTypes.OFPMP_PORT_STATS: PortStatsRequest, MultipartTypes.OFPMP_QUEUE: QueueStatsRequest, MultipartTypes.OFPMP_GROUP: GroupStatsRequest, MultipartTypes.OFPMP_METER: MeterMultipartRequest, MultipartTypes.OFPMP_EXPERIMENTER: ExperimenterMultipartHeader } array_of_bodies = {MultipartTypes.OFPMP_TABLE_FEATURES: TableFeatures} if isinstance(self.multipart_type, UBInt16): self.multipart_type = self.multipart_type.enum_ref( self.multipart_type.value) pyof_class = simple_body.get(self.multipart_type, None) if pyof_class: return pyof_class() array_of_class = array_of_bodies.get(self.multipart_type, None) if array_of_class: return FixedTypeList(pyof_class=array_of_class) return BinaryData(b'')
class MeterMod(GenericMessage): """Meter configuration.""" header = Header(message_type=Type.OFPT_METER_MOD) command = UBInt16(enum_ref=MeterModCommand) flags = UBInt16(enum_ref=MeterFlags) meter_id = UBInt32() bands = FixedTypeList(MeterBandHeader) def __init__(self, xid=None, command=None, flags=None, meter_id=None, bands=None): """Instance attributes assignment. Args: xid (int): Headers transaction id. Defaults to random. command (MeterModCommand): One of OFPMC_*. flags (MeterFlags): One of OFPMF_*. meter_id (int): Meter instance. bands (MeterBandHeader): The bands length is inferred from the length field in the header. """ super().__init__(xid) self.command = command self.flags = flags self.meter_id = meter_id self.bands = bands
def __init__(self, xid=None, port_no=None, hw_addr=None, config=None, mask=None, properties=FixedTypeList(pyof_class=PortModPropHeader)): """Create a PortMod with the optional parameters below. Args: xid (int): OpenFlow xid to the header. port_no (int): Physical port number. hw_addr (HWAddress): The hardware address is not configurable. This is used to sanity-check the request, so it must be the same as returned in an ofp_phy_port struct. config (~pyof.v0x05.common.port.PortConfig): Bitmap of OFPPC_* flags mask (~pyof.v0x05.common.port.PortConfig): Bitmap of OFPPC_* flags to be changed properties (FixedTypeList(pyof_class=PortModPropHeader)): Port mod property list - 0 or more properties """ super().__init__(xid) self.port_no = port_no self.hw_addr = hw_addr self.config = config self.mask = mask self.properties = properties
class MeterMod(GenericMessage): """Meter configuration.""" header = Header(message_type=Type.OFPT_METER_MOD) #: One of OFPMC_*. command = UBInt16(enum_ref=MeterModCommand) #: Bitmap of OFPMF_* flags. flags = UBInt16(enum_ref=MeterFlags) #: Meter instance. meter_id = UBInt32() #: The band list length field in the header. bands = FixedTypeList(MeterBandHeader) def __init__(self, xid=None, command=None, flags=None, meter_id=None, bands=None): """Create a MeterMod with the optional parameters below. Args: xid (int): Headers transaction id. Defaults to random. command (MeterModCommand): One of OFPMC_*. flags (MeterFlags): One of OFPMF_*. meter_id (int): Meter instance. bands (MeterBandHeader): The bands length is inferred from the length field in the header. """ super().__init__(xid) self.command = command self.flags = flags self.meter_id = meter_id self.bands = bands
def unpack(self, buff, offset=0): """Unpack according to :attr:`body_type`.""" super().unpack(buff) class_name = self._get_body_class() buff = self.body.value self.body = FixedTypeList(pyof_class=class_name) self.body.unpack(buff)
class Bucket(GenericStruct): """Bucket for use in groups.""" length = UBInt16() weight = UBInt16() watch_port = UBInt32() watch_group = UBInt32() pad = Pad(4) actions = FixedTypeList(ActionHeader) def __init__(self, length=None, weight=None, watch_port=None, watch_group=None, actions=None): """Initialize all instance variables. Args: length (int): Length the bucket in bytes, including this header and any padding to make it 64-bit aligned. weight (int): Relative weight of bucket. Only defined for select groups. watch_port (int): Port whose state affects whether this bucket is live. Only required for fast failover groups. watch_group (int): Group whose state affects whether this bucket is live. Only required for fast failover groups. actions (~pyof.v0x04.common.action.ListOfActions): The action length is inferred from the length field in the header. """ super().__init__() self.length = length self.weight = weight self.watch_port = watch_port self.watch_group = watch_group self.actions = actions def unpack(self, buff, offset=0): """Unpack bucket. Bucket has a dynamic content with length as first field. The length is needed to compute the total buffer offset. """ length = UBInt16() length.unpack(buff, offset=offset) super().unpack(buff[:offset + length.value], offset=offset) def get_size(self, value=None): """ Return the Bucket length. If the object length is None, returns the minimum size. """ if self.length is None: return super().get_size() return self.length
def _get_body_instance(self): """Return the body instance.""" pyof_class = self._get_body_class() if pyof_class is None: return BinaryData(b'') elif pyof_class is DescStats: return pyof_class() return FixedTypeList(pyof_class=pyof_class)
class GroupStats(GenericStruct): """Body of reply to OFPMP_GROUP request.""" length = UBInt16() #: Align to 64 bits. pad = Pad(2) group_id = UBInt32() ref_count = UBInt32() #: Align to 64 bits. pad2 = Pad(4) packet_count = UBInt64() byte_count = UBInt64() duration_sec = UBInt32() duration_nsec = UBInt32() bucket_stats = FixedTypeList(BucketCounter) def __init__(self, length=None, group_id=None, ref_count=None, packet_count=None, byte_count=None, duration_sec=None, duration_nsec=None, bucket_stats=None): """Create a GroupStats with the optional parameters below. Args: length: Length of this entry group_id: Group identifier ref_count: Number of flows or groups that directly forward to this group. packet_count: Number of packets processed by group byte_count: Number of bytes processed by group duration_sec: Time group has been alive in seconds duration_nsec: Time group has been alive in nanoseconds bucket_stats: List of stats of group buckets """ super().__init__() self.length = length self.group_id = group_id self.ref_count = ref_count self.packet_count = packet_count self.byte_count = byte_count self.duration_sec = duration_sec self.duration_nsec = duration_nsec self.bucket_stats = bucket_stats
class PortMod(GenericMessage): """Implement messages to modify the physical port behavior.""" header = Header(message_type=Type.OFPT_PORT_MOD) port_no = UBInt32() pad = Pad(4) #: The hardware address is not configurable. This is used to #: sanity-check the request, so it must be the same as returned in an port struct. hw_addr = HWAddress() #: Pad to 64 bits. pad2 = Pad(2) #: Bitmap of OFPPC_* flags. config = UBInt32(enum_ref=PortConfig) #: Bitmap of OFPPC_* flags to be changed. mask = UBInt32(enum_ref=PortConfig) #: Port mod property list - 0 or more properties properties = FixedTypeList(pyof_class=PortModPropHeader) def __init__(self, xid=None, port_no=None, hw_addr=None, config=None, mask=None, properties=FixedTypeList(pyof_class=PortModPropHeader)): """Create a PortMod with the optional parameters below. Args: xid (int): OpenFlow xid to the header. port_no (int): Physical port number. hw_addr (HWAddress): The hardware address is not configurable. This is used to sanity-check the request, so it must be the same as returned in an ofp_phy_port struct. config (~pyof.v0x05.common.port.PortConfig): Bitmap of OFPPC_* flags mask (~pyof.v0x05.common.port.PortConfig): Bitmap of OFPPC_* flags to be changed properties (FixedTypeList(pyof_class=PortModPropHeader)): Port mod property list - 0 or more properties """ super().__init__(xid) self.port_no = port_no self.hw_addr = hw_addr self.config = config self.mask = mask self.properties = properties
class Bucket(GenericStruct): """Bucket for use in groups.""" length = UBInt16() weight = UBInt16() watch_port = UBInt32() watch_group = UBInt32() pad = Pad(4) actions = FixedTypeList(ActionHeader) def __init__(self, length=None, weight=None, watch_port=None, watch_group=None, actions=None): """Initialize all instance variables. Args: length (int): Length the bucket in bytes, including this header and any padding to make it 64-bit aligned. weight (int): Relative weight of bucket. Only defined for select groups. watch_port (int): Port whose state affects whether this bucket is live. Only required for fast failover groups. watch_group (int): Group whose state affects whether this bucket is live. Only required for fast failover groups. actions (~pyof.v0x04.common.action.ListOfActions): The action length is inferred from the length field in the header. """ super().__init__() self.length = length self.weight = weight self.watch_port = watch_port self.watch_group = watch_group self.actions = actions