blob: ecfd850dbb0ce24a3976c3c837e38218eb5f3380 [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 *
39import oxm
40import loxi_utils.loxi_utils as loxi_utils
41
42invalid_type = "invalid_type"
43invalid_value = "0xeeee" # Note, as a string
44
45################################################################
46#
47# Define type data for inheritance classes:
48# instructions, actions, queue properties and OXM
49#
50# Messages are not in this group; they're treated specially for now
51#
52# These are indexed by wire protocol number
53#
54################################################################
55
56instruction_types = {
57 # version 1.0
58 of_g.VERSION_1_0:dict(),
59
60 # version 1.1
61 of_g.VERSION_1_1:dict(
62 goto_table = 1,
63 write_metadata = 2,
64 write_actions = 3,
65 apply_actions = 4,
66 clear_actions = 5,
67 experimenter = 0xffff
68 ),
69
70 # version 1.2
71 of_g.VERSION_1_2:dict(
72 goto_table = 1,
73 write_metadata = 2,
74 write_actions = 3,
75 apply_actions = 4,
76 clear_actions = 5,
77 experimenter = 0xffff
78 ),
79
80 # version 1.3
81 of_g.VERSION_1_3:dict(
82 goto_table = 1,
83 write_metadata = 2,
84 write_actions = 3,
85 apply_actions = 4,
86 clear_actions = 5,
87 meter = 6,
88 experimenter = 0xffff
89 )
90 }
91
92of_1_3_action_types = dict(
93 output = 0,
94 copy_ttl_out = 11,
95 copy_ttl_in = 12,
96 set_mpls_ttl = 15,
97 dec_mpls_ttl = 16,
98 push_vlan = 17,
99 pop_vlan = 18,
100 push_mpls = 19,
101 pop_mpls = 20,
102 set_queue = 21,
103 group = 22,
104 set_nw_ttl = 23,
105 dec_nw_ttl = 24,
106 set_field = 25,
107 push_pbb = 26,
108 pop_pbb = 27,
109 experimenter = 0xffff,
110 bsn_mirror = 0xffff,
111 bsn_set_tunnel_dst = 0xffff,
112 nicira_dec_ttl = 0xffff
113 )
114
115# Indexed by OF version
116action_types = {
117 # version 1.0
118 of_g.VERSION_1_0:dict(
119 output = 0,
120 set_vlan_vid = 1,
121 set_vlan_pcp = 2,
122 strip_vlan = 3,
123 set_dl_src = 4,
124 set_dl_dst = 5,
125 set_nw_src = 6,
126 set_nw_dst = 7,
127 set_nw_tos = 8,
128 set_tp_src = 9,
129 set_tp_dst = 10,
130 enqueue = 11,
131 experimenter = 0xffff,
132 bsn_mirror = 0xffff,
133 bsn_set_tunnel_dst = 0xffff,
134 nicira_dec_ttl = 0xffff
135 ),
136
137 # version 1.1
138 of_g.VERSION_1_1:dict(
139 output = 0,
140 set_vlan_vid = 1,
141 set_vlan_pcp = 2,
142 set_dl_src = 3,
143 set_dl_dst = 4,
144 set_nw_src = 5,
145 set_nw_dst = 6,
146 set_nw_tos = 7,
147 set_nw_ecn = 8,
148 set_tp_src = 9,
149 set_tp_dst = 10,
150 copy_ttl_out = 11,
151 copy_ttl_in = 12,
152 set_mpls_label = 13,
153 set_mpls_tc = 14,
154 set_mpls_ttl = 15,
155 dec_mpls_ttl = 16,
156 push_vlan = 17,
157 pop_vlan = 18,
158 push_mpls = 19,
159 pop_mpls = 20,
160 set_queue = 21,
161 group = 22,
162 set_nw_ttl = 23,
163 dec_nw_ttl = 24,
164 experimenter = 0xffff,
165 bsn_mirror = 0xffff,
166 bsn_set_tunnel_dst = 0xffff,
167 nicira_dec_ttl = 0xffff
168 ),
169
170 # version 1.2
171 of_g.VERSION_1_2:dict(
172 output = 0,
173 copy_ttl_out = 11,
174 copy_ttl_in = 12,
175 set_mpls_ttl = 15,
176 dec_mpls_ttl = 16,
177 push_vlan = 17,
178 pop_vlan = 18,
179 push_mpls = 19,
180 pop_mpls = 20,
181 set_queue = 21,
182 group = 22,
183 set_nw_ttl = 23,
184 dec_nw_ttl = 24,
185 set_field = 25,
186 experimenter = 0xffff,
187 bsn_mirror = 0xffff,
188 bsn_set_tunnel_dst = 0xffff,
189 nicira_dec_ttl = 0xffff
190 ),
191
192 # version 1.3
193 of_g.VERSION_1_3:of_1_3_action_types
194
195 }
196
197action_id_types = {
198 # version 1.0
199 of_g.VERSION_1_0:dict(),
200 of_g.VERSION_1_1:dict(),
201 of_g.VERSION_1_2:dict(),
202 of_g.VERSION_1_3:of_1_3_action_types
203 }
204
205queue_prop_types = {
206 # version 1.0
207 of_g.VERSION_1_0:dict(
208 min_rate = 1,
209 # experimenter = 0xffff
210 ),
211 # version 1.1
212 of_g.VERSION_1_1:dict(
213 min_rate = 1,
214 # experimenter = 0xffff
215 ),
216 # version 1.2
217 of_g.VERSION_1_2:dict(
218 min_rate = 1,
219 max_rate = 2,
220 experimenter = 0xffff
221 ),
222 # version 1.3
223 of_g.VERSION_1_3:dict(
224 min_rate = 1,
225 max_rate = 2,
226 experimenter = 0xffff
227 )
228 }
229
230oxm_types = {
231 # version 1.0
232 of_g.VERSION_1_0:dict(),
233
234 # version 1.1
235 of_g.VERSION_1_1:dict(),
236
237 # version 1.2
238 of_g.VERSION_1_2:oxm.oxm_wire_type,
239
240 # version 1.3
241 of_g.VERSION_1_3:oxm.oxm_wire_type # FIXME needs update for 1.3?
242 }
243
244hello_elem_types = {
245 # version 1.0
246 of_g.VERSION_1_0:dict(),
247
248 # version 1.1
249 of_g.VERSION_1_1:dict(),
250
251 # version 1.2
252 of_g.VERSION_1_2:dict(),
253
254 # version 1.3
255 of_g.VERSION_1_3:dict(
256 versionbitmap = 1
257 )
258 }
259
260table_feature_prop_types = {
261 # version 1.0
262 of_g.VERSION_1_0:dict(),
263
264 # version 1.1
265 of_g.VERSION_1_1:dict(),
266
267 # version 1.2
268 of_g.VERSION_1_2:dict(),
269
270 # version 1.3
271 of_g.VERSION_1_3:dict(
272 instructions = 0,
273 instructions_miss = 1,
274 next_tables = 2,
275 next_tables_miss = 3,
276 write_actions = 4,
277 write_actions_miss = 5,
278 apply_actions = 6,
279 apply_actions_miss = 7,
280 match = 8,
281 wildcards = 10,
282 write_setfield = 12,
283 write_setfield_miss = 13,
284 apply_setfield = 14,
285 apply_setfield_miss = 15,
286# experimenter = 0xFFFE,
287# experimenter_miss = 0xFFFF,
288 experimenter = 0xFFFF, # Wrong: should be experimenter_miss
289 )
290 }
291
292meter_band_types = {
293 # version 1.0
294 of_g.VERSION_1_0:dict(),
295
296 # version 1.1
297 of_g.VERSION_1_1:dict(),
298
299 # version 1.2
300 of_g.VERSION_1_2:dict(),
301
302 # version 1.3
303 of_g.VERSION_1_3:dict(
304 drop = 1,
305 dscp_remark = 2,
306 experimenter = 0xFFFF,
307 )
308 }
309
310# All inheritance data for non-messages
311inheritance_data = dict(
312 of_instruction = instruction_types,
313 of_action = action_types,
314 of_action_id = action_id_types,
315 of_oxm = oxm_types,
316 of_queue_prop = queue_prop_types,
317 of_hello_elem = hello_elem_types,
318 of_table_feature_prop = table_feature_prop_types,
319 of_meter_band = meter_band_types
320 )
321
322################################################################
323# Now generate the maps from parent to list of subclasses
324################################################################
325
326# # These lists have entries which are a fixed type, no inheritance
327# fixed_lists = [
328# "of_list_bucket",
329# "of_list_bucket_counter",
330# "of_list_flow_stats_entry",
331# "of_list_group_desc_stats_entry",
332# "of_list_group_stats_entry",
333# "of_list_packet_queue",
334# "of_list_port_desc",
335# "of_list_port_stats_entry",
336# "of_list_queue_stats_entry",
337# "of_list_table_stats_entry"
338# ]
339
340# for cls in fixed_lists:
341# base_type = list_to_entry_type(cls)
342# of_g.inheritance_map[base_type] = [base_type]
343
344inheritance_map = dict()
345for parent, versioned in inheritance_data.items():
346 inheritance_map[parent] = set()
347 for ver, subclasses in versioned.items():
348 for subcls in subclasses:
349 inheritance_map[parent].add(subcls)
350
351def class_is_virtual(cls):
352 """
353 Returns True if cls is a virtual class
354 """
355 if cls in inheritance_map:
356 return True
357 if cls.find("header") > 0:
358 return True
359 if loxi_utils.class_is_list(cls):
360 return True
361 return False
362
363################################################################
364#
365# These are message types
366#
367################################################################
368
369message_types = {
370 # version 1.0
371 of_g.VERSION_1_0:dict(
372 hello = 0,
373 error_msg = 1,
374 echo_request = 2,
375 echo_reply = 3,
376 experimenter = 4,
377 features_request = 5,
378 features_reply = 6,
379 get_config_request = 7,
380 get_config_reply = 8,
381 set_config = 9,
382 packet_in = 10,
383 flow_removed = 11,
384 port_status = 12,
385 packet_out = 13,
386 flow_mod = 14,
387 port_mod = 15,
388 stats_request = 16,
389 stats_reply = 17,
390 barrier_request = 18,
391 barrier_reply = 19,
392 queue_get_config_request = 20,
393 queue_get_config_reply = 21,
394 table_mod = 22 # Unofficial 1.0 extension
395 ),
396
397 # version 1.1
398 of_g.VERSION_1_1:dict(
399 hello = 0,
400 error_msg = 1,
401 echo_request = 2,
402 echo_reply = 3,
403 experimenter = 4,
404 features_request = 5,
405 features_reply = 6,
406 get_config_request = 7,
407 get_config_reply = 8,
408 set_config = 9,
409 packet_in = 10,
410 flow_removed = 11,
411 port_status = 12,
412 packet_out = 13,
413 flow_mod = 14,
414 group_mod = 15,
415 port_mod = 16,
416 table_mod = 17,
417 stats_request = 18,
418 stats_reply = 19,
419 barrier_request = 20,
420 barrier_reply = 21,
421 queue_get_config_request = 22,
422 queue_get_config_reply = 23
423 ),
424
425 # version 1.2
426 of_g.VERSION_1_2:dict(
427 hello = 0,
428 error_msg = 1,
429 echo_request = 2,
430 echo_reply = 3,
431 experimenter = 4,
432 features_request = 5,
433 features_reply = 6,
434 get_config_request = 7,
435 get_config_reply = 8,
436 set_config = 9,
437 packet_in = 10,
438 flow_removed = 11,
439 port_status = 12,
440 packet_out = 13,
441 flow_mod = 14,
442 group_mod = 15,
443 port_mod = 16,
444 table_mod = 17,
445 stats_request = 18,
446 stats_reply = 19,
447 barrier_request = 20,
448 barrier_reply = 21,
449 queue_get_config_request = 22,
450 queue_get_config_reply = 23,
451 role_request = 24,
452 role_reply = 25,
453 ),
454
455 # version 1.3
456 of_g.VERSION_1_3:dict(
457 hello = 0,
458 error_msg = 1,
459 echo_request = 2,
460 echo_reply = 3,
461 experimenter = 4,
462 features_request = 5,
463 features_reply = 6,
464 get_config_request = 7,
465 get_config_reply = 8,
466 set_config = 9,
467 packet_in = 10,
468 flow_removed = 11,
469 port_status = 12,
470 packet_out = 13,
471 flow_mod = 14,
472 group_mod = 15,
473 port_mod = 16,
474 table_mod = 17,
475 stats_request = 18, # FIXME Multipart
476 stats_reply = 19,
477 barrier_request = 20,
478 barrier_reply = 21,
479 queue_get_config_request = 22,
480 queue_get_config_reply = 23,
481 role_request = 24,
482 role_reply = 25,
483 async_get_request = 26,
484 async_get_reply = 27,
485 async_set = 28,
486 meter_mod = 29
487 )
488 }
489
490################################################################
491#
492# These are other objects that have a notion of type but are
493# not (yet) promoted to objects with inheritance
494#
495################################################################
496
497stats_types = {
498 # version 1.0
499 of_g.VERSION_1_0:dict(
500 desc = 0,
501 flow = 1,
502 aggregate = 2,
503 table = 3,
504 port = 4,
505 queue = 5,
506 experimenter = 0xffff
507 ),
508
509 # version 1.1
510 of_g.VERSION_1_1:dict(
511 desc = 0,
512 flow = 1,
513 aggregate = 2,
514 table = 3,
515 port = 4,
516 queue = 5,
517 group = 6,
518 group_desc = 7,
519 experimenter = 0xffff
520 ),
521
522 # version 1.2
523 of_g.VERSION_1_2:dict(
524 desc = 0,
525 flow = 1,
526 aggregate = 2,
527 table = 3,
528 port = 4,
529 queue = 5,
530 group = 6,
531 group_desc = 7,
532 group_features = 8,
533 experimenter = 0xffff
534 ),
535
536 # version 1.3
537 of_g.VERSION_1_3:dict(
538 desc = 0,
539 flow = 1,
540 aggregate = 2,
541 table = 3,
542 port = 4,
543 queue = 5,
544 group = 6,
545 group_desc = 7,
546 group_features = 8,
547 meter = 9,
548 meter_config = 10,
549 meter_features = 11,
550 table_features = 12,
551 port_desc = 13,
552 experimenter = 0xffff
553 )
554 }
555
556common_flow_mod_types = dict(
557 add = 0,
558 modify = 1,
559 modify_strict = 2,
560 delete = 3,
561 delete_strict = 4
562 )
563
564flow_mod_types = {
565 # version 1.0
566 of_g.VERSION_1_0:common_flow_mod_types,
567 of_g.VERSION_1_1:common_flow_mod_types,
568 of_g.VERSION_1_2:common_flow_mod_types,
569 of_g.VERSION_1_3:common_flow_mod_types
570 }
571
572# These do not translate to objects (yet)
573error_types = {
574 # version 1.0
575 of_g.VERSION_1_0:dict(
576 hello_failed = 0,
577 bad_request = 1,
578 bad_action = 2,
579 flow_mod_failed = 3,
580 port_mod_failed = 4,
581 queue_op_failed = 5
582 ),
583
584 # version 1.1
585 of_g.VERSION_1_1:dict(
586 hello_failed = 0,
587 bad_request = 1,
588 bad_action = 2,
589 bad_instruction = 3,
590 bad_match = 4,
591 flow_mod_failed = 5,
592 group_mod_failed = 6,
593 port_mod_failed = 7,
594 table_mod_failed = 8,
595 queue_op_failed = 9,
596 switch_config_failed = 10
597 ),
598
599 # version 1.2
600 of_g.VERSION_1_2:dict(
601 hello_failed = 0,
602 bad_request = 1,
603 bad_action = 2,
604 bad_instruction = 3,
605 bad_match = 4,
606 flow_mod_failed = 5,
607 group_mod_failed = 6,
608 port_mod_failed = 7,
609 table_mod_failed = 8,
610 queue_op_failed = 9,
611 switch_config_failed = 10,
612 role_request_failed = 11,
613 experimenter = 0xffff
614 ),
615
616 # version 1.3
617 of_g.VERSION_1_3:dict(
618 hello_failed = 0,
619 bad_request = 1,
620 bad_action = 2,
621 bad_instruction = 3,
622 bad_match = 4,
623 flow_mod_failed = 5,
624 group_mod_failed = 6,
625 port_mod_failed = 7,
626 table_mod_failed = 8,
627 queue_op_failed = 9,
628 switch_config_failed = 10,
629 role_request_failed = 11,
630 meter_mod_failed = 12,
631 table_features_failed= 13,
632 experimenter = 0xffff
633 )
634 }
635
636##
637# These are the objects whose length is specified by an external
638# reference, specifically another data member in the class.
639#
640#external_length_spec = {
641# ("of_packet_out", "actions", OF_VERSION_1_0) : "actions_len",
642# ("of_packet_out", "actions", OF_VERSION_1_1) : "actions_len",
643# ("of_packet_out", "actions", OF_VERSION_1_2) : "actions_len",
644# ("of_packet_out", "actions", OF_VERSION_1_3) : "actions_len"
645#}
646
647
648################################################################
649#
650# type_val is the primary data structure that maps an
651# (class_name, version) pair to the wire data type value
652#
653################################################################
654
655type_val = dict()
656
657for version, classes in message_types.items():
658 for cls in classes:
659 name = "of_" + cls
660 type_val[(name, version)] = classes[cls]
661
662for parent, versioned in inheritance_data.items():
663 for version, subclasses in versioned.items():
664 for subcls, value in subclasses.items():
665 name = parent + "_" + subcls
666 type_val[(name, version)] = value
667
668# Special case OF-1.2 match type
669type_val[("of_match_v3", of_g.VERSION_1_2)] = 0x8000
670type_val[("of_match_v3", of_g.VERSION_1_3)] = 0x8000
671
672# Utility function
673def dict_to_array(d, m_val, def_val=-1):
674 """
675 Given a dictionary, d, with each value a small integer,
676 produce an array indexed by the integer whose value is the key.
677 @param d The dictionary
678 @param m_val Ignore values greater than m_val
679 @param def_val The default value (for indices not in range of d)
680 """
681
682 # Get the max value in range for hash
683 max_val = 0
684 for key in d:
685 if (d[key] > max_val) and (d[key] < m_val):
686 max_val = d[key]
687 ar = []
688 for x in range(0, max_val + 1):
689 ar.append(def_val)
690 for key in d:
691 if (d[key] < m_val):
692 ar[d[key]] = key
693 return ar
694
695def type_array_len(version_indexed, max_val):
696 """
697 Given versioned information about a type, calculate how long
698 the unified array should be.
699
700 @param version_indexed A dict indexed by version. Each value is a
701 dict indexed by a name and whose value is an integer
702 @param max_val Ignore values greater than this for length calcs
703 """
704 # First, find the max length of all arrays
705 arr_len = 0
706 for version, val_dict in version_indexed.items():
707 ar = dict_to_array(val_dict, max_val, invalid_type)
708 if arr_len < len(ar):
709 arr_len = len(ar)
710 return arr_len
711
712# FIXME: Need to move update for multipart messages
713
714stats_reply_list = [
715 "of_aggregate_stats_reply",
716 "of_desc_stats_reply",
717 "of_experimenter_stats_reply",
718 "of_flow_stats_reply",
719 "of_group_stats_reply",
720 "of_group_desc_stats_reply",
721 "of_group_features_stats_reply",
722 "of_meter_stats_reply",
723 "of_meter_config_stats_reply",
724 "of_meter_features_stats_reply",
725 "of_port_stats_reply",
726 "of_port_desc_stats_reply",
727 "of_queue_stats_reply",
728 "of_table_stats_reply",
729 "of_table_features_stats_reply"
730]
731
732stats_request_list = [
733 "of_aggregate_stats_request",
734 "of_desc_stats_request",
735 "of_experimenter_stats_request",
736 "of_flow_stats_request",
737 "of_group_stats_request",
738 "of_group_desc_stats_request",
739 "of_group_features_stats_request",
740 "of_meter_stats_request",
741 "of_meter_config_stats_request",
742 "of_meter_features_stats_request",
743 "of_port_stats_request",
744 "of_port_desc_stats_request",
745 "of_queue_stats_request",
746 "of_table_stats_request",
747 "of_table_features_stats_request"
748]
749
750flow_mod_list = [
751 "of_flow_add",
752 "of_flow_modify",
753 "of_flow_modify_strict",
754 "of_flow_delete",
755 "of_flow_delete_strict"
756]
757
758def sub_class_map(base_type, version):
759 """
760 Returns an iterable object giving the instance nameys and subclass types
761 for the base_type, version values
762 """
763 rv = []
764 if base_type not in inheritance_map:
765 return rv
766
767 for instance in inheritance_map[base_type]:
768 subcls = loxi_utils.instance_to_class(instance, base_type)
769 if not loxi_utils.class_in_version(subcls, version):
770 continue
771 rv.append((instance, subcls))
772
773 return rv
774
775################################################################
776#
777# Extension related data and functions
778#
779################################################################
780
781# Per OF Version, per experimenter, map exp msg type (subtype) to object IDs
782# @fixme Generate defines for OF_<exp>_SUBTYPE_<msg> for the values below?
783extension_message_subtype = {
784 # version 1.0
785 of_g.VERSION_1_0:dict( # Version 1.0 extensions
786 bsn = { # BSN extensions; indexed by class name, value is subtype
787 "of_bsn_set_ip_mask" : 0,
788 "of_bsn_get_ip_mask_request" : 1,
789 "of_bsn_get_ip_mask_reply" : 2,
790 "of_bsn_set_mirroring" : 3,
791 "of_bsn_get_mirroring_request" : 4,
792 "of_bsn_get_mirroring_reply" : 5,
793 "of_bsn_shell_command" : 6,
794 "of_bsn_shell_output" : 7,
795 "of_bsn_shell_status" : 8,
796 "of_bsn_get_interfaces_request" : 9,
797 "of_bsn_get_interfaces_reply" : 10,
798 },
799 nicira = { # Nicira extensions, value is subtype
800 "of_nicira_controller_role_request" : 10,
801 "of_nicira_controller_role_reply" : 11,
802 },
803 ),
804 of_g.VERSION_1_1:dict( # Version 1.0 extensions
805 bsn = { # BSN extensions; indexed by class name, value is subtype
806 "of_bsn_set_mirroring" : 3,
807 "of_bsn_get_mirroring_request" : 4,
808 "of_bsn_get_mirroring_reply" : 5,
809 "of_bsn_get_interfaces_request" : 9,
810 "of_bsn_get_interfaces_reply" : 10,
811 },
812 ),
813 of_g.VERSION_1_2:dict( # Version 1.0 extensions
814 bsn = { # BSN extensions; indexed by class name, value is subtype
815 "of_bsn_set_mirroring" : 3,
816 "of_bsn_get_mirroring_request" : 4,
817 "of_bsn_get_mirroring_reply" : 5,
818 "of_bsn_get_interfaces_request" : 9,
819 "of_bsn_get_interfaces_reply" : 10,
820 },
821 ),
822 of_g.VERSION_1_3:dict( # Version 1.0 extensions
823 bsn = { # BSN extensions; indexed by class name, value is subtype
824 "of_bsn_set_mirroring" : 3,
825 "of_bsn_get_mirroring_request" : 4,
826 "of_bsn_get_mirroring_reply" : 5,
827 "of_bsn_get_interfaces_request" : 9,
828 "of_bsn_get_interfaces_reply" : 10,
829 },
830 ),
831}
832
833# Set to empty dict if no extension actions defined
834# Per OF Version, per experimenter, map actions to subtype
835extension_action_subtype = {
836 # version 1.0
837 of_g.VERSION_1_0:dict( # Version 1.0 extensions
838 bsn = { # of_action_bsn_
839 "of_action_bsn_mirror" : 1,
840 "of_action_bsn_set_tunnel_dst" : 2,
841 },
842 nicira = { # of_action_nicira_
843 "of_action_nicira_dec_ttl" : 18,
844 }
845 ),
846 of_g.VERSION_1_1:dict( # Version 1.0 extensions
847 bsn = { # of_action_bsn_
848 "of_action_bsn_mirror" : 1,
849 "of_action_bsn_set_tunnel_dst" : 2,
850 },
851 nicira = { # of_action_nicira_
852 "of_action_nicira_dec_ttl" : 18,
853 }
854 ),
855 of_g.VERSION_1_2:dict( # Version 1.0 extensions
856 bsn = { # of_action_bsn_
857 "of_action_bsn_mirror" : 1,
858 "of_action_bsn_set_tunnel_dst" : 2,
859 },
860 nicira = { # of_action_nicira_
861 "of_action_nicira_dec_ttl" : 18,
862 }
863 ),
864 of_g.VERSION_1_3:dict( # Version 1.0 extensions
865 bsn = { # of_action_bsn_
866 "of_action_bsn_mirror" : 1,
867 "of_action_bsn_set_tunnel_dst" : 2,
868 },
869 nicira = { # of_action_nicira_
870 "of_action_nicira_dec_ttl" : 18,
871 }
872 ),
873}
874
875# Set to empty dict if no extension actions defined
876# Per OF Version, per experimenter, map actions to subtype
877extension_action_id_subtype = {
878 # version 1.0
879 of_g.VERSION_1_0:dict(),
880 of_g.VERSION_1_1:dict(),
881 of_g.VERSION_1_2:dict(),
882 of_g.VERSION_1_3:dict( # Version 1.3 extensions
883 bsn = { # of_action_bsn_
884 "of_action_id_bsn_mirror" : 1,
885 "of_action_id_bsn_set_tunnel_dst" : 2,
886 },
887 nicira = { # of_action_nicira_
888 "of_action_id_nicira_dec_ttl" : 18,
889 }
890 ),
891}
892
893# Set to empty dict if no extension instructions defined
894extension_instruction_subtype = {}
895
896# Set to empty dict if no extension instructions defined
897extension_queue_prop_subtype = {}
898
899# Set to empty dict if no extension instructions defined
900extension_table_feature_prop_subtype = {}
901
902extension_objects = [
903 extension_message_subtype,
904 extension_action_subtype,
905 extension_action_id_subtype,
906 extension_instruction_subtype,
907 extension_queue_prop_subtype,
908 extension_table_feature_prop_subtype
909]
910
911################################################################
912# These are extension type generic (for messages, actions...)
913################################################################
914
915def extension_to_experimenter_name(cls):
916 """
917 Return the name of the experimenter if class is an
918 extension, else None
919
920 This is brute force; we search all extension data for a match
921 """
922
923 for ext_obj in extension_objects:
924 for version, exp_list in ext_obj.items():
925 for exp_name, classes in exp_list.items():
926 if cls in classes:
927 return exp_name
928 return None
929
930def extension_to_experimenter_id(cls):
931 """
932 Return the ID of the experimenter if class is an
933 extension, else None
934 """
935 exp_name = extension_to_experimenter_name(cls)
936 if exp_name:
937 return of_g.experimenter_name_to_id[exp_name]
938 return None
939
940def extension_to_experimenter_macro_name(cls):
941 """
942 Return the "macro name" of the ID of the experimenter if class is an
943 extension, else None
944 """
945 exp_name = extension_to_experimenter_name(cls)
946 if exp_name:
947 return "OF_EXPERIMENTER_ID_" + exp_name.upper()
948 return None
949
950def extension_to_subtype(cls, version):
951 """
952 Generic across all extension objects, return subtype identifier
953 """
954 for ext_obj in extension_objects:
955 for version, exp_list in ext_obj.items():
956 for exp_name, classes in exp_list.items():
957 if cls in classes:
958 return classes[cls]
959
960def class_is_extension(cls, version):
961 """
962 Return True if class, version is recognized as an extension
963 of any type (message, action....)
964
965 Accepts of_g.OF_VERSION_ANY
966 """
967
968 for ext_obj in extension_objects:
969 if cls_is_ext_obj(cls, version, ext_obj):
970 return True
971
972 return False
973
974# Internal
975def cls_is_ext_obj(cls, version, ext_obj):
976 """
977 @brief Return True if cls in an extension of type ext_obj
978 @param cls The class to check
979 @param version The version to check
980 @param ext_obj The extension object dictionary (messages, actions...)
981
982 Accepts of_g.VERSION_ANY
983 """
984
985 # Call with each version if "any" is passed
986 if version == of_g.VERSION_ANY:
987 for v in of_g.of_version_range:
988 if cls_is_ext_obj(cls, v, ext_obj):
989 return True
990 else: # Version specified
991 if version in ext_obj:
992 for exp, subtype_vals in ext_obj[version].items():
993 if cls in subtype_vals:
994 return True
995
996 return False
997
998################################################################
999# These are extension message specific
1000################################################################
1001
1002def message_is_extension(cls, version):
1003 """
1004 Return True if cls, version is recognized as an extension
1005 This is brute force, searching records for a match
1006 """
1007 return cls_is_ext_obj(cls, version, extension_message_subtype)
1008
1009def extension_message_to_subtype(cls, version):
1010 """
1011 Return the subtype of the experimenter message if the class is an
1012 extension, else None
1013 """
1014 if version in extension_message_subtype:
1015 for exp, classes in extension_message_subtype[version].items():
1016 for ext_class, subtype in classes.items():
1017 if cls == ext_class:
1018 return subtype
1019 return None
1020
1021################################################################
1022# These are extension action specific
1023################################################################
1024
1025def action_is_extension(cls, version):
1026 """
1027 Return True if cls, version is recognized as an action extension
1028 This is brute force, searching records for a match
1029 """
1030 return cls_is_ext_obj(cls, version, extension_action_subtype)
1031
1032def extension_action_to_subtype(cls, version):
1033 """
1034 Return the ID of the action subtype (for its experimenteer)
1035 if class is an action extension, else None
1036 """
1037 if version in extension_action_subtype:
1038 for exp, classes in extension_action_subtype[version].items():
1039 if cls in classes:
1040 return classes[cls]
1041
1042 return None
1043
1044################################################################
1045# These are extension action specific
1046################################################################
1047
1048def action_id_is_extension(cls, version):
1049 """
1050 Return True if cls, version is recognized as an action ID extension
1051 This is brute force, searching records for a match
1052 """
1053 if version not in [of_g.VERSION_1_3]: # Action IDs only 1.3
1054 return False
1055 return cls_is_ext_obj(cls, version, extension_action_id_subtype)
1056
1057def extension_action_id_to_subtype(cls, version):
1058 """
1059 Return the ID of the action ID subtype (for its experimenteer)
1060 if class is an action ID extension, else None
1061 """
1062 if version in extension_action_id_subtype:
1063 for exp, classes in extension_action_id_subtype[version].items():
1064 if cls in classes:
1065 return classes[cls]
1066
1067 return None
1068
1069################################################################
1070# These are extension instruction specific
1071################################################################
1072
1073def instruction_is_extension(cls, version):
1074 """
1075 Return True if cls, version is recognized as an instruction extension
1076 This is brute force, searching records for a match
1077 """
1078 return cls_is_ext_obj(cls, version, extension_instruction_subtype)
1079
1080################################################################
1081# These are extension queue_prop specific
1082################################################################
1083
1084def queue_prop_is_extension(cls, version):
1085 """
1086 Return True if cls, version is recognized as an instruction extension
1087 This is brute force, searching records for a match
1088 """
1089 return cls_is_ext_obj(cls, version, extension_queue_prop_subtype)
1090
1091################################################################
1092# These are extension table_feature_prop specific
1093################################################################
1094
1095def table_feature_prop_is_extension(cls, version):
1096 """
1097 Return True if cls, version is recognized as an instruction extension
1098 This is brute force, searching records for a match
1099 """
1100 return cls_is_ext_obj(cls, version,
1101 extension_table_feature_prop_subtype)