[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20210929152848.1710552-4-razor@blackwall.org>
Date: Wed, 29 Sep 2021 18:28:40 +0300
From: Nikolay Aleksandrov <razor@...ckwall.org>
To: netdev@...r.kernel.org
Cc: roopa@...dia.com, donaldsharp72@...il.com, dsahern@...il.com,
idosch@...sch.org, Nikolay Aleksandrov <nikolay@...dia.com>
Subject: [RFC iproute2-next 03/11] ip: nexthop: add nh struct and a helper to parse nhmsg into it
From: Nikolay Aleksandrov <nikolay@...dia.com>
Add a structure which describes a nexthop with all of its properties and
a helper which parses a nhmsg into it. Note the LWT attribute is copied
because there are too many different types with their own structures,
having to follow them all for changes would be overkill. It's much better
to copy the attribtue and pass it for decoding to the lwt code which is
already well maintained.
Signed-off-by: Nikolay Aleksandrov <nikolay@...dia.com>
---
ip/ipnexthop.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++-
ip/nh_common.h | 33 +++++++++++++++++
2 files changed, 129 insertions(+), 1 deletion(-)
create mode 100644 ip/nh_common.h
diff --git a/ip/ipnexthop.c b/ip/ipnexthop.c
index a4048d803325..be8541476fa6 100644
--- a/ip/ipnexthop.c
+++ b/ip/ipnexthop.c
@@ -13,6 +13,7 @@
#include "utils.h"
#include "ip_common.h"
+#include "nh_common.h"
static struct {
unsigned int flushed;
@@ -212,13 +213,20 @@ out:
return rc;
}
+static bool __valid_nh_group_attr(const struct rtattr *g_attr)
+{
+ int num = RTA_PAYLOAD(g_attr) / sizeof(struct nexthop_grp);
+
+ return num && num * sizeof(struct nexthop_grp) == RTA_PAYLOAD(g_attr);
+}
+
static void print_nh_group(FILE *fp, const struct rtattr *grps_attr)
{
struct nexthop_grp *nhg = RTA_DATA(grps_attr);
int num = RTA_PAYLOAD(grps_attr) / sizeof(*nhg);
int i;
- if (!num || num * sizeof(*nhg) != RTA_PAYLOAD(grps_attr)) {
+ if (!__valid_nh_group_attr(grps_attr)) {
fprintf(fp, "<invalid nexthop group>");
return;
}
@@ -328,6 +336,93 @@ static void print_nh_res_bucket(FILE *fp, const struct rtattr *res_bucket_attr)
close_json_object();
}
+static void ipnh_destroy_entry(struct nh_entry *nhe)
+{
+ if (nhe->nh_encap)
+ free(nhe->nh_encap);
+ if (nhe->nh_groups)
+ free(nhe->nh_groups);
+}
+
+/* parse nhmsg into nexthop entry struct which must be destroyed by
+ * ipnh_destroy_enty when it's not needed anymore
+ */
+static int ipnh_parse_nhmsg(FILE *fp, const struct nhmsg *nhm, int len,
+ struct nh_entry *nhe)
+{
+ struct rtattr *tb[NHA_MAX+1];
+ int err = 0;
+
+ memset(nhe, 0, sizeof(*nhe));
+ parse_rtattr_flags(tb, NHA_MAX, RTM_NHA(nhm), len, NLA_F_NESTED);
+
+ if (tb[NHA_ID])
+ nhe->nh_id = rta_getattr_u32(tb[NHA_ID]);
+
+ if (tb[NHA_OIF])
+ nhe->nh_oif = rta_getattr_u32(tb[NHA_OIF]);
+
+ if (tb[NHA_GROUP_TYPE])
+ nhe->nh_grp_type = rta_getattr_u16(tb[NHA_GROUP_TYPE]);
+
+ if (tb[NHA_GATEWAY]) {
+ if (RTA_PAYLOAD(tb[NHA_GATEWAY]) > sizeof(nhe->nh_gateway)) {
+ fprintf(fp, "<nexthop id %u invalid gateway length %lu>\n",
+ nhe->nh_id, RTA_PAYLOAD(tb[NHA_GATEWAY]));
+ err = EINVAL;
+ goto out_err;
+ }
+ nhe->nh_gateway_len = RTA_PAYLOAD(tb[NHA_GATEWAY]);
+ memcpy(&nhe->nh_gateway, RTA_DATA(tb[NHA_GATEWAY]),
+ RTA_PAYLOAD(tb[NHA_GATEWAY]));
+ }
+
+ if (tb[NHA_ENCAP]) {
+ nhe->nh_encap = malloc(RTA_LENGTH(RTA_PAYLOAD(tb[NHA_ENCAP])));
+ if (!nhe->nh_encap) {
+ err = ENOMEM;
+ goto out_err;
+ }
+ memcpy(nhe->nh_encap, tb[NHA_ENCAP],
+ RTA_LENGTH(RTA_PAYLOAD(tb[NHA_ENCAP])));
+ memcpy(&nhe->nh_encap_type, tb[NHA_ENCAP_TYPE],
+ sizeof(nhe->nh_encap_type));
+ }
+
+ if (tb[NHA_GROUP]) {
+ if (!__valid_nh_group_attr(tb[NHA_GROUP])) {
+ fprintf(fp, "<nexthop id %u invalid nexthop group>",
+ nhe->nh_id);
+ err = EINVAL;
+ goto out_err;
+ }
+
+ nhe->nh_groups = malloc(RTA_PAYLOAD(tb[NHA_GROUP]));
+ if (!nhe->nh_groups) {
+ err = ENOMEM;
+ goto out_err;
+ }
+ nhe->nh_groups_cnt = RTA_PAYLOAD(tb[NHA_GROUP]) /
+ sizeof(struct nexthop_grp);
+ memcpy(nhe->nh_groups, RTA_DATA(tb[NHA_GROUP]),
+ RTA_PAYLOAD(tb[NHA_GROUP]));
+ }
+
+ nhe->nh_blackhole = !!tb[NHA_BLACKHOLE];
+ nhe->nh_fdb = !!tb[NHA_FDB];
+
+ nhe->nh_family = nhm->nh_family;
+ nhe->nh_protocol = nhm->nh_protocol;
+ nhe->nh_scope = nhm->nh_scope;
+ nhe->nh_flags = nhm->nh_flags;
+
+ return 0;
+
+out_err:
+ ipnh_destroy_entry(nhe);
+ return err;
+}
+
int print_nexthop(struct nlmsghdr *n, void *arg)
{
struct nhmsg *nhm = NLMSG_DATA(n);
diff --git a/ip/nh_common.h b/ip/nh_common.h
new file mode 100644
index 000000000000..f2ff0e6532d3
--- /dev/null
+++ b/ip/nh_common.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __NH_COMMON_H__
+#define __NH_COMMON_H__ 1
+
+struct nh_entry {
+ __u32 nh_id;
+ __u32 nh_oif;
+ __u32 nh_flags;
+ __u16 nh_grp_type;
+ __u8 nh_family;
+ __u8 nh_scope;
+ __u8 nh_protocol;
+
+ bool nh_blackhole;
+ bool nh_fdb;
+
+ int nh_gateway_len;
+ union {
+ __be32 ipv4;
+ struct in6_addr ipv6;
+ } nh_gateway;
+
+ struct rtattr *nh_encap;
+ union {
+ struct rtattr rta;
+ __u8 _buf[RTA_LENGTH(sizeof(__u16))];
+ } nh_encap_type;
+
+ int nh_groups_cnt;
+ struct nexthop_grp *nh_groups;
+};
+
+#endif /* __NH_COMMON_H__ */
--
2.31.1
Powered by blists - more mailing lists