Passed
Pull Request — master (#462)
by
unknown
01:55
created

ActionSetField   A

Complexity

Total Complexity 5

Size/Duplication

Total Lines 36
Duplicated Lines 0 %

Test Coverage

Coverage 35.29%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 5
c 1
b 0
f 0
dl 0
loc 36
ccs 6
cts 17
cp 0.3529
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A _prepare_pack() 0 11 2
A __init__() 0 13 2
A pack() 0 4 1
1
"""Defines actions that may be associated with flows packets."""
2
# System imports
3 1
from enum import IntEnum
4
5
# Local source tree imports
6 1
from pyof.foundation.base import GenericStruct
7 1
from pyof.foundation.basic_types import (
8
    BinaryData, FixedTypeList, Pad, UBInt8, UBInt16, UBInt32)
9 1
from pyof.v0x04.common.flow_match import OxmTLV
10
11
# Third-party imports
12
13 1
__all__ = ('ActionExperimenterHeader', 'ActionGroup', 'ActionHeader',
14
           'ActionCopyTTLIn', 'ActionCopyTTLOut', 'ActionDecMPLSTTL',
15
           'ActionSetMPLSTTL', 'ActionDecNWTTL', 'ActionSetNWTTL',
16
           'ActionOutput', 'ActionPopMPLS', 'ActionPopPBB', 'ActionPopVLAN',
17
           'ActionPush', 'ActionSetField', 'ActionSetQueue', 'ActionType',
18
           'ControllerMaxLen', 'ListOfActions')
19
20
# Enums
21
22
23 1
class ActionType(IntEnum):
24
    """Actions associated with flows and packets."""
25
26
    #: Output to switch port.
27 1
    OFPAT_OUTPUT = 0
28
    #: Copy TTL "outwards" -- from next-to-outermost to outermost
29 1
    OFPAT_COPY_TTL_OUT = 11
30
    #: Copy TTL "inwards" -- from outermost to next-to-outermost
31 1
    OFPAT_COPY_TTL_IN = 12
32
    #: MPLS TTL
33 1
    OFPAT_SET_MPLS_TTL = 15
34
    #: Decrement MPLS TTL
35 1
    OFPAT_DEC_MPLS_TTL = 16
36
    #: Push a new VLAN tag
37 1
    OFPAT_PUSH_VLAN = 17
38
    #: Pop the outer VLAN tag
39 1
    OFPAT_POP_VLAN = 18
40
    #: Push a new MPLS tag
41 1
    OFPAT_PUSH_MPLS = 19
42
    #: Pop the outer MPLS tag
43 1
    OFPAT_POP_MPLS = 20
44
    #: Set queue id when outputting to a port
45 1
    OFPAT_SET_QUEUE = 21
46
    #: Apply group.
47 1
    OFPAT_GROUP = 22
48
    #: IP TTL.
49 1
    OFPAT_SET_NW_TTL = 23
50
    #: Decrement IP TTL.
51 1
    OFPAT_DEC_NW_TTL = 24
52
    #: Set a header field using OXM TLV format.
53 1
    OFPAT_SET_FIELD = 25
54
    #: Push a new PBB service tag (I-TAG)
55 1
    OFPAT_PUSH_PBB = 26
56
    #: Pop the outer PBB service tag (I-TAG)
57 1
    OFPAT_POP_PBB = 27
58
    #: Experimenter type
59 1
    OFPAT_EXPERIMENTER = 0xffff
60
61
62 1
class ControllerMaxLen(IntEnum):
63
    """A max_len of OFPCML_NO_BUFFER means not to buffer.
64
65
    The packet should be sent.
66
    """
67
68
    #: maximum max_len value which can be used to request a specific byte
69
    #:     length.
70 1
    OFPCML_MAX = 0xffe5
71
    #: indicates that no buffering should be applied and the whole packet is to
72
    #:     be sent to the controller.
73 1
    OFPCML_NO_BUFFER = 0xffff
74
75
76
# Classes
77
78
79 1
class ActionHeader(GenericStruct):
80
    """Action header that is common to all actions.
81
82
    The length includes the header and any padding used to make the action
83
    64-bit aligned.
84
    NB: The length of an action *must* always be a multiple of eight.
85
    """
86
87
    #: One of OFPAT_*.
88 1
    action_type = UBInt16(enum_ref=ActionType)
89
    #: Length of action, including this header. This is the length of actions,
90
    #:    including any padding to make it 64-bit aligned.
91 1
    length = UBInt16()
92
    # Pad for 64-bit alignment.
93
    # This should not be implemented, as each action type has its own padding.
94
    # pad = Pad(4)
95
96 1
    _allowed_types = ()
97
98 1
    def __init__(self, action_type=None, length=None):
99
        """Create an ActionHeader with the optional parameters below.
100
101
        Args:
102
            action_type (~pyof.v0x04.common.action.ActionType):
103
                The type of the action.
104
            length (int): Length of action, including this header.
105
        """
106
        super().__init__()
107
        self.action_type = action_type
108
        self.length = length
109
110 1
    def unpack(self, buff, offset=0):
111
        """Unpack a binary message into this object's attributes.
112
113
        Unpack the binary value *buff* and update this object attributes based
114
        on the results.
115
116
        Args:
117
            buff (bytes): Binary data package to be unpacked.
118
            offset (int): Where to begin unpacking.
119
120
        Raises:
121
            Exception: If there is a struct unpacking error.
122
123
        """
124
        self.action_type = UBInt16(enum_ref=ActionType)
125
        self.action_type.unpack(buff, offset)
126
127
        for cls in ActionHeader.__subclasses__():
128
            if self.action_type.value in cls.get_allowed_types():
129
                self.__class__ = cls
130
                break
131
132
        super().unpack(buff, offset)
133
134 1
    @classmethod
135
    def get_allowed_types(cls):
136
        """Return allowed types for the class."""
137
        return cls._allowed_types
138
139
140 1
class ActionExperimenterHeader(ActionHeader):
141
    """Action structure for OFPAT_EXPERIMENTER."""
142
143 1
    experimenter = UBInt32()
144
145 1
    _allowed_types = ActionType.OFPAT_EXPERIMENTER,
146
147 1
    def __init__(self, length=None, experimenter=None):
148
        """Create ActionExperimenterHeader with the optional parameters below.
149
150
        Args:
151
            experimenter (int): The experimenter field is the Experimenter ID,
152
                which takes the same form as in struct ofp_experimenter.
153
        """
154
        super().__init__(action_type=ActionType.OFPAT_EXPERIMENTER)
155
        self.length = length
156
        self.experimenter = experimenter
157
158
159 1
class ActionGroup(ActionHeader):
160
    """Action structure for OFPAT_GROUP."""
161
162 1
    group_id = UBInt32()
163
164 1
    _allowed_types = ActionType.OFPAT_GROUP,
165
166 1
    def __init__(self, group_id=None):
167
        """Create an ActionGroup with the optional parameters below.
168
169
        Args:
170
            group_id (int): The group_id indicates the group used to process
171
                this packet. The set of buckets to apply depends on the group
172
                type.
173
        """
174
        super().__init__(action_type=ActionType.OFPAT_GROUP, length=8)
175
        self.group_id = group_id
176
177
178 1
class ActionDecMPLSTTL(ActionHeader):
179
    """Action structure for OFPAT_DEC_MPLS_TTL."""
180
181 1
    pad = Pad(4)
182
183 1
    _allowed_types = ActionType.OFPAT_DEC_MPLS_TTL,
184
185 1
    def __init__(self):
186
        """Create an ActionDecMPLSTTL."""
187
        super().__init__(action_type=ActionType.OFPAT_DEC_MPLS_TTL, length=8)
188
189
190 1
class ActionSetMPLSTTL(ActionHeader):
191
    """Action structure for OFPAT_SET_MPLS_TTL."""
192
193 1
    mpls_ttl = UBInt8()
194 1
    pad = Pad(3)
195
196 1
    _allowed_types = ActionType.OFPAT_SET_MPLS_TTL,
197
198 1
    def __init__(self, mpls_ttl=None):
199
        """Create an ActionSetMPLSTTL with the optional parameters below.
200
201
        Args:
202
            mpls_ttl (int): The mpls_ttl field is the MPLS TTL to set.
203
        """
204
        super().__init__(action_type=ActionType.OFPAT_SET_MPLS_TTL, length=8)
205
        self.mpls_ttl = mpls_ttl
206
207
208 1
class ActionCopyTTLIn(ActionHeader):
209
    """Action structure for OFPAT_COPY_TTL_IN."""
210
211 1
    pad = Pad(4)
212
213 1
    _allowed_types = ActionType.OFPAT_COPY_TTL_IN,
214
215 1
    def __init__(self):
216
        """Create an ActionCopyTTLIn."""
217
        super().__init__(action_type=ActionType.OFPAT_COPY_TTL_IN, length=8)
218
219
220 1
class ActionCopyTTLOut(ActionHeader):
221
    """Action structure for OFPAT_COPY_TTL_OUT."""
222
223 1
    pad = Pad(4)
224
225 1
    _allowed_types = ActionType.OFPAT_COPY_TTL_OUT,
226
227 1
    def __init__(self):
228
        """Create an ActionCopyTTLOut."""
229
        super().__init__(action_type=ActionType.OFPAT_COPY_TTL_OUT, length=8)
230
231
232 1
class ActionPopVLAN(ActionHeader):
233
    """Action structure for OFPAT_POP_VLAN."""
234
235 1
    pad = Pad(4)
236
237 1
    _allowed_types = ActionType.OFPAT_POP_VLAN,
238
239 1
    def __init__(self):
240
        """Create an ActionPopVLAN."""
241
        super().__init__(action_type=ActionType.OFPAT_POP_VLAN, length=8)
242
243
244 1
class ActionPopPBB(ActionHeader):
245
    """Action structure for OFPAT_POP_PBB."""
246
247 1
    pad = Pad(4)
248
249 1
    _allowed_types = ActionType.OFPAT_POP_PBB,
250
251 1
    def __init__(self):
252
        """Create an ActionPopPBB."""
253
        super().__init__(action_type=ActionType.OFPAT_POP_PBB, length=8)
254
255
256 1
class ActionDecNWTTL(ActionHeader):
257
    """Action structure for OFPAT_DEC_NW_TTL."""
258
259 1
    pad = Pad(4)
260
261 1
    _allowed_types = ActionType.OFPAT_DEC_NW_TTL,
262
263 1
    def __init__(self):
264
        """Create a ActionDecNWTTL."""
265
        super().__init__(action_type=ActionType.OFPAT_DEC_NW_TTL, length=8)
266
267
268 1
class ActionSetNWTTL(ActionHeader):
269
    """Action structure for OFPAT_SET_NW_TTL."""
270
271 1
    nw_ttl = UBInt8()
272 1
    pad = Pad(3)
273
274 1
    _allowed_types = ActionType.OFPAT_SET_NW_TTL,
275
276 1
    def __init__(self, nw_ttl=None):
277
        """Create an ActionSetNWTTL with the optional parameters below.
278
279
        Args:
280
            nw_ttl (int): the TTL address to set in the IP header.
281
        """
282
        super().__init__(action_type=ActionType.OFPAT_SET_NW_TTL, length=8)
283
        self.nw_ttl = nw_ttl
284
285
286 1
class ActionOutput(ActionHeader):
287
    """Defines the actions output.
288
289
    Action structure for :attr:`ActionType.OFPAT_OUTPUT`, which sends packets
290
    out :attr:`port`. When the :attr:`port` is the
291
    :attr:`.Port.OFPP_CONTROLLER`, :attr:`max_length` indicates the max number
292
    of bytes to send. A :attr:`max_length` of zero means no bytes of the packet
293
    should be sent.
294
    """
295
296 1
    port = UBInt32()
297 1
    max_length = UBInt16()
298 1
    pad = Pad(6)
299
300 1
    _allowed_types = ActionType.OFPAT_OUTPUT,
301
302 1
    def __init__(self, port=None, max_length=None):
303
        """Create a ActionOutput with the optional parameters below.
304
305
        Args:
306
            port (:class:`Port` or :class:`int`): Output port.
307
            max_length (int): Max length to send to controller.
308
        """
309
        super().__init__(action_type=ActionType.OFPAT_OUTPUT, length=16)
310
        self.port = port
311
        self.max_length = max_length
312
313
314 1
class ActionPopMPLS(ActionHeader):
315
    """Action structure for OFPAT_POP_MPLS."""
316
317 1
    ethertype = UBInt16()
318 1
    pad = Pad(2)
319
320 1
    _allowed_types = ActionType.OFPAT_POP_MPLS,
321
322 1
    def __init__(self, ethertype=None):
323
        """Create an ActionPopMPLS with the optional parameters below.
324
325
        Args:
326
            ethertype (int): indicates the Ethertype of the payload.
327
        """
328
        super().__init__(action_type=ActionType.OFPAT_POP_MPLS)
329
        self.ethertype = ethertype
330
331
332 1
class ActionPush(ActionHeader):
333
    """Action structure for OFPAT_PUSH_[VLAN/MPLS/PBB]."""
334
335 1
    ethertype = UBInt16()
336 1
    pad = Pad(2)
337
338 1
    _allowed_types = (ActionType.OFPAT_PUSH_VLAN, ActionType.OFPAT_PUSH_MPLS,
339
                      ActionType.OFPAT_PUSH_PBB)
340
341 1
    def __init__(self, action_type=None, ethertype=None):
342
        """Create a ActionPush with the optional parameters below.
343
344
        Args:
345
            action_type (:class:`ActionType`): indicates which tag will be
346
            pushed (VLAN, MPLS, PBB).
347
            ethertype (int): indicates the Ethertype of the new tag.
348
        """
349
        super().__init__(action_type, length=8)
350
        self.ethertype = ethertype
351
352
353 1
class ActionSetField(ActionHeader):
354
    """Action structure for OFPAT_SET_FIELD."""
355
356 1
    field = OxmTLV()
357 1
    pad = BinaryData()
358
359 1
    def __init__(self, field=None):
360
        """Create a ActionSetField with the optional parameters below.
361
362
        Args:
363
            length (int): length padded to 64 bits, followed by exactly
364
                          oxm_len bytes containing a single OXM TLV, then
365
                          exactly ((oxm_len + 4) + 7)/8*8 - (oxm_len + 4)
366
                          (between 0 and 7) bytes of all-zero bytes
367
            field (:class:`OxmTLV`): OXM field and value.
368
        """
369
        super().__init__(action_type=ActionType.OFPAT_SET_FIELD)
370
        self.field = OxmTLV() if field is None else field
371
        self.pad = b''
372
373 1
    def pack(self, value=None):
374
        """Pack this structure updating the length and padding it."""
375
        self._prepare_pack()
376
        return super().pack()
377
378 1
    def _prepare_pack(self):
379
        """Update length and pad before packing."""
380
        # Calculate the real action length
381
        action_length = 4 + len(self.field.pack())
382
        # Pad it to 64 bits
383
        overflow = action_length % 8
384
        if overflow != 0:
385
            self.length = action_length + 8 - overflow
386
            self.pad = b'\x00' * (8 - overflow)
387
        else:
388
            self.length = action_length
389
390
391 1
class ActionSetQueue(ActionHeader):
392
    """Action structure for OFPAT_SET_QUEUE."""
393
394 1
    queue_id = UBInt32()
395
396 1
    _allowed_types = ActionType.OFPAT_SET_QUEUE,
397
398 1
    def __init__(self, queue_id=None):
399
        """Create an ActionSetQueue with the optional parameters below.
400
401
        Args:
402
            queue_id (int): The queue_id send packets to given queue on port.
403
        """
404
        super().__init__(action_type=ActionType.OFPAT_SET_QUEUE, length=8)
405
        self.queue_id = queue_id
406
407
408 1
class ListOfActions(FixedTypeList):
409
    """List of actions.
410
411
    Represented by instances of ActionHeader and used on ActionHeader objects.
412
    """
413
414 1
    def __init__(self, items=None):
415
        """Create a ListOfActions with the optional parameters below.
416
417
        Args:
418
            items (~pyof.v0x04.common.action.ActionHeader):
419
                Instance or a list of instances.
420
        """
421
        super().__init__(pyof_class=ActionHeader, items=items)
422