Skip to content

Commit e497335

Browse files
authored
Merge pull request #1228 from fwsGonzo/dev
Bufferstore chaining to support on-demand buffer count
2 parents c456bfa + a626978 commit e497335

9 files changed

Lines changed: 105 additions & 43 deletions

File tree

api/net/buffer_store.hpp

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ namespace net
3535
**/
3636
class BufferStore {
3737
public:
38-
using buffer_t = uint8_t*;
38+
struct buffer_t
39+
{
40+
BufferStore* bufstore;
41+
uint8_t* addr;
42+
};
3943

4044
BufferStore() = delete;
4145
BufferStore(size_t num, size_t bufsize);
@@ -45,41 +49,43 @@ namespace net
4549
void release(void*);
4650

4751
/** Get size of a buffer **/
48-
inline size_t bufsize() const noexcept
52+
size_t bufsize() const noexcept
4953
{ return bufsize_; }
5054

51-
inline size_t poolsize() const noexcept
55+
size_t poolsize() const noexcept
5256
{ return poolsize_; }
5357

5458
/** Check if a buffer belongs here */
55-
inline bool is_from_pool(buffer_t addr) const noexcept
59+
bool is_from_pool(uint8_t* addr) const noexcept
5660
{ return addr >= pool_begin() and addr < pool_end(); }
5761

5862
/** Check if an address is the start of a buffer */
59-
inline bool is_buffer(buffer_t addr) const noexcept
63+
bool is_buffer(uint8_t* addr) const noexcept
6064
{ return (addr - pool_) % bufsize_ == 0; }
6165

62-
inline size_t available() const noexcept
66+
size_t available() const noexcept
6367
{ return available_.size(); }
6468

6569
/** move this bufferstore to the current CPU **/
6670
void move_to_this_cpu() noexcept;
6771

6872
private:
69-
buffer_t pool_begin() const noexcept {
73+
uint8_t* pool_begin() const noexcept {
7074
return pool_;
7175
}
72-
buffer_t pool_end() const noexcept {
76+
uint8_t* pool_end() const noexcept {
7377
return pool_begin() + poolsize_;
7478
}
75-
size_t buffer_id(buffer_t addr) const {
76-
return (addr - pool_) / bufsize_;
77-
}
79+
80+
BufferStore* get_next_bufstore();
81+
inline buffer_t get_buffer_directly() noexcept;
82+
inline void release_directly(uint8_t*);
7883

7984
size_t poolsize_;
8085
size_t bufsize_;
81-
buffer_t pool_;
82-
std::vector<buffer_t> available_;
86+
uint8_t* pool_;
87+
std::vector<uint8_t*> available_;
88+
BufferStore* next_;
8389
int cpu;
8490
static bool smp_enabled_;
8591
#ifndef INCLUDEOS_SINGLE_THREADED

src/drivers/virtionet.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ void VirtioNet::get_config() {
4444
VirtioNet::VirtioNet(hw::PCI_Device& d)
4545
: Virtio(d),
4646
Link(Link_protocol{{this, &VirtioNet::transmit}, mac()},
47-
std::max(256u, queue_size(0) * 2), 2048 /* half-page buffers */),
47+
256u, 2048 /* 256x half-page buffers */),
4848
packets_rx_{Statman::get().create(Stat::UINT64, device_name() + ".packets_rx").get_uint64()},
4949
packets_tx_{Statman::get().create(Stat::UINT64, device_name() + ".packets_tx").get_uint64()}
5050
{
@@ -119,7 +119,7 @@ VirtioNet::VirtioNet(hw::PCI_Device& d)
119119
rx_q.size() / 2, bufstore().bufsize());
120120

121121
for (int i = 0; i < rx_q.size() / 2; i++)
122-
add_receive_buffer(bufstore().get_buffer());
122+
add_receive_buffer(bufstore().get_buffer().addr);
123123

124124
// Step 4 - If there are many queues, we should negotiate the number.
125125
// Set config length, based on whether there are multiple queues
@@ -196,7 +196,7 @@ void VirtioNet::msix_recv_handler()
196196

197197
dequeued_rx++;
198198
// Requeue a new buffer
199-
add_receive_buffer(bufstore().get_buffer());
199+
add_receive_buffer(bufstore().get_buffer().addr);
200200

201201
// Stat increase packets received
202202
packets_rx_++;
@@ -270,13 +270,14 @@ VirtioNet::recv_packet(uint8_t* data, uint16_t size)
270270
net::Packet_ptr
271271
VirtioNet::create_packet(int link_offset)
272272
{
273-
auto* ptr = (net::Packet*) bufstore().get_buffer();
273+
auto buffer = bufstore().get_buffer();
274+
auto* ptr = (net::Packet*) buffer.addr;
274275

275276
new (ptr) net::Packet(
276277
sizeof(virtio_net_hdr) + link_offset,
277278
0,
278279
sizeof(virtio_net_hdr) + packet_len(),
279-
&bufstore());
280+
buffer.bufstore);
280281

281282
return net::Packet_ptr(ptr);
282283
}

src/drivers/vmxnet3.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ void vmxnet3::refill(rxring_state& rxq)
340340
(rxq.producers & vmxnet3::NUM_RX_DESC) ? 0 : VMXNET3_RXF_GEN;
341341

342342
// get a pointer to packet data
343-
auto* pkt_data = bufstore().get_buffer();
343+
auto* pkt_data = bufstore().get_buffer().addr;
344344
rxq.buffers[i] = &pkt_data[sizeof(net::Packet)];
345345

346346
// assign rx descriptor
@@ -369,8 +369,13 @@ vmxnet3::recv_packet(uint8_t* data, uint16_t size)
369369
net::Packet_ptr
370370
vmxnet3::create_packet(int link_offset)
371371
{
372-
auto* ptr = (net::Packet*) bufstore().get_buffer();
373-
new (ptr) net::Packet(frame_offset_device() + link_offset, 0 , frame_offset_device() + packet_len(), &bufstore());
372+
auto buffer = bufstore().get_buffer();
373+
auto* ptr = (net::Packet*) buffer.addr;
374+
new (ptr) net::Packet(
375+
frame_offset_device() + link_offset,
376+
0,
377+
frame_offset_device() + packet_len(),
378+
buffer.bufstore);
374379
return net::Packet_ptr(ptr);
375380
}
376381

src/kernel/irq_manager.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ static std::array<IRQ_manager, SMP_MAX_CORES> managers;
3333

3434
IRQ_manager& IRQ_manager::get(int cpuid)
3535
{
36+
#ifndef INCLUDEOS_SINGLE_THREADED
3637
return managers.at(cpuid);
38+
#else
39+
return managers[0];
40+
#endif
3741
}
3842
IRQ_manager& IRQ_manager::get()
3943
{

src/net/buffer_store.cpp

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717

1818
//#define DEBUG
1919
//#undef NO_DEBUG
20-
#include <debug>
21-
#include <cassert>
2220
#if !defined(__MACH__)
2321
#include <malloc.h>
2422
#else
@@ -27,26 +25,33 @@ extern void *memalign(size_t, size_t);
2725
#include <net/buffer_store.hpp>
2826
#include <kernel/syscalls.hpp>
2927
#include <common>
28+
#include <debug>
29+
#include <info>
30+
#include <cassert>
3031
#include <smp>
3132
#define PAGE_SIZE 0x1000
3233

34+
#define ENABLE_BUFFERSTORE_CHAIN
35+
#define BS_CHAIN_ALLOC_PACKETS 2048
36+
3337
namespace net {
3438

3539
bool BufferStore::smp_enabled_ = false;
3640

3741
BufferStore::BufferStore(size_t num, size_t bufsize) :
3842
poolsize_ {num * bufsize},
39-
bufsize_ {bufsize}
43+
bufsize_ {bufsize},
44+
next_(nullptr)
4045
{
4146
assert(num != 0);
4247
assert(bufsize != 0);
4348
const size_t DATA_SIZE = poolsize_;
4449

45-
this->pool_ = (buffer_t) memalign(PAGE_SIZE, DATA_SIZE);
50+
this->pool_ = (uint8_t*) memalign(PAGE_SIZE, DATA_SIZE);
4651
assert(this->pool_);
4752

4853
available_.reserve(num);
49-
for (buffer_t b = pool_end()-bufsize; b >= pool_begin(); b -= bufsize) {
54+
for (uint8_t* b = pool_end()-bufsize; b >= pool_begin(); b -= bufsize) {
5055
available_.push_back(b);
5156
}
5257
assert(available() == num);
@@ -61,9 +66,33 @@ namespace net {
6166
}
6267

6368
BufferStore::~BufferStore() {
69+
delete this->next_;
6470
free(this->pool_);
6571
}
6672

73+
BufferStore* BufferStore::get_next_bufstore()
74+
{
75+
#ifdef ENABLE_BUFFERSTORE_CHAIN
76+
BufferStore* parent = this;
77+
while (parent->next_ != nullptr) {
78+
parent = parent->next_;
79+
if (parent->available() != 0) return parent;
80+
}
81+
INFO("BufferStore", "Allocating %u new packets", BS_CHAIN_ALLOC_PACKETS);
82+
parent->next_ = new BufferStore(BS_CHAIN_ALLOC_PACKETS, bufsize());
83+
return parent->next_;
84+
#else
85+
return nullptr;
86+
#endif
87+
}
88+
89+
BufferStore::buffer_t BufferStore::get_buffer_directly() noexcept
90+
{
91+
auto addr = available_.back();
92+
available_.pop_back();
93+
return { this, addr };
94+
}
95+
6796
BufferStore::buffer_t BufferStore::get_buffer()
6897
{
6998
#ifndef INCLUDEOS_SINGLE_THREADED
@@ -78,7 +107,11 @@ namespace net {
78107
#ifndef INCLUDEOS_SINGLE_THREADED
79108
if (is_locked) unlock(plock);
80109
#endif
81-
panic("<BufferStore> Storage pool full! Don't know how to increase pool size yet.\n");
110+
#ifdef ENABLE_BUFFERSTORE_CHAIN
111+
return get_next_bufstore()->get_buffer_directly();
112+
#else
113+
panic("<BufferStore> Buffer pool empty! Not configured to increase pool size.\n");
114+
#endif
82115
}
83116

84117
auto addr = available_.back();
@@ -87,12 +120,12 @@ namespace net {
87120
#ifndef INCLUDEOS_SINGLE_THREADED
88121
if (is_locked) unlock(plock);
89122
#endif
90-
return addr;
123+
return { this, addr };
91124
}
92125

93126
void BufferStore::release(void* addr)
94127
{
95-
buffer_t buff = (buffer_t) addr;
128+
auto* buff = (uint8_t*) addr;
96129
debug("Release %p -> ", buff);
97130

98131
#ifndef INCLUDEOS_SINGLE_THREADED
@@ -111,6 +144,18 @@ namespace net {
111144
debug("released\n");
112145
return;
113146
}
147+
#ifdef ENABLE_BUFFERSTORE_CHAIN
148+
// try to release buffer on linked bufferstore
149+
BufferStore* ptr = next_;
150+
while (ptr != nullptr) {
151+
if (ptr->is_from_pool(buff)) {
152+
debug("released on other bufferstore\n");
153+
ptr->release_directly(buff);
154+
return;
155+
}
156+
ptr = ptr->next_;
157+
}
158+
#endif
114159
// buffer not owned by bufferstore, so just delete it?
115160
debug("deleted\n");
116161
delete[] buff;
@@ -119,6 +164,11 @@ namespace net {
119164
#endif
120165
}
121166

167+
void BufferStore::release_directly(uint8_t* buffer)
168+
{
169+
available_.push_back(buffer);
170+
}
171+
122172
void BufferStore::move_to_this_cpu() noexcept
123173
{
124174
this->cpu = SMP::cpu_id();

test/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ if ("${ARCH}" STREQUAL "")
88
set (ARCH "ARCH_X86")
99
endif("${ARCH}" STREQUAL "")
1010

11-
add_definitions(-D${ARCH})
11+
add_definitions(-D${ARCH} -DINCLUDEOS_SINGLE_THREADED)
1212

1313
set(CMAKE_CXX_STANDARD 14)
1414
set(CMAKE_C_FLAGS "-m32 -g -O0 -std=c11 -Wall -Wextra")

test/net/integration/bufstore/service.cpp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@ BufferStore bufstore_{ BUFFER_CNT, MTU };
3030

3131
auto create_packet(BufferStore& bufstore) {
3232
// get buffer (as packet + data)
33-
auto* ptr = (Packet*) bufstore.get_buffer();
33+
auto buffer = bufstore.get_buffer();
3434
// place packet at front of buffer
35-
new (ptr) Packet(0, 0, MTU, &bufstore);
35+
auto* ptr = (Packet*) buffer.addr;
36+
new (ptr) Packet(0, 0, MTU, buffer.bufstore);
3637
// regular shared_ptr that calls delete on Packet
3738
return std::unique_ptr<Packet>(ptr);
3839
}
@@ -61,28 +62,24 @@ void Service::start(const std::string&)
6162
packet = nullptr;
6263
CHECKSERT(bufstore_.available() == BUFFER_CNT, "Bufcount is now %i", BUFFER_CNT);
6364

64-
INFO("Test 2","Create and chain packets, release one-by-one");
65+
INFO("Test 2", "Create and chain %u packets, release one-by-one", BUFFER_CNT*10);
6566

6667
// Reinitialize the first packet
6768
packet = create_packet(bufstore_);
6869
CHECKSERT(bufstore_.available() == BUFFER_CNT - 1, "Bufcount is now %i", BUFFER_CNT - 1);
6970

7071
// Chain
71-
for (int i = 0; i < chain_size - 1; i++){
72+
for (int i = 0; i < 10*BUFFER_CNT - 1; i++){
7273
auto chained_packet = create_packet(bufstore_);
7374
packet->chain(std::move(chained_packet));
74-
CHECKSERT(bufstore_.available() == BUFFER_CNT - i - 2, "Bufcount is now %i", BUFFER_CNT - i - 2);
7575
}
7676

7777
INFO("Test 2","Releasing packet-chain one-by-one");
7878

7979
// Release one-by-one
8080
auto tail = std::move(packet);
8181
size_t i = 0;
82-
while(tail && i < BUFFER_CNT - 1) {
83-
CHECKSERT(bufstore_.available() == i,
84-
"Bufcount is now %i == %i", i,
85-
bufstore_.available());
82+
while(tail && i < 10*BUFFER_CNT - 1) {
8683
tail = tail->detach_tail();
8784
i++;
8885
}

test/net/unit/packets.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,9 @@ CASE("Create empty packet")
4646

4747
Packet_ptr create_packet() noexcept
4848
{
49-
auto* ptr = (net::Packet*) bufstore.get_buffer();
50-
new (ptr) net::Packet(DRIVER_OFFSET, 0, DRIVER_OFFSET + PACKET_CAPA, &bufstore);
49+
auto buffer = bufstore.get_buffer();
50+
auto* ptr = (net::Packet*) buffer.addr;
51+
new (ptr) net::Packet(DRIVER_OFFSET, 0, DRIVER_OFFSET + PACKET_CAPA, buffer.bufstore);
5152
return net::Packet_ptr(ptr);
5253
}
5354

test/skipped_tests.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
"reason": "Serial input from vmrunner to vm does not work yet"},
44
{"name": "net/integration/transmit",
55
"reason": "The test suffers from UDP packet loss which is expected."},
6-
{"name": "net/integration/router",
7-
"reason": "The test suffers uses too many buffers at present."},
86
{"name": "posix/integration/ucontext",
97
"reason": "The test shows that ucontext is unrealiable, as is."}
108
]

0 commit comments

Comments
 (0)