blob: c4e8b5c4f61ff063e242ff254429fe6e701d9aea [file] [log] [blame]
:: # Copyright 2014, Big Switch Networks, Inc.
:: #
:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
:: # the following special exception:
:: #
:: # LOXI Exception
:: #
:: # As a special exception to the terms of the EPL, you may distribute libraries
:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
:: # from the LoxiGen Libraries and the notice provided below is (i) included in
:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
:: # documentation for the LoxiGen Libraries, if distributed in binary form.
:: #
:: # Notice: "Copyright 2014, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
:: #
:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
:: # a copy of the EPL at:
:: #
:: # http://www.eclipse.org/legal/epl-v10.html
:: #
:: # Unless required by applicable law or agreed to in writing, software
:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
:: # EPL for the specific language governing permissions and limitations
:: # under the EPL.
::
:: include('_copyright.c')
:: import loxi_globals
:: from loxi_ir import *
/**
*
* AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
*
* Source file for OpenFlow message validation.
*
*/
#include "loci_log.h"
#include <loci/loci.h>
#include <loci/loci_validator.h>
#define VALIDATOR_LOG(...) LOCI_LOG_ERROR("Validator Error: " __VA_ARGS__)
:: raw_validator_name = lambda cls, version: "loci_validate_%s_%s" % (cls, version.constant_version(prefix='OF_VERSION_'))
:: validator_name = lambda ofclass: "loci_validate_%s_%s" % (ofclass.name, ofclass.protocol.version.constant_version(prefix='OF_VERSION_'))
/* Forward declarations */
:: for version, proto in loxi_globals.ir.items():
:: for ofclass in proto.classes:
static int __attribute__((unused)) ${validator_name(ofclass)}(uint8_t *data, int len, int *out_len);
:: #endfor
:: #endfor
:: readers = { 1: 'buf_u8_get', 2: 'buf_u16_get', 4: 'buf_u32_get' }
:: types = { 1: 'uint8_t', 2: 'uint16_t', 4: 'uint32_t' }
:: for version, proto in loxi_globals.ir.items():
:: # Identify classes in lists and generate list validators
:: seen_lists = set()
:: for ofclass in proto.classes:
:: for m in ofclass.members:
:: if type(m) == OFDataMember and m.oftype.startswith('list'):
:: element_name = m.oftype[8:-3]
:: if element_name in seen_lists:
:: continue
:: #endif
:: seen_lists.add(element_name)
:: list_validator_name = raw_validator_name('of_list_' + element_name, version)
static int __attribute__((unused))
${list_validator_name}(uint8_t *data, int len, int *out_len)
{
while (len > 0) {
int cur_len = 0xffff;
if (${raw_validator_name('of_' + element_name, version)}(data, len, &cur_len) < 0) {
return -1;
}
len -= cur_len;
data += cur_len;
}
return 0;
}
:: #endif
:: #endfor
:: #endfor
:: for ofclass in proto.classes:
static int
${validator_name(ofclass)}(uint8_t *data, int len, int *out_len)
{
if (len < ${ofclass.base_length}) {
return -1;
}
:: if ofclass.is_fixed_length:
len = ${ofclass.base_length};
:: #endif
:: # Read and validate length fields
:: field_length_members = {}
:: for m in ofclass.members:
:: if type(m) == OFLengthMember:
${types[m.length]} wire_len;
${readers[m.length]}(data + ${m.offset}, &wire_len);
if (wire_len > len || wire_len < ${ofclass.base_length}) {
return -1;
}
:: if not ofclass.is_fixed_length:
len = wire_len;
:: #endif
::
:: elif type(m) == OFFieldLengthMember:
:: # Read field length members
:: field_length_members[m.field_name] = m
${types[m.length]} wire_len_${m.field_name};
${readers[m.length]}(data + ${m.offset}, &wire_len_${m.field_name});
:: #endif
:: #endfor
:: # Dispatch to subclass validators
:: if ofclass.virtual:
:: discriminator = ofclass.discriminator
${types[discriminator.length]} wire_type;
${readers[discriminator.length]}(data + ${discriminator.offset}, &wire_type);
switch (wire_type) {
:: for subclass in proto.classes:
:: if subclass.superclass == ofclass:
case ${hex(subclass.member_by_name(discriminator.name).value)}:
return ${validator_name(subclass)}(data, len, out_len);
:: #endif
:: #endfor
}
:: #endif
:: for m in ofclass.members:
:: # Validate field-length members
:: if type(m) == OFDataMember and m.name in field_length_members and m.offset is not None:
if (${m.offset} + wire_len_${m.name} > len) {
return -1;
}
:: #endif
:: if type(m) == OFDataMember and m.oftype.startswith('list'):
:: # Validate lists
:: if m.offset is None:
// TODO validate non fixed offset member ${m.name}
:: continue
:: #endif
:: if not m.name in field_length_members:
int wire_len_${m.name} = len - ${m.offset};
:: #endif
:: element_name = m.oftype[8:-3]
:: list_validator_name = raw_validator_name('of_list_' + element_name, version)
if (${list_validator_name}(data + ${m.offset}, wire_len_${m.name}, out_len) < 0) {
return -1;
}
:: elif type(m) == OFDataMember and m.oftype == "of_match_t":
// TODO validate of_match_t
:: elif type(m) == OFDataMember and m.oftype == "of_bsn_vport_t":
// TODO validate of_bsn_vport_t
:: elif type(m) == OFDataMember and m.oftype == "of_meter_config_t":
// TODO validate of_meter_config_t
:: elif type(m) == OFDataMember and m.oftype == "of_meter_features_t":
// TODO validate of_meter_features_t
:: #endif
:: #endfor
*out_len = len;
return 0;
}
:: #endfor
:: #endfor
int
of_validate_message(of_message_t msg, int len)
{
of_version_t version;
if (len < OF_MESSAGE_MIN_LENGTH ||
len != of_message_length_get(msg)) {
VALIDATOR_LOG("message length %d != %d", len,
of_message_length_get(msg));
return -1;
}
version = of_message_version_get(msg);
int out_len;
switch (version) {
:: for version, proto in loxi_globals.ir.items():
case ${version.constant_version(prefix='OF_VERSION_')}:
return ${validator_name(proto.class_by_name('of_header'))}(msg, len, &out_len);
:: #endfor
default:
VALIDATOR_LOG("Bad version %d", version);
return -1;
}
}