Re: [PATCH net] macvlan: cap IFLA_MACVLAN_BC_QUEUE_LEN to bound broadcast backlog

From: Xiang Mei

Date: Sat Jul 25 2026 - 21:20:33 EST


On Mon, Jul 6, 2026 at 4:25 PM Thomas Karlsson
<thomas.karlsson@xxxxxxxxx> wrote:
>
> Hello Xiang,
>
> Let me elaborate on our use-case with a little example calculation. Lets say medium latency real-time audio sent at 1ms per packet. This would amount to 1000 packets per second per stream. Scaling that to 600-800 unique audio streams would result in 6-800k pps. This would be a typical use case for our servers. The macvlan BC queue len need adjustment to be able to swallow short scheduling/processing delays in these workloads or packet loss start to show.
>
> Switching to even lower latency (although not recommended) or increasing the number of unique streams could of course increase the load even further.
>
> As for a recommended upper limit, I'm not sure. Like I said, we use 100k today and are currently running our workload extremely stable with that. Do we have some margin in that number? Probably, but I'm not able to quantify exactly how much.
>
> To account for someone using it even more aggressively, 128 or 256k could perhaps be a resonable upper limit?
>
> Best regards,
> Thomas
>

Thanks Thomas, I tested those. They suggest adding a limit is limited,
I would like to discuss an alternative before sending a v2.

The memory the backlog pins depends on three things the caller picks:
the slot count, the frame size (the queue counts skbs, not bytes, and a
self-created veth takes ETH_MAX_MTU), and the number of lower devices
(the limit is per port, and nothing counts ports). They multiply. On a
3.5G guest, from an unprivileged user+net namespace:

131072 slots, 9000-byte frames -> survived, 104 MB free
262144 slots, 9000-byte frames -> OOM, host dead
4096 slots, 65000-byte frames, 64 ports -> MemAvailable 0

No value is both safe on a small host and large enough for real
multicast workloads: the two are ~25x apart, and the safe line depends
on the victim's RAM.

So I am considering a permission check instead. What separates the two
cases is the caller: a production server is configured by real root.

--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -1335,6 +1335,21 @@ static int macvlan_validate(struct nlattr
*tb[], struct nlattr *data[],
if (!data)
return 0;

+ /* bc_queue_len_used is the max of every bc_queue_len_req on the port
+ * and the only bound on port->bc_queue. rtnetlink checks CAP_NET_ADMIN
+ * against the target netns only, which a user namespace owner holds
+ * over a lower device it created itself, so require privilege in the
+ * initial user namespace to exceed the default.
+ */
+ if (data[IFLA_MACVLAN_BC_QUEUE_LEN] &&
+ nla_get_u32(data[IFLA_MACVLAN_BC_QUEUE_LEN]) >
+ MACVLAN_DEFAULT_BC_QUEUE_LEN &&
+ !capable(CAP_NET_ADMIN)) {
+ NL_SET_ERR_MSG_ATTR(extack, data[IFLA_MACVLAN_BC_QUEUE_LEN],
+ "bc_queue_len above the default requires CAP_NET_ADMIN in the
initial user namespace");
+ return -EPERM;
+ }
+
if (data[IFLA_MACVLAN_FLAGS] &&
nla_get_u16(data[IFLA_MACVLAN_FLAGS]) & ~(MACVLAN_FLAG_NOPROMISC |
MACVLAN_FLAG_NODST))

->validate() runs for both RTM_NEWLINK and changelink before any state
changes, so one check covers both. With it, 0xffffffff and 100000 are
refused from a namespace while real root still gets 100000.

It does not fix everything: 1000 skbs of ETH_MAX_MTU is ~65 MB per port,
and nothing counts ports. At the untouched default I still got a 1500 MB
workload OOM-killed given enough ports and large frames, identically on
patched and unpatched kernels since the check is inert there. Bounding
the backlog by bytes rather than skb count would cover that, and would
let small-frame workloads queue more rather than less; that looks like
net-next material to me.

Separate from what Doruk Tan Ozturk reported: his check is against the
lower device's netns and does not cover this case, where the caller does
administer that device. Both seem wanted.

Does this look like a reasonable direction, or should I go straight to
byte-based accounting? I am also unsure whether gating a link attribute
on init-userns privilege is acceptable here.

Thanks,
Xiang
> ________________________________________
> From: Xiang Mei <xmei5@xxxxxxx>
> Sent: Tuesday, 7 July 2026 00:34
> To: Thomas Karlsson <thomas.karlsson@xxxxxxxxx>
> Cc: Andrew Lunn <andrew+netdev@xxxxxxx>; David S . Miller <davem@xxxxxxxxxxxxx>; Eric Dumazet <edumazet@xxxxxxxxxx>; Jakub Kicinski <kuba@xxxxxxxxxx>; Paolo Abeni <pabeni@xxxxxxxxxx>; netdev@xxxxxxxxxxxxxxx <netdev@xxxxxxxxxxxxxxx>; linux-kernel@xxxxxxxxxxxxxxx <linux-kernel@xxxxxxxxxxxxxxx>; AutonomousCodeSecurity@xxxxxxxxxxxxx <AutonomousCodeSecurity@xxxxxxxxxxxxx>; tgopinath@xxxxxxxxxxxxxxxxxxx <tgopinath@xxxxxxxxxxxxxxxxxxx>; kys@xxxxxxxxxxxxx <kys@xxxxxxxxxxxxx>
> Subject: Re: [PATCH net] macvlan: cap IFLA_MACVLAN_BC_QUEUE_LEN to bound broadcast backlog
>
> On Mon, Jul 6, 2026 at 3:31 PM Thomas Karlsson
> <thomas.karlsson@xxxxxxxxx> wrote:
> >
> > Dear all,
> >
> > While restricting a lower max than MAX U32 may be warranted the proposed limit of 4096 is way too small for high throughput multicast traffic.
> >
> > We currently run many production servers with the BC queue len set to a value of 100 000.
> >
>
> Thanks, Thomas, for your feedback. 4096 could be small.
> We would like to hear your suggested values, and we would like to do
> some tests with the value you suggest.
>
> Xiang
>
>
> >
> > Best regards,
> > Thomas Karlsson
> >
> >
> > Sent from Outlook for Android
> > ________________________________
> > From: Xiang Mei (Microsoft) <xmei5@xxxxxxx>
> > Sent: Monday, 06 July 2026 23:25:56
> > To: Andrew Lunn <andrew+netdev@xxxxxxx>; David S . Miller <davem@xxxxxxxxxxxxx>; Eric Dumazet <edumazet@xxxxxxxxxx>; Jakub Kicinski <kuba@xxxxxxxxxx>; Paolo Abeni <pabeni@xxxxxxxxxx>
> > Cc: Thomas Karlsson <thomas.karlsson@xxxxxxxxx>; netdev@xxxxxxxxxxxxxxx <netdev@xxxxxxxxxxxxxxx>; linux-kernel@xxxxxxxxxxxxxxx <linux-kernel@xxxxxxxxxxxxxxx>; AutonomousCodeSecurity@xxxxxxxxxxxxx <AutonomousCodeSecurity@xxxxxxxxxxxxx>; tgopinath@xxxxxxxxxxxxxxxxxxx <tgopinath@xxxxxxxxxxxxxxxxxxx>; kys@xxxxxxxxxxxxx <kys@xxxxxxxxxxxxx>; Xiang Mei (Microsoft) <xmei5@xxxxxxx>
> > Subject: [PATCH net] macvlan: cap IFLA_MACVLAN_BC_QUEUE_LEN to bound broadcast backlog
> >
> > The netlink policy for IFLA_MACVLAN_BC_QUEUE_LEN accepts any u32, and the
> > value becomes port->bc_queue_len_used, the only cap on how many skbs
> > macvlan_broadcast_enqueue() may queue on port->bc_queue. An unprivileged
> > user owning a user+net namespace (CAP_NET_ADMIN is checked only against
> > the target netns) can set it to 0xffffffff, so the backlog check never
> > trips and every broadcast frame is skb_clone()'d with GFP_ATOMIC and
> > queued. When RX softirq outpaces the bc_work drain (e.g. many ALLMULTI
> > macvlans under a broadcast flood), the queue grows unbounded and
> > OOMs/panics the host.
> >
> > Bound the value with NLA_POLICY_MAX() at 4096, 4x the default of 1000.
> > This keeps headroom above the default while capping the backlog; values
> > above the cap are now rejected with -ERANGE at netlink parse time.
> >
> > Out of memory: Killed process 141 (su) UID:0
> > Kernel panic - not syncing: System is deadlocked on memory
> > Call Trace:
> > vpanic (kernel/panic.c:650)
> > panic (kernel/panic.c:787)
> > out_of_memory (mm/oom_kill.c:1166)
> > __alloc_frozen_pages_noprof (mm/page_alloc.c:4914)
> > alloc_pages_mpol (mm/mempolicy.c:2490)
> > folio_alloc_noprof (mm/mempolicy.c:2591)
> > filemap_fault (mm/filemap.c:3565)
> >
> > Fixes: d4bff72c8401 ("macvlan: Support for high multicast packet rate")
> > Reported-by: AutonomousCodeSecurity@xxxxxxxxxxxxx
> > Signed-off-by: Xiang Mei (Microsoft) <xmei5@xxxxxxx>
> > ---
> > drivers/net/macvlan.c | 3 ++-
> > 1 file changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
> > index c40fa331836b..d4cede6393b0 100644
> > --- a/drivers/net/macvlan.c
> > +++ b/drivers/net/macvlan.c
> > @@ -37,6 +37,7 @@
> > #define MACVLAN_HASH_BITS 8
> > #define MACVLAN_HASH_SIZE (1<<MACVLAN_HASH_BITS)
> > #define MACVLAN_DEFAULT_BC_QUEUE_LEN 1000
> > +#define MACVLAN_MAX_BC_QUEUE_LEN 4096
> >
> > #define MACVLAN_F_PASSTHRU 1
> > #define MACVLAN_F_ADDRCHANGE 2
> > @@ -1755,7 +1756,7 @@ static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = {
> > [IFLA_MACVLAN_MACADDR] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
> > [IFLA_MACVLAN_MACADDR_DATA] = { .type = NLA_NESTED },
> > [IFLA_MACVLAN_MACADDR_COUNT] = { .type = NLA_U32 },
> > - [IFLA_MACVLAN_BC_QUEUE_LEN] = { .type = NLA_U32 },
> > + [IFLA_MACVLAN_BC_QUEUE_LEN] = NLA_POLICY_MAX(NLA_U32, MACVLAN_MAX_BC_QUEUE_LEN),
> > [IFLA_MACVLAN_BC_QUEUE_LEN_USED] = { .type = NLA_REJECT },
> > [IFLA_MACVLAN_BC_CUTOFF] = { .type = NLA_S32 },
> > };
> > --
> > 2.43.0
> >