diff options
author | Konstantin Belousov <kib@FreeBSD.org> | 2021-03-29 09:03:07 +0000 |
---|---|---|
committer | Konstantin Belousov <kib@FreeBSD.org> | 2021-03-31 11:38:26 +0000 |
commit | baacf701372bfeb3927c6b9e0b85d6eff198c6a3 (patch) | |
tree | 86d251406f7f8f96b463b042996948f29d4a214f | |
parent | e243367b644562c9410b39f8d78dafdb7e785d85 (diff) | |
download | src-baacf701372bfeb3927c6b9e0b85d6eff198c6a3.tar.gz src-baacf701372bfeb3927c6b9e0b85d6eff198c6a3.zip |
vxlan: correct interface MTU when using hw offloads
Otherwise it breaks when offloading like checksum or TSO are used,
because second (encapsulated) ip_output() processing passes fragments of
the encapsulated packet down to the hardware interface.
Diagnosed by: hselasky
Reviewed by: np
Sponsored by: Nvidia Networking / Mellanox Technologies
MFC after: 1 week
Differential revision: https://reviews.freebsd.org/D29501
-rw-r--r-- | share/man/man4/vxlan.4 | 15 | ||||
-rw-r--r-- | sys/net/if_vxlan.c | 17 |
2 files changed, 28 insertions, 4 deletions
diff --git a/share/man/man4/vxlan.4 b/share/man/man4/vxlan.4 index 1848897d97c9..99f3411c02d2 100644 --- a/share/man/man4/vxlan.4 +++ b/share/man/man4/vxlan.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 17, 2020 +.Dd March 30, 2021 .Dt VXLAN 4 .Os .Sh NAME @@ -175,13 +175,24 @@ The .Nm specification recommends the physical network MTU be configured to use jumbo frames to accommodate the encapsulated frame size. +.Pp +By default, the +.Nm +driver sets its MTU to usual ethernet MTU of 1500 bytes, reduced by +the size of vxlan headers prepended to the encapsulated packets. +.Pp Alternatively, the .Xr ifconfig 8 .Cm mtu -command may be used to reduce the MTU size on the +command may be used to set the fixed MTU size on the .Nm interface to allow the encapsulated frame to fit in the current MTU of the physical network. +If the +.Cm mtu +command was used, system no longer adjust the +.Nm +interface MTU on routing or address changes. .Sh HARDWARE The .Nm diff --git a/sys/net/if_vxlan.c b/sys/net/if_vxlan.c index 0d69244ce64b..f56ec23540a7 100644 --- a/sys/net/if_vxlan.c +++ b/sys/net/if_vxlan.c @@ -171,6 +171,7 @@ struct vxlan_softc { #define VXLAN_FLAG_INIT 0x0001 #define VXLAN_FLAG_TEARDOWN 0x0002 #define VXLAN_FLAG_LEARN 0x0004 +#define VXLAN_FLAG_USER_MTU 0x0008 uint32_t vxl_port_hash_key; uint16_t vxl_min_port; @@ -1620,6 +1621,8 @@ vxlan_setup_interface_hdrlen(struct vxlan_softc *sc) { struct ifnet *ifp; + VXLAN_LOCK_WASSERT(sc); + ifp = sc->vxl_ifp; ifp->if_hdrlen = ETHER_HDR_LEN + sizeof(struct vxlanudphdr); @@ -1627,6 +1630,9 @@ vxlan_setup_interface_hdrlen(struct vxlan_softc *sc) ifp->if_hdrlen += sizeof(struct ip); else if (VXLAN_SOCKADDR_IS_IPV6(&sc->vxl_dst_addr) != 0) ifp->if_hdrlen += sizeof(struct ip6_hdr); + + if ((sc->vxl_flags & VXLAN_FLAG_USER_MTU) == 0) + ifp->if_mtu = ETHERMTU - ifp->if_hdrlen; } static int @@ -2354,10 +2360,14 @@ vxlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; case SIOCSIFMTU: - if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > VXLAN_MAX_MTU) + if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > VXLAN_MAX_MTU) { error = EINVAL; - else + } else { + VXLAN_WLOCK(sc); ifp->if_mtu = ifr->ifr_mtu; + sc->vxl_flags |= VXLAN_FLAG_USER_MTU; + VXLAN_WUNLOCK(sc); + } break; case SIOCSIFCAP: @@ -3211,7 +3221,10 @@ vxlan_clone_create(struct if_clone *ifc, int unit, caddr_t params) ether_ifattach(ifp, sc->vxl_hwaddr.octet); ifp->if_baudrate = 0; + + VXLAN_WLOCK(sc); vxlan_setup_interface_hdrlen(sc); + VXLAN_WUNLOCK(sc); return (0); |