|
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
|
|
|
|