net: Support network packet checksum calc offloading
Create infrastructure that allows ethernet device driver to tell if it supports network packet checksum offloading. This applies only to IPv4, UDP or TCP checksums. The driver can enable/disable checksum offloading separately for Tx and Rx network packets. If the device (ethernet in this case) can calculate the network packet checksum for IPv4, UDP or TCP, then do not calculate the corresponding checksum by the stack itself. Fixes #2987 Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
parent
74d1835505
commit
85a2459edb
14 changed files with 143 additions and 35 deletions
|
@ -19,6 +19,7 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys_io.h>
|
||||
#include <net/ethernet.h>
|
||||
|
||||
#include "eth_dw_priv.h"
|
||||
|
||||
|
@ -372,9 +373,9 @@ static struct eth_runtime eth_0_runtime = {
|
|||
#endif
|
||||
};
|
||||
|
||||
static struct net_if_api api_funcs = {
|
||||
.init = eth_initialize,
|
||||
.send = eth_tx,
|
||||
static const struct ethernet_api api_funcs = {
|
||||
.iface_api.init = eth_initialize,
|
||||
.iface_api.send = eth_tx,
|
||||
};
|
||||
|
||||
NET_DEVICE_INIT(eth_dw_0, CONFIG_ETH_DW_0_NAME,
|
||||
|
|
|
@ -705,9 +705,9 @@ static void eth_enc28j60_iface_init_0(struct net_if *iface)
|
|||
context->iface = iface;
|
||||
}
|
||||
|
||||
static struct net_if_api api_funcs_0 = {
|
||||
.init = eth_enc28j60_iface_init_0,
|
||||
.send = eth_net_tx,
|
||||
static const struct ethernet_api api_funcs_0 = {
|
||||
.iface_api.init = eth_enc28j60_iface_init_0,
|
||||
.iface_api.send = eth_net_tx,
|
||||
};
|
||||
|
||||
static struct eth_enc28j60_runtime eth_enc28j60_0_runtime;
|
||||
|
|
|
@ -601,9 +601,9 @@ static void eth_0_iface_init(struct net_if *iface)
|
|||
context->iface = iface;
|
||||
}
|
||||
|
||||
static struct net_if_api api_funcs_0 = {
|
||||
.init = eth_0_iface_init,
|
||||
.send = eth_tx,
|
||||
static const struct ethernet_api api_funcs_0 = {
|
||||
.iface_api.init = eth_0_iface_init,
|
||||
.iface_api.send = eth_tx,
|
||||
};
|
||||
|
||||
static void eth_mcux_rx_isr(void *p)
|
||||
|
|
|
@ -228,9 +228,9 @@ static void eth_iface_init(struct net_if *iface)
|
|||
}
|
||||
}
|
||||
|
||||
static struct net_if_api eth_if_api = {
|
||||
.init = eth_iface_init,
|
||||
.send = eth_send,
|
||||
static const struct ethernet_api eth_if_api = {
|
||||
.iface_api.init = eth_iface_init,
|
||||
.iface_api.send = eth_send,
|
||||
};
|
||||
|
||||
NET_DEVICE_INIT(eth_native_posix, CONFIG_ETH_NATIVE_POSIX_DRV_NAME,
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <stdbool.h>
|
||||
#include <net/net_pkt.h>
|
||||
#include <net/net_if.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <i2c.h>
|
||||
#include <soc.h>
|
||||
#include "phy_sam_gmac.h"
|
||||
|
@ -838,9 +839,9 @@ static void eth0_iface_init(struct net_if *iface)
|
|||
link_configure(cfg->regs, link_status);
|
||||
}
|
||||
|
||||
static struct net_if_api eth0_api = {
|
||||
.init = eth0_iface_init,
|
||||
.send = eth_tx,
|
||||
static const struct ethernet_api eth0_api = {
|
||||
.iface_api.init = eth0_iface_init,
|
||||
.iface_api.send = eth_tx,
|
||||
};
|
||||
|
||||
static struct device DEVICE_NAME_GET(eth0_sam_gmac);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <stdbool.h>
|
||||
#include <net/net_pkt.h>
|
||||
#include <net/net_if.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <soc.h>
|
||||
#include <misc/printk.h>
|
||||
#include <clock_control.h>
|
||||
|
@ -368,9 +369,9 @@ static void eth0_iface_init(struct net_if *iface)
|
|||
NET_LINK_ETHERNET);
|
||||
}
|
||||
|
||||
static struct net_if_api eth0_api = {
|
||||
.init = eth0_iface_init,
|
||||
.send = eth_tx,
|
||||
static const struct ethernet_api eth0_api = {
|
||||
.iface_api.init = eth0_iface_init,
|
||||
.iface_api.send = eth_tx,
|
||||
};
|
||||
|
||||
static struct device DEVICE_NAME_GET(eth0_stm32_hal);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <net/net_if.h>
|
||||
#include <net/net_core.h>
|
||||
#include <console/uart_pipe.h>
|
||||
#include <net/ethernet.h>
|
||||
|
||||
#define SLIP_END 0300
|
||||
#define SLIP_ESC 0333
|
||||
|
@ -464,18 +465,24 @@ use_random_mac:
|
|||
NET_LINK_ETHERNET);
|
||||
}
|
||||
|
||||
static struct net_if_api slip_if_api = {
|
||||
.init = slip_iface_init,
|
||||
.send = slip_send,
|
||||
};
|
||||
|
||||
static struct slip_context slip_context_data;
|
||||
|
||||
#if defined(CONFIG_SLIP_TAP) && defined(CONFIG_NET_L2_ETHERNET)
|
||||
static const struct ethernet_api slip_if_api = {
|
||||
.iface_api.init = slip_iface_init,
|
||||
.iface_api.send = slip_send,
|
||||
};
|
||||
|
||||
#define _SLIP_L2_LAYER ETHERNET_L2
|
||||
#define _SLIP_L2_CTX_TYPE NET_L2_GET_CTX_TYPE(ETHERNET_L2)
|
||||
#define _SLIP_MTU 1500
|
||||
#else
|
||||
|
||||
static const struct net_if_api slip_if_api = {
|
||||
.init = slip_iface_init,
|
||||
.send = slip_send,
|
||||
};
|
||||
|
||||
#define _SLIP_L2_LAYER DUMMY_L2
|
||||
#define _SLIP_L2_CTX_TYPE NET_L2_GET_CTX_TYPE(DUMMY_L2)
|
||||
#define _SLIP_MTU 576
|
||||
|
|
|
@ -39,6 +39,25 @@ extern "C" {
|
|||
|
||||
#define NET_ETH_MINIMAL_FRAME_SIZE 60
|
||||
|
||||
enum eth_hw_caps {
|
||||
/** TX Checksum offloading supported */
|
||||
ETH_HW_TX_CHKSUM_OFFLOAD = BIT(0),
|
||||
|
||||
/** RX Checksum offloading supported */
|
||||
ETH_HW_RX_CHKSUM_OFFLOAD = BIT(1),
|
||||
};
|
||||
|
||||
struct ethernet_api {
|
||||
/**
|
||||
* The net_if_api must be placed in first position in this
|
||||
* struct so that we are compatible with network interface API.
|
||||
*/
|
||||
struct net_if_api iface_api;
|
||||
|
||||
/** Get the device capabilities */
|
||||
enum eth_hw_caps (*get_capabilities)(struct device *dev);
|
||||
} __packed;
|
||||
|
||||
struct net_eth_addr {
|
||||
u8_t addr[6];
|
||||
};
|
||||
|
@ -94,6 +113,26 @@ const struct net_eth_addr *net_eth_broadcast_addr(void);
|
|||
void net_eth_ipv6_mcast_to_mac_addr(const struct in6_addr *ipv6_addr,
|
||||
struct net_eth_addr *mac_addr);
|
||||
|
||||
/**
|
||||
* @brief Return ethernet device hardware capability information.
|
||||
*
|
||||
* @param iface Network interface
|
||||
*
|
||||
* @return Hardware capabilities
|
||||
*/
|
||||
static inline
|
||||
enum eth_hw_caps net_eth_get_hw_capabilities(struct net_if *iface)
|
||||
{
|
||||
const struct ethernet_api *eth =
|
||||
net_if_get_device(iface)->driver_api;
|
||||
|
||||
if (!eth->get_capabilities) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return eth->get_capabilities(net_if_get_device(iface));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1261,6 +1261,29 @@ void net_if_unregister_link_cb(struct net_if_link_cb *link);
|
|||
void net_if_call_link_cb(struct net_if *iface, struct net_linkaddr *lladdr,
|
||||
int status);
|
||||
|
||||
/**
|
||||
* @brief Check if received network packet checksum calculation can be avoided
|
||||
* or not. For example many ethernet devices support network packet offloading
|
||||
* in which case the IP stack does not need to calculate the checksum.
|
||||
*
|
||||
* @param iface Network interface
|
||||
*
|
||||
* @return True if checksum needs to be calculated, false otherwise.
|
||||
*/
|
||||
bool net_if_need_calc_rx_checksum(struct net_if *iface);
|
||||
|
||||
/**
|
||||
* @brief Check if network packet checksum calculation can be avoided or not
|
||||
* when sending the packet. For example many ethernet devices support network
|
||||
* packet offloading in which case the IP stack does not need to calculate the
|
||||
* checksum.
|
||||
*
|
||||
* @param iface Network interface
|
||||
*
|
||||
* @return True if checksum needs to be calculated, false otherwise.
|
||||
*/
|
||||
bool net_if_need_calc_tx_checksum(struct net_if *iface);
|
||||
|
||||
/**
|
||||
* @brief Get interface according to index
|
||||
*
|
||||
|
|
|
@ -907,7 +907,8 @@ enum net_verdict net_conn_input(enum net_ip_protocol proto, struct net_pkt *pkt)
|
|||
* If the checksum calculation fails, then discard the message.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_NET_UDP_CHECKSUM) &&
|
||||
proto == IPPROTO_UDP) {
|
||||
proto == IPPROTO_UDP &&
|
||||
net_if_need_calc_rx_checksum(net_pkt_iface(pkt))) {
|
||||
u16_t chksum_calc;
|
||||
|
||||
net_udp_set_chksum(pkt, pkt->frags);
|
||||
|
@ -922,7 +923,8 @@ enum net_verdict net_conn_input(enum net_ip_protocol proto, struct net_pkt *pkt)
|
|||
}
|
||||
|
||||
} else if (IS_ENABLED(CONFIG_NET_TCP_CHECKSUM) &&
|
||||
proto == IPPROTO_TCP) {
|
||||
proto == IPPROTO_TCP &&
|
||||
net_if_need_calc_rx_checksum(net_pkt_iface(pkt))) {
|
||||
u16_t chksum_calc;
|
||||
|
||||
net_tcp_set_chksum(pkt, pkt->frags);
|
||||
|
|
|
@ -100,15 +100,18 @@ int net_ipv4_finalize_raw(struct net_pkt *pkt, u8_t next_header)
|
|||
NET_IPV4_HDR(pkt)->len[1] = total_len & 0xff;
|
||||
|
||||
NET_IPV4_HDR(pkt)->chksum = 0;
|
||||
NET_IPV4_HDR(pkt)->chksum = ~net_calc_chksum_ipv4(pkt);
|
||||
|
||||
#if defined(CONFIG_NET_UDP)
|
||||
if (next_header == IPPROTO_UDP) {
|
||||
if (next_header == IPPROTO_UDP &&
|
||||
net_if_need_calc_tx_checksum(net_pkt_iface(pkt))) {
|
||||
NET_IPV4_HDR(pkt)->chksum = ~net_calc_chksum_ipv4(pkt);
|
||||
net_udp_set_chksum(pkt, pkt->frags);
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_NET_TCP)
|
||||
if (next_header == IPPROTO_TCP) {
|
||||
if (next_header == IPPROTO_TCP &&
|
||||
net_if_need_calc_tx_checksum(net_pkt_iface(pkt))) {
|
||||
NET_IPV4_HDR(pkt)->chksum = ~net_calc_chksum_ipv4(pkt);
|
||||
net_tcp_set_chksum(pkt, pkt->frags);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -779,13 +779,15 @@ int net_ipv6_finalize_raw(struct net_pkt *pkt, u8_t next_header)
|
|||
NET_IPV6_HDR(pkt)->len[1] = total_len & 0xff;
|
||||
|
||||
#if defined(CONFIG_NET_UDP)
|
||||
if (next_header == IPPROTO_UDP) {
|
||||
if (next_header == IPPROTO_UDP &&
|
||||
net_if_need_calc_tx_checksum(net_pkt_iface(pkt))) {
|
||||
net_udp_set_chksum(pkt, pkt->frags);
|
||||
} else
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NET_TCP)
|
||||
if (next_header == IPPROTO_TCP) {
|
||||
if (next_header == IPPROTO_TCP &&
|
||||
net_if_need_calc_tx_checksum(net_pkt_iface(pkt))) {
|
||||
net_tcp_set_chksum(pkt, pkt->frags);
|
||||
} else
|
||||
#endif
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <net/net_if.h>
|
||||
#include <net/arp.h>
|
||||
#include <net/net_mgmt.h>
|
||||
#include <net/ethernet.h>
|
||||
|
||||
#include "net_private.h"
|
||||
#include "ipv6.h"
|
||||
|
@ -1807,6 +1808,29 @@ void net_if_call_link_cb(struct net_if *iface, struct net_linkaddr *lladdr,
|
|||
}
|
||||
}
|
||||
|
||||
static bool need_calc_checksum(struct net_if *iface, enum eth_hw_caps caps)
|
||||
{
|
||||
#if defined(CONFIG_NET_L2_ETHERNET)
|
||||
if (iface->l2 != &NET_L2_GET_NAME(ETHERNET)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !(net_eth_get_hw_capabilities(iface) & caps);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool net_if_need_calc_tx_checksum(struct net_if *iface)
|
||||
{
|
||||
return need_calc_checksum(iface, ETH_HW_TX_CHKSUM_OFFLOAD);
|
||||
}
|
||||
|
||||
bool net_if_need_calc_rx_checksum(struct net_if *iface)
|
||||
{
|
||||
return need_calc_checksum(iface, ETH_HW_RX_CHKSUM_OFFLOAD);
|
||||
}
|
||||
|
||||
struct net_if *net_if_get_by_index(u8_t index)
|
||||
{
|
||||
if (&__net_if_start[index] >= __net_if_end) {
|
||||
|
|
|
@ -283,15 +283,20 @@ static void setup_eth_header(struct net_if *iface, struct net_pkt *pkt,
|
|||
|
||||
struct net_arp_context net_arp_context_data;
|
||||
|
||||
static struct net_if_api net_arp_if_api = {
|
||||
#if defined(CONFIG_NET_ARP) && defined(CONFIG_NET_L2_ETHERNET)
|
||||
static const struct ethernet_api net_arp_if_api = {
|
||||
.iface_api.init = net_arp_iface_init,
|
||||
.iface_api.send = tester_send,
|
||||
};
|
||||
|
||||
#define _ETH_L2_LAYER ETHERNET_L2
|
||||
#define _ETH_L2_CTX_TYPE NET_L2_GET_CTX_TYPE(ETHERNET_L2)
|
||||
#else
|
||||
static const struct net_if_api net_arp_if_api = {
|
||||
.init = net_arp_iface_init,
|
||||
.send = tester_send,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_NET_ARP) && defined(CONFIG_NET_L2_ETHERNET)
|
||||
#define _ETH_L2_LAYER ETHERNET_L2
|
||||
#define _ETH_L2_CTX_TYPE NET_L2_GET_CTX_TYPE(ETHERNET_L2)
|
||||
#else
|
||||
#define _ETH_L2_LAYER DUMMY_L2
|
||||
#define _ETH_L2_CTX_TYPE NET_L2_GET_CTX_TYPE(DUMMY_L2)
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue