summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJarno Rajahalme <jarno@ovn.org>2016-08-30 10:20:51 -0700
committerJarno Rajahalme <jarno@ovn.org>2016-08-30 10:20:51 -0700
commitc184807ced554c1dc7b69b3cd4f59cd85575fdf1 (patch)
tree8a477f382ec8b177ea7a436753933efc8ede606c
parent88e62998a2db1f8c9f3df2ef9f8d0cf8a2277262 (diff)
downloadopenvswitch-c184807ced554c1dc7b69b3cd4f59cd85575fdf1.tar.gz
lib: Retire packet buffering feature.
OVS implementation of buffering packets that are sent to the controller is not compliant with the OpenFlow specifications after OpenFlow 1.0, which is possibly true since OpenFlow 1.0 is not really specifying the packet buffering behavior. OVS implementation executes the buffered packet against the actions of the modified or added rule, whereas OpenFlow (since 1.1) specifies that the packet should be matched against the flow table 0 and processed accordingly. Rather than fix this behavior, and potentially break OVS users, the packet buffering feature is removed altogether. After all, such packet buffering is an optional OpenFlow feature, and as such any possible users should continue to work without this feature. This patch also makes OVS check the received 'buffer_id' values more rigorously, and fixes some internal users accordingly. Found by inspection. Signed-off-by: Jarno Rajahalme <jarno@ovn.org> Acked-by: Ben Pfaff <blp@ovn.org>
-rw-r--r--FAQ.md64
-rw-r--r--include/openvswitch/ofp-util.h4
-rw-r--r--lib/automake.mk2
-rw-r--r--lib/ofp-util.c80
-rw-r--r--lib/pktbuf.c220
-rw-r--r--lib/pktbuf.h40
-rw-r--r--ofproto/bundles.c1
-rw-r--r--ofproto/connmgr.c21
-rw-r--r--ofproto/connmgr.h3
-rw-r--r--ofproto/fail-open.c1
-rw-r--r--ofproto/ofproto-dpif.c21
-rw-r--r--ofproto/ofproto-provider.h28
-rw-r--r--ofproto/ofproto.c142
-rw-r--r--tests/ofproto.at10
-rw-r--r--tutorial/OVN-Tutorial.md4
-rw-r--r--vswitchd/ovs-vswitchd.8.in5
16 files changed, 66 insertions, 580 deletions
diff --git a/FAQ.md b/FAQ.md
index 787c67dee..5a09d1344 100644
--- a/FAQ.md
+++ b/FAQ.md
@@ -1970,55 +1970,21 @@ A: Reconfiguring your bridge can change your bridge's datapath-id because
ovs-vsctl set bridge br0 other-config:datapath-id=0123456789abcdef
-### Q: My controller is getting errors about "buffers". What's going on?
-
-A: When a switch sends a packet to an OpenFlow controller using a
- "packet-in" message, it can also keep a copy of that packet in a
- "buffer", identified by a 32-bit integer "buffer_id". There are
- two advantages to buffering. First, when the controller wants to
- tell the switch to do something with the buffered packet (with a
- "packet-out" OpenFlow request), it does not need to send another
- copy of the packet back across the OpenFlow connection, which
- reduces the bandwidth cost of the connection and improves latency.
- This enables the second advantage: the switch can optionally send
- only the first part of the packet to the controller (assuming that
- the switch only needs to look at the first few bytes of the
- packet), further reducing bandwidth and improving latency.
-
- However, buffering introduces some issues of its own. First, any
- switch has limited resources, so if the controller does not use a
- buffered packet, the switch has to decide how long to keep it
- buffered. When many packets are sent to a controller and buffered,
- Open vSwitch can discard buffered packets that the controller has
- not used after as little as 5 seconds. This means that
- controllers, if they make use of packet buffering, should use the
- buffered packets promptly. (This includes sending a "packet-out"
- with no actions if the controller does not want to do anything with
- a buffered packet, to clear the packet buffer and effectively
- "drop" its packet.)
-
- Second, packet buffers are one-time-use, meaning that a controller
- cannot use a single packet buffer in two or more "packet-out"
- commands. Open vSwitch will respond with an error to the second
- and subsequent "packet-out"s in such a case.
-
- Finally, a common error early in controller development is to try
- to use buffer_id 0 in a "packet-out" message as if 0 represented
- "no buffered packet". This is incorrect usage: the buffer_id with
- this meaning is actually 0xffffffff.
-
- ovs-vswitchd(8) describes some details of Open vSwitch packet
- buffering that the OpenFlow specification requires implementations
- to document.
-
- Note that the packet buffering support is deprecated in OVS 2.6
- release, and will be removed in OVS 2.7. After the change OVS
- always sends the 'buffer_id' as 0xffffffff in "packet-in" messages
- and will send an error response if any other value of this field is
- included in "packet-out" and "flow mod" sent by a controller.
- Controllers are already expected to work properly in cases where
- the switch can not buffer packets, so this change should not affect
- existing users.
+### Q: My controller complains that OVS is not buffering packets.
+ What's going on?
+
+A: "Packet buffering" is an optional OpenFlow feature, and controllers
+ should detect how many "buffers" an OpenFlow switch implements. It
+ was recently noticed that OVS implementation of the buffering
+ feature was not compliant to OpenFlow specifications. Rather than
+ fix it and risk controller incompatibility, the buffering feature
+ is removed as of OVS 2.7. Controllers are already expected to work
+ properly in cases where the switch can not buffer packets, but
+ sends full packets in "packet-in" messages instead, so this change
+ should not affect existing users. After the change OVS always
+ sends the 'buffer_id' as 0xffffffff in "packet-in" messages and
+ will send an error response if any other value of this field is
+ included in a "packet-out" or a "flow mod" sent by a controller.
### Q: How does OVS divide flows among buckets in an OpenFlow "select" group?
diff --git a/include/openvswitch/ofp-util.h b/include/openvswitch/ofp-util.h
index 177bf2be8..450e739ac 100644
--- a/include/openvswitch/ofp-util.h
+++ b/include/openvswitch/ofp-util.h
@@ -36,7 +36,6 @@
struct ofpbuf;
union ofp_action;
struct ofpact_set_field;
-struct pktbuf;
/* Port numbers. */
enum ofperr ofputil_port_from_ofp11(ovs_be32 ofp11_port,
@@ -498,8 +497,7 @@ struct ofputil_packet_in_private {
struct ofpbuf *ofputil_encode_packet_in_private(
const struct ofputil_packet_in_private *,
enum ofputil_protocol protocol,
- enum nx_packet_in_format,
- uint16_t max_len, struct pktbuf *);
+ enum nx_packet_in_format);
enum ofperr ofputil_decode_packet_in_private(
const struct ofp_header *, bool loose,
diff --git a/lib/automake.mk b/lib/automake.mk
index 165e6a8bd..b00e90f5d 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -201,8 +201,6 @@ lib_libopenvswitch_la_SOURCES = \
lib/pcap-file.h \
lib/perf-counter.h \
lib/perf-counter.c \
- lib/pktbuf.c \
- lib/pktbuf.h \
lib/poll-loop.c \
lib/poll-loop.h \
lib/process.c \
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index ccb06fe6b..1fa499841 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -45,7 +45,6 @@
#include "openvswitch/vlog.h"
#include "openflow/intel-ext.h"
#include "packets.h"
-#include "pktbuf.h"
#include "random.h"
#include "tun-metadata.h"
#include "unaligned.h"
@@ -3588,17 +3587,14 @@ encode_packet_in_reason(enum ofp_packet_in_reason reason,
* function omits it. The caller can add it itself if desired. */
static void
ofputil_put_packet_in(const struct ofputil_packet_in *pin,
- enum ofp_version version, uint32_t buffer_id,
- size_t include_bytes, struct ofpbuf *msg)
+ enum ofp_version version, size_t include_bytes,
+ struct ofpbuf *msg)
{
/* Add packet properties. */
ofpprop_put(msg, NXPINT_PACKET, pin->packet, include_bytes);
if (include_bytes != pin->packet_len) {
ofpprop_put_u32(msg, NXPINT_FULL_LEN, pin->packet_len);
}
- if (buffer_id != UINT32_MAX) {
- ofpprop_put_u32(msg, NXPINT_BUFFER_ID, buffer_id);
- }
/* Add flow properties. */
ofpprop_put_u8(msg, NXPINT_TABLE_ID, pin->table_id);
@@ -3642,11 +3638,10 @@ enum nx_continuation_prop_type {
* function omits it. The caller can add it itself if desired. */
static void
ofputil_put_packet_in_private(const struct ofputil_packet_in_private *pin,
- enum ofp_version version, uint32_t buffer_id,
- size_t include_bytes, struct ofpbuf *msg)
+ enum ofp_version version, size_t include_bytes,
+ struct ofpbuf *msg)
{
- ofputil_put_packet_in(&pin->public, version, buffer_id,
- include_bytes, msg);
+ ofputil_put_packet_in(&pin->public, version, include_bytes, msg);
size_t continuation_ofs = ofpprop_start_nested(msg, NXPINT_CONTINUATION);
size_t inner_ofs = msg->size;
@@ -3734,8 +3729,7 @@ ofputil_put_packet_in_private(const struct ofputil_packet_in_private *pin,
}
static struct ofpbuf *
-ofputil_encode_ofp10_packet_in(const struct ofputil_packet_in *pin,
- uint32_t buffer_id)
+ofputil_encode_ofp10_packet_in(const struct ofputil_packet_in *pin)
{
struct ofp10_packet_in *opi;
struct ofpbuf *msg;
@@ -3746,14 +3740,14 @@ ofputil_encode_ofp10_packet_in(const struct ofputil_packet_in *pin,
opi->total_len = htons(pin->packet_len);
opi->in_port = htons(ofp_to_u16(pin->flow_metadata.flow.in_port.ofp_port));
opi->reason = encode_packet_in_reason(pin->reason, OFP10_VERSION);
- opi->buffer_id = htonl(buffer_id);
+ opi->buffer_id = htonl(UINT32_MAX);
return msg;
}
static struct ofpbuf *
ofputil_encode_nx_packet_in(const struct ofputil_packet_in *pin,
- enum ofp_version version, uint32_t buffer_id)
+ enum ofp_version version)
{
struct nx_packet_in *npi;
struct ofpbuf *msg;
@@ -3767,7 +3761,7 @@ ofputil_encode_nx_packet_in(const struct ofputil_packet_in *pin,
ofpbuf_put_zeros(msg, 2);
npi = msg->msg;
- npi->buffer_id = htonl(buffer_id);
+ npi->buffer_id = htonl(UINT32_MAX);
npi->total_len = htons(pin->packet_len);
npi->reason = encode_packet_in_reason(pin->reason, version);
npi->table_id = pin->table_id;
@@ -3779,8 +3773,7 @@ ofputil_encode_nx_packet_in(const struct ofputil_packet_in *pin,
static struct ofpbuf *
ofputil_encode_nx_packet_in2(const struct ofputil_packet_in_private *pin,
- enum ofp_version version, uint32_t buffer_id,
- size_t include_bytes)
+ enum ofp_version version, size_t include_bytes)
{
/* 'extra' is just an estimate of the space required. */
size_t extra = (pin->public.packet_len
@@ -3792,7 +3785,7 @@ ofputil_encode_nx_packet_in2(const struct ofputil_packet_in_private *pin,
struct ofpbuf *msg = ofpraw_alloc_xid(OFPRAW_NXT_PACKET_IN2, version,
htonl(0), extra);
- ofputil_put_packet_in_private(pin, version, buffer_id, include_bytes, msg);
+ ofputil_put_packet_in_private(pin, version, include_bytes, msg);
if (pin->public.userdata_len) {
ofpprop_put(msg, NXPINT_USERDATA, pin->public.userdata,
pin->public.userdata_len);
@@ -3803,8 +3796,7 @@ ofputil_encode_nx_packet_in2(const struct ofputil_packet_in_private *pin,
}
static struct ofpbuf *
-ofputil_encode_ofp11_packet_in(const struct ofputil_packet_in *pin,
- uint32_t buffer_id)
+ofputil_encode_ofp11_packet_in(const struct ofputil_packet_in *pin)
{
struct ofp11_packet_in *opi;
struct ofpbuf *msg;
@@ -3812,7 +3804,7 @@ ofputil_encode_ofp11_packet_in(const struct ofputil_packet_in *pin,
msg = ofpraw_alloc_xid(OFPRAW_OFPT11_PACKET_IN, OFP11_VERSION,
htonl(0), pin->packet_len);
opi = ofpbuf_put_zeros(msg, sizeof *opi);
- opi->buffer_id = htonl(buffer_id);
+ opi->buffer_id = htonl(UINT32_MAX);
opi->in_port = ofputil_port_to_ofp11(
pin->flow_metadata.flow.in_port.ofp_port);
opi->in_phy_port = opi->in_port;
@@ -3825,8 +3817,7 @@ ofputil_encode_ofp11_packet_in(const struct ofputil_packet_in *pin,
static struct ofpbuf *
ofputil_encode_ofp12_packet_in(const struct ofputil_packet_in *pin,
- enum ofp_version version,
- uint32_t buffer_id)
+ enum ofp_version version)
{
enum ofpraw raw = (version >= OFP13_VERSION
? OFPRAW_OFPT13_PACKET_IN
@@ -3838,7 +3829,7 @@ ofputil_encode_ofp12_packet_in(const struct ofputil_packet_in *pin,
htonl(0), NXM_TYPICAL_LEN + 2 + pin->packet_len);
struct ofp12_packet_in *opi = ofpbuf_put_zeros(msg, sizeof *opi);
- opi->buffer_id = htonl(buffer_id);
+ opi->buffer_id = htonl(UINT32_MAX);
opi->total_len = htons(pin->packet_len);
opi->reason = encode_packet_in_reason(pin->reason, version);
opi->table_id = pin->table_id;
@@ -3857,11 +3848,6 @@ ofputil_encode_ofp12_packet_in(const struct ofputil_packet_in *pin,
/* Converts abstract ofputil_packet_in_private 'pin' into a PACKET_IN message
* for 'protocol', using the packet-in format specified by 'packet_in_format'.
*
- * If 'pkt_buf' is nonnull and 'max_len' allows the packet to be buffered, this
- * function will attempt to obtain a buffer ID from 'pktbuf' and truncate the
- * packet to 'max_len' bytes. Otherwise, or if 'pktbuf' doesn't have a free
- * buffer, it will send the whole packet without buffering.
- *
* This function is really meant only for use by ovs-vswitchd. To any other
* code, the "continuation" data, i.e. the data that is in struct
* ofputil_packet_in_private but not in struct ofputil_packet_in, is supposed
@@ -3873,28 +3859,10 @@ ofputil_encode_ofp12_packet_in(const struct ofputil_packet_in *pin,
struct ofpbuf *
ofputil_encode_packet_in_private(const struct ofputil_packet_in_private *pin,
enum ofputil_protocol protocol,
- enum nx_packet_in_format packet_in_format,
- uint16_t max_len, struct pktbuf *pktbuf)
+ enum nx_packet_in_format packet_in_format)
{
enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
- /* Get buffer ID. */
- ofp_port_t in_port = pin->public.flow_metadata.flow.in_port.ofp_port;
- uint32_t buffer_id = (max_len != OFPCML12_NO_BUFFER && pktbuf
- ? pktbuf_save(pktbuf, pin->public.packet,
- pin->public.packet_len, in_port)
- : UINT32_MAX);
-
- /* Calculate the number of bytes of the packet to include in the
- * packet-in:
- *
- * - If not buffered, the whole thing.
- *
- * - Otherwise, no more than 'max_len' bytes. */
- size_t include_bytes = (buffer_id == UINT32_MAX
- ? pin->public.packet_len
- : MIN(max_len, pin->public.packet_len));
-
struct ofpbuf *msg;
switch (packet_in_format) {
case NXPIF_STANDARD:
@@ -3903,11 +3871,11 @@ ofputil_encode_packet_in_private(const struct ofputil_packet_in_private *pin,
case OFPUTIL_P_OF10_STD_TID:
case OFPUTIL_P_OF10_NXM:
case OFPUTIL_P_OF10_NXM_TID:
- msg = ofputil_encode_ofp10_packet_in(&pin->public, buffer_id);
+ msg = ofputil_encode_ofp10_packet_in(&pin->public);
break;
case OFPUTIL_P_OF11_STD:
- msg = ofputil_encode_ofp11_packet_in(&pin->public, buffer_id);
+ msg = ofputil_encode_ofp11_packet_in(&pin->public);
break;
case OFPUTIL_P_OF12_OXM:
@@ -3915,7 +3883,7 @@ ofputil_encode_packet_in_private(const struct ofputil_packet_in_private *pin,
case OFPUTIL_P_OF14_OXM:
case OFPUTIL_P_OF15_OXM:
case OFPUTIL_P_OF16_OXM:
- msg = ofputil_encode_ofp12_packet_in(&pin->public, version, buffer_id);
+ msg = ofputil_encode_ofp12_packet_in(&pin->public, version);
break;
default:
@@ -3924,18 +3892,18 @@ ofputil_encode_packet_in_private(const struct ofputil_packet_in_private *pin,
break;
case NXPIF_NXT_PACKET_IN:
- msg = ofputil_encode_nx_packet_in(&pin->public, version, buffer_id);
+ msg = ofputil_encode_nx_packet_in(&pin->public, version);
break;
case NXPIF_NXT_PACKET_IN2:
- return ofputil_encode_nx_packet_in2(pin, version, buffer_id,
- include_bytes);
+ return ofputil_encode_nx_packet_in2(pin, version,
+ pin->public.packet_len);
default:
OVS_NOT_REACHED();
}
- ofpbuf_put(msg, pin->public.packet, include_bytes);
+ ofpbuf_put(msg, pin->public.packet, pin->public.packet_len);
ofpmsg_update_length(msg);
return msg;
}
@@ -4004,7 +3972,7 @@ ofputil_encode_resume(const struct ofputil_packet_in *pin,
size_t extra = pin->packet_len + NXM_TYPICAL_LEN + continuation->size;
struct ofpbuf *msg = ofpraw_alloc_xid(OFPRAW_NXT_RESUME, version,
0, extra);
- ofputil_put_packet_in(pin, version, UINT32_MAX, pin->packet_len, msg);
+ ofputil_put_packet_in(pin, version, pin->packet_len, msg);
ofpprop_put_nested(msg, NXPINT_CONTINUATION, continuation);
ofpmsg_update_length(msg);
return msg;
diff --git a/lib/pktbuf.c b/lib/pktbuf.c
deleted file mode 100644
index e2c61fd4d..000000000
--- a/lib/pktbuf.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2016 Nicira, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <config.h>
-#include "pktbuf.h"
-#include <inttypes.h>
-#include <stdlib.h>
-#include "coverage.h"
-#include "openvswitch/ofp-util.h"
-#include "dp-packet.h"
-#include "timeval.h"
-#include "util.h"
-#include "openvswitch/vconn.h"
-#include "openvswitch/vlog.h"
-
-VLOG_DEFINE_THIS_MODULE(pktbuf);
-
-COVERAGE_DEFINE(pktbuf_buffer_unknown);
-COVERAGE_DEFINE(pktbuf_retrieved);
-COVERAGE_DEFINE(pktbuf_reuse_error);
-
-/* Buffers are identified by a 32-bit opaque ID. We divide the ID
- * into a buffer number (low bits) and a cookie (high bits). The buffer number
- * is an index into an array of buffers. The cookie distinguishes between
- * different packets that have occupied a single buffer. Thus, the more
- * buffers we have, the lower-quality the cookie... */
-#define PKTBUF_BITS 8
-#define PKTBUF_MASK (PKTBUF_CNT - 1)
-#define PKTBUF_CNT (1u << PKTBUF_BITS)
-
-#define COOKIE_BITS (32 - PKTBUF_BITS)
-#define COOKIE_MAX ((1u << COOKIE_BITS) - 1)
-
-#define OVERWRITE_MSECS 5000
-
-struct packet {
- struct dp_packet *buffer;
- uint32_t cookie;
- long long int timeout;
- ofp_port_t in_port;
-};
-
-struct pktbuf {
- struct packet packets[PKTBUF_CNT];
- unsigned int buffer_idx;
- unsigned int null_idx;
-};
-
-int
-pktbuf_capacity(void)
-{
- return PKTBUF_CNT;
-}
-
-struct pktbuf *
-pktbuf_create(void)
-{
- return xzalloc(sizeof *pktbuf_create());
-}
-
-void
-pktbuf_destroy(struct pktbuf *pb)
-{
- if (pb) {
- size_t i;
-
- for (i = 0; i < PKTBUF_CNT; i++) {
- dp_packet_delete(pb->packets[i].buffer);
- }
- free(pb);
- }
-}
-
-static unsigned int
-make_id(unsigned int buffer_idx, unsigned int cookie)
-{
- return buffer_idx | (cookie << PKTBUF_BITS);
-}
-
-/* Attempts to allocate an OpenFlow packet buffer id within 'pb'. The packet
- * buffer will store a copy of 'buffer_size' bytes in 'buffer' and the port
- * number 'in_port', which should be the OpenFlow port number on which 'buffer'
- * was received.
- *
- * If successful, returns the packet buffer id (a number other than
- * UINT32_MAX). pktbuf_retrieve() can later be used to retrieve the buffer and
- * its input port number (buffers do expire after a time, so this is not
- * guaranteed to be true forever). On failure, returns UINT32_MAX.
- *
- * The caller retains ownership of 'buffer'. */
-uint32_t
-pktbuf_save(struct pktbuf *pb, const void *buffer, size_t buffer_size,
- ofp_port_t in_port)
-{
- struct packet *p = &pb->packets[pb->buffer_idx];
- pb->buffer_idx = (pb->buffer_idx + 1) & PKTBUF_MASK;
- if (p->buffer) {
- if (time_msec() < p->timeout) {
- return UINT32_MAX;
- }
- dp_packet_delete(p->buffer);
- }
-
- /* Don't use maximum cookie value since all-1-bits ID is special. */
- if (++p->cookie >= COOKIE_MAX) {
- p->cookie = 0;
- }
-
- /* Use 2 bytes of headroom to 32-bit align the L3 header. */
- p->buffer = dp_packet_clone_data_with_headroom(buffer, buffer_size, 2);
-
- p->timeout = time_msec() + OVERWRITE_MSECS;
- p->in_port = in_port;
- return make_id(p - pb->packets, p->cookie);
-}
-
-/* Attempts to retrieve a saved packet with the given 'id' from 'pb'. Returns
- * 0 if successful, otherwise an OpenFlow error code.
- *
- * On success, stores the buffered packet in '*bufferp' and the OpenFlow port
- * number on which the packet was received in '*in_port'. The caller becomes
- * responsible for freeing the buffer.
- *
- * 'in_port' may be NULL if the input port is not of interest.
- *
- * The L3 header of a returned packet will be 32-bit aligned.
- *
- * On failure, stores NULL in in '*bufferp' and UINT16_MAX in '*in_port'. */
-enum ofperr
-pktbuf_retrieve(struct pktbuf *pb, uint32_t id, struct dp_packet **bufferp,
- ofp_port_t *in_port)
-{
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 20);
- struct packet *p;
- enum ofperr error;
-
- if (id == UINT32_MAX) {
- error = 0;
- goto error;
- }
-
- if (!pb) {
- VLOG_WARN_RL(&rl, "attempt to send buffered packet via connection "
- "without buffers");
- error = OFPERR_OFPBRC_BUFFER_UNKNOWN;
- goto error;
- }
-
- p = &pb->packets[id & PKTBUF_MASK];
- if (p->cookie == id >> PKTBUF_BITS) {
- struct dp_packet *buffer = p->buffer;
- if (buffer) {
- *bufferp = buffer;
- if (in_port) {
- *in_port = p->in_port;
- }
- p->buffer = NULL;
- COVERAGE_INC(pktbuf_retrieved);
- return 0;
- } else {
- COVERAGE_INC(pktbuf_reuse_error);
- VLOG_WARN_RL(&rl, "attempt to reuse buffer %08"PRIx32, id);
- error = OFPERR_OFPBRC_BUFFER_EMPTY;
- }
- } else {
- COVERAGE_INC(pktbuf_buffer_unknown);
- VLOG_WARN_RL(&rl, "cookie mismatch: %08"PRIx32" != %08"PRIx32,
- id, (id & PKTBUF_MASK) | (p->cookie << PKTBUF_BITS));
- error = OFPERR_OFPBRC_BUFFER_UNKNOWN;
- }
-error:
- *bufferp = NULL;
- if (in_port) {
- *in_port = OFPP_NONE;
- }
- return error;
-}
-
-void
-pktbuf_discard(struct pktbuf *pb, uint32_t id)
-{
- struct packet *p = &pb->packets[id & PKTBUF_MASK];
- if (p->cookie == id >> PKTBUF_BITS) {
- dp_packet_delete(p->buffer);
- p->buffer = NULL;
- }
-}
-
-/* Returns the number of packets buffered in 'pb'. Returns 0 if 'pb' is
- * null. */
-unsigned int
-pktbuf_count_packets(const struct pktbuf *pb)
-{
- int n = 0;
-
- if (pb) {
- int i;
-
- for (i = 0; i < PKTBUF_CNT; i++) {
- if (pb->packets[i].buffer) {
- n++;
- }
- }
- }
-
- return n;
-}
diff --git a/lib/pktbuf.h b/lib/pktbuf.h
deleted file mode 100644
index ccbaed779..000000000
--- a/lib/pktbuf.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2008, 2009, 2011, 2012, 2016 Nicira, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef PKTBUF_H
-#define PKTBUF_H 1
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "openvswitch/ofp-errors.h"
-
-struct pktbuf;
-struct dp_packet;
-
-int pktbuf_capacity(void);
-
-struct pktbuf *pktbuf_create(void);
-void pktbuf_destroy(struct pktbuf *);
-uint32_t pktbuf_save(struct pktbuf *, const void *buffer, size_t buffer_size,
- ofp_port_t in_port);
-enum ofperr pktbuf_retrieve(struct pktbuf *, uint32_t id,
- struct dp_packet **bufferp, ofp_port_t *in_port);
-void pktbuf_discard(struct pktbuf *, uint32_t id);
-
-unsigned int pktbuf_count_packets(const struct pktbuf *);
-
-#endif /* pktbuf.h */
diff --git a/ofproto/bundles.c b/ofproto/bundles.c
index e8fb7ba16..353a3a730 100644
--- a/ofproto/bundles.c
+++ b/ofproto/bundles.c
@@ -32,7 +32,6 @@
#include "openvswitch/vlog.h"
#include "pinsched.h"
#include "poll-loop.h"
-#include "pktbuf.h"
#include "rconn.h"
#include "openvswitch/shash.h"
#include "simap.h"
diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
index d70d9902c..d2bedadd0 100644
--- a/ofproto/connmgr.c
+++ b/ofproto/connmgr.c
@@ -34,7 +34,6 @@
#include "openvswitch/vlog.h"
#include "pinsched.h"
#include "poll-loop.h"
-#include "pktbuf.h"
#include "rconn.h"
#include "openvswitch/shash.h"
#include "simap.h"
@@ -78,7 +77,6 @@ struct ofconn {
struct rconn_packet_counter *packet_in_counter; /* # queued on 'rconn'. */
#define N_SCHEDULERS 2
struct pinsched *schedulers[N_SCHEDULERS];
- struct pktbuf *pktbuf; /* OpenFlow packet buffers. */
int miss_send_len; /* Bytes to send of buffered packets. */
uint16_t controller_id; /* Connection controller ID. */
@@ -416,7 +414,6 @@ connmgr_get_memory_usage(const struct connmgr *mgr, struct simap *usage)
pinsched_get_stats(ofconn->schedulers[i], &stats);
packets += stats.n_queued;
}
- packets += pktbuf_count_packets(ofconn->pktbuf);
}
simap_increase(usage, "ofconns", ofconns);
simap_increase(usage, "packets", packets);
@@ -694,7 +691,6 @@ add_controller(struct connmgr *mgr, const char *target, uint8_t dscp,
ofconn = ofconn_create(mgr, rconn_create(5, 8, dscp, allowed_versions),
OFCONN_PRIMARY, true);
- ofconn->pktbuf = pktbuf_create();
rconn_connect(ofconn->rconn, target, name);
hmap_insert(&mgr->controllers, &ofconn->hmap_node, hash_string(target, 0));
@@ -1113,14 +1109,6 @@ ofconn_send_error(const struct ofconn *ofconn,
ofconn_send_reply(ofconn, reply);
}
-/* Same as pktbuf_retrieve(), using the pktbuf owned by 'ofconn'. */
-enum ofperr
-ofconn_pktbuf_retrieve(struct ofconn *ofconn, uint32_t id,
- struct dp_packet **bufferp, ofp_port_t *in_port)
-{
- return pktbuf_retrieve(ofconn->pktbuf, id, bufferp, in_port);
-}
-
/* Reports that a flow_mod operation of the type specified by 'command' was
* successfully executed by 'ofconn', so that the connmgr can log it. */
void
@@ -1261,10 +1249,6 @@ ofconn_flush(struct ofconn *ofconn)
ofconn->schedulers[i] = pinsched_create(rate, burst);
}
}
- if (ofconn->pktbuf) {
- pktbuf_destroy(ofconn->pktbuf);
- ofconn->pktbuf = pktbuf_create();
- }
ofconn->miss_send_len = (ofconn->type == OFCONN_PRIMARY
? OFP_DEFAULT_MISS_SEND_LEN
: 0);
@@ -1308,7 +1292,6 @@ ofconn_destroy(struct ofconn *ofconn)
rconn_destroy(ofconn->rconn);
rconn_packet_counter_destroy(ofconn->packet_in_counter);
rconn_packet_counter_destroy(ofconn->reply_counter);
- pktbuf_destroy(ofconn->pktbuf);
rconn_packet_counter_destroy(ofconn->monitor_counter);
free(ofconn);
}
@@ -1695,9 +1678,7 @@ connmgr_send_async_msg(struct connmgr *mgr,
}
struct ofpbuf *msg = ofputil_encode_packet_in_private(
- &am->pin.up, protocol, ofconn->packet_in_format,
- am->pin.max_len >= 0 ? am->pin.max_len : ofconn->miss_send_len,
- ofconn->pktbuf);
+ &am->pin.up, protocol, ofconn->packet_in_format);
struct ovs_list txq;
bool is_miss = (am->pin.up.public.reason == OFPR_NO_MATCH ||
diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h
index be4ce2894..0768aa0bf 100644
--- a/ofproto/connmgr.h
+++ b/ofproto/connmgr.h
@@ -128,9 +128,6 @@ void ofconn_send_replies(const struct ofconn *, struct ovs_list *);
void ofconn_send_error(const struct ofconn *, const struct ofp_header *request,
enum ofperr);
-enum ofperr ofconn_pktbuf_retrieve(struct ofconn *, uint32_t id,
- struct dp_packet **bufferp, ofp_port_t *in_port);
-
struct ofp_bundle;
struct ofp_bundle *ofconn_get_bundle(struct ofconn *, uint32_t id);
diff --git a/ofproto/fail-open.c b/ofproto/fail-open.c
index d8ec2131e..3c3579ef1 100644
--- a/ofproto/fail-open.c
+++ b/ofproto/fail-open.c
@@ -31,7 +31,6 @@
#include "openvswitch/vlog.h"
#include "ofproto.h"
#include "ofproto-provider.h"
-#include "pktbuf.h"
#include "poll-loop.h"
#include "rconn.h"
#include "timeval.h"
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index fd2c2bde2..289e7d65d 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -4247,24 +4247,6 @@ rule_get_stats(struct rule *rule_, uint64_t *packets, uint64_t *bytes,
ovs_mutex_unlock(&rule->stats_mutex);
}
-static void
-rule_dpif_execute(struct rule_dpif *rule, const struct flow *flow,
- struct dp_packet *packet)
-{
- struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
-
- ofproto_dpif_execute_actions(ofproto, flow, rule, NULL, 0, packet);
-}
-
-static enum ofperr
-rule_execute(struct rule *rule, const struct flow *flow,
- struct dp_packet *packet)
-{
- rule_dpif_execute(rule_dpif_cast(rule), flow, packet);
- dp_packet_delete(packet);
- return 0;
-}
-
static struct group_dpif *group_dpif_cast(const struct ofgroup *group)
{
return group ? CONTAINER_OF(group, struct group_dpif, up) : NULL;
@@ -5542,6 +5524,7 @@ ofproto_dpif_add_internal_flow(struct ofproto_dpif *ofproto,
int error;
fm = (struct ofputil_flow_mod) {
+ .buffer_id = UINT32_MAX,
.match = *match,
.priority = priority,
.table_id = TBL_INTERNAL,
@@ -5580,6 +5563,7 @@ ofproto_dpif_delete_internal_flow(struct ofproto_dpif *ofproto,
int error;
fm = (struct ofputil_flow_mod) {
+ .buffer_id = UINT32_MAX,
.match = *match,
.priority = priority,
.table_id = TBL_INTERNAL,
@@ -5648,7 +5632,6 @@ const struct ofproto_class ofproto_dpif_class = {
rule_destruct,
rule_dealloc,
rule_get_stats,
- rule_execute,
set_frag_handling,
packet_out,
nxt_resume,
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index 401d1b5e6..7f7813e3d 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -115,14 +115,6 @@ struct ofproto {
/* OpenFlow connections. */
struct connmgr *connmgr;
- /* Delayed rule executions.
- *
- * We delay calls to ->ofproto_class->rule_execute() past releasing
- * ofproto_mutex during a flow_mod, because otherwise a "learn" action
- * triggered by the executing the packet would try to recursively modify
- * the flow table and reacquire the global lock. */
- struct guarded_list rule_executes; /* Contains "struct rule_execute"s. */
-
int min_mtu; /* Current MTU of non-internal ports. */
/* Groups. */
@@ -1285,25 +1277,6 @@ struct ofproto_class {
uint64_t *byte_count, long long int *used)
/* OVS_EXCLUDED(ofproto_mutex) */;
- /* Applies the actions in 'rule' to 'packet'. (This implements sending
- * buffered packets for OpenFlow OFPT_FLOW_MOD commands.)
- *
- * Takes ownership of 'packet' (so it should eventually free it, with
- * ofpbuf_delete()).
- *
- * 'flow' reflects the flow information for 'packet'. All of the
- * information in 'flow' is extracted from 'packet', except for
- * flow->tunnel and flow->in_port, which are assigned the correct values
- * for the incoming packet. The register values are zeroed. 'packet''s
- * header pointers and offsets (e.g. packet->l3) are appropriately
- * initialized. packet->l3 is aligned on a 32-bit boundary.
- *
- * The implementation should add the statistics for 'packet' into 'rule'.
- *
- * Returns 0 if successful, otherwise an OpenFlow error code. */
- enum ofperr (*rule_execute)(struct rule *rule, const struct flow *flow,
- struct dp_packet *packet);
-
/* Changes the OpenFlow IP fragment handling policy to 'frag_handling',
* which takes one of the following values, with the corresponding
* meanings:
@@ -1880,7 +1853,6 @@ struct ofproto_flow_mod {
/* Replicate needed fields from ofputil_flow_mod to not need it after the
* flow has been created. */
uint16_t command;
- uint32_t buffer_id;
bool modify_cookie;
/* Fields derived from ofputil_flow_mod. */
bool modify_may_add_flow;
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index aec483732..8c95aa0f5 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -50,7 +50,6 @@
#include "ovs-rcu.h"
#include "packets.h"
#include "pinsched.h"
-#include "pktbuf.h"
#include "poll-loop.h"
#include "random.h"
#include "seq.h"
@@ -142,20 +141,6 @@ static enum ofperr collect_rules_loose(struct ofproto *,
const struct rule_criteria *,
struct rule_collection *);
-/* A packet that needs to be passed to rule_execute().
- *
- * (We can't do this immediately from ofopgroup_complete() because that holds
- * ofproto_mutex, which rule_execute() needs released.) */
-struct rule_execute {
- struct ovs_list list_node; /* In struct ofproto's "rule_executes" list. */
- struct rule *rule; /* Owns a reference to the rule. */
- ofp_port_t in_port;
- struct dp_packet *packet; /* Owns the packet. */
-};
-
-static void run_rule_executes(struct ofproto *) OVS_EXCLUDED(ofproto_mutex);
-static void destroy_rule_executes(struct ofproto *);
-
struct learned_cookie {
union {
/* In struct ofproto's 'learned_cookies' hmap. */
@@ -264,10 +249,6 @@ static void delete_flows__(struct rule_collection *,
const struct openflow_mod_requester *)
OVS_REQUIRES(ofproto_mutex);
-static void send_buffered_packet(const struct openflow_mod_requester *,
- uint32_t buffer_id, struct rule *)
- OVS_REQUIRES(ofproto_mutex);
-
static bool ofproto_group_exists(const struct ofproto *, uint32_t group_id);
static void handle_openflow(struct ofconn *, const struct ofpbuf *);
static enum ofperr ofproto_flow_mod_init(struct ofproto *,
@@ -533,7 +514,6 @@ ofproto_create(const char *datapath_name, const char *datapath_type,
hmap_init(&ofproto->learned_cookies);
ovs_list_init(&ofproto->expirable);
ofproto->connmgr = connmgr_create(ofproto, datapath_name, datapath_name);
- guarded_list_init(&ofproto->rule_executes);
ofproto->min_mtu = INT_MAX;
cmap_init(&ofproto->groups);
ovs_mutex_unlock(&ofproto_mutex);
@@ -1556,9 +1536,6 @@ ofproto_destroy__(struct ofproto *ofproto)
{
struct oftable *table;
- destroy_rule_executes(ofproto);
-
- guarded_list_destroy(&ofproto->rule_executes);
cmap_destroy(&ofproto->groups);
hmap_remove(&all_ofprotos, &ofproto->hmap_node);
@@ -1703,8 +1680,6 @@ ofproto_run(struct ofproto *p)
VLOG_ERR_RL(&rl, "%s: run failed (%s)", p->name, ovs_strerror(error));
}
- run_rule_executes(p);
-
/* Restore the eviction group heap invariant occasionally. */
if (p->eviction_group_timer < time_msec()) {
size_t i;
@@ -3069,50 +3044,6 @@ ofproto_rule_has_out_group(const struct rule *rule, uint32_t group_id)
}
}
-static void
-rule_execute_destroy(struct rule_execute *e)
-{
- ofproto_rule_unref(e->rule);
- ovs_list_remove(&e->list_node);
- free(e);
-}
-
-/* Executes all "rule_execute" operations queued up in ofproto->rule_executes,
- * by passing them to the ofproto provider. */
-static void
-run_rule_executes(struct ofproto *ofproto)
- OVS_EXCLUDED(ofproto_mutex)
-{
- struct rule_execute *e, *next;
- struct ovs_list executes;
-
- guarded_list_pop_all(&ofproto->rule_executes, &executes);
- LIST_FOR_EACH_SAFE (e, next, list_node, &executes) {
- struct flow flow;
-
- flow_extract(e->packet, &flow);
- flow.in_port.ofp_port = e->in_port;
- ofproto->ofproto_class->rule_execute(e->rule, &flow, e->packet);
-
- rule_execute_destroy(e);
- }
-}
-
-/* Destroys and discards all "rule_execute" operations queued up in
- * ofproto->rule_executes. */
-static void
-destroy_rule_executes(struct ofproto *ofproto)
-{
- struct rule_execute *e, *next;
- struct ovs_list executes;
-
- guarded_list_pop_all(&ofproto->rule_executes, &executes);
- LIST_FOR_EACH_SAFE (e, next, list_node, &executes) {
- dp_packet_delete(e->packet);
- rule_execute_destroy(e);
- }
-}
-
static bool
rule_is_readonly(const struct rule *rule)
{
@@ -3353,7 +3284,7 @@ handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh)
query_switch_features(ofproto, &arp_match_ip, &features.ofpacts);
features.datapath_id = ofproto->datapath_id;
- features.n_buffers = pktbuf_capacity();
+ features.n_buffers = 0;
features.n_tables = ofproto_get_n_visible_tables(ofproto);
features.capabilities = (OFPUTIL_C_FLOW_STATS | OFPUTIL_C_TABLE_STATS |
OFPUTIL_C_PORT_STATS | OFPUTIL_C_QUEUE_STATS |
@@ -3502,14 +3433,11 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
/* Get payload. */
if (po.buffer_id != UINT32_MAX) {
- error = ofconn_pktbuf_retrieve(ofconn, po.buffer_id, &payload, NULL);
- if (error) {
- goto exit_free_ofpacts;
- }
- } else {
- /* Ensure that the L3 header is 32-bit aligned. */
- payload = dp_packet_clone_data_with_headroom(po.packet, po.packet_len, 2);
+ error = OFPERR_OFPBRC_BUFFER_UNKNOWN;
+ goto exit_free_ofpacts;
}
+ /* Ensure that the L3 header is 32-bit aligned. */
+ payload = dp_packet_clone_data_with_headroom(po.packet, po.packet_len, 2);
/* Verify actions against packet, then send packet if successful. */
flow_extract(payload, &flow);
@@ -4807,8 +4735,6 @@ add_flow_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
/* Send Vacancy Events for OF1.4+. */
send_table_status(ofproto, new_rule->table_id);
}
-
- send_buffered_packet(req, ofm->buffer_id, new_rule);
}
/* OFPFC_MODIFY and OFPFC_MODIFY_STRICT. */
@@ -5107,10 +5033,7 @@ modify_flows_init_loose(struct ofproto *ofproto,
}
/* Implements OFPFC_MODIFY. Returns 0 on success or an OpenFlow error code on
- * failure.
- *
- * 'ofconn' is used to retrieve the packet buffer specified in ofm->buffer_id,
- * if any. */
+ * failure. */
static enum ofperr
modify_flows_start_loose(struct ofproto *ofproto, struct ofproto_flow_mod *ofm)
OVS_REQUIRES(ofproto_mutex)
@@ -5173,9 +5096,6 @@ modify_flows_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
}
learned_cookies_flush(ofproto, &dead_cookies);
remove_rules_postponed(old_rules);
-
- send_buffered_packet(req, ofm->buffer_id,
- rule_collection_rules(new_rules)[0]);
rule_collection_destroy(new_rules);
}
}
@@ -5520,7 +5440,6 @@ handle_flow_mod__(struct ofproto *ofproto, const struct ofputil_flow_mod *fm,
ofmonitor_flush(ofproto->connmgr);
ovs_mutex_unlock(&ofproto_mutex);
- run_rule_executes(ofproto);
return error;
}
@@ -7110,7 +7029,6 @@ ofproto_flow_mod_init(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
/* Forward flow mod fields we need later. */
ofm->command = fm->command;
- ofm->buffer_id = fm->buffer_id;
ofm->modify_cookie = fm->modify_cookie;
ofm->modify_may_add_flow = (fm->new_cookie != OVS_BE64_MAX
@@ -7122,14 +7040,19 @@ ofproto_flow_mod_init(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
ofm->conjs = NULL;
ofm->n_conjs = 0;
+ bool check_buffer_id = false;
+
switch (ofm->command) {
case OFPFC_ADD:
+ check_buffer_id = true;
error = add_flow_init(ofproto, ofm, fm);
break;
case OFPFC_MODIFY:
+ check_buffer_id = true;
error = modify_flows_init_loose(ofproto, ofm, fm);
break;
case OFPFC_MODIFY_STRICT:
+ check_buffer_id = true;
error = modify_flow_init_strict(ofproto, ofm, fm);
break;
case OFPFC_DELETE:
@@ -7142,6 +7065,10 @@ ofproto_flow_mod_init(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
error = OFPERR_OFPFMFC_BAD_COMMAND;
break;
}
+ if (!error && check_buffer_id && fm->buffer_id != UINT32_MAX) {
+ error = OFPERR_OFPBRC_BUFFER_UNKNOWN;
+ }
+
if (error) {
ofproto_flow_mod_uninit(ofm);
}
@@ -7381,8 +7308,6 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags)
ofmonitor_flush(ofproto->connmgr);
ovs_mutex_unlock(&ofproto_mutex);
-
- run_rule_executes(ofproto);
}
/* The bundle is discarded regardless the outcome. */
@@ -7751,43 +7676,6 @@ handle_openflow(struct ofconn *ofconn, const struct ofpbuf *ofp_msg)
COVERAGE_INC(ofproto_recv_openflow);
}
-/* Asynchronous operations. */
-
-static void
-send_buffered_packet(const struct openflow_mod_requester *req,
- uint32_t buffer_id, struct rule *rule)
- OVS_REQUIRES(ofproto_mutex)
-{
- if (req && req->ofconn && buffer_id != UINT32_MAX) {
- struct ofproto *ofproto = ofconn_get_ofproto(req->ofconn);
- struct dp_packet *packet;
- ofp_port_t in_port;
- enum ofperr error;
-
- error = ofconn_pktbuf_retrieve(req->ofconn, buffer_id, &packet,
- &in_port);
- if (packet) {
- struct rule_execute *re;
-
- ofproto_rule_ref(rule);
-
- re = xmalloc(sizeof *re);
- re->rule = rule;
- re->in_port = in_port;
- re->packet = packet;
-
- if (!guarded_list_push_back(&ofproto->rule_executes,
- &re->list_node, 1024)) {
- ofproto_rule_unref(rule);
- dp_packet_delete(re->packet);
- free(re);
- }
- } else {
- ofconn_send_error(req->ofconn, req->request, error);
- }
- }
-}
-
static uint64_t
pick_datapath_id(const struct ofproto *ofproto)
{
diff --git a/tests/ofproto.at b/tests/ofproto.at
index 147ac23ca..a849c4312 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -34,7 +34,7 @@ OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -vwarn show br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPT_FEATURES_REPLY: dpid:fedcba9876543210
-n_tables:254, n_buffers:256
+n_tables:254, n_buffers:0
capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
LOCAL(br0): addr:aa:55:aa:55:00:00
@@ -56,7 +56,7 @@ s/ (xid=0x[0-9a-fA-F]*)//
s/00:0.$/00:0x/' < stdout]],
[0], [dnl
OFPT_FEATURES_REPLY: dpid:fedcba9876543210
-n_tables:254, n_buffers:256
+n_tables:254, n_buffers:0
capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
1(p1): addr:aa:55:aa:55:00:0x
@@ -1174,7 +1174,7 @@ do
AT_CHECK([ovs-ofctl -vwarn show br0], [0], [stdout])
AT_CHECK_UNQUOTED([strip_xids < stdout], [0], [dnl
OFPT_FEATURES_REPLY: dpid:fedcba9876543210
-n_tables:254, n_buffers:256
+n_tables:254, n_buffers:0
capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
LOCAL(br0): addr:aa:55:aa:55:00:00
@@ -1206,7 +1206,7 @@ do
AT_CHECK([ovs-ofctl -O OpenFlow12 -vwarn show br0], [0], [stdout])
AT_CHECK_UNQUOTED([strip_xids < stdout], [0], [dnl
OFPT_FEATURES_REPLY (OF1.2): dpid:fedcba9876543210
-n_tables:254, n_buffers:256
+n_tables:254, n_buffers:0
capabilities: FLOW_STATS TABLE_STATS PORT_STATS GROUP_STATS QUEUE_STATS
LOCAL(br0): addr:aa:55:aa:55:00:00
config: $config
@@ -1237,7 +1237,7 @@ do
AT_CHECK([ovs-ofctl -O OpenFlow14 -vwarn show br0], [0], [stdout])
AT_CHECK_UNQUOTED([strip_xids < stdout], [0], [dnl
OFPT_FEATURES_REPLY (OF1.4): dpid:fedcba9876543210
-n_tables:254, n_buffers:256
+n_tables:254, n_buffers:0
capabilities: FLOW_STATS TABLE_STATS PORT_STATS GROUP_STATS QUEUE_STATS
OFPST_PORT_DESC reply (OF1.4):
LOCAL(br0): addr:aa:55:aa:55:00:00
diff --git a/tutorial/OVN-Tutorial.md b/tutorial/OVN-Tutorial.md
index 65e4ea2bf..5ae8ed5be 100644
--- a/tutorial/OVN-Tutorial.md
+++ b/tutorial/OVN-Tutorial.md
@@ -144,7 +144,7 @@ OpenFlow port number of `1`. Similarly, `lport2` has an OpenFlow port number of
$ ovs-ofctl show br-int
OFPT_FEATURES_REPLY (xid=0x2): dpid:00003e1ba878364d
- n_tables:254, n_buffers:256
+ n_tables:254, n_buffers:0
capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
1(lport1): addr:aa:55:aa:55:00:07
@@ -624,7 +624,7 @@ We get those port numbers using `ovs-ofctl`:
$ ovs-ofctl show br-int
OFPT_FEATURES_REPLY (xid=0x2): dpid:00002a84824b0d40
- n_tables:254, n_buffers:256
+ n_tables:254, n_buffers:0
capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst
1(ovn-fakech-0): addr:aa:55:aa:55:00:0e
diff --git a/vswitchd/ovs-vswitchd.8.in b/vswitchd/ovs-vswitchd.8.in
index 3dacfc34b..01b998c90 100644
--- a/vswitchd/ovs-vswitchd.8.in
+++ b/vswitchd/ovs-vswitchd.8.in
@@ -285,10 +285,7 @@ documentation, both the amount of available buffering, and the length
of time before buffers may be reused.
.
.PP
-Open vSwitch maintains a separate set of 256 packet buffers for each
-OpenFlow connection. Any given packet buffer is preserved until it is
-referenced by an \fBOFPT_FLOW_MOD\fR or \fBOFPT_PACKET_OUT\fR request
-or for 5 seconds, whichever comes first.
+Open vSwitch does not maintains any packet buffers.
.
.SH "LIMITS"
.