Skip to content

Commit 5055ccc

Browse files
Lukasz MajewskiPaolo Abeni
authored andcommitted
net: hsr: Provide RedBox support (HSR-SAN)
Introduce RedBox support (HSR-SAN to be more precise) for HSR networks. Following traffic reduction optimizations have been implemented: - Do not send HSR supervisory frames to Port C (interlink) - Do not forward to HSR ring frames addressed to Port C - Do not forward to Port C frames from HSR ring - Do not send duplicate HSR frame to HSR ring when destination is Port C The corresponding patch to modify iptable2 sources has already been sent: https://lore.kernel.org/netdev/20240308145729.490863-1-lukma@denx.de/T/ Testing procedure (veth and netns): ----------------------------------- One shall run: linux-vanila/tools/testing/selftests/net/hsr/hsr_redbox.sh (Detailed description of the setup one can find in the test script file). Testing procedure (real hardware): ---------------------------------- The EVB-KSZ9477 has been used for testing on net-next branch (SHA1: 5fc6832). 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 (single USB-ETH dongle). Configuration - RedBox (EVB-KSZ9477): if link set lan1 down;ip link set 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 ip link set lan4 up;ip link set lan5 up ip link set lan3 up ip addr add 192.168.0.11/24 dev hsr1 ip link set hsr1 up Configuration - DAN-H (EVB-KSZ9477): ip link set lan1 down;ip link set 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 ip link set lan4 up;ip link set lan5 up ip addr add 192.168.0.12/24 dev hsr1 ip link set hsr1 up This approach uses only SW based HSR devices (hsr1). -------------- ----------------- ------------ DAN-H Port5 | <------> | Port5 | | Port4 | <------> | Port4 Port3 | <---> | PC | | (RedBox) | | (USB-ETH) EVB-KSZ9477 | | EVB-KSZ9477 | | -------------- ----------------- ------------ Signed-off-by: Lukasz Majewski <lukma@denx.de> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent af0cb3f commit 5055ccc

File tree

9 files changed

+204
-16
lines changed

9 files changed

+204
-16
lines changed

include/uapi/linux/if_link.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,6 +1771,7 @@ enum {
17711771
IFLA_HSR_PROTOCOL, /* Indicate different protocol than
17721772
* HSR. For example PRP.
17731773
*/
1774+
IFLA_HSR_INTERLINK, /* HSR interlink network device */
17741775
__IFLA_HSR_MAX,
17751776
};
17761777

net/hsr/hsr_device.c

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ static int hsr_dev_open(struct net_device *dev)
146146
case HSR_PT_SLAVE_B:
147147
designation = "Slave B";
148148
break;
149+
case HSR_PT_INTERLINK:
150+
designation = "Interlink";
151+
break;
149152
default:
150153
designation = "Unknown";
151154
}
@@ -285,6 +288,7 @@ static void send_hsr_supervision_frame(struct hsr_port *master,
285288
struct hsr_priv *hsr = master->hsr;
286289
__u8 type = HSR_TLV_LIFE_CHECK;
287290
struct hsr_sup_payload *hsr_sp;
291+
struct hsr_sup_tlv *hsr_stlv;
288292
struct hsr_sup_tag *hsr_stag;
289293
struct sk_buff *skb;
290294

@@ -324,6 +328,16 @@ static void send_hsr_supervision_frame(struct hsr_port *master,
324328
hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload));
325329
ether_addr_copy(hsr_sp->macaddress_A, master->dev->dev_addr);
326330

331+
if (hsr->redbox) {
332+
hsr_stlv = skb_put(skb, sizeof(struct hsr_sup_tlv));
333+
hsr_stlv->HSR_TLV_type = PRP_TLV_REDBOX_MAC;
334+
hsr_stlv->HSR_TLV_length = sizeof(struct hsr_sup_payload);
335+
336+
/* Payload: MacAddressRedBox */
337+
hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload));
338+
ether_addr_copy(hsr_sp->macaddress_A, hsr->macaddress_redbox);
339+
}
340+
327341
if (skb_put_padto(skb, ETH_ZLEN)) {
328342
spin_unlock_bh(&hsr->seqnr_lock);
329343
return;
@@ -405,6 +419,10 @@ void hsr_del_ports(struct hsr_priv *hsr)
405419
if (port)
406420
hsr_del_port(port);
407421

422+
port = hsr_port_get_hsr(hsr, HSR_PT_INTERLINK);
423+
if (port)
424+
hsr_del_port(port);
425+
408426
port = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
409427
if (port)
410428
hsr_del_port(port);
@@ -534,8 +552,8 @@ static const unsigned char def_multicast_addr[ETH_ALEN] __aligned(2) = {
534552
};
535553

536554
int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
537-
unsigned char multicast_spec, u8 protocol_version,
538-
struct netlink_ext_ack *extack)
555+
struct net_device *interlink, unsigned char multicast_spec,
556+
u8 protocol_version, struct netlink_ext_ack *extack)
539557
{
540558
bool unregister = false;
541559
struct hsr_priv *hsr;
@@ -544,6 +562,7 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
544562
hsr = netdev_priv(hsr_dev);
545563
INIT_LIST_HEAD(&hsr->ports);
546564
INIT_LIST_HEAD(&hsr->node_db);
565+
INIT_LIST_HEAD(&hsr->proxy_node_db);
547566
spin_lock_init(&hsr->list_lock);
548567

549568
eth_hw_addr_set(hsr_dev, slave[0]->dev_addr);
@@ -569,6 +588,7 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
569588
/* Overflow soon to find bugs easier: */
570589
hsr->sequence_nr = HSR_SEQNR_START;
571590
hsr->sup_sequence_nr = HSR_SUP_SEQNR_START;
591+
hsr->interlink_sequence_nr = HSR_SEQNR_START;
572592

573593
timer_setup(&hsr->announce_timer, hsr_announce, 0);
574594
timer_setup(&hsr->prune_timer, hsr_prune_nodes, 0);
@@ -604,6 +624,18 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
604624
if (res)
605625
goto err_unregister;
606626

627+
if (interlink) {
628+
res = hsr_add_port(hsr, interlink, HSR_PT_INTERLINK, extack);
629+
if (res)
630+
goto err_unregister;
631+
632+
hsr->redbox = true;
633+
ether_addr_copy(hsr->macaddress_redbox, interlink->dev_addr);
634+
timer_setup(&hsr->prune_proxy_timer, hsr_prune_proxy_nodes, 0);
635+
mod_timer(&hsr->prune_proxy_timer,
636+
jiffies + msecs_to_jiffies(PRUNE_PROXY_PERIOD));
637+
}
638+
607639
hsr_debugfs_init(hsr, hsr_dev);
608640
mod_timer(&hsr->prune_timer, jiffies + msecs_to_jiffies(PRUNE_PERIOD));
609641

net/hsr/hsr_device.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
void hsr_del_ports(struct hsr_priv *hsr);
1717
void hsr_dev_setup(struct net_device *dev);
1818
int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
19-
unsigned char multicast_spec, u8 protocol_version,
20-
struct netlink_ext_ack *extack);
19+
struct net_device *interlink, unsigned char multicast_spec,
20+
u8 protocol_version, struct netlink_ext_ack *extack);
2121
void hsr_check_carrier_and_operstate(struct hsr_priv *hsr);
2222
int hsr_get_max_mtu(struct hsr_priv *hsr);
2323
#endif /* __HSR_DEVICE_H */

net/hsr/hsr_forward.c

Lines changed: 76 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,15 @@ static int hsr_xmit(struct sk_buff *skb, struct hsr_port *port,
377377
*/
378378
ether_addr_copy(eth_hdr(skb)->h_source, port->dev->dev_addr);
379379
}
380+
381+
/* When HSR node is used as RedBox - the frame received from HSR ring
382+
* requires source MAC address (SA) replacement to one which can be
383+
* recognized by SAN devices (otherwise, frames are dropped by switch)
384+
*/
385+
if (port->type == HSR_PT_INTERLINK)
386+
ether_addr_copy(eth_hdr(skb)->h_source,
387+
port->hsr->macaddress_redbox);
388+
380389
return dev_queue_xmit(skb);
381390
}
382391

@@ -390,9 +399,57 @@ bool prp_drop_frame(struct hsr_frame_info *frame, struct hsr_port *port)
390399

391400
bool hsr_drop_frame(struct hsr_frame_info *frame, struct hsr_port *port)
392401
{
402+
struct sk_buff *skb;
403+
393404
if (port->dev->features & NETIF_F_HW_HSR_FWD)
394405
return prp_drop_frame(frame, port);
395406

407+
/* RedBox specific frames dropping policies
408+
*
409+
* Do not send HSR supervisory frames to SAN devices
410+
*/
411+
if (frame->is_supervision && port->type == HSR_PT_INTERLINK)
412+
return true;
413+
414+
/* Do not forward to other HSR port (A or B) unicast frames which
415+
* are addressed to interlink port (and are in the ProxyNodeTable).
416+
*/
417+
skb = frame->skb_hsr;
418+
if (skb && prp_drop_frame(frame, port) &&
419+
is_unicast_ether_addr(eth_hdr(skb)->h_dest) &&
420+
hsr_is_node_in_db(&port->hsr->proxy_node_db,
421+
eth_hdr(skb)->h_dest)) {
422+
return true;
423+
}
424+
425+
/* Do not forward to port C (Interlink) frames from nodes A and B
426+
* if DA is in NodeTable.
427+
*/
428+
if ((frame->port_rcv->type == HSR_PT_SLAVE_A ||
429+
frame->port_rcv->type == HSR_PT_SLAVE_B) &&
430+
port->type == HSR_PT_INTERLINK) {
431+
skb = frame->skb_hsr;
432+
if (skb && is_unicast_ether_addr(eth_hdr(skb)->h_dest) &&
433+
hsr_is_node_in_db(&port->hsr->node_db,
434+
eth_hdr(skb)->h_dest)) {
435+
return true;
436+
}
437+
}
438+
439+
/* Do not forward to port A and B unicast frames received on the
440+
* interlink port if it is addressed to one of nodes registered in
441+
* the ProxyNodeTable.
442+
*/
443+
if ((port->type == HSR_PT_SLAVE_A || port->type == HSR_PT_SLAVE_B) &&
444+
frame->port_rcv->type == HSR_PT_INTERLINK) {
445+
skb = frame->skb_std;
446+
if (skb && is_unicast_ether_addr(eth_hdr(skb)->h_dest) &&
447+
hsr_is_node_in_db(&port->hsr->proxy_node_db,
448+
eth_hdr(skb)->h_dest)) {
449+
return true;
450+
}
451+
}
452+
396453
return false;
397454
}
398455

@@ -448,13 +505,14 @@ static void hsr_forward_do(struct hsr_frame_info *frame)
448505
}
449506

450507
/* Check if frame is to be dropped. Eg. for PRP no forward
451-
* between ports.
508+
* between ports, or sending HSR supervision to RedBox.
452509
*/
453510
if (hsr->proto_ops->drop_frame &&
454511
hsr->proto_ops->drop_frame(frame, port))
455512
continue;
456513

457-
if (port->type != HSR_PT_MASTER)
514+
if (port->type == HSR_PT_SLAVE_A ||
515+
port->type == HSR_PT_SLAVE_B)
458516
skb = hsr->proto_ops->create_tagged_frame(frame, port);
459517
else
460518
skb = hsr->proto_ops->get_untagged_frame(frame, port);
@@ -469,7 +527,9 @@ static void hsr_forward_do(struct hsr_frame_info *frame)
469527
hsr_deliver_master(skb, port->dev, frame->node_src);
470528
} else {
471529
if (!hsr_xmit(skb, port, frame))
472-
sent = true;
530+
if (port->type == HSR_PT_SLAVE_A ||
531+
port->type == HSR_PT_SLAVE_B)
532+
sent = true;
473533
}
474534
}
475535
}
@@ -503,10 +563,12 @@ static void handle_std_frame(struct sk_buff *skb,
503563
frame->skb_prp = NULL;
504564
frame->skb_std = skb;
505565

506-
if (port->type != HSR_PT_MASTER) {
566+
if (port->type != HSR_PT_MASTER)
507567
frame->is_from_san = true;
508-
} else {
509-
/* Sequence nr for the master node */
568+
569+
if (port->type == HSR_PT_MASTER ||
570+
port->type == HSR_PT_INTERLINK) {
571+
/* Sequence nr for the master/interlink node */
510572
lockdep_assert_held(&hsr->seqnr_lock);
511573
frame->sequence_nr = hsr->sequence_nr;
512574
hsr->sequence_nr++;
@@ -564,6 +626,7 @@ static int fill_frame_info(struct hsr_frame_info *frame,
564626
{
565627
struct hsr_priv *hsr = port->hsr;
566628
struct hsr_vlan_ethhdr *vlan_hdr;
629+
struct list_head *n_db;
567630
struct ethhdr *ethhdr;
568631
__be16 proto;
569632
int ret;
@@ -574,9 +637,13 @@ static int fill_frame_info(struct hsr_frame_info *frame,
574637

575638
memset(frame, 0, sizeof(*frame));
576639
frame->is_supervision = is_supervision_frame(port->hsr, skb);
577-
frame->node_src = hsr_get_node(port, &hsr->node_db, skb,
578-
frame->is_supervision,
579-
port->type);
640+
641+
n_db = &hsr->node_db;
642+
if (port->type == HSR_PT_INTERLINK)
643+
n_db = &hsr->proxy_node_db;
644+
645+
frame->node_src = hsr_get_node(port, n_db, skb,
646+
frame->is_supervision, port->type);
580647
if (!frame->node_src)
581648
return -1; /* Unknown node and !is_supervision, or no mem */
582649

net/hsr/hsr_framereg.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,14 @@ static struct hsr_node *find_node_by_addr_A(struct list_head *node_db,
7171
return NULL;
7272
}
7373

74+
/* Check if node for a given MAC address is already present in data base
75+
*/
76+
bool hsr_is_node_in_db(struct list_head *node_db,
77+
const unsigned char addr[ETH_ALEN])
78+
{
79+
return !!find_node_by_addr_A(node_db, addr);
80+
}
81+
7482
/* Helper for device init; the self_node is used in hsr_rcv() to recognize
7583
* frames from self that's been looped over the HSR ring.
7684
*/
@@ -223,6 +231,15 @@ struct hsr_node *hsr_get_node(struct hsr_port *port, struct list_head *node_db,
223231
}
224232
}
225233

234+
/* Check if required node is not in proxy nodes table */
235+
list_for_each_entry_rcu(node, &hsr->proxy_node_db, mac_list) {
236+
if (ether_addr_equal(node->macaddress_A, ethhdr->h_source)) {
237+
if (hsr->proto_ops->update_san_info)
238+
hsr->proto_ops->update_san_info(node, is_sup);
239+
return node;
240+
}
241+
}
242+
226243
/* Everyone may create a node entry, connected node to a HSR/PRP
227244
* device.
228245
*/
@@ -418,6 +435,10 @@ void hsr_addr_subst_dest(struct hsr_node *node_src, struct sk_buff *skb,
418435

419436
node_dst = find_node_by_addr_A(&port->hsr->node_db,
420437
eth_hdr(skb)->h_dest);
438+
if (!node_dst && port->hsr->redbox)
439+
node_dst = find_node_by_addr_A(&port->hsr->proxy_node_db,
440+
eth_hdr(skb)->h_dest);
441+
421442
if (!node_dst) {
422443
if (port->hsr->prot_version != PRP_V1 && net_ratelimit())
423444
netdev_err(skb->dev, "%s: Unknown node\n", __func__);
@@ -561,6 +582,37 @@ void hsr_prune_nodes(struct timer_list *t)
561582
jiffies + msecs_to_jiffies(PRUNE_PERIOD));
562583
}
563584

585+
void hsr_prune_proxy_nodes(struct timer_list *t)
586+
{
587+
struct hsr_priv *hsr = from_timer(hsr, t, prune_proxy_timer);
588+
unsigned long timestamp;
589+
struct hsr_node *node;
590+
struct hsr_node *tmp;
591+
592+
spin_lock_bh(&hsr->list_lock);
593+
list_for_each_entry_safe(node, tmp, &hsr->proxy_node_db, mac_list) {
594+
timestamp = node->time_in[HSR_PT_INTERLINK];
595+
596+
/* Prune old entries */
597+
if (time_is_before_jiffies(timestamp +
598+
msecs_to_jiffies(HSR_PROXY_NODE_FORGET_TIME))) {
599+
hsr_nl_nodedown(hsr, node->macaddress_A);
600+
if (!node->removed) {
601+
list_del_rcu(&node->mac_list);
602+
node->removed = true;
603+
/* Note that we need to free this entry later: */
604+
kfree_rcu(node, rcu_head);
605+
}
606+
}
607+
}
608+
609+
spin_unlock_bh(&hsr->list_lock);
610+
611+
/* Restart timer */
612+
mod_timer(&hsr->prune_proxy_timer,
613+
jiffies + msecs_to_jiffies(PRUNE_PROXY_PERIOD));
614+
}
615+
564616
void *hsr_get_next_node(struct hsr_priv *hsr, void *_pos,
565617
unsigned char addr[ETH_ALEN])
566618
{

net/hsr/hsr_framereg.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ int hsr_register_frame_out(struct hsr_port *port, struct hsr_node *node,
4646
u16 sequence_nr);
4747

4848
void hsr_prune_nodes(struct timer_list *t);
49+
void hsr_prune_proxy_nodes(struct timer_list *t);
4950

5051
int hsr_create_self_node(struct hsr_priv *hsr,
5152
const unsigned char addr_a[ETH_ALEN],
@@ -67,6 +68,9 @@ void prp_handle_san_frame(bool san, enum hsr_port_type port,
6768
struct hsr_node *node);
6869
void prp_update_san_info(struct hsr_node *node, bool is_sup);
6970

71+
bool hsr_is_node_in_db(struct list_head *node_db,
72+
const unsigned char addr[ETH_ALEN]);
73+
7074
struct hsr_node {
7175
struct list_head mac_list;
7276
/* Protect R/W access to seq_out */

net/hsr/hsr_main.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
*/
2222
#define HSR_LIFE_CHECK_INTERVAL 2000 /* ms */
2323
#define HSR_NODE_FORGET_TIME 60000 /* ms */
24+
#define HSR_PROXY_NODE_FORGET_TIME 60000 /* ms */
2425
#define HSR_ANNOUNCE_INTERVAL 100 /* ms */
2526
#define HSR_ENTRY_FORGET_TIME 400 /* ms */
2627

@@ -35,6 +36,7 @@
3536
* HSR_NODE_FORGET_TIME?
3637
*/
3738
#define PRUNE_PERIOD 3000 /* ms */
39+
#define PRUNE_PROXY_PERIOD 3000 /* ms */
3840
#define HSR_TLV_EOT 0 /* End of TLVs */
3941
#define HSR_TLV_ANNOUNCE 22
4042
#define HSR_TLV_LIFE_CHECK 23
@@ -192,11 +194,14 @@ struct hsr_priv {
192194
struct rcu_head rcu_head;
193195
struct list_head ports;
194196
struct list_head node_db; /* Known HSR nodes */
197+
struct list_head proxy_node_db; /* RedBox HSR proxy nodes */
195198
struct hsr_self_node __rcu *self_node; /* MACs of slaves */
196199
struct timer_list announce_timer; /* Supervision frame dispatch */
197200
struct timer_list prune_timer;
201+
struct timer_list prune_proxy_timer;
198202
int announce_count;
199203
u16 sequence_nr;
204+
u16 interlink_sequence_nr; /* Interlink port seq_nr */
200205
u16 sup_sequence_nr; /* For HSRv1 separate seq_nr for supervision */
201206
enum hsr_version prot_version; /* Indicate if HSRv0, HSRv1 or PRPv1 */
202207
spinlock_t seqnr_lock; /* locking for sequence_nr */
@@ -209,6 +214,8 @@ struct hsr_priv {
209214
* of lan_id
210215
*/
211216
bool fwd_offloaded; /* Forwarding offloaded to HW */
217+
bool redbox; /* Device supports HSR RedBox */
218+
unsigned char macaddress_redbox[ETH_ALEN];
212219
unsigned char sup_multicast_addr[ETH_ALEN] __aligned(sizeof(u16));
213220
/* Align to u16 boundary to avoid unaligned access
214221
* in ether_addr_equal

0 commit comments

Comments
 (0)