ip: add NLM_F_ECHO support
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>
This commit is contained in:
@@ -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"
|
||||
|
||||
3
ip/ip.c
3
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",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
20
ip/iplink.c
20
ip/iplink.c
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
21
ip/iproute.c
21
ip/iproute.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
21
ip/iprule.c
21
ip/iprule.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user