浏览代码

net: hsr/prp: introduce net device lre ops for config and stats

LRE device requires configuration from user space through snmpd. This
patch introduces lredev ops in net_device struct to allow configure lre
parameters (attributes), query lre stats and node table from lower slave
devices when the lre is offloaded. This API is similar to the switch
device ops and is implemented in a similar manner.

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Murali Karicheri 6 年之前
父节点
当前提交
32a3eba58f
共有 4 个文件被更改,包括 254 次插入1 次删除
  1. 3 0
      include/linux/netdevice.h
  2. 130 0
      include/net/lredev.h
  3. 111 0
      net/hsr-prp/hsr_prp_device.c
  4. 10 1
      net/hsr-prp/hsr_prp_main.h

+ 3 - 0
include/linux/netdevice.h

@@ -1805,6 +1805,9 @@ struct net_device {
 #ifdef CONFIG_NET_SWITCHDEV
 	const struct switchdev_ops *switchdev_ops;
 #endif
+#ifdef CONFIG_HSR_PRP
+	const struct lredev_ops *lredev_ops;
+#endif
 #ifdef CONFIG_NET_L3_MASTER_DEV
 	const struct l3mdev_ops	*l3mdev_ops;
 #endif

+ 130 - 0
include/net/lredev.h

@@ -0,0 +1,130 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * include/net/lredev.h - lre device API
+ * Copyright (c) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ */
+#ifndef _LINUX_LREDEV_H_
+#define _LINUX_LREDEV_H_
+
+#include <linux/netdevice.h>
+
+/* PRP duplicate discard modes */
+enum iec62439_3_dd_modes {
+	IEC62439_3_DA = 1,
+	IEC62439_3_DD,
+};
+
+/* HSR modes */
+enum iec62439_3_hsr_modes {
+	IEC62439_3_HSR_MODE_H = 1,
+	IEC62439_3_HSR_MODE_N,
+	IEC62439_3_HSR_MODE_T,
+	IEC62439_3_HSR_MODE_U,
+	IEC62439_3_HSR_MODE_M,
+};
+
+/* PRP Transparent reception modes */
+enum iec62439_3_tr_modes {
+	IEC62439_3_TR_REMOVE_RCT = 1,
+	IEC62439_3_TR_PASS_RCT,
+};
+
+enum iec62439_3_clear_nt_cmd {
+	IEC62439_3_CLEAR_NT_NO_OP,
+	IEC62439_3_CLEAR_NT,
+};
+
+enum lredev_attr_id {
+	LREDEV_ATTR_ID_UNDEFINED,
+	/* For HSR only */
+	LREDEV_ATTR_ID_HSR_MODE,
+	/* Duplicate discard for PRP */
+	LREDEV_ATTR_ID_DD_MODE,
+	/* Duplicate List Reside Max time for HSR & PRP */
+	LREDEV_ATTR_ID_DLRMT,
+	/* Transparent reception for PRP */
+	LREDEV_ATTR_ID_PRP_TR,
+	/* Clear node table - for HSR & PRP */
+	LREDEV_ATTR_ID_CLEAR_NT,
+};
+
+struct lredev_attr {
+	enum lredev_attr_id id;
+	union {
+		enum iec62439_3_hsr_modes mode;
+		enum iec62439_3_dd_modes dd_mode;
+		/* in msec */
+		u32  dl_reside_max_time;
+		enum iec62439_3_tr_modes tr_mode;
+		enum iec62439_3_clear_nt_cmd clear_nt_cmd;
+	};
+};
+
+enum iec62439_node_type {
+	IEC62439_3_DANP,
+	IEC62439_3_REDBOXP,
+	IEC62439_3_VDANP,
+	IEC62439_3_DANH,
+	IEC62439_3_REDBOXH,
+	IEC62439_3_VDANH,
+};
+
+struct lre_node_table_entry {
+	u8 mac_address[ETH_ALEN];
+	/* in 1/100 seconds */
+	u32 time_last_seen_a;
+	/* in 1/100 seconds */
+	u32 time_last_seen_b;
+	enum iec62439_node_type node_type;
+};
+
+#define LRE_MAX_NT_ENTRIES	256
+
+struct lre_stats {
+	u32 cnt_tx_a;
+	u32 cnt_tx_b;
+	u32 cnt_tx_c;
+	u32 cnt_errwronglan_a;
+	u32 cnt_errwronglan_b;
+	u32 cnt_errwronglan_c;
+	u32 cnt_rx_a;
+	u32 cnt_rx_b;
+	u32 cnt_rx_c;
+	u32 cnt_errors_a;
+	u32 cnt_errors_b;
+	u32 cnt_errors_c;
+	u32 cnt_nodes;
+	u32 cnt_proxy_nodes;
+	u32 cnt_unique_rx_a;
+	u32 cnt_unique_rx_b;
+	u32 cnt_unique_rx_c;
+	u32 cnt_duplicate_rx_a;
+	u32 cnt_duplicate_rx_b;
+	u32 cnt_duplicate_rx_c;
+	u32 cnt_multiple_rx_a;
+	u32 cnt_multiple_rx_b;
+	u32 cnt_multiple_rx_c;
+	u32 cnt_own_rx_a;
+	u32 cnt_own_rx_b;
+};
+
+/**
+ * struct lredev_ops - lredev operations
+ *
+ * @lredev_attr_get: Get a attribute (see switchdev_attr).
+ *
+ * @lredev_port_attr_set: Set a attribute (see switchdev_attr).
+ */
+struct lredev_ops {
+	int	(*lredev_attr_get)(struct net_device *dev,
+				   struct lredev_attr *attr);
+	int	(*lredev_attr_set)(struct net_device *dev,
+				   struct lredev_attr *attr);
+	int	(*lredev_get_node_table)(struct net_device *dev,
+					 struct lre_node_table_entry table[],
+					 int size);
+	int	(*lredev_get_stats)(struct net_device *dev,
+				    struct lre_stats *stats);
+};
+
+#endif

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

@@ -139,6 +139,117 @@ int hsr_prp_get_max_mtu(struct hsr_prp_priv *priv)
 	return mtu_max;
 }
 
+int hsr_prp_lredev_attr_get(struct hsr_prp_priv *priv,
+			    struct lredev_attr *attr)
+{
+	struct hsr_prp_port *port_a =
+		hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_A);
+	struct net_device *slave_a_dev;
+
+	if (!port_a)
+		return -EINVAL;
+
+	slave_a_dev = port_a->dev;
+	if (slave_a_dev && slave_a_dev->lredev_ops &&
+	    slave_a_dev->lredev_ops->lredev_attr_get)
+		return slave_a_dev->lredev_ops->lredev_attr_get(slave_a_dev,
+								attr);
+	return -EINVAL;
+}
+
+int hsr_prp_lredev_attr_set(struct hsr_prp_priv *priv,
+			    struct lredev_attr *attr)
+{
+	struct hsr_prp_port *port_a =
+		hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_A);
+	struct net_device *slave_a_dev;
+
+	if (!port_a)
+		return -EINVAL;
+
+	slave_a_dev = port_a->dev;
+	if (slave_a_dev && slave_a_dev->lredev_ops &&
+	    slave_a_dev->lredev_ops->lredev_attr_set)
+		return slave_a_dev->lredev_ops->lredev_attr_set(slave_a_dev,
+								attr);
+	return -EINVAL;
+}
+
+static int _hsr_prp_lredev_get_node_table(struct hsr_prp_priv *priv,
+					  struct lre_node_table_entry table[],
+					  int size)
+{
+	struct hsr_prp_node *node;
+	int i = 0;
+
+	rcu_read_lock();
+
+	list_for_each_entry_rcu(node, &priv->node_db, mac_list) {
+		if (hsr_prp_addr_is_self(priv, node->macaddress_A))
+			continue;
+		memcpy(&table[i].mac_address[0],
+		       &node->macaddress_A[0], ETH_ALEN);
+		table[i].time_last_seen_a = node->time_in[HSR_PRP_PT_SLAVE_A];
+		table[i].time_last_seen_b = node->time_in[HSR_PRP_PT_SLAVE_B];
+		if (priv->prot_version == PRP_V1)
+			table[i].node_type = IEC62439_3_DANP;
+		else if (priv->prot_version <= HSR_V1)
+			table[i].node_type = IEC62439_3_DANH;
+		else
+			continue;
+		i++;
+	}
+	rcu_read_unlock();
+
+	return i;
+}
+
+int hsr_prp_lredev_get_node_table(struct hsr_prp_priv *priv,
+				  struct lre_node_table_entry table[],
+				  int size)
+{
+	struct hsr_prp_port *port_a =
+		hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_A);
+	struct net_device *slave_a_dev;
+	int ret = -EINVAL;
+
+	if (!port_a)
+		return ret;
+
+	if (!priv->rx_offloaded)
+		return _hsr_prp_lredev_get_node_table(priv, table, size);
+
+	slave_a_dev = port_a->dev;
+
+	if (slave_a_dev && slave_a_dev->lredev_ops &&
+	    slave_a_dev->lredev_ops->lredev_get_node_table)
+		ret =
+		slave_a_dev->lredev_ops->lredev_get_node_table(slave_a_dev,
+							       table,
+							       size);
+	return ret;
+}
+
+int hsr_prp_lredev_get_lre_stats(struct hsr_prp_priv *priv,
+				 struct lre_stats *stats)
+{
+	struct hsr_prp_port *port_a =
+		hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_A);
+	struct net_device *slave_a_dev;
+	int ret = -EINVAL;
+
+	if (!port_a)
+		return ret;
+
+	slave_a_dev = port_a->dev;
+
+	if (slave_a_dev && slave_a_dev->lredev_ops &&
+	    slave_a_dev->lredev_ops->lredev_get_stats)
+		ret =
+		slave_a_dev->lredev_ops->lredev_get_stats(slave_a_dev, stats);
+	return ret;
+}
+
 static int hsr_prp_dev_change_mtu(struct net_device *dev, int new_mtu)
 {
 	struct hsr_prp_priv *priv;

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

@@ -11,6 +11,7 @@
 #include <linux/netdevice.h>
 #include <linux/list.h>
 #include <linux/if_vlan.h>
+#include <net/lredev.h>
 
 /* Time constants as specified in the HSR specification (IEC-62439-3 2010)
  * Table 8.
@@ -326,5 +327,13 @@ static inline int hsr_prp_debugfs_init(struct hsr_prp_priv *priv,
 static inline void hsr_prp_debugfs_term(struct hsr_prp_priv *priv)
 {}
 #endif
-
+int hsr_prp_lredev_attr_set(struct hsr_prp_priv *priv,
+			    struct lredev_attr *attr);
+int hsr_prp_lredev_attr_get(struct hsr_prp_priv *priv,
+			    struct lredev_attr *attr);
+int hsr_prp_lredev_get_node_table(struct hsr_prp_priv *priv,
+				  struct lre_node_table_entry table[],
+				  int size);
+int  hsr_prp_lredev_get_lre_stats(struct hsr_prp_priv *priv,
+				  struct lre_stats *stats);
 #endif /*  __HSR_PRP_MAIN_H */