Browse Source

net: prp: add supervision frame generation and handling support

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 <m-karicheri2@ti.com>
Murali Karicheri 6 years ago
parent
commit
e830e41f50

+ 38 - 10
net/hsr-prp/hsr_prp_device.c

@@ -248,13 +248,20 @@ static void send_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);
@@ -263,18 +270,21 @@ static void send_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;
 	skb_reset_mac_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);
@@ -282,15 +292,19 @@ static void send_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++;
@@ -309,6 +323,16 @@ static void send_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;
 
@@ -337,8 +361,12 @@ static void hsr_prp_announce(struct timer_list *t)
 
 		interval = msecs_to_jiffies(HSR_PRP_ANNOUNCE_INTERVAL);
 	} else {
-		send_supervision_frame(master, HSR_TLV_LIFE_CHECK,
-				       priv->prot_version);
+		if (priv->prot_version <= HSR_V1)
+			send_supervision_frame(master, HSR_TLV_LIFE_CHECK,
+					       priv->prot_version);
+		else /* PRP */
+			send_supervision_frame(master, PRP_TLV_LIFE_CHECK_DD,
+					       priv->prot_version);
 
 		interval = msecs_to_jiffies(HSR_PRP_LIFE_CHECK_INTERVAL);
 	}

+ 3 - 1
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))

+ 6 - 2
net/hsr-prp/hsr_prp_framereg.c

@@ -17,6 +17,7 @@
 #include "hsr_prp_main.h"
 #include "hsr_prp_framereg.h"
 #include "hsr_netlink.h"
+#include "prp_netlink.h"
 
 /*	TODO: use hash lists for mac addresses (linux/jhash.h)?    */
 
@@ -406,8 +407,11 @@ void hsr_prp_prune_nodes(struct timer_list *t)
 
 		/* Prune old entries */
 		if (time_is_before_jiffies(timestamp +
-				msecs_to_jiffies(HSR_PRP_NODE_FORGET_TIME))) {
-			hsr_nl_nodedown(priv, node->macaddress_A);
+		    msecs_to_jiffies(HSR_PRP_NODE_FORGET_TIME))) {
+			if (priv->prot_version <= HSR_V1)
+				hsr_nl_nodedown(priv, node->macaddress_A);
+			else
+				prp_nl_nodedown(priv, node->macaddress_A);
 			list_del_rcu(&node->mac_list);
 			/* Note that we need to free this entry later: */
 			kfree_rcu(node, rcu_head);

+ 23 - 0
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,
@@ -144,6 +148,25 @@ 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;