blob: b8e014fd7475e5899604ad2e58e4124acd33ec36 [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
29import of_g
30import loxi_front_end.type_maps as type_maps
31import loxi_utils.loxi_utils as utils
32import util
33import oftype
34
35OFClass = namedtuple('OFClass', ['name', 'pyname',
36 'members', 'length_member', 'type_members',
37 'min_length', 'is_fixed_length'])
38Member = namedtuple('Member', ['name', 'oftype', 'offset', 'skip'])
39LengthMember = namedtuple('LengthMember', ['name', 'oftype', 'offset'])
40TypeMember = namedtuple('TypeMember', ['name', 'oftype', 'offset', 'value'])
41
42def get_type_values(cls, version):
43 """
44 Returns a map from the name of the type member to its value.
45 """
46 type_values = {}
47
48 # Primary wire type
49 if utils.class_is_message(cls):
50 type_values['version'] = 'const.OFP_VERSION'
51 type_values['type'] = util.constant_for_value(version, "ofp_type", util.primary_wire_type(cls, version))
52 if cls in type_maps.flow_mod_list:
53 type_values['_command'] = util.constant_for_value(version, "ofp_flow_mod_command",
54 type_maps.flow_mod_types[version][cls[8:]])
55 if cls in type_maps.stats_request_list:
56 type_values['stats_type'] = util.constant_for_value(version, "ofp_stats_types",
57 type_maps.stats_types[version][cls[3:-14]])
58 if cls in type_maps.stats_reply_list:
59 type_values['stats_type'] = util.constant_for_value(version, "ofp_stats_types",
60 type_maps.stats_types[version][cls[3:-12]])
61 if type_maps.message_is_extension(cls, version):
62 type_values['experimenter'] = '%#x' % type_maps.extension_to_experimenter_id(cls)
63 type_values['subtype'] = type_maps.extension_message_to_subtype(cls, version)
64 elif utils.class_is_action(cls):
65 type_values['type'] = util.constant_for_value(version, "ofp_action_type", util.primary_wire_type(cls, version))
66 if type_maps.action_is_extension(cls, version):
67 type_values['experimenter'] = '%#x' % type_maps.extension_to_experimenter_id(cls)
68 type_values['subtype'] = type_maps.extension_action_to_subtype(cls, version)
69 elif utils.class_is_queue_prop(cls):
70 type_values['type'] = util.constant_for_value(version, "ofp_queue_properties", util.primary_wire_type(cls, version))
71
72 return type_values
73
74# Create intermediate representation
75def build_ofclasses(version):
76 blacklist = ["of_action", "of_action_header", "of_header", "of_queue_prop",
Rich Lane3f075972013-03-15 22:56:29 -070077 "of_queue_prop_header", "of_experimenter", "of_action_experimenter",
78 "of_oxm"]
Rich Lanea06d0c32013-03-25 08:52:03 -070079 ofclasses = []
80 for cls in of_g.standard_class_order:
81 if version not in of_g.unified[cls] or cls in blacklist:
82 continue
83 unified_class = util.lookup_unified_class(cls, version)
84
85 # Name for the generated Python class
86 if utils.class_is_action(cls):
87 pyname = cls[10:]
88 else:
89 pyname = cls[3:]
90
91 type_values = get_type_values(cls, version)
92 members = []
93
94 length_member = None
95 type_members = []
Rich Lanec58a2322013-03-15 23:28:52 -070096 pad_count = 0
Rich Lanea06d0c32013-03-25 08:52:03 -070097
98 for member in unified_class['members']:
99 if member['name'] in ['length', 'len']:
100 length_member = LengthMember(name=member['name'],
101 offset=member['offset'],
102 oftype=oftype.OFType(member['m_type'], version))
103 elif member['name'] in type_values:
104 type_members.append(TypeMember(name=member['name'],
105 offset=member['offset'],
106 oftype=oftype.OFType(member['m_type'], version),
107 value=type_values[member['name']]))
108 else:
109 # HACK ensure member names are unique
Rich Lanec58a2322013-03-15 23:28:52 -0700110 if member['name'].startswith("pad"):
111 if pad_count == 0:
112 m_name = 'pad'
113 else:
114 m_name = "pad%d" % pad_count
115 pad_count += 1
Rich Lanea06d0c32013-03-25 08:52:03 -0700116 else:
117 m_name = member['name']
118 members.append(Member(name=m_name,
119 oftype=oftype.OFType(member['m_type'], version),
120 offset=member['offset'],
121 skip=member['name'] in of_g.skip_members))
122
123 ofclasses.append(
124 OFClass(name=cls,
125 pyname=pyname,
126 members=members,
127 length_member=length_member,
128 type_members=type_members,
129 min_length=of_g.base_length[(cls, version)],
130 is_fixed_length=(cls, version) in of_g.is_fixed_length))
131 return ofclasses
132
133def generate_init(out, name, version):
134 util.render_template(out, 'init.py')
135
136def generate_action(out, name, version):
137 ofclasses = [x for x in build_ofclasses(version)
138 if utils.class_is_action(x.name)]
Rich Lane3f075972013-03-15 22:56:29 -0700139 util.render_template(out, 'action.py', ofclasses=ofclasses, version=version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700140
141def generate_common(out, name, version):
142 ofclasses = [x for x in build_ofclasses(version)
143 if not utils.class_is_message(x.name)
144 and not utils.class_is_action(x.name)
145 and not utils.class_is_list(x.name)]
Rich Lane3f075972013-03-15 22:56:29 -0700146 util.render_template(out, 'common.py', ofclasses=ofclasses, version=version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700147
148def generate_const(out, name, version):
149 groups = {}
150 for (group, idents) in of_g.identifiers_by_group.items():
151 items = []
152 for ident in idents:
153 info = of_g.identifiers[ident]
154 if version in info["values_by_version"]:
155 items.append((info["ofp_name"], info["values_by_version"][version]))
156 if items:
157 groups[group] = items
158 util.render_template(out, 'const.py', version=version, groups=groups)
159
160def generate_message(out, name, version):
161 ofclasses = [x for x in build_ofclasses(version)
162 if utils.class_is_message(x.name)]
163 util.render_template(out, 'message.py', ofclasses=ofclasses, version=version)
164
165def generate_pp(out, name, version):
166 util.render_template(out, 'pp.py')
167
168def generate_util(out, name, version):
169 util.render_template(out, 'util.py')