* [PATCH 1/1] net: hsr: avoid learning nodes from ordinary PRP SAN traffic
[not found] <cover.1775056603.git.royenheart@outlook.com>
@ 2026-04-02 14:18 ` 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
1 sibling, 1 reply; 3+ messages in thread
From: Ao Zhou @ 2026-04-02 14:18 UTC (permalink / raw)
To: netdev
Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Felix Maurer, Murali Karicheri, Shaurya Rane,
Sebastian Andrzej Siewior, Ingo Molnar, Kees Cook, Yifan Wu,
Juefei Pu, Yuan Tan, Xin Liu, Yuqi Xu, Ao Zhou
From: Haoze Xie <royenheart@gmail.com>
PRP slave ports accept ordinary SAN traffic and forward it to the
master device without needing a persistent node entry. Creating one
node per previously unseen SAN source lets arbitrary source MAC floods
grow node_db until the prune timer catches up.
Keep the receive path for ordinary PRP SAN traffic, but stop learning a
new node when the frame is untagged and does not carry a PRP trailer.
Continue to deliver the frame locally and only keep node state for
actual HSR/PRP senders or nodes that have already been learned.
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>
---
net/hsr/hsr_forward.c | 14 ++++++++++----
net/hsr/hsr_framereg.c | 16 +++++++++++++---
2 files changed, 23 insertions(+), 7 deletions(-)
diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c
index aefc9b6936ba..5fbfc42997d2 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);
@@ -699,8 +700,12 @@ static int fill_frame_info(struct hsr_frame_info *frame,
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 */
+ if (IS_ERR(frame->node_src)) {
+ ret = PTR_ERR(frame->node_src);
+ if (ret != -ENOENT)
+ return ret;
+ frame->node_src = NULL;
+ }
ethhdr = (struct ethhdr *)skb_mac_header(skb);
frame->is_vlan = false;
@@ -739,7 +744,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..13e1a0484879 100644
--- a/net/hsr/hsr_framereg.c
+++ b/net/hsr/hsr_framereg.c
@@ -230,7 +230,7 @@ struct hsr_node *hsr_get_node(struct hsr_port *port, struct list_head *node_db,
bool san = false;
if (!skb_mac_header_was_set(skb))
- return NULL;
+ return ERR_PTR(-EINVAL);
ethhdr = (struct ethhdr *)skb_mac_header(skb);
@@ -263,14 +263,24 @@ struct hsr_node *hsr_get_node(struct hsr_port *port, struct list_head *node_db,
ethhdr->h_proto == htons(ETH_P_HSR)) {
/* Check if skb contains hsr_ethhdr */
if (skb->mac_len < sizeof(struct hsr_ethhdr))
- return NULL;
+ return ERR_PTR(-EINVAL);
} else {
rct = skb_get_PRP_rct(skb);
if (!rct && rx_port != HSR_PT_MASTER)
san = true;
}
- return hsr_add_node(hsr, node_db, ethhdr->h_source, san, rx_port);
+ /* PRP accepts ordinary SAN traffic on slave ports without learning a
+ * persistent node entry.
+ */
+ if (hsr->prot_version == PRP_V1 && san)
+ return ERR_PTR(-ENOENT);
+
+ node = hsr_add_node(hsr, node_db, ethhdr->h_source, san, rx_port);
+ if (!node)
+ return ERR_PTR(-ENOMEM);
+
+ return node;
}
static bool hsr_seq_block_is_old(struct hsr_seq_block *block)
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH net v2 1/1] net: hsr: avoid learning unknown senders for local delivery
[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-04 11:30 ` Ao Zhou
1 sibling, 0 replies; 3+ messages in thread
From: Ao Zhou @ 2026-04-04 11:30 UTC (permalink / raw)
To: netdev, Sebastian Andrzej Siewior
Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Felix Maurer, Murali Karicheri, Shaurya Rane,
Ingo Molnar, Kees Cook, Yifan Wu, Juefei Pu, Yuan Tan, Xin Liu,
Yuqi Xu, Ao Zhou, Haoze Xie
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.
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
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH 1/1] net: hsr: avoid learning nodes from ordinary PRP SAN traffic
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
0 siblings, 0 replies; 3+ messages in thread
From: Paolo Abeni @ 2026-04-07 8:40 UTC (permalink / raw)
To: Ao Zhou, netdev
Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Simon Horman,
Felix Maurer, Murali Karicheri, Shaurya Rane,
Sebastian Andrzej Siewior, Ingo Molnar, Kees Cook, Yifan Wu,
Juefei Pu, Yuan Tan, Xin Liu, Yuqi Xu
On 4/2/26 4:18 PM, Ao Zhou wrote:
> From: Haoze Xie <royenheart@gmail.com>
>
> PRP slave ports accept ordinary SAN traffic and forward it to the
> master device without needing a persistent node entry. Creating one
> node per previously unseen SAN source lets arbitrary source MAC floods
> grow node_db until the prune timer catches up.
>
> Keep the receive path for ordinary PRP SAN traffic, but stop learning a
> new node when the frame is untagged and does not carry a PRP trailer.
> Continue to deliver the frame locally and only keep node state for
> actual HSR/PRP senders or nodes that have already been learned.
It's not clear to me what prevents the rouge sender from always
including a valid PRP trailer, thus still causing the issue addressed
here. Some rationale needs to be included, or possibly limit the amount
of newly created nodes to some configurable maximum.
> 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>
> ---
> net/hsr/hsr_forward.c | 14 ++++++++++----
> net/hsr/hsr_framereg.c | 16 +++++++++++++---
> 2 files changed, 23 insertions(+), 7 deletions(-)
>
> diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c
> index aefc9b6936ba..5fbfc42997d2 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);
> @@ -699,8 +700,12 @@ static int fill_frame_info(struct hsr_frame_info *frame,
>
> 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 */
> + if (IS_ERR(frame->node_src)) {
> + ret = PTR_ERR(frame->node_src);
> + if (ret != -ENOENT)
> + return ret;
> + frame->node_src = NULL;
> + }
>
> ethhdr = (struct ethhdr *)skb_mac_header(skb);
> frame->is_vlan = false;
> @@ -739,7 +744,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);
I *think* the hsr_forward_do() could unconditionally dereference
node_src in:
hsr->proto_ops->register_frame_out -> {prp,hsr}_register_frame_out ->
hsr_check_duplicate:
node = frame->node_src;
if (WARN_ON_ONCE(port_type >= node->seq_port_cnt))
/P
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-04-07 8:40 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox