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