blob: 9b1bafd96b6a97d11acbab75ba2b854cb4c39671 [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::
Rich Laned983aa52013-06-13 11:48:37 -070028:: include('_copyright.c')
Rich Lanea06d0c32013-03-25 08:52:03 -070029
30/****************************************************************
31 *
32 * of_object.c
33 *
34 * These are the low level object constructor/destructor operators.
35 *
36 ****************************************************************/
37
38#include "loci_log.h"
39#include <loci/loci.h>
40#include <loci/loci_validator.h>
41
Rich Lanea06d0c32013-03-25 08:52:03 -070042/**
43 * Create a generic new object and possibly underlying wire buffer
44 * @param bytes The number of bytes to allocate in the underlying buffer
45 *
46 * If bytes <= 0, do not allocate a wire buffer.
47 *
48 * Note that this is an internal function. The class specific
49 * new functions should be called to properly initialize and track an
50 * OF object.
51 */
52
53of_object_t *
54of_object_new(int bytes)
55{
56 of_object_t *obj;
57
Rich Lane671e7722013-12-15 16:48:54 -080058 if ((obj = (of_object_t *)MALLOC(sizeof(*obj))) == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -070059 return NULL;
60 }
Rich Lane671e7722013-12-15 16:48:54 -080061 MEMSET(obj, 0, sizeof(*obj));
Rich Lanea06d0c32013-03-25 08:52:03 -070062
63 if (bytes > 0) {
64 if ((obj->wire_object.wbuf = of_wire_buffer_new(bytes)) == NULL) {
65 FREE(obj);
66 return NULL;
67 }
68 obj->wire_object.owned = 1;
69 }
70
71 return obj;
72}
73
74/**
75 * The delete function for LOCI objects
76 *
77 * @param obj Pointer to the object to be deleted
78 *
79 * This can be called on any LOCI object; it should not need to be
80 * overridden.
81 */
82
83void
84of_object_delete(of_object_t *obj)
85{
86 if (obj == NULL) {
87 return;
88 }
89
Rich Lanea06d0c32013-03-25 08:52:03 -070090 /*
91 * Make callback if present
92 */
93 if (obj->track_info.delete_cb != NULL) {
94 obj->track_info.delete_cb(obj);
95 }
96
97 if (obj->wire_object.owned) {
98 of_wire_buffer_free(obj->wire_object.wbuf);
99 }
100
101 FREE(obj);
102}
103
104/**
105 * Duplicate an object
106 * @param src The object to be duplicated
107 * @returns Pointer to the duplicate or NULL on error. Caller is responsible
108 * for freeing the returned object.
109 */
110
111of_object_t *
Rich Lanecd6ef152013-12-15 16:42:18 -0800112of_object_dup(of_object_t *src)
Rich Lanea06d0c32013-03-25 08:52:03 -0700113{
114 of_object_t *dst;
115 of_object_init_f init_fn;
116
Rich Lane671e7722013-12-15 16:48:54 -0800117 if ((dst = (of_object_t *)MALLOC(sizeof(*dst))) == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700118 return NULL;
119 }
120
121 MEMSET(dst, 0, sizeof(*dst));
122
123 /* Allocate a minimal wire buffer assuming we will not write to it. */
124 if ((dst->wire_object.wbuf = of_wire_buffer_new(src->length)) == NULL) {
125 FREE(dst);
126 return NULL;
127 }
128
129 dst->wire_object.owned = 1;
130
131 init_fn = of_object_init_map[src->object_id];
132 init_fn(dst, src->version, src->length, 0);
133
134 MEMCPY(OF_OBJECT_BUFFER_INDEX(dst, 0),
135 OF_OBJECT_BUFFER_INDEX(src, 0),
136 src->length);
137
138 return dst;
139}
140
Rich Lanea06d0c32013-03-25 08:52:03 -0700141/**
142 * Generic new from message call
143 */
144
145of_object_t *
146of_object_new_from_message(of_message_t msg, int len)
147{
148 of_object_id_t object_id;
149 of_object_t *obj;
150 of_version_t version;
151
152 version = of_message_version_get(msg);
153 if (!OF_VERSION_OKAY(version)) {
154 return NULL;
155 }
156
157 if (of_validate_message(msg, len) != 0) {
158 LOCI_LOG_ERROR("message validation failed\n");
159 return NULL;
160 }
161
162 object_id = of_message_to_object_id(msg, len);
163 ASSERT(object_id != OF_OBJECT_INVALID);
164
165 if ((obj = of_object_new(-1)) == NULL) {
166 return NULL;
167 }
168
169 of_object_init_map[object_id](obj, version, 0, 0);
170
171 if (of_object_buffer_bind(obj, OF_MESSAGE_TO_BUFFER(msg), len,
172 OF_MESSAGE_FREE_FUNCTION) < 0) {
173 FREE(obj);
174 return NULL;
175 }
176 obj->length = len;
177 obj->version = version;
178
Rich Lanea06d0c32013-03-25 08:52:03 -0700179 return obj;
180}
181
182/**
183 * Bind an existing buffer to an LOCI object
184 *
185 * @param obj Pointer to the object to be updated
186 * @param buf Pointer to the buffer to bind to obj
187 * @param bytes Length of buf
188 * @param buf_free An optional free function to be applied to
189 * buf on deallocation
190 *
191 * This can be called on any LOCI object; it should not need to be
192 * overridden.
193 */
194
195int
196of_object_buffer_bind(of_object_t *obj, uint8_t *buf, int bytes,
197 of_buffer_free_f buf_free)
198{
199 of_wire_object_t *wobj;
200 of_wire_buffer_t *wbuf;
201
202 ASSERT(buf != NULL);
203 ASSERT(bytes > 0);
204 // ASSERT(wobj is not bound);
205
206 wobj = &obj->wire_object;
207 MEMSET(wobj, 0, sizeof(*wobj));
208
209 wbuf = of_wire_buffer_new_bind(buf, bytes, buf_free);
210 if (wbuf == NULL) {
211 return OF_ERROR_RESOURCE;
212 }
213
214 wobj->wbuf = wbuf;
215 wobj->owned = 1;
216 obj->length = bytes;
217
218 return OF_ERROR_NONE;
219}
220
221/**
222 * Connect a child to a parent at the wire buffer level
223 *
224 * @param parent The top level object to bind to
225 * @param child The sub-object connecting to the parent
226 * @param offset The offset at which to attach the child RELATIVE
227 * TO THE PARENT in the buffer
228 * @param bytes The amount of the buffer dedicated to the child; see below
229 * @param inc_ref_count Should the ref count of the parent be incremented
230 *
231 * This is used for 'get' accessors for composite types as well as
232 * iterator functions for lists, both read (first/next) and write
233 * (append_init, append_advance).
234 *
235 * Connect a child object to a parent by setting up the child's
236 * wire_object to point to the parent's underlying buffer. The value
237 * of the parameter bytes is important in determining how the child
238 * is initialized:
239 * @li If bytes <= 0, the length and type of the child are not modified;
240 * no additional space is added to the buffer.
241 * @li If bytes > 0, the current wire buffer is grown to
242 * accomodate this many bytes. This is to support append operations.
243 *
244 * If an error is returned, future references to the child object
245 * (until it is reinitialized) are undefined.
246 */
247static void
248object_child_attach(of_object_t *parent, of_object_t *child,
249 int offset, int bytes)
250{
251 of_wire_object_t *c_wobj; /* Pointer to child's wire object */
252 of_wire_buffer_t *wbuf; /* Pointer to common wire buffer manager */
253
254 child->parent = parent;
255 wbuf = parent->wire_object.wbuf;
256
257 /* Set up the child's wire buf to point to same as parent */
258 c_wobj = &child->wire_object;
259 c_wobj->wbuf = wbuf;
260 c_wobj->obj_offset = parent->wire_object.obj_offset + offset;
261 c_wobj->owned = 0;
262
263 /*
264 * bytes determines if this is a read or write setup.
265 * If > 0, grow the buffer to accomodate the space
266 * Otherwise do nothing
267 */
268 if (bytes > 0) { /* Set internal length, request buffer space */
269 int tot_bytes; /* Total bytes to request for buffer if updated */
270
271 /* Set up space for the child in the parent's buffer */
272 tot_bytes = parent->wire_object.obj_offset + offset + bytes;
273
274 of_wire_buffer_grow(wbuf, tot_bytes);
275 child->length = bytes;
276 }
277 /* if bytes == 0 don't do anything */
278}
279
280/**
281 * Check for room in an object's wire buffer.
282 * @param obj The object being checked
283 * @param new_len The desired length
284 * @return Boolean
285 */
286
287int
288of_object_can_grow(of_object_t *obj, int new_len)
289{
290 return OF_OBJECT_ABSOLUTE_OFFSET(obj, new_len) <=
291 WBUF_ALLOC_BYTES(obj->wire_object.wbuf);
292}
293
294/**
295 * Set the xid of a message object
296 * @param obj The object being accessed
297 * @param xid The xid value to store in the wire buffer
298 * @return OF_ERROR_
299 * Since the XID is common across all versions, this is used
300 * for all XID accessors.
301 */
302
303int
304of_object_xid_set(of_object_t *obj, uint32_t xid)
305{
306 of_wire_buffer_t *wbuf;
307
308 if ((wbuf = OF_OBJECT_TO_WBUF(obj)) == NULL) {
309 return OF_ERROR_PARAM;
310 }
311 of_wire_buffer_u32_set(wbuf,
312 OF_OBJECT_ABSOLUTE_OFFSET(obj, OF_MESSAGE_XID_OFFSET), xid);
313 return OF_ERROR_NONE;
314}
315
316/**
317 * Get the xid of a message object
318 * @param obj The object being accessed
319 * @param xid Pointer to where to store the xid value
320 * @return OF_ERROR_
321 * Since the XID is common across all versions, this is used
322 * for all XID accessors.
323 */
324
325int
326of_object_xid_get(of_object_t *obj, uint32_t *xid)
327{
328 of_wire_buffer_t *wbuf;
329
330 if ((wbuf = OF_OBJECT_TO_WBUF(obj)) == NULL) {
331 return OF_ERROR_PARAM;
332 }
333 of_wire_buffer_u32_get(wbuf,
334 OF_OBJECT_ABSOLUTE_OFFSET(obj, OF_MESSAGE_XID_OFFSET), xid);
335 return OF_ERROR_NONE;
336}
337
338/****************************************************************
339 *
340 * Generic list operation implementations
341 *
342 ****************************************************************/
343
344/**
345 * Set up a child for appending to a parent list
346 * @param parent The parent; must be a list object
347 * @param child The child object; must be of type list element
348 * @return OF_ERROR_
349 *
350 * Attaches the wire buffer of the parent to the child by pointing
351 * the child to the end of the parent.
352 *
353 * Set the wire length and type from the child.
354 * Update the parent length adding the current child length
355 *
356 * After calling this function, the child object may be updated
357 * resulting in changes to the parent's wire buffer
358 *
359 */
360
361int
362of_list_append_bind(of_object_t *parent, of_object_t *child)
363{
364 if (parent == NULL || child == NULL ||
365 parent->wire_object.wbuf == NULL) {
366 return OF_ERROR_PARAM;
367 }
368
369 if (!of_object_can_grow(parent, parent->length + child->length)) {
370 return OF_ERROR_RESOURCE;
371 }
372
373 object_child_attach(parent, child, parent->length,
374 child->length);
375
376 /* Update the wire length and type if needed */
377 if (child->wire_length_set) {
378 child->wire_length_set(child, child->length);
379 }
380
381 if (child->wire_type_set) {
Rich Lane92feca82013-12-10 15:57:13 -0800382 child->wire_type_set(child);
Rich Lanea06d0c32013-03-25 08:52:03 -0700383 }
384
385 /* Update the parent's length */
386 of_object_parent_length_update(parent, child->length);
387
388 OF_LENGTH_CHECK_ASSERT(parent);
389
390 return OF_ERROR_NONE;
391}
392
393/**
394 * Generic atomic list append operation
395 * @param list The list to which an item is being appended
396 * @param item THe item to append to the list
397 *
398 * The contents of the item are copied to the end of the list.
399 * Currently assumes the list is at the end of its parent.
400 */
401int
402of_list_append(of_object_t *list, of_object_t *item)
403{
404 int new_len;
405
406 new_len = list->length + item->length;
407
408 if (!of_object_can_grow(list, new_len)) {
409 return OF_ERROR_RESOURCE;
410 }
411
412 of_wire_buffer_grow(list->wire_object.wbuf,
413 OF_OBJECT_ABSOLUTE_OFFSET(list, new_len));
414
415 MEMCPY(OF_OBJECT_BUFFER_INDEX(list, list->length),
416 OF_OBJECT_BUFFER_INDEX(item, 0), item->length);
417
418 /* Update the list's length */
419 of_object_parent_length_update(list, item->length);
420
421 OF_LENGTH_CHECK_ASSERT(list);
422
423 return OF_ERROR_NONE;
424}
425
426/**
427 * Generic list first function
428 * @param parent The parent; must be a list object
429 * @param child The child object; must be of type list element
430 * @return OF_ERROR_RANGE if list is empty
431 * @return OF_ERROR_
432 *
433 * Sets up the child to point to the first element in the list
434 *
435 * Child init must be called before this is called.
436 *
437 * @note TREAT AS PRIVATE
438 * Does not fully initialized object
439 */
440int
441of_list_first(of_object_t *parent, of_object_t *child)
442{
443 if (parent->length == 0) { /* Empty list */
444 return OF_ERROR_RANGE;
445 }
446
447 object_child_attach(parent, child, 0, 0);
448
449 return OF_ERROR_NONE;
450}
451
452/**
453 * Return boolean indicating if child is pointing to last entry in parent
454 * @param parent The parent; must be a list object
455 * @param child The child object; must be of type list element
456 * @return OF_ERROR_RANGE if list is empty
457 * @return OF_ERROR_
458 *
459 */
460static int
461of_list_is_last(of_object_t *parent, of_object_t *child)
462{
463 if (child->wire_object.obj_offset + child->length >=
464 parent->wire_object.obj_offset + parent->length) {
465 return 1;
466 }
467
468 return 0;
469}
470
471/**
472 * Generic list next function
473 * @param parent The parent; must be a list object
474 * @param child The child object; must be of type list element
475 * @return OF_ERROR_RANGE if at end of list
476 * @return OF_ERROR_
477 *
478 * Advances the child to point to the subsequent element in the list.
479 * The wire buffer object must not have been modified since the
480 * previous call to _first or _next.
481 *
482 * @note TREAT AS PRIVATE
483 * Does not fully initialized object
484 */
485int
486of_list_next(of_object_t *parent, of_object_t *child)
487{
488 int offset;
489
490 ASSERT(child->length > 0);
491
492 /* Get offset of parent */
493 if (of_list_is_last(parent, child)) {
494 return OF_ERROR_RANGE; /* We were on the last object */
495 }
496
497 /* Offset is relative to parent start */
498 offset = (child->wire_object.obj_offset - parent->wire_object.obj_offset) +
499 child->length;
500 object_child_attach(parent, child, offset, 0);
501
502 return OF_ERROR_NONE;
503}
504
505void
506of_object_wire_buffer_steal(of_object_t *obj, uint8_t **buffer)
507{
508 ASSERT(obj != NULL);
509 of_wire_buffer_steal(obj->wire_object.wbuf, buffer);
510 obj->wire_object.wbuf = NULL;
511}
512
Rich Lane50aa5942013-12-15 16:20:38 -0800513#define _MAX_PARENT_ITERATIONS 4
514/**
515 * Iteratively update parent lengths thru hierarchy
516 * @param obj The object whose length is being updated
517 * @param delta The difference between the current and new lengths
518 *
519 * Note that this includes updating the object itself. It will
520 * iterate thru parents.
521 *
522 * Assumes delta > 0.
523 */
524void
525of_object_parent_length_update(of_object_t *obj, int delta)
526{
527#ifndef NDEBUG
528 int count = 0;
529 of_wire_buffer_t *wbuf; /* For debug asserts only */
530#endif
531
532 while (obj != NULL) {
533 ASSERT(count++ < _MAX_PARENT_ITERATIONS);
534 obj->length += delta;
535 if (obj->wire_length_set != NULL) {
536 obj->wire_length_set(obj, obj->length);
537 }
538#ifndef NDEBUG
539 wbuf = obj->wire_object.wbuf;
540#endif
541
542 /* Asserts for wire length checking */
543 ASSERT(obj->length + obj->wire_object.obj_offset <=
544 WBUF_CURRENT_BYTES(wbuf));
545 if (obj->parent == NULL) {
546 ASSERT(obj->length + obj->wire_object.obj_offset ==
547 WBUF_CURRENT_BYTES(wbuf));
548 }
549
550 obj = obj->parent;
551 }
552}
553
Rich Lanec0e20ff2013-12-15 23:40:31 -0800554/**
555 * Use the type/length from the wire buffer and init the object
556 * @param obj The object being initialized
557 * @param base_object_id If > 0, this indicates the base object
558 * @param max_len If > 0, the max length to expect for the obj
559 * type for inheritance checking
560 * @return OF_ERROR_
561 *
562 * Used for inheritance type objects such as actions and OXMs
563 * The type is checked and if valid, the object is initialized.
564 * Then the length is taken from the buffer.
565 *
566 * Note that the object version must already be properly set.
567 */
568int
569of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id,
570 int max_len)
571{
572 if (obj->wire_type_get != NULL) {
573 of_object_id_t id;
574 obj->wire_type_get(obj, &id);
575 if (!of_wire_id_valid(id, base_object_id)) {
576 return OF_ERROR_PARSE;
577 }
578 obj->object_id = id;
579 /* Call the init function for this object type; do not push to wire */
580 of_object_init_map[id]((of_object_t *)(obj), obj->version, -1, 0);
581 }
582 if (obj->wire_length_get != NULL) {
583 int length;
584 obj->wire_length_get(obj, &length);
585 if (length < 0 || (max_len > 0 && length > max_len)) {
586 return OF_ERROR_PARSE;
587 }
588 obj->length = length;
589 } else {
590 /* @fixme Does this cover everything else? */
591 obj->length = of_object_fixed_len[obj->version][base_object_id];
592 }
593
594 return OF_ERROR_NONE;
595}
596
Rich Lanea06d0c32013-03-25 08:52:03 -0700597/*
598 * Set member:
599 * get_wbuf_extent
600 * find offset of start of member
601 * if offset is at wbuf_extent (append new data)
602 * copy data at extent
603 * update parent length
604 * else
605 * find length of current entry
606 * move from end of current to extent to create (or remove) space
607 * copy data to offset
608 * update my length -- NEED LOCAL INFO TO DO THIS for some cases
609 */
610
611/* Also need: get offset of member for all combinations */
612/* Also need: get length of member for all combinations */
613#if 0
614/**
615 * Append the wire buffer data from src to the end of dst's wire buffer
616 */
617int
618of_object_append_buffer(of_object_t *dst, of_object_t *src)
619{
620 of_wire_buffer_t *s_wbuf, *d_wbuf;
621 int orig_len, dst_offset, src_offset;
622
623 d_wbuf = OF_OBJECT_TO_WBUF(dst);
624 s_wbuf = OF_OBJECT_TO_WBUF(src);
625 dst_offset = dst->wire_object.obj_offset + dst_length;
626 src_offset = src->wire_object.obj_offset;
627 OF_WIRE_BUFFER_INIT_CHECK(d_wbuf, dst_offset + src->length);
628 MEMCPY(OF_WBUF_BUFFER_POINTER(d_wbuf, dst_offset),
629 OF_WBUF_BUFFER_POINTER(s_wbuf, 0), src->length);
630
631 orig_len = dst->length;
632 dst->length += src->length;
633
634 return OF_ERROR_NONE;
635}
636
637/**
638 * Set the length of the actions object in a packet_in object
639 */
640
641int
642of_packet_out_actions_length_set(of_packet_t *obj, int len)
643{
644 if (obj == NULL || obj->object_id != OF_PACKET_IN ||
645 obj->wire_object.wbuf == NULL) {
646 return OF_ERROR_PARAM;
647 }
648
649 obj->actions_len_set(obj, len);
650}
651
652int
653_packet_out_data_offset_get(of_packet_t *obj)
654{
655 if (obj == NULL || obj->object_id != OF_PACKET_IN ||
656 obj->wire_object.wbuf == NULL) {
657 return -1;
658 }
659
660 return OF_PACKET_OUT_FIXED_LENGTH + _packet_out_actions_length_get(obj);
661}
662
663
664/**
665 * Simple length derivation function
666 *
667 * Most variable length fields are alone at the end of a structure.
668 * Their length is a simple calculation, just the total length of
669 * the parent minus the length of the non-variable part of the
670 * parent's class type.
671 *
672 * @param parent The parent object
673 * @param length (out) Where to store the length of the final
674 * variable length member
675 */
676int
677of_object_simple_length_derive(of_object_t *obj, int *length)
678{
679
680}
681#endif