]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
ip: add NLM_F_ECHO support
authorHangbin Liu <liuhangbin@gmail.com>
Fri, 16 Sep 2022 03:34:28 +0000 (11:34 +0800)
committerDavid Ahern <dsahern@kernel.org>
Thu, 22 Sep 2022 23:12:33 +0000 (16:12 -0700)
When user space configures the kernel with netlink messages, it can set the
NLM_F_ECHO flag to request the kernel to send the applied configuration back
to the caller. This allows user space to retrieve configuration information
that are filled by the kernel (either because these parameters can only be
set by the kernel or because user space let the kernel choose a default
value).

NLM_F_ACK is also supplied incase the kernel doesn't support NLM_F_ECHO
and we will wait for the reply forever. Just like the update in
iplink.c, which I plan to post a patch to kernel later.

A new parameter -echo is added when user want to get feedback from kernel.
e.g.

  # ip -echo addr add 192.168.0.1/24 dev eth1
  3: eth1    inet 192.168.0.1/24 scope global eth1
         valid_lft forever preferred_lft forever
  # ip -j -p -echo addr del 192.168.0.1/24 dev eth1
  [ {
          "deleted": true,
          "index": 3,
          "dev": "eth1",
          "family": "inet",
          "local": "192.168.0.1",
          "prefixlen": 24,
          "scope": "global",
          "label": "eth1",
          "valid_life_time": 4294967295,
          "preferred_life_time": 4294967295
      } ]

Suggested-by: Guillaume Nault <gnault@redhat.com>
Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
include/utils.h
ip/ip.c
ip/ipaddress.c
ip/iplink.c
ip/ipnexthop.c
ip/iproute.c
ip/iprule.c
man/man8/ip.8

index eeb23a64f008b5f31522783ed5d8e076c68c6fa1..2eb80b3e487ced3854c5f52438d8de36236d00fa 100644 (file)
@@ -36,6 +36,7 @@ extern int max_flush_loops;
 extern int batch_mode;
 extern int numeric;
 extern bool do_all;
+extern int echo_request;
 
 #ifndef CONFDIR
 #define CONFDIR                "/etc/iproute2"
diff --git a/ip/ip.c b/ip/ip.c
index 82282babdcdb91bf7c15bbdbed5bcf6305224dff..863e42aad9eb7c0cddd5731a98c18ab3d947fb1a 100644 (file)
--- a/ip/ip.c
+++ b/ip/ip.c
@@ -39,6 +39,7 @@ int oneline;
 int brief;
 int json;
 int timestamp;
+int echo_request;
 int force;
 int max_flush_loops = 10;
 int batch_mode;
@@ -293,6 +294,8 @@ int main(int argc, char **argv)
                        ++numeric;
                } else if (matches(opt, "-all") == 0) {
                        do_all = true;
+               } else if (strcmp(opt, "-echo") == 0) {
+                       ++echo_request;
                } else {
                        fprintf(stderr,
                                "Option \"%s\" is unknown, try \"ip -help\".\n",
index 45955e1c065e6f92417c4ac309df2cb0559c574d..71c1ad5f21a898137723bb8e022a30d1d13dba55 100644 (file)
@@ -1586,7 +1586,7 @@ int print_addrinfo(struct nlmsghdr *n, void *arg)
        if (!brief) {
                const char *name;
 
-               if (filter.oneline || filter.flushb) {
+               if (filter.oneline || filter.flushb || echo_request) {
                        const char *dev = ll_index_to_name(ifa->ifa_index);
 
                        if (is_json_context()) {
@@ -2416,6 +2416,11 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
        __u32 preferred_lft = INFINITY_LIFE_TIME;
        __u32 valid_lft = INFINITY_LIFE_TIME;
        unsigned int ifa_flags = 0;
+       struct nlmsghdr *answer;
+       int ret;
+
+       if (echo_request)
+               req.n.nlmsg_flags |= NLM_F_ECHO | NLM_F_ACK;
 
        while (argc > 0) {
                if (strcmp(*argv, "peer") == 0 ||
@@ -2597,9 +2602,23 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
                return -1;
        }
 
-       if (rtnl_talk(&rth, &req.n, NULL) < 0)
+       if (echo_request)
+               ret = rtnl_talk(&rth, &req.n, &answer);
+       else
+               ret = rtnl_talk(&rth, &req.n, NULL);
+
+       if (ret < 0)
                return -2;
 
+       if (echo_request) {
+               new_json_obj(json);
+               open_json_object(NULL);
+               print_addrinfo(answer, stdout);
+               close_json_object();
+               delete_json_obj();
+               free(answer);
+       }
+
        return 0;
 }
 
index b98c1694991e8d629618a5260eac751ed6a644ed..ad22f2d75d3a78ef42c8cbb5da2fe919ae43488d 100644 (file)
@@ -1073,12 +1073,16 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
                .n.nlmsg_type = cmd,
                .i.ifi_family = preferred_family,
        };
+       struct nlmsghdr *answer;
        int ret;
 
        ret = iplink_parse(argc, argv, &req, &type);
        if (ret < 0)
                return ret;
 
+       if (echo_request)
+               req.n.nlmsg_flags |= NLM_F_ECHO | NLM_F_ACK;
+
        if (type) {
                struct link_util *lu;
                struct rtattr *linkinfo;
@@ -1123,9 +1127,23 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
                return -1;
        }
 
-       if (rtnl_talk(&rth, &req.n, NULL) < 0)
+       if (echo_request)
+               ret = rtnl_talk(&rth, &req.n, &answer);
+       else
+               ret = rtnl_talk(&rth, &req.n, NULL);
+
+       if (ret < 0)
                return -2;
 
+       if (echo_request) {
+               new_json_obj(json);
+               open_json_object(NULL);
+               print_linkinfo(answer, stdout);
+               close_json_object();
+               delete_json_obj();
+               free(answer);
+       }
+
        /* remove device from cache; next use can refresh with new data */
        ll_drop_by_index(req.i.ifi_index);
 
index 2f448449ea1d14817840121b4678d7f80c31824e..59f8f2fb0c140466cd9b29ab0d96b71ed6fedb0e 100644 (file)
@@ -919,7 +919,12 @@ static int ipnh_modify(int cmd, unsigned int flags, int argc, char **argv)
                .n.nlmsg_type = cmd,
                .nhm.nh_family = preferred_family,
        };
+       struct nlmsghdr *answer;
        __u32 nh_flags = 0;
+       int ret;
+
+       if (echo_request)
+               req.n.nlmsg_flags |= NLM_F_ECHO | NLM_F_ACK;
 
        while (argc > 0) {
                if (!strcmp(*argv, "id")) {
@@ -999,9 +1004,23 @@ static int ipnh_modify(int cmd, unsigned int flags, int argc, char **argv)
 
        req.nhm.nh_flags = nh_flags;
 
-       if (rtnl_talk(&rth, &req.n, NULL) < 0)
+       if (echo_request)
+               ret = rtnl_talk(&rth, &req.n, &answer);
+       else
+               ret = rtnl_talk(&rth, &req.n, NULL);
+
+       if (ret < 0)
                return -2;
 
+       if (echo_request) {
+               new_json_obj(json);
+               open_json_object(NULL);
+               print_nexthop_nocache(answer, (void *)stdout);
+               close_json_object();
+               delete_json_obj();
+               free(answer);
+       }
+
        return 0;
 }
 
index a8ad7d521f68401f2204dc1cfc038c33bacbf451..4774aac0f884c74d5d5f4735f8a1ec1d6ca2d18f 100644 (file)
@@ -1123,6 +1123,7 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv)
        };
        char  mxbuf[256];
        struct rtattr *mxrta = (void *)mxbuf;
+       struct nlmsghdr *answer;
        unsigned int mxlock = 0;
        char  *d = NULL;
        int gw_ok = 0;
@@ -1133,6 +1134,7 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv)
        int raw = 0;
        int type_ok = 0;
        __u32 nhid = 0;
+       int ret;
 
        if (cmd != RTM_DELROUTE) {
                req.r.rtm_protocol = RTPROT_BOOT;
@@ -1140,6 +1142,9 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv)
                req.r.rtm_type = RTN_UNICAST;
        }
 
+       if (echo_request)
+               req.n.nlmsg_flags |= NLM_F_ECHO | NLM_F_ACK;
+
        mxrta->rta_type = RTA_METRICS;
        mxrta->rta_len = RTA_LENGTH(0);
 
@@ -1586,9 +1591,23 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv)
        if (!type_ok && req.r.rtm_family == AF_MPLS)
                req.r.rtm_type = RTN_UNICAST;
 
-       if (rtnl_talk(&rth, &req.n, NULL) < 0)
+       if (echo_request)
+               ret = rtnl_talk(&rth, &req.n, &answer);
+       else
+               ret = rtnl_talk(&rth, &req.n, NULL);
+
+       if (ret < 0)
                return -2;
 
+       if (echo_request) {
+               new_json_obj(json);
+               open_json_object(NULL);
+               print_route(answer, (void *)stdout);
+               close_json_object();
+               delete_json_obj();
+               free(answer);
+       }
+
        return 0;
 }
 
index 2d39e01bcd3f1e44499c9366ff7ca79578c55b08..af77e62c9249c30e34c35fc4e9ef8c4333595f9d 100644 (file)
@@ -787,6 +787,11 @@ static int iprule_modify(int cmd, int argc, char **argv)
                .frh.family = preferred_family,
                .frh.action = FR_ACT_UNSPEC,
        };
+       struct nlmsghdr *answer;
+       int ret;
+
+       if (echo_request)
+               req.n.nlmsg_flags |= NLM_F_ECHO | NLM_F_ACK;
 
        if (cmd == RTM_NEWRULE) {
                if (argc == 0) {
@@ -1016,9 +1021,23 @@ static int iprule_modify(int cmd, int argc, char **argv)
        if (!table_ok && cmd == RTM_NEWRULE)
                req.frh.table = RT_TABLE_MAIN;
 
-       if (rtnl_talk(&rth, &req.n, NULL) < 0)
+       if (echo_request)
+               ret = rtnl_talk(&rth, &req.n, &answer);
+       else
+               ret = rtnl_talk(&rth, &req.n, NULL);
+
+       if (ret < 0)
                return -2;
 
+       if (echo_request) {
+               new_json_obj(json);
+               open_json_object(NULL);
+               print_rule(answer, stdout);
+               close_json_object();
+               delete_json_obj();
+               free(answer);
+       }
+
        return 0;
 }
 
index f6adbc772925535c0db9fcc72d9e9336be16b5f1..72227d44fd30a6b6e286e0aff58dcb7da0404218 100644 (file)
@@ -237,6 +237,10 @@ The default JSON format is compact and more efficient to parse but
 hard for most users to read.  This flag adds indentation for
 readability.
 
+.TP
+.BR "\-echo"
+Request the kernel to send the applied configuration back.
+
 .SH IP - COMMAND SYNTAX
 
 .SS