Skip to content

Commit 45ac1f9

Browse files
jukkarkartben
authored andcommitted
net: pkt: Add possibility to reserve link layer header
Allow network device driver to configure the system so that when a network packet is sent to it, the link layer header is stored just before the L2 payload in the same packet. Currently the link layer header is stored in a separate net_buf that is linked in front of the L2 payload. This option can typically save one net_buf when sending a network packet. Note that if you are using variable data size buffers (CONFIG_NET_BUF_VARIABLE_DATA_SIZE) then this embedding is not needed because one can allocate just the right size network buffers and not waste any memory. Signed-off-by: Jukka Rissanen <[email protected]>
1 parent df20c6d commit 45ac1f9

File tree

3 files changed

+164
-29
lines changed

3 files changed

+164
-29
lines changed

include/zephyr/net/net_l2.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include <zephyr/device.h>
1616
#include <zephyr/net_buf.h>
17+
#include <zephyr/net/net_ip.h>
1718
#include <zephyr/net/capture.h>
1819
#include <zephyr/sys/iterable_sections.h>
1920

@@ -79,6 +80,13 @@ struct net_l2 {
7980
* Return L2 flags for the network interface.
8081
*/
8182
enum net_l2_flags (*get_flags)(struct net_if *iface);
83+
84+
/**
85+
* Optional function for reserving L2 header space for this technology.
86+
*/
87+
int (*alloc)(struct net_if *iface, struct net_pkt *pkt,
88+
size_t size, enum net_ip_protocol proto,
89+
k_timeout_t timeout);
8290
};
8391

8492
/** @cond INTERNAL_HIDDEN */
@@ -121,13 +129,16 @@ NET_L2_DECLARE_PUBLIC(CANBUS_RAW_L2);
121129
NET_L2_DECLARE_PUBLIC(CUSTOM_IEEE802154_L2);
122130
#endif /* CONFIG_NET_L2_CUSTOM_IEEE802154 */
123131

124-
#define NET_L2_INIT(_name, _recv_fn, _send_fn, _enable_fn, _get_flags_fn) \
132+
#define NET_L2_INIT(_name, _recv_fn, _send_fn, _enable_fn, _get_flags_fn, ...) \
125133
const STRUCT_SECTION_ITERABLE(net_l2, \
126134
NET_L2_GET_NAME(_name)) = { \
127135
.recv = (_recv_fn), \
128136
.send = (_send_fn), \
129137
.enable = (_enable_fn), \
130138
.get_flags = (_get_flags_fn), \
139+
.alloc = COND_CODE_0(NUM_VA_ARGS_LESS_1(LIST_DROP_EMPTY(__VA_ARGS__, _)), \
140+
(NULL), \
141+
(GET_ARG_N(1, __VA_ARGS__))), \
131142
}
132143

133144
#define NET_L2_GET_DATA(name, sfx) _net_l2_data_##name##sfx

include/zephyr/net/net_pkt.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1907,6 +1907,18 @@ struct net_pkt *net_pkt_rx_alloc_with_buffer_debug(struct net_if *iface,
19071907
net_pkt_rx_alloc_with_buffer_debug(_iface, _size, _family, \
19081908
_proto, _timeout, \
19091909
__func__, __LINE__)
1910+
1911+
int net_pkt_alloc_buffer_with_reserve_debug(struct net_pkt *pkt,
1912+
size_t size,
1913+
size_t reserve,
1914+
enum net_ip_protocol proto,
1915+
k_timeout_t timeout,
1916+
const char *caller,
1917+
int line);
1918+
#define net_pkt_alloc_buffer_with_reserve(_pkt, _size, _reserve, _proto, _timeout) \
1919+
net_pkt_alloc_buffer_with_reserve_debug(_pkt, _size, _reserve, _proto, \
1920+
_timeout, __func__, __LINE__)
1921+
19101922
#endif /* NET_PKT_DEBUG_ENABLED */
19111923
/** @endcond */
19121924

@@ -2001,6 +2013,31 @@ int net_pkt_alloc_buffer(struct net_pkt *pkt,
20012013
#endif
20022014

20032015
#if !defined(NET_PKT_DEBUG_ENABLED)
2016+
/**
2017+
* @brief Allocate buffer for a net_pkt and reserve some space in the first net_buf.
2018+
*
2019+
* @details: such allocator will take into account space necessary for headers,
2020+
* MTU, and existing buffer (if any). Beware that, due to all these
2021+
* criteria, the allocated size might be smaller/bigger than
2022+
* requested one.
2023+
*
2024+
* @param pkt The network packet requiring buffer to be allocated.
2025+
* @param size The size of buffer being requested.
2026+
* @param reserve The L2 header size to reserve. This can be 0, in which case
2027+
* the L2 header is placed into a separate net_buf.
2028+
* @param proto The IP protocol type (can be 0 for none).
2029+
* @param timeout Maximum time to wait for an allocation.
2030+
*
2031+
* @return 0 on success, negative errno code otherwise.
2032+
*/
2033+
#if !defined(NET_PKT_DEBUG_ENABLED)
2034+
int net_pkt_alloc_buffer_with_reserve(struct net_pkt *pkt,
2035+
size_t size,
2036+
size_t reserve,
2037+
enum net_ip_protocol proto,
2038+
k_timeout_t timeout);
2039+
#endif
2040+
20042041
/**
20052042
* @brief Allocate buffer for a net_pkt, of specified size, w/o any additional
20062043
* preconditions

subsys/net/ip/net_pkt.c

Lines changed: 115 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -924,12 +924,14 @@ static struct net_pkt_alloc_stats_slab *find_alloc_stats(struct k_mem_slab *slab
924924
#if NET_LOG_LEVEL >= LOG_LEVEL_DBG
925925
static struct net_buf *pkt_alloc_buffer(struct net_pkt *pkt,
926926
struct net_buf_pool *pool,
927-
size_t size, k_timeout_t timeout,
927+
size_t size, size_t headroom,
928+
k_timeout_t timeout,
928929
const char *caller, int line)
929930
#else
930931
static struct net_buf *pkt_alloc_buffer(struct net_pkt *pkt,
931932
struct net_buf_pool *pool,
932-
size_t size, k_timeout_t timeout)
933+
size_t size, size_t headroom,
934+
k_timeout_t timeout)
933935
#endif
934936
{
935937
#if defined(CONFIG_NET_PKT_ALLOC_STATS)
@@ -958,11 +960,25 @@ static struct net_buf *pkt_alloc_buffer(struct net_pkt *pkt,
958960
}
959961

960962
current = new;
961-
if (current->size > size) {
962-
current->size = size;
963-
}
964963

965-
size -= current->size;
964+
/* If there is headroom reserved, then allocate that to the
965+
* first buf.
966+
*/
967+
if (current == first && headroom > 0) {
968+
if (current->size > (headroom + size)) {
969+
current->size = size + headroom;
970+
971+
size = 0U;
972+
} else {
973+
size -= current->size;
974+
}
975+
} else {
976+
if (current->size > size) {
977+
current->size = size;
978+
}
979+
980+
size -= current->size;
981+
}
966982

967983
timeout = sys_timepoint_timeout(end);
968984

@@ -1003,12 +1019,14 @@ static struct net_buf *pkt_alloc_buffer(struct net_pkt *pkt,
10031019
#if NET_LOG_LEVEL >= LOG_LEVEL_DBG
10041020
static struct net_buf *pkt_alloc_buffer(struct net_pkt *pkt,
10051021
struct net_buf_pool *pool,
1006-
size_t size, k_timeout_t timeout,
1022+
size_t size, size_t headroom,
1023+
k_timeout_t timeout,
10071024
const char *caller, int line)
10081025
#else
10091026
static struct net_buf *pkt_alloc_buffer(struct net_pkt *pkt,
10101027
struct net_buf_pool *pool,
1011-
size_t size, k_timeout_t timeout)
1028+
size_t size, size_t headroom,
1029+
k_timeout_t timeout)
10121030
#endif
10131031
{
10141032
struct net_buf *buf;
@@ -1019,6 +1037,7 @@ static struct net_buf *pkt_alloc_buffer(struct net_pkt *pkt,
10191037
#else
10201038
ARG_UNUSED(pkt);
10211039
#endif
1040+
ARG_UNUSED(headroom);
10221041

10231042
buf = net_buf_alloc_len(pool, size, timeout);
10241043

@@ -1231,17 +1250,19 @@ int net_pkt_remove_tail(struct net_pkt *pkt, size_t length)
12311250
}
12321251

12331252
#if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1234-
int net_pkt_alloc_buffer_debug(struct net_pkt *pkt,
1235-
size_t size,
1236-
enum net_ip_protocol proto,
1237-
k_timeout_t timeout,
1238-
const char *caller,
1239-
int line)
1253+
int net_pkt_alloc_buffer_with_reserve_debug(struct net_pkt *pkt,
1254+
size_t size,
1255+
size_t reserve,
1256+
enum net_ip_protocol proto,
1257+
k_timeout_t timeout,
1258+
const char *caller,
1259+
int line)
12401260
#else
1241-
int net_pkt_alloc_buffer(struct net_pkt *pkt,
1242-
size_t size,
1243-
enum net_ip_protocol proto,
1244-
k_timeout_t timeout)
1261+
int net_pkt_alloc_buffer_with_reserve(struct net_pkt *pkt,
1262+
size_t size,
1263+
size_t reserve,
1264+
enum net_ip_protocol proto,
1265+
k_timeout_t timeout)
12451266
#endif
12461267
{
12471268
struct net_buf_pool *pool = NULL;
@@ -1271,8 +1292,8 @@ int net_pkt_alloc_buffer(struct net_pkt *pkt,
12711292
/* Calculate the maximum that can be allocated depending on size */
12721293
alloc_len = pkt_buffer_length(pkt, size + hdr_len, proto, alloc_len);
12731294

1274-
NET_DBG("Data allocation maximum size %zu (requested %zu)",
1275-
alloc_len, size);
1295+
NET_DBG("Data allocation maximum size %zu (requested %zu, reserve %zu)",
1296+
alloc_len, size, reserve);
12761297

12771298
if (pkt->context) {
12781299
pool = get_data_pool(pkt->context);
@@ -1283,26 +1304,92 @@ int net_pkt_alloc_buffer(struct net_pkt *pkt,
12831304
}
12841305

12851306
#if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1286-
buf = pkt_alloc_buffer(pkt, pool, alloc_len, timeout, caller, line);
1307+
buf = pkt_alloc_buffer(pkt, pool, alloc_len, reserve,
1308+
timeout, caller, line);
12871309
#else
1288-
buf = pkt_alloc_buffer(pkt, pool, alloc_len, timeout);
1310+
buf = pkt_alloc_buffer(pkt, pool, alloc_len, reserve, timeout);
12891311
#endif
12901312

12911313
if (!buf) {
12921314
#if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1293-
NET_ERR("Data buffer (%zd) allocation failed (%s:%d)",
1294-
alloc_len, caller, line);
1315+
NET_ERR("Data buffer (%zu) allocation failed (%s:%d)",
1316+
alloc_len + reserve, caller, line);
12951317
#else
1296-
NET_ERR("Data buffer (%zd) allocation failed.", alloc_len);
1318+
NET_ERR("Data buffer (%zu) allocation failed.",
1319+
alloc_len + reserve);
12971320
#endif
12981321
return -ENOMEM;
12991322
}
13001323

13011324
net_pkt_append_buffer(pkt, buf);
13021325

1326+
/* Hide the link layer header for now. The space is used when
1327+
* link layer header needs to be written to the packet by L2 send.
1328+
*/
1329+
if (reserve > 0U) {
1330+
NET_DBG("Reserving %zu bytes for L2 header", reserve);
1331+
1332+
net_buf_reserve(pkt->buffer, reserve);
1333+
1334+
net_pkt_cursor_init(pkt);
1335+
}
1336+
13031337
return 0;
13041338
}
13051339

1340+
#if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1341+
int net_pkt_alloc_buffer_debug(struct net_pkt *pkt,
1342+
size_t size,
1343+
enum net_ip_protocol proto,
1344+
k_timeout_t timeout,
1345+
const char *caller,
1346+
int line)
1347+
#else
1348+
int net_pkt_alloc_buffer(struct net_pkt *pkt,
1349+
size_t size,
1350+
enum net_ip_protocol proto,
1351+
k_timeout_t timeout)
1352+
#endif
1353+
{
1354+
struct net_if *iface;
1355+
int ret;
1356+
1357+
if (!size && proto == 0 && net_pkt_family(pkt) == AF_UNSPEC) {
1358+
return 0;
1359+
}
1360+
1361+
if (k_is_in_isr()) {
1362+
timeout = K_NO_WAIT;
1363+
}
1364+
1365+
iface = net_pkt_iface(pkt);
1366+
1367+
if (iface != NULL && net_if_l2(iface)->alloc != NULL) {
1368+
ret = net_if_l2(iface)->alloc(iface, pkt, size, proto, timeout);
1369+
if (ret != -ENOTSUP) {
1370+
return ret;
1371+
}
1372+
}
1373+
1374+
#if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1375+
ret = net_pkt_alloc_buffer_with_reserve_debug(pkt,
1376+
size,
1377+
0U,
1378+
proto,
1379+
timeout,
1380+
caller,
1381+
line);
1382+
#else
1383+
ret = net_pkt_alloc_buffer_with_reserve(pkt,
1384+
size,
1385+
0U,
1386+
proto,
1387+
timeout);
1388+
#endif
1389+
1390+
return ret;
1391+
}
1392+
13061393

13071394
#if NET_LOG_LEVEL >= LOG_LEVEL_DBG
13081395
int net_pkt_alloc_buffer_raw_debug(struct net_pkt *pkt, size_t size,
@@ -1335,9 +1422,9 @@ int net_pkt_alloc_buffer_raw(struct net_pkt *pkt, size_t size,
13351422
}
13361423

13371424
#if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1338-
buf = pkt_alloc_buffer(pkt, pool, size, timeout, caller, line);
1425+
buf = pkt_alloc_buffer(pkt, pool, size, 0U, timeout, caller, line);
13391426
#else
1340-
buf = pkt_alloc_buffer(pkt, pool, size, timeout);
1427+
buf = pkt_alloc_buffer(pkt, pool, size, 0U, timeout);
13411428
#endif
13421429

13431430
if (!buf) {
@@ -1569,7 +1656,7 @@ pkt_alloc_with_buffer(struct k_mem_slab *slab,
15691656
struct net_pkt *pkt;
15701657
int ret;
15711658

1572-
NET_DBG("On iface %p size %zu", iface, size);
1659+
NET_DBG("On iface %d (%p) size %zu", net_if_get_by_iface(iface), iface, size);
15731660

15741661
#if NET_LOG_LEVEL >= LOG_LEVEL_DBG
15751662
pkt = pkt_alloc_on_iface(slab, iface, timeout, caller, line);

0 commit comments

Comments
 (0)