net/hsr: Add support for IEC 62439-3 High-availability Seamless Redundancy
Subsystems (4)
RFC v2 1/2 net/hsr: Add support for IEC 62439-3 High-availability Seamless Redundancy
The kernel patch.
Documentation/networking/hsr/hsr_genl.c | 213 +++++++++++++ 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 | 531 +++++++++++++++++++++++++++++++ net/hsr/hsr_device.h | 27 ++ net/hsr/hsr_framereg.c | 328 +++++++++++++++++++ net/hsr/hsr_framereg.h | 54 ++++ net/hsr/hsr_main.c | 411 ++++++++++++++++++++++++ net/hsr/hsr_netlink.c | 293 +++++++++++++++++ net/hsr/hsr_netlink.h | 64 ++++ net/hsr/hsr_private.h | 114 +++++++ 15 files changed, 2140 insertions(+), 0 deletions(-) create mode 100644 Documentation/networking/hsr/hsr_genl.c 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_netlink.c create mode 100644 net/hsr/hsr_netlink.h create mode 100644 net/hsr/hsr_private.h
Documentation/networking/hsr/hsr_genl.c new file +118 -0
@@ -0,0 +1,213 @@ +/* +* 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] +* +* Userspace example of using Generic Netlink (through libnl-3) to get HSR +* ("High-availability Seamless Redundancy") link/network status. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <netlink/netlink.h> +#include <netlink/socket.h> +#include <netlink/attr.h> +#include <netlink/genl/genl.h> +#include <netlink/genl/ctrl.h> +#include "../../linux-next/net/hsr/hsr_netlink.h" + + +static struct nla_policy hsr_genl_policy[HSR_A_MAX +1 ] = { + [HSR_A_NODE_ADDR ] = { .type =NLA_UNSPEC }, + [HSR_A_IFINDEX ] = { .type =NLA_U32 }, + [HSR_A_IF1AGE ] = { .type =NLA_U32 }, + [HSR_A_IF2AGE ] = { .type =NLA_U32 }, +}; + +#define ETH_ALEN 6 + +void print_mac (const unsigned char *addr) +{ +int i; + +for (i =0 ; i <ETH_ALEN ; i++) +printf ("%02x " , addr[i]); +} + + +int parse_genlmsg (struct nl_msg *msg,void *arg) +{ +struct nlattr *attrs[HSR_A_MAX +1 ]; +int rc; +struct genlmsghdr *hdr; +int i; + + rc =genlmsg_parse (nlmsg_hdr (msg),0 , attrs,HSR_A_MAX , hsr_genl_policy); +if (rc <0 ) { +printf ("Error parsing genlmsg: %d\n" , rc); +return rc; + } + + +/* +* Extract command ID from "message" -> "netlink header" -> +* "generic netlink header". +* +* These are the command enums used when creating a genl msg header +* in the kernel with genlmsg_put(). +*/ + hdr =genlmsg_hdr (nlmsg_hdr (msg)); + +switch (hdr->cmd) { +case HSR_C_RING_ERROR : +printf ("Ring error: \n" ); +break ; +case HSR_C_NODE_DOWN : +printf ("Node down: \n" ); +break ; +case HSR_C_SET_NODE_STATUS : +printf ("Node status: \n" ); +break ; +default : +printf ("Unknown genl message (%d)\n" , hdr->cmd); + } + + +/* +* Extract the attached data (the "attributes"). +*/ +for (i =0 ; i <HSR_A_MAX +1 ; i++) +if (attrs[i]) { +switch (attrs[i]->nla_type) { +case HSR_A_NODE_ADDR : +printf (" node address " ); +print_mac (nla_data (attrs[i])); +printf ("\n" ); +break ; +case HSR_A_IFINDEX : +printf (" interface index %d\n" ,nla_get_u32 (attrs[i])); +break ; +case HSR_A_IF1AGE : +printf (" last frame over slave #1 %d ms ago\n" , (int )nla_get_u32 (attrs[i])); +break ; +case HSR_A_IF2AGE : +printf (" last frame over slave #2 %d ms ago\n" , (int )nla_get_u32 (attrs[i])); +break ; +default : +printf (" unknown attribute type: %d\n" , attrs[i]->nla_type); + } + } + +return 0 ; +} + +/* +* Send a "simple" (header only) Generic Netlink message +int query_link_status(int family) +{ +return (genl_send_simple(nlsk, family, HSR_C_GET_STATUS, 1, 0)); +} +*/ + +int query_node_status(struct nl_sock *nlsk, int family, int ifindex, const unsigned char
node_addr[ETH_ALEN])
+{
+ struct nl_msg *msg;
+ void *user_hdr;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ user_hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, family,
+ 0, 0, HSR_C_GET_NODE_STATUS, 1);
+ if (!user_hdr)
+ goto nla_put_failure;
+
+/*
+ * Query by interface name could be implemented in the kernel if needed:
+ NLA_PUT_STRING(msg, HSR_A_IFNAME, ifname);
+ */
+ NLA_PUT_U32(msg, HSR_A_IFINDEX, ifindex);
+ NLA_PUT(msg, HSR_A_NODE_ADDR, ETH_ALEN, node_addr);
+
+ printf("Querying if %d for status of node ", ifindex);
+ print_mac(node_addr);
+ printf("\n");
+
+ return (nl_send_auto(nlsk, msg));
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+int main()
+{
+ struct nl_sock *nlsk;
+ int hsr_mgroup;
+ int rc;
+
+ nlsk = nl_socket_alloc();
+ if (!nlsk) {
+ printf("nl_socket_alloc() failed\n");
+ return EXIT_FAILURE;
+ }
+ nl_socket_disable_seq_check(nlsk);
+ nl_socket_modify_cb(nlsk, NL_CB_VALID, NL_CB_CUSTOM, parse_genlmsg, NULL);
+ genl_connect(nlsk);
+
+ /*
+ * Sign up for HSR messages
+ */
+ hsr_mgroup = genl_ctrl_resolve_grp(nlsk, "HSR", "hsr-network");
+ if (hsr_mgroup < 0) {
+ printf("genl_ctrl_resolve_grp() failed: %d\n", hsr_mgroup);
+ rc = EXIT_FAILURE;
+ goto out;
+ }
+
+ printf("Registering for multicast group %d\n", hsr_mgroup);
+ rc = nl_socket_add_memberships(nlsk, hsr_mgroup, 0);
+ if (rc < 0) {
+ printf("nl_socket_add_memberships() failed: %d\n", rc);
+ goto out;
+ }
+
+ /*
+ * Send a query about the status of another node on the HSR network:
+ */
+ int hsr_family;
+ /* The hsr if we send the enquiry to (get it with e.g.
+ * 'cat /sys/class/net/hsr0/ifindex'): */
+ const int hsr_ifindex = 4;
+ /* The node to enquire about: */
+ const unsigned char node[ETH_ALEN] = {0x00, 0x24, 0x74, 0x00, 0x17, 0xAD};
+
+ hsr_family = genl_ctrl_resolve(nlsk, "HSR");
+ if (hsr_family < 0) {
+ printf("genl_ctrl_resolve() failed: %d\n", hsr_family);
+ goto receive;
+ }
+ rc = query_node_status(nlsk, hsr_family, hsr_ifindex, node);
+ printf("query_node_status() returned %d\n", rc);
+
+ /*
+ * Receive messages
+ */
+receive:
+ while (1)
+ nl_recvmsgs_default(nlsk);
+
+ rc = EXIT_SUCCESS;
+out:
+ nl_close(nlsk);
+ nl_socket_free(nlsk);
+ return rc;
+}
include/linux/if_ether.h +1 -0
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 +531 -0
531 lines not on this page · raw message
net/hsr/hsr_device.h new file +27 -0
@@ -0,0 +1,27 @@ +/* +* 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 *slave[2 ]); +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); +int is_hsr_master (struct net_device *dev); + +#endif /* __HSR_DEVICE_H */
net/hsr/hsr_framereg.c new file +328 -0
328 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 +411 -0
411 lines not on this page · raw message
net/hsr/hsr_netlink.c new file +293 -0
293 lines not on this page · raw message
net/hsr/hsr_netlink.h new file +64 -0
64 lines not on this page · raw message
net/hsr/hsr_private.h new file +114 -0
114 lines not on this page · raw message
Signature · 2 lines
Arvid Brodin | Consultant (Linux) XDIN AB | Jan Stenbecks Torg 17 | SE-164 40 Kista | Sweden | xdin.com
Quoted 1 line · Arvid Brodin
The kernel patch.
[]
net/hsr/hsr_device.c line 35
Quoted 13 lines
net/hsr/hsr_device.c +9
-0@@ -0,0 +1,531 @@ +static int is_admin_up (struct net_device *dev) +{ +return (dev->flags &IFF_UP ); +} + +static int is_operstate_up (struct net_device *dev) +{ +return (dev->operstate ==IF_OPER_UP ); +}
bool?
net/hsr/hsr_device.c line 43
Quoted 7 lines
net/hsr/hsr_device.c +7
-0+static void __hsr_set_operstate (struct net_device *dev,int transition) +{ +if (dev->operstate != transition) { +/* +switch (transition) { +case IF_OPER_UP: +printk(KERN_INFO "%s: new operstate is IF_OPER_UP\n", dev->name);
netdev_info(dev, "new operstate is IF_OPER_UP\n");
net/hsr/hsr_device.c line 46
Quoted 3 lines
net/hsr/hsr_device.c +3
-0+break ; +default : +printk (KERN_INFO "%s: new operstate is !IF_OPER_UP (%d)\n" , dev->name, transition);
etc.
net/hsr/hsr_device.c line 66
Quoted 11 lines
net/hsr/hsr_device.c +11
-0+void hsr_set_operstate (struct net_device *hsr_dev,struct net_device *slave1, +struct net_device *slave2) +{ +if (!is_admin_up (hsr_dev)) { +__hsr_set_operstate (hsr_dev,IF_OPER_DOWN ); +return ; + } +/* +printk(KERN_INFO "Slave1/2 operstate: %d/%d\n", +slave1->operstate, slave2->operstate); +*/
Please remove commented out code.
Quoted 13 lines
net/hsr/hsr_device.c +13
-0+static void restore_slaves (struct net_device *hsr_dev) +{ +struct hsr_priv *hsr_priv; +struct net_device *slave[2 ]; +int i; +int res; + + hsr_priv =netdev_priv (hsr_dev); +for (i =0 ; i <2 ; i++) + slave[i] = hsr_priv->slave_data[i].dev; + +rtnl_lock (); +
net/hsr/hsr_device.c line 355
Quoted 10 lines
net/hsr/hsr_device.c +10
-0+/* Restore promiscuity */ +for (i =0 ; i <2 ; i++) { +if (!hsr_priv->slave_data[i].promisc) +continue ; + res =dev_set_promiscuity (slave[i], + -hsr_priv->slave_data[i].promisc); +if (res) +pr_info ("HSR: Cannot restore promiscuity (%s, %d)\n" , + slave[i]->name, + res);
shouldn't this just be:
netdev_info(slave[i], "cannot restore promiscuity: %d\n", res);
If you must use pr_<level> please add
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
before any include and let the printk subsystem
add MODNAME as a prefix.
net/hsr/hsr_device.c line 429
Quoted 7 lines
net/hsr/hsr_device.c +7
-0+static int check_slave_ok (struct net_device *dev) +{ +/* Don't allow HSR on non-ethernet like devices */ +if ((dev->flags &IFF_LOOPBACK ) || (dev->type !=ARPHRD_ETHER ) || + (dev->addr_len !=ETH_ALEN )) { +pr_info ("%s: Cannot enslave loopback or non-ethernet device\n" , + dev->name);
netdev_info(dev, "Cannot enslave...");
net/hsr/hsr_device.c line 436
Quoted 7 lines
net/hsr/hsr_device.c +7
-0+return -EINVAL ; + } + +/* Don't allow enslaving hsr devices */ +if (is_hsr_master (dev)) { +pr_info ("%s: Don't try to create trees of hsr devices!\n" , + dev->name);
netdev_err(dev, "Cannot create trees of hsr devices\n");
net/hsr/hsr_device.c line 490
Quoted 6 lines
net/hsr/hsr_device.c +5
-0+int hsr_dev_finalize (struct net_device *hsr_dev,struct net_device *slave[2 ]) +{ +/* Set hsr_dev's MAC address to that of mac_slave1 */ +memcpy (hsr_dev->dev_addr, hsr_priv->slave_data[0 ].dev->dev_addr, + hsr_dev->addr_len);
ETH_ALEN?
net/hsr/hsr_device.h
Quoted 1 line
net/hsr/hsr_device.h +0
-0
[]
net/hsr/hsr_device.h line 21
Quoted 6 lines
net/hsr/hsr_device.h +4
-0@@ -0,0 +1,27 @@ +void hsr_dev_setup (struct net_device *dev); +int hsr_dev_finalize (struct net_device *hsr_dev,struct net_device *slave[2 ]); +void hsr_set_operstate (struct net_device *hsr_dev,struct net_device *slave1, +struct net_device *slave2);
please align arguments immediately after the open parenthesis.
net/hsr/hsr_framereg.c
Quoted 1 line
net/hsr/hsr_framereg.c +0
-0
[]
net/hsr/hsr_framereg.c
Quoted 2 lines
net/hsr/hsr_framereg.c +2
-0+static struct node_entry *find_node_by_AddrA (struct list_head *node_db, +unsigned char addr[ETH_ALEN ])
static struct node_entry *find_node_by_AddrA(struct list_head *node_db,
unsigned char addr[ETH_ALEN])
[]
net/hsr/hsr_framereg.c line 66
Quoted 2 lines
net/hsr/hsr_framereg.c +2
-0+static struct node_entry *find_node_by_AddrB (struct list_head *node_db, +unsigned char addr[ETH_ALEN ])
Alignment...
net/hsr/hsr_framereg.c line 124
Quoted 3 lines
net/hsr/hsr_framereg.c +3
-0+int framereg_merge_node (struct hsr_priv *hsr_priv,enum hsr_dev_idx dev_idx, +struct sk_buff *skb) +{
[]
net/hsr/hsr_framereg.c line 141
Quoted 5 lines
net/hsr/hsr_framereg.c +5
-0+ node =find_node_by_AddrA (&hsr_priv->node_db, hsr_stag->MacAddressA); +if (!node) { +rcu_read_unlock (); + found =0 ; + node =kmalloc (sizeof (*node),GFP_ATOMIC );
why GFP_ATOMIC?
Quoted 5 lines
net/hsr/hsr_framereg.c +5
-0+if (!node) +return -ENOMEM ; + +memcpy (node->MacAddressA, hsr_stag->MacAddressA,ETH_ALEN ); +memcpy (node->MacAddressB, ethhdr->h_source,ETH_ALEN );
net/hsr/hsr_framereg.c line 156
Quoted 10 lines
net/hsr/hsr_framereg.c +10
-0+ +for (i =0 ; i <HSR_MAX_SLAVE ; i++) + node->time_in[i] =0 ; +for (i =0 ; i <HSR_MAX_DEV ; i++) + node->seq_out[i] =0 ; +/* +printk(KERN_INFO "HSR: Added node %pM / %pM\n", +node->MacAddressA, +node->MacAddressB); +*/
Please remove commented out code here and everywhere else...
[too long, stopped reading]
Quoted 4 lines · Joe Perches
Quoted 1 line · Arvid Brodin
The kernel patch.
[]
What does this mean (the "[]")?
Quoted 5 lines
Quoted 4 lines
net/hsr/hsr_device.c +0
-0@@ -0,0 +1,531 @@
Quoted 11 lines
net/hsr/hsr_device.c line 35
Quoted 9 lines
net/hsr/hsr_device.c +9
-0+static int is_admin_up (struct net_device *dev) +{ +return (dev->flags &IFF_UP ); +} + +static int is_operstate_up (struct net_device *dev) +{ +return (dev->operstate ==IF_OPER_UP ); +}bool?
Yep, didn't know the bool type existed.
Quoted 17 lines
net/hsr/hsr_device.c line 43
Quoted 8 lines
net/hsr/hsr_device.c +7
-0+static void __hsr_set_operstate (struct net_device *dev,int transition) +{ +if (dev->operstate != transition) { +/* +switch (transition) { +case IF_OPER_UP: +printk(KERN_INFO "%s: new operstate is IF_OPER_UP\n", dev->name); netdev_info(dev, "new operstate is IF_OPER_UP\n");net/hsr/hsr_device.c line 46
Quoted 3 lines
net/hsr/hsr_device.c +3
-0+break ; +default : +printk (KERN_INFO "%s: new operstate is !IF_OPER_UP (%d)\n" , dev->name, transition);etc.
Quoted 13 lines
net/hsr/hsr_device.c line 66
Quoted 11 lines
net/hsr/hsr_device.c +11
-0+void hsr_set_operstate (struct net_device *hsr_dev,struct net_device *slave1, +struct net_device *slave2) +{ +if (!is_admin_up (hsr_dev)) { +__hsr_set_operstate (hsr_dev,IF_OPER_DOWN ); +return ; + } +/* +printk(KERN_INFO "Slave1/2 operstate: %d/%d\n", +slave1->operstate, slave2->operstate); +*/ Please remove commented out code.
I intended to do so when I send the patch of course. I didn't know it would be so frowned upon in a RFC, I thought it would be enough to note the existence of the commented out code under known problems, as I did in RFC part 0. Lesson learned!
Quoted 95 lines
Quoted 14 lines
net/hsr/hsr_device.c +13
-0+static void restore_slaves (struct net_device *hsr_dev) +{ +struct hsr_priv *hsr_priv; +struct net_device *slave[2 ]; +int i; +int res; + + hsr_priv =netdev_priv (hsr_dev); +for (i =0 ; i <2 ; i++) + slave[i] = hsr_priv->slave_data[i].dev; + +rtnl_lock (); +net/hsr/hsr_device.c line 355
Quoted 10 lines
net/hsr/hsr_device.c +10
-0+/* Restore promiscuity */ +for (i =0 ; i <2 ; i++) { +if (!hsr_priv->slave_data[i].promisc) +continue ; + res =dev_set_promiscuity (slave[i], + -hsr_priv->slave_data[i].promisc); +if (res) +pr_info ("HSR: Cannot restore promiscuity (%s, %d)\n" , + slave[i]->name, + res);shouldn't this just be:
netdev_info(slave[i], "cannot restore promiscuity: %d\n", res);If you must use pr_<level> please add
#definepr_fmt(fmt)KBUILD_MODNAME": " fmt
before any include and let the printk subsystem
add MODNAME as a prefix.net/hsr/hsr_device.c line 429
Quoted 7 lines
net/hsr/hsr_device.c +7
-0+static int check_slave_ok (struct net_device *dev) +{ +/* Don't allow HSR on non-ethernet like devices */ +if ((dev->flags &IFF_LOOPBACK ) || (dev->type !=ARPHRD_ETHER ) || + (dev->addr_len !=ETH_ALEN )) { +pr_info ("%s: Cannot enslave loopback or non-ethernet device\n" , + dev->name);netdev_info(dev, "Cannot enslave...");net/hsr/hsr_device.c line 436
Quoted 7 lines
net/hsr/hsr_device.c +7
-0+return -EINVAL ; + } + +/* Don't allow enslaving hsr devices */ +if (is_hsr_master (dev)) { +pr_info ("%s: Don't try to create trees of hsr devices!\n" , + dev->name);netdev_err(dev, "Cannot create trees of hsr devices\n");net/hsr/hsr_device.c line 490
Quoted 6 lines
net/hsr/hsr_device.c +5
-0+int hsr_dev_finalize (struct net_device *hsr_dev,struct net_device *slave[2 ]) +{ +/* Set hsr_dev's MAC address to that of mac_slave1 */ +memcpy (hsr_dev->dev_addr, hsr_priv->slave_data[0 ].dev->dev_addr, + hsr_dev->addr_len);
ETH_ALEN?net/hsr/hsr_device.h
Quoted 1 line
net/hsr/hsr_device.h +0
-0[]
net/hsr/hsr_device.h line 21
Quoted 6 lines
net/hsr/hsr_device.h +4
-0@@ -0,0 +1,27 @@ +void hsr_dev_setup (struct net_device *dev); +int hsr_dev_finalize (struct net_device *hsr_dev,struct net_device *slave[2 ]); +void hsr_set_operstate (struct net_device *hsr_dev,struct net_device *slave1, +struct net_device *slave2);please align arguments immediately after the open parenthesis.
net/hsr/hsr_framereg.c
Quoted 1 line
net/hsr/hsr_framereg.c +0
-0[]
net/hsr/hsr_framereg.c
Quoted 2 lines
net/hsr/hsr_framereg.c +2
-0+static struct node_entry *find_node_by_AddrA (struct list_head *node_db, +unsigned char addr[ETH_ALEN ])static struct
node_entry*find_node_by_AddrA(structlist_head*node_db,
unsigned char addr[ETH_ALEN])
[]net/hsr/hsr_framereg.c line 66
Quoted 2 lines
net/hsr/hsr_framereg.c +2
-0+static struct node_entry *find_node_by_AddrB (struct list_head *node_db, +unsigned char addr[ETH_ALEN ])Alignment...
net/hsr/hsr_framereg.c line 124
Quoted 3 lines
net/hsr/hsr_framereg.c +3
-0+int framereg_merge_node (struct hsr_priv *hsr_priv,enum hsr_dev_idx dev_idx, +struct sk_buff *skb) +{[]
Quoted 7 lines
net/hsr/hsr_framereg.c line 141
Quoted 5 lines
net/hsr/hsr_framereg.c +5
-0+ node =find_node_by_AddrA (&hsr_priv->node_db, hsr_stag->MacAddressA); +if (!node) { +rcu_read_unlock (); + found =0 ; + node =kmalloc (sizeof (*node),GFP_ATOMIC );why
GFP_ATOMIC?
This function is (indirectly) called by the receive callback for packet type ETH_P_HSR (hsr_rcv() in hsr_main.c). If I recall correctly, I tried GFP_KERNEL first but the kernel complained over sleeping in atomic context. I'll check it out again.
Quoted 19 lines
Quoted 6 lines
net/hsr/hsr_framereg.c +5
-0+if (!node) +return -ENOMEM ; + +memcpy (node->MacAddressA, hsr_stag->MacAddressA,ETH_ALEN ); +memcpy (node->MacAddressB, ethhdr->h_source,ETH_ALEN );net/hsr/hsr_framereg.c line 156
Quoted 10 lines
net/hsr/hsr_framereg.c +10
-0+ +for (i =0 ; i <HSR_MAX_SLAVE ; i++) + node->time_in[i] =0 ; +for (i =0 ; i <HSR_MAX_DEV ; i++) + node->seq_out[i] =0 ; +/* +printk(KERN_INFO "HSR: Added node %pM / %pM\n", +node->MacAddressA, +node->MacAddressB); +*/ Please remove commented out code here and everywhere else...
Quoted 2 lines
[too long, stopped reading]
Thank you for your time. I will take care of these issues when I get back from my vacation. :)
Signature · 2 lines
Arvid Brodin | Consultant (Linux) XDIN AB | Jan Stenbecks Torg 17 | SE-164 40 Kista | Sweden | xdin.com
Hello! This is version 3 of my RFC for HSR support. The complete diffstat of this version of the kernel patch:
Documentation/networking/hsr/hsr_genl.c | 221 ++++++++++++++ include/linux/if_ether.h | 1 + include/linux/if_link.h | 11 + net/Kconfig | 1 + net/Makefile | 1 + net/hsr/Kconfig | 33 ++ net/hsr/Makefile | 7 + net/hsr/hsr_device.c | 506 +++++++++++++++++++++++++++++++ net/hsr/hsr_device.h | 27 ++ net/hsr/hsr_framereg.c | 303 ++++++++++++++++++ net/hsr/hsr_framereg.h | 52 ++++ net/hsr/hsr_main.c | 402 ++++++++++++++++++++++++ net/hsr/hsr_netlink.c | 293 ++++++++++++++++++ net/hsr/hsr_netlink.h | 64 ++++ net/hsr/hsr_private.h | 162 ++++++++++ 15 files changed, 2084 insertions(+), 0 deletions(-)
Changes since v2:
Quoted 7 lines · Joe Perches
net/hsr/hsr_device.c line 35
Quoted 4 lines · Arvid Brodin
net/hsr/hsr_device.c new file +4
-0+static int is_operstate_up (struct net_device *dev) +{ +return (dev->operstate ==IF_OPER_UP ); +}bool?
Check. (Changed to bool here and in other places where a boolean was returned.)
Quoted 9 lines
net/hsr/hsr_device.c line 43
Quoted 7 lines
net/hsr/hsr_device.c new file +7
-0+static void __hsr_set_operstate (struct net_device *dev,int transition) +{ +if (dev->operstate != transition) { +/* +switch (transition) { +case IF_OPER_UP: +printk(KERN_INFO "%s: new operstate is IF_OPER_UP\n", dev->name); netdev_info(dev, "new operstate is IF_OPER_UP\n");
Check. Changed all printouts to use netdev_info() etc instead of printk()/pr_info().
Quoted 6 lines
net/hsr/hsr_device.c line 66
Quoted 4 lines
net/hsr/hsr_device.c new file +4
-0+/* +printk(KERN_INFO "Slave1/2 operstate: %d/%d\n", +slave1->operstate, slave2->operstate); +*/ Please remove commented out code.
Check. (Removed debug code; still need to keep the FIXMEs so I don't forget them.)
Quoted 4 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+void hsr_set_operstate(struct net_device *hsr_dev, struct net_device *slave1, + struct net_device *slave2);please align arguments immediately after the open parenthesis.
Check, fixed.
Quoted 11 lines
net/hsr/hsr_framereg.c line 124
Quoted 3 lines
net/hsr/hsr_framereg.c new file +3
-0+int framereg_merge_node (struct hsr_priv *hsr_priv,enum hsr_dev_idx dev_idx, +struct sk_buff *skb) +{[]
net/hsr/hsr_framereg.c line 141
Quoted 5 lines
net/hsr/hsr_framereg.c new file +5
-0+ node =find_node_by_AddrA (&hsr_priv->node_db, hsr_stag->MacAddressA); +if (!node) { +rcu_read_unlock (); + found =0 ; + node =kmalloc (sizeof (*node),GFP_ATOMIC );why
GFP_ATOMIC?
This is in the frame receive path; we're not allowed to sleep here (?).
Quoted 4 lines · Stephen Hemminger
Documentation/networking/hsr/hsr_genl.c
Quoted 1 line · Arvid Brodin
Documentation/networking/hsr/hsr_genl.c +0
-01. I like documentation, I like examples, but examples in the Documentation directory get stale and end up not working.
I see your point, but I'd really like to supply this example code, because frankly, the documentation on Generic Netlink with libnl isn't very good if you aren't already "in the know". It took some time to figure this out.
I added "Current as of <date>" in the header comment so that people at least see when it is out of date. Is this an OK compromise?
Quoted 3 lines
2. I am not a fan of the non-standard unaligned access optimization. Stinks too much like the old BSD
IFF_TRAILERSthing that still persists to this day.
This has now been removed. Architectures without HAVE_EFFICIENT_UNALIGNED_ACCESS will always memmove() the payload.
net/hsr/hsr_device.c
Quoted 9 lines
3. The code seems to go to a lot of locking effort to get atomic state update, if it used the bits in
dev_state(ienetif_carrieretc) instead of operstate andif_flagsI think it would be simpler and safer. I.enet/hsr/hsr_device.c new file +4
-0+static int is_admin_up (struct net_device *dev) +{ +return (dev->flags &IFF_UP ); +} is redundant with netif_running()
Not sure what you mean by neither "a lot of locking effort" nor "atomic state update" here? (Please elaborate.)
netif_running() checks __LINK_STATE_START. This has got to do with carrier state rather than administrative state, right? So it's not the same as checking IFF_UP? Actually I'm pretty confused by how the kernel implements state tracking of network devices...
It doesn't seem to be normal practice to change operstate like I do, so I'm probably not doing it right. Linkwatch sets IF_OPER_LOWERLAYERDOWN in default_operstate() (net/core/link_watch.c) if !netif_carrier_ok(dev) and (dev->ifindex != dev->iflink). Can I use this for my virtual hsr device driver somehow? What is dev->iflink?
The HSR interface should be IF_OPER_LOWERLAYERDOWN if it's admin UP but both slaves are inoperable.
(The linkwatch reference to IF_OPER_LOWERLAYERDOWN is the only one that I can find in the kernel code.)
Quoted 2 lines
4. Don't use mixed case as in:
+ HSR_Ver = 0;
The HSR_Ver (and others like MacAddressA, HSR_TLV_Length etc) are the names as written in the HSR IEC standard. Is it still desirable that I change them to lower case?
I've changed the code a bit so the HSR_Ver local variable and some others are no longer present, but the struct hsr_tag fields is still as written in the IEC spec. I also added a comment about this. Ok?
Quoted 3 lines
5. The header create code has to handle error cases where:
1. skb must be copied to add header
2. no space left for header in skb
These checks does not seem to be done anywhere else where eth_header() is used, but I added
if (skb_headroom(skb) < HSR_TAGLEN + ETH_HLEN) return -ENOBUFS;
It is not possible to copy the skb to make room for the header, since there is no way to return the new pointer from hsr_header_create().
Quoted 2 lines
6. Don't comment out code and then submit it. I don't like reading and reviewing leftover debug stuff.
Sorry about that. All debug leftovers should now have been removed.
Quoted 3 lines
7. Any operations type structure should be declared 'const'. This is safer from a security point of view and keeps dirty and immutable variables in separate cache areas.
In general, this results in "warning: passing argument <n> of '<some-func>' discards qualifiers from pointer target type", where <some-func> is genl_register_family, genl_register_mc_group, dev_add_pack etc. It does work (and is now fixed) for struct net_device_ops and struct nla_policy though.
Quoted 2 lines
8. If possible use standard netdev macros for printing info messages:
seenetdev_info()etc.
Done.
Quoted 2 lines
9. Be careful about variable names: "seqlock" implies you are using
seq_lock()but you aren't doing that. It is just a spinlock.
Check (changed variable name to seqnr_lock - it's the lock for the sequence_nr variable in the same struct).
Quoted 3 lines
10.
above()seems like it could be done by signed math in one operation without conditional ?: operation.
See timer_before/timer_after for example.
Thanks. I've now changed the function to something more akin to the time_after() function. However, there's an inconsistency in that code where time_after(0, MAX_UTYPE/2) == time_before(0, MAX_UTYPE/2). I don't like that, so I kept an if statement that fixes that. I hope that's OK.
Quoted 2 lines
11. All global variables need to have one prefix. You are using both
hsr_andframreg_. Can you just usehsr_?
Done (using hsr_ only now).
I have run the patch through checkpatch and the remaining errors and warnings are intentional, except for the "C99 // comments" which will be fixed in due time. I believe fixing the other problems would reduce the readability of the code. I am however open to suggestions about this, of course.
Signature · 2 lines
Arvid Brodin | Consultant (Linux) XDIN AB | Jan Stenbecks Torg 17 | SE-164 40 Kista | Sweden | xdin.com
Documentation/networking/hsr/hsr_genl.c new file +221 -0
@@ -0,0 +1,221 @@ +/* +* 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] +* +* Userspace example of using Generic Netlink to get HSR +* ("High-availability Seamless Redundancy") link/network status. +* +* Needs userspace libnl-3. Current as of 2012-08-07. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <netlink/netlink.h> +#include <netlink/socket.h> +#include <netlink/attr.h> +#include <netlink/genl/genl.h> +#include <netlink/genl/ctrl.h> +/**** insert path to hsr_netlink from your kernel below: ****/ +#include "<path>/net/hsr/hsr_netlink.h" + + +static struct nla_policy hsr_genl_policy[HSR_A_MAX +1 ] = { + [HSR_A_NODE_ADDR ] = { .type =NLA_UNSPEC }, + [HSR_A_IFINDEX ] = { .type =NLA_U32 }, + [HSR_A_IF1AGE ] = { .type =NLA_U32 }, + [HSR_A_IF2AGE ] = { .type =NLA_U32 }, +}; + +#define ETH_ALEN 6 + +void print_mac (const unsigned char *addr) +{ +int i; + +for (i =0 ; i <ETH_ALEN ; i++) +printf ("%02x " , addr[i]); +} + + +int parse_genlmsg (struct nl_msg *msg,void *arg) +{ +struct nlattr *attrs[HSR_A_MAX +1 ]; +int rc; +struct genlmsghdr *hdr; +int i; + + rc =genlmsg_parse (nlmsg_hdr (msg),0 , attrs,HSR_A_MAX , hsr_genl_policy); +if (rc <0 ) { +printf ("Error parsing genlmsg: %d\n" , rc); +return rc; + } + + +/* +* Extract command ID from "message" -> "netlink header" -> +* "generic netlink header". +* +* These are the command enums used when creating a genl msg header +* in the kernel with genlmsg_put(). +*/ + hdr =genlmsg_hdr (nlmsg_hdr (msg)); + +switch (hdr->cmd) { +case HSR_C_RING_ERROR : +printf ("Ring error: \n" ); +break ; +case HSR_C_NODE_DOWN : +printf ("Node down: \n" ); +break ; +case HSR_C_SET_NODE_STATUS : +printf ("Node status: \n" ); +break ; +default : +printf ("Unknown genl message (%d)\n" , hdr->cmd); + } + + +/* +* Extract the attached data (the "attributes"). +*/ +for (i =0 ; i <HSR_A_MAX +1 ; i++) +if (attrs[i]) { +switch (attrs[i]->nla_type) { +case HSR_A_NODE_ADDR : +printf (" node address " ); +print_mac (nla_data (attrs[i])); +printf ("\n" ); +break ; +case HSR_A_IFINDEX : +printf (" interface index %d\n" , +nla_get_u32 (attrs[i])); +break ; +case HSR_A_IF1AGE : +printf (" last frame over slave #1 %d ms ago\n" , + (int )nla_get_u32 (attrs[i])); +break ; +case HSR_A_IF2AGE : +printf (" last frame over slave #2 %d ms ago\n" , + (int )nla_get_u32 (attrs[i])); +break ; +default : +printf (" unknown attribute type: %d\n" , + attrs[i]->nla_type); + } + } + +return 0 ; +} + +/* +* Send a "simple" (header only) Generic Netlink message +int query_link_status(int family) +{ +return (genl_send_simple(nlsk, family, HSR_C_GET_STATUS, 1, 0)); +} +*/ + +int query_node_status (struct nl_sock *nlsk,int family,int ifindex, +const unsigned char node_addr[ETH_ALEN ]) +{ +struct nl_msg *msg; +void *user_hdr; + + msg =nlmsg_alloc (); +if (!msg) +return -1 ; + + user_hdr =genlmsg_put (msg,NL_AUTO_PORT ,NL_AUTO_SEQ , family, +0 ,0 ,HSR_C_GET_NODE_STATUS ,1 ); +if (!user_hdr) + goto nla_put_failure; + +/* +* Query by interface name could be implemented in the kernel if needed: +* NLA_PUT_STRING(msg, HSR_A_IFNAME, ifname); +*/ +NLA_PUT_U32 (msg,HSR_A_IFINDEX , ifindex); +NLA_PUT (msg,HSR_A_NODE_ADDR ,ETH_ALEN , node_addr); + +printf ("Querying if %d for status of node " , ifindex); +print_mac (node_addr); +printf ("\n" ); + +return nl_send_auto (nlsk, msg); + +nla_put_failure: +nlmsg_free (msg); +return -1 ; +} + + +int main () +{ +struct nl_sock *nlsk; +int hsr_mgroup; +int rc; + + nlsk =nl_socket_alloc (); +if (!nlsk) { +printf ("nl_socket_alloc() failed\n" ); +return EXIT_FAILURE ; + } +nl_socket_disable_seq_check (nlsk); +nl_socket_modify_cb (nlsk,NL_CB_VALID ,NL_CB_CUSTOM , parse_genlmsg,NULL ); +genl_connect (nlsk); + +/* +* Sign up for HSR messages +*/ + hsr_mgroup =genl_ctrl_resolve_grp (nlsk,"HSR" ,"hsr-network" ); +if (hsr_mgroup <0 ) { +printf ("genl_ctrl_resolve_grp() failed: %d\n" , hsr_mgroup); + rc =EXIT_FAILURE ; + goto out; + } + +printf ("Registering for multicast group %d\n" , hsr_mgroup); + rc =nl_socket_add_memberships (nlsk, hsr_mgroup,0 ); +if (rc <0 ) { +printf ("nl_socket_add_memberships() failed: %d\n" , rc); + goto out; + } + +/* +* Send a query about the status of another node on the HSR network: +*/ +int hsr_family; +/* The hsr if we send the enquiry to (get it with e.g. +* 'cat /sys/class/net/hsr0/ifindex'): */ +const int hsr_ifindex =4 ; +/* The node to enquire about: */ +const unsigned char node[ETH_ALEN ] = {0x00 ,0x24 ,0x74 ,0x00 ,0x17 ,0xAD }; + + hsr_family =genl_ctrl_resolve (nlsk,"HSR" ); +if (hsr_family <0 ) { +printf ("genl_ctrl_resolve() failed: %d\n" , hsr_family); + goto receive; + } + rc =query_node_status (nlsk, hsr_family, hsr_ifindex, node); +printf ("query_node_status() returned %d\n" , rc); + +/* +* Receive messages +*/ +receive: +while (1 ) +nl_recvmsgs_default (nlsk); + + rc =EXIT_SUCCESS ; +out: +nl_close (nlsk); +nl_socket_free (nlsk); +return rc; +}
include/linux/if_ether.h +1 -0
@@ -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
@@ -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
@@ -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
@@ -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 +33 -0
@@ -0,0 +1,33 @@ +# +# 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 you need to enslave these to a virtual hsr interface using the + appropriate user space tool, i.e.: + + # ip link add name hsr0 type hsr dev1 dev2 + + Your Linux box 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, 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. In particular, the + standard is very diffuse on how to use the Ring ID field in the HSR + tag, and it's probable that this code does not do the right thing. + + 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 +506 -0
506 lines not on this page · raw message
net/hsr/hsr_device.h new file +27 -0
@@ -0,0 +1,27 @@ +/* +* 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 *slave[2 ]); +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); + +#endif /* __HSR_DEVICE_H */
net/hsr/hsr_framereg.c new file +303 -0
303 lines not on this page · raw message
net/hsr/hsr_framereg.h new file +52 -0
52 lines not on this page · raw message
net/hsr/hsr_main.c new file +402 -0
402 lines not on this page · raw message
net/hsr/hsr_netlink.c new file +293 -0
293 lines not on this page · raw message
net/hsr/hsr_netlink.h new file +64 -0
64 lines not on this page · raw message
net/hsr/hsr_private.h new file +162 -0
162 lines not on this page · raw message
Signature · 2 lines
Arvid Brodin | Consultant (Linux) XDIN AB | Jan Stenbecks Torg 17 | SE-164 40 Kista | Sweden | xdin.com
David Miller
maintainerThis is not the correct way to post a patch.
You should provide a proper full Subject: and commit message text in the body of the email before the patch itself.
Quoted 5 lines · David Miller
This is not the correct way to post a patch.
You should provide a proper full Subject: and commit message text in the body of the email before the patch itself.
I fail to see what's missing from the Subject: line; please elaborate.
(Please note that I posted this as an RFC since there's still FIXMEs in the code, and there may still be issues pointed out by Stephen Hemminger to be solved. I'm not sure it's ready to go into the kernel just yet.)
Signature · 2 lines
Arvid Brodin | Consultant (Linux) XDIN AB | Jan Stenbecks Torg 17 | SE-164 40 Kista | Sweden | xdin.com
David Miller
maintainerFrom: Arvid Brodin <[email protected]>
Date: Thu, 16 Aug 2012 21:16:34 +0000
Quoted 8 lines · David Miller
Quoted 5 lines
This is not the correct way to post a patch.
You should provide a proper full Subject: and commit message text in the body of the email before the patch itself.
I fail to see what's missing from the Subject: line; please elaborate.
You left in the "Re: " etc. prefix. You should never post new versions of a patch as a reply, you should make new, fresh, mailing list postings.
And you failed to include the commit message body. Everything you seem to thing belongs in the "0/1" posting, at a minimum actually belongs here in 1/1 too.
RFC v4 1/1 net/hsr: Support for the HSR protocol (IEC:2010 / HSR v0)
In reply to David MillerThis would add support for the High-availability Seamless Redundancy network protocol, version 0 (2010).
This RFC is NOT meant for mainline inclusion at the moment since we're trying to figure out how to handle a probable incompatibility with the newer HSR v1 (2012) standard.
---
This RFC is mainly to let you know that I'm still working on this patch. This is now a pretty complete implementation of the HSR v0 (2010) protocol. As explained above, the main reason I'm still not sending this as a real patch meant for mainline inclusion, is the fact that IEC recently released an updated standard (HSR v1 / 2012) which as far as I can tell is not backwards compatible with the 2010 standard implemented by this patch.
At the moment we're trying to figure out what to do about this.
Changes from RFC v3:
* Fixed style issues.
* More thorough device stats updates.
* Fixed bug where node that is downed and restarted within NODE_FORGET_TIME is never seen by other nodes.
* In RFC v3, a slave that was unregistered (e.g. USB network device that was unplugged) would crash the kernel. Works OK now.
* Slave envent handling: MTU change, MAC address change, unregister, type change.
* Master event handling: MTU change.
* Removed NONSTANDARD_HSR config option.
* Guards for VLAN/HSR combo (allowed by the HSR standard, but not yet implemented).
The patch has mostly been tested on 2.6.37, then modified to apply and compile on 3.6.1.
Documentation/networking/hsr/hsr_genl.c | 221 ++++++++++++ include/linux/if_ether.h | 1 + include/linux/if_link.h | 11 + net/Kconfig | 1 + net/Makefile | 1 + net/hsr/Kconfig | 33 ++ net/hsr/Makefile | 7 + net/hsr/hsr_device.c | 576 +++++++++++++++++++++++++++++++ net/hsr/hsr_device.h | 28 ++ net/hsr/hsr_framereg.c | 338 ++++++++++++++++++ net/hsr/hsr_framereg.h | 51 +++ net/hsr/hsr_main.c | 468 +++++++++++++++++++++++++ net/hsr/hsr_main.h | 157 +++++++++ net/hsr/hsr_netlink.c | 305 ++++++++++++++++ net/hsr/hsr_netlink.h | 64 ++++ 15 files changed, 2262 insertions(+), 0 deletions(-) create mode 100644 Documentation/networking/hsr/hsr_genl.c 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
Documentation/networking/hsr/hsr_genl.c new file +221 -0
@@ -0,0 +1,221 @@ +/* +* 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] +* +* Userspace example of using Generic Netlink to get HSR +* ("High-availability Seamless Redundancy") link/network status. +* +* Needs userspace libnl-3. Current as of 2012-08-07. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <netlink/netlink.h> +#include <netlink/socket.h> +#include <netlink/attr.h> +#include <netlink/genl/genl.h> +#include <netlink/genl/ctrl.h> +/**** insert path to hsr_netlink from your kernel below: ****/ +#include "<path>/net/hsr/hsr_netlink.h" + + +static struct nla_policy hsr_genl_policy[HSR_A_MAX +1 ] = { + [HSR_A_NODE_ADDR ] = { .type =NLA_UNSPEC }, + [HSR_A_IFINDEX ] = { .type =NLA_U32 }, + [HSR_A_IF1AGE ] = { .type =NLA_U32 }, + [HSR_A_IF2AGE ] = { .type =NLA_U32 }, +}; + +#define ETH_ALEN 6 + +void print_mac (const unsigned char *addr) +{ +int i; + +for (i =0 ; i <ETH_ALEN ; i++) +printf ("%02x " , addr[i]); +} + + +int parse_genlmsg (struct nl_msg *msg,void *arg) +{ +struct nlattr *attrs[HSR_A_MAX +1 ]; +int rc; +struct genlmsghdr *hdr; +int i; + + rc =genlmsg_parse (nlmsg_hdr (msg),0 , attrs,HSR_A_MAX , hsr_genl_policy); +if (rc <0 ) { +printf ("Error parsing genlmsg: %d\n" , rc); +return rc; + } + + +/* +* Extract command ID from "message" -> "netlink header" -> +* "generic netlink header". +* +* These are the command enums used when creating a genl msg header +* in the kernel with genlmsg_put(). +*/ + hdr =genlmsg_hdr (nlmsg_hdr (msg)); + +switch (hdr->cmd) { +case HSR_C_RING_ERROR : +printf ("Ring error: \n" ); +break ; +case HSR_C_NODE_DOWN : +printf ("Node down: \n" ); +break ; +case HSR_C_SET_NODE_STATUS : +printf ("Node status: \n" ); +break ; +default : +printf ("Unknown genl message (%d)\n" , hdr->cmd); + } + + +/* +* Extract the attached data (the "attributes"). +*/ +for (i =0 ; i <HSR_A_MAX +1 ; i++) +if (attrs[i]) { +switch (attrs[i]->nla_type) { +case HSR_A_NODE_ADDR : +printf (" node address " ); +print_mac (nla_data (attrs[i])); +printf ("\n" ); +break ; +case HSR_A_IFINDEX : +printf (" interface index %d\n" , +nla_get_u32 (attrs[i])); +break ; +case HSR_A_IF1AGE : +printf (" last frame over slave #1 %d ms ago\n" , + (int )nla_get_u32 (attrs[i])); +break ; +case HSR_A_IF2AGE : +printf (" last frame over slave #2 %d ms ago\n" , + (int )nla_get_u32 (attrs[i])); +break ; +default : +printf (" unknown attribute type: %d\n" , + attrs[i]->nla_type); + } + } + +return 0 ; +} + +/* +* Send a "simple" (header only) Generic Netlink message +int query_link_status(int family) +{ +return (genl_send_simple(nlsk, family, HSR_C_GET_STATUS, 1, 0)); +} +*/ + +int query_node_status (struct nl_sock *nlsk,int family,int ifindex, +const unsigned char node_addr[ETH_ALEN ]) +{ +struct nl_msg *msg; +void *user_hdr; + + msg =nlmsg_alloc (); +if (!msg) +return -1 ; + + user_hdr =genlmsg_put (msg,NL_AUTO_PORT ,NL_AUTO_SEQ , family, +0 ,0 ,HSR_C_GET_NODE_STATUS ,1 ); +if (!user_hdr) + goto nla_put_failure; + +/* +* Query by interface name could be implemented in the kernel if needed: +* NLA_PUT_STRING(msg, HSR_A_IFNAME, ifname); +*/ +NLA_PUT_U32 (msg,HSR_A_IFINDEX , ifindex); +NLA_PUT (msg,HSR_A_NODE_ADDR ,ETH_ALEN , node_addr); + +printf ("Querying if %d for status of node " , ifindex); +print_mac (node_addr); +printf ("\n" ); + +return nl_send_auto (nlsk, msg); + +nla_put_failure: +nlmsg_free (msg); +return -1 ; +} + + +int main () +{ +struct nl_sock *nlsk; +int hsr_mgroup; +int rc; + + nlsk =nl_socket_alloc (); +if (!nlsk) { +printf ("nl_socket_alloc() failed\n" ); +return EXIT_FAILURE ; + } +nl_socket_disable_seq_check (nlsk); +nl_socket_modify_cb (nlsk,NL_CB_VALID ,NL_CB_CUSTOM , parse_genlmsg,NULL ); +genl_connect (nlsk); + +/* +* Sign up for HSR messages +*/ + hsr_mgroup =genl_ctrl_resolve_grp (nlsk,"HSR" ,"hsr-network" ); +if (hsr_mgroup <0 ) { +printf ("genl_ctrl_resolve_grp() failed: %d\n" , hsr_mgroup); + rc =EXIT_FAILURE ; + goto out; + } + +printf ("Registering for multicast group %d\n" , hsr_mgroup); + rc =nl_socket_add_memberships (nlsk, hsr_mgroup,0 ); +if (rc <0 ) { +printf ("nl_socket_add_memberships() failed: %d\n" , rc); + goto out; + } + +/* +* Send a query about the status of another node on the HSR network: +*/ +int hsr_family; +/* The hsr if we send the enquiry to (get it with e.g. +* 'cat /sys/class/net/hsr0/ifindex'): */ +const int hsr_ifindex =4 ; +/* The node to enquire about: */ +const unsigned char node[ETH_ALEN ] = {0x00 ,0x24 ,0x74 ,0x00 ,0x17 ,0xAD }; + + hsr_family =genl_ctrl_resolve (nlsk,"HSR" ); +if (hsr_family <0 ) { +printf ("genl_ctrl_resolve() failed: %d\n" , hsr_family); + goto receive; + } + rc =query_node_status (nlsk, hsr_family, hsr_ifindex, node); +printf ("query_node_status() returned %d\n" , rc); + +/* +* Receive messages +*/ +receive: +while (1 ) +nl_recvmsgs_default (nlsk); + + rc =EXIT_SUCCESS ; +out: +nl_close (nlsk); +nl_socket_free (nlsk); +return rc; +}
include/linux/if_ether.h +1 -0
@@ -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
@@ -432,4 +432,15 @@ enum {#define IFLA_IPOIB_MAX (__IFLA_IPOIB_MAX - 1) +/* 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
@@ -218,6 +218,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
@@ -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 +33 -0
@@ -0,0 +1,33 @@ +# +# 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 you need to enslave these to a virtual hsr interface using the + appropriate user space tool, i.e.: + + # ip link add name hsr0 type hsr dev1 dev2 + + Your Linux box 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, 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. In particular, the + standard is very diffuse on how to use the Ring ID field in the HSR + tag, and it's probable that this code does not do the right thing. + + 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 +576 -0
576 lines not on this page · raw message
net/hsr/hsr_device.h new file +28 -0
@@ -0,0 +1,28 @@ +/* +* 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 *slave[2 ]); +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 +338 -0
338 lines not on this page · raw message
net/hsr/hsr_framereg.h new file +51 -0
51 lines not on this page · raw message
net/hsr/hsr_main.c new file +468 -0
468 lines not on this page · raw message
net/hsr/hsr_main.h new file +157 -0
157 lines not on this page · raw message
net/hsr/hsr_netlink.c new file +305 -0
305 lines not on this page · raw message
net/hsr/hsr_netlink.h new file +64 -0
64 lines not on this page · raw message
Re: [RFC v4 1/1] net/hsr: Support for the HSR protocol (IEC:2010 / HSR v0)
Quoted 33 lines · On Fri, 12 Oct 2012 17:11:12 +0000 Arvid Brodin <[email protected]> wrote:
This would add support for the High-availability Seamless Redundancy network protocol, version 0 (2010).
This RFC is NOT meant for mainline inclusion at the moment since we're trying to figure out how to handle a probable incompatibility with the newer HSR v1 (2012) standard.
---
This RFC is mainly to let you know that I'm still working on this patch. This is now a pretty complete implementation of the HSR v0 (2010) protocol. As explained above, the main reason I'm still not sending this as a real patch meant for mainline inclusion, is the fact that IEC recently released an updated standard (HSR v1 / 2012) which as far as I can tell is not backwards compatible with the 2010 standard implemented by this patch.
At the moment we're trying to figure out what to do about this.
Changes from RFC v3:
* Fixed style issues.
* More thorough device stats updates.
* Fixed bug where node that is downed and restarted withinNODE_FORGET_TIMEis never seen by other nodes.
* In RFC v3, a slave that was unregistered (e.g. USB network device that was unplugged) would crash the kernel. Works OK now.
* Slave envent handling: MTU change, MAC address change, unregister, type change.
* Master event handling: MTU change.
* RemovedNONSTANDARD_HSRconfig option.
* Guards for VLAN/HSR combo (allowed by the HSR standard, but not yet implemented).
Quoted 2 lines
The patch has mostly been tested on 2.6.37, then modified to apply and compile on 3.6.1.
Thanks for keeping up with this, I know it must seem like a long struggle to get it upstream.
1. Since this is new functionality, it should be submitted against net-next tree. Dave isn't accepting patches for that yet.
2. Lots of formatting issues. Please run checkpatch.
3. Minor nits:
Could this be replaced by netif_running()?
+static bool is_admin_up(struct net_device *dev)
+{
+ return (dev && (dev->flags & IFF_UP));
+}
And this by netif_oper_up()?
+static bool is_operstate_up(struct net_device *dev) +{
+ return (dev && (dev->operstate == IF_OPER_UP));
+}
+
Re: [RFC v4 1/1] net/hsr: Support for the HSR protocol (IEC:2010 / HSR v0)
In reply to Arvid BrodinQuoted 6 lines · Arvid Brodin
This would add support for the High-availability Seamless Redundancy network protocol, version 0 (2010).
This RFC is NOT meant for mainline inclusion at the moment since we're trying to figure out how to handle a probable incompatibility with the newer HSR v1 (2012) standard.
just trivial comments, ignore as you choose.
net/hsr/hsr_device.c
Quoted 1 line
net/hsr/hsr_device.c +0
-0
[]
net/hsr/hsr_device.c line 58
Quoted 13 lines
net/hsr/hsr_device.c +13
-0+void hsr_set_operstate (struct net_device *hsr_dev,struct net_device *slave1, +struct net_device *slave2) +{ +if (!is_admin_up (hsr_dev)) { +__hsr_set_operstate (hsr_dev,IF_OPER_DOWN ); +return ; + } + +if (is_operstate_up (slave1) ||is_operstate_up (slave2)) +__hsr_set_operstate (hsr_dev,IF_OPER_UP ); +else +__hsr_set_operstate (hsr_dev,IF_OPER_LOWERLAYERDOWN ); +}
sometimes it's better to have a single call like
{
int type;
if (!is_admin_up(hsr_dev))
type = IF_OPER_DOWN;
else if (is_operstate_up(slave1) || is_operstate_up(slave2))
type = IF_OPER_UP;
else
type = IF_OPER_LOWERLAYERDOWN;
__hsr_set_operstate(hsr_dev, type);
}[]
net/hsr/hsr_device.c line 211
Quoted 12 lines
net/hsr/hsr_device.c +12
-0+static int hsr_dev_xmit (struct sk_buff *skb,struct net_device *dev) +{ +struct hsr_priv *hsr_priv; +struct hsr_ethhdr *hsr_ethhdr; +struct sk_buff *skb2; +int res1, res2; + + hsr_priv =netdev_priv (dev); + hsr_ethhdr = (struct hsr_ethhdr *) skb->data; + +if ((ntohs (skb->protocol) !=ETH_P_HSR ) || + (ntohs (hsr_ethhdr->ethhdr.h_proto) !=ETH_P_HSR )) {
These ntohs calls are done at runtime.
The conversion could be done at compile time instead using
if (skb->protocol != ntohs(ETH_P_HSR) ||
hsr_ethhdr->ethhdr.h_proto != ntohs(ETH_P_HSR)) {[]
net/hsr/hsr_device.c
Quoted 2 lines
net/hsr/hsr_device.c +2
-0+static void restore_slaves (struct net_device *hsr_dev) +{
[]
net/hsr/hsr_device.c line 392
Quoted 3 lines
net/hsr/hsr_device.c +3
-0+netdev_info (hsr_dev,"HSR: Cannot restore slave " +"promiscuity (%s, %d)\n" , + hsr_priv->slave[i]->name, res);
It's nicer to coalesce formats for easier grep
netdev_info(hsr_dev, "HSR: Cannot restore slave promiscuity (%s, %d)\n", hsr_priv->slave[i]->name, res);
or maybe use special wrappers for something like:
int hsr_info(hsr, slave, fmt, ...)
{
}
[]
net/hsr/hsr_framereg.c line 66
Quoted 10 lines
net/hsr/hsr_framereg.c +8
-0+static struct node_entry *find_node_by_AddrB (struct list_head *node_db, +unsigned char addr[ETH_ALEN ]) +{ +struct node_entry *node; + +list_for_each_entry_rcu (node, node_db, mac_list) +if (!compare_ether_addr (node->MacAddressB, addr)) +return node;
please use braces when the list/for has an if
Documentation/networking/hsr/hsr_genl.c
Quoted 1 line · On Wed, 4 Jul 2012 00:12:13 +0000 Arvid Brodin <[email protected]> wrote:
Documentation/networking/hsr/hsr_genl.c +0
-0
1. I like documentation, I like examples, but examples in the Documentation directory get stale and end up not working.
2. I am not a fan of the non-standard unaligned access optimization. Stinks too much like the old BSD IFF_TRAILERS thing that still persists to this day.
3. The code seems to go to a lot of locking effort to get atomic state update, if it used the bits in dev_state (ie netif_carrier etc) instead of operstate and if_flags I think it would be simpler and safer. I.e
+static int is_admin_up(struct net_device *dev)
+{
+ return (dev->flags & IFF_UP);
+}
is redundant with netif_running()
4. Don't use mixed case as in:
+ HSR_Ver = 0;
5. The header create code has to handle error cases where:
1. skb must be copied to add header
2. no space left for header in skb
6. Don't comment out code and then submit it. I don't like reading and reviewing leftover debug stuff.
7. Any operations type structure should be declared 'const'. This is safer from a security point of view and keeps dirty and immutable variables in separate cache areas.
8. If possible use standard netdev macros for printing info messages:
see netdev_info() etc.
9. Be careful about variable names: "seqlock" implies you are using seq_lock() but you aren't doing that. It is just a spinlock.
10. above() seems like it could be done by signed math in one operation without conditional ?: operation.
See timer_before/timer_after for example.
11. All global variables need to have one prefix. You are using both hsr_ and framreg_. Can you just use hsr_?
Quoted 7 lines · Stephen Hemminger
Documentation/networking/hsr/hsr_genl.c
Quoted 1 line · On Wed, 4 Jul 2012 00:12:13 +0000 Arvid Brodin <[email protected]> wrote:
Documentation/networking/hsr/hsr_genl.c +0
-01. I like documentation, I like examples, but examples in the Documentation directory get stale and end up not working.
I'd really like to supply this example code, because frankly, the documentation on Generic Netlink with libnl isn't very good if you aren't already "in the know". It took some time to figure this out.
Any better idea on where to place it? Would it help if I added a "Written <date>" in the header comment so that people at least see when it is out of date?
Quoted 3 lines
2. I am not a fan of the non-standard unaligned access optimization. Stinks too much like the old BSD
IFF_TRAILERSthing that still persists to this day.
Ok, I'll just remove it then, no problem.
net/hsr/hsr_device.c
Quoted 9 lines
3. The code seems to go to a lot of locking effort to get atomic state update, if it used the bits in
dev_state(ienetif_carrieretc) instead of operstate andif_flagsI think it would be simpler and safer. I.enet/hsr/hsr_device.c new file +4
-0+static int is_admin_up (struct net_device *dev) +{ +return (dev->flags &IFF_UP ); +} is redundant with netif_running()
Not sure what you mean by neither "a lot of locking effort" nor "atomic state update" here?
netif_running() checks __LINK_STATE_START. This has got to do with carrier state rather than administrative state, right? So they're not the same? Actually I'm pretty confused by the state tracking of network devices...
It doesn't seem to be normal practice to change operstate like I do, so I'm probably not doing it right. Linkwatch sets IF_OPER_LOWERLAYERDOWN in default_operstate() (net/core/link_watch.c) if !netif_carrier_ok(dev) and (dev->ifindex != dev->iflink). Can I use this for my virtual hsr device driver somehow? I guess it should be IF_OPER_LOWERLAYERDOWN if it's admin UP but both slaves are inoperable.
(The linkwatch reference to IF_OPER_LOWERLAYERDOWN is the only one that I can find.)
Quoted 3 lines
4. Don't use mixed case as in:
+ HSR_Ver = 0;
I was a bit unsure about this. The HSR_Ver (and others like MacAddressA, HSR_TLV_Length etc) are the names as written in the HSR IEC standard. Is it still desirable that I change them to lower case?
Quoted 7 lines
5. The header create code has to handle error cases where:
1. skb must be copied to add header
2. no space left for header in skb6. Don't comment out code and then submit it. I don't like reading and reviewing leftover debug stuff.
Ok, sorry about that.
Quoted 10 lines
7. Any operations type structure should be declared 'const'. This is safer from a security point of view and keeps dirty and immutable variables in separate cache areas.
8. If possible use standard netdev macros for printing info messages:
seenetdev_info()etc.9. Be careful about variable names: "seqlock" implies you are using
seq_lock()but you aren't doing that. It is just a spinlock.
Quoted 7 lines
10.
above()seems like it could be done by signed math in one operation without conditional ?: operation.
See timer_before/timer_after for example.11. All global variables need to have one prefix. You are using both
hsr_andframreg_. Can you just usehsr_?
Thank you for your time on this. I'll take care of these issues when I get back from my vacation, which is long overdue. Thanks!
Signature · 2 lines
Arvid Brodin | Consultant (Linux) XDIN AB | Jan Stenbecks Torg 17 | SE-164 40 Kista | Sweden | xdin.com