blob: 3ab6acf702fe6b09b0077ed23ce05866e2eb0c5e [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@brief Validator function generation
30
31Generates validator function files.
32
33"""
34
35import sys
36import of_g
37import loxi_front_end.match as match
38import loxi_front_end.flags as flags
39from generic_utils import *
40import loxi_front_end.type_maps as type_maps
41import loxi_utils.loxi_utils as loxi_utils
42import loxi_front_end.identifiers as identifiers
43from c_test_gen import var_name_map
44
45def gen_h(out, name):
46 loxi_utils.gen_c_copy_license(out)
47 out.write("""
48/**
49 *
50 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
51 *
52 * Declarations of message validation functions. These functions check that an
53 * OpenFlow message is well formed. Specifically, they check internal length
54 * fields.
55 */
56
57#if !defined(_LOCI_VALIDATOR_H_)
58#define _LOCI_VALIDATOR_H_
59
60#include <loci/loci.h>
61
62/*
63 * Validate an OpenFlow message.
64 * @return 0 if message is valid, -1 otherwise.
65 */
66extern int of_validate_message(of_message_t msg, int len);
67
68#endif /* _LOCI_VALIDATOR_H_ */
69""")
70
71def gen_c(out, name):
72 loxi_utils.gen_c_copy_license(out)
73 out.write("""
74/**
75 *
76 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
77 *
78 * Source file for OpenFlow message validation.
79 *
80 */
81
82#include "loci_log.h"
83#include <loci/loci.h>
84#include <loci/loci_validator.h>
85
86#define VALIDATOR_LOG(...) LOCI_LOG_ERROR("Validator Error: " __VA_ARGS__)
87
88""")
89
90 # Declarations
91 for version in of_g.of_version_range:
92 ver_name = loxi_utils.version_to_name(version)
93 for cls in reversed(of_g.standard_class_order):
94 if not loxi_utils.class_in_version(cls, version):
95 continue
96 if cls in type_maps.inheritance_map:
97 continue
98 out.write("""
99static inline int %(cls)s_%(ver_name)s_validate(uint8_t *buf, int len);\
100""" % dict(cls=cls, ver_name=ver_name))
101
102 out.write("\n")
103
104 # Definitions
105 for version in of_g.of_version_range:
106 ver_name = loxi_utils.version_to_name(version)
107 for cls in reversed(of_g.standard_class_order):
108 if not loxi_utils.class_in_version(cls, version):
109 continue
110 if cls in type_maps.inheritance_map:
111 continue
112 if loxi_utils.class_is_list(cls):
113 gen_list_validator(out, cls, version)
114 else:
115 gen_validator(out, cls, version)
116
117 out.write("""
118int
119of_validate_message_%(ver_name)s(of_message_t msg, int len)
120{
121 of_object_id_t object_id = of_message_to_object_id(msg, len);
122 uint8_t *buf = OF_MESSAGE_TO_BUFFER(msg);
123 switch (object_id) {
124""" % dict(ver_name=ver_name))
125 for cls in reversed(of_g.standard_class_order):
126 if not loxi_utils.class_in_version(cls, version):
127 continue
128 if cls in type_maps.inheritance_map:
129 continue
130 if loxi_utils.class_is_message(cls):
131 out.write("""\
132 case %(cls_id)s:
133 return %(cls)s_%(ver_name)s_validate(buf, len);
134""" % dict(ver_name=ver_name, cls=cls, cls_id=cls.upper()))
135 out.write("""\
136 default:
137 VALIDATOR_LOG("%(cls)s: could not map %(cls_id)s");
138 return -1;
139 }
140}
141""" % dict(ver_name=ver_name, cls=cls, cls_id=cls.upper()))
142
143 out.write("""
144int
145of_validate_message(of_message_t msg, int len)
146{
147 of_version_t version;
148 if (len < OF_MESSAGE_MIN_LENGTH ||
149 len != of_message_length_get(msg)) {
150 VALIDATOR_LOG("message length %d != %d", len,
151 of_message_length_get(msg));
152 return -1;
153 }
154
155 version = of_message_version_get(msg);
156 switch (version) {
157""")
158
159 for version in of_g.of_version_range:
160 ver_name = loxi_utils.version_to_name(version)
161 out.write("""\
162 case %(ver_name)s:
163 return of_validate_message_%(ver_name)s(msg, len);
164""" % dict(ver_name=ver_name))
165
166 out.write("""\
167 default:
168 VALIDATOR_LOG("Bad version %%d", %(ver_name)s);
169 return -1;
170 }
171}
172""" % dict(ver_name=ver_name))
173
174def gen_validator(out, cls, version):
175 fixed_len = of_g.base_length[(cls, version)];
176 ver_name = loxi_utils.version_to_name(version)
177 out.write("""
178static inline int
179%(cls)s_%(ver_name)s_validate(uint8_t *buf, int len)
180{
181 if (len < %(fixed_len)s) {
182 VALIDATOR_LOG("Class %(cls)s. Len %%d too small, < %%d", len, %(fixed_len)s);
183 return -1;
184 }
185""" % dict(cls=cls, ver_name=ver_name, cls_id=cls.upper(), fixed_len=fixed_len))
186 members, member_types = loxi_utils.all_member_types_get(cls, version)
187 for member in members:
188 m_type = member["m_type"]
189 m_name = member["name"]
190 m_offset = member['offset']
191 m_cls = m_type[:-2] # Trim _t
192 if loxi_utils.skip_member_name(m_name):
193 continue
194 if not loxi_utils.type_is_of_object(m_type):
195 continue
196 if not loxi_utils.class_is_var_len(m_cls, version):
197 continue
198 if cls == "of_packet_out" and m_name == "actions":
199 # See _PACKET_OUT_ACTION_LEN
200 out.write("""
201 {
202 uint16_t %(m_name)s_len;
203 buf_u16_get(buf + %(m_offset)s - 2, &%(m_name)s_len);
204 if (%(m_name)s_len + %(m_offset)s > len) {
205 VALIDATOR_LOG("Class %(cls)s, member %(m_name)s. "
206 "Len %%d and offset %%d too big for %%d",
207 %(m_name)s_len, %(m_offset)s, len);
208 return -1;
209 }
210""" % dict(m_name=m_name, m_offset=m_offset, cls=cls))
211 else:
212 out.write("""
213
214 { int %(m_name)s_len = len - %(m_offset)s;
215
216""" % dict(m_name=m_name, m_offset=m_offset))
217 out.write("""
218 if (%(m_cls)s_%(ver_name)s_validate(buf + %(m_offset)s, %(m_name)s_len) < 0) {
219 return -1;
220 }
221 }
222""" % dict(m_name=m_name, m_cls=m_cls, ver_name=ver_name, m_offset=m_offset))
223 out.write("""
224 return 0;
225}
226""")
227
228def gen_list_validator(out, cls, version):
229 ver_name = loxi_utils.version_to_name(version)
230 e_cls = loxi_utils.list_to_entry_type(cls)
231 fixed_len = of_g.base_length[(e_cls, version)];
232 out.write("""
233static inline int
234%(cls)s_%(ver_name)s_validate(uint8_t *buf, int len)
235{
236""" % dict(cls=cls, ver_name=ver_name, cls_id=cls.upper(), e_cls=e_cls))
237
238 # TLV16
239 if loxi_utils.class_is_tlv16(e_cls):
240 subclasses = type_maps.inheritance_map[e_cls]
241 out.write("""\
242 while (len >= %(fixed_len)s) {
243 of_object_id_t e_id;
244 uint16_t e_type, e_len;
245 buf_u16_get(buf, &e_type);
246 buf_u16_get(buf+2, &e_len);
247 e_id = %(e_cls)s_to_object_id(e_type, %(ver_name)s);
248 switch (e_id) {
249""" % dict(fixed_len=fixed_len, ver_name=ver_name, e_cls=e_cls))
250 for subcls in subclasses:
251 subcls = e_cls + '_' + subcls
252 if not loxi_utils.class_in_version(subcls, version):
253 continue
254 out.write("""\
255 case %(subcls_enum)s:
256 if (%(subcls)s_%(ver_name)s_validate(buf, e_len) < 0) {
257 return -1;
258 }
259 break;
260""" % dict(ver_name=ver_name, subcls=subcls, subcls_enum=loxi_utils.enum_name(subcls)))
261 out.write("""\
262 default:
263 return -1;
264 }
265 buf += e_len;
266 len -= e_len;
267 }
268 if (len != 0) {
269 return -1;
270 }
271""" % dict(e_cls=e_cls, ver_name=ver_name))
272
273 # U16 len
274 elif loxi_utils.class_is_u16_len(e_cls) or loxi_utils.class_is_action(e_cls):
275 out.write("""\
276 /* TODO verify U16 len elements */
277""" % dict())
278
279 # OXM
280 elif loxi_utils.class_is_oxm(e_cls):
281 out.write("""\
282 /* TODO verify OXM elements */
283""" % dict())
284
285 # Fixed length
286 elif not loxi_utils.class_is_var_len(e_cls, version):
287 out.write("""\
288 if ((len / %(fixed_len)s) * %(fixed_len)s != len) {
289 return -1;
290 }
291""" % dict(fixed_len=fixed_len))
292
293 # ???
294 else:
295 out.write("""\
296 /* XXX unknown element format */
297""" % dict())
298
299 out.write("""
300 return 0;
301}
302""")