From: Felix Maurer <fmaurer@redhat.com>
To: Ao Zhou <n05ec@lzu.edu.cn>
Cc: netdev@vger.kernel.org,
Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
"David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>,
Murali Karicheri <m-karicheri2@ti.com>,
Shaurya Rane <ssrane_b23@ee.vjti.ac.in>,
Ingo Molnar <mingo@kernel.org>, Kees Cook <kees@kernel.org>,
Yifan Wu <yifanwucs@gmail.com>,
Juefei Pu <tomapufckgml@gmail.com>,
Yuan Tan <yuantan098@gmail.com>, Xin Liu <bird@lzu.edu.cn>,
Yuqi Xu <xuyuqiabc@gmail.com>, Haoze Xie <royenheart@gmail.com>
Subject: Re: [PATCH net v2 1/1] net: hsr: avoid learning unknown senders for local delivery
Date: Wed, 8 Apr 2026 12:40:15 +0200 [thread overview]
Message-ID: <adYwjxLBBaLY52Wb@thinkpad> (raw)
In-Reply-To: <b053e938014c9bac22f7f687ecc2970f23a2b74a.1775281843.git.royenheart@gmail.com>
On Sat, Apr 04, 2026 at 07:30:47PM +0800, Ao Zhou wrote:
> From: Haoze Xie <royenheart@gmail.com>
>
> Traffic that is directly addressed to the local HSR/PRP master can be
> delivered locally without creating a persistent node entry. Learning one
> node per previously unseen source MAC lets forged sender floods grow
> node_db until the prune timer catches up.
>
> Determine whether a frame is locally exclusive before node lookup and
> skip learning for unknown senders in that case. When no node state
> exists, also skip duplicate discard checks that depend on it.
>
> This keeps locally-destined traffic reachable while avoiding node table
> growth from source-MAC floods in both the PRP SAN path and the HSR/PRP
> tagged sender paths.
I see the problem you are trying to solve here, but I don't think this
patch provides a significant improvement over the current situation.
Yes, this will disable learning of new nodes from regular traffic (and
thereby completely prevent the duplicate discard algorithm from
working). New nodes would only be learned from supervision frames. But
nothing prevents a malicious host in the network from spoofing tons of
supervision frames.
HSR and PRP are supposed to be used in pretty restricted network
environments, so the whole protocol design doesn't really expect
malicious actors in the network and doesn't provide good options to
safeguard against misuse.
IMHO, the only real way to prevent excessive resource use on our side is
to put a limit on these resources. In this case, limit the size of the
node table (bonus: make that limit configurable as Paolo suggested).
Thanks,
Felix
> Fixes: f421436a591d ("net/hsr: Add support for the High-availability Seamless Redundancy protocol (HSRv0)")
> Fixes: 451d8123f897 ("net: prp: add packet handling support")
> Reported-by: Yifan Wu <yifanwucs@gmail.com>
> Reported-by: Juefei Pu <tomapufckgml@gmail.com>
> Co-developed-by: Yuan Tan <yuantan098@gmail.com>
> Signed-off-by: Yuan Tan <yuantan098@gmail.com>
> Suggested-by: Xin Liu <bird@lzu.edu.cn>
> Tested-by: Yuqi Xu <xuyuqiabc@gmail.com>
> Signed-off-by: Haoze Xie <royenheart@gmail.com>
> Signed-off-by: Ao Zhou <n05ec@lzu.edu.cn>
> ---
> changes in v2:
> - generalize the fix beyond PRP SAN traffic and cover HSR/PRP tagged sender floods
> - decide whether learning is needed from local-exclusive delivery instead of protocol-specific SAN checks
> - use the normal NULL return semantics from hsr_get_node() instead of ERR_PTR-based error plumbing
> - skip duplicate-discard state checks when no node state exists
>
> net/hsr/hsr_forward.c | 23 +++++++++++++----------
> net/hsr/hsr_framereg.c | 5 ++++-
> net/hsr/hsr_framereg.h | 2 +-
> 3 files changed, 18 insertions(+), 12 deletions(-)
>
> diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c
> index aefc9b6936ba..15bd17b4ee17 100644
> --- a/net/hsr/hsr_forward.c
> +++ b/net/hsr/hsr_forward.c
> @@ -403,7 +403,8 @@ static void hsr_deliver_master(struct sk_buff *skb, struct net_device *dev,
> int res, recv_len;
>
> was_multicast_frame = (skb->pkt_type == PACKET_MULTICAST);
> - hsr_addr_subst_source(node_src, skb);
> + if (node_src)
> + hsr_addr_subst_source(node_src, skb);
> skb_pull(skb, ETH_HLEN);
> recv_len = skb->len;
> res = netif_rx(skb);
> @@ -545,7 +546,7 @@ static void hsr_forward_do(struct hsr_frame_info *frame)
> /* Don't send frame over port where it has been sent before.
> * Also for SAN, this shouldn't be done.
> */
> - if (!frame->is_from_san &&
> + if (frame->node_src && !frame->is_from_san &&
> hsr->proto_ops->register_frame_out &&
> hsr->proto_ops->register_frame_out(port, frame))
> continue;
> @@ -688,21 +689,25 @@ static int fill_frame_info(struct hsr_frame_info *frame,
> return -EINVAL;
>
> memset(frame, 0, sizeof(*frame));
> + frame->port_rcv = port;
> frame->is_supervision = is_supervision_frame(port->hsr, skb);
> if (frame->is_supervision && hsr->redbox)
> frame->is_proxy_supervision =
> is_proxy_supervision_frame(port->hsr, skb);
>
> + ethhdr = (struct ethhdr *)skb_mac_header(skb);
> + check_local_dest(port->hsr, skb, frame);
> +
> n_db = &hsr->node_db;
> if (port->type == HSR_PT_INTERLINK)
> n_db = &hsr->proxy_node_db;
>
> frame->node_src = hsr_get_node(port, n_db, skb,
> - frame->is_supervision, port->type);
> - if (!frame->node_src)
> - return -1; /* Unknown node and !is_supervision, or no mem */
> + frame->is_supervision, port->type,
> + !frame->is_local_exclusive);
> + if (!frame->node_src && !frame->is_local_exclusive)
> + return -1;
>
> - ethhdr = (struct ethhdr *)skb_mac_header(skb);
> frame->is_vlan = false;
> proto = ethhdr->h_proto;
>
> @@ -720,13 +725,10 @@ static int fill_frame_info(struct hsr_frame_info *frame,
> }
>
> frame->is_from_san = false;
> - frame->port_rcv = port;
> ret = hsr->proto_ops->fill_frame_info(proto, skb, frame);
> if (ret)
> return ret;
>
> - check_local_dest(port->hsr, skb, frame);
> -
> return 0;
> }
>
> @@ -739,7 +741,8 @@ void hsr_forward_skb(struct sk_buff *skb, struct hsr_port *port)
> if (fill_frame_info(&frame, skb, port) < 0)
> goto out_drop;
>
> - hsr_register_frame_in(frame.node_src, port, frame.sequence_nr);
> + if (frame.node_src)
> + hsr_register_frame_in(frame.node_src, port, frame.sequence_nr);
> hsr_forward_do(&frame);
> rcu_read_unlock();
> /* Gets called for ingress frames as well as egress from master port.
> diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c
> index 50996f4de7f9..2bc6f8f154c2 100644
> --- a/net/hsr/hsr_framereg.c
> +++ b/net/hsr/hsr_framereg.c
> @@ -221,7 +221,7 @@ void prp_update_san_info(struct hsr_node *node, bool is_sup)
> */
> struct hsr_node *hsr_get_node(struct hsr_port *port, struct list_head *node_db,
> struct sk_buff *skb, bool is_sup,
> - enum hsr_port_type rx_port)
> + enum hsr_port_type rx_port, bool learn)
> {
> struct hsr_priv *hsr = port->hsr;
> struct hsr_node *node;
> @@ -270,6 +270,9 @@ struct hsr_node *hsr_get_node(struct hsr_port *port, struct list_head *node_db,
> san = true;
> }
>
> + if (!learn)
> + return NULL;
> +
> return hsr_add_node(hsr, node_db, ethhdr->h_source, san, rx_port);
> }
>
> diff --git a/net/hsr/hsr_framereg.h b/net/hsr/hsr_framereg.h
> index c65ecb925734..3d9c88e83090 100644
> --- a/net/hsr/hsr_framereg.h
> +++ b/net/hsr/hsr_framereg.h
> @@ -33,7 +33,7 @@ void hsr_del_self_node(struct hsr_priv *hsr);
> void hsr_del_nodes(struct list_head *node_db);
> struct hsr_node *hsr_get_node(struct hsr_port *port, struct list_head *node_db,
> struct sk_buff *skb, bool is_sup,
> - enum hsr_port_type rx_port);
> + enum hsr_port_type rx_port, bool learn);
> void hsr_handle_sup_frame(struct hsr_frame_info *frame);
> bool hsr_addr_is_self(struct hsr_priv *hsr, unsigned char *addr);
> bool hsr_addr_is_redbox(struct hsr_priv *hsr, unsigned char *addr);
> --
> 2.53.0
>
prev parent reply other threads:[~2026-04-08 10:40 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <cover.1775056603.git.royenheart@outlook.com>
2026-04-02 14:18 ` [PATCH 1/1] net: hsr: avoid learning nodes from ordinary PRP SAN traffic Ao Zhou
2026-04-07 8:40 ` Paolo Abeni
2026-04-04 11:30 ` [PATCH net v2 1/1] net: hsr: avoid learning unknown senders for local delivery Ao Zhou
2026-04-08 10:40 ` Felix Maurer [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=adYwjxLBBaLY52Wb@thinkpad \
--to=fmaurer@redhat.com \
--cc=bigeasy@linutronix.de \
--cc=bird@lzu.edu.cn \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=kees@kernel.org \
--cc=kuba@kernel.org \
--cc=m-karicheri2@ti.com \
--cc=mingo@kernel.org \
--cc=n05ec@lzu.edu.cn \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=royenheart@gmail.com \
--cc=ssrane_b23@ee.vjti.ac.in \
--cc=tomapufckgml@gmail.com \
--cc=xuyuqiabc@gmail.com \
--cc=yifanwucs@gmail.com \
--cc=yuantan098@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox