blob: d6d8b32c76fe8135dbc855d11c290d83e4c96c6c [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
28from collections import namedtuple
Rich Lanec2685792013-04-30 14:08:33 -070029import struct
Rich Lanea06d0c32013-03-25 08:52:03 -070030import of_g
31import loxi_front_end.type_maps as type_maps
32import loxi_utils.loxi_utils as utils
33import util
34import oftype
35
Rich Lane8ca3b772013-04-30 13:36:55 -070036OFClass = namedtuple('OFClass', ['name', 'pyname', 'members', 'type_members',
Rich Lanea06d0c32013-03-25 08:52:03 -070037 'min_length', 'is_fixed_length'])
Rich Laneef0b8872013-05-01 13:54:19 -070038Member = namedtuple('Member', ['name', 'oftype'])
39LengthMember = namedtuple('LengthMember', ['name', 'oftype'])
40FieldLengthMember = namedtuple('FieldLengthMember', ['name', 'oftype', 'field_name'])
41TypeMember = namedtuple('TypeMember', ['name', 'oftype', 'value'])
42PadMember = namedtuple('PadMember', ['length'])
Rich Lanea06d0c32013-03-25 08:52:03 -070043
Rich Lane193317b2013-05-01 12:09:42 -070044# XXX move to frontend
45field_length_members = {
46 ('of_packet_out', 1, 'actions_len') : 'actions',
47 ('of_packet_out', 2, 'actions_len') : 'actions',
48 ('of_packet_out', 3, 'actions_len') : 'actions',
49 ('of_packet_out', 4, 'actions_len') : 'actions',
50}
51
Rich Lanea06d0c32013-03-25 08:52:03 -070052def get_type_values(cls, version):
53 """
54 Returns a map from the name of the type member to its value.
55 """
56 type_values = {}
57
58 # Primary wire type
59 if utils.class_is_message(cls):
60 type_values['version'] = 'const.OFP_VERSION'
61 type_values['type'] = util.constant_for_value(version, "ofp_type", util.primary_wire_type(cls, version))
62 if cls in type_maps.flow_mod_list:
63 type_values['_command'] = util.constant_for_value(version, "ofp_flow_mod_command",
64 type_maps.flow_mod_types[version][cls[8:]])
65 if cls in type_maps.stats_request_list:
66 type_values['stats_type'] = util.constant_for_value(version, "ofp_stats_types",
67 type_maps.stats_types[version][cls[3:-14]])
68 if cls in type_maps.stats_reply_list:
69 type_values['stats_type'] = util.constant_for_value(version, "ofp_stats_types",
70 type_maps.stats_types[version][cls[3:-12]])
71 if type_maps.message_is_extension(cls, version):
72 type_values['experimenter'] = '%#x' % type_maps.extension_to_experimenter_id(cls)
73 type_values['subtype'] = type_maps.extension_message_to_subtype(cls, version)
74 elif utils.class_is_action(cls):
75 type_values['type'] = util.constant_for_value(version, "ofp_action_type", util.primary_wire_type(cls, version))
76 if type_maps.action_is_extension(cls, version):
77 type_values['experimenter'] = '%#x' % type_maps.extension_to_experimenter_id(cls)
78 type_values['subtype'] = type_maps.extension_action_to_subtype(cls, version)
79 elif utils.class_is_queue_prop(cls):
80 type_values['type'] = util.constant_for_value(version, "ofp_queue_properties", util.primary_wire_type(cls, version))
Rich Lanee90685c2013-04-05 17:27:41 -070081 elif utils.class_is_hello_elem(cls):
82 type_values['type'] = util.constant_for_value(version, "ofp_hello_elem_type", util.primary_wire_type(cls, version))
Rich Laneea693752013-03-18 11:05:45 -070083 elif utils.class_is_oxm(cls):
84 oxm_class = 0x8000
85 oxm_type = util.primary_wire_type(cls, version)
86 oxm_masked = cls.find('masked') != -1 and 1 or 0
Rich Lane82e9f6e2013-04-25 17:32:22 -070087 oxm_len = of_g.base_length[(cls, version)] - 4
Rich Laneea693752013-03-18 11:05:45 -070088 type_values['type_len'] = '%#x' % (oxm_class << 16 | oxm_type << 8 | \
89 oxm_masked << 8 | oxm_len)
Rich Lane0b2ce252013-05-01 13:21:22 -070090 elif cls == "of_match_v2":
91 type_values['type'] = 0
Rich Lane3005cf92013-05-01 12:33:35 -070092 elif cls == "of_match_v3":
93 type_values['type'] = 1
Rich Laned82c0a62013-05-02 15:40:35 -070094 elif utils.class_is_meter_band(cls):
95 type_values['type'] = util.constant_for_value(version, "ofp_meter_band_type", util.primary_wire_type(cls, version))
Rich Lanee02314c2013-05-02 16:42:04 -070096 elif utils.class_is_instruction(cls):
97 type_values['type'] = util.constant_for_value(version, "ofp_instruction_type", util.primary_wire_type(cls, version))
Rich Lanea06d0c32013-03-25 08:52:03 -070098
99 return type_values
100
101# Create intermediate representation
102def build_ofclasses(version):
103 blacklist = ["of_action", "of_action_header", "of_header", "of_queue_prop",
Rich Lane3f075972013-03-15 22:56:29 -0700104 "of_queue_prop_header", "of_experimenter", "of_action_experimenter",
Rich Lanee90685c2013-04-05 17:27:41 -0700105 "of_oxm", "of_oxm_header", "of_oxm_experimenter_header",
106 "of_hello_elem", "of_hello_elem_header"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700107 ofclasses = []
108 for cls in of_g.standard_class_order:
Rich Laned82c0a62013-05-02 15:40:35 -0700109 if type_maps.class_is_virtual(cls):
110 continue
Rich Lanea06d0c32013-03-25 08:52:03 -0700111 if version not in of_g.unified[cls] or cls in blacklist:
112 continue
113 unified_class = util.lookup_unified_class(cls, version)
114
115 # Name for the generated Python class
116 if utils.class_is_action(cls):
117 pyname = cls[10:]
Rich Laneea693752013-03-18 11:05:45 -0700118 elif utils.class_is_oxm(cls):
119 pyname = cls[7:]
Rich Laned82c0a62013-05-02 15:40:35 -0700120 elif utils.class_is_meter_band(cls):
121 pyname = cls[14:]
Rich Lanee02314c2013-05-02 16:42:04 -0700122 elif utils.class_is_instruction(cls):
123 pyname = cls[15:]
Rich Lanea06d0c32013-03-25 08:52:03 -0700124 else:
125 pyname = cls[3:]
126
127 type_values = get_type_values(cls, version)
128 members = []
Rich Lanea06d0c32013-03-25 08:52:03 -0700129 type_members = []
Rich Lane8ca3b772013-04-30 13:36:55 -0700130
Rich Lanec58a2322013-03-15 23:28:52 -0700131 pad_count = 0
Rich Lanea06d0c32013-03-25 08:52:03 -0700132
133 for member in unified_class['members']:
134 if member['name'] in ['length', 'len']:
Rich Lane8ca3b772013-04-30 13:36:55 -0700135 members.append(LengthMember(name=member['name'],
Rich Lane8ca3b772013-04-30 13:36:55 -0700136 oftype=oftype.OFType(member['m_type'], version)))
Rich Lane193317b2013-05-01 12:09:42 -0700137 elif (cls, version, member['name']) in field_length_members:
138 field_name = field_length_members[(cls, version, member['name'])]
139 members.append(FieldLengthMember(name=member['name'],
Rich Lane193317b2013-05-01 12:09:42 -0700140 oftype=oftype.OFType(member['m_type'], version),
141 field_name=field_name))
Rich Lanea06d0c32013-03-25 08:52:03 -0700142 elif member['name'] in type_values:
Rich Lane8ca3b772013-04-30 13:36:55 -0700143 members.append(TypeMember(name=member['name'],
Rich Lane8ca3b772013-04-30 13:36:55 -0700144 oftype=oftype.OFType(member['m_type'], version),
145 value=type_values[member['name']]))
146 type_members.append(members[-1])
Rich Lanec2685792013-04-30 14:08:33 -0700147 elif member['name'].startswith("pad"):
148 # HACK this should be moved to the frontend
149 pad_oftype = oftype.OFType(member['m_type'], version)
150 length = struct.calcsize("!" + pad_oftype._pack_fmt())
151 if pad_oftype.is_array: length *= pad_oftype.array_length
Rich Laneef0b8872013-05-01 13:54:19 -0700152 members.append(PadMember(length=length))
Rich Lanec2685792013-04-30 14:08:33 -0700153 else:
154 members.append(Member(name=member['name'],
Rich Laneef0b8872013-05-01 13:54:19 -0700155 oftype=oftype.OFType(member['m_type'], version)))
Rich Lanea06d0c32013-03-25 08:52:03 -0700156
157 ofclasses.append(
158 OFClass(name=cls,
159 pyname=pyname,
160 members=members,
Rich Lanea06d0c32013-03-25 08:52:03 -0700161 type_members=type_members,
162 min_length=of_g.base_length[(cls, version)],
163 is_fixed_length=(cls, version) in of_g.is_fixed_length))
164 return ofclasses
165
166def generate_init(out, name, version):
Rich Laneea693752013-03-18 11:05:45 -0700167 util.render_template(out, 'init.py', version=version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700168
169def generate_action(out, name, version):
170 ofclasses = [x for x in build_ofclasses(version)
171 if utils.class_is_action(x.name)]
Rich Lane3f075972013-03-15 22:56:29 -0700172 util.render_template(out, 'action.py', ofclasses=ofclasses, version=version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700173
Rich Laneea693752013-03-18 11:05:45 -0700174def generate_oxm(out, name, version):
175 ofclasses = [x for x in build_ofclasses(version)
176 if utils.class_is_oxm(x.name)]
177 util.render_template(out, 'oxm.py', ofclasses=ofclasses, version=version)
178
Rich Lanea06d0c32013-03-25 08:52:03 -0700179def generate_common(out, name, version):
180 ofclasses = [x for x in build_ofclasses(version)
181 if not utils.class_is_message(x.name)
182 and not utils.class_is_action(x.name)
Rich Lanee02314c2013-05-02 16:42:04 -0700183 and not utils.class_is_instruction(x.name)
Rich Laned82c0a62013-05-02 15:40:35 -0700184 and not utils.class_is_meter_band(x.name)
Rich Laneea693752013-03-18 11:05:45 -0700185 and not utils.class_is_oxm(x.name)
Rich Lanea06d0c32013-03-25 08:52:03 -0700186 and not utils.class_is_list(x.name)]
Rich Lane3f075972013-03-15 22:56:29 -0700187 util.render_template(out, 'common.py', ofclasses=ofclasses, version=version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700188
189def generate_const(out, name, version):
190 groups = {}
191 for (group, idents) in of_g.identifiers_by_group.items():
192 items = []
193 for ident in idents:
194 info = of_g.identifiers[ident]
195 if version in info["values_by_version"]:
196 items.append((info["ofp_name"], info["values_by_version"][version]))
197 if items:
198 groups[group] = items
199 util.render_template(out, 'const.py', version=version, groups=groups)
200
Rich Lanee02314c2013-05-02 16:42:04 -0700201def generate_instruction(out, name, version):
202 ofclasses = [x for x in build_ofclasses(version)
203 if utils.class_is_instruction(x.name)]
204 util.render_template(out, 'instruction.py', ofclasses=ofclasses, version=version)
205
Rich Lanea06d0c32013-03-25 08:52:03 -0700206def generate_message(out, name, version):
207 ofclasses = [x for x in build_ofclasses(version)
208 if utils.class_is_message(x.name)]
209 util.render_template(out, 'message.py', ofclasses=ofclasses, version=version)
210
Rich Laned82c0a62013-05-02 15:40:35 -0700211def generate_meter_band(out, name, version):
212 ofclasses = [x for x in build_ofclasses(version)
213 if utils.class_is_meter_band(x.name)]
214 util.render_template(out, 'meter_band.py', ofclasses=ofclasses, version=version)
215
Rich Lanea06d0c32013-03-25 08:52:03 -0700216def generate_pp(out, name, version):
217 util.render_template(out, 'pp.py')
218
219def generate_util(out, name, version):
Rich Laneadb79832013-05-02 17:14:33 -0700220 util.render_template(out, 'util.py', version=version)