Skip to contentSkip to conversation

net/hsr: Add support for IEC 62439-3 High-availability Seamless Redundancy

RFC In review Arvid Brodin 5 participants 20 messages Mar 27, 2012 – May 24, 2012

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

RFC 1/1 net/hsr: Add support for IEC 62439-3 High-availability Seamless Redundancy

Hi!

This is a patch-in-progress for adding support for instant-failover redundant Ethernet networks using less and easier cabling than what's required by e.g. bonding/pairing. General info about HSR can be found at

http://en.wikipedia.org/wiki/High-availability_Seamless_Redundancy

but basically, HSR is a network topology where all nodes are equipped with (at least) two physical Ethernet interfaces, and are daisy- chained together to form a ring. Each node forwards all frames that are not exclusively destined to itself, except for frames that have been forwarded before. Each frame is sent in both directions on the ring by the source node.

I have two wishes with this RFC:

1) General code review. I haven't worked with neither kernel network code nor used rcu locking before, so I feel I need a sanity check of the code. Am I doing things in a sane way?

There are some debug printouts and "//" comments in this code. These will be removed in the final patch, please ignore them.

Missing in this patch are mechanisms for detecting and reporting network problems to user space (via Netlink), which I'm working on now.

2) I have a locking problem that I haven't managed to figure out. This happens the first time I send any packet (hsr_dev_xmit() in hsr_device.c:121, called from hsr_device.c:147). It happens even if I set skb2 to NULL (i.e. only send one copy):

=============================================
[ INFO: possible recursive locking detected ]
2.6.37 #118
---------------------------------------------
swapper/0 is trying to acquire lock:
(_xmit_ETHER#2){+.-...}, at: [<901bf38e>] sch_direct_xmit+0x24/0x152

but task is already holding lock:
(_xmit_ETHER#2){+.-...}, at: [<901b4d1a>] dev_queue_xmit+0x31e/0x3cc

other info that might help us debug this:
4 locks held by swapper/0:

 #0:  (&n->timer){+.-...}, at: [<9002bc20>] run_timer_softirq+0x98/0x184
 #1:  (rcu_read_lock_bh){.+....}, at: [<901b49fc>] dev_queue_xmit+0x0/0x3cc
 #2:  (_xmit_ETHER#2){+.-...}, at: [<901b4d1a>] dev_queue_xmit+0x31e/0x3cc
 #3:  (rcu_read_lock_bh){.+....}, at: [<901b49fc>] dev_queue_xmit+0x0/0x3cc
stack backtrace:
Call trace:
 [<9001c640>] dump_stack+0x18/0x20
 [<90040eac>] validate_chain+0x40c/0x9ac
 [<90041a58>] __lock_acquire+0x60c/0x670
 [<90042f32>] lock_acquire+0x3a/0x48
 [<902201a4>] _raw_spin_lock+0x20/0x44
 [<901bf38e>] sch_direct_xmit+0x24/0x152
 [<901b4c14>] dev_queue_xmit+0x218/0x3cc
 [<9021c2e0>] slave_xmit+0x10/0x14
 [<9021c540>] hsr_dev_xmit+0x88/0x8c
 [<901b4942>] dev_hard_start_xmit+0x3c6/0x480
 [<901b4d34>] dev_queue_xmit+0x338/0x3cc
 [<901e3cd8>] arp_xmit+0x8/0xc
 [<901e4436>] arp_send+0x2a/0x2c
 [<901e4e74>] arp_solicit+0x15c/0x170
 [<901bad0c>] neigh_timer_handler+0x1c0/0x204
 [<9002bc8a>] run_timer_softirq+0x102/0x184
 [<900287d8>] __do_softirq+0x64/0xe0
 [<9002896a>] do_softirq+0x26/0x48
 [<90028a66>] irq_exit+0x2e/0x64
 [<90019f16>] do_IRQ+0x46/0x5c
 [<90018428>] irq_level0+0x18/0x60
 [<9021cc16>] rest_init+0x72/0x98
 [<9000063c>] start_kernel+0x21c/0x258
 [<00000000>] 0x0

Any idea why this happens? I need help!

And here's the actual patch (against linux-next-20120306):

---
 include/linux/if_ether.h |    1 +
 include/linux/if_link.h  |   11 +
 net/Kconfig              |    1 +
 net/Makefile             |    1 +
 net/hsr/Kconfig          |   84 ++++++++
 net/hsr/Makefile         |    7 +
 net/hsr/hsr_device.c     |  518 ++++++++++++++++++++++++++++++++++++++++++++++
 net/hsr/hsr_device.h     |   22 ++
 net/hsr/hsr_framereg.c   |  157 ++++++++++++++
 net/hsr/hsr_framereg.h   |   23 ++
 net/hsr/hsr_main.c       |  383 ++++++++++++++++++++++++++++++++++
 net/hsr/hsr_netlink.c    |   78 +++++++
 net/hsr/hsr_netlink.h    |   21 ++
 net/hsr/hsr_private.h    |  114 ++++++++++
 14 files changed, 1418 insertions(+), 0 deletions(-)
include/linux/if_ether.h +1 -0
index 56d907a..0d0e2f9 100644
@@ -83,6 +83,7 @@
 #define ETH_P_TIPC	0x88CA		/* TIPC 			*/
 #define ETH_P_8021AH	0x88E7          /* 802.1ah Backbone Service Tag */
 #define ETH_P_1588	0x88F7		/* IEEE 1588 Timesync */
+#define ETH_P_HSR	0x88FB		/* IEC 62439-3 HSR/PRP		*/
 #define ETH_P_FCOE	0x8906		/* Fibre Channel over Ethernet  */
 #define ETH_P_TDLS	0x890D          /* TDLS */
 #define ETH_P_FIP	0x8914		/* FCoE Initialization Protocol */
include/linux/if_link.h +11 -0
index 4b24ff4..3e3efb4 100644
@@ -391,4 +391,15 @@ struct ifla_port_vsi {
 	__u8 pad[3];
 };
 
+/* HSR section */
+
+enum {
+	IFLA_HSR_UNSPEC,
+	IFLA_HSR_SLAVE1,
+	IFLA_HSR_SLAVE2,
+	__IFLA_HSR_MAX,
+};
+
+#define IFLA_HSR_MAX (__IFLA_HSR_MAX - 1)
+
 #endif /* _LINUX_IF_LINK_H */
net/Kconfig +1 -0
index e07272d..99d666d 100644
@@ -216,6 +216,7 @@ source "net/dcb/Kconfig"
 source "net/dns_resolver/Kconfig"
 source "net/batman-adv/Kconfig"
 source "net/openvswitch/Kconfig"
+source "net/hsr/Kconfig"
 
 config RPS
 	boolean
net/Makefile +1 -0
index ad432fa..7d8787f 100644
@@ -70,3 +70,4 @@ obj-$(CONFIG_CEPH_LIB)		+= ceph/
 obj-$(CONFIG_BATMAN_ADV)	+= batman-adv/
 obj-$(CONFIG_NFC)		+= nfc/
 obj-$(CONFIG_OPENVSWITCH)	+= openvswitch/
+obj-$(CONFIG_HSR)		+= hsr/
net/hsr/Kconfig new file +84 -0

84 lines not on this page · raw message

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 +518 -0

518 lines not on this page · raw message

net/hsr/hsr_device.h new file +22 -0
new file mode 100644
index 0000000..a1adab4
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2011-2012 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-2012 Arvid Brodin, [email protected]
+ */
+
+#ifndef __HSR_DEVICE_H
+#define __HSR_DEVICE_H
+
+#include <linux/netdevice.h>
+
+void hsr_dev_setup(struct net_device *dev);
+int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *dev1,
+						struct net_device *dev2);
+
+#endif /* __HSR_DEVICE_H */
net/hsr/hsr_framereg.c new file +157 -0

157 lines not on this page · raw message

net/hsr/hsr_framereg.h new file +23 -0
new file mode 100644
index 0000000..970181e
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2011-2012 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-2012 Arvid Brodin, [email protected]
+ */
+
+#ifndef _HSR_FRAMEREG_H
+#define _HSR_FRAMEREG_H
+
+#include "hsr_private.h"
+
+int register_frame(struct hsr_dev_data *dev_data, struct sk_buff *skb);
+void update_node_seqnr(struct list_head *frame_db, u8 ethaddr[ETH_ALEN],
+							u16 sequence_nr);
+void prune_mac_entries(struct list_head *frame_db);
+
+#endif /* _HSR_FRAMEREG_H */
net/hsr/hsr_main.c new file +383 -0

383 lines not on this page · raw message

net/hsr/hsr_netlink.c new file +78 -0

78 lines not on this page · raw message

net/hsr/hsr_netlink.h new file +21 -0
new file mode 100644
index 0000000..9d8a14d
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2011-2012 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-2012 Arvid Brodin, [email protected]
+ */
+
+#ifndef __HSR_NETLINK_H
+#define __HSR_NETLINK_H
+
+#include <linux/module.h>
+
+int __init hsr_netlink_init(void);
+void __exit hsr_netlink_exit(void);
+
+#endif /* __HSR_NETLINK_H */
net/hsr/hsr_private.h new file +114 -0

114 lines not on this page · raw message

Signature · 4 lines
Arvid Brodin
Enea Services Stockholm AB - since February 16 a part of Xdin in the Alten
Group. Soon we will be working under the common brand Xdin. Read more at
www.xdin.com.
#1 lore raw

net/hsr/Kconfig line 46

Quoted 10 lines · On Tue, 27 Mar 2012 15:20:45 +0200 Arvid Brodin <[email protected]> wrote:
net/hsr/Kconfig new file +10 -0
+config NONSTANDARD_HSR
+	bool "HSR: Use efficient tag (breaks HSR standard, read help!)"
+	depends on HSR
+	---help---
+	  The HSR standard specifies a 6-byte HSR tag to be inserted into the
+	  transmitted network frames. This breaks the 32-bit alignment that the
+	  Linux network stack relies on, and would cause kernel panics on
+	  certain architectures. To avoid this, the whole frame payload is
+	  memmoved 2 bytes on reception on these architectures - which is very
+	  inefficient!

This option won't fly. Don't do it.
If you need to copy/realign packets on some architecture the stack should be changed to handle it.

#2 lore raw
Quoted 17 lines · Stephen Hemminger

Review

Quoted 10 lines · On Tue, 27 Mar 2012 15:20:45 +0200 Arvid Brodin <[email protected]> wrote:
(quoted diff) +10 -0
+config NONSTANDARD_HSR
+	bool "HSR: Use efficient tag (breaks HSR standard, read help!)"
+	depends on HSR
+	---help---
+	  The HSR standard specifies a 6-byte HSR tag to be inserted into the
+	  transmitted network frames. This breaks the 32-bit alignment that the
+	  Linux network stack relies on, and would cause kernel panics on
+	  certain architectures. To avoid this, the whole frame payload is
+	  memmoved 2 bytes on reception on these architectures - which is very
+	  inefficient!

This option won't fly. Don't do it.
If you need to copy/realign packets on some architecture the stack should be changed to handle it.

Ok. The problems are in net/ipv4/icmp.c. The below patch seems to do the trick for me - does it look OK (and if so, should I resend it as a normal patch instead of a reply or is this enough)?

Note that I've only triggered this problem in icmp_echo(), but I noticed that icmp_timestamp() does the same thing, so I made the change there too.

[PATCH] net/ipv4/icmp: Fix kernel panic due to unaligned access with HSR on AVR32

icmp_echo() and icmp_timestamp() requires the icmphdr struct to be 32-bit aligned. This causes a kernel panic on AVR32 when HSR is used, since the HSR protocol inserts a 6-byte "HSR tag" into Ethernet frame headers, thus changing the alignment.

HSR = IEC 62439-3 High-availability Seamless Redundancy.

---
 net/ipv4/icmp.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
net/ipv4/icmp.c +4 -2
index 2cb2bf8..fdd8097 100644
@@ -818,7 +818,8 @@ static void icmp_echo(struct sk_buff *skb)
 	if (!net->ipv4.sysctl_icmp_echo_ignore_all) {
 		struct icmp_bxm icmp_param;
 
-		icmp_param.data.icmph	   = *icmp_hdr(skb);
+		memcpy(&icmp_param.data.icmph, icmp_hdr(skb),
+						sizeof(icmp_param.data.icmph));
 		icmp_param.data.icmph.type = ICMP_ECHOREPLY;
 		icmp_param.skb		   = skb;
 		icmp_param.offset	   = 0;
@@ -854,7 +855,8 @@ static void icmp_timestamp(struct sk_buff *skb)
 	icmp_param.data.times[2] = icmp_param.data.times[1];
 	if (skb_copy_bits(skb, 0, &icmp_param.data.times[0], 4))
 		BUG();
-	icmp_param.data.icmph	   = *icmp_hdr(skb);
+	memcpy(&icmp_param.data.icmph, icmp_hdr(skb),
+						sizeof(icmp_param.data.icmph));
 	icmp_param.data.icmph.type = ICMP_TIMESTAMPREPLY;
 	icmp_param.data.icmph.code = 0;
 	icmp_param.skb		   = skb;
Signature · 8 lines
1.6.3.3


-- 
Arvid Brodin
Enea Services Stockholm AB - since February 16 a part of Xdin in the Alten
Group. Soon we will be working under the common brand Xdin. Read more at
www.xdin.com.
#3 lore raw
Quoted 57 lines · On Thu, 5 Apr 2012 01:09:48 +0200 Arvid Brodin <[email protected]> wrote:
Quoted 17 lines · Stephen Hemminger

Review

Quoted 10 lines · On Tue, 27 Mar 2012 15:20:45 +0200 Arvid Brodin <[email protected]> wrote:
(quoted diff) +10 -0
+config NONSTANDARD_HSR
+	bool "HSR: Use efficient tag (breaks HSR standard, read help!)"
+	depends on HSR
+	---help---
+	  The HSR standard specifies a 6-byte HSR tag to be inserted into the
+	  transmitted network frames. This breaks the 32-bit alignment that the
+	  Linux network stack relies on, and would cause kernel panics on
+	  certain architectures. To avoid this, the whole frame payload is
+	  memmoved 2 bytes on reception on these architectures - which is very
+	  inefficient!

This option won't fly. Don't do it.
If you need to copy/realign packets on some architecture the stack should be changed to handle it.

Ok. The problems are in net/ipv4/icmp.c. The below patch seems to do the trick for me - does it look OK (and if so, should I resend it as a normal patch instead of a reply or is this enough)?

Note that I've only triggered this problem in icmp_echo(), but I noticed that icmp_timestamp() does the same thing, so I made the change there too.

[PATCH] net/ipv4/icmp: Fix kernel panic due to unaligned access with HSR on AVR32

icmp_echo() and icmp_timestamp() requires the icmphdr struct to be 32-bit aligned. This causes a kernel panic on AVR32 when HSR is used, since the HSR protocol inserts a 6-byte "HSR tag" into Ethernet frame headers, thus changing the alignment.

HSR = IEC 62439-3 High-availability Seamless Redundancy.

---
 net/ipv4/icmp.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
net/ipv4/icmp.c +2 -1
index 2cb2bf8..fdd8097 100644
@@ -818,7 +818,8 @@ static void icmp_echo(struct sk_buff *skb)
 	if (!net->ipv4.sysctl_icmp_echo_ignore_all) {
 		struct icmp_bxm icmp_param;
 
-		icmp_param.data.icmph	   = *icmp_hdr(skb);
+		memcpy(&icmp_param.data.icmph, icmp_hdr(skb),
+						sizeof(icmp_param.data.icmph));
 		icmp_param.data.icmph.type = ICMP_ECHOREPLY;
 		icmp_param.skb		   = skb;
 		icmp_param.offset	   = 0;

net/ipv4/icmp.c static void icmp_timestamp(struct sk_buff *skb) · line 862

Quoted 9 lines
net/ipv4/icmp.c +2 -1
@@ -854,7 +855,8 @@ static void icmp_timestamp(struct sk_buff *skb)
 	icmp_param.data.times[2] = icmp_param.data.times[1];
 	if (skb_copy_bits(skb, 0, &icmp_param.data.times[0], 4))
 		BUG();
-	icmp_param.data.icmph	   = *icmp_hdr(skb);
+	memcpy(&icmp_param.data.icmph, icmp_hdr(skb),
+						sizeof(icmp_param.data.icmph));
 	icmp_param.data.icmph.type = ICMP_TIMESTAMPREPLY;
 	icmp_param.data.icmph.code = 0;
 	icmp_param.skb		   = skb;

That isn't so bad, doing a memcpy versus a structure copy.

maintainer
#4 lore raw

From: Stephen Hemminger <[email protected]>
Date: Wed, 4 Apr 2012 16:55:59 -0700

Quoted 1 line

That isn't so bad, doing a memcpy versus a structure copy.

GCC is going to inline the memcpy and thus we'll still do the unaligned accesses. This change therefore won't fix the problem.

#5 lore raw
Quoted 7 lines · David Miller

From: Stephen Hemminger <[email protected]>
Date: Wed, 4 Apr 2012 16:55:59 -0700

Quoted 1 line

That isn't so bad, doing a memcpy versus a structure copy.

GCC is going to inline the memcpy and thus we'll still do the unaligned accesses. This change therefore won't fix the problem.

Well, it does work for me, with gcc-4.2.2-compiled linux-2.6.37 running on an AVR32 board.

Just out of curiosity, what's the mechanism behind this inline assignment that turns the memcpy into an unaligned access? If gcc is "smart" enough to detect a bunch of char * accesses and turn them into unaligned 32-bit accesses, isn't that a bug in gcc?

Or will this only happen on archs which __HAVE_ARCH_MEMCPY? (But looking at a couple of arch/xxx/lib/string.c, these too seem to take alignment into account.)

Signature · 4 lines
Arvid Brodin
Enea Services Stockholm AB - since February 16 a part of Xdin in the Alten
Group. Soon we will be working under the common brand Xdin. Read more at
www.xdin.com.
maintainer
#6 lore raw

From: Arvid Brodin <[email protected]>
Date: Fri, 6 Apr 2012 17:51:24 +0200

Quoted 4 lines

Just out of curiosity, what's the mechanism behind this inline assignment that turns the memcpy into an unaligned access? If gcc is "smart" enough to detect a bunch of char * accesses and turn them into unaligned 32-bit accesses, isn't that a bug in gcc?

It's not doing it with "char *", it's doing it with other types like the type of the ICMP header in this case.

memcpy is expanded by the compiler internally into __builtin_memcpy() which if it sees the length is reasonably short will inline the copy. And subsequently it uses the alignment of the types involved to determine what kinds of loads and stores it can use in that inline memcpy().

So the result is that just because in your case with your compiler it doesn't get expanded inline and fault, it doesn't mean it won't for someone else.

You're just lucky, and you really haven't fixed the bug.

#7 lore raw
Quoted 17 lines · David Miller

From: Arvid Brodin <[email protected]>
Date: Fri, 6 Apr 2012 17:51:24 +0200

Quoted 4 lines

Just out of curiosity, what's the mechanism behind this inline assignment that turns the memcpy into an unaligned access? If gcc is "smart" enough to detect a bunch of char * accesses and turn them into unaligned 32-bit accesses, isn't that a bug in gcc?

It's not doing it with "char *", it's doing it with other types like the type of the ICMP header in this case.

memcpy is expanded by the compiler internally into __builtin_memcpy() which if it sees the length is reasonably short will inline the copy. And subsequently it uses the alignment of the types involved to determine what kinds of loads and stores it can use in that inline memcpy().

Quoted 6 lines

So the result is that just because in your case with your compiler it doesn't get expanded inline and fault, it doesn't mean it won't for someone else.

You're just lucky, and you really haven't fixed the bug.

Ok. And thanks for the explanation. Would something like this do the trick then?

+ /* Need to cast to (char *) below to keep gcc optimizations
+ from causing alignment faults. */
+ memcpy(&icmp_param.data.icmph, (char *) icmp_hdr(skb),
+ sizeof(icmp_param.data.icmph));

If not, any suggestions on how to tackle this?

Signature · 4 lines
Arvid Brodin
Enea Services Stockholm AB - since February 16 a part of Xdin in the Alten
Group. Soon we will be working under the common brand Xdin. Read more at
www.xdin.com.
#8 lore raw
In reply to Arvid Brodin
Quoted 9 lines · Arvid Brodin
Quoted 7 lines · David Miller

From: Stephen Hemminger <[email protected]>
Date: Wed, 4 Apr 2012 16:55:59 -0700

Quoted 1 line

That isn't so bad, doing a memcpy versus a structure copy.

GCC is going to inline the memcpy and thus we'll still do the unaligned accesses. This change therefore won't fix the problem.

Quoted 7 lines

Well, it does work for me, with gcc-4.2.2-compiled linux-2.6.37 running on an AVR32 board.

Just out of curiosity, what's the mechanism behind this inline assignment that turns the memcpy into an unaligned access? If gcc is "smart" enough to detect a bunch of char * accesses and turn them into unaligned 32-bit accesses, isn't that a bug in gcc?

If I remember correctly, casting a char* pointer to foo* where the original pointer isn't properly aligned for type foo results in undefined behaviour. And that is what icmp_hdr() is doing, so there is no requirement that the compiler does anything reasonable with the result. Removing that cast (using skb_transport_header() instead of icmp_hdr()) should avoid that.

(We do generally assume, however, that if the processor can handle unaligned accesses in a useful way then the compiler will be reasonable and not break them.)

Ben.

Quoted 4 lines

Or will this only happen on archs which __HAVE_ARCH_MEMCPY? (But looking at a couple of arch/xxx/lib/string.c, these too seem to take alignment into account.)

Signature · 3 lines
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
#9 lore raw
Quoted 25 lines · On Fri, 6 Apr 2012 18:06:31 +0100 Ben Hutchings <[email protected]>…
Quoted 9 lines · Arvid Brodin
Quoted 7 lines · David Miller

From: Stephen Hemminger <[email protected]>
Date: Wed, 4 Apr 2012 16:55:59 -0700

Quoted 1 line

That isn't so bad, doing a memcpy versus a structure copy.

GCC is going to inline the memcpy and thus we'll still do the unaligned accesses. This change therefore won't fix the problem.

Quoted 7 lines

Well, it does work for me, with gcc-4.2.2-compiled linux-2.6.37 running on an AVR32 board.

Just out of curiosity, what's the mechanism behind this inline assignment that turns the memcpy into an unaligned access? If gcc is "smart" enough to detect a bunch of char * accesses and turn them into unaligned 32-bit accesses, isn't that a bug in gcc?

If I remember correctly, casting a char* pointer to foo* where the original pointer isn't properly aligned for type foo results in undefined behaviour. And that is what icmp_hdr() is doing, so there is no requirement that the compiler does anything reasonable with the result. Removing that cast (using skb_transport_header() instead of icmp_hdr()) should avoid that.

Quoted 11 lines

(We do generally assume, however, that if the processor can handle unaligned accesses in a useful way then the compiler will be reasonable and not break them.)

Ben.

Quoted 4 lines

Or will this only happen on archs which __HAVE_ARCH_MEMCPY? (But looking at a couple of arch/xxx/lib/string.c, these too seem to take alignment into account.)

Since icmp_hdr is 64 bits you might be able to use get_unaligned64 in some way.

#10 lore raw
Quoted 34 lines · Stephen Hemminger
Quoted 31 lines · On Fri, 6 Apr 2012 18:06:31 +0100 Ben Hutchings <[email protected]>…
Quoted 9 lines · Arvid Brodin
Quoted 7 lines · David Miller

From: Stephen Hemminger <[email protected]>
Date: Wed, 4 Apr 2012 16:55:59 -0700

Quoted 1 line

That isn't so bad, doing a memcpy versus a structure copy.

GCC is going to inline the memcpy and thus we'll still do the unaligned accesses. This change therefore won't fix the problem.

Quoted 7 lines

Well, it does work for me, with gcc-4.2.2-compiled linux-2.6.37 running on an AVR32 board.

Just out of curiosity, what's the mechanism behind this inline assignment that turns the memcpy into an unaligned access? If gcc is "smart" enough to detect a bunch of char * accesses and turn them into unaligned 32-bit accesses, isn't that a bug in gcc?

If I remember correctly, casting a char* pointer to foo* where the original pointer isn't properly aligned for type foo results in undefined behaviour. And that is what icmp_hdr() is doing, so there is no requirement that the compiler does anything reasonable with the result. Removing that cast (using skb_transport_header() instead of icmp_hdr()) should avoid that.

(We do generally assume, however, that if the processor can handle unaligned accesses in a useful way then the compiler will be reasonable and not break them.)

Ben.

Quoted 9 lines
Quoted 5 lines
Quoted 4 lines

Or will this only happen on archs which __HAVE_ARCH_MEMCPY? (But looking at a couple of arch/xxx/lib/string.c, these too seem to take alignment into account.)

Since icmp_hdr is 64 bits you might be able to use get_unaligned64 in some way.

I'm sorry, I have no idea how to do this. Besides, get_unaligned64 seems to be implemented for the "c6x" arch only?

So far we have:

1) icmp_hdr() casts an unaligned char * to a wider type, which is bad (undefined).
2) We cannot use skb_transport_header():

Quoted 7 lines · David Miller

From: Ben Hutchings <[email protected]>
Date: Thu, 5 Apr 2012 20:21:08 +0100

Quoted 2 lines

So presumably icmp_hdr() should be changed to skb_transport_header().

I would not say so. Otherwise we introduce ugly casts everywhere.

3) My feeble suggestion to cast icmp_hdr() to (char *) is of course even worse (it doesn't even avoid the erroneous cast in the first place).

So what do we do?

Signature · 3 lines
Arvid Brodin
Enea Services Stockholm AB - since February 16 a part of Xdin in the Alten Group. Soon we
will be working under the common brand name Xdin. Read more at www.xdin.com.
#11 lore raw
Quoted 6 lines

3) My feeble suggestion to cast icmp_hdr() to (char *) is of course even worse (it doesn't even avoid the erroneous cast in the first place).

So what do we do?

Reading Documentation/unalgined-memory-access.txt suggests that you probably should copy the skb before passing up the stack (if necessary). That is safe (but slightly slower).

#12 lore raw
Quoted 10 lines · Stephen Hemminger
Quoted 6 lines

3) My feeble suggestion to cast icmp_hdr() to (char *) is of course even worse (it doesn't even avoid the erroneous cast in the first place).

So what do we do?

Reading Documentation/unalgined-memory-access.txt suggests that you probably should copy the skb before passing up the stack (if necessary). That is safe (but slightly slower).

Ok, so my patch does the right thing then? I.e. if no HAVE_EFFICIENT_UNALIGNED_ACCESS and the user does not choose to pad the HSR tag (with NONSTANDARD_HSR), we memmove the payload (look in hsr_rcv()).

Or do you want me to remove the option to pad the HSR tag to get rid of the memmove if we don't HAVE_EFFICIENT_UNALIGNED_ACCESS?

Signature · 3 lines
Arvid Brodin
Enea Services Stockholm AB - since February 16 a part of Xdin in the Alten Group. Soon we
will be working under the common brand name Xdin. Read more at www.xdin.com.
maintainer
#13 lore raw
In reply to Arvid Brodin

From: Arvid Brodin <[email protected]>
Date: Thu, 5 Apr 2012 01:09:48 +0200

net/ipv4/icmp.c static void icmp_echo(struct sk_buff *skb) · line 822

Quoted 3 lines
net/ipv4/icmp.c +2 -1
-		icmp_param.data.icmph	   = *icmp_hdr(skb);
+		memcpy(&icmp_param.data.icmph, icmp_hdr(skb),
+						sizeof(icmp_param.data.icmph));

GCC can and will optimize this into an inline assignment, and thus have the same unaligned access problems, because it determines alignment based upon the types involved.

#14 lore raw
Quoted 10 lines · David Miller

From: Arvid Brodin <[email protected]>
Date: Thu, 5 Apr 2012 01:09:48 +0200

net/ipv4/icmp.c static void icmp_echo(struct sk_buff *skb) · line 822

Quoted 3 lines
net/ipv4/icmp.c +2 -1
-		icmp_param.data.icmph	   = *icmp_hdr(skb);
+		memcpy(&icmp_param.data.icmph, icmp_hdr(skb),
+						sizeof(icmp_param.data.icmph));

GCC can and will optimize this into an inline assignment, and thus have the same unaligned access problems, because it determines alignment based upon the types involved.

So presumably icmp_hdr() should be changed to skb_transport_header().

Ben.

Signature · 3 lines
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
maintainer
#15 lore raw

From: Ben Hutchings <[email protected]>
Date: Thu, 5 Apr 2012 20:21:08 +0100

Quoted 12 lines · David Miller
Quoted 10 lines

From: Arvid Brodin <[email protected]>
Date: Thu, 5 Apr 2012 01:09:48 +0200

net/ipv4/icmp.c static void icmp_echo(struct sk_buff *skb) · line 822

Quoted 3 lines
net/ipv4/icmp.c +2 -1
-		icmp_param.data.icmph	   = *icmp_hdr(skb);
+		memcpy(&icmp_param.data.icmph, icmp_hdr(skb),
+						sizeof(icmp_param.data.icmph));

GCC can and will optimize this into an inline assignment, and thus have the same unaligned access problems, because it determines alignment based upon the types involved.

Quoted 1 line

So presumably icmp_hdr() should be changed to skb_transport_header().

I would not say so. Otherwise we introduce ugly casts everywhere.

#16 lore raw
In reply to Arvid Brodin
Quoted 1 line · Arvid Brodin

Hi!

*snip*

Quoted 50 lines

2) I have a locking problem that I haven't managed to figure out. This happens the first time I send any packet (hsr_dev_xmit() in hsr_device.c:121, called from hsr_device.c:147). It happens even if I set skb2 to NULL (i.e. only send one copy):

=============================================
[ INFO: possible recursive locking detected ]
2.6.37 #118
---------------------------------------------
swapper/0 is trying to acquire lock:
(_xmit_ETHER#2){+.-...}, at: [<901bf38e>] sch_direct_xmit+0x24/0x152

but task is already holding lock:
(_xmit_ETHER#2){+.-...}, at: [<901b4d1a>] dev_queue_xmit+0x31e/0x3cc

other info that might help us debug this:
4 locks held by swapper/0:

 #0:  (&n->timer){+.-...}, at: [<9002bc20>] run_timer_softirq+0x98/0x184
 #1:  (rcu_read_lock_bh){.+....}, at: [<901b49fc>] dev_queue_xmit+0x0/0x3cc
 #2:  (_xmit_ETHER#2){+.-...}, at: [<901b4d1a>] dev_queue_xmit+0x31e/0x3cc
 #3:  (rcu_read_lock_bh){.+....}, at: [<901b49fc>] dev_queue_xmit+0x0/0x3cc
stack backtrace:
Call trace:
 [<9001c640>] dump_stack+0x18/0x20
 [<90040eac>] validate_chain+0x40c/0x9ac
 [<90041a58>] __lock_acquire+0x60c/0x670
 [<90042f32>] lock_acquire+0x3a/0x48
 [<902201a4>] _raw_spin_lock+0x20/0x44
 [<901bf38e>] sch_direct_xmit+0x24/0x152
 [<901b4c14>] dev_queue_xmit+0x218/0x3cc
 [<9021c2e0>] slave_xmit+0x10/0x14
 [<9021c540>] hsr_dev_xmit+0x88/0x8c
 [<901b4942>] dev_hard_start_xmit+0x3c6/0x480
 [<901b4d34>] dev_queue_xmit+0x338/0x3cc
 [<901e3cd8>] arp_xmit+0x8/0xc
 [<901e4436>] arp_send+0x2a/0x2c
 [<901e4e74>] arp_solicit+0x15c/0x170
 [<901bad0c>] neigh_timer_handler+0x1c0/0x204
 [<9002bc8a>] run_timer_softirq+0x102/0x184
 [<900287d8>] __do_softirq+0x64/0xe0
 [<9002896a>] do_softirq+0x26/0x48
 [<90028a66>] irq_exit+0x2e/0x64
 [<90019f16>] do_IRQ+0x46/0x5c
 [<90018428>] irq_level0+0x18/0x60
 [<9021cc16>] rest_init+0x72/0x98
 [<9000063c>] start_kernel+0x21c/0x258
 [<00000000>] 0x0
Quoted 1 line

Any idea why this happens? I need help!

I've spent a few days digging into this and the key apparently is NETIF_F_LLTX.

The problem seems to be that HARD_TX_LOCK is called more than once, first for my virtual hsr device and then, recursively, for each of the slaves in turn. (At least that's where lockdep complains - at __netif_tx_lock(), that is.)

At first I just could not understand why both the VLAN and the bonding code got away with recursive calls to dev_queue_xmit() but I didn't. After some gooling (a lot, actually) I found some references to the NETIF_F_LLTX flag (here's one:
http://lwn.net/Articles/121566/). I realised both VLAN and bonding code set this flag. And sure enough, if I set it for my hsr device lockdep does not complain any more.

But NETIF_F_LLTX is described as deprecated in both netdevice.h and in Documentation/networking/netdevices.txt. Is there an alternative solution that I should use instead?

(To recap, a hsr device is a virtual device which uses two Ethernet devices as slaves. This gives redundancy with instant failover, and since nodes are connected in a ring topology, uses less cabling than duplication.)

Signature · 2 lines
Arvid Brodin | Consultant (Linux)
XDIN AB | Jan Stenbecks Torg 17 | SE-164 40 Kista | Sweden | xdin.com
#17 lore raw
Quoted 69 lines · On Mon, 14 May 2012 18:11:44 +0000 Arvid Brodin <[email protected]> wrote:
Quoted 1 line · Arvid Brodin

Hi!

*snip*

Quoted 50 lines

2) I have a locking problem that I haven't managed to figure out. This happens the first time I send any packet (hsr_dev_xmit() in hsr_device.c:121, called from hsr_device.c:147). It happens even if I set skb2 to NULL (i.e. only send one copy):

=============================================
[ INFO: possible recursive locking detected ]
2.6.37 #118
---------------------------------------------
swapper/0 is trying to acquire lock:
(_xmit_ETHER#2){+.-...}, at: [<901bf38e>] sch_direct_xmit+0x24/0x152

but task is already holding lock:
(_xmit_ETHER#2){+.-...}, at: [<901b4d1a>] dev_queue_xmit+0x31e/0x3cc

other info that might help us debug this:
4 locks held by swapper/0:

 #0:  (&n->timer){+.-...}, at: [<9002bc20>] run_timer_softirq+0x98/0x184
 #1:  (rcu_read_lock_bh){.+....}, at: [<901b49fc>] dev_queue_xmit+0x0/0x3cc
 #2:  (_xmit_ETHER#2){+.-...}, at: [<901b4d1a>] dev_queue_xmit+0x31e/0x3cc
 #3:  (rcu_read_lock_bh){.+....}, at: [<901b49fc>] dev_queue_xmit+0x0/0x3cc
stack backtrace:
Call trace:
 [<9001c640>] dump_stack+0x18/0x20
 [<90040eac>] validate_chain+0x40c/0x9ac
 [<90041a58>] __lock_acquire+0x60c/0x670
 [<90042f32>] lock_acquire+0x3a/0x48
 [<902201a4>] _raw_spin_lock+0x20/0x44
 [<901bf38e>] sch_direct_xmit+0x24/0x152
 [<901b4c14>] dev_queue_xmit+0x218/0x3cc
 [<9021c2e0>] slave_xmit+0x10/0x14
 [<9021c540>] hsr_dev_xmit+0x88/0x8c
 [<901b4942>] dev_hard_start_xmit+0x3c6/0x480
 [<901b4d34>] dev_queue_xmit+0x338/0x3cc
 [<901e3cd8>] arp_xmit+0x8/0xc
 [<901e4436>] arp_send+0x2a/0x2c
 [<901e4e74>] arp_solicit+0x15c/0x170
 [<901bad0c>] neigh_timer_handler+0x1c0/0x204
 [<9002bc8a>] run_timer_softirq+0x102/0x184
 [<900287d8>] __do_softirq+0x64/0xe0
 [<9002896a>] do_softirq+0x26/0x48
 [<90028a66>] irq_exit+0x2e/0x64
 [<90019f16>] do_IRQ+0x46/0x5c
 [<90018428>] irq_level0+0x18/0x60
 [<9021cc16>] rest_init+0x72/0x98
 [<9000063c>] start_kernel+0x21c/0x258
 [<00000000>] 0x0
Quoted 1 line

Any idea why this happens? I need help!

I've spent a few days digging into this and the key apparently is NETIF_F_LLTX.

The problem seems to be that HARD_TX_LOCK is called more than once, first for my virtual hsr device and then, recursively, for each of the slaves in turn. (At least that's where lockdep complains - at __netif_tx_lock(), that is.)

At first I just could not understand why both the VLAN and the bonding code got away with recursive calls to dev_queue_xmit() but I didn't. After some gooling (a lot, actually) I found some references to the NETIF_F_LLTX flag (here's one:
http://lwn.net/Articles/121566/). I realised both VLAN and bonding code set this flag. And sure enough, if I set it for my hsr device lockdep does not complain any more.

Quoted 8 lines

But NETIF_F_LLTX is described as deprecated in both netdevice.h and in Documentation/networking/netdevices.txt. Is there an alternative solution that I should use instead?

(To recap, a hsr device is a virtual device which uses two Ethernet devices as slaves. This gives redundancy with instant failover, and since nodes are connected in a ring topology, uses less cabling than duplication.)

LLTX is deprecated (ie should not be used) for physical devices.

Also, for virtual devices, there should be non transmit queue, this causes mulit-queue lockless semantics to be preserved as the call passes through the virtual device.

#18 lore raw
Quoted 81 lines · Stephen Hemminger
Quoted 69 lines · On Mon, 14 May 2012 18:11:44 +0000 Arvid Brodin <[email protected]> wrote:
Quoted 1 line · Arvid Brodin

Hi!

*snip*

Quoted 50 lines

2) I have a locking problem that I haven't managed to figure out. This happens the first time I send any packet (hsr_dev_xmit() in hsr_device.c:121, called from hsr_device.c:147). It happens even if I set skb2 to NULL (i.e. only send one copy):

=============================================
[ INFO: possible recursive locking detected ]
2.6.37 #118
---------------------------------------------
swapper/0 is trying to acquire lock:
(_xmit_ETHER#2){+.-...}, at: [<901bf38e>] sch_direct_xmit+0x24/0x152

but task is already holding lock:
(_xmit_ETHER#2){+.-...}, at: [<901b4d1a>] dev_queue_xmit+0x31e/0x3cc

other info that might help us debug this:
4 locks held by swapper/0:

 #0:  (&n->timer){+.-...}, at: [<9002bc20>] run_timer_softirq+0x98/0x184
 #1:  (rcu_read_lock_bh){.+....}, at: [<901b49fc>] dev_queue_xmit+0x0/0x3cc
 #2:  (_xmit_ETHER#2){+.-...}, at: [<901b4d1a>] dev_queue_xmit+0x31e/0x3cc
 #3:  (rcu_read_lock_bh){.+....}, at: [<901b49fc>] dev_queue_xmit+0x0/0x3cc
stack backtrace:
Call trace:
 [<9001c640>] dump_stack+0x18/0x20
 [<90040eac>] validate_chain+0x40c/0x9ac
 [<90041a58>] __lock_acquire+0x60c/0x670
 [<90042f32>] lock_acquire+0x3a/0x48
 [<902201a4>] _raw_spin_lock+0x20/0x44
 [<901bf38e>] sch_direct_xmit+0x24/0x152
 [<901b4c14>] dev_queue_xmit+0x218/0x3cc
 [<9021c2e0>] slave_xmit+0x10/0x14
 [<9021c540>] hsr_dev_xmit+0x88/0x8c
 [<901b4942>] dev_hard_start_xmit+0x3c6/0x480
 [<901b4d34>] dev_queue_xmit+0x338/0x3cc
 [<901e3cd8>] arp_xmit+0x8/0xc
 [<901e4436>] arp_send+0x2a/0x2c
 [<901e4e74>] arp_solicit+0x15c/0x170
 [<901bad0c>] neigh_timer_handler+0x1c0/0x204
 [<9002bc8a>] run_timer_softirq+0x102/0x184
 [<900287d8>] __do_softirq+0x64/0xe0
 [<9002896a>] do_softirq+0x26/0x48
 [<90028a66>] irq_exit+0x2e/0x64
 [<90019f16>] do_IRQ+0x46/0x5c
 [<90018428>] irq_level0+0x18/0x60
 [<9021cc16>] rest_init+0x72/0x98
 [<9000063c>] start_kernel+0x21c/0x258
 [<00000000>] 0x0
Quoted 1 line

Any idea why this happens? I need help!

I've spent a few days digging into this and the key apparently is NETIF_F_LLTX.

The problem seems to be that HARD_TX_LOCK is called more than once, first for my virtual hsr device and then, recursively, for each of the slaves in turn. (At least that's where lockdep complains - at __netif_tx_lock(), that is.)

At first I just could not understand why both the VLAN and the bonding code got away with recursive calls to dev_queue_xmit() but I didn't. After some gooling (a lot, actually) I found some references to the NETIF_F_LLTX flag (here's one:
http://lwn.net/Articles/121566/). I realised both VLAN and bonding code set this flag. And sure enough, if I set it for my hsr device lockdep does not complain any more.

Quoted 8 lines

But NETIF_F_LLTX is described as deprecated in both netdevice.h and in Documentation/networking/netdevices.txt. Is there an alternative solution that I should use instead?

(To recap, a hsr device is a virtual device which uses two Ethernet devices as slaves. This gives redundancy with instant failover, and since nodes are connected in a ring topology, uses less cabling than duplication.)

Quoted 5 lines

LLTX is deprecated (ie should not be used) for physical devices.

Also, for virtual devices, there should be non transmit queue, this causes mulit-queue lockless semantics to be preserved as the call passes through the virtual device.

(First: apologies for my late reply; your emails doesn't get through to me for some reason.)

So does this mean that it is OK to use LLTX for virtual devices? My virtual device has zero queue length (no transmit queue), but since it calls dev_queue_xmit for its slaves, I still get recursive locking if I don't set LLTX (just like vlan and bonding does).

Signature · 2 lines
Arvid Brodin | Consultant (Linux)
XDIN AB | Jan Stenbecks Torg 17 | SE-164 40 Kista | Sweden | xdin.com
#19 lore raw
Quoted 88 lines · On Thu, 24 May 2012 17:09:53 +0000 Arvid Brodin <[email protected]> wrote:
Quoted 81 lines · Stephen Hemminger
Quoted 69 lines · On Mon, 14 May 2012 18:11:44 +0000 Arvid Brodin <[email protected]> wrote:
Quoted 1 line · Arvid Brodin

Hi!

*snip*

Quoted 50 lines

2) I have a locking problem that I haven't managed to figure out. This happens the first time I send any packet (hsr_dev_xmit() in hsr_device.c:121, called from hsr_device.c:147). It happens even if I set skb2 to NULL (i.e. only send one copy):

=============================================
[ INFO: possible recursive locking detected ]
2.6.37 #118
---------------------------------------------
swapper/0 is trying to acquire lock:
(_xmit_ETHER#2){+.-...}, at: [<901bf38e>] sch_direct_xmit+0x24/0x152

but task is already holding lock:
(_xmit_ETHER#2){+.-...}, at: [<901b4d1a>] dev_queue_xmit+0x31e/0x3cc

other info that might help us debug this:
4 locks held by swapper/0:

 #0:  (&n->timer){+.-...}, at: [<9002bc20>] run_timer_softirq+0x98/0x184
 #1:  (rcu_read_lock_bh){.+....}, at: [<901b49fc>] dev_queue_xmit+0x0/0x3cc
 #2:  (_xmit_ETHER#2){+.-...}, at: [<901b4d1a>] dev_queue_xmit+0x31e/0x3cc
 #3:  (rcu_read_lock_bh){.+....}, at: [<901b49fc>] dev_queue_xmit+0x0/0x3cc
stack backtrace:
Call trace:
 [<9001c640>] dump_stack+0x18/0x20
 [<90040eac>] validate_chain+0x40c/0x9ac
 [<90041a58>] __lock_acquire+0x60c/0x670
 [<90042f32>] lock_acquire+0x3a/0x48
 [<902201a4>] _raw_spin_lock+0x20/0x44
 [<901bf38e>] sch_direct_xmit+0x24/0x152
 [<901b4c14>] dev_queue_xmit+0x218/0x3cc
 [<9021c2e0>] slave_xmit+0x10/0x14
 [<9021c540>] hsr_dev_xmit+0x88/0x8c
 [<901b4942>] dev_hard_start_xmit+0x3c6/0x480
 [<901b4d34>] dev_queue_xmit+0x338/0x3cc
 [<901e3cd8>] arp_xmit+0x8/0xc
 [<901e4436>] arp_send+0x2a/0x2c
 [<901e4e74>] arp_solicit+0x15c/0x170
 [<901bad0c>] neigh_timer_handler+0x1c0/0x204
 [<9002bc8a>] run_timer_softirq+0x102/0x184
 [<900287d8>] __do_softirq+0x64/0xe0
 [<9002896a>] do_softirq+0x26/0x48
 [<90028a66>] irq_exit+0x2e/0x64
 [<90019f16>] do_IRQ+0x46/0x5c
 [<90018428>] irq_level0+0x18/0x60
 [<9021cc16>] rest_init+0x72/0x98
 [<9000063c>] start_kernel+0x21c/0x258
 [<00000000>] 0x0
Quoted 1 line

Any idea why this happens? I need help!

I've spent a few days digging into this and the key apparently is NETIF_F_LLTX.

The problem seems to be that HARD_TX_LOCK is called more than once, first for my virtual hsr device and then, recursively, for each of the slaves in turn. (At least that's where lockdep complains - at __netif_tx_lock(), that is.)

At first I just could not understand why both the VLAN and the bonding code got away with recursive calls to dev_queue_xmit() but I didn't. After some gooling (a lot, actually) I found some references to the NETIF_F_LLTX flag (here's one:
http://lwn.net/Articles/121566/). I realised both VLAN and bonding code set this flag. And sure enough, if I set it for my hsr device lockdep does not complain any more.

Quoted 8 lines

But NETIF_F_LLTX is described as deprecated in both netdevice.h and in Documentation/networking/netdevices.txt. Is there an alternative solution that I should use instead?

(To recap, a hsr device is a virtual device which uses two Ethernet devices as slaves. This gives redundancy with instant failover, and since nodes are connected in a ring topology, uses less cabling than duplication.)

Quoted 5 lines

LLTX is deprecated (ie should not be used) for physical devices.

Also, for virtual devices, there should be non transmit queue, this causes mulit-queue lockless semantics to be preserved as the call passes through the virtual device.

Quoted 5 lines

(First: apologies for my late reply; your emails doesn't get through to me for some reason.)

So does this mean that it is OK to use LLTX for virtual devices? My virtual device has zero queue length (no transmit queue), but since it calls dev_queue_xmit for its slaves, I still get recursive locking if I don't set LLTX (just like vlan and bonding does).

Yes LLTX is fine for virtual devices.