diff mbox series

[RFC,iproute2-next,03/11] ip: nexthop: add nh struct and a helper to parse nhmsg into it

Message ID 20210929152848.1710552-4-razor@blackwall.org (mailing list archive)
State Superseded
Delegated to: David Ahern
Headers show
Series ip: nexthop: cache nexthops and print routes' nh info | expand

Checks

Context Check Description
netdev/tree_selection success Not a local patch

Commit Message

Nikolay Aleksandrov Sept. 29, 2021, 3:28 p.m. UTC
From: Nikolay Aleksandrov <nikolay@nvidia.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@nvidia.com>
---
 ip/ipnexthop.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++-
 ip/nh_common.h | 33 +++++++++++++++++
 2 files changed, 129 insertions(+), 1 deletion(-)
 create mode 100644 ip/nh_common.h

Comments

David Ahern Sept. 30, 2021, 3:33 a.m. UTC | #1
On 9/29/21 9:28 AM, Nikolay Aleksandrov wrote:
> @@ -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
> + */

I'd rather not have 2 functions interpreting the attributes. You should
be able to get print_nexthop to use the parse function and then print
using the nh_entry.


> +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;
> +}
> +
diff mbox series

Patch

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__ */