From: Haoze Xie <royenheart@gmail.com>
To: Felix Maurer <fmaurer@redhat.com>, 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>,
royenheart@gmail.com
Subject: Re: [PATCH net v2 1/1] net: hsr: avoid learning unknown senders for local delivery
Date: Tue, 21 Apr 2026 22:39:03 +0800 [thread overview]
Message-ID: <60c9218e-33fe-441e-ac25-1a42fecb29a5@gmail.com> (raw)
In-Reply-To: <adYwjxLBBaLY52Wb@thinkpad>
On 4/8/2026 6:40 PM, Felix Maurer wrote:
> 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
>
I agree and therefore dropped the v2 learning-suppression approach and
reworked the fix toward directly bounding node-table growth in v3 patch.
If the node-table-limit approach in v3 looks acceptable, I can also follow
up later with refinements such as per-device configurability and better
visibility when the table is saturated.
Best regards,
Haoze Xie
>
>> 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-21 14:39 UTC|newest]
Thread overview: 7+ 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
2026-04-14 14:59 ` Sebastian Andrzej Siewior
2026-04-14 23:05 ` Yuan Tan
2026-04-21 14:39 ` Haoze Xie [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=60c9218e-33fe-441e-ac25-1a42fecb29a5@gmail.com \
--to=royenheart@gmail.com \
--cc=bigeasy@linutronix.de \
--cc=bird@lzu.edu.cn \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=fmaurer@redhat.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=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