/*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <config.h>
#include "ofpbuf.h"
-#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "dynamic-string.h"
b->allocated = allocated;
b->source = source;
b->size = 0;
- b->l2 = b->l3 = b->l4 = b->l7 = NULL;
+ b->l2 = b->l2_5 = b->l3 = b->l4 = b->l7 = NULL;
list_poison(&b->list_node);
b->private_p = NULL;
}
/* Initializes 'b' as an empty ofpbuf that contains the 'allocated' bytes of
* memory starting at 'base'. 'base' should point to a buffer on the stack.
- * If 'b' is resized, new memory will be allocated with malloc() and 'base'
- * will not be freed. This is useful when a small stack-allocated buffer is
- * normally appropriate but sometimes it must be expanded.
+ * (Nothing actually relies on 'base' being allocated on the stack. It could
+ * be static or malloc()'d memory. But stack space is the most common use
+ * case.)
*
* 'base' should be appropriately aligned. Using an array of uint32_t or
* uint64_t for the buffer is a reasonable way to ensure appropriate alignment
* for 32- or 64-bit data.
*
- * (Nothing actually relies on 'base' being allocated on the stack. It could
- * be static or malloc()'d memory. But stack space is the most common use
- * case.) */
+ * An ofpbuf operation that requires reallocating data will assert-fail if this
+ * function was used to initialize it. Thus, one need not call ofpbuf_uninit()
+ * on an ofpbuf initialized by this function (though doing so is harmless),
+ * because it is guaranteed that 'b' does not own any heap-allocated memory. */
void
ofpbuf_use_stack(struct ofpbuf *b, void *base, size_t allocated)
{
ofpbuf_use__(b, base, allocated, OFPBUF_STACK);
}
+/* Initializes 'b' as an empty ofpbuf that contains the 'allocated' bytes of
+ * memory starting at 'base'. 'base' should point to a buffer on the stack.
+ * (Nothing actually relies on 'base' being allocated on the stack. It could
+ * be static or malloc()'d memory. But stack space is the most common use
+ * case.)
+ *
+ * 'base' should be appropriately aligned. Using an array of uint32_t or
+ * uint64_t for the buffer is a reasonable way to ensure appropriate alignment
+ * for 32- or 64-bit data.
+ *
+ * An ofpbuf operation that requires reallocating data will copy the provided
+ * buffer into a malloc()'d buffer. Thus, it is wise to call ofpbuf_uninit()
+ * on an ofpbuf initialized by this function, so that if it expanded into the
+ * heap, that memory is freed. */
+void
+ofpbuf_use_stub(struct ofpbuf *b, void *base, size_t allocated)
+{
+ ofpbuf_use__(b, base, allocated, OFPBUF_STUB);
+}
+
/* Initializes 'b' as an ofpbuf whose data starts at 'data' and continues for
* 'size' bytes. This is appropriate for an ofpbuf that will be used to
* inspect existing data, without moving it around or reallocating it, and
void
ofpbuf_use_const(struct ofpbuf *b, const void *data, size_t size)
{
- ofpbuf_use__(b, (void *) data, size, OFPBUF_CONST);
+ ofpbuf_use__(b, CONST_CAST(void *, data), size, OFPBUF_STACK);
b->size = size;
}
}
}
+/* Returns a pointer that may be passed to free() to accomplish the same thing
+ * as ofpbuf_uninit(b). The return value is a null pointer if ofpbuf_uninit()
+ * would not free any memory. */
+void *
+ofpbuf_get_uninit_pointer(struct ofpbuf *b)
+{
+ return b && b->source == OFPBUF_MALLOC ? b->base : NULL;
+}
+
/* Frees memory that 'b' points to and allocates a new ofpbuf */
void
ofpbuf_reinit(struct ofpbuf *b, size_t size)
struct ofpbuf *
ofpbuf_clone(const struct ofpbuf *buffer)
{
- return ofpbuf_clone_data(buffer->data, buffer->size);
+ return ofpbuf_clone_with_headroom(buffer, 0);
}
/* Creates and returns a new ofpbuf whose data are copied from 'buffer'. The
struct ofpbuf *
ofpbuf_clone_with_headroom(const struct ofpbuf *buffer, size_t headroom)
{
- return ofpbuf_clone_data_with_headroom(buffer->data, buffer->size,
- headroom);
+ struct ofpbuf *new_buffer;
+ uintptr_t data_delta;
+
+ new_buffer = ofpbuf_clone_data_with_headroom(buffer->data, buffer->size,
+ headroom);
+ data_delta = (char *) new_buffer->data - (char *) buffer->data;
+
+ if (buffer->l2) {
+ new_buffer->l2 = (char *) buffer->l2 + data_delta;
+ }
+ if (buffer->l2_5) {
+ new_buffer->l2_5 = (char *) buffer->l2_5 + data_delta;
+ }
+ if (buffer->l3) {
+ new_buffer->l3 = (char *) buffer->l3 + data_delta;
+ }
+ if (buffer->l4) {
+ new_buffer->l4 = (char *) buffer->l4 + data_delta;
+ }
+ if (buffer->l7) {
+ new_buffer->l7 = (char *) buffer->l7 + data_delta;
+ }
+
+ return new_buffer;
}
/* Creates and returns a new ofpbuf that initially contains a copy of the
break;
case OFPBUF_STACK:
+ NOT_REACHED();
+
+ case OFPBUF_STUB:
+ b->source = OFPBUF_MALLOC;
new_base = xmalloc(new_allocated);
ofpbuf_copy__(b, new_base, new_headroom, new_tailroom);
- b->source = OFPBUF_MALLOC;
break;
- case OFPBUF_CONST:
- NOT_REACHED();
-
default:
NOT_REACHED();
}
if (b->l2) {
b->l2 = (char *) b->l2 + data_delta;
}
+ if (b->l2_5) {
+ b->l2_5 = (char *) b->l2_5 + data_delta;
+ }
if (b->l3) {
b->l3 = (char *) b->l3 + data_delta;
}
}
}
+/* If 'b' is shorter than 'length' bytes, pads its tail out with zeros to that
+ * length. */
+void
+ofpbuf_padto(struct ofpbuf *b, size_t length)
+{
+ if (b->size < length) {
+ ofpbuf_put_zeros(b, length - b->size);
+ }
+}
+
/* Appends 'size' bytes of data to the tail end of 'b', reallocating and
* copying its data if necessary. Returns a pointer to the first byte of the
* new data, which is left uninitialized. */
if (n) {
*n = b->size - initial_size;
}
- return (char *) s;
+ return CONST_CAST(char *, s);
}
ofpbuf_put(b, &byte, 1);
void
ofpbuf_reserve(struct ofpbuf *b, size_t size)
{
- assert(!b->size);
+ ovs_assert(!b->size);
ofpbuf_prealloc_tailroom(b, size);
b->data = (char*)b->data + size;
}
void *
ofpbuf_at_assert(const struct ofpbuf *b, size_t offset, size_t size)
{
- assert(offset + size <= b->size);
+ ovs_assert(offset + size <= b->size);
return ((char *) b->data) + offset;
}
ofpbuf_pull(struct ofpbuf *b, size_t size)
{
void *data = b->data;
- assert(b->size >= size);
+ ovs_assert(b->size >= size);
b->data = (char*)b->data + size;
b->size -= size;
return data;