net: icmp: Gracefully timeout net_buf get in RX path

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 <jukka.rissanen@linux.intel.com>
This commit is contained in:
Jukka Rissanen 2017-03-15 10:15:45 +02:00
parent d48ef44d25
commit d233f91388
2 changed files with 37 additions and 10 deletions

View file

@ -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
@ -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;
@ -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;
}
@ -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;
}

View file

@ -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)
@ -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;
}
@ -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;
@ -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.
@ -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;
}
@ -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,