net: Check per-flow priority code point for untagged traffic

Commit 868aabb470 introduced per-flow priority. There's a defect in the
logic for untagged traffic, it does not check M_VLANTAG set in the mbuf
packet header or MTAG_8021Q/MTAG_8021Q_PCP_OUT tag set by firewall, then
can result missing desired priority in the outbound packets.

For mbuf packet with M_VLANTAG in header, some interfaces happen to work
due to bug in the drivers mentioned in D39499. As modern interfaces have
VLAN hardware offloading, the defect is barely noticeable unless the
feature per-flow priority is widely tested.

As a side effect of this defect, the soft padding to work around buggy
bridges is bypassed. That may result in regression if soft padding is
requested.

PR:		273431
Discussed with:	kib
Fixes:	868aabb470 Add IP(V6)_VLAN_PCP to set 802.1 priority per-flow
MFC after:	1 week
Differential Revision:	https://reviews.freebsd.org/D39536
This commit is contained in:
Zhenlei Huang 2023-09-06 18:15:14 +08:00
parent cb1a0aab4f
commit 49d6743da1

View file

@ -123,6 +123,8 @@ static int ether_resolvemulti(struct ifnet *, struct sockaddr **,
struct sockaddr *);
static int ether_requestencap(struct ifnet *, struct if_encap_req *);
static inline bool ether_do_pcp(struct ifnet *, struct mbuf *);
#define senderr(e) do { error = (e); goto bad;} while (0)
static void
@ -470,11 +472,7 @@ ether_set_pcp(struct mbuf **mp, struct ifnet *ifp, uint8_t pcp)
int
ether_output_frame(struct ifnet *ifp, struct mbuf *m)
{
uint8_t pcp;
pcp = ifp->if_pcp;
if (pcp != IFNET_PCP_NONE && ifp->if_type != IFT_L2VLAN &&
!ether_set_pcp(&m, ifp, pcp))
if (ether_do_pcp(ifp, m) && !ether_set_pcp(&m, ifp, ifp->if_pcp))
return (0);
if (PFIL_HOOKED_OUT(V_link_pfil_head))
@ -1400,6 +1398,19 @@ SYSCTL_INT(_net_link_vlan, OID_AUTO, mtag_pcp, CTLFLAG_RW | CTLFLAG_VNET,
&VNET_NAME(vlan_mtag_pcp), 0,
"Retain VLAN PCP information as packets are passed up the stack");
static inline bool
ether_do_pcp(struct ifnet *ifp, struct mbuf *m)
{
if (ifp->if_type == IFT_L2VLAN)
return (false);
if (ifp->if_pcp != IFNET_PCP_NONE || (m->m_flags & M_VLANTAG) != 0)
return (true);
if (V_vlan_mtag_pcp &&
m_tag_locate(m, MTAG_8021Q, MTAG_8021Q_PCP_OUT, NULL) != NULL)
return (true);
return (false);
}
bool
ether_8021q_frame(struct mbuf **mp, struct ifnet *ife, struct ifnet *p,
const struct ether_8021q_tag *qtag)