diff options
-rw-r--r-- | FAQ.md | 64 | ||||
-rw-r--r-- | include/openvswitch/ofp-util.h | 4 | ||||
-rw-r--r-- | lib/automake.mk | 2 | ||||
-rw-r--r-- | lib/ofp-util.c | 80 | ||||
-rw-r--r-- | lib/pktbuf.c | 220 | ||||
-rw-r--r-- | lib/pktbuf.h | 40 | ||||
-rw-r--r-- | ofproto/bundles.c | 1 | ||||
-rw-r--r-- | ofproto/connmgr.c | 21 | ||||
-rw-r--r-- | ofproto/connmgr.h | 3 | ||||
-rw-r--r-- | ofproto/fail-open.c | 1 | ||||
-rw-r--r-- | ofproto/ofproto-dpif.c | 21 | ||||
-rw-r--r-- | ofproto/ofproto-provider.h | 28 | ||||
-rw-r--r-- | ofproto/ofproto.c | 142 | ||||
-rw-r--r-- | tests/ofproto.at | 10 | ||||
-rw-r--r-- | tutorial/OVN-Tutorial.md | 4 | ||||
-rw-r--r-- | vswitchd/ovs-vswitchd.8.in | 5 |
16 files changed, 66 insertions, 580 deletions
@@ -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" . |