2 * Copyright (c) 2008, 2009 Nicira Networks.
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
27 #define THIS_MODULE VLM_pktbuf
30 /* Buffers are identified by a 32-bit opaque ID. We divide the ID
31 * into a buffer number (low bits) and a cookie (high bits). The buffer number
32 * is an index into an array of buffers. The cookie distinguishes between
33 * different packets that have occupied a single buffer. Thus, the more
34 * buffers we have, the lower-quality the cookie... */
36 #define PKTBUF_MASK (PKTBUF_CNT - 1)
37 #define PKTBUF_CNT (1u << PKTBUF_BITS)
39 #define COOKIE_BITS (32 - PKTBUF_BITS)
40 #define COOKIE_MAX ((1u << COOKIE_BITS) - 1)
42 #define OVERWRITE_MSECS 5000
45 struct ofpbuf *buffer;
47 long long int timeout;
52 struct packet packets[PKTBUF_CNT];
53 unsigned int buffer_idx;
65 return xcalloc(1, sizeof *pktbuf_create());
69 pktbuf_destroy(struct pktbuf *pb)
74 for (i = 0; i < PKTBUF_CNT; i++) {
75 ofpbuf_delete(pb->packets[i].buffer);
82 pktbuf_save(struct pktbuf *pb, struct ofpbuf *buffer, uint16_t in_port)
84 struct packet *p = &pb->packets[pb->buffer_idx];
85 pb->buffer_idx = (pb->buffer_idx + 1) & PKTBUF_MASK;
87 if (time_msec() < p->timeout) {
90 ofpbuf_delete(p->buffer);
93 /* Don't use maximum cookie value since all-1-bits ID is special. */
94 if (++p->cookie >= COOKIE_MAX) {
97 p->buffer = ofpbuf_clone(buffer);
98 p->timeout = time_msec() + OVERWRITE_MSECS;
100 return (p - pb->packets) | (p->cookie << PKTBUF_BITS);
104 pktbuf_retrieve(struct pktbuf *pb, uint32_t id, struct ofpbuf **bufferp,
107 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 20);
112 VLOG_WARN_RL(&rl, "attempt to send buffered packet via connection "
114 return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_COOKIE);
117 p = &pb->packets[id & PKTBUF_MASK];
118 if (p->cookie == id >> PKTBUF_BITS) {
119 struct ofpbuf *buffer = p->buffer;
122 *in_port = p->in_port;
124 COVERAGE_INC(pktbuf_retrieved);
127 COVERAGE_INC(pktbuf_reuse_error);
128 VLOG_WARN_RL(&rl, "attempt to reuse buffer %08"PRIx32, id);
129 error = ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BUFFER_EMPTY);
132 COVERAGE_INC(pktbuf_bad_cookie);
133 VLOG_WARN_RL(&rl, "cookie mismatch: %08"PRIx32" != %08"PRIx32,
134 id, (id & PKTBUF_MASK) | (p->cookie << PKTBUF_BITS));
135 error = ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_COOKIE);
143 pktbuf_discard(struct pktbuf *pb, uint32_t id)
145 struct packet *p = &pb->packets[id & PKTBUF_MASK];
146 if (p->cookie == id >> PKTBUF_BITS) {
147 ofpbuf_delete(p->buffer);