Commit 65ccbbda authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'Add-PRP-driver'

Murali Karicheri says:

====================
Add PRP driver

This series is dependent on the following patches sent out to
netdev list. All (1-3) are already merged to net/master as of
sending this, but not on the net-next master branch. So need
to apply them to net-next before applying this series. v3 of
the iproute2 patches can be merged to work with this series
as there are no updates since then.

[1] https://marc.info/?l=linux-netdev&m=159526378131542&w=2
[2] https://marc.info/?l=linux-netdev&m=159499772225350&w=2
[3] https://marc.info/?l=linux-netdev&m=159499772425352&w=2

This series adds support for Parallel Redundancy Protocol (PRP)
in the Linux HSR driver as defined in IEC-62439-3. PRP Uses a
Redundancy Control Trailer (RCT) the format of which is
similar to HSR Tag. This is used for implementing redundancy.
RCT consists of 6 bytes similar to HSR tag and contain following
fields:-

- 16-bit sequence number (SeqNr);
- 4-bit LAN identifier (LanId);
- 12 bit frame size (LSDUsize);
- 16-bit suffix (PRPsuffix).

The PRPsuffix identifies PRP frames and distinguishes PRP frames
from other protocols that also append a trailer to their useful
data. The LSDUsize field allows the receiver to distinguish PRP
frames from random, nonredundant frames as an additional check.
LSDUsize is the size of the Ethernet payload inclusive of the
RCT. Sequence number along with LanId is used for duplicate
detection and discard.

PRP node is also known as Dual Attached Node (DAN-P) since it
is typically attached to two different LAN for redundancy.
DAN-P duplicates each of L2 frames and send it over the two
Ethernet links. Each outgoing frame is appended with RCT.
Unlike HSR, these are added to the end of L2 frame and will be
treated as pad by bridges and therefore would be work with
traditional bridges or switches, where as HSR wouldn't as Tag
is prefixed to the Ethenet frame. At the remote end, these are
received and the duplicate frame is discarded before the stripped
frame is send up the networking stack. Like HSR, PRP also sends
periodic Supervision frames to the network. These frames are
received and MAC address from the SV frames are populated in a
database called Node Table. The above functions are grouped into
a block called Link Redundancy Entity (LRE) in the IEC spec.

As there are many similarities between HSR and PRP protocols,
this patch re-uses the code from HSR driver to implement PRP
driver. As per feedback from the RFC series, the implementation
uses the existing HSR Netlink socket interface to create the
PRP interface by adding a new proto parameter to the ip link
command to identify the PRP protocol. iproute2 is enhanced to
implement this new parameter. The hsr_netlink.c is enhanced
to handle the new proto parameter. As suggested during the RFC
review, the driver introduced a proto_ops structure to hold
protocol specfic functions to handle HSR and PRP specific
function pointers and use them in the code based on the
protocol to handle protocol specific part differently in the
driver.

Please review this and provide me feedback so that I can work to
incorporate them and spin the next version if needed.

The patch was tested using two TI AM57x IDK boards for PRP which
are connected back to back over two CPSW Ethernet ports.

PRP Test setup
---------------

--------eth0             eth0 --------
|AM572x|----------------------|AM572x|
|      |----------------------|      |
--------eth1             eth1 --------

To build, enable CONFIG_HSR=y or m
make omap2plus_defconfig
make zImage; make modules; make dtbs
Copy the zImage and dtb files to the file system on SD card
and power on the AM572x boards.
This can be tested on any platforms with 2 Ethernet interfaces.
So will appreciate if you can give it a try and provide your
Tested-by.

Command to create PRP interface
-------------------------------
ifconfig eth0 0.0.0.0 down
ifconfig eth1 0.0.0.0 down
ifconfig eth0 hw ether 70:FF:76:1C:0E:8C
ifconfig eth1 hw ether 70:FF:76:1C:0E:8C
ifconfig eth0 up
ifconfig eth1 up
ip link add name prp0 type hsr slave1 eth0 slave2 eth1 supervision 45 proto 1
ifconfig prp0 192.168.2.10

ifconfig eth0 0.0.0.0 down
ifconfig eth1 0.0.0.0 down
ifconfig eth0 hw ether 70:FF:76:1C:0E:8D
ifconfig eth1 hw ether 70:FF:76:1C:0E:8D
ifconfig eth0 up
ifconfig eth1 up
ip link add name prp0 type hsr slave1 eth0 slave2 eth1 supervision 45 proto 1
ifconfig prp0 192.168.2.20

command to show node table
----------------------------
Ping the peer board after the prp0 interface is up.

The remote node (DAN-P) will be shown in the node table as below.

root@am57xx-evm:~# cat /sys/kernel/debug/hsr/prp0/node_table
Node Table entries for (PRP) device
MAC-Address-A,    MAC-Address-B,    time_in[A], time_in[B], Address-B port, SAN-A, SAN-B, DAN-P
70:ff:76:1c:0e:8c 00:00:00:00:00:00   ffffe83f,   ffffe83f,              0,     0,     0,     1

Try to capture the raw PRP frames at the eth0 interface as
tcpdump -i eth0 -xxx

Sample Supervision frames and ARP frames shown below.

==================================================================================
Successive Supervision frames captured with tcpdump (with RCT at the end):

03:43:29.500999 70:ff:76:1c:0e:8d (oui Unknown) > 01:15:4e:00:01:2d (oui Unknown), ethertype Unknown (0x88f
        0x0000:  0115 4e00 012d 70ff 761c 0e8d 88fb 0001
        0x0010:  7e0a 1406 70ff 761c 0e8d 0000 0000 0000
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000
        0x0030:  0000 0000 0000 0000 0000 0000 fc2b a034
        0x0040:  88fb

03:43:31.581025 70:ff:76:1c:0e:8d (oui Unknown) > 01:15:4e:00:01:2d (oui Unknown), ethertype Unknown (0x88f
        0x0000:  0115 4e00 012d 70ff 761c 0e8d 88fb 0001
        0x0010:  7e0b 1406 70ff 761c 0e8d 0000 0000 0000
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000
        0x0030:  0000 0000 0000 0000 0000 0000 fc2c a034
        0x0040:  88fb

ICMP Echo request frame with RCT
03:43:33.805354 IP 192.168.2.20 > 192.168.2.10: ICMP echo request, id 63748, seq 1, length 64
        0x0000:  70ff 761c 0e8c 70ff 761c 0e8d 0800 4500
        0x0010:  0054 26a4 4000 4001 8e96 c0a8 0214 c0a8
        0x0020:  020a 0800 c28e f904 0001 202e 1c3d 0000
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000
        0x0040:  0000 0000 0000 0000 0000 0000 0000 0000
        0x0050:  0000 0000 0000 0000 0000 0000 0000 0000
        0x0060:  0000 fc31 a05a 88fb
==================================================================================
The iperf3 traffic test logs can be accessed at the links below.
DUT-1: https://pastebin.ubuntu.com/p/8SkQzWJMn8/
DUT-2: https://pastebin.ubuntu.com/p/j2BZvvs7p4/

Other tests done.
 - Connect a SAN (eth0 and eth1 without prp interface) and
   do ping test from eth0 (192.168.2.40) to prp0 (192.168.2.10)
   verify the SAN node shows at the correct link A and B as shown
   in the node table dump
 - Regress HSR interface using 3 nodes connected in a ring topology.
   create hsr link version 0. Do iperf3 test between all nodes
   create hsr link version 1. Do iperf3 test between all nodes.

         --------eth0             eth1 --------eth0      eth1-------|
         |AM572x|----------------------|AM572x|--------------|AM572x|
         |      |                      |      |        ------|      |
         --------eth1---|               -------        | eth0 -------
                        |-------------------------------

   command used for HSR interface

   HSR V0

   ifconfig eth0 0.0.0.0 down
   ifconfig eth1 0.0.0.0 down
   ifconfig eth0 hw ether 70:FF:76:1C:0E:8C
   ifconfig eth1 hw ether 70:FF:76:1C:0E:8C
   ifconfig eth0 up
   ifconfig eth1 up
   ip link add name hsr0 type hsr slave1 eth0 slave2 eth1 supervision 45 version 0
   ifconfig hsr0 192.168.2.10

   HSR V1

   ifconfig eth0 0.0.0.0 down
   ifconfig eth1 0.0.0.0 down
   ifconfig eth0 hw ether 70:FF:76:1C:0E:8C
   ifconfig eth1 hw ether 70:FF:76:1C:0E:8C
   ifconfig eth0 up
   ifconfig eth1 up
   ip link add name hsr0 type hsr slave1 eth0 slave2 eth1 supervision 45 version 1
   ifconfig hsr0 192.168.2.10

   Logs at
   DUT-1 : https://pastebin.ubuntu.com/p/6PSJbZwQ6y/
   DUT-2 : https://pastebin.ubuntu.com/p/T8TqJsPRHc/
   DUT-3 : https://pastebin.ubuntu.com/p/VNzpv6HzKj/
 - Build tests :-
   Build with CONFIG_HSR=m
   allmodconfig build
   build with CONFIG_HSR=y and rebuild with sparse checker
   make C=1 zImage; make modules

Version history:
  v5 : Fixed comments about Kconfig changes on Patch 1/7 against v4
       Rebased to netnext/master branch.

  v4 : fixed following vs v3
       reverse xmas tree for local variables
       check for return type in call to skb_put_padto()

  v3 : Separated bug fixes from this series and send them for immediate merge
       But for that this is same as v2.

  v2 : updated comments on RFC. Following are the main changes:-
       - Removed the hsr_prp prefix
       - Added PRP information in header files to indicate
         the support for PRP explicitely
       - Re-use netlink socket interface with an added
         parameter proto for identifying PRP.
       - Use function pointers using a proto_ops struct
         to do things differently for PRP vs HSR.

   RFC: initial version posted and discussed at
       https://www.spinics.net/lists/netdev/msg656229.html


====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1775da47 795ec4f5
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@
/* Generic Netlink HSR family definition
 */

/* attributes */
/* attributes for HSR or PRP node */
enum {
	HSR_A_UNSPEC,
	HSR_A_NODE_ADDR,
+11 −1
Original line number Diff line number Diff line
@@ -907,7 +907,14 @@ enum {
#define IFLA_IPOIB_MAX (__IFLA_IPOIB_MAX - 1)


/* HSR section */
/* HSR/PRP section, both uses same interface */

/* Different redundancy protocols for hsr device */
enum {
	HSR_PROTOCOL_HSR,
	HSR_PROTOCOL_PRP,
	HSR_PROTOCOL_MAX,
};

enum {
	IFLA_HSR_UNSPEC,
@@ -917,6 +924,9 @@ enum {
	IFLA_HSR_SUPERVISION_ADDR,	/* Supervision frame multicast addr */
	IFLA_HSR_SEQ_NR,
	IFLA_HSR_VERSION,		/* HSR version */
	IFLA_HSR_PROTOCOL,		/* Indicate different protocol than
					 * HSR. For example PRP.
					 */
	__IFLA_HSR_MAX,
};

+23 −12
Original line number Diff line number Diff line
@@ -4,24 +4,35 @@
#

config HSR
	tristate "High-availability Seamless Redundancy (HSR)"
	tristate "High-availability Seamless Redundancy (HSR & PRP)"
	help
	  This enables IEC 62439 defined High-availability Seamless
	  Redundancy (HSR) and Parallel Redundancy Protocol (PRP).

	  If you say Y here, then your Linux box will be able to act as a
	  DANH ("Doubly attached node implementing HSR"). For this to work,
	  your Linux box needs (at least) two physical Ethernet interfaces,
	  and it must be connected as a node in a ring network together with
	  other HSR capable nodes.
	  DANH ("Doubly attached node implementing HSR") or DANP ("Doubly
	  attached node implementing PRP"). For this to work, your Linux box
	  needs (at least) two physical Ethernet interfaces.

	  For DANH, it must be connected as a node in a ring network together
	  with other HSR capable nodes. All Ethernet frames sent over the HSR
	  device will be sent in both directions on the ring (over both slave
	  ports), giving a redundant, instant fail-over network. Each HSR node
	  in the ring acts like a bridge for HSR frames, but filters frames
	  that have been forwarded earlier.

	  All Ethernet frames sent over the hsr device will be sent in both
	  directions on the ring (over both slave ports), giving a redundant,
	  instant fail-over network. Each HSR node in the ring acts like a
	  bridge for HSR frames, but filters frames that have been forwarded
	  earlier.
	  For DANP, it must be connected as a node connecting to two
	  separate networks over the two slave interfaces. Like HSR, Ethernet
	  frames sent over the PRP device will be sent to both networks giving
	  a redundant, instant fail-over network. Unlike HSR, PRP networks
	  can have Singly Attached Nodes (SAN) such as PC, printer, bridges
	  etc and will be able to communicate with DANP nodes.

	  This code is a "best effort" to comply with the HSR standard as
	  described in IEC 62439-3:2010 (HSRv0) and IEC 62439-3:2012 (HSRv1),
	  but no compliancy tests have been made. Use iproute2 to select
	  the version you desire.
	  and PRP standard described in IEC 62439-4:2012 (PRP), but no
	  compliancy tests have been made. Use iproute2 to select the protocol
	  you would like to use.

	  You need to perform any and all necessary tests yourself before
	  relying on this code in a safety critical system!
+23 −10
Original line number Diff line number Diff line
/*
 * hsr_debugfs code
 * debugfs code for HSR & PRP
 * Copyright (C) 2019 Texas Instruments Incorporated
 *
 * Author(s):
@@ -24,7 +24,7 @@ static struct dentry *hsr_debugfs_root_dir;

static void print_mac_address(struct seq_file *sfp, unsigned char *mac)
{
	seq_printf(sfp, "%02x:%02x:%02x:%02x:%02x:%02x:",
	seq_printf(sfp, "%02x:%02x:%02x:%02x:%02x:%02x ",
		   mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}

@@ -35,20 +35,32 @@ hsr_node_table_show(struct seq_file *sfp, void *data)
	struct hsr_priv *priv = (struct hsr_priv *)sfp->private;
	struct hsr_node *node;

	seq_puts(sfp, "Node Table entries\n");
	seq_printf(sfp, "Node Table entries for (%s) device\n",
		   (priv->prot_version == PRP_V1 ? "PRP" : "HSR"));
	seq_puts(sfp, "MAC-Address-A,    MAC-Address-B,    time_in[A], ");
	seq_puts(sfp, "time_in[B], Address-B port\n");
	seq_puts(sfp, "time_in[B], Address-B port, ");
	if (priv->prot_version == PRP_V1)
		seq_puts(sfp, "SAN-A, SAN-B, DAN-P\n");
	else
		seq_puts(sfp, "DAN-H\n");

	rcu_read_lock();
	list_for_each_entry_rcu(node, &priv->node_db, mac_list) {
		/* skip self node */
		if (hsr_addr_is_self(priv, node->macaddress_A))
			continue;
		print_mac_address(sfp, &node->macaddress_A[0]);
		seq_puts(sfp, " ");
		print_mac_address(sfp, &node->macaddress_B[0]);
		seq_printf(sfp, "0x%lx, ", node->time_in[HSR_PT_SLAVE_A]);
		seq_printf(sfp, "0x%lx ", node->time_in[HSR_PT_SLAVE_B]);
		seq_printf(sfp, "0x%x\n", node->addr_B_port);
		seq_printf(sfp, "%10lx, ", node->time_in[HSR_PT_SLAVE_A]);
		seq_printf(sfp, "%10lx, ", node->time_in[HSR_PT_SLAVE_B]);
		seq_printf(sfp, "%14x, ", node->addr_B_port);

		if (priv->prot_version == PRP_V1)
			seq_printf(sfp, "%5x, %5x, %5x\n",
				   node->san_a, node->san_b,
				   (node->san_a == 0 && node->san_b == 0));
		else
			seq_printf(sfp, "%5x\n", 1);
	}
	rcu_read_unlock();
	return 0;
@@ -57,7 +69,8 @@ hsr_node_table_show(struct seq_file *sfp, void *data)
/* hsr_node_table_open - Open the node_table file
 *
 * Description:
 * This routine opens a debugfs file node_table of specific hsr device
 * This routine opens a debugfs file node_table of specific hsr
 * or prp device
 */
static int
hsr_node_table_open(struct inode *inode, struct file *filp)
+140 −41
Original line number Diff line number Diff line
@@ -3,9 +3,8 @@
 *
 * Author(s):
 *	2011-2014 Arvid Brodin, arvid.brodin@alten.se
 *
 * This file contains device methods for creating, using and destroying
 * virtual HSR devices.
 * virtual HSR or PRP devices.
 */

#include <linux/netdevice.h>
@@ -231,66 +230,103 @@ static const struct header_ops hsr_header_ops = {
	.parse	 = eth_header_parse,
};

static void send_hsr_supervision_frame(struct hsr_port *master,
				       u8 type, u8 hsr_ver)
static struct sk_buff *hsr_init_skb(struct hsr_port *master, u16 proto)
{
	struct hsr_priv *hsr = master->hsr;
	struct sk_buff *skb;
	int hlen, tlen;
	struct hsr_tag *hsr_tag;
	struct hsr_sup_tag *hsr_stag;
	struct hsr_sup_payload *hsr_sp;
	unsigned long irqflags;

	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 trailer and for HSR it is a
	 * header
	 */
	skb = dev_alloc_skb(sizeof(struct hsr_tag) +
			    sizeof(struct hsr_sup_tag) +
			    sizeof(struct hsr_sup_payload) + hlen + tlen);

	if (!skb)
		return;
		return skb;

	skb_reserve(skb, hlen);

	skb->dev = master->dev;
	skb->protocol = htons(hsr_ver ? ETH_P_HSR : ETH_P_PRP);
	skb->protocol = htons(proto);
	skb->priority = TC_PRIO_CONTROL;

	if (dev_hard_header(skb, skb->dev, (hsr_ver ? ETH_P_HSR : ETH_P_PRP),
			    master->hsr->sup_multicast_addr,
	if (dev_hard_header(skb, skb->dev, proto,
			    hsr->sup_multicast_addr,
			    skb->dev->dev_addr, skb->len) <= 0)
		goto out;

	skb_reset_mac_header(skb);
	skb_reset_network_header(skb);
	skb_reset_transport_header(skb);

	if (hsr_ver > 0) {
	return skb;
out:
	kfree_skb(skb);

	return NULL;
}

static void send_hsr_supervision_frame(struct hsr_port *master,
				       unsigned long *interval)
{
	struct hsr_priv *hsr = master->hsr;
	__u8 type = HSR_TLV_LIFE_CHECK;
	struct hsr_tag *hsr_tag = NULL;
	struct hsr_sup_payload *hsr_sp;
	struct hsr_sup_tag *hsr_stag;
	unsigned long irqflags;
	struct sk_buff *skb;
	u16 proto;

	*interval = msecs_to_jiffies(HSR_LIFE_CHECK_INTERVAL);
	if (hsr->announce_count < 3 && hsr->prot_version == 0) {
		type = HSR_TLV_ANNOUNCE;
		*interval = msecs_to_jiffies(HSR_ANNOUNCE_INTERVAL);
		hsr->announce_count++;
	}

	if (!hsr->prot_version)
		proto = ETH_P_PRP;
	else
		proto = ETH_P_HSR;

	skb = hsr_init_skb(master, proto);
	if (!skb) {
		WARN_ONCE(1, "HSR: Could not send supervision frame\n");
		return;
	}

	if (hsr->prot_version > 0) {
		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);
	}

	hsr_stag = skb_put(skb, sizeof(struct hsr_sup_tag));
	set_hsr_stag_path(hsr_stag, (hsr_ver ? 0x0 : 0xf));
	set_hsr_stag_HSR_ver(hsr_stag, hsr_ver);
	set_hsr_stag_path(hsr_stag, (hsr->prot_version ? 0x0 : 0xf));
	set_hsr_stag_HSR_ver(hsr_stag, hsr->prot_version);

	/* From HSRv1 on we have separate supervision sequence numbers. */
	spin_lock_irqsave(&master->hsr->seqnr_lock, irqflags);
	if (hsr_ver > 0) {
		hsr_stag->sequence_nr = htons(master->hsr->sup_sequence_nr);
		hsr_tag->sequence_nr = htons(master->hsr->sequence_nr);
		master->hsr->sup_sequence_nr++;
		master->hsr->sequence_nr++;
	if (hsr->prot_version > 0) {
		hsr_stag->sequence_nr = htons(hsr->sup_sequence_nr);
		hsr->sup_sequence_nr++;
		hsr_tag->sequence_nr = htons(hsr->sequence_nr);
		hsr->sequence_nr++;
	} else {
		hsr_stag->sequence_nr = htons(master->hsr->sequence_nr);
		master->hsr->sequence_nr++;
		hsr_stag->sequence_nr = htons(hsr->sequence_nr);
		hsr->sequence_nr++;
	}
	spin_unlock_irqrestore(&master->hsr->seqnr_lock, irqflags);

	hsr_stag->HSR_TLV_type = type;
	/* TODO: Why 12 in HSRv0? */
	hsr_stag->HSR_TLV_length =
				hsr_ver ? sizeof(struct hsr_sup_payload) : 12;
	hsr_stag->HSR_TLV_length = hsr->prot_version ?
				sizeof(struct hsr_sup_payload) : 12;

	/* Payload: MacAddressA */
	hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload));
@@ -300,11 +336,57 @@ static void send_hsr_supervision_frame(struct hsr_port *master,
		return;

	hsr_forward_skb(skb, master);

	return;
}

out:
	WARN_ONCE(1, "HSR: Could not send supervision frame\n");
	kfree_skb(skb);
static void send_prp_supervision_frame(struct hsr_port *master,
				       unsigned long *interval)
{
	struct hsr_priv *hsr = master->hsr;
	struct hsr_sup_payload *hsr_sp;
	struct hsr_sup_tag *hsr_stag;
	unsigned long irqflags;
	struct sk_buff *skb;
	struct prp_rct *rct;
	u8 *tail;

	skb = hsr_init_skb(master, ETH_P_PRP);
	if (!skb) {
		WARN_ONCE(1, "PRP: Could not send supervision frame\n");
		return;
	}

	*interval = msecs_to_jiffies(HSR_LIFE_CHECK_INTERVAL);
	hsr_stag = skb_put(skb, sizeof(struct hsr_sup_tag));
	set_hsr_stag_path(hsr_stag, (hsr->prot_version ? 0x0 : 0xf));
	set_hsr_stag_HSR_ver(hsr_stag, (hsr->prot_version ? 1 : 0));

	/* From HSRv1 on we have separate supervision sequence numbers. */
	spin_lock_irqsave(&master->hsr->seqnr_lock, irqflags);
	hsr_stag->sequence_nr = htons(hsr->sup_sequence_nr);
	hsr->sup_sequence_nr++;
	hsr_stag->HSR_TLV_type = PRP_TLV_LIFE_CHECK_DD;
	hsr_stag->HSR_TLV_length = sizeof(struct hsr_sup_payload);

	/* Payload: MacAddressA */
	hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload));
	ether_addr_copy(hsr_sp->macaddress_A, master->dev->dev_addr);

	if (skb_put_padto(skb, ETH_ZLEN + HSR_HLEN)) {
		spin_unlock_irqrestore(&master->hsr->seqnr_lock, irqflags);
		return;
	}

	tail = skb_tail_pointer(skb) - HSR_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(hsr->sequence_nr);
	hsr->sequence_nr++;
	spin_unlock_irqrestore(&master->hsr->seqnr_lock, irqflags);

	hsr_forward_skb(skb, master);
}

/* Announce (supervision frame) timer function
@@ -319,19 +401,7 @@ static void hsr_announce(struct timer_list *t)

	rcu_read_lock();
	master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);

	if (hsr->announce_count < 3 && hsr->prot_version == 0) {
		send_hsr_supervision_frame(master, HSR_TLV_ANNOUNCE,
					   hsr->prot_version);
		hsr->announce_count++;

		interval = msecs_to_jiffies(HSR_ANNOUNCE_INTERVAL);
	} else {
		send_hsr_supervision_frame(master, HSR_TLV_LIFE_CHECK,
					   hsr->prot_version);

		interval = msecs_to_jiffies(HSR_LIFE_CHECK_INTERVAL);
	}
	hsr->proto_ops->send_sv_frame(master, &interval);

	if (is_admin_up(master->dev))
		mod_timer(&hsr->announce_timer, jiffies + interval);
@@ -368,6 +438,24 @@ static struct device_type hsr_type = {
	.name = "hsr",
};

static struct hsr_proto_ops hsr_ops = {
	.send_sv_frame = send_hsr_supervision_frame,
	.create_tagged_frame = hsr_create_tagged_frame,
	.get_untagged_frame = hsr_get_untagged_frame,
	.fill_frame_info = hsr_fill_frame_info,
	.invalid_dan_ingress_frame = hsr_invalid_dan_ingress_frame,
};

static struct hsr_proto_ops prp_ops = {
	.send_sv_frame = send_prp_supervision_frame,
	.create_tagged_frame = prp_create_tagged_frame,
	.get_untagged_frame = prp_get_untagged_frame,
	.drop_frame = prp_drop_frame,
	.fill_frame_info = prp_fill_frame_info,
	.handle_san_frame = prp_handle_san_frame,
	.update_san_info = prp_update_san_info,
};

void hsr_dev_setup(struct net_device *dev)
{
	eth_hw_addr_random(dev);
@@ -427,6 +515,17 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],

	ether_addr_copy(hsr_dev->dev_addr, slave[0]->dev_addr);

	/* initialize protocol specific functions */
	if (protocol_version == PRP_V1) {
		/* For PRP, lan_id has most significant 3 bits holding
		 * the net_id of PRP_LAN_ID
		 */
		hsr->net_id = PRP_LAN_ID << 1;
		hsr->proto_ops = &prp_ops;
	} else {
		hsr->proto_ops = &hsr_ops;
	}

	/* Make sure we recognize frames from ourselves in hsr_rcv() */
	res = hsr_create_self_node(hsr, hsr_dev->dev_addr,
				   slave[1]->dev_addr);
Loading