RE: [PATCH v2 net-next 5/7] net: dsa: netc: enable ingress port filtering lookup by default

"Wei Fang (OSS)" <[email protected]>
Newsgroups dev.linux.lists.sashiko-reviews,dev.linux.lists.imx,org.kernel.vger.netdev
Message-ID <GV2PR04MB11739F27D5C3B374E6667293E88DE2@GV2PR04MB11739.eurprd04.prod.outlook.com>
> > @@ -1753,8 +1757,6 @@ static int netc_port_add_host_flood_rule(struct
> netc_port *np,
> >  	np->uc = uc;
> >  	np->mc = mc;
> >  	np->ipft_hf_eid = host_flood->entry_id;
> > -	/* Enable ingress port filter table lookup */
> > -	netc_port_wr(np, NETC_PIPFCR, PIPFCR_EN);
> >
> >  free_host_flood:
> >  	kfree(host_flood);
> 
> [Severity: High]
> This isn't a bug introduced by this patch, but does
> netc_port_add_host_flood_rule() execute sleepable operations in atomic
> context?
> 
> When userspace changes interface flags (e.g., ip link set dev ethX promisc on),
> the network core calls ndo_change_rx_flags while holding
> netif_addr_lock_bh(),
> which disables bottom halves and establishes an atomic context.
> 
> The DSA core delegates this to the port_set_host_flood callback, which calls
> netc_port_set_host_flood() -> netc_port_add_host_flood_rule() synchronously.
> 
> Looking at the code, do these functions execute sleepable operations?
> 
> - Allocating memory using GFP_KERNEL (via kzalloc_obj() in
>   netc_port_add_host_flood_rule())
> - Acquiring a sleeping lock (via mutex_lock() in ntmp_select_and_lock_cbdr())
> - Yielding to the scheduler (via read_poll_timeout() with sleep=true in
>   netc_xmit_ntmp_cmd())
> 
> Could this lead to a "scheduling while atomic" panic if
> CONFIG_DEBUG_ATOMIC_SLEEP is enabled? Should this hardware
> configuration
> be deferred to a workqueue?
> 

This a false positive, dev_change_rx_flags() is not called in the
netif_addr_lock_bh context.

dev_change_rx_flags()
├── __dev_set_promiscuity()
│   ├── netif_set_promiscuity()
│   │   └── dev_set_promiscuity()          [netdev_lock_ops = mutex]
│   ├── __dev_change_flags()
│   │   ├── netif_change_flags()
│   │   │   ├── do_setlink()               [rtnl_nets_lock = mutex]
│   │   │   ├── dev_change_flags()         [netdev_lock_ops = mutex]
│   │   │   └── vlan_dev_work/ndo_work     [netdev_lock_ops = mutex]
│   │   └── rtnl_configure_link()          [netdev_lock_ops = mutex]
│   └── netif_rx_mode_run()                [might_sleep() + netdev_assert_locked_ops_compat]
│       ├── netif_rx_mode_sync()           [netdev_lock_ops = mutex]
│       └── netdev_work_proc()             [rtnl_lock + netdev_lock_ops = mutex]
├── netif_set_allmulti()
│   ├── __dev_change_flags()               (Same as above)
│   └── dev_set_allmulti()                 [netdev_lock_ops = mutex]
└── __dev_change_flags()                   (Same as above)

__dev_set_rx_mode() is called with netif_addr_lock_bh() held, placing it
in atomic context. However, drivers implementing ndo_change_rx_flags
are not invoked directly from this path.

Inside __dev_set_rx_mode(), there is an explicit guard:

if (ops->ndo_set_rx_mode_async || ops->ndo_change_rx_flags ||
    netdev_need_ops_lock(dev)) {
    netif_rx_mode_queue(dev);
    return;
}

If a driver implements ndo_change_rx_flags, the function
immediately enqueues a work item via netif_rx_mode_queue() and
returns without invoking any driver callback. The actual
ndo_change_rx_flags call is deferred to a workqueue, which runs in
process context under rtnl_lock and netdev_lock_ops() — both mutexes
that allow sleeping.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.