net/hsr: Add support for the High-availability Seamless Redundancy protocol (HSRv0)
Subsystems (3)
PATCH v2 1/1 net/hsr: Add support for the High-availability Seamless Redundancy protocol (HSRv0)
High-availability Seamless Redundancy ("HSR") provides instant failover redundancy for Ethernet networks. It requires a special network topology where all nodes are connected in a ring (each node having two physical network interfaces). It is suited for applications that demand high availability and very short reaction time.
HSR acts on the Ethernet layer, using a registered Ethernet protocol type to send special HSR frames in both directions over the ring. The driver creates virtual network interfaces that can be used just like any ordinary Linux network interface, for IP/TCP/UDP traffic etc. All nodes in the network ring must be HSR capable.
This code is a "best effort" to comply with the HSR standard as described in IEC 62439-3:2010 (HSRv0).
---
This is a patch against net-next (2013-06-20).
The code has been statically analysed using sparse (no problems detected).
kmemleak has been used to detect memory leaks (no known leaks exist).
The code passes checkpatch.pl with the option --max-line-length=83, except for CamelCase warnings. CamelCase is used in the IEC standard to describe field names, and these names have been used in the code. This usage is intentional.
The code has been tested extensively on rings of up to 32 avr32-based nodes. Less intense testing has included an x86_64 (SMP) system, and running HSR over a USB-to-Ethernet device.
Earlier RFC:s:
RFC v1: http://www.spinics.net/lists/netdev/msg192817.html
RFC v2: http://www.spinics.net/lists/netdev/msg203397.html
RFC v3: http://www.spinics.net/lists/netdev/msg207816.html
RFC v4: http://www.spinics.net/lists/netdev/msg213309.html
Thanks to Stephen Hemminger, Joe Perches, and others for their comments on these RFC:s.
Changes since v1:
* Aligned newlines with open parenthesis (Joe Perches)
* Removed unneccessary WARN_ON_ONCE from is_hsr_master() (Joe Perches)
* Removed deprecated comments about "actually signed" for HSR_A_IFn_AGE (Joe Perches)
* Broke out userspace hsr_netlink.h into include/uapi/linux/ (Joe Perches)
* Use netif_oper_up() to check for operational state UP (Stephen Hemminger)
Possibly unresolved:
* dev_base_lock vs rtnl_mutex when setting operstate? (Stephen Hemminger)
* Move more (local) header files into include/net/? (checkpatch still warns about CamelCase) (Joe Perches / with help from David Miller?)
include/uapi/linux/hsr_netlink.h | 50 ++++ include/uapi/linux/if_ether.h | 1 + include/uapi/linux/if_link.h | 13 + net/Kconfig | 1 + net/Makefile | 1 + net/hsr/Kconfig | 27 ++ net/hsr/Makefile | 7 + net/hsr/hsr_device.c | 585 +++++++++++++++++++++++++++++++++++++++ net/hsr/hsr_device.h | 30 ++ net/hsr/hsr_framereg.c | 502 +++++++++++++++++++++++++++++++++ net/hsr/hsr_framereg.h | 54 ++++ net/hsr/hsr_main.c | 457 ++++++++++++++++++++++++++++++ net/hsr/hsr_main.h | 167 +++++++++++ net/hsr/hsr_netlink.c | 458 ++++++++++++++++++++++++++++++ net/hsr/hsr_netlink.h | 31 +++ 15 files changed, 2384 insertions(+) create mode 100644 include/uapi/linux/hsr_netlink.h create mode 100644 net/hsr/Kconfig create mode 100644 net/hsr/Makefile create mode 100644 net/hsr/hsr_device.c create mode 100644 net/hsr/hsr_device.h create mode 100644 net/hsr/hsr_framereg.c create mode 100644 net/hsr/hsr_framereg.h create mode 100644 net/hsr/hsr_main.c create mode 100644 net/hsr/hsr_main.h create mode 100644 net/hsr/hsr_netlink.c create mode 100644 net/hsr/hsr_netlink.h
include/uapi/linux/hsr_netlink.h new file +50 -0
@@ -0,0 +1,50 @@ +/* +* Copyright 2011-2013 Autronica Fire and Security AS +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the Free +* Software Foundation; either version 2 of the License, or (at your option) +* any later version. +* +* Author(s): +* 2011-2013 Arvid Brodin, [email protected] +*/ + +#ifndef __UAPI_HSR_NETLINK_H +#define __UAPI_HSR_NETLINK_H + +/* Generic Netlink HSR family definition +*/ + +/* attributes */ +enum { +HSR_A_UNSPEC , +HSR_A_NODE_ADDR , +HSR_A_IFINDEX , +HSR_A_IF1_AGE , +HSR_A_IF2_AGE , +HSR_A_NODE_ADDR_B , +HSR_A_IF1_SEQ , +HSR_A_IF2_SEQ , +HSR_A_IF1_IFINDEX , +HSR_A_IF2_IFINDEX , +HSR_A_ADDR_B_IFINDEX , + __HSR_A_MAX, +}; +#define HSR_A_MAX (__HSR_A_MAX - 1) + + +/* commands */ +enum { +HSR_C_UNSPEC , +HSR_C_RING_ERROR , +HSR_C_NODE_DOWN , +HSR_C_GET_NODE_STATUS , +HSR_C_SET_NODE_STATUS , +HSR_C_GET_NODE_LIST , +HSR_C_SET_NODE_LIST , + __HSR_C_MAX, +}; +#define HSR_C_MAX (__HSR_C_MAX - 1) + +#endif /* __UAPI_HSR_NETLINK_H */
include/uapi/linux/if_ether.h +1 -0
@@ -85,6 +85,7 @@#define ETH_P_8021AH 0x88E7/* 802.1ah Backbone Service Tag */ #define ETH_P_MVRP 0x88F5/* 802.1Q MVRP */ #define ETH_P_1588 0x88F7/* IEEE 1588 Timesync */ +#define ETH_P_PRP 0x88FB/* IEC 62439-3 PRP/HSRv0 */ #define ETH_P_FCOE 0x8906/* Fibre Channel over Ethernet */ #define ETH_P_TDLS 0x890D/* TDLS */ #define ETH_P_FIP 0x8914/* FCoE Initialization Protocol */
include/uapi/linux/if_link.h +13 -0
@@ -467,4 +467,17 @@ enum {#define IFLA_IPOIB_MAX (__IFLA_IPOIB_MAX - 1) + +/* HSR section */ + +enum { +IFLA_HSR_UNSPEC , +IFLA_HSR_SLAVE1 , +IFLA_HSR_SLAVE2 , +IFLA_HSR_MULTICAST_SPEC , + __IFLA_HSR_MAX, +}; + +#define IFLA_HSR_MAX (__IFLA_HSR_MAX - 1) +#endif /* _UAPI_LINUX_IF_LINK_H */
net/Kconfig +1 -0
@@ -219,6 +219,7 @@ source "net/openvswitch/Kconfig" source "net/vmw_vsock/Kconfig" source "net/netlink/Kconfig" source "net/mpls/Kconfig" +source "net/hsr/Kconfig" config RPS boolean
net/Makefile +1 -0
@@ -71,3 +71,4 @@ obj-$(CONFIG_NFC) += nfc/ obj-$(CONFIG_OPENVSWITCH) += openvswitch/ obj-$(CONFIG_VSOCKETS) += vmw_vsock/ obj-$(CONFIG_NET_MPLS_GSO) += mpls/ +obj-$(CONFIG_HSR) += hsr/
net/hsr/Kconfig new file +27 -0
@@ -0,0 +1,27 @@ +# +# IEC 62439-3 High-availability Seamless Redundancy +# + +config HSR + tristate "High-availability Seamless Redundancy (HSR)" + ---help--- + 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. + + 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. + + This code is a "best effort" to comply with the HSR standard as + described in IEC 62439-3:2010 (HSRv0), but no compliancy tests have + been made. + + You need to perform any and all necessary tests yourself before + relying on this code in a safety critical system! + + If unsure, say N.
net/hsr/Makefile new file +7 -0
@@ -0,0 +1,7 @@ +# +# Makefile for HSR +# + +obj-$(CONFIG_HSR) += hsr.o + +hsr-y := hsr_main.o hsr_framereg.o hsr_device.o hsr_netlink.o
net/hsr/hsr_device.c new file +585 -0
585 lines not on this page · raw message
net/hsr/hsr_device.h new file +30 -0
@@ -0,0 +1,30 @@ +/* +* Copyright 2011-2013 Autronica Fire and Security AS +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the Free +* Software Foundation; either version 2 of the License, or (at your option) +* any later version. +* +* Author(s): +* 2011-2013 Arvid Brodin, [email protected] +*/ + +#ifndef __HSR_DEVICE_H +#define __HSR_DEVICE_H + +#include <linux/netdevice.h> +#include "hsr_main.h" + +void hsr_dev_setup (struct net_device *dev); +int hsr_dev_finalize (struct net_device *hsr_dev,struct net_device *slave[2 ], +unsigned char multicast_spec); +void hsr_set_operstate (struct net_device *hsr_dev,struct net_device *slave1, +struct net_device *slave2); +void hsr_set_carrier (struct net_device *hsr_dev,struct net_device *slave1, +struct net_device *slave2); +void hsr_check_announce (struct net_device *hsr_dev,int old_operstate); +bool is_hsr_master (struct net_device *dev); +int hsr_get_max_mtu (struct hsr_priv *hsr_priv); + +#endif /* __HSR_DEVICE_H */
net/hsr/hsr_framereg.c new file +502 -0
502 lines not on this page · raw message
net/hsr/hsr_framereg.h new file +54 -0
54 lines not on this page · raw message
net/hsr/hsr_main.c new file +457 -0
457 lines not on this page · raw message
net/hsr/hsr_main.h new file +167 -0
167 lines not on this page · raw message
net/hsr/hsr_netlink.c new file +458 -0
458 lines not on this page · raw message
net/hsr/hsr_netlink.h new file +31 -0
@@ -0,0 +1,31 @@ +/* +* Copyright 2011-2013 Autronica Fire and Security AS +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the Free +* Software Foundation; either version 2 of the License, or (at your option) +* any later version. +* +* Author(s): +* 2011-2013 Arvid Brodin, [email protected] +*/ + +#ifndef __HSR_NETLINK_H +#define __HSR_NETLINK_H + +#include <linux/if_ether.h> +#include <linux/module.h> +#include <uapi/linux/hsr_netlink.h> + +struct hsr_priv ; + +int __init hsr_netlink_init (void ); +void __exit hsr_netlink_exit(void); + +void hsr_nl_ringerror (struct hsr_priv *hsr_priv,unsigned char addr[ETH_ALEN ], +int dev_idx); +void hsr_nl_nodedown (struct hsr_priv *hsr_priv,unsigned char addr[ETH_ALEN ]); +void hsr_nl_framedrop (int dropcount,int dev_idx); +void hsr_nl_linkdown (int dev_idx); + +#endif /* __HSR_NETLINK_H */
Signature · 6 lines
1.8.1.5 -- Arvid Brodin | Consultant (Linux) XDIN AB | Knarrarnäsgatan 7 | SE-164 40 Kista | Sweden | xdin.com
David Miller
maintainerFrom: Arvid Brodin <[email protected]>
Date: Wed, 26 Jun 2013 17:16:11 +0200
net/hsr/hsr_device.c line 136
Quoted 13 lines
net/hsr/hsr_device.c new file +13
-0+static int hsr_dev_open (struct net_device *dev) +{ +struct hsr_priv *hsr_priv; + + hsr_priv =netdev_priv (dev); + +if (hsr_priv->slave[0 ]) +dev_open (hsr_priv->slave[0 ]); +if (hsr_priv->slave[1 ]) +dev_open (hsr_priv->slave[1 ]); + +return 0 ; +}
dev_open() can and does fail, you must thus check for error returns, undo any necessary state, and propagate that error to callers of hsr_dev_open.
Quoted 20 lines · David Miller
From: Arvid Brodin <[email protected]>
Date: Wed, 26 Jun 2013 17:16:11 +0200net/hsr/hsr_device.c line 136
Quoted 13 lines
net/hsr/hsr_device.c new file +13
-0+static int hsr_dev_open (struct net_device *dev) +{ +struct hsr_priv *hsr_priv; + + hsr_priv =netdev_priv (dev); + +if (hsr_priv->slave[0 ]) +dev_open (hsr_priv->slave[0 ]); +if (hsr_priv->slave[1 ]) +dev_open (hsr_priv->slave[1 ]); + +return 0 ; +}
dev_open()can and does fail, you must thus check for error returns, undo any necessary state, and propagate that error to callers ofhsr_dev_open.
I'm not sure it's an error (from the HSR interface's point of view) if the slave(s) won't come up here. The calls to dev_open() can be seen more like a convenience than a necessity (I actually left them out to begin with). If none of the slaves could go up the HSR interface would end up as admin UP but with operstate IF_OPER_LOWERLAYERDOWN until any of the slaves went up.
I see that the VLAN code, in its vlan_dev_open(), checks the underlying interface's IFF_UP flag and returns -ENETDOWN if it's not set. That might be an option here - but then one would have to set three interfaces up to get a working HSR interface, which is a bit tedious... Also, the HSR interface could end up in the state above anyway if both slaves went down after the HSR interface went up successfully.
What about checking the return values and printing a warning if a slave dev_open() fails, but still return success for the HSR interface no matter what?
Signature · 2 lines
Arvid Brodin | Consultant (Linux) XDIN AB | Knarrarnäsgatan 7 | SE-164 40 Kista | Sweden | xdin.com
Quoted 28 lines · Arvid Brodin
Quoted 20 lines · David Miller
From: Arvid Brodin <[email protected]>
Date: Wed, 26 Jun 2013 17:16:11 +0200net/hsr/hsr_device.c line 136
Quoted 13 lines
net/hsr/hsr_device.c new file +13
-0+static int hsr_dev_open (struct net_device *dev) +{ +struct hsr_priv *hsr_priv; + + hsr_priv =netdev_priv (dev); + +if (hsr_priv->slave[0 ]) +dev_open (hsr_priv->slave[0 ]); +if (hsr_priv->slave[1 ]) +dev_open (hsr_priv->slave[1 ]); + +return 0 ; +}
dev_open()can and does fail, you must thus check for error returns, undo any necessary state, and propagate that error to callers ofhsr_dev_open.I'm not sure it's an error (from the HSR interface's point of view) if the slave(s) won't come up here. The calls to
dev_open()can be seen more like a convenience than a necessity (I actually left them out to begin with). If none of the slaves could go up the HSR interface would end up as admin UP but with operstateIF_OPER_LOWERLAYERDOWNuntil any of the slaves went up.
Quoted 9 lines
I see that the VLAN code, in its
vlan_dev_open(), checks the underlying interface'sIFF_UPflag and returns-ENETDOWNif it's not set. That might be an option here - but then one would have to set three interfaces up to get a working HSR interface, which is a bit tedious... Also, the HSR interface could end up in the state above anyway if both slaves went down after the HSR interface went up successfully.What about checking the return values and printing a warning if a slave
dev_open()fails, but still return success for the HSR interface no matter what?
Is there anything else I can do to get this patch accepted? Anything that's missing or done incorrectly that I need to fix?
Signature · 3 lines
Arvid Brodin | Consultant (Linux) T: +46-8-56254286 | M: +46-70-9714286 | [email protected] XDIN AB | Knarrarnäsgatan 7 | SE-164 40 Kista | Sweden | xdin.com
Quoted 22 lines · Arvid Brodin
Quoted 20 lines · David Miller
From: Arvid Brodin <[email protected]>
Date: Wed, 26 Jun 2013 17:16:11 +0200net/hsr/hsr_device.c line 136
Quoted 13 lines
net/hsr/hsr_device.c new file +13
-0+static int hsr_dev_open (struct net_device *dev) +{ +struct hsr_priv *hsr_priv; + + hsr_priv =netdev_priv (dev); + +if (hsr_priv->slave[0 ]) +dev_open (hsr_priv->slave[0 ]); +if (hsr_priv->slave[1 ]) +dev_open (hsr_priv->slave[1 ]); + +return 0 ; +}
dev_open()can and does fail, you must thus check for error returns, undo any necessary state, and propagate that error to callers ofhsr_dev_open.
Quoted 5 lines
I'm not sure it's an error (from the HSR interface's point of view) if the slave(s) won't come up here. The calls to
dev_open()can be seen more like a convenience than a necessity (I actually left them out to begin with). If none of the slaves could go up the HSR interface would end up as admin UP but with operstateIF_OPER_LOWERLAYERDOWNuntil any of the slaves went up.
[snip]
Stephen Hemminger explained to me (in private email) that many of the errors from dev_open() aren't soft errors - i.e. they should be propagated back up even if the HSR driver doesn't care (out of memory, and hardware dead being examples).
But HSR is often used in safety critical systems, and it may be important that a hsr_dev->dev_open() does not fail just because one of the slave's cable happens to be unplugged (or cut) - redundancy being the whole point of HSR.
I think the only reasonable thing to do is not to call dev_open() at all here, and instead just inform the user if a slave is not already up. This way user space must explicitly set both slaves UP and thus must also decide how to treat different kinds of "slave errors".
I will send a new patch with this change.
Thanks to Stephen for helping me with this!
Signature · 2 lines
Arvid Brodin | Consultant (Linux) XDIN AB | Knarrarnäsgatan 7 | SE-164 40 Kista | Sweden | xdin.com