@@ -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);
new file mode 100644
@@ -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__ */