Merge into master from pull request #203:
loci: fix byte swapping on OS X (https://github.com/floodlight/loxigen/pull/203)
diff --git a/README.md b/README.md
index 1e70f9d..98ec28e 100644
--- a/README.md
+++ b/README.md
@@ -31,6 +31,8 @@
itself. We do ask you to install it and use it before submitting pull requests,
though.
+Running the Java unit tests requires Maven 3: `sudo apt-get install maven`.
+
Usage
=====
diff --git a/c_gen/c_code_gen.py b/c_gen/c_code_gen.py
index b655433..ff9a654 100644
--- a/c_gen/c_code_gen.py
+++ b/c_gen/c_code_gen.py
@@ -437,6 +437,7 @@
of_object_id_t of_action_to_object_id(int action, of_version_t version);
of_object_id_t of_action_id_to_object_id(int action_id, of_version_t version);
of_object_id_t of_instruction_to_object_id(int instruction, of_version_t version);
+of_object_id_t of_instruction_id_to_object_id(int instruction, of_version_t version);
of_object_id_t of_queue_prop_to_object_id(int queue_prop, of_version_t version);
of_object_id_t of_table_feature_prop_to_object_id(int table_feature_prop, of_version_t version);
of_object_id_t of_meter_band_to_object_id(int meter_band, of_version_t version);
@@ -467,7 +468,7 @@
* underlying wire buffer's current bytes.
*/
#define OF_LENGTH_CHECK_ASSERT(obj) \\
- ASSERT(((obj)->parent != NULL) || \\
+ LOCI_ASSERT(((obj)->parent != NULL) || \\
((obj)->wire_object.wbuf == NULL) || \\
(WBUF_CURRENT_BYTES((obj)->wire_object.wbuf) == (obj)->length))
@@ -609,14 +610,21 @@
extern const char *const of_error_strings[];
-#ifndef NDEBUG
-/* #define ASSERT(val) assert(val) */
-#define FORCE_FAULT *(volatile int *)0 = 1
-#define ASSERT(val) if (!(val)) \\
- fprintf(stderr, "\\nASSERT %s. %s:%d\\n", #val, __FILE__, __LINE__), \\
- FORCE_FAULT
+#ifdef __GNUC__
+#define LOCI_NORETURN_ATTR __attribute__((__noreturn__))
#else
-#define ASSERT(val)
+#define LOCI_NORETURN_ATTR
+#endif
+
+extern void loci_assert_fail(
+ const char *cond,
+ const char *file,
+ unsigned int line) LOCI_NORETURN_ATTR;
+
+#ifndef NDEBUG
+#define LOCI_ASSERT(val) ((val) ? (void)0 : loci_assert_fail(#val, __FILE__, __LINE__))
+#else
+#define LOCI_ASSERT(val)
#endif
/*
@@ -1650,13 +1658,13 @@
out.write(" OF_PORT_NO_VALUE_CHECK(*%s, ver);\n" % m_name)
elif m_type == "of_octets_t":
out.write("""\
- ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
+ LOCI_ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
%(m_name)s->bytes = cur_len;
%(m_name)s->data = OF_WIRE_BUFFER_INDEX(wbuf, abs_offset);
""" % dict(m_name=m_name))
elif m_type == "of_match_t":
out.write("""
- ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
+ LOCI_ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
match_octets.bytes = cur_len;
match_octets.data = OF_OBJECT_BUFFER_INDEX(obj, offset);
OF_TRY(of_match_deserialize(ver, %(m_name)s, &match_octets));
@@ -1714,8 +1722,8 @@
if (obj->wire_object.wbuf == %(m_name)s->wire_object.wbuf) {
of_wire_buffer_grow(wbuf, abs_offset + new_len);
/* Verify that the offsets are correct */
- ASSERT(abs_offset == OF_OBJECT_ABSOLUTE_OFFSET(%(m_name)s, 0));
- /* ASSERT(new_len == cur_len); */ /* fixme: may fail for OXM lists */
+ LOCI_ASSERT(abs_offset == OF_OBJECT_ABSOLUTE_OFFSET(%(m_name)s, 0));
+ /* LOCI_ASSERT(new_len == cur_len); */ /* fixme: may fail for OXM lists */
return %(ret_success)s;
}
@@ -1831,10 +1839,10 @@
""")
out.write("""
- ASSERT(%(assert_str)s);
+ LOCI_ASSERT(%(assert_str)s);
ver = obj->version;
wbuf = OF_OBJECT_TO_WBUF(obj);
- ASSERT(wbuf != NULL);
+ LOCI_ASSERT(wbuf != NULL);
/* By version, determine offset and current length (where needed) */
switch (ver) {
@@ -1863,14 +1871,14 @@
gen_accessor_offsets(out, cls, m_name, next, a_type, m_type, prev_o)
out.write("""\
default:
- ASSERT(0);
+ LOCI_ASSERT(0);
}
abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, offset);
- ASSERT(abs_offset >= 0);
+ LOCI_ASSERT(abs_offset >= 0);
""")
if not loxi_utils.type_is_scalar(m_type):
- out.write(" ASSERT(cur_len >= 0 && cur_len < 64 * 1024);\n")
+ out.write(" LOCI_ASSERT(cur_len >= 0 && cur_len < 64 * 1024);\n")
# Now generate the common accessor code
if a_type in ["get", "bind"]:
@@ -2038,7 +2046,7 @@
""" % cls)
out.write("""
- ASSERT(of_object_fixed_len[version][%(enum)s] >= 0);
+ LOCI_ASSERT(of_object_fixed_len[version][%(enum)s] >= 0);
if (clean_wire) {
MEMSET(obj, 0, sizeof(*obj));
}
@@ -2364,6 +2372,10 @@
out.write("""
obj->wire_type_get = of_instruction_wire_object_id_get;
""")
+ if loxi_utils.class_is_instruction_id(cls):
+ out.write("""
+ obj->wire_type_get = of_instruction_id_wire_object_id_get;
+""")
if loxi_utils.class_is_queue_prop(cls):
out.write("""
obj->wire_type_get = of_queue_prop_wire_object_id_get;
diff --git a/c_gen/c_test_gen.py b/c_gen/c_test_gen.py
index cf03e0e..5b74649 100644
--- a/c_gen/c_test_gen.py
+++ b/c_gen/c_test_gen.py
@@ -68,6 +68,8 @@
import c_gen.identifiers as identifiers
import util
import test_data
+import loxi_globals
+from loxi_ir import *
def var_name_map(m_type):
"""
@@ -124,40 +126,14 @@
or those that should not be messed with
or whose types we're not ready to deal with yet.
"""
- # This will probably need more granularity as more extensions are added
- if (type_maps.class_is_extension(cls, version) and (
- m_name == "experimenter" or
- m_name == "subtype")):
+
+ uclass = loxi_globals.unified.class_by_name(cls)
+ if not uclass:
return True
- classes = ["of_bsn_lacp_stats_request",
- "of_bsn_lacp_stats_reply",
- "of_bsn_switch_pipeline_stats_request",
- "of_bsn_switch_pipeline_stats_reply",
- "of_bsn_port_counter_stats_request",
- "of_bsn_port_counter_stats_reply",
- "of_bsn_vlan_counter_stats_request",
- "of_bsn_vlan_counter_stats_reply",
- "of_bsn_gentable_entry_desc_stats_request",
- "of_bsn_gentable_entry_desc_stats_reply",
- "of_bsn_gentable_entry_stats_request",
- "of_bsn_gentable_entry_stats_reply",
- "of_bsn_gentable_desc_stats_request",
- "of_bsn_gentable_desc_stats_reply",
- "of_bsn_gentable_stats_request",
- "of_bsn_gentable_stats_reply",
- "of_bsn_gentable_bucket_stats_request",
- "of_bsn_gentable_bucket_stats_reply",
- "of_bsn_flow_checksum_bucket_stats_request",
- "of_bsn_flow_checksum_bucket_stats_reply",
- "of_bsn_table_checksum_stats_request",
- "of_bsn_table_checksum_stats_reply",
- ]
-
- if (cls in classes and (
- m_name == "experimenter" or
- m_name == "subtype")):
+ if not isinstance(uclass.member_by_name(m_name), OFDataMember):
return True
+
return loxi_utils.skip_member_name(m_name) or m_type not in scalar_types
def gen_fill_string(out):
diff --git a/c_gen/c_type_maps.py b/c_gen/c_type_maps.py
index d4525ba..a13e23e 100644
--- a/c_gen/c_type_maps.py
+++ b/c_gen/c_type_maps.py
@@ -118,6 +118,9 @@
gen_type_to_object_id(out, "instruction_type_to_id", "OF_INSTRUCTION",
"OF_INSTRUCTION_%s", type_maps.instruction_types,
max_type_value)
+ gen_type_to_object_id(out, "instruction_id_type_to_id", "OF_INSTRUCTION_ID",
+ "OF_INSTRUCTION_ID_%s", type_maps.instruction_id_types,
+ max_type_value)
gen_type_to_object_id(out, "queue_prop_type_to_id", "OF_QUEUE_PROP",
"OF_QUEUE_PROP_%s", type_maps.queue_prop_types,
max_type_value)
@@ -229,7 +232,43 @@
return of_%(name)s_type_to_id[version][%(name)s];
}
"""
+ table_features_prop_template = """
+/**
+ * %(name)s wire type to object ID array.
+ * Treat as private; use function accessor below
+ */
+extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
+
+#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
+
+/**
+ * Map an %(name)s wire value to an OF object
+ * @param %(name)s The %(name)s type wire value
+ * @param version The version associated with the check
+ * @return The %(name)s OF object type
+ * @return OF_OBJECT_INVALID if type does not map to an object
+ *
+ */
+of_object_id_t
+of_%(name)s_to_object_id(int %(name)s, of_version_t version)
+{
+ if (!OF_VERSION_OKAY(version)) {
+ return OF_OBJECT_INVALID;
+ }
+ if (%(name)s == 0xfffe) {
+ return OF_%(u_name)s_EXPERIMENTER;
+ }
+ if (%(name)s == 0xffff) {
+ return OF_%(u_name)s_EXPERIMENTER_MISS;
+ }
+ if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
+ return OF_OBJECT_INVALID;
+ }
+
+ return of_%(name)s_type_to_id[version][%(name)s];
+}
+"""
stats_template = """
/**
* %(name)s wire type to object ID array.
@@ -529,6 +568,11 @@
out.write(map_with_experimenter_template %
dict(name="instruction", u_name="INSTRUCTION", ar_len=ar_len))
+ # Instruction ID types array gen
+ ar_len = type_maps.type_array_len(type_maps.instruction_id_types, max_type_value)
+ out.write(map_with_experimenter_template %
+ dict(name="instruction_id", u_name="INSTRUCTION_ID", ar_len=ar_len))
+
# Queue prop types array gen
ar_len = type_maps.type_array_len(type_maps.queue_prop_types,
max_type_value)
@@ -538,7 +582,7 @@
# Table feature prop types array gen
ar_len = type_maps.type_array_len(type_maps.table_feature_prop_types,
max_type_value)
- out.write(map_with_experimenter_template %
+ out.write(table_features_prop_template %
dict(name="table_feature_prop", u_name="TABLE_FEATURE_PROP",
ar_len=ar_len))
@@ -680,6 +724,8 @@
extern void of_action_id_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
extern void of_instruction_wire_object_id_get(of_object_t *obj,
of_object_id_t *id);
+extern void of_instruction_id_wire_object_id_get(of_object_t *obj,
+ of_object_id_t *id);
extern void of_queue_prop_wire_object_id_get(of_object_t *obj,
of_object_id_t *id);
extern void of_table_feature_prop_wire_object_id_get(of_object_t *obj,
diff --git a/c_gen/codegen.py b/c_gen/codegen.py
index 3249747..121bc42 100644
--- a/c_gen/codegen.py
+++ b/c_gen/codegen.py
@@ -35,6 +35,7 @@
from itertools import groupby
from StringIO import StringIO
import template_utils
+from generic_utils import chunks
import loxi_globals
import loxi_ir.ir as ir
import util
@@ -43,6 +44,8 @@
import c_gen.type_maps as type_maps
import c_gen.c_type_maps as c_type_maps
+CLASS_CHUNK_SIZE = 32
+
PushWireTypesData = namedtuple('PushWireTypesData',
['class_name', 'versioned_type_members'])
PushWireTypesMember = namedtuple('PushWireTypesMember',
@@ -75,14 +78,18 @@
class_name=uclass.name,
versioned_type_members=versioned_type_members)
+# Output multiple LOCI classes into each C file. This reduces the overhead of
+# parsing header files, which takes longer than compiling the actual code
+# for many classes. It also reduces the compiled code size.
def generate_classes(install_dir):
- for uclass in loxi_globals.unified.classes:
- with template_utils.open_output(install_dir, "loci/src/%s.c" % uclass.name) as out:
- util.render_template(out, "class.c",
- push_wire_types_data=push_wire_types_data(uclass))
- # Append legacy generated code
- c_code_gen.gen_new_function_definitions(out, uclass.name)
- c_code_gen.gen_accessor_definitions(out, uclass.name)
+ for i, chunk in enumerate(chunks(loxi_globals.unified.classes, CLASS_CHUNK_SIZE)):
+ with template_utils.open_output(install_dir, "loci/src/class%02d.c" % i) as out:
+ for uclass in chunk:
+ util.render_template(out, "class.c",
+ push_wire_types_data=push_wire_types_data(uclass))
+ # Append legacy generated code
+ c_code_gen.gen_new_function_definitions(out, uclass.name)
+ c_code_gen.gen_accessor_definitions(out, uclass.name)
# TODO remove header classes and use the corresponding class instead
def generate_header_classes(install_dir):
diff --git a/c_gen/loxi_utils_legacy.py b/c_gen/loxi_utils_legacy.py
index 4092d4f..df93c2b 100644
--- a/c_gen/loxi_utils_legacy.py
+++ b/c_gen/loxi_utils_legacy.py
@@ -191,7 +191,26 @@
# For each vendor, check for vendor specific action
for exp in of_g.experimenter_name_to_id:
- if cls.find("of_instruction_" + exp) == 0:
+ if cls.find("of_instruction" + exp) == 0:
+ return True
+
+ return False
+
+def class_is_instruction_id(cls):
+ """
+ Return True if cls_name is an action object
+
+ Note that instruction_id is not an instruction object, though it has
+ the same header. It looks like an instruction header, but the type
+ is used to identify a kind of instruction, it does not indicate the
+ type of the object following.
+ """
+ if cls.find("of_instruction_id") == 0:
+ return True
+
+ # For each vendor, check for vendor specific action
+ for exp in of_g.experimenter_name_to_id:
+ if cls.find("of_instruction_id_" + exp) == 0:
return True
return False
diff --git a/c_gen/templates/locitest/test_ext.c b/c_gen/templates/locitest/test_ext.c
index 87f9916..75f4a00 100644
--- a/c_gen/templates/locitest/test_ext.c
+++ b/c_gen/templates/locitest/test_ext.c
@@ -61,9 +61,13 @@
TEST_ASSERT(of_meter_band_to_object_id(OF_EXPERIMENTER_TYPE, OF_VERSION_1_0) ==
OF_METER_BAND_EXPERIMENTER);
- TEST_ASSERT(of_table_feature_prop_to_object_id(OF_EXPERIMENTER_TYPE,
+ TEST_ASSERT(of_table_feature_prop_to_object_id(OF_EXPERIMENTER_TYPE-1,
OF_VERSION_1_3) ==
OF_TABLE_FEATURE_PROP_EXPERIMENTER);
+ TEST_ASSERT(of_table_feature_prop_to_object_id(OF_EXPERIMENTER_TYPE,
+ OF_VERSION_1_3) ==
+ OF_TABLE_FEATURE_PROP_EXPERIMENTER_MISS);
+
return TEST_PASS;
}
diff --git a/c_gen/templates/locitest/test_list_limits.c b/c_gen/templates/locitest/test_list_limits.c
index d8368ff..68ead8f 100644
--- a/c_gen/templates/locitest/test_list_limits.c
+++ b/c_gen/templates/locitest/test_list_limits.c
@@ -44,19 +44,19 @@
of_flow_stats_reply_entries_bind(obj, &list);
- ASSERT(element != NULL);
+ LOCI_ASSERT(element != NULL);
while (1) {
int rv = of_list_flow_stats_entry_append(&list, element);
- ASSERT(rv == OF_ERROR_NONE || rv == OF_ERROR_RESOURCE);
+ LOCI_ASSERT(rv == OF_ERROR_NONE || rv == OF_ERROR_RESOURCE);
if (rv != OF_ERROR_NONE) {
break;
}
i++;
}
- ASSERT(i == 744);
+ LOCI_ASSERT(i == 744);
of_flow_stats_entry_delete(element);
of_flow_stats_reply_delete(obj);
@@ -77,14 +77,14 @@
int rv;
of_flow_stats_entry_init(&element, OF_VERSION_1_0, -1, 1);
rv = of_list_flow_stats_entry_append_bind(&list, &element);
- ASSERT(rv == OF_ERROR_NONE || rv == OF_ERROR_RESOURCE);
+ LOCI_ASSERT(rv == OF_ERROR_NONE || rv == OF_ERROR_RESOURCE);
if (rv != OF_ERROR_NONE) {
break;
}
i++;
}
- ASSERT(i == 744);
+ LOCI_ASSERT(i == 744);
of_flow_stats_reply_delete(obj);
return TEST_PASS;
diff --git a/c_gen/templates/locitest/test_utils.c b/c_gen/templates/locitest/test_utils.c
index bcd4194..563f510 100644
--- a/c_gen/templates/locitest/test_utils.c
+++ b/c_gen/templates/locitest/test_utils.c
@@ -118,10 +118,32 @@
return TEST_PASS;
}
+static int
+test_of_object_new_from_message_preallocated(void)
+{
+ /* v1 OFPT_HELLO, xid=0x12345678 */
+ uint8_t buf[] = { 0x01, 0x00, 0x00, 0x08, 0x12, 0x34, 0x56, 0x78 };
+
+ of_object_storage_t storage;
+ of_object_t *obj = of_object_new_from_message_preallocated(
+ &storage, buf, sizeof(buf));
+
+ TEST_ASSERT(obj != NULL);
+ TEST_ASSERT(obj->version = OF_VERSION_1_0);
+ TEST_ASSERT(obj->object_id = OF_HELLO);
+
+ uint32_t xid;
+ of_hello_xid_get(obj, &xid);
+ TEST_ASSERT(xid == 0x12345678);
+
+ return TEST_PASS;
+}
+
int
run_utility_tests(void)
{
RUN_TEST(has_outport);
+ RUN_TEST(of_object_new_from_message_preallocated);
RUN_TEST(dump_objs);
return TEST_PASS;
diff --git a/c_gen/templates/locitest/unittest.h b/c_gen/templates/locitest/unittest.h
index c897d67..06568d3 100644
--- a/c_gen/templates/locitest/unittest.h
+++ b/c_gen/templates/locitest/unittest.h
@@ -41,9 +41,9 @@
} while (0)
#define TEST_ASSERT(result) if (!(result)) do { \
- fprintf(stderr, "\nTEST ASSERT FAILURE " \
+ fprintf(stderr, "\nTEST LOCI_ASSERT FAILURE " \
#result " :: %s:%d\n",__FILE__,__LINE__); \
- ASSERT(0); \
+ LOCI_ASSERT(0); \
return TEST_FAIL; \
} while (0)
diff --git a/c_gen/templates/of_object.c b/c_gen/templates/of_object.c
index 9b1bafd..8fd0aab 100644
--- a/c_gen/templates/of_object.c
+++ b/c_gen/templates/of_object.c
@@ -160,7 +160,7 @@
}
object_id = of_message_to_object_id(msg, len);
- ASSERT(object_id != OF_OBJECT_INVALID);
+ LOCI_ASSERT(object_id != OF_OBJECT_INVALID);
if ((obj = of_object_new(-1)) == NULL) {
return NULL;
@@ -180,6 +180,54 @@
}
/**
+ * Parse a message without allocating memory
+ *
+ * @param storage Pointer to an uninitialized of_object_storage_t
+ * @param buf Pointer to the buffer
+ * @param length Length of buf
+ * @returns Pointer to an initialized of_object_t
+ *
+ * The lifetime of the returned object is the minimum of the lifetimes of
+ * 'buf' and 'storage'.
+ */
+
+of_object_t *
+of_object_new_from_message_preallocated(of_object_storage_t *storage,
+ uint8_t *buf, int len)
+{
+ of_object_t *obj = &storage->obj;
+ of_wire_buffer_t *wbuf = &storage->wbuf;
+ of_message_t msg = buf;
+ of_version_t version;
+ of_object_id_t object_id;
+
+ memset(storage, 0, sizeof(*storage));
+
+ version = of_message_version_get(msg);
+ if (!OF_VERSION_OKAY(version)) {
+ return NULL;
+ }
+
+ if (of_validate_message(msg, len) != 0) {
+ LOCI_LOG_ERROR("message validation failed\n");
+ return NULL;
+ }
+
+ object_id = of_message_to_object_id(msg, len);
+ /* Already validated */
+ LOCI_ASSERT(object_id != OF_OBJECT_INVALID);
+
+ of_object_init_map[object_id](obj, version, len, 0);
+
+ obj->wire_object.wbuf = wbuf;
+ wbuf->buf = msg;
+ wbuf->alloc_bytes = len;
+ wbuf->current_bytes = len;
+
+ return obj;
+}
+
+/**
* Bind an existing buffer to an LOCI object
*
* @param obj Pointer to the object to be updated
@@ -199,9 +247,9 @@
of_wire_object_t *wobj;
of_wire_buffer_t *wbuf;
- ASSERT(buf != NULL);
- ASSERT(bytes > 0);
- // ASSERT(wobj is not bound);
+ LOCI_ASSERT(buf != NULL);
+ LOCI_ASSERT(bytes > 0);
+ // LOCI_ASSERT(wobj is not bound);
wobj = &obj->wire_object;
MEMSET(wobj, 0, sizeof(*wobj));
@@ -487,7 +535,7 @@
{
int offset;
- ASSERT(child->length > 0);
+ LOCI_ASSERT(child->length > 0);
/* Get offset of parent */
if (of_list_is_last(parent, child)) {
@@ -505,7 +553,7 @@
void
of_object_wire_buffer_steal(of_object_t *obj, uint8_t **buffer)
{
- ASSERT(obj != NULL);
+ LOCI_ASSERT(obj != NULL);
of_wire_buffer_steal(obj->wire_object.wbuf, buffer);
obj->wire_object.wbuf = NULL;
}
@@ -530,7 +578,7 @@
#endif
while (obj != NULL) {
- ASSERT(count++ < _MAX_PARENT_ITERATIONS);
+ LOCI_ASSERT(count++ < _MAX_PARENT_ITERATIONS);
obj->length += delta;
if (obj->wire_length_set != NULL) {
obj->wire_length_set(obj, obj->length);
@@ -540,10 +588,10 @@
#endif
/* Asserts for wire length checking */
- ASSERT(obj->length + obj->wire_object.obj_offset <=
+ LOCI_ASSERT(obj->length + obj->wire_object.obj_offset <=
WBUF_CURRENT_BYTES(wbuf));
if (obj->parent == NULL) {
- ASSERT(obj->length + obj->wire_object.obj_offset ==
+ LOCI_ASSERT(obj->length + obj->wire_object.obj_offset ==
WBUF_CURRENT_BYTES(wbuf));
}
diff --git a/c_gen/templates/of_object.h b/c_gen/templates/of_object.h
index 0e761fd..3172ad1 100644
--- a/c_gen/templates/of_object.h
+++ b/c_gen/templates/of_object.h
@@ -122,6 +122,11 @@
extern of_object_t *of_object_new_from_message(of_message_t msg, int len);
+typedef struct of_object_storage_s of_object_storage_t;
+
+of_object_t *of_object_new_from_message_preallocated(
+ of_object_storage_t *storage, uint8_t *buf, int len);
+
/* Delete an OpenFlow object without reference to its type */
extern void of_object_delete(of_object_t *obj);
@@ -169,4 +174,9 @@
uint64_t metadata[(OF_OBJECT_METADATA_BYTES + 7) / 8];
};
+struct of_object_storage_s {
+ of_object_t obj;
+ of_wire_buffer_t wbuf;
+};
+
#endif /* _OF_OBJECT_H_ */
diff --git a/c_gen/templates/of_type_maps.c b/c_gen/templates/of_type_maps.c
index 6026512..ef3f82b 100644
--- a/c_gen/templates/of_type_maps.c
+++ b/c_gen/templates/of_type_maps.c
@@ -55,8 +55,8 @@
void
of_object_message_wire_length_get(of_object_t *obj, int *bytes)
{
- ASSERT(OF_OBJECT_TO_WBUF(obj) != NULL);
- // ASSERT(obj is message)
+ LOCI_ASSERT(OF_OBJECT_TO_WBUF(obj) != NULL);
+ // LOCI_ASSERT(obj is message)
*bytes = of_message_length_get(OF_OBJECT_TO_MESSAGE(obj));
}
@@ -69,8 +69,8 @@
void
of_object_message_wire_length_set(of_object_t *obj, int bytes)
{
- ASSERT(OF_OBJECT_TO_WBUF(obj) != NULL);
- // ASSERT(obj is message)
+ LOCI_ASSERT(OF_OBJECT_TO_WBUF(obj) != NULL);
+ // LOCI_ASSERT(obj is message)
of_message_length_set(OF_OBJECT_TO_MESSAGE(obj), bytes);
}
@@ -97,7 +97,7 @@
{
uint16_t val16;
of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
- ASSERT(wbuf != NULL);
+ LOCI_ASSERT(wbuf != NULL);
of_wire_buffer_u16_get(wbuf,
OF_OBJECT_ABSOLUTE_OFFSET(obj, TLV16_WIRE_LENGTH_OFFSET), &val16);
@@ -115,7 +115,7 @@
of_tlv16_wire_length_set(of_object_t *obj, int bytes)
{
of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
- ASSERT(wbuf != NULL);
+ LOCI_ASSERT(wbuf != NULL);
of_wire_buffer_u16_set(wbuf,
OF_OBJECT_ABSOLUTE_OFFSET(obj, TLV16_WIRE_LENGTH_OFFSET), bytes);
@@ -247,10 +247,10 @@
return;
}
- ASSERT(wire_type >= 0 && wire_type < OF_ACTION_ITEM_COUNT);
+ LOCI_ASSERT(wire_type >= 0 && wire_type < OF_ACTION_ITEM_COUNT);
*id = of_action_type_to_id[obj->version][wire_type];
- ASSERT(*id != OF_OBJECT_INVALID);
+ LOCI_ASSERT(*id != OF_OBJECT_INVALID);
}
/**
@@ -271,10 +271,10 @@
return;
}
- ASSERT(wire_type >= 0 && wire_type < OF_ACTION_ID_ITEM_COUNT);
+ LOCI_ASSERT(wire_type >= 0 && wire_type < OF_ACTION_ID_ITEM_COUNT);
*id = of_action_id_type_to_id[obj->version][wire_type];
- ASSERT(*id != OF_OBJECT_INVALID);
+ LOCI_ASSERT(*id != OF_OBJECT_INVALID);
}
/**
@@ -303,6 +303,45 @@
case 1: *id = OF_INSTRUCTION_BSN_ARP_OFFLOAD; break;
case 2: *id = OF_INSTRUCTION_BSN_DHCP_OFFLOAD; break;
case 3: *id = OF_INSTRUCTION_BSN_DISABLE_SPLIT_HORIZON_CHECK; break;
+ case 4: *id = OF_INSTRUCTION_BSN_PERMIT; break;
+ case 5: *id = OF_INSTRUCTION_BSN_DENY; break;
+ }
+ break;
+ }
+ }
+
+ return OF_ERROR_NONE;
+}
+
+
+/**
+ * @fixme to do when we have instruction extensions
+ * See extension_action above
+ */
+
+static int
+extension_instruction_id_object_id_get(of_object_t *obj, of_object_id_t *id)
+{
+ uint32_t exp_id;
+ uint8_t *buf;
+
+ *id = OF_INSTRUCTION_ID_EXPERIMENTER;
+
+ buf = OF_OBJECT_BUFFER_INDEX(obj, 0);
+
+ buf_u32_get(buf + OF_INSTRUCTION_EXPERIMENTER_ID_OFFSET, &exp_id);
+
+ switch (exp_id) {
+ case OF_EXPERIMENTER_ID_BSN: {
+ uint32_t subtype;
+ buf_u32_get(buf + OF_INSTRUCTION_EXPERIMENTER_SUBTYPE_OFFSET, &subtype);
+ switch (subtype) {
+ case 0: *id = OF_INSTRUCTION_ID_BSN_DISABLE_SRC_MAC_CHECK; break;
+ case 1: *id = OF_INSTRUCTION_ID_BSN_ARP_OFFLOAD; break;
+ case 2: *id = OF_INSTRUCTION_ID_BSN_DHCP_OFFLOAD; break;
+ case 3: *id = OF_INSTRUCTION_ID_BSN_DISABLE_SPLIT_HORIZON_CHECK; break;
+ case 4: *id = OF_INSTRUCTION_ID_BSN_PERMIT; break;
+ case 5: *id = OF_INSTRUCTION_ID_BSN_DENY; break;
}
break;
}
@@ -328,12 +367,35 @@
return;
}
- ASSERT(wire_type >= 0 && wire_type < OF_INSTRUCTION_ITEM_COUNT);
+ LOCI_ASSERT(wire_type >= 0 && wire_type < OF_INSTRUCTION_ITEM_COUNT);
*id = of_instruction_type_to_id[obj->version][wire_type];
- ASSERT(*id != OF_OBJECT_INVALID);
+ LOCI_ASSERT(*id != OF_OBJECT_INVALID);
}
+/**
+ * Get the object ID based on the wire buffer for an instruction ID object
+ * @param obj The object being referenced
+ * @param id Where to store the object ID
+ */
+
+
+void
+of_instruction_id_wire_object_id_get(of_object_t *obj, of_object_id_t *id)
+{
+ int wire_type;
+
+ of_tlv16_wire_type_get(obj, &wire_type);
+ if (wire_type == OF_EXPERIMENTER_TYPE) {
+ extension_instruction_id_object_id_get(obj, id);
+ return;
+ }
+
+ LOCI_ASSERT(wire_type >= 0 && wire_type < OF_INSTRUCTION_ID_ITEM_COUNT);
+
+ *id = of_instruction_id_type_to_id[obj->version][wire_type];
+ LOCI_ASSERT(*id != OF_OBJECT_INVALID);
+}
/**
* @fixme to do when we have queue_prop extensions
@@ -365,27 +427,14 @@
return;
}
- ASSERT(wire_type >= 0 && wire_type < OF_QUEUE_PROP_ITEM_COUNT);
+ LOCI_ASSERT(wire_type >= 0 && wire_type < OF_QUEUE_PROP_ITEM_COUNT);
*id = of_queue_prop_type_to_id[obj->version][wire_type];
- ASSERT(*id != OF_OBJECT_INVALID);
+ LOCI_ASSERT(*id != OF_OBJECT_INVALID);
}
/**
- * @fixme to do when we have table_feature_prop extensions
- * See extension_action above
- */
-
-static void
-extension_table_feature_prop_object_id_get(of_object_t *obj, of_object_id_t *id)
-{
- (void)obj;
-
- *id = OF_TABLE_FEATURE_PROP_EXPERIMENTER;
-}
-
-/**
* Table feature property object ID determination
*
* @param obj The object being referenced
@@ -398,15 +447,7 @@
int wire_type;
of_tlv16_wire_type_get(obj, &wire_type);
- if (wire_type == OF_EXPERIMENTER_TYPE) {
- extension_table_feature_prop_object_id_get(obj, id);
- return;
- }
-
- ASSERT(wire_type >= 0 && wire_type < OF_TABLE_FEATURE_PROP_ITEM_COUNT);
-
- *id = of_table_feature_prop_type_to_id[obj->version][wire_type];
- ASSERT(*id != OF_OBJECT_INVALID);
+ *id = of_table_feature_prop_to_object_id(wire_type, obj->version);
}
/**
@@ -426,10 +467,10 @@
return;
}
- ASSERT(wire_type >= 0 && wire_type < OF_METER_BAND_ITEM_COUNT);
+ LOCI_ASSERT(wire_type >= 0 && wire_type < OF_METER_BAND_ITEM_COUNT);
*id = of_meter_band_type_to_id[obj->version][wire_type];
- ASSERT(*id != OF_OBJECT_INVALID);
+ LOCI_ASSERT(*id != OF_OBJECT_INVALID);
}
/**
@@ -444,9 +485,9 @@
int wire_type;
of_tlv16_wire_type_get(obj, &wire_type);
- ASSERT(wire_type >= 0 && wire_type < OF_HELLO_ELEM_ITEM_COUNT);
+ LOCI_ASSERT(wire_type >= 0 && wire_type < OF_HELLO_ELEM_ITEM_COUNT);
*id = of_hello_elem_type_to_id[obj->version][wire_type];
- ASSERT(*id != OF_OBJECT_INVALID);
+ LOCI_ASSERT(*id != OF_OBJECT_INVALID);
}
/**
@@ -461,9 +502,9 @@
int wire_type;
of_tlv16_wire_type_get(obj, &wire_type);
- ASSERT(wire_type >= 0 && wire_type < OF_BSN_TLV_ITEM_COUNT);
+ LOCI_ASSERT(wire_type >= 0 && wire_type < OF_BSN_TLV_ITEM_COUNT);
*id = of_bsn_tlv_type_to_id[obj->version][wire_type];
- ASSERT(*id != OF_OBJECT_INVALID);
+ LOCI_ASSERT(*id != OF_OBJECT_INVALID);
}
/****************************************************************
@@ -482,14 +523,14 @@
#define _GET_OXM_TYPE_LEN(obj, tl_p, wbuf) do { \
wbuf = OF_OBJECT_TO_WBUF(obj); \
- ASSERT(wbuf != NULL); \
+ LOCI_ASSERT(wbuf != NULL); \
of_wire_buffer_u32_get(wbuf, \
OF_OBJECT_ABSOLUTE_OFFSET(obj, OXM_HDR_OFFSET), (tl_p)); \
} while (0)
#define _SET_OXM_TYPE_LEN(obj, tl_p, wbuf) do { \
wbuf = OF_OBJECT_TO_WBUF(obj); \
- ASSERT(wbuf != NULL); \
+ LOCI_ASSERT(wbuf != NULL); \
of_wire_buffer_u32_set(wbuf, \
OF_OBJECT_ABSOLUTE_OFFSET(obj, OXM_HDR_OFFSET), (tl_p)); \
} while (0)
@@ -539,7 +580,7 @@
of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
uint16_t u16;
- ASSERT(wbuf != NULL);
+ LOCI_ASSERT(wbuf != NULL);
of_wire_buffer_u16_get(wbuf,
OF_OBJECT_ABSOLUTE_OFFSET(obj, OF_U16_LEN_LENGTH_OFFSET),
@@ -558,9 +599,9 @@
of_u16_len_wire_length_set(of_object_t *obj, int bytes)
{
of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
- ASSERT(wbuf != NULL);
+ LOCI_ASSERT(wbuf != NULL);
- /* ASSERT(obj is u16-len entry) */
+ /* LOCI_ASSERT(obj is u16-len entry) */
of_wire_buffer_u16_set(wbuf,
OF_OBJECT_ABSOLUTE_OFFSET(obj, OF_U16_LEN_LENGTH_OFFSET),
@@ -585,9 +626,9 @@
uint16_t u16;
int offset;
- ASSERT(wbuf != NULL);
+ LOCI_ASSERT(wbuf != NULL);
- /* ASSERT(obj is packet queue obj) */
+ /* LOCI_ASSERT(obj is packet queue obj) */
offset = OF_PACKET_QUEUE_LENGTH_OFFSET(obj->version);
of_wire_buffer_u16_get(wbuf, OF_OBJECT_ABSOLUTE_OFFSET(obj, offset),
&u16);
@@ -609,9 +650,9 @@
of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
int offset;
- ASSERT(wbuf != NULL);
+ LOCI_ASSERT(wbuf != NULL);
- /* ASSERT(obj is packet queue obj) */
+ /* LOCI_ASSERT(obj is packet queue obj) */
offset = OF_PACKET_QUEUE_LENGTH_OFFSET(obj->version);
of_wire_buffer_u16_set(wbuf, OF_OBJECT_ABSOLUTE_OFFSET(obj, offset),
bytes);
@@ -628,8 +669,8 @@
void
of_list_meter_band_stats_wire_length_get(of_object_t *obj, int *bytes)
{
- ASSERT(obj->parent != NULL);
- ASSERT(obj->parent->object_id == OF_METER_STATS);
+ LOCI_ASSERT(obj->parent != NULL);
+ LOCI_ASSERT(obj->parent->object_id == OF_METER_STATS);
/* We're counting on the parent being properly initialized already.
* The length is stored in a uint16 at offset 4 of the parent.
@@ -652,7 +693,7 @@
{
uint16_t val16;
of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
- ASSERT(wbuf != NULL);
+ LOCI_ASSERT(wbuf != NULL);
of_wire_buffer_u16_get(wbuf,
OF_OBJECT_ABSOLUTE_OFFSET(obj, OF_METER_STATS_LENGTH_OFFSET),
&val16);
@@ -663,7 +704,7 @@
of_meter_stats_wire_length_set(of_object_t *obj, int bytes)
{
of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
- ASSERT(wbuf != NULL);
+ LOCI_ASSERT(wbuf != NULL);
of_wire_buffer_u16_set(wbuf,
OF_OBJECT_ABSOLUTE_OFFSET(obj, OF_METER_STATS_LENGTH_OFFSET), bytes);
diff --git a/c_gen/templates/of_utils.c b/c_gen/templates/of_utils.c
index ba22536..373ad59 100644
--- a/c_gen/templates/of_utils.c
+++ b/c_gen/templates/of_utils.c
@@ -35,6 +35,8 @@
****************************************************************/
#include <loci/of_utils.h>
+#include <stdio.h>
+#include <stdlib.h>
/**
@@ -76,3 +78,9 @@
return rv;
}
+void
+loci_assert_fail(const char *msg, const char *file, unsigned int line)
+{
+ fprintf(stderr, "\\nASSERT %s. %s:%d\\n", msg, file, line);
+ abort();
+}
diff --git a/c_gen/templates/of_wire_buf.c b/c_gen/templates/of_wire_buf.c
index 13da8e3..7f759f9 100644
--- a/c_gen/templates/of_wire_buf.c
+++ b/c_gen/templates/of_wire_buf.c
@@ -131,12 +131,12 @@
uint8_t *src_ptr, *dst_ptr;
int cur_bytes;
- ASSERT(wbuf != NULL);
+ LOCI_ASSERT(wbuf != NULL);
cur_bytes = wbuf->current_bytes;
/* Doesn't make sense; mismatch in current buffer info */
- ASSERT(old_len + offset <= wbuf->current_bytes);
+ LOCI_ASSERT(old_len + offset <= wbuf->current_bytes);
wbuf->current_bytes += (new_len - old_len); // may decrease size
@@ -151,5 +151,5 @@
dst_ptr = &wbuf->buf[offset];
MEMCPY(dst_ptr, data, new_len);
- ASSERT(wbuf->current_bytes == cur_bytes + (new_len - old_len));
+ LOCI_ASSERT(wbuf->current_bytes == cur_bytes + (new_len - old_len));
}
diff --git a/c_gen/templates/of_wire_buf.h b/c_gen/templates/of_wire_buf.h
index f977004..4736ac0 100644
--- a/c_gen/templates/of_wire_buf.h
+++ b/c_gen/templates/of_wire_buf.h
@@ -88,7 +88,7 @@
* @param offset The extent of the buffer required
*/
#define OF_WIRE_BUFFER_ACCESS_CHECK(wbuf, offset) \
- ASSERT(((wbuf) != NULL) && (WBUF_BUF(wbuf) != NULL) && \
+ LOCI_ASSERT(((wbuf) != NULL) && (WBUF_BUF(wbuf) != NULL) && \
(offset > 0) && (WBUF_CURRENT_BYTES(wbuf) >= offset))
/*
@@ -242,8 +242,8 @@
static inline void
of_wire_buffer_grow(of_wire_buffer_t *wbuf, int bytes)
{
- ASSERT(wbuf != NULL);
- ASSERT(wbuf->alloc_bytes >= bytes);
+ LOCI_ASSERT(wbuf != NULL);
+ LOCI_ASSERT(wbuf->alloc_bytes >= bytes);
if (bytes > wbuf->current_bytes) {
wbuf->current_bytes = bytes;
}
@@ -426,7 +426,7 @@
of_wire_buffer_match_get(int version, of_wire_buffer_t *wbuf, int offset,
of_match_t *value)
{
- ASSERT(0);
+ LOCI_ASSERT(0);
}
/**
@@ -443,7 +443,7 @@
of_wire_buffer_match_set(int version, of_wire_buffer_t *wbuf, int offset,
of_match_t *value)
{
- ASSERT(0);
+ LOCI_ASSERT(0);
}
/**
@@ -461,7 +461,7 @@
of_wire_buffer_of_port_desc_get(int version, of_wire_buffer_t *wbuf, int offset,
void *value)
{
- ASSERT(0);
+ LOCI_ASSERT(0);
}
/**
@@ -479,7 +479,7 @@
of_wire_buffer_of_port_desc_set(int version, of_wire_buffer_t *wbuf, int offset,
void *value)
{
- ASSERT(0);
+ LOCI_ASSERT(0);
}
/**
@@ -510,7 +510,7 @@
*value = v32;
break;
default:
- ASSERT(0);
+ LOCI_ASSERT(0);
}
}
@@ -538,7 +538,7 @@
of_wire_buffer_u32_set(wbuf, offset, (uint32_t)value);
break;
default:
- ASSERT(0);
+ LOCI_ASSERT(0);
}
}
@@ -568,7 +568,7 @@
*value = v8;
break;
default:
- ASSERT(0);
+ LOCI_ASSERT(0);
}
}
@@ -593,7 +593,7 @@
of_wire_buffer_u8_set(wbuf, offset, (uint8_t)value);
break;
default:
- ASSERT(0);
+ LOCI_ASSERT(0);
}
}
@@ -623,7 +623,7 @@
*value = v64;
break;
default:
- ASSERT(0);
+ LOCI_ASSERT(0);
}
}
@@ -648,7 +648,7 @@
of_wire_buffer_u64_set(wbuf, offset, (uint64_t)value);
break;
default:
- ASSERT(0);
+ LOCI_ASSERT(0);
}
}
@@ -702,7 +702,7 @@
of_octets_t *value, int cur_len)
{
// FIXME need to adjust length of octets member in buffer
- ASSERT(cur_len == 0 || cur_len == value->bytes);
+ LOCI_ASSERT(cur_len == 0 || cur_len == value->bytes);
OF_WIRE_BUFFER_ACCESS_CHECK(wbuf, offset + OF_OCTETS_BYTES_GET(value));
buf_octets_set(OF_WIRE_BUFFER_INDEX(wbuf, offset),
diff --git a/c_gen/type_maps.py b/c_gen/type_maps.py
index 875a34e..ee452fc 100644
--- a/c_gen/type_maps.py
+++ b/c_gen/type_maps.py
@@ -584,6 +584,20 @@
}
# Set to empty dict if no extension instructions defined
+extension_instruction_id_subtype = {
+ # version 1.0
+ of_g.VERSION_1_0:dict(),
+ of_g.VERSION_1_1:dict(),
+ of_g.VERSION_1_2:dict(),
+ of_g.VERSION_1_3:dict(
+ bsn = { # of_instruction_bsn_
+ },
+ nicira = { # of_instruction_nicira_
+ }
+ ),
+}
+
+# Set to empty dict if no extension instructions defined
extension_queue_prop_subtype = {}
# Set to empty dict if no extension instructions defined
@@ -594,6 +608,7 @@
extension_action_subtype,
extension_action_id_subtype,
extension_instruction_subtype,
+ extension_instruction_id_subtype,
extension_queue_prop_subtype,
extension_table_feature_prop_subtype
]
@@ -768,6 +783,17 @@
return cls_is_ext_obj(cls, version, extension_instruction_subtype)
################################################################
+# These are extension instruction specific
+################################################################
+
+def instruction_id_is_extension(cls, version):
+ """
+ Return True if cls, version is recognized as an instruction ID extension
+ This is brute force, searching records for a match
+ """
+ return cls_is_ext_obj(cls, version, extension_instruction_id_subtype)
+
+################################################################
# These are extension queue_prop specific
################################################################
diff --git a/generic_utils.py b/generic_utils.py
index 1cfba86..5683aa1 100644
--- a/generic_utils.py
+++ b/generic_utils.py
@@ -214,3 +214,11 @@
if func(i):
c +=1
return c
+
+def chunks(l, n):
+ """
+ Yield successive n-sized chunks from l.
+ From http://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks-in-python
+ """
+ for i in xrange(0, len(l), n):
+ yield l[i:i+n]
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
index a9da637..43a7a17 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
@@ -1,5 +1,7 @@
package org.projectfloodlight.openflow.types;
+import java.util.Arrays;
+
import org.jboss.netty.buffer.ChannelBuffer;
import com.google.common.hash.PrimitiveSink;
@@ -119,7 +121,7 @@
return rawValue;
}
- volatile byte[] bytesCache = null;
+ private volatile byte[] bytesCache = null;
public byte[] getBytes() {
if (bytesCache == null) {
@@ -133,7 +135,7 @@
}
}
}
- return bytesCache;
+ return Arrays.copyOf(bytesCache, bytesCache.length);
}
@Override
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
index 4e7b856..c9dea13 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
@@ -1,9 +1,11 @@
package org.projectfloodlight.openflow.types;
+import java.util.Arrays;
import java.util.regex.Pattern;
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
+
import com.google.common.hash.PrimitiveSink;
import com.google.common.primitives.Longs;
@@ -201,7 +203,7 @@
return new IPv6Address(raw1, raw2);
}
- volatile byte[] bytesCache = null;
+ private volatile byte[] bytesCache = null;
public byte[] getBytes() {
if (bytesCache == null) {
@@ -228,7 +230,7 @@
}
}
}
- return bytesCache;
+ return Arrays.copyOf(bytesCache, bytesCache.length);
}
@Override
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/MacAddress.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/MacAddress.java
index 27d5b66..f592ea8 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/MacAddress.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/MacAddress.java
@@ -1,5 +1,7 @@
package org.projectfloodlight.openflow.types;
+import java.util.Arrays;
+
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import org.projectfloodlight.openflow.util.HexString;
@@ -79,7 +81,7 @@
return MacAddress.of(raw);
}
- volatile byte[] bytesCache = null;
+ private volatile byte[] bytesCache = null;
public byte[] getBytes() {
if (bytesCache == null) {
@@ -95,7 +97,7 @@
}
}
}
- return bytesCache;
+ return Arrays.copyOf(bytesCache, bytesCache.length);
}
/**
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFVlanVidMatch.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFVlanVidMatch.java
index fddaa5d..0fae3e6 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFVlanVidMatch.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFVlanVidMatch.java
@@ -1,5 +1,7 @@
package org.projectfloodlight.openflow.types;
+import java.util.Arrays;
+
import javax.annotation.Nullable;
import org.jboss.netty.buffer.ChannelBuffer;
@@ -143,7 +145,7 @@
}
- volatile byte[] bytesCache = null;
+ private volatile byte[] bytesCache = null;
public byte[] getBytes() {
if (bytesCache == null) {
@@ -155,7 +157,7 @@
}
}
}
- return bytesCache;
+ return Arrays.copyOf(bytesCache, bytesCache.length);
}
public void write2Bytes(ChannelBuffer c) {
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVid.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVid.java
index 8337eb6..2e675d4 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVid.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVid.java
@@ -1,5 +1,7 @@
package org.projectfloodlight.openflow.types;
+import java.util.Arrays;
+
import org.jboss.netty.buffer.ChannelBuffer;
import org.projectfloodlight.openflow.exceptions.OFParseError;
@@ -67,7 +69,7 @@
return LENGTH;
}
- volatile byte[] bytesCache = null;
+ private volatile byte[] bytesCache = null;
public byte[] getBytes() {
if (bytesCache == null) {
@@ -79,7 +81,7 @@
}
}
}
- return bytesCache;
+ return Arrays.copyOf(bytesCache, bytesCache.length);
}
public void write2Bytes(ChannelBuffer c) {
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/HexString.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/HexString.java
index ddf0f25..bcc46f7 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/HexString.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/HexString.java
@@ -17,8 +17,6 @@
package org.projectfloodlight.openflow.util;
-import java.math.BigInteger;
-
import org.projectfloodlight.openflow.types.U8;
public class HexString {
@@ -86,13 +84,17 @@
return ret;
}
- public static long toLong(final String values) throws NumberFormatException {
- // Long.parseLong() can't handle HexStrings with MSB set. Sigh.
- BigInteger bi = new BigInteger(values.replaceAll(":", ""), 16);
- if (bi.bitLength() > 64)
- throw new NumberFormatException("Input string too big to fit in long: "
- + values);
- return bi.longValue();
+ public static long toLong(String value) throws NumberFormatException {
+ String[] octets = value.split(":");
+ if (octets.length > 8)
+ throw new NumberFormatException("Input string is too big to fit in long: " + value);
+ long l = 0;
+ for (String octet: octets) {
+ if (octet.length() > 2)
+ throw new NumberFormatException("Each colon-separated byte component must consist of 1 or 2 hex digits: " + value);
+ short s = Short.parseShort(octet, 16);
+ l = (l << 8) + s;
+ }
+ return l;
}
-
}
diff --git a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/util/HexStringTest.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/util/HexStringTest.java
new file mode 100644
index 0000000..360cb5a
--- /dev/null
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/util/HexStringTest.java
@@ -0,0 +1,103 @@
+/**
+* Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+* University
+*
+* Licensed under the Apache License, Version 2.0 (the "License"); you may
+* not use this file except in compliance with the License. You may obtain
+* a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* 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
+* License for the specific language governing permissions and limitations
+* under the License.
+**/
+
+package org.projectfloodlight.openflow.util;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+/**
+ * Does hexstring conversion work?
+ *
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ */
+public class HexStringTest {
+
+ @Test
+ public void testMarshalling() throws Exception {
+ String dpidStr = "00:00:00:23:20:2d:16:71";
+ long dpid = HexString.toLong(dpidStr);
+ String testStr = HexString.toHexString(dpid);
+ assertEquals(dpidStr, testStr);
+ }
+
+ @Test
+ public void testToLong() {
+ String dpidStr = "3e:1f:01:fc:72:8c:63:31";
+ long valid = 0x3e1f01fc728c6331L;
+ long testLong = HexString.toLong(dpidStr);
+ assertEquals(valid, testLong);
+ }
+
+ @Test
+ public void testToLong2() {
+ String dpidStr = "1f:1:fc:72:3:f:31";
+ long valid = 0x1f01fc72030f31L;
+ long testLong = HexString.toLong(dpidStr);
+ assertEquals(valid, testLong);
+ }
+
+ @Test
+ public void testToLongMSB() {
+ String dpidStr = "ca:7c:5e:d1:64:7a:95:9b";
+ long valid = -3856102927509056101L;
+ long testLong = HexString.toLong(dpidStr);
+ assertEquals(valid, testLong);
+ }
+
+ @Test(expected=NumberFormatException.class)
+ public void testToLongErrorTooManyBytes() {
+ HexString.toLong("09:08:07:06:05:04:03:02:01");
+ }
+
+ @Test(expected=NumberFormatException.class)
+ public void testToLongErrorByteValueTooLong() {
+ HexString.toLong("234:01");
+ }
+
+ @Test(expected=NumberFormatException.class)
+ public void testToLongErrorEmptyByte() {
+ HexString.toLong("03::01");
+ }
+
+ @Test(expected=NumberFormatException.class)
+ public void testToLongErrorInvalidHexDigit() {
+ HexString.toLong("ss:01");
+ }
+
+ @Test(expected=NumberFormatException.class)
+ public void testToLongErrorEmptyString() {
+ HexString.toLong("");
+ }
+
+
+ @Test
+ public void testToStringBytes() {
+ byte[] dpid = { 0, 0, 0, 0, 0, 0, 0, -1 };
+ String valid = "00:00:00:00:00:00:00:ff";
+ String testString = HexString.toHexString(dpid);
+ assertEquals(valid, testString);
+ }
+
+ @Test(expected=NumberFormatException.class)
+ public void testFromHexStringError() {
+ String invalidStr = "00:00:00:00:00:00:ffff";
+ HexString.fromHexString(invalidStr);
+ }
+}
+
diff --git a/loxi_ir/ir.py b/loxi_ir/ir.py
index 6a053c6..c8ca04d 100644
--- a/loxi_ir/ir.py
+++ b/loxi_ir/ir.py
@@ -440,10 +440,15 @@
superclass_name = None
superclass = None
+ ofc_members = []
+ for m in orig_fe.members:
+ if not isinstance(m, frontend_ir.OFDataMember) and not isinstance(m, frontend_ir.OFPadMember):
+ ofc_members.append(m)
+
fe = frontend_ir.OFClass(
name=name,
superclass=superclass_name,
- members=[m for m in orig_fe.members if not isinstance(m, frontend_ir.OFDataMember)],
+ members=ofc_members,
virtual=orig_fe.virtual,
params={})
diff --git a/openflow_input/bsn_acl b/openflow_input/bsn_acl
new file mode 100644
index 0000000..4035904
--- /dev/null
+++ b/openflow_input/bsn_acl
@@ -0,0 +1,50 @@
+// 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.
+//
+// Also derived from the OpenFlow header files which have these copyrights:
+// Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University
+// Copyright (c) 2011, 2012 Open Networking Foundation
+
+#version 4
+
+// Instructions to express control flow in ACL tables
+
+struct of_instruction_bsn_permit : of_instruction_bsn {
+ uint16_t type == 65535;
+ uint16_t len;
+ uint32_t experimenter == 0x5c16c7;
+ uint32_t subtype == 4;
+ pad(4);
+};
+
+struct of_instruction_bsn_deny : of_instruction_bsn {
+ uint16_t type == 65535;
+ uint16_t len;
+ uint32_t experimenter == 0x5c16c7;
+ uint32_t subtype == 5;
+ pad(4);
+};
diff --git a/openflow_input/standard-1.3 b/openflow_input/standard-1.3
index af7e501..6010880 100644
--- a/openflow_input/standard-1.3
+++ b/openflow_input/standard-1.3
@@ -292,6 +292,7 @@
OFPR_BSN_FRAGMENTATION_REQUIRED = 137,
OFPR_BSN_ARP = 139,
OFPR_BSN_DHCP = 140,
+ OFPR_BSN_DEBUG = 141,
};
enum ofp_flow_removed_reason(wire_type=uint8_t) {
@@ -757,7 +758,6 @@
struct of_action_id {
uint16_t type;
uint16_t len;
- pad(4);
};
struct of_action_output : of_action {
@@ -877,6 +877,11 @@
pad(4);
};
+struct of_instruction_id {
+ uint16_t type;
+ uint16_t len;
+};
+
struct of_instruction {
uint16_t type == ?;
uint16_t len;
@@ -1610,13 +1615,13 @@
uint16_t type == 0;
uint16_t length;
// FIXME Check if instruction_t is right for ids here
- list(of_instruction_t) instruction_ids;
+ list(of_instruction_id_t) instruction_ids;
};
struct of_table_feature_prop_instructions_miss : of_table_feature_prop {
uint16_t type == 1;
uint16_t length;
- list(of_instruction_t) instruction_ids;
+ list(of_instruction_id_t) instruction_ids;
};
struct of_table_feature_prop_next_tables : of_table_feature_prop {
@@ -1692,21 +1697,20 @@
};
struct of_table_feature_prop_experimenter : of_table_feature_prop {
- uint16_t type == 65535;
+ uint16_t type == 65534;
uint16_t length;
uint32_t experimenter;
uint32_t subtype;
of_octets_t experimenter_data;
};
-// Not yet supported
-// struct of_table_feature_prop_experimenter_miss : of_table_feature_prop {
-// uint16_t type;
-// uint16_t length;
-// uint32_t experimenter;
-// uint32_t subtype;
-// of_octets_t experimenter_data;
-// };
+struct of_table_feature_prop_experimenter_miss : of_table_feature_prop {
+ uint16_t type == 65535;
+ uint16_t length;
+ uint32_t experimenter;
+ uint32_t subtype;
+ of_octets_t experimenter_data;
+};
struct of_table_features {
uint16_t length;
diff --git a/test_data/of13/action_id_output.data b/test_data/of13/action_id_output.data
new file mode 100644
index 0000000..7712203
--- /dev/null
+++ b/test_data/of13/action_id_output.data
@@ -0,0 +1,8 @@
+-- binary
+00 00 # type
+00 04 # length
+-- python
+ofp.action_id.output()
+-- c
+obj = of_action_id_output_new(OF_VERSION_1_3);
+-- java
diff --git a/test_data/of13/instruction_id_goto_table.data b/test_data/of13/instruction_id_goto_table.data
new file mode 100644
index 0000000..e52d9c9
--- /dev/null
+++ b/test_data/of13/instruction_id_goto_table.data
@@ -0,0 +1,8 @@
+-- binary
+00 01 # type
+00 04 # length
+-- python
+ofp.instruction_id.goto_table()
+-- c
+obj = of_instruction_id_goto_table_new(OF_VERSION_1_3);
+-- java