瀏覽代碼

net: hsr/prp: Support VLAN tagged SV frames

In hsr/prp networks, user may choose to use vlan tagged SV frames
in the network which is defined as an optional feature in the
iec-62439 standard. User would then require to configure the VLAN ID,
PCP and DEI values to be used in the SV frames. This patch update the
driver to accept these values optionally from user as part of the
ip link add command and use VLAN info to format the VLAN tag in the
SV frame. Also pass the VLAN ID to the lower device so that it may
be added to the VLAN filter in h/w. Update the procfs interface to
allow user to enable/disable SV frame generation logic for debug
purpose.

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Murali Karicheri 6 年之前
父節點
當前提交
f5c7ccb69f

+ 1 - 0
include/net/lredev.h

@@ -125,6 +125,7 @@ struct lredev_ops {
 					 int size);
 	int	(*lredev_get_stats)(struct net_device *dev,
 				    struct lre_stats *stats);
+	int	(*lredev_set_sv_vlan_id)(struct net_device *dev, u16 vid);
 };
 
 #endif

+ 3 - 0
include/uapi/linux/if_link.h

@@ -991,6 +991,9 @@ enum {
 	IFLA_HSR_PRP_SF_MC_ADDR,      /* Supervision frame multicast addr */
 	IFLA_HSR_PRP_SEQ_NR,
 	IFLA_HSR_VERSION,		/* HSR version */
+	IFLA_HSR_PRP_SV_VID,
+	IFLA_HSR_PRP_SV_DEI,
+	IFLA_HSR_PRP_SV_PCP,
 	__IFLA_HSR_PRP_MAX,
 };
 

+ 3 - 0
net/hsr-prp/hsr_netlink.c

@@ -24,6 +24,9 @@ static const struct nla_policy hsr_policy[IFLA_HSR_PRP_MAX + 1] = {
 	[IFLA_HSR_VERSION]	= { .type = NLA_U8 },
 	[IFLA_HSR_PRP_SF_MC_ADDR]	= { .len = ETH_ALEN },
 	[IFLA_HSR_PRP_SEQ_NR]		= { .type = NLA_U16 },
+	[IFLA_HSR_PRP_SV_VID]		= { .type = NLA_U16 },
+	[IFLA_HSR_PRP_SV_PCP]		= { .type = NLA_U8 },
+	[IFLA_HSR_PRP_SV_DEI]		= { .type = NLA_U8 },
 };
 
 static int hsr_newlink(struct net *src_net, struct net_device *dev,

+ 11 - 0
net/hsr-prp/hsr_prp_debugfs.c

@@ -36,7 +36,18 @@ hsr_prp_lre_info_show(struct seq_file *sfp, void *data)
 	if (!prp)
 		seq_printf(sfp, "L2 fw Offloaded: %s\n",
 			   priv->l2_fwd_offloaded ? "Yes" : "No");
+	seq_printf(sfp, "vlan tag used in sv frame : %s\n",
+		   priv->use_vlan_for_sv ? "Yes" : "No");
+	if (priv->use_vlan_for_sv) {
+		seq_printf(sfp, "SV Frame VID : %d\n",
+			   priv->sv_frame_vid);
+		seq_printf(sfp, "SV Frame PCP : %d\n",
+			   priv->sv_frame_pcp);
+		seq_printf(sfp, "SV Frame DEI : %d\n",
+			   priv->sv_frame_dei);
+	}
 	seq_printf(sfp, "cnt_tx_sup = %d\n", priv->dbg_stats.cnt_tx_sup);
+	seq_printf(sfp, "disable SV Frame = %d\n", priv->disable_sv_frame);
 	seq_puts(sfp, "\n");
 	return 0;
 }

+ 98 - 28
net/hsr-prp/hsr_prp_device.c

@@ -230,6 +230,27 @@ int hsr_prp_lredev_get_node_table(struct hsr_prp_priv *priv,
 	return ret;
 }
 
+static int hsr_prp_set_sv_frame_vid(struct hsr_prp_priv *priv,
+				    u16 vid)
+{
+	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;
+
+	/* TODO can we use vlan_vid_add() here?? */
+	if (slave_a_dev && slave_a_dev->lredev_ops &&
+	    slave_a_dev->lredev_ops->lredev_set_sv_vlan_id)
+		slave_a_dev->lredev_ops->lredev_set_sv_vlan_id(slave_a_dev,
+							       vid);
+	return 0;
+}
+
 int hsr_prp_lredev_get_lre_stats(struct hsr_prp_priv *priv,
 				 struct lre_stats *stats)
 {
@@ -384,42 +405,73 @@ static void send_supervision_frame(struct hsr_prp_port *master,
 	struct sk_buff *skb;
 	int hlen, tlen;
 	struct hsr_tag *hsr_tag = NULL;
+	struct vlan_hdr *vhdr;
 	struct prp_rct *rct;
 	struct hsr_prp_sup_tag *hsr_stag;
 	struct hsr_prp_sup_payload *hsr_sp;
+	struct hsr_prp_priv *priv;
 	unsigned long irqflags;
-	u16 proto;
+	u16 proto, vlan_tci = 0;
 	u8 *tail;
+	int len;
+
+	priv = master->priv;
+
+	if (priv->disable_sv_frame)
+		return;
 
 	hlen = LL_RESERVED_SPACE(master->dev);
 	tlen = master->dev->needed_tailroom;
+	len = sizeof(struct hsr_tag) +
+	      sizeof(struct hsr_prp_sup_tag) +
+	      sizeof(struct hsr_prp_sup_payload) + hlen + tlen;
+
+	if (priv->use_vlan_for_sv)
+		len += VLAN_HLEN;
+
 	/* 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);
-
+	skb = dev_alloc_skb(len);
 	if (!skb)
 		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;
+	if (priv->use_vlan_for_sv) {
+		proto = ETH_P_8021Q;
+		skb->priority = priv->sv_frame_pcp;
+	} else {
+		if (!proto_ver)
+			proto = ETH_P_PRP;
+		else
+			proto = (proto_ver == HSR_V1) ? ETH_P_HSR : ETH_P_PRP;
+		skb->priority = TC_PRIO_CONTROL;
+	}
 	skb->protocol = htons(proto);
-	skb->priority = TC_PRIO_CONTROL;
 
 	if (dev_hard_header(skb, skb->dev, proto,
-			    master->priv->sup_multicast_addr,
+			    priv->sup_multicast_addr,
 			    skb->dev->dev_addr, skb->len) <= 0)
 		goto out;
 	skb_reset_mac_header(skb);
 	skb_reset_network_header(skb);
 
+	if (priv->use_vlan_for_sv) {
+		vhdr = skb_put(skb, VLAN_HLEN);
+		vlan_tci = priv->sv_frame_vid;
+		vlan_tci |= (priv->sv_frame_pcp	<< VLAN_PRIO_SHIFT);
+		if (priv->sv_frame_dei)
+			vlan_tci |= VLAN_CFI_MASK;
+		if (!proto_ver)
+			proto = ETH_P_PRP;
+		else
+			proto = (proto_ver == HSR_V1) ? ETH_P_HSR : ETH_P_PRP;
+		vhdr->h_vlan_TCI = htons(vlan_tci);
+		vhdr->h_vlan_encapsulated_proto = htons(proto);
+	}
+
 	if (proto_ver == HSR_V1) {
 		hsr_tag = skb_put(skb, sizeof(struct hsr_tag));
 		hsr_tag->encap_proto = htons(ETH_P_PRP);
@@ -431,21 +483,21 @@ static void send_supervision_frame(struct hsr_prp_port *master,
 	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);
+	spin_lock_irqsave(&priv->seqnr_lock, irqflags);
 	if (proto_ver > 0) {
-		hsr_stag->sequence_nr = htons(master->priv->sup_sequence_nr);
+		hsr_stag->sequence_nr = htons(priv->sup_sequence_nr);
 		if (hsr_tag)
-			hsr_tag->sequence_nr = htons(master->priv->sequence_nr);
-		master->priv->sup_sequence_nr++;
+			hsr_tag->sequence_nr = htons(priv->sequence_nr);
+		priv->sup_sequence_nr++;
 		if (proto_ver == HSR_V1) {
-			hsr_tag->sequence_nr = htons(master->priv->sequence_nr);
-			master->priv->sequence_nr++;
+			hsr_tag->sequence_nr = htons(priv->sequence_nr);
+			priv->sequence_nr++;
 		}
 	} else {
-		hsr_stag->sequence_nr = htons(master->priv->sequence_nr);
-		master->priv->sequence_nr++;
+		hsr_stag->sequence_nr = htons(priv->sequence_nr);
+		priv->sequence_nr++;
 	}
-	spin_unlock_irqrestore(&master->priv->seqnr_lock, irqflags);
+	spin_unlock_irqrestore(&priv->seqnr_lock, irqflags);
 
 	hsr_stag->HSR_TLV_type = type;
 	/* TODO: Why 12 in HSRv0? */
@@ -456,21 +508,26 @@ static void send_supervision_frame(struct hsr_prp_port *master,
 	hsr_sp = skb_put(skb, sizeof(struct hsr_prp_sup_payload));
 	ether_addr_copy(hsr_sp->macaddress_A, master->dev->dev_addr);
 
-	if (skb_put_padto(skb, ETH_ZLEN + HSR_PRP_HLEN))
-		return;
+	if (!priv->use_vlan_for_sv) {
+		if (skb_put_padto(skb, ETH_ZLEN + HSR_PRP_HLEN))
+			return;
+	} else {
+		if (skb_put_padto(skb, ETH_ZLEN + HSR_PRP_HLEN + VLAN_HLEN))
+			return;
+	}
 
-	spin_lock_irqsave(&master->priv->seqnr_lock, irqflags);
+	spin_lock_irqsave(&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_PRP_V1_SUP_LSDUSIZE);
-		rct->sequence_nr = htons(master->priv->sequence_nr);
-		master->priv->sequence_nr++;
+		rct->sequence_nr = htons(priv->sequence_nr);
+		priv->sequence_nr++;
 	}
-	spin_unlock_irqrestore(&master->priv->seqnr_lock, irqflags);
+	spin_unlock_irqrestore(&priv->seqnr_lock, irqflags);
 	hsr_prp_forward_skb(skb, master);
-	INC_CNT_TX_SUP(master->priv);
+	INC_CNT_TX_SUP(priv);
 	return;
 
 out:
@@ -730,7 +787,9 @@ static const unsigned char def_multicast_addr[ETH_ALEN] __aligned(2) = {
 
 int hsr_prp_dev_finalize(struct net_device *hsr_prp_dev,
 			 struct net_device *slave[2],
-			 unsigned char multicast_spec, u8 protocol_version)
+			 unsigned char multicast_spec, u8 protocol_version,
+			 bool sv_vlan_tag_needed, unsigned short vid,
+			 unsigned char pcp, unsigned char dei)
 {
 	netdev_features_t mask =
 		NETIF_F_HW_PRP_RX_OFFLOAD | NETIF_F_HW_HSR_RX_OFFLOAD;
@@ -775,6 +834,11 @@ int hsr_prp_dev_finalize(struct net_device *hsr_prp_dev,
 
 	ether_addr_copy(priv->sup_multicast_addr, def_multicast_addr);
 	priv->sup_multicast_addr[ETH_ALEN - 1] = multicast_spec;
+	/* update vlan tag infor for SV frames */
+	priv->use_vlan_for_sv = sv_vlan_tag_needed;
+	priv->sv_frame_vid = vid;
+	priv->sv_frame_dei = dei;
+	priv->sv_frame_pcp = pcp;
 
 	/* FIXME: should I modify the value of these?
 	 *
@@ -860,6 +924,12 @@ int hsr_prp_dev_finalize(struct net_device *hsr_prp_dev,
 	if (res)
 		goto fail_procfs;
 
+	if (priv->use_vlan_for_sv)
+		res = hsr_prp_set_sv_frame_vid(priv, priv->sv_frame_vid);
+
+	if (res)
+		goto fail_procfs;
+
 	return 0;
 
 fail_procfs:

+ 3 - 1
net/hsr-prp/hsr_prp_device.h

@@ -14,7 +14,9 @@
 void hsr_dev_setup(struct net_device *dev);
 void prp_dev_setup(struct net_device *dev);
 int hsr_prp_dev_finalize(struct net_device *dev, struct net_device *slave[2],
-			 unsigned char multicast_spec, u8 protocol_version);
+			 unsigned char multicast_spec, u8 protocol_version,
+			 bool sv_vlan_tag_needed, unsigned short vid,
+			 unsigned char pcp, unsigned char cfi);
 void hsr_prp_check_carrier_and_operstate(struct hsr_prp_priv *priv);
 bool is_hsr_prp_master(struct net_device *dev);
 int hsr_prp_get_max_mtu(struct hsr_prp_priv *priv);

+ 47 - 12
net/hsr-prp/hsr_prp_forward.c

@@ -46,9 +46,12 @@ struct hsr_prp_frame_info {
  */
 static bool is_supervision_frame(struct hsr_prp_priv *priv, struct sk_buff *skb)
 {
-	struct ethhdr *eth_hdr;
+	struct hsrv1_ethhdr_vlan_sp *hsr_v1_vlan_hdr;
 	struct hsr_prp_sup_tag *hsr_sup_tag;
-	struct hsrv1_ethhdr_sp *hsr_V1_hdr;
+	struct hsrv1_ethhdr_sp *hsr_v1_hdr;
+	struct ethhdr *eth_hdr;
+	bool vlan = false;
+	u16 proto;
 
 	WARN_ON_ONCE(!skb_mac_header_was_set(skb));
 	eth_hdr = (struct ethhdr *)skb_mac_header(skb);
@@ -58,21 +61,39 @@ static bool is_supervision_frame(struct hsr_prp_priv *priv, struct sk_buff *skb)
 			      priv->sup_multicast_addr))
 		return false;
 
+	if (skb_vlan_tagged(skb)) {
+		proto = vlan_get_protocol(skb);
+		vlan = true;
+	} else {
+		proto = eth_hdr->h_proto;
+	}
+
 	/* Correct ether type?. */
-	if (!(eth_hdr->h_proto == htons(ETH_P_PRP) ||
-	      eth_hdr->h_proto == htons(ETH_P_HSR)))
+	if (!(proto == htons(ETH_P_PRP) || proto == htons(ETH_P_HSR)))
 		return false;
 
 	/* Get the supervision header from correct location. */
-	if (eth_hdr->h_proto == htons(ETH_P_HSR)) { /* Okay HSRv1. */
-		hsr_V1_hdr = (struct hsrv1_ethhdr_sp *)skb_mac_header(skb);
-		if (hsr_V1_hdr->hsr.encap_proto != htons(ETH_P_PRP))
-			return false;
-
-		hsr_sup_tag = &hsr_V1_hdr->hsr_sup;
+	if (proto == htons(ETH_P_HSR)) { /* Okay HSRv1. */
+		if (!vlan) {
+			hsr_v1_hdr = (struct hsrv1_ethhdr_sp *)eth_hdr;
+			if (hsr_v1_hdr->hsr.encap_proto != htons(ETH_P_PRP))
+				return false;
+			hsr_sup_tag = &hsr_v1_hdr->hsr_sup;
+		} else {
+			hsr_v1_vlan_hdr =
+				(struct hsrv1_ethhdr_vlan_sp *)eth_hdr;
+			if (hsr_v1_vlan_hdr->hsr.encap_proto !=
+						htons(ETH_P_PRP))
+				return false;
+			hsr_sup_tag = &hsr_v1_vlan_hdr->hsr_sup;
+		}
 	} else {
-		hsr_sup_tag =
-		     &((struct hsrv0_ethhdr_sp *)skb_mac_header(skb))->hsr_sup;
+		if (!vlan)
+			hsr_sup_tag =
+			&((struct hsrv0_ethhdr_sp *)eth_hdr)->hsr_sup;
+		else
+			hsr_sup_tag =
+			&((struct hsrv0_ethhdr_vlan_sp *)eth_hdr)->hsr_sup;
 	}
 
 	if (hsr_sup_tag->HSR_TLV_type != HSR_TLV_ANNOUNCE &&
@@ -311,9 +332,23 @@ static struct sk_buff *frame_get_tagged_skb(struct hsr_prp_frame_info *frame,
 					    struct hsr_prp_port *port)
 {
 	if (frame->skb_hsr) {
+		u8 *pc;
 		struct hsr_ethhdr *hsr_ethhdr =
 			(struct hsr_ethhdr *)skb_mac_header(frame->skb_hsr);
 
+		/* This case is for SV frame created by this device */
+		pc = (u8 *)hsr_ethhdr;
+		if (frame->is_vlan)
+			/* This 4-byte shift (size of a vlan tag) does not
+			 * mean that the ethhdr starts there. But rather it
+			 * provides the proper environment for accessing
+			 * the fields, such as hsr_tag etc., just like
+			 * when the vlan tag is not there. This is because
+			 * the hsr tag is after the vlan tag.
+			 */
+			hsr_ethhdr = (struct hsr_ethhdr *)(pc + VLAN_HLEN);
+		else
+			hsr_ethhdr = (struct hsr_ethhdr *)pc;
 		/* set the lane id properly */
 		hsr_set_path_id(hsr_ethhdr, port);
 		return skb_clone(frame->skb_hsr, GFP_ATOMIC);

+ 20 - 0
net/hsr-prp/hsr_prp_main.h

@@ -140,12 +140,25 @@ struct hsrv0_ethhdr_sp {
 	struct hsr_prp_sup_tag	hsr_sup;
 } __packed;
 
+struct hsrv0_ethhdr_vlan_sp {
+	struct ethhdr		ethhdr;
+	struct vlan_hdr		vlanHdr;
+	struct hsr_prp_sup_tag	hsr_sup;
+} __packed;
+
 struct hsrv1_ethhdr_sp {
 	struct ethhdr		ethhdr;
 	struct hsr_tag		hsr;
 	struct hsr_prp_sup_tag	hsr_sup;
 } __packed;
 
+struct hsrv1_ethhdr_vlan_sp {
+	struct ethhdr		ethhdr;
+	struct vlan_hdr		vlanHdr;
+	struct hsr_tag		hsr;
+	struct hsr_prp_sup_tag	hsr_sup;
+} __packed;
+
 enum hsr_prp_port_type {
 	HSR_PRP_PT_NONE = 0,	/* Must be 0, used by framereg */
 	HSR_PRP_PT_SLAVE_A,
@@ -222,6 +235,13 @@ struct hsr_prp_priv {
 	u8 net_id;		/* for PRP, it occupies most significant 3 bits
 				 * of lan_id
 				 */
+	/* Below are used when SV frames are to be sent with VLAN tag */
+	u8 use_vlan_for_sv;
+	u16 sv_frame_vid;
+	u8 sv_frame_dei;
+	u8 sv_frame_pcp;
+	/* To enable/disable SV frame transmission */
+	u8 disable_sv_frame;
 	/* value of hsr mode */
 	enum iec62439_3_hsr_modes hsr_mode;
 	/* PRP Transparent Reception */

+ 28 - 1
net/hsr-prp/hsr_prp_netlink.c

@@ -29,6 +29,9 @@ int hsr_prp_newlink(int proto, struct net *src_net,
 	struct net_device *link[2];
 	unsigned char mc_lsb, version = 0;
 	char *sproto = (proto == PRP) ? "PRP" : "HSR";
+	unsigned short vid = 0;
+	unsigned char pcp = 0, dei = 0;
+	bool sv_vlan_tag_needed = false;
 
 	if (!data) {
 		netdev_info(dev, "%s: No slave devices specified\n", sproto);
@@ -66,7 +69,31 @@ int hsr_prp_newlink(int proto, struct net *src_net,
 			version = nla_get_u8(data[IFLA_HSR_VERSION]);
 	}
 
-	return hsr_prp_dev_finalize(dev, link, mc_lsb, version);
+	if (data[IFLA_HSR_PRP_SV_VID]) {
+		sv_vlan_tag_needed = true;
+		vid = nla_get_u16(data[IFLA_HSR_PRP_SV_VID]);
+	}
+
+	if (data[IFLA_HSR_PRP_SV_PCP]) {
+		sv_vlan_tag_needed = true;
+		pcp = nla_get_u8(data[IFLA_HSR_PRP_SV_PCP]);
+	}
+
+	if (data[IFLA_HSR_PRP_SV_DEI]) {
+		sv_vlan_tag_needed = true;
+		dei = nla_get_u8(data[IFLA_HSR_PRP_SV_DEI]);
+	}
+
+	if (sv_vlan_tag_needed &&
+	    (vid >= (VLAN_N_VID - 1) || dei > 1 || pcp > 7)) {
+		netdev_info(dev,
+			    "%s: wrong vlan params: vid %d, pcp %d, dei %d\n",
+			    sproto, vid, pcp, dei);
+		return -EINVAL;
+	}
+
+	return hsr_prp_dev_finalize(dev, link, mc_lsb, version,
+				    sv_vlan_tag_needed, vid, pcp, dei);
 }
 
 int hsr_prp_fill_info(struct sk_buff *skb, const struct net_device *dev)

+ 61 - 0
net/hsr-prp/hsr_prp_proc.c

@@ -548,6 +548,57 @@ static const struct file_operations clear_nt_fops = {
 	.release	= single_release,
 };
 
+static int disable_sv_show(struct seq_file *sfp, void *v)
+{
+	struct hsr_prp_priv *priv = (struct hsr_prp_priv *)sfp->private;
+
+	seq_printf(sfp, "%u\n", priv->disable_sv_frame);
+	return 0;
+}
+
+static int disable_sv_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, disable_sv_show, PDE_DATA(inode));
+}
+
+static ssize_t disable_sv_store(struct file *file,
+				const char __user *buffer,
+				size_t count, loff_t *pos)
+{
+	struct hsr_prp_priv *priv =
+		(struct hsr_prp_priv *)PDE_DATA(file_inode(file));
+	char cmd_buffer[BUF_SIZE];
+	int ret = -EINVAL;
+	u32 val;
+
+	if (count > (sizeof(cmd_buffer) - 1))
+		goto err;
+
+	if (copy_from_user(cmd_buffer, buffer, count)) {
+		ret = -EFAULT;
+		goto err;
+	}
+	cmd_buffer[count] = '\0';
+	ret = kstrtou32(cmd_buffer, 0, &val);
+	if (ret < 0 || val > 1)
+		goto err;
+
+	priv->disable_sv_frame = val;
+
+	return  count;
+err:
+	return ret;
+}
+
+static const struct file_operations disable_sv_fops = {
+	.owner		= THIS_MODULE,
+	.open		= disable_sv_open,
+	.read		= seq_read,
+	.write		= disable_sv_store,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
 int hsr_prp_create_procfs(struct hsr_prp_priv *priv, struct net_device *ndev)
 {
 	int ret = -ENODEV;
@@ -593,7 +644,16 @@ int hsr_prp_create_procfs(struct hsr_prp_priv *priv, struct net_device *ndev)
 	if (!priv->dlrmt_file)
 		goto fail_dlrmt;
 
+	priv->disable_sv_file = proc_create_data("disable-sv-frame", 0644,
+						 priv->dir, &disable_sv_fops,
+						 (void *)priv);
+	if (!priv->disable_sv_file)
+		goto fail_disable_sv;
+
 	return 0;
+fail_disable_sv:
+	if (priv->dlrmt_file)
+		remove_proc_entry("dlrmt", priv->dir);
 fail_dlrmt:
 	if (priv->clear_nt_file)
 		remove_proc_entry("clear-nt", priv->dir);
@@ -619,6 +679,7 @@ fail_lre_stats:
 
 void hsr_prp_remove_procfs(struct hsr_prp_priv *priv, struct net_device *ndev)
 {
+	remove_proc_entry("disable-sv-frame", priv->dir);
 	remove_proc_entry("dlrmt", priv->dir);
 	remove_proc_entry("clear-nt", priv->dir);
 	remove_proc_entry("prp-tr", priv->dir);