This will be used in the userspace switch implementation.
void *data; /* First byte actually in use. */
size_t size; /* Number of bytes in use. */
+ void *l2; /* Link-level header. */
+ void *l3; /* Network-level header. */
+ void *l4; /* Transport-level header. */
+
struct buffer *next; /* Next in a list of buffers. */
};
void buffer_reinit(struct buffer *, size_t);
struct buffer *buffer_new(size_t);
+struct buffer *buffer_clone(const struct buffer *);
void buffer_delete(struct buffer *);
void *buffer_at(const struct buffer *, size_t offset, size_t size);
void *buffer_put_uninit(struct buffer *, size_t);
void buffer_put(struct buffer *, const void *, size_t);
+void *buffer_push_uninit(struct buffer *b, size_t);
size_t buffer_headroom(struct buffer *);
size_t buffer_tailroom(struct buffer *);
};
BUILD_ASSERT_DECL(sizeof (struct flow) == 32);
-void flow_extract(const struct buffer *, uint16_t in_port, struct flow *);
+void flow_extract(struct buffer *, uint16_t in_port, struct flow *);
void flow_print(FILE *, const struct flow *);
int flow_compare(const struct flow *, const struct flow *);
unsigned long int flow_hash(const struct flow *, uint32_t basis);
b->base = b->data = base;
b->allocated = allocated;
b->size = 0;
+ b->l2 = b->l3 = b->l4 = NULL;
b->next = NULL;
}
return b;
}
+struct buffer *
+buffer_clone(const struct buffer *buffer)
+{
+ /* FIXME: reference counting. */
+ struct buffer *b = buffer_new(buffer->size);
+ buffer_put(b, buffer->data, buffer->size);
+ return b;
+}
+
/* Frees memory that 'b' points to, as well as 'b' itself. */
void
buffer_delete(struct buffer *b)
buffer_reserve_tailroom(struct buffer *b, size_t size)
{
if (size > buffer_tailroom(b)) {
- size_t headroom = buffer_headroom(b);
size_t new_allocated = b->allocated + MAX(size, 64);
void *new_base = xmalloc(new_allocated);
+ uintptr_t base_delta = new_base - b->base;
memcpy(new_base, b->base, b->allocated);
free(b->base);
b->base = new_base;
b->allocated = new_allocated;
- b->data = new_base + headroom;
+ b->data += base_delta;
+ if (b->l2) {
+ b->l2 += base_delta;
+ }
+ if (b->l3) {
+ b->l3 += base_delta;
+ }
+ if (b->l4) {
+ b->l4 += base_delta;
+ }
}
}
+void
+buffer_reserve_headroom(struct buffer *b, size_t size)
+{
+ assert(size <= buffer_headroom(b));
+}
+
/* 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. */
memcpy(buffer_put_uninit(b, size), p, size);
}
+void *
+buffer_push_uninit(struct buffer *b, size_t size)
+{
+ buffer_reserve_headroom(b, size);
+ b->data -= size;
+ b->size += size;
+ return b->data;
+}
+
/* If 'b' contains at least 'offset + size' bytes of data, returns a pointer to
* byte 'offset'. Otherwise, returns a null pointers. */
void *
b->data += size;
b->size -= size;
}
+
#define THIS_MODULE VLM_flow
void
-flow_extract(const struct buffer *packet, uint16_t in_port, struct flow *flow)
+flow_extract(struct buffer *packet, uint16_t in_port, struct flow *flow)
{
struct buffer b = *packet;
struct eth_header *eth;
memset(flow, 0, sizeof *flow);
flow->in_port = htons(in_port);
+ packet->l2 = b.data;
+ packet->l3 = NULL;
+ packet->l4 = NULL;
+
eth = buffer_at(&b, 0, sizeof *eth);
if (eth) {
buffer_pull(&b, ETH_HEADER_LEN);
memcpy(flow->dl_src, eth->eth_src, ETH_ADDR_LEN);
memcpy(flow->dl_dst, eth->eth_dst, ETH_ADDR_LEN);
+ packet->l3 = b.data;
if (flow->dl_type == htons(ETH_TYPE_IP)) {
const struct ip_header *nh = buffer_at(&b, 0, sizeof *nh);
if (nh) {
flow->nw_src = nh->ip_src;
flow->nw_dst = nh->ip_dst;
flow->nw_proto = nh->ip_proto;
+ packet->l4 = b.data + IP_HEADER_LEN;
if (flow->nw_proto == IP_TYPE_TCP
|| flow->nw_proto == IP_TYPE_UDP) {
int udp_ofs = IP_IHL(nh->ip_ihl_ver) * 4;