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