[net-next RFC PATCH 11/13] net: prp: add supervision frame generation and handling support
From: Murali Karicheri <hidden>
Date: 2020-05-06 16:31:05
Also in:
lkml, netdev
Subsystem:
networking [general], the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
Add support for sending and handling supervision frames. For PRP, supervision frame format is similar to HSR version 0, but have a PRP Redunancy Control Trailor (RCT) added. Signed-off-by: Murali Karicheri <redacted> --- net/hsr-prp/hsr_prp_device.c | 50 ++++++++++++++++++++++++++++------- net/hsr-prp/hsr_prp_forward.c | 4 ++- net/hsr-prp/hsr_prp_main.h | 22 +++++++++++++++ 3 files changed, 65 insertions(+), 11 deletions(-)
diff --git a/net/hsr-prp/hsr_prp_device.c b/net/hsr-prp/hsr_prp_device.c
index 501de23a97f5..3c463e185f64 100644
--- a/net/hsr-prp/hsr_prp_device.c
+++ b/net/hsr-prp/hsr_prp_device.c@@ -237,13 +237,20 @@ static void send_hsr_prp_supervision_frame(struct hsr_prp_port *master, { struct sk_buff *skb; int hlen, tlen; - struct hsr_tag *hsr_tag; + struct hsr_tag *hsr_tag = NULL; + struct prp_rct *rct; struct hsr_prp_sup_tag *hsr_stag; struct hsr_prp_sup_payload *hsr_sp; unsigned long irqflags; + u16 proto; + u8 *tail; hlen = LL_RESERVED_SPACE(master->dev); tlen = master->dev->needed_tailroom; + /* skb size is same for PRP/HSR frames, only difference + * being for PRP, it is a trailor and for HSR it is a + * header + */ skb = dev_alloc_skb(sizeof(struct hsr_tag) + sizeof(struct hsr_prp_sup_tag) + sizeof(struct hsr_prp_sup_payload) + hlen + tlen);
@@ -252,12 +259,15 @@ static void send_hsr_prp_supervision_frame(struct hsr_prp_port *master, return; skb_reserve(skb, hlen); - + if (!proto_ver) + proto = ETH_P_PRP; + else + proto = (proto_ver == HSR_V1) ? ETH_P_HSR : ETH_P_PRP; skb->dev = master->dev; - skb->protocol = htons(proto_ver ? ETH_P_HSR : ETH_P_PRP); + skb->protocol = htons(proto); skb->priority = TC_PRIO_CONTROL; - if (dev_hard_header(skb, skb->dev, (proto_ver ? ETH_P_HSR : ETH_P_PRP), + if (dev_hard_header(skb, skb->dev, proto, master->priv->sup_multicast_addr, skb->dev->dev_addr, skb->len) <= 0) goto out;
@@ -265,7 +275,7 @@ static void send_hsr_prp_supervision_frame(struct hsr_prp_port *master, skb_reset_network_header(skb); skb_reset_transport_header(skb); - if (proto_ver > 0) { + if (proto_ver == HSR_V1) { hsr_tag = skb_put(skb, sizeof(struct hsr_tag)); hsr_tag->encap_proto = htons(ETH_P_PRP); set_hsr_tag_LSDU_size(hsr_tag, HSR_V1_SUP_LSDUSIZE);
@@ -273,15 +283,19 @@ static void send_hsr_prp_supervision_frame(struct hsr_prp_port *master, hsr_stag = skb_put(skb, sizeof(struct hsr_prp_sup_tag)); set_hsr_stag_path(hsr_stag, (proto_ver ? 0x0 : 0xf)); - set_hsr_stag_HSR_ver(hsr_stag, proto_ver); + set_hsr_stag_HSR_ver(hsr_stag, proto_ver ? 0x1 : 0x0); /* From HSRv1 on we have separate supervision sequence numbers. */ spin_lock_irqsave(&master->priv->seqnr_lock, irqflags); if (proto_ver > 0) { hsr_stag->sequence_nr = htons(master->priv->sup_sequence_nr); - hsr_tag->sequence_nr = htons(master->priv->sequence_nr); + if (hsr_tag) + hsr_tag->sequence_nr = htons(master->priv->sequence_nr); master->priv->sup_sequence_nr++; - master->priv->sequence_nr++; + if (proto_ver == HSR_V1) { + hsr_tag->sequence_nr = htons(master->priv->sequence_nr); + master->priv->sequence_nr++; + } } else { hsr_stag->sequence_nr = htons(master->priv->sequence_nr); master->priv->sequence_nr++;
@@ -300,6 +314,16 @@ static void send_hsr_prp_supervision_frame(struct hsr_prp_port *master, if (skb_put_padto(skb, ETH_ZLEN + HSR_PRP_HLEN)) return; + spin_lock_irqsave(&master->priv->seqnr_lock, irqflags); + if (proto_ver == PRP_V1) { + tail = skb_tail_pointer(skb) - HSR_PRP_HLEN; + rct = (struct prp_rct *)tail; + rct->PRP_suffix = htons(ETH_P_PRP); + set_prp_LSDU_size(rct, HSR_V1_SUP_LSDUSIZE); + rct->sequence_nr = htons(master->priv->sequence_nr); + master->priv->sequence_nr++; + } + spin_unlock_irqrestore(&master->priv->seqnr_lock, irqflags); hsr_prp_forward_skb(skb, master); return;
@@ -328,8 +352,14 @@ static void hsr_prp_announce(struct timer_list *t) interval = msecs_to_jiffies(HSR_PRP_ANNOUNCE_INTERVAL); } else { - send_hsr_prp_supervision_frame(master, HSR_TLV_LIFE_CHECK, - priv->prot_version); + if (priv->prot_version <= HSR_V1) + send_hsr_prp_supervision_frame(master, + HSR_TLV_LIFE_CHECK, + priv->prot_version); + else /* PRP */ + send_hsr_prp_supervision_frame(master, + PRP_TLV_LIFE_CHECK_DD, + priv->prot_version); interval = msecs_to_jiffies(HSR_PRP_LIFE_CHECK_INTERVAL); }
diff --git a/net/hsr-prp/hsr_prp_forward.c b/net/hsr-prp/hsr_prp_forward.c
index 59b33d711ea6..d7e975919322 100644
--- a/net/hsr-prp/hsr_prp_forward.c
+++ b/net/hsr-prp/hsr_prp_forward.c@@ -74,7 +74,9 @@ static bool is_supervision_frame(struct hsr_prp_priv *priv, struct sk_buff *skb) } if (hsr_sup_tag->HSR_TLV_type != HSR_TLV_ANNOUNCE && - hsr_sup_tag->HSR_TLV_type != HSR_TLV_LIFE_CHECK) + hsr_sup_tag->HSR_TLV_type != HSR_TLV_LIFE_CHECK && + hsr_sup_tag->HSR_TLV_type != PRP_TLV_LIFE_CHECK_DD && + hsr_sup_tag->HSR_TLV_type != PRP_TLV_LIFE_CHECK_DA) return false; if (hsr_sup_tag->HSR_TLV_length != 12 && hsr_sup_tag->HSR_TLV_length != sizeof(struct hsr_prp_sup_payload))
diff --git a/net/hsr-prp/hsr_prp_main.h b/net/hsr-prp/hsr_prp_main.h
index 00c312e5189f..17049d040226 100644
--- a/net/hsr-prp/hsr_prp_main.h
+++ b/net/hsr-prp/hsr_prp_main.h@@ -33,6 +33,10 @@ #define HSR_TLV_ANNOUNCE 22 #define HSR_TLV_LIFE_CHECK 23 +/* PRP V1 life check for Duplicate discard */ +#define PRP_TLV_LIFE_CHECK_DD 20 +/* PRP V1 life check for Duplicate Accept */ +#define PRP_TLV_LIFE_CHECK_DA 21 /* HSR Tag. * As defined in IEC-62439-3:2010, the HSR tag is really { ethertype = 0x88FB,
@@ -125,6 +129,24 @@ enum hsr_prp_port_type { HSR_PRP_PT_PORTS, /* This must be the last item in the enum */ }; +/* PRP Redunancy Control Trailor (RCT). + * As defined in IEC-62439-4:2012, the PRP RCT is really { sequence Nr, + * Lan indentifier (LanId), LSDU_size and PRP_suffix = 0x88FB }. + * + * Field names as defined in the IEC:2012 standard for PRP. + */ +struct prp_rct { + __be16 sequence_nr; + __be16 lan_id_and_LSDU_size; + __be16 PRP_suffix; +} __packed; + +static inline void set_prp_LSDU_size(struct prp_rct *rct, u16 LSDU_size) +{ + rct->lan_id_and_LSDU_size = htons((ntohs(rct->lan_id_and_LSDU_size) & + 0xF000) | (LSDU_size & 0x0FFF)); +} + struct hsr_prp_port { struct list_head port_list; struct net_device *dev;
--
2.17.1