blob: e2b3a836289177a0ee6fe510bfe7f9992ed3373e [file] [log] [blame]
Rich Lanea06d0c32013-03-25 08:52:03 -07001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
28#
29# Miscellaneous type information
30#
31# Define the map between sub-class types and wire values. In each
32# case, an array indexed by wire version gives a hash from identifier
33# to wire value.
34#
35
36import of_g
37import sys
38from generic_utils import *
Rich Lanea06d0c32013-03-25 08:52:03 -070039import loxi_utils.loxi_utils as loxi_utils
40
41invalid_type = "invalid_type"
42invalid_value = "0xeeee" # Note, as a string
43
44################################################################
45#
46# Define type data for inheritance classes:
47# instructions, actions, queue properties and OXM
48#
49# Messages are not in this group; they're treated specially for now
50#
51# These are indexed by wire protocol number
52#
53################################################################
54
55instruction_types = {
Rich Lanea06d0c32013-03-25 08:52:03 -070056 of_g.VERSION_1_0:dict(),
Rich Lane4db4d042013-05-13 18:13:48 -070057 of_g.VERSION_1_1:dict(),
58 of_g.VERSION_1_2:dict(),
59 of_g.VERSION_1_3:dict()
Rich Lanea06d0c32013-03-25 08:52:03 -070060 }
61
Rich Lane4db4d042013-05-13 18:13:48 -070062# HACK shared between actions and action_ids
63of_1_3_action_types = dict()
Rich Lanea06d0c32013-03-25 08:52:03 -070064
Rich Lanea06d0c32013-03-25 08:52:03 -070065action_types = {
Rich Lane4db4d042013-05-13 18:13:48 -070066 of_g.VERSION_1_0:dict(),
67 of_g.VERSION_1_1:dict(),
68 of_g.VERSION_1_2:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -070069 of_g.VERSION_1_3:of_1_3_action_types
Rich Lanea06d0c32013-03-25 08:52:03 -070070 }
71
72action_id_types = {
Rich Lanea06d0c32013-03-25 08:52:03 -070073 of_g.VERSION_1_0:dict(),
74 of_g.VERSION_1_1:dict(),
75 of_g.VERSION_1_2:dict(),
76 of_g.VERSION_1_3:of_1_3_action_types
77 }
78
79queue_prop_types = {
Rich Lane4db4d042013-05-13 18:13:48 -070080 of_g.VERSION_1_0:dict(),
81 of_g.VERSION_1_1:dict(),
82 of_g.VERSION_1_2:dict(),
83 of_g.VERSION_1_3:dict()
Rich Lanea06d0c32013-03-25 08:52:03 -070084 }
85
Dan Talaycoc0e802e2013-05-18 23:52:39 -070086bsn_vport_types = {
87 # version 1.0
88 of_g.VERSION_1_0:dict(
89 q_in_q = 0,
90 ),
91 # version 1.1
92 of_g.VERSION_1_1:dict(
93 q_in_q = 0,
94 ),
95 # version 1.2
96 of_g.VERSION_1_2:dict(
97 q_in_q = 0,
98 ),
99 # version 1.3
100 of_g.VERSION_1_3:dict(
101 q_in_q = 0,
102 )
103 }
104
Rich Lanea06d0c32013-03-25 08:52:03 -0700105oxm_types = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700106 of_g.VERSION_1_0:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700107 of_g.VERSION_1_1:dict(),
Rich Lane4db4d042013-05-13 18:13:48 -0700108 of_g.VERSION_1_2:dict(),
109 of_g.VERSION_1_3:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700110 }
111
112hello_elem_types = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700113 of_g.VERSION_1_0:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700114 of_g.VERSION_1_1:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700115 of_g.VERSION_1_2:dict(),
Rich Lane4db4d042013-05-13 18:13:48 -0700116 of_g.VERSION_1_3:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700117 }
118
119table_feature_prop_types = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700120 of_g.VERSION_1_0:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700121 of_g.VERSION_1_1:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700122 of_g.VERSION_1_2:dict(),
Rich Lane4db4d042013-05-13 18:13:48 -0700123 of_g.VERSION_1_3:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700124 }
125
126meter_band_types = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700127 of_g.VERSION_1_0:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700128 of_g.VERSION_1_1:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700129 of_g.VERSION_1_2:dict(),
Rich Lane4db4d042013-05-13 18:13:48 -0700130 of_g.VERSION_1_3:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700131 }
132
133# All inheritance data for non-messages
134inheritance_data = dict(
135 of_instruction = instruction_types,
136 of_action = action_types,
137 of_action_id = action_id_types,
138 of_oxm = oxm_types,
139 of_queue_prop = queue_prop_types,
140 of_hello_elem = hello_elem_types,
141 of_table_feature_prop = table_feature_prop_types,
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700142 of_meter_band = meter_band_types,
143 # BSN specific inheritance extensions
144 of_bsn_vport = bsn_vport_types
Rich Lanea06d0c32013-03-25 08:52:03 -0700145 )
146
Rich Lanea06d0c32013-03-25 08:52:03 -0700147def class_is_virtual(cls):
148 """
149 Returns True if cls is a virtual class
150 """
151 if cls in inheritance_map:
152 return True
153 if cls.find("header") > 0:
154 return True
155 if loxi_utils.class_is_list(cls):
156 return True
157 return False
158
159################################################################
160#
161# These are message types
162#
163################################################################
164
Rich Lanedf847e32013-05-29 16:57:30 -0700165# The hardcoded message types are for inheritance parents
Rich Lanea06d0c32013-03-25 08:52:03 -0700166message_types = {
167 # version 1.0
168 of_g.VERSION_1_0:dict(
Rich Lanedf847e32013-05-29 16:57:30 -0700169 experimenter = 4,
Rich Lanea06d0c32013-03-25 08:52:03 -0700170 flow_mod = 14,
Rich Lanea06d0c32013-03-25 08:52:03 -0700171 stats_request = 16,
172 stats_reply = 17,
Rich Lanea06d0c32013-03-25 08:52:03 -0700173 ),
174
175 # version 1.1
176 of_g.VERSION_1_1:dict(
Rich Lanedf847e32013-05-29 16:57:30 -0700177 experimenter = 4,
Rich Lanea06d0c32013-03-25 08:52:03 -0700178 flow_mod = 14,
Rich Lanea06d0c32013-03-25 08:52:03 -0700179 stats_request = 18,
180 stats_reply = 19,
Rich Lanea06d0c32013-03-25 08:52:03 -0700181 ),
182
183 # version 1.2
184 of_g.VERSION_1_2:dict(
Rich Lanedf847e32013-05-29 16:57:30 -0700185 experimenter = 4,
Rich Lanea06d0c32013-03-25 08:52:03 -0700186 flow_mod = 14,
Rich Lanea06d0c32013-03-25 08:52:03 -0700187 stats_request = 18,
188 stats_reply = 19,
Rich Lanea06d0c32013-03-25 08:52:03 -0700189 ),
190
191 # version 1.3
192 of_g.VERSION_1_3:dict(
Rich Lanedf847e32013-05-29 16:57:30 -0700193 experimenter = 4,
Rich Lanea06d0c32013-03-25 08:52:03 -0700194 flow_mod = 14,
Rich Lanea06d0c32013-03-25 08:52:03 -0700195 stats_request = 18, # FIXME Multipart
196 stats_reply = 19,
Rich Lanea06d0c32013-03-25 08:52:03 -0700197 )
198 }
199
200################################################################
201#
202# These are other objects that have a notion of type but are
203# not (yet) promoted to objects with inheritance
204#
205################################################################
206
207stats_types = {
208 # version 1.0
209 of_g.VERSION_1_0:dict(
210 desc = 0,
211 flow = 1,
212 aggregate = 2,
213 table = 3,
214 port = 4,
215 queue = 5,
216 experimenter = 0xffff
217 ),
218
219 # version 1.1
220 of_g.VERSION_1_1:dict(
221 desc = 0,
222 flow = 1,
223 aggregate = 2,
224 table = 3,
225 port = 4,
226 queue = 5,
227 group = 6,
228 group_desc = 7,
229 experimenter = 0xffff
230 ),
231
232 # version 1.2
233 of_g.VERSION_1_2:dict(
234 desc = 0,
235 flow = 1,
236 aggregate = 2,
237 table = 3,
238 port = 4,
239 queue = 5,
240 group = 6,
241 group_desc = 7,
242 group_features = 8,
243 experimenter = 0xffff
244 ),
245
246 # version 1.3
247 of_g.VERSION_1_3:dict(
248 desc = 0,
249 flow = 1,
250 aggregate = 2,
251 table = 3,
252 port = 4,
253 queue = 5,
254 group = 6,
255 group_desc = 7,
256 group_features = 8,
257 meter = 9,
258 meter_config = 10,
259 meter_features = 11,
260 table_features = 12,
261 port_desc = 13,
262 experimenter = 0xffff
263 )
264 }
265
266common_flow_mod_types = dict(
267 add = 0,
268 modify = 1,
269 modify_strict = 2,
270 delete = 3,
271 delete_strict = 4
272 )
273
274flow_mod_types = {
275 # version 1.0
276 of_g.VERSION_1_0:common_flow_mod_types,
277 of_g.VERSION_1_1:common_flow_mod_types,
278 of_g.VERSION_1_2:common_flow_mod_types,
279 of_g.VERSION_1_3:common_flow_mod_types
280 }
281
282# These do not translate to objects (yet)
283error_types = {
284 # version 1.0
285 of_g.VERSION_1_0:dict(
286 hello_failed = 0,
287 bad_request = 1,
288 bad_action = 2,
289 flow_mod_failed = 3,
290 port_mod_failed = 4,
291 queue_op_failed = 5
292 ),
293
294 # version 1.1
295 of_g.VERSION_1_1:dict(
296 hello_failed = 0,
297 bad_request = 1,
298 bad_action = 2,
299 bad_instruction = 3,
300 bad_match = 4,
301 flow_mod_failed = 5,
302 group_mod_failed = 6,
303 port_mod_failed = 7,
304 table_mod_failed = 8,
305 queue_op_failed = 9,
306 switch_config_failed = 10
307 ),
308
309 # version 1.2
310 of_g.VERSION_1_2:dict(
311 hello_failed = 0,
312 bad_request = 1,
313 bad_action = 2,
314 bad_instruction = 3,
315 bad_match = 4,
316 flow_mod_failed = 5,
317 group_mod_failed = 6,
318 port_mod_failed = 7,
319 table_mod_failed = 8,
320 queue_op_failed = 9,
321 switch_config_failed = 10,
322 role_request_failed = 11,
323 experimenter = 0xffff
324 ),
325
326 # version 1.3
327 of_g.VERSION_1_3:dict(
328 hello_failed = 0,
329 bad_request = 1,
330 bad_action = 2,
331 bad_instruction = 3,
332 bad_match = 4,
333 flow_mod_failed = 5,
334 group_mod_failed = 6,
335 port_mod_failed = 7,
336 table_mod_failed = 8,
337 queue_op_failed = 9,
338 switch_config_failed = 10,
339 role_request_failed = 11,
340 meter_mod_failed = 12,
341 table_features_failed= 13,
342 experimenter = 0xffff
343 )
344 }
345
346##
347# These are the objects whose length is specified by an external
348# reference, specifically another data member in the class.
Andreas Wundsam53256162013-05-02 14:05:53 -0700349#
Rich Lanea06d0c32013-03-25 08:52:03 -0700350#external_length_spec = {
351# ("of_packet_out", "actions", OF_VERSION_1_0) : "actions_len",
352# ("of_packet_out", "actions", OF_VERSION_1_1) : "actions_len",
353# ("of_packet_out", "actions", OF_VERSION_1_2) : "actions_len",
354# ("of_packet_out", "actions", OF_VERSION_1_3) : "actions_len"
355#}
356
357
358################################################################
359#
Andreas Wundsam53256162013-05-02 14:05:53 -0700360# type_val is the primary data structure that maps an
Rich Lanea06d0c32013-03-25 08:52:03 -0700361# (class_name, version) pair to the wire data type value
362#
363################################################################
364
365type_val = dict()
Rich Lane6bb28dd2013-05-13 15:19:14 -0700366inheritance_map = dict()
Rich Lanea06d0c32013-03-25 08:52:03 -0700367
Rich Lane6bb28dd2013-05-13 15:19:14 -0700368def generate_maps():
369 for parent, versioned in inheritance_data.items():
370 inheritance_map[parent] = set()
371 for ver, subclasses in versioned.items():
372 for subcls in subclasses:
373 inheritance_map[parent].add(subcls)
Rich Lanea06d0c32013-03-25 08:52:03 -0700374
Rich Lane6bb28dd2013-05-13 15:19:14 -0700375 for version, classes in message_types.items():
376 for cls in classes:
377 name = "of_" + cls
378 type_val[(name, version)] = classes[cls]
Rich Lanea06d0c32013-03-25 08:52:03 -0700379
Rich Lane6bb28dd2013-05-13 15:19:14 -0700380 for parent, versioned in inheritance_data.items():
381 for version, subclasses in versioned.items():
382 for subcls, value in subclasses.items():
383 name = parent + "_" + subcls
384 type_val[(name, version)] = value
385
386 # Special case OF-1.2 match type
387 type_val[("of_match_v3", of_g.VERSION_1_2)] = 0x8000
388 type_val[("of_match_v3", of_g.VERSION_1_3)] = 0x8000
Rich Lanea06d0c32013-03-25 08:52:03 -0700389
390# Utility function
391def dict_to_array(d, m_val, def_val=-1):
392 """
393 Given a dictionary, d, with each value a small integer,
394 produce an array indexed by the integer whose value is the key.
395 @param d The dictionary
396 @param m_val Ignore values greater than m_val
397 @param def_val The default value (for indices not in range of d)
398 """
399
400 # Get the max value in range for hash
401 max_val = 0
402 for key in d:
403 if (d[key] > max_val) and (d[key] < m_val):
404 max_val = d[key]
405 ar = []
406 for x in range(0, max_val + 1):
407 ar.append(def_val)
408 for key in d:
409 if (d[key] < m_val):
410 ar[d[key]] = key
411 return ar
412
413def type_array_len(version_indexed, max_val):
414 """
415 Given versioned information about a type, calculate how long
416 the unified array should be.
417
Andreas Wundsam53256162013-05-02 14:05:53 -0700418 @param version_indexed A dict indexed by version. Each value is a
Rich Lanea06d0c32013-03-25 08:52:03 -0700419 dict indexed by a name and whose value is an integer
420 @param max_val Ignore values greater than this for length calcs
421 """
422 # First, find the max length of all arrays
423 arr_len = 0
424 for version, val_dict in version_indexed.items():
425 ar = dict_to_array(val_dict, max_val, invalid_type)
426 if arr_len < len(ar):
427 arr_len = len(ar)
428 return arr_len
429
430# FIXME: Need to move update for multipart messages
431
432stats_reply_list = [
433 "of_aggregate_stats_reply",
434 "of_desc_stats_reply",
435 "of_experimenter_stats_reply",
436 "of_flow_stats_reply",
437 "of_group_stats_reply",
438 "of_group_desc_stats_reply",
439 "of_group_features_stats_reply",
440 "of_meter_stats_reply",
441 "of_meter_config_stats_reply",
442 "of_meter_features_stats_reply",
443 "of_port_stats_reply",
444 "of_port_desc_stats_reply",
445 "of_queue_stats_reply",
446 "of_table_stats_reply",
447 "of_table_features_stats_reply"
448]
449
450stats_request_list = [
451 "of_aggregate_stats_request",
452 "of_desc_stats_request",
453 "of_experimenter_stats_request",
454 "of_flow_stats_request",
455 "of_group_stats_request",
456 "of_group_desc_stats_request",
457 "of_group_features_stats_request",
458 "of_meter_stats_request",
459 "of_meter_config_stats_request",
460 "of_meter_features_stats_request",
461 "of_port_stats_request",
462 "of_port_desc_stats_request",
463 "of_queue_stats_request",
464 "of_table_stats_request",
465 "of_table_features_stats_request"
466]
467
468flow_mod_list = [
469 "of_flow_add",
470 "of_flow_modify",
471 "of_flow_modify_strict",
472 "of_flow_delete",
473 "of_flow_delete_strict"
474]
475
476def sub_class_map(base_type, version):
477 """
478 Returns an iterable object giving the instance nameys and subclass types
479 for the base_type, version values
480 """
481 rv = []
482 if base_type not in inheritance_map:
483 return rv
484
485 for instance in inheritance_map[base_type]:
486 subcls = loxi_utils.instance_to_class(instance, base_type)
487 if not loxi_utils.class_in_version(subcls, version):
488 continue
489 rv.append((instance, subcls))
490
491 return rv
492
493################################################################
494#
495# Extension related data and functions
496#
497################################################################
498
499# Per OF Version, per experimenter, map exp msg type (subtype) to object IDs
500# @fixme Generate defines for OF_<exp>_SUBTYPE_<msg> for the values below?
501extension_message_subtype = {
502 # version 1.0
503 of_g.VERSION_1_0:dict( # Version 1.0 extensions
504 bsn = { # BSN extensions; indexed by class name, value is subtype
Rich Lanea06d0c32013-03-25 08:52:03 -0700505 },
506 nicira = { # Nicira extensions, value is subtype
Rich Lanea06d0c32013-03-25 08:52:03 -0700507 },
508 ),
509 of_g.VERSION_1_1:dict( # Version 1.0 extensions
510 bsn = { # BSN extensions; indexed by class name, value is subtype
Rich Lanea06d0c32013-03-25 08:52:03 -0700511 },
512 ),
513 of_g.VERSION_1_2:dict( # Version 1.0 extensions
514 bsn = { # BSN extensions; indexed by class name, value is subtype
Rich Lanea06d0c32013-03-25 08:52:03 -0700515 },
516 ),
517 of_g.VERSION_1_3:dict( # Version 1.0 extensions
518 bsn = { # BSN extensions; indexed by class name, value is subtype
Rich Lanea06d0c32013-03-25 08:52:03 -0700519 },
520 ),
521}
522
523# Set to empty dict if no extension actions defined
524# Per OF Version, per experimenter, map actions to subtype
525extension_action_subtype = {
526 # version 1.0
527 of_g.VERSION_1_0:dict( # Version 1.0 extensions
528 bsn = { # of_action_bsn_
Rich Lanea06d0c32013-03-25 08:52:03 -0700529 },
530 nicira = { # of_action_nicira_
Rich Lanea06d0c32013-03-25 08:52:03 -0700531 }
532 ),
533 of_g.VERSION_1_1:dict( # Version 1.0 extensions
534 bsn = { # of_action_bsn_
Rich Lanea06d0c32013-03-25 08:52:03 -0700535 },
536 nicira = { # of_action_nicira_
Rich Lanea06d0c32013-03-25 08:52:03 -0700537 }
538 ),
539 of_g.VERSION_1_2:dict( # Version 1.0 extensions
540 bsn = { # of_action_bsn_
Rich Lanea06d0c32013-03-25 08:52:03 -0700541 },
542 nicira = { # of_action_nicira_
Rich Lanea06d0c32013-03-25 08:52:03 -0700543 }
544 ),
545 of_g.VERSION_1_3:dict( # Version 1.0 extensions
546 bsn = { # of_action_bsn_
Rich Lanea06d0c32013-03-25 08:52:03 -0700547 },
548 nicira = { # of_action_nicira_
Rich Lanea06d0c32013-03-25 08:52:03 -0700549 }
550 ),
551}
552
553# Set to empty dict if no extension actions defined
554# Per OF Version, per experimenter, map actions to subtype
555extension_action_id_subtype = {
556 # version 1.0
557 of_g.VERSION_1_0:dict(),
558 of_g.VERSION_1_1:dict(),
559 of_g.VERSION_1_2:dict(),
560 of_g.VERSION_1_3:dict( # Version 1.3 extensions
561 bsn = { # of_action_bsn_
Rich Lanea06d0c32013-03-25 08:52:03 -0700562 },
563 nicira = { # of_action_nicira_
Rich Lanea06d0c32013-03-25 08:52:03 -0700564 }
565 ),
566}
567
568# Set to empty dict if no extension instructions defined
569extension_instruction_subtype = {}
570
571# Set to empty dict if no extension instructions defined
572extension_queue_prop_subtype = {}
573
574# Set to empty dict if no extension instructions defined
575extension_table_feature_prop_subtype = {}
576
577extension_objects = [
578 extension_message_subtype,
579 extension_action_subtype,
580 extension_action_id_subtype,
581 extension_instruction_subtype,
582 extension_queue_prop_subtype,
583 extension_table_feature_prop_subtype
584]
585
586################################################################
587# These are extension type generic (for messages, actions...)
588################################################################
589
590def extension_to_experimenter_name(cls):
591 """
592 Return the name of the experimenter if class is an
593 extension, else None
594
595 This is brute force; we search all extension data for a match
596 """
Andreas Wundsam53256162013-05-02 14:05:53 -0700597
Rich Lanea06d0c32013-03-25 08:52:03 -0700598 for ext_obj in extension_objects:
599 for version, exp_list in ext_obj.items():
600 for exp_name, classes in exp_list.items():
601 if cls in classes:
602 return exp_name
603 return None
604
605def extension_to_experimenter_id(cls):
606 """
607 Return the ID of the experimenter if class is an
608 extension, else None
609 """
610 exp_name = extension_to_experimenter_name(cls)
611 if exp_name:
612 return of_g.experimenter_name_to_id[exp_name]
613 return None
614
615def extension_to_experimenter_macro_name(cls):
616 """
617 Return the "macro name" of the ID of the experimenter if class is an
618 extension, else None
619 """
620 exp_name = extension_to_experimenter_name(cls)
621 if exp_name:
622 return "OF_EXPERIMENTER_ID_" + exp_name.upper()
623 return None
624
625def extension_to_subtype(cls, version):
626 """
627 Generic across all extension objects, return subtype identifier
628 """
629 for ext_obj in extension_objects:
630 for version, exp_list in ext_obj.items():
631 for exp_name, classes in exp_list.items():
632 if cls in classes:
633 return classes[cls]
634
635def class_is_extension(cls, version):
636 """
637 Return True if class, version is recognized as an extension
638 of any type (message, action....)
639
640 Accepts of_g.OF_VERSION_ANY
641 """
642
643 for ext_obj in extension_objects:
644 if cls_is_ext_obj(cls, version, ext_obj):
645 return True
646
647 return False
648
649# Internal
650def cls_is_ext_obj(cls, version, ext_obj):
651 """
652 @brief Return True if cls in an extension of type ext_obj
653 @param cls The class to check
654 @param version The version to check
655 @param ext_obj The extension object dictionary (messages, actions...)
656
657 Accepts of_g.VERSION_ANY
658 """
659
660 # Call with each version if "any" is passed
661 if version == of_g.VERSION_ANY:
662 for v in of_g.of_version_range:
663 if cls_is_ext_obj(cls, v, ext_obj):
664 return True
665 else: # Version specified
666 if version in ext_obj:
667 for exp, subtype_vals in ext_obj[version].items():
668 if cls in subtype_vals:
669 return True
670
671 return False
Andreas Wundsam53256162013-05-02 14:05:53 -0700672
Rich Lanea06d0c32013-03-25 08:52:03 -0700673################################################################
674# These are extension message specific
675################################################################
676
677def message_is_extension(cls, version):
678 """
679 Return True if cls, version is recognized as an extension
680 This is brute force, searching records for a match
681 """
682 return cls_is_ext_obj(cls, version, extension_message_subtype)
683
684def extension_message_to_subtype(cls, version):
685 """
686 Return the subtype of the experimenter message if the class is an
687 extension, else None
688 """
689 if version in extension_message_subtype:
690 for exp, classes in extension_message_subtype[version].items():
691 for ext_class, subtype in classes.items():
692 if cls == ext_class:
693 return subtype
694 return None
695
696################################################################
697# These are extension action specific
698################################################################
699
700def action_is_extension(cls, version):
701 """
702 Return True if cls, version is recognized as an action extension
703 This is brute force, searching records for a match
704 """
705 return cls_is_ext_obj(cls, version, extension_action_subtype)
706
707def extension_action_to_subtype(cls, version):
708 """
709 Return the ID of the action subtype (for its experimenteer)
710 if class is an action extension, else None
711 """
712 if version in extension_action_subtype:
713 for exp, classes in extension_action_subtype[version].items():
714 if cls in classes:
715 return classes[cls]
716
717 return None
718
719################################################################
720# These are extension action specific
721################################################################
722
723def action_id_is_extension(cls, version):
724 """
725 Return True if cls, version is recognized as an action ID extension
726 This is brute force, searching records for a match
727 """
728 if version not in [of_g.VERSION_1_3]: # Action IDs only 1.3
729 return False
730 return cls_is_ext_obj(cls, version, extension_action_id_subtype)
731
732def extension_action_id_to_subtype(cls, version):
733 """
734 Return the ID of the action ID subtype (for its experimenteer)
735 if class is an action ID extension, else None
736 """
737 if version in extension_action_id_subtype:
738 for exp, classes in extension_action_id_subtype[version].items():
739 if cls in classes:
740 return classes[cls]
741
742 return None
743
744################################################################
745# These are extension instruction specific
746################################################################
747
748def instruction_is_extension(cls, version):
749 """
750 Return True if cls, version is recognized as an instruction extension
751 This is brute force, searching records for a match
752 """
753 return cls_is_ext_obj(cls, version, extension_instruction_subtype)
754
755################################################################
756# These are extension queue_prop specific
757################################################################
758
759def queue_prop_is_extension(cls, version):
760 """
761 Return True if cls, version is recognized as an instruction extension
762 This is brute force, searching records for a match
763 """
764 return cls_is_ext_obj(cls, version, extension_queue_prop_subtype)
765
766################################################################
767# These are extension table_feature_prop specific
768################################################################
769
770def table_feature_prop_is_extension(cls, version):
771 """
772 Return True if cls, version is recognized as an instruction extension
773 This is brute force, searching records for a match
774 """
775 return cls_is_ext_obj(cls, version,
776 extension_table_feature_prop_subtype)