pyof.v0x04.controller2switch.multipart_reply   A
last analyzed

Complexity

Total Complexity 32

Size/Duplication

Total Lines 749
Duplicated Lines 17.49 %

Test Coverage

Coverage 84.87%

Importance

Changes 0
Metric Value
wmc 32
eloc 348
dl 131
loc 749
rs 9.84
c 0
b 0
f 0
ccs 258
cts 304
cp 0.8487

23 Methods

Rating   Name   Duplication   Size   Complexity  
A MeterStats.unpack() 0 19 1
A MeterFeatures.__init__() 0 19 1
A MeterConfig.__init__() 0 18 2
A MultipartReply._unpack_body() 0 5 1
A QueueStats.__init__() 0 25 1
A MultipartReply.unpack() 0 18 1
A Desc.__init__() 17 18 1
A PortStats.__init__() 0 49 1
A ListOfBandStats.__init__() 0 8 1
A MultipartReply.__init__() 0 14 1
A FlowStats.__init__() 36 36 1
A MeterStats.__init__() 0 25 2
A MeterStats.pack() 0 9 1
A TableStats.__init__() 0 17 1
A GroupDescStats.__init__() 0 16 1
A BandStats.__init__() 0 11 1
A MeterStats.update_length() 0 3 1
A MultipartReply._get_body_instance() 0 33 4
A GroupFeatures.__init__() 0 24 1
A MultipartReply.pack() 27 27 5
A AggregateStatsReply.__init__() 0 13 1
A GroupStats.__init__() 0 26 1
A FlowStats.unpack() 11 13 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
"""Controller replying state from datapath."""
2
3
# System imports
4 1
from enum import Enum
5
6
# Local source tree imports
7 1
from pyof.foundation.base import GenericBitMask, GenericMessage, GenericStruct
8 1
from pyof.foundation.basic_types import (
9
    BinaryData, Char, FixedTypeList, Pad, UBInt8, UBInt16, UBInt32, UBInt64)
10 1
from pyof.foundation.constants import DESC_STR_LEN, SERIAL_NUM_LEN
11 1
from pyof.v0x04.common.flow_instructions import ListOfInstruction
12 1
from pyof.v0x04.common.flow_match import Match
13 1
from pyof.v0x04.common.header import Header, Type
14 1
from pyof.v0x04.common.port import Port
15 1
from pyof.v0x04.controller2switch.common import (
16
    Bucket, ExperimenterMultipartHeader, ListOfBucketCounter, MultipartType,
17
    TableFeatures)
18 1
from pyof.v0x04.controller2switch.meter_mod import (
19
    ListOfMeterBandHeader, MeterBandType, MeterFlags)
20
21
# Third-party imports
22
23
24 1
__all__ = ('MultipartReply', 'MultipartReplyFlags', 'AggregateStatsReply',
25
           'Desc', 'FlowStats', 'PortStats', 'QueueStats', 'GroupDescStats',
26
           'GroupFeatures', 'GroupStats', 'MeterConfig', 'MeterFeatures',
27
           'BandStats', 'ListOfBandStats', 'MeterStats', 'GroupCapabilities',
28
           'TableStats')
29
30
# Enum
31
32
33 1
class MultipartReplyFlags(Enum):
34
    """Flags for MultipartReply."""
35
36
    #: More replies to follow.
37 1
    OFPMPF_REPLY_MORE = 1 << 0
38
39
40 1
class GroupCapabilities(GenericBitMask):
41
    """Group configuration flags."""
42
43
    #: Support weight for select groups.
44 1
    OFPGFC_SELECT_WEIGHT = 1 << 0
45
    #: Support liveness for select groups.
46 1
    OFPGFC_SELECT_LIVENESS = 1 << 1
47
    #: Support chaining groups.
48 1
    OFPGFC_CHAINING = 1 << 2
49
    #: Chack chaining for loops and delete.
50 1
    OFPGFC_CHAINING_CHECKS = 1 << 3
51
52
# Classes
53
54
55 1
class MultipartReply(GenericMessage):
56
    """Reply datapath state.
57
58
    While the system is running, the controller may reply state from the
59
    datapath using the OFPT_MULTIPART_REPLY message.
60
    """
61
62
    #: Openflow :class:`~pyof.v0x04.common.header.Header`
63 1
    header = Header(message_type=Type.OFPT_MULTIPART_REPLY)
64
    #: One of the OFPMP_* constants.
65 1
    multipart_type = UBInt16(enum_ref=MultipartType)
66
    #: OFPMPF_REPLY_* flags.
67 1
    flags = UBInt16()
68
    #: Padding
69 1
    pad = Pad(4)
70
    #: Body of the reply
71 1
    body = BinaryData()
72
73 1
    def __init__(self, xid=None, multipart_type=None, flags=None, body=b''):
74
        """Create a MultipartReply with the optional parameters below.
75
76
        Args:
77
            xid (int): xid to the header.
78
            multipart_type (int): One of the OFPMP_* constants.
79
            flags (int): OFPMPF_REPLY_* flags.
80
            body (bytes): Body of the reply.
81
82
        """
83 1
        super().__init__(xid)
84 1
        self.multipart_type = multipart_type
85 1
        self.flags = flags
86 1
        self.body = body
87
88 1 View Code Duplication
    def pack(self, value=None):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
89
        """Pack a StatsReply using the object's attributes.
90
91
        This method will pack the attribute body and multipart_type before pack
92
        the StatsReply object, then will return this struct as a binary data.
93
94
        Returns:
95
            stats_reply_packed (bytes): Binary data with StatsReply packed.
96
97
        """
98 1
        buff = self.body
99 1
        if not value:
100 1
            value = self.body
101
102 1
        if value:
103 1
            if isinstance(value, (list, FixedTypeList)):
104 1
                obj = self._get_body_instance()
105 1
                obj.extend(value)
106 1
            elif hasattr(value, 'pack'):
107 1
                obj = value
108
109 1
            self.body = obj.pack()
0 ignored issues
show
introduced by
The variable obj does not seem to be defined for all execution paths.
Loading history...
110
111 1
        multipart_packed = super().pack()
112 1
        self.body = buff
113
114 1
        return multipart_packed
115
116 1
    def unpack(self, buff, offset=0):
117
        """Unpack a binary message into this object's attributes.
118
119
        Unpack the binary value *buff* and update this object attributes based
120
        on the results. It is an inplace method and it receives the binary data
121
        of the message **without the header**.
122
123
        This class' unpack method is like the :meth:`.GenericMessage.unpack`
124
        one, except for the ``body`` attribute which has its type determined
125
        by the ``multipart_type`` attribute.
126
127
        Args:
128
            buff (bytes): Binary data package to be unpacked, without the
129
                header.
130
131
        """
132 1
        super().unpack(buff[offset:])
133 1
        self._unpack_body()
134
135 1
    def _unpack_body(self):
136
        """Unpack `body` replace it by the result."""
137 1
        obj = self._get_body_instance()
138 1
        obj.unpack(self.body.value)
139 1
        self.body = obj
140
141 1
    def _get_body_instance(self):
142
        """Return the body instance."""
143 1
        exp_header = ExperimenterMultipartHeader
144 1
        simple_body = {MultipartType.OFPMP_DESC: Desc,
145
                       MultipartType.OFPMP_GROUP_FEATURES: GroupFeatures,
146
                       MultipartType.OFPMP_METER_FEATURES: MeterFeatures,
147
                       MultipartType.OFPMP_EXPERIMENTER: exp_header}
148
149 1
        array_of_bodies = {MultipartType.OFPMP_FLOW: FlowStats,
150
                           MultipartType.OFPMP_AGGREGATE: AggregateStatsReply,
151
                           MultipartType.OFPMP_TABLE: TableStats,
152
                           MultipartType.OFPMP_PORT_STATS: PortStats,
153
                           MultipartType.OFPMP_QUEUE: QueueStats,
154
                           MultipartType.OFPMP_GROUP: GroupStats,
155
                           MultipartType.OFPMP_GROUP_DESC: GroupDescStats,
156
                           MultipartType.OFPMP_METER: MeterStats,
157
                           MultipartType.OFPMP_METER_CONFIG: MeterConfig,
158
                           MultipartType.OFPMP_TABLE_FEATURES: TableFeatures,
159
                           MultipartType.OFPMP_PORT_DESC: Port}
160
161 1
        if isinstance(self.multipart_type, UBInt16):
162 1
            self.multipart_type = self.multipart_type.enum_ref(
163
                self.multipart_type.value)
164
165 1
        pyof_class = simple_body.get(self.multipart_type, None)
166 1
        if pyof_class:
167 1
            return pyof_class()
168
169 1
        array_of_class = array_of_bodies.get(self.multipart_type, None)
170 1
        if array_of_class:
171 1
            return FixedTypeList(pyof_class=array_of_class)
172
173
        return BinaryData(b'')
174
175
176
# MultipartReply Body
177
178 1
class AggregateStatsReply(GenericStruct):
179
    """Body of reply to OFPMP_AGGREGATE request."""
180
181
    #: Number of packets in flows.
182 1
    packet_count = UBInt64()
183
    #: Number of bytes in flows.
184 1
    byte_count = UBInt64()
185
    #: Number of flows.
186 1
    flow_count = UBInt32()
187
    #: Align to 64 bits
188 1
    pad = Pad(4)
189
190 1
    def __init__(self, packet_count=None, byte_count=None, flow_count=None):
191
        """Create a AggregateStatsReply with the optional parameters below.
192
193
        Args:
194
            packet_count (int): Number of packets in flows
195
            byte_count (int):   Number of bytes in flows
196
            flow_count (int):   Number of flows
197
198
        """
199 1
        super().__init__()
200 1
        self.packet_count = packet_count
201 1
        self.byte_count = byte_count
202 1
        self.flow_count = flow_count
203
204
205 1 View Code Duplication
class Desc(GenericStruct):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
206
    """Information available from the OFPST_DESC stats request.
207
208
    Information about the switch manufacturer, hardware revision, software
209
    revision, serial number and a description field.
210
    """
211
212
    #: Manufacturer description
213 1
    mfr_desc = Char(length=DESC_STR_LEN)
214
    #: Hardware description
215 1
    hw_desc = Char(length=DESC_STR_LEN)
216
    #: Software description
217 1
    sw_desc = Char(length=DESC_STR_LEN)
218
    #: Serial number
219 1
    serial_num = Char(length=SERIAL_NUM_LEN)
220
    #: Datapath description
221 1
    dp_desc = Char(length=DESC_STR_LEN)
222
223 1
    def __init__(self, mfr_desc=None, hw_desc=None, sw_desc=None,
224
                 serial_num=None, dp_desc=None):
225
        """Create a Desc with the optional parameters below.
226
227
        Args:
228
            mfr_desc (str): Manufacturer description
229
            hw_desc (str): Hardware description
230
            sw_desc (str): Software description
231
            serial_num (str): Serial number
232
            dp_desc (str): Datapath description
233
234
        """
235 1
        super().__init__()
236 1
        self.mfr_desc = mfr_desc
237 1
        self.hw_desc = hw_desc
238 1
        self.sw_desc = sw_desc
239 1
        self.serial_num = serial_num
240 1
        self.dp_desc = dp_desc
241
242
243 1 View Code Duplication
class FlowStats(GenericStruct):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
244
    """Body of reply to OFPST_FLOW request."""
245
246 1
    length = UBInt16()
247 1
    table_id = UBInt8()
248
    #: Align to 32 bits.
249 1
    pad = Pad(1)
250 1
    duration_sec = UBInt32()
251 1
    duration_nsec = UBInt32()
252 1
    priority = UBInt16()
253 1
    idle_timeout = UBInt16()
254 1
    hard_timeout = UBInt16()
255 1
    flags = UBInt16()
256
    #: Align to 64-bits
257 1
    pad2 = Pad(4)
258 1
    cookie = UBInt64()
259 1
    packet_count = UBInt64()
260 1
    byte_count = UBInt64()
261 1
    match = Match()
262 1
    instructions = ListOfInstruction()
263
264 1
    def __init__(self, length=None, table_id=None, duration_sec=None,
265
                 duration_nsec=None, priority=None, idle_timeout=None,
266
                 hard_timeout=None, flags=None, cookie=None, packet_count=None,
267
                 byte_count=None, match=None, instructions=None):
268
        """Create a FlowStats with the optional parameters below.
269
270
        Args:
271
            length (int): Length of this entry.
272
            table_id (int): ID of table flow came from.
273
            duration_sec (int): Time flow has been alive in seconds.
274
            duration_nsec (int): Time flow has been alive in nanoseconds in
275
                addition to duration_sec.
276
            priority (int): Priority of the entry. Only meaningful when this
277
                is not an exact-match entry.
278
            idle_timeout (int): Number of seconds idle before expiration.
279
            hard_timeout (int): Number of seconds before expiration.
280
            cookie (int): Opaque controller-issued identifier.
281
            packet_count (int): Number of packets in flow.
282
            byte_count (int): Number of bytes in flow.
283
            match (~pyof.v0x04.common.flow_match.Match): Description of fields.
284
285
        """
286 1
        super().__init__()
287 1
        self.length = length
288 1
        self.table_id = table_id
289 1
        self.duration_sec = duration_sec
290 1
        self.duration_nsec = duration_nsec
291 1
        self.priority = priority
292 1
        self.idle_timeout = idle_timeout
293 1
        self.hard_timeout = hard_timeout
294 1
        self.flags = flags
295 1
        self.cookie = cookie
296 1
        self.packet_count = packet_count
297 1
        self.byte_count = byte_count
298 1
        self.match = match
299 1
        self.instructions = instructions or []
300
301 1
    def unpack(self, buff, offset=0):
302
        """Unpack a binary message into this object's attributes.
303
304
        Pass the correct length for list unpacking.
305
306
        Args:
307
            buff (bytes): Binary data package to be unpacked.
308
            offset (int): Where to begin unpacking.
309
310
        """
311 1
        unpack_length = UBInt16()
312 1
        unpack_length.unpack(buff, offset)
313 1
        super().unpack(buff[:offset+unpack_length], offset)
314
315
316 1
class PortStats(GenericStruct):
317
    """Body of reply to OFPST_PORT request.
318
319
    If a counter is unsupported, set the field to all ones.
320
    """
321
322 1
    port_no = UBInt32()
323
    #: Align to 64-bits.
324 1
    pad = Pad(4)
325 1
    rx_packets = UBInt64()
326 1
    tx_packets = UBInt64()
327 1
    rx_bytes = UBInt64()
328 1
    tx_bytes = UBInt64()
329 1
    rx_dropped = UBInt64()
330 1
    tx_dropped = UBInt64()
331 1
    rx_errors = UBInt64()
332 1
    tx_errors = UBInt64()
333 1
    rx_frame_err = UBInt64()
334 1
    rx_over_err = UBInt64()
335 1
    rx_crc_err = UBInt64()
336 1
    collisions = UBInt64()
337 1
    duration_sec = UBInt32()
338 1
    duration_nsec = UBInt32()
339
340 1
    def __init__(self, port_no=None, rx_packets=None,
341
                 tx_packets=None, rx_bytes=None, tx_bytes=None,
342
                 rx_dropped=None, tx_dropped=None, rx_errors=None,
343
                 tx_errors=None, rx_frame_err=None, rx_over_err=None,
344
                 rx_crc_err=None, collisions=None, duration_sec=None,
345
                 duration_nsec=None):
346
        """Create a PortStats with the optional parameters below.
347
348
        Args:
349
            port_no (:class:`int`, :class:`~pyof.v0x04.common.port.Port`):
350
                Port number.
351
            rx_packets (int): Number of received packets.
352
            tx_packets (int): Number of transmitted packets.
353
            rx_bytes (int): Number of received bytes.
354
            tx_bytes (int): Number of transmitted bytes.
355
            rx_dropped (int): Number of packets dropped by RX.
356
            tx_dropped (int): Number of packets dropped by TX.
357
            rx_errors (int): Number of receive errors. This is a super-set of
358
                more specific receive errors and should be greater than or
359
                equal to the sum of all rx_*_err values.
360
            tx_errors (int): Number of transmit errors.  This is a super-set of
361
                more specific transmit errors and should be greater than or
362
                equal to the sum of all tx_*_err values (none currently
363
                defined).
364
            rx_frame_err (int): Number of frame alignment errors.
365
            rx_over_err (int): Number of packets with RX overrun.
366
            rx_crc_err (int): Number of CRC errors.
367
            collisions (int): Number of collisions.
368
            duration_sec (int): Time port has been alive in seconds
369
            duration_nsec (int): Time port has been alive in nanoseconds beyond
370
                duration_sec
371
372
        """
373 1
        super().__init__()
374 1
        self.port_no = port_no
375 1
        self.rx_packets = rx_packets
376 1
        self.tx_packets = tx_packets
377 1
        self.rx_bytes = rx_bytes
378 1
        self.tx_bytes = tx_bytes
379 1
        self.rx_dropped = rx_dropped
380 1
        self.tx_dropped = tx_dropped
381 1
        self.rx_errors = rx_errors
382 1
        self.tx_errors = tx_errors
383 1
        self.rx_frame_err = rx_frame_err
384 1
        self.rx_over_err = rx_over_err
385 1
        self.rx_crc_err = rx_crc_err
386 1
        self.collisions = collisions
387 1
        self.duration_sec = duration_sec
388 1
        self.duration_nsec = duration_nsec
389
390
391 1
class QueueStats(GenericStruct):
392
    """Implements the reply body of a port_no."""
393
394 1
    port_no = UBInt32()
395 1
    queue_id = UBInt32()
396 1
    tx_bytes = UBInt64()
397 1
    tx_packets = UBInt64()
398 1
    tx_errors = UBInt64()
399 1
    duration_sec = UBInt32()
400 1
    duration_nsec = UBInt32()
401
402 1
    def __init__(self, port_no=None, queue_id=None, tx_bytes=None,
403
                 tx_packets=None, tx_errors=None, duration_sec=None,
404
                 duration_nsec=None):
405
        """Create a QueueStats with the optional parameters below.
406
407
        Args:
408
            port_no (:class:`int`, :class:`~pyof.v0x04.common.port.Port`):
409
                Port Number.
410
            queue_id (int): Queue ID.
411
            tx_bytes (int): Number of transmitted bytes.
412
            tx_packets (int): Number of transmitted packets.
413
            tx_errors (int): Number of packets dropped due to overrun.
414
            duration_sec (int): Time queue has been alive in seconds.
415
            duration_nsec (int): Time queue has been alive in nanoseconds
416
                beyond duration_sec.
417
418
        """
419 1
        super().__init__()
420 1
        self.port_no = port_no
421 1
        self.queue_id = queue_id
422 1
        self.tx_bytes = tx_bytes
423 1
        self.tx_packets = tx_packets
424 1
        self.tx_errors = tx_errors
425 1
        self.duration_sec = duration_sec
426 1
        self.duration_nsec = duration_nsec
427
428
429 1
class GroupDescStats(GenericStruct):
430
    """Body of reply to OFPMP_GROUP_DESC request."""
431
432 1
    length = UBInt16()
433 1
    group_type = UBInt8()
434
    #: Pad to 64 bits.
435 1
    pad = Pad(1)
436 1
    group_id = UBInt32()
437 1
    buckets = FixedTypeList(Bucket)
438
439 1
    def __init__(self, length=None, group_type=None, group_id=None,
440
                 buckets=None):
441
        """Create a GroupDescStats with the optional parameters below.
442
443
        Args:
444
            length (int): Length of this entry.
445
            group_type (|GroupType_v0x04|): One of OFPGT_*.
446
            group_id (int): Group identifier.
447
            buckets (|ListOfBuckets_v0x04|): List of buckets in group.
448
449
        """
450
        super().__init__()
451
        self.length = length
452
        self.group_type = group_type
453
        self.group_id = group_id
454
        self.buckets = buckets
455
456
457 1
class GroupFeatures(GenericStruct):
458
    """Body of reply to OFPMP_GROUP_FEATURES request.Group features."""
459
460 1
    types = UBInt32()
461 1
    capabilities = UBInt32(enum_ref=GroupCapabilities)
462 1
    max_groups1 = UBInt32()
463 1
    max_groups2 = UBInt32()
464 1
    max_groups3 = UBInt32()
465 1
    max_groups4 = UBInt32()
466 1
    actions1 = UBInt32()
467 1
    actions2 = UBInt32()
468 1
    actions3 = UBInt32()
469 1
    actions4 = UBInt32()
470
471 1
    def __init__(self, types=None, capabilities=None, max_groups1=None,
472
                 max_groups2=None, max_groups3=None, max_groups4=None,
473
                 actions1=None, actions2=None, actions3=None, actions4=None):
474
        """Create a GroupFeatures with the optional parameters below.
475
476
        Args:
477
            types: Bitmap of OFPGT_* values supported.
478
            capabilities: Bitmap of OFPGFC_* capability supported.
479
            max_groups: 4-position array; Maximum number of groups for each
480
                type.
481
            actions: 4-position array; Bitmaps of OFPAT_* that are supported.
482
483
        """
484
        super().__init__()
485
        self.types = types
486
        self.capabilities = capabilities
487
        self.max_groups1 = max_groups1
488
        self.max_groups2 = max_groups2
489
        self.max_groups3 = max_groups3
490
        self.max_groups4 = max_groups4
491
        self.actions1 = actions1
492
        self.actions2 = actions2
493
        self.actions3 = actions3
494
        self.actions4 = actions4
495
496
497 1
class GroupStats(GenericStruct):
498
    """Body of reply to OFPMP_GROUP request."""
499
500 1
    length = UBInt16()
501
    #: Align to 64 bits.
502 1
    pad = Pad(2)
503 1
    group_id = UBInt32()
504 1
    ref_count = UBInt32()
505
    #: Align to 64 bits.
506 1
    pad2 = Pad(4)
507 1
    packet_count = UBInt64()
508 1
    byte_count = UBInt64()
509 1
    duration_sec = UBInt32()
510 1
    duration_nsec = UBInt32()
511 1
    bucket_stats = ListOfBucketCounter()
512
513 1
    def __init__(self, length=None, group_id=None, ref_count=None,
514
                 packet_count=None, byte_count=None, duration_sec=None,
515
                 duration_nsec=None, bucket_stats=None):
516
        """Create a GroupStats with the optional parameters below.
517
518
        Args:
519
            length: Length of this entry
520
            group_id: Group identifier
521
            ref_count: Number of flows or groups that directly forward
522
                to this group.
523
            packet_count: Number of packets processed by group
524
            byte_count: Number of bytes processed by group
525
            duration_sec: Time group has been alive in seconds
526
            duration_nsec: Time group has been alive in nanoseconds
527
            bucket_stats: List of stats of group buckets
528
529
        """
530 1
        super().__init__()
531 1
        self.length = length
532 1
        self.group_id = group_id
533 1
        self.ref_count = ref_count
534 1
        self.packet_count = packet_count
535 1
        self.byte_count = byte_count
536 1
        self.duration_sec = duration_sec
537 1
        self.duration_nsec = duration_nsec
538 1
        self.bucket_stats = bucket_stats
539
540
541 1
class MeterConfig(GenericStruct):
542
    """MeterConfig is a class to represent ofp_meter_config structure.
543
544
    Body of reply to OFPMP_METER_CONFIG request.
545
    """
546
547
    # Length of this entry.
548 1
    length = UBInt16()
549
    # All OFPMC_* that apply.
550 1
    flags = UBInt16(enum_ref=MeterFlags)
551
    # Meter instance or OFPM_ALL .
552 1
    meter_id = UBInt32()
553
    # The bands length is inferred from the length field.
554 1
    bands = ListOfMeterBandHeader()
555
556 1
    def __init__(self, flags=MeterFlags.OFPMF_STATS, meter_id=None,
557
                 bands=None):
558
        """Create a MeterConfig with the optional parameters below.
559
560
        Args:
561
            flags (|MeterFlags_v0x04|):
562
                Meter configuration flags.The default value is
563
                MeterFlags.OFPMF_STATS
564
            meter_id (|Meter_v0x04|):
565
                Meter Indentify.The value Meter.OFPM_ALL is used to
566
                refer to all Meters on the switch.
567
            bands(list): List of MeterBandHeader instances.
568
569
        """
570
        super().__init__()
571
        self.flags = flags
572
        self.meter_id = meter_id
573
        self.bands = bands if bands else []
574
575
576 1
class MeterFeatures(GenericStruct):
577
    """Body of reply to OFPMP_METER_FEATURES request. Meter features."""
578
579 1
    max_meter = UBInt32()
580 1
    band_types = UBInt32(enum_ref=MeterBandType)
581 1
    capabilities = UBInt32(enum_ref=MeterFlags)
582 1
    max_bands = UBInt8()
583 1
    max_color = UBInt8()
584 1
    pad = Pad(2)
585
586 1
    def __init__(self, max_meter=None, band_types=None, capabilities=None,
587
                 max_bands=None, max_color=None):
588
        """Create a MeterFeatures with the optional parameters below.
589
590
        Args:
591
            max_meter(int): Maximum number of meters.
592
            band_types (|MeterBandType_v0x04|):
593
                Bitmaps of OFPMBT_* values supported.
594
            capabilities (|MeterFlags_v0x04|): Bitmaps of "ofp_meter_flags".
595
            max_bands(int): Maximum bands per meters
596
            max_color(int): Maximum color value
597
598
        """
599
        super().__init__()
600
        self.max_meter = max_meter
601
        self.band_types = band_types
602
        self.capabilities = capabilities
603
        self.max_bands = max_bands
604
        self.max_color = max_color
605
606
607 1
class BandStats(GenericStruct):
608
    """Band  Statistics.
609
610
    Statistics for each meter band.
611
    """
612
613 1
    packet_band_count = UBInt64()
614 1
    byte_band_count = UBInt64()
615
616 1
    def __init__(self, packet_band_count=None, byte_band_count=None):
617
        """Create a BandStats with the optional parameters below.
618
619
        Args:
620
            packet_band_count(int): Number of packets in band.
621
            byte_band_count(int):   Number of bytes in band.
622
623
        """
624
        super().__init__()
625
        self.packet_band_count = packet_band_count
626
        self.byte_band_count = byte_band_count
627
628
629 1
class ListOfBandStats(FixedTypeList):
630
    """List of BandStats.
631
632
    Represented by instances of BandStats.
633
    """
634
635 1
    def __init__(self, items=None):
636
        """Create a ListOfBandStats with the optional parameters below.
637
638
        Args:
639
            items (|BandStats_v0x04|): Instance or a list of instances.
640
641
        """
642 1
        super().__init__(pyof_class=BandStats, items=items)
643
644
645 1
class MeterStats(GenericStruct):
646
    """Meter Statistics.
647
648
    Body of reply to OFPMP_METER request.
649
    """
650
651 1
    meter_id = UBInt32()
652 1
    length = UBInt16()
653 1
    pad = Pad(6)
654 1
    flow_count = UBInt32()
655 1
    packet_in_count = UBInt64()
656 1
    byte_in_count = UBInt64()
657 1
    duration_sec = UBInt32()
658 1
    duration_nsec = UBInt32()
659 1
    band_stats = ListOfBandStats()
660
661 1
    def __init__(self, meter_id=None, flow_count=None,
662
                 packet_in_count=None, byte_in_count=None, duration_sec=None,
663
                 duration_nsec=None, band_stats=None):
664
        """Create a MeterStats with the optional parameters below.
665
666
        Args:
667
            meter_id (|Meter_v0x04|):  Meter instance.
668
            flow_count(int):      Number of flows bound to meter.
669
            packet_in_count(int): Number of packets in input.
670
            byte_in_count(int):   Number of bytes in input.
671
            duration_sec(int):    Time meter has been alive in seconds.
672
            duration_nsec(int):   Time meter has been alive in
673
                                  nanoseconds beyond duration_sec.
674
            band_stats(list):     Instances of BandStats
675
676
        """
677
        super().__init__()
678
        self.meter_id = meter_id
679
        self.flow_count = flow_count
680
        self.packet_in_count = packet_in_count
681
        self.byte_in_count = byte_in_count
682
        self.duration_sec = duration_sec
683
        self.duration_nsec = duration_nsec
684
        self.band_stats = band_stats if band_stats else []
685
        self.update_length()
686
687 1
    def update_length(self):
688
        """Update length attribute with current struct length."""
689
        self.length = self.get_size()
690
691 1
    def pack(self, value=None):
692
        """Pack method used to update the length of instance and packing.
693
694
        Args:
695
            value: Structure to be packed.
696
697
        """
698
        self.update_length()
699
        return super().pack(value)
700
701 1
    def unpack(self, buff=None, offset=0):
702
        """Unpack *buff* into this object.
703
704
        This method will convert a binary data into a readable value according
705
        to the attribute format.
706
707
        Args:
708
            buff (bytes): Binary buffer.
709
            offset (int): Where to begin unpacking.
710
711
        Raises:
712
            :exc:`~.exceptions.UnpackException`: If unpack fails.
713
714
        """
715
        length = UBInt16()
716
        length.unpack(buff, offset)
717
718
        length.unpack(buff, offset=offset+MeterStats.meter_id.get_size())
719
        super().unpack(buff[:offset+length.value], offset=offset)
720
721
722 1
class TableStats(GenericStruct):
723
    """Body of reply to OFPST_TABLE request."""
724
725 1
    table_id = UBInt8()
726
    #: Align to 32-bits.
727 1
    pad = Pad(3)
728 1
    active_count = UBInt32()
729 1
    lookup_count = UBInt64()
730 1
    matched_count = UBInt64()
731
732 1
    def __init__(self, table_id=None, active_count=None, lookup_count=None,
733
                 matched_count=None):
734
        """Create a TableStats with the optional parameters below.
735
736
        Args:
737
            table_id (int): Identifier of table.  Lower numbered tables are
738
                consulted first.
739
            active_count (int): Number of active entries.
740
            lookup_count (int): Number of packets looked up in table.
741
            matched_count (int): Number of packets that hit table.
742
743
        """
744 1
        super().__init__()
745 1
        self.table_id = table_id
746 1
        self.active_count = active_count
747 1
        self.lookup_count = lookup_count
748
        self.matched_count = matched_count
749