Skip to content

Commit

Permalink
net: icmp: Gracefully timeout net_buf get in RX path
Browse files Browse the repository at this point in the history
If we are replying ICMPv{4|6} message, then do not wait forever
for a free buffer. In a busy system, this might lead to non-progress
in RX path if we receive lot of packet from the network and never get
a free buffer.

Change-Id: Iaef92541b8745f872a07bc6e2052d0393d4d1e8b
Signed-off-by: Jukka Rissanen <[email protected]>
  • Loading branch information
jukkar committed Mar 17, 2017
1 parent d48ef44 commit d233f91
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 10 deletions.
19 changes: 15 additions & 4 deletions subsys/net/ip/icmpv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include "icmpv4.h"
#include "net_stats.h"

#define BUF_WAIT_TIME K_SECONDS(1)

static inline enum net_verdict handle_echo_request(struct net_buf *buf)
{
/* Note that we send the same data buffers back and just swap
Expand Down Expand Up @@ -179,17 +181,23 @@ int net_icmpv4_send_error(struct net_buf *orig, uint8_t type, uint8_t code)
struct net_if *iface = net_nbuf_iface(orig);
size_t extra_len, reserve;
struct in_addr addr, *src, *dst;
int err = -EIO;

if (NET_IPV4_BUF(orig)->proto == IPPROTO_ICMP) {
if (NET_ICMP_BUF(orig)->code < 8) {
/* We must not send ICMP errors back */
return -EINVAL;
err = -EINVAL;
goto drop_no_buf;
}
}

iface = net_nbuf_iface(orig);

buf = net_nbuf_get_reserve_tx(0, K_FOREVER);
buf = net_nbuf_get_reserve_tx(0, BUF_WAIT_TIME);
if (!buf) {
err = -ENOMEM;
goto drop_no_buf;
}

reserve = sizeof(struct net_ipv4_hdr) + sizeof(struct net_icmp_hdr) +
NET_ICMPV4_UNUSED_LEN;
Expand Down Expand Up @@ -220,8 +228,9 @@ int net_icmpv4_send_error(struct net_buf *orig, uint8_t type, uint8_t code)
/* We only copy minimal IPv4 + next header from original message.
* This is so that the memory pressure is minimized.
*/
frag = net_nbuf_copy(orig, extra_len, reserve, K_FOREVER);
frag = net_nbuf_copy(orig, extra_len, reserve, BUF_WAIT_TIME);
if (!frag) {
err = -ENOMEM;
goto drop;
}

Expand Down Expand Up @@ -264,10 +273,12 @@ int net_icmpv4_send_error(struct net_buf *orig, uint8_t type, uint8_t code)

drop:
net_nbuf_unref(buf);

drop_no_buf:
net_stats_update_icmp_drop();

/* Note that we always return < 0 so that the caller knows to
* discard the original buffer.
*/
return -EIO;
return err;
}
28 changes: 22 additions & 6 deletions subsys/net/ip/icmpv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
#include "rpl.h"
#endif

#define BUF_WAIT_TIME K_SECONDS(1)

static sys_slist_t handlers;

void net_icmpv6_register_handler(struct net_icmpv6_handler *handler)
Expand Down Expand Up @@ -101,12 +103,15 @@ static enum net_verdict handle_echo_request(struct net_buf *orig)

iface = net_nbuf_iface(orig);

buf = net_nbuf_get_reserve_tx(0, K_FOREVER);
buf = net_nbuf_get_reserve_tx(0, BUF_WAIT_TIME);
if (!buf) {
goto drop_no_buf;
}

payload_len = sys_get_be16(NET_IPV6_BUF(orig)->len) -
sizeof(NET_ICMPH_LEN) - NET_ICMPV6_UNUSED_LEN;

frag = net_nbuf_copy_all(orig, 0, K_FOREVER);
frag = net_nbuf_copy_all(orig, 0, BUF_WAIT_TIME);
if (!frag) {
goto drop;
}
Expand Down Expand Up @@ -185,6 +190,8 @@ static enum net_verdict handle_echo_request(struct net_buf *orig)

drop:
net_nbuf_unref(buf);

drop_no_buf:
net_stats_update_icmp_drop();

return NET_DROP;
Expand All @@ -197,17 +204,23 @@ int net_icmpv6_send_error(struct net_buf *orig, uint8_t type, uint8_t code,
struct net_if *iface;
struct in6_addr *src, *dst;
size_t extra_len, reserve;
int err = -EIO;

if (NET_IPV6_BUF(orig)->nexthdr == IPPROTO_ICMPV6) {
if (NET_ICMP_BUF(orig)->code < 128) {
/* We must not send ICMP errors back */
return -EINVAL;
err = -EINVAL;
goto drop_no_buf;
}
}

iface = net_nbuf_iface(orig);

buf = net_nbuf_get_reserve_tx(0, K_FOREVER);
buf = net_nbuf_get_reserve_tx(0, BUF_WAIT_TIME);
if (!buf) {
err = -ENOMEM;
goto drop_no_buf;
}

/* We need to remember the original location of source and destination
* addresses as the net_nbuf_copy() will mangle the original buffer.
Expand Down Expand Up @@ -241,8 +254,9 @@ int net_icmpv6_send_error(struct net_buf *orig, uint8_t type, uint8_t code,
/* We only copy minimal IPv6 + next header from original message.
* This is so that the memory pressure is minimized.
*/
frag = net_nbuf_copy(orig, extra_len, reserve, K_FOREVER);
frag = net_nbuf_copy(orig, extra_len, reserve, BUF_WAIT_TIME);
if (!frag) {
err = -ENOMEM;
goto drop;
}

Expand Down Expand Up @@ -301,12 +315,14 @@ int net_icmpv6_send_error(struct net_buf *orig, uint8_t type, uint8_t code,

drop:
net_nbuf_unref(buf);

drop_no_buf:
net_stats_update_icmp_drop();

/* Note that we always return < 0 so that the caller knows to
* discard the original buffer.
*/
return -EIO;
return err;
}

int net_icmpv6_send_echo_request(struct net_if *iface,
Expand Down

0 comments on commit d233f91

Please sign in to comment.