Skip to contentSkip to conversation

net/hsr: Add support for the High-availability Seamless Redundancy protocol (HSRv0)

PATCH Superseded Arvid Brodin 3 participants 6 messages Oct 23, 2013 – Oct 29, 2013

Subsystems (3)

v5 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

PATCH v5 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-10-23).

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 v5:

* Tried to address the issues with aligning the skb header that was brought up by David Miller in v4. Fixed comment where true/false was called 1/0.

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               | 469 +++++++++++++++++++++++++++++++
 net/hsr/hsr_main.h               | 166 +++++++++++
 net/hsr/hsr_netlink.c            | 457 ++++++++++++++++++++++++++++++
 net/hsr/hsr_netlink.h            |  30 ++
 15 files changed, 2399 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
new file mode 100644
index 0000000..2475cb8
@@ -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
index ade07f1..2ce0f6a 100644
@@ -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
index 8a1e346..b78566f 100644
@@ -481,4 +481,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
index b50dacc..0715db6 100644
@@ -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
index 9492e8c..8fa2f91 100644
@@ -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
new file mode 100644
index 0000000..0d3d709
@@ -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
new file mode 100644
index 0000000..b68359f
@@ -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
new file mode 100644
index 0000000..2c7148e
@@ -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 +469 -0

469 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
new file mode 100644
index 0000000..d4579dc
@@ -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 · 7 lines
1.8.1.5



-- 
Arvid Brodin | Consultant (Linux)
XDIN AB | Knarrarnäsgatan 7 | SE-164 40 Kista | Sweden | xdin.com
#1 lore raw
Quoted 5 lines · Arvid Brodin

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.

trivia: (can be ignored/fixed later)

net/hsr/hsr_device.c line 397

Quoted 12 lines
net/hsr/hsr_device.c new file +12 -0
+static void restore_slaves(struct net_device *hsr_dev)
+{
+	struct hsr_priv *hsr_priv;
+	int i;
+	int res;
+
+	hsr_priv = netdev_priv(hsr_dev);
+
+	rtnl_lock();
+
+	/* Restore promiscuity */
+	for (i = 0; i < 2; i++) {

I presume all of these for slave loops that use for (i = 0; i < 2; i++) should be i < HSR_MAX_SLAVE

Maybe it'd be useful to add a foreach_slave() helper.

net/hsr/hsr_framereg.c line 51

Quoted 7 lines
net/hsr/hsr_framereg.c new file +7 -0
+static struct node_entry *find_node_by_AddrA(struct list_head *node_db,
+					     const unsigned char addr[ETH_ALEN])
+{
+	struct node_entry *node;
+
+	list_for_each_entry_rcu(node, node_db, mac_list) {
+		if (!compare_ether_addr(node->MacAddressA, addr))

Please use ether_addr_equal instead for all these uses. compare_ether_addr should be removed one day.

net/hsr/hsr_framereg.c line 62

Quoted 2 lines
net/hsr/hsr_framereg.c new file +2 -0
+static struct node_entry *find_node_by_AddrB(struct list_head *node_db,
+					     const unsigned char addr[ETH_ALEN])

[]

net/hsr/hsr_framereg.c line 67

Quoted 1 line
net/hsr/hsr_framereg.c new file +1 -0
+		if (!compare_ether_addr(node->MacAddressB, addr))

[]

Quoted 1 line

+struct node_entry *hsr_find_node(struct list_head *node_db, struct sk_buff *skb)

[]

Review

Quoted 9 lines
(quoted diff) +8 -0
+		if (!compare_ether_addr(node->MacAddressA, ethhdr->h_source))
+			return node;
+		if (!compare_ether_addr(node->MacAddressB, ethhdr->h_source))
+			return node;
 
+struct node_entry *hsr_merge_node(struct hsr_priv *hsr_priv,
+				  struct node_entry *node,
+				  struct sk_buff *skb,
+				  enum hsr_dev_idx dev_idx)

[]

net/hsr/hsr_framereg.c line 175

Quoted 1 line
net/hsr/hsr_framereg.c new file +1 -0
+	if (node && compare_ether_addr(node->MacAddressA, hsr_sp->MacAddressA)) {

[]

net/hsr/hsr_framereg.c line 183

Quoted 2 lines
net/hsr/hsr_framereg.c new file +2 -0
+	if (node && (dev_idx == node->AddrB_if) &&
+	    compare_ether_addr(node->MacAddressB, hsr_ethsup->ethhdr.h_source)) {

[]

net/hsr/hsr_framereg.c line 192

Quoted 3 lines
net/hsr/hsr_framereg.c new file +3 -0
+	if (node && (dev_idx != node->AddrB_if) &&
+	    (node->AddrB_if != HSR_DEV_NONE) &&
+	    compare_ether_addr(node->MacAddressA, hsr_ethsup->ethhdr.h_source)) {

[]

net/hsr/hsr_framereg.c line 218

Quoted 1 line
net/hsr/hsr_framereg.c new file +1 -0
+	if (compare_ether_addr(hsr_sp->MacAddressA, hsr_ethsup->ethhdr.h_source))

[]

net/hsr/hsr_framereg.c line 297

Quoted 13 lines
net/hsr/hsr_framereg.c new file +13 -0
+/* above(a, b) - return 1 if a > b, 0 otherwise.
+ */
+static bool above(u16 a, u16 b)
+{
+	/* Remove inconsistency where above(a, b) == below(a, b) */
+	if ((int) b - a == 32768)
+		return 0;
+
+	return (((s16) (b - a)) < 0);
+}
+#define below(a, b)		above((b), (a))
+#define above_or_eq(a, b)	(!below((a), (b)))
+#define below_or_eq(a, b)	(!above((a), (b)))

This looks odd. Perhaps

static bool above(u16 a, u16 b)

{
	return a > b;
}

#define below(a, b) above(b, a)

static bool above_or_eq(u16 a, u16 b)

{
	return a >= b;
}

#define below_or_eq(a, b) above_or_eq(b, a)

#2 lore raw
Quoted 9 lines · Joe Perches
Quoted 5 lines · Arvid Brodin

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.

trivia: (can be ignored/fixed later)

Quoted 15 lines

net/hsr/hsr_device.c line 397

Quoted 12 lines
net/hsr/hsr_device.c new file +12 -0
+static void restore_slaves(struct net_device *hsr_dev)
+{
+	struct hsr_priv *hsr_priv;
+	int i;
+	int res;
+
+	hsr_priv = netdev_priv(hsr_dev);
+
+	rtnl_lock();
+
+	/* Restore promiscuity */
+	for (i = 0; i < 2; i++) {

I presume all of these for slave loops that use for (i = 0; i < 2; i++) should be i < HSR_MAX_SLAVE

Yes, that's not nice at all. Will fix.

Quoted 1 line

Maybe it'd be useful to add a foreach_slave() helper.

I experimented a bit with this, but since the slaves are held in an array and can be NULL, and since we aren't allowed to do for loop initial declarations, it became a bit cumbersome. So I'll stick with the "manual" for loops.

Quoted 10 lines

net/hsr/hsr_framereg.c line 51

Quoted 7 lines
net/hsr/hsr_framereg.c new file +7 -0
+static struct node_entry *find_node_by_AddrA(struct list_head *node_db,
+					     const unsigned char addr[ETH_ALEN])
+{
+	struct node_entry *node;
+
+	list_for_each_entry_rcu(node, node_db, mac_list) {
+		if (!compare_ether_addr(node->MacAddressA, addr))

Please use ether_addr_equal instead for all these uses. compare_ether_addr should be removed one day.

Ok! Much nicer with ether_addr_equal().

Quoted 30 lines

net/hsr/hsr_framereg.c line 62

Quoted 2 lines
net/hsr/hsr_framereg.c new file +2 -0
+static struct node_entry *find_node_by_AddrB(struct list_head *node_db,
+					     const unsigned char addr[ETH_ALEN])

[]

net/hsr/hsr_framereg.c line 67

Quoted 1 line
net/hsr/hsr_framereg.c new file +1 -0
+		if (!compare_ether_addr(node->MacAddressB, addr))

[]

Quoted 1 line

+struct node_entry *hsr_find_node(struct list_head *node_db, struct sk_buff *skb)

[]

Review

Quoted 9 lines
(quoted diff) +8 -0
+		if (!compare_ether_addr(node->MacAddressA, ethhdr->h_source))
+			return node;
+		if (!compare_ether_addr(node->MacAddressB, ethhdr->h_source))
+			return node;
 
+struct node_entry *hsr_merge_node(struct hsr_priv *hsr_priv,
+				  struct node_entry *node,
+				  struct sk_buff *skb,
+				  enum hsr_dev_idx dev_idx)

[]

net/hsr/hsr_framereg.c line 175

Quoted 1 line
net/hsr/hsr_framereg.c new file +1 -0
+	if (node && compare_ether_addr(node->MacAddressA, hsr_sp->MacAddressA)) {

[]

net/hsr/hsr_framereg.c line 183

Quoted 2 lines
net/hsr/hsr_framereg.c new file +2 -0
+	if (node && (dev_idx == node->AddrB_if) &&
+	    compare_ether_addr(node->MacAddressB, hsr_ethsup->ethhdr.h_source)) {

[]

net/hsr/hsr_framereg.c line 192

Quoted 3 lines
net/hsr/hsr_framereg.c new file +3 -0
+	if (node && (dev_idx != node->AddrB_if) &&
+	    (node->AddrB_if != HSR_DEV_NONE) &&
+	    compare_ether_addr(node->MacAddressA, hsr_ethsup->ethhdr.h_source)) {

[]

net/hsr/hsr_framereg.c line 218

Quoted 1 line
net/hsr/hsr_framereg.c new file +1 -0
+	if (compare_ether_addr(hsr_sp->MacAddressA, hsr_ethsup->ethhdr.h_source))

[]

Quoted 15 lines

net/hsr/hsr_framereg.c line 297

Quoted 13 lines
net/hsr/hsr_framereg.c new file +13 -0
+/* above(a, b) - return 1 if a > b, 0 otherwise.
+ */
+static bool above(u16 a, u16 b)
+{
+	/* Remove inconsistency where above(a, b) == below(a, b) */
+	if ((int) b - a == 32768)
+		return 0;
+
+	return (((s16) (b - a)) < 0);
+}
+#define below(a, b)		above((b), (a))
+#define above_or_eq(a, b)	(!below((a), (b)))
+#define below_or_eq(a, b)	(!above((a), (b)))

This looks odd.

It relies on unsigned arithmetic to compare two values that may wrap. I.e., it doesn't care about the absolute sizes, but only about the distance between the numbers.

It is inspired in part by the code in jiffies.h, but adapted to 16-bit types. The code you suggested (below) will not work in this case.

See e.g. http://en.wikipedia.org/wiki/Serial_number_arithmetic

Quoted 15 lines

static bool above(u16 a, u16 b)

{
	return a > b;
}

#define below(a, b) above(b, a)

static bool above_or_eq(u16 a, u16 b)

{
	return a >= b;
}

#define below_or_eq(a, b) above_or_eq(b, a)

Signature · 2 lines
Arvid Brodin | Consultant (Linux)
XDIN AB | Knarrarnäsgatan 7 | SE-164 40 Kista | Sweden | xdin.com
#3 lore raw
Quoted 2 lines · Arvid Brodin
Quoted 1 line · Joe Perches

On Wed, 2013-10-23 at 18:09 +0200, Arvid Brodin wrote:

[]

Quoted 16 lines
Quoted 7 lines
Quoted 7 lines
net/hsr/hsr_framereg.c new file +7 -0
+/* above(a, b) - return 1 if a > b, 0 otherwise.
+ */
+static bool above(u16 a, u16 b)
+{
+	/* Remove inconsistency where above(a, b) == below(a, b) */
+	if ((int) b - a == 32768)
+		return 0;
Quoted 8 lines

net/hsr/hsr_framereg.c line 297

Quoted 6 lines
net/hsr/hsr_framereg.c new file +6 -0
+
+	return (((s16) (b - a)) < 0);
+}
+#define below(a, b)		above((b), (a))
+#define above_or_eq(a, b)	(!below((a), (b)))
+#define below_or_eq(a, b)	(!above((a), (b)))

This looks odd.

Quoted 8 lines

It relies on unsigned arithmetic to compare two values that may wrap. I.e., it doesn't care about the absolute sizes, but only about the distance between the numbers.

It is inspired in part by the code in jiffies.h, but adapted to 16-bit types. The code you suggested (below) will not work in this case.

See e.g. http://en.wikipedia.org/wiki/Serial_number_arithmetic

No worries, I was just reading the comment as the
comment doesn't match the code.

Perhaps the comment should be updated to reflect the wrapping test.

#4 lore raw
Quoted 26 lines

Subject: Re: [PATCH v5] net/hsr: Add support for the High-availability Seamless Redundancy protocol (HSRv0)

Quoted 2 lines · Arvid Brodin
Quoted 1 line · Joe Perches

On Wed, 2013-10-23 at 18:09 +0200, Arvid Brodin wrote:

[]

Quoted 19 lines
Quoted 7 lines
Quoted 7 lines
net/hsr/hsr_framereg.c new file +7 -0
+/* above(a, b) - return 1 if a > b, 0 otherwise.
+ */
+static bool above(u16 a, u16 b)
+{
+	/* Remove inconsistency where above(a, b) == below(a, b) */
+	if ((int) b - a == 32768)
+		return 0;
Quoted 8 lines

net/hsr/hsr_framereg.c line 297

Quoted 6 lines
net/hsr/hsr_framereg.c new file +6 -0
+
+	return (((s16) (b - a)) < 0);
+}
+#define below(a, b)		above((b), (a))
+#define above_or_eq(a, b)	(!below((a), (b)))
+#define below_or_eq(a, b)	(!above((a), (b)))

This looks odd.

It relies on unsigned arithmetic to compare two values that may wrap. I.e., it doesn't care about the absolute sizes, but only about the distance between the numbers.

I'd have thought it wasn't really worth worrying about what happens when a ^ b == 0x8000. Anything using modulo 16 distances shouldn't really see such values.
Perhaps just document the effect.

Also, if these definitions are in a .h file they need better names

David

#5 lore raw
Quoted 23 lines · David Laight
Quoted 23 lines

Subject: Re: [PATCH v5] net/hsr: Add support for the High-availability Seamless Redundancy protocol (HSRv0)

Quoted 2 lines · Arvid Brodin
Quoted 1 line · Joe Perches

On Wed, 2013-10-23 at 18:09 +0200, Arvid Brodin wrote:

[]

Quoted 16 lines
Quoted 15 lines

net/hsr/hsr_framereg.c line 297

Quoted 13 lines
net/hsr/hsr_framereg.c new file +13 -0
+/* above(a, b) - return 1 if a > b, 0 otherwise.
+ */
+static bool above(u16 a, u16 b)
+{
+	/* Remove inconsistency where above(a, b) == below(a, b) */
+	if ((int) b - a == 32768)
+		return 0;
+
+	return (((s16) (b - a)) < 0);
+}
+#define below(a, b)		above((b), (a))
+#define above_or_eq(a, b)	(!below((a), (b)))
+#define below_or_eq(a, b)	(!above((a), (b)))

This looks odd.

Quoted 8 lines
Quoted 3 lines
Quoted 3 lines

It relies on unsigned arithmetic to compare two values that may wrap. I.e., it doesn't care about the absolute sizes, but only about the distance between the numbers.

I'd have thought it wasn't really worth worrying about what happens when a ^ b == 0x8000. Anything using modulo 16 distances shouldn't really see such values.
Perhaps just document the effect.

Unfortunately there are circumstances where such values can be seen - specifically when there is a network problem. And since HSR is meant to be a high-availability protocol, it is imperative that such cases are handled consistently. (That would have been the case with modulo 32 as well, even if the occations when it happened would be a lot rarer, and the resulting bugs would be much harder to find.)

Quoted 2 lines

Also, if these definitions are in a .h file they need better names

They're in a .c file, but between your's and Joe Perches' comments, I can see that the names and description needs a face-lift.

Thanks for looking at the code!

Quoted 3 lines

David

Signature · 2 lines
Arvid Brodin | Consultant (Linux)
XDIN AB | Knarrarnäsgatan 7 | SE-164 40 Kista | Sweden | xdin.com