+/* SPDX-License-Identifier: GPL-2.0 */
#define _ATFILE_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include "list.h"
#include "ip_common.h"
#include "namespace.h"
+#include "json_print.h"
static int usage(void)
{
fprintf(stderr, " ip [-all] netns exec [NAME] cmd ...\n");
fprintf(stderr, " ip netns monitor\n");
fprintf(stderr, " ip netns list-id\n");
+ fprintf(stderr, "NETNSID := auto | POSITIVE-INT\n");
exit(-1);
}
static int have_rtnl_getnsid = -1;
-static int ipnetns_accept_msg(const struct sockaddr_nl *who,
- struct rtnl_ctrl_data *ctrl,
+static int ipnetns_accept_msg(struct rtnl_ctrl_data *ctrl,
struct nlmsghdr *n, void *arg)
{
struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
return have_rtnl_getnsid;
}
-static int get_netnsid_from_name(const char *name)
+int get_netnsid_from_name(const char *name)
{
struct {
struct nlmsghdr n;
struct rtgenmsg g;
char buf[1024];
- } answer, req = {
+ } req = {
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
.n.nlmsg_flags = NLM_F_REQUEST,
.n.nlmsg_type = RTM_GETNSID,
.g.rtgen_family = AF_UNSPEC,
};
+ struct nlmsghdr *answer;
struct rtattr *tb[NETNSA_MAX + 1];
struct rtgenmsg *rthdr;
int len, fd;
+ netns_nsid_socket_init();
+
fd = netns_get_fd(name);
if (fd < 0)
return fd;
addattr32(&req.n, 1024, NETNSA_FD, fd);
- if (rtnl_talk(&rtnsh, &req.n, &answer.n, sizeof(answer)) < 0) {
+ if (rtnl_talk(&rtnsh, &req.n, &answer) < 0) {
close(fd);
return -2;
}
close(fd);
/* Validate message and parse attributes */
- if (answer.n.nlmsg_type == NLMSG_ERROR)
- return -1;
+ if (answer->nlmsg_type == NLMSG_ERROR)
+ goto err_out;
- rthdr = NLMSG_DATA(&answer.n);
- len = answer.n.nlmsg_len - NLMSG_SPACE(sizeof(*rthdr));
+ rthdr = NLMSG_DATA(answer);
+ len = answer->nlmsg_len - NLMSG_SPACE(sizeof(*rthdr));
if (len < 0)
- return -1;
+ goto err_out;
parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
- if (tb[NETNSA_NSID])
+ if (tb[NETNSA_NSID]) {
+ free(answer);
return rta_getattr_u32(tb[NETNSA_NSID]);
+ }
+err_out:
+ free(answer);
return -1;
}
return NULL;
}
+char *get_name_from_nsid(int nsid)
+{
+ struct nsid_cache *c;
+
+ netns_nsid_socket_init();
+ netns_map_init();
+
+ c = netns_map_get_by_nsid(nsid);
+ if (c)
+ return c->name;
+
+ return NULL;
+}
+
static int netns_map_add(int nsid, const char *name)
{
struct nsid_cache *c;
return -ENOENT;
}
-int print_nsid(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+int print_nsid(struct nlmsghdr *n, void *arg)
{
struct rtgenmsg *rthdr = NLMSG_DATA(n);
struct rtattr *tb[NETNSA_MAX+1];
return -1;
}
+ open_json_object(NULL);
if (n->nlmsg_type == RTM_DELNSID)
- fprintf(fp, "Deleted ");
+ print_bool(PRINT_ANY, "deleted", "Deleted ", true);
nsid = rta_getattr_u32(tb[NETNSA_NSID]);
- fprintf(fp, "nsid %u ", nsid);
+ print_uint(PRINT_ANY, "nsid", "nsid %u ", nsid);
c = netns_map_get_by_nsid(nsid);
if (c != NULL) {
- fprintf(fp, "(iproute2 netns name: %s)", c->name);
+ print_string(PRINT_ANY, "name",
+ "(iproute2 netns name: %s)", c->name);
netns_map_del(c);
}
/* During 'ip monitor nsid', no chance to have new nsid in cache. */
if (c == NULL && n->nlmsg_type == RTM_NEWNSID)
if (netns_get_name(nsid, name) == 0) {
- fprintf(fp, "(iproute2 netns name: %s)", name);
+ print_string(PRINT_ANY, "name",
+ "(iproute2 netns name: %s)", name);
netns_map_add(nsid, name);
}
- fprintf(fp, "\n");
+ print_string(PRINT_FP, NULL, "\n", NULL);
+ close_json_object();
fflush(fp);
return 0;
}
return -ENOTSUP;
}
- if (rtnl_wilddump_request(&rth, AF_UNSPEC, RTM_GETNSID) < 0) {
+ if (rtnl_nsiddump_req(&rth, AF_UNSPEC) < 0) {
perror("Cannot send dump request");
exit(1);
}
+
+ new_json_obj(json);
if (rtnl_dump_filter(&rth, print_nsid, stdout) < 0) {
+ delete_json_obj();
fprintf(stderr, "Dump terminated\n");
exit(1);
}
+ delete_json_obj();
return 0;
}
if (!dir)
return 0;
+ new_json_obj(json);
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0)
continue;
if (strcmp(entry->d_name, "..") == 0)
continue;
- printf("%s", entry->d_name);
+
+ open_json_object(NULL);
+ print_string(PRINT_ANY, "name",
+ "%s", entry->d_name);
if (ipnetns_have_nsid()) {
id = get_netnsid_from_name(entry->d_name);
if (id >= 0)
- printf(" (id: %d)", id);
+ print_uint(PRINT_ANY, "id",
+ " (id: %d)", id);
}
- printf("\n");
+ print_string(PRINT_FP, NULL, "\n", NULL);
+ close_json_object();
}
closedir(dir);
+ delete_json_obj();
return 0;
}
return -1;
}
-static int set_netnsid_from_name(const char *name, int nsid)
+int set_netnsid_from_name(const char *name, int nsid)
{
struct {
struct nlmsghdr n;
};
int fd, err = 0;
+ netns_nsid_socket_init();
+
fd = netns_get_fd(name);
if (fd < 0)
return fd;
addattr32(&req.n, 1024, NETNSA_FD, fd);
addattr32(&req.n, 1024, NETNSA_NSID, nsid);
- if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL) < 0)
err = -2;
close(fd);
return -1;
}
name = argv[0];
- nsid = atoi(argv[1]);
+ /* If a negative nsid is specified the kernel will select the nsid. */
+ if (strcmp(argv[1], "auto") == 0)
+ nsid = -1;
+ else if (get_integer(&nsid, argv[1], 0))
+ invarg("Invalid \"netnsid\" value\n", argv[1]);
+ else if (nsid < 0)
+ invarg("\"netnsid\" value should be >= 0\n", argv[1]);
snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
netns = open(netns_path, O_RDONLY | O_CLOEXEC);