net/hsr: Add support for the High-availability Seamless Redundancy protocol (HSRv0)
Subsystems (3)
PATCH v4 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-09-18).
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 options --strict --max-line-length=83 except for CHECKs, which are all intentional; e.g. CamelCase is used in the IEC standard to describe field names, and these names have been used in the code.
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.
Changes in v4:
* Fixed racy test-and-modify lock for device operstate in __hsr_set_operstate().
Changes in v3:
* hsr_dev_open() no longer calls dev_open() on the HSR slave interfaces. This is to let user space decide how to treat any errors on slave open.
* is_operstate_up() is now called is_slave_up() and checks both admin state and operational state. Slaves going DOWN could otherwise be detected as still UP when HSR decided its own state.
* Files under net/ now have header comments that follow the network code standard.
Changes in v2:
* 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) David Miller asked about this on 2013-09-03; no response.
* Move more (local) header files into include/net/? (checkpatch still warns about CamelCase) (Joe Perches / with help from David Miller?)
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.
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 | 594 +++++++++++++++++++++++++++++++++++++++ net/hsr/hsr_device.h | 29 ++ net/hsr/hsr_framereg.c | 501 +++++++++++++++++++++++++++++++++ net/hsr/hsr_framereg.h | 53 ++++ net/hsr/hsr_main.c | 458 ++++++++++++++++++++++++++++++ net/hsr/hsr_main.h | 166 +++++++++++ net/hsr/hsr_netlink.c | 457 ++++++++++++++++++++++++++++++ net/hsr/hsr_netlink.h | 30 ++ 15 files changed, 2388 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
@@ -470,4 +470,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
@@ -220,6 +220,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 +594 -0
594 lines not on this page · raw message
net/hsr/hsr_device.h new file +29 -0
@@ -0,0 +1,29 @@ +/* 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 +501 -0
501 lines not on this page · raw message
net/hsr/hsr_framereg.h new file +53 -0
53 lines not on this page · raw message
net/hsr/hsr_main.c new file +458 -0
458 lines not on this page · raw message
net/hsr/hsr_main.h new file +166 -0
166 lines not on this page · raw message
net/hsr/hsr_netlink.c new file +457 -0
457 lines not on this page · raw message
net/hsr/hsr_netlink.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_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 · 5 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: Thu, 19 Sep 2013 03:11:58 +0200
net/hsr/hsr_device.c line 456
Quoted 3 lines
net/hsr/hsr_device.c new file +3
-0+/* If dev is a HSR master, return 1; otherwise, return 0. +*/ +bool is_hsr_master (struct net_device *dev)
Bool takes on either 'true' or 'false', not '1' or '0'.
net/hsr/hsr_main.c line 391
Quoted 9 lines
net/hsr/hsr_main.c new file +9
-0+#if !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ) +/* We need to memmove the whole header to work around +* alignment problems caused by the 6-byte HSR tag. +*/ +memmove (skb_deliver->data -HSR_TAGLEN , skb_deliver->data, +skb_headlen (skb_deliver)); + skb_deliver->data -=HSR_TAGLEN ; + skb_deliver->tail -=HSR_TAGLEN ; +#endif
You can't do this.
First of all, you have no idea if subtracting skb->data a given amount will underflow the skb buffer start. You aren't even checking, all of the standard skb_*() data adjustment interfaces do.
Secondly, everything after the header is now at the wrong offset from the beginning of the packet.
You will have to memmove() the entire packet if you want to realign where it starts.
Quoted 15 lines · David Miller
From: Arvid Brodin <[email protected]>
Date: Thu, 19 Sep 2013 03:11:58 +0200net/hsr/hsr_main.c line 391
Quoted 9 lines
net/hsr/hsr_main.c new file +9
-0+#if !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ) +/* We need to memmove the whole header to work around +* alignment problems caused by the 6-byte HSR tag. +*/ +memmove (skb_deliver->data -HSR_TAGLEN , skb_deliver->data, +skb_headlen (skb_deliver)); + skb_deliver->data -=HSR_TAGLEN ; + skb_deliver->tail -=HSR_TAGLEN ; +#endif You can't do this.
Quoted 3 lines
First of all, you have no idea if subtracting
skb->dataa given amount will underflow the skb buffer start. You aren't even checking, all of the standard skb_*() data adjustment interfaces do.
Isn't it reasonable to assume that skb points to an sk_buff with a valid Ethernet header, and with skb->data pointing to the end of that header, at the start of ETH_P_... protocol handlers?
Quoted 5 lines
Secondly, everything after the header is now at the wrong offset from the beginning of the packet.
You will have to
memmove()the entire packet if you want to realign where it starts.
Are you saying packet data may contain offsets from itself to the mac header? Or are you talking about fragments? This being the Ethernet protocol handler, e.g. skb->network_header and skb->transport_header should not have been set yet.
Anyway, I should do
skb_deliver->len -= HSR_TAGLEN;
here! (I'm removing 6 bytes after the mac header from the packet, not just realigning it.)
Given all this, and looking at e.g. __pskb_pull_tail(), it should be correct to memmove() only the linear part of the packet after the removed bytes - any fragments will just be appended directly after the end of the (shortened) linear part on use?
It's weird though, the "len" bug doesn't show up in my practical tests - scp of 16 MiB file (sha1sum compared afterwards) and ping with default and 65 KB packets work just fine before and after this change - even between one fixed system and one with the bug remaining. Could it be that none of the network device drivers we use (e1000e and macb) make use of nonlinear skbs?
Signature · 2 lines
Arvid Brodin | Consultant (Linux) XDIN AB | Knarrarnäsgatan 7 | SE-164 40 Kista | Sweden | xdin.com
Quoted 6 lines · Arvid Brodin
It's weird though, the "len" bug doesn't show up in my practical tests - scp of 16 MiB file (sha1sum compared afterwards) and ping with default and 65 KB packets work just fine before and after this change - even between one fixed system and one with the bug remaining. Could it be that none of the network device drivers we use (e1000e and macb) make use of nonlinear skbs?
Forget about this, e1000e is running on an architecture with HAVE_EFFICIENT_UNALIGNED_ACCESS, and on macb it does affect things - with the "fix" nothing works. :-|
Signature · 2 lines
Arvid Brodin | Consultant (Linux) XDIN AB | Knarrarnäsgatan 7 | SE-164 40 Kista | Sweden | xdin.com
Quoted 11 lines · Arvid Brodin
Quoted 6 lines · Arvid Brodin
It's weird though, the "len" bug doesn't show up in my practical tests - scp of 16 MiB file (sha1sum compared afterwards) and ping with default and 65 KB packets work just fine before and after this change - even between one fixed system and one with the bug remaining. Could it be that none of the network device drivers we use (e1000e and macb) make use of nonlinear skbs?
Forget about this, e1000e is running on an architecture with
HAVE_EFFICIENT_UNALIGNED_ACCESS, and on macb it does affect things - with the "fix" nothing works. :-|
... and that is because I have already shortened the packet through the call to strip_hsr_tag() a few lines above, which calls skb_pull(..., HSR_TAGLEN) in turn. So ->len is already correct.
Moving both ->data and ->tail, and all data between them, HSR_TAGLEN bytes lower, should not be a problem if
a) the space ahead of ->data is vacant (not part of the packet),
b) there is enough headroom,
c) it does not break 32-bit alignment, and
d) there are no references to headers etc in the data being moved.
Right?
Signature · 2 lines
Arvid Brodin | Consultant (Linux) XDIN AB | Knarrarnäsgatan 7 | SE-164 40 Kista | Sweden | xdin.com
Quoted 15 lines · David Miller
From: Arvid Brodin <[email protected]>
Date: Thu, 19 Sep 2013 03:11:58 +0200net/hsr/hsr_main.c line 391
Quoted 9 lines
net/hsr/hsr_main.c new file +9
-0+#if !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ) +/* We need to memmove the whole header to work around +* alignment problems caused by the 6-byte HSR tag. +*/ +memmove (skb_deliver->data -HSR_TAGLEN , skb_deliver->data, +skb_headlen (skb_deliver)); + skb_deliver->data -=HSR_TAGLEN ; + skb_deliver->tail -=HSR_TAGLEN ; +#endif You can't do this.
Quoted 3 lines
First of all, you have no idea if subtracting
skb->dataa given amount will underflow the skb buffer start. You aren't even checking, all of the standard skb_*() data adjustment interfaces do.
(Shorter and more to the point than my previous replies:)
I _do_ know: this can't possibly underflow since strip_hsr_tag() a few lines above pulled the same amount of data. I will rename strip_hsr_tag() to hsr_pull_tag() to make this clearer.
Quoted 2 lines
Secondly, everything after the header is now at the wrong offset from the beginning of the packet.
How does this matter? The memmove moves everything back (restores the changes made to the packet on the sending side) so that it is at the "normal" position for an ethernet packet.
Signature · 2 lines
Arvid Brodin | Consultant (Linux) XDIN AB | Knarrarnäsgatan 7 | SE-164 40 Kista | Sweden | xdin.com
Quoted 27 lines · Arvid Brodin
Quoted 15 lines · David Miller
From: Arvid Brodin <[email protected]>
Date: Thu, 19 Sep 2013 03:11:58 +0200net/hsr/hsr_main.c line 391
Quoted 9 lines
net/hsr/hsr_main.c new file +9
-0+#if !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ) +/* We need to memmove the whole header to work around +* alignment problems caused by the 6-byte HSR tag. +*/ +memmove (skb_deliver->data -HSR_TAGLEN , skb_deliver->data, +skb_headlen (skb_deliver)); + skb_deliver->data -=HSR_TAGLEN ; + skb_deliver->tail -=HSR_TAGLEN ; +#endif You can't do this.
Quoted 3 lines
First of all, you have no idea if subtracting
skb->dataa given amount will underflow the skb buffer start. You aren't even checking, all of the standard skb_*() data adjustment interfaces do.(Shorter and more to the point than my previous replies:)
I _do_ know: this can't possibly underflow since
strip_hsr_tag()a few lines above pulled the same amount of data. I will renamestrip_hsr_tag()tohsr_pull_tag()to make this clearer.
Quoted 7 lines
Quoted 2 lines
Secondly, everything after the header is now at the wrong offset from the beginning of the packet.
How does this matter? The memmove moves everything back (restores the changes made to the packet on the sending side) so that it is at the "normal" position for an ethernet packet.
Obviously, David is too busy to help me figure out what the problem is (I know he reviews several thousand patches each year, so maybe that's no wonder).
If anyone else has got an idea you are very welcome to chime in, and perhaps we can solve this. I can't fix the problem if I don't understand it.
Quoted 2 lines · David Miller
Secondly, everything after the header is now at the wrong offset from the beginning of the packet.
Maybe he's talking about systems with NET_SKBUFF_DATA_USES_OFFSET here? This means the transport, network and mac headers are all relative to skb->head, if I understand correctly. But at the point in the protocol stack where this code is (the Ethernet protocol handler), the transport and network headers have not been set yet, and the mac header is not moved by the code. And tail is updated by the code. So that should not be a problem?
Signature · 2 lines
Arvid Brodin | Consultant (Linux) XDIN AB | Knarrarnäsgatan 7 | SE-164 40 Kista | Sweden | xdin.com