diff --git a/sys/dev/virtio/network/virtio_net.h b/sys/dev/virtio/network/virtio_net.h --- a/sys/dev/virtio/network/virtio_net.h +++ b/sys/dev/virtio/network/virtio_net.h @@ -407,6 +407,32 @@ return (error); } +/* + * For an outgoing packet, set the transmission csum flags if, according + * to the virtio-net header flag, the packet still needs a valid checksum. + */ +static inline int +virtio_net_tx_txcsum(struct mbuf *m, struct virtio_net_hdr *hdr) +{ + if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { + switch (hdr->csum_offset) { + case offsetof(struct udphdr, uh_sum): + m->m_pkthdr.csum_flags |= CSUM_IP_UDP | CSUM_PSEUDO_HDR; + break; + case offsetof(struct tcphdr, th_sum): + m->m_pkthdr.csum_flags |= CSUM_IP_TCP | CSUM_PSEUDO_HDR; + break; + default: + /* A packet other than TCP or UDP is unexpected here */ + return (1); + } + } + + m->m_pkthdr.csum_data = hdr->csum_offset; + + return (0); +} + static inline int virtio_net_tx_offload_ctx(struct mbuf *m, int *etype, int *proto, int *start) { diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -2896,6 +2896,15 @@ } \ if ((iface) != bifp) \ ETHER_BPF_MTAP(iface, m); \ + if (m->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP_UDP)) { \ + /* Incoming pkt that still needs csum calc. */ \ + /* Probably from a software interface. */ \ + /* In this case, we don't need the csum. */ \ + m->m_pkthdr.csum_flags &= ~(CSUM_IP_TCP | CSUM_IP_UDP);\ + m->m_pkthdr.csum_flags |= CSUM_DATA_VALID \ + | CSUM_PSEUDO_HDR; \ + m->m_pkthdr.csum_data = 0xFFFF; \ + } \ /* Pass tagged packets to if_vlan, if it's loaded */ \ if (VLANTAGOF(m) != 0) { \ if (bifp->if_vlantrunk == NULL) { \ diff --git a/sys/net/if_tuntap.c b/sys/net/if_tuntap.c --- a/sys/net/if_tuntap.c +++ b/sys/net/if_tuntap.c @@ -1781,9 +1781,21 @@ } if (vhdr != NULL) { - if (virtio_net_rx_csum(m, &vhdr->hdr)) { - m_freem(m); - return (0); + if (ifp->if_bridge == NULL) { + if (virtio_net_rx_csum(m, &vhdr->hdr)) { + m_freem(m); + return (0); + } + } else { + /* + * The tap interface is a bridge member. Most likely it + * will be forwarded out over another interface. Thus, + * setting transmission offload flags in the mbuf here. + */ + if (virtio_net_tx_txcsum(m, &vhdr->hdr)) { + m_freem(m); + return (0); + } } } else { switch (ntohs(eh->ether_type)) {