Test Failed
Pull Request — master (#461)
by Diego Rabatone
01:50
created

MultipartReplyFlags

Complexity

Total Complexity 0

Size/Duplication

Total Lines 5
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

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