Test Failed
Push — master ( 182015...f7f025 )
by Carlos Eduardo
01:35
created

MultipartReply._get_body_instance()   B

Complexity

Conditions 4

Size

Total Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

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