1
|
|
|
"""Defines an Error Message.""" |
2
|
|
|
|
3
|
|
|
# System imports |
4
|
1 |
|
from enum import IntEnum |
5
|
|
|
|
6
|
1 |
|
from pyof.foundation.base import GenericMessage |
7
|
1 |
|
from pyof.foundation.basic_types import BinaryData, UBInt16 |
8
|
1 |
|
from pyof.foundation.exceptions import PackException |
9
|
|
|
# Do not import new_message_from_header directly to avoid cyclic import. |
10
|
1 |
|
from pyof.v0x01.common.header import Header, Type |
11
|
|
|
|
12
|
1 |
|
__all__ = ('ErrorMsg', 'ErrorType', 'BadActionCode', 'BadRequestCode', |
13
|
|
|
'FlowModFailedCode', 'HelloFailedCode', 'PortModFailedCode', |
14
|
|
|
'QueueOpFailedCode', 'GenericFailedCode') |
15
|
|
|
|
16
|
|
|
|
17
|
|
|
# Enums |
18
|
|
|
|
19
|
1 |
|
class ErrorType(IntEnum): |
20
|
|
|
"""Values for ’type’ in ofp_error_message. |
21
|
|
|
|
22
|
|
|
These values are immutable: they will not change in future versions of the |
23
|
|
|
protocol (although new values may be added). |
24
|
|
|
""" |
25
|
|
|
|
26
|
|
|
#: Hello protocol failed |
27
|
1 |
|
OFPET_HELLO_FAILED = 0 |
28
|
|
|
#: Request was not understood |
29
|
1 |
|
OFPET_BAD_REQUEST = 1 |
30
|
|
|
#: Error in action description |
31
|
1 |
|
OFPET_BAD_ACTION = 2 |
32
|
|
|
#: Problem in modifying Flow entry |
33
|
1 |
|
OFPET_FLOW_MOD_FAILED = 3 |
34
|
|
|
#: Problem in modifying Port entry |
35
|
1 |
|
OFPET_PORT_MOD_FAILED = 4 |
36
|
|
|
#: Problem in modifying Queue entry |
37
|
1 |
|
OFPET_QUEUE_OP_FAILED = 5 |
38
|
|
|
|
39
|
1 |
|
def get_class(self): |
40
|
|
|
"""Return a Code class based on current ErrorType value. |
41
|
|
|
|
42
|
|
|
Returns: |
43
|
|
|
enum.IntEnum: class referenced by current error type. |
44
|
|
|
|
45
|
|
|
""" |
46
|
1 |
|
classes = {'OFPET_HELLO_FAILED': HelloFailedCode, |
47
|
|
|
'OFPET_BAD_REQUEST': BadRequestCode, |
48
|
|
|
'OFPET_BAD_ACTION': BadActionCode, |
49
|
|
|
'OFPET_FLOW_MOD_FAILED': FlowModFailedCode, |
50
|
|
|
'OFPET_PORT_MOD_FAILED': PortModFailedCode, |
51
|
|
|
'OFPET_QUEUE_OP_FAILED': QueueOpFailedCode} |
52
|
1 |
|
return classes.get(self.name, GenericFailedCode) |
53
|
|
|
|
54
|
|
|
|
55
|
1 |
|
class GenericFailedCode(IntEnum): |
56
|
|
|
"""Error_msg 'code' values for OFPET_BAD_ACTION. |
57
|
|
|
|
58
|
|
|
'data' contains at least the first 64 bytes of the failed request. |
59
|
|
|
""" |
60
|
|
|
|
61
|
|
|
#: Unknown error |
62
|
1 |
|
GENERIC_ERROR = 0 |
63
|
|
|
|
64
|
|
|
|
65
|
1 |
|
class HelloFailedCode(IntEnum): |
66
|
|
|
"""Error_msg 'code' values for OFPET_HELLO_FAILED. |
67
|
|
|
|
68
|
|
|
'data' contains an ASCII text string that may give failure details. |
69
|
|
|
""" |
70
|
|
|
|
71
|
|
|
#: No compatible version |
72
|
1 |
|
OFPHFC_INCOMPATIBLE = 0 |
73
|
|
|
#: Permissions error |
74
|
1 |
|
OFPHFC_EPERM = 1 |
75
|
|
|
|
76
|
|
|
|
77
|
1 |
|
class BadRequestCode(IntEnum): |
78
|
|
|
"""Error_msg 'code' values for OFPET_BAD_REQUEST. |
79
|
|
|
|
80
|
|
|
'data' contains at least the first 64 bytes of the failed request. |
81
|
|
|
""" |
82
|
|
|
|
83
|
|
|
#: ofp_header.version not supported. |
84
|
1 |
|
OFPBRC_BAD_VERSION = 0 |
85
|
|
|
#: ofp_header.type not supported. |
86
|
1 |
|
OFPBRC_BAD_TYPE = 1 |
87
|
|
|
#: ofp_stats_request.type not supported. |
88
|
1 |
|
OFPBRC_BAD_STAT = 2 |
89
|
|
|
#: Vendor not supported (in ofp_vendor_header or ofp_stats_request or |
90
|
|
|
#: ofp_stats_reply). |
91
|
1 |
|
OFPBRC_BAD_VENDOR = 3 |
92
|
|
|
#: Vendor subtype not supported. |
93
|
1 |
|
OFPBRC_BAD_SUBTYPE = 4 |
94
|
|
|
#: Permissions error. |
95
|
1 |
|
OFPBRC_EPERM = 5 |
96
|
|
|
#: Wrong request length for type. |
97
|
1 |
|
OFPBRC_BAD_LEN = 6 |
98
|
|
|
#: Specified buffer has already been used. |
99
|
1 |
|
OFPBRC_BUFFER_EMPTY = 7 |
100
|
|
|
#: Specified buffer does not exist. |
101
|
1 |
|
OFPBRC_BUFFER_UNKNOWN = 8 |
102
|
|
|
|
103
|
|
|
|
104
|
1 |
|
class BadActionCode(IntEnum): |
105
|
|
|
"""Error_msg 'code' values for OFPET_BAD_ACTION. |
106
|
|
|
|
107
|
|
|
'data' contains at least the first 64 bytes of the failed request. |
108
|
|
|
""" |
109
|
|
|
|
110
|
|
|
#: Unknown action type |
111
|
1 |
|
OFPBAC_BAD_TYPE = 0 |
112
|
|
|
#: Length problem in actions |
113
|
1 |
|
OFPBAC_BAD_LEN = 1 |
114
|
|
|
#: Unknown vendor id specified |
115
|
1 |
|
OFPBAC_BAD_VENDOR = 2 |
116
|
|
|
#: Unknown action type for vendor id |
117
|
1 |
|
OFPBAC_BAD_VENDOR_TYPE = 3 |
118
|
|
|
#: Problem validating output action |
119
|
1 |
|
OFPBAC_BAD_OUT_PORT = 4 |
120
|
|
|
#: Bad action argument |
121
|
1 |
|
OFPBAC_BAD_ARGUMENT = 5 |
122
|
|
|
#: Permissions error |
123
|
1 |
|
OFPBAC_EPERM = 6 |
124
|
|
|
#: Can’t handle this many actions |
125
|
1 |
|
OFPBAC_TOO_MANY = 7 |
126
|
|
|
#: Problem validating output queue |
127
|
1 |
|
OFPBAC_BAD_QUEUE = 8 |
128
|
|
|
|
129
|
|
|
|
130
|
1 |
|
class FlowModFailedCode(IntEnum): |
131
|
|
|
"""Error_msg 'code' values for OFPET_FLOW_MOD_FAILED. |
132
|
|
|
|
133
|
|
|
'data' contains at least the first 64 bytes of the failed request. |
134
|
|
|
""" |
135
|
|
|
|
136
|
|
|
#: Flow not added because of full tables |
137
|
1 |
|
OFPFMFC_ALL_TABLES_FULL = 0 |
138
|
|
|
#: Attempted to add overlapping flow with CHECK_OVERLAP flag set |
139
|
1 |
|
OFPFMFC_OVERLAP = 1 |
140
|
|
|
#: Permissions error |
141
|
1 |
|
OFPFMFC_EPERM = 2 |
142
|
|
|
#: Flow not added because of non-zero idle/hard timeout |
143
|
1 |
|
OFPFMFC_BAD_EMERG_TIMEOUT = 3 |
144
|
|
|
#: Unknown command |
145
|
1 |
|
OFPFMFC_BAD_COMMAND = 4 |
146
|
|
|
#: Unsupported action list - cannot process in the order specified |
147
|
1 |
|
OFPFMFC_UNSUPPORTED = 5 |
148
|
|
|
|
149
|
|
|
|
150
|
1 |
|
class PortModFailedCode(IntEnum): |
151
|
|
|
"""Error_msg 'code' values for OFPET_PORT_MOD_FAILED. |
152
|
|
|
|
153
|
|
|
'data' contains at least the first 64 bytes of the failed request. |
154
|
|
|
""" |
155
|
|
|
|
156
|
|
|
#: Specified port does not exist |
157
|
1 |
|
OFPPMFC_BAD_PORT = 0 |
158
|
|
|
#: Specified hardware address is wrong |
159
|
1 |
|
OFPPMFC_BAD_HW_ADDR = 1 |
160
|
|
|
|
161
|
|
|
|
162
|
1 |
|
class QueueOpFailedCode(IntEnum): |
163
|
|
|
"""Error msg 'code' values for OFPET_QUEUE_OP_FAILED. |
164
|
|
|
|
165
|
|
|
'data' contains at least the first 64 bytes of the failed request. |
166
|
|
|
""" |
167
|
|
|
|
168
|
|
|
#: Invalid port (or port does not exist) |
169
|
1 |
|
OFPQOFC_BAD_PORT = 0 |
170
|
|
|
#: Queue does not exist |
171
|
1 |
|
OFPQOFC_BAD_QUEUE = 1 |
172
|
|
|
#: Permissions error |
173
|
1 |
|
OFPQOFC_EPERM = 2 |
174
|
|
|
|
175
|
|
|
|
176
|
|
|
# Classes |
177
|
|
|
|
178
|
1 |
|
class ErrorMsg(GenericMessage): |
179
|
|
|
"""OpenFlow Error Message. |
180
|
|
|
|
181
|
|
|
This message does not contain a body in addition to the OpenFlow Header. |
182
|
|
|
""" |
183
|
|
|
|
184
|
|
|
#: :class:`~pyof.v0x01.common.header.Header`: OpenFlow Header |
185
|
1 |
|
header = Header(message_type=Type.OFPT_ERROR) |
186
|
1 |
|
error_type = UBInt16(enum_ref=ErrorType) |
187
|
1 |
|
code = UBInt16() |
188
|
1 |
|
data = BinaryData() |
189
|
|
|
|
190
|
1 |
|
def __init__(self, xid=None, error_type=None, code=None, data=b''): |
191
|
|
|
"""Assign parameters to object attributes. |
192
|
|
|
|
193
|
|
|
Args: |
194
|
|
|
xid (int): To be included in the message header. |
195
|
|
|
error_type (:class:`ErrorType`): Error type. |
196
|
|
|
code (enum.IntEnum): Error code. |
197
|
|
|
data (bytes): Its content is based on the error type and code. |
198
|
|
|
""" |
199
|
1 |
|
super().__init__(xid) |
200
|
1 |
|
self.error_type = error_type |
201
|
1 |
|
self.code = code |
202
|
1 |
|
self.data = data |
203
|
|
|
|
204
|
1 |
|
def pack(self, value=None): |
205
|
|
|
"""Pack the value as a binary representation. |
206
|
|
|
|
207
|
|
|
:attr:`data` is packed before the calling :meth:`.GenericMessage.pack`. |
208
|
|
|
After that, :attr:`data`'s value is restored. |
209
|
|
|
|
210
|
|
|
Returns: |
211
|
|
|
bytes: The binary representation. |
212
|
|
|
|
213
|
|
|
Raises: |
214
|
|
|
:exc:`~.exceptions.PackException`: If pack fails. |
215
|
|
|
|
216
|
|
|
""" |
217
|
1 |
|
if value is None: |
218
|
1 |
|
data_backup = None |
219
|
1 |
|
if self.data is not None and not isinstance(self.data, bytes): |
220
|
1 |
|
data_backup = self.data |
221
|
1 |
|
self.data = self.data.pack() |
222
|
1 |
|
packed = super().pack() |
223
|
1 |
|
if data_backup is not None: |
224
|
1 |
|
self.data = data_backup |
225
|
1 |
|
return packed |
226
|
|
|
if isinstance(value, type(self)): |
227
|
|
|
return value.pack() |
228
|
|
|
msg = "{} is not an instance of {}".format(value, type(self).__name__) |
229
|
|
|
raise PackException(msg) |
230
|
|
|
|
231
|
1 |
|
def unpack(self, buff, offset=0): |
232
|
|
|
"""Unpack *buff* into this object. |
233
|
|
|
|
234
|
|
|
This method will convert a binary data into a readable value according |
235
|
|
|
to the attribute format. |
236
|
|
|
|
237
|
|
|
Args: |
238
|
|
|
buff (bytes): Binary buffer. |
239
|
|
|
offset (int): Where to begin unpacking. |
240
|
|
|
|
241
|
|
|
Raises: |
242
|
|
|
:exc:`~.exceptions.UnpackException`: If unpack fails. |
243
|
|
|
|
244
|
|
|
""" |
245
|
1 |
|
super().unpack(buff, offset) |
246
|
1 |
|
code_class = ErrorType(self.error_type).get_class() |
247
|
|
|
self.code = code_class(self.code) |
248
|
|
|
|