Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F154930360
D54948.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D54948.diff
View Options
diff --git a/share/man/man4/bridge.4 b/share/man/man4/bridge.4
--- a/share/man/man4/bridge.4
+++ b/share/man/man4/bridge.4
@@ -36,7 +36,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd October 13, 2025
+.Dd January 29, 2026
.Dt IF_BRIDGE 4
.Os
.Sh NAME
@@ -144,7 +144,7 @@
If the MTU of a bridge is changed after its creation, the MTU of all member
interfaces is also changed to match.
.Pp
-The TOE, TSO, TXCSUM and TXCSUM6 capabilities on all interfaces added to the
+The TOE and TSO capabilities on all interfaces added to the
bridge are disabled if any of the interfaces do not support/enable them.
The LRO capability is always disabled.
All the capabilities are restored when the interface is removed from the bridge.
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
@@ -78,6 +78,7 @@
#include "opt_inet.h"
#include "opt_inet6.h"
+#include "opt_sctp.h"
#define EXTERR_CATEGORY EXTERR_CAT_BRIDGE
@@ -137,6 +138,10 @@
#include <net/route.h>
+#if defined(SCTP) || defined(SCTP_SUPPORT)
+#include <netinet/sctp_crc32.h>
+#endif
+
/*
* At various points in the code we need to know if we're hooked into the INET
* and/or INET6 pfil. Define some macros to do that based on which IP versions
@@ -195,8 +200,7 @@
/*
* List of capabilities to possibly mask on the member interface.
*/
-#define BRIDGE_IFCAPS_MASK (IFCAP_TOE|IFCAP_TSO|IFCAP_TXCSUM|\
- IFCAP_TXCSUM_IPV6|IFCAP_MEXTPG)
+#define BRIDGE_IFCAPS_MASK (IFCAP_TOE|IFCAP_TSO|IFCAP_MEXTPG)
/*
* List of capabilities to strip
@@ -841,6 +845,10 @@
return (bifa->bif_sc == bifb->bif_sc);
}
+#define BRIDGE_CSUM_IP4_ALL (CSUM_IP | CSUM_IP_SCTP | CSUM_IP_TCP | CSUM_IP_UDP)
+#define BRIDGE_CSUM_IP6_ALL (CSUM_IP6_SCTP | CSUM_IP6_TCP | CSUM_IP6_UDP)
+#define BRIDGE_CSUM_ALL (BRIDGE_CSUM_IP4_ALL | BRIDGE_CSUM_IP6_ALL)
+
/*
* bridge_clone_create:
*
@@ -871,7 +879,9 @@
ifp->if_softc = sc;
if_initname(ifp, bridge_name, ifd->unit);
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
- ifp->if_capabilities = ifp->if_capenable = IFCAP_VLAN_HWTAGGING;
+ ifp->if_capabilities = ifp->if_capenable = IFCAP_VLAN_HWTAGGING |
+ IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6 | IFCAP_VLAN_HWCSUM;
+ ifp->if_hwassist = BRIDGE_CSUM_ALL;
ifp->if_ioctl = bridge_ioctl;
#ifdef ALTQ
ifp->if_start = bridge_altq_start;
@@ -998,7 +1008,7 @@
} args;
struct ifdrv *ifd = (struct ifdrv *) data;
const struct bridge_control *bc;
- int error = 0, oldmtu;
+ int error = 0, oldmtu, mask;
BRIDGE_LOCK(sc);
@@ -1125,6 +1135,20 @@
sc->sc_ifp->if_mtu = ifr->ifr_mtu;
}
break;
+ case SIOCSIFCAP:
+ mask = ifr->ifr_reqcap ^ if_getcapenable(ifp);
+ if (mask & IFCAP_TXCSUM) {
+ if_togglecapenable(ifp, IFCAP_TXCSUM);
+ if_togglehwassist(ifp, BRIDGE_CSUM_IP4_ALL);
+ }
+ if (mask & IFCAP_TXCSUM_IPV6) {
+ if_togglecapenable(ifp, IFCAP_TXCSUM_IPV6);
+ if_togglehwassist(ifp, BRIDGE_CSUM_IP6_ALL);
+ }
+ if (mask & IFCAP_VLAN_HWCSUM) {
+ if_togglecapenable(ifp, IFCAP_VLAN_HWCSUM);
+ }
+ break;
default:
/*
* drop the lock as ether_ioctl() will call bridge_start() and
@@ -2373,6 +2397,134 @@
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
}
+#if defined(INET) || defined(INET6)
+
+/*
+ * Depending on what is set in the given csum_req, compute and insert the IP,
+ * SCTP, TCP, or UDP checksum for the given mbuf chain m.
+ * Return the modified mbuf chain, or NULL if the mbuf chain was destroyed.
+ */
+static struct mbuf *
+bridge_delayed_cksum(struct mbuf *m, uint32_t csum_req)
+{
+ struct ether_header *eh;
+ uint16_t ether_type, inner_ether_type, iph_offset;
+
+ KASSERT((csum_req & BRIDGE_CSUM_ALL) != 0,
+ ("%s: got an mbuf without csum offloading flag set.", __func__));
+
+ m = m_pullup(m, ETHER_HDR_LEN + 2 * ETHER_VLAN_ENCAP_LEN);
+ if (m == NULL) {
+ return (NULL);
+ }
+ /* determine ethernet header length */
+ eh = mtod(m, struct ether_header *);
+ ether_type = ntohs(eh->ether_type);
+ switch (ether_type) {
+ case ETHERTYPE_IP:
+ case ETHERTYPE_IPV6:
+ iph_offset = ETHER_HDR_LEN;
+ inner_ether_type = ether_type;
+ break;
+ case ETHERTYPE_VLAN:
+ iph_offset = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
+ inner_ether_type =
+ ntohs(((struct ether_vlan_header *)eh)->evl_proto);
+ break;
+ case ETHERTYPE_QINQ:
+ iph_offset = ETHER_HDR_LEN + 2 * ETHER_VLAN_ENCAP_LEN;
+ /* QINQ header adds four 2-byte fields before the ether_type */
+ inner_ether_type = ntohs(*(&(eh->ether_type) + 4));
+ break;
+ default:
+ KASSERT(0, ("%s: got the unexpected ether_type %d.\n",
+ __func__, ether_type));
+ return (m);
+ }
+
+#if defined(INET)
+ if (csum_req & BRIDGE_CSUM_IP4_ALL) {
+ struct ip *ip;
+
+ if (inner_ether_type != ETHERTYPE_IP) {
+ KASSERT(0, ("%s: got an mbuf with an IPv4 csum offloading flag set that contains no IPv4 packet.",
+ __func__));
+ return (m);
+ }
+ /*
+ * pullup enough to access the ihl, total length, and checksum
+ * fields in the IP header.
+ */
+ m = m_pullup(m, iph_offset + offsetof(struct ip, ip_src));
+ if (m == NULL) {
+ return (NULL);
+ }
+ ip = (struct ip *)mtodo(m, iph_offset);
+ if (csum_req & CSUM_IP) {
+ ip->ip_sum = 0;
+ ip->ip_sum = in_cksum_skip(m,
+ iph_offset + (ip->ip_hl << 2), iph_offset);
+ if (m->m_flags & M_PKTHDR) {
+ m->m_pkthdr.csum_flags &= ~CSUM_IP;
+ }
+ }
+ if (csum_req & (CSUM_IP_TCP | CSUM_IP_UDP)) {
+ in_delayed_cksum_o(m, iph_offset);
+ if (m->m_flags & M_PKTHDR) {
+ m->m_pkthdr.csum_flags &=
+ ~(CSUM_IP_TCP | CSUM_IP_UDP);
+ }
+ }
+#if defined(SCTP) || defined(SCTP_SUPPORT)
+ else if (csum_req & CSUM_IP_SCTP) {
+ sctp_delayed_cksum(m, (uint32_t)(iph_offset +
+ (ip->ip_hl << 2)));
+ if (m->m_flags & M_PKTHDR) {
+ m->m_pkthdr.csum_flags &= ~CSUM_IP_SCTP;
+ }
+ }
+#endif /* defined(SCTP) || defined(SCTP_SUPPORT) */
+ }
+#endif /* defined(INET) */
+#if defined(INET6)
+ if (csum_req & BRIDGE_CSUM_IP6_ALL) {
+ int ip6p_offset;
+
+ if (inner_ether_type != ETHERTYPE_IPV6) {
+ KASSERT(0, ("%s: got an mbuf with an IPv6 csum offloading flag set that contains no IPv6 packet.",
+ __func__));
+ return (m);
+ }
+ ip6p_offset = ip6_lasthdr(m, iph_offset, IPPROTO_IPV6, NULL);
+ if ((ip6p_offset < iph_offset + sizeof(struct ip6_hdr)) ||
+ (m->m_flags & M_PKTHDR && ip6p_offset > m->m_pkthdr.len)) {
+ KASSERT(0, ("%s: offset to the IPv6 payload seems incorrect.",
+ __func__));
+ return (m);
+ }
+
+ if (csum_req & (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
+ in6_delayed_cksum(m, m->m_pkthdr.len - ip6p_offset,
+ ip6p_offset);
+ if (m->m_flags & M_PKTHDR) {
+ m->m_pkthdr.csum_flags &=
+ ~(CSUM_IP6_TCP | CSUM_IP6_UDP);
+ }
+ }
+#if defined(SCTP) || defined(SCTP_SUPPORT)
+ else { /* csum_req & CSUM_IP6_SCTP */
+ sctp_delayed_cksum(m, ip6p_offset);
+ if (m->m_flags & M_PKTHDR) {
+ m->m_pkthdr.csum_flags &= ~CSUM_IP6_SCTP;
+ }
+ }
+#endif /* defined(SCTP) || defined(SCTP_SUPPORT) */
+ }
+#endif /* defined(INET6) */
+ return (m);
+}
+#endif /* defined(INET) || defined(INET6) */
+
/*
* bridge_enqueue:
*
@@ -2442,6 +2594,32 @@
}
M_ASSERTPKTHDR(m); /* We shouldn't transmit mbuf without pkthdr */
+
+#if defined(INET) || defined(INET6)
+ uint32_t csum_req;
+
+ /*
+ * If IP, SCTP, TCP, or UDP header still needs a valid checksum
+ * and the outgoing interface will not compute it for us,
+ * do it here.
+ */
+ csum_req = m->m_pkthdr.csum_flags & BRIDGE_CSUM_ALL &
+ ~dst_ifp->if_hwassist;
+ if (__predict_false(csum_req != 0)) {
+ m = bridge_delayed_cksum(m, csum_req);
+ if (m == NULL) {
+ /*
+ * The mbuf was destroyed during the attempt to
+ * compute and insert the checksum.
+ */
+ if_printf(dst_ifp,
+ "error while computing and inserting IP/SCTP/TCP/UDP checksum\n");
+ if_inc_counter(dst_ifp, IFCOUNTER_OERRORS, 1);
+ continue;
+ }
+ }
+#endif /* defined(INET) || defined(INET6) */
+
/*
* XXXZL: gif(4) requires the af to be saved in csum_data field
* so that gif_transmit() routine can pull it back.
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, May 1, 3:21 AM (5 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
32552053
Default Alt Text
D54948.diff (7 KB)
Attached To
Mode
D54948: bridge: Add checksum offloading
Attached
Detach File
Event Timeline
Log In to Comment