Skip to content

Commit

Permalink
net: hsr: Send supervisory frames to HSR network with ProxyNodeTable …
Browse files Browse the repository at this point in the history
…data

This patch provides support for sending supervision HSR frames with
MAC addresses stored in ProxyNodeTable when RedBox (i.e. HSR-SAN) is
enabled.

Supervision frames with RedBox MAC address (appended as second TLV)
are only send for ProxyNodeTable nodes.

This patch series shall be tested with hsr_redbox.sh script.

Signed-off-by: Lukasz Majewski <lukma@denx.de>
Reviewed-by: Wojciech Drewek <wojciech.drewek@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Lukasz Majewski authored and David S. Miller committed Jun 14, 2024
1 parent 6e7e2e7 commit 5f703ce
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 14 deletions.
63 changes: 52 additions & 11 deletions net/hsr/hsr_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,15 @@ static void hsr_check_announce(struct net_device *hsr_dev)
mod_timer(&hsr->announce_timer, jiffies +
msecs_to_jiffies(HSR_ANNOUNCE_INTERVAL));
}

if (hsr->redbox && !timer_pending(&hsr->announce_proxy_timer))
mod_timer(&hsr->announce_proxy_timer, jiffies +
msecs_to_jiffies(HSR_ANNOUNCE_INTERVAL) / 2);
} else {
/* Deactivate the announce timer */
timer_delete(&hsr->announce_timer);
if (hsr->redbox)
timer_delete(&hsr->announce_proxy_timer);
}
}

Expand Down Expand Up @@ -279,10 +285,11 @@ static struct sk_buff *hsr_init_skb(struct hsr_port *master)
return NULL;
}

static void send_hsr_supervision_frame(struct hsr_port *master,
unsigned long *interval)
static void send_hsr_supervision_frame(struct hsr_port *port,
unsigned long *interval,
const unsigned char *addr)
{
struct hsr_priv *hsr = master->hsr;
struct hsr_priv *hsr = port->hsr;
__u8 type = HSR_TLV_LIFE_CHECK;
struct hsr_sup_payload *hsr_sp;
struct hsr_sup_tlv *hsr_stlv;
Expand All @@ -296,9 +303,9 @@ static void send_hsr_supervision_frame(struct hsr_port *master,
hsr->announce_count++;
}

skb = hsr_init_skb(master);
skb = hsr_init_skb(port);
if (!skb) {
netdev_warn_once(master->dev, "HSR: Could not send supervision frame\n");
netdev_warn_once(port->dev, "HSR: Could not send supervision frame\n");
return;
}

Expand All @@ -321,11 +328,12 @@ static void send_hsr_supervision_frame(struct hsr_port *master,
hsr_stag->tlv.HSR_TLV_length = hsr->prot_version ?
sizeof(struct hsr_sup_payload) : 12;

/* Payload: MacAddressA */
/* Payload: MacAddressA / SAN MAC from ProxyNodeTable */
hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload));
ether_addr_copy(hsr_sp->macaddress_A, master->dev->dev_addr);
ether_addr_copy(hsr_sp->macaddress_A, addr);

if (hsr->redbox) {
if (hsr->redbox &&
hsr_is_node_in_db(&hsr->proxy_node_db, addr)) {
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);
Expand All @@ -340,13 +348,14 @@ static void send_hsr_supervision_frame(struct hsr_port *master,
return;
}

hsr_forward_skb(skb, master);
hsr_forward_skb(skb, port);
spin_unlock_bh(&hsr->seqnr_lock);
return;
}

static void send_prp_supervision_frame(struct hsr_port *master,
unsigned long *interval)
unsigned long *interval,
const unsigned char *addr)
{
struct hsr_priv *hsr = master->hsr;
struct hsr_sup_payload *hsr_sp;
Expand Down Expand Up @@ -396,14 +405,45 @@ static void hsr_announce(struct timer_list *t)

rcu_read_lock();
master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
hsr->proto_ops->send_sv_frame(master, &interval);
hsr->proto_ops->send_sv_frame(master, &interval, master->dev->dev_addr);

if (is_admin_up(master->dev))
mod_timer(&hsr->announce_timer, jiffies + interval);

rcu_read_unlock();
}

/* Announce (supervision frame) timer function for RedBox
*/
static void hsr_proxy_announce(struct timer_list *t)
{
struct hsr_priv *hsr = from_timer(hsr, t, announce_proxy_timer);
struct hsr_port *interlink;
unsigned long interval = 0;
struct hsr_node *node;

rcu_read_lock();
/* RedBOX sends supervisory frames to HSR network with MAC addresses
* of SAN nodes stored in ProxyNodeTable.
*/
interlink = hsr_port_get_hsr(hsr, HSR_PT_INTERLINK);
list_for_each_entry_rcu(node, &hsr->proxy_node_db, mac_list) {
if (hsr_addr_is_redbox(hsr, node->macaddress_A))
continue;
hsr->proto_ops->send_sv_frame(interlink, &interval,
node->macaddress_A);
}

if (is_admin_up(interlink->dev)) {
if (!interval)
interval = msecs_to_jiffies(HSR_ANNOUNCE_INTERVAL);

mod_timer(&hsr->announce_proxy_timer, jiffies + interval);
}

rcu_read_unlock();
}

void hsr_del_ports(struct hsr_priv *hsr)
{
struct hsr_port *port;
Expand Down Expand Up @@ -590,6 +630,7 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
timer_setup(&hsr->announce_timer, hsr_announce, 0);
timer_setup(&hsr->prune_timer, hsr_prune_nodes, 0);
timer_setup(&hsr->prune_proxy_timer, hsr_prune_proxy_nodes, 0);
timer_setup(&hsr->announce_proxy_timer, hsr_proxy_announce, 0);

ether_addr_copy(hsr->sup_multicast_addr, def_multicast_addr);
hsr->sup_multicast_addr[ETH_ALEN - 1] = multicast_spec;
Expand Down
37 changes: 35 additions & 2 deletions net/hsr/hsr_forward.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,35 @@ static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb)
return true;
}

static bool is_proxy_supervision_frame(struct hsr_priv *hsr,
struct sk_buff *skb)
{
struct hsr_sup_payload *payload;
struct ethhdr *eth_hdr;
u16 total_length = 0;

eth_hdr = (struct ethhdr *)skb_mac_header(skb);

/* Get the HSR protocol revision. */
if (eth_hdr->h_proto == htons(ETH_P_HSR))
total_length = sizeof(struct hsrv1_ethhdr_sp);
else
total_length = sizeof(struct hsrv0_ethhdr_sp);

if (!pskb_may_pull(skb, total_length + sizeof(struct hsr_sup_payload)))
return false;

skb_pull(skb, total_length);
payload = (struct hsr_sup_payload *)skb->data;
skb_push(skb, total_length);

/* For RedBox (HSR-SAN) check if we have received the supervision
* frame with MAC addresses from own ProxyNodeTable.
*/
return hsr_is_node_in_db(&hsr->proxy_node_db,
payload->macaddress_A);
}

static struct sk_buff *create_stripped_skb_hsr(struct sk_buff *skb_in,
struct hsr_frame_info *frame)
{
Expand Down Expand Up @@ -499,7 +528,8 @@ static void hsr_forward_do(struct hsr_frame_info *frame)
frame->sequence_nr))
continue;

if (frame->is_supervision && port->type == HSR_PT_MASTER) {
if (frame->is_supervision && port->type == HSR_PT_MASTER &&
!frame->is_proxy_supervision) {
hsr_handle_sup_frame(frame);
continue;
}
Expand Down Expand Up @@ -637,6 +667,9 @@ static int fill_frame_info(struct hsr_frame_info *frame,

memset(frame, 0, sizeof(*frame));
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);

n_db = &hsr->node_db;
if (port->type == HSR_PT_INTERLINK)
Expand Down Expand Up @@ -688,7 +721,7 @@ void hsr_forward_skb(struct sk_buff *skb, struct hsr_port *port)
/* Gets called for ingress frames as well as egress from master port.
* So check and increment stats for master port only here.
*/
if (port->type == HSR_PT_MASTER) {
if (port->type == HSR_PT_MASTER || port->type == HSR_PT_INTERLINK) {
port->dev->stats.tx_packets++;
port->dev->stats.tx_bytes += skb->len;
}
Expand Down
12 changes: 12 additions & 0 deletions net/hsr/hsr_framereg.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ static bool seq_nr_after(u16 a, u16 b)
#define seq_nr_before(a, b) seq_nr_after((b), (a))
#define seq_nr_before_or_eq(a, b) (!seq_nr_after((a), (b)))

bool hsr_addr_is_redbox(struct hsr_priv *hsr, unsigned char *addr)
{
if (!hsr->redbox || !is_valid_ether_addr(hsr->macaddress_redbox))
return false;

return ether_addr_equal(addr, hsr->macaddress_redbox);
}

bool hsr_addr_is_self(struct hsr_priv *hsr, unsigned char *addr)
{
struct hsr_self_node *sn;
Expand Down Expand Up @@ -591,6 +599,10 @@ void hsr_prune_proxy_nodes(struct timer_list *t)

spin_lock_bh(&hsr->list_lock);
list_for_each_entry_safe(node, tmp, &hsr->proxy_node_db, mac_list) {
/* Don't prune RedBox node. */
if (hsr_addr_is_redbox(hsr, node->macaddress_A))
continue;

timestamp = node->time_in[HSR_PT_INTERLINK];

/* Prune old entries */
Expand Down
2 changes: 2 additions & 0 deletions net/hsr/hsr_framereg.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ struct hsr_frame_info {
struct hsr_node *node_src;
u16 sequence_nr;
bool is_supervision;
bool is_proxy_supervision;
bool is_vlan;
bool is_local_dest;
bool is_local_exclusive;
Expand All @@ -35,6 +36,7 @@ struct hsr_node *hsr_get_node(struct hsr_port *port, struct list_head *node_db,
enum hsr_port_type rx_port);
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);

void hsr_addr_subst_source(struct hsr_node *node, struct sk_buff *skb);
void hsr_addr_subst_dest(struct hsr_node *node_src, struct sk_buff *skb,
Expand Down
4 changes: 3 additions & 1 deletion net/hsr/hsr_main.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@ struct hsr_node;

struct hsr_proto_ops {
/* format and send supervision frame */
void (*send_sv_frame)(struct hsr_port *port, unsigned long *interval);
void (*send_sv_frame)(struct hsr_port *port, unsigned long *interval,
const unsigned char addr[ETH_ALEN]);
void (*handle_san_frame)(bool san, enum hsr_port_type port,
struct hsr_node *node);
bool (*drop_frame)(struct hsr_frame_info *frame, struct hsr_port *port);
Expand All @@ -197,6 +198,7 @@ struct hsr_priv {
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 announce_proxy_timer;
struct timer_list prune_timer;
struct timer_list prune_proxy_timer;
int announce_count;
Expand Down
1 change: 1 addition & 0 deletions net/hsr/hsr_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ static void hsr_dellink(struct net_device *dev, struct list_head *head)
del_timer_sync(&hsr->prune_timer);
del_timer_sync(&hsr->prune_proxy_timer);
del_timer_sync(&hsr->announce_timer);
timer_delete_sync(&hsr->announce_proxy_timer);

hsr_debugfs_term(hsr);
hsr_del_ports(hsr);
Expand Down

0 comments on commit 5f703ce

Please sign in to comment.