blob: b0d3e14d957c5a8086898e44af3021f9e0fa8df3 [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) {
Rich Lanecdd542d2014-04-03 16:13:12 -070064 if ((obj->wbuf = of_wire_buffer_new(bytes)) == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -070065 FREE(obj);
66 return NULL;
67 }
Rich Lanea06d0c32013-03-25 08:52:03 -070068 }
69
70 return obj;
71}
72
73/**
74 * The delete function for LOCI objects
75 *
76 * @param obj Pointer to the object to be deleted
77 *
78 * This can be called on any LOCI object; it should not need to be
79 * overridden.
80 */
81
82void
83of_object_delete(of_object_t *obj)
84{
85 if (obj == NULL) {
86 return;
87 }
88
Rich Lane3e431082014-04-03 16:21:30 -070089 if (obj->parent == NULL) {
Rich Lanecdd542d2014-04-03 16:13:12 -070090 of_wire_buffer_free(obj->wbuf);
Rich Lanea06d0c32013-03-25 08:52:03 -070091 }
92
93 FREE(obj);
94}
95
96/**
97 * Duplicate an object
98 * @param src The object to be duplicated
99 * @returns Pointer to the duplicate or NULL on error. Caller is responsible
100 * for freeing the returned object.
101 */
102
103of_object_t *
Rich Lanecd6ef152013-12-15 16:42:18 -0800104of_object_dup(of_object_t *src)
Rich Lanea06d0c32013-03-25 08:52:03 -0700105{
106 of_object_t *dst;
107 of_object_init_f init_fn;
108
Rich Lane671e7722013-12-15 16:48:54 -0800109 if ((dst = (of_object_t *)MALLOC(sizeof(*dst))) == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700110 return NULL;
111 }
112
113 MEMSET(dst, 0, sizeof(*dst));
114
115 /* Allocate a minimal wire buffer assuming we will not write to it. */
Rich Lanecdd542d2014-04-03 16:13:12 -0700116 if ((dst->wbuf = of_wire_buffer_new(src->length)) == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700117 FREE(dst);
118 return NULL;
119 }
120
Rich Lanea06d0c32013-03-25 08:52:03 -0700121 init_fn = of_object_init_map[src->object_id];
122 init_fn(dst, src->version, src->length, 0);
123
124 MEMCPY(OF_OBJECT_BUFFER_INDEX(dst, 0),
125 OF_OBJECT_BUFFER_INDEX(src, 0),
126 src->length);
127
128 return dst;
129}
130
Rich Lanea06d0c32013-03-25 08:52:03 -0700131/**
132 * Generic new from message call
133 */
134
135of_object_t *
136of_object_new_from_message(of_message_t msg, int len)
137{
138 of_object_id_t object_id;
139 of_object_t *obj;
140 of_version_t version;
141
142 version = of_message_version_get(msg);
143 if (!OF_VERSION_OKAY(version)) {
144 return NULL;
145 }
146
147 if (of_validate_message(msg, len) != 0) {
148 LOCI_LOG_ERROR("message validation failed\n");
149 return NULL;
150 }
151
Rich Lanea06d0c32013-03-25 08:52:03 -0700152 if ((obj = of_object_new(-1)) == NULL) {
153 return NULL;
154 }
155
Rich Lanea06d0c32013-03-25 08:52:03 -0700156 if (of_object_buffer_bind(obj, OF_MESSAGE_TO_BUFFER(msg), len,
157 OF_MESSAGE_FREE_FUNCTION) < 0) {
158 FREE(obj);
159 return NULL;
160 }
Rich Lanea06d0c32013-03-25 08:52:03 -0700161 obj->version = version;
162
Rich Lane76f181e2014-03-04 23:23:36 -0800163 of_header_wire_object_id_get(obj, &object_id);
164 of_object_init_map[object_id](obj, version, len, 0);
165
Rich Lanea06d0c32013-03-25 08:52:03 -0700166 return obj;
167}
168
169/**
Rich Lanec73680c2014-02-22 10:44:28 -0800170 * Parse a message without allocating memory
171 *
172 * @param storage Pointer to an uninitialized of_object_storage_t
173 * @param buf Pointer to the buffer
174 * @param length Length of buf
175 * @returns Pointer to an initialized of_object_t
176 *
177 * The lifetime of the returned object is the minimum of the lifetimes of
178 * 'buf' and 'storage'.
179 */
180
181of_object_t *
182of_object_new_from_message_preallocated(of_object_storage_t *storage,
183 uint8_t *buf, int len)
184{
185 of_object_t *obj = &storage->obj;
186 of_wire_buffer_t *wbuf = &storage->wbuf;
187 of_message_t msg = buf;
188 of_version_t version;
189 of_object_id_t object_id;
190
191 memset(storage, 0, sizeof(*storage));
192
193 version = of_message_version_get(msg);
194 if (!OF_VERSION_OKAY(version)) {
195 return NULL;
196 }
197
198 if (of_validate_message(msg, len) != 0) {
199 LOCI_LOG_ERROR("message validation failed\n");
200 return NULL;
201 }
202
Rich Lane76f181e2014-03-04 23:23:36 -0800203 obj->version = version;
Rich Lanecdd542d2014-04-03 16:13:12 -0700204 obj->wbuf = wbuf;
Rich Lanec73680c2014-02-22 10:44:28 -0800205 wbuf->buf = msg;
206 wbuf->alloc_bytes = len;
207 wbuf->current_bytes = len;
208
Rich Lane76f181e2014-03-04 23:23:36 -0800209 of_header_wire_object_id_get(obj, &object_id);
210 of_object_init_map[object_id](obj, version, len, 0);
211
Rich Lanec73680c2014-02-22 10:44:28 -0800212 return obj;
213}
214
215/**
Rich Lanea06d0c32013-03-25 08:52:03 -0700216 * Bind an existing buffer to an LOCI object
217 *
218 * @param obj Pointer to the object to be updated
219 * @param buf Pointer to the buffer to bind to obj
220 * @param bytes Length of buf
221 * @param buf_free An optional free function to be applied to
222 * buf on deallocation
223 *
224 * This can be called on any LOCI object; it should not need to be
225 * overridden.
226 */
227
228int
229of_object_buffer_bind(of_object_t *obj, uint8_t *buf, int bytes,
230 of_buffer_free_f buf_free)
231{
Rich Lanea06d0c32013-03-25 08:52:03 -0700232 of_wire_buffer_t *wbuf;
233
Rich Lanee57f0432014-02-19 10:31:53 -0800234 LOCI_ASSERT(buf != NULL);
235 LOCI_ASSERT(bytes > 0);
Rich Lanea06d0c32013-03-25 08:52:03 -0700236
237 wbuf = of_wire_buffer_new_bind(buf, bytes, buf_free);
238 if (wbuf == NULL) {
239 return OF_ERROR_RESOURCE;
240 }
241
Rich Lanecdd542d2014-04-03 16:13:12 -0700242 obj->wbuf = wbuf;
243 obj->obj_offset = 0;
Rich Lanea06d0c32013-03-25 08:52:03 -0700244 obj->length = bytes;
245
246 return OF_ERROR_NONE;
247}
248
249/**
250 * Connect a child to a parent at the wire buffer level
251 *
252 * @param parent The top level object to bind to
253 * @param child The sub-object connecting to the parent
254 * @param offset The offset at which to attach the child RELATIVE
255 * TO THE PARENT in the buffer
256 * @param bytes The amount of the buffer dedicated to the child; see below
Rich Lanea06d0c32013-03-25 08:52:03 -0700257 *
258 * This is used for 'get' accessors for composite types as well as
259 * iterator functions for lists, both read (first/next) and write
260 * (append_init, append_advance).
261 *
262 * Connect a child object to a parent by setting up the child's
263 * wire_object to point to the parent's underlying buffer. The value
264 * of the parameter bytes is important in determining how the child
265 * is initialized:
266 * @li If bytes <= 0, the length and type of the child are not modified;
267 * no additional space is added to the buffer.
268 * @li If bytes > 0, the current wire buffer is grown to
269 * accomodate this many bytes. This is to support append operations.
270 *
271 * If an error is returned, future references to the child object
272 * (until it is reinitialized) are undefined.
273 */
274static void
275object_child_attach(of_object_t *parent, of_object_t *child,
276 int offset, int bytes)
277{
Rich Laned1fe6972014-06-12 14:53:24 -0700278 of_object_attach(parent, child, offset, bytes);
Rich Lanea06d0c32013-03-25 08:52:03 -0700279
280 /*
281 * bytes determines if this is a read or write setup.
282 * If > 0, grow the buffer to accomodate the space
283 * Otherwise do nothing
284 */
285 if (bytes > 0) { /* Set internal length, request buffer space */
286 int tot_bytes; /* Total bytes to request for buffer if updated */
287
288 /* Set up space for the child in the parent's buffer */
Rich Lanecdd542d2014-04-03 16:13:12 -0700289 tot_bytes = parent->obj_offset + offset + bytes;
Rich Lanea06d0c32013-03-25 08:52:03 -0700290
Rich Laned1fe6972014-06-12 14:53:24 -0700291 of_wire_buffer_grow(parent->wbuf, tot_bytes);
Rich Lanea06d0c32013-03-25 08:52:03 -0700292 }
293 /* if bytes == 0 don't do anything */
294}
295
296/**
297 * Check for room in an object's wire buffer.
298 * @param obj The object being checked
299 * @param new_len The desired length
300 * @return Boolean
301 */
302
303int
304of_object_can_grow(of_object_t *obj, int new_len)
305{
306 return OF_OBJECT_ABSOLUTE_OFFSET(obj, new_len) <=
Rich Lanecdd542d2014-04-03 16:13:12 -0700307 WBUF_ALLOC_BYTES(obj->wbuf);
Rich Lanea06d0c32013-03-25 08:52:03 -0700308}
309
310/**
311 * Set the xid of a message object
312 * @param obj The object being accessed
313 * @param xid The xid value to store in the wire buffer
314 * @return OF_ERROR_
315 * Since the XID is common across all versions, this is used
316 * for all XID accessors.
317 */
318
319int
320of_object_xid_set(of_object_t *obj, uint32_t xid)
321{
322 of_wire_buffer_t *wbuf;
323
324 if ((wbuf = OF_OBJECT_TO_WBUF(obj)) == NULL) {
325 return OF_ERROR_PARAM;
326 }
327 of_wire_buffer_u32_set(wbuf,
328 OF_OBJECT_ABSOLUTE_OFFSET(obj, OF_MESSAGE_XID_OFFSET), xid);
329 return OF_ERROR_NONE;
330}
331
332/**
333 * Get the xid of a message object
334 * @param obj The object being accessed
335 * @param xid Pointer to where to store the xid value
336 * @return OF_ERROR_
337 * Since the XID is common across all versions, this is used
338 * for all XID accessors.
339 */
340
341int
342of_object_xid_get(of_object_t *obj, uint32_t *xid)
343{
344 of_wire_buffer_t *wbuf;
345
346 if ((wbuf = OF_OBJECT_TO_WBUF(obj)) == NULL) {
347 return OF_ERROR_PARAM;
348 }
349 of_wire_buffer_u32_get(wbuf,
350 OF_OBJECT_ABSOLUTE_OFFSET(obj, OF_MESSAGE_XID_OFFSET), xid);
351 return OF_ERROR_NONE;
352}
353
354/****************************************************************
355 *
356 * Generic list operation implementations
357 *
358 ****************************************************************/
359
360/**
361 * Set up a child for appending to a parent list
362 * @param parent The parent; must be a list object
363 * @param child The child object; must be of type list element
364 * @return OF_ERROR_
365 *
366 * Attaches the wire buffer of the parent to the child by pointing
367 * the child to the end of the parent.
368 *
369 * Set the wire length and type from the child.
370 * Update the parent length adding the current child length
371 *
372 * After calling this function, the child object may be updated
373 * resulting in changes to the parent's wire buffer
374 *
375 */
376
377int
378of_list_append_bind(of_object_t *parent, of_object_t *child)
379{
380 if (parent == NULL || child == NULL ||
Rich Lanecdd542d2014-04-03 16:13:12 -0700381 parent->wbuf == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700382 return OF_ERROR_PARAM;
383 }
384
385 if (!of_object_can_grow(parent, parent->length + child->length)) {
386 return OF_ERROR_RESOURCE;
387 }
388
389 object_child_attach(parent, child, parent->length,
390 child->length);
391
392 /* Update the wire length and type if needed */
Rich Lanedc46fe22014-04-03 15:10:38 -0700393 of_object_wire_length_set(child, child->length);
394 of_object_wire_type_set(child);
Rich Lanea06d0c32013-03-25 08:52:03 -0700395
396 /* Update the parent's length */
397 of_object_parent_length_update(parent, child->length);
398
399 OF_LENGTH_CHECK_ASSERT(parent);
400
401 return OF_ERROR_NONE;
402}
403
404/**
405 * Generic atomic list append operation
406 * @param list The list to which an item is being appended
407 * @param item THe item to append to the list
408 *
409 * The contents of the item are copied to the end of the list.
410 * Currently assumes the list is at the end of its parent.
411 */
412int
413of_list_append(of_object_t *list, of_object_t *item)
414{
415 int new_len;
416
417 new_len = list->length + item->length;
418
419 if (!of_object_can_grow(list, new_len)) {
420 return OF_ERROR_RESOURCE;
421 }
422
Rich Lanecdd542d2014-04-03 16:13:12 -0700423 of_wire_buffer_grow(list->wbuf,
Rich Lanea06d0c32013-03-25 08:52:03 -0700424 OF_OBJECT_ABSOLUTE_OFFSET(list, new_len));
425
426 MEMCPY(OF_OBJECT_BUFFER_INDEX(list, list->length),
427 OF_OBJECT_BUFFER_INDEX(item, 0), item->length);
428
429 /* Update the list's length */
430 of_object_parent_length_update(list, item->length);
431
432 OF_LENGTH_CHECK_ASSERT(list);
433
434 return OF_ERROR_NONE;
435}
436
437/**
438 * Generic list first function
439 * @param parent The parent; must be a list object
440 * @param child The child object; must be of type list element
441 * @return OF_ERROR_RANGE if list is empty
442 * @return OF_ERROR_
443 *
444 * Sets up the child to point to the first element in the list
445 *
446 * Child init must be called before this is called.
447 *
448 * @note TREAT AS PRIVATE
449 * Does not fully initialized object
450 */
451int
452of_list_first(of_object_t *parent, of_object_t *child)
453{
454 if (parent->length == 0) { /* Empty list */
455 return OF_ERROR_RANGE;
456 }
457
458 object_child_attach(parent, child, 0, 0);
459
460 return OF_ERROR_NONE;
461}
462
463/**
464 * Return boolean indicating if child is pointing to last entry in parent
465 * @param parent The parent; must be a list object
466 * @param child The child object; must be of type list element
467 * @return OF_ERROR_RANGE if list is empty
468 * @return OF_ERROR_
469 *
470 */
471static int
472of_list_is_last(of_object_t *parent, of_object_t *child)
473{
Rich Lanecdd542d2014-04-03 16:13:12 -0700474 if (child->obj_offset + child->length >=
475 parent->obj_offset + parent->length) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700476 return 1;
477 }
478
479 return 0;
480}
481
482/**
483 * Generic list next function
484 * @param parent The parent; must be a list object
485 * @param child The child object; must be of type list element
486 * @return OF_ERROR_RANGE if at end of list
487 * @return OF_ERROR_
488 *
489 * Advances the child to point to the subsequent element in the list.
490 * The wire buffer object must not have been modified since the
491 * previous call to _first or _next.
492 *
493 * @note TREAT AS PRIVATE
494 * Does not fully initialized object
495 */
496int
497of_list_next(of_object_t *parent, of_object_t *child)
498{
499 int offset;
500
Rich Lanee57f0432014-02-19 10:31:53 -0800501 LOCI_ASSERT(child->length > 0);
Rich Lanea06d0c32013-03-25 08:52:03 -0700502
503 /* Get offset of parent */
504 if (of_list_is_last(parent, child)) {
505 return OF_ERROR_RANGE; /* We were on the last object */
506 }
507
508 /* Offset is relative to parent start */
Rich Lanecdd542d2014-04-03 16:13:12 -0700509 offset = (child->obj_offset - parent->obj_offset) +
Rich Lanea06d0c32013-03-25 08:52:03 -0700510 child->length;
511 object_child_attach(parent, child, offset, 0);
512
513 return OF_ERROR_NONE;
514}
515
516void
517of_object_wire_buffer_steal(of_object_t *obj, uint8_t **buffer)
518{
Rich Lanee57f0432014-02-19 10:31:53 -0800519 LOCI_ASSERT(obj != NULL);
Rich Lanecdd542d2014-04-03 16:13:12 -0700520 of_wire_buffer_steal(obj->wbuf, buffer);
521 obj->wbuf = NULL;
Rich Lanea06d0c32013-03-25 08:52:03 -0700522}
523
Rich Lane50aa5942013-12-15 16:20:38 -0800524#define _MAX_PARENT_ITERATIONS 4
525/**
526 * Iteratively update parent lengths thru hierarchy
527 * @param obj The object whose length is being updated
528 * @param delta The difference between the current and new lengths
529 *
530 * Note that this includes updating the object itself. It will
531 * iterate thru parents.
532 *
533 * Assumes delta > 0.
534 */
535void
536of_object_parent_length_update(of_object_t *obj, int delta)
537{
538#ifndef NDEBUG
539 int count = 0;
540 of_wire_buffer_t *wbuf; /* For debug asserts only */
541#endif
542
543 while (obj != NULL) {
Rich Lanee57f0432014-02-19 10:31:53 -0800544 LOCI_ASSERT(count++ < _MAX_PARENT_ITERATIONS);
Rich Lane50aa5942013-12-15 16:20:38 -0800545 obj->length += delta;
Rich Lanedc46fe22014-04-03 15:10:38 -0700546 of_object_wire_length_set(obj, obj->length);
Rich Lane50aa5942013-12-15 16:20:38 -0800547#ifndef NDEBUG
Rich Lanecdd542d2014-04-03 16:13:12 -0700548 wbuf = obj->wbuf;
Rich Lane50aa5942013-12-15 16:20:38 -0800549#endif
550
551 /* Asserts for wire length checking */
Rich Lanecdd542d2014-04-03 16:13:12 -0700552 LOCI_ASSERT(obj->length + obj->obj_offset <=
Rich Lane50aa5942013-12-15 16:20:38 -0800553 WBUF_CURRENT_BYTES(wbuf));
554 if (obj->parent == NULL) {
Rich Lanecdd542d2014-04-03 16:13:12 -0700555 LOCI_ASSERT(obj->length + obj->obj_offset ==
Rich Lane50aa5942013-12-15 16:20:38 -0800556 WBUF_CURRENT_BYTES(wbuf));
557 }
558
559 obj = obj->parent;
560 }
561}
562
Rich Lanec0e20ff2013-12-15 23:40:31 -0800563/**
564 * Use the type/length from the wire buffer and init the object
565 * @param obj The object being initialized
566 * @param base_object_id If > 0, this indicates the base object
567 * @param max_len If > 0, the max length to expect for the obj
568 * type for inheritance checking
569 * @return OF_ERROR_
570 *
571 * Used for inheritance type objects such as actions and OXMs
572 * The type is checked and if valid, the object is initialized.
573 * Then the length is taken from the buffer.
574 *
575 * Note that the object version must already be properly set.
576 */
577int
578of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id,
579 int max_len)
580{
Rich Lanedc46fe22014-04-03 15:10:38 -0700581 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanec0e20ff2013-12-15 23:40:31 -0800582 of_object_id_t id;
Rich Lanedc46fe22014-04-03 15:10:38 -0700583 loci_class_metadata[obj->object_id].wire_type_get(obj, &id);
Rich Lanec0e20ff2013-12-15 23:40:31 -0800584 if (!of_wire_id_valid(id, base_object_id)) {
585 return OF_ERROR_PARSE;
586 }
587 obj->object_id = id;
588 /* Call the init function for this object type; do not push to wire */
589 of_object_init_map[id]((of_object_t *)(obj), obj->version, -1, 0);
590 }
Rich Lanedc46fe22014-04-03 15:10:38 -0700591 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanec0e20ff2013-12-15 23:40:31 -0800592 int length;
Rich Lanedc46fe22014-04-03 15:10:38 -0700593 loci_class_metadata[obj->object_id].wire_length_get(obj, &length);
Rich Lanec0e20ff2013-12-15 23:40:31 -0800594 if (length < 0 || (max_len > 0 && length > max_len)) {
595 return OF_ERROR_PARSE;
596 }
597 obj->length = length;
598 } else {
599 /* @fixme Does this cover everything else? */
600 obj->length = of_object_fixed_len[obj->version][base_object_id];
601 }
602
603 return OF_ERROR_NONE;
604}
605
Rich Lanea06d0c32013-03-25 08:52:03 -0700606/*
607 * Set member:
608 * get_wbuf_extent
609 * find offset of start of member
610 * if offset is at wbuf_extent (append new data)
611 * copy data at extent
612 * update parent length
613 * else
614 * find length of current entry
615 * move from end of current to extent to create (or remove) space
616 * copy data to offset
617 * update my length -- NEED LOCAL INFO TO DO THIS for some cases
618 */
619
620/* Also need: get offset of member for all combinations */
621/* Also need: get length of member for all combinations */
622#if 0
623/**
624 * Append the wire buffer data from src to the end of dst's wire buffer
625 */
626int
627of_object_append_buffer(of_object_t *dst, of_object_t *src)
628{
629 of_wire_buffer_t *s_wbuf, *d_wbuf;
630 int orig_len, dst_offset, src_offset;
631
632 d_wbuf = OF_OBJECT_TO_WBUF(dst);
633 s_wbuf = OF_OBJECT_TO_WBUF(src);
Rich Lanecdd542d2014-04-03 16:13:12 -0700634 dst_offset = dst->obj_offset + dst_length;
635 src_offset = src->obj_offset;
Rich Lanea06d0c32013-03-25 08:52:03 -0700636 OF_WIRE_BUFFER_INIT_CHECK(d_wbuf, dst_offset + src->length);
637 MEMCPY(OF_WBUF_BUFFER_POINTER(d_wbuf, dst_offset),
638 OF_WBUF_BUFFER_POINTER(s_wbuf, 0), src->length);
639
640 orig_len = dst->length;
641 dst->length += src->length;
642
643 return OF_ERROR_NONE;
644}
645
646/**
647 * Set the length of the actions object in a packet_in object
648 */
649
650int
651of_packet_out_actions_length_set(of_packet_t *obj, int len)
652{
653 if (obj == NULL || obj->object_id != OF_PACKET_IN ||
Rich Lanecdd542d2014-04-03 16:13:12 -0700654 obj->wbuf == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700655 return OF_ERROR_PARAM;
656 }
657
658 obj->actions_len_set(obj, len);
659}
660
661int
662_packet_out_data_offset_get(of_packet_t *obj)
663{
664 if (obj == NULL || obj->object_id != OF_PACKET_IN ||
Rich Lanecdd542d2014-04-03 16:13:12 -0700665 obj->wbuf == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700666 return -1;
667 }
668
669 return OF_PACKET_OUT_FIXED_LENGTH + _packet_out_actions_length_get(obj);
670}
671
672
673/**
674 * Simple length derivation function
675 *
676 * Most variable length fields are alone at the end of a structure.
677 * Their length is a simple calculation, just the total length of
678 * the parent minus the length of the non-variable part of the
679 * parent's class type.
680 *
681 * @param parent The parent object
682 * @param length (out) Where to store the length of the final
683 * variable length member
684 */
685int
686of_object_simple_length_derive(of_object_t *obj, int *length)
687{
688
689}
690#endif