Skip to content

Commit c184807

Browse files
author
Jarno Rajahalme
committed
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>
1 parent 88e6299 commit c184807

File tree

16 files changed

+66
-580
lines changed

16 files changed

+66
-580
lines changed

FAQ.md

Lines changed: 15 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1970,55 +1970,21 @@ A: Reconfiguring your bridge can change your bridge's datapath-id because
19701970

19711971
ovs-vsctl set bridge br0 other-config:datapath-id=0123456789abcdef
19721972

1973-
### Q: My controller is getting errors about "buffers". What's going on?
1974-
1975-
A: When a switch sends a packet to an OpenFlow controller using a
1976-
"packet-in" message, it can also keep a copy of that packet in a
1977-
"buffer", identified by a 32-bit integer "buffer_id". There are
1978-
two advantages to buffering. First, when the controller wants to
1979-
tell the switch to do something with the buffered packet (with a
1980-
"packet-out" OpenFlow request), it does not need to send another
1981-
copy of the packet back across the OpenFlow connection, which
1982-
reduces the bandwidth cost of the connection and improves latency.
1983-
This enables the second advantage: the switch can optionally send
1984-
only the first part of the packet to the controller (assuming that
1985-
the switch only needs to look at the first few bytes of the
1986-
packet), further reducing bandwidth and improving latency.
1987-
1988-
However, buffering introduces some issues of its own. First, any
1989-
switch has limited resources, so if the controller does not use a
1990-
buffered packet, the switch has to decide how long to keep it
1991-
buffered. When many packets are sent to a controller and buffered,
1992-
Open vSwitch can discard buffered packets that the controller has
1993-
not used after as little as 5 seconds. This means that
1994-
controllers, if they make use of packet buffering, should use the
1995-
buffered packets promptly. (This includes sending a "packet-out"
1996-
with no actions if the controller does not want to do anything with
1997-
a buffered packet, to clear the packet buffer and effectively
1998-
"drop" its packet.)
1999-
2000-
Second, packet buffers are one-time-use, meaning that a controller
2001-
cannot use a single packet buffer in two or more "packet-out"
2002-
commands. Open vSwitch will respond with an error to the second
2003-
and subsequent "packet-out"s in such a case.
2004-
2005-
Finally, a common error early in controller development is to try
2006-
to use buffer_id 0 in a "packet-out" message as if 0 represented
2007-
"no buffered packet". This is incorrect usage: the buffer_id with
2008-
this meaning is actually 0xffffffff.
2009-
2010-
ovs-vswitchd(8) describes some details of Open vSwitch packet
2011-
buffering that the OpenFlow specification requires implementations
2012-
to document.
2013-
2014-
Note that the packet buffering support is deprecated in OVS 2.6
2015-
release, and will be removed in OVS 2.7. After the change OVS
2016-
always sends the 'buffer_id' as 0xffffffff in "packet-in" messages
2017-
and will send an error response if any other value of this field is
2018-
included in "packet-out" and "flow mod" sent by a controller.
2019-
Controllers are already expected to work properly in cases where
2020-
the switch can not buffer packets, so this change should not affect
2021-
existing users.
1973+
### Q: My controller complains that OVS is not buffering packets.
1974+
What's going on?
1975+
1976+
A: "Packet buffering" is an optional OpenFlow feature, and controllers
1977+
should detect how many "buffers" an OpenFlow switch implements. It
1978+
was recently noticed that OVS implementation of the buffering
1979+
feature was not compliant to OpenFlow specifications. Rather than
1980+
fix it and risk controller incompatibility, the buffering feature
1981+
is removed as of OVS 2.7. Controllers are already expected to work
1982+
properly in cases where the switch can not buffer packets, but
1983+
sends full packets in "packet-in" messages instead, so this change
1984+
should not affect existing users. After the change OVS always
1985+
sends the 'buffer_id' as 0xffffffff in "packet-in" messages and
1986+
will send an error response if any other value of this field is
1987+
included in a "packet-out" or a "flow mod" sent by a controller.
20221988

20231989
### Q: How does OVS divide flows among buckets in an OpenFlow "select" group?
20241990

include/openvswitch/ofp-util.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
struct ofpbuf;
3737
union ofp_action;
3838
struct ofpact_set_field;
39-
struct pktbuf;
4039

4140
/* Port numbers. */
4241
enum ofperr ofputil_port_from_ofp11(ovs_be32 ofp11_port,
@@ -498,8 +497,7 @@ struct ofputil_packet_in_private {
498497
struct ofpbuf *ofputil_encode_packet_in_private(
499498
const struct ofputil_packet_in_private *,
500499
enum ofputil_protocol protocol,
501-
enum nx_packet_in_format,
502-
uint16_t max_len, struct pktbuf *);
500+
enum nx_packet_in_format);
503501

504502
enum ofperr ofputil_decode_packet_in_private(
505503
const struct ofp_header *, bool loose,

lib/automake.mk

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,6 @@ lib_libopenvswitch_la_SOURCES = \
201201
lib/pcap-file.h \
202202
lib/perf-counter.h \
203203
lib/perf-counter.c \
204-
lib/pktbuf.c \
205-
lib/pktbuf.h \
206204
lib/poll-loop.c \
207205
lib/poll-loop.h \
208206
lib/process.c \

lib/ofp-util.c

Lines changed: 24 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
#include "openvswitch/vlog.h"
4646
#include "openflow/intel-ext.h"
4747
#include "packets.h"
48-
#include "pktbuf.h"
4948
#include "random.h"
5049
#include "tun-metadata.h"
5150
#include "unaligned.h"
@@ -3588,17 +3587,14 @@ encode_packet_in_reason(enum ofp_packet_in_reason reason,
35883587
* function omits it. The caller can add it itself if desired. */
35893588
static void
35903589
ofputil_put_packet_in(const struct ofputil_packet_in *pin,
3591-
enum ofp_version version, uint32_t buffer_id,
3592-
size_t include_bytes, struct ofpbuf *msg)
3590+
enum ofp_version version, size_t include_bytes,
3591+
struct ofpbuf *msg)
35933592
{
35943593
/* Add packet properties. */
35953594
ofpprop_put(msg, NXPINT_PACKET, pin->packet, include_bytes);
35963595
if (include_bytes != pin->packet_len) {
35973596
ofpprop_put_u32(msg, NXPINT_FULL_LEN, pin->packet_len);
35983597
}
3599-
if (buffer_id != UINT32_MAX) {
3600-
ofpprop_put_u32(msg, NXPINT_BUFFER_ID, buffer_id);
3601-
}
36023598

36033599
/* Add flow properties. */
36043600
ofpprop_put_u8(msg, NXPINT_TABLE_ID, pin->table_id);
@@ -3642,11 +3638,10 @@ enum nx_continuation_prop_type {
36423638
* function omits it. The caller can add it itself if desired. */
36433639
static void
36443640
ofputil_put_packet_in_private(const struct ofputil_packet_in_private *pin,
3645-
enum ofp_version version, uint32_t buffer_id,
3646-
size_t include_bytes, struct ofpbuf *msg)
3641+
enum ofp_version version, size_t include_bytes,
3642+
struct ofpbuf *msg)
36473643
{
3648-
ofputil_put_packet_in(&pin->public, version, buffer_id,
3649-
include_bytes, msg);
3644+
ofputil_put_packet_in(&pin->public, version, include_bytes, msg);
36503645

36513646
size_t continuation_ofs = ofpprop_start_nested(msg, NXPINT_CONTINUATION);
36523647
size_t inner_ofs = msg->size;
@@ -3734,8 +3729,7 @@ ofputil_put_packet_in_private(const struct ofputil_packet_in_private *pin,
37343729
}
37353730

37363731
static struct ofpbuf *
3737-
ofputil_encode_ofp10_packet_in(const struct ofputil_packet_in *pin,
3738-
uint32_t buffer_id)
3732+
ofputil_encode_ofp10_packet_in(const struct ofputil_packet_in *pin)
37393733
{
37403734
struct ofp10_packet_in *opi;
37413735
struct ofpbuf *msg;
@@ -3746,14 +3740,14 @@ ofputil_encode_ofp10_packet_in(const struct ofputil_packet_in *pin,
37463740
opi->total_len = htons(pin->packet_len);
37473741
opi->in_port = htons(ofp_to_u16(pin->flow_metadata.flow.in_port.ofp_port));
37483742
opi->reason = encode_packet_in_reason(pin->reason, OFP10_VERSION);
3749-
opi->buffer_id = htonl(buffer_id);
3743+
opi->buffer_id = htonl(UINT32_MAX);
37503744

37513745
return msg;
37523746
}
37533747

37543748
static struct ofpbuf *
37553749
ofputil_encode_nx_packet_in(const struct ofputil_packet_in *pin,
3756-
enum ofp_version version, uint32_t buffer_id)
3750+
enum ofp_version version)
37573751
{
37583752
struct nx_packet_in *npi;
37593753
struct ofpbuf *msg;
@@ -3767,7 +3761,7 @@ ofputil_encode_nx_packet_in(const struct ofputil_packet_in *pin,
37673761
ofpbuf_put_zeros(msg, 2);
37683762

37693763
npi = msg->msg;
3770-
npi->buffer_id = htonl(buffer_id);
3764+
npi->buffer_id = htonl(UINT32_MAX);
37713765
npi->total_len = htons(pin->packet_len);
37723766
npi->reason = encode_packet_in_reason(pin->reason, version);
37733767
npi->table_id = pin->table_id;
@@ -3779,8 +3773,7 @@ ofputil_encode_nx_packet_in(const struct ofputil_packet_in *pin,
37793773

37803774
static struct ofpbuf *
37813775
ofputil_encode_nx_packet_in2(const struct ofputil_packet_in_private *pin,
3782-
enum ofp_version version, uint32_t buffer_id,
3783-
size_t include_bytes)
3776+
enum ofp_version version, size_t include_bytes)
37843777
{
37853778
/* 'extra' is just an estimate of the space required. */
37863779
size_t extra = (pin->public.packet_len
@@ -3792,7 +3785,7 @@ ofputil_encode_nx_packet_in2(const struct ofputil_packet_in_private *pin,
37923785
struct ofpbuf *msg = ofpraw_alloc_xid(OFPRAW_NXT_PACKET_IN2, version,
37933786
htonl(0), extra);
37943787

3795-
ofputil_put_packet_in_private(pin, version, buffer_id, include_bytes, msg);
3788+
ofputil_put_packet_in_private(pin, version, include_bytes, msg);
37963789
if (pin->public.userdata_len) {
37973790
ofpprop_put(msg, NXPINT_USERDATA, pin->public.userdata,
37983791
pin->public.userdata_len);
@@ -3803,16 +3796,15 @@ ofputil_encode_nx_packet_in2(const struct ofputil_packet_in_private *pin,
38033796
}
38043797

38053798
static struct ofpbuf *
3806-
ofputil_encode_ofp11_packet_in(const struct ofputil_packet_in *pin,
3807-
uint32_t buffer_id)
3799+
ofputil_encode_ofp11_packet_in(const struct ofputil_packet_in *pin)
38083800
{
38093801
struct ofp11_packet_in *opi;
38103802
struct ofpbuf *msg;
38113803

38123804
msg = ofpraw_alloc_xid(OFPRAW_OFPT11_PACKET_IN, OFP11_VERSION,
38133805
htonl(0), pin->packet_len);
38143806
opi = ofpbuf_put_zeros(msg, sizeof *opi);
3815-
opi->buffer_id = htonl(buffer_id);
3807+
opi->buffer_id = htonl(UINT32_MAX);
38163808
opi->in_port = ofputil_port_to_ofp11(
38173809
pin->flow_metadata.flow.in_port.ofp_port);
38183810
opi->in_phy_port = opi->in_port;
@@ -3825,8 +3817,7 @@ ofputil_encode_ofp11_packet_in(const struct ofputil_packet_in *pin,
38253817

38263818
static struct ofpbuf *
38273819
ofputil_encode_ofp12_packet_in(const struct ofputil_packet_in *pin,
3828-
enum ofp_version version,
3829-
uint32_t buffer_id)
3820+
enum ofp_version version)
38303821
{
38313822
enum ofpraw raw = (version >= OFP13_VERSION
38323823
? OFPRAW_OFPT13_PACKET_IN
@@ -3838,7 +3829,7 @@ ofputil_encode_ofp12_packet_in(const struct ofputil_packet_in *pin,
38383829
htonl(0), NXM_TYPICAL_LEN + 2 + pin->packet_len);
38393830

38403831
struct ofp12_packet_in *opi = ofpbuf_put_zeros(msg, sizeof *opi);
3841-
opi->buffer_id = htonl(buffer_id);
3832+
opi->buffer_id = htonl(UINT32_MAX);
38423833
opi->total_len = htons(pin->packet_len);
38433834
opi->reason = encode_packet_in_reason(pin->reason, version);
38443835
opi->table_id = pin->table_id;
@@ -3857,11 +3848,6 @@ ofputil_encode_ofp12_packet_in(const struct ofputil_packet_in *pin,
38573848
/* Converts abstract ofputil_packet_in_private 'pin' into a PACKET_IN message
38583849
* for 'protocol', using the packet-in format specified by 'packet_in_format'.
38593850
*
3860-
* If 'pkt_buf' is nonnull and 'max_len' allows the packet to be buffered, this
3861-
* function will attempt to obtain a buffer ID from 'pktbuf' and truncate the
3862-
* packet to 'max_len' bytes. Otherwise, or if 'pktbuf' doesn't have a free
3863-
* buffer, it will send the whole packet without buffering.
3864-
*
38653851
* This function is really meant only for use by ovs-vswitchd. To any other
38663852
* code, the "continuation" data, i.e. the data that is in struct
38673853
* 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,
38733859
struct ofpbuf *
38743860
ofputil_encode_packet_in_private(const struct ofputil_packet_in_private *pin,
38753861
enum ofputil_protocol protocol,
3876-
enum nx_packet_in_format packet_in_format,
3877-
uint16_t max_len, struct pktbuf *pktbuf)
3862+
enum nx_packet_in_format packet_in_format)
38783863
{
38793864
enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
38803865

3881-
/* Get buffer ID. */
3882-
ofp_port_t in_port = pin->public.flow_metadata.flow.in_port.ofp_port;
3883-
uint32_t buffer_id = (max_len != OFPCML12_NO_BUFFER && pktbuf
3884-
? pktbuf_save(pktbuf, pin->public.packet,
3885-
pin->public.packet_len, in_port)
3886-
: UINT32_MAX);
3887-
3888-
/* Calculate the number of bytes of the packet to include in the
3889-
* packet-in:
3890-
*
3891-
* - If not buffered, the whole thing.
3892-
*
3893-
* - Otherwise, no more than 'max_len' bytes. */
3894-
size_t include_bytes = (buffer_id == UINT32_MAX
3895-
? pin->public.packet_len
3896-
: MIN(max_len, pin->public.packet_len));
3897-
38983866
struct ofpbuf *msg;
38993867
switch (packet_in_format) {
39003868
case NXPIF_STANDARD:
@@ -3903,19 +3871,19 @@ ofputil_encode_packet_in_private(const struct ofputil_packet_in_private *pin,
39033871
case OFPUTIL_P_OF10_STD_TID:
39043872
case OFPUTIL_P_OF10_NXM:
39053873
case OFPUTIL_P_OF10_NXM_TID:
3906-
msg = ofputil_encode_ofp10_packet_in(&pin->public, buffer_id);
3874+
msg = ofputil_encode_ofp10_packet_in(&pin->public);
39073875
break;
39083876

39093877
case OFPUTIL_P_OF11_STD:
3910-
msg = ofputil_encode_ofp11_packet_in(&pin->public, buffer_id);
3878+
msg = ofputil_encode_ofp11_packet_in(&pin->public);
39113879
break;
39123880

39133881
case OFPUTIL_P_OF12_OXM:
39143882
case OFPUTIL_P_OF13_OXM:
39153883
case OFPUTIL_P_OF14_OXM:
39163884
case OFPUTIL_P_OF15_OXM:
39173885
case OFPUTIL_P_OF16_OXM:
3918-
msg = ofputil_encode_ofp12_packet_in(&pin->public, version, buffer_id);
3886+
msg = ofputil_encode_ofp12_packet_in(&pin->public, version);
39193887
break;
39203888

39213889
default:
@@ -3924,18 +3892,18 @@ ofputil_encode_packet_in_private(const struct ofputil_packet_in_private *pin,
39243892
break;
39253893

39263894
case NXPIF_NXT_PACKET_IN:
3927-
msg = ofputil_encode_nx_packet_in(&pin->public, version, buffer_id);
3895+
msg = ofputil_encode_nx_packet_in(&pin->public, version);
39283896
break;
39293897

39303898
case NXPIF_NXT_PACKET_IN2:
3931-
return ofputil_encode_nx_packet_in2(pin, version, buffer_id,
3932-
include_bytes);
3899+
return ofputil_encode_nx_packet_in2(pin, version,
3900+
pin->public.packet_len);
39333901

39343902
default:
39353903
OVS_NOT_REACHED();
39363904
}
39373905

3938-
ofpbuf_put(msg, pin->public.packet, include_bytes);
3906+
ofpbuf_put(msg, pin->public.packet, pin->public.packet_len);
39393907
ofpmsg_update_length(msg);
39403908
return msg;
39413909
}
@@ -4004,7 +3972,7 @@ ofputil_encode_resume(const struct ofputil_packet_in *pin,
40043972
size_t extra = pin->packet_len + NXM_TYPICAL_LEN + continuation->size;
40053973
struct ofpbuf *msg = ofpraw_alloc_xid(OFPRAW_NXT_RESUME, version,
40063974
0, extra);
4007-
ofputil_put_packet_in(pin, version, UINT32_MAX, pin->packet_len, msg);
3975+
ofputil_put_packet_in(pin, version, pin->packet_len, msg);
40083976
ofpprop_put_nested(msg, NXPINT_CONTINUATION, continuation);
40093977
ofpmsg_update_length(msg);
40103978
return msg;

0 commit comments

Comments
 (0)