mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 09:58:01 +00:00
dp-packet: Remove Linux specific L4 offloads.
As the virtio-net offload API is used for netdev-linux ports, but provides no information about the potentially encapsulated protocol concerned by a checksum request, specific information from this netdev- specific implementation is propagated into OVS code, and must be carefully evaluated when some tunnel gets decapsulated. This induces a cost in "normal" processing path, while the netdev-linux path is not performance critical. This patch removes such specific information, yet try harder to parse the packet on the Rx side and set offload flags accordingly for non encapsulated traffic. For encapsulated traffic, the inner checksum is computed. Signed-off-by: David Marchand <david.marchand@redhat.com> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
This commit is contained in:
parent
a86ae3c865
commit
52fdeda11a
@ -39,9 +39,6 @@ dp_packet_init__(struct dp_packet *b, size_t allocated, enum dp_packet_source so
|
||||
dp_packet_init_specific(b);
|
||||
/* By default assume the packet type to be Ethernet. */
|
||||
b->packet_type = htonl(PT_ETH);
|
||||
/* Reset csum start and offset. */
|
||||
b->csum_start = 0;
|
||||
b->csum_offset = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -178,8 +178,6 @@ struct dp_packet {
|
||||
or UINT16_MAX. */
|
||||
uint32_t cutlen; /* length in bytes to cut from the end. */
|
||||
ovs_be32 packet_type; /* Packet type as defined in OpenFlow */
|
||||
uint16_t csum_start; /* Position to start checksumming from. */
|
||||
uint16_t csum_offset; /* Offset to place checksum. */
|
||||
union {
|
||||
struct pkt_metadata md;
|
||||
uint64_t data[DP_PACKET_CONTEXT_SIZE / 8];
|
||||
@ -1539,34 +1537,12 @@ dp_packet_ol_set_l4_csum_bad(struct dp_packet *p)
|
||||
*dp_packet_ol_flags_ptr(p) |= DP_PACKET_OL_RX_L4_CKSUM_BAD;
|
||||
}
|
||||
|
||||
/* Marks packet 'p' with good integrity if checksum offload locations
|
||||
* were provided. In the case of encapsulated packets, these values may
|
||||
* be deeper into the packet than OVS might expect. But the packet
|
||||
* should still be considered to have good integrity.
|
||||
* The 'csum_start' is the offset from the begin of the packet headers.
|
||||
* The 'csum_offset' is the offset from start to place the checksum.
|
||||
* The csum_start and csum_offset fields are set from the virtio_net_hdr
|
||||
* struct that may be provided by a netdev on packet ingress. */
|
||||
static inline void
|
||||
dp_packet_ol_l4_csum_check_partial(struct dp_packet *p)
|
||||
{
|
||||
if (p->csum_start && p->csum_offset) {
|
||||
dp_packet_ol_set_l4_csum_partial(p);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
dp_packet_reset_packet(struct dp_packet *b, int off)
|
||||
{
|
||||
dp_packet_set_size(b, dp_packet_size(b) - off);
|
||||
dp_packet_set_data(b, ((unsigned char *) dp_packet_data(b) + off));
|
||||
dp_packet_reset_offsets(b);
|
||||
|
||||
if (b->csum_start >= off && b->csum_offset) {
|
||||
/* Adjust values for decapsulation. */
|
||||
b->csum_start -= off;
|
||||
dp_packet_ol_set_l4_csum_partial(b);
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t ALWAYS_INLINE
|
||||
|
@ -776,7 +776,6 @@ mfex_ipv6_set_hwol(struct dp_packet *pkt)
|
||||
static void
|
||||
mfex_tcp_set_hwol(struct dp_packet *pkt)
|
||||
{
|
||||
dp_packet_ol_l4_csum_check_partial(pkt);
|
||||
if (dp_packet_l4_checksum_good(pkt)
|
||||
|| dp_packet_ol_l4_csum_partial(pkt)) {
|
||||
dp_packet_hwol_set_csum_tcp(pkt);
|
||||
@ -786,7 +785,6 @@ mfex_tcp_set_hwol(struct dp_packet *pkt)
|
||||
static void
|
||||
mfex_udp_set_hwol(struct dp_packet *pkt)
|
||||
{
|
||||
dp_packet_ol_l4_csum_check_partial(pkt);
|
||||
if (dp_packet_l4_checksum_good(pkt)
|
||||
|| dp_packet_ol_l4_csum_partial(pkt)) {
|
||||
dp_packet_hwol_set_csum_udp(pkt);
|
||||
|
@ -1080,7 +1080,6 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
|
||||
} else if (dl_type == htons(ETH_TYPE_IPV6)) {
|
||||
dp_packet_update_rss_hash_ipv6_tcp_udp(packet);
|
||||
}
|
||||
dp_packet_ol_l4_csum_check_partial(packet);
|
||||
if (dp_packet_l4_checksum_good(packet)
|
||||
|| dp_packet_ol_l4_csum_partial(packet)) {
|
||||
dp_packet_hwol_set_csum_tcp(packet);
|
||||
@ -1100,7 +1099,6 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
|
||||
} else if (dl_type == htons(ETH_TYPE_IPV6)) {
|
||||
dp_packet_update_rss_hash_ipv6_tcp_udp(packet);
|
||||
}
|
||||
dp_packet_ol_l4_csum_check_partial(packet);
|
||||
if (dp_packet_l4_checksum_good(packet)
|
||||
|| dp_packet_ol_l4_csum_partial(packet)) {
|
||||
if (tunneling) {
|
||||
@ -1118,7 +1116,6 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
|
||||
miniflow_push_be16(mf, tp_dst, sctp->sctp_dst);
|
||||
miniflow_push_be16(mf, ct_tp_src, ct_tp_src);
|
||||
miniflow_push_be16(mf, ct_tp_dst, ct_tp_dst);
|
||||
dp_packet_ol_l4_csum_check_partial(packet);
|
||||
if (dp_packet_l4_checksum_good(packet)
|
||||
|| dp_packet_ol_l4_csum_partial(packet)) {
|
||||
dp_packet_hwol_set_csum_sctp(packet);
|
||||
@ -1309,20 +1306,17 @@ parse_tcp_flags(struct dp_packet *packet,
|
||||
if (nw_proto == IPPROTO_TCP && size >= TCP_HEADER_LEN) {
|
||||
const struct tcp_header *tcp = data;
|
||||
|
||||
dp_packet_ol_l4_csum_check_partial(packet);
|
||||
if (dp_packet_l4_checksum_good(packet)
|
||||
|| dp_packet_ol_l4_csum_partial(packet)) {
|
||||
dp_packet_hwol_set_csum_tcp(packet);
|
||||
}
|
||||
return TCP_FLAGS(tcp->tcp_ctl);
|
||||
} else if (nw_proto == IPPROTO_UDP && size >= UDP_HEADER_LEN) {
|
||||
dp_packet_ol_l4_csum_check_partial(packet);
|
||||
if (dp_packet_l4_checksum_good(packet)
|
||||
|| dp_packet_ol_l4_csum_partial(packet)) {
|
||||
dp_packet_hwol_set_csum_udp(packet);
|
||||
}
|
||||
} else if (nw_proto == IPPROTO_SCTP && size >= SCTP_HEADER_LEN) {
|
||||
dp_packet_ol_l4_csum_check_partial(packet);
|
||||
if (dp_packet_l4_checksum_good(packet)
|
||||
|| dp_packet_ol_l4_csum_partial(packet)) {
|
||||
dp_packet_hwol_set_csum_sctp(packet);
|
||||
|
@ -89,6 +89,8 @@ COVERAGE_DEFINE(netdev_get_hwaddr);
|
||||
COVERAGE_DEFINE(netdev_set_hwaddr);
|
||||
COVERAGE_DEFINE(netdev_get_ethtool);
|
||||
COVERAGE_DEFINE(netdev_set_ethtool);
|
||||
COVERAGE_DEFINE(netdev_linux_invalid_l4_csum);
|
||||
COVERAGE_DEFINE(netdev_linux_unknown_l4_csum);
|
||||
|
||||
|
||||
#ifndef IFLA_IF_NETNSID
|
||||
@ -7055,16 +7057,51 @@ netdev_linux_parse_vnet_hdr(struct dp_packet *b)
|
||||
}
|
||||
|
||||
if (vnet->flags == VIRTIO_NET_HDR_F_NEEDS_CSUM) {
|
||||
/* The packet has offloaded checksum. However, there is no
|
||||
* additional information like the protocol used, so it would
|
||||
* require to parse the packet here. The checksum starting point
|
||||
* and offset are going to be verified when the packet headers
|
||||
* are parsed during miniflow extraction. */
|
||||
b->csum_start = (OVS_FORCE uint16_t) vnet->csum_start;
|
||||
b->csum_offset = (OVS_FORCE uint16_t) vnet->csum_offset;
|
||||
uint16_t csum_offset = (OVS_FORCE uint16_t) vnet->csum_offset;
|
||||
uint16_t csum_start = (OVS_FORCE uint16_t) vnet->csum_start;
|
||||
|
||||
if (csum_start >= dp_packet_size(b)
|
||||
|| csum_start + csum_offset >= dp_packet_size(b)) {
|
||||
COVERAGE_INC(netdev_linux_invalid_l4_csum);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Chicken/egg situation, report L4 checksum as partial so that
|
||||
* L4 extraction works. */
|
||||
dp_packet_ol_set_l4_csum_partial(b);
|
||||
parse_tcp_flags(b, NULL, NULL, NULL);
|
||||
|
||||
if (csum_start == b->l4_ofs
|
||||
&& ((csum_offset == offsetof(struct tcp_header, tcp_csum)
|
||||
&& dp_packet_hwol_l4_is_tcp(b))
|
||||
|| (csum_offset == offsetof(struct udp_header, udp_csum)
|
||||
&& dp_packet_hwol_l4_is_udp(b))
|
||||
|| (csum_offset == offsetof(struct sctp_header, sctp_csum)
|
||||
&& dp_packet_hwol_l4_is_sctp(b)))) {
|
||||
/* Nothing to do, L4 csum is already marked as partial. */
|
||||
} else {
|
||||
b->csum_start = 0;
|
||||
b->csum_offset = 0;
|
||||
ovs_be16 *csum_l4;
|
||||
void *l4;
|
||||
|
||||
COVERAGE_INC(netdev_linux_unknown_l4_csum);
|
||||
|
||||
csum_l4 = dp_packet_at(b, csum_start + csum_offset,
|
||||
sizeof *csum_l4);
|
||||
if (!csum_l4) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
l4 = dp_packet_at(b, csum_start, dp_packet_size(b) - csum_start);
|
||||
*csum_l4 = csum(l4, dp_packet_size(b) - csum_start);
|
||||
|
||||
if (dp_packet_hwol_l4_is_tcp(b)
|
||||
|| dp_packet_hwol_l4_is_udp(b)
|
||||
|| dp_packet_hwol_l4_is_sctp(b)) {
|
||||
dp_packet_ol_set_l4_csum_good(b);
|
||||
} else {
|
||||
*dp_packet_ol_flags_ptr(b) &= ~DP_PACKET_OL_RX_L4_CKSUM_MASK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
|
@ -337,11 +337,7 @@ netdev_tnl_push_udp_header(const struct netdev *netdev OVS_UNUSED,
|
||||
} else {
|
||||
dp_packet_hwol_set_csum_udp(packet);
|
||||
}
|
||||
}
|
||||
|
||||
if (packet->csum_start && packet->csum_offset) {
|
||||
dp_packet_ol_set_l4_csum_partial(packet);
|
||||
} else if (!udp->udp_csum) {
|
||||
} else {
|
||||
dp_packet_ol_set_l4_csum_good(packet);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user