-
Notifications
You must be signed in to change notification settings - Fork 5.5k
connection: tighten network connection buffer limits #14333
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
ggreenway
merged 8 commits into
envoyproxy:master
from
antoniovicente:network_connection_watermarks
Jan 14, 2021
Merged
Changes from 5 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
eab8734
Tighten ConnectionImpl watermark tests
antoniovicente 918c53b
tighten network connection buffer limits
antoniovicente ecac94a
adjust test expectations
antoniovicente 22ce683
fix test after merge
antoniovicente c5cff0c
Merge remote-tracking branch 'upstream/master' into network_connectio…
antoniovicente 212054d
fix typo
antoniovicente 10da10d
Merge remote-tracking branch 'upstream/master' into network_connectio…
antoniovicente ba6b3be
add release note
antoniovicente File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -981,38 +981,55 @@ TEST_P(ConnectionImplTest, ReadWatermarks) { | |
| }; | ||
|
|
||
| EXPECT_FALSE(testClientConnection()->readBuffer().highWatermarkTriggered()); | ||
| EXPECT_FALSE(testClientConnection()->shouldDrainReadBuffer()); | ||
| EXPECT_TRUE(client_connection_->readEnabled()); | ||
| // Add 4 bytes to the buffer and verify the connection becomes read disabled. | ||
| // Add 3 bytes to the buffer so that it sits at exactly the read limit. Verify that | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "2 bytes" |
||
| // shouldDrainReadBuffer is true, but the connection remains read enabled. | ||
| { | ||
| Buffer::OwnedImpl buffer("data"); | ||
| Buffer::OwnedImpl buffer("12"); | ||
| server_connection_->write(buffer, false); | ||
| EXPECT_CALL(*client_read_filter, onData(_, false)).WillOnce(Invoke(on_filter_data_exit)); | ||
| dispatcher_->run(Event::Dispatcher::RunType::Block); | ||
|
|
||
| EXPECT_TRUE(testClientConnection()->shouldDrainReadBuffer()); | ||
| EXPECT_FALSE(testClientConnection()->readBuffer().highWatermarkTriggered()); | ||
| EXPECT_TRUE(client_connection_->readEnabled()); | ||
| } | ||
| // Add 1 bytes to the buffer to go over the high watermark. Verify the connection becomes read | ||
| // disabled. | ||
| { | ||
| Buffer::OwnedImpl buffer("3"); | ||
| server_connection_->write(buffer, false); | ||
| EXPECT_CALL(*client_read_filter, onData(_, false)).WillOnce(Invoke(on_filter_data_exit)); | ||
| dispatcher_->run(Event::Dispatcher::RunType::Block); | ||
|
|
||
| EXPECT_TRUE(testClientConnection()->readBuffer().highWatermarkTriggered()); | ||
| EXPECT_TRUE(testClientConnection()->shouldDrainReadBuffer()); | ||
| EXPECT_FALSE(client_connection_->readEnabled()); | ||
| } | ||
|
|
||
| // Drain 3 bytes from the buffer. This bring sit below the low watermark, and | ||
| // Drain 2 bytes from the buffer. This bring sit below the low watermark, and | ||
| // read enables, as well as triggering a kick for the remaining byte. | ||
| { | ||
| testClientConnection()->readBuffer().drain(3); | ||
| testClientConnection()->readBuffer().drain(2); | ||
| EXPECT_FALSE(testClientConnection()->readBuffer().highWatermarkTriggered()); | ||
| EXPECT_FALSE(testClientConnection()->shouldDrainReadBuffer()); | ||
| EXPECT_TRUE(client_connection_->readEnabled()); | ||
|
|
||
| EXPECT_CALL(*client_read_filter, onData(_, false)); | ||
| dispatcher_->run(Event::Dispatcher::RunType::NonBlock); | ||
| } | ||
|
|
||
| // Add 3 bytes to the buffer and verify the connection becomes read disabled | ||
| // Add 2 bytes to the buffer and verify the connection becomes read disabled | ||
| // again. | ||
| { | ||
| Buffer::OwnedImpl buffer("bye"); | ||
| Buffer::OwnedImpl buffer("45"); | ||
| server_connection_->write(buffer, false); | ||
| EXPECT_CALL(*client_read_filter, onData(_, false)).WillOnce(Invoke(on_filter_data_exit)); | ||
| dispatcher_->run(Event::Dispatcher::RunType::Block); | ||
|
|
||
| EXPECT_TRUE(testClientConnection()->readBuffer().highWatermarkTriggered()); | ||
| EXPECT_TRUE(testClientConnection()->shouldDrainReadBuffer()); | ||
| EXPECT_FALSE(client_connection_->readEnabled()); | ||
| } | ||
|
|
||
|
|
@@ -1021,8 +1038,9 @@ TEST_P(ConnectionImplTest, ReadWatermarks) { | |
| // does not want to read. | ||
| { | ||
| client_connection_->readDisable(true); | ||
| testClientConnection()->readBuffer().drain(3); | ||
| testClientConnection()->readBuffer().drain(2); | ||
| EXPECT_FALSE(testClientConnection()->readBuffer().highWatermarkTriggered()); | ||
| EXPECT_FALSE(testClientConnection()->shouldDrainReadBuffer()); | ||
| EXPECT_FALSE(client_connection_->readEnabled()); | ||
|
|
||
| EXPECT_CALL(*client_read_filter, onData(_, false)).Times(0); | ||
|
|
@@ -1058,6 +1076,7 @@ TEST_P(ConnectionImplTest, ReadWatermarks) { | |
| })); | ||
| dispatcher_->run(Event::Dispatcher::RunType::Block); | ||
| EXPECT_TRUE(testClientConnection()->readBuffer().highWatermarkTriggered()); | ||
| EXPECT_TRUE(testClientConnection()->shouldDrainReadBuffer()); | ||
| EXPECT_FALSE(client_connection_->readEnabled()); | ||
|
|
||
| // Read disable and read enable, to set dispatch_buffered_data_ true. | ||
|
|
@@ -1217,7 +1236,7 @@ TEST_P(ConnectionImplTest, WatermarkFuzzing) { | |
| // If the current bytes buffered plus the bytes we write this loop go over | ||
| // the watermark and we're not currently above, we will get a callback for | ||
| // going above. | ||
| if (bytes_to_write + bytes_buffered > 11 && is_below) { | ||
| if (bytes_to_write + bytes_buffered > 10 && is_below) { | ||
| ENVOY_LOG_MISC(trace, "Expect onAboveWriteBufferHighWatermark"); | ||
| EXPECT_CALL(client_callbacks_, onAboveWriteBufferHighWatermark()); | ||
| is_below = false; | ||
|
|
@@ -2002,17 +2021,41 @@ TEST_F(MockTransportConnectionImplTest, ReadBufferResumeAfterReadDisable) { | |
| connection_->enableHalfClose(true); | ||
| connection_->addReadFilter(read_filter); | ||
|
|
||
| // Add some data to the read buffer to trigger read activate calls when re-enabling read. | ||
| EXPECT_CALL(*transport_socket_, doRead(_)) | ||
| .WillOnce(Invoke([](Buffer::Instance& buffer) -> IoResult { | ||
| buffer.add("0123456789"); | ||
| return {PostIoAction::KeepOpen, 10, false}; | ||
| buffer.add("0123"); | ||
| return {PostIoAction::KeepOpen, 4, false}; | ||
| })); | ||
| // Expect a change to the event mask when hitting the read buffer high-watermark. | ||
| EXPECT_CALL(*file_event_, setEnabled(Event::FileReadyType::Write)); | ||
| // Buffer is under the read limit, expect no changes to the file event registration. | ||
| EXPECT_CALL(*file_event_, setEnabled(_)).Times(0); | ||
| EXPECT_CALL(*read_filter, onNewConnection()).WillOnce(Return(FilterStatus::Continue)); | ||
| EXPECT_CALL(*read_filter, onData(_, false)).WillOnce(Return(FilterStatus::Continue)); | ||
| file_ready_cb_(Event::FileReadyType::Read); | ||
| EXPECT_FALSE(connection_->shouldDrainReadBuffer()); | ||
|
|
||
| // Do a second read to hit the read limit. | ||
| EXPECT_CALL(*transport_socket_, doRead(_)) | ||
| .WillOnce(Invoke([](Buffer::Instance& buffer) -> IoResult { | ||
| buffer.add("4"); | ||
| return {PostIoAction::KeepOpen, 1, false}; | ||
| })); | ||
| // Buffer is exactly at the read limit, expect no changes to the file event registration. | ||
| EXPECT_CALL(*file_event_, setEnabled(_)).Times(0); | ||
| EXPECT_CALL(*read_filter, onData(_, false)).WillOnce(Return(FilterStatus::Continue)); | ||
| file_ready_cb_(Event::FileReadyType::Read); | ||
| EXPECT_TRUE(connection_->shouldDrainReadBuffer()); | ||
|
|
||
| // Do a third read to trigger the high watermark. | ||
| EXPECT_CALL(*transport_socket_, doRead(_)) | ||
| .WillOnce(Invoke([](Buffer::Instance& buffer) -> IoResult { | ||
| buffer.add("5"); | ||
| return {PostIoAction::KeepOpen, 1, false}; | ||
| })); | ||
| // Expect a change to the event mask when going over the read limit. | ||
| EXPECT_CALL(*file_event_, setEnabled(Event::FileReadyType::Write)); | ||
| EXPECT_CALL(*read_filter, onData(_, false)).WillOnce(Return(FilterStatus::Continue)); | ||
| file_ready_cb_(Event::FileReadyType::Read); | ||
| EXPECT_TRUE(connection_->shouldDrainReadBuffer()); | ||
|
|
||
| // Already read disabled, expect no changes to enabled events mask. | ||
| EXPECT_CALL(*file_event_, setEnabled(_)).Times(0); | ||
|
|
@@ -2030,7 +2073,7 @@ TEST_F(MockTransportConnectionImplTest, ReadBufferResumeAfterReadDisable) { | |
| EXPECT_CALL(*transport_socket_, doRead(_)).Times(0); | ||
| EXPECT_CALL(*read_filter, onData(_, _)) | ||
| .WillRepeatedly(Invoke([&](Buffer::Instance& data, bool) -> FilterStatus { | ||
| EXPECT_EQ(10, data.length()); | ||
| EXPECT_EQ(6, data.length()); | ||
| data.drain(data.length() - 1); | ||
| return FilterStatus::Continue; | ||
| })); | ||
|
|
@@ -2039,6 +2082,7 @@ TEST_F(MockTransportConnectionImplTest, ReadBufferResumeAfterReadDisable) { | |
| EXPECT_CALL(*file_event_, setEnabled(Event::FileReadyType::Read | Event::FileReadyType::Write)); | ||
| EXPECT_CALL(*file_event_, activate(Event::FileReadyType::Read)); | ||
| file_ready_cb_(Event::FileReadyType::Read); | ||
| EXPECT_FALSE(connection_->shouldDrainReadBuffer()); | ||
|
|
||
| // Drain the rest of the buffer and verify there are no spurious read activate calls. | ||
| EXPECT_CALL(*transport_socket_, doRead(_)) | ||
|
|
@@ -2050,6 +2094,7 @@ TEST_F(MockTransportConnectionImplTest, ReadBufferResumeAfterReadDisable) { | |
| return FilterStatus::Continue; | ||
| })); | ||
| file_ready_cb_(Event::FileReadyType::Read); | ||
| EXPECT_FALSE(connection_->shouldDrainReadBuffer()); | ||
|
|
||
| EXPECT_CALL(*file_event_, setEnabled(_)); | ||
| connection_->readDisable(true); | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should mention that the +1 on the limit can result in a uint32_t overflow. One example where this happens is source/extensions/filters/network/dubbo_proxy/conn_manager.cc which passes in UINT32_MAX to setBufferLimits. It may also happen based on config.
I expect this overflow to be handled fine, but it is not explicitly covered by tests.