summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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"
.