]> git.proxmox.com Git - mirror_iproute2.git/blobdiff - lib/libnetlink.c
vdpa: add .gitignore
[mirror_iproute2.git] / lib / libnetlink.c
index 1892a02ab5d0d73776c9882ffc77edcd2c663d01..c958aa57d0cd3c5d5beffa882631ac622dec4317 100644 (file)
 #include <linux/fib_rules.h>
 #include <linux/if_addrlabel.h>
 #include <linux/if_bridge.h>
+#include <linux/nexthop.h>
 
 #include "libnetlink.h"
+#include "utils.h"
 
+#ifndef __aligned
 #define __aligned(x)           __attribute__((aligned(x)))
+#endif
 
 #ifndef SOL_NETLINK
 #define SOL_NETLINK 270
@@ -125,7 +129,7 @@ int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)
        return 0;
 }
 
-static int nl_dump_ext_ack_done(const struct nlmsghdr *nlh, int error)
+int nl_dump_ext_ack_done(const struct nlmsghdr *nlh, int error)
 {
        struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
        unsigned int hlen = sizeof(int);
@@ -155,7 +159,7 @@ int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)
        return 0;
 }
 
-static int nl_dump_ext_ack_done(const struct nlmsghdr *nlh, int error)
+int nl_dump_ext_ack_done(const struct nlmsghdr *nlh, int error)
 {
        return 0;
 }
@@ -173,6 +177,12 @@ void rtnl_set_strict_dump(struct rtnl_handle *rth)
        rth->flags |= RTNL_HANDLE_F_STRICT_CHK;
 }
 
+int rtnl_add_nl_group(struct rtnl_handle *rth, unsigned int group)
+{
+       return setsockopt(rth->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
+                         &group, sizeof(group));
+}
+
 void rtnl_close(struct rtnl_handle *rth)
 {
        if (rth->fd >= 0) {
@@ -246,6 +256,32 @@ int rtnl_open(struct rtnl_handle *rth, unsigned int subscriptions)
        return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
 }
 
+int rtnl_nexthopdump_req(struct rtnl_handle *rth, int family,
+                        req_filter_fn_t filter_fn)
+{
+       struct {
+               struct nlmsghdr nlh;
+               struct nhmsg nhm;
+               char buf[128];
+       } req = {
+               .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)),
+               .nlh.nlmsg_type = RTM_GETNEXTHOP,
+               .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
+               .nlh.nlmsg_seq = rth->dump = ++rth->seq,
+               .nhm.nh_family = family,
+       };
+
+       if (filter_fn) {
+               int err;
+
+               err = filter_fn(&req.nlh, sizeof(req));
+               if (err)
+                       return err;
+       }
+
+       return send(rth->fd, &req, sizeof(req), 0);
+}
+
 int rtnl_addrdump_req(struct rtnl_handle *rth, int family,
                      req_filter_fn_t filter_fn)
 {
@@ -405,12 +441,13 @@ int rtnl_netconfdump_req(struct rtnl_handle *rth, int family)
        return send(rth->fd, &req, sizeof(req), 0);
 }
 
-int rtnl_nsiddump_req(struct rtnl_handle *rth, int family)
+int rtnl_nsiddump_req_filter_fn(struct rtnl_handle *rth, int family,
+                               req_filter_fn_t filter_fn)
 {
        struct {
                struct nlmsghdr nlh;
                struct rtgenmsg rtm;
-               char buf[0] __aligned(NLMSG_ALIGNTO);
+               char buf[1024];
        } req = {
                .nlh.nlmsg_len = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct rtgenmsg))),
                .nlh.nlmsg_type = RTM_GETNSID,
@@ -418,8 +455,16 @@ int rtnl_nsiddump_req(struct rtnl_handle *rth, int family)
                .nlh.nlmsg_seq = rth->dump = ++rth->seq,
                .rtm.rtgen_family = family,
        };
+       int err;
 
-       return send(rth->fd, &req, sizeof(req), 0);
+       if (!filter_fn)
+               return -EINVAL;
+
+       err = filter_fn(&req.nlh, sizeof(req));
+       if (err)
+               return err;
+
+       return send(rth->fd, &req, req.nlh.nlmsg_len, 0);
 }
 
 static int __rtnl_linkdump_req(struct rtnl_handle *rth, int family)
@@ -718,6 +763,8 @@ static int rtnl_recvmsg(int fd, struct msghdr *msg, char **answer)
        if (len < 0)
                return len;
 
+       if (len < 32768)
+               len = 32768;
        buf = malloc(len);
        if (!buf) {
                fprintf(stderr, "malloc error: not enough buffer\n");
@@ -1130,7 +1177,7 @@ int rtnl_listen(struct rtnl_handle *rtnl,
 int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler,
                   void *jarg)
 {
-       int status;
+       size_t status;
        char buf[16384];
        struct nlmsghdr *h = (struct nlmsghdr *)buf;
 
@@ -1140,14 +1187,15 @@ int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler,
 
                status = fread(&buf, 1, sizeof(*h), rtnl);
 
-               if (status < 0) {
-                       if (errno == EINTR)
-                               continue;
-                       perror("rtnl_from_file: fread");
+               if (status == 0 && feof(rtnl))
+                       return 0;
+               if (status != sizeof(*h)) {
+                       if (ferror(rtnl))
+                               perror("rtnl_from_file: fread");
+                       if (feof(rtnl))
+                               fprintf(stderr, "rtnl-from_file: truncated message\n");
                        return -1;
                }
-               if (status == 0)
-                       return 0;
 
                len = h->nlmsg_len;
                l = len - sizeof(*h);
@@ -1160,12 +1208,11 @@ int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler,
 
                status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
 
-               if (status < 0) {
-                       perror("rtnl_from_file: fread");
-                       return -1;
-               }
-               if (status < l) {
-                       fprintf(stderr, "rtnl-from_file: truncated message\n");
+               if (status != NLMSG_ALIGN(l)) {
+                       if (ferror(rtnl))
+                               perror("rtnl_from_file: fread");
+                       if (feof(rtnl))
+                               fprintf(stderr, "rtnl-from_file: truncated message\n");
                        return -1;
                }
 
@@ -1334,6 +1381,7 @@ struct rtattr *rta_nest(struct rtattr *rta, int maxlen, int type)
        struct rtattr *nest = RTA_TAIL(rta);
 
        rta_addattr_l(rta, maxlen, type, NULL, 0);
+       nest->rta_type |= NLA_F_NESTED;
 
        return nest;
 }
@@ -1395,3 +1443,75 @@ int __parse_rtattr_nested_compat(struct rtattr *tb[], int max,
        memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
        return 0;
 }
+
+static const char *get_nla_type_str(unsigned int attr)
+{
+       switch (attr) {
+#define C(x) case NL_ATTR_TYPE_ ## x: return #x
+       C(U8);
+       C(U16);
+       C(U32);
+       C(U64);
+       C(STRING);
+       C(FLAG);
+       C(NESTED);
+       C(NESTED_ARRAY);
+       C(NUL_STRING);
+       C(BINARY);
+       C(S8);
+       C(S16);
+       C(S32);
+       C(S64);
+       C(BITFIELD32);
+       default:
+               return "unknown";
+       }
+}
+
+void nl_print_policy(const struct rtattr *attr, FILE *fp)
+{
+       const struct rtattr *pos;
+
+       rtattr_for_each_nested(pos, attr) {
+               const struct rtattr *attr;
+
+               fprintf(fp, " policy[%u]:", pos->rta_type & ~NLA_F_NESTED);
+
+               rtattr_for_each_nested(attr, pos) {
+                       struct rtattr *tp[NL_POLICY_TYPE_ATTR_MAX + 1];
+
+                       parse_rtattr_nested(tp, ARRAY_SIZE(tp) - 1, attr);
+
+                       if (tp[NL_POLICY_TYPE_ATTR_TYPE])
+                               fprintf(fp, "attr[%u]: type=%s",
+                                       attr->rta_type & ~NLA_F_NESTED,
+                                       get_nla_type_str(rta_getattr_u32(tp[NL_POLICY_TYPE_ATTR_TYPE])));
+
+                       if (tp[NL_POLICY_TYPE_ATTR_POLICY_IDX])
+                               fprintf(fp, " policy:%u",
+                                       rta_getattr_u32(tp[NL_POLICY_TYPE_ATTR_POLICY_IDX]));
+
+                       if (tp[NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE])
+                               fprintf(fp, " maxattr:%u",
+                                       rta_getattr_u32(tp[NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE]));
+
+                       if (tp[NL_POLICY_TYPE_ATTR_MIN_VALUE_S] && tp[NL_POLICY_TYPE_ATTR_MAX_VALUE_S])
+                               fprintf(fp, " range:[%lld,%lld]",
+                                       (signed long long)rta_getattr_u64(tp[NL_POLICY_TYPE_ATTR_MIN_VALUE_S]),
+                                       (signed long long)rta_getattr_u64(tp[NL_POLICY_TYPE_ATTR_MAX_VALUE_S]));
+
+                       if (tp[NL_POLICY_TYPE_ATTR_MIN_VALUE_U] && tp[NL_POLICY_TYPE_ATTR_MAX_VALUE_U])
+                               fprintf(fp, " range:[%llu,%llu]",
+                                       (unsigned long long)rta_getattr_u64(tp[NL_POLICY_TYPE_ATTR_MIN_VALUE_U]),
+                                       (unsigned long long)rta_getattr_u64(tp[NL_POLICY_TYPE_ATTR_MAX_VALUE_U]));
+
+                       if (tp[NL_POLICY_TYPE_ATTR_MIN_LENGTH])
+                               fprintf(fp, " min len:%u",
+                                       rta_getattr_u32(tp[NL_POLICY_TYPE_ATTR_MIN_LENGTH]));
+
+                       if (tp[NL_POLICY_TYPE_ATTR_MAX_LENGTH])
+                               fprintf(fp, " max len:%u",
+                                       rta_getattr_u32(tp[NL_POLICY_TYPE_ATTR_MAX_LENGTH]));
+               }
+       }
+}