* [PATCH] net: hsr: Provide RedBox support
@ 2024-03-06 12:38 Lukasz Majewski
2024-03-06 13:11 ` Dan Carpenter
2024-03-06 13:33 ` Wojciech Drewek
0 siblings, 2 replies; 3+ messages in thread
From: Lukasz Majewski @ 2024-03-06 12:38 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Eric Dumazet, Florian Fainelli, Vladimir Oltean,
David S. Miller, Jakub Kicinski, Oleksij Rempel, Tristram.Ha,
Sebastian Andrzej Siewior, Paolo Abeni, Ravi Gunasekaran,
Simon Horman, Wojciech Drewek, Nikita Zhandarovich,
Murali Karicheri, Dan Carpenter, Ziyang Xuan, Kristian Overskeid,
Matthieu Baerts, linux-kernel, Lukasz Majewski
This patch provides RedBox support (HSR-SAN to be more precise) for HSR
networks. It implements the 'Mode U' without optimizations for traffic
reduction (only supports preventing sending HSR supervisory frames to
Port C and not forwarding to HSR ring frames addressed to Port C).
The corresponding patch to modify iptable2 sources has already been sent:
https://lore.kernel.org/netdev/20240226124110.37892211@hermes.local/T/
Testing procedure:
------------------
The EVB-KSZ9477 has been used for testing on net-next branch
(SHA1: 709776ea8562).
Ports 4/5 were used for SW managed HSR (hsr1) as first hsr0 for ports 1/2
(with HW offloading for ksz9477) was created. Port 3 has been used as
interlink port (USB-ETH dongle).
Configuration - RedBox (EVB-KSZ9477):
ifconfig lan1 down;ifconfig lan2 down
ip link add name hsr0 type hsr slave1 lan1 slave2 lan2 supervision 45 version 1
ip link add name hsr1 type hsr slave1 lan4 slave2 lan5 interlink lan3 supervision 45 version 1
ifconfig lan4 up;ifconfig lan5 up
ifconfig lan3 up
ifconfig hsr1 192.168.0.11 up
Configuration - DAN-H (EVB-KSZ9477):
ifconfig lan1 down;ifconfig lan2 down
ip link add name hsr0 type hsr slave1 lan1 slave2 lan2 supervision 45 version 1
ip link add name hsr1 type hsr slave1 lan4 slave2 lan5 supervision 45 version 1
ifconfig lan4 up;ifconfig lan5 up
ifconfig hsr1 192.168.0.12 up
This approach uses only SW based HSR devices (hsr1).
Signed-off-by: Lukasz Majewski <lukma@denx.de>
---
include/uapi/linux/if_link.h | 1 +
net/hsr/hsr_device.c | 32 +++++++++++++++--
net/hsr/hsr_device.h | 4 +--
net/hsr/hsr_forward.c | 66 +++++++++++++++++++++++++++++++-----
net/hsr/hsr_framereg.c | 55 ++++++++++++++++++++++++++++++
net/hsr/hsr_framereg.h | 6 ++++
net/hsr/hsr_main.h | 7 ++++
net/hsr/hsr_netlink.c | 29 ++++++++++++++--
net/hsr/hsr_slave.c | 1 +
9 files changed, 185 insertions(+), 16 deletions(-)
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index ab9bcff96e4d..b93a3acdd83f 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -1770,6 +1770,7 @@ enum {
IFLA_HSR_PROTOCOL, /* Indicate different protocol than
* HSR. For example PRP.
*/
+ IFLA_HSR_INTERLINK, /* HSR interlink network device */
__IFLA_HSR_MAX,
};
diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
index 904cd8f8f830..4288d2b74472 100644
--- a/net/hsr/hsr_device.c
+++ b/net/hsr/hsr_device.c
@@ -156,6 +156,9 @@ static int hsr_dev_open(struct net_device *dev)
case HSR_PT_SLAVE_B:
designation = "Slave B";
break;
+ case HSR_PT_INTERLINK:
+ designation = "Interlink";
+ break;
default:
designation = "Unknown";
}
@@ -295,6 +298,7 @@ static void send_hsr_supervision_frame(struct hsr_port *master,
struct hsr_priv *hsr = master->hsr;
__u8 type = HSR_TLV_LIFE_CHECK;
struct hsr_sup_payload *hsr_sp;
+ struct hsr_sup_tlv *hsr_stlv;
struct hsr_sup_tag *hsr_stag;
struct sk_buff *skb;
@@ -334,6 +338,16 @@ static void send_hsr_supervision_frame(struct hsr_port *master,
hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload));
ether_addr_copy(hsr_sp->macaddress_A, master->dev->dev_addr);
+ if (hsr->redbox) {
+ hsr_stlv = skb_put(skb, sizeof(struct hsr_sup_tlv));
+ hsr_stlv->HSR_TLV_type = PRP_TLV_REDBOX_MAC;
+ hsr_stlv->HSR_TLV_length = sizeof(struct hsr_sup_payload);
+
+ /* Payload: MacAddressRedBox */
+ hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload));
+ ether_addr_copy(hsr_sp->macaddress_A, hsr->macaddress_redbox);
+ }
+
if (skb_put_padto(skb, ETH_ZLEN)) {
spin_unlock_bh(&hsr->seqnr_lock);
return;
@@ -544,8 +558,8 @@ static const unsigned char def_multicast_addr[ETH_ALEN] __aligned(2) = {
};
int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
- unsigned char multicast_spec, u8 protocol_version,
- struct netlink_ext_ack *extack)
+ struct net_device *interlink, unsigned char multicast_spec,
+ u8 protocol_version, struct netlink_ext_ack *extack)
{
bool unregister = false;
struct hsr_priv *hsr;
@@ -554,6 +568,7 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
hsr = netdev_priv(hsr_dev);
INIT_LIST_HEAD(&hsr->ports);
INIT_LIST_HEAD(&hsr->node_db);
+ INIT_LIST_HEAD(&hsr->proxy_node_db);
spin_lock_init(&hsr->list_lock);
eth_hw_addr_set(hsr_dev, slave[0]->dev_addr);
@@ -579,6 +594,7 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
/* Overflow soon to find bugs easier: */
hsr->sequence_nr = HSR_SEQNR_START;
hsr->sup_sequence_nr = HSR_SUP_SEQNR_START;
+ hsr->interlink_sequence_nr = HSR_SEQNR_START;
timer_setup(&hsr->announce_timer, hsr_announce, 0);
timer_setup(&hsr->prune_timer, hsr_prune_nodes, 0);
@@ -614,6 +630,18 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
if (res)
goto err_unregister;
+ if (interlink) {
+ res = hsr_add_port(hsr, interlink, HSR_PT_INTERLINK, extack);
+ if (res)
+ goto err_unregister;
+
+ hsr->redbox = true;
+ ether_addr_copy(hsr->macaddress_redbox, interlink->dev_addr);
+ timer_setup(&hsr->prune_proxy_timer, hsr_prune_proxy_nodes, 0);
+ mod_timer(&hsr->prune_proxy_timer,
+ jiffies + msecs_to_jiffies(PRUNE_PROXY_PERIOD));
+ }
+
hsr_debugfs_init(hsr, hsr_dev);
mod_timer(&hsr->prune_timer, jiffies + msecs_to_jiffies(PRUNE_PERIOD));
diff --git a/net/hsr/hsr_device.h b/net/hsr/hsr_device.h
index 9060c92168f9..655284095b78 100644
--- a/net/hsr/hsr_device.h
+++ b/net/hsr/hsr_device.h
@@ -16,8 +16,8 @@
void hsr_del_ports(struct hsr_priv *hsr);
void hsr_dev_setup(struct net_device *dev);
int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
- unsigned char multicast_spec, u8 protocol_version,
- struct netlink_ext_ack *extack);
+ struct net_device *interlink, unsigned char multicast_spec,
+ u8 protocol_version, struct netlink_ext_ack *extack);
void hsr_check_carrier_and_operstate(struct hsr_priv *hsr);
int hsr_get_max_mtu(struct hsr_priv *hsr);
#endif /* __HSR_DEVICE_H */
diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c
index 5d68cb181695..8ae7066846e2 100644
--- a/net/hsr/hsr_forward.c
+++ b/net/hsr/hsr_forward.c
@@ -390,9 +390,29 @@ bool prp_drop_frame(struct hsr_frame_info *frame, struct hsr_port *port)
bool hsr_drop_frame(struct hsr_frame_info *frame, struct hsr_port *port)
{
+ struct sk_buff *skb;
+
if (port->dev->features & NETIF_F_HW_HSR_FWD)
return prp_drop_frame(frame, port);
+ /* RedBox specific frames dropping policies
+ *
+ * Do not send HSR supervisory frames to SAN devices
+ */
+ if (frame->is_supervision && port->type == HSR_PT_INTERLINK)
+ return true;
+
+ /* Do not forward to other HSR port (A or B) unicast frames which
+ * are addressed to interlink port (and are in the ProxyNodeTable).
+ */
+ skb = frame->skb_hsr;
+ if (skb && prp_drop_frame(frame, port) &&
+ is_unicast_ether_addr(eth_hdr(skb)->h_dest) &&
+ hsr_is_node_in_db(&port->hsr->proxy_node_db,
+ eth_hdr(skb)->h_dest)) {
+ return true;
+ }
+
return false;
}
@@ -448,13 +468,14 @@ static void hsr_forward_do(struct hsr_frame_info *frame)
}
/* Check if frame is to be dropped. Eg. for PRP no forward
- * between ports.
+ * between ports, or sending HSR supervision to RedBox.
*/
if (hsr->proto_ops->drop_frame &&
hsr->proto_ops->drop_frame(frame, port))
continue;
- if (port->type != HSR_PT_MASTER)
+ if (port->type == HSR_PT_SLAVE_A ||
+ port->type == HSR_PT_SLAVE_B)
skb = hsr->proto_ops->create_tagged_frame(frame, port);
else
skb = hsr->proto_ops->get_untagged_frame(frame, port);
@@ -469,7 +490,9 @@ static void hsr_forward_do(struct hsr_frame_info *frame)
hsr_deliver_master(skb, port->dev, frame->node_src);
} else {
if (!hsr_xmit(skb, port, frame))
- sent = true;
+ if (port->type == HSR_PT_SLAVE_A ||
+ port->type == HSR_PT_SLAVE_B)
+ sent = true;
}
}
}
@@ -503,13 +526,23 @@ static void handle_std_frame(struct sk_buff *skb,
frame->skb_prp = NULL;
frame->skb_std = skb;
- if (port->type != HSR_PT_MASTER) {
- frame->is_from_san = true;
- } else {
+ switch (port->type) {
+ case HSR_PT_MASTER:
/* Sequence nr for the master node */
lockdep_assert_held(&hsr->seqnr_lock);
frame->sequence_nr = hsr->sequence_nr;
hsr->sequence_nr++;
+ break;
+
+ case HSR_PT_INTERLINK:
+ frame->is_from_san = true;
+ lockdep_assert_held(&hsr->seqnr_lock);
+ frame->sequence_nr = hsr->sequence_nr;
+ hsr->sequence_nr++;
+ break;
+
+ default:
+ pr_err("Standard frame from wrong port type!");
}
}
@@ -564,6 +597,7 @@ static int fill_frame_info(struct hsr_frame_info *frame,
{
struct hsr_priv *hsr = port->hsr;
struct hsr_vlan_ethhdr *vlan_hdr;
+ struct list_head *n_db;
struct ethhdr *ethhdr;
__be16 proto;
int ret;
@@ -574,9 +608,23 @@ static int fill_frame_info(struct hsr_frame_info *frame,
memset(frame, 0, sizeof(*frame));
frame->is_supervision = is_supervision_frame(port->hsr, skb);
- frame->node_src = hsr_get_node(port, &hsr->node_db, skb,
- frame->is_supervision,
- port->type);
+
+ n_db = &hsr->node_db;
+
+ if (port->type == HSR_PT_INTERLINK)
+ n_db = &hsr->proxy_node_db;
+
+ if (port->type == HSR_PT_SLAVE_A || port->type == HSR_PT_SLAVE_B)
+ /* If for frame received from HSR ring the node is
+ * not present in NodeTable, look for destination one
+ * in the ProxyNodeTable.
+ */
+ if (hsr_is_node_in_db(&hsr->proxy_node_db,
+ eth_hdr(skb)->h_dest))
+ 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 */
diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c
index 6d14d935ee82..d7188b16ad04 100644
--- a/net/hsr/hsr_framereg.c
+++ b/net/hsr/hsr_framereg.c
@@ -71,6 +71,14 @@ static struct hsr_node *find_node_by_addr_A(struct list_head *node_db,
return NULL;
}
+/* Check if node for a given MAC address is already present in data base
+ */
+bool hsr_is_node_in_db(struct list_head *node_db,
+ const unsigned char addr[ETH_ALEN])
+{
+ return !!find_node_by_addr_A(node_db, addr);
+}
+
/* Helper for device init; the self_node is used in hsr_rcv() to recognize
* frames from self that's been looped over the HSR ring.
*/
@@ -223,6 +231,15 @@ struct hsr_node *hsr_get_node(struct hsr_port *port, struct list_head *node_db,
}
}
+ /* Check if required node is not in proxy nodes table */
+ list_for_each_entry_rcu(node, &hsr->proxy_node_db, mac_list) {
+ if (ether_addr_equal(node->macaddress_A, ethhdr->h_source)) {
+ if (hsr->proto_ops->update_san_info)
+ hsr->proto_ops->update_san_info(node, is_sup);
+ return node;
+ }
+ }
+
/* Everyone may create a node entry, connected node to a HSR/PRP
* device.
*/
@@ -414,6 +431,10 @@ void hsr_addr_subst_dest(struct hsr_node *node_src, struct sk_buff *skb,
node_dst = find_node_by_addr_A(&port->hsr->node_db,
eth_hdr(skb)->h_dest);
+ if (!node_dst && port->hsr->redbox)
+ node_dst = find_node_by_addr_A(&port->hsr->proxy_node_db,
+ eth_hdr(skb)->h_dest);
+
if (!node_dst) {
if (port->hsr->prot_version != PRP_V1 && net_ratelimit())
netdev_err(skb->dev, "%s: Unknown node\n", __func__);
@@ -557,6 +578,40 @@ void hsr_prune_nodes(struct timer_list *t)
jiffies + msecs_to_jiffies(PRUNE_PERIOD));
}
+void hsr_prune_proxy_nodes(struct timer_list *t)
+{
+ struct hsr_priv *hsr = from_timer(hsr, t, prune_proxy_timer);
+ struct hsr_node *node;
+ struct hsr_node *tmp;
+ unsigned long timestamp;
+
+ spin_lock_bh(&hsr->list_lock);
+ list_for_each_entry_safe(node, tmp, &hsr->proxy_node_db, mac_list) {
+ timestamp = node->time_in[HSR_PT_INTERLINK];
+ /* Check for timestamps old enough to risk wrap-around */
+ if (time_after(jiffies, timestamp + MAX_JIFFY_OFFSET / 2))
+ node->time_in_stale[HSR_PT_INTERLINK] = true;
+
+ /* Prune old entries */
+ if (time_is_before_jiffies(timestamp +
+ msecs_to_jiffies(HSR_PROXY_NODE_FORGET_TIME))) {
+ hsr_nl_nodedown(hsr, node->macaddress_A);
+ if (!node->removed) {
+ list_del_rcu(&node->mac_list);
+ node->removed = true;
+ /* Note that we need to free this entry later: */
+ kfree_rcu(node, rcu_head);
+ }
+ }
+ }
+
+ spin_unlock_bh(&hsr->list_lock);
+
+ /* Restart timer */
+ mod_timer(&hsr->prune_proxy_timer,
+ jiffies + msecs_to_jiffies(PRUNE_PROXY_PERIOD));
+}
+
void *hsr_get_next_node(struct hsr_priv *hsr, void *_pos,
unsigned char addr[ETH_ALEN])
{
diff --git a/net/hsr/hsr_framereg.h b/net/hsr/hsr_framereg.h
index b23556251d62..67456a75d8fe 100644
--- a/net/hsr/hsr_framereg.h
+++ b/net/hsr/hsr_framereg.h
@@ -46,6 +46,7 @@ int hsr_register_frame_out(struct hsr_port *port, struct hsr_node *node,
u16 sequence_nr);
void hsr_prune_nodes(struct timer_list *t);
+void hsr_prune_proxy_nodes(struct timer_list *t);
int hsr_create_self_node(struct hsr_priv *hsr,
const unsigned char addr_a[ETH_ALEN],
@@ -63,10 +64,15 @@ int hsr_get_node_data(struct hsr_priv *hsr,
int *if2_age,
u16 *if2_seq);
+void hsr_handle_san_frame(bool san, enum hsr_port_type port,
+ struct hsr_node *node);
void prp_handle_san_frame(bool san, enum hsr_port_type port,
struct hsr_node *node);
void prp_update_san_info(struct hsr_node *node, bool is_sup);
+bool hsr_is_node_in_db(struct list_head *node_db,
+ const unsigned char addr[ETH_ALEN]);
+
struct hsr_node {
struct list_head mac_list;
/* Protect R/W access to seq_out */
diff --git a/net/hsr/hsr_main.h b/net/hsr/hsr_main.h
index 18e01791ad79..23850b16d1ea 100644
--- a/net/hsr/hsr_main.h
+++ b/net/hsr/hsr_main.h
@@ -21,6 +21,7 @@
*/
#define HSR_LIFE_CHECK_INTERVAL 2000 /* ms */
#define HSR_NODE_FORGET_TIME 60000 /* ms */
+#define HSR_PROXY_NODE_FORGET_TIME 60000 /* ms */
#define HSR_ANNOUNCE_INTERVAL 100 /* ms */
#define HSR_ENTRY_FORGET_TIME 400 /* ms */
@@ -35,6 +36,7 @@
* HSR_NODE_FORGET_TIME?
*/
#define PRUNE_PERIOD 3000 /* ms */
+#define PRUNE_PROXY_PERIOD 3000 /* ms */
#define HSR_TLV_EOT 0 /* End of TLVs */
#define HSR_TLV_ANNOUNCE 22
#define HSR_TLV_LIFE_CHECK 23
@@ -192,11 +194,14 @@ struct hsr_priv {
struct rcu_head rcu_head;
struct list_head ports;
struct list_head node_db; /* Known HSR nodes */
+ struct list_head proxy_node_db; /* RedBox HSR proxy nodes */
struct hsr_self_node __rcu *self_node; /* MACs of slaves */
struct timer_list announce_timer; /* Supervision frame dispatch */
struct timer_list prune_timer;
+ struct timer_list prune_proxy_timer;
int announce_count;
u16 sequence_nr;
+ u16 interlink_sequence_nr; /* Interlink port seq_nr */
u16 sup_sequence_nr; /* For HSRv1 separate seq_nr for supervision */
enum hsr_version prot_version; /* Indicate if HSRv0, HSRv1 or PRPv1 */
spinlock_t seqnr_lock; /* locking for sequence_nr */
@@ -209,6 +214,8 @@ struct hsr_priv {
* of lan_id
*/
bool fwd_offloaded; /* Forwarding offloaded to HW */
+ bool redbox; /* Device supports HSR RedBox */
+ unsigned char macaddress_redbox[ETH_ALEN];
unsigned char sup_multicast_addr[ETH_ALEN] __aligned(sizeof(u16));
/* Align to u16 boundary to avoid unaligned access
* in ether_addr_equal
diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c
index 78fe40eb9f01..86eae49009cb 100644
--- a/net/hsr/hsr_netlink.c
+++ b/net/hsr/hsr_netlink.c
@@ -23,6 +23,7 @@ static const struct nla_policy hsr_policy[IFLA_HSR_MAX + 1] = {
[IFLA_HSR_SUPERVISION_ADDR] = { .len = ETH_ALEN },
[IFLA_HSR_SEQ_NR] = { .type = NLA_U16 },
[IFLA_HSR_PROTOCOL] = { .type = NLA_U8 },
+ [IFLA_HSR_INTERLINK] = { .type = NLA_U32 },
};
/* Here, it seems a netdevice has already been allocated for us, and the
@@ -35,8 +36,8 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev,
enum hsr_version proto_version;
unsigned char multicast_spec;
u8 proto = HSR_PROTOCOL_HSR;
- struct net_device *link[2];
+ struct net_device *link[2], *interlink = NULL;
if (!data) {
NL_SET_ERR_MSG_MOD(extack, "No slave devices specified");
return -EINVAL;
@@ -67,6 +68,20 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev,
return -EINVAL;
}
+ if (data[IFLA_HSR_INTERLINK])
+ interlink = __dev_get_by_index(src_net,
+ nla_get_u32(data[IFLA_HSR_INTERLINK]));
+
+ if (interlink && interlink == link[0]) {
+ NL_SET_ERR_MSG_MOD(extack, "Interlink and Slave1 are the same");
+ return -EINVAL;
+ }
+
+ if (interlink && interlink == link[1]) {
+ NL_SET_ERR_MSG_MOD(extack, "Interlink and Slave2 are the same");
+ return -EINVAL;
+ }
+
if (!data[IFLA_HSR_MULTICAST_SPEC])
multicast_spec = 0;
else
@@ -96,10 +111,17 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev,
}
}
- if (proto == HSR_PROTOCOL_PRP)
+ if (proto == HSR_PROTOCOL_PRP) {
proto_version = PRP_V1;
+ if (interlink) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Interlink only works with HSR");
+ return -EINVAL;
+ }
+ }
- return hsr_dev_finalize(dev, link, multicast_spec, proto_version, extack);
+ return hsr_dev_finalize(dev, link, interlink, multicast_spec,
+ proto_version, extack);
}
static void hsr_dellink(struct net_device *dev, struct list_head *head)
@@ -114,6 +136,7 @@ static void hsr_dellink(struct net_device *dev, struct list_head *head)
hsr_del_self_node(hsr);
hsr_del_nodes(&hsr->node_db);
+ hsr_del_nodes(&hsr->proxy_node_db);
unregister_netdevice_queue(dev, head);
}
diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c
index e5742f2a2d52..136e3917f477 100644
--- a/net/hsr/hsr_slave.c
+++ b/net/hsr/hsr_slave.c
@@ -55,6 +55,7 @@ static rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb)
protocol = eth_hdr(skb)->h_proto;
if (!(port->dev->features & NETIF_F_HW_HSR_TAG_RM) &&
+ port->type != HSR_PT_INTERLINK &&
hsr->proto_ops->invalid_dan_ingress_frame &&
hsr->proto_ops->invalid_dan_ingress_frame(protocol))
goto finish_pass;
--
2.20.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] net: hsr: Provide RedBox support
2024-03-06 12:38 [PATCH] net: hsr: Provide RedBox support Lukasz Majewski
@ 2024-03-06 13:11 ` Dan Carpenter
2024-03-06 13:33 ` Wojciech Drewek
1 sibling, 0 replies; 3+ messages in thread
From: Dan Carpenter @ 2024-03-06 13:11 UTC (permalink / raw)
To: Lukasz Majewski
Cc: netdev, Andrew Lunn, Eric Dumazet, Florian Fainelli,
Vladimir Oltean, David S. Miller, Jakub Kicinski, Oleksij Rempel,
Tristram.Ha, Sebastian Andrzej Siewior, Paolo Abeni,
Ravi Gunasekaran, Simon Horman, Wojciech Drewek,
Nikita Zhandarovich, Murali Karicheri, Ziyang Xuan,
Kristian Overskeid, Matthieu Baerts, linux-kernel
You still forgot to add the interlink port to hsr_del_ports().
regards,
dan carpenter
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] net: hsr: Provide RedBox support
2024-03-06 12:38 [PATCH] net: hsr: Provide RedBox support Lukasz Majewski
2024-03-06 13:11 ` Dan Carpenter
@ 2024-03-06 13:33 ` Wojciech Drewek
1 sibling, 0 replies; 3+ messages in thread
From: Wojciech Drewek @ 2024-03-06 13:33 UTC (permalink / raw)
To: Lukasz Majewski, netdev
Cc: Andrew Lunn, Eric Dumazet, Florian Fainelli, Vladimir Oltean,
David S. Miller, Jakub Kicinski, Oleksij Rempel, Tristram.Ha,
Sebastian Andrzej Siewior, Paolo Abeni, Ravi Gunasekaran,
Simon Horman, Nikita Zhandarovich, Murali Karicheri,
Dan Carpenter, Ziyang Xuan, Kristian Overskeid, Matthieu Baerts,
linux-kernel
On 06.03.2024 13:38, Lukasz Majewski wrote:
> This patch provides RedBox support (HSR-SAN to be more precise) for HSR
> networks. It implements the 'Mode U' without optimizations for traffic
I'd suggest to use imperative mode e.g:
"Introduce RedBox support ..."
"Implement the 'Mode U' ..."
> reduction (only supports preventing sending HSR supervisory frames to
> Port C and not forwarding to HSR ring frames addressed to Port C).
>
> The corresponding patch to modify iptable2 sources has already been sent:
> https://lore.kernel.org/netdev/20240226124110.37892211@hermes.local/T/
>
>
> Testing procedure:
> ------------------
> The EVB-KSZ9477 has been used for testing on net-next branch
> (SHA1: 709776ea8562).
>
> Ports 4/5 were used for SW managed HSR (hsr1) as first hsr0 for ports 1/2
> (with HW offloading for ksz9477) was created. Port 3 has been used as
> interlink port (USB-ETH dongle).
>
> Configuration - RedBox (EVB-KSZ9477):
> ifconfig lan1 down;ifconfig lan2 down
> ip link add name hsr0 type hsr slave1 lan1 slave2 lan2 supervision 45 version 1
> ip link add name hsr1 type hsr slave1 lan4 slave2 lan5 interlink lan3 supervision 45 version 1
> ifconfig lan4 up;ifconfig lan5 up
> ifconfig lan3 up
> ifconfig hsr1 192.168.0.11 up
>
> Configuration - DAN-H (EVB-KSZ9477):
>
> ifconfig lan1 down;ifconfig lan2 down
> ip link add name hsr0 type hsr slave1 lan1 slave2 lan2 supervision 45 version 1
> ip link add name hsr1 type hsr slave1 lan4 slave2 lan5 supervision 45 version 1
> ifconfig lan4 up;ifconfig lan5 up
> ifconfig hsr1 192.168.0.12 up
>
> This approach uses only SW based HSR devices (hsr1).
>
> Signed-off-by: Lukasz Majewski <lukma@denx.de>
> ---
> include/uapi/linux/if_link.h | 1 +
> net/hsr/hsr_device.c | 32 +++++++++++++++--
> net/hsr/hsr_device.h | 4 +--
> net/hsr/hsr_forward.c | 66 +++++++++++++++++++++++++++++++-----
> net/hsr/hsr_framereg.c | 55 ++++++++++++++++++++++++++++++
> net/hsr/hsr_framereg.h | 6 ++++
> net/hsr/hsr_main.h | 7 ++++
> net/hsr/hsr_netlink.c | 29 ++++++++++++++--
> net/hsr/hsr_slave.c | 1 +
> 9 files changed, 185 insertions(+), 16 deletions(-)
>
> diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
> index ab9bcff96e4d..b93a3acdd83f 100644
> --- a/include/uapi/linux/if_link.h
> +++ b/include/uapi/linux/if_link.h
> @@ -1770,6 +1770,7 @@ enum {
> IFLA_HSR_PROTOCOL, /* Indicate different protocol than
> * HSR. For example PRP.
> */
> + IFLA_HSR_INTERLINK, /* HSR interlink network device */
> __IFLA_HSR_MAX,
> };
>
> diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
> index 904cd8f8f830..4288d2b74472 100644
> --- a/net/hsr/hsr_device.c
> +++ b/net/hsr/hsr_device.c
> @@ -156,6 +156,9 @@ static int hsr_dev_open(struct net_device *dev)
> case HSR_PT_SLAVE_B:
> designation = "Slave B";
> break;
> + case HSR_PT_INTERLINK:
> + designation = "Interlink";
> + break;
> default:
> designation = "Unknown";
> }
> @@ -295,6 +298,7 @@ static void send_hsr_supervision_frame(struct hsr_port *master,
> struct hsr_priv *hsr = master->hsr;
> __u8 type = HSR_TLV_LIFE_CHECK;
> struct hsr_sup_payload *hsr_sp;
> + struct hsr_sup_tlv *hsr_stlv;
> struct hsr_sup_tag *hsr_stag;
> struct sk_buff *skb;
>
> @@ -334,6 +338,16 @@ static void send_hsr_supervision_frame(struct hsr_port *master,
> hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload));
> ether_addr_copy(hsr_sp->macaddress_A, master->dev->dev_addr);
>
> + if (hsr->redbox) {
> + hsr_stlv = skb_put(skb, sizeof(struct hsr_sup_tlv));
> + hsr_stlv->HSR_TLV_type = PRP_TLV_REDBOX_MAC;
> + hsr_stlv->HSR_TLV_length = sizeof(struct hsr_sup_payload);
> +
> + /* Payload: MacAddressRedBox */
> + hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload));
> + ether_addr_copy(hsr_sp->macaddress_A, hsr->macaddress_redbox);
> + }
> +
> if (skb_put_padto(skb, ETH_ZLEN)) {
> spin_unlock_bh(&hsr->seqnr_lock);
> return;
> @@ -544,8 +558,8 @@ static const unsigned char def_multicast_addr[ETH_ALEN] __aligned(2) = {
> };
>
> int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
> - unsigned char multicast_spec, u8 protocol_version,
> - struct netlink_ext_ack *extack)
> + struct net_device *interlink, unsigned char multicast_spec,
> + u8 protocol_version, struct netlink_ext_ack *extack)
> {
> bool unregister = false;
> struct hsr_priv *hsr;
> @@ -554,6 +568,7 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
> hsr = netdev_priv(hsr_dev);
> INIT_LIST_HEAD(&hsr->ports);
> INIT_LIST_HEAD(&hsr->node_db);
> + INIT_LIST_HEAD(&hsr->proxy_node_db);
> spin_lock_init(&hsr->list_lock);
>
> eth_hw_addr_set(hsr_dev, slave[0]->dev_addr);
> @@ -579,6 +594,7 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
> /* Overflow soon to find bugs easier: */
> hsr->sequence_nr = HSR_SEQNR_START;
> hsr->sup_sequence_nr = HSR_SUP_SEQNR_START;
> + hsr->interlink_sequence_nr = HSR_SEQNR_START;
>
> timer_setup(&hsr->announce_timer, hsr_announce, 0);
> timer_setup(&hsr->prune_timer, hsr_prune_nodes, 0);
> @@ -614,6 +630,18 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
> if (res)
> goto err_unregister;
>
> + if (interlink) {
> + res = hsr_add_port(hsr, interlink, HSR_PT_INTERLINK, extack);
> + if (res)
> + goto err_unregister;
As Dan pointed out you should delete HSR_PT_INTERLINK port in hsr_del_ports
> +
> + hsr->redbox = true;
> + ether_addr_copy(hsr->macaddress_redbox, interlink->dev_addr);
> + timer_setup(&hsr->prune_proxy_timer, hsr_prune_proxy_nodes, 0);
> + mod_timer(&hsr->prune_proxy_timer,
> + jiffies + msecs_to_jiffies(PRUNE_PROXY_PERIOD));
> + }
> +
> hsr_debugfs_init(hsr, hsr_dev);
> mod_timer(&hsr->prune_timer, jiffies + msecs_to_jiffies(PRUNE_PERIOD));
>
> diff --git a/net/hsr/hsr_device.h b/net/hsr/hsr_device.h
> index 9060c92168f9..655284095b78 100644
> --- a/net/hsr/hsr_device.h
> +++ b/net/hsr/hsr_device.h
> @@ -16,8 +16,8 @@
> void hsr_del_ports(struct hsr_priv *hsr);
> void hsr_dev_setup(struct net_device *dev);
> int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
> - unsigned char multicast_spec, u8 protocol_version,
> - struct netlink_ext_ack *extack);
> + struct net_device *interlink, unsigned char multicast_spec,
> + u8 protocol_version, struct netlink_ext_ack *extack);
> void hsr_check_carrier_and_operstate(struct hsr_priv *hsr);
> int hsr_get_max_mtu(struct hsr_priv *hsr);
> #endif /* __HSR_DEVICE_H */
> diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c
> index 5d68cb181695..8ae7066846e2 100644
> --- a/net/hsr/hsr_forward.c
> +++ b/net/hsr/hsr_forward.c
> @@ -390,9 +390,29 @@ bool prp_drop_frame(struct hsr_frame_info *frame, struct hsr_port *port)
>
> bool hsr_drop_frame(struct hsr_frame_info *frame, struct hsr_port *port)
> {
> + struct sk_buff *skb;
> +
> if (port->dev->features & NETIF_F_HW_HSR_FWD)
> return prp_drop_frame(frame, port);
>
> + /* RedBox specific frames dropping policies
> + *
> + * Do not send HSR supervisory frames to SAN devices
> + */
> + if (frame->is_supervision && port->type == HSR_PT_INTERLINK)
> + return true;
> +
> + /* Do not forward to other HSR port (A or B) unicast frames which
> + * are addressed to interlink port (and are in the ProxyNodeTable).
> + */
> + skb = frame->skb_hsr;
> + if (skb && prp_drop_frame(frame, port) &&
> + is_unicast_ether_addr(eth_hdr(skb)->h_dest) &&
> + hsr_is_node_in_db(&port->hsr->proxy_node_db,
> + eth_hdr(skb)->h_dest)) {
> + return true;
> + }
> +
> return false;
> }
>
> @@ -448,13 +468,14 @@ static void hsr_forward_do(struct hsr_frame_info *frame)
> }
>
> /* Check if frame is to be dropped. Eg. for PRP no forward
> - * between ports.
> + * between ports, or sending HSR supervision to RedBox.
> */
> if (hsr->proto_ops->drop_frame &&
> hsr->proto_ops->drop_frame(frame, port))
> continue;
>
> - if (port->type != HSR_PT_MASTER)
> + if (port->type == HSR_PT_SLAVE_A ||
> + port->type == HSR_PT_SLAVE_B)
> skb = hsr->proto_ops->create_tagged_frame(frame, port);
> else
> skb = hsr->proto_ops->get_untagged_frame(frame, port);
> @@ -469,7 +490,9 @@ static void hsr_forward_do(struct hsr_frame_info *frame)
> hsr_deliver_master(skb, port->dev, frame->node_src);
> } else {
> if (!hsr_xmit(skb, port, frame))
> - sent = true;
> + if (port->type == HSR_PT_SLAVE_A ||
> + port->type == HSR_PT_SLAVE_B)
> + sent = true;
> }
> }
> }
> @@ -503,13 +526,23 @@ static void handle_std_frame(struct sk_buff *skb,
> frame->skb_prp = NULL;
> frame->skb_std = skb;
>
> - if (port->type != HSR_PT_MASTER) {
> - frame->is_from_san = true;
> - } else {
> + switch (port->type) {
> + case HSR_PT_MASTER:
> /* Sequence nr for the master node */
> lockdep_assert_held(&hsr->seqnr_lock);
> frame->sequence_nr = hsr->sequence_nr;
> hsr->sequence_nr++;
> + break;
> +
> + case HSR_PT_INTERLINK:
> + frame->is_from_san = true;
> + lockdep_assert_held(&hsr->seqnr_lock);
> + frame->sequence_nr = hsr->sequence_nr;
> + hsr->sequence_nr++;
Everything except setting is_from_san flag is the same as in HSR_PT_MASTER case.
Looks like a helper function could be used here.
> + break;
> +
> + default:
> + pr_err("Standard frame from wrong port type!");
> }
> }
>
> @@ -564,6 +597,7 @@ static int fill_frame_info(struct hsr_frame_info *frame,
> {
> struct hsr_priv *hsr = port->hsr;
> struct hsr_vlan_ethhdr *vlan_hdr;
> + struct list_head *n_db;
> struct ethhdr *ethhdr;
> __be16 proto;
> int ret;
> @@ -574,9 +608,23 @@ static int fill_frame_info(struct hsr_frame_info *frame,
>
> memset(frame, 0, sizeof(*frame));
> frame->is_supervision = is_supervision_frame(port->hsr, skb);
> - frame->node_src = hsr_get_node(port, &hsr->node_db, skb,
> - frame->is_supervision,
> - port->type);
> +
> + n_db = &hsr->node_db;
> +
> + if (port->type == HSR_PT_INTERLINK)
> + n_db = &hsr->proxy_node_db;
> +
> + if (port->type == HSR_PT_SLAVE_A || port->type == HSR_PT_SLAVE_B)
> + /* If for frame received from HSR ring the node is
> + * not present in NodeTable, look for destination one
> + * in the ProxyNodeTable.
> + */
> + if (hsr_is_node_in_db(&hsr->proxy_node_db,
> + eth_hdr(skb)->h_dest))
> + 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 */
>
> diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c
> index 6d14d935ee82..d7188b16ad04 100644
> --- a/net/hsr/hsr_framereg.c
> +++ b/net/hsr/hsr_framereg.c
> @@ -71,6 +71,14 @@ static struct hsr_node *find_node_by_addr_A(struct list_head *node_db,
> return NULL;
> }
>
> +/* Check if node for a given MAC address is already present in data base
> + */
> +bool hsr_is_node_in_db(struct list_head *node_db,
> + const unsigned char addr[ETH_ALEN])
> +{
> + return !!find_node_by_addr_A(node_db, addr);
> +}
> +
> /* Helper for device init; the self_node is used in hsr_rcv() to recognize
> * frames from self that's been looped over the HSR ring.
> */
> @@ -223,6 +231,15 @@ struct hsr_node *hsr_get_node(struct hsr_port *port, struct list_head *node_db,
> }
> }
>
> + /* Check if required node is not in proxy nodes table */
> + list_for_each_entry_rcu(node, &hsr->proxy_node_db, mac_list) {
> + if (ether_addr_equal(node->macaddress_A, ethhdr->h_source)) {
> + if (hsr->proto_ops->update_san_info)
> + hsr->proto_ops->update_san_info(node, is_sup);
> + return node;
> + }
> + }
> +
> /* Everyone may create a node entry, connected node to a HSR/PRP
> * device.
> */
> @@ -414,6 +431,10 @@ void hsr_addr_subst_dest(struct hsr_node *node_src, struct sk_buff *skb,
>
> node_dst = find_node_by_addr_A(&port->hsr->node_db,
> eth_hdr(skb)->h_dest);
> + if (!node_dst && port->hsr->redbox)
> + node_dst = find_node_by_addr_A(&port->hsr->proxy_node_db,
> + eth_hdr(skb)->h_dest);
> +
> if (!node_dst) {
> if (port->hsr->prot_version != PRP_V1 && net_ratelimit())
> netdev_err(skb->dev, "%s: Unknown node\n", __func__);
> @@ -557,6 +578,40 @@ void hsr_prune_nodes(struct timer_list *t)
> jiffies + msecs_to_jiffies(PRUNE_PERIOD));
> }
>
> +void hsr_prune_proxy_nodes(struct timer_list *t)
> +{
> + struct hsr_priv *hsr = from_timer(hsr, t, prune_proxy_timer);
> + struct hsr_node *node;
> + struct hsr_node *tmp;
> + unsigned long timestamp;
RCT
> +
> + spin_lock_bh(&hsr->list_lock);
> + list_for_each_entry_safe(node, tmp, &hsr->proxy_node_db, mac_list) {
> + timestamp = node->time_in[HSR_PT_INTERLINK];
> + /* Check for timestamps old enough to risk wrap-around */
> + if (time_after(jiffies, timestamp + MAX_JIFFY_OFFSET / 2))
> + node->time_in_stale[HSR_PT_INTERLINK] = true;
> +
> + /* Prune old entries */
> + if (time_is_before_jiffies(timestamp +
> + msecs_to_jiffies(HSR_PROXY_NODE_FORGET_TIME))) {
> + hsr_nl_nodedown(hsr, node->macaddress_A);
> + if (!node->removed) {
> + list_del_rcu(&node->mac_list);
> + node->removed = true;
> + /* Note that we need to free this entry later: */
> + kfree_rcu(node, rcu_head);
> + }
> + }
> + }
> +
> + spin_unlock_bh(&hsr->list_lock);
> +
> + /* Restart timer */
> + mod_timer(&hsr->prune_proxy_timer,
> + jiffies + msecs_to_jiffies(PRUNE_PROXY_PERIOD));
> +}
> +
> void *hsr_get_next_node(struct hsr_priv *hsr, void *_pos,
> unsigned char addr[ETH_ALEN])
> {
> diff --git a/net/hsr/hsr_framereg.h b/net/hsr/hsr_framereg.h
> index b23556251d62..67456a75d8fe 100644
> --- a/net/hsr/hsr_framereg.h
> +++ b/net/hsr/hsr_framereg.h
> @@ -46,6 +46,7 @@ int hsr_register_frame_out(struct hsr_port *port, struct hsr_node *node,
> u16 sequence_nr);
>
> void hsr_prune_nodes(struct timer_list *t);
> +void hsr_prune_proxy_nodes(struct timer_list *t);
>
> int hsr_create_self_node(struct hsr_priv *hsr,
> const unsigned char addr_a[ETH_ALEN],
> @@ -63,10 +64,15 @@ int hsr_get_node_data(struct hsr_priv *hsr,
> int *if2_age,
> u16 *if2_seq);
>
> +void hsr_handle_san_frame(bool san, enum hsr_port_type port,
> + struct hsr_node *node);
> void prp_handle_san_frame(bool san, enum hsr_port_type port,
> struct hsr_node *node);
> void prp_update_san_info(struct hsr_node *node, bool is_sup);
>
> +bool hsr_is_node_in_db(struct list_head *node_db,
> + const unsigned char addr[ETH_ALEN]);
> +
> struct hsr_node {
> struct list_head mac_list;
> /* Protect R/W access to seq_out */
> diff --git a/net/hsr/hsr_main.h b/net/hsr/hsr_main.h
> index 18e01791ad79..23850b16d1ea 100644
> --- a/net/hsr/hsr_main.h
> +++ b/net/hsr/hsr_main.h
> @@ -21,6 +21,7 @@
> */
> #define HSR_LIFE_CHECK_INTERVAL 2000 /* ms */
> #define HSR_NODE_FORGET_TIME 60000 /* ms */
> +#define HSR_PROXY_NODE_FORGET_TIME 60000 /* ms */
> #define HSR_ANNOUNCE_INTERVAL 100 /* ms */
> #define HSR_ENTRY_FORGET_TIME 400 /* ms */
>
> @@ -35,6 +36,7 @@
> * HSR_NODE_FORGET_TIME?
> */
> #define PRUNE_PERIOD 3000 /* ms */
> +#define PRUNE_PROXY_PERIOD 3000 /* ms */
> #define HSR_TLV_EOT 0 /* End of TLVs */
> #define HSR_TLV_ANNOUNCE 22
> #define HSR_TLV_LIFE_CHECK 23
> @@ -192,11 +194,14 @@ struct hsr_priv {
> struct rcu_head rcu_head;
> struct list_head ports;
> struct list_head node_db; /* Known HSR nodes */
> + struct list_head proxy_node_db; /* RedBox HSR proxy nodes */
> struct hsr_self_node __rcu *self_node; /* MACs of slaves */
> struct timer_list announce_timer; /* Supervision frame dispatch */
> struct timer_list prune_timer;
> + struct timer_list prune_proxy_timer;
> int announce_count;
> u16 sequence_nr;
> + u16 interlink_sequence_nr; /* Interlink port seq_nr */
> u16 sup_sequence_nr; /* For HSRv1 separate seq_nr for supervision */
> enum hsr_version prot_version; /* Indicate if HSRv0, HSRv1 or PRPv1 */
> spinlock_t seqnr_lock; /* locking for sequence_nr */
> @@ -209,6 +214,8 @@ struct hsr_priv {
> * of lan_id
> */
> bool fwd_offloaded; /* Forwarding offloaded to HW */
> + bool redbox; /* Device supports HSR RedBox */
> + unsigned char macaddress_redbox[ETH_ALEN];
> unsigned char sup_multicast_addr[ETH_ALEN] __aligned(sizeof(u16));
> /* Align to u16 boundary to avoid unaligned access
> * in ether_addr_equal
> diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c
> index 78fe40eb9f01..86eae49009cb 100644
> --- a/net/hsr/hsr_netlink.c
> +++ b/net/hsr/hsr_netlink.c
> @@ -23,6 +23,7 @@ static const struct nla_policy hsr_policy[IFLA_HSR_MAX + 1] = {
> [IFLA_HSR_SUPERVISION_ADDR] = { .len = ETH_ALEN },
> [IFLA_HSR_SEQ_NR] = { .type = NLA_U16 },
> [IFLA_HSR_PROTOCOL] = { .type = NLA_U8 },
> + [IFLA_HSR_INTERLINK] = { .type = NLA_U32 },
> };
>
> /* Here, it seems a netdevice has already been allocated for us, and the
> @@ -35,8 +36,8 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev,
> enum hsr_version proto_version;
> unsigned char multicast_spec;
> u8 proto = HSR_PROTOCOL_HSR;
> - struct net_device *link[2];
>
> + struct net_device *link[2], *interlink = NULL;
> if (!data) {
> NL_SET_ERR_MSG_MOD(extack, "No slave devices specified");
> return -EINVAL;
> @@ -67,6 +68,20 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev,
> return -EINVAL;
> }
>
> + if (data[IFLA_HSR_INTERLINK])
> + interlink = __dev_get_by_index(src_net,
> + nla_get_u32(data[IFLA_HSR_INTERLINK]));
> +
> + if (interlink && interlink == link[0]) {
> + NL_SET_ERR_MSG_MOD(extack, "Interlink and Slave1 are the same");
> + return -EINVAL;
> + }
> +
> + if (interlink && interlink == link[1]) {
> + NL_SET_ERR_MSG_MOD(extack, "Interlink and Slave2 are the same");
> + return -EINVAL;
> + }
> +
> if (!data[IFLA_HSR_MULTICAST_SPEC])
> multicast_spec = 0;
> else
> @@ -96,10 +111,17 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev,
> }
> }
>
> - if (proto == HSR_PROTOCOL_PRP)
> + if (proto == HSR_PROTOCOL_PRP) {
> proto_version = PRP_V1;
> + if (interlink) {
> + NL_SET_ERR_MSG_MOD(extack,
> + "Interlink only works with HSR");
> + return -EINVAL;
> + }
> + }
>
> - return hsr_dev_finalize(dev, link, multicast_spec, proto_version, extack);
> + return hsr_dev_finalize(dev, link, interlink, multicast_spec,
> + proto_version, extack);
> }
>
> static void hsr_dellink(struct net_device *dev, struct list_head *head)
> @@ -114,6 +136,7 @@ static void hsr_dellink(struct net_device *dev, struct list_head *head)
>
> hsr_del_self_node(hsr);
> hsr_del_nodes(&hsr->node_db);
> + hsr_del_nodes(&hsr->proxy_node_db);
>
> unregister_netdevice_queue(dev, head);
> }
> diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c
> index e5742f2a2d52..136e3917f477 100644
> --- a/net/hsr/hsr_slave.c
> +++ b/net/hsr/hsr_slave.c
> @@ -55,6 +55,7 @@ static rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb)
> protocol = eth_hdr(skb)->h_proto;
>
> if (!(port->dev->features & NETIF_F_HW_HSR_TAG_RM) &&
> + port->type != HSR_PT_INTERLINK &&
> hsr->proto_ops->invalid_dan_ingress_frame &&
> hsr->proto_ops->invalid_dan_ingress_frame(protocol))
> goto finish_pass;
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2024-03-06 13:33 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-03-06 12:38 [PATCH] net: hsr: Provide RedBox support Lukasz Majewski
2024-03-06 13:11 ` Dan Carpenter
2024-03-06 13:33 ` Wojciech Drewek
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).