[net-next RFC PATCH 1/2] add support for PRP similar to HSR

From: Murali Karicheri
Date: Wed May 06 2020 - 12:35:47 EST


PRP protocol is similar to HSR in many aspects and this patch add a
command type prp to create prp interface using two slave interfaces
similar to HSR

HSR and PRP interfaces are setup in a similar way in kernel as
the protocols shares many similar attributes. So restructure
the code to avoid duplication and use a unified netlink
interface for both HSR and PRP

Signed-off-by: Murali Karicheri <m-karicheri2@xxxxxx>
---
include/uapi/linux/if_link.h | 16 ++++-
ip/Makefile | 5 +-
ip/iplink_hsr.c | 111 +++-------------------------------
ip/iplink_hsr_prp_common.c | 114 +++++++++++++++++++++++++++++++++++
ip/iplink_hsr_prp_common.h | 24 ++++++++
ip/iplink_prp.c | 60 ++++++++++++++++++
6 files changed, 223 insertions(+), 107 deletions(-)
create mode 100644 ip/iplink_hsr_prp_common.c
create mode 100644 ip/iplink_hsr_prp_common.h
create mode 100644 ip/iplink_prp.c

diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 978f98c76be1..30d9d2c9c12f 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -904,7 +904,6 @@ enum {


/* HSR section */
-
enum {
IFLA_HSR_UNSPEC,
IFLA_HSR_SLAVE1,
@@ -915,7 +914,6 @@ enum {
IFLA_HSR_VERSION, /* HSR version */
__IFLA_HSR_MAX,
};
-
#define IFLA_HSR_MAX (__IFLA_HSR_MAX - 1)

/* STATS section */
@@ -1052,4 +1050,18 @@ struct ifla_rmnet_flags {
__u32 mask;
};

+/* HSR-PRP section */
+enum {
+ IFLA_HSR_PRP_UNSPEC,
+ IFLA_HSR_PRP_SLAVE1,
+ IFLA_HSR_PRP_SLAVE2,
+ IFLA_HSR_PRP_SF_MC_ADDR_LSB, /* Last byte of supervision addr */
+ IFLA_HSR_PRP_SF_MC_ADDR, /* Supervision frame multicast addr */
+ IFLA_HSR_PRP_SEQ_NR,
+ IFLA_HSR_PRP_VERSION, /* HSR version */
+ __IFLA_HSR_PRP_MAX,
+};
+
+#define IFLA_HSR_PRP_MAX (__IFLA_HSR_PRP_MAX - 1)
+
#endif /* _LINUX_IF_LINK_H */
diff --git a/ip/Makefile b/ip/Makefile
index 5ab78d7d3b84..8dc72fbfb2b1 100644
--- a/ip/Makefile
+++ b/ip/Makefile
@@ -7,8 +7,9 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \
iplink_vlan.o link_veth.o link_gre.o iplink_can.o iplink_xdp.o \
iplink_macvlan.o ipl2tp.o link_vti.o link_vti6.o link_xfrm.o \
iplink_vxlan.o tcp_metrics.o iplink_ipoib.o ipnetconf.o link_ip6tnl.o \
- link_iptnl.o link_gre6.o iplink_bond.o iplink_bond_slave.o iplink_hsr.o \
- iplink_bridge.o iplink_bridge_slave.o ipfou.o iplink_ipvlan.o \
+ link_iptnl.o link_gre6.o iplink_bond.o iplink_bond_slave.o \
+ iplink_hsr_prp_common.o iplink_hsr.o iplink_prp.o iplink_bridge.o \
+ iplink_bridge_slave.o ipfou.o iplink_ipvlan.o \
iplink_geneve.o iplink_vrf.o iproute_lwtunnel.o ipmacsec.o ipila.o \
ipvrf.o iplink_xstats.o ipseg6.o iplink_netdevsim.o iplink_rmnet.o \
ipnexthop.o
diff --git a/ip/iplink_hsr.c b/ip/iplink_hsr.c
index 7d9167d4e6a3..d8a7f9a52267 100644
--- a/ip/iplink_hsr.c
+++ b/ip/iplink_hsr.c
@@ -11,15 +11,7 @@
* Based on iplink_vlan.c by Patrick McHardy <kaber@xxxxxxxxx>
*/

-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h> /* Needed by linux/if.h for some reason */
-#include <linux/if.h>
-#include <linux/if_arp.h>
-#include "rt_names.h"
-#include "utils.h"
-#include "ip_common.h"
+#include "iplink_hsr_prp_common.h"

static void print_usage(FILE *f)
{
@@ -46,100 +38,13 @@ static void usage(void)
static int hsr_parse_opt(struct link_util *lu, int argc, char **argv,
struct nlmsghdr *n)
{
- int ifindex;
- unsigned char multicast_spec;
- unsigned char protocol_version;
+ int ret;

- while (argc > 0) {
- if (matches(*argv, "supervision") == 0) {
- NEXT_ARG();
- if (get_u8(&multicast_spec, *argv, 0))
- invarg("ADDR-BYTE is invalid", *argv);
- addattr_l(n, 1024, IFLA_HSR_MULTICAST_SPEC,
- &multicast_spec, 1);
- } else if (matches(*argv, "version") == 0) {
- NEXT_ARG();
- if (!(get_u8(&protocol_version, *argv, 0) == 0 ||
- get_u8(&protocol_version, *argv, 0) == 1))
- invarg("version is invalid", *argv);
- addattr_l(n, 1024, IFLA_HSR_VERSION,
- &protocol_version, 1);
- } else if (matches(*argv, "slave1") == 0) {
- NEXT_ARG();
- ifindex = ll_name_to_index(*argv);
- if (ifindex == 0)
- invarg("No such interface", *argv);
- addattr_l(n, 1024, IFLA_HSR_SLAVE1, &ifindex, 4);
- } else if (matches(*argv, "slave2") == 0) {
- NEXT_ARG();
- ifindex = ll_name_to_index(*argv);
- if (ifindex == 0)
- invarg("No such interface", *argv);
- addattr_l(n, 1024, IFLA_HSR_SLAVE2, &ifindex, 4);
- } else if (matches(*argv, "help") == 0) {
- usage();
- return -1;
- } else {
- fprintf(stderr, "hsr: what is \"%s\"?\n", *argv);
- usage();
- return -1;
- }
- argc--, argv++;
- }
+ ret = hsr_prp_parse_opt(true, lu, argc, argv, n);
+ if (ret < 0)
+ usage();

- return 0;
-}
-
-static void hsr_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
-{
- SPRINT_BUF(b1);
-
- if (!tb)
- return;
-
- if (tb[IFLA_HSR_SLAVE1] &&
- RTA_PAYLOAD(tb[IFLA_HSR_SLAVE1]) < sizeof(__u32))
- return;
- if (tb[IFLA_HSR_SLAVE2] &&
- RTA_PAYLOAD(tb[IFLA_HSR_SLAVE2]) < sizeof(__u32))
- return;
- if (tb[IFLA_HSR_SEQ_NR] &&
- RTA_PAYLOAD(tb[IFLA_HSR_SEQ_NR]) < sizeof(__u16))
- return;
- if (tb[IFLA_HSR_SUPERVISION_ADDR] &&
- RTA_PAYLOAD(tb[IFLA_HSR_SUPERVISION_ADDR]) < ETH_ALEN)
- return;
-
- if (tb[IFLA_HSR_SLAVE1])
- print_string(PRINT_ANY,
- "slave1",
- "slave1 %s ",
- ll_index_to_name(rta_getattr_u32(tb[IFLA_HSR_SLAVE1])));
- else
- print_null(PRINT_ANY, "slave1", "slave1 %s ", "<none>");
-
- if (tb[IFLA_HSR_SLAVE2])
- print_string(PRINT_ANY,
- "slave2",
- "slave2 %s ",
- ll_index_to_name(rta_getattr_u32(tb[IFLA_HSR_SLAVE2])));
- else
- print_null(PRINT_ANY, "slave2", "slave2 %s ", "<none>");
-
- if (tb[IFLA_HSR_SEQ_NR])
- print_int(PRINT_ANY,
- "seq_nr",
- "sequence %d ",
- rta_getattr_u16(tb[IFLA_HSR_SEQ_NR]));
-
- if (tb[IFLA_HSR_SUPERVISION_ADDR])
- print_string(PRINT_ANY,
- "supervision_addr",
- "supervision %s ",
- ll_addr_n2a(RTA_DATA(tb[IFLA_HSR_SUPERVISION_ADDR]),
- RTA_PAYLOAD(tb[IFLA_HSR_SUPERVISION_ADDR]),
- ARPHRD_VOID,
- b1, sizeof(b1)));
+ return ret;
}

static void hsr_print_help(struct link_util *lu, int argc, char **argv,
@@ -150,8 +55,8 @@ static void hsr_print_help(struct link_util *lu, int argc, char **argv,

struct link_util hsr_link_util = {
.id = "hsr",
- .maxattr = IFLA_HSR_MAX,
+ .maxattr = IFLA_HSR_PRP_MAX,
.parse_opt = hsr_parse_opt,
- .print_opt = hsr_print_opt,
+ .print_opt = hsr_prp_print_opt,
.print_help = hsr_print_help,
};
diff --git a/ip/iplink_hsr_prp_common.c b/ip/iplink_hsr_prp_common.c
new file mode 100644
index 000000000000..780c1cbb6a05
--- /dev/null
+++ b/ip/iplink_hsr_prp_common.c
@@ -0,0 +1,114 @@
+/*
+ * iplink_hsr_prp_common.c Common utilities for hsr and prp
+ *
+ * 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.
+ *
+ * Authors: Murali Karicheri <m-karicheri2@xxxxxx>
+ *
+ *
+ */
+
+#include "iplink_hsr_prp_common.h"
+
+int hsr_prp_parse_opt(bool hsr, struct link_util *lu, int argc, char **argv,
+ struct nlmsghdr *n)
+{
+ int ifindex;
+ unsigned char multicast_spec;
+ unsigned char protocol_version;
+
+ while (argc > 0) {
+ if (matches(*argv, "supervision") == 0) {
+ NEXT_ARG();
+ if (get_u8(&multicast_spec, *argv, 0))
+ invarg("ADDR-BYTE is invalid", *argv);
+ addattr_l(n, 1024, IFLA_HSR_PRP_SF_MC_ADDR_LSB,
+ &multicast_spec, 1);
+ } else if (hsr && matches(*argv, "version") == 0) {
+ NEXT_ARG();
+ if (!(get_u8(&protocol_version, *argv, 0) == 0 ||
+ get_u8(&protocol_version, *argv, 0) == 1))
+ invarg("version is invalid", *argv);
+ addattr_l(n, 1024, IFLA_HSR_PRP_VERSION,
+ &protocol_version, 1);
+ } else if (matches(*argv, "slave1") == 0) {
+ NEXT_ARG();
+ ifindex = ll_name_to_index(*argv);
+ if (ifindex == 0)
+ invarg("No such interface", *argv);
+ addattr_l(n, 1024, IFLA_HSR_PRP_SLAVE1, &ifindex, 4);
+ } else if (matches(*argv, "slave2") == 0) {
+ NEXT_ARG();
+ ifindex = ll_name_to_index(*argv);
+ if (ifindex == 0)
+ invarg("No such interface", *argv);
+ addattr_l(n, 1024, IFLA_HSR_PRP_SLAVE2, &ifindex, 4);
+ } else if (matches(*argv, "help") == 0) {
+ return -1;
+ } else {
+ if (hsr)
+ fprintf(stderr, "hsr: what is \"%s\"?\n", *argv);
+ else
+ fprintf(stderr, "prp: what is \"%s\"?\n", *argv);
+ return -1;
+ }
+ argc--, argv++;
+ }
+
+ return 0;
+}
+
+void hsr_prp_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+{
+ SPRINT_BUF(b1);
+
+ if (!tb)
+ return;
+
+ if (tb[IFLA_HSR_PRP_SLAVE1] &&
+ RTA_PAYLOAD(tb[IFLA_HSR_PRP_SLAVE1]) < sizeof(__u32))
+ return;
+ if (tb[IFLA_HSR_PRP_SLAVE2] &&
+ RTA_PAYLOAD(tb[IFLA_HSR_PRP_SLAVE2]) < sizeof(__u32))
+ return;
+ if (tb[IFLA_HSR_PRP_SEQ_NR] &&
+ RTA_PAYLOAD(tb[IFLA_HSR_PRP_SEQ_NR]) < sizeof(__u16))
+ return;
+ if (tb[IFLA_HSR_PRP_SF_MC_ADDR] &&
+ RTA_PAYLOAD(tb[IFLA_HSR_PRP_SF_MC_ADDR]) < ETH_ALEN)
+ return;
+
+ if (tb[IFLA_HSR_PRP_SLAVE1])
+ print_string(PRINT_ANY,
+ "slave1",
+ "slave1 %s ",
+ ll_index_to_name(rta_getattr_u32(tb[IFLA_HSR_PRP_SLAVE1])));
+ else
+ print_null(PRINT_ANY, "slave1", "slave1 %s ", "<none>");
+
+ if (tb[IFLA_HSR_PRP_SLAVE2])
+ print_string(PRINT_ANY,
+ "slave2",
+ "slave2 %s ",
+ ll_index_to_name(rta_getattr_u32(tb[IFLA_HSR_PRP_SLAVE2])));
+ else
+ print_null(PRINT_ANY, "slave2", "slave2 %s ", "<none>");
+
+ if (tb[IFLA_HSR_PRP_SEQ_NR])
+ print_int(PRINT_ANY,
+ "seq_nr",
+ "sequence %d ",
+ rta_getattr_u16(tb[IFLA_HSR_PRP_SEQ_NR]));
+
+ if (tb[IFLA_HSR_PRP_SF_MC_ADDR])
+ print_string(PRINT_ANY,
+ "supervision_addr",
+ "supervision %s ",
+ ll_addr_n2a(RTA_DATA(tb[IFLA_HSR_PRP_SF_MC_ADDR]),
+ RTA_PAYLOAD(tb[IFLA_HSR_PRP_SF_MC_ADDR]),
+ ARPHRD_VOID,
+ b1, sizeof(b1)));
+}
diff --git a/ip/iplink_hsr_prp_common.h b/ip/iplink_hsr_prp_common.h
new file mode 100644
index 000000000000..a50bd7e532ee
--- /dev/null
+++ b/ip/iplink_hsr_prp_common.h
@@ -0,0 +1,24 @@
+/*
+ * iplink_hsr_prp_common.h HSR/PRP common header file
+ *
+ * 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.
+ *
+ * Authors: Murali Karicheri <m-karicheri2@xxxxxx>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h> /* Needed by linux/if.h for some reason */
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+int hsr_prp_parse_opt(bool hsr, struct link_util *lu, int argc, char **argv,
+ struct nlmsghdr *n);
+void hsr_prp_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]);
diff --git a/ip/iplink_prp.c b/ip/iplink_prp.c
new file mode 100644
index 000000000000..eff8a0d215fa
--- /dev/null
+++ b/ip/iplink_prp.c
@@ -0,0 +1,60 @@
+/*
+ * iplink_prp.c PRP device support
+ *
+ * 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.
+ *
+ * Authors: Murali Karicheri <m-karicheri2@xxxxxx>
+ *
+ * Based on iplink_hsr.c by Arvid Brodin <arvid.brodin@xxxxxxxx>
+ */
+
+#include "iplink_hsr_prp_common.h"
+
+static void print_usage(FILE *f)
+{
+ fprintf(f,
+"Usage:\tip link add name NAME type prp slave1 SLAVE1-IF slave2 SLAVE2-IF\n"
+"\t[ supervision ADDR-BYTE ]\n"
+"\n"
+"NAME\n"
+" name of new prp device (e.g. prp0)\n"
+"SLAVE1-IF, SLAVE2-IF\n"
+" the two slave devices bound to the PRP device\n"
+"ADDR-BYTE\n"
+" 0-255; the last byte of the multicast address used for PRP supervision\n"
+" frames (default = 0)\n");
+}
+
+static void usage(void)
+{
+ print_usage(stderr);
+}
+
+static int prp_parse_opt(struct link_util *lu, int argc, char **argv,
+ struct nlmsghdr *n)
+{
+ int ret;
+
+ ret = hsr_prp_parse_opt(false, lu, argc, argv, n);
+ if (ret < 0)
+ usage();
+
+ return ret;
+}
+
+static void prp_print_help(struct link_util *lu, int argc, char **argv,
+ FILE *f)
+{
+ print_usage(f);
+}
+
+struct link_util prp_link_util = {
+ .id = "prp",
+ .maxattr = IFLA_HSR_PRP_MAX,
+ .parse_opt = prp_parse_opt,
+ .print_opt = hsr_prp_print_opt,
+ .print_help = prp_print_help,
+};
--
2.17.1