ソースを参照

net: hsr/prp: add lre stats and debugfs display for the same

Add lre (Link Redundancy Entity) stats defined in IEC62539 spec
and way to display them as part of debugfs file

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Murali Karicheri 6 年 前
コミット
7e0a21d82d

+ 93 - 16
net/hsr-prp/hsr_prp_debugfs.c

@@ -73,7 +73,7 @@ hsr_prp_node_table_open(struct inode *inode, struct file *filp)
 	return single_open(filp, hsr_prp_node_table_show, inode->i_private);
 }
 
-static const struct file_operations hsr_prp_fops = {
+static const struct file_operations hsr_prp_node_table_fops = {
 	.owner	= THIS_MODULE,
 	.open	= hsr_prp_node_table_open,
 	.read	= seq_read,
@@ -81,37 +81,112 @@ static const struct file_operations hsr_prp_fops = {
 	.release = single_release,
 };
 
-/* hsr_prp_debugfs_init - create hsr node_table file for dumping
- * the node table
+/* hsr_prp_stats_show - Formats and prints stats in the device
+ */
+static int
+hsr_prp_stats_show(struct seq_file *sfp, void *data)
+{
+	struct hsr_prp_priv *priv = (struct hsr_prp_priv *)sfp->private;
+	struct hsr_prp_port *master;
+
+	rcu_read_lock();
+	master = hsr_prp_get_port(priv, HSR_PRP_PT_MASTER);
+	rcu_read_unlock();
+
+	seq_puts(sfp, "LRE Stats entries\n");
+	seq_printf(sfp, "cnt_tx_a = %d\n", priv->stats.cnt_tx_a);
+	seq_printf(sfp, "cnt_tx_b = %d\n", priv->stats.cnt_tx_b);
+	/* actually lre_tx_c is whatever sent to the application interface. So
+	 * same as rx_packets
+	 */
+	seq_printf(sfp, "cnt_tx_c = %ld\n", master->dev->stats.rx_packets);
+	seq_printf(sfp, "cnt_tx_sup = %d\n", priv->stats.cnt_tx_sup);
+	seq_printf(sfp, "cnt_rx_wrong_lan_a = %d\n",
+		   priv->stats.cnt_rx_wrong_lan_a);
+	seq_printf(sfp, "cnt_rx_wrong_lan_b = %d\n",
+		   priv->stats.cnt_rx_wrong_lan_b);
+	seq_printf(sfp, "cnt_rx_a = %d\n", priv->stats.cnt_rx_a);
+	seq_printf(sfp, "cnt_rx_b = %d\n", priv->stats.cnt_rx_b);
+	/* actually lre_rx_c is whatever received from the application
+	 * interface,  So same as tx_packets
+	 */
+	seq_printf(sfp, "cnt_rx_c = %ld\n", master->dev->stats.tx_packets);
+	seq_printf(sfp, "cnt_rx_errors_a = %d\n", priv->stats.cnt_rx_errors_a);
+	seq_printf(sfp, "cnt_rx_errors_b = %d\n", priv->stats.cnt_rx_errors_b);
+	if (priv->prot_version <= HSR_V1) {
+		seq_printf(sfp, "cnt_own_rx_a = %d\n",
+			   priv->stats.cnt_own_rx_a);
+		seq_printf(sfp, "cnt_own_rx_b = %d\n",
+			   priv->stats.cnt_own_rx_b);
+	}
+	seq_puts(sfp, "\n");
+	return 0;
+}
+
+/* hsr_prp_stats_open - open stats file
+ *
+ * Description:
+ * This routine opens a debugfs file stats of specific hsr or
+ * prp device
+ */
+static int
+hsr_prp_stats_open(struct inode *inode, struct file *filp)
+{
+	return single_open(filp, hsr_prp_stats_show, inode->i_private);
+}
+
+static const struct file_operations hsr_prp_stats_fops = {
+	.owner	= THIS_MODULE,
+	.open	= hsr_prp_stats_open,
+	.read	= seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+/* hsr_prp_debugfs_init - create hsr-prp node_table file for dumping
+ * the node table and lre stats
  *
  * Description:
  * When debugfs is configured this routine sets up the node_table file per
- * hsr device for dumping the node_table entries
+ * hsr device for dumping the node_table entries and stats file for
+ * lre stats dump.
  */
-int hsr_prp_debugfs_init(struct hsr_prp_priv *priv, struct net_device *hsr_dev)
+int hsr_prp_debugfs_init(struct hsr_prp_priv *priv, struct net_device *ndev)
 {
 	int rc = -1;
 	struct dentry *de = NULL;
 
-	de = debugfs_create_dir(hsr_dev->name, NULL);
+	de = debugfs_create_dir(ndev->name, NULL);
 	if (!de) {
-		pr_err("Cannot create hsr debugfs root\n");
+		netdev_err(ndev, "Cannot create debugfs root %s\n", ndev->name);
 		return rc;
 	}
 
-	priv->node_tbl_root = de;
+	priv->root_dir = de;
 
-	de = debugfs_create_file("node_table", S_IFREG | 0444,
-				 priv->node_tbl_root, priv,
-				 &hsr_prp_fops);
+	de = debugfs_create_file("node_table", S_IFREG | 0444, priv->root_dir,
+				 priv, &hsr_prp_node_table_fops);
 	if (!de) {
-		pr_err("Cannot create hsr node_table directory\n");
-		return rc;
+		netdev_err(ndev, "Cannot create hsr node_table directory\n");
+		goto error_nt;
 	}
 	priv->node_tbl_file = de;
 
+	de = debugfs_create_file("stats", S_IFREG | 0444, priv->root_dir, priv,
+				 &hsr_prp_stats_fops);
+	if (!de) {
+		netdev_err(ndev, "Cannot create hsr-prp stats directory\n");
+		goto error_stats;
+	}
+	priv->stats_file = de;
+
 	return 0;
-}
+
+error_stats:
+	debugfs_remove(priv->node_tbl_file);
+error_nt:
+	debugfs_remove(priv->root_dir);
+	return -ENODEV;
+} /* end of hst_prp_debugfs_init */
 
 /* hsr_prp_debugfs_term - Tear down debugfs intrastructure
  *
@@ -124,6 +199,8 @@ hsr_prp_debugfs_term(struct hsr_prp_priv *priv)
 {
 	debugfs_remove(priv->node_tbl_file);
 	priv->node_tbl_file = NULL;
-	debugfs_remove(priv->node_tbl_root);
-	priv->node_tbl_root = NULL;
+	debugfs_remove(priv->stats_file);
+	priv->stats_file = NULL;
+	debugfs_remove(priv->root_dir);
+	priv->root_dir = NULL;
 }

+ 1 - 0
net/hsr-prp/hsr_prp_device.c

@@ -334,6 +334,7 @@ static void send_supervision_frame(struct hsr_prp_port *master,
 	}
 	spin_unlock_irqrestore(&master->priv->seqnr_lock, irqflags);
 	hsr_prp_forward_skb(skb, master);
+	INC_CNT_TX_SUP(master->priv);
 	return;
 
 out:

+ 37 - 1
net/hsr-prp/hsr_prp_forward.c

@@ -146,6 +146,28 @@ static struct sk_buff *frame_get_stripped_skb(struct hsr_prp_frame_info *frame,
 	return skb_clone(frame->skb_std, GFP_ATOMIC);
 }
 
+/* only prp skb should be passed in */
+static void prp_check_lan_id(struct sk_buff *skb, struct hsr_prp_port *port)
+{
+	int lan_id;
+	struct prp_rct *trailor = skb_get_PRP_rct(skb);
+
+	if (!trailor) {
+		INC_CNT_RX_ERROR(port->type, port->priv);
+		return;
+	}
+
+	lan_id = get_prp_lan_id(trailor);
+
+	if (port->type == HSR_PRP_PT_SLAVE_A) {
+		if (lan_id & 1)
+			INC_CNT_RX_WRONG_LAN(port->type, port->priv);
+	} else {
+		if (!(lan_id & 1))
+			INC_CNT_RX_WRONG_LAN(port->type, port->priv);
+	}
+}
+
 static void prp_set_lan_id(struct prp_rct *trailor,
 			   struct hsr_prp_port *port)
 {
@@ -327,6 +349,7 @@ static int slave_xmit(struct sk_buff *skb, struct hsr_prp_port *port,
 		 */
 		ether_addr_copy(eth_hdr(skb)->h_source, port->dev->dev_addr);
 	}
+	INC_CNT_TX(port->type, port->priv);
 	return dev_queue_xmit(skb);
 }
 
@@ -395,7 +418,11 @@ static void hsr_prp_forward_do(struct hsr_prp_frame_info *frame)
 			skb = frame_get_stripped_skb(frame, port);
 
 		if (!skb) {
-			if (frame->port_rcv->type == HSR_PRP_PT_MASTER) {
+			if (frame->port_rcv->type == HSR_PRP_PT_SLAVE_A ||
+			    frame->port_rcv->type ==  HSR_PRP_PT_SLAVE_B)
+				INC_CNT_RX_ERROR(frame->port_rcv->type,
+						 port->priv);
+			else {
 				struct net_device *master_dev =
 				hsr_prp_get_port(port->priv,
 						 HSR_PRP_PT_MASTER)->dev;
@@ -533,7 +560,15 @@ void hsr_prp_forward_skb(struct sk_buff *skb, struct hsr_prp_port *port)
 	    (frame.skb_prp && port->priv->prot_version <= HSR_V1))
 		goto out_drop;
 
+	/* Check for LAN_ID only for PRP */
+	if (frame.skb_prp) {
+		if (port->type == HSR_PRP_PT_SLAVE_A  ||
+		    port->type == HSR_PRP_PT_SLAVE_B)
+			prp_check_lan_id(frame.skb_prp, port);
+	}
+
 	hsr_prp_register_frame_in(frame.node_src, port, frame.sequence_nr);
+
 	hsr_prp_forward_do(&frame);
 	/* Gets called for ingress frames as well as egress from master port.
 	 * So check and increment stats for master port only here.
@@ -552,6 +587,7 @@ void hsr_prp_forward_skb(struct sk_buff *skb, struct hsr_prp_port *port)
 	return;
 
 out_drop:
+	INC_CNT_RX_ERROR(port->type, port->priv);
 	port->dev->stats.tx_dropped++;
 	kfree_skb(skb);
 }

+ 4 - 0
net/hsr-prp/hsr_prp_framereg.h

@@ -57,6 +57,10 @@ struct hsr_prp_node {
 	unsigned char		macaddress_B[ETH_ALEN];
 	/* Local slave through which AddrB frames are received from this node */
 	enum hsr_prp_port_type	addr_B_port;
+	u32			cnt_received_a;
+	u32			cnt_received_b;
+	u32			cnt_err_wrong_lan_a;
+	u32			cnt_err_wrong_lan_b;
 	unsigned long		time_in[HSR_PRP_PT_PORTS];
 	bool			time_in_stale[HSR_PRP_PT_PORTS];
 	/* if the node is a SAN */

+ 30 - 1
net/hsr-prp/hsr_prp_main.h

@@ -183,6 +183,20 @@ static inline void set_prp_LSDU_size(struct prp_rct *rct, u16 LSDU_size)
 			(LSDU_size & 0x0FFF));
 }
 
+struct hsr_prp_lre_if_stats {
+	u32	cnt_tx_a;
+	u32	cnt_tx_b;
+	u32	cnt_rx_wrong_lan_a;
+	u32	cnt_rx_wrong_lan_b;
+	u32	cnt_rx_a;
+	u32	cnt_rx_b;
+	u32	cnt_rx_errors_a;
+	u32	cnt_rx_errors_b;
+	u32	cnt_own_rx_a; /* For HSR only */
+	u32	cnt_own_rx_b; /* For HSR only */
+	u32	cnt_tx_sup;
+};
+
 struct hsr_prp_port {
 	struct list_head	port_list;
 	struct net_device	*dev;
@@ -199,6 +213,7 @@ struct hsr_prp_priv {
 	struct list_head	self_node_db;	/* MACs of slaves */
 	struct timer_list	announce_timer;	/* Supervision frame dispatch */
 	struct timer_list	prune_timer;
+	struct	hsr_prp_lre_if_stats stats;	/* lre interface stats */
 	int announce_count;
 	u16 sequence_nr;
 	u16 sup_sequence_nr;	/* For HSRv1 separate seq_nr for supervision */
@@ -215,8 +230,9 @@ struct hsr_prp_priv {
 				 */
 	unsigned char		sup_multicast_addr[ETH_ALEN];
 #ifdef	CONFIG_DEBUG_FS
-	struct dentry *node_tbl_root;
+	struct dentry *root_dir;
 	struct dentry *node_tbl_file;
+	struct dentry *stats_file;
 #endif
 };
 
@@ -283,6 +299,19 @@ static inline bool prp_check_lsdu_size(struct sk_buff *skb,
 int hsr_prp_register_notifier(u8 proto);
 void hsr_prp_unregister_notifier(u8 proto);
 
+#define INC_CNT_TX(type, priv) (((type) == HSR_PRP_PT_SLAVE_A) ? \
+		priv->stats.cnt_tx_a++ : priv->stats.cnt_tx_b++)
+#define INC_CNT_RX_WRONG_LAN(type, priv) (((type) == HSR_PRP_PT_SLAVE_A) ? \
+		priv->stats.cnt_rx_wrong_lan_a++ : \
+		priv->stats.cnt_rx_wrong_lan_b++)
+#define INC_CNT_RX(type, priv) (((type) == HSR_PRP_PT_SLAVE_A) ? \
+		priv->stats.cnt_rx_a++ : priv->stats.cnt_rx_b++)
+#define INC_CNT_RX_ERROR(type, priv) (((type) == HSR_PRP_PT_SLAVE_A) ? \
+		priv->stats.cnt_rx_errors_a++ : priv->stats.cnt_rx_errors_b++)
+#define INC_CNT_OWN_RX(type, priv) (((type) == HSR_PRP_PT_SLAVE_A) ? \
+		priv->stats.cnt_own_rx_a++ : priv->stats.cnt_own_rx_b++)
+#define INC_CNT_TX_SUP(priv) ((priv)->stats.cnt_tx_sup++)
+
 #if IS_ENABLED(CONFIG_DEBUG_FS)
 int hsr_prp_debugfs_init(struct hsr_prp_priv *priv, struct net_device *ndev);
 void hsr_prp_debugfs_term(struct hsr_prp_priv *priv);

+ 6 - 1
net/hsr-prp/hsr_prp_slave.c

@@ -33,6 +33,7 @@ static rx_handler_result_t handle_frame(struct sk_buff **pskb)
 
 	if (hsr_prp_addr_is_self(priv, eth_hdr(skb)->h_source)) {
 		/* Directly kill frames sent by ourselves */
+		INC_CNT_OWN_RX(port->type, priv);
 		kfree_skb(skb);
 		goto finish_consume;
 	}
@@ -59,10 +60,13 @@ static rx_handler_result_t handle_frame(struct sk_buff **pskb)
 		skb_push(skb, ETH_HLEN);
 
 		/* do one more check and bail out */
-		if (skb_mac_header(skb) != skb->data)
+		if (skb_mac_header(skb) != skb->data) {
+			INC_CNT_RX_ERROR(port->type, priv);
 			goto finish_consume;
+		}
 	}
 
+	INC_CNT_RX(port->type, priv);
 	hsr_prp_forward_skb(skb, port);
 
 finish_consume:
@@ -70,6 +74,7 @@ finish_consume:
 	return RX_HANDLER_CONSUMED;
 
 finish_pass:
+	INC_CNT_RX_ERROR(port->type, priv);
 	rcu_read_unlock(); /* hsr->node_db, hsr->ports */
 	return RX_HANDLER_PASS;
 }