Passed
Push — master ( 3643f6...384c84 )
by Diego Rabatone
01:22
created

ActionSetField   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 41
Duplicated Lines 0 %

Test Coverage

Coverage 31.82%

Importance

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