[<prev] [next>] [day] [month] [year] [list]
Message-ID: <525D9721.9020402@xdin.com>
Date: Tue, 15 Oct 2013 21:27:29 +0200
From: Arvid Brodin <arvid.brodin@...n.com>
To: Elías Molina Muñoz <elias.molina@....es>
CC: "netdev@...r.kernel.org" <netdev@...r.kernel.org>,
Stephen Hemminger <shemminger@...tta.com>,
Javier Boticario <jboticario@...il.com>,
balferreira <balferreira@...glemail.com>,
Joe Perches <joe@...ches.com>
Subject: Re: net/hsr Patch - Help
On 2013-10-15 09:42, Elías Molina Muñoz wrote:
> El 09/09/2013 20:15, Arvid Brodin escribió:
>> On 2013-09-06 10:25, Elías Molina Muñoz wrote:
>>> Dear Mr. Brodin,
>>>
>>> I would like to introduce myself. My name is Elías Molina, PhD.
>>> Student at University of Basque Country (Spain). I am writing to
>>> enquire about your HSR patch.
>> Hi!
>>
>>> I have read "This is a patch against net-next (2013-08-21)" in
>>> its last version (v3) so I have tried with several kernel
>>> versions but I do not know which is the repo's correct version
>>> of
>>> http://git.kernel.org/cgit/linux/kernel/git/davem/net-next.git/
>>> .
>>>
>>> Could you tell me which is the kernel version to apply your
>>> patch?
>> I made an error when I sent that patch, so it won't apply to any
>> kernel version.
>>
>> The below patch should work (cd to the net-next directory and apply
>> with patch -Np1):
>>
[removed]
> Dear Mr. Brodin,
>
> Thanks for getting back to me and I apologize for being so late
> replying.
>
> I am writing to enquire if, once compiled the kernel with your patch,
> there is a sample application for verifying the correct operation of
> HSR, as you did in http://patchwork.ozlabs.org/patch/191165/ with
> Documentation/networking/hsr/hsr_genl.c
>
> Thank you very much. Best regards,
>
> Elías Molina
Hi again,
I'm CC:ing the netdev list and others who've shown interest in HSR, since
they might be interested as well.
Yes, I have patches for iproute2 (to make it possible to add HSR devices)
and also a "hsrinfo" program which can be used to query an HSR interface
for statistics, and to listen for any HSR errors detected. The hsrinfo
program is based on the hsr_genl program that you mention. It requires
the libnl3 library.
The hsrinfo program is below (the iproute2 patch was sent in a previous
message). This code is not of the same quality standards as you would
expect of a kernel/iproute2 patch. The idea is to re-write it so that it
becomes part of iproute2, but I won't spend time on that unless there is
some progress with the HSR kernel patch.
---
diff -Nurp hsrinfo-a/hsr_netlink.h hsrinfo-b/hsr_netlink.h
--- hsrinfo-a/hsr_netlink.h 1970-01-01 01:00:00.000000000 +0100
+++ hsrinfo-b/hsr_netlink.h 2013-10-15 21:21:09.058960618 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2011-2013 Autronica Fire and Security AS
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * Author(s):
+ * 2011-2013 Arvid Brodin, arvid.brodin@...n.com
+ */
+
+#ifndef __HSR_NETLINK_H
+#define __HSR_NETLINK_H
+
+/* attributes */
+enum {
+ HSR_A_UNSPEC,
+ HSR_A_NODE_ADDR,
+ HSR_A_IFINDEX,
+ HSR_A_IF1_AGE,
+ HSR_A_IF2_AGE,
+ HSR_A_NODE_ADDR_B,
+ HSR_A_IF1_SEQ,
+ HSR_A_IF2_SEQ,
+ HSR_A_IF1_IFINDEX,
+ HSR_A_IF2_IFINDEX,
+ HSR_A_ADDR_B_IFINDEX,
+ __HSR_A_MAX,
+};
+#define HSR_A_MAX (__HSR_A_MAX - 1)
+
+
+#ifdef __KERNEL__
+
+#include <linux/if_ether.h>
+#include <linux/module.h>
+
+int __init hsr_netlink_init(void);
+void __exit hsr_netlink_exit(void);
+
+void hsr_nl_ringerror(unsigned char addr[ETH_ALEN], int dev_idx);
+void hsr_nl_nodedown(unsigned char addr[ETH_ALEN]);
+void hsr_nl_framedrop(int dropcount, int dev_idx);
+void hsr_nl_linkdown(int dev_idx);
+
+
+/*
+ * Generic Netlink HSR family definition
+ */
+
+
+#endif /* __KERNEL__ */
+
+
+
+/* commands */
+enum {
+ HSR_C_UNSPEC,
+ HSR_C_RING_ERROR,
+ HSR_C_NODE_DOWN,
+ HSR_C_GET_NODE_STATUS,
+ HSR_C_SET_NODE_STATUS,
+ HSR_C_GET_NODE_LIST,
+ HSR_C_SET_NODE_LIST,
+ __HSR_C_MAX,
+};
+#define HSR_C_MAX (__HSR_C_MAX - 1)
+
+
+
+#endif /* __HSR_NETLINK_H */
diff -Nurp hsrinfo-a/hsrinfo.c hsrinfo-b/hsrinfo.c
--- hsrinfo-a/hsrinfo.c 1970-01-01 01:00:00.000000000 +0100
+++ hsrinfo-b/hsrinfo.c 2013-10-15 21:23:32.983517217 +0200
@@ -0,0 +1,504 @@
+/*
+ * Copyright 2011-2013 Autronica Fire and Security AS
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * Author(s):
+ * 2011-2013 Arvid Brodin, arvid.brodin@...n.com
+ *
+ * Userspace example of using Generic Netlink (through libnl-3) to get HSR
+ * ("High-availability Seamless Redundancy") link/network status.
+ */
+
+
+/*
+
+Manual static cross-build:
+
+$ PATH=[toolchain-path]/usr/bin/:${PATH} avr32-unknown-linux-uclibc-gcc -Wall -g -I[toolchain-path]/usr/include/libnl3 -static -L[toolchain-path]/usr/lib hsrinfo.c -o hsrinfo -lnl-genl-3 -lnl-3 -pthread -lm
+
+Native build:
+$ gcc -Wall -g -I /usr/include/libnl3/ -lnl-3 -lnl-genl-3 hsrinfo.c -o hsrinfo-x86
+
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/attr.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/ctrl.h>
+#include <net/if.h>
+#include <linux/if_ether.h>
+#include "hsr_netlink.h"
+
+struct node_item {
+ struct node_item *next;
+ unsigned char addr[ETH_ALEN];
+};
+
+static struct node_item *node_head = NULL;
+
+static int seq_nr = 10;
+
+
+static void nodelist_clear(struct node_item **ni)
+{
+ if (!*ni)
+ return;
+
+ nodelist_clear(&(*ni)->next);
+
+ free(*ni);
+ (*ni) = NULL;
+}
+
+static void nodelist_add(struct node_item **head, const char addr[ETH_ALEN])
+{
+ struct node_item **ni;
+
+ ni = head;
+ while (*ni)
+ ni = &(*ni)->next;
+
+ *ni = calloc(1, sizeof(struct node_item));
+ if (!*ni)
+ return; // No mem
+
+ memcpy((*ni)->addr, addr, ETH_ALEN);
+}
+
+
+static void print_mac(const unsigned char *addr)
+{
+ int i;
+
+ if (!addr) {
+ printf("(null) ");
+ return;
+ }
+
+ for (i = 0; i < ETH_ALEN - 1; i++)
+ printf("%02x:", addr[i]);
+ printf("%02x", addr[ETH_ALEN - 1]);
+}
+
+
+static void parse_ring_error(struct genlmsghdr *hdr)
+{
+ struct nlattr *attr;
+ unsigned char *AddrA;
+ int ifindex;
+ char ifname[IF_NAMESIZE];
+ char *nameptr;
+
+ printf("Ring error: ");
+
+ AddrA = NULL;
+ ifindex = -1;
+
+ attr = genlmsg_attrdata(hdr, 0);
+ int remaining = genlmsg_attrlen(hdr, 0);
+ while (nla_ok(attr, remaining)) {
+ switch (attr->nla_type) {
+ case HSR_A_NODE_ADDR:
+ AddrA = nla_data(attr);
+ break;
+ case HSR_A_IFINDEX:
+ ifindex = nla_get_u32(attr);
+ break;
+ default:
+ printf("unknown attribute type: %d\n", attr->nla_type);
+ }
+ attr = nla_next(attr, &remaining);
+ }
+
+ if (!AddrA) {
+ printf("Error: invalid HSR_C_RING_ERROR packet\n");
+ return;
+ }
+
+ nameptr = if_indextoname(ifindex, ifname);
+ if (!nameptr)
+ snprintf(ifname, IF_NAMESIZE, "if%d", ifindex);
+ printf("interface %s, node ", ifname);
+ print_mac(AddrA);
+ printf("\n");
+}
+
+static void parse_node_down(struct genlmsghdr *hdr)
+{
+ struct nlattr *attr;
+ unsigned char *AddrA;
+
+ printf("Node down: ");
+
+ AddrA = NULL;
+
+ attr = genlmsg_attrdata(hdr, 0);
+ int remaining = genlmsg_attrlen(hdr, 0);
+ while (nla_ok(attr, remaining)) {
+ switch (attr->nla_type) {
+ case HSR_A_NODE_ADDR:
+ AddrA = nla_data(attr);
+ break;
+ default:
+ printf("unknown attribute type: %d\n", attr->nla_type);
+ }
+ attr = nla_next(attr, &remaining);
+ }
+
+ if (!AddrA) {
+ printf("Error: invalid HSR_C_NODE_DOWN packet\n");
+ return;
+ }
+
+ print_mac(AddrA);
+ printf("\n");
+}
+
+static void parse_node_status(struct genlmsghdr *hdr)
+{
+ unsigned char *AddrA, *AddrB;
+ int if1_age, if2_age;
+ int if1_seq, if2_seq;
+ int if1_ifindex, if2_ifindex, addr_b_ifindex;
+ char if1_ifname[IF_NAMESIZE];
+ char if2_ifname[IF_NAMESIZE];
+ char addr_b_ifname[IF_NAMESIZE];
+ char *nameptr;
+ struct nlattr *attr;
+
+ AddrA = NULL;
+ AddrB = NULL;
+ if1_age = -1;
+ if2_age = -1;
+ if1_seq = -1;
+ if2_seq = -1;
+ if1_ifindex = -1;
+ if2_ifindex = -1;
+ addr_b_ifindex = -1;
+
+ attr = genlmsg_attrdata(hdr, 0);
+ int remaining = genlmsg_attrlen(hdr, 0);
+ while (nla_ok(attr, remaining)) {
+ switch (attr->nla_type) {
+ case HSR_A_NODE_ADDR:
+ if (AddrA)
+ printf("%s: Too many AddrA in message!\n", __func__);
+ AddrA = nla_data(attr);
+ break;
+ case HSR_A_NODE_ADDR_B:
+ if (AddrB)
+ printf("%s: Too many AddrB in message!\n", __func__);
+ AddrB = nla_data(attr);
+ break;
+ case HSR_A_IFINDEX:
+ break;
+ case HSR_A_IF1_AGE:
+ if1_age = (int) nla_get_u32(attr);
+ break;
+ case HSR_A_IF2_AGE:
+ if2_age = (int) nla_get_u32(attr);
+ break;
+ case HSR_A_IF1_SEQ:
+ if1_seq = nla_get_u16(attr);
+ break;
+ case HSR_A_IF2_SEQ:
+ if2_seq = nla_get_u16(attr);
+ break;
+ case HSR_A_IF1_IFINDEX:
+ if1_ifindex = nla_get_u32(attr);
+ break;
+ case HSR_A_IF2_IFINDEX:
+ if2_ifindex = nla_get_u32(attr);
+ break;
+ case HSR_A_ADDR_B_IFINDEX:
+ addr_b_ifindex = nla_get_u32(attr);
+ break;
+ default:
+ printf("%s: unknown attribute type: %d\n", __func__, attr->nla_type);
+ }
+ attr = nla_next(attr, &remaining);
+ }
+
+ if (!AddrA) {
+ printf("Error: invalid HSR_C_SET_NODE_STATUS packet\n");
+ return;
+ }
+
+ nameptr = if_indextoname(if1_ifindex, if1_ifname);
+ if (!nameptr)
+ snprintf(if1_ifname, IF_NAMESIZE, "if%d", if1_ifindex);
+ nameptr = if_indextoname(if2_ifindex, if2_ifname);
+ if (!nameptr)
+ snprintf(if2_ifname, IF_NAMESIZE, "if%d", if2_ifindex);
+ nameptr = if_indextoname(addr_b_ifindex, addr_b_ifname);
+ if (!nameptr)
+ snprintf(addr_b_ifname, IF_NAMESIZE, "if%d", addr_b_ifindex);
+
+ printf("Node: ");
+ print_mac(AddrA);
+ if (AddrB) {
+ printf(" AddrB: ");
+ print_mac(AddrB);
+ printf(" (over %s)", addr_b_ifname);
+ }
+ printf("\n Sequence nr (age): %s: %5d (%5d ms); %s: %5d (%5d ms)\n",
+ if1_ifname, if1_seq, if1_age,
+ if2_ifname, if2_seq, if2_age);
+}
+
+static void parse_node_list(struct genlmsghdr *hdr)
+{
+ struct nlattr *attr;
+
+ nodelist_clear(&node_head);
+
+ attr = genlmsg_attrdata(hdr, 0);
+ int remaining = genlmsg_attrlen(hdr, 0);
+ while (nla_ok(attr, remaining)) {
+ switch (attr->nla_type) {
+ case HSR_A_NODE_ADDR:
+ nodelist_add(&node_head, nla_data(attr));
+ break;
+ default:
+ printf("Unknown attribute type for HSR_C_SET_NODE_LIST: %d\n", attr->nla_type);
+ }
+ attr = nla_next(attr, &remaining);
+ }
+}
+
+
+static int parse_genlmsg(struct nl_msg *msg, void *arg)
+{
+ struct genlmsghdr *hdr;
+
+ /*
+ * 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));
+
+// printf("%d: ", nlmsg_hdr(msg)->nlmsg_seq);
+ switch (hdr->cmd) {
+ case HSR_C_RING_ERROR:
+ parse_ring_error(hdr);
+ break;
+ case HSR_C_NODE_DOWN:
+ parse_node_down(hdr);
+ break;
+ case HSR_C_SET_NODE_STATUS:
+ parse_node_status(hdr);
+ break;
+ case HSR_C_SET_NODE_LIST:
+ parse_node_list(hdr);
+ break;
+ default:
+ printf("Unknown genl message received (%d)\n", hdr->cmd);
+ }
+
+ return 0;
+}
+
+
+static int query_get_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, seq_nr++, family,
+ 0, NLM_F_REQUEST, HSR_C_GET_NODE_STATUS, 1);
+ if (!user_hdr)
+ goto nla_put_failure;
+
+ 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;
+}
+
+
+static int query_get_node_list(struct nl_sock *nlsk, int family, int ifindex)
+{
+ struct nl_msg *msg;
+ void *user_hdr;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ user_hdr = genlmsg_put(msg, NL_AUTO_PORT, seq_nr++, family,
+ 0, NLM_F_REQUEST, HSR_C_GET_NODE_LIST, 1);
+ if (!user_hdr)
+ goto nla_put_failure;
+
+ NLA_PUT_U32(msg, HSR_A_IFINDEX, ifindex);
+
+// printf("Querying if %d for node list\n", ifindex);
+
+ return (nl_send_auto(nlsk, msg));
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+
+static void print_usage(const char *name)
+{
+ printf(
+"Usage: %s [-q] interface [node mac address]\n"
+"Display ring error messages for a HSR network interface, or\n"
+"(-q) query the interface node database. The node address parameter is only\n"
+"valid with -q, and limits the output to data about a specific node.\n", name);
+}
+
+
+static const char optstring[] = "+q";
+
+int main(int argc, char **argv)
+{
+ struct nl_sock *nlsk;
+ int hsr_mgroup;
+ int query;
+ int opt, rc;
+ int hsr_ifindex;
+ struct node_item *ni;
+
+ query = 0;
+ opt = getopt(argc, argv, optstring);
+ while (opt != -1) {
+ switch (opt) {
+ case 'q':
+ query = 1;
+ break;
+ default:
+ print_usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ opt = getopt(argc, argv, optstring);
+ }
+
+
+ nlsk = nl_socket_alloc();
+ if (!nlsk) {
+ printf("nl_socket_alloc() failed\n");
+ return EXIT_FAILURE;
+ }
+ 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;
+ }
+
+ nl_socket_disable_seq_check(nlsk);
+
+ if (!query) {
+ if (argc - optind != 1) {
+ print_usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+// 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;
+ }
+
+ while (1)
+ nl_recvmsgs_default(nlsk);
+
+ /* Not reached */
+ }
+
+
+ if (argc - optind < 1) {
+ print_usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ /* The hsr if we send the enquiry to (get it with e.g.
+ * 'cat /sys/class/net/hsr0/ifindex'): */
+ hsr_ifindex = if_nametoindex(argv[optind]);
+ if (hsr_ifindex == 0) {
+ printf("%s: %s\n", argv[optind], strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ /* Get node list */
+ int hsr_family;
+
+ hsr_family = genl_ctrl_resolve(nlsk, "HSR");
+ if (hsr_family < 0) {
+ printf("genl_ctrl_resolve() failed: %d\n", hsr_family);
+ goto out;
+ }
+
+ rc = query_get_node_list(nlsk, hsr_family, hsr_ifindex);
+// printf("query_get_node_list() returned %d\n", rc);
+
+ rc = nl_recvmsgs_default(nlsk);
+// printf("nl_recvmsgs_default() returned %d\n", rc);
+
+ ni = node_head;
+ while (ni) {
+ /*
+ * Send a query about the status of another node on the HSR network:
+ */
+ /* The node to enquire about: */
+ //const unsigned char node[ETH_ALEN] = {0x00, 0x24, 0x74, 0x00, 0x17, 0xAD};
+
+ rc = query_get_node_status(nlsk, hsr_family, hsr_ifindex, ni->addr);
+// printf("query_node_status() returned %d\n", rc);
+
+ ni = ni->next;
+ }
+
+ while (1) {
+ rc = nl_recvmsgs_default(nlsk);
+// printf("nl_recvmsgs_default() returned %d\n", rc);
+ }
+
+
+ rc = EXIT_SUCCESS;
+out:
+ nl_close(nlsk);
+ nl_socket_free(nlsk);
+ return rc;
+}
--
Arvid Brodin | Consultant (Linux)
XDIN AB | Knarrarnäsgatan 7 | SE-164 40 Kista | Sweden | xdin.com
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists