blob: 64cb40ae67adff8d2e7d9c6a97cd1afb04980577 [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
86oxm_types = {
Rich Lanea06d0c32013-03-25 08:52:03 -070087 of_g.VERSION_1_0:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -070088 of_g.VERSION_1_1:dict(),
Rich Lane4db4d042013-05-13 18:13:48 -070089 of_g.VERSION_1_2:dict(),
90 of_g.VERSION_1_3:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -070091 }
92
93hello_elem_types = {
Rich Lanea06d0c32013-03-25 08:52:03 -070094 of_g.VERSION_1_0:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -070095 of_g.VERSION_1_1:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -070096 of_g.VERSION_1_2:dict(),
Rich Lane4db4d042013-05-13 18:13:48 -070097 of_g.VERSION_1_3:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -070098 }
99
100table_feature_prop_types = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700101 of_g.VERSION_1_0:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700102 of_g.VERSION_1_1:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700103 of_g.VERSION_1_2:dict(),
Rich Lane4db4d042013-05-13 18:13:48 -0700104 of_g.VERSION_1_3:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700105 }
106
107meter_band_types = {
Rich Lanea06d0c32013-03-25 08:52:03 -0700108 of_g.VERSION_1_0:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700109 of_g.VERSION_1_1:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700110 of_g.VERSION_1_2:dict(),
Rich Lane4db4d042013-05-13 18:13:48 -0700111 of_g.VERSION_1_3:dict(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700112 }
113
114# All inheritance data for non-messages
115inheritance_data = dict(
116 of_instruction = instruction_types,
117 of_action = action_types,
118 of_action_id = action_id_types,
119 of_oxm = oxm_types,
120 of_queue_prop = queue_prop_types,
121 of_hello_elem = hello_elem_types,
122 of_table_feature_prop = table_feature_prop_types,
123 of_meter_band = meter_band_types
124 )
125
Rich Lanea06d0c32013-03-25 08:52:03 -0700126def class_is_virtual(cls):
127 """
128 Returns True if cls is a virtual class
129 """
130 if cls in inheritance_map:
131 return True
132 if cls.find("header") > 0:
133 return True
134 if loxi_utils.class_is_list(cls):
135 return True
136 return False
137
138################################################################
139#
140# These are message types
141#
142################################################################
143
Rich Lane4db4d042013-05-13 18:13:48 -0700144# The hardcoded message types are for objects without proper inheritance
Rich Lanea06d0c32013-03-25 08:52:03 -0700145message_types = {
146 # version 1.0
147 of_g.VERSION_1_0:dict(
Rich Lanea06d0c32013-03-25 08:52:03 -0700148 flow_mod = 14,
Rich Lanea06d0c32013-03-25 08:52:03 -0700149 stats_request = 16,
150 stats_reply = 17,
Rich Lanea06d0c32013-03-25 08:52:03 -0700151 ),
152
153 # version 1.1
154 of_g.VERSION_1_1:dict(
Rich Lanea06d0c32013-03-25 08:52:03 -0700155 flow_mod = 14,
Rich Lanea06d0c32013-03-25 08:52:03 -0700156 stats_request = 18,
157 stats_reply = 19,
Rich Lanea06d0c32013-03-25 08:52:03 -0700158 ),
159
160 # version 1.2
161 of_g.VERSION_1_2:dict(
Rich Lanea06d0c32013-03-25 08:52:03 -0700162 flow_mod = 14,
Rich Lanea06d0c32013-03-25 08:52:03 -0700163 stats_request = 18,
164 stats_reply = 19,
Rich Lanea06d0c32013-03-25 08:52:03 -0700165 ),
166
167 # version 1.3
168 of_g.VERSION_1_3:dict(
Rich Lanea06d0c32013-03-25 08:52:03 -0700169 flow_mod = 14,
Rich Lanea06d0c32013-03-25 08:52:03 -0700170 stats_request = 18, # FIXME Multipart
171 stats_reply = 19,
Rich Lanea06d0c32013-03-25 08:52:03 -0700172 )
173 }
174
175################################################################
176#
177# These are other objects that have a notion of type but are
178# not (yet) promoted to objects with inheritance
179#
180################################################################
181
182stats_types = {
183 # version 1.0
184 of_g.VERSION_1_0:dict(
185 desc = 0,
186 flow = 1,
187 aggregate = 2,
188 table = 3,
189 port = 4,
190 queue = 5,
191 experimenter = 0xffff
192 ),
193
194 # version 1.1
195 of_g.VERSION_1_1:dict(
196 desc = 0,
197 flow = 1,
198 aggregate = 2,
199 table = 3,
200 port = 4,
201 queue = 5,
202 group = 6,
203 group_desc = 7,
204 experimenter = 0xffff
205 ),
206
207 # version 1.2
208 of_g.VERSION_1_2:dict(
209 desc = 0,
210 flow = 1,
211 aggregate = 2,
212 table = 3,
213 port = 4,
214 queue = 5,
215 group = 6,
216 group_desc = 7,
217 group_features = 8,
218 experimenter = 0xffff
219 ),
220
221 # version 1.3
222 of_g.VERSION_1_3:dict(
223 desc = 0,
224 flow = 1,
225 aggregate = 2,
226 table = 3,
227 port = 4,
228 queue = 5,
229 group = 6,
230 group_desc = 7,
231 group_features = 8,
232 meter = 9,
233 meter_config = 10,
234 meter_features = 11,
235 table_features = 12,
236 port_desc = 13,
237 experimenter = 0xffff
238 )
239 }
240
241common_flow_mod_types = dict(
242 add = 0,
243 modify = 1,
244 modify_strict = 2,
245 delete = 3,
246 delete_strict = 4
247 )
248
249flow_mod_types = {
250 # version 1.0
251 of_g.VERSION_1_0:common_flow_mod_types,
252 of_g.VERSION_1_1:common_flow_mod_types,
253 of_g.VERSION_1_2:common_flow_mod_types,
254 of_g.VERSION_1_3:common_flow_mod_types
255 }
256
257# These do not translate to objects (yet)
258error_types = {
259 # version 1.0
260 of_g.VERSION_1_0:dict(
261 hello_failed = 0,
262 bad_request = 1,
263 bad_action = 2,
264 flow_mod_failed = 3,
265 port_mod_failed = 4,
266 queue_op_failed = 5
267 ),
268
269 # version 1.1
270 of_g.VERSION_1_1:dict(
271 hello_failed = 0,
272 bad_request = 1,
273 bad_action = 2,
274 bad_instruction = 3,
275 bad_match = 4,
276 flow_mod_failed = 5,
277 group_mod_failed = 6,
278 port_mod_failed = 7,
279 table_mod_failed = 8,
280 queue_op_failed = 9,
281 switch_config_failed = 10
282 ),
283
284 # version 1.2
285 of_g.VERSION_1_2:dict(
286 hello_failed = 0,
287 bad_request = 1,
288 bad_action = 2,
289 bad_instruction = 3,
290 bad_match = 4,
291 flow_mod_failed = 5,
292 group_mod_failed = 6,
293 port_mod_failed = 7,
294 table_mod_failed = 8,
295 queue_op_failed = 9,
296 switch_config_failed = 10,
297 role_request_failed = 11,
298 experimenter = 0xffff
299 ),
300
301 # version 1.3
302 of_g.VERSION_1_3:dict(
303 hello_failed = 0,
304 bad_request = 1,
305 bad_action = 2,
306 bad_instruction = 3,
307 bad_match = 4,
308 flow_mod_failed = 5,
309 group_mod_failed = 6,
310 port_mod_failed = 7,
311 table_mod_failed = 8,
312 queue_op_failed = 9,
313 switch_config_failed = 10,
314 role_request_failed = 11,
315 meter_mod_failed = 12,
316 table_features_failed= 13,
317 experimenter = 0xffff
318 )
319 }
320
321##
322# These are the objects whose length is specified by an external
323# reference, specifically another data member in the class.
Andreas Wundsam53256162013-05-02 14:05:53 -0700324#
Rich Lanea06d0c32013-03-25 08:52:03 -0700325#external_length_spec = {
326# ("of_packet_out", "actions", OF_VERSION_1_0) : "actions_len",
327# ("of_packet_out", "actions", OF_VERSION_1_1) : "actions_len",
328# ("of_packet_out", "actions", OF_VERSION_1_2) : "actions_len",
329# ("of_packet_out", "actions", OF_VERSION_1_3) : "actions_len"
330#}
331
332
333################################################################
334#
Andreas Wundsam53256162013-05-02 14:05:53 -0700335# type_val is the primary data structure that maps an
Rich Lanea06d0c32013-03-25 08:52:03 -0700336# (class_name, version) pair to the wire data type value
337#
338################################################################
339
340type_val = dict()
Rich Lane6bb28dd2013-05-13 15:19:14 -0700341inheritance_map = dict()
Rich Lanea06d0c32013-03-25 08:52:03 -0700342
Rich Lane6bb28dd2013-05-13 15:19:14 -0700343def generate_maps():
344 for parent, versioned in inheritance_data.items():
345 inheritance_map[parent] = set()
346 for ver, subclasses in versioned.items():
347 for subcls in subclasses:
348 inheritance_map[parent].add(subcls)
Rich Lanea06d0c32013-03-25 08:52:03 -0700349
Rich Lane6bb28dd2013-05-13 15:19:14 -0700350 for version, classes in message_types.items():
351 for cls in classes:
352 name = "of_" + cls
353 type_val[(name, version)] = classes[cls]
Rich Lanea06d0c32013-03-25 08:52:03 -0700354
Rich Lane6bb28dd2013-05-13 15:19:14 -0700355 for parent, versioned in inheritance_data.items():
356 for version, subclasses in versioned.items():
357 for subcls, value in subclasses.items():
358 name = parent + "_" + subcls
359 type_val[(name, version)] = value
360
361 # Special case OF-1.2 match type
362 type_val[("of_match_v3", of_g.VERSION_1_2)] = 0x8000
363 type_val[("of_match_v3", of_g.VERSION_1_3)] = 0x8000
Rich Lanea06d0c32013-03-25 08:52:03 -0700364
365# Utility function
366def dict_to_array(d, m_val, def_val=-1):
367 """
368 Given a dictionary, d, with each value a small integer,
369 produce an array indexed by the integer whose value is the key.
370 @param d The dictionary
371 @param m_val Ignore values greater than m_val
372 @param def_val The default value (for indices not in range of d)
373 """
374
375 # Get the max value in range for hash
376 max_val = 0
377 for key in d:
378 if (d[key] > max_val) and (d[key] < m_val):
379 max_val = d[key]
380 ar = []
381 for x in range(0, max_val + 1):
382 ar.append(def_val)
383 for key in d:
384 if (d[key] < m_val):
385 ar[d[key]] = key
386 return ar
387
388def type_array_len(version_indexed, max_val):
389 """
390 Given versioned information about a type, calculate how long
391 the unified array should be.
392
Andreas Wundsam53256162013-05-02 14:05:53 -0700393 @param version_indexed A dict indexed by version. Each value is a
Rich Lanea06d0c32013-03-25 08:52:03 -0700394 dict indexed by a name and whose value is an integer
395 @param max_val Ignore values greater than this for length calcs
396 """
397 # First, find the max length of all arrays
398 arr_len = 0
399 for version, val_dict in version_indexed.items():
400 ar = dict_to_array(val_dict, max_val, invalid_type)
401 if arr_len < len(ar):
402 arr_len = len(ar)
403 return arr_len
404
405# FIXME: Need to move update for multipart messages
406
407stats_reply_list = [
408 "of_aggregate_stats_reply",
409 "of_desc_stats_reply",
410 "of_experimenter_stats_reply",
411 "of_flow_stats_reply",
412 "of_group_stats_reply",
413 "of_group_desc_stats_reply",
414 "of_group_features_stats_reply",
415 "of_meter_stats_reply",
416 "of_meter_config_stats_reply",
417 "of_meter_features_stats_reply",
418 "of_port_stats_reply",
419 "of_port_desc_stats_reply",
420 "of_queue_stats_reply",
421 "of_table_stats_reply",
422 "of_table_features_stats_reply"
423]
424
425stats_request_list = [
426 "of_aggregate_stats_request",
427 "of_desc_stats_request",
428 "of_experimenter_stats_request",
429 "of_flow_stats_request",
430 "of_group_stats_request",
431 "of_group_desc_stats_request",
432 "of_group_features_stats_request",
433 "of_meter_stats_request",
434 "of_meter_config_stats_request",
435 "of_meter_features_stats_request",
436 "of_port_stats_request",
437 "of_port_desc_stats_request",
438 "of_queue_stats_request",
439 "of_table_stats_request",
440 "of_table_features_stats_request"
441]
442
443flow_mod_list = [
444 "of_flow_add",
445 "of_flow_modify",
446 "of_flow_modify_strict",
447 "of_flow_delete",
448 "of_flow_delete_strict"
449]
450
451def sub_class_map(base_type, version):
452 """
453 Returns an iterable object giving the instance nameys and subclass types
454 for the base_type, version values
455 """
456 rv = []
457 if base_type not in inheritance_map:
458 return rv
459
460 for instance in inheritance_map[base_type]:
461 subcls = loxi_utils.instance_to_class(instance, base_type)
462 if not loxi_utils.class_in_version(subcls, version):
463 continue
464 rv.append((instance, subcls))
465
466 return rv
467
468################################################################
469#
470# Extension related data and functions
471#
472################################################################
473
474# Per OF Version, per experimenter, map exp msg type (subtype) to object IDs
475# @fixme Generate defines for OF_<exp>_SUBTYPE_<msg> for the values below?
476extension_message_subtype = {
477 # version 1.0
478 of_g.VERSION_1_0:dict( # Version 1.0 extensions
479 bsn = { # BSN extensions; indexed by class name, value is subtype
Rich Lanea06d0c32013-03-25 08:52:03 -0700480 },
481 nicira = { # Nicira extensions, value is subtype
Rich Lanea06d0c32013-03-25 08:52:03 -0700482 },
483 ),
484 of_g.VERSION_1_1:dict( # Version 1.0 extensions
485 bsn = { # BSN extensions; indexed by class name, value is subtype
Rich Lanea06d0c32013-03-25 08:52:03 -0700486 },
487 ),
488 of_g.VERSION_1_2:dict( # Version 1.0 extensions
489 bsn = { # BSN extensions; indexed by class name, value is subtype
Rich Lanea06d0c32013-03-25 08:52:03 -0700490 },
491 ),
492 of_g.VERSION_1_3:dict( # Version 1.0 extensions
493 bsn = { # BSN extensions; indexed by class name, value is subtype
Rich Lanea06d0c32013-03-25 08:52:03 -0700494 },
495 ),
496}
497
498# Set to empty dict if no extension actions defined
499# Per OF Version, per experimenter, map actions to subtype
500extension_action_subtype = {
501 # version 1.0
502 of_g.VERSION_1_0:dict( # Version 1.0 extensions
503 bsn = { # of_action_bsn_
Rich Lanea06d0c32013-03-25 08:52:03 -0700504 },
505 nicira = { # of_action_nicira_
Rich Lanea06d0c32013-03-25 08:52:03 -0700506 }
507 ),
508 of_g.VERSION_1_1:dict( # Version 1.0 extensions
509 bsn = { # of_action_bsn_
Rich Lanea06d0c32013-03-25 08:52:03 -0700510 },
511 nicira = { # of_action_nicira_
Rich Lanea06d0c32013-03-25 08:52:03 -0700512 }
513 ),
514 of_g.VERSION_1_2:dict( # Version 1.0 extensions
515 bsn = { # of_action_bsn_
Rich Lanea06d0c32013-03-25 08:52:03 -0700516 },
517 nicira = { # of_action_nicira_
Rich Lanea06d0c32013-03-25 08:52:03 -0700518 }
519 ),
520 of_g.VERSION_1_3:dict( # Version 1.0 extensions
521 bsn = { # of_action_bsn_
Rich Lanea06d0c32013-03-25 08:52:03 -0700522 },
523 nicira = { # of_action_nicira_
Rich Lanea06d0c32013-03-25 08:52:03 -0700524 }
525 ),
526}
527
528# Set to empty dict if no extension actions defined
529# Per OF Version, per experimenter, map actions to subtype
530extension_action_id_subtype = {
531 # version 1.0
532 of_g.VERSION_1_0:dict(),
533 of_g.VERSION_1_1:dict(),
534 of_g.VERSION_1_2:dict(),
535 of_g.VERSION_1_3:dict( # Version 1.3 extensions
536 bsn = { # of_action_bsn_
Rich Lanea06d0c32013-03-25 08:52:03 -0700537 },
538 nicira = { # of_action_nicira_
Rich Lanea06d0c32013-03-25 08:52:03 -0700539 }
540 ),
541}
542
543# Set to empty dict if no extension instructions defined
544extension_instruction_subtype = {}
545
546# Set to empty dict if no extension instructions defined
547extension_queue_prop_subtype = {}
548
549# Set to empty dict if no extension instructions defined
550extension_table_feature_prop_subtype = {}
551
552extension_objects = [
553 extension_message_subtype,
554 extension_action_subtype,
555 extension_action_id_subtype,
556 extension_instruction_subtype,
557 extension_queue_prop_subtype,
558 extension_table_feature_prop_subtype
559]
560
561################################################################
562# These are extension type generic (for messages, actions...)
563################################################################
564
565def extension_to_experimenter_name(cls):
566 """
567 Return the name of the experimenter if class is an
568 extension, else None
569
570 This is brute force; we search all extension data for a match
571 """
Andreas Wundsam53256162013-05-02 14:05:53 -0700572
Rich Lanea06d0c32013-03-25 08:52:03 -0700573 for ext_obj in extension_objects:
574 for version, exp_list in ext_obj.items():
575 for exp_name, classes in exp_list.items():
576 if cls in classes:
577 return exp_name
578 return None
579
580def extension_to_experimenter_id(cls):
581 """
582 Return the ID of the experimenter if class is an
583 extension, else None
584 """
585 exp_name = extension_to_experimenter_name(cls)
586 if exp_name:
587 return of_g.experimenter_name_to_id[exp_name]
588 return None
589
590def extension_to_experimenter_macro_name(cls):
591 """
592 Return the "macro name" of the ID of the experimenter if class is an
593 extension, else None
594 """
595 exp_name = extension_to_experimenter_name(cls)
596 if exp_name:
597 return "OF_EXPERIMENTER_ID_" + exp_name.upper()
598 return None
599
600def extension_to_subtype(cls, version):
601 """
602 Generic across all extension objects, return subtype identifier
603 """
604 for ext_obj in extension_objects:
605 for version, exp_list in ext_obj.items():
606 for exp_name, classes in exp_list.items():
607 if cls in classes:
608 return classes[cls]
609
610def class_is_extension(cls, version):
611 """
612 Return True if class, version is recognized as an extension
613 of any type (message, action....)
614
615 Accepts of_g.OF_VERSION_ANY
616 """
617
618 for ext_obj in extension_objects:
619 if cls_is_ext_obj(cls, version, ext_obj):
620 return True
621
622 return False
623
624# Internal
625def cls_is_ext_obj(cls, version, ext_obj):
626 """
627 @brief Return True if cls in an extension of type ext_obj
628 @param cls The class to check
629 @param version The version to check
630 @param ext_obj The extension object dictionary (messages, actions...)
631
632 Accepts of_g.VERSION_ANY
633 """
634
635 # Call with each version if "any" is passed
636 if version == of_g.VERSION_ANY:
637 for v in of_g.of_version_range:
638 if cls_is_ext_obj(cls, v, ext_obj):
639 return True
640 else: # Version specified
641 if version in ext_obj:
642 for exp, subtype_vals in ext_obj[version].items():
643 if cls in subtype_vals:
644 return True
645
646 return False
Andreas Wundsam53256162013-05-02 14:05:53 -0700647
Rich Lanea06d0c32013-03-25 08:52:03 -0700648################################################################
649# These are extension message specific
650################################################################
651
652def message_is_extension(cls, version):
653 """
654 Return True if cls, version is recognized as an extension
655 This is brute force, searching records for a match
656 """
657 return cls_is_ext_obj(cls, version, extension_message_subtype)
658
659def extension_message_to_subtype(cls, version):
660 """
661 Return the subtype of the experimenter message if the class is an
662 extension, else None
663 """
664 if version in extension_message_subtype:
665 for exp, classes in extension_message_subtype[version].items():
666 for ext_class, subtype in classes.items():
667 if cls == ext_class:
668 return subtype
669 return None
670
671################################################################
672# These are extension action specific
673################################################################
674
675def action_is_extension(cls, version):
676 """
677 Return True if cls, version is recognized as an action extension
678 This is brute force, searching records for a match
679 """
680 return cls_is_ext_obj(cls, version, extension_action_subtype)
681
682def extension_action_to_subtype(cls, version):
683 """
684 Return the ID of the action subtype (for its experimenteer)
685 if class is an action extension, else None
686 """
687 if version in extension_action_subtype:
688 for exp, classes in extension_action_subtype[version].items():
689 if cls in classes:
690 return classes[cls]
691
692 return None
693
694################################################################
695# These are extension action specific
696################################################################
697
698def action_id_is_extension(cls, version):
699 """
700 Return True if cls, version is recognized as an action ID extension
701 This is brute force, searching records for a match
702 """
703 if version not in [of_g.VERSION_1_3]: # Action IDs only 1.3
704 return False
705 return cls_is_ext_obj(cls, version, extension_action_id_subtype)
706
707def extension_action_id_to_subtype(cls, version):
708 """
709 Return the ID of the action ID subtype (for its experimenteer)
710 if class is an action ID extension, else None
711 """
712 if version in extension_action_id_subtype:
713 for exp, classes in extension_action_id_subtype[version].items():
714 if cls in classes:
715 return classes[cls]
716
717 return None
718
719################################################################
720# These are extension instruction specific
721################################################################
722
723def instruction_is_extension(cls, version):
724 """
725 Return True if cls, version is recognized as an instruction extension
726 This is brute force, searching records for a match
727 """
728 return cls_is_ext_obj(cls, version, extension_instruction_subtype)
729
730################################################################
731# These are extension queue_prop specific
732################################################################
733
734def queue_prop_is_extension(cls, version):
735 """
736 Return True if cls, version is recognized as an instruction extension
737 This is brute force, searching records for a match
738 """
739 return cls_is_ext_obj(cls, version, extension_queue_prop_subtype)
740
741################################################################
742# These are extension table_feature_prop specific
743################################################################
744
745def table_feature_prop_is_extension(cls, version):
746 """
747 Return True if cls, version is recognized as an instruction extension
748 This is brute force, searching records for a match
749 """
750 return cls_is_ext_obj(cls, version,
751 extension_table_feature_prop_subtype)